1use 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#[repr(transparent)]
25pub struct ResourceViewPoolDescriptor(NonNull<c_void>);
26
27impl ResourceViewPoolDescriptor {
28 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 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 pub fn new() -> Option<Self> {
51 Self::alloc()?.init()
52 }
53
54 #[inline]
60 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
61 NonNull::new(ptr).map(Self)
62 }
63
64 #[inline]
66 pub fn as_raw(&self) -> *mut c_void {
67 self.0.as_ptr()
68 }
69
70 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 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 #[inline]
108 pub fn resource_view_count(&self) -> UInteger {
109 unsafe { msg_send_0(self.as_ptr(), sel!(resourceViewCount)) }
110 }
111
112 #[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#[repr(transparent)]
176pub struct TextureViewPool(NonNull<c_void>);
177
178impl TextureViewPool {
179 #[inline]
185 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
186 NonNull::new(ptr).map(Self)
187 }
188
189 #[inline]
191 pub fn as_raw(&self) -> *mut c_void {
192 self.0.as_ptr()
193 }
194
195 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 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 #[inline]
233 pub fn resource_view_count(&self) -> UInteger {
234 unsafe { msg_send_0(self.as_ptr(), sel!(resourceViewCount)) }
235 }
236
237 #[inline]
241 pub fn base_resource_id(&self) -> ResourceID {
242 unsafe { msg_send_0(self.as_ptr(), sel!(baseResourceID)) }
243 }
244
245 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 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 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 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 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}