cache bind group hashes

This commit is contained in:
Carter Anderson 2020-01-28 01:53:28 -08:00
parent 599d30d861
commit cd1fb92a7a
4 changed files with 102 additions and 38 deletions

View file

@ -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();
}

View file

@ -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)]

View file

@ -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,

View file

@ -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();