dynamic uniform buffer info
This commit is contained in:
parent
6ba659049d
commit
0eb6c6fa74
@ -50,7 +50,6 @@ fn setup(world: &mut World) {
|
|||||||
uniform_selector::<StandardMaterial>,
|
uniform_selector::<StandardMaterial>,
|
||||||
uniform_selector::<LocalToWorld>,
|
uniform_selector::<LocalToWorld>,
|
||||||
],
|
],
|
||||||
dynamic_uniform_indices: indices,
|
|
||||||
},
|
},
|
||||||
local_to_world: LocalToWorld::identity(),
|
local_to_world: LocalToWorld::identity(),
|
||||||
translation: Translation::new(0.0, 0.0, 0.0),
|
translation: Translation::new(0.0, 0.0, 0.0),
|
||||||
@ -66,7 +65,6 @@ fn setup(world: &mut World) {
|
|||||||
uniform_selector::<StandardMaterial>,
|
uniform_selector::<StandardMaterial>,
|
||||||
uniform_selector::<LocalToWorld>,
|
uniform_selector::<LocalToWorld>,
|
||||||
],
|
],
|
||||||
dynamic_uniform_indices: indices_2,
|
|
||||||
},
|
},
|
||||||
local_to_world: LocalToWorld::identity(),
|
local_to_world: LocalToWorld::identity(),
|
||||||
translation: Translation::new(0.0, 0.0, 1.0),
|
translation: Translation::new(0.0, 0.0, 1.0),
|
||||||
@ -81,7 +79,6 @@ fn setup(world: &mut World) {
|
|||||||
uniform_selector::<StandardMaterial>,
|
uniform_selector::<StandardMaterial>,
|
||||||
uniform_selector::<LocalToWorld>,
|
uniform_selector::<LocalToWorld>,
|
||||||
],
|
],
|
||||||
dynamic_uniform_indices: indices_3,
|
|
||||||
},
|
},
|
||||||
local_to_world: LocalToWorld::identity(),
|
local_to_world: LocalToWorld::identity(),
|
||||||
translation: Translation::new(-2.0, 0.0, 1.0),
|
translation: Translation::new(-2.0, 0.0, 1.0),
|
||||||
|
@ -22,7 +22,7 @@ pub fn mesh_draw_target(world: &World, render_pass: &mut dyn RenderPass) {
|
|||||||
let mut current_mesh_index_length = 0;
|
let mut current_mesh_index_length = 0;
|
||||||
let mesh_query =
|
let mesh_query =
|
||||||
<(Read<ShaderUniforms>, Read<Handle<Mesh>>)>::query().filter(!component::<Instanced>());
|
<(Read<ShaderUniforms>, Read<Handle<Mesh>>)>::query().filter(!component::<Instanced>());
|
||||||
for (shader_uniforms, mesh) in mesh_query.iter(world) {
|
for (entity, (_shader_uniforms, mesh)) in mesh_query.iter_entities(world) {
|
||||||
let mut should_load_mesh = current_mesh_id == None;
|
let mut should_load_mesh = current_mesh_id == None;
|
||||||
if let Some(current) = current_mesh_id {
|
if let Some(current) = current_mesh_id {
|
||||||
should_load_mesh = current != mesh.id;
|
should_load_mesh = current != mesh.id;
|
||||||
@ -51,7 +51,7 @@ pub fn mesh_draw_target(world: &World, render_pass: &mut dyn RenderPass) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: validate bind group properties against shader uniform properties at least once
|
// TODO: validate bind group properties against shader uniform properties at least once
|
||||||
render_pass.setup_bind_groups(&&*shader_uniforms);
|
render_pass.setup_bind_groups(Some(&entity));
|
||||||
render_pass.draw_indexed(0..current_mesh_index_length, 0, 0..1);
|
render_pass.draw_indexed(0..current_mesh_index_length, 0, 0..1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::{legion::prelude::*, render::render_graph_2::{RenderGraph, ResourceInfo, PipelineDescriptor, ShaderUniforms}};
|
use crate::{legion::prelude::*, render::render_graph_2::{RenderGraph, ResourceInfo, PipelineDescriptor}};
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
pub trait Renderer {
|
pub trait Renderer {
|
||||||
@ -19,5 +19,5 @@ pub trait RenderPass {
|
|||||||
fn set_index_buffer(&mut self, name: &str, offset: u64);
|
fn set_index_buffer(&mut self, name: &str, offset: u64);
|
||||||
fn set_vertex_buffer(&mut self, start_slot: u32, name: &str, offset: u64);
|
fn set_vertex_buffer(&mut self, start_slot: u32, name: &str, offset: u64);
|
||||||
fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>);
|
fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>);
|
||||||
fn setup_bind_groups(&mut self, shader_uniforms: &ShaderUniforms);
|
fn setup_bind_groups(&mut self, entity: Option<&Entity>);
|
||||||
}
|
}
|
@ -6,7 +6,6 @@ use crate::{
|
|||||||
math::Vec4,
|
math::Vec4,
|
||||||
render::render_graph_2::{BindType, UniformPropertyType},
|
render::render_graph_2::{BindType, UniformPropertyType},
|
||||||
};
|
};
|
||||||
use std::collections::HashMap;
|
|
||||||
use legion::storage::Component;
|
use legion::storage::Component;
|
||||||
use zerocopy::AsBytes;
|
use zerocopy::AsBytes;
|
||||||
|
|
||||||
@ -14,14 +13,12 @@ pub type ShaderUniformSelector = fn(Entity, &World) -> Option<RefMap<&dyn AsUnif
|
|||||||
pub struct ShaderUniforms {
|
pub struct ShaderUniforms {
|
||||||
// used for distinguishing
|
// used for distinguishing
|
||||||
pub uniform_selectors: Vec<ShaderUniformSelector>,
|
pub uniform_selectors: Vec<ShaderUniformSelector>,
|
||||||
pub dynamic_uniform_indices: HashMap<String, u64>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ShaderUniforms {
|
impl ShaderUniforms {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
ShaderUniforms {
|
ShaderUniforms {
|
||||||
uniform_selectors: Vec::new(),
|
uniform_selectors: Vec::new(),
|
||||||
dynamic_uniform_indices: HashMap::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,14 @@ use std::{
|
|||||||
ops::Deref,
|
ops::Deref,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub struct DynamicUniformBufferInfo {
|
||||||
|
pub indices: HashMap<usize, Entity>,
|
||||||
|
pub offsets: HashMap<Entity, u64>,
|
||||||
|
pub capacity: u64,
|
||||||
|
pub count: u64,
|
||||||
|
pub size: u64,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct WgpuRenderer {
|
pub struct WgpuRenderer {
|
||||||
pub device: wgpu::Device,
|
pub device: wgpu::Device,
|
||||||
pub queue: wgpu::Queue,
|
pub queue: wgpu::Queue,
|
||||||
@ -24,6 +32,7 @@ pub struct WgpuRenderer {
|
|||||||
pub resource_info: HashMap<String, ResourceInfo>,
|
pub resource_info: HashMap<String, ResourceInfo>,
|
||||||
pub bind_groups: HashMap<u64, BindGroupInfo>,
|
pub bind_groups: HashMap<u64, BindGroupInfo>,
|
||||||
pub bind_group_layouts: HashMap<u64, wgpu::BindGroupLayout>,
|
pub bind_group_layouts: HashMap<u64, wgpu::BindGroupLayout>,
|
||||||
|
pub dynamic_uniform_buffer_info: HashMap<String, DynamicUniformBufferInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WgpuRenderer {
|
impl WgpuRenderer {
|
||||||
@ -62,6 +71,7 @@ impl WgpuRenderer {
|
|||||||
resource_info: HashMap::new(),
|
resource_info: HashMap::new(),
|
||||||
bind_groups: HashMap::new(),
|
bind_groups: HashMap::new(),
|
||||||
bind_group_layouts: HashMap::new(),
|
bind_group_layouts: HashMap::new(),
|
||||||
|
dynamic_uniform_buffer_info: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,7 +278,11 @@ impl WgpuRenderer {
|
|||||||
dynamic: _,
|
dynamic: _,
|
||||||
properties: _,
|
properties: _,
|
||||||
} => {
|
} => {
|
||||||
if let ResourceInfo::Buffer { size, buffer_usage: _ } = resource_info {
|
if let ResourceInfo::Buffer {
|
||||||
|
size,
|
||||||
|
buffer_usage: _,
|
||||||
|
} = resource_info
|
||||||
|
{
|
||||||
let buffer = self.buffers.get(&b.name).unwrap();
|
let buffer = self.buffers.get(&b.name).unwrap();
|
||||||
wgpu::BindingResource::Buffer {
|
wgpu::BindingResource::Buffer {
|
||||||
buffer: buffer,
|
buffer: buffer,
|
||||||
@ -303,9 +317,12 @@ impl WgpuRenderer {
|
|||||||
bind_group_id
|
bind_group_id
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_dynamic_entity_shader_uniforms(&mut self, world: &World, render_graph: &RenderGraph, encoder: &mut wgpu::CommandEncoder) {
|
fn setup_dynamic_entity_shader_uniforms(
|
||||||
let mut dynamic_uniform_info = HashMap::new();
|
&mut self,
|
||||||
|
world: &World,
|
||||||
|
render_graph: &RenderGraph,
|
||||||
|
encoder: &mut wgpu::CommandEncoder,
|
||||||
|
) {
|
||||||
// retrieve all uniforms buffers that aren't aleady set. these are "dynamic" uniforms, which are set by the user in ShaderUniforms
|
// 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:
|
// TODO: this breaks down in multiple ways:
|
||||||
// (1) resource_info will be set after the first run so this won't update.
|
// (1) resource_info will be set after the first run so this won't update.
|
||||||
@ -314,48 +331,86 @@ impl WgpuRenderer {
|
|||||||
for bind_group in pipeline.pipeline_layout.bind_groups.iter() {
|
for bind_group in pipeline.pipeline_layout.bind_groups.iter() {
|
||||||
for binding in bind_group.bindings.iter() {
|
for binding in bind_group.bindings.iter() {
|
||||||
// if let None = self.resource_info.get(&binding.name) {
|
// if let None = self.resource_info.get(&binding.name) {
|
||||||
if let BindType::Uniform { dynamic: true, .. } = &binding.bind_type {
|
if let BindType::Uniform { dynamic: true, .. } = &binding.bind_type {
|
||||||
if dynamic_uniform_info.contains_key(&binding.name) {
|
if self.dynamic_uniform_buffer_info.contains_key(&binding.name) {
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_uniform_info.insert(binding.name.to_string(), UniformInfo {
|
|
||||||
size: binding.bind_type.get_uniform_size().unwrap(),
|
|
||||||
count: 0,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.dynamic_uniform_buffer_info.insert(
|
||||||
|
binding.name.to_string(),
|
||||||
|
DynamicUniformBufferInfo {
|
||||||
|
capacity: 0,
|
||||||
|
count: 0,
|
||||||
|
size: binding.bind_type.get_uniform_size().unwrap(),
|
||||||
|
indices: HashMap::new(),
|
||||||
|
offsets: HashMap::new(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// count the number of entities providing each uniform
|
// count the number of entities providing each uniform
|
||||||
for (name, info) in dynamic_uniform_info.iter_mut() {
|
for (name, info) in self.dynamic_uniform_buffer_info.iter_mut() {
|
||||||
|
info.count = 0;
|
||||||
for (entity, shader_uniforms) in <Read<ShaderUniforms>>::query().iter_entities(world) {
|
for (entity, shader_uniforms) in <Read<ShaderUniforms>>::query().iter_entities(world) {
|
||||||
if let Some(_) = shader_uniforms.get_uniform_info(world, entity, name) {
|
if let Some(_) = shader_uniforms.get_uniform_info(world, entity, name) {
|
||||||
info.count += 1;
|
info.count += 1;
|
||||||
// TODO: assign indices to shader_uniforms here
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// allocate uniform buffers
|
// allocate uniform buffers
|
||||||
for (name, info) in dynamic_uniform_info.iter() {
|
for (name, info) in self.dynamic_uniform_buffer_info.iter_mut() {
|
||||||
let size = wgpu::BIND_BUFFER_ALIGNMENT * info.count;
|
if self.buffers.contains_key(name) && info.count < info.capacity {
|
||||||
if self.buffers.contains_key(name) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.create_buffer(name, size, wgpu::BufferUsage::COPY_DST | wgpu::BufferUsage::UNIFORM);
|
if info.count >= info.capacity && info.capacity != 0 {
|
||||||
|
panic!("resizing dynamic uniform buffers isn't supported yet. we still need to support updating bind groups");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// TODO: remove this code duplication in favor of self.create_buffer(). this will likely require a refactor
|
||||||
|
// the following is a flattening of the content in self.create_buffer(), which can't be called because
|
||||||
|
// of rust's ownership rules. sometimes rust makes me unhappy
|
||||||
|
|
||||||
|
let buffer_usage = wgpu::BufferUsage::COPY_DST | wgpu::BufferUsage::UNIFORM;
|
||||||
|
let buffer = self.device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
|
size: size,
|
||||||
|
usage: buffer_usage,
|
||||||
|
});
|
||||||
|
|
||||||
|
self.resource_info.insert(
|
||||||
|
name.to_string(),
|
||||||
|
ResourceInfo::Buffer {
|
||||||
|
buffer_usage,
|
||||||
|
size: size,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
self.buffers.insert(name.to_string(), buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy entity uniform data to buffers
|
// copy entity uniform data to buffers
|
||||||
for (name, info) in dynamic_uniform_info.iter_mut() {
|
for (name, info) in self.dynamic_uniform_buffer_info.iter_mut() {
|
||||||
let size = wgpu::BIND_BUFFER_ALIGNMENT * info.count;
|
let size = wgpu::BIND_BUFFER_ALIGNMENT * info.count;
|
||||||
let mapped = self.device.create_buffer_mapped(size as usize, wgpu::BufferUsage::COPY_SRC);
|
let mapped = self
|
||||||
|
.device
|
||||||
|
.create_buffer_mapped(size as usize, wgpu::BufferUsage::COPY_SRC);
|
||||||
let alignment = wgpu::BIND_BUFFER_ALIGNMENT as usize;
|
let alignment = wgpu::BIND_BUFFER_ALIGNMENT as usize;
|
||||||
let mut offset = 0usize;
|
let mut offset = 0usize;
|
||||||
for (entity, shader_uniforms) in <Read<ShaderUniforms>>::query().iter_entities(world) {
|
|
||||||
|
for (i, (entity, shader_uniforms)) in <Read<ShaderUniforms>>::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);
|
||||||
if let Some(bytes) = shader_uniforms.get_uniform_bytes(world, entity, name) {
|
if let Some(bytes) = shader_uniforms.get_uniform_bytes(world, entity, name) {
|
||||||
mapped.data[offset..(offset + bytes.len())].copy_from_slice(bytes.as_slice());
|
mapped.data[offset..(offset + bytes.len())].copy_from_slice(bytes.as_slice());
|
||||||
offset += alignment;
|
offset += alignment;
|
||||||
@ -369,11 +424,6 @@ impl WgpuRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct UniformInfo {
|
|
||||||
pub size: u64,
|
|
||||||
pub count: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Renderer for WgpuRenderer {
|
impl Renderer for WgpuRenderer {
|
||||||
fn initialize(&mut self, world: &mut World, render_graph: &mut RenderGraph) {
|
fn initialize(&mut self, world: &mut World, render_graph: &mut RenderGraph) {
|
||||||
let (surface, window_size) = {
|
let (surface, window_size) = {
|
||||||
@ -423,7 +473,7 @@ impl Renderer for WgpuRenderer {
|
|||||||
let mut encoder = self
|
let mut encoder = self
|
||||||
.device
|
.device
|
||||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
|
.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
|
// setup, pipelines, bind groups, and resources
|
||||||
@ -555,7 +605,7 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: maybe move setup to renderer.setup_bind_groups(&pipeline_desc);
|
// TODO: maybe move setup to renderer.setup_bind_groups(&pipeline_desc);
|
||||||
fn setup_bind_groups(&mut self, shader_uniforms: &ShaderUniforms) {
|
fn setup_bind_groups(&mut self, entity: Option<&Entity>) {
|
||||||
for (i, bind_group) in self
|
for (i, bind_group) in self
|
||||||
.pipeline_descriptor
|
.pipeline_descriptor
|
||||||
.pipeline_layout
|
.pipeline_layout
|
||||||
@ -571,19 +621,28 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> {
|
|||||||
|
|
||||||
let mut dynamic_uniform_indices = Vec::new();
|
let mut dynamic_uniform_indices = Vec::new();
|
||||||
for binding in bind_group.bindings.iter() {
|
for binding in bind_group.bindings.iter() {
|
||||||
if let BindType::Uniform { dynamic, ..} = binding.bind_type {
|
if let BindType::Uniform { dynamic, .. } = binding.bind_type {
|
||||||
if !dynamic {
|
if !dynamic {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(index) = shader_uniforms.dynamic_uniform_indices.get(&binding.name) {
|
if let Some(dynamic_uniform_buffer_info) =
|
||||||
|
self.renderer.dynamic_uniform_buffer_info.get(&binding.name)
|
||||||
|
{
|
||||||
|
let index = dynamic_uniform_buffer_info
|
||||||
|
.offsets
|
||||||
|
.get(entity.unwrap())
|
||||||
|
.unwrap();
|
||||||
dynamic_uniform_indices.push(*index);
|
dynamic_uniform_indices.push(*index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.render_pass
|
self.render_pass.set_bind_group(
|
||||||
.set_bind_group(i as u32, &bind_group_info.bind_group, dynamic_uniform_indices.as_slice());
|
i as u32,
|
||||||
|
&bind_group_info.bind_group,
|
||||||
|
dynamic_uniform_indices.as_slice(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user