From 0073f4a58b45e1d7e5b9cf187381a432a2dd9393 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Thu, 26 Mar 2020 23:40:25 -0700 Subject: [PATCH] refactor pipeline compilation into PipelineCompiler --- ROADMAP.md | 2 + src/app/app.rs | 13 +- src/app/app_builder.rs | 16 +- src/core/window.rs | 2 +- .../assigned_meshes_draw_target.rs | 14 +- .../draw_targets/ui_draw_target.rs | 45 +-- src/render/pipeline/mod.rs | 2 + src/render/pipeline/pipeline.rs | 28 +- src/render/pipeline/pipeline_compiler.rs | 242 ++++++++++++++ src/render/pipeline/pipeline_layout.rs | 39 ++- .../pipeline/pipelines/forward/forward.frag | 1 + src/render/pipeline/pipelines/forward/mod.rs | 2 +- .../batching/asset_batcher2.rs | 8 +- src/render/render_resource/batching/batch.rs | 5 +- src/render/render_resource/batching/mod.rs | 2 +- .../entity_render_resource_assignments.rs | 2 +- src/render/render_resource/render_resource.rs | 10 - .../render_resource_assignments.rs | 22 +- .../camera2d_resource_provider.rs | 13 +- .../camera_resource_provider.rs | 13 +- .../frame_texture_resource_provider.rs | 17 +- .../light_resource_provider.rs | 13 +- .../mesh_resource_provider.rs | 12 +- .../ui_resource_provider.rs | 14 +- .../uniform_resource_provider.rs | 32 +- src/render/renderable.rs | 216 +------------ src/render/renderer/renderer.rs | 5 +- .../wgpu_renderer/wgpu_render_pass.rs | 21 +- .../renderers/wgpu_renderer/wgpu_renderer.rs | 304 ++++++++---------- .../renderers/wgpu_renderer/wgpu_resources.rs | 50 +-- src/render/shader/shader_reflect.rs | 4 +- 31 files changed, 619 insertions(+), 550 deletions(-) create mode 100644 src/render/pipeline/pipeline_compiler.rs diff --git a/ROADMAP.md b/ROADMAP.md index e251d7d5f5..83d3efbda4 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -12,6 +12,8 @@ Here is the current list of planned features. All items are sorted in approximat * Add runtime type safety to uniform bindings (and maybe compile time) * Inject layout set/bindings into shader source so they don't need to be defined in-shader. Specify set / binding indices in resource providers? * Pull as much logic as possible from wgpu_renderer into a "render orchestrator" struct/trait + * Separate original/uncompiled/no_defs PipelineDescriptor from compiled PipelineDescriptor conceptually + * Try to make Renderer a resource + system * Docs * Add doc comments to code * Add tutorials diff --git a/src/app/app.rs b/src/app/app.rs index 6203ed0f29..054d1b90ce 100644 --- a/src/app/app.rs +++ b/src/app/app.rs @@ -6,7 +6,11 @@ use winit::{ use legion::prelude::*; -use crate::{app::AppBuilder, core::{Window, Time}, render::renderer::Renderer}; +use crate::{ + app::AppBuilder, + core::{Time, Window}, + render::renderer::Renderer, +}; pub struct App { pub universe: Universe, @@ -90,7 +94,12 @@ impl App { window.height = size.height; } - renderer.resize(&mut self.world, &mut self.resources, size.width, size.height); + renderer.resize( + &mut self.world, + &mut self.resources, + size.width, + size.height, + ); } else { println!("no renderer {} {}", size.width, size.height); } diff --git a/src/app/app_builder.rs b/src/app/app_builder.rs index d65881f515..d642d75e11 100644 --- a/src/app/app_builder.rs +++ b/src/app/app_builder.rs @@ -13,10 +13,11 @@ use crate::{ }; use bevy_transform::{prelude::LocalToWorld, transform_system_bundle}; -use pipeline::PipelineDescriptor; +use pipeline::{PipelineCompiler, PipelineDescriptor, ShaderPipelineAssignments}; use render_graph::{RenderGraph, RenderGraphBuilder}; use render_resource::{ - build_entity_render_resource_assignments_system, AssetBatchers, EntityRenderResourceAssignments, + build_entity_render_resource_assignments_system, AssetBatchers, + EntityRenderResourceAssignments, RenderResourceAssignments, }; use shader::Shader; use std::collections::HashMap; @@ -165,7 +166,8 @@ impl AppBuilder { resources.insert(AssetStorage::::new()); resources.insert(AssetStorage::::new()); resources.insert(ShaderPipelineAssignments::new()); - resources.insert(CompiledShaderMap::new()); + resources.insert(PipelineCompiler::new()); + resources.insert(RenderResourceAssignments::default()); resources.insert(EntityRenderResourceAssignments::default()); self.batch_types2::(); self @@ -212,11 +214,11 @@ impl AppBuilder { .add_resource_provider(LightResourceProvider::new(10)) .add_resource_provider(UiResourceProvider::new()) .add_resource_provider(MeshResourceProvider::new()) - .add_resource_provider(UniformResourceProvider::::new(true)) - .add_resource_provider(UniformResourceProvider::::new(true)) + .add_resource_provider(UniformResourceProvider::::new(false)) + .add_resource_provider(UniformResourceProvider::::new(false)) .add_forward_pass() - .add_forward_pipeline() - .add_ui_pipeline(); + .add_forward_pipeline(); + // .add_ui_pipeline(); }) } diff --git a/src/core/window.rs b/src/core/window.rs index c11637282a..f05bc1dc0e 100644 --- a/src/core/window.rs +++ b/src/core/window.rs @@ -1,4 +1,4 @@ pub struct Window { pub width: u32, pub height: u32, -} \ No newline at end of file +} diff --git a/src/render/draw_target/draw_targets/assigned_meshes_draw_target.rs b/src/render/draw_target/draw_targets/assigned_meshes_draw_target.rs index 827bcfee23..c4a49994d1 100644 --- a/src/render/draw_target/draw_targets/assigned_meshes_draw_target.rs +++ b/src/render/draw_target/draw_targets/assigned_meshes_draw_target.rs @@ -4,10 +4,12 @@ use crate::{ render::{ draw_target::DrawTarget, mesh::Mesh, - pipeline::PipelineDescriptor, - render_resource::{resource_name, EntityRenderResourceAssignments, ResourceInfo}, + pipeline::{PipelineDescriptor, ShaderPipelineAssignments}, + render_resource::{ + resource_name, EntityRenderResourceAssignments, RenderResourceAssignments, ResourceInfo, + }, renderer::{RenderPass, Renderer}, - Renderable, ShaderPipelineAssignments, + Renderable, }, }; @@ -27,6 +29,9 @@ impl DrawTarget for AssignedMeshesDrawTarget { resources.get::().unwrap(); let mut current_mesh_handle = None; let mut current_mesh_index_len = 0; + let global_render_resource_assignments = + resources.get::().unwrap(); + render_pass.set_render_resources(&global_render_resource_assignments); let assigned_render_resource_assignments = shader_pipeline_assignments .assignments @@ -87,6 +92,9 @@ impl DrawTarget for AssignedMeshesDrawTarget { .get(&pipeline_handle); let pipeline_storage = resources.get::>().unwrap(); let pipeline_descriptor = pipeline_storage.get(&pipeline_handle).unwrap(); + let mut global_render_resource_assignments = + resources.get_mut::().unwrap(); + renderer.setup_bind_groups(&mut global_render_resource_assignments, pipeline_descriptor); if let Some(assigned_render_resource_assignments) = assigned_render_resource_assignments { for assignment_id in assigned_render_resource_assignments.iter() { // TODO: hopefully legion has better random access apis that are more like queries? diff --git a/src/render/draw_target/draw_targets/ui_draw_target.rs b/src/render/draw_target/draw_targets/ui_draw_target.rs index 17dd9d0355..3cdf529c35 100644 --- a/src/render/draw_target/draw_targets/ui_draw_target.rs +++ b/src/render/draw_target/draw_targets/ui_draw_target.rs @@ -1,5 +1,5 @@ use crate::{ - asset::{Asset, Handle}, + asset::{Asset, AssetStorage, Handle}, legion::prelude::*, math, prelude::MeshType, @@ -7,7 +7,10 @@ use crate::{ draw_target::DrawTarget, mesh::Mesh, pipeline::PipelineDescriptor, - render_resource::{resource_name, BufferInfo, BufferUsage, RenderResource, ResourceInfo}, + render_resource::{ + resource_name, BufferInfo, BufferUsage, RenderResource, RenderResourceAssignments, + ResourceInfo, + }, renderer::{RenderPass, Renderer}, }, }; @@ -30,12 +33,9 @@ impl DrawTarget for UiDrawTarget { render_pass: &mut dyn RenderPass, _pipeline_handle: Handle, ) { + let render_resource_assignments = resources.get::().unwrap(); let ui_instances_buffer = { - let renderer = render_pass.get_renderer(); - match renderer - .get_render_resources() - .get_named_resource(resource_name::buffer::UI_INSTANCES) - { + match render_resource_assignments.get(resource_name::buffer::UI_INSTANCES) { Some(buffer) => buffer, None => return, } @@ -54,24 +54,25 @@ impl DrawTarget for UiDrawTarget { } }; - // TODO: set global render resources - // render_pass.set_render_resources(None); - // render_pass.set_index_buffer(self.mesh_index_buffer.unwrap(), 0); - // render_pass.set_vertex_buffer(0, self.mesh_vertex_buffer.unwrap(), 0); - // render_pass.set_vertex_buffer(1, ui_instances_buffer, 0); - // render_pass.draw_indexed( - // 0..self.mesh_index_length as u32, - // 0, - // 0..(index_count.unwrap() as u32), - // ); + let global_render_resource_assignments = + resources.get::().unwrap(); + render_pass.set_render_resources(&global_render_resource_assignments); + render_pass.set_index_buffer(self.mesh_index_buffer.unwrap(), 0); + render_pass.set_vertex_buffer(0, self.mesh_vertex_buffer.unwrap(), 0); + render_pass.set_vertex_buffer(1, ui_instances_buffer, 0); + render_pass.draw_indexed( + 0..self.mesh_index_length as u32, + 0, + 0..(index_count.unwrap() as u32), + ); } fn setup( &mut self, _world: &mut World, - _resources: &Resources, + resources: &Resources, renderer: &mut dyn Renderer, - _pipeline_handle: Handle, + pipeline_handle: Handle, ) { // don't create meshes if they have already been created if let Some(_) = self.mesh_vertex_buffer { @@ -99,6 +100,12 @@ impl DrawTarget for UiDrawTarget { quad.indices.as_bytes(), )); self.mesh_index_length = quad.indices.len(); + + let mut global_render_resource_assignments = + resources.get_mut::().unwrap(); + let pipeline_storage = resources.get::>().unwrap(); + let pipeline_descriptor = pipeline_storage.get(&pipeline_handle).unwrap(); + renderer.setup_bind_groups(&mut global_render_resource_assignments, pipeline_descriptor); } fn get_name(&self) -> String { resource_name::draw_target::UI.to_string() diff --git a/src/render/pipeline/mod.rs b/src/render/pipeline/mod.rs index b795f06271..36436c66c5 100644 --- a/src/render/pipeline/mod.rs +++ b/src/render/pipeline/mod.rs @@ -1,6 +1,7 @@ mod bind_group; mod binding; mod pipeline; +mod pipeline_compiler; mod pipeline_layout; pub mod pipelines; pub mod state_descriptors; @@ -10,6 +11,7 @@ mod vertex_format; pub use bind_group::*; pub use binding::*; pub use pipeline::*; +pub use pipeline_compiler::*; pub use pipeline_layout::*; pub use vertex_buffer_descriptor::*; pub use vertex_format::*; diff --git a/src/render/pipeline/pipeline.rs b/src/render/pipeline/pipeline.rs index dead60f24d..ad39012649 100644 --- a/src/render/pipeline/pipeline.rs +++ b/src/render/pipeline/pipeline.rs @@ -33,7 +33,6 @@ pub struct PipelineDescriptor { pub draw_targets: Vec, pub layout: PipelineLayoutType, pub shader_stages: ShaderStages, - pub reflect_vertex_buffer_descriptors: bool, pub rasterization_state: Option, /// The primitive topology used to interpret vertices. @@ -48,9 +47,6 @@ pub struct PipelineDescriptor { /// The format of any index buffers used with this pipeline. pub index_format: IndexFormat, - /// The format of any vertex buffers used with this pipeline. - pub vertex_buffer_descriptors: Vec, - /// The number of samples calculated per pixel (for MSAA). pub sample_count: u32, @@ -74,7 +70,6 @@ impl PipelineDescriptor { depth_stencil_state: None, draw_targets: Vec::new(), shader_stages: ShaderStages::new(vertex_shader), - vertex_buffer_descriptors: Vec::new(), rasterization_state: Some(RasterizationStateDescriptor { front_face: FrontFace::Ccw, cull_mode: CullMode::Back, @@ -82,7 +77,6 @@ impl PipelineDescriptor { depth_bias_slope_scale: 0.0, depth_bias_clamp: 0.0, }), - reflect_vertex_buffer_descriptors: true, primitive_topology: PrimitiveTopology::TriangleList, index_format: IndexFormat::Uint16, sample_count: 1, @@ -170,12 +164,12 @@ impl<'a> PipelineBuilder<'a> { } pub fn add_bind_group(&mut self, bind_group: BindGroupDescriptor) -> &mut Self { - if let PipelineLayoutType::Reflected(_) = self.pipeline.as_ref().unwrap().layout { - self.pipeline.as_mut().unwrap().layout = - PipelineLayoutType::Manual(PipelineLayout::new()); + let pipeline = self.pipeline.as_mut().unwrap(); + if let PipelineLayoutType::Reflected(_) = pipeline.layout { + pipeline.layout = PipelineLayoutType::Manual(PipelineLayout::default()); } - if let PipelineLayoutType::Manual(ref mut layout) = self.pipeline.as_mut().unwrap().layout { + if let PipelineLayoutType::Manual(ref mut layout) = pipeline.layout { layout.bind_groups.push(bind_group); } @@ -187,10 +181,16 @@ impl<'a> PipelineBuilder<'a> { vertex_buffer_descriptor: VertexBufferDescriptor, ) -> &mut Self { let pipeline = self.pipeline.as_mut().unwrap(); - pipeline.reflect_vertex_buffer_descriptors = false; - pipeline - .vertex_buffer_descriptors - .push(vertex_buffer_descriptor); + if let PipelineLayoutType::Reflected(_) = pipeline.layout { + pipeline.layout = PipelineLayoutType::Manual(PipelineLayout::default()); + } + + if let PipelineLayoutType::Manual(ref mut layout) = pipeline.layout { + layout + .vertex_buffer_descriptors + .push(vertex_buffer_descriptor); + } + self } diff --git a/src/render/pipeline/pipeline_compiler.rs b/src/render/pipeline/pipeline_compiler.rs new file mode 100644 index 0000000000..9fc433e4eb --- /dev/null +++ b/src/render/pipeline/pipeline_compiler.rs @@ -0,0 +1,242 @@ +use super::{PipelineDescriptor, PipelineLayout, PipelineLayoutType}; +use crate::{ + asset::{AssetStorage, Handle}, + prelude::{Renderable, Resources, Shader, World}, + render::{ + render_graph::RenderGraph, + render_resource::{RenderResourceAssignments, RenderResourceAssignmentsId}, + shader::ShaderSource, + }, +}; +use std::collections::{HashMap, HashSet}; + +use legion::prelude::*; + +// TODO: consider using (Typeid, fieldinfo.index) in place of string for hashes +pub struct PipelineCompiler { + pub shader_source_to_compiled: HashMap, Vec<(HashSet, Handle)>>, + pub pipeline_source_to_compiled: + HashMap, Vec<(HashSet, Handle)>>, +} + +impl PipelineCompiler { + pub fn new() -> Self { + PipelineCompiler { + shader_source_to_compiled: HashMap::new(), + pipeline_source_to_compiled: HashMap::new(), + } + } + + fn reflect_layout( + shader_storage: &AssetStorage, + render_graph: &RenderGraph, + pipeline_descriptor: &mut PipelineDescriptor, + ) { + 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_with_render_graph(render_graph); + + for mut _bind_group in layout.bind_groups.iter_mut() { + // TODO: set dynamic here + } + + pipeline_descriptor.layout = PipelineLayoutType::Reflected(Some(layout)); + } + + fn compile_shader( + &mut self, + shader_storage: &mut AssetStorage, + shader_handle: &Handle, + shader_defs: &HashSet, + ) -> Handle { + let compiled_shaders = self + .shader_source_to_compiled + .entry(*shader_handle) + .or_insert_with(|| Vec::new()); + + let shader = shader_storage.get(shader_handle).unwrap(); + + // don't produce new shader if the input source is already spirv + if let ShaderSource::Spirv(_) = shader.source { + return *shader_handle; + } + + if let Some((_compiled_shader_defs, compiled_shader)) = compiled_shaders + .iter() + .find(|(compiled_shader_defs, _compiled_shader)| *compiled_shader_defs == *shader_defs) + { + // if shader has already been compiled with current configuration, use existing shader + *compiled_shader + } else { + // if no shader exists with the current configuration, create new shader and compile + let shader_def_vec = shader_defs.iter().cloned().collect::>(); + let compiled_shader = shader.get_spirv_shader(Some(&shader_def_vec)); + compiled_shaders.push((shader_defs.clone(), *shader_handle)); + shader_storage.add(compiled_shader) + } + } + + fn compile_pipeline( + &mut self, + render_graph: &RenderGraph, + shader_storage: &mut AssetStorage, + pipeline_descriptor: &PipelineDescriptor, + shader_defs: &HashSet, + ) -> 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, + ); + compiled_pipeline_descriptor.shader_stages.fragment = pipeline_descriptor + .shader_stages + .fragment + .as_ref() + .map(|fragment| self.compile_shader(shader_storage, fragment, &shader_defs)); + + Self::reflect_layout( + shader_storage, + render_graph, + &mut compiled_pipeline_descriptor, + ); + + compiled_pipeline_descriptor + } + + fn update_shader_assignments( + &mut self, + render_graph: &RenderGraph, + shader_pipeline_assignments: &mut ShaderPipelineAssignments, + pipeline_storage: &mut AssetStorage, + shader_storage: &mut AssetStorage, + pipelines: &[Handle], + render_resource_assignments: &RenderResourceAssignments, + ) { + for pipeline_handle in pipelines.iter() { + if let None = self.pipeline_source_to_compiled.get(pipeline_handle) { + self.pipeline_source_to_compiled + .insert(*pipeline_handle, Vec::new()); + } + + let final_handle = if let Some((_shader_defs, macroed_pipeline_handle)) = self + .pipeline_source_to_compiled + .get_mut(pipeline_handle) + .unwrap() + .iter() + .find(|(shader_defs, _macroed_pipeline_handle)| { + *shader_defs == render_resource_assignments.shader_defs + }) { + *macroed_pipeline_handle + } else { + let pipeline_descriptor = pipeline_storage.get(pipeline_handle).unwrap(); + let compiled_pipeline = self.compile_pipeline( + render_graph, + shader_storage, + pipeline_descriptor, + &render_resource_assignments.shader_defs, + ); + let compiled_pipeline_handle = pipeline_storage.add(compiled_pipeline); + + let macro_pipelines = self + .pipeline_source_to_compiled + .get_mut(pipeline_handle) + .unwrap(); + macro_pipelines.push(( + render_resource_assignments.shader_defs.clone(), + compiled_pipeline_handle, + )); + compiled_pipeline_handle + }; + + // TODO: this will break down if pipeline layout changes. fix this with "auto-layout" + if let None = shader_pipeline_assignments.assignments.get(&final_handle) { + shader_pipeline_assignments + .assignments + .insert(final_handle, Vec::new()); + } + + let assignments = shader_pipeline_assignments + .assignments + .get_mut(&final_handle) + .unwrap(); + assignments.push(render_resource_assignments.id); + } + } + + pub fn iter_compiled_pipelines( + &self, + pipeline_handle: Handle, + ) -> Option>> { + if let Some(compiled_pipelines) = self.pipeline_source_to_compiled.get(&pipeline_handle) { + Some(compiled_pipelines.iter().map(|(_, handle)| handle)) + } else { + None + } + } +} + +pub struct ShaderPipelineAssignments { + pub assignments: HashMap, Vec>, +} + +impl ShaderPipelineAssignments { + pub fn new() -> Self { + ShaderPipelineAssignments { + assignments: HashMap::new(), + } + } +} + +// TODO: make this a system +pub fn update_shader_assignments(world: &mut World, resources: &mut Resources) { + // 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 + { + let mut shader_pipeline_assignments = + resources.get_mut::().unwrap(); + let mut pipeline_compiler = resources.get_mut::().unwrap(); + let mut shader_storage = resources.get_mut::>().unwrap(); + let mut render_graph = resources.get_mut::().unwrap(); + let mut pipeline_descriptor_storage = resources + .get_mut::>() + .unwrap(); + + // reset assignments so they are updated every frame + shader_pipeline_assignments.assignments = HashMap::new(); + + // TODO: only update when renderable is changed + for mut renderable in >::query().iter_mut(world) { + // skip instanced entities. their batched RenderResourceAssignments will handle shader assignments + if renderable.is_instanced { + continue; + } + + pipeline_compiler.update_shader_assignments( + &mut render_graph, + &mut shader_pipeline_assignments, + &mut pipeline_descriptor_storage, + &mut shader_storage, + &renderable.pipelines, + &renderable.render_resource_assignments, + ); + + // reset shader_defs so they can be changed next frame + renderable.render_resource_assignments.shader_defs.clear(); + } + } +} diff --git a/src/render/pipeline/pipeline_layout.rs b/src/render/pipeline/pipeline_layout.rs index 5baf99743d..b0313fc5b2 100644 --- a/src/render/pipeline/pipeline_layout.rs +++ b/src/render/pipeline/pipeline_layout.rs @@ -1,22 +1,18 @@ -use super::BindGroupDescriptor; -use crate::render::shader::ShaderLayout; +use super::{BindGroupDescriptor, VertexBufferDescriptor}; +use crate::render::{render_graph::RenderGraph, shader::ShaderLayout}; use std::{collections::HashMap, hash::Hash}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct PipelineLayout { pub bind_groups: Vec, + pub vertex_buffer_descriptors: Vec, } impl PipelineLayout { - pub fn new() -> Self { - PipelineLayout { - bind_groups: Vec::new(), - } - } - pub fn from_shader_layouts(shader_layouts: &mut [ShaderLayout]) -> Self { let mut bind_groups = HashMap::::new(); - for shader_layout in shader_layouts { + let mut vertex_buffer_descriptors = Vec::new(); + for shader_layout in shader_layouts.iter_mut() { for shader_bind_group in shader_layout.bind_groups.iter_mut() { match bind_groups.get_mut(&shader_bind_group.index) { Some(bind_group) => { @@ -40,15 +36,38 @@ impl PipelineLayout { } } } + + for vertex_buffer_descriptor in shader_layouts[0].vertex_buffer_descriptors.iter() { + vertex_buffer_descriptors.push(vertex_buffer_descriptor.clone()); + } + let mut bind_groups_result = bind_groups .drain() .map(|(_, value)| value) .collect::>(); // NOTE: for some reason bind groups need to be sorted by index. this is likely an issue with bevy and not with wgpu + // TODO: try removing this bind_groups_result.sort_by(|a, b| a.index.partial_cmp(&b.index).unwrap()); + PipelineLayout { bind_groups: bind_groups_result, + vertex_buffer_descriptors, + } + } + + pub fn sync_vertex_buffer_descriptors_with_render_graph(&mut self, render_graph: &RenderGraph) { + for vertex_buffer_descriptor in self.vertex_buffer_descriptors.iter_mut() { + if let Some(graph_descriptor) = + render_graph.get_vertex_buffer_descriptor(&vertex_buffer_descriptor.name) + { + vertex_buffer_descriptor.sync_with_descriptor(graph_descriptor); + } else { + panic!( + "Encountered unsupported Vertex Buffer: {}", + vertex_buffer_descriptor.name + ); + } } } } diff --git a/src/render/pipeline/pipelines/forward/forward.frag b/src/render/pipeline/pipelines/forward/forward.frag index efcf4a844a..abd93a5768 100644 --- a/src/render/pipeline/pipelines/forward/forward.frag +++ b/src/render/pipeline/pipelines/forward/forward.frag @@ -23,6 +23,7 @@ layout(set = 0, binding = 1) uniform Lights { Light SceneLights[MAX_LIGHTS]; }; +// TODO: this should be binding = 0 right? layout(set = 2, binding = 1) uniform StandardMaterial_albedo { vec4 Albedo; }; diff --git a/src/render/pipeline/pipelines/forward/mod.rs b/src/render/pipeline/pipelines/forward/mod.rs index 0ca98e04aa..a17984cdff 100644 --- a/src/render/pipeline/pipelines/forward/mod.rs +++ b/src/render/pipeline/pipelines/forward/mod.rs @@ -56,7 +56,7 @@ impl<'a> ForwardPipelineBuilder for RenderGraphBuilder<'a> { write_mask: ColorWrite::ALL, }) .add_draw_target(resource_name::draw_target::ASSIGNED_MESHES); - // .add_draw_target(resource_name::draw_target::ASSIGNED_BATCHES); + // .add_draw_target(resource_name::draw_target::ASSIGNED_BATCHES); }) } } diff --git a/src/render/render_resource/batching/asset_batcher2.rs b/src/render/render_resource/batching/asset_batcher2.rs index ec5bf57930..5bd45fec26 100644 --- a/src/render/render_resource/batching/asset_batcher2.rs +++ b/src/render/render_resource/batching/asset_batcher2.rs @@ -1,9 +1,7 @@ -use crate::{ - asset::{HandleId, HandleUntyped}, -}; +use super::{AssetBatcher, Batch}; +use crate::asset::{HandleId, HandleUntyped}; use legion::prelude::Entity; use std::{any::TypeId, collections::HashMap, hash::Hash}; -use super::{AssetBatcher, Batch}; // TODO: if/when const generics land, revisit this design in favor of generic array lengths @@ -141,4 +139,4 @@ impl AssetBatcher for AssetSetBatcher2 { fn get_batches_mut<'a>(&'a mut self) -> Box + 'a> { Box::new(self.set_batches.values_mut()) } -} \ No newline at end of file +} diff --git a/src/render/render_resource/batching/batch.rs b/src/render/render_resource/batching/batch.rs index fa79955066..180330ba5d 100644 --- a/src/render/render_resource/batching/batch.rs +++ b/src/render/render_resource/batching/batch.rs @@ -1,6 +1,6 @@ use crate::{asset::HandleUntyped, render::render_resource::RenderResourceAssignments}; use legion::prelude::Entity; -use std::collections::{HashSet, HashMap}; +use std::collections::{HashMap, HashSet}; #[derive(PartialEq, Eq, Debug, Default)] pub struct Batch { @@ -18,7 +18,8 @@ impl Batch { pub fn add_instanced_entity(&mut self, entity: Entity) { if let None = self.instanced_entity_indices.get(&entity) { - self.instanced_entity_indices.insert(entity, self.current_instanced_entity_index); + self.instanced_entity_indices + .insert(entity, self.current_instanced_entity_index); self.current_instanced_entity_index += 1; } } diff --git a/src/render/render_resource/batching/mod.rs b/src/render/render_resource/batching/mod.rs index f60f4b96b8..90982a894c 100644 --- a/src/render/render_resource/batching/mod.rs +++ b/src/render/render_resource/batching/mod.rs @@ -4,4 +4,4 @@ mod batch; pub use asset_batcher::*; pub use asset_batcher2::*; -pub use batch::*; \ No newline at end of file +pub use batch::*; diff --git a/src/render/render_resource/entity_render_resource_assignments.rs b/src/render/render_resource/entity_render_resource_assignments.rs index 8bc94fdc6b..4b42d961a9 100644 --- a/src/render/render_resource/entity_render_resource_assignments.rs +++ b/src/render/render_resource/entity_render_resource_assignments.rs @@ -25,7 +25,7 @@ pub fn build_entity_render_resource_assignments_system() -> Box .with_query(>::query().filter(changed::())) .build(|_, world, entity_assignments, query| { for (entity, renderable) in query.iter_entities_mut(world) { - entity_assignments.set(renderable.render_resource_assignments.id, entity); + entity_assignments.set(renderable.render_resource_assignments.id, entity); } }) } diff --git a/src/render/render_resource/render_resource.rs b/src/render/render_resource/render_resource.rs index e37d2bf695..4281c58948 100644 --- a/src/render/render_resource/render_resource.rs +++ b/src/render/render_resource/render_resource.rs @@ -3,7 +3,6 @@ use crate::{ render::{mesh::Mesh, texture::Texture}, }; use std::collections::HashMap; -use super::RenderResourceAssignments; #[derive(Copy, Clone, Hash, Debug, Eq, PartialEq)] pub struct RenderResource(pub u64); @@ -12,7 +11,6 @@ pub struct RenderResource(pub u64); // the overlap could cause accidents. #[derive(Default)] pub struct RenderResources { - pub global_assignments: RenderResourceAssignments, pub texture_to_resource: HashMap, RenderResource>, pub texture_to_sampler_resource: HashMap, RenderResource>, pub mesh_to_vertices_resource: HashMap, RenderResource>, @@ -21,14 +19,6 @@ pub struct RenderResources { } impl RenderResources { - pub fn set_named_resource(&mut self, name: &str, resource: RenderResource) { - self.global_assignments.set(name, resource); - } - - pub fn get_named_resource(&self, name: &str) -> Option { - self.global_assignments.get(name).map(|(r, _i)| r) - } - pub fn set_texture_resource(&mut self, texture: Handle, resource: RenderResource) { self.texture_to_resource.insert(texture, resource); } diff --git a/src/render/render_resource/render_resource_assignments.rs b/src/render/render_resource/render_resource_assignments.rs index 4c9612ff66..622345bb34 100644 --- a/src/render/render_resource/render_resource_assignments.rs +++ b/src/render/render_resource/render_resource_assignments.rs @@ -20,7 +20,11 @@ pub struct RenderResourceAssignments { } impl RenderResourceAssignments { - pub fn get(&self, name: &str) -> Option<(RenderResource, Option)> { + pub fn get(&self, name: &str) -> Option { + self.render_resources.get(name).map(|(r, _i)| *r) + } + + pub fn get_indexed(&self, name: &str) -> Option<(RenderResource, Option)> { self.render_resources.get(name).cloned() } @@ -84,7 +88,7 @@ impl RenderResourceAssignments { } else { self.bind_group_resource_sets .get(&bind_group_descriptor.id) - .map(|(set_id, indices)| *set_id) + .map(|(set_id, _indices)| *set_id) } } @@ -102,7 +106,7 @@ impl RenderResourceAssignments { let mut hasher = DefaultHasher::new(); let mut indices = Vec::new(); for binding_descriptor in bind_group_descriptor.bindings.iter() { - if let Some((render_resource, index)) = self.get(&binding_descriptor.name) { + if let Some((render_resource, index)) = self.get_indexed(&binding_descriptor.name) { render_resource.hash(&mut hasher); if let Some(index) = index { indices.push(index); @@ -112,7 +116,14 @@ impl RenderResourceAssignments { } } - Some((RenderResourceSetId(hasher.finish()), if indices.is_empty() { None } else { Some(indices) })) + Some(( + RenderResourceSetId(hasher.finish()), + if indices.is_empty() { + None + } else { + Some(indices) + }, + )) } } @@ -188,7 +199,8 @@ mod tests { assert_ne!(different_set_id, None); assert_ne!(different_set_id, set_id); - let equal_set_id = equal_assignments.get_or_update_render_resource_set_id(&bind_group_descriptor); + let equal_set_id = + equal_assignments.get_or_update_render_resource_set_id(&bind_group_descriptor); assert_ne!(equal_set_id, None); assert_eq!(equal_set_id, set_id); diff --git a/src/render/render_resource/resource_providers/camera2d_resource_provider.rs b/src/render/render_resource/resource_providers/camera2d_resource_provider.rs index f01a547095..84f6f54e4f 100644 --- a/src/render/render_resource/resource_providers/camera2d_resource_provider.rs +++ b/src/render/render_resource/resource_providers/camera2d_resource_provider.rs @@ -1,5 +1,8 @@ use crate::render::{ - render_resource::{resource_name, BufferInfo, BufferUsage, RenderResource, ResourceProvider}, + render_resource::{ + resource_name, BufferInfo, BufferUsage, RenderResource, RenderResourceAssignments, + ResourceProvider, + }, renderer::Renderer, ActiveCamera2d, Camera, }; @@ -17,7 +20,7 @@ impl ResourceProvider for Camera2dResourceProvider { &mut self, renderer: &mut dyn Renderer, _world: &mut World, - _resources: &Resources, + resources: &Resources, ) { let buffer = renderer.create_buffer(BufferInfo { size: std::mem::size_of::<[[f32; 4]; 4]>(), @@ -25,9 +28,9 @@ impl ResourceProvider for Camera2dResourceProvider { ..Default::default() }); - renderer - .get_render_resources_mut() - .set_named_resource(resource_name::uniform::CAMERA2D, buffer); + let mut render_resource_assignments = + resources.get_mut::().unwrap(); + render_resource_assignments.set(resource_name::uniform::CAMERA2D, buffer); self.camera_buffer = Some(buffer); } diff --git a/src/render/render_resource/resource_providers/camera_resource_provider.rs b/src/render/render_resource/resource_providers/camera_resource_provider.rs index d2f2b725b8..0f0ba7f168 100644 --- a/src/render/render_resource/resource_providers/camera_resource_provider.rs +++ b/src/render/render_resource/resource_providers/camera_resource_provider.rs @@ -1,5 +1,8 @@ use crate::render::{ - render_resource::{resource_name, BufferInfo, BufferUsage, RenderResource, ResourceProvider}, + render_resource::{ + resource_name, BufferInfo, BufferUsage, RenderResource, RenderResourceAssignments, + ResourceProvider, + }, renderer::Renderer, ActiveCamera, Camera, }; @@ -18,7 +21,7 @@ impl ResourceProvider for CameraResourceProvider { &mut self, renderer: &mut dyn Renderer, _world: &mut World, - _resources: &Resources, + resources: &Resources, ) { let buffer = renderer.create_buffer(BufferInfo { size: std::mem::size_of::<[[f32; 4]; 4]>(), @@ -26,9 +29,9 @@ impl ResourceProvider for CameraResourceProvider { ..Default::default() }); - renderer - .get_render_resources_mut() - .set_named_resource(resource_name::uniform::CAMERA, buffer); + let mut render_resource_assignments = + resources.get_mut::().unwrap(); + render_resource_assignments.set(resource_name::uniform::CAMERA, buffer); self.camera_buffer = Some(buffer); } diff --git a/src/render/render_resource/resource_providers/frame_texture_resource_provider.rs b/src/render/render_resource/resource_providers/frame_texture_resource_provider.rs index 06d699e413..c813c75227 100644 --- a/src/render/render_resource/resource_providers/frame_texture_resource_provider.rs +++ b/src/render/render_resource/resource_providers/frame_texture_resource_provider.rs @@ -1,7 +1,11 @@ use crate::{ core::Window, prelude::World, - render::{render_resource::ResourceProvider, renderer::Renderer, texture::TextureDescriptor}, + render::{ + render_resource::{RenderResourceAssignments, ResourceProvider}, + renderer::Renderer, + texture::TextureDescriptor, + }, }; use legion::prelude::Resources; @@ -23,17 +27,14 @@ impl FrameTextureResourceProvider { self.descriptor.size.width = window.width; self.descriptor.size.height = window.height; - if let Some(old_resource) = renderer - .get_render_resources() - .get_named_resource(&self.name) - { + let mut render_resource_assignments = + resources.get_mut::().unwrap(); + if let Some(old_resource) = render_resource_assignments.get(&self.name) { renderer.remove_texture(old_resource); } let texture_resource = renderer.create_texture(&self.descriptor, None); - renderer - .get_render_resources_mut() - .set_named_resource(&self.name, texture_resource); + render_resource_assignments.set(&self.name, texture_resource); } } diff --git a/src/render/render_resource/resource_providers/light_resource_provider.rs b/src/render/render_resource/resource_providers/light_resource_provider.rs index bd9f70c89f..0ad13f83cc 100644 --- a/src/render/render_resource/resource_providers/light_resource_provider.rs +++ b/src/render/render_resource/resource_providers/light_resource_provider.rs @@ -1,5 +1,8 @@ use crate::render::{ - render_resource::{resource_name, BufferInfo, BufferUsage, RenderResource, ResourceProvider}, + render_resource::{ + resource_name, BufferInfo, BufferUsage, RenderResource, RenderResourceAssignments, + ResourceProvider, + }, renderer::Renderer, Light, LightRaw, }; @@ -38,7 +41,7 @@ impl ResourceProvider for LightResourceProvider { &mut self, renderer: &mut dyn Renderer, _world: &mut World, - _resources: &Resources, + resources: &Resources, ) { let light_uniform_size = std::mem::size_of::() + self.max_lights * std::mem::size_of::(); @@ -48,9 +51,9 @@ impl ResourceProvider for LightResourceProvider { buffer_usage: BufferUsage::UNIFORM | BufferUsage::COPY_SRC | BufferUsage::COPY_DST, ..Default::default() }); - renderer - .get_render_resources_mut() - .set_named_resource(resource_name::uniform::LIGHTS, buffer); + let mut render_resource_assignments = + resources.get_mut::().unwrap(); + render_resource_assignments.set(resource_name::uniform::LIGHTS, buffer); self.light_buffer = Some(buffer); } diff --git a/src/render/render_resource/resource_providers/mesh_resource_provider.rs b/src/render/render_resource/resource_providers/mesh_resource_provider.rs index 64f802bba8..7072a15a2d 100644 --- a/src/render/render_resource/resource_providers/mesh_resource_provider.rs +++ b/src/render/render_resource/resource_providers/mesh_resource_provider.rs @@ -89,12 +89,12 @@ impl ResourceProvider for MeshResourceProvider { &mut self, _renderer: &mut dyn Renderer, _world: &mut World, - resources: &Resources, + _resources: &Resources, ) { - let mesh_storage = resources.get_mut::>().unwrap(); - let mut asset_batchers = resources.get_mut::().unwrap(); - for batch in asset_batchers.get_handle_batches::() { - // batch.render_resource_assignments. - } + // TODO: assign vertex buffers + // let mesh_storage = resources.get_mut::>().unwrap(); + // let mut asset_batchers = resources.get_mut::().unwrap(); + // for batch in asset_batchers.get_handle_batches::() { + // } } } diff --git a/src/render/render_resource/resource_providers/ui_resource_provider.rs b/src/render/render_resource/resource_providers/ui_resource_provider.rs index 82df680c9b..2c4b4a2a97 100644 --- a/src/render/render_resource/resource_providers/ui_resource_provider.rs +++ b/src/render/render_resource/resource_providers/ui_resource_provider.rs @@ -6,7 +6,7 @@ use crate::{ render_graph::RenderGraph, render_resource::{ resource_name, BufferArrayInfo, BufferInfo, BufferUsage, RenderResource, - ResourceProvider, + RenderResourceAssignments, ResourceProvider, }, renderer::Renderer, shader::AsUniforms, @@ -41,7 +41,7 @@ impl UiResourceProvider { } } - pub fn update(&mut self, renderer: &mut dyn Renderer, world: &World) { + pub fn update(&mut self, renderer: &mut dyn Renderer, world: &World, resources: &Resources) { let node_query = >::query().filter(!component::()); let mut data = Vec::new(); @@ -99,9 +99,9 @@ impl UiResourceProvider { data.as_bytes(), ); - renderer - .get_render_resources_mut() - .set_named_resource(resource_name::buffer::UI_INSTANCES, buffer); + let mut render_resource_assignments = + resources.get_mut::().unwrap(); + render_resource_assignments.set(resource_name::buffer::UI_INSTANCES, buffer); self.instance_buffer = Some(buffer); } } @@ -118,7 +118,7 @@ impl ResourceProvider for UiResourceProvider { .set_vertex_buffer_descriptor(Rect::get_vertex_buffer_descriptor().cloned().unwrap()); } - fn update(&mut self, renderer: &mut dyn Renderer, world: &mut World, _resources: &Resources) { - self.update(renderer, world); + fn update(&mut self, renderer: &mut dyn Renderer, world: &mut World, resources: &Resources) { + self.update(renderer, world, resources); } } diff --git a/src/render/render_resource/resource_providers/uniform_resource_provider.rs b/src/render/render_resource/resource_providers/uniform_resource_provider.rs index 4c61234baa..b997b085c2 100644 --- a/src/render/render_resource/resource_providers/uniform_resource_provider.rs +++ b/src/render/render_resource/resource_providers/uniform_resource_provider.rs @@ -4,8 +4,7 @@ use crate::{ render_graph::RenderGraph, render_resource::{ AssetBatchers, BufferArrayInfo, BufferInfo, BufferUsage, RenderResource, - RenderResourceAssignments, ResourceInfo, - ResourceProvider, + RenderResourceAssignments, ResourceInfo, ResourceProvider, }, renderer::Renderer, shader::{AsUniforms, FieldBindType}, @@ -122,10 +121,7 @@ where self.increment_uniform_counts(&uniforms); } - Self::update_shader_defs( - &uniforms, - &mut renderable.render_resource_assignments, - ); + Self::update_shader_defs(&uniforms, &mut renderable.render_resource_assignments); } self.query = Some(query); @@ -158,10 +154,7 @@ where let uniforms = assets .get(&handle) .expect("Handle points to a non-existent resource"); - Self::update_shader_defs( - uniforms, - &mut renderable.render_resource_assignments, - ); + Self::update_shader_defs(uniforms, &mut renderable.render_resource_assignments); self.increment_uniform_counts(&uniforms); } @@ -264,9 +257,13 @@ where .. })) = renderer.get_resource_info_mut(buffer) { - let index = array_info - .get_or_assign_index(render_resource_assignments.id); - render_resource_assignments.set_indexed(&field_info.uniform_name, buffer, index as u32); + let index = + array_info.get_or_assign_index(render_resource_assignments.id); + render_resource_assignments.set_indexed( + &field_info.uniform_name, + buffer, + (index * array_info.item_size) as u32, + ); (buffer, index * uniform_buffer_status.aligned_size) } else { panic!("Expected a dynamic uniform buffer"); @@ -275,7 +272,7 @@ where let resource = match render_resource_assignments .get(field_info.uniform_name) { - Some((render_resource, _index)) => render_resource, + Some(render_resource) => render_resource, None => { let resource = renderer.create_buffer(BufferInfo { size, @@ -470,12 +467,9 @@ where fn setup_buffer_arrays(&mut self, renderer: &mut dyn Renderer) { for buffer_array_status in self.uniform_buffer_status.iter_mut() { - if let Some((name, buffer_array_status)) = buffer_array_status { + if let Some((_name, buffer_array_status)) = buffer_array_status { if self.use_dynamic_uniforms { Self::setup_buffer_array(buffer_array_status, renderer, true); - renderer - .get_render_resources_mut() - .set_named_resource(name, buffer_array_status.buffer.unwrap()); } buffer_array_status.queued_buffer_writes = @@ -623,7 +617,7 @@ where let mut staging_buffer: [u8; 0] = []; self.setup_uniforms_resources(world, resources, renderer, &mut staging_buffer); self.setup_handles_resources(world, resources, renderer, &mut staging_buffer); - // self.setup_batched_resources(world, resources, renderer, &mut staging_buffer); + // self.setup_batched_resources(world, resources, renderer, &mut staging_buffer); } else { let staging_buffer = renderer.create_buffer_mapped( BufferInfo { diff --git a/src/render/renderable.rs b/src/render/renderable.rs index b9e6fca588..5acc363f3b 100644 --- a/src/render/renderable.rs +++ b/src/render/renderable.rs @@ -1,14 +1,5 @@ -use super::{ - pipeline::PipelineDescriptor, - render_resource::{RenderResourceAssignments, RenderResourceAssignmentsId}, - shader::{Shader, ShaderSource}, -}; -use crate::{ - asset::{AssetStorage, Handle}, - render::{render_graph::RenderGraph, render_resource::resource_name}, -}; -use legion::prelude::*; -use std::collections::{HashMap, HashSet}; +use super::render_resource::RenderResourceAssignments; +use crate::{asset::Handle, prelude::PipelineDescriptor}; pub struct Renderable { pub is_visible: bool, @@ -40,206 +31,3 @@ impl Default for Renderable { } } } - -// TODO: consider using (Typeid, fieldinfo.index) in place of string for hashes -pub struct CompiledShaderMap { - // TODO: need macro hash lookup - pub source_to_compiled: HashMap, Vec<(HashSet, Handle)>>, - pub pipeline_to_macro_pipelines: - HashMap, Vec<(HashSet, Handle)>>, -} - -impl CompiledShaderMap { - pub fn new() -> Self { - CompiledShaderMap { - source_to_compiled: HashMap::new(), - pipeline_to_macro_pipelines: HashMap::new(), - } - } - - fn update_shader_assignments( - &mut self, - render_graph: &mut RenderGraph, - shader_pipeline_assignments: &mut ShaderPipelineAssignments, - pipeline_storage: &mut AssetStorage, - shader_storage: &mut AssetStorage, - pipelines: &[Handle], - render_resource_assignments: &RenderResourceAssignments, - ) { - for pipeline_handle in pipelines.iter() { - if let None = self.pipeline_to_macro_pipelines.get(pipeline_handle) { - self.pipeline_to_macro_pipelines - .insert(*pipeline_handle, Vec::new()); - } - - let final_handle = if let Some((_shader_defs, macroed_pipeline_handle)) = self - .pipeline_to_macro_pipelines - .get_mut(pipeline_handle) - .unwrap() - .iter() - .find(|(shader_defs, _macroed_pipeline_handle)| { - *shader_defs == render_resource_assignments.shader_defs - }) { - *macroed_pipeline_handle - } else { - let pipeline_descriptor = pipeline_storage.get(pipeline_handle).unwrap(); - let macroed_pipeline_handle = { - let mut macroed_vertex_handle = try_compiling_shader_with_macros( - self, - shader_storage, - &render_resource_assignments, - &pipeline_descriptor.shader_stages.vertex, - ); - let mut macroed_fragment_handle = pipeline_descriptor - .shader_stages - .fragment - .as_ref() - .map(|fragment| { - try_compiling_shader_with_macros( - self, - shader_storage, - &render_resource_assignments, - fragment, - ) - }); - - if macroed_vertex_handle.is_some() || macroed_fragment_handle.is_some() { - let mut macroed_pipeline = pipeline_descriptor.clone(); - if let Some(vertex) = macroed_vertex_handle.take() { - macroed_pipeline.shader_stages.vertex = vertex; - } - - if let Some(fragment) = macroed_fragment_handle.take() { - macroed_pipeline.shader_stages.fragment = fragment; - } - - let macroed_pipeline_handle = pipeline_storage.add(macroed_pipeline); - // TODO: get correct pass name - render_graph - .add_pipeline(resource_name::pass::MAIN, macroed_pipeline_handle); - macroed_pipeline_handle - } else { - *pipeline_handle - } - }; - - let macro_pipelines = self - .pipeline_to_macro_pipelines - .get_mut(pipeline_handle) - .unwrap(); - macro_pipelines.push(( - render_resource_assignments.shader_defs.clone(), - macroed_pipeline_handle, - )); - macroed_pipeline_handle - }; - - // TODO: this will break down if pipeline layout changes. fix this with "auto-layout" - if let None = shader_pipeline_assignments.assignments.get(&final_handle) { - shader_pipeline_assignments - .assignments - .insert(final_handle, Vec::new()); - } - - let assignments = shader_pipeline_assignments - .assignments - .get_mut(&final_handle) - .unwrap(); - assignments.push(render_resource_assignments.id); - } - } -} - -pub struct ShaderPipelineAssignments { - pub assignments: HashMap, Vec>, -} - -impl ShaderPipelineAssignments { - pub fn new() -> Self { - ShaderPipelineAssignments { - assignments: HashMap::new(), - } - } -} - -fn try_compiling_shader_with_macros( - compiled_shader_map: &mut CompiledShaderMap, - shader_storage: &mut AssetStorage, - assignments: &RenderResourceAssignments, - shader_handle: &Handle, -) -> Option> { - if let None = compiled_shader_map.source_to_compiled.get(shader_handle) { - compiled_shader_map - .source_to_compiled - .insert(*shader_handle, Vec::new()); - } - - let compiled_shaders = compiled_shader_map - .source_to_compiled - .get_mut(shader_handle) - .unwrap(); - let shader = shader_storage.get(shader_handle).unwrap(); - - // don't produce new shader if the input source is already spirv - if let ShaderSource::Spirv(_) = shader.source { - return None; - } - - if let Some((_shader_defs, compiled_shader)) = compiled_shaders - .iter() - .find(|(shader_defs, _shader)| *shader_defs == assignments.shader_defs) - { - Some(compiled_shader.clone()) - } else { - let shader_def_vec = assignments - .shader_defs - .iter() - .cloned() - .collect::>(); - let compiled_shader = shader.get_spirv_shader(Some(&shader_def_vec)); - compiled_shaders.push((assignments.shader_defs.clone(), *shader_handle)); - let compiled_shader_handle = shader_storage.add(compiled_shader); - Some(compiled_shader_handle) - } -} - -pub fn update_shader_assignments(world: &mut World, resources: &mut Resources) { - // 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 - { - let mut shader_pipeline_assignments = - resources.get_mut::().unwrap(); - let mut compiled_shader_map = resources.get_mut::().unwrap(); - let mut shader_storage = resources.get_mut::>().unwrap(); - let mut render_graph = resources.get_mut::().unwrap(); - let mut pipeline_descriptor_storage = resources - .get_mut::>() - .unwrap(); - - // reset assignments so they are updated every frame - shader_pipeline_assignments.assignments = HashMap::new(); - - // TODO: only update when renderable is changed - for mut renderable in >::query().iter_mut(world) { - // skip instanced entities. their batched RenderResourceAssignments will handle shader assignments - if renderable.is_instanced { - continue; - } - - compiled_shader_map.update_shader_assignments( - &mut render_graph, - &mut shader_pipeline_assignments, - &mut pipeline_descriptor_storage, - &mut shader_storage, - &renderable.pipelines, - &renderable.render_resource_assignments, - ); - - // reset shader_defs so they can be changed next frame - renderable - .render_resource_assignments - .shader_defs - .clear(); - } - } -} diff --git a/src/render/renderer/renderer.rs b/src/render/renderer/renderer.rs index fd2aaf994c..5517ce18a0 100644 --- a/src/render/renderer/renderer.rs +++ b/src/render/renderer/renderer.rs @@ -55,5 +55,8 @@ pub trait RenderPass { fn set_index_buffer(&mut self, resource: RenderResource, offset: u64); fn set_vertex_buffer(&mut self, start_slot: u32, resource: RenderResource, offset: u64); fn draw_indexed(&mut self, indices: Range, base_vertex: i32, instances: Range); - fn set_render_resources(&mut self, render_resource_assignments: &RenderResourceAssignments) -> Option>; + fn set_render_resources( + &mut self, + render_resource_assignments: &RenderResourceAssignments, + ) -> Option>; } diff --git a/src/render/renderer/renderers/wgpu_renderer/wgpu_render_pass.rs b/src/render/renderer/renderers/wgpu_renderer/wgpu_render_pass.rs index 7feacbb983..2bf4b49da7 100644 --- a/src/render/renderer/renderers/wgpu_renderer/wgpu_render_pass.rs +++ b/src/render/renderer/renderers/wgpu_renderer/wgpu_render_pass.rs @@ -1,7 +1,7 @@ use super::{WgpuRenderer, WgpuResources}; use crate::render::{ - pipeline::{BindType, PipelineDescriptor}, - render_resource::{BufferInfo, RenderResource, RenderResourceAssignments, ResourceInfo}, + pipeline::PipelineDescriptor, + render_resource::{RenderResource, RenderResourceAssignments}, renderer::{RenderPass, Renderer}, }; use std::ops::Range; @@ -53,11 +53,18 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> { { // TODO: check to see if bind group is already set let empty = &[]; - let dynamic_uniform_indices = if let Some(dynamic_uniform_indices) = dynamic_uniform_indices { - dynamic_uniform_indices.as_slice() - } else { - empty - }; + let dynamic_uniform_indices = + if let Some(dynamic_uniform_indices) = dynamic_uniform_indices { + dynamic_uniform_indices.as_slice() + } else { + empty + }; + + // TODO: remove this + // if dynamic_uniform_indices.len() == 0 && bind_group.index > 0 { + // continue; + // } + self.render_pass.set_bind_group( bind_group.index, &wgpu_bind_group, diff --git a/src/render/renderer/renderers/wgpu_renderer/wgpu_renderer.rs b/src/render/renderer/renderers/wgpu_renderer/wgpu_renderer.rs index 1f28f7c214..d5acdfe685 100644 --- a/src/render/renderer/renderers/wgpu_renderer/wgpu_renderer.rs +++ b/src/render/renderer/renderers/wgpu_renderer/wgpu_renderer.rs @@ -8,7 +8,7 @@ use crate::{ PassDescriptor, RenderPassColorAttachmentDescriptor, RenderPassDepthStencilAttachmentDescriptor, }, - pipeline::{BindType, PipelineDescriptor, PipelineLayout, PipelineLayoutType}, + pipeline::{update_shader_assignments, PipelineCompiler, PipelineDescriptor}, render_graph::RenderGraph, render_resource::{ resource_name, BufferInfo, RenderResource, RenderResourceAssignments, RenderResources, @@ -17,7 +17,6 @@ use crate::{ renderer::Renderer, shader::Shader, texture::{SamplerDescriptor, TextureDescriptor}, - update_shader_assignments, }, }; use std::{cell::RefCell, collections::HashMap, ops::Deref, rc::Rc}; @@ -65,7 +64,7 @@ impl WgpuRenderer { encoder: None, intialized: false, swap_chain_descriptor, - wgpu_resources: WgpuResources::new(), + wgpu_resources: WgpuResources::default(), render_pipelines: HashMap::new(), } } @@ -88,102 +87,14 @@ impl WgpuRenderer { self.intialized = true; } - pub fn setup_vertex_buffer_descriptors( - render_graph: &RenderGraph, - vertex_spirv: &Shader, - pipeline_descriptor: &PipelineDescriptor, - ) -> Vec { - let mut reflected_vertex_layout = if pipeline_descriptor.reflect_vertex_buffer_descriptors { - Some(vertex_spirv.reflect_layout().unwrap()) - } else { - None - }; - - let vertex_buffer_descriptors = if let Some(ref mut layout) = reflected_vertex_layout { - for vertex_buffer_descriptor in layout.vertex_buffer_descriptors.iter_mut() { - if let Some(graph_descriptor) = - render_graph.get_vertex_buffer_descriptor(&vertex_buffer_descriptor.name) - { - vertex_buffer_descriptor.sync_with_descriptor(graph_descriptor); - } else { - panic!( - "Encountered unsupported Vertex Buffer: {}", - vertex_buffer_descriptor.name - ); - } - } - &layout.vertex_buffer_descriptors - } else { - &pipeline_descriptor.vertex_buffer_descriptors - }; - - vertex_buffer_descriptors - .iter() - .map(|v| v.into()) - .collect::>() - } - pub fn create_render_pipeline( wgpu_resources: &mut WgpuResources, pipeline_descriptor: &mut PipelineDescriptor, + shader_storage: &AssetStorage, device: &wgpu::Device, - render_graph: &RenderGraph, - vertex_shader: &Shader, - fragment_shader: Option<&Shader>, ) -> wgpu::RenderPipeline { - let vertex_spirv = vertex_shader.get_spirv_shader(None); - let fragment_spirv = fragment_shader.map(|f| f.get_spirv_shader(None)); - - let vertex_shader_module = Self::create_shader_module(device, &vertex_spirv, None); - let fragment_shader_module = match fragment_shader { - Some(fragment_spirv) => Some(Self::create_shader_module(device, fragment_spirv, None)), - None => None, - }; - - if let PipelineLayoutType::Reflected(None) = pipeline_descriptor.layout { - 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); - - // set each uniform binding to dynamic if there is a matching dynamic uniform buffer info - for mut bind_group in layout.bind_groups.iter_mut() { - bind_group.bindings = bind_group - .bindings - .iter() - .cloned() - .map(|mut binding| { - if let BindType::Uniform { - ref mut dynamic, .. - } = binding.bind_type - { - if let Some(resource) = wgpu_resources - .render_resources - .get_named_resource(&binding.name) - { - if let Some(ResourceInfo::Buffer(buffer_info)) = - wgpu_resources.resource_info.get(&resource) - { - *dynamic = buffer_info.is_dynamic; - } - } - } - - binding - }) - .collect(); - } - - pipeline_descriptor.layout = PipelineLayoutType::Reflected(Some(layout)); - } - - let layout = pipeline_descriptor.get_layout_mut().unwrap(); - - // setup new bind group layouts - for bind_group in layout.bind_groups.iter_mut() { + let layout = pipeline_descriptor.get_layout().unwrap(); + for bind_group in layout.bind_groups.iter() { if let None = wgpu_resources.bind_group_layouts.get(&bind_group.id) { let bind_group_layout_binding = bind_group .bindings @@ -194,18 +105,18 @@ impl WgpuRenderer { ty: (&binding.bind_type).into(), }) .collect::>(); - let bind_group_layout = + let wgpu_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { bindings: bind_group_layout_binding.as_slice(), }); wgpu_resources .bind_group_layouts - .insert(bind_group.id, bind_group_layout); + .insert(bind_group.id, wgpu_bind_group_layout); } } - // collect bind group layout references + // setup and collect bind group layouts let bind_group_layouts = layout .bind_groups .iter() @@ -221,8 +132,11 @@ impl WgpuRenderer { bind_group_layouts: bind_group_layouts.as_slice(), }); - let owned_vertex_buffer_descriptors = - Self::setup_vertex_buffer_descriptors(render_graph, &vertex_spirv, pipeline_descriptor); + let owned_vertex_buffer_descriptors = layout + .vertex_buffer_descriptors + .iter() + .map(|v| v.into()) + .collect::>(); let color_states = pipeline_descriptor .color_states @@ -230,13 +144,42 @@ impl WgpuRenderer { .map(|c| c.into()) .collect::>(); + if let None = wgpu_resources + .shader_modules + .get(&pipeline_descriptor.shader_stages.vertex) + { + wgpu_resources.create_shader_module( + device, + pipeline_descriptor.shader_stages.vertex, + shader_storage, + ); + } + + if let Some(fragment_handle) = pipeline_descriptor.shader_stages.fragment { + if let None = wgpu_resources.shader_modules.get(&fragment_handle) { + wgpu_resources.create_shader_module(device, fragment_handle, shader_storage); + } + }; + + let vertex_shader_module = wgpu_resources + .shader_modules + .get(&pipeline_descriptor.shader_stages.vertex) + .unwrap(); + + let fragment_shader_module = match pipeline_descriptor.shader_stages.fragment { + Some(fragment_handle) => { + Some(wgpu_resources.shader_modules.get(&fragment_handle).unwrap()) + } + None => None, + }; + let mut render_pipeline_descriptor = wgpu::RenderPipelineDescriptor { layout: &pipeline_layout, vertex_stage: wgpu::ProgrammableStageDescriptor { module: &vertex_shader_module, entry_point: "main", }, - fragment_stage: match fragment_shader { + fragment_stage: match pipeline_descriptor.shader_stages.fragment { Some(_) => Some(wgpu::ProgrammableStageDescriptor { entry_point: "main", module: fragment_shader_module.as_ref().unwrap(), @@ -269,6 +212,7 @@ impl WgpuRenderer { pub fn create_render_pass<'a>( wgpu_resources: &'a WgpuResources, pass_descriptor: &PassDescriptor, + global_render_resource_assignments: &RenderResourceAssignments, encoder: &'a mut wgpu::CommandEncoder, frame: &'a wgpu::SwapChainOutput, ) -> wgpu::RenderPass<'a> { @@ -276,25 +220,37 @@ impl WgpuRenderer { color_attachments: &pass_descriptor .color_attachments .iter() - .map(|c| Self::create_wgpu_color_attachment_descriptor(wgpu_resources, c, frame)) + .map(|c| { + Self::create_wgpu_color_attachment_descriptor( + wgpu_resources, + global_render_resource_assignments, + c, + frame, + ) + }) .collect::>(), depth_stencil_attachment: pass_descriptor.depth_stencil_attachment.as_ref().map(|d| { - Self::create_wgpu_depth_stencil_attachment_descriptor(wgpu_resources, d, frame) + Self::create_wgpu_depth_stencil_attachment_descriptor( + wgpu_resources, + global_render_resource_assignments, + d, + frame, + ) }), }) } fn create_wgpu_color_attachment_descriptor<'a>( wgpu_resources: &'a WgpuResources, + global_render_resource_assignments: &RenderResourceAssignments, color_attachment_descriptor: &RenderPassColorAttachmentDescriptor, frame: &'a wgpu::SwapChainOutput, ) -> wgpu::RenderPassColorAttachmentDescriptor<'a> { let attachment = match color_attachment_descriptor.attachment.as_str() { resource_name::texture::SWAP_CHAIN => &frame.view, _ => { - match wgpu_resources - .render_resources - .get_named_resource(&color_attachment_descriptor.attachment) + match global_render_resource_assignments + .get(&color_attachment_descriptor.attachment) { Some(resource) => wgpu_resources.textures.get(&resource).unwrap(), None => panic!( @@ -308,10 +264,7 @@ impl WgpuRenderer { let resolve_target = match color_attachment_descriptor.resolve_target { Some(ref target) => match target.as_str() { resource_name::texture::SWAP_CHAIN => Some(&frame.view), - _ => match wgpu_resources - .render_resources - .get_named_resource(target.as_str()) - { + _ => match global_render_resource_assignments.get(target.as_str()) { Some(resource) => Some(wgpu_resources.textures.get(&resource).unwrap()), None => panic!( "Color attachment {} does not exist", @@ -333,15 +286,15 @@ impl WgpuRenderer { fn create_wgpu_depth_stencil_attachment_descriptor<'a>( wgpu_resources: &'a WgpuResources, + global_render_resource_assignments: &RenderResourceAssignments, depth_stencil_attachment_descriptor: &RenderPassDepthStencilAttachmentDescriptor, frame: &'a wgpu::SwapChainOutput, ) -> wgpu::RenderPassDepthStencilAttachmentDescriptor<'a> { let attachment = match depth_stencil_attachment_descriptor.attachment.as_str() { resource_name::texture::SWAP_CHAIN => &frame.view, _ => { - match wgpu_resources - .render_resources - .get_named_resource(&depth_stencil_attachment_descriptor.attachment) + match global_render_resource_assignments + .get(&depth_stencil_attachment_descriptor.attachment) { Some(ref resource) => wgpu_resources.textures.get(&resource).unwrap(), None => panic!( @@ -363,14 +316,6 @@ impl WgpuRenderer { } } - pub fn create_shader_module( - device: &wgpu::Device, - shader: &Shader, - macros: Option<&[String]>, - ) -> wgpu::ShaderModule { - device.create_shader_module(&shader.get_spirv(macros)) - } - pub fn initialize_resource_providers(&mut self, world: &mut World, resources: &mut Resources) { let mut render_graph = resources.get_mut::().unwrap(); self.encoder = Some( @@ -400,11 +345,11 @@ impl WgpuRenderer { pub fn create_queued_textures(&mut self, resources: &mut Resources) { let mut render_graph = resources.get_mut::().unwrap(); + let mut render_resource_assignments = + resources.get_mut::().unwrap(); for (name, texture_descriptor) in render_graph.queued_textures.drain(..) { let resource = self.create_texture(&texture_descriptor, None); - self.wgpu_resources - .render_resources - .set_named_resource(&name, resource); + render_resource_assignments.set(&name, resource); } } @@ -471,33 +416,31 @@ impl Renderer for WgpuRenderer { let shader_storage = resources.get::>().unwrap(); let render_graph = resources.get::().unwrap(); let mut render_graph_mut = resources.get_mut::().unwrap(); + let global_render_resource_assignments = + resources.get::().unwrap(); + let pipeline_compiler = resources.get::().unwrap(); + for pipeline_descriptor_handle in render_graph.pipeline_descriptors.iter() { - let pipeline_descriptor = pipeline_storage - .get_mut(pipeline_descriptor_handle) - .unwrap(); - // create pipelines - if !self - .render_pipelines - .contains_key(pipeline_descriptor_handle) + if let Some(compiled_pipelines_iter) = + pipeline_compiler.iter_compiled_pipelines(*pipeline_descriptor_handle) { - let vertex_shader = shader_storage - .get(&pipeline_descriptor.shader_stages.vertex) - .unwrap(); - let fragment_shader = pipeline_descriptor - .shader_stages - .fragment - .as_ref() - .map(|handle| &*shader_storage.get(&handle).unwrap()); - let render_pipeline = WgpuRenderer::create_render_pipeline( - &mut self.wgpu_resources, - pipeline_descriptor, - &self.device.borrow(), - &render_graph, - vertex_shader, - fragment_shader, - ); - self.render_pipelines - .insert(*pipeline_descriptor_handle, render_pipeline); + for compiled_pipeline_handle in compiled_pipelines_iter { + // create pipelines + // TODO: merge this into "setup draw targets" loop + if !self.render_pipelines.contains_key(compiled_pipeline_handle) { + let compiled_pipeline_descriptor = + pipeline_storage.get_mut(compiled_pipeline_handle).unwrap(); + + let render_pipeline = WgpuRenderer::create_render_pipeline( + &mut self.wgpu_resources, + compiled_pipeline_descriptor, + &shader_storage, + &self.device.borrow(), + ); + self.render_pipelines + .insert(*compiled_pipeline_handle, render_pipeline); + } + } } } @@ -505,13 +448,25 @@ impl Renderer for WgpuRenderer { for (pass_name, _pass_descriptor) in render_graph.pass_descriptors.iter() { if let Some(pass_pipelines) = render_graph.pass_pipelines.get(pass_name) { for pass_pipeline in pass_pipelines.iter() { - let pipeline_descriptor = pipeline_storage.get(pass_pipeline).unwrap(); - for draw_target_name in pipeline_descriptor.draw_targets.iter() { - let draw_target = render_graph_mut - .draw_targets - .get_mut(draw_target_name) - .unwrap(); - draw_target.setup(world, resources, self, *pass_pipeline); + if let Some(compiled_pipelines_iter) = + pipeline_compiler.iter_compiled_pipelines(*pass_pipeline) + { + for compiled_pipeline_handle in compiled_pipelines_iter { + let pipeline_descriptor = + pipeline_storage.get(compiled_pipeline_handle).unwrap(); + for draw_target_name in pipeline_descriptor.draw_targets.iter() { + let draw_target = render_graph_mut + .draw_targets + .get_mut(draw_target_name) + .unwrap(); + draw_target.setup( + world, + resources, + self, + *compiled_pipeline_handle, + ); + } + } } } } @@ -522,25 +477,40 @@ impl Renderer for WgpuRenderer { let mut render_pass = Self::create_render_pass( &self.wgpu_resources, pass_descriptor, + &global_render_resource_assignments, &mut encoder, &frame, ); if let Some(pass_pipelines) = render_graph.pass_pipelines.get(pass_name) { for pass_pipeline in pass_pipelines.iter() { - let pipeline_descriptor = pipeline_storage.get(pass_pipeline).unwrap(); - let render_pipeline = self.render_pipelines.get(pass_pipeline).unwrap(); - render_pass.set_pipeline(render_pipeline); + if let Some(compiled_pipelines_iter) = + pipeline_compiler.iter_compiled_pipelines(*pass_pipeline) + { + for compiled_pipeline_handle in compiled_pipelines_iter { + let pipeline_descriptor = + pipeline_storage.get(compiled_pipeline_handle).unwrap(); + let render_pipeline = + self.render_pipelines.get(compiled_pipeline_handle).unwrap(); + render_pass.set_pipeline(render_pipeline); - let mut wgpu_render_pass = WgpuRenderPass { - render_pass: &mut render_pass, - pipeline_descriptor, - wgpu_resources: &self.wgpu_resources, - renderer: &self, - }; + let mut wgpu_render_pass = WgpuRenderPass { + render_pass: &mut render_pass, + pipeline_descriptor, + wgpu_resources: &self.wgpu_resources, + renderer: &self, + }; - for draw_target_name in pipeline_descriptor.draw_targets.iter() { - let draw_target = render_graph.draw_targets.get(draw_target_name).unwrap(); - draw_target.draw(world, resources, &mut wgpu_render_pass, *pass_pipeline); + for draw_target_name in pipeline_descriptor.draw_targets.iter() { + let draw_target = + render_graph.draw_targets.get(draw_target_name).unwrap(); + draw_target.draw( + world, + resources, + &mut wgpu_render_pass, + *compiled_pipeline_handle, + ); + } + } } } } diff --git a/src/render/renderer/renderers/wgpu_renderer/wgpu_resources.rs b/src/render/renderer/renderers/wgpu_renderer/wgpu_resources.rs index 7688b59629..254536040e 100644 --- a/src/render/renderer/renderers/wgpu_renderer/wgpu_resources.rs +++ b/src/render/renderer/renderers/wgpu_renderer/wgpu_resources.rs @@ -1,12 +1,16 @@ use super::WgpuRenderer; -use crate::render::{ - pipeline::{BindGroupDescriptor, BindGroupDescriptorId, BindType}, - render_resource::{ - BufferInfo, RenderResource, RenderResourceAssignments, RenderResourceSetId, - RenderResources, ResourceInfo, +use crate::{ + asset::{AssetStorage, Handle}, + prelude::Shader, + render::{ + pipeline::{BindGroupDescriptor, BindGroupDescriptorId, BindType}, + render_resource::{ + BufferInfo, RenderResource, RenderResourceAssignments, RenderResourceSetId, + RenderResources, ResourceInfo, + }, + renderer::Renderer, + texture::{SamplerDescriptor, TextureDescriptor}, }, - renderer::Renderer, - texture::{SamplerDescriptor, TextureDescriptor}, }; use std::collections::HashMap; @@ -15,29 +19,19 @@ pub struct WgpuBindGroupInfo { pub bind_groups: HashMap, } +#[derive(Default)] pub struct WgpuResources { pub render_resources: RenderResources, pub buffers: HashMap, pub textures: HashMap, pub samplers: HashMap, pub resource_info: HashMap, + pub shader_modules: HashMap, wgpu::ShaderModule>, pub bind_groups: HashMap, pub bind_group_layouts: HashMap, } impl WgpuResources { - pub fn new() -> Self { - WgpuResources { - buffers: HashMap::new(), - textures: HashMap::new(), - samplers: HashMap::new(), - resource_info: HashMap::new(), - bind_groups: HashMap::new(), - bind_group_layouts: HashMap::new(), - render_resources: RenderResources::default(), - } - } - pub fn add_resource_info(&mut self, resource: RenderResource, resource_info: ResourceInfo) { self.resource_info.insert(resource, resource_info); } @@ -67,7 +61,7 @@ impl WgpuResources { .bindings .iter() .map(|binding| { - if let Some((resource, index)) = render_resource_assignments.get(&binding.name) { + if let Some(resource) = render_resource_assignments.get(&binding.name) { let resource_info = self.resource_info.get(&resource).unwrap(); wgpu::Binding { binding: binding.index, @@ -121,9 +115,7 @@ impl WgpuResources { }; let bind_group = device.create_bind_group(&wgpu_bind_group_descriptor); - // TODO: storing a large number entity bind groups might actually be really bad. make sure this is ok - - let mut bind_group_info = self + let bind_group_info = self .bind_groups .entry(bind_group_descriptor.id) .or_insert_with(|| WgpuBindGroupInfo::default()); @@ -212,6 +204,18 @@ impl WgpuResources { encoder.copy_buffer_to_buffer(source, source_offset, destination, destination_offset, size); } + pub fn create_shader_module( + &mut self, + device: &wgpu::Device, + shader_handle: Handle, + shader_storage: &AssetStorage, + ) { + self.shader_modules.entry(shader_handle).or_insert_with(|| { + let shader = shader_storage.get(&shader_handle).unwrap(); + device.create_shader_module(&shader.get_spirv(None)) + }); + } + pub fn create_sampler( &mut self, device: &wgpu::Device, diff --git a/src/render/shader/shader_reflect.rs b/src/render/shader/shader_reflect.rs index cdc08a930e..81bd2d0f21 100644 --- a/src/render/shader/shader_reflect.rs +++ b/src/render/shader/shader_reflect.rs @@ -1,7 +1,7 @@ use crate::render::{ pipeline::{ - BindGroupDescriptor, BindType, BindingDescriptor, InputStepMode, UniformProperty, UniformPropertyType, - VertexAttributeDescriptor, VertexBufferDescriptor, VertexFormat, + BindGroupDescriptor, BindType, BindingDescriptor, InputStepMode, UniformProperty, + UniformPropertyType, VertexAttributeDescriptor, VertexBufferDescriptor, VertexFormat, }, texture::TextureViewDimension, };