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]
166 pub fn as_raw(&self) -> cudaArray_t {
167 self.inner.handle
168 }
169
170 #[inline]
171 pub fn width(&self) -> usize {
172 self.inner.width
173 }
174 #[inline]
175 pub fn height(&self) -> usize {
176 self.inner.height
177 }
178 #[inline]
179 pub fn depth(&self) -> usize {
180 self.inner.depth
181 }
182 #[inline]
183 pub fn desc(&self) -> &cudaChannelFormatDesc {
184 &self.inner.desc
185 }
186
187 pub fn info(&self) -> Result<(cudaChannelFormatDesc, cudaExtent, u32)> {
189 let r = runtime()?;
190 let cu = r.cuda_array_get_info()?;
191 let mut desc = cudaChannelFormatDesc::default();
192 let mut extent = cudaExtent::default();
193 let mut flags: core::ffi::c_uint = 0;
194 check(unsafe {
195 cu(
196 &mut desc as *mut cudaChannelFormatDesc as *mut c_void,
197 &mut extent as *mut cudaExtent as *mut c_void,
198 &mut flags,
199 self.inner.handle,
200 )
201 })?;
202 Ok((desc, extent, flags))
203 }
204}
205
206impl Drop for ArrayInner {
207 fn drop(&mut self) {
208 if self.handle.is_null() {
209 return;
210 }
211 if let Ok(r) = runtime() {
212 if let Ok(cu) = r.cuda_free_array() {
213 let _ = unsafe { cu(self.handle) };
214 }
215 }
216 }
217}
218
219#[derive(Clone)]
221pub struct MipmappedArray {
222 inner: Arc<MipmappedArrayInner>,
223}
224
225struct MipmappedArrayInner {
226 handle: cudaMipmappedArray_t,
227}
228
229unsafe impl Send for MipmappedArrayInner {}
230unsafe impl Sync for MipmappedArrayInner {}
231
232impl core::fmt::Debug for MipmappedArray {
233 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
234 f.debug_struct("MipmappedArray")
235 .field("handle", &self.inner.handle)
236 .finish()
237 }
238}
239
240impl MipmappedArray {
241 pub fn new(
243 desc: &cudaChannelFormatDesc,
244 extent: cudaExtent,
245 num_levels: u32,
246 flags: u32,
247 ) -> Result<Self> {
248 let r = runtime()?;
249 let cu = r.cuda_malloc_mipmapped_array()?;
250 let mut h: cudaMipmappedArray_t = core::ptr::null_mut();
251 check(unsafe {
252 cu(
253 &mut h,
254 desc as *const cudaChannelFormatDesc as *const c_void,
255 &extent as *const cudaExtent as *const c_void,
256 num_levels,
257 flags,
258 )
259 })?;
260 Ok(Self {
261 inner: Arc::new(MipmappedArrayInner { handle: h }),
262 })
263 }
264
265 #[inline]
266 pub fn as_raw(&self) -> cudaMipmappedArray_t {
267 self.inner.handle
268 }
269
270 pub fn level(&self, level: u32) -> Result<cudaArray_t> {
273 let r = runtime()?;
274 let cu = r.cuda_get_mipmapped_array_level()?;
275 let mut out: cudaArray_t = core::ptr::null_mut();
276 check(unsafe { cu(&mut out, self.inner.handle, level) })?;
277 Ok(out)
278 }
279}
280
281impl Drop for MipmappedArrayInner {
282 fn drop(&mut self) {
283 if let Ok(r) = runtime() {
284 if let Ok(cu) = r.cuda_free_mipmapped_array() {
285 let _ = unsafe { cu(self.handle) };
286 }
287 }
288 }
289}
290
291pub struct TextureObject {
294 handle: cudaTextureObject_t,
295 _backing: Option<Array>,
297}
298
299impl core::fmt::Debug for TextureObject {
300 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
301 f.debug_struct("TextureObject")
302 .field("handle", &self.handle)
303 .finish()
304 }
305}
306
307impl TextureObject {
308 pub fn new(
310 array: &Array,
311 tex_desc: &cudaTextureDesc,
312 view_desc: Option<&cudaResourceViewDesc>,
313 ) -> Result<Self> {
314 let res_desc = cudaResourceDesc::from_array(array.as_raw());
315 let r = runtime()?;
316 let cu = r.cuda_create_texture_object()?;
317 let mut obj: cudaTextureObject_t = 0;
318 let view_ptr = view_desc
319 .map(|v| v as *const cudaResourceViewDesc as *const c_void)
320 .unwrap_or(core::ptr::null());
321 check(unsafe {
322 cu(
323 &mut obj,
324 &res_desc as *const cudaResourceDesc as *const c_void,
325 tex_desc as *const cudaTextureDesc as *const c_void,
326 view_ptr,
327 )
328 })?;
329 Ok(Self {
330 handle: obj,
331 _backing: Some(array.clone()),
332 })
333 }
334
335 pub unsafe fn from_resource(
342 res_desc: &cudaResourceDesc,
343 tex_desc: &cudaTextureDesc,
344 view_desc: Option<&cudaResourceViewDesc>,
345 ) -> Result<Self> {
346 let r = runtime()?;
347 let cu = r.cuda_create_texture_object()?;
348 let mut obj: cudaTextureObject_t = 0;
349 let view_ptr = view_desc
350 .map(|v| v as *const cudaResourceViewDesc as *const c_void)
351 .unwrap_or(core::ptr::null());
352 check(cu(
353 &mut obj,
354 res_desc as *const cudaResourceDesc as *const c_void,
355 tex_desc as *const cudaTextureDesc as *const c_void,
356 view_ptr,
357 ))?;
358 Ok(Self {
359 handle: obj,
360 _backing: None,
361 })
362 }
363
364 #[inline]
365 pub fn as_raw(&self) -> cudaTextureObject_t {
366 self.handle
367 }
368
369 pub fn resource_desc(&self) -> Result<cudaResourceDesc> {
371 let r = runtime()?;
372 let cu = r.cuda_get_texture_object_resource_desc()?;
373 let mut d = cudaResourceDesc::default();
374 check(unsafe { cu(&mut d as *mut cudaResourceDesc as *mut c_void, self.handle) })?;
375 Ok(d)
376 }
377
378 pub fn texture_desc(&self) -> Result<cudaTextureDesc> {
380 let r = runtime()?;
381 let cu = r.cuda_get_texture_object_texture_desc()?;
382 let mut d = cudaTextureDesc::default();
383 check(unsafe { cu(&mut d as *mut cudaTextureDesc as *mut c_void, self.handle) })?;
384 Ok(d)
385 }
386}
387
388impl Drop for TextureObject {
389 fn drop(&mut self) {
390 if let Ok(r) = runtime() {
391 if let Ok(cu) = r.cuda_destroy_texture_object() {
392 let _ = unsafe { cu(self.handle) };
393 }
394 }
395 }
396}
397
398pub struct SurfaceObject {
400 handle: cudaSurfaceObject_t,
401 _backing: Option<Array>,
402}
403
404impl core::fmt::Debug for SurfaceObject {
405 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
406 f.debug_struct("SurfaceObject")
407 .field("handle", &self.handle)
408 .finish()
409 }
410}
411
412impl SurfaceObject {
413 pub fn new(array: &Array) -> Result<Self> {
415 let res_desc = cudaResourceDesc::from_array(array.as_raw());
416 let r = runtime()?;
417 let cu = r.cuda_create_surface_object()?;
418 let mut obj: cudaSurfaceObject_t = 0;
419 check(unsafe {
420 cu(
421 &mut obj,
422 &res_desc as *const cudaResourceDesc as *const c_void,
423 )
424 })?;
425 Ok(Self {
426 handle: obj,
427 _backing: Some(array.clone()),
428 })
429 }
430
431 #[inline]
432 pub fn as_raw(&self) -> cudaSurfaceObject_t {
433 self.handle
434 }
435
436 pub fn resource_desc(&self) -> Result<cudaResourceDesc> {
438 let r = runtime()?;
439 let cu = r.cuda_get_surface_object_resource_desc()?;
440 let mut d = cudaResourceDesc::default();
441 check(unsafe { cu(&mut d as *mut cudaResourceDesc as *mut c_void, self.handle) })?;
442 Ok(d)
443 }
444}
445
446impl Drop for SurfaceObject {
447 fn drop(&mut self) {
448 if let Ok(r) = runtime() {
449 if let Ok(cu) = r.cuda_destroy_surface_object() {
450 let _ = unsafe { cu(self.handle) };
451 }
452 }
453 }
454}