diff --git a/cts_runner/test.lst b/cts_runner/test.lst index dfa3995aab4..d30d20ae3e0 100644 --- a/cts_runner/test.lst +++ b/cts_runner/test.lst @@ -140,7 +140,12 @@ webgpu:api,validation,resource_usages,texture,in_pass_encoder:shader_stages_and_ webgpu:api,validation,resource_usages,texture,in_pass_encoder:subresources_and_binding_types_combination_for_aspect:* webgpu:api,validation,resource_usages,texture,in_pass_encoder:subresources_and_binding_types_combination_for_color:compute=false;type0="render-target";type1="render-target" webgpu:api,validation,resource_usages,texture,in_pass_encoder:unused_bindings_in_pipeline:* -webgpu:api,validation,resource_usages,texture,in_render_common:subresources,multiple_bind_groups:bg0Levels={"base":0,"count":1};* +webgpu:api,validation,resource_usages,texture,in_render_common:subresources,color_attachments:* +webgpu:api,validation,resource_usages,texture,in_render_common:subresources,color_attachment_and_bind_group:* +// FAIL: webgpu:api,validation,resource_usages,texture,in_render_common:subresources,depth_stencil_attachment_and_bind_group:* +// https://github.com/gfx-rs/wgpu/issues/8705 +webgpu:api,validation,resource_usages,texture,in_render_common:subresources,multiple_bind_groups:* +webgpu:api,validation,resource_usages,texture,in_render_common:subresources,depth_stencil_texture_in_bind_groups:* webgpu:api,validation,texture,rg11b10ufloat_renderable:* webgpu:api,operation,render_pipeline,overrides:* webgpu:api,operation,rendering,3d_texture_slices:* diff --git a/deno_webgpu/command_encoder.rs b/deno_webgpu/command_encoder.rs index 358d8c352a1..45fb5d2c5a8 100644 --- a/deno_webgpu/command_encoder.rs +++ b/deno_webgpu/command_encoder.rs @@ -3,6 +3,8 @@ use std::borrow::Cow; use std::cell::RefCell; use std::num::NonZero; +#[cfg(target_vendor = "apple")] +use std::sync::OnceLock; use deno_core::cppgc::Ptr; use deno_core::op2; @@ -30,6 +32,11 @@ pub struct GPUCommandEncoder { pub id: wgpu_core::id::CommandEncoderId, pub label: String, + + // Weak reference to the JS object so we can attach a finalizer. + // See `GPUDevice::create_command_encoder`. + #[cfg(target_vendor = "apple")] + pub(crate) weak: OnceLock>, } impl Drop for GPUCommandEncoder { diff --git a/deno_webgpu/device.rs b/deno_webgpu/device.rs index 300d3a09a2c..2b9c585046b 100644 --- a/deno_webgpu/device.rs +++ b/deno_webgpu/device.rs @@ -5,8 +5,7 @@ use std::cell::RefCell; use std::num::NonZeroU64; use std::rc::Rc; -use deno_core::cppgc::make_cppgc_object; -use deno_core::cppgc::SameObject; +use deno_core::cppgc::{make_cppgc_object, SameObject}; use deno_core::op2; use deno_core::v8; use deno_core::webidl::WebIdlInterfaceConverter; @@ -531,18 +530,30 @@ impl GPUDevice { self.new_render_pipeline(descriptor) } - #[cppgc] - fn create_command_encoder( + fn create_command_encoder<'a>( &self, + scope: &mut v8::HandleScope<'a>, #[webidl] descriptor: Option< super::command_encoder::GPUCommandEncoderDescriptor, >, - ) -> GPUCommandEncoder { + ) -> v8::Local<'a, v8::Object> { + // Metal imposes a limit on the number of outstanding command buffers. + // Attempting to create another command buffer after reaching that limit + // will block, which can result in a deadlock if GC is required to + // recover old command buffers. To encourage V8 to garbage collect + // command buffers before that happens, we associate some external + // memory with each command buffer. + #[cfg(target_vendor = "apple")] + const EXTERNAL_MEMORY_AMOUNT: i64 = 1 << 16; + let label = descriptor.map(|d| d.label).unwrap_or_default(); let wgpu_descriptor = wgpu_types::CommandEncoderDescriptor { label: Some(Cow::Owned(label.clone())), }; + #[cfg(target_vendor = "apple")] + scope.adjust_amount_of_external_allocated_memory(EXTERNAL_MEMORY_AMOUNT); + let (id, err) = self.instance.device_create_command_encoder( self.id, &wgpu_descriptor, @@ -551,12 +562,39 @@ impl GPUDevice { self.error_handler.push_error(err); - GPUCommandEncoder { + let encoder = GPUCommandEncoder { instance: self.instance.clone(), error_handler: self.error_handler.clone(), id, label, + #[cfg(target_vendor = "apple")] + weak: std::sync::OnceLock::new(), + }; + + let obj = make_cppgc_object(scope, encoder); + + #[cfg(target_vendor = "apple")] + { + let finalizer = v8::Weak::with_finalizer( + scope, + obj, + Box::new(|isolate: &mut v8::Isolate| { + isolate.adjust_amount_of_external_allocated_memory( + -EXTERNAL_MEMORY_AMOUNT, + ); + }), + ); + deno_core::cppgc::try_unwrap_cppgc_object::( + scope, + obj.into(), + ) + .unwrap() + .weak + .set(finalizer) + .unwrap(); } + + obj } #[required(1)]