From 4d17763c8556a2cbb32fd0a11a520da4b4b333ab Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Tue, 24 Mar 2020 19:17:41 -0700 Subject: [PATCH] finish new uniform resource provider staging buffer. dynamic uniforms work again. both dynamic and non-dynamic uniforms perform better than the previous implementation. --- src/app/app_builder.rs | 4 +- src/render/render_resource/resource_info.rs | 36 +- .../camera2d_resource_provider.rs | 6 +- .../camera_resource_provider.rs | 6 +- .../light_resource_provider.rs | 13 +- .../render_resource/resource_providers/mod.rs | 2 - .../ui_resource_provider.rs | 5 +- .../uniform_resource_provider.rs | 957 ++++++++++-------- .../uniform_resource_provider_new.rs | 589 ----------- src/render/renderer/renderer.rs | 2 +- .../wgpu_renderer/wgpu_render_pass.rs | 10 +- .../renderers/wgpu_renderer/wgpu_renderer.rs | 33 +- .../renderers/wgpu_renderer/wgpu_resources.rs | 41 +- src/render/shader/uniform.rs | 8 +- src/render/shader/uniforms/local_to_world.rs | 2 +- 15 files changed, 620 insertions(+), 1094 deletions(-) delete mode 100644 src/render/render_resource/resource_providers/uniform_resource_provider_new.rs diff --git a/src/app/app_builder.rs b/src/app/app_builder.rs index da2fb8d00b..50a6799109 100644 --- a/src/app/app_builder.rs +++ b/src/app/app_builder.rs @@ -199,8 +199,8 @@ impl AppBuilder { .add_resource_provider(LightResourceProvider::new(10)) .add_resource_provider(UiResourceProvider::new()) .add_resource_provider(MeshResourceProvider::new()) - .add_resource_provider(UniformResourceProviderNew::::new(false)) - .add_resource_provider(UniformResourceProviderNew::::new(false)) + .add_resource_provider(UniformResourceProvider::::new(true)) + .add_resource_provider(UniformResourceProvider::::new(true)) .add_forward_pass() .add_forward_pipeline() .add_ui_pipeline(); diff --git a/src/render/render_resource/resource_info.rs b/src/render/render_resource/resource_info.rs index aeeee614b0..0db7f3c622 100644 --- a/src/render/render_resource/resource_info.rs +++ b/src/render/render_resource/resource_info.rs @@ -4,21 +4,39 @@ use std::collections::HashMap; #[derive(Default)] pub struct BufferArrayInfo { - pub item_count: u64, - pub item_size: u64, - pub item_capacity: u64, + pub item_count: usize, + pub item_size: usize, + pub item_capacity: usize, + pub indices: HashMap, + pub current_index: usize, } -#[derive(Default)] -pub struct BufferDynamicUniformInfo { - pub offsets: HashMap, +impl BufferArrayInfo { + pub fn get_index(&self, id: RenderResourceAssignmentsId) -> Option { + self.indices.get(&id).map(|offset| *offset) + } + + 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.item_capacity { + panic!("no empty slots available in array"); + } + + let index = self.current_index; + self.indices.insert(id, index); + self.current_index += 1; + index + } + } } pub struct BufferInfo { - pub size: u64, + pub size: usize, pub buffer_usage: BufferUsage, pub array_info: Option, - pub dynamic_uniform_info: Option, + pub is_dynamic: bool, } impl Default for BufferInfo { @@ -27,7 +45,7 @@ impl Default for BufferInfo { size: 0, buffer_usage: BufferUsage::NONE, array_info: None, - dynamic_uniform_info: None, + is_dynamic: false, } } } 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 434b663c50..f01a547095 100644 --- a/src/render/render_resource/resource_providers/camera2d_resource_provider.rs +++ b/src/render/render_resource/resource_providers/camera2d_resource_provider.rs @@ -20,7 +20,7 @@ impl ResourceProvider for Camera2dResourceProvider { _resources: &Resources, ) { let buffer = renderer.create_buffer(BufferInfo { - size: std::mem::size_of::<[[f32; 4]; 4]>() as u64, + size: std::mem::size_of::<[[f32; 4]; 4]>(), buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM, ..Default::default() }); @@ -50,11 +50,11 @@ impl ResourceProvider for Camera2dResourceProvider { self.tmp_buffer = Some(renderer.create_buffer_mapped( BufferInfo { - size: matrix_size as u64, + size: matrix_size, buffer_usage: BufferUsage::COPY_SRC, ..Default::default() }, - &mut |data| { + &mut |data, _renderer| { data[0..matrix_size].copy_from_slice(camera_matrix.as_bytes()); }, )); 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 e3018b740d..d2f2b725b8 100644 --- a/src/render/render_resource/resource_providers/camera_resource_provider.rs +++ b/src/render/render_resource/resource_providers/camera_resource_provider.rs @@ -21,7 +21,7 @@ impl ResourceProvider for CameraResourceProvider { _resources: &Resources, ) { let buffer = renderer.create_buffer(BufferInfo { - size: std::mem::size_of::<[[f32; 4]; 4]>() as u64, + size: std::mem::size_of::<[[f32; 4]; 4]>(), buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM, ..Default::default() }); @@ -54,11 +54,11 @@ impl ResourceProvider for CameraResourceProvider { self.tmp_buffer = Some(renderer.create_buffer_mapped( BufferInfo { - size: matrix_size as u64, + size: matrix_size, buffer_usage: BufferUsage::COPY_SRC, ..Default::default() }, - &mut |data| { + &mut |data, _renderer| { data[0..matrix_size].copy_from_slice(camera_matrix.as_bytes()); }, )); 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 1074f60bb0..bd9f70c89f 100644 --- a/src/render/render_resource/resource_providers/light_resource_provider.rs +++ b/src/render/render_resource/resource_providers/light_resource_provider.rs @@ -40,9 +40,8 @@ impl ResourceProvider for LightResourceProvider { _world: &mut World, _resources: &Resources, ) { - let light_uniform_size = (std::mem::size_of::() - + self.max_lights * std::mem::size_of::()) - as u64; + let light_uniform_size = + std::mem::size_of::() + self.max_lights * std::mem::size_of::(); let buffer = renderer.create_buffer(BufferInfo { size: light_uniform_size, @@ -79,11 +78,11 @@ impl ResourceProvider for LightResourceProvider { self.tmp_light_buffer = Some(renderer.create_buffer_mapped( BufferInfo { - size: total_size as u64, + size: total_size, buffer_usage: BufferUsage::COPY_SRC, ..Default::default() }, - &mut |data| { + &mut |data, _renderer| { for ((light, local_to_world, translation), slot) in light_query.iter(world).zip(data.chunks_exact_mut(size)) { @@ -95,11 +94,11 @@ impl ResourceProvider for LightResourceProvider { )); self.tmp_count_buffer = Some(renderer.create_buffer_mapped( BufferInfo { - size: light_count_size as u64, + size: light_count_size, buffer_usage: BufferUsage::COPY_SRC, ..Default::default() }, - &mut |data| { + &mut |data, _renderer| { data.copy_from_slice([light_count as u32, 0, 0, 0].as_bytes()); }, )); diff --git a/src/render/render_resource/resource_providers/mod.rs b/src/render/render_resource/resource_providers/mod.rs index bda54c6668..855535e8da 100644 --- a/src/render/render_resource/resource_providers/mod.rs +++ b/src/render/render_resource/resource_providers/mod.rs @@ -5,7 +5,6 @@ mod light_resource_provider; mod mesh_resource_provider; mod ui_resource_provider; mod uniform_resource_provider; -mod uniform_resource_provider_new; pub use camera2d_resource_provider::*; pub use camera_resource_provider::*; @@ -14,4 +13,3 @@ pub use light_resource_provider::*; pub use mesh_resource_provider::*; pub use ui_resource_provider::*; pub use uniform_resource_provider::*; -pub use uniform_resource_provider_new::*; 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 1c8be2624e..82df680c9b 100644 --- a/src/render/render_resource/resource_providers/ui_resource_provider.rs +++ b/src/render/render_resource/resource_providers/ui_resource_provider.rs @@ -77,8 +77,8 @@ impl UiResourceProvider { return; } - let size = std::mem::size_of::() as u64; - let data_len = data.len() as u64; + let size = std::mem::size_of::(); + let data_len = data.len(); if let Some(old_instance_buffer) = self.instance_buffer { renderer.remove_buffer(old_instance_buffer); @@ -92,6 +92,7 @@ impl UiResourceProvider { item_capacity: data_len, item_count: data_len, item_size: size, + ..Default::default() }), ..Default::default() }, 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 68792a56a9..278d5d0285 100644 --- a/src/render/render_resource/resource_providers/uniform_resource_provider.rs +++ b/src/render/render_resource/resource_providers/uniform_resource_provider.rs @@ -1,100 +1,168 @@ use crate::{ asset::{AssetStorage, Handle}, render::{ - pipeline::BindType, render_graph::RenderGraph, render_resource::{ - AssetBatchers, BufferArrayInfo, BufferDynamicUniformInfo, BufferInfo, BufferUsage, - RenderResource, RenderResourceAssignments, RenderResourceAssignmentsId, - RenderResourceAssignmentsProvider, ResourceInfo, ResourceProvider, + AssetBatchers, BufferArrayInfo, BufferInfo, BufferUsage, RenderResource, + RenderResourceAssignments, RenderResourceAssignmentsProvider, ResourceInfo, + ResourceProvider, }, renderer::Renderer, - shader::{AsUniforms, UniformInfoIter}, + shader::{AsUniforms, FieldBindType}, texture::{SamplerDescriptor, Texture, TextureDescriptor}, Renderable, }, }; use legion::{filter::*, prelude::*}; -use std::{ - collections::{HashMap, HashSet}, - marker::PhantomData, - ops::Deref, -}; -pub const BIND_BUFFER_ALIGNMENT: u64 = 256; +use std::marker::PhantomData; +pub const BIND_BUFFER_ALIGNMENT: usize = 256; + +#[derive(Debug)] +struct BufferArrayStatus { + new_item_count: usize, + item_size: usize, + aligned_size: usize, + staging_buffer_offset: usize, + queued_buffer_writes: Vec, + buffer: Option, +} + +#[derive(Debug)] +struct QueuedBufferWrite { + buffer: RenderResource, + offset: usize, +} + +type UniformQuery = Query< + (Read, Write), + EntityFilterTuple< + And<(ComponentFilter, ComponentFilter)>, + And<(Passthrough, Passthrough)>, + And<(Passthrough, Passthrough)>, + >, +>; + +type UniformHandleQuery = Query< + (Read>, Write), + EntityFilterTuple< + And<(ComponentFilter>, ComponentFilter)>, + And<(Passthrough, Passthrough)>, + And<(Passthrough, Passthrough)>, + >, +>; pub struct UniformResourceProvider where T: AsUniforms + Send + Sync + 'static, { _marker: PhantomData, + use_dynamic_uniforms: bool, + is_instanceable: bool, // PERF: somehow remove this HashSet - uniform_buffer_info_resources: HashMap< - String, - ( - Option, - usize, - HashSet, - ), - >, - asset_resources: HashMap, HashMap>, - resource_query: Query< - (Read, Write), - EntityFilterTuple< - And<(ComponentFilter, ComponentFilter)>, - And<(Passthrough, Passthrough)>, - And<(Passthrough, Passthrough)>, - >, - >, - handle_query: Option< - Query< - (Read>, Write), - EntityFilterTuple< - And<(ComponentFilter>, ComponentFilter)>, - And<(Passthrough, Passthrough)>, - And<(Passthrough, Passthrough)>, - >, - >, - >, + uniform_buffer_status: Vec>, + instance_buffer_status: Option, + query: Option>, + query_finish: Option>, + handle_query: Option>, + handle_query_finish: Option>, } impl UniformResourceProvider where T: AsUniforms + Send + Sync + 'static, { - pub fn new() -> Self { + pub fn new(use_dynamic_uniforms: bool) -> Self { + let mut dynamic_uniform_buffer_status = Vec::new(); + let field_infos = T::get_field_infos(); + dynamic_uniform_buffer_status.resize_with(field_infos.len(), || None); + let is_instanceable = field_infos.iter().find(|f| f.is_instanceable).is_some(); UniformResourceProvider { - uniform_buffer_info_resources: Default::default(), - asset_resources: Default::default(), - _marker: PhantomData, - resource_query: <(Read, Write)>::query(), + uniform_buffer_status: dynamic_uniform_buffer_status, + use_dynamic_uniforms, + instance_buffer_status: None, + is_instanceable, + query: Some(<(Read, Write)>::query()), + query_finish: Some(<(Read, Write)>::query()), handle_query: Some(<(Read>, Write)>::query()), + handle_query_finish: Some(<(Read>, Write)>::query()), + _marker: PhantomData, } } - fn update_asset_uniforms( - &mut self, - renderer: &mut dyn Renderer, - world: &mut World, - resources: &Resources, - ) { - let handle_query = self.handle_query.take().unwrap(); - let mut asset_batchers = resources.get_mut::().unwrap(); - // TODO: only update handle values when Asset value has changed - if let Some(asset_storage) = resources.get::>() { - for (entity, (handle, mut renderable)) in handle_query.iter_entities_mut(world) { - if renderable.is_instanced { - asset_batchers.set_entity_handle(entity, *handle); + fn reset_buffer_array_status_counts(&mut self) { + for buffer_status in self.uniform_buffer_status.iter_mut() { + if let Some((_name, buffer_status)) = buffer_status { + buffer_status.new_item_count = 0; + } + } + + if let Some(ref mut buffer_status) = self.instance_buffer_status { + buffer_status.new_item_count = 0; + } + } + + fn update_uniforms_info(&mut self, world: &mut World) { + let query = self.query.take().unwrap(); + for (uniforms, mut renderable) in query.iter_mut(world) { + if !renderable.is_visible { + return; + } + + if renderable.is_instanced { + if self.is_instanceable { + self.increment_instance_count(|| Self::get_instance_size(&uniforms)); } else { - if let Some(uniforms) = asset_storage.get(&handle) { - self.setup_uniform_resources( - uniforms, - renderer, - resources, - renderable.render_resource_assignments.as_mut().unwrap(), - true, - Some(*handle), - ) + panic!( + "Cannot instance uniforms of type {}", + std::any::type_name::() + ); + } + } else { + self.increment_uniform_counts(&uniforms); + } + + Self::update_shader_defs( + &uniforms, + renderable.render_resource_assignments.as_mut().unwrap(), + ); + } + + self.query = Some(query); + } + + fn update_handles_info(&mut self, world: &mut World, resources: &Resources) { + let handle_query = self.handle_query.take().unwrap(); + let assets = resources.get::>(); + let mut asset_batchers = resources.get_mut::().unwrap(); + if let Some(assets) = assets { + for (entity, (handle, mut renderable)) in handle_query.iter_entities_mut(world) { + if !renderable.is_visible { + return; + } + + if renderable.is_instanced { + if self.is_instanceable { + asset_batchers.set_entity_handle(entity, *handle); + self.increment_instance_count(|| { + let uniforms = assets.get(&handle).unwrap(); + Self::get_instance_size(uniforms) + }); + } else { + panic!( + "Cannot instance uniforms of type Handle<{}>", + std::any::type_name::() + ); } + } else { + let uniforms = assets + .get(&handle) + .expect("Handle points to a non-existent resource"); + Self::update_shader_defs( + uniforms, + renderable.render_resource_assignments.as_mut().unwrap(), + ); + + self.increment_uniform_counts(&uniforms); } } } @@ -102,432 +170,274 @@ where self.handle_query = Some(handle_query); } + fn increment_instance_count(&mut self, f: impl Fn() -> usize) { + if let Some(ref mut buffer_array_status) = self.instance_buffer_status { + buffer_array_status.new_item_count += 1; + } else { + self.instance_buffer_status = Some(BufferArrayStatus { + new_item_count: 1, + queued_buffer_writes: Vec::new(), + aligned_size: 0, + item_size: f(), + staging_buffer_offset: 0, + buffer: None, + }) + } + } + + fn get_instance_size(uniforms: &T) -> usize { + let mut instance_buffer_size = 0; + for field_info in T::get_field_infos().iter() { + if field_info.is_instanceable { + if let Some(FieldBindType::Uniform { size }) = + uniforms.get_field_bind_type(field_info.name) + { + instance_buffer_size += size; + } + } + } + + instance_buffer_size + } + + 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_buffer_status[i] + { + buffer_array_status.new_item_count += 1; + } else { + self.uniform_buffer_status[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, + }, + )) + } + } + } + } + + 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 update_shader_defs( + uniforms: &T, + render_resource_assignments: &mut RenderResourceAssignments, + ) { + if let Some(shader_defs) = uniforms.get_shader_defs() { + for shader_def in shader_defs { + render_resource_assignments.shader_defs.insert(shader_def); + } + } + } + fn setup_uniform_resources( &mut self, uniforms: &T, renderer: &mut dyn Renderer, resources: &Resources, render_resource_assignments: &mut RenderResourceAssignments, - dynamic_unforms: bool, - asset_handle: Option>, + staging_buffer: &mut [u8], ) { - for uniform_info in UniformInfoIter::new(uniforms.deref()) { - match uniform_info.bind_type { - BindType::Uniform { .. } => { - if dynamic_unforms { - if let None = self.uniform_buffer_info_resources.get(uniform_info.name) { - self.uniform_buffer_info_resources - .insert(uniform_info.name.to_string(), (None, 0, HashSet::new())); + 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_buffer_status[i].as_mut().unwrap(); + let (target_buffer, target_offset) = if self.use_dynamic_uniforms { + let buffer = uniform_buffer_status.buffer.unwrap(); + if let Some(ResourceInfo::Buffer(BufferInfo { + array_info: Some(ref mut array_info), + is_dynamic: true, + .. + })) = renderer.get_resource_info_mut(buffer) + { + let index = array_info + .get_or_assign_index(render_resource_assignments.get_id()); + render_resource_assignments.set(&field_info.uniform_name, buffer); + (buffer, index * uniform_buffer_status.aligned_size) + } else { + panic!("Expected a dynamic uniform buffer"); } - - let (_resource, counts, render_resource_assignments_ids) = self - .uniform_buffer_info_resources - .get_mut(uniform_info.name) - .unwrap(); - render_resource_assignments_ids - .insert(render_resource_assignments.get_id()); - *counts += 1; } else { - let handle = asset_handle.expect( - "non-dynamic uniform currently only works with Handle types", - ); - if let None = self.asset_resources.get(&handle) { - self.asset_resources.insert(handle, HashMap::new()); - } - - let resources = self.asset_resources.get_mut(&handle).unwrap(); - - let render_resource = match resources.get(uniform_info.name) { - Some(render_resource) => *render_resource, + let resource = match render_resource_assignments + .get(field_info.uniform_name) + { + Some(render_resource) => render_resource, None => { - // let size = uniform_info.bind_type.get_uniform_size().unwrap(); - // TODO: get actual size here - let size = BIND_BUFFER_ALIGNMENT; let resource = renderer.create_buffer(BufferInfo { size, buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM, ..Default::default() }); - resources.insert(uniform_info.name.to_string(), resource); + render_resource_assignments.set(&field_info.uniform_name, resource); resource } }; - render_resource_assignments.set(uniform_info.name, render_resource); + (resource, 0) + }; - let (tmp_buffer, tmp_buffer_size) = if let Some(uniform_bytes) = - uniforms.get_uniform_bytes_ref(uniform_info.name) - { - ( - renderer.create_buffer_mapped( - BufferInfo { - size: uniform_bytes.len() as u64, - buffer_usage: BufferUsage::COPY_SRC, - ..Default::default() - }, - &mut |mapped| { - mapped.copy_from_slice(uniform_bytes); - }, - ), - uniform_bytes.len(), - ) - } else if let Some(uniform_bytes) = - uniforms.get_uniform_bytes(uniform_info.name) - { - ( - renderer.create_buffer_mapped( - BufferInfo { - size: uniform_bytes.len() as u64, - buffer_usage: BufferUsage::COPY_SRC, - ..Default::default() - }, - &mut |mapped| { - mapped.copy_from_slice(&uniform_bytes); - }, - ), - uniform_bytes.len(), - ) - } else { - panic!("failed to get data from uniform: {}", uniform_info.name); - }; + 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); + } - renderer.copy_buffer_to_buffer( - tmp_buffer, - 0, - render_resource, - 0, - tmp_buffer_size as u64, + 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 ); + }; - renderer.remove_buffer(tmp_buffer); - } + uniform_buffer_status + .queued_buffer_writes + .push(QueuedBufferWrite { + buffer: target_buffer, + offset: target_offset, + }); } - BindType::SampledTexture { .. } => { - let texture_handle = uniforms.get_uniform_texture(&uniform_info.name).unwrap(); - let resource = match renderer + Some(FieldBindType::Texture) => { + let texture_handle = uniforms + .get_uniform_texture(&field_info.texture_name) + .unwrap(); + let (texture_resource, sampler_resource) = match renderer .get_render_resources() .get_texture_resource(texture_handle) { - Some(resource) => resource, + Some(texture_resource) => ( + texture_resource, + renderer + .get_render_resources() + .get_texture_sampler_resource(texture_handle) + .unwrap(), + ), None => { let storage = resources.get::>().unwrap(); let texture = storage.get(&texture_handle).unwrap(); - let descriptor: TextureDescriptor = texture.into(); - let resource = - renderer.create_texture(&descriptor, Some(&texture.data)); - renderer - .get_render_resources_mut() - .set_texture_resource(texture_handle, resource); - resource + + let texture_descriptor: TextureDescriptor = texture.into(); + let texture_resource = + renderer.create_texture(&texture_descriptor, Some(&texture.data)); + + let sampler_descriptor: SamplerDescriptor = texture.into(); + let sampler_resource = renderer.create_sampler(&sampler_descriptor); + + let render_resources = renderer.get_render_resources_mut(); + render_resources.set_texture_resource(texture_handle, texture_resource); + render_resources + .set_texture_sampler_resource(texture_handle, sampler_resource); + (texture_resource, sampler_resource) } }; - render_resource_assignments.set(uniform_info.name, resource); + render_resource_assignments.set(field_info.texture_name, texture_resource); + render_resource_assignments.set(field_info.sampler_name, sampler_resource); } - BindType::Sampler { .. } => { - let texture_handle = uniforms.get_uniform_texture(&uniform_info.name).unwrap(); - let resource = match renderer - .get_render_resources() - .get_texture_sampler_resource(texture_handle) - { - Some(resource) => resource, - None => { - let storage = resources.get::>().unwrap(); - let texture = storage.get(&texture_handle).unwrap(); - let descriptor: SamplerDescriptor = texture.into(); - let resource = renderer.create_sampler(&descriptor); - renderer - .get_render_resources_mut() - .set_texture_sampler_resource(texture_handle, resource); - resource - } - }; - - render_resource_assignments.set(uniform_info.name, resource); - } - _ => panic!( - "encountered unsupported bind_type {:?}", - uniform_info.bind_type - ), + None => {} } } } - fn setup_dynamic_uniform_buffers( + fn setup_uniforms_resources( &mut self, - renderer: &mut dyn Renderer, world: &mut World, resources: &Resources, - ) { - // allocate uniform buffers - for (name, (resource, count, _entities)) in self.uniform_buffer_info_resources.iter_mut() { - let count = *count as u64; - if let Some(resource) = resource { - if let Some(ResourceInfo::Buffer(BufferInfo { - array_info: Some(array_info), - .. - })) = renderer.get_resource_info_mut(*resource) - { - array_info.item_count = count; - continue; - } - } - - // allocate enough space for twice as many entities as there are currently; - let capacity = count * 2; - let size = BIND_BUFFER_ALIGNMENT * capacity; - let created_resource = renderer.create_buffer(BufferInfo { - size, - buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM, - array_info: Some(BufferArrayInfo { - item_capacity: capacity, - item_count: count, - item_size: BIND_BUFFER_ALIGNMENT, - }), - dynamic_uniform_info: Some(BufferDynamicUniformInfo::default()), - ..Default::default() - }); - - *resource = Some(created_resource); - renderer - .get_render_resources_mut() - .set_named_resource(name, created_resource); - } - - // copy entity uniform data to buffers - // PERF: consider iter_chunks here and calling get_bytes() on each chunk? - for (name, (resource, count, entities)) in self.uniform_buffer_info_resources.iter() { - let resource = resource.unwrap(); - let resource_info = renderer.get_resource_info_mut(resource); - if let Some(ResourceInfo::Buffer(BufferInfo { - dynamic_uniform_info: Some(dynamic_uniform_info), - .. - })) = resource_info - { - // TODO: properly handle alignments > BIND_BUFFER_ALIGNMENT - let size = BIND_BUFFER_ALIGNMENT * *count as u64; - let alignment = BIND_BUFFER_ALIGNMENT as usize; - let mut offset = 0usize; - // TODO: check if index has changed. if it has, then entity should be updated - // TODO: only mem-map entities if their data has changed - // PERF: These hashmap inserts are pretty expensive (10 fps for 10000 entities) - for (_, renderable) in self.resource_query.iter_mut(world) { - if renderable.is_instanced { - continue; - } - - let id = renderable - .render_resource_assignments - .as_ref() - .unwrap() - .get_id(); - - // this unwrap is safe because the assignments were created in the calling function - if !entities.contains(&id) { - continue; - } - - dynamic_uniform_info.offsets.insert(id, offset as u32); - - offset += alignment; - } - - for (_, renderable) in self.handle_query.as_ref().unwrap().iter_mut(world) { - if renderable.is_instanced { - continue; - } - - dynamic_uniform_info.offsets.insert( - renderable - .render_resource_assignments - .as_ref() - .unwrap() - .get_id(), - offset as u32, - ); - - offset += alignment; - } - - // TODO: check if index has changed. if it has, then entity should be updated - // TODO: only mem-map entities if their data has changed - let mapped_buffer_resource = renderer.create_buffer_mapped( - BufferInfo { - size, - buffer_usage: BufferUsage::COPY_SRC, - ..Default::default() - }, - &mut |mapped| { - let alignment = BIND_BUFFER_ALIGNMENT as usize; - let mut offset = 0usize; - for (uniforms, renderable) in self.resource_query.iter_mut(world) { - if renderable.is_instanced { - continue; - } - - if !entities.contains( - &renderable - .render_resource_assignments - .as_ref() - .unwrap() - .get_id(), - ) { - continue; - } - if let Some(uniform_bytes) = uniforms.get_uniform_bytes_ref(&name) { - mapped[offset..(offset + uniform_bytes.len())] - .copy_from_slice(uniform_bytes); - offset += alignment; - } else if let Some(uniform_bytes) = uniforms.get_uniform_bytes(&name) { - mapped[offset..(offset + uniform_bytes.len())] - .copy_from_slice(uniform_bytes.as_slice()); - offset += alignment; - } - } - - if let Some(asset_storage) = resources.get::>() { - for (handle, renderable) in - self.handle_query.as_ref().unwrap().iter_mut(world) - { - if renderable.is_instanced { - continue; - } - - if !entities.contains( - &renderable - .render_resource_assignments - .as_ref() - .unwrap() - .get_id(), - ) { - continue; - } - - let uniforms = asset_storage.get(&handle).unwrap(); - if let Some(uniform_bytes) = uniforms.get_uniform_bytes_ref(&name) { - mapped[offset..(offset + uniform_bytes.len())] - .copy_from_slice(uniform_bytes); - offset += alignment; - } else if let Some(uniform_bytes) = - uniforms.get_uniform_bytes(&name) - { - mapped[offset..(offset + uniform_bytes.len())] - .copy_from_slice(uniform_bytes.as_slice()); - offset += alignment; - } - } - } - }, - ); - - renderer.copy_buffer_to_buffer(mapped_buffer_resource, 0, resource, 0, size); - renderer.remove_buffer(mapped_buffer_resource); - } - } - } - - fn initialize_vertex_buffer_descriptor(&self, render_graph: &mut RenderGraph) { - let vertex_buffer_descriptor = T::get_vertex_buffer_descriptor(); - if let Some(vertex_buffer_descriptor) = vertex_buffer_descriptor { - if let None = render_graph.get_vertex_buffer_descriptor(&vertex_buffer_descriptor.name) - { - render_graph.set_vertex_buffer_descriptor(vertex_buffer_descriptor.clone()); - } - } - } -} - -impl ResourceProvider for UniformResourceProvider -where - T: AsUniforms + Send + Sync + 'static, -{ - fn initialize( - &mut self, renderer: &mut dyn Renderer, - world: &mut World, - resources: &Resources, + staging_buffer: &mut [u8], ) { - let mut render_graph = resources.get_mut::().unwrap(); - self.initialize_vertex_buffer_descriptor(&mut render_graph); - self.update(renderer, world, resources); - } - - fn update(&mut self, renderer: &mut dyn Renderer, world: &mut World, resources: &Resources) { - // TODO: this breaks down in multiple ways: - // (SOLVED 1) resource_info will be set after the first run so this won't update. - // (2) if we create new buffers, the old bind groups will be invalid - - // reset all uniform buffer info counts - let query = <(Read, Write)>::query(); - for (_name, (resource, count, _entities)) in self.uniform_buffer_info_resources.iter_mut() { - if let Some(ResourceInfo::Buffer(BufferInfo { - array_info: Some(array_info), - .. - })) = renderer.get_resource_info_mut(resource.unwrap()) - { - array_info.item_count = 0; + let query_finish = self.query_finish.take().unwrap(); + for (uniforms, mut renderable) in query_finish.iter_mut(world) { + if !renderable.is_visible { + return; } - *count = 0; - } - - self.update_asset_uniforms(renderer, world, resources); - - for (uniforms, mut renderable) in query.iter_mut(world) { if renderable.is_instanced { - continue; - } - - self.setup_uniform_resources( - &uniforms, - renderer, - resources, - renderable.render_resource_assignments.as_mut().unwrap(), - true, - None, - ); - } - - self.setup_dynamic_uniform_buffers(renderer, world, resources); - - // update shader assignments based on current macro defs - for (uniforms, mut renderable) in <(Read, Write)>::query().iter_mut(world) { - if let Some(shader_defs) = uniforms.get_shader_defs() { - for shader_def in shader_defs { - renderable - .render_resource_assignments - .as_mut() - .unwrap() - .shader_defs - .insert(shader_def); - } + panic!( + "Cannot instance uniforms of type {0}. Only Handle<{0}> can be instanced.", + std::any::type_name::() + ); + } else { + self.setup_uniform_resources( + &uniforms, + renderer, + resources, + renderable.render_resource_assignments.as_mut().unwrap(), + staging_buffer, + ) } } - if let Some(asset_storage) = resources.get::>() { - for (handle, mut renderable) in - <(Read>, Write)>::query().iter_mut(world) - { - let uniforms = asset_storage.get(&handle).unwrap(); - if let Some(shader_defs) = uniforms.get_shader_defs() { - for shader_def in shader_defs { - renderable - .render_resource_assignments - .as_mut() - .unwrap() - .shader_defs - .insert(shader_def); - } + self.query_finish = Some(query_finish); + } + + fn setup_handles_resources( + &mut self, + world: &mut World, + resources: &Resources, + renderer: &mut dyn Renderer, + staging_buffer: &mut [u8], + ) { + let assets = resources.get::>(); + if let Some(assets) = assets { + let handle_query_finish = self.handle_query_finish.take().unwrap(); + for (handle, mut renderable) in handle_query_finish.iter_mut(world) { + if !renderable.is_visible || renderable.is_instanced { + return; } + + let uniforms = assets + .get(&handle) + .expect("Handle points to a non-existent resource"); + self.setup_uniform_resources( + &uniforms, + renderer, + resources, + renderable.render_resource_assignments.as_mut().unwrap(), + staging_buffer, + ) } + + self.handle_query_finish = Some(handle_query_finish); } } - fn finish_update( + #[allow(dead_code)] + fn setup_batched_resources( &mut self, - renderer: &mut dyn Renderer, _world: &mut World, resources: &Resources, + renderer: &mut dyn Renderer, + staging_buffer: &mut [u8], ) { // update batch resources. this needs to run in "finish_update" because batches aren't finalized across // all members of the batch until "UniformResourceProvider.update" has run for all members of the batch @@ -554,11 +464,186 @@ where renderer, resources, render_resource_assignments, - false, - Some(handle), + staging_buffer, ); + + Self::update_shader_defs(&uniforms, render_resource_assignments); + } + } + } + } + + 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 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 = + Vec::with_capacity(buffer_array_status.new_item_count); + } + } + + if let Some(ref mut buffer_array_status) = self.instance_buffer_status { + Self::setup_buffer_array(buffer_array_status, renderer, false); + } + } + + fn setup_buffer_array( + buffer_array_status: &mut BufferArrayStatus, + renderer: &mut dyn Renderer, + align: bool, + ) { + let new_capacity = if let Some(buffer) = buffer_array_status.buffer { + if let Some(ResourceInfo::Buffer(BufferInfo { + array_info: Some(array_info), + .. + })) = renderer.get_resource_info_mut(buffer) + { + 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) + } + } else { + // buffer does not exist. create it now. + Some(buffer_array_status.new_item_count) + }; + + if let Some(new_capacity) = new_capacity { + println!("creating buffer {}", new_capacity); + let mut item_size = buffer_array_status.item_size; + if align { + item_size = Self::get_aligned_dynamic_uniform_size(item_size); + } + + let buffer = renderer.create_buffer(BufferInfo { + array_info: Some(BufferArrayInfo { + item_capacity: new_capacity, + item_count: buffer_array_status.new_item_count, + item_size, + ..Default::default() + }), + size: item_size * new_capacity, + buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM, + is_dynamic: true, + }); + + buffer_array_status.buffer = Some(buffer); + } + } + + fn initialize_vertex_buffer_descriptor(&self, render_graph: &mut RenderGraph) { + let vertex_buffer_descriptor = T::get_vertex_buffer_descriptor(); + if let Some(vertex_buffer_descriptor) = vertex_buffer_descriptor { + if let None = render_graph.get_vertex_buffer_descriptor(&vertex_buffer_descriptor.name) + { + render_graph.set_vertex_buffer_descriptor(vertex_buffer_descriptor.clone()); + } + } + } + + fn update_staging_buffer_offsets(&mut self) -> usize { + let mut size = 0; + for dynamic_buffer_array_status in self.uniform_buffer_status.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 copy_staging_buffer_to_final_buffers( + &mut self, + renderer: &mut dyn Renderer, + staging_buffer: RenderResource, + ) { + for uniform_buffer_status in self.uniform_buffer_status.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() + { + renderer.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, + ) } } } } } + +impl ResourceProvider for UniformResourceProvider +where + T: AsUniforms + Send + Sync + 'static, +{ + fn initialize( + &mut self, + renderer: &mut dyn Renderer, + world: &mut World, + resources: &Resources, + ) { + let mut render_graph = resources.get_mut::().unwrap(); + self.initialize_vertex_buffer_descriptor(&mut render_graph); + self.update(renderer, world, resources); + } + + fn update(&mut self, _renderer: &mut dyn Renderer, world: &mut World, resources: &Resources) { + self.reset_buffer_array_status_counts(); + self.update_uniforms_info(world); + self.update_handles_info(world, resources); + } + + fn finish_update( + &mut self, + renderer: &mut dyn Renderer, + world: &mut World, + resources: &Resources, + ) { + // TODO: when setting batch shader_defs, add INSTANCING + self.setup_buffer_arrays(renderer); + + let staging_buffer_size = self.update_staging_buffer_offsets(); + if staging_buffer_size == 0 { + 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); + } else { + let staging_buffer = renderer.create_buffer_mapped( + BufferInfo { + buffer_usage: BufferUsage::COPY_SRC, + size: staging_buffer_size, + ..Default::default() + }, + &mut |staging_buffer, renderer| { + self.setup_uniforms_resources(world, resources, renderer, staging_buffer); + self.setup_handles_resources(world, resources, renderer, staging_buffer); + // self.setup_batched_resources(world, resources, renderer, staging_buffer); + }, + ); + + self.copy_staging_buffer_to_final_buffers(renderer, staging_buffer) + } + } +} diff --git a/src/render/render_resource/resource_providers/uniform_resource_provider_new.rs b/src/render/render_resource/resource_providers/uniform_resource_provider_new.rs deleted file mode 100644 index 13afb33a2d..0000000000 --- a/src/render/render_resource/resource_providers/uniform_resource_provider_new.rs +++ /dev/null @@ -1,589 +0,0 @@ -use crate::{ - asset::{AssetStorage, Handle}, - render::{ - render_graph::RenderGraph, - render_resource::{ - AssetBatchers, BufferArrayInfo, BufferDynamicUniformInfo, BufferInfo, BufferUsage, - RenderResource, RenderResourceAssignments, RenderResourceAssignmentsProvider, - ResourceInfo, ResourceProvider, - }, - renderer::Renderer, - shader::{AsUniforms, FieldBindType}, - texture::{SamplerDescriptor, Texture, TextureDescriptor}, - Renderable, - }, -}; -use legion::{filter::*, prelude::*}; -use std::marker::PhantomData; -pub const BIND_BUFFER_ALIGNMENT: u64 = 256; - -#[derive(Debug)] -struct BufferArrayStatus { - new_item_count: usize, - item_size: usize, - staging_buffer_offset: usize, - buffer: Option, -} - -pub struct UniformResourceProviderNew -where - T: AsUniforms + Send + Sync + 'static, -{ - _marker: PhantomData, - use_dynamic_uniforms: bool, - is_instanceable: bool, - // PERF: somehow remove this HashSet - dynamic_uniform_buffer_status: Vec>, - instance_buffer_status: Option, - query: Option< - Query< - (Read, Write), - EntityFilterTuple< - And<(ComponentFilter, ComponentFilter)>, - And<(Passthrough, Passthrough)>, - And<(Passthrough, Passthrough)>, - >, - >, - >, - query_finish: Option< - Query< - (Read, Write), - EntityFilterTuple< - And<(ComponentFilter, ComponentFilter)>, - And<(Passthrough, Passthrough)>, - And<(Passthrough, Passthrough)>, - >, - >, - >, - handle_query: Option< - Query< - (Read>, Write), - EntityFilterTuple< - And<(ComponentFilter>, ComponentFilter)>, - And<(Passthrough, Passthrough)>, - And<(Passthrough, Passthrough)>, - >, - >, - >, - handle_query_finish: Option< - Query< - (Read>, Write), - EntityFilterTuple< - And<(ComponentFilter>, ComponentFilter)>, - And<(Passthrough, Passthrough)>, - And<(Passthrough, Passthrough)>, - >, - >, - >, -} - -impl UniformResourceProviderNew -where - T: AsUniforms + Send + Sync + 'static, -{ - pub fn new(use_dynamic_uniforms: bool) -> Self { - let mut dynamic_uniform_buffer_status = Vec::new(); - let field_infos = T::get_field_infos(); - dynamic_uniform_buffer_status.resize_with(field_infos.len(), || None); - let is_instanceable = field_infos.iter().find(|f| f.is_instanceable).is_some(); - UniformResourceProviderNew { - dynamic_uniform_buffer_status, - use_dynamic_uniforms, - instance_buffer_status: None, - is_instanceable, - query: Some(<(Read, Write)>::query()), - query_finish: Some(<(Read, Write)>::query()), - handle_query: Some(<(Read>, Write)>::query()), - handle_query_finish: Some(<(Read>, Write)>::query()), - _marker: PhantomData, - } - } - - fn reset_buffer_array_status_counts(&mut self) { - for buffer_status in self.dynamic_uniform_buffer_status.iter_mut() { - if let Some((_name, buffer_status)) = buffer_status { - buffer_status.new_item_count = 0; - } - } - - if let Some(ref mut buffer_status) = self.instance_buffer_status { - buffer_status.new_item_count = 0; - } - } - - fn update_uniforms_info(&mut self, world: &mut World) { - if !self.use_dynamic_uniforms { - return; - } - - let query = self.query.take().unwrap(); - for (uniforms, mut renderable) in query.iter_mut(world) { - if !renderable.is_visible { - return; - } - - if renderable.is_instanced { - if self.is_instanceable { - self.increment_instance_count(|| Self::get_instance_size(&uniforms)); - } else { - panic!( - "Cannot instance uniforms of type {}", - std::any::type_name::() - ); - } - } else if self.use_dynamic_uniforms { - self.increment_dynamic_uniform_counts(&uniforms); - } - - Self::update_shader_defs( - &uniforms, - renderable.render_resource_assignments.as_mut().unwrap(), - ); - } - - self.query = Some(query); - } - - fn update_handles_info(&mut self, world: &mut World, resources: &Resources) { - let handle_query = self.handle_query.take().unwrap(); - let assets = resources.get::>(); - let mut asset_batchers = resources.get_mut::().unwrap(); - if let Some(assets) = assets { - for (entity, (handle, mut renderable)) in handle_query.iter_entities_mut(world) { - if !renderable.is_visible { - return; - } - - if renderable.is_instanced { - if self.is_instanceable { - asset_batchers.set_entity_handle(entity, *handle); - self.increment_instance_count(|| { - let uniforms = assets.get(&handle).unwrap(); - Self::get_instance_size(uniforms) - }); - } else { - panic!( - "Cannot instance uniforms of type Handle<{}>", - std::any::type_name::() - ); - } - } else { - let uniforms = assets - .get(&handle) - .expect("Handle points to a non-existent resource"); - Self::update_shader_defs( - uniforms, - renderable.render_resource_assignments.as_mut().unwrap(), - ); - if self.use_dynamic_uniforms { - self.increment_dynamic_uniform_counts(&uniforms); - } - } - } - } - - self.handle_query = Some(handle_query); - } - - fn increment_instance_count(&mut self, f: impl Fn() -> usize) { - if let Some(ref mut buffer_array_status) = self.instance_buffer_status { - buffer_array_status.new_item_count += 1; - } else { - self.instance_buffer_status = Some(BufferArrayStatus { - new_item_count: 1, - item_size: f(), - staging_buffer_offset: 0, - buffer: None, - }) - } - } - - fn get_instance_size(uniforms: &T) -> usize { - let mut instance_buffer_size = 0; - for field_info in T::get_field_infos().iter() { - if field_info.is_instanceable { - if let Some(FieldBindType::Uniform { size }) = - uniforms.get_field_bind_type(field_info.name) - { - instance_buffer_size += size; - } - } - } - - instance_buffer_size - } - - fn increment_dynamic_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.dynamic_uniform_buffer_status[i] - { - buffer_array_status.new_item_count += 1; - } else { - self.dynamic_uniform_buffer_status[i] = Some(( - field_info.uniform_name.to_string(), - BufferArrayStatus { - new_item_count: 1, - item_size: size, - staging_buffer_offset: 0, - buffer: None, - }, - )) - } - } - } - } - - fn update_shader_defs( - uniforms: &T, - render_resource_assignments: &mut RenderResourceAssignments, - ) { - if let Some(shader_defs) = uniforms.get_shader_defs() { - for shader_def in shader_defs { - render_resource_assignments.shader_defs.insert(shader_def); - } - } - } - - fn setup_uniform_resources( - &mut self, - uniforms: &T, - renderer: &mut dyn Renderer, - resources: &Resources, - render_resource_assignments: &mut RenderResourceAssignments, - ) { - for field_info in T::get_field_infos() { - let bind_type = uniforms.get_field_bind_type(&field_info.name); - match bind_type { - Some(FieldBindType::Uniform { size }) => { - if self.use_dynamic_uniforms { - } else { - let buffer_resource = match render_resource_assignments - .get(field_info.uniform_name) - { - Some(render_resource) => render_resource, - None => { - let resource = renderer.create_buffer(BufferInfo { - size: size as u64, - buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM, - ..Default::default() - }); - render_resource_assignments.set(&field_info.uniform_name, resource); - resource - } - }; - - let (tmp_buffer, tmp_buffer_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); - } - - ( - renderer.create_buffer_mapped( - BufferInfo { - size: uniform_bytes.len() as u64, - buffer_usage: BufferUsage::COPY_SRC, - ..Default::default() - }, - &mut |mapped| { - mapped.copy_from_slice(uniform_bytes); - }, - ), - uniform_bytes.len(), - ) - } 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); - } - - ( - renderer.create_buffer_mapped( - BufferInfo { - size: uniform_bytes.len() as u64, - buffer_usage: BufferUsage::COPY_SRC, - ..Default::default() - }, - &mut |mapped| { - mapped.copy_from_slice(&uniform_bytes); - }, - ), - uniform_bytes.len(), - ) - } else { - panic!( - "failed to get data from uniform: {}", - field_info.uniform_name - ); - }; - - renderer.copy_buffer_to_buffer( - tmp_buffer, - 0, - buffer_resource, - 0, - tmp_buffer_size as u64, - ); - - renderer.remove_buffer(tmp_buffer); - } - } - Some(FieldBindType::Texture) => { - let texture_handle = uniforms - .get_uniform_texture(&field_info.texture_name) - .unwrap(); - let (texture_resource, sampler_resource) = match renderer - .get_render_resources() - .get_texture_resource(texture_handle) - { - Some(texture_resource) => ( - texture_resource, - renderer - .get_render_resources() - .get_texture_sampler_resource(texture_handle) - .unwrap(), - ), - None => { - let storage = resources.get::>().unwrap(); - let texture = storage.get(&texture_handle).unwrap(); - - let texture_descriptor: TextureDescriptor = texture.into(); - let texture_resource = - renderer.create_texture(&texture_descriptor, Some(&texture.data)); - - let sampler_descriptor: SamplerDescriptor = texture.into(); - let sampler_resource = renderer.create_sampler(&sampler_descriptor); - - let render_resources = renderer.get_render_resources_mut(); - render_resources.set_texture_resource(texture_handle, texture_resource); - render_resources - .set_texture_sampler_resource(texture_handle, sampler_resource); - (texture_resource, sampler_resource) - } - }; - - render_resource_assignments.set(field_info.texture_name, texture_resource); - render_resource_assignments.set(field_info.sampler_name, sampler_resource); - } - None => {} - } - } - } - - fn setup_uniforms_resources( - &mut self, - world: &mut World, - resources: &Resources, - renderer: &mut dyn Renderer, - ) { - let query_finish = self.query_finish.take().unwrap(); - for (uniforms, mut renderable) in query_finish.iter_mut(world) { - if !renderable.is_visible { - return; - } - - if renderable.is_instanced { - panic!( - "Cannot instance uniforms of type {0}. Only Handle<{0}> can be instanced.", - std::any::type_name::() - ); - } else { - self.setup_uniform_resources( - &uniforms, - renderer, - resources, - renderable.render_resource_assignments.as_mut().unwrap(), - ) - } - } - - self.query_finish = Some(query_finish); - } - - fn setup_handles_resources( - &mut self, - world: &mut World, - resources: &Resources, - renderer: &mut dyn Renderer, - ) { - let assets = resources.get::>(); - if let Some(assets) = assets { - let handle_query_finish = self.handle_query_finish.take().unwrap(); - for (handle, mut renderable) in handle_query_finish.iter_mut(world) { - if !renderable.is_visible || renderable.is_instanced { - return; - } - - let uniforms = assets - .get(&handle) - .expect("Handle points to a non-existent resource"); - self.setup_uniform_resources( - &uniforms, - renderer, - resources, - renderable.render_resource_assignments.as_mut().unwrap(), - ) - } - - self.handle_query_finish = Some(handle_query_finish); - } - } - - fn setup_batched_resources( - &mut self, - world: &mut World, - resources: &Resources, - renderer: &mut dyn Renderer, - ) { - // update batch resources. this needs to run in "finish_update" because batches aren't finalized across - // all members of the batch until "UniformResourceProvider.update" has run for all members of the batch - if let Some(asset_storage) = resources.get::>() { - let mut asset_batchers = resources.get_mut::().unwrap(); - let mut render_resource_assignments_provider = resources - .get_mut::() - .unwrap(); - let handle_type = std::any::TypeId::of::(); - for batch in asset_batchers.get_handle_batches_mut::().unwrap() { - let handle: Handle = batch - .handles - .iter() - .find(|h| h.type_id == handle_type) - .map(|h| (*h).into()) - .unwrap(); - - let render_resource_assignments = batch - .render_resource_assignments - .get_or_insert_with(|| render_resource_assignments_provider.next()); - if let Some(uniforms) = asset_storage.get(&handle) { - self.setup_uniform_resources( - uniforms, - renderer, - resources, - render_resource_assignments, - ); - - Self::update_shader_defs(&uniforms, render_resource_assignments); - } - } - } - } - - fn setup_buffer_arrays(&mut self, renderer: &mut dyn Renderer) { - for buffer_array_status in self.dynamic_uniform_buffer_status.iter_mut() { - if let Some((name, buffer_array_status)) = buffer_array_status { - println!("dynamic {} {:?}", name, buffer_array_status); - Self::setup_buffer_array(buffer_array_status, renderer); - } - } - - if let Some(ref mut buffer_array_status) = self.instance_buffer_status { - println!("instance {}", std::any::type_name::()); - Self::setup_buffer_array(buffer_array_status, renderer); - } - } - - fn setup_buffer_array( - buffer_array_status: &mut BufferArrayStatus, - renderer: &mut dyn Renderer, - ) { - let new_capacity = if let Some(buffer) = buffer_array_status.buffer { - if let Some(ResourceInfo::Buffer(BufferInfo { - array_info: Some(array_info), - .. - })) = renderer.get_resource_info_mut(buffer) - { - if array_info.item_capacity < buffer_array_status.new_item_count as u64 { - Some( - buffer_array_status.new_item_count + buffer_array_status.new_item_count / 2, - ) - } else { - None - } - } else { - Some(buffer_array_status.new_item_count) - } - } else { - Some(buffer_array_status.new_item_count) - }; - - if let Some(new_capacity) = new_capacity { - println!("creating buffer {}", new_capacity); - let buffer = renderer.create_buffer(BufferInfo { - array_info: Some(BufferArrayInfo { - item_capacity: new_capacity as u64, - item_count: buffer_array_status.new_item_count as u64, - item_size: buffer_array_status.item_size as u64, - }), - size: (buffer_array_status.item_size * new_capacity) as u64, - buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM, - dynamic_uniform_info: Some(BufferDynamicUniformInfo::default()), - }); - - buffer_array_status.buffer = Some(buffer); - } - } - - fn initialize_vertex_buffer_descriptor(&self, render_graph: &mut RenderGraph) { - let vertex_buffer_descriptor = T::get_vertex_buffer_descriptor(); - if let Some(vertex_buffer_descriptor) = vertex_buffer_descriptor { - if let None = render_graph.get_vertex_buffer_descriptor(&vertex_buffer_descriptor.name) - { - render_graph.set_vertex_buffer_descriptor(vertex_buffer_descriptor.clone()); - } - } - } - - fn update_staging_buffer_offsets(&mut self) -> usize { - let mut size = 0; - for dynamic_buffer_array_status in self.dynamic_uniform_buffer_status.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 - } -} - -impl ResourceProvider for UniformResourceProviderNew -where - T: AsUniforms + Send + Sync + 'static, -{ - fn initialize( - &mut self, - renderer: &mut dyn Renderer, - world: &mut World, - resources: &Resources, - ) { - let mut render_graph = resources.get_mut::().unwrap(); - self.initialize_vertex_buffer_descriptor(&mut render_graph); - self.update(renderer, world, resources); - } - - fn update(&mut self, renderer: &mut dyn Renderer, world: &mut World, resources: &Resources) { - self.reset_buffer_array_status_counts(); - self.update_uniforms_info(world); - self.update_handles_info(world, resources); - } - - fn finish_update( - &mut self, - renderer: &mut dyn Renderer, - world: &mut World, - resources: &Resources, - ) { - let staging_buffer_size = self.update_staging_buffer_offsets(); - // TODO: when setting batch shader_defs, add INSTANCING - self.setup_buffer_arrays(renderer); - self.setup_uniforms_resources(world, resources, renderer); - self.setup_handles_resources(world, resources, renderer); - self.setup_batched_resources(world, resources, renderer); - } -} diff --git a/src/render/renderer/renderer.rs b/src/render/renderer/renderer.rs index c33095a978..99accc7a8d 100644 --- a/src/render/renderer/renderer.rs +++ b/src/render/renderer/renderer.rs @@ -24,7 +24,7 @@ pub trait Renderer { fn create_buffer_mapped( &mut self, buffer_info: BufferInfo, - func: &mut dyn FnMut(&mut [u8]), + func: &mut dyn FnMut(&mut [u8], &mut dyn Renderer), ) -> RenderResource; fn remove_buffer(&mut self, resource: RenderResource); fn remove_texture(&mut self, resource: RenderResource); 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 d34afc3d71..5d9889c74e 100644 --- a/src/render/renderer/renderers/wgpu_renderer/wgpu_render_pass.rs +++ b/src/render/renderer/renderers/wgpu_renderer/wgpu_render_pass.rs @@ -58,6 +58,7 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> { }; // setup dynamic uniform instances + // TODO: these indices could be stored in RenderResourceAssignments so they dont need to be collected on each draw let mut dynamic_uniform_indices = Vec::new(); for binding in bind_group.bindings.iter() { if let BindType::Uniform { dynamic, .. } = binding.bind_type { @@ -72,16 +73,17 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> { .get_named_resource(&binding.name) { if let Some(ResourceInfo::Buffer(BufferInfo { - dynamic_uniform_info: Some(dynamic_uniform_info), + array_info: Some(array_info), + is_dynamic: true, .. })) = self.wgpu_resources.resource_info.get(&resource) { - let index = dynamic_uniform_info - .offsets + let index = array_info + .indices .get(&render_resource_assignments.unwrap().get_id()) .unwrap(); - dynamic_uniform_indices.push(*index); + dynamic_uniform_indices.push((*index * array_info.item_size) as u32); } } } diff --git a/src/render/renderer/renderers/wgpu_renderer/wgpu_renderer.rs b/src/render/renderer/renderers/wgpu_renderer/wgpu_renderer.rs index c9d225728e..a16628220d 100644 --- a/src/render/renderer/renderers/wgpu_renderer/wgpu_renderer.rs +++ b/src/render/renderer/renderers/wgpu_renderer/wgpu_renderer.rs @@ -19,10 +19,10 @@ use crate::{ update_shader_assignments, }, }; -use std::{collections::HashMap, ops::Deref}; +use std::{cell::RefCell, collections::HashMap, ops::Deref, rc::Rc}; pub struct WgpuRenderer { - pub device: wgpu::Device, + pub device: Rc>, pub queue: wgpu::Queue, pub surface: Option, pub encoder: Option, @@ -58,7 +58,7 @@ impl WgpuRenderer { }; WgpuRenderer { - device, + device: Rc::new(RefCell::new(device)), queue, surface: None, encoder: None, @@ -160,7 +160,7 @@ impl WgpuRenderer { if let Some(ResourceInfo::Buffer(buffer_info)) = wgpu_resources.resource_info.get(&resource) { - *dynamic = buffer_info.dynamic_uniform_info.is_some(); + *dynamic = buffer_info.is_dynamic; } } } @@ -370,6 +370,7 @@ impl WgpuRenderer { let mut render_graph = resources.get_mut::().unwrap(); self.encoder = Some( self.device + .borrow() .create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }), ); for resource_provider in render_graph.resource_providers.iter_mut() { @@ -417,12 +418,14 @@ impl Renderer for WgpuRenderer { }; self.encoder = Some( self.device + .borrow() .create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }), ); self.swap_chain_descriptor.width = window_size.width; self.swap_chain_descriptor.height = window_size.height; let swap_chain = self .device + .borrow() .create_swap_chain(self.surface.as_ref().unwrap(), &self.swap_chain_descriptor); // WgpuRenderer can't own swap_chain without creating lifetime ergonomics issues, so lets just store it in World. @@ -449,6 +452,7 @@ impl Renderer for WgpuRenderer { // exposing the wgpu renderer internals to ResourceProvider traits. if this can be made cleaner that would be pretty cool. self.encoder = Some( self.device + .borrow() .create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }), ); @@ -492,7 +496,7 @@ impl Renderer for WgpuRenderer { let render_pipeline = WgpuRenderer::create_render_pipeline( &mut self.wgpu_resources, pipeline_descriptor, - &self.device, + &self.device.borrow(), &render_graph, vertex_shader, fragment_shader, @@ -505,7 +509,7 @@ impl Renderer for WgpuRenderer { let pipeline_layout = pipeline_descriptor.get_layout().unwrap(); for bind_group in pipeline_layout.bind_groups.iter() { self.wgpu_resources - .setup_bind_group(&self.device, bind_group); + .setup_bind_group(&self.device.borrow(), bind_group); } } @@ -560,11 +564,12 @@ impl Renderer for WgpuRenderer { fn create_buffer_with_data(&mut self, buffer_info: BufferInfo, data: &[u8]) -> RenderResource { self.wgpu_resources - .create_buffer_with_data(&self.device, buffer_info, data) + .create_buffer_with_data(&self.device.borrow(), buffer_info, data) } fn create_buffer(&mut self, buffer_info: BufferInfo) -> RenderResource { - self.wgpu_resources.create_buffer(&self.device, buffer_info) + self.wgpu_resources + .create_buffer(&self.device.borrow(), buffer_info) } fn get_resource_info(&self, resource: RenderResource) -> Option<&ResourceInfo> { @@ -582,10 +587,10 @@ impl Renderer for WgpuRenderer { fn create_buffer_mapped( &mut self, buffer_info: BufferInfo, - setup_data: &mut dyn FnMut(&mut [u8]), + setup_data: &mut dyn FnMut(&mut [u8], &mut dyn Renderer), ) -> RenderResource { - self.wgpu_resources - .create_buffer_mapped(&self.device, buffer_info, setup_data) + let buffer = WgpuResources::begin_create_buffer_mapped(&buffer_info, self, setup_data); + self.wgpu_resources.assign_buffer(buffer, buffer_info) } fn copy_buffer_to_buffer( @@ -608,7 +613,7 @@ impl Renderer for WgpuRenderer { fn create_sampler(&mut self, sampler_descriptor: &SamplerDescriptor) -> RenderResource { self.wgpu_resources - .create_sampler(&self.device, sampler_descriptor) + .create_sampler(&self.device.borrow(), sampler_descriptor) } fn create_texture( @@ -617,7 +622,7 @@ impl Renderer for WgpuRenderer { bytes: Option<&[u8]>, ) -> RenderResource { self.wgpu_resources.create_texture( - &self.device, + &self.device.borrow(), self.encoder.as_mut().unwrap(), texture_descriptor, bytes, @@ -655,7 +660,7 @@ impl Renderer for WgpuRenderer { .get_assignments_bind_group(render_resource_assignments.get_id(), bind_group_id) { self.wgpu_resources.create_assignments_bind_group( - &self.device, + &self.device.borrow(), bind_group, render_resource_assignments, ); diff --git a/src/render/renderer/renderers/wgpu_renderer/wgpu_resources.rs b/src/render/renderer/renderers/wgpu_renderer/wgpu_resources.rs index 7153999cee..91105e7495 100644 --- a/src/render/renderer/renderers/wgpu_renderer/wgpu_resources.rs +++ b/src/render/renderer/renderers/wgpu_renderer/wgpu_resources.rs @@ -1,9 +1,11 @@ +use super::WgpuRenderer; use crate::render::{ pipeline::{BindGroup, BindType}, render_resource::{ BufferInfo, RenderResource, RenderResourceAssignments, RenderResourceAssignmentsId, RenderResources, ResourceInfo, }, + renderer::Renderer, texture::{SamplerDescriptor, TextureDescriptor}, }; use std::collections::HashMap; @@ -77,7 +79,7 @@ impl WgpuResources { let buffer = self.buffers.get(&resource).unwrap(); wgpu::BindingResource::Buffer { buffer, - range: 0..buffer_info.size, + range: 0..buffer_info.size as u64, } } else { panic!("expected a Buffer resource"); @@ -147,7 +149,7 @@ impl WgpuResources { let buffer = self.buffers.get(&resource).unwrap(); wgpu::BindingResource::Buffer { buffer, - range: 0..buffer_info.size, + range: 0..buffer_info.size as u64, } } else { panic!("expected a Buffer resource"); @@ -185,7 +187,7 @@ impl WgpuResources { buffer_info: BufferInfo, ) -> RenderResource { let buffer = device.create_buffer(&wgpu::BufferDescriptor { - size: buffer_info.size, + size: buffer_info.size as u64, usage: buffer_info.buffer_usage.into(), }); @@ -202,13 +204,9 @@ impl WgpuResources { mut buffer_info: BufferInfo, data: &[u8], ) -> RenderResource { - buffer_info.size = data.len() as u64; - let resource = self.render_resources.get_next_resource(); + buffer_info.size = data.len(); let buffer = device.create_buffer_with_data(data, buffer_info.buffer_usage.into()); - self.add_resource_info(resource, ResourceInfo::Buffer(buffer_info)); - - self.buffers.insert(resource, buffer); - resource + self.assign_buffer(buffer, buffer_info) } pub fn get_resource_info(&self, resource: RenderResource) -> Option<&ResourceInfo> { @@ -220,24 +218,31 @@ impl WgpuResources { self.resource_info.remove(&resource); } - pub fn create_buffer_mapped( + pub fn assign_buffer( &mut self, - device: &wgpu::Device, + buffer: wgpu::Buffer, buffer_info: BufferInfo, - setup_data: &mut dyn FnMut(&mut [u8]), ) -> RenderResource { - let mut mapped = - device.create_buffer_mapped(buffer_info.size as usize, buffer_info.buffer_usage.into()); - setup_data(&mut mapped.data); - let buffer = mapped.finish(); - let resource = self.render_resources.get_next_resource(); self.add_resource_info(resource, ResourceInfo::Buffer(buffer_info)); - self.buffers.insert(resource, buffer); resource } + pub fn begin_create_buffer_mapped( + buffer_info: &BufferInfo, + renderer: &mut WgpuRenderer, + setup_data: &mut dyn FnMut(&mut [u8], &mut dyn Renderer), + ) -> wgpu::Buffer { + let device_rc = renderer.device.clone(); + let device = device_rc.borrow(); + + let mut mapped = + device.create_buffer_mapped(buffer_info.size as usize, buffer_info.buffer_usage.into()); + setup_data(&mut mapped.data, renderer); + mapped.finish() + } + pub fn copy_buffer_to_buffer( &mut self, encoder: &mut wgpu::CommandEncoder, diff --git a/src/render/shader/uniform.rs b/src/render/shader/uniform.rs index 91988b8460..70255fa079 100644 --- a/src/render/shader/uniform.rs +++ b/src/render/shader/uniform.rs @@ -5,7 +5,7 @@ use crate::{ color::ColorSource, pipeline::{BindType, VertexBufferDescriptor}, texture::{Texture, TextureViewDimension}, - }, prelude::Color, + }, }; pub trait AsUniforms { @@ -79,7 +79,7 @@ where let bind_type = self.uniforms.get_field_bind_type(field_info.name); if let Some(bind_type) = bind_type { Some(match bind_type { - FieldBindType::Uniform { .. }=> UniformInfo { + FieldBindType::Uniform { .. } => UniformInfo { bind_type: BindType::Uniform { dynamic: false, properties: Vec::new(), @@ -147,7 +147,9 @@ where { // TODO: this breaks if get_bytes_ref() isn't supported for a datatype default fn get_field_bind_type(&self) -> Option { - Some(FieldBindType::Uniform { size: self.get_bytes_ref().unwrap().len() }) + Some(FieldBindType::Uniform { + size: self.get_bytes_ref().unwrap().len(), + }) } } diff --git a/src/render/shader/uniforms/local_to_world.rs b/src/render/shader/uniforms/local_to_world.rs index c8c28d562c..695e2fbf63 100644 --- a/src/render/shader/uniforms/local_to_world.rs +++ b/src/render/shader/uniforms/local_to_world.rs @@ -5,7 +5,7 @@ use crate::{ pipeline::{ InputStepMode, VertexAttributeDescriptor, VertexBufferDescriptor, VertexFormat, }, - shader::{AsUniforms, FieldBindType, FieldInfo, AsFieldBindType}, + shader::{AsFieldBindType, AsUniforms, FieldBindType, FieldInfo}, texture::Texture, }, };