@@ -2,12 +2,19 @@ use crate::metal::CommandBuffer;
22use crate :: MetalKernelError ;
33use objc2:: { rc:: Retained , runtime:: ProtocolObject } ;
44use objc2_metal:: { MTLCommandBufferStatus , MTLCommandQueue , MTLCounterSet } ;
5+ use std:: {
6+ collections:: HashMap ,
7+ sync:: { Arc , Mutex } ,
8+ thread,
9+ } ;
510
611// Use Retained when appropriate. Gives us a more elegant way of handling memory (peaks) than autoreleasepool.
712// https://docs.rs/objc2/latest/objc2/rc/struct.Retained.html
813pub type CommandQueue = Retained < ProtocolObject < dyn MTLCommandQueue > > ;
914pub type CounterSet = Retained < ProtocolObject < dyn MTLCounterSet > > ;
1015
16+ type CommandBufferMap = HashMap < thread:: ThreadId , CommandBuffer > ;
17+
1118pub struct Commands {
1219 /// Single command queue for the entire device.
1320 command_queue : CommandQueue ,
@@ -20,13 +27,15 @@ pub struct Commands {
2027 /// Despite what the documentation says, command buffers are NOT ordered. They are ordered
2128 /// for their START time, but there's no guarantee that command buffer1 will finish before
2229 /// command buffer2 starts (or there are metal bugs there)
23- command_buffer : CommandBuffer ,
30+ command_buffers : Arc < Mutex < CommandBufferMap > > ,
2431 /// Keeps track of the current amount of compute command encoders on the current
2532 /// command buffer
2633 /// Arc, RwLock because of the interior mutability.
2734 command_buffer_index : usize ,
2835 /// The maximum amount of [compute command encoder](https://developer.apple.com/documentation/metal/mtlcomputecommandencoder?language=objc) per [command buffer](https://developer.apple.com/documentation/metal/mtlcommandbuffer?language=objc)
2936 compute_per_buffer : usize ,
37+ //capture: Option<Retained<MTLCaptureManager>>,
38+ //timestamp_counter_set: Option<CounterSet>,
3039}
3140unsafe impl Send for Commands { }
3241unsafe impl Sync for Commands { }
@@ -43,44 +52,60 @@ impl Commands {
4352 pub fn new ( command_queue : CommandQueue ) -> Result < Self , MetalKernelError > {
4453 let command_buffer = create_command_buffer ( & command_queue) ?;
4554 command_buffer. enqueue ( ) ;
55+ let command_buffers = HashMap :: from ( [ ( thread:: current ( ) . id ( ) , command_buffer) ] ) ;
56+ let command_buffers = Arc :: new ( Mutex :: new ( command_buffers) ) ;
57+
4658 let compute_per_buffer = match std:: env:: var ( "CANDLE_METAL_COMPUTE_PER_BUFFER" ) {
4759 Ok ( val) => val. parse ( ) . unwrap_or ( 50 ) ,
4860 _ => 50 ,
4961 } ;
5062 Ok ( Self {
5163 command_queue,
52- command_buffer ,
64+ command_buffers ,
5365 command_buffer_index : 0 ,
5466 compute_per_buffer,
5567 } )
5668 }
5769
5870 pub fn command_buffer ( & mut self ) -> Result < ( bool , CommandBuffer ) , MetalKernelError > {
59- let mut command_buffer = self . command_buffer . to_owned ( ) ;
71+ let mut command_buffers = self . command_buffers . lock ( ) ?;
72+ let command_buffer =
73+ command_buffers
74+ . get_mut ( & thread:: current ( ) . id ( ) )
75+ . ok_or ( MetalKernelError :: LockError (
76+ "Command buffer map" . to_string ( ) ,
77+ ) ) ?;
78+
6079 let mut flushed = false ;
6180 if self . command_buffer_index > self . compute_per_buffer {
62- self . command_buffer . commit ( ) ;
63- command_buffer = create_command_buffer ( & self . command_queue ) ?;
64- self . command_buffer = command_buffer. clone ( ) ;
81+ command_buffer. commit ( ) ;
82+ * command_buffer = create_command_buffer ( & self . command_queue ) ?;
6583 self . command_buffer_index = 0 ;
6684 flushed = true ;
6785 }
6886 self . command_buffer_index += 1 ;
69- Ok ( ( flushed, command_buffer) )
87+ Ok ( ( flushed, command_buffer. clone ( ) ) )
7088 }
7189
7290 pub fn wait_until_completed ( & mut self ) -> Result < ( ) , MetalKernelError > {
73- match self . command_buffer . status ( ) {
91+ let mut command_buffers = self . command_buffers . lock ( ) ?;
92+ let command_buffer =
93+ command_buffers
94+ . get_mut ( & thread:: current ( ) . id ( ) )
95+ . ok_or ( MetalKernelError :: LockError (
96+ "Command buffer map" . to_string ( ) ,
97+ ) ) ?;
98+ match command_buffer. status ( ) {
7499 MTLCommandBufferStatus :: Committed
75100 | MTLCommandBufferStatus :: Scheduled
76101 | MTLCommandBufferStatus :: Completed => {
77102 panic ! ( "Already committed" ) ;
78103 }
79104 _ => { }
80105 }
81- self . command_buffer . commit ( ) ;
82- self . command_buffer . wait_until_completed ( ) ;
83- self . command_buffer = create_command_buffer ( & self . command_queue ) ?;
106+ command_buffer. commit ( ) ;
107+ command_buffer. wait_until_completed ( ) ;
108+ * command_buffer = create_command_buffer ( & self . command_queue ) ?;
84109
85110 Ok ( ( ) )
86111 }
0 commit comments