diff --git a/examples/simple_new_graph.rs b/examples/simple_new_graph.rs index b5929f0d7b..096835ca6d 100644 --- a/examples/simple_new_graph.rs +++ b/examples/simple_new_graph.rs @@ -141,7 +141,7 @@ fn setup(world: &mut World) { builder = builder.add_archetype(NewMeshEntity { mesh: cube_handle.clone(), material: StandardMaterial { - albedo: math::vec4(0.0, 1.0, 0.0, 1.0), + albedo: math::vec4(rng.gen_range(0.0, 1.0), rng.gen_range(0.0, 1.0), rng.gen_range(0.0, 1.0), 1.0), }, shader_uniforms: ShaderUniforms { uniform_selectors: vec![ diff --git a/src/app/app_builder.rs b/src/app/app_builder.rs index d7221217f4..1e3eda99c3 100644 --- a/src/app/app_builder.rs +++ b/src/app/app_builder.rs @@ -4,13 +4,13 @@ use crate::{ core::Time, legion::prelude::{Runnable, Schedulable, Schedule, Universe, World}, render::render_graph_2, - render::render_graph_2::{pipelines::*, wgpu_renderer::WgpuRenderer, resource_provider::CameraResourceProvider}, + render::render_graph_2::{pipelines::*, wgpu_renderer::WgpuRenderer, resource_provider::CameraResourceProvider, UniformResourceProvider, StandardMaterial}, render::{passes::*, *}, plugin::load_plugin, ui, }; -use bevy_transform::transform_system_bundle; +use bevy_transform::{transform_system_bundle, prelude::LocalToWorld}; use std::collections::HashMap; pub struct AppBuilder { @@ -175,6 +175,8 @@ impl AppBuilder { self.render_graph_builder = self .render_graph_builder .add_resource_provider(Box::new(CameraResourceProvider)) + .add_resource_provider(Box::new(UniformResourceProvider::::new())) + .add_resource_provider(Box::new(UniformResourceProvider::::new())) .add_forward_pass() .add_forward_pipeline(); diff --git a/src/render/render_graph_2/pipeline_layout.rs b/src/render/render_graph_2/pipeline_layout.rs index 7bfae3c0fa..9ba79456ed 100644 --- a/src/render/render_graph_2/pipeline_layout.rs +++ b/src/render/render_graph_2/pipeline_layout.rs @@ -97,7 +97,7 @@ pub enum UniformPropertyType { } impl UniformPropertyType { - fn get_size(&self) -> u64 { + pub fn get_size(&self) -> u64 { match self { UniformPropertyType::Int => 4, UniformPropertyType::Float => 4, diff --git a/src/render/render_graph_2/renderer.rs b/src/render/render_graph_2/renderer.rs index 1cbcd7e7e7..c28dc9b81f 100644 --- a/src/render/render_graph_2/renderer.rs +++ b/src/render/render_graph_2/renderer.rs @@ -1,4 +1,4 @@ -use crate::{legion::prelude::*, render::render_graph_2::{RenderGraph, ResourceInfo, PipelineDescriptor}}; +use crate::{legion::prelude::*, render::render_graph_2::{RenderGraph, ResourceInfo, PipelineDescriptor, wgpu_renderer::DynamicUniformBufferInfo}}; use std::ops::Range; pub trait Renderer { @@ -7,9 +7,14 @@ pub trait Renderer { fn process_render_graph(&mut self, render_graph: &mut RenderGraph, world: &mut World); // TODO: swap out wgpu::BufferUsage for non-wgpu type fn create_buffer_with_data(&mut self, name: &str, data: &[u8], buffer_usage: wgpu::BufferUsage); + fn get_dynamic_uniform_buffer_info(&self, name: &str) -> Option<&DynamicUniformBufferInfo>; + fn get_dynamic_uniform_buffer_info_mut(&mut self, name: &str) -> Option<&mut DynamicUniformBufferInfo>; + fn add_dynamic_uniform_buffer_info(&mut self, name: &str, info: DynamicUniformBufferInfo); fn create_buffer(&mut self, name: &str, size: u64, buffer_usage: wgpu::BufferUsage); + fn create_buffer_mapped(&mut self, name: &str, size: usize, buffer_usage: wgpu::BufferUsage, func: &mut dyn FnMut(&mut [u8])); fn remove_buffer(&mut self, name: &str); fn get_resource_info(&self, name: &str) -> Option<&ResourceInfo>; + fn copy_buffer_to_buffer(&mut self, source_buffer: &str, source_offset: u64, destination_buffer: &str, destination_offset: u64, size: u64); } pub trait RenderPass { diff --git a/src/render/render_graph_2/resource_provider.rs b/src/render/render_graph_2/resource_provider.rs index 28844a3930..bcd901d953 100644 --- a/src/render/render_graph_2/resource_provider.rs +++ b/src/render/render_graph_2/resource_provider.rs @@ -7,20 +7,20 @@ use legion::prelude::*; use zerocopy::AsBytes; pub trait ResourceProvider { - fn initialize(&self, renderer: &mut dyn Renderer, world: &mut World); - fn update(&self, renderer: &mut dyn Renderer, world: &mut World); - fn resize(&self, renderer: &mut dyn Renderer, world: &mut World, width: u32, height: u32); + fn initialize(&mut self, renderer: &mut dyn Renderer, world: &mut World); + fn update(&mut self, renderer: &mut dyn Renderer, world: &mut World); + fn resize(&mut self, renderer: &mut dyn Renderer, world: &mut World, width: u32, height: u32); } pub struct CameraResourceProvider; impl ResourceProvider for CameraResourceProvider { - fn initialize(&self, _renderer: &mut dyn Renderer, _world: &mut World) { + fn initialize(&mut self, _renderer: &mut dyn Renderer, _world: &mut World) { // TODO: create real buffer here } - fn update(&self, _renderer: &mut dyn Renderer, _world: &mut World) {} - fn resize(&self, renderer: &mut dyn Renderer, world: &mut World, width: u32, height: u32) { + fn update(&mut self, _renderer: &mut dyn Renderer, _world: &mut World) {} + fn resize(&mut self, renderer: &mut dyn Renderer, world: &mut World, width: u32, height: u32) { for (mut camera, local_to_world, _) in <(Write, Read, Read)>::query().iter_mut(world) { diff --git a/src/render/render_graph_2/shader.rs b/src/render/render_graph_2/shader.rs index 319ad1bf25..663d88e010 100644 --- a/src/render/render_graph_2/shader.rs +++ b/src/render/render_graph_2/shader.rs @@ -4,9 +4,13 @@ use crate::{ prelude::{Entity, World}, }, math::Vec4, - render::render_graph_2::{BindType, UniformPropertyType}, + render::render_graph_2::{ + wgpu_renderer::DynamicUniformBufferInfo, BindType, ResourceProvider, UniformPropertyType, + }, }; -use legion::storage::Component; +use legion::{prelude::*, storage::Component}; +use std::collections::HashSet; +use std::marker::PhantomData; use zerocopy::AsBytes; pub type ShaderUniformSelector = fn(Entity, &World) -> Option>; @@ -42,7 +46,7 @@ impl ShaderUniforms { let info = uniforms.get_uniform_info(uniform_name); if let Some(_) = info { - return info; + return info; } } @@ -65,7 +69,7 @@ impl ShaderUniforms { let bytes = uniforms.get_uniform_bytes(uniform_name); if let Some(_) = bytes { - return bytes; + return bytes; } } @@ -145,7 +149,7 @@ const STANDARD_MATERIAL_UNIFORM_INFO: &[UniformInfo] = &[UniformInfo { // these are separate from BindType::Uniform{properties} because they need to be const const STANDARD_MATERIAL_UNIFORM_LAYOUTS: &[&[UniformPropertyType]] = &[&[]]; -// const ST +// const impl AsUniforms for StandardMaterial { fn get_uniform_infos(&self) -> &[UniformInfo] { STANDARD_MATERIAL_UNIFORM_INFO @@ -187,7 +191,7 @@ const LOCAL_TO_WORLD_UNIFORM_INFO: &[UniformInfo] = &[UniformInfo { name: "Object", bind_type: BindType::Uniform { dynamic: false, - // TODO: fill this in with properties + // TODO: maybe fill this in with properties (vec.push cant be const though) properties: Vec::new(), }, }]; @@ -230,3 +234,107 @@ impl AsUniforms for bevy_transform::prelude::LocalToWorld { // } // } } + +pub struct UniformResourceProvider +where + T: AsUniforms + Send + Sync, +{ + _marker: PhantomData, + uniform_buffer_info_names: HashSet, + // dynamic_uniform_buffer_infos: HashMap, +} + +impl UniformResourceProvider +where + T: AsUniforms + Send + Sync, +{ + pub fn new() -> Self { + UniformResourceProvider { + // dynamic_uniform_buffer_infos: HashMap::new(), + uniform_buffer_info_names: HashSet::new(), + _marker: PhantomData, + } + } +} + +impl ResourceProvider for UniformResourceProvider +where + T: AsUniforms + Send + Sync + 'static, +{ + fn initialize(&mut self, renderer: &mut dyn super::Renderer, world: &mut World) { + } + + fn update(&mut self, renderer: &mut dyn super::Renderer, world: &mut World) { + let query = >::query(); + // retrieve all uniforms buffers that aren't aleady set. these are "dynamic" uniforms, which are set by the user in ShaderUniforms + // TODO: this breaks down in multiple ways: + // (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 + for uniforms in query.iter(world) { + let uniform_layouts = uniforms.get_uniform_layouts(); + for (i, uniform_info) in uniforms.get_uniform_infos().iter().enumerate() { + if let None = renderer.get_dynamic_uniform_buffer_info(uniform_info.name) { + let uniform_layout = uniform_layouts[i]; + let mut info = DynamicUniformBufferInfo::new(); + info.size = uniform_layout.iter().map(|u| u.get_size()).fold(0, |total, current| total + current); + self.uniform_buffer_info_names.insert(uniform_info.name.to_string()); + renderer.add_dynamic_uniform_buffer_info(uniform_info.name, info); + } + + let mut info = renderer.get_dynamic_uniform_buffer_info_mut(uniform_info.name) + .unwrap(); + info.count += 1; + } + } + + // allocate uniform buffers + // for (name, info) in self.dynamic_uniform_buffer_infos.iter_mut() { + // if let Some(_) = renderer.get_resource_info(name) { + // continue; + // } + + // // allocate enough space for twice as many entities as there are currently; + // info.capacity = info.count * 2; + // let size = wgpu::BIND_BUFFER_ALIGNMENT * info.capacity; + // renderer.create_buffer(name, size, wgpu::BufferUsage::COPY_DST | wgpu::BufferUsage::UNIFORM) + // } + + // copy entity uniform data to buffers + for name in self.uniform_buffer_info_names.iter() { + let info = renderer.get_dynamic_uniform_buffer_info_mut(name).unwrap(); + info.capacity = info.count; + let size = wgpu::BIND_BUFFER_ALIGNMENT * info.count; + let mut data = vec![Default::default(); size as usize]; + // renderer + // .create_buffer_mapped("tmp_uniform_mapped", size as usize, wgpu::BufferUsage::COPY_SRC, &mut |mapped| { + + let alignment = wgpu::BIND_BUFFER_ALIGNMENT as usize; + let mut offset = 0usize; + for (i, (entity, uniforms)) in query.iter_entities(world).enumerate() { + // TODO: check if index has changed. if it has, then entity should be updated + // TODO: only mem-map entities if their data has changed + info.offsets.insert(entity, offset as u64); + info.indices.insert(i, entity); + // TODO: try getting ref first + if let Some(uniform_bytes) = uniforms.get_uniform_bytes(name) { + data[offset..(offset + uniform_bytes.len())].copy_from_slice(uniform_bytes.as_slice()); + offset += alignment; + } + } + // }); + + // TODO: port me + // let uniform_buffer = self.buffers.get(name); + renderer.create_buffer_with_data(name, &data, wgpu::BufferUsage::UNIFORM); + } + } + + fn resize( + &mut self, + renderer: &mut dyn super::Renderer, + world: &mut World, + width: u32, + height: u32, + ) { + } +} diff --git a/src/render/render_graph_2/wgpu_renderer.rs b/src/render/render_graph_2/wgpu_renderer.rs index 138d0fc750..5aa7ddd15f 100644 --- a/src/render/render_graph_2/wgpu_renderer.rs +++ b/src/render/render_graph_2/wgpu_renderer.rs @@ -17,6 +17,18 @@ pub struct DynamicUniformBufferInfo { pub size: u64, } +impl DynamicUniformBufferInfo { + pub fn new() -> Self { + DynamicUniformBufferInfo { + capacity: 0, + count: 0, + indices: HashMap::new(), + offsets: HashMap::new(), + size: 0, + } + } +} + pub struct WgpuRenderer { pub device: wgpu::Device, pub queue: wgpu::Queue, @@ -466,7 +478,7 @@ impl Renderer for WgpuRenderer { .device .create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }); - self.setup_dynamic_entity_shader_uniforms(world, render_graph, &mut encoder); + // self.setup_dynamic_entity_shader_uniforms(world, render_graph, &mut encoder); // setup, pipelines, bind groups, and resources for (pipeline_name, pipeline_descriptor) in render_graph.pipeline_descriptors.iter_mut() { @@ -558,6 +570,28 @@ impl Renderer for WgpuRenderer { fn remove_buffer(&mut self, name: &str) { self.buffers.remove(name); } + + fn create_buffer_mapped(&mut self, name: &str, size: usize, buffer_usage: wgpu::BufferUsage, setup_data: &mut dyn FnMut(&mut [u8])) { + let mut mapped = self.device.create_buffer_mapped(size, buffer_usage); + setup_data(&mut mapped.data); + mapped.finish(); + } + + fn copy_buffer_to_buffer(&mut self, source_buffer: &str, source_offset: u64, destination_buffer: &str, destination_offset: u64, size: u64) { + let source = self.buffers.get(source_buffer).unwrap(); + let destination = self.buffers.get(destination_buffer).unwrap(); + } + fn get_dynamic_uniform_buffer_info(&self, name: &str) -> Option<&DynamicUniformBufferInfo> { + self.dynamic_uniform_buffer_info.get(name) + } + + fn get_dynamic_uniform_buffer_info_mut(&mut self, name: &str) -> Option<&mut DynamicUniformBufferInfo> { + self.dynamic_uniform_buffer_info.get_mut(name) + } + + fn add_dynamic_uniform_buffer_info(&mut self, name: &str, info: DynamicUniformBufferInfo) { + self.dynamic_uniform_buffer_info.insert(name.to_string(), info); + } } pub struct WgpuRenderPass<'a, 'b, 'c, 'd> { @@ -622,6 +656,7 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> { .offsets .get(entity.unwrap()) .unwrap(); + dynamic_uniform_indices.push(*index); } }