From 512bf118bf3451700611512362e55cd23a888d87 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Fri, 24 Apr 2020 11:08:46 -0700 Subject: [PATCH] RenderGraph2: UniformNode --- bevy_render/src/lib.rs | 5 +- bevy_render/src/pipeline/pipeline_compiler.rs | 18 +- bevy_render/src/render_graph_2/nodes.rs | 4 +- .../src/render_graph_2/nodes/uniform_node.rs | 649 ++++++++++++++++++ .../src/renderer_2/render_resource_context.rs | 1 + bevy_render/src/shader/uniform.rs | 2 +- bevy_wgpu/src/wgpu_renderer.rs | 14 +- 7 files changed, 673 insertions(+), 20 deletions(-) create mode 100644 bevy_render/src/render_graph_2/nodes/uniform_node.rs diff --git a/bevy_render/src/lib.rs b/bevy_render/src/lib.rs index 957060632d..479841520b 100644 --- a/bevy_render/src/lib.rs +++ b/bevy_render/src/lib.rs @@ -54,7 +54,7 @@ use bevy_window::{WindowCreated, WindowReference, WindowResized}; use pass::PassDescriptor; use pipeline::pipelines::build_forward_pipeline; use render_graph_2::{ - nodes::{Camera2dNode, CameraNode, PassNode, WindowSwapChainNode, WindowTextureNode}, + nodes::{Camera2dNode, CameraNode, PassNode, WindowSwapChainNode, WindowTextureNode, UniformNode}, RenderGraph2, }; use render_resource::resource_providers::mesh_resource_provider_system; @@ -78,7 +78,6 @@ impl RenderPlugin { render_graph .build(&mut pipelines, &mut shaders) .add_resource_provider(LightResourceProvider::new(10)) - .add_resource_provider(UniformResourceProvider::::new(true)) .add_resource_provider(UniformResourceProvider::::new(true)); } } @@ -124,6 +123,7 @@ impl AppPlugin for RenderPlugin { let resources = app.resources_mut(); render_graph.add_system_node_named("camera", CameraNode::default(), resources); render_graph.add_system_node_named("camera2d", Camera2dNode::default(), resources); + render_graph.add_system_node_named("standard_material", UniformNode::::new(true), resources); render_graph.add_node_named( "swapchain", WindowSwapChainNode::new( @@ -185,6 +185,7 @@ impl AppPlugin for RenderPlugin { // TODO: replace these with "autowire" groups render_graph.add_node_edge("camera", "main_pass").unwrap(); render_graph.add_node_edge("camera2d", "main_pass").unwrap(); + render_graph.add_node_edge("standard_material", "main_pass").unwrap(); render_graph .add_slot_edge( "swapchain", diff --git a/bevy_render/src/pipeline/pipeline_compiler.rs b/bevy_render/src/pipeline/pipeline_compiler.rs index 756d2a1ed0..8a78642a1b 100644 --- a/bevy_render/src/pipeline/pipeline_compiler.rs +++ b/bevy_render/src/pipeline/pipeline_compiler.rs @@ -6,7 +6,7 @@ use crate::{ render_resource::{ BufferInfo, RenderResourceAssignments, RenderResourceAssignmentsId, ResourceInfo, }, - renderer_2::RenderContext, + renderer_2::{RenderResourceContext, GlobalRenderResourceContext}, shader::{Shader, ShaderSource}, Renderable, }; @@ -48,7 +48,7 @@ impl PipelineCompiler { shader_storage: &AssetStorage, vertex_buffer_descriptors: &VertexBufferDescriptors, pipeline_descriptor: &mut PipelineDescriptor, - render_context: &dyn RenderContext, + render_resource_context: &dyn RenderResourceContext, render_resource_assignments: &RenderResourceAssignments, ) { let vertex_spirv = shader_storage @@ -75,7 +75,7 @@ impl PipelineCompiler { 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_context.resources().get_resource_info( + render_resource_context.get_resource_info( render_resource, &mut |resource_info| { if let Some(ResourceInfo::Buffer(BufferInfo { is_dynamic, .. })) = @@ -142,7 +142,7 @@ impl PipelineCompiler { &mut self, vertex_buffer_descriptors: &VertexBufferDescriptors, shader_storage: &mut AssetStorage, - render_context: &dyn RenderContext, + render_resource_context: &dyn RenderResourceContext, pipeline_descriptor: &PipelineDescriptor, render_resource_assignments: &RenderResourceAssignments, ) -> PipelineDescriptor { @@ -173,7 +173,7 @@ impl PipelineCompiler { shader_storage, vertex_buffer_descriptors, &mut compiled_pipeline_descriptor, - render_context, + render_resource_context, render_resource_assignments, ); @@ -187,7 +187,7 @@ impl PipelineCompiler { &mut self, vertex_buffer_descriptors: &VertexBufferDescriptors, shader_pipeline_assignments: &mut PipelineAssignments, - render_context: &dyn RenderContext, + render_resource_context: &dyn RenderResourceContext, pipeline_storage: &mut AssetStorage, shader_storage: &mut AssetStorage, pipelines: &[Handle], @@ -213,7 +213,7 @@ impl PipelineCompiler { let compiled_pipeline = self.compile_pipeline( vertex_buffer_descriptors, shader_storage, - render_context, + render_resource_context, pipeline_descriptor, render_resource_assignments, ); @@ -286,7 +286,6 @@ impl PipelineAssignments { pub fn update_shader_assignments( world: &mut World, resources: &Resources, - render_context: &dyn RenderContext, ) { // 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 @@ -295,6 +294,7 @@ pub fn update_shader_assignments( let mut pipeline_compiler = resources.get_mut::().unwrap(); let mut shader_storage = resources.get_mut::>().unwrap(); let vertex_buffer_descriptors = resources.get::().unwrap(); + let global_render_resource_context = resources.get::().unwrap(); let mut pipeline_descriptor_storage = resources .get_mut::>() .unwrap(); @@ -312,7 +312,7 @@ pub fn update_shader_assignments( pipeline_compiler.update_shader_assignments( &vertex_buffer_descriptors, &mut shader_pipeline_assignments, - render_context, + &*global_render_resource_context.context, &mut pipeline_descriptor_storage, &mut shader_storage, &renderable.pipelines, diff --git a/bevy_render/src/render_graph_2/nodes.rs b/bevy_render/src/render_graph_2/nodes.rs index 7c28635082..c577591857 100644 --- a/bevy_render/src/render_graph_2/nodes.rs +++ b/bevy_render/src/render_graph_2/nodes.rs @@ -3,9 +3,11 @@ mod camera2d_node; mod window_texture_node; mod window_swapchain_node; mod pass_node; +mod uniform_node; pub use camera_node::*; pub use camera2d_node::*; pub use window_texture_node::*; pub use window_swapchain_node::*; -pub use pass_node::*; \ No newline at end of file +pub use pass_node::*; +pub use uniform_node::*; \ No newline at end of file diff --git a/bevy_render/src/render_graph_2/nodes/uniform_node.rs b/bevy_render/src/render_graph_2/nodes/uniform_node.rs new file mode 100644 index 0000000000..e06f2de2a3 --- /dev/null +++ b/bevy_render/src/render_graph_2/nodes/uniform_node.rs @@ -0,0 +1,649 @@ +use crate::{ + pipeline::VertexBufferDescriptors, + render_graph_2::{CommandQueue, Node, ResourceSlots, SystemNode}, + render_resource::{ + BufferArrayInfo, BufferInfo, BufferUsage, RenderResource, RenderResourceAssignments, + RenderResourceAssignmentsId, ResourceInfo, + }, + renderer_2::{GlobalRenderResourceContext, RenderContext, RenderResourceContext}, + shader::{AsUniforms, FieldBindType}, + texture, Renderable, +}; + +use bevy_asset::{AssetStorage, Handle}; +use legion::prelude::*; +use std::{collections::HashMap, marker::PhantomData}; +use texture::{SamplerDescriptor, Texture, TextureDescriptor}; + +pub const BIND_BUFFER_ALIGNMENT: usize = 256; +#[derive(Debug)] +struct QueuedBufferWrite { + buffer: RenderResource, + offset: usize, +} + +#[derive(Debug)] +struct BufferArrayStatus { + new_item_count: usize, + item_size: usize, + aligned_size: usize, + staging_buffer_offset: usize, + buffer: Option, + queued_buffer_writes: Vec, + current_item_count: usize, + current_item_capacity: usize, + indices: HashMap, + current_index: usize, +} + +impl BufferArrayStatus { + pub fn get_or_assign_index(&mut self, id: RenderResourceAssignmentsId) -> usize { + if let Some(offset) = self.indices.get(&id) { + *offset + } else { + if self.current_index == self.current_item_capacity { + panic!("no empty slots available in array"); + } + + let index = self.current_index; + self.indices.insert(id, index); + self.current_index += 1; + index + } + } +} + +struct UniformBufferArrays +where + T: AsUniforms, +{ + uniform_arrays: Vec>, + _marker: PhantomData, +} + +impl UniformBufferArrays +where + T: AsUniforms, +{ + fn new() -> Self { + let mut uniform_arrays = Vec::new(); + let field_infos = T::get_field_infos(); + uniform_arrays.resize_with(field_infos.len(), || None); + UniformBufferArrays { + uniform_arrays, + _marker: PhantomData::default(), + } + } + fn reset_new_item_counts(&mut self) { + for buffer_status in self.uniform_arrays.iter_mut() { + if let Some((_name, buffer_status)) = buffer_status { + buffer_status.new_item_count = 0; + } + } + } + + fn increment_uniform_counts(&mut self, uniforms: &T) { + for (i, field_info) in T::get_field_infos().iter().enumerate() { + if let Some(FieldBindType::Uniform { size }) = + uniforms.get_field_bind_type(&field_info.name) + { + if let Some((ref _name, ref mut buffer_array_status)) = self.uniform_arrays[i] { + buffer_array_status.new_item_count += 1; + } else { + self.uniform_arrays[i] = Some(( + field_info.uniform_name.to_string(), + BufferArrayStatus { + new_item_count: 1, + queued_buffer_writes: Vec::new(), + aligned_size: Self::get_aligned_dynamic_uniform_size(size), + item_size: size, + staging_buffer_offset: 0, + buffer: None, + current_index: 0, + current_item_count: 0, + current_item_capacity: 0, + indices: HashMap::new(), + }, + )) + } + } + } + } + + fn get_aligned_dynamic_uniform_size(data_size: usize) -> usize { + BIND_BUFFER_ALIGNMENT * ((data_size as f32 / BIND_BUFFER_ALIGNMENT as f32).ceil() as usize) + } + + fn setup_buffer_arrays( + &mut self, + render_resource_context: &dyn RenderResourceContext, + dynamic_uniforms: bool, + ) { + for buffer_array_status in self.uniform_arrays.iter_mut() { + if let Some((_name, buffer_array_status)) = buffer_array_status { + if dynamic_uniforms { + Self::setup_buffer_array(buffer_array_status, render_resource_context, true); + } + + buffer_array_status.queued_buffer_writes = + Vec::with_capacity(buffer_array_status.new_item_count); + } + } + } + + fn setup_buffer_array( + buffer_array_status: &mut BufferArrayStatus, + render_resource_context: &dyn RenderResourceContext, + align: bool, + ) { + let new_capacity = if let Some(buffer) = buffer_array_status.buffer { + let mut new_capacity = None; + render_resource_context.get_resource_info(buffer, &mut |resource_info| { + new_capacity = if let Some(ResourceInfo::Buffer(BufferInfo { + array_info: Some(array_info), + .. + })) = resource_info + { + if array_info.item_capacity < buffer_array_status.new_item_count { + // over capacity. lets resize + Some( + buffer_array_status.new_item_count + + buffer_array_status.new_item_count / 2, + ) + } else { + // under capacity. no change needed + None + } + } else { + // incorrect resource type. overwrite with new buffer + Some(buffer_array_status.new_item_count) + }; + }); + new_capacity + } else { + // buffer does not exist. create it now. + Some(buffer_array_status.new_item_count) + }; + + if let Some(new_capacity) = new_capacity { + let mut item_size = buffer_array_status.item_size; + if align { + item_size = Self::get_aligned_dynamic_uniform_size(item_size); + } + + let total_size = item_size * new_capacity; + + let buffer = render_resource_context.create_buffer(BufferInfo { + array_info: Some(BufferArrayInfo { + item_capacity: new_capacity, + item_size, + ..Default::default() + }), + size: total_size, + buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM, + is_dynamic: true, + }); + + buffer_array_status.current_item_capacity = new_capacity; + + log::trace!( + "creating buffer for uniform {}. size: {} item_capacity: {} item_size: {}", + std::any::type_name::(), + total_size, + new_capacity, + item_size + ); + + buffer_array_status.buffer = Some(buffer); + } + } + fn update_staging_buffer_offsets(&mut self) -> usize { + let mut size = 0; + for dynamic_buffer_array_status in self.uniform_arrays.iter_mut() { + if let Some((_name, ref mut buffer_array_status)) = dynamic_buffer_array_status { + buffer_array_status.staging_buffer_offset = size; + size += buffer_array_status.item_size * buffer_array_status.new_item_count; + } + } + + size + } + + fn setup_uniform_buffer_resources( + &mut self, + uniforms: &T, + dynamic_uniforms: bool, + render_resources: &dyn RenderResourceContext, + render_resource_assignments: &mut RenderResourceAssignments, + staging_buffer: &mut [u8], + ) { + for (i, field_info) in T::get_field_infos().iter().enumerate() { + let bind_type = uniforms.get_field_bind_type(&field_info.name); + match bind_type { + Some(FieldBindType::Uniform { size }) => { + let (_name, uniform_buffer_status) = self.uniform_arrays[i].as_mut().unwrap(); + let (target_buffer, target_offset) = if dynamic_uniforms { + let buffer = uniform_buffer_status.buffer.unwrap(); + let mut offset = 0; + render_resources.get_resource_info(buffer, &mut |resource_info| { + if let Some(ResourceInfo::Buffer(BufferInfo { + array_info: Some(ref array_info), + is_dynamic: true, + .. + })) = resource_info + { + let index = uniform_buffer_status + .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, + ); + offset = index * uniform_buffer_status.aligned_size; + } else { + panic!("Expected a dynamic uniform buffer"); + } + }); + (buffer, offset) + } else { + let resource = match render_resource_assignments + .get(field_info.uniform_name) + { + Some(render_resource) => render_resource, + None => { + let resource = render_resources.create_buffer(BufferInfo { + size, + buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM, + ..Default::default() + }); + render_resource_assignments.set(&field_info.uniform_name, resource); + resource + } + }; + + (resource, 0) + }; + + let staging_buffer_start = uniform_buffer_status.staging_buffer_offset + + (uniform_buffer_status.queued_buffer_writes.len() + * uniform_buffer_status.item_size); + if let Some(uniform_bytes) = + uniforms.get_uniform_bytes_ref(&field_info.uniform_name) + { + if size != uniform_bytes.len() { + panic!("The number of bytes produced for {} do not match the expected count. Actual: {}. Expected: {}.", field_info.uniform_name, uniform_bytes.len(), size); + } + + staging_buffer + [staging_buffer_start..(staging_buffer_start + uniform_bytes.len())] + .copy_from_slice(uniform_bytes); + } else if let Some(uniform_bytes) = + uniforms.get_uniform_bytes(field_info.uniform_name) + { + if size != uniform_bytes.len() { + panic!("The number of bytes produced for {} do not match the expected count. Actual: {}. Expected: {}.", field_info.uniform_name, uniform_bytes.len(), size); + } + + staging_buffer + [staging_buffer_start..(staging_buffer_start + uniform_bytes.len())] + .copy_from_slice(&uniform_bytes); + } else { + panic!( + "failed to get data from uniform: {}", + field_info.uniform_name + ); + }; + + uniform_buffer_status + .queued_buffer_writes + .push(QueuedBufferWrite { + buffer: target_buffer, + offset: target_offset, + }); + } + _ => {} + } + } + } + + fn copy_staging_buffer_to_final_buffers( + &mut self, + command_queue: &mut CommandQueue, + staging_buffer: RenderResource, + ) { + for uniform_buffer_status in self.uniform_arrays.iter_mut() { + if let Some((_name, buffer_array_status)) = uniform_buffer_status { + let start = buffer_array_status.staging_buffer_offset; + for (i, queued_buffer_write) in buffer_array_status + .queued_buffer_writes + .drain(..) + .enumerate() + { + command_queue.copy_buffer_to_buffer( + staging_buffer, + (start + (i * buffer_array_status.item_size)) as u64, + queued_buffer_write.buffer, + queued_buffer_write.offset as u64, + buffer_array_status.item_size as u64, + ) + } + } + } + } +} + +#[derive(Default)] +pub struct UniformNode +where + T: AsUniforms, +{ + command_queue: CommandQueue, + dynamic_uniforms: bool, + _marker: PhantomData, +} + +impl UniformNode +where + T: AsUniforms, +{ + pub fn new(dynamic_uniforms: bool) -> Self { + UniformNode { + command_queue: CommandQueue::default(), + dynamic_uniforms, + _marker: PhantomData::default(), + } + } + + fn initialize_vertex_buffer_descriptor( + vertex_buffer_descriptors: &mut VertexBufferDescriptors, + ) { + let vertex_buffer_descriptor = T::get_vertex_buffer_descriptor(); + if let Some(vertex_buffer_descriptor) = vertex_buffer_descriptor { + if let None = vertex_buffer_descriptors.get(&vertex_buffer_descriptor.name) { + vertex_buffer_descriptors.set(vertex_buffer_descriptor.clone()); + } + } + } + + fn setup_uniform_texture_resources( + uniforms: &T, + texture_storage: &AssetStorage, + render_resource_context: &dyn RenderResourceContext, + render_resource_assignments: &mut RenderResourceAssignments, + ) { + for field_info in T::get_field_infos().iter() { + let bind_type = uniforms.get_field_bind_type(&field_info.name); + match bind_type { + Some(FieldBindType::Texture) => { + let texture_handle = uniforms + .get_uniform_texture(&field_info.texture_name) + .unwrap(); + let (texture_resource, sampler_resource) = match render_resource_context + .get_asset_resource(texture_handle, texture::TEXTURE_ASSET_INDEX) + { + Some(texture_resource) => ( + texture_resource, + render_resource_context + .get_asset_resource(texture_handle, texture::SAMPLER_ASSET_INDEX) + .unwrap(), + ), + None => { + let texture = texture_storage.get(&texture_handle).unwrap(); + + let texture_descriptor: TextureDescriptor = texture.into(); + let texture_resource = + render_resource_context.create_texture(&texture_descriptor); + // TODO: queue texture copy + // .create_texture_with_data(&texture_descriptor, &texture.data); + + let sampler_descriptor: SamplerDescriptor = texture.into(); + let sampler_resource = + render_resource_context.create_sampler(&sampler_descriptor); + + render_resource_context.set_asset_resource( + texture_handle, + texture_resource, + 0, + ); + render_resource_context.set_asset_resource( + texture_handle, + sampler_resource, + 1, + ); + (texture_resource, sampler_resource) + } + }; + + render_resource_assignments.set(field_info.texture_name, texture_resource); + render_resource_assignments.set(field_info.sampler_name, sampler_resource); + } + _ => {} + } + } + } +} + +impl Node for UniformNode +where + T: AsUniforms, +{ + fn update( + &mut self, + _world: &World, + _resources: &Resources, + render_context: &mut dyn RenderContext, + _input: &ResourceSlots, + _output: &mut ResourceSlots, + ) { + self.command_queue.execute(render_context); + } +} + +impl SystemNode for UniformNode +where + T: AsUniforms, +{ + fn get_system(&self, resources: &mut Resources) -> Box { + let mut command_queue = self.command_queue.clone(); + let mut uniform_buffer_arrays = UniformBufferArrays::::new(); + let mut vertex_buffer_descriptors = resources.get_mut::().unwrap(); + let dynamic_uniforms = self.dynamic_uniforms; + let mut staging_buffer_resource = None; + UniformNode::::initialize_vertex_buffer_descriptor(&mut vertex_buffer_descriptors); + // TODO: maybe run "update" here + SystemBuilder::new("uniform_resource_provider") + .read_resource::>() + .read_resource::>() + .read_resource::() + // TODO: this write on RenderResourceAssignments will prevent this system from running in parallel with other systems that do the same + .with_query(<(Read, Read)>::query()) + .with_query(<(Read>, Read)>::query()) + .with_query(<(Read, Write)>::query()) + .with_query(<(Read>, Write)>::query()) + .build( + move |_, + world, + (assets, textures, global_render_resource_context), + ( + read_resource_query, + read_handle_query, + write_resource_query, + write_handle_query, + )| { + let render_resource_context = &*global_render_resource_context.context; + if let Some(staging_buffer_resource) = staging_buffer_resource { + render_resource_context.remove_buffer(staging_buffer_resource); + } + staging_buffer_resource = None; + + uniform_buffer_arrays.reset_new_item_counts(); + // update uniforms info + for (uniforms, renderable) in read_resource_query.iter(world) { + if !renderable.is_visible { + return; + } + + if renderable.is_instanced { + panic!("instancing not currently supported"); + } else { + uniform_buffer_arrays.increment_uniform_counts(&uniforms); + } + } + + // update uniform handles info + for (handle, renderable) in read_handle_query.iter(world) { + if !renderable.is_visible { + return; + } + + if renderable.is_instanced { + panic!("instancing not currently supported"); + } else { + let uniforms = assets + .get(&handle) + .expect("Handle points to a non-existent resource"); + // TODO: only increment count if we haven't seen this uniform handle before + uniform_buffer_arrays.increment_uniform_counts(&uniforms); + } + } + + uniform_buffer_arrays + .setup_buffer_arrays(render_resource_context, dynamic_uniforms); + let staging_buffer_size = uniform_buffer_arrays.update_staging_buffer_offsets(); + + for (uniforms, mut renderable) in write_resource_query.iter_mut(world) { + if !renderable.is_visible { + return; + } + + if renderable.is_instanced { + panic!("instancing not currently supported"); + } else { + Self::setup_uniform_texture_resources( + &uniforms, + textures, + render_resource_context, + &mut renderable.render_resource_assignments, + ) + } + } + + for (handle, mut renderable) in write_handle_query.iter_mut(world) { + if !renderable.is_visible { + return; + } + + if renderable.is_instanced { + panic!("instancing not currently supported"); + } else { + let uniforms = assets + .get(&handle) + .expect("Handle points to a non-existent resource"); + Self::setup_uniform_texture_resources( + &uniforms, + textures, + render_resource_context, + &mut renderable.render_resource_assignments, + ) + } + } + if staging_buffer_size == 0 { + let mut staging_buffer: [u8; 0] = []; + for (uniforms, mut renderable) in write_resource_query.iter_mut(world) { + if !renderable.is_visible { + return; + } + + if renderable.is_instanced { + panic!("instancing not currently supported"); + } else { + uniform_buffer_arrays.setup_uniform_buffer_resources( + &uniforms, + dynamic_uniforms, + render_resource_context, + &mut renderable.render_resource_assignments, + &mut staging_buffer, + ); + } + } + for (handle, mut renderable) in write_handle_query.iter_mut(world) { + if !renderable.is_visible { + return; + } + if renderable.is_instanced { + panic!("instancing not currently supported"); + } else { + let uniforms = assets + .get(&handle) + .expect("Handle points to a non-existent resource"); + // TODO: only setup buffer if we haven't seen this handle before + uniform_buffer_arrays.setup_uniform_buffer_resources( + &uniforms, + dynamic_uniforms, + render_resource_context, + &mut renderable.render_resource_assignments, + &mut staging_buffer, + ); + } + } + } else { + let staging_buffer = render_resource_context.create_buffer_mapped( + BufferInfo { + buffer_usage: BufferUsage::COPY_SRC, + size: staging_buffer_size, + ..Default::default() + }, + &mut |mut staging_buffer, _render_resources| { + for (uniforms, mut renderable) in + write_resource_query.iter_mut(world) + { + if !renderable.is_visible { + return; + } + + if renderable.is_instanced { + panic!("instancing not currently supported"); + } else { + uniform_buffer_arrays.setup_uniform_buffer_resources( + &uniforms, + dynamic_uniforms, + render_resource_context, + &mut renderable.render_resource_assignments, + &mut staging_buffer, + ); + } + } + for (handle, mut renderable) in write_handle_query.iter_mut(world) { + if !renderable.is_visible { + return; + } + if renderable.is_instanced { + panic!("instancing not currently supported"); + } else { + let uniforms = assets + .get(&handle) + .expect("Handle points to a non-existent resource"); + // TODO: only setup buffer if we haven't seen this handle before + uniform_buffer_arrays.setup_uniform_buffer_resources( + &uniforms, + dynamic_uniforms, + render_resource_context, + &mut renderable.render_resource_assignments, + &mut staging_buffer, + ); + } + } + }, + ); + + uniform_buffer_arrays.copy_staging_buffer_to_final_buffers( + &mut command_queue, + staging_buffer, + ); + + staging_buffer_resource = Some(staging_buffer); + } + }, + ) + } +} diff --git a/bevy_render/src/renderer_2/render_resource_context.rs b/bevy_render/src/renderer_2/render_resource_context.rs index 5021d1712e..3987ff0ca5 100644 --- a/bevy_render/src/renderer_2/render_resource_context.rs +++ b/bevy_render/src/renderer_2/render_resource_context.rs @@ -30,6 +30,7 @@ pub trait RenderResourceContext: Downcast + Send + Sync + 'static { fn create_sampler(&self, sampler_descriptor: &SamplerDescriptor) -> RenderResource; fn create_texture(&self, texture_descriptor: &TextureDescriptor) -> RenderResource; fn create_buffer(&self, buffer_info: BufferInfo) -> RenderResource; + // TODO: remove RenderResourceContext here fn create_buffer_mapped( &self, buffer_info: BufferInfo, diff --git a/bevy_render/src/shader/uniform.rs b/bevy_render/src/shader/uniform.rs index 8973f07e7b..8803e19e6a 100644 --- a/bevy_render/src/shader/uniform.rs +++ b/bevy_render/src/shader/uniform.rs @@ -10,7 +10,7 @@ use bevy_asset::{AssetStorage, Handle}; use bevy_core::bytes::GetBytes; use legion::prelude::*; -pub trait AsUniforms { +pub trait AsUniforms: Send + Sync + 'static { fn get_field_infos() -> &'static [FieldInfo]; fn get_uniform_bytes(&self, name: &str) -> Option>; fn get_uniform_texture(&self, name: &str) -> Option>; diff --git a/bevy_wgpu/src/wgpu_renderer.rs b/bevy_wgpu/src/wgpu_renderer.rs index d16cc9dfe0..229569d447 100644 --- a/bevy_wgpu/src/wgpu_renderer.rs +++ b/bevy_wgpu/src/wgpu_renderer.rs @@ -187,19 +187,20 @@ impl WgpuRenderer { pub fn run_graph(&mut self, world: &mut World, resources: &mut Resources) { // run systems - let mut executor = { + let mut system_executor = { let mut render_graph = resources.get_mut::().unwrap(); render_graph.take_executor() }; - if let Some(executor) = executor.as_mut() { + if let Some(executor) = system_executor.as_mut() { executor.execute(world, resources); } + update_shader_assignments(world, resources); render_resource_sets_system().run(world, resources); let mut render_graph = resources.get_mut::().unwrap(); - if let Some(executor) = executor.take() { + if let Some(executor) = system_executor.take() { render_graph.set_executor(executor); } @@ -207,12 +208,12 @@ impl WgpuRenderer { let mut stager = DependentNodeStager::loose_grouping(); let stages = stager.get_stages(&render_graph).unwrap(); let mut borrowed = stages.borrow(&mut render_graph); - + // execute stages - let executor = WgpuRenderGraphExecutor { + let graph_executor = WgpuRenderGraphExecutor { max_thread_count: 2, }; - executor.execute( + graph_executor.execute( world, resources, self.device.clone(), @@ -244,7 +245,6 @@ impl WgpuRenderer { self.update_resource_providers(world, resources, render_resource_context); - update_shader_assignments(world, resources, &render_context); self.create_queued_textures(resources, &mut render_context.render_resources); };