use std::sync::Arc;
use crate::{
error::CudaError,
execution::{CudaExecutionStats, CudaLaunchMode},
kernels::CudaKernel,
memory::{pooled_device_buffer, CudaDeviceBuffer, CudaPooledDeviceBuffer},
};
use super::output_regions::ValidatedHtj2kOutputLayout;
#[doc(hidden)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct CudaHtj2kCodeBlockJob {
pub payload_offset: u64,
pub width: u32,
pub height: u32,
pub payload_len: u32,
pub cleanup_length: u32,
pub refinement_length: u32,
pub missing_bit_planes: u8,
pub num_bitplanes: u8,
pub number_of_coding_passes: u8,
pub output_stride: u32,
pub output_offset: u32,
pub dequantization_step: f32,
pub stripe_causal: bool,
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub(crate) struct CudaHtj2kCodeBlockKernelJob {
pub(crate) coded_offset: u32,
pub(crate) width: u32,
pub(crate) height: u32,
pub(crate) coded_len: u32,
pub(crate) cleanup_length: u32,
pub(crate) refinement_length: u32,
pub(crate) missing_msbs: u32,
pub(crate) num_bitplanes: u32,
pub(crate) number_of_coding_passes: u32,
pub(crate) output_stride: u32,
pub(crate) output_offset: u32,
pub(crate) dequantization_step: f32,
pub(crate) stripe_causal: u32,
}
#[doc(hidden)]
#[derive(Clone, Copy, Debug)]
pub struct CudaHtj2kCleanupTarget<'a> {
pub coefficients: &'a CudaDeviceBuffer,
pub jobs: &'a [CudaHtj2kCodeBlockJob],
pub output_words: usize,
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub(crate) struct CudaHtj2kCleanupMultiKernelJob {
pub(crate) output_ptr: u64,
pub(crate) coded_offset: u32,
pub(crate) width: u32,
pub(crate) height: u32,
pub(crate) coded_len: u32,
pub(crate) cleanup_length: u32,
pub(crate) refinement_length: u32,
pub(crate) missing_msbs: u32,
pub(crate) num_bitplanes: u32,
pub(crate) number_of_coding_passes: u32,
pub(crate) output_stride: u32,
pub(crate) output_offset: u32,
pub(crate) dequantization_step: f32,
pub(crate) stripe_causal: u32,
pub(crate) reserved_tail: u32,
}
#[doc(hidden)]
#[derive(Clone, Copy, Debug)]
pub struct CudaHtj2kDequantizeTarget<'a> {
pub coefficients: &'a CudaDeviceBuffer,
pub jobs: &'a [CudaHtj2kCodeBlockJob],
pub output_words: usize,
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub(crate) struct CudaHtj2kDequantizeKernelJob {
pub(crate) output_ptr: u64,
pub(crate) width: u32,
pub(crate) height: u32,
pub(crate) output_stride: u32,
pub(crate) output_offset: u32,
pub(crate) num_bitplanes: u32,
pub(crate) reserved: u32,
pub(crate) dequantization_step: f32,
pub(crate) reserved_tail: u32,
}
#[doc(hidden)]
#[derive(Clone, Copy, Debug)]
pub struct CudaHtj2kDecodeTables<'a> {
pub vlc_table0: &'a [u16; 1024],
pub vlc_table1: &'a [u16; 1024],
pub uvlc_table0: &'a [u16; 320],
pub uvlc_table1: &'a [u16; 256],
}
#[doc(hidden)]
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct CudaHtj2kStatus {
pub code: u32,
pub detail: u32,
pub reserved0: u32,
pub reserved1: u32,
}
impl CudaHtj2kStatus {
pub fn is_ok(self) -> bool {
self.code == HTJ2K_STATUS_OK
}
}
#[doc(hidden)]
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct CudaHtj2kDecodeStageTimings {
pub ht_cleanup_us: u128,
pub ht_refine_us: u128,
pub dequant_us: u128,
pub status_d2h_us: u128,
}
#[doc(hidden)]
#[derive(Debug)]
pub struct CudaHtj2kDecodeOutput {
pub(crate) coefficients: CudaDeviceBuffer,
pub(crate) execution: CudaExecutionStats,
pub(crate) statuses: Vec<CudaHtj2kStatus>,
pub(crate) stage_timings: CudaHtj2kDecodeStageTimings,
}
impl CudaHtj2kDecodeOutput {
pub fn coefficients(&self) -> &CudaDeviceBuffer {
&self.coefficients
}
pub fn execution(&self) -> CudaExecutionStats {
self.execution
}
pub fn statuses(&self) -> &[CudaHtj2kStatus] {
&self.statuses
}
pub fn stage_timings(&self) -> CudaHtj2kDecodeStageTimings {
self.stage_timings
}
pub fn into_parts(self) -> (CudaDeviceBuffer, CudaExecutionStats, Vec<CudaHtj2kStatus>) {
(self.coefficients, self.execution, self.statuses)
}
}
#[doc(hidden)]
#[derive(Debug)]
pub struct CudaPooledHtj2kDecodeOutput {
pub(crate) coefficients: CudaPooledDeviceBuffer,
pub(crate) execution: CudaExecutionStats,
pub(crate) statuses: Vec<CudaHtj2kStatus>,
pub(crate) stage_timings: CudaHtj2kDecodeStageTimings,
}
impl CudaPooledHtj2kDecodeOutput {
pub fn coefficients(&self) -> Option<&CudaDeviceBuffer> {
self.coefficients.as_device_buffer()
}
pub fn execution(&self) -> CudaExecutionStats {
self.execution
}
pub fn statuses(&self) -> &[CudaHtj2kStatus] {
&self.statuses
}
pub fn stage_timings(&self) -> CudaHtj2kDecodeStageTimings {
self.stage_timings
}
pub fn into_parts(
self,
) -> (
CudaPooledDeviceBuffer,
CudaExecutionStats,
Vec<CudaHtj2kStatus>,
) {
(self.coefficients, self.execution, self.statuses)
}
}
#[doc(hidden)]
#[derive(Clone, Debug)]
pub struct CudaHtj2kDecodeTableResources {
pub(crate) inner: Arc<CudaHtj2kDecodeTableResourceInner>,
}
#[derive(Debug)]
pub(crate) struct CudaHtj2kDecodeTableResourceInner {
pub(crate) vlc_table0: CudaDeviceBuffer,
pub(crate) vlc_table1: CudaDeviceBuffer,
pub(crate) uvlc_table0: CudaDeviceBuffer,
pub(crate) uvlc_table1: CudaDeviceBuffer,
}
#[doc(hidden)]
#[derive(Debug)]
pub struct CudaHtj2kDecodeResources {
pub(crate) payload: CudaHtj2kDecodePayload,
pub(crate) payload_len: usize,
pub(crate) tables: Option<CudaHtj2kDecodeTableResources>,
}
#[derive(Debug)]
pub(crate) enum CudaHtj2kDecodePayload {
Owned(CudaDeviceBuffer),
Pooled(CudaPooledDeviceBuffer),
}
#[derive(Clone, Copy)]
pub(super) struct Htj2kDecodeKernelTables<'a> {
pub(super) vlc_table0: &'a CudaDeviceBuffer,
pub(super) vlc_table1: &'a CudaDeviceBuffer,
pub(super) uvlc_table0: &'a CudaDeviceBuffer,
pub(super) uvlc_table1: &'a CudaDeviceBuffer,
}
#[derive(Clone, Copy)]
pub(super) struct Htj2kDecodeCodeblocksLaunch<'a> {
pub(super) payload: &'a CudaDeviceBuffer,
pub(super) coefficients: &'a CudaDeviceBuffer,
pub(super) jobs: &'a CudaDeviceBuffer,
pub(super) tables: Htj2kDecodeKernelTables<'a>,
pub(super) statuses: &'a CudaDeviceBuffer,
pub(super) job_count: usize,
pub(super) mode: CudaLaunchMode,
}
#[derive(Clone, Copy)]
pub(super) struct Htj2kDecodeCodeblocksMultiLaunch<'a> {
pub(super) kernel: CudaKernel,
pub(super) payload: &'a CudaDeviceBuffer,
pub(super) jobs: &'a CudaDeviceBuffer,
pub(super) tables: Htj2kDecodeKernelTables<'a>,
pub(super) statuses: &'a CudaDeviceBuffer,
pub(super) job_count: usize,
pub(super) mode: CudaLaunchMode,
}
pub(super) struct ValidatedHtj2kKernelJobs {
pub(super) jobs: Vec<CudaHtj2kCodeBlockKernelJob>,
pub(super) output_layout: ValidatedHtj2kOutputLayout,
}
impl CudaHtj2kDecodePayload {
pub(crate) fn buffer(&self) -> Result<&CudaDeviceBuffer, CudaError> {
match self {
Self::Owned(buffer) => Ok(buffer),
Self::Pooled(buffer) => pooled_device_buffer(buffer),
}
}
}
pub(super) fn htj2k_decode_kernel_tables(
resources: &CudaHtj2kDecodeResources,
) -> Result<Htj2kDecodeKernelTables<'_>, CudaError> {
let tables = resources
.tables
.as_ref()
.ok_or_else(|| CudaError::InvalidArgument {
message: "HTJ2K decode requires resident lookup tables".to_string(),
})?;
Ok(Htj2kDecodeKernelTables {
vlc_table0: &tables.inner.vlc_table0,
vlc_table1: &tables.inner.vlc_table1,
uvlc_table0: &tables.inner.uvlc_table0,
uvlc_table1: &tables.inner.uvlc_table1,
})
}
pub(crate) const HTJ2K_STATUS_OK: u32 = 0;
pub(crate) const HTJ2K_STATUS_UNSUPPORTED: u32 = 2;