From e6095223424122f093206c127f50a10c4b8109d1 Mon Sep 17 00:00:00 2001 From: Renato Caldas Date: Fri, 22 Jan 2021 01:53:43 +0000 Subject: [PATCH] Add support for reading from mapped buffers (#1274) * Add support for mapping buffers for reading. * Add support for reading from a mapped buffer. --- .../bevy_pbr/src/render_graph/lights_node.rs | 4 +-- .../src/render_graph/nodes/camera_node.rs | 4 +-- .../nodes/render_resources_node.rs | 6 ++--- .../headless_render_resource_context.rs | 17 ++++++++++-- .../src/renderer/render_resource/buffer.rs | 6 +++++ .../render_resource/shared_buffers.rs | 4 +-- .../src/renderer/render_resource_context.rs | 12 +++++++-- .../renderer/wgpu_render_resource_context.rs | 27 ++++++++++++++++--- 8 files changed, 63 insertions(+), 17 deletions(-) diff --git a/crates/bevy_pbr/src/render_graph/lights_node.rs b/crates/bevy_pbr/src/render_graph/lights_node.rs index d327d56c2fffe8..94ad213f4fbfcb 100644 --- a/crates/bevy_pbr/src/render_graph/lights_node.rs +++ b/crates/bevy_pbr/src/render_graph/lights_node.rs @@ -9,7 +9,7 @@ use bevy_ecs::{ use bevy_render::{ render_graph::{CommandQueue, Node, ResourceSlots, SystemNode}, renderer::{ - BufferId, BufferInfo, BufferUsage, RenderContext, RenderResourceBinding, + BufferId, BufferInfo, BufferMapMode, BufferUsage, RenderContext, RenderResourceBinding, RenderResourceBindings, RenderResourceContext, }, }; @@ -103,7 +103,7 @@ pub fn lights_node_system( return; } - render_resource_context.map_buffer(staging_buffer); + render_resource_context.map_buffer(staging_buffer, BufferMapMode::Write); } else { let buffer = render_resource_context.create_buffer(BufferInfo { size: max_light_uniform_size, diff --git a/crates/bevy_render/src/render_graph/nodes/camera_node.rs b/crates/bevy_render/src/render_graph/nodes/camera_node.rs index 245b890d920420..54d119c13a4b4f 100644 --- a/crates/bevy_render/src/render_graph/nodes/camera_node.rs +++ b/crates/bevy_render/src/render_graph/nodes/camera_node.rs @@ -2,7 +2,7 @@ use crate::{ camera::{ActiveCameras, Camera}, render_graph::{CommandQueue, Node, ResourceSlots, SystemNode}, renderer::{ - BufferId, BufferInfo, BufferUsage, RenderContext, RenderResourceBinding, + BufferId, BufferInfo, BufferMapMode, BufferUsage, RenderContext, RenderResourceBinding, RenderResourceBindings, RenderResourceContext, }, }; @@ -87,7 +87,7 @@ pub fn camera_node_system( }; let staging_buffer = if let Some(staging_buffer) = state.staging_buffer { - render_resource_context.map_buffer(staging_buffer); + render_resource_context.map_buffer(staging_buffer, BufferMapMode::Write); staging_buffer } else { let size = std::mem::size_of::<[[f32; 4]; 4]>(); diff --git a/crates/bevy_render/src/render_graph/nodes/render_resources_node.rs b/crates/bevy_render/src/render_graph/nodes/render_resources_node.rs index 68422596b07ff5..141d8bfc9d7573 100644 --- a/crates/bevy_render/src/render_graph/nodes/render_resources_node.rs +++ b/crates/bevy_render/src/render_graph/nodes/render_resources_node.rs @@ -3,7 +3,7 @@ use crate::{ prelude::Visible, render_graph::{CommandQueue, Node, ResourceSlots, SystemNode}, renderer::{ - self, BufferInfo, BufferUsage, RenderContext, RenderResourceBinding, + self, BufferInfo, BufferMapMode, BufferUsage, RenderContext, RenderResourceBinding, RenderResourceBindings, RenderResourceContext, RenderResourceHints, }, texture, @@ -490,7 +490,7 @@ fn render_resources_node_system( uniform_buffer_arrays.resize_staging_buffer(render_resource_context); if let Some(staging_buffer) = state.uniform_buffer_arrays.staging_buffer { - render_resource_context.map_buffer(staging_buffer); + render_resource_context.map_buffer(staging_buffer, BufferMapMode::Write); render_resource_context.write_mapped_buffer( staging_buffer, 0..state.uniform_buffer_arrays.staging_buffer_size as u64, @@ -703,7 +703,7 @@ fn asset_render_resources_node_system( uniform_buffer_arrays.resize_staging_buffer(render_resource_context); if let Some(staging_buffer) = state.uniform_buffer_arrays.staging_buffer { - render_resource_context.map_buffer(staging_buffer); + render_resource_context.map_buffer(staging_buffer, BufferMapMode::Write); render_resource_context.write_mapped_buffer( staging_buffer, 0..state.uniform_buffer_arrays.staging_buffer_size as u64, diff --git a/crates/bevy_render/src/renderer/headless_render_resource_context.rs b/crates/bevy_render/src/renderer/headless_render_resource_context.rs index ed182a51bb1d39..738c065966b1c7 100644 --- a/crates/bevy_render/src/renderer/headless_render_resource_context.rs +++ b/crates/bevy_render/src/renderer/headless_render_resource_context.rs @@ -1,7 +1,9 @@ use super::RenderResourceContext; use crate::{ pipeline::{BindGroupDescriptorId, PipelineDescriptor}, - renderer::{BindGroup, BufferId, BufferInfo, RenderResourceId, SamplerId, TextureId}, + renderer::{ + BindGroup, BufferId, BufferInfo, BufferMapMode, RenderResourceId, SamplerId, TextureId, + }, shader::{Shader, ShaderError}, texture::{SamplerDescriptor, TextureDescriptor}, }; @@ -66,7 +68,18 @@ impl RenderResourceContext for HeadlessRenderResourceContext { write(&mut buffer, self); } - fn map_buffer(&self, _id: BufferId) {} + fn read_mapped_buffer( + &self, + id: BufferId, + _range: Range, + read: &dyn Fn(&[u8], &dyn RenderResourceContext), + ) { + let size = self.buffer_info.read().get(&id).unwrap().size; + let buffer = vec![0; size]; + read(&buffer, self); + } + + fn map_buffer(&self, _id: BufferId, _mode: BufferMapMode) {} fn unmap_buffer(&self, _id: BufferId) {} diff --git a/crates/bevy_render/src/renderer/render_resource/buffer.rs b/crates/bevy_render/src/renderer/render_resource/buffer.rs index c254e228f17d14..00252ffa9e2d6e 100644 --- a/crates/bevy_render/src/renderer/render_resource/buffer.rs +++ b/crates/bevy_render/src/renderer/render_resource/buffer.rs @@ -43,3 +43,9 @@ bitflags::bitflags! { const INDIRECT = 256; } } + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum BufferMapMode { + Read, + Write, +} diff --git a/crates/bevy_render/src/renderer/render_resource/shared_buffers.rs b/crates/bevy_render/src/renderer/render_resource/shared_buffers.rs index bf2e399e19938a..82dfc231bb8003 100644 --- a/crates/bevy_render/src/renderer/render_resource/shared_buffers.rs +++ b/crates/bevy_render/src/renderer/render_resource/shared_buffers.rs @@ -1,7 +1,7 @@ use super::{BufferId, BufferInfo, RenderResource, RenderResourceBinding}; use crate::{ render_graph::CommandQueue, - renderer::{BufferUsage, RenderContext, RenderResourceContext}, + renderer::{BufferMapMode, BufferUsage, RenderContext, RenderResourceContext}, }; use bevy_ecs::{Res, ResMut}; @@ -115,7 +115,7 @@ impl SharedBuffers { } if let Some(staging_buffer) = self.staging_buffer { - render_resource_context.map_buffer(staging_buffer); + render_resource_context.map_buffer(staging_buffer, BufferMapMode::Write); } } diff --git a/crates/bevy_render/src/renderer/render_resource_context.rs b/crates/bevy_render/src/renderer/render_resource_context.rs index 365595fac78168..87d3e21a0603c5 100644 --- a/crates/bevy_render/src/renderer/render_resource_context.rs +++ b/crates/bevy_render/src/renderer/render_resource_context.rs @@ -1,6 +1,8 @@ use crate::{ pipeline::{BindGroupDescriptorId, PipelineDescriptor, PipelineLayout}, - renderer::{BindGroup, BufferId, BufferInfo, RenderResourceId, SamplerId, TextureId}, + renderer::{ + BindGroup, BufferId, BufferInfo, BufferMapMode, RenderResourceId, SamplerId, TextureId, + }, shader::{Shader, ShaderError, ShaderLayout, ShaderStages}, texture::{SamplerDescriptor, TextureDescriptor}, }; @@ -24,7 +26,13 @@ pub trait RenderResourceContext: Downcast + Send + Sync + 'static { range: Range, write: &mut dyn FnMut(&mut [u8], &dyn RenderResourceContext), ); - fn map_buffer(&self, id: BufferId); + fn read_mapped_buffer( + &self, + id: BufferId, + range: Range, + read: &dyn Fn(&[u8], &dyn RenderResourceContext), + ); + fn map_buffer(&self, id: BufferId, mode: BufferMapMode); fn unmap_buffer(&self, id: BufferId); fn create_buffer_with_data(&self, buffer_info: BufferInfo, data: &[u8]) -> BufferId; fn create_shader_module(&self, shader_handle: &Handle, shaders: &Assets); diff --git a/crates/bevy_wgpu/src/renderer/wgpu_render_resource_context.rs b/crates/bevy_wgpu/src/renderer/wgpu_render_resource_context.rs index bd1be8db72260a..6bbaf74eb44b92 100644 --- a/crates/bevy_wgpu/src/renderer/wgpu_render_resource_context.rs +++ b/crates/bevy_wgpu/src/renderer/wgpu_render_resource_context.rs @@ -9,8 +9,8 @@ use bevy_render::{ BindGroupDescriptor, BindGroupDescriptorId, BindingShaderStage, PipelineDescriptor, }, renderer::{ - BindGroup, BufferId, BufferInfo, RenderResourceBinding, RenderResourceContext, - RenderResourceId, SamplerId, TextureId, + BindGroup, BufferId, BufferInfo, BufferMapMode, RenderResourceBinding, + RenderResourceContext, RenderResourceId, SamplerId, TextureId, }, shader::{glsl_to_spirv, Shader, ShaderError, ShaderSource}, texture::{Extent3d, SamplerDescriptor, TextureDescriptor}, @@ -622,11 +622,30 @@ impl RenderResourceContext for WgpuRenderResourceContext { write(&mut data, self); } - fn map_buffer(&self, id: BufferId) { + fn read_mapped_buffer( + &self, + id: BufferId, + range: Range, + read: &dyn Fn(&[u8], &dyn RenderResourceContext), + ) { + let buffer = { + let buffers = self.resources.buffers.read(); + buffers.get(&id).unwrap().clone() + }; + let buffer_slice = buffer.slice(range); + let data = buffer_slice.get_mapped_range(); + read(&data, self); + } + + fn map_buffer(&self, id: BufferId, mode: BufferMapMode) { let buffers = self.resources.buffers.read(); let buffer = buffers.get(&id).unwrap(); let buffer_slice = buffer.slice(..); - let data = buffer_slice.map_async(wgpu::MapMode::Write); + let wgpu_mode = match mode { + BufferMapMode::Read => wgpu::MapMode::Read, + BufferMapMode::Write => wgpu::MapMode::Write, + }; + let data = buffer_slice.map_async(wgpu_mode); self.device.poll(wgpu::Maintain::Wait); if future::block_on(data).is_err() { panic!("Failed to map buffer to host.");