1use core::fmt;
6use core::marker::PhantomData;
7
8use j2k_core::{BackendKind, DeviceMemoryRange};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum ResidentHandoffError {
13 EmptyRange,
15 OffsetOverflow,
17 RangeExceedsAllocation,
19 BackendMismatch {
21 expected: BackendKind,
23 actual: BackendKind,
25 },
26 ZeroDimension,
28 ZeroSampling,
30 InvalidBitDepth,
32 ZeroByteStride,
34 LayoutExceedsBuffer,
36 CodestreamExceedsCapacity,
38}
39
40impl fmt::Display for ResidentHandoffError {
41 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42 match self {
43 Self::EmptyRange => f.write_str("resident buffer range is empty"),
44 Self::OffsetOverflow => f.write_str("resident buffer range offset overflows"),
45 Self::RangeExceedsAllocation => {
46 f.write_str("resident buffer range exceeds allocation length")
47 }
48 Self::BackendMismatch { expected, actual } => write!(
49 f,
50 "resident buffer backend mismatch: expected {expected:?}, got {actual:?}"
51 ),
52 Self::ZeroDimension => f.write_str("resident component dimensions must be nonzero"),
53 Self::ZeroSampling => f.write_str("resident component sampling must be nonzero"),
54 Self::InvalidBitDepth => f.write_str("resident sample bit depth must be 1..=32"),
55 Self::ZeroByteStride => f.write_str("resident byte stride must be nonzero"),
56 Self::LayoutExceedsBuffer => f.write_str("resident row layout exceeds buffer range"),
57 Self::CodestreamExceedsCapacity => {
58 f.write_str("resident codestream byte length exceeds buffer capacity")
59 }
60 }
61 }
62}
63
64impl std::error::Error for ResidentHandoffError {}
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq)]
68pub struct ResidentBufferRef<'a> {
69 memory: DeviceMemoryRange,
70 _lifetime: PhantomData<&'a ()>,
71}
72
73impl ResidentBufferRef<'_> {
74 pub fn new(memory: DeviceMemoryRange) -> Result<Self, ResidentHandoffError> {
76 if memory.len == 0 {
77 return Err(ResidentHandoffError::EmptyRange);
78 }
79 memory
80 .offset
81 .checked_add(memory.len)
82 .ok_or(ResidentHandoffError::OffsetOverflow)?;
83 Ok(Self {
84 memory,
85 _lifetime: PhantomData,
86 })
87 }
88
89 pub fn with_allocation_len(
91 memory: DeviceMemoryRange,
92 allocation_len: usize,
93 ) -> Result<Self, ResidentHandoffError> {
94 let buffer = Self::new(memory)?;
95 let end = memory
96 .offset
97 .checked_add(memory.len)
98 .ok_or(ResidentHandoffError::OffsetOverflow)?;
99 if end > allocation_len {
100 return Err(ResidentHandoffError::RangeExceedsAllocation);
101 }
102 Ok(buffer)
103 }
104
105 pub const fn memory_range(&self) -> DeviceMemoryRange {
107 self.memory
108 }
109
110 pub const fn backend(&self) -> BackendKind {
112 self.memory.backend
113 }
114
115 pub const fn byte_len(&self) -> usize {
117 self.memory.len
118 }
119
120 fn require_backend(self, backend: BackendKind) -> Result<Self, ResidentHandoffError> {
121 if self.memory.backend == backend {
122 Ok(self)
123 } else {
124 Err(ResidentHandoffError::BackendMismatch {
125 expected: backend,
126 actual: self.memory.backend,
127 })
128 }
129 }
130}
131
132#[derive(Debug, Clone, Copy, PartialEq, Eq)]
134pub struct ResidentSampling {
135 pub x_rsiz: u8,
137 pub y_rsiz: u8,
139}
140
141impl ResidentSampling {
142 pub const fn new(x_rsiz: u8, y_rsiz: u8) -> Result<Self, ResidentHandoffError> {
144 if x_rsiz == 0 || y_rsiz == 0 {
145 return Err(ResidentHandoffError::ZeroSampling);
146 }
147 Ok(Self { x_rsiz, y_rsiz })
148 }
149}
150
151#[derive(Debug, Clone, Copy, PartialEq, Eq)]
153pub struct ResidentSampleInfo {
154 pub bit_depth: u8,
156 pub signed: bool,
158}
159
160impl ResidentSampleInfo {
161 pub const fn new(bit_depth: u8, signed: bool) -> Result<Self, ResidentHandoffError> {
163 if bit_depth == 0 || bit_depth > 32 {
164 return Err(ResidentHandoffError::InvalidBitDepth);
165 }
166 Ok(Self { bit_depth, signed })
167 }
168}
169
170#[derive(Debug, Clone, Copy, PartialEq, Eq)]
172pub enum ResidentColorModel {
173 Unknown,
175 Grayscale,
177 Rgb,
179 YCbCr,
181 Rgba,
183}
184
185#[derive(Debug, Clone, Copy, PartialEq, Eq)]
187pub struct ResidentComponentGeometry {
188 pub component_index: usize,
190 pub width: u32,
192 pub height: u32,
194 pub sampling: ResidentSampling,
196}
197
198impl ResidentComponentGeometry {
199 pub const fn new(
201 component_index: usize,
202 width: u32,
203 height: u32,
204 sampling: ResidentSampling,
205 ) -> Result<Self, ResidentHandoffError> {
206 if width == 0 || height == 0 {
207 return Err(ResidentHandoffError::ZeroDimension);
208 }
209 Ok(Self {
210 component_index,
211 width,
212 height,
213 sampling,
214 })
215 }
216}
217
218#[derive(Debug, Clone, Copy, PartialEq, Eq)]
220pub enum ResidentDctCoefficientOrder {
221 Natural,
223 ZigZag,
225}
226
227#[derive(Debug, Clone, Copy, PartialEq, Eq)]
229pub struct ResidentJpegDctGrid<'a> {
230 pub buffer: ResidentBufferRef<'a>,
232 pub component: ResidentComponentGeometry,
234 pub sample: ResidentSampleInfo,
236 pub color: ResidentColorModel,
238 pub block_cols: u32,
240 pub block_rows: u32,
242 pub row_pitch_bytes: usize,
244 pub bytes_per_coefficient: usize,
246 pub coefficient_order: ResidentDctCoefficientOrder,
248}
249
250impl<'a> ResidentJpegDctGrid<'a> {
251 pub fn new(
253 buffer: ResidentBufferRef<'a>,
254 component: ResidentComponentGeometry,
255 sample: ResidentSampleInfo,
256 color: ResidentColorModel,
257 layout: ResidentDctGridLayout,
258 ) -> Result<Self, ResidentHandoffError> {
259 if layout.block_cols == 0 || layout.block_rows == 0 {
260 return Err(ResidentHandoffError::ZeroDimension);
261 }
262 if layout.row_pitch_bytes == 0 || layout.bytes_per_coefficient == 0 {
263 return Err(ResidentHandoffError::ZeroByteStride);
264 }
265 let row_coefficients = usize::try_from(layout.block_cols)
266 .ok()
267 .and_then(|cols| cols.checked_mul(64))
268 .ok_or(ResidentHandoffError::OffsetOverflow)?;
269 validate_row_layout_fits_buffer(
270 buffer,
271 row_coefficients,
272 layout.block_rows,
273 layout.row_pitch_bytes,
274 layout.bytes_per_coefficient,
275 )?;
276 Ok(Self {
277 buffer,
278 component,
279 sample,
280 color,
281 block_cols: layout.block_cols,
282 block_rows: layout.block_rows,
283 row_pitch_bytes: layout.row_pitch_bytes,
284 bytes_per_coefficient: layout.bytes_per_coefficient,
285 coefficient_order: layout.coefficient_order,
286 })
287 }
288
289 pub fn require_backend(self, backend: BackendKind) -> Result<Self, ResidentHandoffError> {
291 self.buffer.require_backend(backend)?;
292 Ok(self)
293 }
294}
295
296#[derive(Debug, Clone, Copy, PartialEq, Eq)]
298pub struct ResidentDctGridLayout {
299 pub block_cols: u32,
301 pub block_rows: u32,
303 pub row_pitch_bytes: usize,
305 pub bytes_per_coefficient: usize,
307 pub coefficient_order: ResidentDctCoefficientOrder,
309}
310
311#[derive(Debug, Clone, Copy, PartialEq, Eq)]
313pub enum ResidentDwtSubbandKind {
314 LowLow,
316 HighLow,
318 LowHigh,
320 HighHigh,
322}
323
324#[derive(Debug, Clone, Copy, PartialEq, Eq)]
326pub struct ResidentDwtSubband<'a> {
327 pub buffer: ResidentBufferRef<'a>,
329 pub component: ResidentComponentGeometry,
331 pub sample: ResidentSampleInfo,
333 pub color: ResidentColorModel,
335 pub level: u8,
337 pub subband: ResidentDwtSubbandKind,
339 pub width: u32,
341 pub height: u32,
343 pub row_pitch_bytes: usize,
345 pub bytes_per_coefficient: usize,
347}
348
349impl<'a> ResidentDwtSubband<'a> {
350 pub fn new(
352 buffer: ResidentBufferRef<'a>,
353 component: ResidentComponentGeometry,
354 sample: ResidentSampleInfo,
355 color: ResidentColorModel,
356 layout: ResidentDwtSubbandLayout,
357 ) -> Result<Self, ResidentHandoffError> {
358 if layout.width == 0 || layout.height == 0 {
359 return Err(ResidentHandoffError::ZeroDimension);
360 }
361 if layout.row_pitch_bytes == 0 || layout.bytes_per_coefficient == 0 {
362 return Err(ResidentHandoffError::ZeroByteStride);
363 }
364 validate_row_layout_fits_buffer(
365 buffer,
366 usize::try_from(layout.width).map_err(|_| ResidentHandoffError::OffsetOverflow)?,
367 layout.height,
368 layout.row_pitch_bytes,
369 layout.bytes_per_coefficient,
370 )?;
371 Ok(Self {
372 buffer,
373 component,
374 sample,
375 color,
376 level: layout.level,
377 subband: layout.subband,
378 width: layout.width,
379 height: layout.height,
380 row_pitch_bytes: layout.row_pitch_bytes,
381 bytes_per_coefficient: layout.bytes_per_coefficient,
382 })
383 }
384
385 pub fn require_backend(self, backend: BackendKind) -> Result<Self, ResidentHandoffError> {
387 self.buffer.require_backend(backend)?;
388 Ok(self)
389 }
390}
391
392fn validate_row_layout_fits_buffer(
393 buffer: ResidentBufferRef<'_>,
394 row_values: usize,
395 rows: u32,
396 row_pitch_bytes: usize,
397 bytes_per_value: usize,
398) -> Result<(), ResidentHandoffError> {
399 let row_bytes = row_values
400 .checked_mul(bytes_per_value)
401 .ok_or(ResidentHandoffError::OffsetOverflow)?;
402 if row_pitch_bytes < row_bytes {
403 return Err(ResidentHandoffError::LayoutExceedsBuffer);
404 }
405 let rows = usize::try_from(rows).map_err(|_| ResidentHandoffError::OffsetOverflow)?;
406 let last_row_offset = rows
407 .saturating_sub(1)
408 .checked_mul(row_pitch_bytes)
409 .ok_or(ResidentHandoffError::OffsetOverflow)?;
410 let required_len = last_row_offset
411 .checked_add(row_bytes)
412 .ok_or(ResidentHandoffError::OffsetOverflow)?;
413 if required_len > buffer.byte_len() {
414 return Err(ResidentHandoffError::LayoutExceedsBuffer);
415 }
416 Ok(())
417}
418
419#[derive(Debug, Clone, Copy, PartialEq, Eq)]
421pub struct ResidentDwtSubbandLayout {
422 pub level: u8,
424 pub subband: ResidentDwtSubbandKind,
426 pub width: u32,
428 pub height: u32,
430 pub row_pitch_bytes: usize,
432 pub bytes_per_coefficient: usize,
434}
435
436#[derive(Debug, Clone, Copy, PartialEq, Eq)]
438pub struct ResidentCodestreamBuffer<'a> {
439 pub buffer: ResidentBufferRef<'a>,
441 pub byte_len: usize,
443 pub capacity: usize,
445}
446
447impl<'a> ResidentCodestreamBuffer<'a> {
448 pub fn new(
450 buffer: ResidentBufferRef<'a>,
451 byte_len: usize,
452 capacity: usize,
453 ) -> Result<Self, ResidentHandoffError> {
454 if byte_len > capacity || capacity > buffer.byte_len() {
455 return Err(ResidentHandoffError::CodestreamExceedsCapacity);
456 }
457 Ok(Self {
458 buffer,
459 byte_len,
460 capacity,
461 })
462 }
463
464 pub fn require_backend(self, backend: BackendKind) -> Result<Self, ResidentHandoffError> {
466 self.buffer.require_backend(backend)?;
467 Ok(self)
468 }
469}