mirror of
https://github.com/denoland/deno.git
synced 2024-12-20 14:24:48 -05:00
212 lines
5.4 KiB
Rust
212 lines
5.4 KiB
Rust
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
|
|
|
use deno_core::op2;
|
|
use deno_core::OpState;
|
|
use deno_core::Resource;
|
|
use deno_core::ResourceId;
|
|
use std::borrow::Cow;
|
|
use std::cell::RefCell;
|
|
use std::rc::Rc;
|
|
use std::sync::Arc;
|
|
use std::sync::Mutex;
|
|
use std::time::Duration;
|
|
|
|
use super::error::WebGpuResult;
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
pub enum BufferError {
|
|
#[error(transparent)]
|
|
Resource(deno_core::error::AnyError),
|
|
#[error("usage is not valid")]
|
|
InvalidUsage,
|
|
#[error(transparent)]
|
|
Access(wgpu_core::resource::BufferAccessError),
|
|
}
|
|
|
|
pub(crate) struct WebGpuBuffer(
|
|
pub(crate) super::Instance,
|
|
pub(crate) wgpu_core::id::BufferId,
|
|
);
|
|
impl Resource for WebGpuBuffer {
|
|
fn name(&self) -> Cow<str> {
|
|
"webGPUBuffer".into()
|
|
}
|
|
|
|
fn close(self: Rc<Self>) {
|
|
gfx_select!(self.1 => self.0.buffer_drop(self.1, true));
|
|
}
|
|
}
|
|
|
|
struct WebGpuBufferMapped(*mut u8, usize);
|
|
impl Resource for WebGpuBufferMapped {
|
|
fn name(&self) -> Cow<str> {
|
|
"webGPUBufferMapped".into()
|
|
}
|
|
}
|
|
|
|
#[op2]
|
|
#[serde]
|
|
pub fn op_webgpu_create_buffer(
|
|
state: &mut OpState,
|
|
#[smi] device_rid: ResourceId,
|
|
#[string] label: Cow<str>,
|
|
#[number] size: u64,
|
|
usage: u32,
|
|
mapped_at_creation: bool,
|
|
) -> Result<WebGpuResult, BufferError> {
|
|
let instance = state.borrow::<super::Instance>();
|
|
let device_resource = state
|
|
.resource_table
|
|
.get::<super::WebGpuDevice>(device_rid)
|
|
.map_err(BufferError::Resource)?;
|
|
let device = device_resource.1;
|
|
|
|
let descriptor = wgpu_core::resource::BufferDescriptor {
|
|
label: Some(label),
|
|
size,
|
|
usage: wgpu_types::BufferUsages::from_bits(usage)
|
|
.ok_or(BufferError::InvalidUsage)?,
|
|
mapped_at_creation,
|
|
};
|
|
|
|
gfx_put!(device => instance.device_create_buffer(
|
|
device,
|
|
&descriptor,
|
|
None
|
|
) => state, WebGpuBuffer)
|
|
}
|
|
|
|
#[op2(async)]
|
|
#[serde]
|
|
pub async fn op_webgpu_buffer_get_map_async(
|
|
state: Rc<RefCell<OpState>>,
|
|
#[smi] buffer_rid: ResourceId,
|
|
#[smi] device_rid: ResourceId,
|
|
mode: u32,
|
|
#[number] offset: u64,
|
|
#[number] size: u64,
|
|
) -> Result<WebGpuResult, BufferError> {
|
|
let device;
|
|
let done = Arc::new(Mutex::new(None));
|
|
{
|
|
let state_ = state.borrow();
|
|
let instance = state_.borrow::<super::Instance>();
|
|
let buffer_resource = state_
|
|
.resource_table
|
|
.get::<WebGpuBuffer>(buffer_rid)
|
|
.map_err(BufferError::Resource)?;
|
|
let buffer = buffer_resource.1;
|
|
let device_resource = state_
|
|
.resource_table
|
|
.get::<super::WebGpuDevice>(device_rid)
|
|
.map_err(BufferError::Resource)?;
|
|
device = device_resource.1;
|
|
|
|
let done_ = done.clone();
|
|
let callback = Box::new(move |status| {
|
|
*done_.lock().unwrap() = Some(status);
|
|
});
|
|
|
|
let maybe_err = gfx_select!(buffer => instance.buffer_map_async(
|
|
buffer,
|
|
offset,
|
|
Some(size),
|
|
wgpu_core::resource::BufferMapOperation {
|
|
host: match mode {
|
|
1 => wgpu_core::device::HostMap::Read,
|
|
2 => wgpu_core::device::HostMap::Write,
|
|
_ => unreachable!(),
|
|
},
|
|
callback: Some(wgpu_core::resource::BufferMapCallback::from_rust(callback)),
|
|
}
|
|
))
|
|
.err();
|
|
|
|
if maybe_err.is_some() {
|
|
return Ok(WebGpuResult::maybe_err(maybe_err));
|
|
}
|
|
}
|
|
|
|
loop {
|
|
let result = done.lock().unwrap().take();
|
|
match result {
|
|
Some(Ok(())) => return Ok(WebGpuResult::empty()),
|
|
Some(Err(e)) => return Err(BufferError::Access(e)),
|
|
None => {
|
|
{
|
|
let state = state.borrow();
|
|
let instance = state.borrow::<super::Instance>();
|
|
gfx_select!(device => instance.device_poll(device, wgpu_types::Maintain::Poll)).unwrap();
|
|
}
|
|
tokio::time::sleep(Duration::from_millis(10)).await;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[op2]
|
|
#[serde]
|
|
pub fn op_webgpu_buffer_get_mapped_range(
|
|
state: &mut OpState,
|
|
#[smi] buffer_rid: ResourceId,
|
|
#[number] offset: u64,
|
|
#[number] size: Option<u64>,
|
|
#[buffer] buf: &mut [u8],
|
|
) -> Result<WebGpuResult, BufferError> {
|
|
let instance = state.borrow::<super::Instance>();
|
|
let buffer_resource = state
|
|
.resource_table
|
|
.get::<WebGpuBuffer>(buffer_rid)
|
|
.map_err(BufferError::Resource)?;
|
|
let buffer = buffer_resource.1;
|
|
|
|
let (slice_pointer, range_size) =
|
|
gfx_select!(buffer => instance.buffer_get_mapped_range(
|
|
buffer,
|
|
offset,
|
|
size
|
|
))
|
|
.map_err(BufferError::Access)?;
|
|
|
|
// SAFETY: guarantee to be safe from wgpu
|
|
let slice = unsafe {
|
|
std::slice::from_raw_parts_mut(slice_pointer, range_size as usize)
|
|
};
|
|
buf.copy_from_slice(slice);
|
|
|
|
let rid = state
|
|
.resource_table
|
|
.add(WebGpuBufferMapped(slice_pointer, range_size as usize));
|
|
|
|
Ok(WebGpuResult::rid(rid))
|
|
}
|
|
|
|
#[op2]
|
|
#[serde]
|
|
pub fn op_webgpu_buffer_unmap(
|
|
state: &mut OpState,
|
|
#[smi] buffer_rid: ResourceId,
|
|
#[smi] mapped_rid: ResourceId,
|
|
#[buffer] buf: Option<&[u8]>,
|
|
) -> Result<WebGpuResult, BufferError> {
|
|
let mapped_resource = state
|
|
.resource_table
|
|
.take::<WebGpuBufferMapped>(mapped_rid)
|
|
.map_err(BufferError::Resource)?;
|
|
let instance = state.borrow::<super::Instance>();
|
|
let buffer_resource = state
|
|
.resource_table
|
|
.get::<WebGpuBuffer>(buffer_rid)
|
|
.map_err(BufferError::Resource)?;
|
|
let buffer = buffer_resource.1;
|
|
|
|
if let Some(buf) = buf {
|
|
// SAFETY: guarantee to be safe from wgpu
|
|
let slice = unsafe {
|
|
std::slice::from_raw_parts_mut(mapped_resource.0, mapped_resource.1)
|
|
};
|
|
slice.copy_from_slice(buf);
|
|
}
|
|
|
|
gfx_ok!(buffer => instance.buffer_unmap(buffer))
|
|
}
|