render: add direct buffer mapping/unmapping

This commit is contained in:
Carter Anderson 2020-07-11 12:29:07 -07:00
parent cb1ffb42c4
commit 6d58a5a033
9 changed files with 231 additions and 201 deletions

View File

@ -58,10 +58,8 @@ impl SystemNode for LightsNode {
LightsNodeSystemState { LightsNodeSystemState {
command_queue: self.command_queue.clone(), command_queue: self.command_queue.clone(),
max_lights: self.max_lights, max_lights: self.max_lights,
tmp_count_buffer: None,
tmp_light_buffer: None,
light_buffer: None, light_buffer: None,
lights_are_dirty: true, staging_buffer: None,
}, },
); );
system system
@ -71,10 +69,7 @@ impl SystemNode for LightsNode {
#[derive(Default)] #[derive(Default)]
pub struct LightsNodeSystemState { pub struct LightsNodeSystemState {
light_buffer: Option<BufferId>, light_buffer: Option<BufferId>,
lights_are_dirty: bool, staging_buffer: Option<BufferId>,
// TODO: merge these
tmp_count_buffer: Option<BufferId>,
tmp_light_buffer: Option<BufferId>,
command_queue: CommandQueue, command_queue: CommandQueue,
max_lights: usize, max_lights: usize,
} }
@ -82,22 +77,30 @@ pub struct LightsNodeSystemState {
pub fn lights_node_system( pub fn lights_node_system(
mut state: Local<LightsNodeSystemState>, mut state: Local<LightsNodeSystemState>,
render_resource_context: Res<Box<dyn RenderResourceContext>>, render_resource_context: Res<Box<dyn RenderResourceContext>>,
// TODO: this write on RenderResourceAssignments will prevent this system from running in parallel with other systems that do the same // TODO: this write on RenderResourceBindings will prevent this system from running in parallel with other systems that do the same
mut render_resource_bindings: ResMut<RenderResourceBindings>, mut render_resource_bindings: ResMut<RenderResourceBindings>,
mut query: Query<(&Light, &Transform, &Translation)>, mut query: Query<(&Light, &Transform, &Translation)>,
) { ) {
let state = &mut state; let state = &mut state;
if !state.lights_are_dirty {
return;
}
let render_resource_context = &**render_resource_context; let render_resource_context = &**render_resource_context;
if state.light_buffer.is_none() {
let light_uniform_size =
std::mem::size_of::<LightCount>() + state.max_lights * std::mem::size_of::<LightRaw>();
let light_count = query.iter().iter().count();
let size = std::mem::size_of::<LightRaw>();
let light_count_size = std::mem::size_of::<LightCount>();
let light_array_size = size * light_count;
let light_array_max_size = size * state.max_lights;
let current_light_uniform_size = light_count_size + light_array_size;
let max_light_uniform_size = light_count_size + light_array_max_size;
if let Some(staging_buffer) = state.staging_buffer {
if light_count == 0 {
return;
}
render_resource_context.map_buffer(staging_buffer);
} else {
let buffer = render_resource_context.create_buffer(BufferInfo { let buffer = render_resource_context.create_buffer(BufferInfo {
size: light_uniform_size, size: max_light_uniform_size,
buffer_usage: BufferUsage::UNIFORM | BufferUsage::COPY_SRC | BufferUsage::COPY_DST, buffer_usage: BufferUsage::UNIFORM | BufferUsage::COPY_SRC | BufferUsage::COPY_DST,
..Default::default() ..Default::default()
}); });
@ -105,74 +108,45 @@ pub fn lights_node_system(
uniform::LIGHTS, uniform::LIGHTS,
RenderResourceBinding::Buffer { RenderResourceBinding::Buffer {
buffer, buffer,
range: 0..light_uniform_size as u64, range: 0..max_light_uniform_size as u64,
dynamic_index: None, dynamic_index: None,
}, },
); );
state.light_buffer = Some(buffer); state.light_buffer = Some(buffer);
let staging_buffer = render_resource_context.create_buffer(BufferInfo {
size: max_light_uniform_size,
buffer_usage: BufferUsage::COPY_SRC | BufferUsage::MAP_WRITE,
mapped_at_creation: true,
});
state.staging_buffer = Some(staging_buffer);
} }
let light_count = query.iter().iter().count(); let staging_buffer = state.staging_buffer.unwrap();
render_resource_context.write_mapped_buffer(
if light_count == 0 { staging_buffer,
return; 0..current_light_uniform_size as u64,
}
state.lights_are_dirty = false;
let size = std::mem::size_of::<LightRaw>();
let total_size = size * light_count;
let light_count_size = std::mem::size_of::<LightCount>();
if let Some(old_tmp_light_buffer) = state.tmp_light_buffer {
render_resource_context.remove_buffer(old_tmp_light_buffer);
}
if let Some(old_tmp_count_buffer) = state.tmp_count_buffer {
render_resource_context.remove_buffer(old_tmp_count_buffer);
}
state.tmp_light_buffer = Some(render_resource_context.create_buffer_mapped(
BufferInfo {
size: total_size,
buffer_usage: BufferUsage::COPY_SRC,
..Default::default()
},
&mut |data, _renderer| { &mut |data, _renderer| {
// light count
data[0..light_count_size].copy_from_slice([light_count as u32, 0, 0, 0].as_bytes());
// light array
for ((light, transform, translation), slot) in for ((light, transform, translation), slot) in
query.iter().iter().zip(data.chunks_exact_mut(size)) query.iter().iter().zip(data[light_count_size..current_light_uniform_size].chunks_exact_mut(size))
{ {
slot.copy_from_slice( slot.copy_from_slice(
LightRaw::from(&light, &transform.value, &translation).as_bytes(), LightRaw::from(&light, &transform.value, &translation).as_bytes(),
); );
} }
}, },
)); );
state.tmp_count_buffer = Some(render_resource_context.create_buffer_mapped( render_resource_context.unmap_buffer(staging_buffer);
BufferInfo {
size: light_count_size,
buffer_usage: BufferUsage::COPY_SRC,
..Default::default()
},
&mut |data, _renderer| {
data.copy_from_slice([light_count as u32, 0, 0, 0].as_bytes());
},
));
let tmp_count_buffer = state.tmp_count_buffer.unwrap();
let light_buffer = state.light_buffer.unwrap(); let light_buffer = state.light_buffer.unwrap();
state.command_queue.copy_buffer_to_buffer( state.command_queue.copy_buffer_to_buffer(
tmp_count_buffer, staging_buffer,
0, 0,
light_buffer, light_buffer,
0, 0,
light_count_size as u64, max_light_uniform_size as u64,
);
let tmp_light_buffer = state.tmp_light_buffer.unwrap();
state.command_queue.copy_buffer_to_buffer(
tmp_light_buffer,
0,
light_buffer,
light_count_size as u64,
total_size as u64,
); );
} }

View File

@ -51,6 +51,7 @@ impl SystemNode for CameraNode {
camera_name: self.camera_name.clone(), camera_name: self.camera_name.clone(),
command_queue: self.command_queue.clone(), command_queue: self.command_queue.clone(),
camera_buffer: None, camera_buffer: None,
staging_buffer: None,
}, },
); );
system system
@ -62,6 +63,7 @@ pub struct CameraNodeState {
command_queue: CommandQueue, command_queue: CommandQueue,
camera_name: Cow<'static, str>, camera_name: Cow<'static, str>,
camera_buffer: Option<BufferId>, camera_buffer: Option<BufferId>,
staging_buffer: Option<BufferId>,
} }
pub fn camera_node_system( pub fn camera_node_system(
@ -74,27 +76,7 @@ pub fn camera_node_system(
query: Query<(&Camera, &Transform)>, query: Query<(&Camera, &Transform)>,
) { ) {
let render_resource_context = &**render_resource_context; let render_resource_context = &**render_resource_context;
state.camera_buffer = Some(match state.camera_buffer {
Some(buffer) => buffer,
None => {
let size = std::mem::size_of::<[[f32; 4]; 4]>();
let buffer = render_resource_context.create_buffer(BufferInfo {
size,
buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM,
..Default::default()
});
render_resource_bindings.set(
&state.camera_name,
RenderResourceBinding::Buffer {
buffer,
range: 0..size as u64,
dynamic_index: None,
},
);
state.camera_buffer = Some(buffer);
buffer
}
});
let (camera, transform) = if let Some(camera_entity) = active_cameras.get(&state.camera_name) { let (camera, transform) = if let Some(camera_entity) = active_cameras.get(&state.camera_name) {
( (
query.get::<Camera>(camera_entity).unwrap(), query.get::<Camera>(camera_entity).unwrap(),
@ -104,24 +86,55 @@ pub fn camera_node_system(
return; return;
}; };
let staging_buffer = if let Some(staging_buffer) = state.staging_buffer {
render_resource_context.map_buffer(staging_buffer);
staging_buffer
} else {
let size = std::mem::size_of::<[[f32; 4]; 4]>();
let buffer = render_resource_context.create_buffer(BufferInfo {
size,
buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM,
..Default::default()
});
render_resource_bindings.set(
&state.camera_name,
RenderResourceBinding::Buffer {
buffer,
range: 0..size as u64,
dynamic_index: None,
},
);
state.camera_buffer = Some(buffer);
let staging_buffer = render_resource_context.create_buffer(BufferInfo {
size,
buffer_usage: BufferUsage::COPY_SRC | BufferUsage::MAP_WRITE,
mapped_at_creation: true,
});
state.staging_buffer = Some(staging_buffer);
staging_buffer
};
let matrix_size = std::mem::size_of::<[[f32; 4]; 4]>(); let matrix_size = std::mem::size_of::<[[f32; 4]; 4]>();
let camera_matrix: [f32; 16] = let camera_matrix: [f32; 16] =
(camera.projection_matrix * transform.value.inverse()).to_cols_array(); (camera.projection_matrix * transform.value.inverse()).to_cols_array();
let tmp_buffer = render_resource_context.create_buffer_mapped( render_resource_context.write_mapped_buffer(
BufferInfo { staging_buffer,
size: matrix_size, 0..matrix_size as u64,
buffer_usage: BufferUsage::COPY_SRC,
..Default::default()
},
&mut |data, _renderer| { &mut |data, _renderer| {
data[0..matrix_size].copy_from_slice(camera_matrix.as_bytes()); data[0..matrix_size].copy_from_slice(camera_matrix.as_bytes());
}, },
); );
render_resource_context.unmap_buffer(staging_buffer);
let camera_buffer = state.camera_buffer.unwrap(); let camera_buffer = state.camera_buffer.unwrap();
state state.command_queue.copy_buffer_to_buffer(
.command_queue staging_buffer,
.copy_buffer_to_buffer(tmp_buffer, 0, camera_buffer, 0, matrix_size as u64); 0,
state.command_queue.free_buffer(tmp_buffer); camera_buffer,
0,
matrix_size as u64,
);
} }

View File

@ -63,6 +63,8 @@ where
T: render_resource::RenderResources, T: render_resource::RenderResources,
{ {
uniform_arrays: Vec<Option<(String, BufferArrayStatus)>>, uniform_arrays: Vec<Option<(String, BufferArrayStatus)>>,
staging_buffer: Option<BufferId>,
staging_buffer_size: usize,
_marker: PhantomData<T>, _marker: PhantomData<T>,
} }
@ -73,6 +75,8 @@ where
fn default() -> Self { fn default() -> Self {
Self { Self {
uniform_arrays: Default::default(), uniform_arrays: Default::default(),
staging_buffer: Default::default(),
staging_buffer_size: 0,
_marker: Default::default(), _marker: Default::default(),
} }
} }
@ -166,6 +170,7 @@ where
let buffer = render_resource_context.create_buffer(BufferInfo { let buffer = render_resource_context.create_buffer(BufferInfo {
size: total_size, size: total_size,
buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM, buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM,
..Default::default()
}); });
buffer_array_status.current_item_capacity = new_capacity; buffer_array_status.current_item_capacity = new_capacity;
@ -181,7 +186,7 @@ where
buffer_array_status.buffer = Some(buffer); buffer_array_status.buffer = Some(buffer);
} }
} }
fn update_staging_buffer_offsets(&mut self) -> usize { fn update_staging_buffer(&mut self, render_resource_context: &dyn RenderResourceContext) {
let mut size = 0; let mut size = 0;
for dynamic_buffer_array_status in self.uniform_arrays.iter_mut() { for dynamic_buffer_array_status in self.uniform_arrays.iter_mut() {
if let Some((_name, ref mut buffer_array_status)) = dynamic_buffer_array_status { if let Some((_name, ref mut buffer_array_status)) = dynamic_buffer_array_status {
@ -190,7 +195,24 @@ where
} }
} }
size if self.staging_buffer_size != size {
if let Some(staging_buffer) = self.staging_buffer {
render_resource_context.remove_buffer(staging_buffer);
}
if size > 0 {
let staging_buffer = render_resource_context.create_buffer(BufferInfo {
buffer_usage: BufferUsage::COPY_SRC | BufferUsage::MAP_WRITE,
size,
..Default::default()
});
self.staging_buffer = Some(staging_buffer);
} else {
self.staging_buffer = None;
}
self.staging_buffer_size = size;
}
} }
fn setup_uniform_buffer_resources( fn setup_uniform_buffer_resources(
@ -412,7 +434,9 @@ fn render_resources_node_system<T: RenderResources>(
state state
.uniform_buffer_arrays .uniform_buffer_arrays
.setup_buffer_arrays(render_resource_context, state.dynamic_uniforms); .setup_buffer_arrays(render_resource_context, state.dynamic_uniforms);
let staging_buffer_size = state.uniform_buffer_arrays.update_staging_buffer_offsets(); state
.uniform_buffer_arrays
.update_staging_buffer(render_resource_context);
for (uniforms, draw, render_pipelines) in &mut query.iter() { for (uniforms, draw, render_pipelines) in &mut query.iter() {
if !draw.is_visible { if !draw.is_visible {
@ -426,28 +450,11 @@ fn render_resources_node_system<T: RenderResources>(
) )
} }
if staging_buffer_size == 0 { if let Some(staging_buffer) = state.uniform_buffer_arrays.staging_buffer {
let mut staging_buffer: [u8; 0] = []; render_resource_context.map_buffer(staging_buffer);
for (uniforms, draw, render_pipelines) in &mut query.iter() { render_resource_context.write_mapped_buffer(
if !draw.is_visible { staging_buffer,
return; 0..state.uniform_buffer_arrays.staging_buffer_size as u64,
}
state.uniform_buffer_arrays.setup_uniform_buffer_resources(
&uniforms,
state.dynamic_uniforms,
render_resource_context,
&mut render_pipelines.bindings,
&mut staging_buffer,
);
}
} else {
let staging_buffer = render_resource_context.create_buffer_mapped(
BufferInfo {
buffer_usage: BufferUsage::COPY_SRC,
size: staging_buffer_size,
..Default::default()
},
&mut |mut staging_buffer, _render_resource_context| { &mut |mut staging_buffer, _render_resource_context| {
for (uniforms, draw, render_pipelines) in &mut query.iter() { for (uniforms, draw, render_pipelines) in &mut query.iter() {
if !draw.is_visible { if !draw.is_visible {
@ -464,11 +471,27 @@ fn render_resources_node_system<T: RenderResources>(
} }
}, },
); );
render_resource_context.unmap_buffer(staging_buffer);
state state
.uniform_buffer_arrays .uniform_buffer_arrays
.copy_staging_buffer_to_final_buffers(&mut state.command_queue, staging_buffer); .copy_staging_buffer_to_final_buffers(&mut state.command_queue, staging_buffer);
state.command_queue.free_buffer(staging_buffer); } else {
// TODO: can we just remove this?
let mut staging_buffer: [u8; 0] = [];
for (uniforms, draw, render_pipelines) in &mut query.iter() {
if !draw.is_visible {
return;
}
state.uniform_buffer_arrays.setup_uniform_buffer_resources(
&uniforms,
state.dynamic_uniforms,
render_resource_context,
&mut render_pipelines.bindings,
&mut staging_buffer,
);
}
} }
} }
@ -576,7 +599,7 @@ fn asset_render_resources_node_system<T: RenderResources>(
state state
.uniform_buffer_arrays .uniform_buffer_arrays
.setup_buffer_arrays(render_resource_context, state.dynamic_uniforms); .setup_buffer_arrays(render_resource_context, state.dynamic_uniforms);
let staging_buffer_size = state.uniform_buffer_arrays.update_staging_buffer_offsets(); state.uniform_buffer_arrays.update_staging_buffer(render_resource_context);
for asset_handle in modified_assets.iter() { for asset_handle in modified_assets.iter() {
let asset = assets.get(&asset_handle).expect(EXPECT_ASSET_MESSAGE); let asset = assets.get(&asset_handle).expect(EXPECT_ASSET_MESSAGE);
@ -589,28 +612,11 @@ fn asset_render_resources_node_system<T: RenderResources>(
); );
} }
if staging_buffer_size == 0 { if let Some(staging_buffer) = state.uniform_buffer_arrays.staging_buffer {
let mut staging_buffer: [u8; 0] = []; render_resource_context.map_buffer(staging_buffer);
for asset_handle in modified_assets.iter() { render_resource_context.write_mapped_buffer(
let asset = assets.get(&asset_handle).expect(EXPECT_ASSET_MESSAGE); staging_buffer,
let mut render_resource_bindings = 0..state.uniform_buffer_arrays.staging_buffer_size as u64,
asset_render_resource_bindings.get_or_insert_mut(*asset_handle);
// TODO: only setup buffer if we haven't seen this handle before
state.uniform_buffer_arrays.setup_uniform_buffer_resources(
&asset,
state.dynamic_uniforms,
render_resource_context,
&mut render_resource_bindings,
&mut staging_buffer,
);
}
} else {
let staging_buffer = render_resource_context.create_buffer_mapped(
BufferInfo {
buffer_usage: BufferUsage::COPY_SRC,
size: staging_buffer_size,
..Default::default()
},
&mut |mut staging_buffer, _render_resource_context| { &mut |mut staging_buffer, _render_resource_context| {
for asset_handle in modified_assets.iter() { for asset_handle in modified_assets.iter() {
let asset = assets.get(&asset_handle).expect(EXPECT_ASSET_MESSAGE); let asset = assets.get(&asset_handle).expect(EXPECT_ASSET_MESSAGE);
@ -627,11 +633,26 @@ fn asset_render_resources_node_system<T: RenderResources>(
} }
}, },
); );
render_resource_context.unmap_buffer(staging_buffer);
state state
.uniform_buffer_arrays .uniform_buffer_arrays
.copy_staging_buffer_to_final_buffers(&mut state.command_queue, staging_buffer); .copy_staging_buffer_to_final_buffers(&mut state.command_queue, staging_buffer);
state.command_queue.free_buffer(staging_buffer); } else {
let mut staging_buffer: [u8; 0] = [];
for asset_handle in modified_assets.iter() {
let asset = assets.get(&asset_handle).expect(EXPECT_ASSET_MESSAGE);
let mut render_resource_bindings =
asset_render_resource_bindings.get_or_insert_mut(*asset_handle);
// TODO: only setup buffer if we haven't seen this handle before
state.uniform_buffer_arrays.setup_uniform_buffer_resources(
&asset,
state.dynamic_uniforms,
render_resource_context,
&mut render_resource_bindings,
&mut staging_buffer,
);
}
} }
for (asset_handle, _draw, render_pipelines) in &mut query.iter() { for (asset_handle, _draw, render_pipelines) in &mut query.iter() {

View File

@ -13,6 +13,7 @@ impl BufferId {
pub struct BufferInfo { pub struct BufferInfo {
pub size: usize, pub size: usize,
pub buffer_usage: BufferUsage, pub buffer_usage: BufferUsage,
pub mapped_at_creation: bool,
} }
impl Default for BufferInfo { impl Default for BufferInfo {
@ -20,6 +21,7 @@ impl Default for BufferInfo {
BufferInfo { BufferInfo {
size: 0, size: 0,
buffer_usage: BufferUsage::empty(), buffer_usage: BufferUsage::empty(),
mapped_at_creation: false,
} }
} }
} }

View File

@ -30,19 +30,26 @@ impl SharedBuffers {
) -> Option<RenderResourceBinding> { ) -> Option<RenderResourceBinding> {
if let Some(size) = render_resource.buffer_byte_len() { if let Some(size) = render_resource.buffer_byte_len() {
// PERF: this buffer will be slow // PERF: this buffer will be slow
let staging_buffer = self.render_resource_context.create_buffer_mapped( let staging_buffer = self.render_resource_context.create_buffer(BufferInfo {
BufferInfo { size,
size, buffer_usage: BufferUsage::COPY_SRC | BufferUsage::MAP_WRITE,
buffer_usage: BufferUsage::COPY_SRC, mapped_at_creation: true,
}, });
self.render_resource_context.write_mapped_buffer(
staging_buffer,
0..size as u64,
&mut |data, _renderer| { &mut |data, _renderer| {
render_resource.write_buffer_bytes(data); render_resource.write_buffer_bytes(data);
}, },
); );
self.render_resource_context.unmap_buffer(staging_buffer);
let destination_buffer = self.render_resource_context.create_buffer(BufferInfo { let destination_buffer = self.render_resource_context.create_buffer(BufferInfo {
size, size,
buffer_usage: BufferUsage::COPY_DST | buffer_usage, buffer_usage: BufferUsage::COPY_DST | buffer_usage,
..Default::default()
}); });
let mut command_queue = self.command_queue.write().unwrap(); let mut command_queue = self.command_queue.write().unwrap();

View File

@ -9,6 +9,7 @@ use bevy_asset::{Assets, Handle, HandleUntyped};
use bevy_window::{Window, WindowId}; use bevy_window::{Window, WindowId};
use std::{ use std::{
collections::HashMap, collections::HashMap,
ops::Range,
sync::{Arc, RwLock}, sync::{Arc, RwLock},
}; };
@ -52,15 +53,18 @@ impl RenderResourceContext for HeadlessRenderResourceContext {
self.add_buffer_info(buffer, buffer_info); self.add_buffer_info(buffer, buffer_info);
buffer buffer
} }
fn create_buffer_mapped( fn write_mapped_buffer(
&self, &self,
buffer_info: BufferInfo, id: BufferId,
setup_data: &mut dyn FnMut(&mut [u8], &dyn RenderResourceContext), _range: Range<u64>,
) -> BufferId { write: &mut dyn FnMut(&mut [u8], &dyn RenderResourceContext),
let mut buffer = vec![0; buffer_info.size]; ) {
setup_data(&mut buffer, self); let size = self.buffer_info.read().unwrap().get(&id).unwrap().size;
BufferId::new() let mut buffer = vec![0; size];
write(&mut buffer, self);
} }
fn map_buffer(&self, _id: BufferId) {}
fn unmap_buffer(&self, _id: BufferId) {}
fn create_buffer_with_data(&self, buffer_info: BufferInfo, _data: &[u8]) -> BufferId { fn create_buffer_with_data(&self, buffer_info: BufferInfo, _data: &[u8]) -> BufferId {
let buffer = BufferId::new(); let buffer = BufferId::new();
self.add_buffer_info(buffer, buffer_info); self.add_buffer_info(buffer, buffer_info);

View File

@ -7,6 +7,7 @@ use crate::{
use bevy_asset::{Assets, Handle, HandleUntyped}; use bevy_asset::{Assets, Handle, HandleUntyped};
use bevy_window::{Window, WindowId}; use bevy_window::{Window, WindowId};
use downcast_rs::{impl_downcast, Downcast}; use downcast_rs::{impl_downcast, Downcast};
use std::ops::Range;
pub trait RenderResourceContext: Downcast + Send + Sync + 'static { pub trait RenderResourceContext: Downcast + Send + Sync + 'static {
fn create_swap_chain(&self, window: &Window); fn create_swap_chain(&self, window: &Window);
@ -17,11 +18,20 @@ pub trait RenderResourceContext: Downcast + Send + Sync + 'static {
fn create_texture(&self, texture_descriptor: TextureDescriptor) -> TextureId; fn create_texture(&self, texture_descriptor: TextureDescriptor) -> TextureId;
fn create_buffer(&self, buffer_info: BufferInfo) -> BufferId; fn create_buffer(&self, buffer_info: BufferInfo) -> BufferId;
// TODO: remove RenderResourceContext here // TODO: remove RenderResourceContext here
fn create_buffer_mapped( fn write_mapped_buffer(
&self, &self,
buffer_info: BufferInfo, id: BufferId,
setup_data: &mut dyn FnMut(&mut [u8], &dyn RenderResourceContext), range: Range<u64>,
) -> BufferId; write: &mut dyn FnMut(&mut [u8], &dyn RenderResourceContext),
);
fn map_buffer(
&self,
id: BufferId,
);
fn unmap_buffer(
&self,
id: BufferId,
);
fn create_buffer_with_data(&self, buffer_info: BufferInfo, data: &[u8]) -> BufferId; fn create_buffer_with_data(&self, buffer_info: BufferInfo, data: &[u8]) -> BufferId;
fn create_shader_module(&self, shader_handle: Handle<Shader>, shaders: &Assets<Shader>); fn create_shader_module(&self, shader_handle: Handle<Shader>, shaders: &Assets<Shader>);
fn create_shader_module_from_source(&self, shader_handle: Handle<Shader>, shader: &Shader); fn create_shader_module_from_source(&self, shader_handle: Handle<Shader>, shader: &Shader);

View File

@ -15,7 +15,7 @@ use bevy_render::{
texture::{Extent3d, SamplerDescriptor, TextureDescriptor}, texture::{Extent3d, SamplerDescriptor, TextureDescriptor},
}; };
use bevy_window::{Window, WindowId}; use bevy_window::{Window, WindowId};
use std::sync::Arc; use std::{ops::Range, sync::Arc};
#[derive(Clone)] #[derive(Clone)]
pub struct WgpuRenderResourceContext { pub struct WgpuRenderResourceContext {
@ -167,43 +167,12 @@ impl RenderResourceContext for WgpuRenderResourceContext {
label: None, label: None,
size: buffer_info.size as u64, size: buffer_info.size as u64,
usage: buffer_info.buffer_usage.wgpu_into(), usage: buffer_info.buffer_usage.wgpu_into(),
mapped_at_creation: false, mapped_at_creation: buffer_info.mapped_at_creation,
}); });
let id = BufferId::new(); let id = BufferId::new();
buffer_infos.insert(id, buffer_info); buffer_infos.insert(id, buffer_info);
buffers.insert(id, buffer); buffers.insert(id, Arc::new(buffer));
id
}
fn create_buffer_mapped(
&self,
buffer_info: BufferInfo,
setup_data: &mut dyn FnMut(&mut [u8], &dyn RenderResourceContext),
) -> BufferId {
let usage: wgpu::BufferUsage = buffer_info.buffer_usage.wgpu_into();
let buffer = self.device.create_buffer(&wgpu::BufferDescriptor {
size: buffer_info.size as u64,
usage: usage | wgpu::BufferUsage::MAP_WRITE,
label: None,
mapped_at_creation: false,
});
let buffer_slice = buffer.slice(..);
let data = buffer_slice.map_async(wgpu::MapMode::Write);
self.device.poll(wgpu::Maintain::Wait);
if let Ok(()) = pollster::block_on(data) {
let mut data = buffer_slice.get_mapped_range_mut();
setup_data(&mut data, self);
} else {
panic!("failed to map buffer to host");
}
buffer.unmap();
let id = BufferId::new();
let mut buffer_infos = self.resources.buffer_infos.write().unwrap();
let mut buffers = self.resources.buffers.write().unwrap();
buffer_infos.insert(id, buffer_info);
buffers.insert(id, buffer);
id id
} }
@ -219,7 +188,7 @@ impl RenderResourceContext for WgpuRenderResourceContext {
let id = BufferId::new(); let id = BufferId::new();
buffer_infos.insert(id, buffer_info); buffer_infos.insert(id, buffer_info);
buffers.insert(id, buffer); buffers.insert(id, Arc::new(buffer));
id id
} }
@ -522,4 +491,34 @@ impl RenderResourceContext for WgpuRenderResourceContext {
.get(&buffer) .get(&buffer)
.cloned() .cloned()
} }
fn write_mapped_buffer(
&self,
id: BufferId,
range: Range<u64>,
write: &mut dyn FnMut(&mut [u8], &dyn RenderResourceContext),
) {
let buffer = {
let buffers = self.resources.buffers.read().unwrap();
buffers.get(&id).unwrap().clone()
};
let buffer_slice = buffer.slice(range);
let mut data = buffer_slice.get_mapped_range_mut();
write(&mut data, self);
}
fn map_buffer(&self, id: BufferId) {
let buffers = self.resources.buffers.read().unwrap();
let buffer = buffers.get(&id).unwrap();
let buffer_slice = buffer.slice(..);
let data = buffer_slice.map_async(wgpu::MapMode::Write);
self.device.poll(wgpu::Maintain::Wait);
if let Err(_) = pollster::block_on(data) {
panic!("failed to map buffer to host");
}
}
fn unmap_buffer(&self, id: BufferId) {
let buffers = self.resources.buffers.read().unwrap();
let buffer = buffers.get(&id).unwrap();
buffer.unmap();
}
} }

View File

@ -39,7 +39,7 @@ pub struct WgpuBindGroupInfo {
/// Single threaded implementations don't need to worry about these lifetimes constraints at all. RenderPasses can use a RenderContext's /// Single threaded implementations don't need to worry about these lifetimes constraints at all. RenderPasses can use a RenderContext's
/// WgpuResources directly. RenderContext already has a lifetime greater than the RenderPass. /// WgpuResources directly. RenderContext already has a lifetime greater than the RenderPass.
pub struct WgpuResourcesReadLock<'a> { pub struct WgpuResourcesReadLock<'a> {
pub buffers: RwLockReadGuard<'a, HashMap<BufferId, wgpu::Buffer>>, pub buffers: RwLockReadGuard<'a, HashMap<BufferId, Arc<wgpu::Buffer>>>,
pub textures: RwLockReadGuard<'a, HashMap<TextureId, wgpu::TextureView>>, pub textures: RwLockReadGuard<'a, HashMap<TextureId, wgpu::TextureView>>,
pub swap_chain_frames: RwLockReadGuard<'a, HashMap<TextureId, wgpu::SwapChainFrame>>, pub swap_chain_frames: RwLockReadGuard<'a, HashMap<TextureId, wgpu::SwapChainFrame>>,
pub render_pipelines: pub render_pipelines:
@ -61,7 +61,7 @@ impl<'a> WgpuResourcesReadLock<'a> {
/// Stores read only references to WgpuResource collections. See WgpuResourcesReadLock docs for context on why this exists /// Stores read only references to WgpuResource collections. See WgpuResourcesReadLock docs for context on why this exists
pub struct WgpuResourceRefs<'a> { pub struct WgpuResourceRefs<'a> {
pub buffers: &'a HashMap<BufferId, wgpu::Buffer>, pub buffers: &'a HashMap<BufferId, Arc<wgpu::Buffer>>,
pub textures: &'a HashMap<TextureId, wgpu::TextureView>, pub textures: &'a HashMap<TextureId, wgpu::TextureView>,
pub swap_chain_frames: &'a HashMap<TextureId, wgpu::SwapChainFrame>, pub swap_chain_frames: &'a HashMap<TextureId, wgpu::SwapChainFrame>,
pub render_pipelines: &'a HashMap<Handle<PipelineDescriptor>, wgpu::RenderPipeline>, pub render_pipelines: &'a HashMap<Handle<PipelineDescriptor>, wgpu::RenderPipeline>,
@ -75,7 +75,7 @@ pub struct WgpuResources {
pub window_surfaces: Arc<RwLock<HashMap<WindowId, wgpu::Surface>>>, pub window_surfaces: Arc<RwLock<HashMap<WindowId, wgpu::Surface>>>,
pub window_swap_chains: Arc<RwLock<HashMap<WindowId, wgpu::SwapChain>>>, pub window_swap_chains: Arc<RwLock<HashMap<WindowId, wgpu::SwapChain>>>,
pub swap_chain_frames: Arc<RwLock<HashMap<TextureId, wgpu::SwapChainFrame>>>, pub swap_chain_frames: Arc<RwLock<HashMap<TextureId, wgpu::SwapChainFrame>>>,
pub buffers: Arc<RwLock<HashMap<BufferId, wgpu::Buffer>>>, pub buffers: Arc<RwLock<HashMap<BufferId, Arc<wgpu::Buffer>>>>,
pub texture_views: Arc<RwLock<HashMap<TextureId, wgpu::TextureView>>>, pub texture_views: Arc<RwLock<HashMap<TextureId, wgpu::TextureView>>>,
pub textures: Arc<RwLock<HashMap<TextureId, wgpu::Texture>>>, pub textures: Arc<RwLock<HashMap<TextureId, wgpu::Texture>>>,
pub samplers: Arc<RwLock<HashMap<SamplerId, wgpu::Sampler>>>, pub samplers: Arc<RwLock<HashMap<SamplerId, wgpu::Sampler>>>,