mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
[rs] Merge #710
710: Implement read_buffer r=kvark a=fintelia I'm not sure about the exact interface that makes sense, but this PR sketches out how read_buffer (and eventually also read_texture) could be implemented. Resolves #694 Co-authored-by: Dzmitry Malyshau <kvarkus@gmail.com> Co-authored-by: Jonathan Behrens <fintelia@gmail.com>
This commit is contained in:
@@ -1325,7 +1325,6 @@ impl crate::Context for Context {
|
||||
Ok(ptr) => BufferMappedRange {
|
||||
ptr,
|
||||
size: size as usize,
|
||||
phantom: PhantomData,
|
||||
},
|
||||
Err(err) => self.handle_error_fatal(err, "Buffer::get_mapped_range"),
|
||||
}
|
||||
@@ -1897,13 +1896,12 @@ fn default_error_handler(err: crate::Error) {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BufferMappedRange<'a> {
|
||||
pub struct BufferMappedRange {
|
||||
ptr: *mut u8,
|
||||
size: usize,
|
||||
phantom: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
impl<'a> crate::BufferMappedRangeSlice for BufferMappedRange<'a> {
|
||||
impl crate::BufferMappedRangeSlice for BufferMappedRange {
|
||||
fn slice(&self) -> &[u8] {
|
||||
unsafe { slice::from_raw_parts(self.ptr, self.size) }
|
||||
}
|
||||
@@ -1913,7 +1911,7 @@ impl<'a> crate::BufferMappedRangeSlice for BufferMappedRange<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for BufferMappedRange<'a> {
|
||||
impl Drop for BufferMappedRange {
|
||||
fn drop(&mut self) {
|
||||
// Intentionally left blank so that `BufferMappedRange` still
|
||||
// implements `Drop`, to match the web backend
|
||||
|
||||
@@ -2,7 +2,6 @@ use std::{
|
||||
collections::HashSet,
|
||||
fmt,
|
||||
future::Future,
|
||||
marker::PhantomData,
|
||||
ops::Range,
|
||||
pin::Pin,
|
||||
task::{self, Poll},
|
||||
@@ -1436,7 +1435,6 @@ impl crate::Context for Context {
|
||||
BufferMappedRange {
|
||||
actual_mapping,
|
||||
temporary_mapping,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1888,13 +1886,12 @@ impl crate::Context for Context {
|
||||
pub(crate) type SwapChainOutputDetail = ();
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BufferMappedRange<'a> {
|
||||
pub struct BufferMappedRange {
|
||||
actual_mapping: js_sys::Uint8Array,
|
||||
temporary_mapping: Vec<u8>,
|
||||
phantom: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
impl<'a> crate::BufferMappedRangeSlice for BufferMappedRange<'a> {
|
||||
impl crate::BufferMappedRangeSlice for BufferMappedRange {
|
||||
fn slice(&self) -> &[u8] {
|
||||
&self.temporary_mapping
|
||||
}
|
||||
@@ -1904,7 +1901,7 @@ impl<'a> crate::BufferMappedRangeSlice for BufferMappedRange<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for BufferMappedRange<'a> {
|
||||
impl Drop for BufferMappedRange {
|
||||
fn drop(&mut self) {
|
||||
// Copy from the temporary mapping back into the array buffer that was
|
||||
// originally provided by the browser
|
||||
|
||||
@@ -1690,14 +1690,14 @@ trait BufferMappedRangeSlice {
|
||||
#[derive(Debug)]
|
||||
pub struct BufferView<'a> {
|
||||
slice: BufferSlice<'a>,
|
||||
data: BufferMappedRange<'a>,
|
||||
data: BufferMappedRange,
|
||||
}
|
||||
|
||||
/// Write only view into mapped buffer.
|
||||
#[derive(Debug)]
|
||||
pub struct BufferViewMut<'a> {
|
||||
slice: BufferSlice<'a>,
|
||||
data: BufferMappedRange<'a>,
|
||||
data: BufferMappedRange,
|
||||
readable: bool,
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ mod encoder;
|
||||
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
future::Future,
|
||||
mem::{align_of, size_of},
|
||||
ptr::copy_nonoverlapping,
|
||||
};
|
||||
@@ -54,3 +55,42 @@ pub fn make_spirv<'a>(data: &'a [u8]) -> super::ShaderSource<'a> {
|
||||
);
|
||||
super::ShaderSource::SpirV(words)
|
||||
}
|
||||
|
||||
/// CPU accessible buffer used to download data back from the GPU.
|
||||
pub struct DownloadBuffer(super::Buffer, super::BufferMappedRange);
|
||||
|
||||
impl DownloadBuffer {
|
||||
/// Asynchronously read the contents of a buffer.
|
||||
pub fn read_buffer(device: &super::Device, queue: &super::Queue, buffer: &super::BufferSlice) -> impl Future<Output=Result<Self, super::BufferAsyncError>> + Send {
|
||||
let size = match buffer.size {
|
||||
Some(size) => size.into(),
|
||||
None => buffer.buffer.map_context.lock().total_size - buffer.offset,
|
||||
};
|
||||
|
||||
let download = device.create_buffer(&super::BufferDescriptor {
|
||||
size,
|
||||
usage: super::BufferUsage::COPY_DST | super::BufferUsage::MAP_READ,
|
||||
mapped_at_creation: false,
|
||||
label: None,
|
||||
});
|
||||
|
||||
let mut encoder = device.create_command_encoder(&super::CommandEncoderDescriptor { label: None });
|
||||
encoder.copy_buffer_to_buffer(buffer.buffer, buffer.offset, &download, 0, size);
|
||||
let command_buffer: super::CommandBuffer = encoder.finish();
|
||||
queue.submit(Some(command_buffer));
|
||||
|
||||
let fut = download.slice(..).map_async(super::MapMode::Read);
|
||||
async move {
|
||||
fut.await?;
|
||||
let mapped_range = super::Context::buffer_get_mapped_range(&*download.context, &download.id, 0..size);
|
||||
Ok(Self(download, mapped_range))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for DownloadBuffer{
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
super::BufferMappedRangeSlice::slice(&self.1)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user