1#![allow(non_camel_case_types, non_snake_case, non_upper_case_globals)]
8#![warn(missing_debug_implementations)]
9
10use core::ffi::c_int;
11use std::sync::OnceLock;
12
13use baracuda_core::{platform, Library, LoaderError};
14use baracuda_cuda_sys::runtime::cudaStream_t;
15use baracuda_types::CudaStatus;
16
17pub type cufftHandle = c_int;
19
20pub const CUFFT_FORWARD: c_int = -1;
22pub const CUFFT_INVERSE: c_int = 1;
24
25#[repr(i32)]
27#[derive(Copy, Clone, Debug, Eq, PartialEq)]
28pub enum cufftType {
29 R2C = 0x2A,
31 C2R = 0x2C,
33 C2C = 0x29,
35 D2Z = 0x6A,
37 Z2D = 0x6C,
39 Z2Z = 0x69,
41}
42
43#[repr(C)]
46#[derive(Copy, Clone, Debug, Default, PartialEq)]
47pub struct cufftComplex {
48 pub x: f32,
50 pub y: f32,
52}
53
54#[repr(C)]
56#[derive(Copy, Clone, Debug, Default, PartialEq)]
57pub struct cufftDoubleComplex {
58 pub x: f64,
60 pub y: f64,
62}
63
64#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
66#[repr(transparent)]
67pub struct cufftResult(pub i32);
68
69impl cufftResult {
70 pub const SUCCESS: Self = Self(0);
72 pub const INVALID_PLAN: Self = Self(1);
74 pub const ALLOC_FAILED: Self = Self(2);
76 pub const INVALID_TYPE: Self = Self(3);
78 pub const INVALID_VALUE: Self = Self(4);
80 pub const INTERNAL_ERROR: Self = Self(5);
82 pub const EXEC_FAILED: Self = Self(6);
84 pub const SETUP_FAILED: Self = Self(7);
86 pub const INVALID_SIZE: Self = Self(8);
88 pub const UNALIGNED_DATA: Self = Self(9);
90 pub const INVALID_DEVICE: Self = Self(11);
92 pub const NOT_IMPLEMENTED: Self = Self(14);
94 pub const NOT_SUPPORTED: Self = Self(16);
96
97 pub const fn is_success(self) -> bool {
99 self.0 == 0
100 }
101}
102
103impl CudaStatus for cufftResult {
104 fn code(self) -> i32 {
105 self.0
106 }
107 fn name(self) -> &'static str {
108 match self.0 {
109 0 => "CUFFT_SUCCESS",
110 1 => "CUFFT_INVALID_PLAN",
111 2 => "CUFFT_ALLOC_FAILED",
112 3 => "CUFFT_INVALID_TYPE",
113 4 => "CUFFT_INVALID_VALUE",
114 5 => "CUFFT_INTERNAL_ERROR",
115 6 => "CUFFT_EXEC_FAILED",
116 7 => "CUFFT_SETUP_FAILED",
117 8 => "CUFFT_INVALID_SIZE",
118 9 => "CUFFT_UNALIGNED_DATA",
119 11 => "CUFFT_INVALID_DEVICE",
120 14 => "CUFFT_NOT_IMPLEMENTED",
121 16 => "CUFFT_NOT_SUPPORTED",
122 _ => "CUFFT_ERROR_UNRECOGNIZED",
123 }
124 }
125 fn description(self) -> &'static str {
126 match self.0 {
127 0 => "success",
128 1 => "invalid plan handle",
129 2 => "allocation failed",
130 4 => "invalid argument",
131 6 => "transform execution failed",
132 8 => "invalid transform size",
133 9 => "misaligned data",
134 14 => "feature not implemented in this version",
135 16 => "feature not supported on the target device",
136 _ => "unrecognized cuFFT status code",
137 }
138 }
139 fn is_success(self) -> bool {
140 cufftResult::is_success(self)
141 }
142 fn library(self) -> &'static str {
143 "cufft"
144 }
145}
146
147pub type PFN_cufftCreate = unsafe extern "C" fn(plan: *mut cufftHandle) -> cufftResult;
151pub type PFN_cufftDestroy = unsafe extern "C" fn(plan: cufftHandle) -> cufftResult;
153pub type PFN_cufftPlan1d = unsafe extern "C" fn(
155 plan: *mut cufftHandle,
156 nx: c_int,
157 ty: cufftType,
158 batch: c_int,
159) -> cufftResult;
160pub type PFN_cufftPlan2d = unsafe extern "C" fn(
162 plan: *mut cufftHandle,
163 nx: c_int,
164 ny: c_int,
165 ty: cufftType,
166) -> cufftResult;
167pub type PFN_cufftPlan3d = unsafe extern "C" fn(
169 plan: *mut cufftHandle,
170 nx: c_int,
171 ny: c_int,
172 nz: c_int,
173 ty: cufftType,
174) -> cufftResult;
175pub type PFN_cufftSetStream =
177 unsafe extern "C" fn(plan: cufftHandle, stream: cudaStream_t) -> cufftResult;
178pub type PFN_cufftGetVersion = unsafe extern "C" fn(version: *mut c_int) -> cufftResult;
180
181pub type PFN_cufftExecR2C = unsafe extern "C" fn(
183 plan: cufftHandle,
184 input: *mut f32,
185 output: *mut cufftComplex,
186) -> cufftResult;
187pub type PFN_cufftExecC2R = unsafe extern "C" fn(
189 plan: cufftHandle,
190 input: *mut cufftComplex,
191 output: *mut f32,
192) -> cufftResult;
193pub type PFN_cufftExecC2C = unsafe extern "C" fn(
195 plan: cufftHandle,
196 input: *mut cufftComplex,
197 output: *mut cufftComplex,
198 direction: c_int,
199) -> cufftResult;
200
201pub type PFN_cufftExecD2Z = unsafe extern "C" fn(
205 plan: cufftHandle,
206 input: *mut f64,
207 output: *mut cufftDoubleComplex,
208) -> cufftResult;
209
210pub type PFN_cufftExecZ2D = unsafe extern "C" fn(
212 plan: cufftHandle,
213 input: *mut cufftDoubleComplex,
214 output: *mut f64,
215) -> cufftResult;
216
217pub type PFN_cufftExecZ2Z = unsafe extern "C" fn(
219 plan: cufftHandle,
220 input: *mut cufftDoubleComplex,
221 output: *mut cufftDoubleComplex,
222 direction: c_int,
223) -> cufftResult;
224
225pub type PFN_cufftPlanMany = unsafe extern "C" fn(
229 plan: *mut cufftHandle,
230 rank: c_int,
231 n: *mut c_int,
232 inembed: *mut c_int,
233 istride: c_int,
234 idist: c_int,
235 onembed: *mut c_int,
236 ostride: c_int,
237 odist: c_int,
238 ty: cufftType,
239 batch: c_int,
240) -> cufftResult;
241
242pub type PFN_cufftMakePlan1d = unsafe extern "C" fn(
244 plan: cufftHandle,
245 nx: c_int,
246 ty: cufftType,
247 batch: c_int,
248 work_size: *mut usize,
249) -> cufftResult;
250
251pub type PFN_cufftMakePlan2d = unsafe extern "C" fn(
253 plan: cufftHandle,
254 nx: c_int,
255 ny: c_int,
256 ty: cufftType,
257 work_size: *mut usize,
258) -> cufftResult;
259
260pub type PFN_cufftMakePlan3d = unsafe extern "C" fn(
262 plan: cufftHandle,
263 nx: c_int,
264 ny: c_int,
265 nz: c_int,
266 ty: cufftType,
267 work_size: *mut usize,
268) -> cufftResult;
269
270pub type PFN_cufftMakePlanMany = unsafe extern "C" fn(
272 plan: cufftHandle,
273 rank: c_int,
274 n: *mut c_int,
275 inembed: *mut c_int,
276 istride: c_int,
277 idist: c_int,
278 onembed: *mut c_int,
279 ostride: c_int,
280 odist: c_int,
281 ty: cufftType,
282 batch: c_int,
283 work_size: *mut usize,
284) -> cufftResult;
285
286pub type PFN_cufftMakePlanMany64 = unsafe extern "C" fn(
288 plan: cufftHandle,
289 rank: c_int,
290 n: *mut i64,
291 inembed: *mut i64,
292 istride: i64,
293 idist: i64,
294 onembed: *mut i64,
295 ostride: i64,
296 odist: i64,
297 ty: cufftType,
298 batch: i64,
299 work_size: *mut usize,
300) -> cufftResult;
301
302pub type PFN_cufftEstimate1d = unsafe extern "C" fn(
304 nx: c_int,
305 ty: cufftType,
306 batch: c_int,
307 work_size: *mut usize,
308) -> cufftResult;
309
310pub type PFN_cufftEstimate2d = unsafe extern "C" fn(
312 nx: c_int,
313 ny: c_int,
314 ty: cufftType,
315 work_size: *mut usize,
316) -> cufftResult;
317
318pub type PFN_cufftEstimate3d = unsafe extern "C" fn(
320 nx: c_int,
321 ny: c_int,
322 nz: c_int,
323 ty: cufftType,
324 work_size: *mut usize,
325) -> cufftResult;
326
327pub type PFN_cufftEstimateMany = unsafe extern "C" fn(
329 rank: c_int,
330 n: *mut c_int,
331 inembed: *mut c_int,
332 istride: c_int,
333 idist: c_int,
334 onembed: *mut c_int,
335 ostride: c_int,
336 odist: c_int,
337 ty: cufftType,
338 batch: c_int,
339 work_size: *mut usize,
340) -> cufftResult;
341
342pub type PFN_cufftGetSize1d = unsafe extern "C" fn(
344 plan: cufftHandle,
345 nx: c_int,
346 ty: cufftType,
347 batch: c_int,
348 work_size: *mut usize,
349) -> cufftResult;
350
351pub type PFN_cufftGetSize = unsafe extern "C" fn(plan: cufftHandle, work_size: *mut usize) -> cufftResult;
353
354pub type PFN_cufftSetWorkArea = unsafe extern "C" fn(
358 plan: cufftHandle,
359 work_area: *mut core::ffi::c_void,
360) -> cufftResult;
361
362pub type PFN_cufftSetAutoAllocation =
364 unsafe extern "C" fn(plan: cufftHandle, auto_allocate: c_int) -> cufftResult;
365
366pub type PFN_cufftGetProperty =
370 unsafe extern "C" fn(prop: c_int, value_out: *mut c_int) -> cufftResult;
371
372pub type PFN_cufftXtSetGPUs =
376 unsafe extern "C" fn(plan: cufftHandle, n: c_int, which_gpus: *mut c_int) -> cufftResult;
377
378pub type PFN_cufftXtMakePlanMany = unsafe extern "C" fn(
380 plan: cufftHandle,
381 rank: c_int,
382 n: *mut i64,
383 inembed: *mut i64,
384 istride: i64,
385 idist: i64,
386 input_type: cudaDataType,
387 onembed: *mut i64,
388 ostride: i64,
389 odist: i64,
390 output_type: cudaDataType,
391 batch: i64,
392 work_size: *mut usize,
393 execution_type: cudaDataType,
394) -> cufftResult;
395
396pub type PFN_cufftXtMalloc = unsafe extern "C" fn(
398 plan: cufftHandle,
399 desc_out: *mut *mut core::ffi::c_void, subformat: c_int,
401) -> cufftResult;
402
403pub type PFN_cufftXtFree = unsafe extern "C" fn(desc: *mut core::ffi::c_void) -> cufftResult;
405
406pub type PFN_cufftXtMemcpy = unsafe extern "C" fn(
408 plan: cufftHandle,
409 dst: *mut core::ffi::c_void,
410 src: *mut core::ffi::c_void,
411 ty: c_int, ) -> cufftResult;
413
414pub type PFN_cufftXtExec = unsafe extern "C" fn(
416 plan: cufftHandle,
417 input: *mut core::ffi::c_void,
418 output: *mut core::ffi::c_void,
419 direction: c_int,
420) -> cufftResult;
421
422pub type PFN_cufftXtExecDescriptor = unsafe extern "C" fn(
424 plan: cufftHandle,
425 input: *mut core::ffi::c_void,
426 output: *mut core::ffi::c_void,
427 direction: c_int,
428) -> cufftResult;
429
430pub type PFN_cufftXtQueryPlan = unsafe extern "C" fn(
432 plan: cufftHandle,
433 query_struct: *mut core::ffi::c_void,
434 query_type: c_int,
435) -> cufftResult;
436
437pub type PFN_cufftXtSetCallback = unsafe extern "C" fn(
439 plan: cufftHandle,
440 callback_routine: *mut *mut core::ffi::c_void,
441 cb_type: c_int,
442 caller_info: *mut *mut core::ffi::c_void,
443) -> cufftResult;
444
445pub type PFN_cufftXtClearCallback =
447 unsafe extern "C" fn(plan: cufftHandle, cb_type: c_int) -> cufftResult;
448
449pub type PFN_cufftXtSetCallbackSharedSize = unsafe extern "C" fn(
451 plan: cufftHandle,
452 cb_type: c_int,
453 shared_size: usize,
454) -> cufftResult;
455
456pub type cudaDataType = c_int;
460
461fn cufft_candidates() -> Vec<String> {
464 platform::versioned_library_candidates("cufft", &["13", "12", "11"])
465}
466
467macro_rules! cufft_fns {
468 ($($name:ident as $sym:literal : $pfn:ty);* $(;)?) => {
469 pub struct Cufft {
471 lib: Library,
472 $($name: OnceLock<$pfn>,)*
473 }
474 impl core::fmt::Debug for Cufft {
475 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
476 f.debug_struct("Cufft").field("lib", &self.lib).finish_non_exhaustive()
477 }
478 }
479 impl Cufft {
480 $(
481 pub fn $name(&self) -> Result<$pfn, LoaderError> {
483 if let Some(&p) = self.$name.get() { return Ok(p); }
484 let raw: *mut () = unsafe { self.lib.raw_symbol($sym)? };
485 let p: $pfn = unsafe { core::mem::transmute_copy::<*mut (), $pfn>(&raw) };
486 let _ = self.$name.set(p);
487 Ok(p)
488 }
489 )*
490 fn empty(lib: Library) -> Self {
491 Self { lib, $($name: OnceLock::new(),)* }
492 }
493 }
494 };
495}
496
497cufft_fns! {
498 cufft_create as "cufftCreate": PFN_cufftCreate;
500 cufft_destroy as "cufftDestroy": PFN_cufftDestroy;
501 cufft_plan_1d as "cufftPlan1d": PFN_cufftPlan1d;
502 cufft_plan_2d as "cufftPlan2d": PFN_cufftPlan2d;
503 cufft_plan_3d as "cufftPlan3d": PFN_cufftPlan3d;
504 cufft_plan_many as "cufftPlanMany": PFN_cufftPlanMany;
505 cufft_make_plan_1d as "cufftMakePlan1d": PFN_cufftMakePlan1d;
506 cufft_make_plan_2d as "cufftMakePlan2d": PFN_cufftMakePlan2d;
507 cufft_make_plan_3d as "cufftMakePlan3d": PFN_cufftMakePlan3d;
508 cufft_make_plan_many as "cufftMakePlanMany": PFN_cufftMakePlanMany;
509 cufft_make_plan_many64 as "cufftMakePlanMany64": PFN_cufftMakePlanMany64;
510
511 cufft_estimate_1d as "cufftEstimate1d": PFN_cufftEstimate1d;
513 cufft_estimate_2d as "cufftEstimate2d": PFN_cufftEstimate2d;
514 cufft_estimate_3d as "cufftEstimate3d": PFN_cufftEstimate3d;
515 cufft_estimate_many as "cufftEstimateMany": PFN_cufftEstimateMany;
516 cufft_get_size_1d as "cufftGetSize1d": PFN_cufftGetSize1d;
517 cufft_get_size as "cufftGetSize": PFN_cufftGetSize;
518
519 cufft_set_work_area as "cufftSetWorkArea": PFN_cufftSetWorkArea;
521 cufft_set_auto_allocation as "cufftSetAutoAllocation": PFN_cufftSetAutoAllocation;
522
523 cufft_set_stream as "cufftSetStream": PFN_cufftSetStream;
525
526 cufft_get_version as "cufftGetVersion": PFN_cufftGetVersion;
528 cufft_get_property as "cufftGetProperty": PFN_cufftGetProperty;
529
530 cufft_exec_r2c as "cufftExecR2C": PFN_cufftExecR2C;
532 cufft_exec_c2r as "cufftExecC2R": PFN_cufftExecC2R;
533 cufft_exec_c2c as "cufftExecC2C": PFN_cufftExecC2C;
534
535 cufft_exec_d2z as "cufftExecD2Z": PFN_cufftExecD2Z;
537 cufft_exec_z2d as "cufftExecZ2D": PFN_cufftExecZ2D;
538 cufft_exec_z2z as "cufftExecZ2Z": PFN_cufftExecZ2Z;
539
540 cufft_xt_set_gpus as "cufftXtSetGPUs": PFN_cufftXtSetGPUs;
542 cufft_xt_make_plan_many as "cufftXtMakePlanMany": PFN_cufftXtMakePlanMany;
543 cufft_xt_malloc as "cufftXtMalloc": PFN_cufftXtMalloc;
544 cufft_xt_free as "cufftXtFree": PFN_cufftXtFree;
545 cufft_xt_memcpy as "cufftXtMemcpy": PFN_cufftXtMemcpy;
546 cufft_xt_exec as "cufftXtExec": PFN_cufftXtExec;
547 cufft_xt_exec_descriptor as "cufftXtExecDescriptor": PFN_cufftXtExecDescriptor;
548 cufft_xt_query_plan as "cufftXtQueryPlan": PFN_cufftXtQueryPlan;
549
550 cufft_xt_set_callback as "cufftXtSetCallback": PFN_cufftXtSetCallback;
552 cufft_xt_clear_callback as "cufftXtClearCallback": PFN_cufftXtClearCallback;
553 cufft_xt_set_callback_shared_size as "cufftXtSetCallbackSharedSize":
554 PFN_cufftXtSetCallbackSharedSize;
555}
556
557pub fn cufft() -> Result<&'static Cufft, LoaderError> {
559 static CUFFT: OnceLock<Cufft> = OnceLock::new();
560 if let Some(c) = CUFFT.get() {
561 return Ok(c);
562 }
563 let candidates: Vec<&'static str> = cufft_candidates()
564 .into_iter()
565 .map(|s| Box::leak(s.into_boxed_str()) as &'static str)
566 .collect();
567 let candidates_leaked: &'static [&'static str] = Box::leak(candidates.into_boxed_slice());
568 let lib = Library::open("cufft", candidates_leaked)?;
569 let c = Cufft::empty(lib);
570 let _ = CUFFT.set(c);
571 Ok(CUFFT.get().expect("OnceLock set or lost race"))
572}