mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
Merge #344
344: Use the new map-async r=kvark a=kvark Depends on https://github.com/gfx-rs/wgpu/pull/675 It changes the API of mapping and removes `create_buffer_mapped`. The new functionality is not implemented in Gecko yet, so this breaks the web target, for now. Co-authored-by: Dzmitry Malyshau <kvarkus@gmail.com>
This commit is contained in:
@@ -28,14 +28,14 @@ vulkan = ["wgc/gfx-backend-vulkan"]
|
||||
package = "wgpu-core"
|
||||
version = "0.5"
|
||||
git = "https://github.com/gfx-rs/wgpu"
|
||||
rev = "fbc2c87de61b0e7bab2583ddf305742e3cbf85e8"
|
||||
rev = "9120f0399ce8d8cc48b0b87c26d58c71b2e925be"
|
||||
features = ["raw-window-handle"]
|
||||
|
||||
[dependencies.wgt]
|
||||
package = "wgpu-types"
|
||||
version = "0.5"
|
||||
git = "https://github.com/gfx-rs/wgpu"
|
||||
rev = "fbc2c87de61b0e7bab2583ddf305742e3cbf85e8"
|
||||
rev = "9120f0399ce8d8cc48b0b87c26d58c71b2e925be"
|
||||
|
||||
[dependencies]
|
||||
arrayvec = "0.5"
|
||||
|
||||
@@ -34,9 +34,10 @@ async fn run() {
|
||||
|
||||
// The output buffer lets us retrieve the data as an array
|
||||
let output_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: None,
|
||||
size: (size * size) as u64 * size_of::<u32>() as u64,
|
||||
usage: wgpu::BufferUsage::MAP_READ | wgpu::BufferUsage::COPY_DST,
|
||||
label: None,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
|
||||
let texture_extent = wgpu::Extent3d {
|
||||
@@ -95,7 +96,7 @@ async fn run() {
|
||||
queue.submit(Some(command_buffer));
|
||||
|
||||
// Note that we're not calling `.await` here.
|
||||
let buffer_future = output_buffer.map_read(0, wgt::BufferSize::WHOLE);
|
||||
let buffer_future = output_buffer.map_async(wgpu::MapMode::Read, 0, wgt::BufferSize::WHOLE);
|
||||
|
||||
// Poll the device in a blocking manner so that our future resolves.
|
||||
// In an actual application, `device.poll(...)` should
|
||||
@@ -108,15 +109,17 @@ async fn run() {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Ok(mapping) = buffer_future.await {
|
||||
if let Ok(()) = buffer_future.await {
|
||||
let data = output_buffer.get_mapped_range(0, wgt::BufferSize::WHOLE);
|
||||
let mut png_encoder = png::Encoder::new(File::create("red.png").unwrap(), size, size);
|
||||
png_encoder.set_depth(png::BitDepth::Eight);
|
||||
png_encoder.set_color(png::ColorType::RGBA);
|
||||
png_encoder
|
||||
.write_header()
|
||||
.unwrap()
|
||||
.write_image_data(mapping.as_slice())
|
||||
.write_image_data(data)
|
||||
.unwrap();
|
||||
output_buffer.unmap();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,20 +51,20 @@ async fn execute_gpu(numbers: Vec<u32>) -> Vec<u32> {
|
||||
let cs_module =
|
||||
device.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&cs[..])).unwrap());
|
||||
|
||||
let staging_buffer = device.create_buffer_with_data(
|
||||
bytemuck::cast_slice(&numbers),
|
||||
wgpu::BufferUsage::MAP_READ | wgpu::BufferUsage::COPY_DST | wgpu::BufferUsage::COPY_SRC,
|
||||
);
|
||||
|
||||
let storage_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
size,
|
||||
usage: wgpu::BufferUsage::STORAGE
|
||||
| wgpu::BufferUsage::COPY_DST
|
||||
| wgpu::BufferUsage::COPY_SRC,
|
||||
let staging_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: None,
|
||||
size,
|
||||
usage: wgpu::BufferUsage::MAP_READ | wgpu::BufferUsage::COPY_DST,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
|
||||
let storage_buffer = device.create_buffer_with_data(
|
||||
bytemuck::cast_slice(&numbers),
|
||||
wgpu::BufferUsage::STORAGE | wgpu::BufferUsage::COPY_DST | wgpu::BufferUsage::COPY_SRC,
|
||||
);
|
||||
|
||||
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
label: None,
|
||||
bindings: &[wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStage::COMPUTE,
|
||||
@@ -73,16 +73,15 @@ async fn execute_gpu(numbers: Vec<u32>) -> Vec<u32> {
|
||||
readonly: false,
|
||||
},
|
||||
}],
|
||||
label: None,
|
||||
});
|
||||
|
||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
label: None,
|
||||
layout: &bind_group_layout,
|
||||
bindings: &[wgpu::Binding {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Buffer(storage_buffer.slice(..)),
|
||||
}],
|
||||
label: None,
|
||||
});
|
||||
|
||||
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
@@ -99,7 +98,6 @@ async fn execute_gpu(numbers: Vec<u32>) -> Vec<u32> {
|
||||
|
||||
let mut encoder =
|
||||
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
||||
encoder.copy_buffer_to_buffer(&staging_buffer, 0, &storage_buffer, 0, size);
|
||||
{
|
||||
let mut cpass = encoder.begin_compute_pass();
|
||||
cpass.set_pipeline(&compute_pipeline);
|
||||
@@ -111,19 +109,21 @@ async fn execute_gpu(numbers: Vec<u32>) -> Vec<u32> {
|
||||
queue.submit(Some(encoder.finish()));
|
||||
|
||||
// Note that we're not calling `.await` here.
|
||||
let buffer_future = staging_buffer.map_read(0, wgt::BufferSize::WHOLE);
|
||||
let buffer_future = staging_buffer.map_async(wgpu::MapMode::Read, 0, wgt::BufferSize::WHOLE);
|
||||
|
||||
// Poll the device in a blocking manner so that our future resolves.
|
||||
// In an actual application, `device.poll(...)` should
|
||||
// be called in an event loop or on another thread.
|
||||
device.poll(wgpu::Maintain::Wait);
|
||||
|
||||
if let Ok(mapping) = buffer_future.await {
|
||||
mapping
|
||||
.as_slice()
|
||||
if let Ok(()) = buffer_future.await {
|
||||
let data = staging_buffer.get_mapped_range(0, wgt::BufferSize::WHOLE);
|
||||
let result = data
|
||||
.chunks_exact(4)
|
||||
.map(|b| u32::from_ne_bytes(b.try_into().unwrap()))
|
||||
.collect()
|
||||
.collect();
|
||||
staging_buffer.unmap();
|
||||
result
|
||||
} else {
|
||||
panic!("failed to run compute on gpu!")
|
||||
}
|
||||
|
||||
@@ -236,9 +236,10 @@ impl framework::Example for Example {
|
||||
|
||||
let entity_uniform_size = mem::size_of::<EntityUniforms>() as wgpu::BufferAddress;
|
||||
let plane_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: None,
|
||||
size: entity_uniform_size,
|
||||
usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
|
||||
label: None,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
|
||||
let local_bind_group_layout =
|
||||
@@ -316,9 +317,10 @@ impl framework::Example for Example {
|
||||
scale: cube.scale,
|
||||
};
|
||||
let uniform_buf = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: None,
|
||||
size: entity_uniform_size,
|
||||
usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
|
||||
label: None,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
entities.push(Entity {
|
||||
mx_world: cgmath::Matrix4::from(transform),
|
||||
@@ -408,11 +410,12 @@ impl framework::Example for Example {
|
||||
let light_uniform_size =
|
||||
(Self::MAX_LIGHTS * mem::size_of::<LightRaw>()) as wgpu::BufferAddress;
|
||||
let light_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: None,
|
||||
size: light_uniform_size,
|
||||
usage: wgpu::BufferUsage::UNIFORM
|
||||
| wgpu::BufferUsage::COPY_SRC
|
||||
| wgpu::BufferUsage::COPY_DST,
|
||||
label: None,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
|
||||
let vb_desc = wgpu::VertexBufferDescriptor {
|
||||
@@ -438,9 +441,10 @@ impl framework::Example for Example {
|
||||
|
||||
let uniform_size = mem::size_of::<ShadowUniforms>() as wgpu::BufferAddress;
|
||||
let uniform_buf = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: None,
|
||||
size: uniform_size,
|
||||
usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
|
||||
label: None,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
|
||||
// Create bind group
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use crate::{
|
||||
backend::native_gpu_future, BindGroupDescriptor, BindGroupLayoutDescriptor, BindingResource,
|
||||
BindingType, BufferDescriptor, CommandEncoderDescriptor, ComputePipelineDescriptor, Extensions,
|
||||
Limits, PipelineLayoutDescriptor, RenderPipelineDescriptor, SamplerDescriptor, SwapChainStatus,
|
||||
TextureDescriptor, TextureViewDescriptor, TextureViewDimension,
|
||||
Limits, MapMode, PipelineLayoutDescriptor, RenderPipelineDescriptor, SamplerDescriptor,
|
||||
SwapChainStatus, TextureDescriptor, TextureViewDescriptor, TextureViewDimension,
|
||||
};
|
||||
|
||||
use arrayvec::ArrayVec;
|
||||
@@ -202,18 +202,12 @@ impl crate::Context for Context {
|
||||
type SwapChainId = wgc::id::SwapChainId;
|
||||
type RenderPassId = wgc::command::RawPass;
|
||||
|
||||
type CreateBufferMappedDetail = CreateBufferMappedDetail;
|
||||
type BufferReadMappingDetail = BufferReadMappingDetail;
|
||||
type BufferWriteMappingDetail = BufferWriteMappingDetail;
|
||||
type SwapChainOutputDetail = SwapChainOutputDetail;
|
||||
|
||||
type RequestAdapterFuture = Ready<Option<Self::AdapterId>>;
|
||||
type RequestDeviceFuture =
|
||||
Ready<Result<(Self::DeviceId, Self::QueueId), crate::RequestDeviceError>>;
|
||||
type MapReadFuture =
|
||||
native_gpu_future::GpuFuture<Result<BufferReadMappingDetail, crate::BufferAsyncError>>;
|
||||
type MapWriteFuture =
|
||||
native_gpu_future::GpuFuture<Result<BufferWriteMappingDetail, crate::BufferAsyncError>>;
|
||||
type MapAsyncFuture = native_gpu_future::GpuFuture<Result<(), crate::BufferAsyncError>>;
|
||||
|
||||
fn init() -> Self {
|
||||
wgc::hub::Global::new("wgpu", wgc::hub::IdentityManagerFactory)
|
||||
@@ -513,23 +507,6 @@ impl crate::Context for Context {
|
||||
))
|
||||
}
|
||||
|
||||
fn device_create_buffer_mapped<'a>(
|
||||
&self,
|
||||
device: &Self::DeviceId,
|
||||
desc: &BufferDescriptor,
|
||||
) -> (Self::BufferId, &'a mut [u8], Self::CreateBufferMappedDetail) {
|
||||
let owned_label = OwnedLabel::new(desc.label.as_deref());
|
||||
unsafe {
|
||||
let (id, ptr) = gfx_select!(*device => self.device_create_buffer_mapped(
|
||||
*device,
|
||||
&desc.map_label(|_| owned_label.as_ptr()),
|
||||
PhantomData
|
||||
));
|
||||
let mapped_data = std::slice::from_raw_parts_mut(ptr, desc.size as usize);
|
||||
(id, mapped_data, CreateBufferMappedDetail)
|
||||
}
|
||||
}
|
||||
|
||||
fn device_create_buffer(
|
||||
&self,
|
||||
device: &Self::DeviceId,
|
||||
@@ -603,78 +580,65 @@ impl crate::Context for Context {
|
||||
));
|
||||
}
|
||||
|
||||
fn buffer_map_read(
|
||||
fn buffer_map_async(
|
||||
&self,
|
||||
buffer: &Self::BufferId,
|
||||
mode: MapMode,
|
||||
range: Range<wgt::BufferAddress>,
|
||||
) -> Self::MapReadFuture {
|
||||
let (future, completion) =
|
||||
native_gpu_future::new_gpu_future(*buffer, range.end - range.start);
|
||||
) -> Self::MapAsyncFuture {
|
||||
let (future, completion) = native_gpu_future::new_gpu_future();
|
||||
|
||||
extern "C" fn buffer_map_read_future_wrapper(
|
||||
extern "C" fn buffer_map_future_wrapper(
|
||||
status: wgc::resource::BufferMapAsyncStatus,
|
||||
data: *const u8,
|
||||
user_data: *mut u8,
|
||||
) {
|
||||
let completion =
|
||||
unsafe { native_gpu_future::GpuFutureCompletion::from_raw(user_data as _) };
|
||||
let (buffer_id, size) = completion.get_buffer_info();
|
||||
|
||||
if let wgc::resource::BufferMapAsyncStatus::Success = status {
|
||||
completion.complete(Ok(BufferReadMappingDetail {
|
||||
data,
|
||||
size: size as usize,
|
||||
buffer_id,
|
||||
}));
|
||||
} else {
|
||||
completion.complete(Err(crate::BufferAsyncError));
|
||||
}
|
||||
completion.complete(match status {
|
||||
wgc::resource::BufferMapAsyncStatus::Success => Ok(()),
|
||||
_ => Err(crate::BufferAsyncError),
|
||||
})
|
||||
}
|
||||
|
||||
let operation = wgc::resource::BufferMapOperation::Read {
|
||||
callback: buffer_map_read_future_wrapper,
|
||||
userdata: completion.to_raw() as _,
|
||||
let operation = wgc::resource::BufferMapOperation {
|
||||
host: match mode {
|
||||
MapMode::Read => wgc::device::HostMap::Read,
|
||||
MapMode::Write => wgc::device::HostMap::Write,
|
||||
},
|
||||
callback: buffer_map_future_wrapper,
|
||||
user_data: completion.to_raw() as _,
|
||||
};
|
||||
gfx_select!(*buffer => self.buffer_map_async(*buffer, range, operation));
|
||||
|
||||
future
|
||||
}
|
||||
|
||||
fn buffer_map_write(
|
||||
fn buffer_get_mapped_range(
|
||||
&self,
|
||||
buffer: &Self::BufferId,
|
||||
range: Range<wgt::BufferAddress>,
|
||||
) -> Self::MapWriteFuture {
|
||||
let (future, completion) =
|
||||
native_gpu_future::new_gpu_future(*buffer, range.end - range.start);
|
||||
sub_range: Range<wgt::BufferAddress>,
|
||||
) -> &[u8] {
|
||||
let size = sub_range.end - sub_range.start;
|
||||
let ptr = gfx_select!(*buffer => self.buffer_get_mapped_range(
|
||||
*buffer,
|
||||
sub_range.start,
|
||||
wgt::BufferSize(size)
|
||||
));
|
||||
unsafe { slice::from_raw_parts(ptr, size as usize) }
|
||||
}
|
||||
|
||||
extern "C" fn buffer_map_write_future_wrapper(
|
||||
status: wgc::resource::BufferMapAsyncStatus,
|
||||
data: *mut u8,
|
||||
user_data: *mut u8,
|
||||
) {
|
||||
let completion =
|
||||
unsafe { native_gpu_future::GpuFutureCompletion::from_raw(user_data as _) };
|
||||
let (buffer_id, size) = completion.get_buffer_info();
|
||||
|
||||
if let wgc::resource::BufferMapAsyncStatus::Success = status {
|
||||
completion.complete(Ok(BufferWriteMappingDetail {
|
||||
data,
|
||||
size: size as usize,
|
||||
buffer_id,
|
||||
}));
|
||||
} else {
|
||||
completion.complete(Err(crate::BufferAsyncError));
|
||||
}
|
||||
}
|
||||
|
||||
let operation = wgc::resource::BufferMapOperation::Write {
|
||||
callback: buffer_map_write_future_wrapper,
|
||||
userdata: completion.to_raw() as _,
|
||||
};
|
||||
gfx_select!(*buffer => self.buffer_map_async(*buffer, range, operation));
|
||||
|
||||
future
|
||||
fn buffer_get_mapped_range_mut(
|
||||
&self,
|
||||
buffer: &Self::BufferId,
|
||||
sub_range: Range<wgt::BufferAddress>,
|
||||
) -> &mut [u8] {
|
||||
let size = sub_range.end - sub_range.start;
|
||||
let ptr = gfx_select!(*buffer => self.buffer_get_mapped_range(
|
||||
*buffer,
|
||||
sub_range.start,
|
||||
wgt::BufferSize(size)
|
||||
));
|
||||
unsafe { slice::from_raw_parts_mut(ptr, size as usize) }
|
||||
}
|
||||
|
||||
fn buffer_unmap(&self, buffer: &Self::BufferId) {
|
||||
@@ -749,8 +713,6 @@ impl crate::Context for Context {
|
||||
gfx_select!(*pipeline => self.render_pipeline_destroy(*pipeline))
|
||||
}
|
||||
|
||||
fn flush_mapped_data(_data: &mut [u8], _detail: CreateBufferMappedDetail) {}
|
||||
|
||||
fn encoder_copy_buffer_to_buffer(
|
||||
&self,
|
||||
encoder: &Self::CommandEncoderId,
|
||||
@@ -933,38 +895,6 @@ impl crate::Context for Context {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct CreateBufferMappedDetail;
|
||||
|
||||
pub(crate) struct BufferReadMappingDetail {
|
||||
pub(crate) buffer_id: wgc::id::BufferId,
|
||||
data: *const u8,
|
||||
size: usize,
|
||||
}
|
||||
|
||||
impl BufferReadMappingDetail {
|
||||
pub(crate) fn as_slice(&self) -> &[u8] {
|
||||
unsafe { slice::from_raw_parts(self.data as *const u8, self.size) }
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct BufferWriteMappingDetail {
|
||||
pub(crate) buffer_id: wgc::id::BufferId,
|
||||
data: *mut u8,
|
||||
size: usize,
|
||||
}
|
||||
|
||||
// SAFETY: It is safe to implement Send for `BufferReadMappingDetail` and `BufferWriteMappingDetail`
|
||||
// because the only !Send field is `data`, and it is used similarly to `&[u8]` or `&mut [u8]`.
|
||||
|
||||
unsafe impl Send for BufferReadMappingDetail {}
|
||||
unsafe impl Send for BufferWriteMappingDetail {}
|
||||
|
||||
impl BufferWriteMappingDetail {
|
||||
pub(crate) fn as_slice(&mut self) -> &mut [u8] {
|
||||
unsafe { slice::from_raw_parts_mut(self.data as *mut u8, self.size) }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct SwapChainOutputDetail {
|
||||
swap_chain_id: wgc::id::SwapChainId,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use crate::BufferAddress;
|
||||
use parking_lot::Mutex;
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
@@ -10,29 +9,26 @@ enum WakerOrResult<T> {
|
||||
Result(T),
|
||||
}
|
||||
|
||||
type GpuFutureData<T> = Mutex<Option<WakerOrResult<T>>>;
|
||||
|
||||
/// A Future that can poll the wgpu::Device
|
||||
pub struct GpuFuture<T> {
|
||||
data: Arc<Data<T>>,
|
||||
data: Arc<GpuFutureData<T>>,
|
||||
}
|
||||
|
||||
pub enum OpaqueData {}
|
||||
|
||||
struct Data<T> {
|
||||
buffer_id: wgc::id::BufferId,
|
||||
size: BufferAddress,
|
||||
waker_or_result: Mutex<Option<WakerOrResult<T>>>,
|
||||
}
|
||||
|
||||
//TODO: merge this with `GpuFuture` and avoid `Arc` on the data.
|
||||
/// A completion handle to set the result on a GpuFuture
|
||||
pub struct GpuFutureCompletion<T> {
|
||||
data: Arc<Data<T>>,
|
||||
data: Arc<GpuFutureData<T>>,
|
||||
}
|
||||
|
||||
impl<T> Future for GpuFuture<T> {
|
||||
type Output = T;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, context: &mut Context) -> Poll<Self::Output> {
|
||||
let mut waker_or_result = self.into_ref().get_ref().data.waker_or_result.lock();
|
||||
let mut waker_or_result = self.into_ref().get_ref().data.lock();
|
||||
|
||||
match waker_or_result.take() {
|
||||
Some(WakerOrResult::Result(res)) => Poll::Ready(res),
|
||||
@@ -46,7 +42,7 @@ impl<T> Future for GpuFuture<T> {
|
||||
|
||||
impl<T> GpuFutureCompletion<T> {
|
||||
pub fn complete(self, value: T) {
|
||||
let mut waker_or_result = self.data.waker_or_result.lock();
|
||||
let mut waker_or_result = self.data.lock();
|
||||
|
||||
match waker_or_result.replace(WakerOrResult::Result(value)) {
|
||||
Some(WakerOrResult::Waker(waker)) => waker.wake(),
|
||||
@@ -68,22 +64,10 @@ impl<T> GpuFutureCompletion<T> {
|
||||
data: Arc::from_raw(this as _),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_buffer_info(&self) -> (wgc::id::BufferId, BufferAddress) {
|
||||
(self.data.buffer_id, self.data.size)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new_gpu_future<T>(
|
||||
buffer_id: wgc::id::BufferId,
|
||||
size: BufferAddress,
|
||||
) -> (GpuFuture<T>, GpuFutureCompletion<T>) {
|
||||
let data = Arc::new(Data {
|
||||
buffer_id,
|
||||
size,
|
||||
waker_or_result: Mutex::new(None),
|
||||
});
|
||||
|
||||
pub(crate) fn new_gpu_future<T>() -> (GpuFuture<T>, GpuFutureCompletion<T>) {
|
||||
let data = Arc::new(Mutex::new(None));
|
||||
(
|
||||
GpuFuture {
|
||||
data: Arc::clone(&data),
|
||||
|
||||
@@ -574,25 +574,10 @@ pub(crate) struct MapFuture<T> {
|
||||
marker: PhantomData<T>,
|
||||
}
|
||||
impl<T> Unpin for MapFuture<T> {}
|
||||
type MapData = (web_sys::GpuBuffer, Vec<u8>);
|
||||
impl From<MapData> for BufferReadMappingDetail {
|
||||
fn from((buffer_id, mapped): MapData) -> Self {
|
||||
BufferReadMappingDetail {
|
||||
buffer_id: Sendable(buffer_id),
|
||||
mapped,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<MapData> for BufferWriteMappingDetail {
|
||||
fn from((buffer_id, mapped): MapData) -> Self {
|
||||
BufferWriteMappingDetail {
|
||||
buffer_id: Sendable(buffer_id),
|
||||
mapped,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T: From<MapData>> std::future::Future for MapFuture<T> {
|
||||
type Output = Result<T, crate::BufferAsyncError>;
|
||||
//type MapData = (web_sys::GpuBuffer, Vec<u8>);
|
||||
|
||||
impl std::future::Future for MapFuture<()> {
|
||||
type Output = Result<(), crate::BufferAsyncError>;
|
||||
fn poll(
|
||||
mut self: std::pin::Pin<&mut Self>,
|
||||
context: &mut std::task::Context,
|
||||
@@ -602,12 +587,12 @@ impl<T: From<MapData>> std::future::Future for MapFuture<T> {
|
||||
context,
|
||||
)
|
||||
.map(|result| {
|
||||
let buffer = self.buffer.take().unwrap();
|
||||
let _buffer = self.buffer.take().unwrap();
|
||||
result
|
||||
.map(|js_value| {
|
||||
let array_buffer = js_sys::ArrayBuffer::from(js_value);
|
||||
let view = js_sys::Uint8Array::new(&array_buffer);
|
||||
T::from((buffer, view.to_vec()))
|
||||
let _view = js_sys::Uint8Array::new(&array_buffer);
|
||||
() //TODO
|
||||
})
|
||||
.map_err(|_| crate::BufferAsyncError)
|
||||
})
|
||||
@@ -635,17 +620,13 @@ impl crate::Context for Context {
|
||||
type SwapChainId = Sendable<web_sys::GpuSwapChain>;
|
||||
type RenderPassId = RenderPass;
|
||||
|
||||
type CreateBufferMappedDetail = CreateBufferMappedDetail;
|
||||
type BufferReadMappingDetail = BufferReadMappingDetail;
|
||||
type BufferWriteMappingDetail = BufferWriteMappingDetail;
|
||||
type SwapChainOutputDetail = SwapChainOutputDetail;
|
||||
|
||||
type RequestAdapterFuture = MakeSendFuture<FutureMap<Option<Self::AdapterId>>>;
|
||||
type RequestDeviceFuture = MakeSendFuture<
|
||||
FutureMap<Result<(Self::DeviceId, Self::QueueId), crate::RequestDeviceError>>,
|
||||
>;
|
||||
type MapReadFuture = MakeSendFuture<MapFuture<BufferReadMappingDetail>>;
|
||||
type MapWriteFuture = MakeSendFuture<MapFuture<BufferWriteMappingDetail>>;
|
||||
type MapAsyncFuture = MakeSendFuture<MapFuture<()>>;
|
||||
|
||||
fn init() -> Self {
|
||||
Sendable(web_sys::window().unwrap().navigator().gpu())
|
||||
@@ -720,26 +701,26 @@ impl crate::Context for Context {
|
||||
)
|
||||
}
|
||||
|
||||
fn adapter_extensions(&self, adapter: &Self::AdapterId) -> wgt::Extensions {
|
||||
fn adapter_extensions(&self, _adapter: &Self::AdapterId) -> wgt::Extensions {
|
||||
// TODO: web-sys has no way of getting extensions on adapters
|
||||
wgt::Extensions {
|
||||
anisotropic_filtering: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn adapter_limits(&self, adapter: &Self::AdapterId) -> wgt::Limits {
|
||||
fn adapter_limits(&self, _adapter: &Self::AdapterId) -> wgt::Limits {
|
||||
// TODO: web-sys has no way of getting limits on adapters
|
||||
wgt::Limits::default()
|
||||
}
|
||||
|
||||
fn device_extensions(&self, device: &Self::DeviceId) -> wgt::Extensions {
|
||||
fn device_extensions(&self, _device: &Self::DeviceId) -> wgt::Extensions {
|
||||
// TODO: web-sys has no way of getting extensions on devices
|
||||
wgt::Extensions {
|
||||
anisotropic_filtering: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn device_limits(&self, device: &Self::DeviceId) -> wgt::Limits {
|
||||
fn device_limits(&self, _device: &Self::DeviceId) -> wgt::Limits {
|
||||
// TODO: web-sys has a method for getting limits on devices, but it returns Object not GpuLimit
|
||||
wgt::Limits::default()
|
||||
}
|
||||
@@ -968,34 +949,6 @@ impl crate::Context for Context {
|
||||
Sendable(device.0.create_compute_pipeline(&mapped_desc))
|
||||
}
|
||||
|
||||
fn device_create_buffer_mapped<'a>(
|
||||
&self,
|
||||
device: &Self::DeviceId,
|
||||
desc: &BufferDescriptor,
|
||||
) -> (Self::BufferId, &'a mut [u8], Self::CreateBufferMappedDetail) {
|
||||
let mut mapped_desc =
|
||||
web_sys::GpuBufferDescriptor::new(desc.size as f64, desc.usage.bits());
|
||||
if let Some(label) = desc.label {
|
||||
mapped_desc.label(label);
|
||||
}
|
||||
unsafe {
|
||||
let pair = device.0.create_buffer_mapped(&mapped_desc);
|
||||
let id = pair.get(0).into();
|
||||
let array_buffer = pair.get(1).into();
|
||||
// TODO: Use `Vec::from_raw_parts` once it's stable
|
||||
let memory = vec![0; desc.size as usize].into_boxed_slice();
|
||||
let mapped_data = std::slice::from_raw_parts_mut(
|
||||
Box::into_raw(memory) as *mut u8,
|
||||
desc.size as usize,
|
||||
);
|
||||
(
|
||||
Sendable(id),
|
||||
mapped_data,
|
||||
CreateBufferMappedDetail { array_buffer },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn device_create_buffer(
|
||||
&self,
|
||||
device: &Self::DeviceId,
|
||||
@@ -1071,28 +1024,34 @@ impl crate::Context for Context {
|
||||
// Device is polled automatically
|
||||
}
|
||||
|
||||
fn buffer_map_read(
|
||||
fn buffer_map_async(
|
||||
&self,
|
||||
buffer: &Self::BufferId,
|
||||
_buffer: &Self::BufferId,
|
||||
_mode: crate::MapMode,
|
||||
_range: Range<wgt::BufferAddress>,
|
||||
) -> Self::MapReadFuture {
|
||||
MakeSendFuture(MapFuture {
|
||||
child: wasm_bindgen_futures::JsFuture::from(buffer.0.map_read_async()),
|
||||
buffer: Some(buffer.0.clone()),
|
||||
marker: PhantomData,
|
||||
})
|
||||
) -> Self::MapAsyncFuture {
|
||||
unimplemented!()
|
||||
//MakeSendFuture(MapFuture {
|
||||
// child: wasm_bindgen_futures::JsFuture::from(buffer.0.map_async()),
|
||||
// buffer: Some(buffer.0.clone()),
|
||||
// marker: PhantomData,
|
||||
//})
|
||||
}
|
||||
|
||||
fn buffer_map_write(
|
||||
fn buffer_get_mapped_range(
|
||||
&self,
|
||||
buffer: &Self::BufferId,
|
||||
_range: Range<wgt::BufferAddress>,
|
||||
) -> Self::MapWriteFuture {
|
||||
MakeSendFuture(MapFuture {
|
||||
child: wasm_bindgen_futures::JsFuture::from(buffer.0.map_write_async()),
|
||||
buffer: Some(buffer.0.clone()),
|
||||
marker: PhantomData,
|
||||
})
|
||||
_buffer: &Self::BufferId,
|
||||
_sub_range: Range<wgt::BufferAddress>,
|
||||
) -> &[u8] {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn buffer_get_mapped_range_mut(
|
||||
&self,
|
||||
_buffer: &Self::BufferId,
|
||||
_sub_range: Range<wgt::BufferAddress>,
|
||||
) -> &mut [u8] {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn buffer_unmap(&self, buffer: &Self::BufferId) {
|
||||
@@ -1180,26 +1139,6 @@ impl crate::Context for Context {
|
||||
// Buffer is dropped automatically
|
||||
}
|
||||
|
||||
fn flush_mapped_data(data: &mut [u8], detail: CreateBufferMappedDetail) {
|
||||
unsafe {
|
||||
// Convert the `mapped_data` slice back into a `Vec`. This should be
|
||||
// safe because `mapped_data` is no longer accessible beyond this
|
||||
// function.
|
||||
let memory: Vec<u8> = Box::<[u8]>::from_raw(data).into();
|
||||
|
||||
// Create a view into the mapped `ArrayBuffer` that was provided by the
|
||||
// browser
|
||||
let mapped = js_sys::Uint8Array::new(&detail.array_buffer);
|
||||
|
||||
// Convert `memory` into a temporary `Uint8Array` view. This should be
|
||||
// safe as long as the backing wasm memory is not resized.
|
||||
let memory_view = js_sys::Uint8Array::view(&memory[..]);
|
||||
|
||||
// Finally copy into `mapped` and let `memory` drop
|
||||
mapped.set(&memory_view, 0);
|
||||
}
|
||||
}
|
||||
|
||||
fn encoder_copy_buffer_to_buffer(
|
||||
&self,
|
||||
encoder: &Self::CommandEncoderId,
|
||||
@@ -1382,39 +1321,4 @@ impl crate::Context for Context {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct CreateBufferMappedDetail {
|
||||
/// On wasm we need to allocate our own temporary storage for `data`. Later
|
||||
/// we copy this temporary storage into the `Uint8Array` which was returned
|
||||
/// by the browser originally.
|
||||
array_buffer: js_sys::ArrayBuffer,
|
||||
}
|
||||
|
||||
// `CreateBufferMappedDetail` must be `Send` to match native.
|
||||
//
|
||||
// SAFETY: This is safe on wasm32 *for now*, but similarly to the unsafe Send impls for the handle
|
||||
// type wrappers, the full story for threading on wasm32 is still unfolding.
|
||||
unsafe impl Send for CreateBufferMappedDetail {}
|
||||
|
||||
pub(crate) struct BufferReadMappingDetail {
|
||||
pub(crate) buffer_id: Sendable<web_sys::GpuBuffer>,
|
||||
mapped: Vec<u8>,
|
||||
}
|
||||
|
||||
impl BufferReadMappingDetail {
|
||||
pub(crate) fn as_slice(&self) -> &[u8] {
|
||||
&self.mapped[..]
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct BufferWriteMappingDetail {
|
||||
pub(crate) buffer_id: Sendable<web_sys::GpuBuffer>,
|
||||
mapped: Vec<u8>,
|
||||
}
|
||||
|
||||
impl BufferWriteMappingDetail {
|
||||
pub(crate) fn as_slice(&mut self) -> &mut [u8] {
|
||||
&mut self.mapped[..]
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type SwapChainOutputDetail = ();
|
||||
|
||||
244
src/lib.rs
244
src/lib.rs
@@ -5,7 +5,6 @@ mod backend;
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
use futures::FutureExt as _;
|
||||
use std::{
|
||||
future::Future,
|
||||
marker::PhantomData,
|
||||
@@ -14,6 +13,9 @@ use std::{
|
||||
thread,
|
||||
};
|
||||
|
||||
use futures::FutureExt as _;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub use wgc::instance::{AdapterInfo, DeviceType};
|
||||
pub use wgt::{
|
||||
@@ -105,18 +107,12 @@ trait Context: Sized {
|
||||
type SwapChainId: Send + Sync;
|
||||
type RenderPassId: RenderPassInner<Self>;
|
||||
|
||||
type CreateBufferMappedDetail: Send;
|
||||
type BufferReadMappingDetail: Send;
|
||||
type BufferWriteMappingDetail: Send;
|
||||
type SwapChainOutputDetail: Send;
|
||||
|
||||
type RequestAdapterFuture: Future<Output = Option<Self::AdapterId>> + Send;
|
||||
type RequestDeviceFuture: Future<Output = Result<(Self::DeviceId, Self::QueueId), RequestDeviceError>>
|
||||
+ Send;
|
||||
type MapReadFuture: Future<Output = Result<Self::BufferReadMappingDetail, BufferAsyncError>>
|
||||
+ Send;
|
||||
type MapWriteFuture: Future<Output = Result<Self::BufferWriteMappingDetail, BufferAsyncError>>
|
||||
+ Send;
|
||||
type MapAsyncFuture: Future<Output = Result<(), BufferAsyncError>> + Send;
|
||||
|
||||
fn init() -> Self;
|
||||
fn instance_create_surface(
|
||||
@@ -175,11 +171,6 @@ trait Context: Sized {
|
||||
device: &Self::DeviceId,
|
||||
desc: &ComputePipelineDescriptor,
|
||||
) -> Self::ComputePipelineId;
|
||||
fn device_create_buffer_mapped<'a>(
|
||||
&self,
|
||||
device: &Self::DeviceId,
|
||||
desc: &BufferDescriptor,
|
||||
) -> (Self::BufferId, &'a mut [u8], Self::CreateBufferMappedDetail);
|
||||
fn device_create_buffer(
|
||||
&self,
|
||||
device: &Self::DeviceId,
|
||||
@@ -203,16 +194,24 @@ trait Context: Sized {
|
||||
fn device_drop(&self, device: &Self::DeviceId);
|
||||
fn device_poll(&self, device: &Self::DeviceId, maintain: Maintain);
|
||||
|
||||
fn buffer_map_read(
|
||||
fn buffer_map_async(
|
||||
&self,
|
||||
buffer: &Self::BufferId,
|
||||
mode: MapMode,
|
||||
range: Range<BufferAddress>,
|
||||
) -> Self::MapReadFuture;
|
||||
fn buffer_map_write(
|
||||
) -> Self::MapAsyncFuture;
|
||||
//TODO: we might be able to merge these, depending on how Web backend
|
||||
// turns out to be implemented.
|
||||
fn buffer_get_mapped_range(
|
||||
&self,
|
||||
buffer: &Self::BufferId,
|
||||
range: Range<BufferAddress>,
|
||||
) -> Self::MapWriteFuture;
|
||||
sub_range: Range<BufferAddress>,
|
||||
) -> &[u8];
|
||||
fn buffer_get_mapped_range_mut(
|
||||
&self,
|
||||
buffer: &Self::BufferId,
|
||||
sub_range: Range<BufferAddress>,
|
||||
) -> &mut [u8];
|
||||
fn buffer_unmap(&self, buffer: &Self::BufferId);
|
||||
fn swap_chain_get_next_texture(
|
||||
&self,
|
||||
@@ -271,7 +270,6 @@ trait Context: Sized {
|
||||
copy_size: Extent3d,
|
||||
);
|
||||
|
||||
fn flush_mapped_data(data: &mut [u8], detail: Self::CreateBufferMappedDetail);
|
||||
fn encoder_begin_compute_pass(&self, encoder: &Self::CommandEncoderId) -> Self::ComputePassId;
|
||||
fn encoder_end_compute_pass(
|
||||
&self,
|
||||
@@ -354,11 +352,54 @@ pub enum Maintain {
|
||||
Poll,
|
||||
}
|
||||
|
||||
/// The main purpose of this struct is to resolve mapped ranges
|
||||
/// (convert sizes to end points), and to ensure that the sub-ranges
|
||||
/// don't intersect.
|
||||
#[derive(Debug)]
|
||||
struct MapContext {
|
||||
total_size: BufferAddress,
|
||||
initial_range: Range<BufferAddress>,
|
||||
sub_ranges: Vec<Range<BufferAddress>>,
|
||||
}
|
||||
|
||||
impl MapContext {
|
||||
fn new(total_size: BufferAddress) -> Self {
|
||||
MapContext {
|
||||
total_size,
|
||||
initial_range: 0..0,
|
||||
sub_ranges: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
self.initial_range = 0..0;
|
||||
self.sub_ranges.clear();
|
||||
}
|
||||
|
||||
fn add(&mut self, offset: BufferAddress, size: BufferSize) -> BufferAddress {
|
||||
let end = if size == BufferSize::WHOLE {
|
||||
self.initial_range.end
|
||||
} else {
|
||||
offset + size.0
|
||||
};
|
||||
assert!(self.initial_range.start <= offset && end <= self.initial_range.end);
|
||||
for sub in self.sub_ranges.iter() {
|
||||
assert!(
|
||||
end <= sub.start || offset >= sub.end,
|
||||
"Intersecting map range with {:?}",
|
||||
sub
|
||||
);
|
||||
}
|
||||
self.sub_ranges.push(offset..end);
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
/// A handle to a GPU-accessible buffer.
|
||||
pub struct Buffer {
|
||||
context: Arc<C>,
|
||||
id: <C as Context>::BufferId,
|
||||
size: BufferAddress,
|
||||
map_context: Mutex<MapContext>,
|
||||
}
|
||||
|
||||
/// A description of what portion of a buffer to use
|
||||
@@ -871,35 +912,6 @@ pub struct TextureCopyView<'a> {
|
||||
pub origin: Origin3d,
|
||||
}
|
||||
|
||||
/// A buffer being created, mapped in host memory.
|
||||
pub struct CreateBufferMapped<'a> {
|
||||
context: Arc<C>,
|
||||
id: <C as Context>::BufferId,
|
||||
/// The backing field for `data()`. This isn't `pub` because users shouldn't
|
||||
/// be able to replace it to point somewhere else. We rely on it pointing to
|
||||
/// to the correct memory later during `unmap()`.
|
||||
mapped_data: &'a mut [u8],
|
||||
detail: <C as Context>::CreateBufferMappedDetail,
|
||||
}
|
||||
|
||||
impl CreateBufferMapped<'_> {
|
||||
/// The mapped data.
|
||||
pub fn data(&mut self) -> &mut [u8] {
|
||||
self.mapped_data
|
||||
}
|
||||
|
||||
/// Unmaps the buffer from host memory and returns a [`Buffer`].
|
||||
pub fn finish(self) -> Buffer {
|
||||
<C as Context>::flush_mapped_data(self.mapped_data, self.detail);
|
||||
Context::buffer_unmap(&*self.context, &self.id);
|
||||
Buffer {
|
||||
context: self.context,
|
||||
id: self.id,
|
||||
size: self.mapped_data.len() as BufferAddress,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Instance {
|
||||
/// Create an new instance.
|
||||
pub fn new() -> Self {
|
||||
@@ -1098,36 +1110,24 @@ impl Device {
|
||||
Buffer {
|
||||
context: Arc::clone(&self.context),
|
||||
id: Context::device_create_buffer(&*self.context, &self.id, desc),
|
||||
size: desc.size,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new buffer and maps it into host-visible memory.
|
||||
///
|
||||
/// This returns a [`CreateBufferMapped`], which exposes a `&mut [u8]`. The actual [`Buffer`]
|
||||
/// will not be created until calling [`CreateBufferMapped::finish`].
|
||||
pub fn create_buffer_mapped(&self, desc: &BufferDescriptor) -> CreateBufferMapped<'_> {
|
||||
assert_ne!(desc.size, 0);
|
||||
let (id, mapped_data, detail) =
|
||||
Context::device_create_buffer_mapped(&*self.context, &self.id, desc);
|
||||
CreateBufferMapped {
|
||||
context: Arc::clone(&self.context),
|
||||
id,
|
||||
mapped_data,
|
||||
detail,
|
||||
map_context: Mutex::new(MapContext::new(desc.size)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new buffer, maps it into host-visible memory, copies data from the given slice,
|
||||
/// and finally unmaps it, returning a [`Buffer`].
|
||||
pub fn create_buffer_with_data(&self, data: &[u8], usage: BufferUsage) -> Buffer {
|
||||
let mut mapped = self.create_buffer_mapped(&BufferDescriptor {
|
||||
size: data.len() as u64,
|
||||
usage,
|
||||
let size = data.len() as u64;
|
||||
let buffer = self.create_buffer(&BufferDescriptor {
|
||||
label: None,
|
||||
size,
|
||||
usage,
|
||||
mapped_at_creation: true,
|
||||
});
|
||||
mapped.data().copy_from_slice(data);
|
||||
mapped.finish()
|
||||
Context::buffer_get_mapped_range_mut(&*self.context, &buffer.id, 0..size)
|
||||
.copy_from_slice(data);
|
||||
buffer.unmap();
|
||||
buffer
|
||||
}
|
||||
|
||||
/// Creates a new [`Texture`].
|
||||
@@ -1172,44 +1172,10 @@ pub struct RequestDeviceError;
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct BufferAsyncError;
|
||||
|
||||
pub struct BufferReadMapping {
|
||||
context: Arc<C>,
|
||||
detail: <C as Context>::BufferReadMappingDetail,
|
||||
}
|
||||
|
||||
unsafe impl Send for BufferReadMapping {}
|
||||
unsafe impl Sync for BufferReadMapping {}
|
||||
|
||||
impl BufferReadMapping {
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
self.detail.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for BufferReadMapping {
|
||||
fn drop(&mut self) {
|
||||
Context::buffer_unmap(&*self.context, &self.detail.buffer_id);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BufferWriteMapping {
|
||||
context: Arc<C>,
|
||||
detail: <C as Context>::BufferWriteMappingDetail,
|
||||
}
|
||||
|
||||
unsafe impl Send for BufferWriteMapping {}
|
||||
unsafe impl Sync for BufferWriteMapping {}
|
||||
|
||||
impl BufferWriteMapping {
|
||||
pub fn as_slice(&mut self) -> &mut [u8] {
|
||||
self.detail.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for BufferWriteMapping {
|
||||
fn drop(&mut self) {
|
||||
Context::buffer_unmap(&*self.context, &self.detail.buffer_id);
|
||||
}
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum MapMode {
|
||||
Read,
|
||||
Write,
|
||||
}
|
||||
|
||||
impl Buffer {
|
||||
@@ -1233,7 +1199,7 @@ impl Buffer {
|
||||
}
|
||||
}
|
||||
|
||||
/// Map the buffer for reading. The result is returned in a future.
|
||||
/// Map the buffer. Buffer is ready to map once the future is resolved.
|
||||
///
|
||||
/// For the future to complete, `device.poll(...)` must be called elsewhere in the runtime, possibly integrated
|
||||
/// into an event loop, run on a separate thread, or continually polled in the same task runtime that this
|
||||
@@ -1241,44 +1207,44 @@ impl Buffer {
|
||||
///
|
||||
/// It's expected that wgpu will eventually supply its own event loop infrastructure that will be easy to integrate
|
||||
/// into other event loops, like winit's.
|
||||
pub fn map_read(
|
||||
pub fn map_async(
|
||||
&self,
|
||||
start: BufferAddress,
|
||||
mode: MapMode,
|
||||
offset: BufferAddress,
|
||||
size: BufferSize,
|
||||
) -> impl Future<Output = Result<BufferReadMapping, BufferAsyncError>> + Send {
|
||||
let context = Arc::clone(&self.context);
|
||||
let end = if size == BufferSize::WHOLE {
|
||||
self.size
|
||||
} else {
|
||||
start + size.0
|
||||
) -> impl Future<Output = Result<(), BufferAsyncError>> + Send {
|
||||
let end = {
|
||||
let mut mc = self.map_context.lock();
|
||||
assert_eq!(
|
||||
mc.initial_range,
|
||||
0..0,
|
||||
"Buffer {:?} is already mapped",
|
||||
self.id
|
||||
);
|
||||
let end = if size == BufferSize::WHOLE {
|
||||
mc.total_size
|
||||
} else {
|
||||
offset + size.0
|
||||
};
|
||||
mc.initial_range = offset..end;
|
||||
end
|
||||
};
|
||||
self.context
|
||||
.buffer_map_read(&self.id, start..end)
|
||||
.map(|result| result.map(|detail| BufferReadMapping { context, detail }))
|
||||
Context::buffer_map_async(&*self.context, &self.id, mode, offset..end)
|
||||
}
|
||||
|
||||
/// Map the buffer for writing. The result is returned in a future.
|
||||
///
|
||||
/// See the documentation of (map_read)[#method.map_read] for more information about
|
||||
/// how to run this future.
|
||||
pub fn map_write(
|
||||
&self,
|
||||
start: BufferAddress,
|
||||
size: BufferSize,
|
||||
) -> impl Future<Output = Result<BufferWriteMapping, BufferAsyncError>> + Send {
|
||||
let context = Arc::clone(&self.context);
|
||||
let end = if size == BufferSize::WHOLE {
|
||||
self.size
|
||||
} else {
|
||||
start + size.0
|
||||
};
|
||||
self.context
|
||||
.buffer_map_write(&self.id, start..end)
|
||||
.map(|result| result.map(|detail| BufferWriteMapping { context, detail }))
|
||||
pub fn get_mapped_range(&self, offset: BufferAddress, size: BufferSize) -> &[u8] {
|
||||
let end = self.map_context.lock().add(offset, size);
|
||||
Context::buffer_get_mapped_range(&*self.context, &self.id, offset..end)
|
||||
}
|
||||
|
||||
pub fn get_mapped_range_mut(&self, offset: BufferAddress, size: BufferSize) -> &mut [u8] {
|
||||
let end = self.map_context.lock().add(offset, size);
|
||||
Context::buffer_get_mapped_range_mut(&*self.context, &self.id, offset..end)
|
||||
}
|
||||
|
||||
/// Flushes any pending write operations and unmaps the buffer from host memory.
|
||||
pub fn unmap(&self) {
|
||||
self.map_context.lock().reset();
|
||||
Context::buffer_unmap(&*self.context, &self.id);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user