1use std::ffi::c_void;
4use std::ptr::NonNull;
5
6use mtl_foundation::{Referencing, UInteger};
7use mtl_sys::{msg_send_0, msg_send_1, sel};
8
9use crate::enums::{
10 PixelFormat, ResourceOptions, TextureCompressionType, TextureSparseTier,
11 TextureSwizzleChannels, TextureType, TextureUsage,
12};
13use crate::types::ResourceID;
14
15use super::{SharedTextureHandle, TextureViewDescriptor};
16
17#[repr(transparent)]
21pub struct Texture(pub(crate) NonNull<c_void>);
22
23impl Texture {
24 #[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 #[inline]
48 pub fn texture_type(&self) -> TextureType {
49 unsafe { msg_send_0(self.as_ptr(), sel!(textureType)) }
50 }
51
52 #[inline]
56 pub fn pixel_format(&self) -> PixelFormat {
57 unsafe { msg_send_0(self.as_ptr(), sel!(pixelFormat)) }
58 }
59
60 #[inline]
64 pub fn width(&self) -> UInteger {
65 unsafe { msg_send_0(self.as_ptr(), sel!(width)) }
66 }
67
68 #[inline]
72 pub fn height(&self) -> UInteger {
73 unsafe { msg_send_0(self.as_ptr(), sel!(height)) }
74 }
75
76 #[inline]
80 pub fn depth(&self) -> UInteger {
81 unsafe { msg_send_0(self.as_ptr(), sel!(depth)) }
82 }
83
84 #[inline]
88 pub fn mipmap_level_count(&self) -> UInteger {
89 unsafe { msg_send_0(self.as_ptr(), sel!(mipmapLevelCount)) }
90 }
91
92 #[inline]
96 pub fn sample_count(&self) -> UInteger {
97 unsafe { msg_send_0(self.as_ptr(), sel!(sampleCount)) }
98 }
99
100 #[inline]
104 pub fn array_length(&self) -> UInteger {
105 unsafe { msg_send_0(self.as_ptr(), sel!(arrayLength)) }
106 }
107
108 #[inline]
112 pub fn usage(&self) -> TextureUsage {
113 unsafe { msg_send_0(self.as_ptr(), sel!(usage)) }
114 }
115
116 #[inline]
120 pub fn is_shareable(&self) -> bool {
121 unsafe { msg_send_0(self.as_ptr(), sel!(isShareable)) }
122 }
123
124 #[inline]
128 pub fn is_framebuffer_only(&self) -> bool {
129 unsafe { msg_send_0(self.as_ptr(), sel!(isFramebufferOnly)) }
130 }
131
132 #[inline]
136 pub fn first_mipmap_in_tail(&self) -> UInteger {
137 unsafe { msg_send_0(self.as_ptr(), sel!(firstMipmapInTail)) }
138 }
139
140 #[inline]
144 pub fn tail_size_in_bytes(&self) -> UInteger {
145 unsafe { msg_send_0(self.as_ptr(), sel!(tailSizeInBytes)) }
146 }
147
148 #[inline]
152 pub fn is_sparse(&self) -> bool {
153 unsafe { msg_send_0(self.as_ptr(), sel!(isSparse)) }
154 }
155
156 #[inline]
160 pub fn gpu_resource_id(&self) -> ResourceID {
161 unsafe { msg_send_0(self.as_ptr(), sel!(gpuResourceID)) }
162 }
163
164 #[inline]
168 pub fn allow_gpu_optimized_contents(&self) -> bool {
169 unsafe { msg_send_0(self.as_ptr(), sel!(allowGPUOptimizedContents)) }
170 }
171
172 #[inline]
176 pub fn compression_type(&self) -> TextureCompressionType {
177 unsafe { msg_send_0(self.as_ptr(), sel!(compressionType)) }
178 }
179
180 #[inline]
184 pub fn swizzle(&self) -> TextureSwizzleChannels {
185 unsafe { msg_send_0(self.as_ptr(), sel!(swizzle)) }
186 }
187
188 pub fn parent_texture(&self) -> Option<Texture> {
192 unsafe {
193 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(parentTexture));
194 if ptr.is_null() {
195 return None;
196 }
197 let _: *mut c_void = msg_send_0(ptr, sel!(retain));
198 Texture::from_raw(ptr)
199 }
200 }
201
202 #[inline]
206 pub fn parent_relative_level(&self) -> UInteger {
207 unsafe { msg_send_0(self.as_ptr(), sel!(parentRelativeLevel)) }
208 }
209
210 #[inline]
214 pub fn parent_relative_slice(&self) -> UInteger {
215 unsafe { msg_send_0(self.as_ptr(), sel!(parentRelativeSlice)) }
216 }
217
218 pub fn buffer(&self) -> Option<crate::buffer::Buffer> {
222 unsafe {
223 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(buffer));
224 if ptr.is_null() {
225 return None;
226 }
227 let _: *mut c_void = msg_send_0(ptr, sel!(retain));
228 crate::buffer::Buffer::from_raw(ptr)
229 }
230 }
231
232 #[inline]
236 pub fn buffer_offset(&self) -> UInteger {
237 unsafe { msg_send_0(self.as_ptr(), sel!(bufferOffset)) }
238 }
239
240 #[inline]
244 pub fn buffer_bytes_per_row(&self) -> UInteger {
245 unsafe { msg_send_0(self.as_ptr(), sel!(bufferBytesPerRow)) }
246 }
247
248 #[inline]
255 pub fn iosurface(&self) -> Option<*mut c_void> {
256 unsafe {
257 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(iosurface));
258 if ptr.is_null() { None } else { Some(ptr) }
259 }
260 }
261
262 #[inline]
266 pub fn iosurface_plane(&self) -> UInteger {
267 unsafe { msg_send_0(self.as_ptr(), sel!(iosurfacePlane)) }
268 }
269
270 #[inline]
274 pub fn sparse_texture_tier(&self) -> TextureSparseTier {
275 unsafe { msg_send_0(self.as_ptr(), sel!(sparseTextureTier)) }
276 }
277
278 pub fn remote_storage_texture(&self) -> Option<Texture> {
282 unsafe {
283 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(remoteStorageTexture));
284 if ptr.is_null() {
285 return None;
286 }
287 let _: *mut c_void = msg_send_0(ptr, sel!(retain));
289 Texture::from_raw(ptr)
290 }
291 }
292
293 pub fn new_remote_texture_view_for_device(&self, device: &crate::Device) -> Option<Texture> {
297 unsafe {
298 let ptr: *mut c_void = msg_send_1(
299 self.as_ptr(),
300 sel!(newRemoteTextureViewForDevice:),
301 device.as_ptr(),
302 );
303 Texture::from_raw(ptr)
304 }
305 }
306
307 pub fn new_texture_view_with_pixel_format(&self, pixel_format: PixelFormat) -> Option<Texture> {
315 unsafe {
316 let ptr: *mut c_void = msg_send_1(
317 self.as_ptr(),
318 sel!(newTextureViewWithPixelFormat:),
319 pixel_format,
320 );
321 Texture::from_raw(ptr)
322 }
323 }
324
325 pub fn new_texture_view(
329 &self,
330 pixel_format: PixelFormat,
331 texture_type: TextureType,
332 level_range: mtl_foundation::Range,
333 slice_range: mtl_foundation::Range,
334 ) -> Option<Texture> {
335 unsafe {
336 let ptr: *mut c_void = mtl_sys::msg_send_4(
337 self.as_ptr(),
338 sel!(newTextureViewWithPixelFormat: textureType: levels: slices:),
339 pixel_format,
340 texture_type,
341 level_range,
342 slice_range,
343 );
344 Texture::from_raw(ptr)
345 }
346 }
347
348 pub fn new_texture_view_with_swizzle(
352 &self,
353 pixel_format: PixelFormat,
354 texture_type: TextureType,
355 level_range: mtl_foundation::Range,
356 slice_range: mtl_foundation::Range,
357 swizzle: TextureSwizzleChannels,
358 ) -> Option<Texture> {
359 unsafe {
360 let ptr: *mut c_void = mtl_sys::msg_send_5(
361 self.as_ptr(),
362 sel!(newTextureViewWithPixelFormat: textureType: levels: slices: swizzle:),
363 pixel_format,
364 texture_type,
365 level_range,
366 slice_range,
367 swizzle,
368 );
369 Texture::from_raw(ptr)
370 }
371 }
372
373 pub fn new_shared_texture_handle(&self) -> Option<SharedTextureHandle> {
377 unsafe {
378 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(newSharedTextureHandle));
379 SharedTextureHandle::from_raw(ptr)
380 }
381 }
382
383 pub fn new_texture_view_with_descriptor(
387 &self,
388 descriptor: &TextureViewDescriptor,
389 ) -> Option<Texture> {
390 unsafe {
391 let ptr: *mut c_void = msg_send_1(
392 self.as_ptr(),
393 sel!(newTextureViewWithDescriptor:),
394 descriptor.as_ptr(),
395 );
396 Texture::from_raw(ptr)
397 }
398 }
399
400 pub unsafe fn get_bytes(
412 &self,
413 pixel_bytes: *mut c_void,
414 bytes_per_row: UInteger,
415 bytes_per_image: UInteger,
416 region: crate::types::Region,
417 mipmap_level: UInteger,
418 slice: UInteger,
419 ) {
420 unsafe {
421 mtl_sys::msg_send_6::<
422 (),
423 *mut c_void,
424 UInteger,
425 UInteger,
426 crate::types::Region,
427 UInteger,
428 UInteger,
429 >(
430 self.as_ptr(),
431 sel!(getBytes: bytesPerRow: bytesPerImage: fromRegion: mipmapLevel: slice:),
432 pixel_bytes,
433 bytes_per_row,
434 bytes_per_image,
435 region,
436 mipmap_level,
437 slice,
438 );
439 }
440 }
441
442 pub unsafe fn get_bytes_simple(
450 &self,
451 pixel_bytes: *mut c_void,
452 bytes_per_row: UInteger,
453 region: crate::types::Region,
454 mipmap_level: UInteger,
455 ) {
456 unsafe {
457 mtl_sys::msg_send_4::<(), *mut c_void, UInteger, crate::types::Region, UInteger>(
458 self.as_ptr(),
459 sel!(getBytes: bytesPerRow: fromRegion: mipmapLevel:),
460 pixel_bytes,
461 bytes_per_row,
462 region,
463 mipmap_level,
464 );
465 }
466 }
467
468 pub unsafe fn replace_region(
476 &self,
477 region: crate::types::Region,
478 mipmap_level: UInteger,
479 slice: UInteger,
480 pixel_bytes: *const c_void,
481 bytes_per_row: UInteger,
482 bytes_per_image: UInteger,
483 ) {
484 unsafe {
485 mtl_sys::msg_send_6::<
486 (),
487 crate::types::Region,
488 UInteger,
489 UInteger,
490 *const c_void,
491 UInteger,
492 UInteger,
493 >(
494 self.as_ptr(),
495 sel!(replaceRegion: mipmapLevel: slice: withBytes: bytesPerRow: bytesPerImage:),
496 region,
497 mipmap_level,
498 slice,
499 pixel_bytes,
500 bytes_per_row,
501 bytes_per_image,
502 );
503 }
504 }
505
506 pub unsafe fn replace_region_simple(
514 &self,
515 region: crate::types::Region,
516 mipmap_level: UInteger,
517 pixel_bytes: *const c_void,
518 bytes_per_row: UInteger,
519 ) {
520 unsafe {
521 mtl_sys::msg_send_4::<(), crate::types::Region, UInteger, *const c_void, UInteger>(
522 self.as_ptr(),
523 sel!(replaceRegion: mipmapLevel: withBytes: bytesPerRow:),
524 region,
525 mipmap_level,
526 pixel_bytes,
527 bytes_per_row,
528 );
529 }
530 }
531
532 pub fn label(&self) -> Option<String> {
540 unsafe {
541 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(label));
542 if ptr.is_null() {
543 return None;
544 }
545 let utf8_ptr: *const std::ffi::c_char =
546 mtl_sys::msg_send_0(ptr as *const c_void, sel!(UTF8String));
547 if utf8_ptr.is_null() {
548 return None;
549 }
550 let c_str = std::ffi::CStr::from_ptr(utf8_ptr);
551 Some(c_str.to_string_lossy().into_owned())
552 }
553 }
554
555 pub fn set_label(&self, label: &str) {
559 if let Some(ns_label) = mtl_foundation::String::from_str(label) {
560 unsafe {
561 msg_send_1::<(), *const c_void>(self.as_ptr(), sel!(setLabel:), ns_label.as_ptr());
562 }
563 }
564 }
565
566 pub fn device(&self) -> crate::Device {
570 unsafe {
571 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(device));
572 let _: *mut c_void = msg_send_0(ptr, sel!(retain));
573 crate::Device::from_raw(ptr).expect("texture has no device")
574 }
575 }
576
577 #[inline]
581 pub fn resource_options(&self) -> ResourceOptions {
582 unsafe { msg_send_0(self.as_ptr(), sel!(resourceOptions)) }
583 }
584
585 #[inline]
589 pub fn allocated_size(&self) -> UInteger {
590 unsafe { msg_send_0(self.as_ptr(), sel!(allocatedSize)) }
591 }
592}
593
594impl Clone for Texture {
595 fn clone(&self) -> Self {
596 unsafe {
597 msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
598 }
599 Self(self.0)
600 }
601}
602
603impl Drop for Texture {
604 fn drop(&mut self) {
605 unsafe {
606 msg_send_0::<()>(self.as_ptr(), sel!(release));
607 }
608 }
609}
610
611impl Referencing for Texture {
612 #[inline]
613 fn as_ptr(&self) -> *const c_void {
614 self.0.as_ptr()
615 }
616}
617
618unsafe impl Send for Texture {}
619unsafe impl Sync for Texture {}
620
621impl std::fmt::Debug for Texture {
622 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
623 f.debug_struct("Texture")
624 .field("texture_type", &self.texture_type())
625 .field("pixel_format", &self.pixel_format())
626 .field("width", &self.width())
627 .field("height", &self.height())
628 .field("depth", &self.depth())
629 .field("label", &self.label())
630 .finish()
631 }
632}