1use alloc::vec::Vec;
4
5use crate::{
6 accelerator::{DeviceMemoryRange, ExecutionStats, SurfaceResidency},
7 backend::{BackendKind, BackendRequest},
8 batch::{TileRegionScaledDecodeJob, TileRegionScaledDeviceDecodeRequest},
9 context::CodecContext,
10 error::CodecError,
11 pixel::PixelFormat,
12 row_sink::RowSink,
13 sample::Sample,
14 scale::Downscale,
15 scratch::ScratchPool,
16 types::{DecodeOutcome, Info, Rect},
17};
18
19#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
22pub enum DecodeRowsError<D, E>
23where
24 D: core::error::Error + 'static,
25 E: core::error::Error + 'static,
26{
27 #[error(transparent)]
28 Decode(D),
30 #[error(transparent)]
31 Sink(E),
33}
34
35pub trait ImageCodec {
37 type Error: CodecError;
39 type Warning: core::fmt::Debug + core::fmt::Display + Send + Sync + 'static;
41 type Pool: ScratchPool;
43}
44
45pub trait DeviceSurface {
47 fn backend_kind(&self) -> BackendKind;
49 fn residency(&self) -> SurfaceResidency {
51 SurfaceResidency::for_backend(self.backend_kind())
52 }
53 fn dimensions(&self) -> (u32, u32);
55 fn pixel_format(&self) -> PixelFormat;
57 fn byte_len(&self) -> usize;
59 fn execution_stats(&self) -> ExecutionStats {
61 ExecutionStats::default()
62 }
63 fn memory_range(&self) -> Option<DeviceMemoryRange> {
65 None
66 }
67}
68
69pub trait DeviceCodestream {
71 fn codestream_memory_range(&self) -> Option<DeviceMemoryRange>;
73 fn codestream_allocation_len(&self) -> Option<usize>;
75 fn codestream_byte_len(&self) -> usize;
77 fn codestream_capacity(&self) -> usize;
79}
80
81pub trait DeviceSubmission {
83 type Output;
85 type Error;
87
88 fn wait(self) -> Result<Self::Output, Self::Error>;
94}
95
96#[derive(Debug)]
98#[doc(hidden)]
99pub struct ReadySubmission<T, E>(Result<T, E>);
100
101impl<T, E> ReadySubmission<T, E> {
102 pub fn from_result(result: Result<T, E>) -> Self {
104 Self(result)
105 }
106}
107
108impl<T, E> DeviceSubmission for ReadySubmission<T, E> {
109 type Output = T;
110 type Error = E;
111
112 fn wait(self) -> Result<Self::Output, Self::Error> {
113 self.0
114 }
115}
116
117#[doc(hidden)]
119pub trait DeviceSubmitSession {
120 fn record_submit(&mut self);
122}
123
124#[doc(hidden)]
126pub fn submit_ready_device<S, T, E>(
127 session: &mut S,
128 submit: impl FnOnce(&mut S) -> Result<T, E>,
129) -> ReadySubmission<T, E>
130where
131 S: DeviceSubmitSession + ?Sized,
132{
133 session.record_submit();
134 ReadySubmission::from_result(submit(session))
135}
136
137pub trait ImageDecode<'a>: ImageCodec + Sized + 'a {
139 type View: 'a;
141
142 fn inspect(input: &'a [u8]) -> Result<Info, Self::Error>;
149 fn parse(input: &'a [u8]) -> Result<Self::View, Self::Error>;
156 fn from_view(view: Self::View) -> Result<Self, Self::Error>;
163
164 fn decode_into(
171 &mut self,
172 out: &mut [u8],
173 stride: usize,
174 fmt: PixelFormat,
175 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
176
177 fn decode_into_with_scratch(
184 &mut self,
185 pool: &mut Self::Pool,
186 out: &mut [u8],
187 stride: usize,
188 fmt: PixelFormat,
189 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
190
191 fn decode_region_into(
198 &mut self,
199 pool: &mut Self::Pool,
200 out: &mut [u8],
201 stride: usize,
202 fmt: PixelFormat,
203 roi: Rect,
204 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
205
206 fn decode_scaled_into(
213 &mut self,
214 pool: &mut Self::Pool,
215 out: &mut [u8],
216 stride: usize,
217 fmt: PixelFormat,
218 scale: Downscale,
219 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
220
221 fn decode_region_scaled_into(
228 &mut self,
229 pool: &mut Self::Pool,
230 out: &mut [u8],
231 stride: usize,
232 fmt: PixelFormat,
233 roi: Rect,
234 scale: Downscale,
235 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
236}
237
238#[doc(hidden)]
245pub trait CpuBackedImageDecode<'a>: ImageCodec + Sized + 'a {
246 type Cpu: ImageDecode<'a, Pool = Self::Pool>;
248 type View: 'a;
250
251 fn inspect_cpu(input: &'a [u8]) -> Result<Info, Self::Error>;
253 fn parse_cpu(input: &'a [u8]) -> Result<Self::View, Self::Error>;
255 fn from_cpu_view(view: Self::View) -> Result<Self, Self::Error>;
257 fn cpu_decoder_mut(&mut self) -> &mut Self::Cpu;
259 fn map_cpu_outcome(
261 outcome: DecodeOutcome<<Self::Cpu as ImageCodec>::Warning>,
262 ) -> DecodeOutcome<Self::Warning>;
263}
264
265#[doc(hidden)]
266impl<'a, T> ImageDecode<'a> for T
267where
268 T: CpuBackedImageDecode<'a>,
269 <T::Cpu as ImageCodec>::Error: Into<T::Error>,
270{
271 type View = T::View;
272
273 fn inspect(input: &'a [u8]) -> Result<Info, Self::Error> {
274 T::inspect_cpu(input)
275 }
276
277 fn parse(input: &'a [u8]) -> Result<Self::View, Self::Error> {
278 T::parse_cpu(input)
279 }
280
281 fn from_view(view: Self::View) -> Result<Self, Self::Error> {
282 T::from_cpu_view(view)
283 }
284
285 fn decode_into(
286 &mut self,
287 out: &mut [u8],
288 stride: usize,
289 fmt: PixelFormat,
290 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error> {
291 let outcome = self
292 .cpu_decoder_mut()
293 .decode_into(out, stride, fmt)
294 .map_err(Into::into)?;
295 Ok(T::map_cpu_outcome(outcome))
296 }
297
298 fn decode_into_with_scratch(
299 &mut self,
300 pool: &mut Self::Pool,
301 out: &mut [u8],
302 stride: usize,
303 fmt: PixelFormat,
304 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error> {
305 let outcome = self
306 .cpu_decoder_mut()
307 .decode_into_with_scratch(pool, out, stride, fmt)
308 .map_err(Into::into)?;
309 Ok(T::map_cpu_outcome(outcome))
310 }
311
312 fn decode_region_into(
313 &mut self,
314 pool: &mut Self::Pool,
315 out: &mut [u8],
316 stride: usize,
317 fmt: PixelFormat,
318 roi: Rect,
319 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error> {
320 let outcome = self
321 .cpu_decoder_mut()
322 .decode_region_into(pool, out, stride, fmt, roi)
323 .map_err(Into::into)?;
324 Ok(T::map_cpu_outcome(outcome))
325 }
326
327 fn decode_scaled_into(
328 &mut self,
329 pool: &mut Self::Pool,
330 out: &mut [u8],
331 stride: usize,
332 fmt: PixelFormat,
333 scale: Downscale,
334 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error> {
335 let outcome = self
336 .cpu_decoder_mut()
337 .decode_scaled_into(pool, out, stride, fmt, scale)
338 .map_err(Into::into)?;
339 Ok(T::map_cpu_outcome(outcome))
340 }
341
342 fn decode_region_scaled_into(
343 &mut self,
344 pool: &mut Self::Pool,
345 out: &mut [u8],
346 stride: usize,
347 fmt: PixelFormat,
348 roi: Rect,
349 scale: Downscale,
350 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error> {
351 let outcome = self
352 .cpu_decoder_mut()
353 .decode_region_scaled_into(pool, out, stride, fmt, roi, scale)
354 .map_err(Into::into)?;
355 Ok(T::map_cpu_outcome(outcome))
356 }
357}
358
359pub trait ImageDecodeSubmit<'a>: ImageDecode<'a> {
361 type Session: Default + Send;
363 type DeviceSurface: DeviceSurface;
365 type SubmittedSurface: DeviceSubmission<Output = Self::DeviceSurface, Error = Self::Error>;
367
368 fn submit_to_device(
375 &mut self,
376 session: &mut Self::Session,
377 fmt: PixelFormat,
378 backend: BackendRequest,
379 ) -> Result<Self::SubmittedSurface, Self::Error>;
380
381 fn submit_region_to_device(
388 &mut self,
389 session: &mut Self::Session,
390 fmt: PixelFormat,
391 roi: Rect,
392 backend: BackendRequest,
393 ) -> Result<Self::SubmittedSurface, Self::Error>;
394
395 fn submit_scaled_to_device(
402 &mut self,
403 session: &mut Self::Session,
404 fmt: PixelFormat,
405 scale: Downscale,
406 backend: BackendRequest,
407 ) -> Result<Self::SubmittedSurface, Self::Error>;
408
409 fn submit_region_scaled_to_device(
416 &mut self,
417 session: &mut Self::Session,
418 fmt: PixelFormat,
419 roi: Rect,
420 scale: Downscale,
421 backend: BackendRequest,
422 ) -> Result<Self::SubmittedSurface, Self::Error>;
423}
424
425pub trait ImageDecodeDevice<'a>: ImageDecode<'a> {
427 type DeviceSurface: DeviceSurface;
429
430 fn decode_to_device(
436 &mut self,
437 fmt: PixelFormat,
438 backend: BackendRequest,
439 ) -> Result<<Self as ImageDecodeDevice<'a>>::DeviceSurface, Self::Error>
440 where
441 Self: ImageDecodeSubmit<'a, DeviceSurface = <Self as ImageDecodeDevice<'a>>::DeviceSurface>,
442 {
443 let mut session = <Self as ImageDecodeSubmit<'a>>::Session::default();
444 <Self as ImageDecodeSubmit<'a>>::submit_to_device(self, &mut session, fmt, backend)?.wait()
445 }
446
447 fn decode_region_to_device(
454 &mut self,
455 fmt: PixelFormat,
456 roi: Rect,
457 backend: BackendRequest,
458 ) -> Result<<Self as ImageDecodeDevice<'a>>::DeviceSurface, Self::Error>
459 where
460 Self: ImageDecodeSubmit<'a, DeviceSurface = <Self as ImageDecodeDevice<'a>>::DeviceSurface>,
461 {
462 let mut session = <Self as ImageDecodeSubmit<'a>>::Session::default();
463 <Self as ImageDecodeSubmit<'a>>::submit_region_to_device(
464 self,
465 &mut session,
466 fmt,
467 roi,
468 backend,
469 )?
470 .wait()
471 }
472
473 fn decode_scaled_to_device(
480 &mut self,
481 fmt: PixelFormat,
482 scale: Downscale,
483 backend: BackendRequest,
484 ) -> Result<<Self as ImageDecodeDevice<'a>>::DeviceSurface, Self::Error>
485 where
486 Self: ImageDecodeSubmit<'a, DeviceSurface = <Self as ImageDecodeDevice<'a>>::DeviceSurface>,
487 {
488 let mut session = <Self as ImageDecodeSubmit<'a>>::Session::default();
489 <Self as ImageDecodeSubmit<'a>>::submit_scaled_to_device(
490 self,
491 &mut session,
492 fmt,
493 scale,
494 backend,
495 )?
496 .wait()
497 }
498
499 fn decode_region_scaled_to_device(
506 &mut self,
507 fmt: PixelFormat,
508 roi: Rect,
509 scale: Downscale,
510 backend: BackendRequest,
511 ) -> Result<<Self as ImageDecodeDevice<'a>>::DeviceSurface, Self::Error>
512 where
513 Self: ImageDecodeSubmit<'a, DeviceSurface = <Self as ImageDecodeDevice<'a>>::DeviceSurface>,
514 {
515 let mut session = <Self as ImageDecodeSubmit<'a>>::Session::default();
516 <Self as ImageDecodeSubmit<'a>>::submit_region_scaled_to_device(
517 self,
518 &mut session,
519 fmt,
520 roi,
521 scale,
522 backend,
523 )?
524 .wait()
525 }
526}
527
528pub trait ImageDecodeRows<'a, S: Sample>: ImageDecode<'a> {
530 #[expect(
537 clippy::type_complexity,
538 reason = "the public contract must preserve distinct codec and sink error types"
539 )]
540 fn decode_rows<R: RowSink<S>>(
541 &mut self,
542 sink: &mut R,
543 ) -> Result<DecodeOutcome<Self::Warning>, DecodeRowsError<Self::Error, R::Error>>;
544}
545
546pub trait TileBatchDecode: ImageCodec {
548 type Context: CodecContext;
550
551 fn decode_tile(
558 ctx: &mut Self::Context,
559 pool: &mut Self::Pool,
560 input: &[u8],
561 out: &mut [u8],
562 stride: usize,
563 fmt: PixelFormat,
564 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
565
566 fn decode_tile_region(
573 ctx: &mut Self::Context,
574 pool: &mut Self::Pool,
575 input: &[u8],
576 out: &mut [u8],
577 stride: usize,
578 fmt: PixelFormat,
579 roi: Rect,
580 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
581
582 fn decode_tile_scaled(
589 ctx: &mut Self::Context,
590 pool: &mut Self::Pool,
591 input: &[u8],
592 out: &mut [u8],
593 stride: usize,
594 fmt: PixelFormat,
595 scale: Downscale,
596 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
597
598 fn decode_tile_region_scaled(
605 ctx: &mut Self::Context,
606 pool: &mut Self::Pool,
607 fmt: PixelFormat,
608 job: TileRegionScaledDecodeJob<'_, '_>,
609 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
610}
611
612pub trait TileBatchDecodeDevice: ImageCodec {
614 type Context: CodecContext;
616 type DeviceSurface: DeviceSurface;
618
619 fn decode_tile_to_device(
626 ctx: &mut <Self as TileBatchDecodeDevice>::Context,
627 pool: &mut Self::Pool,
628 input: &[u8],
629 fmt: PixelFormat,
630 backend: BackendRequest,
631 ) -> Result<<Self as TileBatchDecodeDevice>::DeviceSurface, Self::Error>
632 where
633 Self: TileBatchDecodeSubmit<
634 Context = <Self as TileBatchDecodeDevice>::Context,
635 DeviceSurface = <Self as TileBatchDecodeDevice>::DeviceSurface,
636 >,
637 {
638 let mut session = <Self as TileBatchDecodeSubmit>::Session::default();
639 <Self as TileBatchDecodeSubmit>::submit_tile_to_device(
640 ctx,
641 &mut session,
642 pool,
643 input,
644 fmt,
645 backend,
646 )?
647 .wait()
648 }
649
650 fn decode_tile_region_to_device(
657 ctx: &mut <Self as TileBatchDecodeDevice>::Context,
658 pool: &mut Self::Pool,
659 input: &[u8],
660 fmt: PixelFormat,
661 roi: Rect,
662 backend: BackendRequest,
663 ) -> Result<<Self as TileBatchDecodeDevice>::DeviceSurface, Self::Error>
664 where
665 Self: TileBatchDecodeSubmit<
666 Context = <Self as TileBatchDecodeDevice>::Context,
667 DeviceSurface = <Self as TileBatchDecodeDevice>::DeviceSurface,
668 >,
669 {
670 let mut session = <Self as TileBatchDecodeSubmit>::Session::default();
671 <Self as TileBatchDecodeSubmit>::submit_tile_region_to_device(
672 ctx,
673 &mut session,
674 pool,
675 input,
676 fmt,
677 roi,
678 backend,
679 )?
680 .wait()
681 }
682
683 fn decode_tile_scaled_to_device(
690 ctx: &mut <Self as TileBatchDecodeDevice>::Context,
691 pool: &mut Self::Pool,
692 input: &[u8],
693 fmt: PixelFormat,
694 scale: Downscale,
695 backend: BackendRequest,
696 ) -> Result<<Self as TileBatchDecodeDevice>::DeviceSurface, Self::Error>
697 where
698 Self: TileBatchDecodeSubmit<
699 Context = <Self as TileBatchDecodeDevice>::Context,
700 DeviceSurface = <Self as TileBatchDecodeDevice>::DeviceSurface,
701 >,
702 {
703 let mut session = <Self as TileBatchDecodeSubmit>::Session::default();
704 <Self as TileBatchDecodeSubmit>::submit_tile_scaled_to_device(
705 ctx,
706 &mut session,
707 pool,
708 input,
709 fmt,
710 scale,
711 backend,
712 )?
713 .wait()
714 }
715
716 fn decode_tile_region_scaled_to_device(
723 ctx: &mut <Self as TileBatchDecodeDevice>::Context,
724 pool: &mut Self::Pool,
725 input: &[u8],
726 fmt: PixelFormat,
727 roi: Rect,
728 scale: Downscale,
729 backend: BackendRequest,
730 ) -> Result<<Self as TileBatchDecodeDevice>::DeviceSurface, Self::Error>
731 where
732 Self: TileBatchDecodeSubmit<
733 Context = <Self as TileBatchDecodeDevice>::Context,
734 DeviceSurface = <Self as TileBatchDecodeDevice>::DeviceSurface,
735 >,
736 {
737 let mut session = <Self as TileBatchDecodeSubmit>::Session::default();
738 <Self as TileBatchDecodeSubmit>::submit_tile_region_scaled_to_device(
739 ctx,
740 &mut session,
741 pool,
742 TileRegionScaledDeviceDecodeRequest {
743 input,
744 fmt,
745 roi,
746 scale,
747 backend,
748 },
749 )?
750 .wait()
751 }
752}
753
754pub trait TileBatchDecodeManyDevice: ImageCodec {
756 type Context: CodecContext;
758 type DeviceSurface: DeviceSurface;
760
761 fn decode_tiles_to_device(
768 ctx: &mut Self::Context,
769 pool: &mut Self::Pool,
770 inputs: &[&[u8]],
771 fmt: PixelFormat,
772 backend: BackendRequest,
773 ) -> Result<Vec<Self::DeviceSurface>, Self::Error>;
774}
775
776pub trait TileBatchDecodeSubmit: ImageCodec {
778 type Context: CodecContext;
780 type Session: Default + Send;
782 type DeviceSurface: DeviceSurface;
784 type SubmittedSurface: DeviceSubmission<Output = Self::DeviceSurface, Error = Self::Error>;
786
787 fn submit_tile_to_device(
794 ctx: &mut Self::Context,
795 session: &mut Self::Session,
796 pool: &mut Self::Pool,
797 input: &[u8],
798 fmt: PixelFormat,
799 backend: BackendRequest,
800 ) -> Result<Self::SubmittedSurface, Self::Error>;
801
802 fn submit_tile_region_to_device(
809 ctx: &mut Self::Context,
810 session: &mut Self::Session,
811 pool: &mut Self::Pool,
812 input: &[u8],
813 fmt: PixelFormat,
814 roi: Rect,
815 backend: BackendRequest,
816 ) -> Result<Self::SubmittedSurface, Self::Error>;
817
818 fn submit_tile_scaled_to_device(
825 ctx: &mut Self::Context,
826 session: &mut Self::Session,
827 pool: &mut Self::Pool,
828 input: &[u8],
829 fmt: PixelFormat,
830 scale: Downscale,
831 backend: BackendRequest,
832 ) -> Result<Self::SubmittedSurface, Self::Error>;
833
834 fn submit_tile_region_scaled_to_device(
841 ctx: &mut Self::Context,
842 session: &mut Self::Session,
843 pool: &mut Self::Pool,
844 request: TileRegionScaledDeviceDecodeRequest<'_>,
845 ) -> Result<Self::SubmittedSurface, Self::Error>;
846}
847
848pub trait TileDecompress {
851 type Error: CodecError;
853 type Pool: ScratchPool;
855
856 fn expected_size(input: &[u8]) -> Result<Option<usize>, Self::Error>;
862
863 fn decompress_into(
870 pool: &mut Self::Pool,
871 input: &[u8],
872 out: &mut [u8],
873 ) -> Result<usize, Self::Error>;
874}
875
876#[cfg(test)]
877mod tests;