1use std::ffi::c_void;
8use std::ptr::NonNull;
9
10use mtl_foundation::Referencing;
11use mtl_sys::{msg_send_0, msg_send_1, sel};
12
13use crate::enums::{CompareFunction, StencilOperation};
14use crate::types::ResourceID;
15
16#[repr(transparent)]
20pub struct DepthStencilState(pub(crate) NonNull<c_void>);
21
22impl DepthStencilState {
23 #[inline]
29 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
30 NonNull::new(ptr).map(Self)
31 }
32
33 #[inline]
35 pub fn as_raw(&self) -> *mut c_void {
36 self.0.as_ptr()
37 }
38
39 pub fn label(&self) -> Option<String> {
43 unsafe {
44 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(label));
45 if ptr.is_null() {
46 return None;
47 }
48 let utf8_ptr: *const std::ffi::c_char =
49 mtl_sys::msg_send_0(ptr as *const c_void, sel!(UTF8String));
50 if utf8_ptr.is_null() {
51 return None;
52 }
53 let c_str = std::ffi::CStr::from_ptr(utf8_ptr);
54 Some(c_str.to_string_lossy().into_owned())
55 }
56 }
57
58 pub fn device(&self) -> crate::Device {
62 unsafe {
63 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(device));
64 let _: *mut c_void = msg_send_0(ptr, sel!(retain));
65 crate::Device::from_raw(ptr).expect("depth/stencil state has no device")
66 }
67 }
68
69 #[inline]
73 pub fn gpu_resource_id(&self) -> ResourceID {
74 unsafe { msg_send_0(self.as_ptr(), sel!(gpuResourceID)) }
75 }
76}
77
78impl Clone for DepthStencilState {
79 fn clone(&self) -> Self {
80 unsafe {
81 msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
82 }
83 Self(self.0)
84 }
85}
86
87impl Drop for DepthStencilState {
88 fn drop(&mut self) {
89 unsafe {
90 msg_send_0::<()>(self.as_ptr(), sel!(release));
91 }
92 }
93}
94
95impl Referencing for DepthStencilState {
96 #[inline]
97 fn as_ptr(&self) -> *const c_void {
98 self.0.as_ptr()
99 }
100}
101
102unsafe impl Send for DepthStencilState {}
103unsafe impl Sync for DepthStencilState {}
104
105impl std::fmt::Debug for DepthStencilState {
106 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107 f.debug_struct("DepthStencilState")
108 .field("label", &self.label())
109 .finish()
110 }
111}
112
113#[repr(transparent)]
121pub struct StencilDescriptor(pub(crate) NonNull<c_void>);
122
123impl StencilDescriptor {
124 pub fn new() -> Option<Self> {
128 unsafe {
129 let class = mtl_sys::Class::get("MTLStencilDescriptor")?;
130 let ptr: *mut c_void = msg_send_0(class.as_ptr(), sel!(alloc));
131 if ptr.is_null() {
132 return None;
133 }
134 let ptr: *mut c_void = msg_send_0(ptr, sel!(init));
135 Self::from_raw(ptr)
136 }
137 }
138
139 #[inline]
145 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
146 NonNull::new(ptr).map(Self)
147 }
148
149 #[inline]
151 pub fn as_raw(&self) -> *mut c_void {
152 self.0.as_ptr()
153 }
154
155 #[inline]
159 pub fn stencil_compare_function(&self) -> CompareFunction {
160 unsafe { msg_send_0(self.as_ptr(), sel!(stencilCompareFunction)) }
161 }
162
163 #[inline]
167 pub fn set_stencil_compare_function(&self, func: CompareFunction) {
168 unsafe {
169 msg_send_1::<(), CompareFunction>(
170 self.as_ptr(),
171 sel!(setStencilCompareFunction:),
172 func,
173 );
174 }
175 }
176
177 #[inline]
181 pub fn stencil_failure_operation(&self) -> StencilOperation {
182 unsafe { msg_send_0(self.as_ptr(), sel!(stencilFailureOperation)) }
183 }
184
185 #[inline]
189 pub fn set_stencil_failure_operation(&self, op: StencilOperation) {
190 unsafe {
191 msg_send_1::<(), StencilOperation>(
192 self.as_ptr(),
193 sel!(setStencilFailureOperation:),
194 op,
195 );
196 }
197 }
198
199 #[inline]
203 pub fn depth_failure_operation(&self) -> StencilOperation {
204 unsafe { msg_send_0(self.as_ptr(), sel!(depthFailureOperation)) }
205 }
206
207 #[inline]
211 pub fn set_depth_failure_operation(&self, op: StencilOperation) {
212 unsafe {
213 msg_send_1::<(), StencilOperation>(self.as_ptr(), sel!(setDepthFailureOperation:), op);
214 }
215 }
216
217 #[inline]
221 pub fn depth_stencil_pass_operation(&self) -> StencilOperation {
222 unsafe { msg_send_0(self.as_ptr(), sel!(depthStencilPassOperation)) }
223 }
224
225 #[inline]
229 pub fn set_depth_stencil_pass_operation(&self, op: StencilOperation) {
230 unsafe {
231 msg_send_1::<(), StencilOperation>(
232 self.as_ptr(),
233 sel!(setDepthStencilPassOperation:),
234 op,
235 );
236 }
237 }
238
239 #[inline]
243 pub fn read_mask(&self) -> u32 {
244 unsafe { msg_send_0(self.as_ptr(), sel!(readMask)) }
245 }
246
247 #[inline]
251 pub fn set_read_mask(&self, mask: u32) {
252 unsafe {
253 msg_send_1::<(), u32>(self.as_ptr(), sel!(setReadMask:), mask);
254 }
255 }
256
257 #[inline]
261 pub fn write_mask(&self) -> u32 {
262 unsafe { msg_send_0(self.as_ptr(), sel!(writeMask)) }
263 }
264
265 #[inline]
269 pub fn set_write_mask(&self, mask: u32) {
270 unsafe {
271 msg_send_1::<(), u32>(self.as_ptr(), sel!(setWriteMask:), mask);
272 }
273 }
274}
275
276impl Default for StencilDescriptor {
277 fn default() -> Self {
278 Self::new().expect("failed to create stencil descriptor")
279 }
280}
281
282impl Clone for StencilDescriptor {
283 fn clone(&self) -> Self {
284 unsafe {
285 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(copy));
286 Self::from_raw(ptr).expect("failed to copy stencil descriptor")
287 }
288 }
289}
290
291impl Drop for StencilDescriptor {
292 fn drop(&mut self) {
293 unsafe {
294 msg_send_0::<()>(self.as_ptr(), sel!(release));
295 }
296 }
297}
298
299impl Referencing for StencilDescriptor {
300 #[inline]
301 fn as_ptr(&self) -> *const c_void {
302 self.0.as_ptr()
303 }
304}
305
306unsafe impl Send for StencilDescriptor {}
307unsafe impl Sync for StencilDescriptor {}
308
309#[repr(transparent)]
317pub struct DepthStencilDescriptor(pub(crate) NonNull<c_void>);
318
319impl DepthStencilDescriptor {
320 pub fn new() -> Option<Self> {
324 unsafe {
325 let class = mtl_sys::Class::get("MTLDepthStencilDescriptor")?;
326 let ptr: *mut c_void = msg_send_0(class.as_ptr(), sel!(alloc));
327 if ptr.is_null() {
328 return None;
329 }
330 let ptr: *mut c_void = msg_send_0(ptr, sel!(init));
331 Self::from_raw(ptr)
332 }
333 }
334
335 #[inline]
341 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
342 NonNull::new(ptr).map(Self)
343 }
344
345 #[inline]
347 pub fn as_raw(&self) -> *mut c_void {
348 self.0.as_ptr()
349 }
350
351 #[inline]
355 pub fn depth_compare_function(&self) -> CompareFunction {
356 unsafe { msg_send_0(self.as_ptr(), sel!(depthCompareFunction)) }
357 }
358
359 #[inline]
363 pub fn set_depth_compare_function(&self, func: CompareFunction) {
364 unsafe {
365 msg_send_1::<(), CompareFunction>(self.as_ptr(), sel!(setDepthCompareFunction:), func);
366 }
367 }
368
369 #[inline]
373 pub fn is_depth_write_enabled(&self) -> bool {
374 unsafe { msg_send_0(self.as_ptr(), sel!(isDepthWriteEnabled)) }
375 }
376
377 #[inline]
381 pub fn set_depth_write_enabled(&self, enabled: bool) {
382 unsafe {
383 msg_send_1::<(), bool>(self.as_ptr(), sel!(setDepthWriteEnabled:), enabled);
384 }
385 }
386
387 pub fn front_face_stencil(&self) -> Option<StencilDescriptor> {
391 unsafe {
392 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(frontFaceStencil));
393 if ptr.is_null() {
394 return None;
395 }
396 let _: *mut c_void = msg_send_0(ptr, sel!(retain));
397 StencilDescriptor::from_raw(ptr)
398 }
399 }
400
401 pub fn set_front_face_stencil(&self, stencil: Option<&StencilDescriptor>) {
405 let ptr = stencil.map_or(std::ptr::null(), |s| s.as_ptr());
406 unsafe {
407 msg_send_1::<(), *const c_void>(self.as_ptr(), sel!(setFrontFaceStencil:), ptr);
408 }
409 }
410
411 pub fn back_face_stencil(&self) -> Option<StencilDescriptor> {
415 unsafe {
416 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(backFaceStencil));
417 if ptr.is_null() {
418 return None;
419 }
420 let _: *mut c_void = msg_send_0(ptr, sel!(retain));
421 StencilDescriptor::from_raw(ptr)
422 }
423 }
424
425 pub fn set_back_face_stencil(&self, stencil: Option<&StencilDescriptor>) {
429 let ptr = stencil.map_or(std::ptr::null(), |s| s.as_ptr());
430 unsafe {
431 msg_send_1::<(), *const c_void>(self.as_ptr(), sel!(setBackFaceStencil:), ptr);
432 }
433 }
434
435 pub fn label(&self) -> Option<String> {
439 unsafe {
440 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(label));
441 if ptr.is_null() {
442 return None;
443 }
444 let utf8_ptr: *const std::ffi::c_char =
445 mtl_sys::msg_send_0(ptr as *const c_void, sel!(UTF8String));
446 if utf8_ptr.is_null() {
447 return None;
448 }
449 let c_str = std::ffi::CStr::from_ptr(utf8_ptr);
450 Some(c_str.to_string_lossy().into_owned())
451 }
452 }
453
454 pub fn set_label(&self, label: &str) {
458 if let Some(ns_label) = mtl_foundation::String::from_str(label) {
459 unsafe {
460 msg_send_1::<(), *const c_void>(self.as_ptr(), sel!(setLabel:), ns_label.as_ptr());
461 }
462 }
463 }
464}
465
466impl Default for DepthStencilDescriptor {
467 fn default() -> Self {
468 Self::new().expect("failed to create depth/stencil descriptor")
469 }
470}
471
472impl Clone for DepthStencilDescriptor {
473 fn clone(&self) -> Self {
474 unsafe {
475 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(copy));
476 Self::from_raw(ptr).expect("failed to copy depth/stencil descriptor")
477 }
478 }
479}
480
481impl Drop for DepthStencilDescriptor {
482 fn drop(&mut self) {
483 unsafe {
484 msg_send_0::<()>(self.as_ptr(), sel!(release));
485 }
486 }
487}
488
489impl Referencing for DepthStencilDescriptor {
490 #[inline]
491 fn as_ptr(&self) -> *const c_void {
492 self.0.as_ptr()
493 }
494}
495
496unsafe impl Send for DepthStencilDescriptor {}
497unsafe impl Sync for DepthStencilDescriptor {}
498
499impl std::fmt::Debug for DepthStencilDescriptor {
500 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
501 f.debug_struct("DepthStencilDescriptor")
502 .field("depth_compare_function", &self.depth_compare_function())
503 .field("is_depth_write_enabled", &self.is_depth_write_enabled())
504 .field("label", &self.label())
505 .finish()
506 }
507}
508
509#[cfg(test)]
510mod tests {
511 use super::*;
512
513 #[test]
514 fn test_depth_stencil_state_size() {
515 assert_eq!(
516 std::mem::size_of::<DepthStencilState>(),
517 std::mem::size_of::<*mut c_void>()
518 );
519 }
520
521 #[test]
522 fn test_depth_stencil_descriptor_creation() {
523 let desc = DepthStencilDescriptor::new();
524 assert!(desc.is_some());
525 }
526}