diff --git a/src/app/app_builder.rs b/src/app/app_builder.rs index f4a4420414..4566b2e62c 100644 --- a/src/app/app_builder.rs +++ b/src/app/app_builder.rs @@ -232,8 +232,8 @@ impl AppBuilder { .add_resource_provider(LightResourceProvider::new(10)) .add_resource_provider(UiResourceProvider::new()) .add_resource_provider(MeshResourceProvider::new()) - .add_resource_provider(UniformResourceProvider::::new(false)) - .add_resource_provider(UniformResourceProvider::::new(false)) + .add_resource_provider(UniformResourceProvider::::new(true)) + .add_resource_provider(UniformResourceProvider::::new(true)) .add_forward_pass() .add_forward_pipeline(); // .add_ui_pipeline(); diff --git a/src/render/pipeline/bind_group.rs b/src/render/pipeline/bind_group.rs index e863072ed3..321ed4e448 100644 --- a/src/render/pipeline/bind_group.rs +++ b/src/render/pipeline/bind_group.rs @@ -1,13 +1,13 @@ use super::BindingDescriptor; use std::{ - collections::{hash_map::DefaultHasher, BTreeSet}, + collections::hash_map::DefaultHasher, hash::{Hash, Hasher}, }; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct BindGroupDescriptor { pub index: u32, - pub bindings: BTreeSet, + pub bindings: Vec, pub id: BindGroupDescriptorId, } @@ -18,7 +18,7 @@ impl BindGroupDescriptor { pub fn new(index: u32, bindings: Vec) -> Self { let mut descriptor = BindGroupDescriptor { index, - bindings: bindings.iter().cloned().collect(), + bindings, id: BindGroupDescriptorId(0), }; @@ -42,11 +42,3 @@ impl Hash for BindGroupDescriptor { self.bindings.hash(state); } } - -impl PartialEq for BindGroupDescriptor { - fn eq(&self, other: &BindGroupDescriptor) -> bool { - self.index == other.index && self.bindings == other.bindings - } -} - -impl Eq for BindGroupDescriptor {} diff --git a/src/render/pipeline/pipeline_compiler.rs b/src/render/pipeline/pipeline_compiler.rs index 9fc433e4eb..22a009a7bf 100644 --- a/src/render/pipeline/pipeline_compiler.rs +++ b/src/render/pipeline/pipeline_compiler.rs @@ -1,10 +1,13 @@ -use super::{PipelineDescriptor, PipelineLayout, PipelineLayoutType}; +use super::{BindType, PipelineDescriptor, PipelineLayout, PipelineLayoutType}; use crate::{ asset::{AssetStorage, Handle}, prelude::{Renderable, Resources, Shader, World}, render::{ render_graph::RenderGraph, - render_resource::{RenderResourceAssignments, RenderResourceAssignmentsId}, + render_resource::{ + BufferInfo, RenderResourceAssignments, RenderResourceAssignmentsId, ResourceInfo, + }, + renderer::Renderer, shader::ShaderSource, }, }; @@ -31,6 +34,8 @@ impl PipelineCompiler { shader_storage: &AssetStorage, render_graph: &RenderGraph, pipeline_descriptor: &mut PipelineDescriptor, + renderer: &dyn Renderer, + render_resource_assignments: &RenderResourceAssignments, ) { let vertex_spirv = shader_storage .get(&pipeline_descriptor.shader_stages.vertex) @@ -49,8 +54,25 @@ impl PipelineCompiler { let mut layout = PipelineLayout::from_shader_layouts(&mut layouts); layout.sync_vertex_buffer_descriptors_with_render_graph(render_graph); - for mut _bind_group in layout.bind_groups.iter_mut() { - // TODO: set dynamic here + // set binding uniforms to dynamic if render resource assignments use dynamic + // TODO: this breaks down if different assignments have different "dynamic" status or if the dynamic status changes. + // the fix would be to add "dynamic bindings" to the existing shader_def sets. this would ensure new pipelines are generated + // for all permutations of dynamic/non-dynamic + for bind_group in layout.bind_groups.iter_mut() { + for binding in bind_group.bindings.iter_mut() { + if let Some(render_resource) = render_resource_assignments.get(&binding.name) { + if let Some(ResourceInfo::Buffer(BufferInfo { is_dynamic, .. })) = + renderer.get_resource_info(render_resource) + { + if let BindType::Uniform { + ref mut dynamic, .. + } = binding.bind_type + { + *dynamic = *is_dynamic + } + } + } + } } pipeline_descriptor.layout = PipelineLayoutType::Reflected(Some(layout)); @@ -93,26 +115,35 @@ impl PipelineCompiler { &mut self, render_graph: &RenderGraph, shader_storage: &mut AssetStorage, + renderer: &dyn Renderer, pipeline_descriptor: &PipelineDescriptor, - shader_defs: &HashSet, + render_resource_assignments: &RenderResourceAssignments, ) -> PipelineDescriptor { let mut compiled_pipeline_descriptor = pipeline_descriptor.clone(); compiled_pipeline_descriptor.shader_stages.vertex = self.compile_shader( shader_storage, &pipeline_descriptor.shader_stages.vertex, - &shader_defs, + &render_resource_assignments.shader_defs, ); compiled_pipeline_descriptor.shader_stages.fragment = pipeline_descriptor .shader_stages .fragment .as_ref() - .map(|fragment| self.compile_shader(shader_storage, fragment, &shader_defs)); + .map(|fragment| { + self.compile_shader( + shader_storage, + fragment, + &render_resource_assignments.shader_defs, + ) + }); Self::reflect_layout( shader_storage, render_graph, &mut compiled_pipeline_descriptor, + renderer, + render_resource_assignments, ); compiled_pipeline_descriptor @@ -122,6 +153,7 @@ impl PipelineCompiler { &mut self, render_graph: &RenderGraph, shader_pipeline_assignments: &mut ShaderPipelineAssignments, + renderer: &dyn Renderer, pipeline_storage: &mut AssetStorage, shader_storage: &mut AssetStorage, pipelines: &[Handle], @@ -147,8 +179,9 @@ impl PipelineCompiler { let compiled_pipeline = self.compile_pipeline( render_graph, shader_storage, + renderer, pipeline_descriptor, - &render_resource_assignments.shader_defs, + render_resource_assignments, ); let compiled_pipeline_handle = pipeline_storage.add(compiled_pipeline); @@ -203,7 +236,7 @@ impl ShaderPipelineAssignments { } // TODO: make this a system -pub fn update_shader_assignments(world: &mut World, resources: &mut Resources) { +pub fn update_shader_assignments(world: &mut World, resources: &mut Resources, renderer: &dyn Renderer) { // PERF: this seems like a lot of work for things that don't change that often. // lots of string + hashset allocations. sees uniform_resource_provider for more context { @@ -229,6 +262,7 @@ pub fn update_shader_assignments(world: &mut World, resources: &mut Resources) { pipeline_compiler.update_shader_assignments( &mut render_graph, &mut shader_pipeline_assignments, + renderer, &mut pipeline_descriptor_storage, &mut shader_storage, &renderable.pipelines, diff --git a/src/render/pipeline/pipeline_layout.rs b/src/render/pipeline/pipeline_layout.rs index b0313fc5b2..36ea976f20 100644 --- a/src/render/pipeline/pipeline_layout.rs +++ b/src/render/pipeline/pipeline_layout.rs @@ -26,7 +26,7 @@ impl PipelineLayout { panic!("Binding {} in BindGroup {} does not match across all shader types: {:?} {:?}", binding.index, bind_group.index, binding, shader_binding); } } else { - bind_group.bindings.insert(shader_binding.clone()); + bind_group.bindings.push(shader_binding.clone()); } } } diff --git a/src/render/render_resource/batching/asset_batcher.rs b/src/render/render_resource/batching/asset_batcher.rs index cd4ede0f4f..2f0aee2b60 100644 --- a/src/render/render_resource/batching/asset_batcher.rs +++ b/src/render/render_resource/batching/asset_batcher.rs @@ -183,7 +183,9 @@ mod tests { ..Default::default() }; expected_batch.add_entity(entities[0]); - assert_eq!(asset_batchers.get_batch2(a1, b1).unwrap(), &expected_batch); + let actual_batch = asset_batchers.get_batch2(a1, b1).unwrap(); + copy_ignored_fields(actual_batch, &mut expected_batch); + assert_eq!(actual_batch, &expected_batch); asset_batchers.set_entity_handle(entities[0], c1); asset_batchers.set_entity_handle(entities[1], a1); @@ -196,7 +198,9 @@ mod tests { }; expected_batch.add_entity(entities[0]); expected_batch.add_entity(entities[1]); - assert_eq!(asset_batchers.get_batch2(a1, b1).unwrap(), &expected_batch); + let actual_batch = asset_batchers.get_batch2(a1, b1).unwrap(); + copy_ignored_fields(actual_batch, &mut expected_batch); + assert_eq!(actual_batch, &expected_batch); // uncreated batches are empty assert_eq!(asset_batchers.get_batch2(a1, c1), None); @@ -239,6 +243,11 @@ mod tests { ), ]; expected_batches.sort_by(|a, b| a.0.cmp(&b.0)); + // copy ignored fields + batches + .iter() + .zip(expected_batches.iter_mut()) + .for_each(|((_, ref actual), (_, ref mut expected))| copy_ignored_fields(actual, expected)); assert_eq!( batches, expected_batches @@ -247,4 +256,8 @@ mod tests { .collect::>() ); } + + fn copy_ignored_fields(source: &Batch, destination: &mut Batch) { + destination.render_resource_assignments.id = source.render_resource_assignments.id; + } } diff --git a/src/render/renderer/renderer.rs b/src/render/renderer/renderer.rs index 29d6ce7f99..44d73f41ca 100644 --- a/src/render/renderer/renderer.rs +++ b/src/render/renderer/renderer.rs @@ -49,7 +49,6 @@ pub trait Renderer { } pub trait RenderPass { - // TODO: consider using static dispatch for the renderer: Renderer. compare compile times fn get_renderer(&self) -> &dyn Renderer; fn get_pipeline_descriptor(&self) -> &PipelineDescriptor; fn set_index_buffer(&mut self, resource: RenderResource, offset: u64); diff --git a/src/render/renderer/renderers/wgpu_renderer/wgpu_renderer.rs b/src/render/renderer/renderers/wgpu_renderer/wgpu_renderer.rs index 517722ad19..f84c2715c3 100644 --- a/src/render/renderer/renderers/wgpu_renderer/wgpu_renderer.rs +++ b/src/render/renderer/renderers/wgpu_renderer/wgpu_renderer.rs @@ -384,7 +384,7 @@ impl Renderer for WgpuRenderer { ); self.update_resource_providers(world, resources); - update_shader_assignments(world, resources); + update_shader_assignments(world, resources, self); self.create_queued_textures(resources); let mut encoder = self.encoder.take().unwrap(); diff --git a/src/render/shader/shader_reflect.rs b/src/render/shader/shader_reflect.rs index 81bd2d0f21..32c17c17bf 100644 --- a/src/render/shader/shader_reflect.rs +++ b/src/render/shader/shader_reflect.rs @@ -28,7 +28,7 @@ use zerocopy::AsBytes; // println!("{:?}", structured.types); // } -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct ShaderLayout { pub bind_groups: Vec, pub vertex_buffer_descriptors: Vec,