Skip to main content

j2k_cuda/encode/
resident.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3use std::time::Duration;
4
5use j2k_core::{BackendKind, DeviceSubmission, PixelFormat, ReadySubmission};
6use j2k_cuda_runtime::CudaDeviceBuffer;
7
8use crate::runtime::cuda_error;
9
10use super::CudaEncodeStageTimings;
11
12/// CUDA-resident lossless J2K/HTJ2K encode input tile.
13#[derive(Debug, Clone, Copy)]
14pub struct CudaLosslessEncodeTile<'a> {
15    /// Source CUDA buffer containing interleaved Gray/RGB/RGBA pixels.
16    pub buffer: &'a CudaDeviceBuffer,
17    /// Byte offset of the first source pixel in `buffer`.
18    pub byte_offset: usize,
19    /// Width of the valid input region in pixels.
20    pub width: u32,
21    /// Height of the valid input region in pixels.
22    pub height: u32,
23    /// Number of bytes between consecutive input rows.
24    pub pitch_bytes: usize,
25    /// Encoded image width in pixels.
26    pub output_width: u32,
27    /// Encoded image height in pixels.
28    pub output_height: u32,
29    /// Pixel format of the source buffer.
30    pub format: PixelFormat,
31}
32
33/// Residency decisions used by a lossless CUDA device-buffer encode.
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub struct CudaLosslessEncodeResidency {
36    /// Whether coefficient preparation ran on CUDA.
37    pub coefficient_prep_used: bool,
38    /// Whether packetization ran on CUDA.
39    pub packetization_used: bool,
40    /// Whether final codestream assembly stayed resident on CUDA.
41    pub codestream_assembly_used: bool,
42}
43
44/// Lossless CUDA device-buffer encode output with host codestream bytes and timings.
45#[derive(Debug, Clone, PartialEq, Eq)]
46#[doc(hidden)]
47pub struct CudaLosslessEncodeOutcome {
48    /// Encoded J2K codestream.
49    pub encoded: j2k::EncodedJ2k,
50    /// Whether the input buffer had to be copied or padded.
51    pub input_copy_used: bool,
52    /// Residency decisions for encode stages.
53    pub resident: CudaLosslessEncodeResidency,
54    /// Time spent copying or padding input.
55    pub input_copy_duration: Duration,
56    /// End-to-end encode duration for this tile.
57    pub encode_duration: Duration,
58    /// GPU-only duration when timestamp data is available.
59    pub gpu_duration: Option<Duration>,
60    /// Time spent validating encoded output.
61    pub validation_duration: Duration,
62    /// Time spent materializing CUDA output into host codestream bytes.
63    pub host_readback_duration: Duration,
64    /// CUDA encode stage timing buckets collected for this tile.
65    pub stage_timings: CudaEncodeStageTimings,
66}
67
68/// CUDA-resident copy of codestream bytes returned by a CUDA lossless encode.
69#[derive(Debug)]
70pub struct CudaResidentCodestreamBuffer {
71    pub(super) buffer: CudaDeviceBuffer,
72    pub(super) byte_len: usize,
73}
74
75impl CudaResidentCodestreamBuffer {
76    /// CUDA buffer containing the codestream bytes.
77    pub fn buffer(&self) -> &CudaDeviceBuffer {
78        &self.buffer
79    }
80
81    /// Codestream byte length.
82    pub fn byte_len(&self) -> usize {
83        self.byte_len
84    }
85
86    /// Download the resident codestream bytes.
87    pub fn download(&self) -> Result<Vec<u8>, crate::Error> {
88        let mut bytes = crate::allocation::try_vec_filled(
89            self.byte_len,
90            0u8,
91            "CUDA-resident j2k codestream download",
92        )?;
93        self.buffer.copy_to_host(&mut bytes).map_err(cuda_error)?;
94        Ok(bytes)
95    }
96
97    /// Consume this value and return the owned CUDA buffer.
98    pub fn into_buffer(self) -> CudaDeviceBuffer {
99        self.buffer
100    }
101}
102
103/// Host-visible metadata for a CUDA-resident encoded J2K codestream.
104#[derive(Debug, Clone, Copy, PartialEq, Eq)]
105pub struct CudaEncodedJ2kMetadata {
106    /// Backend that satisfied the encode contract.
107    pub backend: BackendKind,
108    /// Encode-stage dispatches observed while producing the codestream.
109    pub dispatch_report: j2k::J2kEncodeDispatchReport,
110    /// Encoded image width in pixels.
111    pub width: u32,
112    /// Encoded image height in pixels.
113    pub height: u32,
114    /// Encoded component count.
115    pub components: u16,
116    /// Encoded significant bits per sample.
117    pub bit_depth: u8,
118    /// Whether encoded samples are signed.
119    pub signed: bool,
120}
121
122impl CudaEncodedJ2kMetadata {
123    pub(super) fn from_host_encoded(encoded: &j2k::EncodedJ2k) -> Self {
124        Self {
125            backend: encoded.backend,
126            dispatch_report: encoded.dispatch_report,
127            width: encoded.width,
128            height: encoded.height,
129            components: encoded.components,
130            bit_depth: encoded.bit_depth,
131            signed: encoded.signed,
132        }
133    }
134}
135
136/// CUDA lossless encode output with host metadata and CUDA-resident codestream bytes.
137///
138/// The final codestream is assembled in host memory today, copied to this
139/// device buffer, and then released from host memory before this value is
140/// returned. `CudaEncodedJ2k` therefore does not retain a duplicate host
141/// codestream. This is a device-resident output contract, not a claim that
142/// final codestream assembly itself ran on CUDA.
143#[derive(Debug)]
144pub struct CudaEncodedJ2k {
145    /// Host-visible encode metadata without codestream bytes.
146    pub metadata: CudaEncodedJ2kMetadata,
147    /// CUDA-resident copy of the codestream bytes.
148    pub codestream: CudaResidentCodestreamBuffer,
149}
150
151impl CudaEncodedJ2k {
152    /// Borrow the host-visible encoded J2K metadata.
153    pub fn metadata(&self) -> &CudaEncodedJ2kMetadata {
154        &self.metadata
155    }
156
157    /// Borrow the CUDA-resident codestream buffer.
158    pub fn codestream(&self) -> &CudaResidentCodestreamBuffer {
159        &self.codestream
160    }
161
162    /// Consume this value and return host metadata plus the CUDA-resident buffer.
163    pub fn into_parts(self) -> (CudaEncodedJ2kMetadata, CudaResidentCodestreamBuffer) {
164        (self.metadata, self.codestream)
165    }
166}
167
168/// Lossless CUDA device-buffer encode output with CUDA-resident codestream bytes.
169#[derive(Debug)]
170#[doc(hidden)]
171pub struct CudaLosslessBufferEncodeOutcome {
172    /// CUDA-resident encoded J2K output.
173    pub encoded: CudaEncodedJ2k,
174    /// Whether the input buffer had to be copied or padded.
175    pub input_copy_used: bool,
176    /// Residency decisions for encode stages.
177    pub resident: CudaLosslessEncodeResidency,
178    /// Time spent copying or padding input.
179    pub input_copy_duration: Duration,
180    /// End-to-end encode duration for this tile.
181    pub encode_duration: Duration,
182    /// GPU-only duration when timestamp data is available.
183    pub gpu_duration: Option<Duration>,
184    /// Time spent validating encoded output.
185    pub validation_duration: Duration,
186    /// Time spent materializing CUDA output into host codestream bytes.
187    pub host_readback_duration: Duration,
188    /// CUDA encode stage timing buckets collected for this tile.
189    pub stage_timings: CudaEncodeStageTimings,
190    /// Time spent uploading codestream bytes into the resident CUDA buffer.
191    pub codestream_upload_duration: Duration,
192}
193
194/// Submitted single-tile CUDA lossless encode.
195#[derive(Debug)]
196pub struct SubmittedJ2kLosslessCudaEncode {
197    pub(super) inner: ReadySubmission<j2k::EncodedJ2k, crate::Error>,
198}
199
200/// Submitted multi-tile CUDA lossless encode.
201#[derive(Debug)]
202pub struct SubmittedJ2kLosslessCudaEncodeBatch {
203    pub(super) inner: ReadySubmission<Vec<j2k::EncodedJ2k>, crate::Error>,
204}
205
206#[doc(hidden)]
207impl DeviceSubmission for SubmittedJ2kLosslessCudaEncode {
208    type Output = j2k::EncodedJ2k;
209    type Error = crate::Error;
210
211    fn wait(self) -> Result<Self::Output, Self::Error> {
212        self.inner.wait()
213    }
214}
215
216#[doc(hidden)]
217impl DeviceSubmission for SubmittedJ2kLosslessCudaEncodeBatch {
218    type Output = Vec<j2k::EncodedJ2k>;
219    type Error = crate::Error;
220
221    fn wait(self) -> Result<Self::Output, Self::Error> {
222        self.inner.wait()
223    }
224}