diff --git a/crates/bevy_render/src/pipeline/pipeline.rs b/crates/bevy_render/src/pipeline/pipeline.rs index c68f4c367b..6c172ba16e 100644 --- a/crates/bevy_render/src/pipeline/pipeline.rs +++ b/crates/bevy_render/src/pipeline/pipeline.rs @@ -4,9 +4,14 @@ use super::{ CompareFunction, CullMode, DepthStencilStateDescriptor, FrontFace, IndexFormat, PrimitiveTopology, RasterizationStateDescriptor, StencilStateFaceDescriptor, }, - PipelineLayout, + PipelineLayout, VertexBufferDescriptors, BindType, }; -use crate::{shader::ShaderStages, texture::TextureFormat}; +use crate::{ + render_resource::{ResourceInfo, RenderResourceAssignments, BufferInfo}, + shader::{Shader, ShaderStages}, + texture::TextureFormat, renderer::RenderResourceContext, +}; +use bevy_asset::AssetStorage; // TODO: consider removing this in favor of Option #[derive(Clone, Debug)] @@ -127,4 +132,66 @@ impl PipelineDescriptor { PipelineLayoutType::Manual(ref mut layout) => Some(layout), } } + + /// Reflects the pipeline layout from its shaders. + /// + /// If `vertex_buffer_descriptors` is set, the pipeline's vertex buffers + /// will inherit their layouts from global descriptors, otherwise the layout will be assumed to be complete / local. + /// + /// If `dynamic_uniform_lookup` is set, shader uniforms will be set to "dynamic" if there is a matching "dynamic uniform" + /// render resource. + pub fn reflect_layout( + &mut self, + shaders: &AssetStorage, + vertex_buffer_descriptors: Option<&VertexBufferDescriptors>, + dynamic_uniform_lookup: Option<(&RenderResourceAssignments, &dyn RenderResourceContext)>, + ) { + let vertex_spirv = shaders.get(&self.shader_stages.vertex).unwrap(); + let fragment_spirv = self + .shader_stages + .fragment + .as_ref() + .map(|handle| shaders.get(&handle).unwrap()); + + let mut layouts = vec![vertex_spirv.reflect_layout().unwrap()]; + if let Some(ref fragment_spirv) = fragment_spirv { + layouts.push(fragment_spirv.reflect_layout().unwrap()); + } + + let mut layout = PipelineLayout::from_shader_layouts(&mut layouts); + if let Some(vertex_buffer_descriptors) = vertex_buffer_descriptors { + layout.sync_vertex_buffer_descriptors(vertex_buffer_descriptors); + } + + if let Some((render_resource_assignments, render_resource_context)) = dynamic_uniform_lookup { + // 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) { + render_resource_context.get_resource_info( + render_resource, + &mut |resource_info| { + if let Some(ResourceInfo::Buffer(BufferInfo { + is_dynamic, .. + })) = resource_info + { + if let BindType::Uniform { + ref mut dynamic, .. + } = binding.bind_type + { + *dynamic = *is_dynamic + } + } + }, + ); + } + } + } + } + + self.layout = PipelineLayoutType::Reflected(Some(layout)); + } } diff --git a/crates/bevy_render/src/pipeline/pipeline_compiler.rs b/crates/bevy_render/src/pipeline/pipeline_compiler.rs index 8d8eb77938..4094a3eadb 100644 --- a/crates/bevy_render/src/pipeline/pipeline_compiler.rs +++ b/crates/bevy_render/src/pipeline/pipeline_compiler.rs @@ -1,11 +1,6 @@ -use super::{ - state_descriptors::PrimitiveTopology, BindType, PipelineDescriptor, PipelineLayout, - PipelineLayoutType, VertexBufferDescriptors, -}; +use super::{state_descriptors::PrimitiveTopology, PipelineDescriptor, VertexBufferDescriptors}; use crate::{ - render_resource::{ - BufferInfo, RenderResourceAssignments, RenderResourceAssignmentsId, ResourceInfo, - }, + render_resource::{RenderResourceAssignments, RenderResourceAssignmentsId}, renderer::{RenderResourceContext, RenderResources}, shader::{Shader, ShaderSource}, Renderable, @@ -44,59 +39,6 @@ impl PipelineCompiler { } } - fn reflect_layout( - shader_storage: &AssetStorage, - vertex_buffer_descriptors: &VertexBufferDescriptors, - pipeline_descriptor: &mut PipelineDescriptor, - render_resource_context: &dyn RenderResourceContext, - render_resource_assignments: &RenderResourceAssignments, - ) { - let vertex_spirv = shader_storage - .get(&pipeline_descriptor.shader_stages.vertex) - .unwrap(); - let fragment_spirv = pipeline_descriptor - .shader_stages - .fragment - .as_ref() - .map(|handle| &*shader_storage.get(&handle).unwrap()); - - let mut layouts = vec![vertex_spirv.reflect_layout().unwrap()]; - if let Some(ref fragment_spirv) = fragment_spirv { - layouts.push(fragment_spirv.reflect_layout().unwrap()); - } - - let mut layout = PipelineLayout::from_shader_layouts(&mut layouts); - layout.sync_vertex_buffer_descriptors(vertex_buffer_descriptors); - - // 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) { - render_resource_context.get_resource_info( - render_resource, - &mut |resource_info| { - if let Some(ResourceInfo::Buffer(BufferInfo { is_dynamic, .. })) = - resource_info - { - if let BindType::Uniform { - ref mut dynamic, .. - } = binding.bind_type - { - *dynamic = *is_dynamic - } - } - }, - ); - } - } - } - - pipeline_descriptor.layout = PipelineLayoutType::Reflected(Some(layout)); - } - fn compile_shader( &mut self, shader_storage: &mut AssetStorage, @@ -141,7 +83,7 @@ impl PipelineCompiler { fn compile_pipeline( &mut self, vertex_buffer_descriptors: &VertexBufferDescriptors, - shader_storage: &mut AssetStorage, + shaders: &mut AssetStorage, render_resource_context: &dyn RenderResourceContext, pipeline_descriptor: &PipelineDescriptor, render_resource_assignments: &RenderResourceAssignments, @@ -149,7 +91,7 @@ impl PipelineCompiler { let mut compiled_pipeline_descriptor = pipeline_descriptor.clone(); compiled_pipeline_descriptor.shader_stages.vertex = self.compile_shader( - shader_storage, + shaders, &pipeline_descriptor.shader_stages.vertex, &render_resource_assignments .pipeline_specialization @@ -161,7 +103,7 @@ impl PipelineCompiler { .as_ref() .map(|fragment| { self.compile_shader( - shader_storage, + shaders, fragment, &render_resource_assignments .pipeline_specialization @@ -169,12 +111,10 @@ impl PipelineCompiler { ) }); - Self::reflect_layout( - shader_storage, - vertex_buffer_descriptors, - &mut compiled_pipeline_descriptor, - render_resource_context, - render_resource_assignments, + compiled_pipeline_descriptor.reflect_layout( + shaders, + Some(vertex_buffer_descriptors), + Some((render_resource_assignments, render_resource_context)), ); compiled_pipeline_descriptor.primitive_topology = render_resource_assignments diff --git a/crates/bevy_render/src/texture/texture_descriptor.rs b/crates/bevy_render/src/texture/texture_descriptor.rs index f755a6dcd6..d419f1ecb0 100644 --- a/crates/bevy_render/src/texture/texture_descriptor.rs +++ b/crates/bevy_render/src/texture/texture_descriptor.rs @@ -1,6 +1,6 @@ use super::{Extent3d, Texture, TextureDimension, TextureFormat, TextureUsage}; -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct TextureDescriptor { pub size: Extent3d, pub mip_level_count: u32,