mirror of
https://github.com/denoland/deno.git
synced 2025-08-04 19:08:15 +00:00
refactor: object wrap WebGPU (#27665)
Fixes #25874 Fixes #26760 Fixes #24288 Fixes #24798 Fixes #25627 Fixes #25915 Fixes #26769
This commit is contained in:
parent
7a112643f5
commit
7253820764
39 changed files with 7138 additions and 11466 deletions
|
@ -1,144 +1,165 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::rc::Rc;
|
||||
|
||||
use deno_core::error::ResourceError;
|
||||
use deno_core::cppgc::Ptr;
|
||||
use deno_core::op2;
|
||||
use deno_core::OpState;
|
||||
use deno_core::Resource;
|
||||
use deno_core::ResourceId;
|
||||
use serde::Deserialize;
|
||||
use deno_core::GarbageCollected;
|
||||
use deno_core::WebIDL;
|
||||
use deno_error::JsErrorBox;
|
||||
|
||||
use super::error::WebGpuResult;
|
||||
use crate::command_encoder::WebGpuCommandBuffer;
|
||||
use crate::buffer::GPUBuffer;
|
||||
use crate::command_buffer::GPUCommandBuffer;
|
||||
use crate::texture::GPUTexture;
|
||||
use crate::texture::GPUTextureAspect;
|
||||
use crate::webidl::GPUExtent3D;
|
||||
use crate::webidl::GPUOrigin3D;
|
||||
use crate::Instance;
|
||||
|
||||
pub struct WebGpuQueue(pub Instance, pub wgpu_core::id::QueueId);
|
||||
impl Resource for WebGpuQueue {
|
||||
fn name(&self) -> Cow<str> {
|
||||
"webGPUQueue".into()
|
||||
}
|
||||
pub struct GPUQueue {
|
||||
pub instance: Instance,
|
||||
pub error_handler: super::error::ErrorHandler,
|
||||
|
||||
fn close(self: Rc<Self>) {
|
||||
gfx_select!(self.1 => self.0.queue_drop(self.1));
|
||||
pub label: String,
|
||||
|
||||
pub id: wgpu_core::id::QueueId,
|
||||
}
|
||||
|
||||
impl Drop for GPUQueue {
|
||||
fn drop(&mut self) {
|
||||
self.instance.queue_drop(self.id);
|
||||
}
|
||||
}
|
||||
|
||||
impl GarbageCollected for GPUQueue {}
|
||||
|
||||
#[op2]
|
||||
#[serde]
|
||||
pub fn op_webgpu_queue_submit(
|
||||
state: &mut OpState,
|
||||
#[smi] queue_rid: ResourceId,
|
||||
#[serde] command_buffers: Vec<ResourceId>,
|
||||
) -> Result<WebGpuResult, ResourceError> {
|
||||
let instance = state.borrow::<Instance>();
|
||||
let queue_resource = state.resource_table.get::<WebGpuQueue>(queue_rid)?;
|
||||
let queue = queue_resource.1;
|
||||
|
||||
let ids = command_buffers
|
||||
.iter()
|
||||
.map(|rid| {
|
||||
let buffer_resource =
|
||||
state.resource_table.get::<WebGpuCommandBuffer>(*rid)?;
|
||||
let mut id = buffer_resource.1.borrow_mut();
|
||||
Ok(id.take().unwrap())
|
||||
})
|
||||
.collect::<Result<Vec<_>, ResourceError>>()?;
|
||||
|
||||
let maybe_err =
|
||||
gfx_select!(queue => instance.queue_submit(queue, &ids)).err();
|
||||
|
||||
for rid in command_buffers {
|
||||
let resource = state.resource_table.take::<WebGpuCommandBuffer>(rid)?;
|
||||
resource.close();
|
||||
impl GPUQueue {
|
||||
#[getter]
|
||||
#[string]
|
||||
fn label(&self) -> String {
|
||||
self.label.clone()
|
||||
}
|
||||
#[setter]
|
||||
#[string]
|
||||
fn label(&self, #[webidl] _label: String) {
|
||||
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
|
||||
}
|
||||
|
||||
Ok(WebGpuResult::maybe_err(maybe_err))
|
||||
#[required(1)]
|
||||
fn submit(
|
||||
&self,
|
||||
#[webidl] command_buffers: Vec<Ptr<GPUCommandBuffer>>,
|
||||
) -> Result<(), JsErrorBox> {
|
||||
let ids = command_buffers
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(i, cb)| {
|
||||
if cb.consumed.set(()).is_err() {
|
||||
Err(JsErrorBox::type_error(format!(
|
||||
"The command buffer at position {i} has already been submitted."
|
||||
)))
|
||||
} else {
|
||||
Ok(cb.id)
|
||||
}
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
let err = self.instance.queue_submit(self.id, &ids).err();
|
||||
|
||||
if let Some((_, err)) = err {
|
||||
self.error_handler.push_error(Some(err));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[async_method]
|
||||
async fn on_submitted_work_done(&self) -> Result<(), JsErrorBox> {
|
||||
Err(JsErrorBox::generic(
|
||||
"This operation is currently not supported",
|
||||
))
|
||||
}
|
||||
|
||||
#[required(3)]
|
||||
fn write_buffer(
|
||||
&self,
|
||||
#[webidl] buffer: Ptr<GPUBuffer>,
|
||||
#[webidl(options(enforce_range = true))] buffer_offset: u64,
|
||||
#[anybuffer] buf: &[u8],
|
||||
#[webidl(default = 0, options(enforce_range = true))] data_offset: u64,
|
||||
#[webidl(options(enforce_range = true))] size: Option<u64>,
|
||||
) {
|
||||
let data = match size {
|
||||
Some(size) => {
|
||||
&buf[(data_offset as usize)..((data_offset + size) as usize)]
|
||||
}
|
||||
None => &buf[(data_offset as usize)..],
|
||||
};
|
||||
|
||||
let err = self
|
||||
.instance
|
||||
.queue_write_buffer(self.id, buffer.id, buffer_offset, data)
|
||||
.err();
|
||||
|
||||
self.error_handler.push_error(err);
|
||||
}
|
||||
|
||||
#[required(4)]
|
||||
fn write_texture(
|
||||
&self,
|
||||
#[webidl] destination: GPUTexelCopyTextureInfo,
|
||||
#[anybuffer] buf: &[u8],
|
||||
#[webidl] data_layout: GPUTexelCopyBufferLayout,
|
||||
#[webidl] size: GPUExtent3D,
|
||||
) {
|
||||
let destination = wgpu_core::command::TexelCopyTextureInfo {
|
||||
texture: destination.texture.id,
|
||||
mip_level: destination.mip_level,
|
||||
origin: destination.origin.into(),
|
||||
aspect: destination.aspect.into(),
|
||||
};
|
||||
|
||||
let data_layout = wgpu_types::TexelCopyBufferLayout {
|
||||
offset: data_layout.offset,
|
||||
bytes_per_row: data_layout.bytes_per_row,
|
||||
rows_per_image: data_layout.rows_per_image,
|
||||
};
|
||||
|
||||
let err = self
|
||||
.instance
|
||||
.queue_write_texture(
|
||||
self.id,
|
||||
&destination,
|
||||
buf,
|
||||
&data_layout,
|
||||
&size.into(),
|
||||
)
|
||||
.err();
|
||||
|
||||
self.error_handler.push_error(err);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GpuImageDataLayout {
|
||||
#[derive(WebIDL)]
|
||||
#[webidl(dictionary)]
|
||||
pub(crate) struct GPUTexelCopyTextureInfo {
|
||||
pub texture: Ptr<GPUTexture>,
|
||||
#[webidl(default = 0)]
|
||||
#[options(enforce_range = true)]
|
||||
pub mip_level: u32,
|
||||
#[webidl(default = Default::default())]
|
||||
pub origin: GPUOrigin3D,
|
||||
#[webidl(default = GPUTextureAspect::All)]
|
||||
pub aspect: GPUTextureAspect,
|
||||
}
|
||||
|
||||
#[derive(WebIDL)]
|
||||
#[webidl(dictionary)]
|
||||
struct GPUTexelCopyBufferLayout {
|
||||
#[webidl(default = 0)]
|
||||
#[options(enforce_range = true)]
|
||||
offset: u64,
|
||||
#[options(enforce_range = true)]
|
||||
bytes_per_row: Option<u32>,
|
||||
#[options(enforce_range = true)]
|
||||
rows_per_image: Option<u32>,
|
||||
}
|
||||
|
||||
impl From<GpuImageDataLayout> for wgpu_types::ImageDataLayout {
|
||||
fn from(layout: GpuImageDataLayout) -> Self {
|
||||
wgpu_types::ImageDataLayout {
|
||||
offset: layout.offset,
|
||||
bytes_per_row: layout.bytes_per_row,
|
||||
rows_per_image: layout.rows_per_image,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[serde]
|
||||
pub fn op_webgpu_write_buffer(
|
||||
state: &mut OpState,
|
||||
#[smi] queue_rid: ResourceId,
|
||||
#[smi] buffer: ResourceId,
|
||||
#[number] buffer_offset: u64,
|
||||
#[number] data_offset: usize,
|
||||
#[number] size: Option<usize>,
|
||||
#[buffer] buf: &[u8],
|
||||
) -> Result<WebGpuResult, ResourceError> {
|
||||
let instance = state.borrow::<Instance>();
|
||||
let buffer_resource = state
|
||||
.resource_table
|
||||
.get::<super::buffer::WebGpuBuffer>(buffer)?;
|
||||
let buffer = buffer_resource.1;
|
||||
let queue_resource = state.resource_table.get::<WebGpuQueue>(queue_rid)?;
|
||||
let queue = queue_resource.1;
|
||||
|
||||
let data = match size {
|
||||
Some(size) => &buf[data_offset..(data_offset + size)],
|
||||
None => &buf[data_offset..],
|
||||
};
|
||||
let maybe_err = gfx_select!(queue => instance.queue_write_buffer(
|
||||
queue,
|
||||
buffer,
|
||||
buffer_offset,
|
||||
data
|
||||
))
|
||||
.err();
|
||||
|
||||
Ok(WebGpuResult::maybe_err(maybe_err))
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[serde]
|
||||
pub fn op_webgpu_write_texture(
|
||||
state: &mut OpState,
|
||||
#[smi] queue_rid: ResourceId,
|
||||
#[serde] destination: super::command_encoder::GpuImageCopyTexture,
|
||||
#[serde] data_layout: GpuImageDataLayout,
|
||||
#[serde] size: wgpu_types::Extent3d,
|
||||
#[buffer] buf: &[u8],
|
||||
) -> Result<WebGpuResult, ResourceError> {
|
||||
let instance = state.borrow::<Instance>();
|
||||
let texture_resource = state
|
||||
.resource_table
|
||||
.get::<super::texture::WebGpuTexture>(destination.texture)?;
|
||||
let queue_resource = state.resource_table.get::<WebGpuQueue>(queue_rid)?;
|
||||
let queue = queue_resource.1;
|
||||
|
||||
let destination = wgpu_core::command::ImageCopyTexture {
|
||||
texture: texture_resource.id,
|
||||
mip_level: destination.mip_level,
|
||||
origin: destination.origin,
|
||||
aspect: destination.aspect,
|
||||
};
|
||||
let data_layout = data_layout.into();
|
||||
|
||||
gfx_ok!(queue => instance.queue_write_texture(
|
||||
queue,
|
||||
&destination,
|
||||
buf,
|
||||
&data_layout,
|
||||
&size
|
||||
))
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue