@@ -5,8 +5,7 @@ use std::cell::RefCell;
55use std:: num:: NonZeroU64 ;
66use std:: rc:: Rc ;
77
8- use deno_core:: cppgc:: make_cppgc_object;
9- use deno_core:: cppgc:: SameObject ;
8+ use deno_core:: cppgc:: { make_cppgc_object, SameObject } ;
109use deno_core:: op2;
1110use deno_core:: v8;
1211use deno_core:: webidl:: WebIdlInterfaceConverter ;
@@ -531,18 +530,30 @@ impl GPUDevice {
531530 self . new_render_pipeline ( descriptor)
532531 }
533532
534- #[ cppgc]
535- fn create_command_encoder (
533+ fn create_command_encoder < ' a > (
536534 & self ,
535+ scope : & mut v8:: HandleScope < ' a > ,
537536 #[ webidl] descriptor : Option <
538537 super :: command_encoder:: GPUCommandEncoderDescriptor ,
539538 > ,
540- ) -> GPUCommandEncoder {
539+ ) -> v8:: Local < ' a , v8:: Object > {
540+ // Metal imposes a limit on the number of outstanding command buffers.
541+ // Attempting to create another command buffer after reaching that limit
542+ // will block, which can result in a deadlock if GC is required to
543+ // recover old command buffers. To encourage V8 to garbage collect
544+ // command buffers before that happens, we associate some external
545+ // memory with each command buffer.
546+ #[ cfg( target_vendor = "apple" ) ]
547+ const EXTERNAL_MEMORY_AMOUNT : i64 = 1 << 16 ;
548+
541549 let label = descriptor. map ( |d| d. label ) . unwrap_or_default ( ) ;
542550 let wgpu_descriptor = wgpu_types:: CommandEncoderDescriptor {
543551 label : Some ( Cow :: Owned ( label. clone ( ) ) ) ,
544552 } ;
545553
554+ #[ cfg( target_vendor = "apple" ) ]
555+ scope. adjust_amount_of_external_allocated_memory ( EXTERNAL_MEMORY_AMOUNT ) ;
556+
546557 let ( id, err) = self . instance . device_create_command_encoder (
547558 self . id ,
548559 & wgpu_descriptor,
@@ -551,12 +562,39 @@ impl GPUDevice {
551562
552563 self . error_handler . push_error ( err) ;
553564
554- GPUCommandEncoder {
565+ let encoder = GPUCommandEncoder {
555566 instance : self . instance . clone ( ) ,
556567 error_handler : self . error_handler . clone ( ) ,
557568 id,
558569 label,
570+ #[ cfg( target_vendor = "apple" ) ]
571+ weak : std:: sync:: OnceLock :: new ( ) ,
572+ } ;
573+
574+ let obj = make_cppgc_object ( scope, encoder) ;
575+
576+ #[ cfg( target_vendor = "apple" ) ]
577+ {
578+ let finalizer = v8:: Weak :: with_finalizer (
579+ scope,
580+ obj,
581+ Box :: new ( |isolate : & mut v8:: Isolate | {
582+ isolate. adjust_amount_of_external_allocated_memory (
583+ -EXTERNAL_MEMORY_AMOUNT ,
584+ ) ;
585+ } ) ,
586+ ) ;
587+ deno_core:: cppgc:: try_unwrap_cppgc_object :: < GPUCommandEncoder > (
588+ scope,
589+ obj. into ( ) ,
590+ )
591+ . unwrap ( )
592+ . weak
593+ . set ( finalizer)
594+ . unwrap ( ) ;
559595 }
596+
597+ obj
560598 }
561599
562600 #[ required( 1 ) ]
0 commit comments