Skip to main content

apple_metal/
argument.rs

1use crate::{ffi, ArgumentEncoder, MetalDevice, SamplerState};
2
3const DATA_TYPE_TEXTURE: usize = 58;
4const DATA_TYPE_SAMPLER: usize = 59;
5const DATA_TYPE_POINTER: usize = 60;
6
7/// `MTLArgumentBuffersTier` enum values.
8pub mod argument_buffers_tier {
9    /// Mirrors the `Metal` framework constant `TIER1`.
10    pub const TIER1: usize = 0;
11    /// Mirrors the `Metal` framework constant `TIER2`.
12    pub const TIER2: usize = 1;
13}
14
15/// `MTLBindingAccess` enum values.
16pub mod binding_access {
17    /// Mirrors the `Metal` framework constant `READ_ONLY`.
18    pub const READ_ONLY: usize = 0;
19    /// Mirrors the `Metal` framework constant `READ_WRITE`.
20    pub const READ_WRITE: usize = 1;
21    /// Mirrors the `Metal` framework constant `WRITE_ONLY`.
22    pub const WRITE_ONLY: usize = 2;
23}
24
25/// `MTLTextureType` enum values.
26pub mod texture_type {
27    /// Mirrors the `Metal` framework constant `TYPE_1D`.
28    pub const TYPE_1D: usize = 0;
29    /// Mirrors the `Metal` framework constant `TYPE_1D_ARRAY`.
30    pub const TYPE_1D_ARRAY: usize = 1;
31    /// Mirrors the `Metal` framework constant `TYPE_2D`.
32    pub const TYPE_2D: usize = 2;
33    /// Mirrors the `Metal` framework constant `TYPE_2D_ARRAY`.
34    pub const TYPE_2D_ARRAY: usize = 3;
35    /// Mirrors the `Metal` framework constant `TYPE_2D_MULTISAMPLE`.
36    pub const TYPE_2D_MULTISAMPLE: usize = 4;
37    /// Mirrors the `Metal` framework constant `CUBE`.
38    pub const CUBE: usize = 5;
39    /// Mirrors the `Metal` framework constant `CUBE_ARRAY`.
40    pub const CUBE_ARRAY: usize = 6;
41    /// Mirrors the `Metal` framework constant `TYPE_3D`.
42    pub const TYPE_3D: usize = 7;
43    /// Mirrors the `Metal` framework constant `TYPE_2D_MULTISAMPLE_ARRAY`.
44    pub const TYPE_2D_MULTISAMPLE_ARRAY: usize = 8;
45    /// Mirrors the `Metal` framework constant `TEXTURE_BUFFER`.
46    pub const TEXTURE_BUFFER: usize = 9;
47}
48
49/// Safe Rust description of `MTLArgumentDescriptor`.
50#[derive(Debug, Clone, Copy)]
51pub struct ArgumentDescriptor {
52    data_type: usize,
53    index: usize,
54    array_length: usize,
55    access: usize,
56    texture_type: usize,
57    constant_block_alignment: usize,
58}
59
60impl ArgumentDescriptor {
61    /// Describe a buffer pointer argument at `index`.
62    #[must_use]
63    pub const fn buffer(index: usize, access: usize) -> Self {
64        Self {
65            data_type: DATA_TYPE_POINTER,
66            index,
67            array_length: 0,
68            access,
69            texture_type: texture_type::TYPE_2D,
70            constant_block_alignment: 0,
71        }
72    }
73
74    /// Describe a texture argument at `index`.
75    #[must_use]
76    pub const fn texture(index: usize, texture_type: usize, access: usize) -> Self {
77        Self {
78            data_type: DATA_TYPE_TEXTURE,
79            index,
80            array_length: 0,
81            access,
82            texture_type,
83            constant_block_alignment: 0,
84        }
85    }
86
87    /// Describe a sampler argument at `index`.
88    #[must_use]
89    pub const fn sampler(index: usize) -> Self {
90        Self {
91            data_type: DATA_TYPE_SAMPLER,
92            index,
93            array_length: 0,
94            access: binding_access::READ_ONLY,
95            texture_type: texture_type::TYPE_2D,
96            constant_block_alignment: 0,
97        }
98    }
99
100    /// Describe a constant block argument using a raw `MTLDataType` value.
101    #[must_use]
102    pub const fn constant(data_type: usize, index: usize, array_length: usize) -> Self {
103        Self {
104            data_type,
105            index,
106            array_length,
107            access: binding_access::READ_ONLY,
108            texture_type: texture_type::TYPE_2D,
109            constant_block_alignment: 0,
110        }
111    }
112
113    /// Override the descriptor's array length.
114    #[must_use]
115    pub fn with_array_length(mut self, array_length: usize) -> Self {
116        self.array_length = array_length;
117        self
118    }
119
120    /// Override the descriptor's constant-block alignment.
121    #[must_use]
122    pub fn with_constant_block_alignment(mut self, alignment: usize) -> Self {
123        self.constant_block_alignment = alignment;
124        self
125    }
126
127    const fn as_words(self) -> [usize; 6] {
128        [
129            self.data_type,
130            self.index,
131            self.array_length,
132            self.access,
133            self.texture_type,
134            self.constant_block_alignment,
135        ]
136    }
137}
138
139impl MetalDevice {
140    /// Create an argument encoder from a slice of `MTLArgumentDescriptor` values.
141    #[must_use]
142    pub fn new_argument_encoder_with_descriptors(
143        &self,
144        descriptors: &[ArgumentDescriptor],
145    ) -> Option<ArgumentEncoder> {
146        let mut words = Vec::with_capacity(descriptors.len().saturating_mul(6));
147        for descriptor in descriptors {
148            words.extend_from_slice(&descriptor.as_words());
149        }
150        let ptr = unsafe {
151            ffi::am_device_new_argument_encoder_with_descriptors(
152                self.as_ptr(),
153                words.as_ptr(),
154                descriptors.len(),
155            )
156        };
157        if ptr.is_null() {
158            None
159        } else {
160            Some(unsafe { ArgumentEncoder::from_retained_ptr(ptr) })
161        }
162    }
163}
164
165impl ArgumentEncoder {
166    /// Encode a sampler binding at `index`.
167    pub fn set_sampler_state(&self, sampler: &SamplerState, index: usize) {
168        unsafe {
169            ffi::am_argument_encoder_set_sampler_state(self.as_ptr(), sampler.as_ptr(), index);
170        };
171    }
172}