1use core::ffi::c_void;
9use std::sync::Arc;
10
11use baracuda_cuda_sys::runtime::runtime;
12use baracuda_cuda_sys::runtime::types::{
13 cudaArray_t, cudaChannelFormatDesc, cudaChannelFormatKind, cudaExtent, cudaMipmappedArray_t,
14 cudaResourceDesc, cudaResourceViewDesc, cudaSurfaceObject_t, cudaTextureDesc,
15 cudaTextureObject_t,
16};
17
18use crate::error::{check, Result};
19
20pub fn channel_desc(
24 bits_x: i32,
25 bits_y: i32,
26 bits_z: i32,
27 bits_w: i32,
28 kind: i32,
29) -> cudaChannelFormatDesc {
30 cudaChannelFormatDesc {
31 x: bits_x,
32 y: bits_y,
33 z: bits_z,
34 w: bits_w,
35 kind,
36 }
37}
38
39#[inline]
41pub fn channel_desc_u8() -> cudaChannelFormatDesc {
42 channel_desc(8, 0, 0, 0, cudaChannelFormatKind::UNSIGNED)
43}
44
45#[inline]
47pub fn channel_desc_f32() -> cudaChannelFormatDesc {
48 channel_desc(32, 0, 0, 0, cudaChannelFormatKind::FLOAT)
49}
50
51#[derive(Clone)]
53pub struct Array {
54 inner: Arc<ArrayInner>,
55}
56
57struct ArrayInner {
58 handle: cudaArray_t,
59 width: usize,
60 height: usize,
61 depth: usize,
62 desc: cudaChannelFormatDesc,
63}
64
65unsafe impl Send for ArrayInner {}
66unsafe impl Sync for ArrayInner {}
67
68impl core::fmt::Debug for ArrayInner {
69 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
70 f.debug_struct("Array")
71 .field("width", &self.width)
72 .field("height", &self.height)
73 .field("depth", &self.depth)
74 .field("desc", &self.desc)
75 .finish_non_exhaustive()
76 }
77}
78
79impl core::fmt::Debug for Array {
80 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
81 self.inner.fmt(f)
82 }
83}
84
85impl Array {
86 pub fn new_2d(
89 desc: &cudaChannelFormatDesc,
90 width: usize,
91 height: usize,
92 flags: u32,
93 ) -> Result<Self> {
94 let r = runtime()?;
95 let cu = r.cuda_malloc_array()?;
96 let mut arr: cudaArray_t = core::ptr::null_mut();
97 check(unsafe {
98 cu(
99 &mut arr,
100 desc as *const cudaChannelFormatDesc as *const c_void,
101 width,
102 height,
103 flags,
104 )
105 })?;
106 Ok(Self {
107 inner: Arc::new(ArrayInner {
108 handle: arr,
109 width,
110 height,
111 depth: 0,
112 desc: *desc,
113 }),
114 })
115 }
116
117 pub fn new_3d(desc: &cudaChannelFormatDesc, extent: cudaExtent, flags: u32) -> Result<Self> {
120 let r = runtime()?;
121 let cu = r.cuda_malloc_3d_array()?;
122 let mut arr: cudaArray_t = core::ptr::null_mut();
123 check(unsafe {
124 cu(
125 &mut arr,
126 desc as *const cudaChannelFormatDesc as *const c_void,
127 &extent as *const cudaExtent as *const c_void,
128 flags,
129 )
130 })?;
131 Ok(Self {
132 inner: Arc::new(ArrayInner {
133 handle: arr,
134 width: extent.width,
135 height: extent.height,
136 depth: extent.depth,
137 desc: *desc,
138 }),
139 })
140 }
141
142 pub unsafe fn from_raw(
148 handle: cudaArray_t,
149 desc: cudaChannelFormatDesc,
150 width: usize,
151 height: usize,
152 depth: usize,
153 ) -> Self {
154 Self {
155 inner: Arc::new(ArrayInner {
156 handle,
157 width,
158 height,
159 depth,
160 desc,
161 }),
162 }
163 }
164
165 #[inline]
167 pub fn as_raw(&self) -> cudaArray_t {
168 self.inner.handle
169 }
170
171 #[inline]
173 pub fn width(&self) -> usize {
174 self.inner.width
175 }
176 #[inline]
178 pub fn height(&self) -> usize {
179 self.inner.height
180 }
181 #[inline]
183 pub fn depth(&self) -> usize {
184 self.inner.depth
185 }
186 #[inline]
188 pub fn desc(&self) -> &cudaChannelFormatDesc {
189 &self.inner.desc
190 }
191
192 pub fn info(&self) -> Result<(cudaChannelFormatDesc, cudaExtent, u32)> {
194 let r = runtime()?;
195 let cu = r.cuda_array_get_info()?;
196 let mut desc = cudaChannelFormatDesc::default();
197 let mut extent = cudaExtent::default();
198 let mut flags: core::ffi::c_uint = 0;
199 check(unsafe {
200 cu(
201 &mut desc as *mut cudaChannelFormatDesc as *mut c_void,
202 &mut extent as *mut cudaExtent as *mut c_void,
203 &mut flags,
204 self.inner.handle,
205 )
206 })?;
207 Ok((desc, extent, flags))
208 }
209}
210
211impl Drop for ArrayInner {
212 fn drop(&mut self) {
213 if self.handle.is_null() {
214 return;
215 }
216 if let Ok(r) = runtime() {
217 if let Ok(cu) = r.cuda_free_array() {
218 let _ = unsafe { cu(self.handle) };
219 }
220 }
221 }
222}
223
224#[derive(Clone)]
226pub struct MipmappedArray {
227 inner: Arc<MipmappedArrayInner>,
228}
229
230struct MipmappedArrayInner {
231 handle: cudaMipmappedArray_t,
232}
233
234unsafe impl Send for MipmappedArrayInner {}
235unsafe impl Sync for MipmappedArrayInner {}
236
237impl core::fmt::Debug for MipmappedArray {
238 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
239 f.debug_struct("MipmappedArray")
240 .field("handle", &self.inner.handle)
241 .finish()
242 }
243}
244
245impl MipmappedArray {
246 pub fn new(
248 desc: &cudaChannelFormatDesc,
249 extent: cudaExtent,
250 num_levels: u32,
251 flags: u32,
252 ) -> Result<Self> {
253 let r = runtime()?;
254 let cu = r.cuda_malloc_mipmapped_array()?;
255 let mut h: cudaMipmappedArray_t = core::ptr::null_mut();
256 check(unsafe {
257 cu(
258 &mut h,
259 desc as *const cudaChannelFormatDesc as *const c_void,
260 &extent as *const cudaExtent as *const c_void,
261 num_levels,
262 flags,
263 )
264 })?;
265 Ok(Self {
266 inner: Arc::new(MipmappedArrayInner { handle: h }),
267 })
268 }
269
270 #[inline]
272 pub fn as_raw(&self) -> cudaMipmappedArray_t {
273 self.inner.handle
274 }
275
276 pub fn level(&self, level: u32) -> Result<cudaArray_t> {
279 let r = runtime()?;
280 let cu = r.cuda_get_mipmapped_array_level()?;
281 let mut out: cudaArray_t = core::ptr::null_mut();
282 check(unsafe { cu(&mut out, self.inner.handle, level) })?;
283 Ok(out)
284 }
285}
286
287impl Drop for MipmappedArrayInner {
288 fn drop(&mut self) {
289 if let Ok(r) = runtime() {
290 if let Ok(cu) = r.cuda_free_mipmapped_array() {
291 let _ = unsafe { cu(self.handle) };
292 }
293 }
294 }
295}
296
297pub struct TextureObject {
300 handle: cudaTextureObject_t,
301 _backing: Option<Array>,
303}
304
305impl core::fmt::Debug for TextureObject {
306 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
307 f.debug_struct("TextureObject")
308 .field("handle", &self.handle)
309 .finish()
310 }
311}
312
313impl TextureObject {
314 pub fn new(
316 array: &Array,
317 tex_desc: &cudaTextureDesc,
318 view_desc: Option<&cudaResourceViewDesc>,
319 ) -> Result<Self> {
320 let res_desc = cudaResourceDesc::from_array(array.as_raw());
321 let r = runtime()?;
322 let cu = r.cuda_create_texture_object()?;
323 let mut obj: cudaTextureObject_t = 0;
324 let view_ptr = view_desc
325 .map(|v| v as *const cudaResourceViewDesc as *const c_void)
326 .unwrap_or(core::ptr::null());
327 check(unsafe {
328 cu(
329 &mut obj,
330 &res_desc as *const cudaResourceDesc as *const c_void,
331 tex_desc as *const cudaTextureDesc as *const c_void,
332 view_ptr,
333 )
334 })?;
335 Ok(Self {
336 handle: obj,
337 _backing: Some(array.clone()),
338 })
339 }
340
341 pub unsafe fn from_resource(
348 res_desc: &cudaResourceDesc,
349 tex_desc: &cudaTextureDesc,
350 view_desc: Option<&cudaResourceViewDesc>,
351 ) -> Result<Self> { unsafe {
352 let r = runtime()?;
353 let cu = r.cuda_create_texture_object()?;
354 let mut obj: cudaTextureObject_t = 0;
355 let view_ptr = view_desc
356 .map(|v| v as *const cudaResourceViewDesc as *const c_void)
357 .unwrap_or(core::ptr::null());
358 check(cu(
359 &mut obj,
360 res_desc as *const cudaResourceDesc as *const c_void,
361 tex_desc as *const cudaTextureDesc as *const c_void,
362 view_ptr,
363 ))?;
364 Ok(Self {
365 handle: obj,
366 _backing: None,
367 })
368 }}
369
370 #[inline]
372 pub fn as_raw(&self) -> cudaTextureObject_t {
373 self.handle
374 }
375
376 pub fn resource_desc(&self) -> Result<cudaResourceDesc> {
378 let r = runtime()?;
379 let cu = r.cuda_get_texture_object_resource_desc()?;
380 let mut d = cudaResourceDesc::default();
381 check(unsafe { cu(&mut d as *mut cudaResourceDesc as *mut c_void, self.handle) })?;
382 Ok(d)
383 }
384
385 pub fn texture_desc(&self) -> Result<cudaTextureDesc> {
387 let r = runtime()?;
388 let cu = r.cuda_get_texture_object_texture_desc()?;
389 let mut d = cudaTextureDesc::default();
390 check(unsafe { cu(&mut d as *mut cudaTextureDesc as *mut c_void, self.handle) })?;
391 Ok(d)
392 }
393}
394
395impl Drop for TextureObject {
396 fn drop(&mut self) {
397 if let Ok(r) = runtime() {
398 if let Ok(cu) = r.cuda_destroy_texture_object() {
399 let _ = unsafe { cu(self.handle) };
400 }
401 }
402 }
403}
404
405pub struct SurfaceObject {
407 handle: cudaSurfaceObject_t,
408 _backing: Option<Array>,
409}
410
411impl core::fmt::Debug for SurfaceObject {
412 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
413 f.debug_struct("SurfaceObject")
414 .field("handle", &self.handle)
415 .finish()
416 }
417}
418
419impl SurfaceObject {
420 pub fn new(array: &Array) -> Result<Self> {
422 let res_desc = cudaResourceDesc::from_array(array.as_raw());
423 let r = runtime()?;
424 let cu = r.cuda_create_surface_object()?;
425 let mut obj: cudaSurfaceObject_t = 0;
426 check(unsafe {
427 cu(
428 &mut obj,
429 &res_desc as *const cudaResourceDesc as *const c_void,
430 )
431 })?;
432 Ok(Self {
433 handle: obj,
434 _backing: Some(array.clone()),
435 })
436 }
437
438 #[inline]
440 pub fn as_raw(&self) -> cudaSurfaceObject_t {
441 self.handle
442 }
443
444 pub fn resource_desc(&self) -> Result<cudaResourceDesc> {
446 let r = runtime()?;
447 let cu = r.cuda_get_surface_object_resource_desc()?;
448 let mut d = cudaResourceDesc::default();
449 check(unsafe { cu(&mut d as *mut cudaResourceDesc as *mut c_void, self.handle) })?;
450 Ok(d)
451 }
452}
453
454impl Drop for SurfaceObject {
455 fn drop(&mut self) {
456 if let Ok(r) = runtime() {
457 if let Ok(cu) = r.cuda_destroy_surface_object() {
458 let _ = unsafe { cu(self.handle) };
459 }
460 }
461 }
462}