use std::sync::Arc;
use cudarc::driver::{CudaContext, CudaSlice, CudaStream, DevicePtrMut, DriverError};
use nvtiff_sys::{
nvtiffDecode, nvtiffDecodeCheckSupported, nvtiffDecodeParams, nvtiffDecodeParamsCreate,
nvtiffDecodeParamsSetRegions, nvtiffDecodeRegion, nvtiffDecoder, nvtiffDecoderCreateSimple,
nvtiffImage, nvtiffStatus, nvtiffStream, nvtiffStreamGetNextIFDOffset,
nvtiffStreamOpenFromFile,
};
#[test]
fn decode_image() -> Result<(), DriverError> {
let mut host_stream = std::mem::MaybeUninit::uninit();
let mut tiff_stream: *mut nvtiffStream = host_stream.as_mut_ptr();
let ctx: Arc<CudaContext> = cudarc::driver::CudaContext::new(0)?; let stream: Arc<CudaStream> = ctx.default_stream();
let cuda_stream: *mut nvtiff_sys::CUstream_st = stream.cu_stream().cast::<_>();
let mut decoder_handle = std::mem::MaybeUninit::uninit();
let mut nvtiff_decoder: *mut nvtiffDecoder = decoder_handle.as_mut_ptr();
let status_decoder: u32 =
unsafe { nvtiffDecoderCreateSimple(&raw mut nvtiff_decoder, cuda_stream) };
dbg!(status_decoder);
assert_eq!(status_decoder, nvtiffStatus::NVTIFF_STATUS_SUCCESS);
let tiff_cstr = std::ffi::CString::new("images/float32.tif").expect("CString::new failed");
let tiff_path: *const std::os::raw::c_char = tiff_cstr.as_ptr();
let status_parse: u32 = unsafe { nvtiffStreamOpenFromFile(tiff_path, &raw mut tiff_stream) };
dbg!(status_parse);
assert_eq!(status_parse, nvtiffStatus::NVTIFF_STATUS_SUCCESS);
let mut params = std::mem::MaybeUninit::uninit();
let mut decode_params: *mut nvtiffDecodeParams = params.as_mut_ptr();
let status_param: u32 = unsafe { nvtiffDecodeParamsCreate(&raw mut decode_params) };
dbg!(status_param);
assert_eq!(status_param, nvtiffStatus::NVTIFF_STATUS_SUCCESS);
let image_size: usize = 3 * 2 * 4; let mut image_stream: CudaSlice<u8> = stream.alloc_zeros::<u8>(image_size)?;
let image_ptr: u64 = image_stream.device_ptr_mut(&stream).0;
let mut plane_data = image_ptr as *mut std::ffi::c_void;
let mut image_out = nvtiffImage {
plane_data: &raw mut plane_data,
plane_pitch_bytes: &mut 0,
num_planes: 1,
};
let status_check: u32 = unsafe {
nvtiffDecodeCheckSupported(
tiff_stream,
nvtiff_decoder,
decode_params,
&raw const image_out,
)
};
dbg!(status_check);
assert_eq!(status_check, nvtiffStatus::NVTIFF_STATUS_SUCCESS);
let status_decode: u32 = unsafe {
nvtiffDecode(
tiff_stream,
nvtiff_decoder,
decode_params,
&raw mut image_out,
cuda_stream,
)
};
dbg!(status_decode); assert_eq!(status_decode, nvtiffStatus::NVTIFF_STATUS_SUCCESS);
let mut image_out_h: Vec<u8> = vec![0; image_size];
stream.memcpy_dtoh(&image_stream, &mut image_out_h)?;
dbg!(image_out_h.clone());
let float_array: Vec<f32> = image_out_h
.chunks_exact(4)
.map(TryInto::try_into)
.map(Result::unwrap)
.map(f32::from_le_bytes)
.collect();
assert_eq!(float_array, vec![1.41, 1.23, 0.78, 0.32, -0.23, -1.88]);
Ok(())
}
#[test]
fn decode_region() -> Result<(), DriverError> {
let mut host_stream = std::mem::MaybeUninit::uninit();
let mut tiff_stream: *mut nvtiffStream = host_stream.as_mut_ptr();
let ctx: Arc<CudaContext> = cudarc::driver::CudaContext::new(0)?; let stream: Arc<CudaStream> = ctx.default_stream();
let cuda_stream: *mut nvtiff_sys::CUstream_st = stream.cu_stream().cast::<_>();
let mut decoder_handle = std::mem::MaybeUninit::uninit();
let mut nvtiff_decoder: *mut nvtiffDecoder = decoder_handle.as_mut_ptr();
let status_decoder: u32 =
unsafe { nvtiffDecoderCreateSimple(&raw mut nvtiff_decoder, cuda_stream) };
dbg!(status_decoder);
assert_eq!(status_decoder, nvtiffStatus::NVTIFF_STATUS_SUCCESS);
let tiff_cstr = std::ffi::CString::new("images/cog_dateline.tif").expect("CString::new failed");
let tiff_path: *const std::os::raw::c_char = tiff_cstr.as_ptr();
let status_parse: u32 = unsafe { nvtiffStreamOpenFromFile(tiff_path, &raw mut tiff_stream) };
dbg!(status_parse);
assert_eq!(status_parse, nvtiffStatus::NVTIFF_STATUS_SUCCESS);
let mut params = std::mem::MaybeUninit::uninit();
let mut decode_params: *mut nvtiffDecodeParams = params.as_mut_ptr();
let status_param: u32 = unsafe { nvtiffDecodeParamsCreate(&raw mut decode_params) };
dbg!(status_param);
assert_eq!(status_param, nvtiffStatus::NVTIFF_STATUS_SUCCESS);
let mut ifd_offset: usize = 0; let status_nextifdoffset: u32 =
unsafe { nvtiffStreamGetNextIFDOffset(tiff_stream, ifd_offset, &raw mut ifd_offset) };
dbg!(status_nextifdoffset);
assert_eq!(status_nextifdoffset, nvtiffStatus::NVTIFF_STATUS_SUCCESS);
assert_eq!(ifd_offset, 568);
let region = nvtiffDecodeRegion {
ifd_offset,
offset_x: 423,
offset_y: 390,
width: 4,
height: 3,
};
let status_region: u32 =
unsafe { nvtiffDecodeParamsSetRegions(decode_params, &raw const region, 1) };
dbg!(status_region); assert_eq!(status_region, nvtiffStatus::NVTIFF_STATUS_SUCCESS);
let image_size: usize = 4 * 3 * 2; let mut image_stream: CudaSlice<u8> = stream.alloc_zeros::<u8>(image_size)?;
let image_ptr: u64 = image_stream.device_ptr_mut(&stream).0;
let mut plane_data = image_ptr as *mut std::ffi::c_void;
let mut image_out = nvtiffImage {
plane_data: &raw mut plane_data,
plane_pitch_bytes: &mut 0,
num_planes: 1,
};
let status_check: u32 = unsafe {
nvtiffDecodeCheckSupported(
tiff_stream,
nvtiff_decoder,
decode_params,
&raw const image_out,
)
};
dbg!(status_check);
assert_eq!(status_check, nvtiffStatus::NVTIFF_STATUS_SUCCESS);
let status_decode: u32 = unsafe {
nvtiffDecode(
tiff_stream,
nvtiff_decoder,
decode_params,
&raw mut image_out,
cuda_stream,
)
};
dbg!(status_decode); assert_eq!(status_decode, nvtiffStatus::NVTIFF_STATUS_SUCCESS);
let mut image_out_h: Vec<u8> = vec![0; image_size];
stream.memcpy_dtoh(&image_stream, &mut image_out_h)?;
let uint_array: Vec<u16> = image_out_h
.chunks_exact(2)
.map(TryInto::try_into)
.map(Result::unwrap)
.map(u16::from_le_bytes)
.collect();
assert_eq!(
uint_array,
vec![
22280, 22280, 22280, 22280, 21890, 22280, 22280, 21952, 21890, 21952, 21952, 21952
]
);
Ok(())
}