Skip to main content

mtl_gpu/
texture_view_pool.rs

1//! Metal texture view pool types.
2//!
3//! Corresponds to `Metal/MTLResourceViewPool.hpp` and `Metal/MTLTextureViewPool.hpp`.
4//!
5//! Texture view pools allow efficient management of texture views for bindless
6//! rendering workflows.
7
8use std::ffi::c_void;
9use std::ptr::NonNull;
10
11use mtl_foundation::{Referencing, UInteger};
12use mtl_sys::{Class, msg_send_0, msg_send_1, msg_send_2, msg_send_3, sel};
13
14use crate::types::ResourceID;
15use crate::{Buffer, Texture, TextureDescriptor};
16
17// ============================================================================
18// ResourceViewPoolDescriptor
19// ============================================================================
20
21/// Descriptor for creating a resource view pool.
22///
23/// C++ equivalent: `MTL::ResourceViewPoolDescriptor`
24#[repr(transparent)]
25pub struct ResourceViewPoolDescriptor(NonNull<c_void>);
26
27impl ResourceViewPoolDescriptor {
28    /// Allocate a new resource view pool descriptor.
29    ///
30    /// C++ equivalent: `static ResourceViewPoolDescriptor* alloc()`
31    pub fn alloc() -> Option<Self> {
32        unsafe {
33            let cls = Class::get("MTLResourceViewPoolDescriptor")?;
34            let ptr: *mut c_void = msg_send_0(cls.as_ptr(), sel!(alloc));
35            Self::from_raw(ptr)
36        }
37    }
38
39    /// Initialize an allocated descriptor.
40    ///
41    /// C++ equivalent: `ResourceViewPoolDescriptor* init()`
42    pub fn init(&self) -> Option<Self> {
43        unsafe {
44            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(init));
45            Self::from_raw(ptr)
46        }
47    }
48
49    /// Create a new resource view pool descriptor.
50    pub fn new() -> Option<Self> {
51        Self::alloc()?.init()
52    }
53
54    /// Create from a raw pointer.
55    ///
56    /// # Safety
57    ///
58    /// The pointer must be a valid Metal resource view pool descriptor.
59    #[inline]
60    pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
61        NonNull::new(ptr).map(Self)
62    }
63
64    /// Get the raw pointer.
65    #[inline]
66    pub fn as_raw(&self) -> *mut c_void {
67        self.0.as_ptr()
68    }
69
70    // =========================================================================
71    // Properties
72    // =========================================================================
73
74    /// Get the label.
75    ///
76    /// C++ equivalent: `NS::String* label() const`
77    pub fn label(&self) -> Option<String> {
78        unsafe {
79            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(label));
80            if ptr.is_null() {
81                return None;
82            }
83            let utf8_ptr: *const std::ffi::c_char =
84                mtl_sys::msg_send_0(ptr as *const c_void, sel!(UTF8String));
85            if utf8_ptr.is_null() {
86                return None;
87            }
88            let c_str = std::ffi::CStr::from_ptr(utf8_ptr);
89            Some(c_str.to_string_lossy().into_owned())
90        }
91    }
92
93    /// Set the label.
94    ///
95    /// C++ equivalent: `void setLabel(const NS::String*)`
96    pub fn set_label(&self, label: &str) {
97        if let Some(ns_label) = mtl_foundation::String::from_str(label) {
98            unsafe {
99                msg_send_1::<(), *const c_void>(self.as_ptr(), sel!(setLabel:), ns_label.as_ptr());
100            }
101        }
102    }
103
104    /// Get the resource view count.
105    ///
106    /// C++ equivalent: `NS::UInteger resourceViewCount() const`
107    #[inline]
108    pub fn resource_view_count(&self) -> UInteger {
109        unsafe { msg_send_0(self.as_ptr(), sel!(resourceViewCount)) }
110    }
111
112    /// Set the resource view count.
113    ///
114    /// C++ equivalent: `void setResourceViewCount(NS::UInteger)`
115    #[inline]
116    pub fn set_resource_view_count(&self, count: UInteger) {
117        unsafe {
118            msg_send_1::<(), UInteger>(self.as_ptr(), sel!(setResourceViewCount:), count);
119        }
120    }
121}
122
123impl Default for ResourceViewPoolDescriptor {
124    fn default() -> Self {
125        Self::new().expect("failed to create ResourceViewPoolDescriptor")
126    }
127}
128
129impl Clone for ResourceViewPoolDescriptor {
130    fn clone(&self) -> Self {
131        unsafe {
132            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(copy));
133            Self::from_raw(ptr).expect("failed to copy ResourceViewPoolDescriptor")
134        }
135    }
136}
137
138impl Drop for ResourceViewPoolDescriptor {
139    fn drop(&mut self) {
140        unsafe {
141            msg_send_0::<()>(self.as_ptr(), sel!(release));
142        }
143    }
144}
145
146impl Referencing for ResourceViewPoolDescriptor {
147    #[inline]
148    fn as_ptr(&self) -> *const c_void {
149        self.0.as_ptr()
150    }
151}
152
153unsafe impl Send for ResourceViewPoolDescriptor {}
154unsafe impl Sync for ResourceViewPoolDescriptor {}
155
156impl std::fmt::Debug for ResourceViewPoolDescriptor {
157    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
158        f.debug_struct("ResourceViewPoolDescriptor")
159            .field("label", &self.label())
160            .field("resource_view_count", &self.resource_view_count())
161            .finish()
162    }
163}
164
165// ============================================================================
166// TextureViewPool
167// ============================================================================
168
169/// A pool for managing texture views.
170///
171/// C++ equivalent: `MTL::TextureViewPool`
172///
173/// Texture view pools allow efficient creation and management of texture views
174/// for bindless rendering. They inherit from ResourceViewPool.
175#[repr(transparent)]
176pub struct TextureViewPool(NonNull<c_void>);
177
178impl TextureViewPool {
179    /// Create from a raw pointer.
180    ///
181    /// # Safety
182    ///
183    /// The pointer must be a valid Metal texture view pool.
184    #[inline]
185    pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
186        NonNull::new(ptr).map(Self)
187    }
188
189    /// Get the raw pointer.
190    #[inline]
191    pub fn as_raw(&self) -> *mut c_void {
192        self.0.as_ptr()
193    }
194
195    // =========================================================================
196    // ResourceViewPool inherited methods
197    // =========================================================================
198
199    /// Get the device that created this pool.
200    ///
201    /// C++ equivalent: `Device* device() const`
202    pub fn device(&self) -> crate::Device {
203        unsafe {
204            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(device));
205            let _: *mut c_void = msg_send_0(ptr, sel!(retain));
206            crate::Device::from_raw(ptr).expect("pool has no device")
207        }
208    }
209
210    /// Get the label.
211    ///
212    /// C++ equivalent: `NS::String* label() const`
213    pub fn label(&self) -> Option<String> {
214        unsafe {
215            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(label));
216            if ptr.is_null() {
217                return None;
218            }
219            let utf8_ptr: *const std::ffi::c_char =
220                mtl_sys::msg_send_0(ptr as *const c_void, sel!(UTF8String));
221            if utf8_ptr.is_null() {
222                return None;
223            }
224            let c_str = std::ffi::CStr::from_ptr(utf8_ptr);
225            Some(c_str.to_string_lossy().into_owned())
226        }
227    }
228
229    /// Get the resource view count.
230    ///
231    /// C++ equivalent: `NS::UInteger resourceViewCount() const`
232    #[inline]
233    pub fn resource_view_count(&self) -> UInteger {
234        unsafe { msg_send_0(self.as_ptr(), sel!(resourceViewCount)) }
235    }
236
237    /// Get the base resource ID for bindless access.
238    ///
239    /// C++ equivalent: `ResourceID baseResourceID() const`
240    #[inline]
241    pub fn base_resource_id(&self) -> ResourceID {
242        unsafe { msg_send_0(self.as_ptr(), sel!(baseResourceID)) }
243    }
244
245    /// Copy resource views from another pool.
246    ///
247    /// C++ equivalent: `void copyResourceViewsFromPool(const ResourceViewPool*, NS::Range, NS::UInteger)`
248    pub fn copy_resource_views_from_pool(
249        &self,
250        source: &TextureViewPool,
251        source_location: UInteger,
252        source_length: UInteger,
253        destination_index: UInteger,
254    ) {
255        unsafe {
256            let range = mtl_foundation::Range::new(source_location, source_length);
257            msg_send_3::<(), *const c_void, mtl_foundation::Range, UInteger>(
258                self.as_ptr(),
259                sel!(copyResourceViewsFromPool:sourceRange:destinationIndex:),
260                source.as_ptr(),
261                range,
262                destination_index,
263            );
264        }
265    }
266
267    // =========================================================================
268    // TextureViewPool specific methods
269    // =========================================================================
270
271    /// Set a texture view at the specified index.
272    ///
273    /// C++ equivalent: `void setTextureView(const Texture*, NS::UInteger)`
274    pub fn set_texture_view(&self, texture: &Texture, index: UInteger) {
275        unsafe {
276            msg_send_2::<(), *const c_void, UInteger>(
277                self.as_ptr(),
278                sel!(setTextureView:atIndex:),
279                texture.as_ptr(),
280                index,
281            );
282        }
283    }
284
285    /// Set a texture view with a descriptor at the specified index.
286    ///
287    /// C++ equivalent: `void setTextureView(const Texture*, const TextureViewDescriptor*, NS::UInteger)`
288    pub fn set_texture_view_with_descriptor(
289        &self,
290        texture: &Texture,
291        descriptor: &crate::TextureViewDescriptor,
292        index: UInteger,
293    ) {
294        unsafe {
295            msg_send_3::<(), *const c_void, *const c_void, UInteger>(
296                self.as_ptr(),
297                sel!(setTextureView:descriptor:atIndex:),
298                texture.as_ptr(),
299                descriptor.as_ptr(),
300                index,
301            );
302        }
303    }
304
305    /// Set a texture view from a buffer.
306    ///
307    /// C++ equivalent: `void setTextureViewFromBuffer(const Buffer*, const TextureDescriptor*, NS::UInteger, NS::UInteger, NS::UInteger)`
308    pub fn set_texture_view_from_buffer(
309        &self,
310        buffer: &Buffer,
311        descriptor: &TextureDescriptor,
312        offset: UInteger,
313        bytes_per_row: UInteger,
314        index: UInteger,
315    ) {
316        unsafe {
317            mtl_sys::msg_send_5::<(), *const c_void, *const c_void, UInteger, UInteger, UInteger>(
318                self.as_ptr(),
319                sel!(setTextureViewFromBuffer:descriptor:offset:bytesPerRow:atIndex:),
320                buffer.as_ptr(),
321                descriptor.as_ptr(),
322                offset,
323                bytes_per_row,
324                index,
325            );
326        }
327    }
328
329    /// Set a texture view from a buffer (raw pointer version).
330    ///
331    /// C++ equivalent: `void setTextureViewFromBuffer(const Buffer*, const TextureDescriptor*, NS::UInteger, NS::UInteger, NS::UInteger)`
332    ///
333    /// # Safety
334    ///
335    /// All pointers must be valid Metal objects.
336    pub unsafe fn set_texture_view_from_buffer_raw(
337        &self,
338        buffer: *const c_void,
339        descriptor: *const c_void,
340        offset: UInteger,
341        bytes_per_row: UInteger,
342        index: UInteger,
343    ) {
344        unsafe {
345            mtl_sys::msg_send_5::<(), *const c_void, *const c_void, UInteger, UInteger, UInteger>(
346                self.as_ptr(),
347                sel!(setTextureViewFromBuffer:descriptor:offset:bytesPerRow:atIndex:),
348                buffer,
349                descriptor,
350                offset,
351                bytes_per_row,
352                index,
353            );
354        }
355    }
356}
357
358impl Clone for TextureViewPool {
359    fn clone(&self) -> Self {
360        unsafe {
361            msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
362        }
363        Self(self.0)
364    }
365}
366
367impl Drop for TextureViewPool {
368    fn drop(&mut self) {
369        unsafe {
370            msg_send_0::<()>(self.as_ptr(), sel!(release));
371        }
372    }
373}
374
375impl Referencing for TextureViewPool {
376    #[inline]
377    fn as_ptr(&self) -> *const c_void {
378        self.0.as_ptr()
379    }
380}
381
382unsafe impl Send for TextureViewPool {}
383unsafe impl Sync for TextureViewPool {}
384
385impl std::fmt::Debug for TextureViewPool {
386    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
387        f.debug_struct("TextureViewPool")
388            .field("label", &self.label())
389            .field("resource_view_count", &self.resource_view_count())
390            .finish()
391    }
392}
393
394#[cfg(test)]
395mod tests {
396    use super::*;
397
398    #[test]
399    fn test_resource_view_pool_descriptor_size() {
400        assert_eq!(
401            std::mem::size_of::<ResourceViewPoolDescriptor>(),
402            std::mem::size_of::<*mut c_void>()
403        );
404    }
405
406    #[test]
407    fn test_texture_view_pool_size() {
408        assert_eq!(
409            std::mem::size_of::<TextureViewPool>(),
410            std::mem::size_of::<*mut c_void>()
411        );
412    }
413}