diff options
author | Andy Hayden <andyhayden1@gmail.com> | 2021-04-30 12:51:48 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-30 15:51:48 -0400 |
commit | 684c357136fd44f9d5a1b8bb4402400ed1354677 (patch) | |
tree | ebc14b1d01b6643dd4d588516692dffc0f8fcb52 /extensions/webgpu/buffer.rs | |
parent | abaec7a88e991188d885bede652f35d76ab4f340 (diff) |
Rename crate_ops to extensions (#10431)
Diffstat (limited to 'extensions/webgpu/buffer.rs')
-rw-r--r-- | extensions/webgpu/buffer.rs | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/extensions/webgpu/buffer.rs b/extensions/webgpu/buffer.rs new file mode 100644 index 000000000..19fc428cb --- /dev/null +++ b/extensions/webgpu/buffer.rs @@ -0,0 +1,239 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +use deno_core::error::bad_resource_id; +use deno_core::error::null_opbuf; +use deno_core::error::AnyError; +use deno_core::futures::channel::oneshot; +use deno_core::OpState; +use deno_core::Resource; +use deno_core::ResourceId; +use deno_core::ZeroCopyBuf; +use serde::Deserialize; +use std::borrow::Cow; +use std::cell::RefCell; +use std::rc::Rc; +use std::time::Duration; + +use super::error::DomExceptionOperationError; +use super::error::WebGpuResult; + +pub(crate) struct WebGpuBuffer(pub(crate) wgpu_core::id::BufferId); +impl Resource for WebGpuBuffer { + fn name(&self) -> Cow<str> { + "webGPUBuffer".into() + } +} + +struct WebGpuBufferMapped(*mut u8, usize); +impl Resource for WebGpuBufferMapped { + fn name(&self) -> Cow<str> { + "webGPUBufferMapped".into() + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CreateBufferArgs { + device_rid: ResourceId, + label: Option<String>, + size: u64, + usage: u32, + mapped_at_creation: Option<bool>, +} + +pub fn op_webgpu_create_buffer( + state: &mut OpState, + args: CreateBufferArgs, + _zero_copy: Option<ZeroCopyBuf>, +) -> Result<WebGpuResult, AnyError> { + let instance = state.borrow::<super::Instance>(); + let device_resource = state + .resource_table + .get::<super::WebGpuDevice>(args.device_rid) + .ok_or_else(bad_resource_id)?; + let device = device_resource.0; + + let descriptor = wgpu_core::resource::BufferDescriptor { + label: args.label.map(Cow::from), + size: args.size, + usage: wgpu_types::BufferUsage::from_bits(args.usage).unwrap(), + mapped_at_creation: args.mapped_at_creation.unwrap_or(false), + }; + + let (buffer, maybe_err) = gfx_select!(device => instance.device_create_buffer( + device, + &descriptor, + std::marker::PhantomData + )); + + let rid = state.resource_table.add(WebGpuBuffer(buffer)); + + Ok(WebGpuResult::rid_err(rid, maybe_err)) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct BufferGetMapAsyncArgs { + buffer_rid: ResourceId, + device_rid: ResourceId, + mode: u32, + offset: u64, + size: u64, +} + +pub async fn op_webgpu_buffer_get_map_async( + state: Rc<RefCell<OpState>>, + args: BufferGetMapAsyncArgs, + _bufs: Option<ZeroCopyBuf>, +) -> Result<WebGpuResult, AnyError> { + let (sender, receiver) = oneshot::channel::<Result<(), AnyError>>(); + + let device; + { + let state_ = state.borrow(); + let instance = state_.borrow::<super::Instance>(); + let buffer_resource = state_ + .resource_table + .get::<WebGpuBuffer>(args.buffer_rid) + .ok_or_else(bad_resource_id)?; + let buffer = buffer_resource.0; + let device_resource = state_ + .resource_table + .get::<super::WebGpuDevice>(args.device_rid) + .ok_or_else(bad_resource_id)?; + device = device_resource.0; + + let boxed_sender = Box::new(sender); + let sender_ptr = Box::into_raw(boxed_sender) as *mut u8; + + extern "C" fn buffer_map_future_wrapper( + status: wgpu_core::resource::BufferMapAsyncStatus, + user_data: *mut u8, + ) { + let sender_ptr = user_data as *mut oneshot::Sender<Result<(), AnyError>>; + let boxed_sender = unsafe { Box::from_raw(sender_ptr) }; + boxed_sender + .send(match status { + wgpu_core::resource::BufferMapAsyncStatus::Success => Ok(()), + _ => unreachable!(), // TODO + }) + .unwrap(); + } + + // TODO(lucacasonato): error handling + gfx_select!(buffer => instance.buffer_map_async( + buffer, + args.offset..(args.offset + args.size), + wgpu_core::resource::BufferMapOperation { + host: match args.mode { + 1 => wgpu_core::device::HostMap::Read, + 2 => wgpu_core::device::HostMap::Write, + _ => unreachable!(), + }, + callback: buffer_map_future_wrapper, + user_data: sender_ptr, + } + ))?; + } + + let done = Rc::new(RefCell::new(false)); + let done_ = done.clone(); + let device_poll_fut = async move { + while !*done.borrow() { + { + let state = state.borrow(); + let instance = state.borrow::<super::Instance>(); + gfx_select!(device => instance.device_poll(device, false)).unwrap() + } + tokio::time::sleep(Duration::from_millis(10)).await; + } + Ok::<(), AnyError>(()) + }; + + let receiver_fut = async move { + receiver.await??; + let mut done = done_.borrow_mut(); + *done = true; + Ok::<(), AnyError>(()) + }; + + tokio::try_join!(device_poll_fut, receiver_fut)?; + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct BufferGetMappedRangeArgs { + buffer_rid: ResourceId, + offset: u64, + size: u64, +} + +pub fn op_webgpu_buffer_get_mapped_range( + state: &mut OpState, + args: BufferGetMappedRangeArgs, + zero_copy: Option<ZeroCopyBuf>, +) -> Result<WebGpuResult, AnyError> { + let mut zero_copy = zero_copy.ok_or_else(null_opbuf)?; + let instance = state.borrow::<super::Instance>(); + let buffer_resource = state + .resource_table + .get::<WebGpuBuffer>(args.buffer_rid) + .ok_or_else(bad_resource_id)?; + let buffer = buffer_resource.0; + + let slice_pointer = gfx_select!(buffer => instance.buffer_get_mapped_range( + buffer, + args.offset, + std::num::NonZeroU64::new(args.size) + )) + .map_err(|e| DomExceptionOperationError::new(&e.to_string()))?; + + let slice = unsafe { + std::slice::from_raw_parts_mut(slice_pointer, args.size as usize) + }; + zero_copy.copy_from_slice(slice); + + let rid = state + .resource_table + .add(WebGpuBufferMapped(slice_pointer, args.size as usize)); + + Ok(WebGpuResult::rid(rid)) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct BufferUnmapArgs { + buffer_rid: ResourceId, + mapped_rid: ResourceId, +} + +pub fn op_webgpu_buffer_unmap( + state: &mut OpState, + args: BufferUnmapArgs, + zero_copy: Option<ZeroCopyBuf>, +) -> Result<WebGpuResult, AnyError> { + let mapped_resource = state + .resource_table + .take::<WebGpuBufferMapped>(args.mapped_rid) + .ok_or_else(bad_resource_id)?; + let instance = state.borrow::<super::Instance>(); + let buffer_resource = state + .resource_table + .get::<WebGpuBuffer>(args.buffer_rid) + .ok_or_else(bad_resource_id)?; + let buffer = buffer_resource.0; + + let slice_pointer = mapped_resource.0; + let size = mapped_resource.1; + + if let Some(buffer) = zero_copy { + let slice = unsafe { std::slice::from_raw_parts_mut(slice_pointer, size) }; + slice.copy_from_slice(&buffer); + } + + let maybe_err = gfx_select!(buffer => instance.buffer_unmap(buffer)).err(); + + Ok(WebGpuResult::maybe_err(maybe_err)) +} |