1use std::ffi::c_void;
6use std::ptr::NonNull;
7
8use mtl_foundation::{Referencing, UInteger};
9use mtl_sys::{msg_send_0, msg_send_1, msg_send_2, msg_send_3, msg_send_4, sel};
10
11use super::{CommandBuffer, CommitFeedback};
12use crate::{Device, Drawable, Event, ResidencySet};
13
14pub type DispatchQueue = *mut c_void;
16
17#[repr(transparent)]
25pub struct CommitOptions(NonNull<c_void>);
26
27impl CommitOptions {
28 #[inline]
30 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
31 NonNull::new(ptr).map(Self)
32 }
33
34 #[inline]
36 pub fn as_raw(&self) -> *mut c_void {
37 self.0.as_ptr()
38 }
39
40 pub fn new() -> Option<Self> {
42 unsafe {
43 let class = mtl_sys::Class::get("MTL4CommitOptions")?;
44 let ptr: *mut c_void = msg_send_0(class.as_ptr(), sel!(alloc));
45 if ptr.is_null() {
46 return None;
47 }
48 let ptr: *mut c_void = msg_send_0(ptr, sel!(init));
49 Self::from_raw(ptr)
50 }
51 }
52
53 pub fn add_feedback_handler<F>(&self, handler: F)
59 where
60 F: Fn(&CommitFeedback) + Send + 'static,
61 {
62 let block = mtl_sys::OneArgBlock::from_fn(move |feedback_ptr: *mut c_void| {
63 unsafe {
64 if let Some(feedback) = CommitFeedback::from_raw(feedback_ptr) {
65 handler(&feedback);
66 std::mem::forget(feedback);
68 }
69 }
70 });
71
72 unsafe {
73 msg_send_1::<(), *const c_void>(
74 self.as_ptr(),
75 sel!(addFeedbackHandler:),
76 block.as_ptr(),
77 );
78 }
79
80 std::mem::forget(block);
82 }
83}
84
85impl Clone for CommitOptions {
86 fn clone(&self) -> Self {
87 unsafe {
88 mtl_sys::msg_send_0::<*mut c_void>(self.as_ptr(), mtl_sys::sel!(retain));
89 }
90 Self(self.0)
91 }
92}
93
94impl Drop for CommitOptions {
95 fn drop(&mut self) {
96 unsafe {
97 mtl_sys::msg_send_0::<()>(self.as_ptr(), mtl_sys::sel!(release));
98 }
99 }
100}
101
102impl Referencing for CommitOptions {
103 #[inline]
104 fn as_ptr(&self) -> *const c_void {
105 self.0.as_ptr()
106 }
107}
108
109unsafe impl Send for CommitOptions {}
110unsafe impl Sync for CommitOptions {}
111
112#[repr(transparent)]
120pub struct CommandQueueDescriptor(NonNull<c_void>);
121
122impl CommandQueueDescriptor {
123 #[inline]
125 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
126 NonNull::new(ptr).map(Self)
127 }
128
129 #[inline]
131 pub fn as_raw(&self) -> *mut c_void {
132 self.0.as_ptr()
133 }
134
135 pub fn new() -> Option<Self> {
137 unsafe {
138 let class = mtl_sys::Class::get("MTL4CommandQueueDescriptor")?;
139 let ptr: *mut c_void = msg_send_0(class.as_ptr(), sel!(alloc));
140 if ptr.is_null() {
141 return None;
142 }
143 let ptr: *mut c_void = msg_send_0(ptr, sel!(init));
144 Self::from_raw(ptr)
145 }
146 }
147
148 pub fn label(&self) -> Option<String> {
150 unsafe {
151 let ns_string: *mut c_void = msg_send_0(self.as_ptr(), sel!(label));
152 if ns_string.is_null() {
153 return None;
154 }
155 let c_str: *const i8 = msg_send_0(ns_string, sel!(UTF8String));
156 if c_str.is_null() {
157 return None;
158 }
159 Some(
160 std::ffi::CStr::from_ptr(c_str)
161 .to_string_lossy()
162 .into_owned(),
163 )
164 }
165 }
166
167 pub fn set_label(&self, label: &str) {
169 if let Some(ns_label) = mtl_foundation::String::from_str(label) {
170 unsafe {
171 let _: () = msg_send_1(self.as_ptr(), sel!(setLabel:), ns_label.as_ptr());
172 }
173 }
174 }
175
176 pub fn feedback_queue(&self) -> DispatchQueue {
180 unsafe { msg_send_0(self.as_ptr(), sel!(feedbackQueue)) }
181 }
182
183 pub fn set_feedback_queue(&self, queue: DispatchQueue) {
187 unsafe {
188 let _: () = msg_send_1(self.as_ptr(), sel!(setFeedbackQueue:), queue);
189 }
190 }
191}
192
193impl Clone for CommandQueueDescriptor {
194 fn clone(&self) -> Self {
195 unsafe {
196 mtl_sys::msg_send_0::<*mut c_void>(self.as_ptr(), mtl_sys::sel!(retain));
197 }
198 Self(self.0)
199 }
200}
201
202impl Drop for CommandQueueDescriptor {
203 fn drop(&mut self) {
204 unsafe {
205 mtl_sys::msg_send_0::<()>(self.as_ptr(), mtl_sys::sel!(release));
206 }
207 }
208}
209
210impl Referencing for CommandQueueDescriptor {
211 #[inline]
212 fn as_ptr(&self) -> *const c_void {
213 self.0.as_ptr()
214 }
215}
216
217unsafe impl Send for CommandQueueDescriptor {}
218unsafe impl Sync for CommandQueueDescriptor {}
219
220#[repr(transparent)]
231pub struct CommandQueue(NonNull<c_void>);
232
233impl CommandQueue {
234 #[inline]
236 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
237 NonNull::new(ptr).map(Self)
238 }
239
240 #[inline]
242 pub fn as_raw(&self) -> *mut c_void {
243 self.0.as_ptr()
244 }
245
246 pub fn device(&self) -> Option<Device> {
250 unsafe {
251 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(device));
252 Device::from_raw(ptr)
253 }
254 }
255
256 pub fn label(&self) -> Option<String> {
260 unsafe {
261 let ns_string: *mut c_void = msg_send_0(self.as_ptr(), sel!(label));
262 if ns_string.is_null() {
263 return None;
264 }
265 let c_str: *const i8 = msg_send_0(ns_string, sel!(UTF8String));
266 if c_str.is_null() {
267 return None;
268 }
269 Some(
270 std::ffi::CStr::from_ptr(c_str)
271 .to_string_lossy()
272 .into_owned(),
273 )
274 }
275 }
276
277 pub fn add_residency_set(&self, residency_set: &ResidencySet) {
283 unsafe {
284 let _: () = msg_send_1(
285 self.as_ptr(),
286 sel!(addResidencySet:),
287 residency_set.as_ptr(),
288 );
289 }
290 }
291
292 pub fn add_residency_sets(&self, residency_sets: &[&ResidencySet]) {
296 let ptrs: Vec<*const c_void> = residency_sets.iter().map(|r| r.as_ptr()).collect();
297 unsafe {
298 let _: () = msg_send_2(
299 self.as_ptr(),
300 sel!(addResidencySets:count:),
301 ptrs.as_ptr(),
302 ptrs.len() as UInteger,
303 );
304 }
305 }
306
307 pub fn remove_residency_set(&self, residency_set: &ResidencySet) {
311 unsafe {
312 let _: () = msg_send_1(
313 self.as_ptr(),
314 sel!(removeResidencySet:),
315 residency_set.as_ptr(),
316 );
317 }
318 }
319
320 pub fn remove_residency_sets(&self, residency_sets: &[&ResidencySet]) {
324 let ptrs: Vec<*const c_void> = residency_sets.iter().map(|r| r.as_ptr()).collect();
325 unsafe {
326 let _: () = msg_send_2(
327 self.as_ptr(),
328 sel!(removeResidencySets:count:),
329 ptrs.as_ptr(),
330 ptrs.len() as UInteger,
331 );
332 }
333 }
334
335 pub fn new_command_buffer(&self) -> Option<CommandBuffer> {
344 unsafe {
345 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(newCommandBuffer));
346 if ptr.is_null() {
347 None
348 } else {
349 CommandBuffer::from_raw(ptr)
350 }
351 }
352 }
353
354 pub fn commit(&self, command_buffers: &[&CommandBuffer]) {
360 let ptrs: Vec<*const c_void> = command_buffers.iter().map(|c| c.as_ptr()).collect();
361 unsafe {
362 let _: () = msg_send_2(
363 self.as_ptr(),
364 sel!(commit:count:),
365 ptrs.as_ptr(),
366 ptrs.len() as UInteger,
367 );
368 }
369 }
370
371 pub fn commit_with_options(&self, command_buffers: &[&CommandBuffer], options: &CommitOptions) {
375 let ptrs: Vec<*const c_void> = command_buffers.iter().map(|c| c.as_ptr()).collect();
376 unsafe {
377 let _: () = msg_send_3(
378 self.as_ptr(),
379 sel!(commit:count:options:),
380 ptrs.as_ptr(),
381 ptrs.len() as UInteger,
382 options.as_ptr(),
383 );
384 }
385 }
386
387 pub fn signal_event(&self, event: &Event, value: u64) {
393 unsafe {
394 let _: () = msg_send_2(
395 self.as_ptr(),
396 sel!(signalEvent:value:),
397 event.as_ptr(),
398 value,
399 );
400 }
401 }
402
403 pub fn wait_for_event(&self, event: &Event, value: u64) {
407 unsafe {
408 let _: () = msg_send_2(
409 self.as_ptr(),
410 sel!(waitForEvent:value:),
411 event.as_ptr(),
412 value,
413 );
414 }
415 }
416
417 pub fn signal_drawable(&self, drawable: &Drawable) {
421 unsafe {
422 let _: () = msg_send_1(self.as_ptr(), sel!(signalDrawable:), drawable.as_ptr());
423 }
424 }
425
426 pub fn wait_for_drawable(&self, drawable: &Drawable) {
430 unsafe {
431 let _: () = msg_send_1(self.as_ptr(), sel!(waitForDrawable:), drawable.as_ptr());
432 }
433 }
434
435 pub unsafe fn copy_buffer_mappings_from_buffer(
445 &self,
446 source_buffer: *const c_void,
447 destination_buffer: *const c_void,
448 operations: *const c_void,
449 count: UInteger,
450 ) {
451 unsafe {
452 let _: () = msg_send_4(
453 self.as_ptr(),
454 sel!(copyBufferMappingsFromBuffer:toBuffer:operations:count:),
455 source_buffer,
456 destination_buffer,
457 operations,
458 count,
459 );
460 }
461 }
462
463 pub unsafe fn copy_texture_mappings_from_texture(
471 &self,
472 source_texture: *const c_void,
473 destination_texture: *const c_void,
474 operations: *const c_void,
475 count: UInteger,
476 ) {
477 unsafe {
478 let _: () = msg_send_4(
479 self.as_ptr(),
480 sel!(copyTextureMappingsFromTexture:toTexture:operations:count:),
481 source_texture,
482 destination_texture,
483 operations,
484 count,
485 );
486 }
487 }
488
489 pub unsafe fn update_buffer_mappings(
497 &self,
498 buffer: *const c_void,
499 heap: *const c_void,
500 operations: *const c_void,
501 count: UInteger,
502 ) {
503 unsafe {
504 let _: () = msg_send_4(
505 self.as_ptr(),
506 sel!(updateBufferMappings:heap:operations:count:),
507 buffer,
508 heap,
509 operations,
510 count,
511 );
512 }
513 }
514
515 pub unsafe fn update_texture_mappings(
523 &self,
524 texture: *const c_void,
525 heap: *const c_void,
526 operations: *const c_void,
527 count: UInteger,
528 ) {
529 unsafe {
530 let _: () = msg_send_4(
531 self.as_ptr(),
532 sel!(updateTextureMappings:heap:operations:count:),
533 texture,
534 heap,
535 operations,
536 count,
537 );
538 }
539 }
540}
541
542impl Clone for CommandQueue {
543 fn clone(&self) -> Self {
544 unsafe {
545 mtl_sys::msg_send_0::<*mut c_void>(self.as_ptr(), mtl_sys::sel!(retain));
546 }
547 Self(self.0)
548 }
549}
550
551impl Drop for CommandQueue {
552 fn drop(&mut self) {
553 unsafe {
554 mtl_sys::msg_send_0::<()>(self.as_ptr(), mtl_sys::sel!(release));
555 }
556 }
557}
558
559impl Referencing for CommandQueue {
560 #[inline]
561 fn as_ptr(&self) -> *const c_void {
562 self.0.as_ptr()
563 }
564}
565
566unsafe impl Send for CommandQueue {}
567unsafe impl Sync for CommandQueue {}
568
569impl std::fmt::Debug for CommandQueue {
570 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
571 f.debug_struct("CommandQueue")
572 .field("label", &self.label())
573 .finish()
574 }
575}
576
577#[cfg(test)]
578mod tests {
579 use super::*;
580
581 #[test]
582 fn test_commit_options_size() {
583 assert_eq!(
584 std::mem::size_of::<CommitOptions>(),
585 std::mem::size_of::<*mut c_void>()
586 );
587 }
588
589 #[test]
590 fn test_command_queue_descriptor_size() {
591 assert_eq!(
592 std::mem::size_of::<CommandQueueDescriptor>(),
593 std::mem::size_of::<*mut c_void>()
594 );
595 }
596
597 #[test]
598 fn test_command_queue_size() {
599 assert_eq!(
600 std::mem::size_of::<CommandQueue>(),
601 std::mem::size_of::<*mut c_void>()
602 );
603 }
604}