mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 15:14:50 +00:00
improve performance dynamic uniforms
This commit is contained in:
parent
c4b10ea4f7
commit
7c2eb63a47
2 changed files with 84 additions and 33 deletions
|
@ -261,8 +261,7 @@ impl<T> ResourceProvider for UniformResourceProvider<T>
|
|||
where
|
||||
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) {
|
||||
let query = <Read<T>>::query();
|
||||
|
@ -270,62 +269,96 @@ where
|
|||
// 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
|
||||
|
||||
// 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) {
|
||||
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());
|
||||
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)
|
||||
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;
|
||||
// }
|
||||
for name in self.uniform_buffer_info_names.iter() {
|
||||
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)
|
||||
// }
|
||||
let info = renderer.get_dynamic_uniform_buffer_info_mut(name).unwrap();
|
||||
|
||||
// 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 size = {
|
||||
let info = renderer.get_dynamic_uniform_buffer_info(name).unwrap();
|
||||
wgpu::BIND_BUFFER_ALIGNMENT * info.count
|
||||
};
|
||||
|
||||
let alignment = wgpu::BIND_BUFFER_ALIGNMENT as usize;
|
||||
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: 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.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;
|
||||
}
|
||||
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
|
||||
// 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 queue: wgpu::Queue,
|
||||
pub surface: Option<wgpu::Surface>,
|
||||
pub encoder: Option<wgpu::CommandEncoder>,
|
||||
pub swap_chain_descriptor: wgpu::SwapChainDescriptor,
|
||||
pub render_pipelines: HashMap<String, wgpu::RenderPipeline>,
|
||||
pub buffers: HashMap<String, wgpu::Buffer>,
|
||||
|
@ -72,6 +73,7 @@ impl WgpuRenderer {
|
|||
device,
|
||||
queue,
|
||||
surface: None,
|
||||
encoder: None,
|
||||
swap_chain_descriptor,
|
||||
render_pipelines: 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) {
|
||||
// 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() {
|
||||
resource_provider.update(self, world);
|
||||
}
|
||||
|
||||
let mut encoder = self.encoder.take().unwrap();
|
||||
|
||||
let mut swap_chain = world.resources.get_mut::<wgpu::SwapChain>().unwrap();
|
||||
let frame = swap_chain
|
||||
.get_next_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);
|
||||
|
||||
|
@ -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])) {
|
||||
let mut mapped = self.device.create_buffer_mapped(size, buffer_usage);
|
||||
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) {
|
||||
let source = self.buffers.get(source_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> {
|
||||
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);
|
||||
}
|
||||
|
||||
// TODO: maybe move setup to renderer.setup_bind_groups(&pipeline_desc);
|
||||
fn setup_bind_groups(&mut self, entity: Option<&Entity>) {
|
||||
for (i, bind_group) in self
|
||||
.pipeline_descriptor
|
||||
|
|
Loading…
Reference in a new issue