diff --git a/ext/webgpu/01_webgpu.js b/ext/webgpu/01_webgpu.js index be7b6f1647..c28cffc40e 100644 --- a/ext/webgpu/01_webgpu.js +++ b/ext/webgpu/01_webgpu.js @@ -213,6 +213,7 @@ ObjectDefineProperty(GPUSupportedFeatures, customInspect, { }, }); const GPUSupportedFeaturesPrototype = GPUSupportedFeatures.prototype; +webidl.setlike(GPUSupportedFeatures, GPUSupportedFeaturesPrototype, true); ObjectDefineProperty(GPUDeviceLostInfo, customInspect, { value(inspect, inspectOptions) { @@ -689,6 +690,7 @@ ObjectDefineProperty(GPUQuerySet, customInspect, { const GPUQuerySetPrototype = GPUQuerySet.prototype; // Converters +/* // DICTIONARY: GPUPipelineErrorInit webidl.converters["GPUPipelineErrorInit"] = webidl.createDictionaryConverter( @@ -712,7 +714,7 @@ webidl.converters["GPUPipelineErrorReason"] = webidl.createEnumConverter( ); // TYPEDEF: GPUError -webidl.converters["GPUError"] = webidl.converters.any /** put union here! **/; +webidl.converters["GPUError"] = webidl.converters.any /!** put union here! **!/; // // INTERFACE: GPUUncapturedErrorEvent // webidl.converters.GPUUncapturedErrorEvent = webidl.createInterfaceConverter( @@ -794,6 +796,7 @@ webidl.converters["GPUCanvasConfiguration"] = webidl "GPUCanvasConfiguration", dictMembersGPUCanvasConfiguration, ); +*/ let gpu; function initGPU() { diff --git a/ext/webgpu/lib.rs b/ext/webgpu/lib.rs index f7b6d9a2d9..58f3d6ceac 100644 --- a/ext/webgpu/lib.rs +++ b/ext/webgpu/lib.rs @@ -2,7 +2,6 @@ #![cfg(not(target_arch = "wasm32"))] #![warn(unsafe_op_in_unsafe_fn)] -use deno_core::GarbageCollected; pub use wgpu_core; pub use wgpu_types; @@ -40,7 +39,7 @@ deno_core::extension!( wrap::render_pipeline::GPURenderPipeline, wrap::sampler::GPUSampler, wrap::shader::GPUShaderModule, - GPUSupportedFeatures, + wrap::adapter::GPUSupportedFeatures, wrap::adapter::GPUSupportedLimits, wrap::texture::GPUTexture, wrap::texture::GPUTextureView, @@ -48,10 +47,3 @@ deno_core::extension!( esm = ["00_init.js"], lazy_loaded_esm = ["01_webgpu.js"], ); - -struct GPUSupportedFeatures {} - -impl GarbageCollected for GPUSupportedFeatures {} - -#[deno_core::op2] -impl GPUSupportedFeatures {} diff --git a/ext/webgpu/wrap/adapter.rs b/ext/webgpu/wrap/adapter.rs index 97ad7b23b1..807ad2665b 100644 --- a/ext/webgpu/wrap/adapter.rs +++ b/ext/webgpu/wrap/adapter.rs @@ -9,9 +9,11 @@ use deno_core::op2; use deno_core::v8; use deno_core::GarbageCollected; use deno_core::WebIDL; +use tokio::sync::Mutex; use super::device::GPUDevice; use crate::wrap::webidl::features_to_feature_names; +use crate::wrap::webidl::GPUFeatureName; use crate::Instance; #[derive(WebIDL)] @@ -36,7 +38,7 @@ struct GPUDeviceDescriptor { label: String, #[webidl(default = vec![])] - required_features: Vec, + required_features: Vec, #[webidl(default = Default::default())] #[options(enforce_range = true)] required_limits: indexmap::IndexMap, @@ -46,11 +48,17 @@ pub struct GPUAdapter { pub instance: Instance, pub id: wgpu_core::id::AdapterId, - pub features: SameObject, + pub features: SameObject, pub limits: SameObject, pub info: Rc>, } +impl Drop for GPUAdapter { + fn drop(&mut self) { + self.instance.adapter_drop(self.id); + } +} + impl GarbageCollected for GPUAdapter {} #[op2] @@ -58,7 +66,7 @@ impl GPUAdapter { #[getter] #[global] fn info(&self, scope: &mut v8::HandleScope) -> v8::Global { - self.info.get(scope, || { + self.info.get(scope, |_| { let info = self.instance.adapter_get_info(self.id); GPUAdapterInfo(info) }) @@ -67,32 +75,16 @@ impl GPUAdapter { #[getter] #[global] fn features(&self, scope: &mut v8::HandleScope) -> v8::Global { - self.features.get(scope, || { + self.features.get(scope, |scope| { let features = self.instance.adapter_features(self.id); let features = features_to_feature_names(features); - - /* - #[symbol("[[set]]")] - function createGPUSupportedFeatures(features) { - /** @type {GPUSupportedFeatures} */ - const supportedFeatures = webidl.createBranded(GPUSupportedFeatures); - supportedFeatures[webidl.setlikeInner] = new SafeSet(features); - webidl.setlike( - supportedFeatures, - GPUSupportedFeaturesPrototype, - true, - ); - return supportedFeatures; - } - */ - - todo!() + GPUSupportedFeatures::new(scope, features) }) } #[getter] #[global] fn limits(&self, scope: &mut v8::HandleScope) -> v8::Global { - self.limits.get(scope, || { + self.limits.get(scope, |_| { let adapter_limits = self.instance.adapter_limits(self.id); GPUSupportedLimits(adapter_limits) }) @@ -156,7 +148,7 @@ impl GPUAdapter { adapter_info: self.info.clone(), error_handler: Arc::new(super::error::DeviceErrorHandler::new(sender)), adapter: self.id, - lost_receiver: receiver, + lost_receiver: Mutex::new(Some(receiver)), limits: SameObject::new(), features: SameObject::new(), }) @@ -333,6 +325,35 @@ impl GPUSupportedLimits { } } +pub struct GPUSupportedFeatures(v8::Global); + +impl GarbageCollected for GPUSupportedFeatures {} + +impl GPUSupportedFeatures { + pub fn new( + scope: &mut v8::HandleScope, + features: HashSet, + ) -> Self { + let set = v8::Set::new(scope); + + for feature in features { + let key = v8::String::new(scope, feature.as_str()).unwrap(); + set.add(scope, key.into()); + } + + Self(v8::Global::new(scope, >::from(set))) + } +} + +#[op2] +impl GPUSupportedFeatures { + #[global] + #[symbol("setlike_set")] + fn set(&self) -> v8::Global { + self.0.clone() + } +} + pub struct GPUAdapterInfo(pub wgpu_types::AdapterInfo); impl GarbageCollected for GPUAdapterInfo {} diff --git a/ext/webgpu/wrap/bind_group.rs b/ext/webgpu/wrap/bind_group.rs index 946572c395..001049fa60 100644 --- a/ext/webgpu/wrap/bind_group.rs +++ b/ext/webgpu/wrap/bind_group.rs @@ -17,12 +17,20 @@ use deno_core::WebIDL; use crate::wrap::buffer::GPUBuffer; use crate::wrap::sampler::GPUSampler; use crate::wrap::texture::GPUTextureView; +use crate::Instance; pub struct GPUBindGroup { + pub instance: Instance, pub id: wgpu_core::id::BindGroupId, pub label: String, } +impl Drop for GPUBindGroup { + fn drop(&mut self) { + self.instance.bind_group_drop(self.id); + } +} + impl WebIdlInterfaceConverter for GPUBindGroup { const NAME: &'static str = "GPUBindGroup"; } @@ -31,7 +39,16 @@ impl GarbageCollected for GPUBindGroup {} #[op2] impl GPUBindGroup { - crate::with_label!(); + #[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 + } } #[derive(WebIDL)] diff --git a/ext/webgpu/wrap/bind_group_layout.rs b/ext/webgpu/wrap/bind_group_layout.rs index 7eb63254fe..c21a348ae9 100644 --- a/ext/webgpu/wrap/bind_group_layout.rs +++ b/ext/webgpu/wrap/bind_group_layout.rs @@ -5,12 +5,20 @@ use deno_core::GarbageCollected; use deno_core::WebIDL; use crate::wrap::texture::GPUTextureViewDimension; +use crate::Instance; pub struct GPUBindGroupLayout { + pub instance: Instance, pub id: wgpu_core::id::BindGroupLayoutId, pub label: String, } +impl Drop for GPUBindGroupLayout { + fn drop(&mut self) { + self.instance.bind_group_layout_drop(self.id); + } +} + impl deno_core::webidl::WebIdlInterfaceConverter for GPUBindGroupLayout { const NAME: &'static str = "GPUBindGroupLayout"; } @@ -19,7 +27,16 @@ impl GarbageCollected for GPUBindGroupLayout {} #[op2] impl GPUBindGroupLayout { - crate::with_label!(); + #[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 + } } #[derive(WebIDL)] diff --git a/ext/webgpu/wrap/buffer.rs b/ext/webgpu/wrap/buffer.rs index 14d1835e7f..d111253773 100644 --- a/ext/webgpu/wrap/buffer.rs +++ b/ext/webgpu/wrap/buffer.rs @@ -37,6 +37,9 @@ pub enum BufferError { #[class("DOMExceptionOperationError")] #[error(transparent)] Access(#[from] wgpu_core::resource::BufferAccessError), + #[class("DOMExceptionOperationError")] + #[error("{0}")] + Operation(&'static str), #[class(inherit)] #[error(transparent)] Other(#[from] JsErrorBox), @@ -60,6 +63,12 @@ pub struct GPUBuffer { pub mapped_js_buffers: RefCell>>, } +impl Drop for GPUBuffer { + fn drop(&mut self) { + self.instance.buffer_drop(self.id); + } +} + impl WebIdlInterfaceConverter for GPUBuffer { const NAME: &'static str = "GPUBuffer"; } @@ -68,7 +77,16 @@ impl GarbageCollected for GPUBuffer {} #[op2] impl GPUBuffer { - crate::with_label!(); + #[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 + } #[getter] #[number] @@ -89,67 +107,16 @@ impl GPUBuffer { #[async_method] async fn map_async( &self, - #[webidl/*(options(enforce_range = true))*/] mode: u32, - #[webidl/*(default = 0)*/] offset: u64, + #[webidl(options(enforce_range = true))] mode: u32, + #[webidl(default = 0)] offset: u64, #[webidl] size: Option, ) -> Result<(), BufferError> { - let range_size = size.unwrap_or_else(|| self.size.saturating_sub(offset)); - if (offset % 8) != 0 { - /* - throw new DOMException( - `${prefix}: offset must be a multiple of 8, received ${offset}`, - "OperationError", - ); - */ - } - if (range_size % 4) != 0 { - /* - throw new DOMException( - `${prefix}: rangeSize must be a multiple of 4, received ${rangeSize}`, - "OperationError", - ); - */ - } - if (offset + range_size) > self.size { - /* - throw new DOMException( - `${prefix}: offset + rangeSize must be less than or equal to buffer size`, - "OperationError", - ); - */ - } - let read_mode = (mode & 0x0001) == 0x0001; let write_mode = (mode & 0x0002) == 0x0002; if (read_mode && write_mode) || (!read_mode && !write_mode) { - /* - throw new DOMException( - `${prefix}: exactly one of READ or WRITE map mode must be set`, - "OperationError", - ); - */ - } - - if read_mode && !(self.usage & 0x0001) == 0x0001 { - /* - throw new DOMException( - `${prefix}: READ map mode not valid because buffer does not have MAP_READ usage`, - "OperationError", - ); - */ - } - - if write_mode && !(self.usage & 0x0002) == 0x0002 { - /* - throw new DOMException( - `${prefix}: WRITE map mode not valid because buffer does not have MAP_WRITE usage`, - "OperationError", - ); - */ - } - - { - *self.map_state.borrow_mut() = "pending"; + return Err(BufferError::Operation( + "exactly one of READ or WRITE map mode must be set", + )); } let mode = if read_mode { @@ -159,6 +126,10 @@ impl GPUBuffer { MapMode::Write }; + { + *self.map_state.borrow_mut() = "pending"; + } + let (sender, receiver) = oneshot::channel::(); @@ -167,13 +138,12 @@ impl GPUBuffer { sender.send(status).unwrap(); }); - // TODO(lucacasonato): error handling let err = self .instance .buffer_map_async( self.id, offset, - Some(range_size), + size, wgpu_core::resource::BufferMapOperation { host: mode, callback: Some(BufferMapCallback::from_rust(callback)), @@ -183,13 +153,7 @@ impl GPUBuffer { if err.is_some() { self.error_handler.push_error(err); - return Err( - JsErrorBox::new( - "DOMExceptionOperationError", - "validation error occurred", - ) - .into(), - ); + return Err(BufferError::Operation("validation error occurred")); } } @@ -226,7 +190,7 @@ impl GPUBuffer { fn get_mapped_range<'s>( &self, scope: &mut v8::HandleScope<'s>, - #[webidl/*(default = 0)*/] offset: u64, + #[webidl(default = 0)] offset: u64, #[webidl] size: Option, ) -> Result, BufferError> { let size = size.unwrap_or_else(|| self.size.saturating_sub(offset)); @@ -247,6 +211,7 @@ impl GPUBuffer { ) { } + // SAFETY: creating a backing store from the pointer and length provided by wgpu unsafe { v8::ArrayBuffer::new_backing_store_from_ptr( slice_pointer.as_ptr() as _, @@ -256,6 +221,7 @@ impl GPUBuffer { ) } } else { + // SAFETY: creating a vector from the pointer and length provided by wgpu let slice = unsafe { std::slice::from_raw_parts(slice_pointer.as_ptr(), range_size as usize) }; diff --git a/ext/webgpu/wrap/command_buffer.rs b/ext/webgpu/wrap/command_buffer.rs index 3a095a8ae1..d03311376c 100644 --- a/ext/webgpu/wrap/command_buffer.rs +++ b/ext/webgpu/wrap/command_buffer.rs @@ -4,11 +4,20 @@ use deno_core::op2; use deno_core::GarbageCollected; use deno_core::WebIDL; +use crate::Instance; + pub struct GPUCommandBuffer { + pub instance: Instance, pub id: wgpu_core::id::CommandBufferId, pub label: String, } +impl Drop for GPUCommandBuffer { + fn drop(&mut self) { + self.instance.command_buffer_drop(self.id); + } +} + impl deno_core::webidl::WebIdlInterfaceConverter for GPUCommandBuffer { const NAME: &'static str = "GPUCommandBuffer"; } @@ -17,7 +26,16 @@ impl GarbageCollected for GPUCommandBuffer {} #[op2] impl GPUCommandBuffer { - crate::with_label!(); + #[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 + } } #[derive(WebIDL)] diff --git a/ext/webgpu/wrap/command_encoder.rs b/ext/webgpu/wrap/command_encoder.rs index b3d02d1c2b..fbb515323b 100644 --- a/ext/webgpu/wrap/command_encoder.rs +++ b/ext/webgpu/wrap/command_encoder.rs @@ -29,11 +29,26 @@ pub struct GPUCommandEncoder { pub label: String, } +impl Drop for GPUCommandEncoder { + fn drop(&mut self) { + self.instance.command_encoder_drop(self.id); + } +} + impl GarbageCollected for GPUCommandEncoder {} #[op2] impl GPUCommandEncoder { - crate::with_label!(); + #[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 + } #[required(1)] #[cppgc] @@ -80,7 +95,7 @@ impl GPUCommandEncoder { .unwrap_or(GPUStoreOp::Store) .into(), clear_value: attachment.depth_clear_value.unwrap_or_default(), - read_only: false, + read_only: attachment.depth_read_only, }, stencil: PassChannel { load_op: attachment @@ -92,7 +107,7 @@ impl GPUCommandEncoder { .unwrap_or(GPUStoreOp::Store) .into(), clear_value: attachment.stencil_clear_value, - read_only: false, + read_only: attachment.stencil_read_only, }, }) }).transpose()?; @@ -169,10 +184,10 @@ impl GPUCommandEncoder { fn copy_buffer_to_buffer( &self, #[webidl] source: Ptr, - #[webidl/*(options(enforce_range = true))*/] source_offset: u64, + #[webidl(options(enforce_range = true))] source_offset: u64, #[webidl] destination: Ptr, - #[webidl/*(options(enforce_range = true))*/] destination_offset: u64, - #[webidl/*(options(enforce_range = true))*/] size: u64, + #[webidl(options(enforce_range = true))] destination_offset: u64, + #[webidl(options(enforce_range = true))] size: u64, ) { let err = self .instance @@ -296,8 +311,8 @@ impl GPUCommandEncoder { fn clear_buffer( &self, #[webidl] buffer: Ptr, - #[webidl/*(default = 0, options(enforce_range = true))*/] offset: u64, - #[webidl/*(options(enforce_range = true))*/] size: Option, + #[webidl(default = 0, options(enforce_range = true))] offset: u64, + #[webidl(options(enforce_range = true))] size: Option, ) { let err = self .instance @@ -310,10 +325,10 @@ impl GPUCommandEncoder { fn resolve_query_set( &self, #[webidl] query_set: Ptr, - #[webidl/*(options(enforce_range = true))*/] first_query: u32, - #[webidl/*(options(enforce_range = true))*/] query_count: u32, + #[webidl(options(enforce_range = true))] first_query: u32, + #[webidl(options(enforce_range = true))] query_count: u32, #[webidl] destination: Ptr, - #[webidl/*(options(enforce_range = true))*/] destination_offset: u64, + #[webidl(options(enforce_range = true))] destination_offset: u64, ) { let err = self .instance @@ -347,6 +362,7 @@ impl GPUCommandEncoder { self.error_handler.push_error(err); GPUCommandBuffer { + instance: self.instance.clone(), id, label: descriptor.label, } diff --git a/ext/webgpu/wrap/compute_pass.rs b/ext/webgpu/wrap/compute_pass.rs index 274cb3a239..52f3b87a1a 100644 --- a/ext/webgpu/wrap/compute_pass.rs +++ b/ext/webgpu/wrap/compute_pass.rs @@ -27,7 +27,16 @@ impl GarbageCollected for GPUComputePassEncoder {} #[op2] impl GPUComputePassEncoder { - crate::with_label!(); + #[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 + } fn set_pipeline( &self, @@ -45,10 +54,10 @@ impl GPUComputePassEncoder { fn dispatch_workgroups( &self, - #[webidl/*(options(enforce_range = true))*/] work_group_count_x: u32, - #[webidl/*(default = 1, options(enforce_range = true))*/] + #[webidl(options(enforce_range = true))] work_group_count_x: u32, + #[webidl(default = 1, options(enforce_range = true))] work_group_count_y: u32, - #[webidl/*(default = 1, options(enforce_range = true))*/] + #[webidl(default = 1, options(enforce_range = true))] work_group_count_z: u32, ) { let err = self @@ -66,7 +75,7 @@ impl GPUComputePassEncoder { fn dispatch_workgroups_indirect( &self, #[webidl] indirect_buffer: Ptr, - #[webidl/*(options(enforce_range = true))*/] indirect_offset: u64, + #[webidl(options(enforce_range = true))] indirect_offset: u64, ) { let err = self .instance @@ -124,7 +133,7 @@ impl GPUComputePassEncoder { fn set_bind_group<'a>( &self, scope: &mut v8::HandleScope<'a>, - #[webidl/*(options(enforce_range = true))*/] index: u32, + #[webidl(options(enforce_range = true))] index: u32, #[webidl] bind_group: Nullable>, dynamic_offsets: v8::Local<'a, v8::Value>, dynamic_offsets_data_start: v8::Local<'a, v8::Value>, @@ -159,6 +168,7 @@ impl GPUComputePassEncoder { let ptr = ab.data().unwrap(); let ab_len = ab.byte_length() / 4; + // SAFETY: compute_pass_set_bind_group internally calls extend_from_slice with this slice let data = unsafe { std::slice::from_raw_parts(ptr.as_ptr() as _, ab_len) }; diff --git a/ext/webgpu/wrap/compute_pipeline.rs b/ext/webgpu/wrap/compute_pipeline.rs index 55e426e6b0..ce17778900 100644 --- a/ext/webgpu/wrap/compute_pipeline.rs +++ b/ext/webgpu/wrap/compute_pipeline.rs @@ -20,6 +20,12 @@ pub struct GPUComputePipeline { pub label: String, } +impl Drop for GPUComputePipeline { + fn drop(&mut self) { + self.instance.compute_pipeline_drop(self.id); + } +} + impl WebIdlInterfaceConverter for GPUComputePipeline { const NAME: &'static str = "GPUComputePipeline"; } @@ -28,7 +34,16 @@ impl GarbageCollected for GPUComputePipeline {} #[op2] impl GPUComputePipeline { - crate::with_label!(); + #[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 + } #[cppgc] fn get_bind_group_layout(&self, #[webidl] index: u32) -> GPUBindGroupLayout { @@ -40,6 +55,7 @@ impl GPUComputePipeline { // TODO: wgpu needs to support retrieving the label GPUBindGroupLayout { + instance: self.instance.clone(), id, label: "".to_string(), } diff --git a/ext/webgpu/wrap/device.rs b/ext/webgpu/wrap/device.rs index 51fda9f925..f822dd111e 100644 --- a/ext/webgpu/wrap/device.rs +++ b/ext/webgpu/wrap/device.rs @@ -23,11 +23,13 @@ use super::sampler::GPUSampler; use super::shader::GPUShaderModule; use super::texture::GPUTexture; use crate::wrap::adapter::GPUAdapterInfo; +use crate::wrap::adapter::GPUSupportedFeatures; use crate::wrap::adapter::GPUSupportedLimits; use crate::wrap::command_encoder::GPUCommandEncoder; use crate::wrap::query_set::GPUQuerySet; use crate::wrap::render_bundle::GPURenderBundleEncoder; use crate::wrap::render_pipeline::GPURenderPipeline; +use crate::wrap::webidl::features_to_feature_names; use crate::Instance; pub struct GPUDevice { @@ -38,14 +40,21 @@ pub struct GPUDevice { pub label: String, - pub features: SameObject, + pub features: SameObject, pub limits: SameObject, pub adapter_info: Rc>, pub queue_obj: SameObject, pub error_handler: super::error::ErrorHandler, - pub lost_receiver: tokio::sync::oneshot::Receiver<()>, + pub lost_receiver: + tokio::sync::Mutex>>, +} + +impl Drop for GPUDevice { + fn drop(&mut self) { + self.instance.device_drop(self.id); + } } impl GarbageCollected for GPUDevice {} @@ -54,19 +63,33 @@ impl GarbageCollected for GPUDevice {} // TODO: setEventTargetData on instance #[op2] impl GPUDevice { - crate::with_label!(); + #[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 + } #[getter] - fn features(&self) { - todo!() + #[global] + fn features(&self, scope: &mut v8::HandleScope) -> v8::Global { + self.features.get(scope, |scope| { + let features = self.instance.device_features(self.id); + let features = features_to_feature_names(features); + GPUSupportedFeatures::new(scope, features) + }) } #[getter] #[global] fn limits(&self, scope: &mut v8::HandleScope) -> v8::Global { - self.limits.get(scope, || { - let adapter_limits = self.instance.device_limits(self.id); - GPUSupportedLimits(adapter_limits) + self.limits.get(scope, |_| { + let limits = self.instance.device_limits(self.id); + GPUSupportedLimits(limits) }) } @@ -76,7 +99,7 @@ impl GPUDevice { &self, scope: &mut v8::HandleScope, ) -> v8::Global { - self.adapter_info.get(scope, || { + self.adapter_info.get(scope, |_| { let info = self.instance.adapter_get_info(self.adapter); GPUAdapterInfo(info) }) @@ -85,7 +108,7 @@ impl GPUDevice { #[getter] #[global] fn queue(&self, scope: &mut v8::HandleScope) -> v8::Global { - self.queue_obj.get(scope, || GPUQueue { + self.queue_obj.get(scope, |_| GPUQueue { id: self.queue, error_handler: self.error_handler.clone(), instance: self.instance.clone(), @@ -287,6 +310,7 @@ impl GPUDevice { self.error_handler.push_error(err); Ok(GPUBindGroupLayout { + instance: self.instance.clone(), id, label: descriptor.label, }) @@ -328,6 +352,7 @@ impl GPUDevice { self.error_handler.push_error(err); Ok(GPUPipelineLayout { + instance: self.instance.clone(), id, label: descriptor.label, }) @@ -376,6 +401,7 @@ impl GPUDevice { self.error_handler.push_error(err); GPUBindGroup { + instance: self.instance.clone(), id, label: descriptor.label, } @@ -404,6 +430,7 @@ impl GPUDevice { self.error_handler.push_error(err); GPUShaderModule { + instance: self.instance.clone(), id, label: descriptor.label, } @@ -543,6 +570,7 @@ impl GPUDevice { self.error_handler.push_error(err); GPUQuerySet { + instance: self.instance.clone(), id, r#type: descriptor.r#type, count: descriptor.count, @@ -550,12 +578,14 @@ impl GPUDevice { } } - // TODO: return same promise + // TODO: support returning same promise #[async_method] #[getter] #[cppgc] async fn lost(&self) -> GPUDeviceLostInfo { - // TODO: self.lost_receiver.await.unwrap(); + if let Some(lost_receiver) = self.lost_receiver.lock().await.take() { + let _ = lost_receiver.await; + } GPUDeviceLostInfo } @@ -565,7 +595,8 @@ impl GPUDevice { self .error_handler .scopes - .borrow_mut() + .lock() + .unwrap() .push((filter, vec![])); } @@ -591,10 +622,7 @@ impl GPUDevice { Ok(v8::null(scope).into()) }*/ - Err(JsErrorBox::new( - "DOMExceptionOperationError", - "There are no error scopes on the error scope stack", - )) + todo!() } } diff --git a/ext/webgpu/wrap/error.rs b/ext/webgpu/wrap/error.rs index 9276c34aec..7d658a7672 100644 --- a/ext/webgpu/wrap/error.rs +++ b/ext/webgpu/wrap/error.rs @@ -1,10 +1,9 @@ // Copyright 2018-2025 the Deno authors. MIT license. -use std::cell::OnceCell; -use std::cell::RefCell; use std::fmt::Display; use std::fmt::Formatter; use std::sync::Mutex; +use std::sync::OnceLock; use wgpu_core::binding_model::CreateBindGroupError; use wgpu_core::binding_model::CreateBindGroupLayoutError; @@ -35,10 +34,10 @@ use wgpu_core::resource::CreateTextureViewError; pub type ErrorHandler = std::sync::Arc; pub struct DeviceErrorHandler { - pub is_lost: OnceCell<()>, + pub is_lost: OnceLock<()>, lost_sender: Mutex>>, - pub scopes: RefCell)>>, + pub scopes: Mutex)>>, } impl DeviceErrorHandler { @@ -46,7 +45,7 @@ impl DeviceErrorHandler { Self { is_lost: Default::default(), lost_sender: Mutex::new(Some(sender)), - scopes: RefCell::new(vec![]), + scopes: Mutex::new(vec![]), } } @@ -77,7 +76,7 @@ impl DeviceErrorHandler { GPUError::Internal => GPUErrorFilter::Internal, }; - let mut scopes = self.scopes.borrow_mut(); + let mut scopes = self.scopes.lock().unwrap(); let scope = scopes .iter_mut() .rfind(|(filter, _)| filter == &error_filter); @@ -106,7 +105,8 @@ pub enum GPUErrorFilter { #[derive(Debug, deno_error::JsError)] pub enum GPUError { - #[class("UNREACHABLE")] // TODO + // TODO(@crowlKats): consider adding an unreachable value that uses unreachable!() + #[class("UNREACHABLE")] Lost, #[class("GPUValidationError")] Validation(String), diff --git a/ext/webgpu/wrap/mod.rs b/ext/webgpu/wrap/mod.rs index 18e43341c4..b995647bb0 100644 --- a/ext/webgpu/wrap/mod.rs +++ b/ext/webgpu/wrap/mod.rs @@ -107,19 +107,3 @@ impl GPU { } } } - -#[macro_export] -macro_rules! with_label { - () => { - #[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 - } - }; -} diff --git a/ext/webgpu/wrap/pipeline_layout.rs b/ext/webgpu/wrap/pipeline_layout.rs index f6ed320823..4559942ea2 100644 --- a/ext/webgpu/wrap/pipeline_layout.rs +++ b/ext/webgpu/wrap/pipeline_layout.rs @@ -7,11 +7,20 @@ use deno_core::webidl::WebIdlInterfaceConverter; use deno_core::GarbageCollected; use deno_core::WebIDL; +use crate::Instance; + pub struct GPUPipelineLayout { + pub instance: Instance, pub id: wgpu_core::id::PipelineLayoutId, pub label: String, } +impl Drop for GPUPipelineLayout { + fn drop(&mut self) { + self.instance.pipeline_layout_drop(self.id); + } +} + impl WebIdlInterfaceConverter for GPUPipelineLayout { const NAME: &'static str = "GPUPipelineLayout"; } @@ -20,7 +29,16 @@ impl GarbageCollected for GPUPipelineLayout {} #[op2] impl GPUPipelineLayout { - crate::with_label!(); + #[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 + } } #[derive(WebIDL)] diff --git a/ext/webgpu/wrap/query_set.rs b/ext/webgpu/wrap/query_set.rs index 6413a8756b..eada34052c 100644 --- a/ext/webgpu/wrap/query_set.rs +++ b/ext/webgpu/wrap/query_set.rs @@ -6,13 +6,22 @@ use deno_core::GarbageCollected; use deno_core::WebIDL; use deno_error::JsErrorBox; +use crate::Instance; + pub struct GPUQuerySet { + pub instance: Instance, pub id: wgpu_core::id::QuerySetId, pub r#type: GPUQueryType, pub count: u32, pub label: String, } +impl Drop for GPUQuerySet { + fn drop(&mut self) { + self.instance.query_set_drop(self.id); + } +} + impl WebIdlInterfaceConverter for GPUQuerySet { const NAME: &'static str = "GPUQuerySet"; } @@ -21,7 +30,16 @@ impl GarbageCollected for GPUQuerySet {} #[op2] impl GPUQuerySet { - crate::with_label!(); + #[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 + } #[fast] fn destroy(&self) -> Result<(), JsErrorBox> { diff --git a/ext/webgpu/wrap/queue.rs b/ext/webgpu/wrap/queue.rs index a582053a8c..8dadcdd4b6 100644 --- a/ext/webgpu/wrap/queue.rs +++ b/ext/webgpu/wrap/queue.rs @@ -22,11 +22,27 @@ pub struct GPUQueue { 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] impl GPUQueue { - crate::with_label!(); + #[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 + } #[required(1)] fn submit(&self, #[webidl] command_buffers: Vec>) { @@ -53,10 +69,10 @@ impl GPUQueue { fn write_buffer( &self, #[webidl] buffer: Ptr, - #[webidl/*(options(enforce_range = true))*/] buffer_offset: u64, - #[anybuffer] buf: &[u8], // TODO: AllowSharedBufferSource - #[webidl/*(default = 0, options(enforce_range = true))*/] data_offset: u64, - #[webidl/*(options(enforce_range = true))*/] size: Option, + #[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, ) { let data = match size { Some(size) => { @@ -77,7 +93,7 @@ impl GPUQueue { fn write_texture( &self, #[webidl] destination: GPUTexelCopyTextureInfo, - #[anybuffer] buf: &[u8], // TODO: AllowSharedBufferSource + #[anybuffer] buf: &[u8], #[webidl] data_layout: GPUTexelCopyBufferLayout, #[webidl] size: GPUExtent3D, ) { diff --git a/ext/webgpu/wrap/render_bundle.rs b/ext/webgpu/wrap/render_bundle.rs index bf6231acfd..28ba01a0f3 100644 --- a/ext/webgpu/wrap/render_bundle.rs +++ b/ext/webgpu/wrap/render_bundle.rs @@ -32,7 +32,16 @@ impl GarbageCollected for GPURenderBundleEncoder {} #[op2] impl GPURenderBundleEncoder { - crate::with_label!(); + #[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 + } #[cppgc] fn finish( @@ -52,6 +61,7 @@ impl GPURenderBundleEncoder { self.error_handler.push_error(err); GPURenderBundle { + instance: self.instance.clone(), id, label: descriptor.label.clone(), } @@ -110,7 +120,7 @@ impl GPURenderBundleEncoder { fn set_bind_group<'a>( &self, scope: &mut v8::HandleScope<'a>, - #[webidl/*(options(enforce_range = true))*/] index: u32, + #[webidl(options(enforce_range = true))] index: u32, #[webidl] bind_group: Nullable>, dynamic_offsets: v8::Local<'a, v8::Value>, dynamic_offsets_data_start: v8::Local<'a, v8::Value>, @@ -211,8 +221,8 @@ impl GPURenderBundleEncoder { &self, #[webidl] buffer: Ptr, #[webidl] index_format: crate::wrap::render_pipeline::GPUIndexFormat, - #[webidl/*(default = 0, options(enforce_range = true))*/] offset: u64, - #[webidl/*(options(enforce_range = true))*/] size: Option, + #[webidl(default = 0, options(enforce_range = true))] offset: u64, + #[webidl(options(enforce_range = true))] size: Option, ) -> Result<(), JsErrorBox> { let mut encoder = self.encoder.borrow_mut(); let encoder = encoder.as_mut().ok_or_else(|| { @@ -231,10 +241,10 @@ impl GPURenderBundleEncoder { #[required(2)] fn set_vertex_buffer( &self, - #[webidl/*(options(enforce_range = true))*/] slot: u32, + #[webidl(options(enforce_range = true))] slot: u32, #[webidl] buffer: Ptr, // TODO: support nullable buffer - #[webidl/*(default = 0, options(enforce_range = true))*/] offset: u64, - #[webidl/*(options(enforce_range = true))*/] size: Option, + #[webidl(default = 0, options(enforce_range = true))] offset: u64, + #[webidl(options(enforce_range = true))] size: Option, ) -> Result<(), JsErrorBox> { let mut encoder = self.encoder.borrow_mut(); let encoder = encoder.as_mut().ok_or_else(|| { @@ -254,12 +264,10 @@ impl GPURenderBundleEncoder { #[required(1)] fn draw( &self, - #[webidl/*(options(enforce_range = true))*/] vertex_count: u32, - #[webidl/*(default = 1, options(enforce_range = true))*/] - instance_count: u32, - #[webidl/*(default = 0, options(enforce_range = true))*/] first_vertex: u32, - #[webidl/*(default = 0, options(enforce_range = true))*/] - first_instance: u32, + #[webidl(options(enforce_range = true))] vertex_count: u32, + #[webidl(default = 1, options(enforce_range = true))] instance_count: u32, + #[webidl(default = 0, options(enforce_range = true))] first_vertex: u32, + #[webidl(default = 0, options(enforce_range = true))] first_instance: u32, ) -> Result<(), JsErrorBox> { let mut encoder = self.encoder.borrow_mut(); let encoder = encoder.as_mut().ok_or_else(|| { @@ -279,13 +287,11 @@ impl GPURenderBundleEncoder { #[required(1)] fn draw_indexed( &self, - #[webidl/*(options(enforce_range = true))*/] index_count: u32, - #[webidl/*(default = 1, options(enforce_range = true))*/] - instance_count: u32, - #[webidl/*(default = 0, options(enforce_range = true))*/] first_index: u32, - #[webidl/*(default = 0, options(enforce_range = true))*/] base_vertex: i32, - #[webidl/*(default = 0, options(enforce_range = true))*/] - first_instance: u32, + #[webidl(options(enforce_range = true))] index_count: u32, + #[webidl(default = 1, options(enforce_range = true))] instance_count: u32, + #[webidl(default = 0, options(enforce_range = true))] first_index: u32, + #[webidl(default = 0, options(enforce_range = true))] base_vertex: i32, + #[webidl(default = 0, options(enforce_range = true))] first_instance: u32, ) -> Result<(), JsErrorBox> { let mut encoder = self.encoder.borrow_mut(); let encoder = encoder.as_mut().ok_or_else(|| { @@ -307,7 +313,7 @@ impl GPURenderBundleEncoder { fn draw_indirect( &self, #[webidl] indirect_buffer: Ptr, - #[webidl/*(options(enforce_range = true))*/] indirect_offset: u64, + #[webidl(options(enforce_range = true))] indirect_offset: u64, ) -> Result<(), JsErrorBox> { let mut encoder = self.encoder.borrow_mut(); let encoder = encoder.as_mut().ok_or_else(|| { @@ -326,7 +332,7 @@ impl GPURenderBundleEncoder { fn draw_indexed_indirect( &self, #[webidl] indirect_buffer: Ptr, - #[webidl/*(options(enforce_range = true))*/] indirect_offset: u64, + #[webidl(options(enforce_range = true))] indirect_offset: u64, ) -> Result<(), JsErrorBox> { let mut encoder = self.encoder.borrow_mut(); let encoder = encoder.as_mut().ok_or_else(|| { @@ -371,10 +377,17 @@ enum SetBindGroupError { } pub struct GPURenderBundle { + pub instance: Instance, pub id: wgpu_core::id::RenderBundleId, pub label: String, } +impl Drop for GPURenderBundle { + fn drop(&mut self) { + self.instance.render_bundle_drop(self.id); + } +} + impl WebIdlInterfaceConverter for GPURenderBundle { const NAME: &'static str = "GPURenderBundle"; } @@ -383,7 +396,16 @@ impl GarbageCollected for GPURenderBundle {} #[op2] impl GPURenderBundle { - crate::with_label!(); + #[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 + } } #[derive(WebIDL)] diff --git a/ext/webgpu/wrap/render_pass.rs b/ext/webgpu/wrap/render_pass.rs index a76e28a19a..05f931085f 100644 --- a/ext/webgpu/wrap/render_pass.rs +++ b/ext/webgpu/wrap/render_pass.rs @@ -32,7 +32,16 @@ impl GarbageCollected for GPURenderPassEncoder {} #[op2] impl GPURenderPassEncoder { - crate::with_label!(); + #[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 + } #[required(6)] fn set_viewport( @@ -62,10 +71,10 @@ impl GPURenderPassEncoder { #[required(4)] fn set_scissor_rect( &self, - #[webidl/*(options(enforce_range = true))*/] x: u32, - #[webidl/*(options(enforce_range = true))*/] y: u32, - #[webidl/*(options(enforce_range = true))*/] width: u32, - #[webidl/*(options(enforce_range = true))*/] height: u32, + #[webidl(options(enforce_range = true))] x: u32, + #[webidl(options(enforce_range = true))] y: u32, + #[webidl(options(enforce_range = true))] width: u32, + #[webidl(options(enforce_range = true))] height: u32, ) { let err = self .instance @@ -95,7 +104,7 @@ impl GPURenderPassEncoder { #[required(1)] fn set_stencil_reference( &self, - #[webidl/*(options(enforce_range = true))*/] reference: u32, + #[webidl(options(enforce_range = true))] reference: u32, ) { let err = self .instance @@ -110,7 +119,7 @@ impl GPURenderPassEncoder { #[required(1)] fn begin_occlusion_query( &self, - #[webidl/*(options(enforce_range = true))*/] query_index: u32, + #[webidl(options(enforce_range = true))] query_index: u32, ) { let err = self .instance @@ -191,7 +200,7 @@ impl GPURenderPassEncoder { fn set_bind_group<'a>( &self, scope: &mut v8::HandleScope<'a>, - #[webidl/*(options(enforce_range = true))*/] index: u32, + #[webidl(options(enforce_range = true))] index: u32, #[webidl] bind_group: Nullable>, dynamic_offsets: v8::Local<'a, v8::Value>, dynamic_offsets_data_start: v8::Local<'a, v8::Value>, @@ -286,8 +295,8 @@ impl GPURenderPassEncoder { &self, #[webidl] buffer: Ptr, #[webidl] index_format: crate::wrap::render_pipeline::GPUIndexFormat, - #[webidl/*(default = 0, options(enforce_range = true))*/] offset: u64, - #[webidl/*(options(enforce_range = true))*/] size: Option, + #[webidl(default = 0, options(enforce_range = true))] offset: u64, + #[webidl(options(enforce_range = true))] size: Option, ) { let err = self .instance @@ -305,10 +314,10 @@ impl GPURenderPassEncoder { #[required(2)] fn set_vertex_buffer( &self, - #[webidl/*(options(enforce_range = true))*/] slot: u32, + #[webidl(options(enforce_range = true))] slot: u32, #[webidl] buffer: Ptr, // TODO: support nullable buffer - #[webidl/*(default = 0, options(enforce_range = true))*/] offset: u64, - #[webidl/*(options(enforce_range = true))*/] size: Option, + #[webidl(default = 0, options(enforce_range = true))] offset: u64, + #[webidl(options(enforce_range = true))] size: Option, ) { let err = self .instance @@ -326,12 +335,10 @@ impl GPURenderPassEncoder { #[required(1)] fn draw( &self, - #[webidl/*(options(enforce_range = true))*/] vertex_count: u32, - #[webidl/*(default = 1, options(enforce_range = true))*/] - instance_count: u32, - #[webidl/*(default = 0, options(enforce_range = true))*/] first_vertex: u32, - #[webidl/*(default = 0, options(enforce_range = true))*/] - first_instance: u32, + #[webidl(options(enforce_range = true))] vertex_count: u32, + #[webidl(default = 1, options(enforce_range = true))] instance_count: u32, + #[webidl(default = 0, options(enforce_range = true))] first_vertex: u32, + #[webidl(default = 0, options(enforce_range = true))] first_instance: u32, ) { let err = self .instance @@ -349,13 +356,11 @@ impl GPURenderPassEncoder { #[required(1)] fn draw_indexed( &self, - #[webidl/*(options(enforce_range = true))*/] index_count: u32, - #[webidl/*(default = 1, options(enforce_range = true))*/] - instance_count: u32, - #[webidl/*(default = 0, options(enforce_range = true))*/] first_index: u32, - #[webidl/*(default = 0, options(enforce_range = true))*/] base_vertex: i32, - #[webidl/*(default = 0, options(enforce_range = true))*/] - first_instance: u32, + #[webidl(options(enforce_range = true))] index_count: u32, + #[webidl(default = 1, options(enforce_range = true))] instance_count: u32, + #[webidl(default = 0, options(enforce_range = true))] first_index: u32, + #[webidl(default = 0, options(enforce_range = true))] base_vertex: i32, + #[webidl(default = 0, options(enforce_range = true))] first_instance: u32, ) { let err = self .instance @@ -375,7 +380,7 @@ impl GPURenderPassEncoder { fn draw_indirect( &self, #[webidl] indirect_buffer: Ptr, - #[webidl/*(options(enforce_range = true))*/] indirect_offset: u64, + #[webidl(options(enforce_range = true))] indirect_offset: u64, ) { let err = self .instance @@ -392,7 +397,7 @@ impl GPURenderPassEncoder { fn draw_indexed_indirect( &self, #[webidl] indirect_buffer: Ptr, - #[webidl/*(options(enforce_range = true))*/] indirect_offset: u64, + #[webidl(options(enforce_range = true))] indirect_offset: u64, ) { let err = self .instance diff --git a/ext/webgpu/wrap/render_pipeline.rs b/ext/webgpu/wrap/render_pipeline.rs index 9c587a8554..254c7541f2 100644 --- a/ext/webgpu/wrap/render_pipeline.rs +++ b/ext/webgpu/wrap/render_pipeline.rs @@ -23,6 +23,12 @@ pub struct GPURenderPipeline { pub label: String, } +impl Drop for GPURenderPipeline { + fn drop(&mut self) { + self.instance.render_pipeline_drop(self.id); + } +} + impl WebIdlInterfaceConverter for GPURenderPipeline { const NAME: &'static str = "GPURenderPipeline"; } @@ -31,7 +37,16 @@ impl GarbageCollected for GPURenderPipeline {} #[op2] impl GPURenderPipeline { - crate::with_label!(); + #[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 + } #[cppgc] fn get_bind_group_layout(&self, #[webidl] index: u32) -> GPUBindGroupLayout { @@ -43,6 +58,7 @@ impl GPURenderPipeline { // TODO: wgpu needs to add a way to retrieve the label GPUBindGroupLayout { + instance: self.instance.clone(), id, label: "".to_string(), } diff --git a/ext/webgpu/wrap/sampler.rs b/ext/webgpu/wrap/sampler.rs index 5a7106753a..997d2acde2 100644 --- a/ext/webgpu/wrap/sampler.rs +++ b/ext/webgpu/wrap/sampler.rs @@ -13,6 +13,12 @@ pub struct GPUSampler { pub label: String, } +impl Drop for GPUSampler { + fn drop(&mut self) { + self.instance.sampler_drop(self.id); + } +} + impl WebIdlInterfaceConverter for GPUSampler { const NAME: &'static str = "GPUSampler"; } @@ -21,7 +27,16 @@ impl GarbageCollected for GPUSampler {} #[op2] impl GPUSampler { - crate::with_label!(); + #[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 + } } #[derive(WebIDL)] diff --git a/ext/webgpu/wrap/shader.rs b/ext/webgpu/wrap/shader.rs index 21d8842d3a..a49dd57152 100644 --- a/ext/webgpu/wrap/shader.rs +++ b/ext/webgpu/wrap/shader.rs @@ -5,11 +5,20 @@ use deno_core::webidl::WebIdlInterfaceConverter; use deno_core::GarbageCollected; use deno_core::WebIDL; +use crate::Instance; + pub struct GPUShaderModule { + pub instance: Instance, pub id: wgpu_core::id::ShaderModuleId, pub label: String, } +impl Drop for GPUShaderModule { + fn drop(&mut self) { + self.instance.shader_module_drop(self.id); + } +} + impl WebIdlInterfaceConverter for GPUShaderModule { const NAME: &'static str = "GPUShaderModule"; } @@ -18,7 +27,16 @@ impl GarbageCollected for GPUShaderModule {} #[op2] impl GPUShaderModule { - crate::with_label!(); + #[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 + } } #[derive(WebIDL)] diff --git a/ext/webgpu/wrap/texture.rs b/ext/webgpu/wrap/texture.rs index 92fd4830d5..3cab5bcfd6 100644 --- a/ext/webgpu/wrap/texture.rs +++ b/ext/webgpu/wrap/texture.rs @@ -55,6 +55,12 @@ pub struct GPUTexture { pub usage: u32, } +impl Drop for GPUTexture { + fn drop(&mut self) { + self.instance.texture_drop(self.id); + } +} + impl WebIdlInterfaceConverter for GPUTexture { const NAME: &'static str = "GPUTexture"; } @@ -63,7 +69,16 @@ impl GarbageCollected for GPUTexture {} #[op2] impl GPUTexture { - crate::with_label!(); + #[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 + } #[getter] fn width(&self) -> u32 { @@ -133,6 +148,7 @@ impl GPUTexture { self.error_handler.push_error(err); Ok(GPUTextureView { + instance: self.instance.clone(), id, label: descriptor.label, }) @@ -209,11 +225,18 @@ impl From for TextureAspect { } } -pub(crate) struct GPUTextureView { +pub struct GPUTextureView { + pub instance: Instance, pub id: wgpu_core::id::TextureViewId, pub label: String, } +impl Drop for GPUTextureView { + fn drop(&mut self) { + let _ = self.instance.texture_view_drop(self.id); + } +} + impl WebIdlInterfaceConverter for GPUTextureView { const NAME: &'static str = "GPUTextureView"; } @@ -223,7 +246,16 @@ impl GarbageCollected for GPUTextureView {} #[op2] impl GPUTextureView { - crate::with_label!(); + #[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 + } } #[derive(WebIDL, Clone)] diff --git a/ext/webidl/00_webidl.js b/ext/webidl/00_webidl.js index 0fa20d465c..d460f8c863 100644 --- a/ext/webidl/00_webidl.js +++ b/ext/webidl/00_webidl.js @@ -1312,18 +1312,17 @@ function configureProperties(obj) { } } -const setlikeInner = SymbolFor("[[set]]"); +const setlikeInner = SymbolFor("setlike_set"); // Ref: https://webidl.spec.whatwg.org/#es-setlike function setlike(obj, objPrototype, readonly) { - ObjectDefineProperties(obj, { + ObjectDefineProperties(objPrototype, { size: { __proto__: null, configurable: true, enumerable: true, get() { - assertBranded(this, objPrototype); - return obj[setlikeInner].size; + return this[setlikeInner].size; }, }, [SymbolIterator]: { @@ -1332,8 +1331,7 @@ function setlike(obj, objPrototype, readonly) { enumerable: false, writable: true, value() { - assertBranded(this, objPrototype); - return obj[setlikeInner][SymbolIterator](); + return this[setlikeInner][SymbolIterator](); }, }, entries: { @@ -1342,8 +1340,7 @@ function setlike(obj, objPrototype, readonly) { enumerable: true, writable: true, value() { - assertBranded(this, objPrototype); - return SetPrototypeEntries(obj[setlikeInner]); + return SetPrototypeEntries(this[setlikeInner]); }, }, keys: { @@ -1352,8 +1349,7 @@ function setlike(obj, objPrototype, readonly) { enumerable: true, writable: true, value() { - assertBranded(this, objPrototype); - return SetPrototypeKeys(obj[setlikeInner]); + return SetPrototypeKeys(this[setlikeInner]); }, }, values: { @@ -1362,8 +1358,7 @@ function setlike(obj, objPrototype, readonly) { enumerable: true, writable: true, value() { - assertBranded(this, objPrototype); - return SetPrototypeValues(obj[setlikeInner]); + return SetPrototypeValues(this[setlikeInner]); }, }, forEach: { @@ -1372,8 +1367,7 @@ function setlike(obj, objPrototype, readonly) { enumerable: true, writable: true, value(callbackfn, thisArg) { - assertBranded(this, objPrototype); - return SetPrototypeForEach(obj[setlikeInner], callbackfn, thisArg); + return SetPrototypeForEach(this[setlikeInner], callbackfn, thisArg); }, }, has: { @@ -1382,22 +1376,20 @@ function setlike(obj, objPrototype, readonly) { enumerable: true, writable: true, value(value) { - assertBranded(this, objPrototype); - return SetPrototypeHas(obj[setlikeInner], value); + return SetPrototypeHas(this[setlikeInner], value); }, }, }); if (!readonly) { - ObjectDefineProperties(obj, { + ObjectDefineProperties(objPrototype, { add: { __proto__: null, configurable: true, enumerable: true, writable: true, value(value) { - assertBranded(this, objPrototype); - return SetPrototypeAdd(obj[setlikeInner], value); + return SetPrototypeAdd(this[setlikeInner], value); }, }, delete: { @@ -1406,8 +1398,7 @@ function setlike(obj, objPrototype, readonly) { enumerable: true, writable: true, value(value) { - assertBranded(this, objPrototype); - return SetPrototypeDelete(obj[setlikeInner], value); + return SetPrototypeDelete(this[setlikeInner], value); }, }, clear: { @@ -1416,8 +1407,7 @@ function setlike(obj, objPrototype, readonly) { enumerable: true, writable: true, value() { - assertBranded(this, objPrototype); - return SetPrototypeClear(obj[setlikeInner]); + return SetPrototypeClear(this[setlikeInner]); }, }, });