improve performance dynamic uniforms
This commit is contained in:
parent
c4b10ea4f7
commit
7c2eb63a47
@ -261,8 +261,7 @@ impl<T> ResourceProvider for UniformResourceProvider<T>
|
|||||||
where
|
where
|
||||||
T: AsUniforms + Send + Sync + 'static,
|
T: AsUniforms + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
fn initialize(&mut self, renderer: &mut dyn super::Renderer, world: &mut World) {
|
fn initialize(&mut self, renderer: &mut dyn super::Renderer, world: &mut World) {}
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, renderer: &mut dyn super::Renderer, world: &mut World) {
|
fn update(&mut self, renderer: &mut dyn super::Renderer, world: &mut World) {
|
||||||
let query = <Read<T>>::query();
|
let query = <Read<T>>::query();
|
||||||
@ -270,62 +269,96 @@ where
|
|||||||
// 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.
|
||||||
// (2) if we create new buffers, the old bind groups will be invalid
|
// (2) if we create new buffers, the old bind groups will be invalid
|
||||||
|
|
||||||
|
// reset all uniform buffer info counts
|
||||||
|
for name in self.uniform_buffer_info_names.iter() {
|
||||||
|
renderer.get_dynamic_uniform_buffer_info_mut(name).unwrap().count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
for uniforms in query.iter(world) {
|
for uniforms in query.iter(world) {
|
||||||
let uniform_layouts = uniforms.get_uniform_layouts();
|
let uniform_layouts = uniforms.get_uniform_layouts();
|
||||||
for (i, uniform_info) in uniforms.get_uniform_infos().iter().enumerate() {
|
for (i, uniform_info) in uniforms.get_uniform_infos().iter().enumerate() {
|
||||||
if let None = renderer.get_dynamic_uniform_buffer_info(uniform_info.name) {
|
if let None = renderer.get_dynamic_uniform_buffer_info(uniform_info.name) {
|
||||||
let uniform_layout = uniform_layouts[i];
|
let uniform_layout = uniform_layouts[i];
|
||||||
let mut info = DynamicUniformBufferInfo::new();
|
let mut info = DynamicUniformBufferInfo::new();
|
||||||
info.size = uniform_layout.iter().map(|u| u.get_size()).fold(0, |total, current| total + current);
|
info.size = uniform_layout
|
||||||
self.uniform_buffer_info_names.insert(uniform_info.name.to_string());
|
.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);
|
renderer.add_dynamic_uniform_buffer_info(uniform_info.name, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut info = renderer.get_dynamic_uniform_buffer_info_mut(uniform_info.name)
|
let mut info = renderer
|
||||||
|
.get_dynamic_uniform_buffer_info_mut(uniform_info.name)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
info.count += 1;
|
info.count += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// allocate uniform buffers
|
// allocate uniform buffers
|
||||||
// for (name, info) in self.dynamic_uniform_buffer_infos.iter_mut() {
|
for name in self.uniform_buffer_info_names.iter() {
|
||||||
// if let Some(_) = renderer.get_resource_info(name) {
|
if let Some(_) = renderer.get_resource_info(name) {
|
||||||
// continue;
|
continue;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// // allocate enough space for twice as many entities as there are currently;
|
let info = renderer.get_dynamic_uniform_buffer_info_mut(name).unwrap();
|
||||||
// info.capacity = info.count * 2;
|
|
||||||
// let size = wgpu::BIND_BUFFER_ALIGNMENT * info.capacity;
|
// allocate enough space for twice as many entities as there are currently;
|
||||||
// renderer.create_buffer(name, size, wgpu::BufferUsage::COPY_DST | wgpu::BufferUsage::UNIFORM)
|
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
|
// copy entity uniform data to buffers
|
||||||
for name in self.uniform_buffer_info_names.iter() {
|
for name in self.uniform_buffer_info_names.iter() {
|
||||||
let info = renderer.get_dynamic_uniform_buffer_info_mut(name).unwrap();
|
let size = {
|
||||||
info.capacity = info.count;
|
let info = renderer.get_dynamic_uniform_buffer_info(name).unwrap();
|
||||||
let size = wgpu::BIND_BUFFER_ALIGNMENT * info.count;
|
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 alignment = wgpu::BIND_BUFFER_ALIGNMENT as usize;
|
||||||
let mut offset = 0usize;
|
let mut offset = 0usize;
|
||||||
for (i, (entity, uniforms)) in query.iter_entities(world).enumerate() {
|
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: check if index has changed. if it has, then entity should be updated
|
||||||
// TODO: only mem-map entities if their data has changed
|
// TODO: only mem-map entities if their data has changed
|
||||||
|
let info = renderer.get_dynamic_uniform_buffer_info_mut(name).unwrap();
|
||||||
info.offsets.insert(entity, offset as u64);
|
info.offsets.insert(entity, offset as u64);
|
||||||
info.indices.insert(i, entity);
|
info.indices.insert(i, entity);
|
||||||
// TODO: try getting ref first
|
// TODO: try getting ref first
|
||||||
if let Some(uniform_bytes) = uniforms.get_uniform_bytes(name) {
|
offset += alignment;
|
||||||
data[offset..(offset + uniform_bytes.len())].copy_from_slice(uniform_bytes.as_slice());
|
|
||||||
offset += alignment;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// });
|
|
||||||
|
// 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 uniforms in query.iter(world) {
|
||||||
|
// TODO: check if index has changed. if it has, then entity should be updated
|
||||||
|
// TODO: only mem-map entities if their data has changed
|
||||||
|
// TODO: try getting ref first
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// TODO: port me
|
// TODO: port me
|
||||||
// let uniform_buffer = self.buffers.get(name);
|
// let uniform_buffer = self.buffers.get(name);
|
||||||
renderer.create_buffer_with_data(name, &data, wgpu::BufferUsage::UNIFORM);
|
// renderer.create_buffer_with_data(name, &data, wgpu::BufferUsage::UNIFORM);
|
||||||
|
renderer.copy_buffer_to_buffer("tmp_uniform_mapped", 0, name, 0, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ pub struct WgpuRenderer {
|
|||||||
pub device: wgpu::Device,
|
pub device: wgpu::Device,
|
||||||
pub queue: wgpu::Queue,
|
pub queue: wgpu::Queue,
|
||||||
pub surface: Option<wgpu::Surface>,
|
pub surface: Option<wgpu::Surface>,
|
||||||
|
pub encoder: Option<wgpu::CommandEncoder>,
|
||||||
pub swap_chain_descriptor: wgpu::SwapChainDescriptor,
|
pub swap_chain_descriptor: wgpu::SwapChainDescriptor,
|
||||||
pub render_pipelines: HashMap<String, wgpu::RenderPipeline>,
|
pub render_pipelines: HashMap<String, wgpu::RenderPipeline>,
|
||||||
pub buffers: HashMap<String, wgpu::Buffer>,
|
pub buffers: HashMap<String, wgpu::Buffer>,
|
||||||
@ -72,6 +73,7 @@ impl WgpuRenderer {
|
|||||||
device,
|
device,
|
||||||
queue,
|
queue,
|
||||||
surface: None,
|
surface: None,
|
||||||
|
encoder: None,
|
||||||
swap_chain_descriptor,
|
swap_chain_descriptor,
|
||||||
render_pipelines: HashMap::new(),
|
render_pipelines: HashMap::new(),
|
||||||
buffers: HashMap::new(),
|
buffers: HashMap::new(),
|
||||||
@ -465,18 +467,23 @@ impl Renderer for WgpuRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn process_render_graph(&mut self, render_graph: &mut RenderGraph, world: &mut World) {
|
fn process_render_graph(&mut self, render_graph: &mut RenderGraph, world: &mut World) {
|
||||||
|
// TODO: this self.encoder handoff is a bit gross, but its here to give resource providers access to buffer copies without
|
||||||
|
// exposing the wgpu renderer internals to ResourceProvider traits. if this can be made cleaner that would be pretty cool.
|
||||||
|
self.encoder = Some(self
|
||||||
|
.device
|
||||||
|
.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }));
|
||||||
|
|
||||||
for resource_provider in render_graph.resource_providers.iter_mut() {
|
for resource_provider in render_graph.resource_providers.iter_mut() {
|
||||||
resource_provider.update(self, world);
|
resource_provider.update(self, world);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut encoder = self.encoder.take().unwrap();
|
||||||
|
|
||||||
let mut swap_chain = world.resources.get_mut::<wgpu::SwapChain>().unwrap();
|
let mut swap_chain = world.resources.get_mut::<wgpu::SwapChain>().unwrap();
|
||||||
let frame = swap_chain
|
let frame = swap_chain
|
||||||
.get_next_texture()
|
.get_next_texture()
|
||||||
.expect("Timeout when acquiring next swap chain texture");
|
.expect("Timeout when acquiring next swap chain texture");
|
||||||
|
|
||||||
let mut encoder = self
|
|
||||||
.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);
|
||||||
|
|
||||||
@ -574,12 +581,24 @@ impl Renderer for WgpuRenderer {
|
|||||||
fn create_buffer_mapped(&mut self, name: &str, size: usize, buffer_usage: wgpu::BufferUsage, setup_data: &mut dyn FnMut(&mut [u8])) {
|
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);
|
let mut mapped = self.device.create_buffer_mapped(size, buffer_usage);
|
||||||
setup_data(&mut mapped.data);
|
setup_data(&mut mapped.data);
|
||||||
mapped.finish();
|
let buffer = mapped.finish();
|
||||||
|
|
||||||
|
self.add_resource_info(
|
||||||
|
name,
|
||||||
|
ResourceInfo::Buffer {
|
||||||
|
buffer_usage,
|
||||||
|
size: size as u64,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
self.buffers.insert(name.to_string(), buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy_buffer_to_buffer(&mut self, source_buffer: &str, source_offset: u64, destination_buffer: &str, destination_offset: u64, size: u64) {
|
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 source = self.buffers.get(source_buffer).unwrap();
|
||||||
let destination = self.buffers.get(destination_buffer).unwrap();
|
let destination = self.buffers.get(destination_buffer).unwrap();
|
||||||
|
let encoder = self.encoder.as_mut().unwrap();
|
||||||
|
encoder.copy_buffer_to_buffer(source, source_offset, destination, destination_offset, size);
|
||||||
}
|
}
|
||||||
fn get_dynamic_uniform_buffer_info(&self, name: &str) -> Option<&DynamicUniformBufferInfo> {
|
fn get_dynamic_uniform_buffer_info(&self, name: &str) -> Option<&DynamicUniformBufferInfo> {
|
||||||
self.dynamic_uniform_buffer_info.get(name)
|
self.dynamic_uniform_buffer_info.get(name)
|
||||||
@ -630,7 +649,6 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> {
|
|||||||
.draw_indexed(indices, base_vertex, instances);
|
.draw_indexed(indices, base_vertex, instances);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: maybe move setup to renderer.setup_bind_groups(&pipeline_desc);
|
|
||||||
fn setup_bind_groups(&mut self, entity: Option<&Entity>) {
|
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
|
||||||
|
Loading…
Reference in New Issue
Block a user