mirror of
https://github.com/bevyengine/bevy
synced 2024-11-21 20:23:28 +00:00
dynamic uniform buffer info
This commit is contained in:
parent
6ba659049d
commit
0eb6c6fa74
5 changed files with 99 additions and 46 deletions
|
@ -50,7 +50,6 @@ fn setup(world: &mut World) {
|
|||
uniform_selector::<StandardMaterial>,
|
||||
uniform_selector::<LocalToWorld>,
|
||||
],
|
||||
dynamic_uniform_indices: indices,
|
||||
},
|
||||
local_to_world: LocalToWorld::identity(),
|
||||
translation: Translation::new(0.0, 0.0, 0.0),
|
||||
|
@ -66,7 +65,6 @@ fn setup(world: &mut World) {
|
|||
uniform_selector::<StandardMaterial>,
|
||||
uniform_selector::<LocalToWorld>,
|
||||
],
|
||||
dynamic_uniform_indices: indices_2,
|
||||
},
|
||||
local_to_world: LocalToWorld::identity(),
|
||||
translation: Translation::new(0.0, 0.0, 1.0),
|
||||
|
@ -81,7 +79,6 @@ fn setup(world: &mut World) {
|
|||
uniform_selector::<StandardMaterial>,
|
||||
uniform_selector::<LocalToWorld>,
|
||||
],
|
||||
dynamic_uniform_indices: indices_3,
|
||||
},
|
||||
local_to_world: LocalToWorld::identity(),
|
||||
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 mesh_query =
|
||||
<(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;
|
||||
if let Some(current) = 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
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
pub trait Renderer {
|
||||
|
@ -19,5 +19,5 @@ pub trait RenderPass {
|
|||
fn set_index_buffer(&mut self, 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 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,
|
||||
render::render_graph_2::{BindType, UniformPropertyType},
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use legion::storage::Component;
|
||||
use zerocopy::AsBytes;
|
||||
|
||||
|
@ -14,14 +13,12 @@ pub type ShaderUniformSelector = fn(Entity, &World) -> Option<RefMap<&dyn AsUnif
|
|||
pub struct ShaderUniforms {
|
||||
// used for distinguishing
|
||||
pub uniform_selectors: Vec<ShaderUniformSelector>,
|
||||
pub dynamic_uniform_indices: HashMap<String, u64>,
|
||||
}
|
||||
|
||||
impl ShaderUniforms {
|
||||
pub fn new() -> Self {
|
||||
ShaderUniforms {
|
||||
uniform_selectors: Vec::new(),
|
||||
dynamic_uniform_indices: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,14 @@ use std::{
|
|||
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 device: wgpu::Device,
|
||||
pub queue: wgpu::Queue,
|
||||
|
@ -24,6 +32,7 @@ pub struct WgpuRenderer {
|
|||
pub resource_info: HashMap<String, ResourceInfo>,
|
||||
pub bind_groups: HashMap<u64, BindGroupInfo>,
|
||||
pub bind_group_layouts: HashMap<u64, wgpu::BindGroupLayout>,
|
||||
pub dynamic_uniform_buffer_info: HashMap<String, DynamicUniformBufferInfo>,
|
||||
}
|
||||
|
||||
impl WgpuRenderer {
|
||||
|
@ -62,6 +71,7 @@ impl WgpuRenderer {
|
|||
resource_info: HashMap::new(),
|
||||
bind_groups: HashMap::new(),
|
||||
bind_group_layouts: HashMap::new(),
|
||||
dynamic_uniform_buffer_info: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -268,7 +278,11 @@ impl WgpuRenderer {
|
|||
dynamic: _,
|
||||
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();
|
||||
wgpu::BindingResource::Buffer {
|
||||
buffer: buffer,
|
||||
|
@ -303,9 +317,12 @@ impl WgpuRenderer {
|
|||
bind_group_id
|
||||
}
|
||||
|
||||
fn setup_dynamic_entity_shader_uniforms(&mut self, world: &World, render_graph: &RenderGraph, encoder: &mut wgpu::CommandEncoder) {
|
||||
let mut dynamic_uniform_info = HashMap::new();
|
||||
|
||||
fn setup_dynamic_entity_shader_uniforms(
|
||||
&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
|
||||
// TODO: this breaks down in multiple ways:
|
||||
// (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 binding in bind_group.bindings.iter() {
|
||||
// if let None = self.resource_info.get(&binding.name) {
|
||||
if let BindType::Uniform { dynamic: true, .. } = &binding.bind_type {
|
||||
if dynamic_uniform_info.contains_key(&binding.name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dynamic_uniform_info.insert(binding.name.to_string(), UniformInfo {
|
||||
size: binding.bind_type.get_uniform_size().unwrap(),
|
||||
count: 0,
|
||||
});
|
||||
if let BindType::Uniform { dynamic: true, .. } = &binding.bind_type {
|
||||
if self.dynamic_uniform_buffer_info.contains_key(&binding.name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
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
|
||||
for (name, info) in dynamic_uniform_info.iter_mut() {
|
||||
// count the number of entities providing each uniform
|
||||
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) {
|
||||
if let Some(_) = shader_uniforms.get_uniform_info(world, entity, name) {
|
||||
info.count += 1;
|
||||
// TODO: assign indices to shader_uniforms here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// allocate uniform buffers
|
||||
for (name, info) in dynamic_uniform_info.iter() {
|
||||
let size = wgpu::BIND_BUFFER_ALIGNMENT * info.count;
|
||||
if self.buffers.contains_key(name) {
|
||||
for (name, info) in self.dynamic_uniform_buffer_info.iter_mut() {
|
||||
if self.buffers.contains_key(name) && info.count < info.capacity {
|
||||
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
|
||||
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 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 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) {
|
||||
mapped.data[offset..(offset + bytes.len())].copy_from_slice(bytes.as_slice());
|
||||
offset += alignment;
|
||||
|
@ -369,11 +424,6 @@ impl WgpuRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct UniformInfo {
|
||||
pub size: u64,
|
||||
pub count: u64,
|
||||
}
|
||||
|
||||
impl Renderer for WgpuRenderer {
|
||||
fn initialize(&mut self, world: &mut World, render_graph: &mut RenderGraph) {
|
||||
let (surface, window_size) = {
|
||||
|
@ -423,7 +473,7 @@ impl Renderer for WgpuRenderer {
|
|||
let mut encoder = self
|
||||
.device
|
||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
|
||||
|
||||
|
||||
self.setup_dynamic_entity_shader_uniforms(world, render_graph, &mut encoder);
|
||||
|
||||
// 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);
|
||||
fn setup_bind_groups(&mut self, shader_uniforms: &ShaderUniforms) {
|
||||
fn setup_bind_groups(&mut self, entity: Option<&Entity>) {
|
||||
for (i, bind_group) in self
|
||||
.pipeline_descriptor
|
||||
.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();
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.render_pass
|
||||
.set_bind_group(i as u32, &bind_group_info.bind_group, dynamic_uniform_indices.as_slice());
|
||||
self.render_pass.set_bind_group(
|
||||
i as u32,
|
||||
&bind_group_info.bind_group,
|
||||
dynamic_uniform_indices.as_slice(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue