use std::ffi::CStr;
use gpufft_cuda_sys as sys;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum CudaError {
#[error("no CUDA-capable device found")]
NoDevice,
#[error("device index {requested} out of range (device count: {count})")]
DeviceOutOfRange {
requested: i32,
count: i32,
},
#[error("CUDA runtime error: {context}: {message} (code {code})")]
Runtime {
context: &'static str,
code: i32,
message: String,
},
#[error("cuFFT error: {context}: {code}")]
CuFft {
context: &'static str,
code: u32,
},
#[error("length mismatch: expected {expected} elements, got {got}")]
LengthMismatch {
expected: usize,
got: usize,
},
#[error("invalid plan: {0}")]
InvalidPlan(&'static str),
#[error(
"PlanDesc::normalize = true is not yet implemented in the CUDA \
backend. Scale on the host after C2R, or use the Vulkan backend."
)]
UnsupportedNormalize,
}
impl CudaError {
pub(crate) fn runtime(context: &'static str, code: sys::cudaError_t) -> Self {
Self::Runtime {
context,
code: code as i32,
message: cuda_error_string(code),
}
}
pub(crate) fn cufft(context: &'static str, code: sys::cufftResult) -> Self {
Self::CuFft { context, code }
}
}
fn cuda_error_string(code: sys::cudaError_t) -> String {
unsafe {
let ptr = sys::cudaGetErrorString(code);
if ptr.is_null() {
return format!("cuda error {code:?}");
}
CStr::from_ptr(ptr).to_string_lossy().into_owned()
}
}
pub(crate) fn check_cuda(context: &'static str, code: sys::cudaError_t) -> Result<(), CudaError> {
if code == sys::cudaError_cudaSuccess {
Ok(())
} else {
Err(CudaError::runtime(context, code))
}
}
pub(crate) fn check_cufft(context: &'static str, code: sys::cufftResult) -> Result<(), CudaError> {
if code == sys::cufftResult_t_CUFFT_SUCCESS {
Ok(())
} else {
Err(CudaError::cufft(context, code))
}
}