Skip to main content

cidre/mtl/
texture.rs

1use crate::{arc, cf, define_mtl, define_obj_type, define_opts, mtl, ns, objc};
2
3#[cfg(feature = "io_surface")]
4use crate::io;
5
6/// Describes the dimensionality of each image, and if multiple images are arranged into an array or cube.
7#[doc(alias = "MTLTextureType")]
8#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd)]
9#[repr(usize)]
10pub enum Type {
11    #[doc(alias = "MTLTextureType1D")]
12    _1d = 0,
13
14    #[doc(alias = "MTLTextureType1DArray")]
15    _1dArray = 1,
16
17    #[doc(alias = "MTLTextureType2D")]
18    _2d = 2,
19
20    #[doc(alias = "MTLTextureType2DArray")]
21    _2dArray = 3,
22
23    #[doc(alias = "MTLTextureType2DMultisample")]
24    _2dMultisample = 4,
25
26    #[doc(alias = "MTLTextureTypeCube")]
27    Cube = 5,
28
29    #[doc(alias = "MTLTextureTypeCubeArray")]
30    CubeArray = 6,
31
32    #[doc(alias = "MTLTextureType3D")]
33    _3d = 7,
34
35    #[doc(alias = "MTLTextureType2DMultisampleArray")]
36    _2dMultisampleArray = 8,
37
38    #[doc(alias = "MTLTextureTypeTextureBuffer")]
39    TextureBuffer = 9,
40}
41
42#[doc(alias = "MTLTextureSwizzle")]
43#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd)]
44#[repr(u8)]
45pub enum Swizzle {
46    #[doc(alias = "MTLTextureSwizzleZero")]
47    Zero = 0,
48
49    #[doc(alias = "MTLTextureSwizzleOne")]
50    One = 1,
51
52    #[doc(alias = "MTLTextureSwizzleRed")]
53    Red = 2,
54
55    #[doc(alias = "MTLTextureSwizzleGreen")]
56    Green = 3,
57
58    #[doc(alias = "MTLTextureSwizzleBlue")]
59    Blue = 4,
60
61    #[doc(alias = "MTLTextureSwizzleAlpha")]
62    Alpha = 5,
63}
64
65#[doc(alias = "MTLTextureSwizzleChannels")]
66#[derive(Debug, Clone, Copy, PartialEq, Eq)]
67#[repr(C)]
68pub struct SwizzleChannels {
69    pub red: Swizzle,
70    pub green: Swizzle,
71    pub blue: Swizzle,
72    pub alpha: Swizzle,
73}
74
75impl Default for SwizzleChannels {
76    #[inline]
77    fn default() -> SwizzleChannels {
78        SwizzleChannels {
79            red: Swizzle::Red,
80            green: Swizzle::Green,
81            blue: Swizzle::Blue,
82            alpha: Swizzle::Alpha,
83        }
84    }
85}
86
87define_obj_type!(
88    #[doc(alias = "MTLSharedTextureHandle")]
89    pub SharedTextureHandle(ns::Id)
90);
91
92impl SharedTextureHandle {
93    #[objc::msg_send(device)]
94    pub fn device(&self) -> &mtl::Device;
95
96    #[objc::msg_send(label)]
97    pub fn label(&self) -> Option<&ns::String>;
98}
99
100define_opts!(
101    #[doc(alias = "MTLTextureUsage")]
102    pub Usage(usize)
103);
104
105impl Usage {
106    #[doc(alias = "MTLTextureUsageUnknown")]
107    pub const UNKNOWN: Self = Self(0x0000);
108
109    #[doc(alias = "MTLTextureUsageShaderRead")]
110    pub const SHADER_READ: Self = Self(0x0001);
111
112    #[doc(alias = "MTLTextureUsageShaderWrite")]
113    pub const SHADER_WRITE: Self = Self(0x0002);
114
115    #[doc(alias = "MTLTextureUsageRenderTarget")]
116    pub const RENDER_TARGET: Self = Self(0x0004);
117
118    #[doc(alias = "MTLTextureUsagePixelFormatView")]
119    pub const PIXEL_FORMAT_VIEW: Self = Self(0x0010);
120
121    #[doc(alias = "MTLTextureUsageShaderAtomic")]
122    pub const SHADER_ATOMIC: Self = Self(0x0020);
123
124    pub fn to_cf_number(&self) -> arc::R<cf::Number> {
125        cf::Number::from_i64(self.0 as _)
126    }
127
128    pub fn to_ns_number(&self) -> arc::R<ns::Number> {
129        ns::Number::with_i64(self.0 as _)
130    }
131}
132
133#[doc(alias = "MTLTextureCompressionType")]
134#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd)]
135#[repr(usize)]
136pub enum Compression {
137    #[doc(alias = "MTLTextureCompressionTypeLossless")]
138    Lossless = 0,
139
140    #[doc(alias = "MTLTextureCompressionTypeLossy")]
141    Lossy = 1,
142}
143
144define_obj_type!(
145    /// An object that you use to configure new Metal texture objects.
146    #[doc(alias = "MTLTextureDescriptor")]
147    pub Desc(ns::Id),
148    MTL_TEXTURE_DESCRIPTOR
149);
150
151impl ns::Copying for Desc {}
152
153impl Desc {
154    #[objc::msg_send(texture2DDescriptorWithPixelFormat:width:height:mipmapped:)]
155    pub fn new_2d(
156        pixel_format: mtl::PixelFormat,
157        width: usize,
158        height: usize,
159        mipmapped: bool,
160    ) -> arc::R<Desc>;
161
162    /// ```
163    /// use cidre::mtl;
164    ///
165    /// let td = mtl::TextureDesc::new_cube(mtl::PixelFormat::A8UNorm, 100, false);
166    ///
167    /// assert_eq!(td.texture_type(), mtl::TextureType::Cube);
168    ///
169    /// ```
170    #[objc::msg_send(textureCubeDescriptorWithPixelFormat:size:mipmapped:)]
171    pub fn new_cube(pixel_format: mtl::PixelFormat, size: usize, mipmapped: bool) -> arc::R<Desc>;
172
173    #[objc::msg_send(textureBufferDescriptorWithPixelFormat:width:resourceOptions:usage:)]
174    pub fn new_buff(
175        pixel_format: mtl::PixelFormat,
176        width: usize,
177        res_opts: mtl::resource::Opts,
178        usage: Usage,
179    ) -> arc::R<Desc>;
180
181    #[objc::msg_send(textureType)]
182    pub fn texture_type(&self) -> Type;
183
184    #[objc::msg_send(setTextureType:)]
185    pub fn set_texture_type(&mut self, val: Type);
186
187    #[inline]
188    pub fn with_texture_type(&mut self, val: Type) -> &mut Self {
189        self.set_texture_type(val);
190        self
191    }
192
193    #[objc::msg_send(pixelFormat)]
194    pub fn pixel_format(&self) -> mtl::PixelFormat;
195
196    #[objc::msg_send(setPixelFormat:)]
197    pub fn set_pixel_format(&mut self, val: mtl::PixelFormat);
198
199    // #[inline]
200    // pub fn with_pixel_format(&mut self, val: mtl::PixelFormat) -> &mut Self {
201    //     self.set_pixel_format(val);
202    //     self
203    // }
204
205    define_mtl!(
206        width,
207        set_width,
208        height,
209        set_height,
210        depth,
211        set_depth,
212        res_opts,
213        set_res_opts,
214        cpu_cache_mode,
215        set_cpu_cache_mode,
216        storage_mode,
217        set_storage_mode,
218        hazard_tracking_mode,
219        set_hazard_tracking_mode
220    );
221
222    #[objc::msg_send(mipmapLevelCount)]
223    pub fn mipmap_level_count(&self) -> usize;
224
225    #[objc::msg_send(setMipmapLevelCount:)]
226    pub fn set_mipmap_level_count(&mut self, val: usize);
227
228    #[objc::msg_send(sampleCount)]
229    pub fn sample_count(&self) -> usize;
230
231    #[objc::msg_send(setSampleCount:)]
232    pub fn set_sample_count(&mut self, val: usize);
233
234    #[objc::msg_send(arrayLength)]
235    pub fn array_len(&self) -> usize;
236
237    #[objc::msg_send(setArrayLength:)]
238    pub fn set_array_len(&mut self, val: usize);
239
240    #[objc::msg_send(usage)]
241    pub fn usage(&self) -> Usage;
242
243    #[objc::msg_send(setUsage:)]
244    pub fn set_usage(&mut self, val: Usage);
245
246    /// Allow GPU-optimization for the contents of this texture. The default value is true.
247    #[objc::msg_send(allowGPUOptimizedContents)]
248    pub fn allow_gpu_optimized_contents(&self) -> bool;
249
250    #[objc::msg_send(setAllowGPUOptimizedContents:)]
251    pub fn set_allow_gpu_optimized_contents(&mut self, val: bool);
252
253    #[objc::msg_send(compressionType)]
254    pub fn compression_type(&self) -> Compression;
255
256    #[objc::msg_send(setCompressionType:)]
257    pub fn set_compression_type(&mut self, val: Compression);
258
259    #[objc::msg_send(swizzle)]
260    pub fn swizzle(&self) -> SwizzleChannels;
261
262    #[objc::msg_send(setSwizzle:)]
263    pub fn set_swizzle(&mut self, val: SwizzleChannels);
264}
265
266define_obj_type!(
267    /// A resource that holds formatted image data.
268    #[doc(alias = "MTLTexture")]
269    pub Texture(mtl::Res)
270);
271
272impl Texture {
273    define_mtl!(width, height, depth, gpu_res_id);
274
275    /// The texture this texture view was created from, or [`None`] if this is not
276    /// a texture view or it was not created from a texture.
277    #[objc::msg_send(parentTexture)]
278    pub fn parent_texture(&self) -> Option<&Texture>;
279
280    #[objc::msg_send(newTextureViewWithPixelFormat:)]
281    pub fn new_texture_view_with_pixel_format(
282        &self,
283        pixel_format: mtl::PixelFormat,
284    ) -> Option<arc::R<Texture>>;
285
286    /// The buffer this texture view was created from, or [`None`] if this is not a texture
287    /// view or it was not created from a buffer.
288    #[objc::msg_send(buffer)]
289    pub fn buf(&self) -> Option<&mtl::Buf>;
290
291    /// The offset of the buffer this texture view was created from, or 0 if this is not a texture view.
292    #[objc::msg_send(bufferOffset)]
293    pub fn buf_offset(&self) -> usize;
294
295    /// The 'bytes_per_row' of the buffer this texture view was created from, or 0 if this is not a texture view.
296    #[objc::msg_send(bufferBytesPerRow)]
297    pub fn buf_bytes_per_row(&self) -> usize;
298
299    #[cfg(feature = "io_surface")]
300    #[objc::msg_send(iosurface)]
301    pub fn io_surf(&self) -> Option<&io::Surf>;
302
303    #[objc::msg_send(iosurfacePlane)]
304    pub fn io_surf_plane(&self) -> usize;
305
306    #[objc::msg_send(textureType)]
307    pub fn texture_type(&self) -> Type;
308
309    #[objc::msg_send(pixelFormat)]
310    pub fn pixel_format(&self) -> mtl::PixelFormat;
311
312    #[objc::msg_send(mipmapLevelCount)]
313    pub fn mipmap_level_count(&self) -> usize;
314
315    #[objc::msg_send(sampleCount)]
316    pub fn sample_count(&self) -> usize;
317
318    #[objc::msg_send(arrayLength)]
319    pub fn array_len(&self) -> usize;
320}
321
322unsafe extern "C" {
323    static MTL_TEXTURE_DESCRIPTOR: &'static objc::Class<Desc>;
324}
325
326#[cfg(test)]
327mod tests {
328    use crate::mtl;
329
330    #[test]
331    fn basics1() {
332        let mut td = mtl::TextureDesc::new_2d(mtl::PixelFormat::A8UNorm, 100, 200, false);
333
334        assert_eq!(td.texture_type(), mtl::TextureType::_2d);
335        assert_eq!(td.pixel_format(), mtl::PixelFormat::A8UNorm);
336        assert_eq!(td.width(), 100);
337        assert_eq!(td.height(), 200);
338        assert_eq!(td.depth(), 1);
339        assert_eq!(td.mipmap_level_count(), 1);
340        assert_eq!(td.sample_count(), 1);
341        assert_eq!(td.array_len(), 1);
342
343        td.set_width(200);
344        assert_eq!(td.width(), 200);
345
346        td.set_height(300);
347        assert_eq!(td.height(), 300);
348    }
349
350    #[test]
351    fn basics2() {
352        let td = mtl::TextureDesc::new_cube(mtl::PixelFormat::A8UNorm, 100, false);
353
354        assert_eq!(td.texture_type(), mtl::TextureType::Cube);
355    }
356
357    #[test]
358    fn basics3() {
359        let device = mtl::Device::sys_default().unwrap();
360
361        let td = mtl::TextureDesc::new_2d(mtl::PixelFormat::A8UNorm, 100, 200, false);
362
363        let t = device.new_texture(&td).unwrap();
364
365        assert_eq!(t.width(), 100);
366        assert_eq!(t.height(), 200);
367        assert_eq!(t.depth(), 1);
368    }
369
370    #[test]
371    fn basics4() {
372        let device = mtl::Device::sys_default().unwrap();
373
374        let td = mtl::TextureDesc::new_2d(mtl::PixelFormat::A8UNorm, 100, 200, false);
375
376        let t = device.new_texture(&td).unwrap();
377
378        assert!(t.parent_texture().is_none());
379        assert!(t.io_surf().is_none());
380        assert_eq!(t.texture_type(), mtl::texture::Type::_2d);
381        assert_eq!(t.pixel_format(), mtl::PixelFormat::A8UNorm);
382        assert!(t.io_surf().is_none());
383        assert_eq!(t.io_surf_plane(), 0);
384
385        let tv = t
386            .new_texture_view_with_pixel_format(mtl::PixelFormat::A8UNorm)
387            .unwrap();
388
389        assert!(tv.parent_texture().is_some());
390        assert_eq!(tv.width(), 100);
391        assert_eq!(tv.height(), 200);
392    }
393}