mirror of
https://github.com/bevyengine/bevy
synced 2024-11-21 20:23:28 +00:00
cache bind group hashes
This commit is contained in:
parent
599d30d861
commit
cd1fb92a7a
4 changed files with 102 additions and 38 deletions
|
@ -1,8 +1,10 @@
|
|||
use bevy::prelude::*;
|
||||
use bevy::render::render_graph_2::{StandardMaterial, ShaderUniforms, uniform_selector};
|
||||
use std::collections::VecDeque;
|
||||
use rand::{rngs::StdRng, Rng, SeedableRng};
|
||||
|
||||
fn main() {
|
||||
AppBuilder::new().add_defaults().add_system(build_move_system()).setup_world(setup).run();
|
||||
AppBuilder::new().add_defaults().add_system(build_move_system()).add_system(build_print_status_system()).setup_world(setup).run();
|
||||
}
|
||||
|
||||
fn build_move_system() -> Box<dyn Schedulable> {
|
||||
|
@ -17,6 +19,35 @@ fn build_move_system() -> Box<dyn Schedulable> {
|
|||
})
|
||||
}
|
||||
|
||||
fn build_print_status_system() -> Box<dyn Schedulable> {
|
||||
let mut elapsed = 0.0;
|
||||
let mut frame_time_total = 0.0;
|
||||
let mut frame_time_count = 0;
|
||||
let frame_time_max = 10;
|
||||
let mut frame_time_values = VecDeque::new();
|
||||
SystemBuilder::new("PrintStatus")
|
||||
.read_resource::<Time>()
|
||||
.build(move |_, _world, time, _queries| {
|
||||
elapsed += time.delta_seconds;
|
||||
frame_time_values.push_front(time.delta_seconds);
|
||||
frame_time_total += time.delta_seconds;
|
||||
frame_time_count += 1;
|
||||
if frame_time_count > frame_time_max {
|
||||
frame_time_count = frame_time_max;
|
||||
frame_time_total -= frame_time_values.pop_back().unwrap();
|
||||
}
|
||||
if elapsed > 1.0 {
|
||||
if frame_time_count > 0 && frame_time_total > 0.0 {
|
||||
println!(
|
||||
"fps: {}",
|
||||
1.0 / (frame_time_total / frame_time_count as f32)
|
||||
)
|
||||
}
|
||||
elapsed = 0.0;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn setup(world: &mut World) {
|
||||
let cube = Mesh::load(MeshType::Cube);
|
||||
let plane = Mesh::load(MeshType::Plane { size: 10.0 });
|
||||
|
@ -26,7 +57,7 @@ fn setup(world: &mut World) {
|
|||
(mesh_storage.add(cube), mesh_storage.add(plane))
|
||||
};
|
||||
|
||||
world.build()
|
||||
let mut builder = world.build()
|
||||
// plane
|
||||
.add_archetype(NewMeshEntity {
|
||||
mesh: plane_handle.clone(),
|
||||
|
@ -102,6 +133,26 @@ fn setup(world: &mut World) {
|
|||
Vec3::new(0.0, 0.0, 0.0),
|
||||
Vec3::new(0.0, 0.0, 1.0),
|
||||
)),
|
||||
});
|
||||
|
||||
let mut rng = StdRng::from_entropy();
|
||||
for _ in 0..10000 {
|
||||
|
||||
builder = builder.add_archetype(NewMeshEntity {
|
||||
mesh: cube_handle.clone(),
|
||||
material: StandardMaterial {
|
||||
albedo: math::vec4(0.0, 1.0, 0.0, 1.0),
|
||||
},
|
||||
shader_uniforms: ShaderUniforms {
|
||||
uniform_selectors: vec![
|
||||
uniform_selector::<StandardMaterial>,
|
||||
uniform_selector::<LocalToWorld>,
|
||||
],
|
||||
},
|
||||
local_to_world: LocalToWorld::identity(),
|
||||
translation: Translation::new(rng.gen_range(-50.0, 50.0), rng.gen_range(-50.0, 50.0), 0.0),
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
builder.build();
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
use std::{
|
||||
collections::{hash_map::DefaultHasher},
|
||||
hash::{Hash, Hasher},
|
||||
};
|
||||
pub struct PipelineLayout {
|
||||
pub bind_groups: Vec<BindGroup>,
|
||||
}
|
||||
|
@ -12,7 +16,27 @@ impl PipelineLayout {
|
|||
|
||||
#[derive(Hash)]
|
||||
pub struct BindGroup {
|
||||
pub bindings: Vec<Binding>
|
||||
pub bindings: Vec<Binding>,
|
||||
hash: Option<u64>,
|
||||
}
|
||||
|
||||
impl BindGroup {
|
||||
pub fn new(bindings: Vec<Binding>) -> Self {
|
||||
BindGroup {
|
||||
bindings,
|
||||
hash: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_hash(&self) -> u64 {
|
||||
self.hash.unwrap()
|
||||
}
|
||||
|
||||
pub fn update_hash(&mut self) {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
self.hash(&mut hasher);
|
||||
self.hash = Some(hasher.finish());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Hash)]
|
||||
|
|
|
@ -24,8 +24,8 @@ impl ForwardPipelineBuilder for RenderGraphBuilder {
|
|||
include_str!("forward.frag"),
|
||||
ShaderStage::Fragment,
|
||||
))
|
||||
.add_bind_group(BindGroup {
|
||||
bindings: vec![
|
||||
.add_bind_group(BindGroup::new(
|
||||
vec![
|
||||
Binding {
|
||||
name: "Camera".to_string(),
|
||||
bind_type: BindType::Uniform {
|
||||
|
@ -39,9 +39,9 @@ impl ForwardPipelineBuilder for RenderGraphBuilder {
|
|||
}
|
||||
},
|
||||
]
|
||||
})
|
||||
.add_bind_group(BindGroup {
|
||||
bindings: vec![
|
||||
))
|
||||
.add_bind_group(BindGroup::new(
|
||||
vec![
|
||||
Binding {
|
||||
name: "Object".to_string(),
|
||||
bind_type: BindType::Uniform {
|
||||
|
@ -67,7 +67,7 @@ impl ForwardPipelineBuilder for RenderGraphBuilder {
|
|||
}
|
||||
},
|
||||
]
|
||||
})
|
||||
))
|
||||
.with_rasterization_state(wgpu::RasterizationStateDescriptor {
|
||||
front_face: wgpu::FrontFace::Ccw,
|
||||
cull_mode: wgpu::CullMode::Back,
|
||||
|
|
|
@ -7,11 +7,7 @@ use crate::{
|
|||
TextureDimension,
|
||||
},
|
||||
};
|
||||
use std::{
|
||||
collections::{hash_map::DefaultHasher, HashMap},
|
||||
hash::{Hash, Hasher},
|
||||
ops::Deref,
|
||||
};
|
||||
use std::{collections::HashMap, ops::Deref};
|
||||
|
||||
pub struct DynamicUniformBufferInfo {
|
||||
pub indices: HashMap<usize, Entity>,
|
||||
|
@ -76,7 +72,7 @@ impl WgpuRenderer {
|
|||
}
|
||||
|
||||
pub fn create_render_pipeline(
|
||||
pipeline_descriptor: &PipelineDescriptor,
|
||||
pipeline_descriptor: &mut PipelineDescriptor,
|
||||
bind_group_layouts: &mut HashMap<u64, wgpu::BindGroupLayout>,
|
||||
device: &wgpu::Device,
|
||||
) -> wgpu::RenderPipeline {
|
||||
|
@ -90,10 +86,9 @@ impl WgpuRenderer {
|
|||
};
|
||||
|
||||
// setup new bind group layouts
|
||||
for bind_group in pipeline_descriptor.pipeline_layout.bind_groups.iter() {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
bind_group.hash(&mut hasher);
|
||||
let bind_group_id = hasher.finish();
|
||||
for bind_group in pipeline_descriptor.pipeline_layout.bind_groups.iter_mut() {
|
||||
bind_group.update_hash();
|
||||
let bind_group_id = bind_group.get_hash();
|
||||
if let None = bind_group_layouts.get(&bind_group_id) {
|
||||
let bind_group_layout_binding = bind_group
|
||||
.bindings
|
||||
|
@ -120,10 +115,7 @@ impl WgpuRenderer {
|
|||
.bind_groups
|
||||
.iter()
|
||||
.map(|bind_group| {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
bind_group.hash(&mut hasher);
|
||||
let bind_group_id = hasher.finish();
|
||||
|
||||
let bind_group_id = bind_group.get_hash();
|
||||
bind_group_layouts.get(&bind_group_id).unwrap()
|
||||
})
|
||||
.collect::<Vec<&wgpu::BindGroupLayout>>();
|
||||
|
@ -132,7 +124,7 @@ impl WgpuRenderer {
|
|||
bind_group_layouts: bind_group_layouts.as_slice(),
|
||||
});
|
||||
|
||||
let render_pipeline_descriptor = wgpu::RenderPipelineDescriptor {
|
||||
let mut render_pipeline_descriptor = wgpu::RenderPipelineDescriptor {
|
||||
layout: &pipeline_layout,
|
||||
vertex_stage: wgpu::ProgrammableStageDescriptor {
|
||||
module: &vertex_shader_module,
|
||||
|
@ -160,7 +152,7 @@ impl WgpuRenderer {
|
|||
alpha_to_coverage_enabled: pipeline_descriptor.alpha_to_coverage_enabled,
|
||||
};
|
||||
|
||||
device.create_render_pipeline(&render_pipeline_descriptor)
|
||||
device.create_render_pipeline(&mut render_pipeline_descriptor)
|
||||
}
|
||||
|
||||
pub fn create_render_pass<'a>(
|
||||
|
@ -242,10 +234,7 @@ impl WgpuRenderer {
|
|||
|
||||
// TODO: consider moving this to a resource provider
|
||||
fn setup_bind_group(&mut self, bind_group: &BindGroup) -> u64 {
|
||||
// TODO: cache hash result in bind_group?
|
||||
let mut hasher = DefaultHasher::new();
|
||||
bind_group.hash(&mut hasher);
|
||||
let bind_group_id = hasher.finish();
|
||||
let bind_group_id = bind_group.get_hash();
|
||||
|
||||
if let None = self.bind_groups.get(&bind_group_id) {
|
||||
let mut unset_uniforms = Vec::new();
|
||||
|
@ -368,10 +357,10 @@ impl WgpuRenderer {
|
|||
continue;
|
||||
}
|
||||
|
||||
if info.count >= info.capacity && info.capacity != 0 {
|
||||
if info.count >= info.capacity && info.capacity != 0 {
|
||||
panic!("resizing dynamic uniform buffers isn't supported yet. we still need to support updating bind groups");
|
||||
}
|
||||
|
||||
|
||||
// allocate enough space for twice as many entities as there are currently;
|
||||
info.capacity = info.count * 2;
|
||||
let size = wgpu::BIND_BUFFER_ALIGNMENT * info.capacity;
|
||||
|
@ -406,7 +395,10 @@ impl WgpuRenderer {
|
|||
let alignment = wgpu::BIND_BUFFER_ALIGNMENT as usize;
|
||||
let mut offset = 0usize;
|
||||
|
||||
for (i, (entity, shader_uniforms)) in <Read<ShaderUniforms>>::query().iter_entities(world).enumerate() {
|
||||
for (i, (entity, shader_uniforms)) in <Read<ShaderUniforms>>::query()
|
||||
.iter_entities(world)
|
||||
.enumerate()
|
||||
{
|
||||
// TODO: check if index has changed. if it has, then entity should be updated
|
||||
// TODO: only mem-map entities if their data has changed
|
||||
info.offsets.insert(entity, offset as u64);
|
||||
|
@ -477,7 +469,7 @@ impl Renderer for WgpuRenderer {
|
|||
self.setup_dynamic_entity_shader_uniforms(world, render_graph, &mut encoder);
|
||||
|
||||
// setup, pipelines, bind groups, and resources
|
||||
for (pipeline_name, pipeline_descriptor) in render_graph.pipeline_descriptors.iter() {
|
||||
for (pipeline_name, pipeline_descriptor) in render_graph.pipeline_descriptors.iter_mut() {
|
||||
// create pipelines
|
||||
if let None = self.render_pipelines.get(pipeline_name) {
|
||||
let render_pipeline = WgpuRenderer::create_render_pipeline(
|
||||
|
@ -613,10 +605,7 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> {
|
|||
.iter()
|
||||
.enumerate()
|
||||
{
|
||||
// TODO: cache hash result in bind_group?
|
||||
let mut hasher = DefaultHasher::new();
|
||||
bind_group.hash(&mut hasher);
|
||||
let bind_group_id = hasher.finish();
|
||||
let bind_group_id = bind_group.get_hash();
|
||||
let bind_group_info = self.renderer.bind_groups.get(&bind_group_id).unwrap();
|
||||
|
||||
let mut dynamic_uniform_indices = Vec::new();
|
||||
|
|
Loading…
Reference in a new issue