mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 04:33:37 +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::prelude::*;
|
||||||
use bevy::render::render_graph_2::{StandardMaterial, ShaderUniforms, uniform_selector};
|
use bevy::render::render_graph_2::{StandardMaterial, ShaderUniforms, uniform_selector};
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use rand::{rngs::StdRng, Rng, SeedableRng};
|
||||||
|
|
||||||
fn main() {
|
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> {
|
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) {
|
fn setup(world: &mut World) {
|
||||||
let cube = Mesh::load(MeshType::Cube);
|
let cube = Mesh::load(MeshType::Cube);
|
||||||
let plane = Mesh::load(MeshType::Plane { size: 10.0 });
|
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))
|
(mesh_storage.add(cube), mesh_storage.add(plane))
|
||||||
};
|
};
|
||||||
|
|
||||||
world.build()
|
let mut builder = world.build()
|
||||||
// plane
|
// plane
|
||||||
.add_archetype(NewMeshEntity {
|
.add_archetype(NewMeshEntity {
|
||||||
mesh: plane_handle.clone(),
|
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, 0.0),
|
||||||
Vec3::new(0.0, 0.0, 1.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 struct PipelineLayout {
|
||||||
pub bind_groups: Vec<BindGroup>,
|
pub bind_groups: Vec<BindGroup>,
|
||||||
}
|
}
|
||||||
|
@ -12,7 +16,27 @@ impl PipelineLayout {
|
||||||
|
|
||||||
#[derive(Hash)]
|
#[derive(Hash)]
|
||||||
pub struct BindGroup {
|
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)]
|
#[derive(Hash)]
|
||||||
|
|
|
@ -24,8 +24,8 @@ impl ForwardPipelineBuilder for RenderGraphBuilder {
|
||||||
include_str!("forward.frag"),
|
include_str!("forward.frag"),
|
||||||
ShaderStage::Fragment,
|
ShaderStage::Fragment,
|
||||||
))
|
))
|
||||||
.add_bind_group(BindGroup {
|
.add_bind_group(BindGroup::new(
|
||||||
bindings: vec![
|
vec![
|
||||||
Binding {
|
Binding {
|
||||||
name: "Camera".to_string(),
|
name: "Camera".to_string(),
|
||||||
bind_type: BindType::Uniform {
|
bind_type: BindType::Uniform {
|
||||||
|
@ -39,9 +39,9 @@ impl ForwardPipelineBuilder for RenderGraphBuilder {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
})
|
))
|
||||||
.add_bind_group(BindGroup {
|
.add_bind_group(BindGroup::new(
|
||||||
bindings: vec![
|
vec![
|
||||||
Binding {
|
Binding {
|
||||||
name: "Object".to_string(),
|
name: "Object".to_string(),
|
||||||
bind_type: BindType::Uniform {
|
bind_type: BindType::Uniform {
|
||||||
|
@ -67,7 +67,7 @@ impl ForwardPipelineBuilder for RenderGraphBuilder {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
})
|
))
|
||||||
.with_rasterization_state(wgpu::RasterizationStateDescriptor {
|
.with_rasterization_state(wgpu::RasterizationStateDescriptor {
|
||||||
front_face: wgpu::FrontFace::Ccw,
|
front_face: wgpu::FrontFace::Ccw,
|
||||||
cull_mode: wgpu::CullMode::Back,
|
cull_mode: wgpu::CullMode::Back,
|
||||||
|
|
|
@ -7,11 +7,7 @@ use crate::{
|
||||||
TextureDimension,
|
TextureDimension,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{collections::HashMap, ops::Deref};
|
||||||
collections::{hash_map::DefaultHasher, HashMap},
|
|
||||||
hash::{Hash, Hasher},
|
|
||||||
ops::Deref,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct DynamicUniformBufferInfo {
|
pub struct DynamicUniformBufferInfo {
|
||||||
pub indices: HashMap<usize, Entity>,
|
pub indices: HashMap<usize, Entity>,
|
||||||
|
@ -76,7 +72,7 @@ impl WgpuRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_render_pipeline(
|
pub fn create_render_pipeline(
|
||||||
pipeline_descriptor: &PipelineDescriptor,
|
pipeline_descriptor: &mut PipelineDescriptor,
|
||||||
bind_group_layouts: &mut HashMap<u64, wgpu::BindGroupLayout>,
|
bind_group_layouts: &mut HashMap<u64, wgpu::BindGroupLayout>,
|
||||||
device: &wgpu::Device,
|
device: &wgpu::Device,
|
||||||
) -> wgpu::RenderPipeline {
|
) -> wgpu::RenderPipeline {
|
||||||
|
@ -90,10 +86,9 @@ impl WgpuRenderer {
|
||||||
};
|
};
|
||||||
|
|
||||||
// setup new bind group layouts
|
// setup new bind group layouts
|
||||||
for bind_group in pipeline_descriptor.pipeline_layout.bind_groups.iter() {
|
for bind_group in pipeline_descriptor.pipeline_layout.bind_groups.iter_mut() {
|
||||||
let mut hasher = DefaultHasher::new();
|
bind_group.update_hash();
|
||||||
bind_group.hash(&mut hasher);
|
let bind_group_id = bind_group.get_hash();
|
||||||
let bind_group_id = hasher.finish();
|
|
||||||
if let None = bind_group_layouts.get(&bind_group_id) {
|
if let None = bind_group_layouts.get(&bind_group_id) {
|
||||||
let bind_group_layout_binding = bind_group
|
let bind_group_layout_binding = bind_group
|
||||||
.bindings
|
.bindings
|
||||||
|
@ -120,10 +115,7 @@ impl WgpuRenderer {
|
||||||
.bind_groups
|
.bind_groups
|
||||||
.iter()
|
.iter()
|
||||||
.map(|bind_group| {
|
.map(|bind_group| {
|
||||||
let mut hasher = DefaultHasher::new();
|
let bind_group_id = bind_group.get_hash();
|
||||||
bind_group.hash(&mut hasher);
|
|
||||||
let bind_group_id = hasher.finish();
|
|
||||||
|
|
||||||
bind_group_layouts.get(&bind_group_id).unwrap()
|
bind_group_layouts.get(&bind_group_id).unwrap()
|
||||||
})
|
})
|
||||||
.collect::<Vec<&wgpu::BindGroupLayout>>();
|
.collect::<Vec<&wgpu::BindGroupLayout>>();
|
||||||
|
@ -132,7 +124,7 @@ impl WgpuRenderer {
|
||||||
bind_group_layouts: bind_group_layouts.as_slice(),
|
bind_group_layouts: bind_group_layouts.as_slice(),
|
||||||
});
|
});
|
||||||
|
|
||||||
let render_pipeline_descriptor = wgpu::RenderPipelineDescriptor {
|
let mut render_pipeline_descriptor = wgpu::RenderPipelineDescriptor {
|
||||||
layout: &pipeline_layout,
|
layout: &pipeline_layout,
|
||||||
vertex_stage: wgpu::ProgrammableStageDescriptor {
|
vertex_stage: wgpu::ProgrammableStageDescriptor {
|
||||||
module: &vertex_shader_module,
|
module: &vertex_shader_module,
|
||||||
|
@ -160,7 +152,7 @@ impl WgpuRenderer {
|
||||||
alpha_to_coverage_enabled: pipeline_descriptor.alpha_to_coverage_enabled,
|
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>(
|
pub fn create_render_pass<'a>(
|
||||||
|
@ -242,10 +234,7 @@ impl WgpuRenderer {
|
||||||
|
|
||||||
// TODO: consider moving this to a resource provider
|
// TODO: consider moving this to a resource provider
|
||||||
fn setup_bind_group(&mut self, bind_group: &BindGroup) -> u64 {
|
fn setup_bind_group(&mut self, bind_group: &BindGroup) -> u64 {
|
||||||
// TODO: cache hash result in bind_group?
|
let bind_group_id = bind_group.get_hash();
|
||||||
let mut hasher = DefaultHasher::new();
|
|
||||||
bind_group.hash(&mut hasher);
|
|
||||||
let bind_group_id = hasher.finish();
|
|
||||||
|
|
||||||
if let None = self.bind_groups.get(&bind_group_id) {
|
if let None = self.bind_groups.get(&bind_group_id) {
|
||||||
let mut unset_uniforms = Vec::new();
|
let mut unset_uniforms = Vec::new();
|
||||||
|
@ -368,10 +357,10 @@ impl WgpuRenderer {
|
||||||
continue;
|
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");
|
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;
|
// allocate enough space for twice as many entities as there are currently;
|
||||||
info.capacity = info.count * 2;
|
info.capacity = info.count * 2;
|
||||||
let size = wgpu::BIND_BUFFER_ALIGNMENT * info.capacity;
|
let size = wgpu::BIND_BUFFER_ALIGNMENT * info.capacity;
|
||||||
|
@ -406,7 +395,10 @@ impl WgpuRenderer {
|
||||||
let alignment = wgpu::BIND_BUFFER_ALIGNMENT as usize;
|
let alignment = wgpu::BIND_BUFFER_ALIGNMENT as usize;
|
||||||
let mut offset = 0usize;
|
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: check if index has changed. if it has, then entity should be updated
|
||||||
// TODO: only mem-map entities if their data has changed
|
// TODO: only mem-map entities if their data has changed
|
||||||
info.offsets.insert(entity, offset as u64);
|
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);
|
self.setup_dynamic_entity_shader_uniforms(world, render_graph, &mut encoder);
|
||||||
|
|
||||||
// setup, pipelines, bind groups, and resources
|
// 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
|
// create pipelines
|
||||||
if let None = self.render_pipelines.get(pipeline_name) {
|
if let None = self.render_pipelines.get(pipeline_name) {
|
||||||
let render_pipeline = WgpuRenderer::create_render_pipeline(
|
let render_pipeline = WgpuRenderer::create_render_pipeline(
|
||||||
|
@ -613,10 +605,7 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> {
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
{
|
{
|
||||||
// TODO: cache hash result in bind_group?
|
let bind_group_id = bind_group.get_hash();
|
||||||
let mut hasher = DefaultHasher::new();
|
|
||||||
bind_group.hash(&mut hasher);
|
|
||||||
let bind_group_id = hasher.finish();
|
|
||||||
let bind_group_info = self.renderer.bind_groups.get(&bind_group_id).unwrap();
|
let bind_group_info = self.renderer.bind_groups.get(&bind_group_id).unwrap();
|
||||||
|
|
||||||
let mut dynamic_uniform_indices = Vec::new();
|
let mut dynamic_uniform_indices = Vec::new();
|
||||||
|
|
Loading…
Reference in a new issue