1use std::ffi::c_void;
8use std::ptr::NonNull;
9
10use mtl_foundation::{Referencing, UInteger};
11use mtl_sys::{msg_send_0, msg_send_1, sel};
12
13use crate::enums::{
14 CompareFunction, SamplerAddressMode, SamplerBorderColor, SamplerMinMagFilter, SamplerMipFilter,
15 SamplerReductionMode,
16};
17use crate::types::ResourceID;
18
19#[repr(transparent)]
23pub struct SamplerState(pub(crate) NonNull<c_void>);
24
25impl SamplerState {
26 #[inline]
32 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
33 NonNull::new(ptr).map(Self)
34 }
35
36 #[inline]
38 pub fn as_raw(&self) -> *mut c_void {
39 self.0.as_ptr()
40 }
41
42 pub fn label(&self) -> Option<String> {
50 unsafe {
51 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(label));
52 if ptr.is_null() {
53 return None;
54 }
55 let utf8_ptr: *const std::ffi::c_char =
56 mtl_sys::msg_send_0(ptr as *const c_void, sel!(UTF8String));
57 if utf8_ptr.is_null() {
58 return None;
59 }
60 let c_str = std::ffi::CStr::from_ptr(utf8_ptr);
61 Some(c_str.to_string_lossy().into_owned())
62 }
63 }
64
65 pub fn device(&self) -> crate::Device {
69 unsafe {
70 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(device));
71 let _: *mut c_void = msg_send_0(ptr, sel!(retain));
72 crate::Device::from_raw(ptr).expect("sampler state has no device")
73 }
74 }
75
76 #[inline]
80 pub fn gpu_resource_id(&self) -> ResourceID {
81 unsafe { msg_send_0(self.as_ptr(), sel!(gpuResourceID)) }
82 }
83}
84
85impl Clone for SamplerState {
86 fn clone(&self) -> Self {
87 unsafe {
88 msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
89 }
90 Self(self.0)
91 }
92}
93
94impl Drop for SamplerState {
95 fn drop(&mut self) {
96 unsafe {
97 msg_send_0::<()>(self.as_ptr(), sel!(release));
98 }
99 }
100}
101
102impl Referencing for SamplerState {
103 #[inline]
104 fn as_ptr(&self) -> *const c_void {
105 self.0.as_ptr()
106 }
107}
108
109unsafe impl Send for SamplerState {}
110unsafe impl Sync for SamplerState {}
111
112impl std::fmt::Debug for SamplerState {
113 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
114 f.debug_struct("SamplerState")
115 .field("label", &self.label())
116 .finish()
117 }
118}
119
120#[repr(transparent)]
128pub struct SamplerDescriptor(pub(crate) NonNull<c_void>);
129
130impl SamplerDescriptor {
131 pub fn new() -> Option<Self> {
135 unsafe {
136 let class = mtl_sys::Class::get("MTLSamplerDescriptor")?;
137 let ptr: *mut c_void = msg_send_0(class.as_ptr(), sel!(alloc));
138 if ptr.is_null() {
139 return None;
140 }
141 let ptr: *mut c_void = msg_send_0(ptr, sel!(init));
142 Self::from_raw(ptr)
143 }
144 }
145
146 #[inline]
152 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
153 NonNull::new(ptr).map(Self)
154 }
155
156 #[inline]
158 pub fn as_raw(&self) -> *mut c_void {
159 self.0.as_ptr()
160 }
161
162 #[inline]
170 pub fn min_filter(&self) -> SamplerMinMagFilter {
171 unsafe { msg_send_0(self.as_ptr(), sel!(minFilter)) }
172 }
173
174 #[inline]
178 pub fn set_min_filter(&self, filter: SamplerMinMagFilter) {
179 unsafe {
180 msg_send_1::<(), SamplerMinMagFilter>(self.as_ptr(), sel!(setMinFilter:), filter);
181 }
182 }
183
184 #[inline]
188 pub fn mag_filter(&self) -> SamplerMinMagFilter {
189 unsafe { msg_send_0(self.as_ptr(), sel!(magFilter)) }
190 }
191
192 #[inline]
196 pub fn set_mag_filter(&self, filter: SamplerMinMagFilter) {
197 unsafe {
198 msg_send_1::<(), SamplerMinMagFilter>(self.as_ptr(), sel!(setMagFilter:), filter);
199 }
200 }
201
202 #[inline]
206 pub fn mip_filter(&self) -> SamplerMipFilter {
207 unsafe { msg_send_0(self.as_ptr(), sel!(mipFilter)) }
208 }
209
210 #[inline]
214 pub fn set_mip_filter(&self, filter: SamplerMipFilter) {
215 unsafe {
216 msg_send_1::<(), SamplerMipFilter>(self.as_ptr(), sel!(setMipFilter:), filter);
217 }
218 }
219
220 #[inline]
228 pub fn s_address_mode(&self) -> SamplerAddressMode {
229 unsafe { msg_send_0(self.as_ptr(), sel!(sAddressMode)) }
230 }
231
232 #[inline]
236 pub fn set_s_address_mode(&self, mode: SamplerAddressMode) {
237 unsafe {
238 msg_send_1::<(), SamplerAddressMode>(self.as_ptr(), sel!(setSAddressMode:), mode);
239 }
240 }
241
242 #[inline]
246 pub fn t_address_mode(&self) -> SamplerAddressMode {
247 unsafe { msg_send_0(self.as_ptr(), sel!(tAddressMode)) }
248 }
249
250 #[inline]
254 pub fn set_t_address_mode(&self, mode: SamplerAddressMode) {
255 unsafe {
256 msg_send_1::<(), SamplerAddressMode>(self.as_ptr(), sel!(setTAddressMode:), mode);
257 }
258 }
259
260 #[inline]
264 pub fn r_address_mode(&self) -> SamplerAddressMode {
265 unsafe { msg_send_0(self.as_ptr(), sel!(rAddressMode)) }
266 }
267
268 #[inline]
272 pub fn set_r_address_mode(&self, mode: SamplerAddressMode) {
273 unsafe {
274 msg_send_1::<(), SamplerAddressMode>(self.as_ptr(), sel!(setRAddressMode:), mode);
275 }
276 }
277
278 #[inline]
282 pub fn border_color(&self) -> SamplerBorderColor {
283 unsafe { msg_send_0(self.as_ptr(), sel!(borderColor)) }
284 }
285
286 #[inline]
290 pub fn set_border_color(&self, color: SamplerBorderColor) {
291 unsafe {
292 msg_send_1::<(), SamplerBorderColor>(self.as_ptr(), sel!(setBorderColor:), color);
293 }
294 }
295
296 #[inline]
304 pub fn lod_min_clamp(&self) -> f32 {
305 unsafe { msg_send_0(self.as_ptr(), sel!(lodMinClamp)) }
306 }
307
308 #[inline]
312 pub fn set_lod_min_clamp(&self, clamp: f32) {
313 unsafe {
314 msg_send_1::<(), f32>(self.as_ptr(), sel!(setLodMinClamp:), clamp);
315 }
316 }
317
318 #[inline]
322 pub fn lod_max_clamp(&self) -> f32 {
323 unsafe { msg_send_0(self.as_ptr(), sel!(lodMaxClamp)) }
324 }
325
326 #[inline]
330 pub fn set_lod_max_clamp(&self, clamp: f32) {
331 unsafe {
332 msg_send_1::<(), f32>(self.as_ptr(), sel!(setLodMaxClamp:), clamp);
333 }
334 }
335
336 #[inline]
340 pub fn lod_bias(&self) -> f32 {
341 unsafe { msg_send_0(self.as_ptr(), sel!(lodBias)) }
342 }
343
344 #[inline]
348 pub fn set_lod_bias(&self, bias: f32) {
349 unsafe {
350 msg_send_1::<(), f32>(self.as_ptr(), sel!(setLodBias:), bias);
351 }
352 }
353
354 #[inline]
358 pub fn lod_average(&self) -> bool {
359 unsafe { msg_send_0(self.as_ptr(), sel!(lodAverage)) }
360 }
361
362 #[inline]
366 pub fn set_lod_average(&self, average: bool) {
367 unsafe {
368 msg_send_1::<(), bool>(self.as_ptr(), sel!(setLodAverage:), average);
369 }
370 }
371
372 #[inline]
380 pub fn max_anisotropy(&self) -> UInteger {
381 unsafe { msg_send_0(self.as_ptr(), sel!(maxAnisotropy)) }
382 }
383
384 #[inline]
388 pub fn set_max_anisotropy(&self, max: UInteger) {
389 unsafe {
390 msg_send_1::<(), UInteger>(self.as_ptr(), sel!(setMaxAnisotropy:), max);
391 }
392 }
393
394 #[inline]
402 pub fn compare_function(&self) -> CompareFunction {
403 unsafe { msg_send_0(self.as_ptr(), sel!(compareFunction)) }
404 }
405
406 #[inline]
410 pub fn set_compare_function(&self, func: CompareFunction) {
411 unsafe {
412 msg_send_1::<(), CompareFunction>(self.as_ptr(), sel!(setCompareFunction:), func);
413 }
414 }
415
416 #[inline]
424 pub fn reduction_mode(&self) -> SamplerReductionMode {
425 unsafe { msg_send_0(self.as_ptr(), sel!(reductionMode)) }
426 }
427
428 #[inline]
432 pub fn set_reduction_mode(&self, mode: SamplerReductionMode) {
433 unsafe {
434 msg_send_1::<(), SamplerReductionMode>(self.as_ptr(), sel!(setReductionMode:), mode);
435 }
436 }
437
438 #[inline]
446 pub fn normalized_coordinates(&self) -> bool {
447 unsafe { msg_send_0(self.as_ptr(), sel!(normalizedCoordinates)) }
448 }
449
450 #[inline]
454 pub fn set_normalized_coordinates(&self, normalized: bool) {
455 unsafe {
456 msg_send_1::<(), bool>(self.as_ptr(), sel!(setNormalizedCoordinates:), normalized);
457 }
458 }
459
460 pub fn label(&self) -> Option<String> {
468 unsafe {
469 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(label));
470 if ptr.is_null() {
471 return None;
472 }
473 let utf8_ptr: *const std::ffi::c_char =
474 mtl_sys::msg_send_0(ptr as *const c_void, sel!(UTF8String));
475 if utf8_ptr.is_null() {
476 return None;
477 }
478 let c_str = std::ffi::CStr::from_ptr(utf8_ptr);
479 Some(c_str.to_string_lossy().into_owned())
480 }
481 }
482
483 pub fn set_label(&self, label: &str) {
487 if let Some(ns_label) = mtl_foundation::String::from_str(label) {
488 unsafe {
489 msg_send_1::<(), *const c_void>(self.as_ptr(), sel!(setLabel:), ns_label.as_ptr());
490 }
491 }
492 }
493
494 #[inline]
498 pub fn support_argument_buffers(&self) -> bool {
499 unsafe { msg_send_0(self.as_ptr(), sel!(supportArgumentBuffers)) }
500 }
501
502 #[inline]
506 pub fn set_support_argument_buffers(&self, support: bool) {
507 unsafe {
508 msg_send_1::<(), bool>(self.as_ptr(), sel!(setSupportArgumentBuffers:), support);
509 }
510 }
511}
512
513impl Default for SamplerDescriptor {
514 fn default() -> Self {
515 Self::new().expect("failed to create sampler descriptor")
516 }
517}
518
519impl Clone for SamplerDescriptor {
520 fn clone(&self) -> Self {
521 unsafe {
522 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(copy));
523 Self::from_raw(ptr).expect("failed to copy sampler descriptor")
524 }
525 }
526}
527
528impl Drop for SamplerDescriptor {
529 fn drop(&mut self) {
530 unsafe {
531 msg_send_0::<()>(self.as_ptr(), sel!(release));
532 }
533 }
534}
535
536impl Referencing for SamplerDescriptor {
537 #[inline]
538 fn as_ptr(&self) -> *const c_void {
539 self.0.as_ptr()
540 }
541}
542
543unsafe impl Send for SamplerDescriptor {}
544unsafe impl Sync for SamplerDescriptor {}
545
546impl std::fmt::Debug for SamplerDescriptor {
547 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
548 f.debug_struct("SamplerDescriptor")
549 .field("min_filter", &self.min_filter())
550 .field("mag_filter", &self.mag_filter())
551 .field("mip_filter", &self.mip_filter())
552 .field("label", &self.label())
553 .finish()
554 }
555}
556
557#[cfg(test)]
558mod tests {
559 use super::*;
560
561 #[test]
562 fn test_sampler_state_size() {
563 assert_eq!(
564 std::mem::size_of::<SamplerState>(),
565 std::mem::size_of::<*mut c_void>()
566 );
567 }
568
569 #[test]
570 fn test_sampler_descriptor_creation() {
571 let desc = SamplerDescriptor::new();
572 assert!(desc.is_some());
573 }
574}