1use alloc::vec::Vec;
4
5use crate::{
6 accelerator::{DeviceMemoryRange, ExecutionStats, SurfaceResidency},
7 backend::{BackendKind, BackendRequest},
8 batch::{TileRegionScaledDecodeJob, TileRegionScaledDeviceDecodeRequest},
9 context::{CodecContext, DecoderContext},
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 DeviceSubmission {
71 type Output;
73 type Error;
75
76 fn wait(self) -> Result<Self::Output, Self::Error>;
82}
83
84#[derive(Debug)]
86#[doc(hidden)]
87pub struct ReadySubmission<T, E>(Result<T, E>);
88
89impl<T, E> ReadySubmission<T, E> {
90 pub fn from_result(result: Result<T, E>) -> Self {
92 Self(result)
93 }
94}
95
96impl<T, E> DeviceSubmission for ReadySubmission<T, E> {
97 type Output = T;
98 type Error = E;
99
100 fn wait(self) -> Result<Self::Output, Self::Error> {
101 self.0
102 }
103}
104
105#[doc(hidden)]
107pub trait DeviceSubmitSession {
108 fn record_submit(&mut self);
110}
111
112#[doc(hidden)]
114pub fn submit_ready_device<S, T, E>(
115 session: &mut S,
116 submit: impl FnOnce(&mut S) -> Result<T, E>,
117) -> ReadySubmission<T, E>
118where
119 S: DeviceSubmitSession + ?Sized,
120{
121 session.record_submit();
122 ReadySubmission::from_result(submit(session))
123}
124
125pub trait ImageDecode<'a>: ImageCodec + Sized + 'a {
127 type View: 'a;
129
130 fn inspect(input: &'a [u8]) -> Result<Info, Self::Error>;
137 fn parse(input: &'a [u8]) -> Result<Self::View, Self::Error>;
144 fn from_view(view: Self::View) -> Result<Self, Self::Error>;
151
152 fn decode_into(
159 &mut self,
160 out: &mut [u8],
161 stride: usize,
162 fmt: PixelFormat,
163 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
164
165 fn decode_into_with_scratch(
172 &mut self,
173 pool: &mut Self::Pool,
174 out: &mut [u8],
175 stride: usize,
176 fmt: PixelFormat,
177 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
178
179 fn decode_region_into(
186 &mut self,
187 pool: &mut Self::Pool,
188 out: &mut [u8],
189 stride: usize,
190 fmt: PixelFormat,
191 roi: Rect,
192 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
193
194 fn decode_scaled_into(
201 &mut self,
202 pool: &mut Self::Pool,
203 out: &mut [u8],
204 stride: usize,
205 fmt: PixelFormat,
206 scale: Downscale,
207 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
208
209 fn decode_region_scaled_into(
216 &mut self,
217 pool: &mut Self::Pool,
218 out: &mut [u8],
219 stride: usize,
220 fmt: PixelFormat,
221 roi: Rect,
222 scale: Downscale,
223 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
224}
225
226#[doc(hidden)]
233pub trait CpuBackedImageDecode<'a>: ImageCodec + Sized + 'a {
234 type Cpu: ImageDecode<'a, Pool = Self::Pool>;
236 type View: 'a;
238
239 fn inspect_cpu(input: &'a [u8]) -> Result<Info, Self::Error>;
241 fn parse_cpu(input: &'a [u8]) -> Result<Self::View, Self::Error>;
243 fn from_cpu_view(view: Self::View) -> Result<Self, Self::Error>;
245 fn cpu_decoder_mut(&mut self) -> &mut Self::Cpu;
247 fn map_cpu_outcome(
249 outcome: DecodeOutcome<<Self::Cpu as ImageCodec>::Warning>,
250 ) -> DecodeOutcome<Self::Warning>;
251}
252
253#[doc(hidden)]
254impl<'a, T> ImageDecode<'a> for T
255where
256 T: CpuBackedImageDecode<'a>,
257 <T::Cpu as ImageCodec>::Error: Into<T::Error>,
258{
259 type View = T::View;
260
261 fn inspect(input: &'a [u8]) -> Result<Info, Self::Error> {
262 T::inspect_cpu(input)
263 }
264
265 fn parse(input: &'a [u8]) -> Result<Self::View, Self::Error> {
266 T::parse_cpu(input)
267 }
268
269 fn from_view(view: Self::View) -> Result<Self, Self::Error> {
270 T::from_cpu_view(view)
271 }
272
273 fn decode_into(
274 &mut self,
275 out: &mut [u8],
276 stride: usize,
277 fmt: PixelFormat,
278 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error> {
279 let outcome = self
280 .cpu_decoder_mut()
281 .decode_into(out, stride, fmt)
282 .map_err(Into::into)?;
283 Ok(T::map_cpu_outcome(outcome))
284 }
285
286 fn decode_into_with_scratch(
287 &mut self,
288 pool: &mut Self::Pool,
289 out: &mut [u8],
290 stride: usize,
291 fmt: PixelFormat,
292 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error> {
293 let outcome = self
294 .cpu_decoder_mut()
295 .decode_into_with_scratch(pool, out, stride, fmt)
296 .map_err(Into::into)?;
297 Ok(T::map_cpu_outcome(outcome))
298 }
299
300 fn decode_region_into(
301 &mut self,
302 pool: &mut Self::Pool,
303 out: &mut [u8],
304 stride: usize,
305 fmt: PixelFormat,
306 roi: Rect,
307 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error> {
308 let outcome = self
309 .cpu_decoder_mut()
310 .decode_region_into(pool, out, stride, fmt, roi)
311 .map_err(Into::into)?;
312 Ok(T::map_cpu_outcome(outcome))
313 }
314
315 fn decode_scaled_into(
316 &mut self,
317 pool: &mut Self::Pool,
318 out: &mut [u8],
319 stride: usize,
320 fmt: PixelFormat,
321 scale: Downscale,
322 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error> {
323 let outcome = self
324 .cpu_decoder_mut()
325 .decode_scaled_into(pool, out, stride, fmt, scale)
326 .map_err(Into::into)?;
327 Ok(T::map_cpu_outcome(outcome))
328 }
329
330 fn decode_region_scaled_into(
331 &mut self,
332 pool: &mut Self::Pool,
333 out: &mut [u8],
334 stride: usize,
335 fmt: PixelFormat,
336 roi: Rect,
337 scale: Downscale,
338 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error> {
339 let outcome = self
340 .cpu_decoder_mut()
341 .decode_region_scaled_into(pool, out, stride, fmt, roi, scale)
342 .map_err(Into::into)?;
343 Ok(T::map_cpu_outcome(outcome))
344 }
345}
346
347pub trait ImageDecodeSubmit<'a>: ImageDecode<'a> {
349 type Session: Default + Send;
351 type DeviceSurface: DeviceSurface;
353 type SubmittedSurface: DeviceSubmission<Output = Self::DeviceSurface, Error = Self::Error>;
355
356 fn submit_to_device(
363 &mut self,
364 session: &mut Self::Session,
365 fmt: PixelFormat,
366 backend: BackendRequest,
367 ) -> Result<Self::SubmittedSurface, Self::Error>;
368
369 fn submit_region_to_device(
376 &mut self,
377 session: &mut Self::Session,
378 fmt: PixelFormat,
379 roi: Rect,
380 backend: BackendRequest,
381 ) -> Result<Self::SubmittedSurface, Self::Error>;
382
383 fn submit_scaled_to_device(
390 &mut self,
391 session: &mut Self::Session,
392 fmt: PixelFormat,
393 scale: Downscale,
394 backend: BackendRequest,
395 ) -> Result<Self::SubmittedSurface, Self::Error>;
396
397 fn submit_region_scaled_to_device(
404 &mut self,
405 session: &mut Self::Session,
406 fmt: PixelFormat,
407 roi: Rect,
408 scale: Downscale,
409 backend: BackendRequest,
410 ) -> Result<Self::SubmittedSurface, Self::Error>;
411}
412
413pub trait ImageDecodeDevice<'a>: ImageDecode<'a> {
415 type DeviceSurface: DeviceSurface;
417
418 fn decode_to_device(
424 &mut self,
425 fmt: PixelFormat,
426 backend: BackendRequest,
427 ) -> Result<<Self as ImageDecodeDevice<'a>>::DeviceSurface, Self::Error>
428 where
429 Self: ImageDecodeSubmit<'a, DeviceSurface = <Self as ImageDecodeDevice<'a>>::DeviceSurface>,
430 {
431 let mut session = <Self as ImageDecodeSubmit<'a>>::Session::default();
432 <Self as ImageDecodeSubmit<'a>>::submit_to_device(self, &mut session, fmt, backend)?.wait()
433 }
434
435 fn decode_region_to_device(
442 &mut self,
443 fmt: PixelFormat,
444 roi: Rect,
445 backend: BackendRequest,
446 ) -> Result<<Self as ImageDecodeDevice<'a>>::DeviceSurface, Self::Error>
447 where
448 Self: ImageDecodeSubmit<'a, DeviceSurface = <Self as ImageDecodeDevice<'a>>::DeviceSurface>,
449 {
450 let mut session = <Self as ImageDecodeSubmit<'a>>::Session::default();
451 <Self as ImageDecodeSubmit<'a>>::submit_region_to_device(
452 self,
453 &mut session,
454 fmt,
455 roi,
456 backend,
457 )?
458 .wait()
459 }
460
461 fn decode_scaled_to_device(
468 &mut self,
469 fmt: PixelFormat,
470 scale: Downscale,
471 backend: BackendRequest,
472 ) -> Result<<Self as ImageDecodeDevice<'a>>::DeviceSurface, Self::Error>
473 where
474 Self: ImageDecodeSubmit<'a, DeviceSurface = <Self as ImageDecodeDevice<'a>>::DeviceSurface>,
475 {
476 let mut session = <Self as ImageDecodeSubmit<'a>>::Session::default();
477 <Self as ImageDecodeSubmit<'a>>::submit_scaled_to_device(
478 self,
479 &mut session,
480 fmt,
481 scale,
482 backend,
483 )?
484 .wait()
485 }
486
487 fn decode_region_scaled_to_device(
494 &mut self,
495 fmt: PixelFormat,
496 roi: Rect,
497 scale: Downscale,
498 backend: BackendRequest,
499 ) -> Result<<Self as ImageDecodeDevice<'a>>::DeviceSurface, Self::Error>
500 where
501 Self: ImageDecodeSubmit<'a, DeviceSurface = <Self as ImageDecodeDevice<'a>>::DeviceSurface>,
502 {
503 let mut session = <Self as ImageDecodeSubmit<'a>>::Session::default();
504 <Self as ImageDecodeSubmit<'a>>::submit_region_scaled_to_device(
505 self,
506 &mut session,
507 fmt,
508 roi,
509 scale,
510 backend,
511 )?
512 .wait()
513 }
514}
515
516pub trait ImageDecodeRows<'a, S: Sample>: ImageDecode<'a> {
518 #[expect(
525 clippy::type_complexity,
526 reason = "the public contract must preserve distinct codec and sink error types"
527 )]
528 fn decode_rows<R: RowSink<S>>(
529 &mut self,
530 sink: &mut R,
531 ) -> Result<DecodeOutcome<Self::Warning>, DecodeRowsError<Self::Error, R::Error>>;
532}
533
534pub trait TileBatchDecode: ImageCodec {
536 type Context: CodecContext;
538
539 fn decode_tile(
546 ctx: &mut DecoderContext<Self::Context>,
547 pool: &mut Self::Pool,
548 input: &[u8],
549 out: &mut [u8],
550 stride: usize,
551 fmt: PixelFormat,
552 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
553
554 fn decode_tile_region(
561 ctx: &mut DecoderContext<Self::Context>,
562 pool: &mut Self::Pool,
563 input: &[u8],
564 out: &mut [u8],
565 stride: usize,
566 fmt: PixelFormat,
567 roi: Rect,
568 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
569
570 fn decode_tile_scaled(
577 ctx: &mut DecoderContext<Self::Context>,
578 pool: &mut Self::Pool,
579 input: &[u8],
580 out: &mut [u8],
581 stride: usize,
582 fmt: PixelFormat,
583 scale: Downscale,
584 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
585
586 fn decode_tile_region_scaled(
593 ctx: &mut DecoderContext<Self::Context>,
594 pool: &mut Self::Pool,
595 fmt: PixelFormat,
596 job: TileRegionScaledDecodeJob<'_, '_>,
597 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
598}
599
600pub trait TileBatchDecodeDevice: ImageCodec {
602 type Context: CodecContext;
604 type DeviceSurface: DeviceSurface;
606
607 fn decode_tile_to_device(
614 ctx: &mut DecoderContext<<Self as TileBatchDecodeDevice>::Context>,
615 pool: &mut Self::Pool,
616 input: &[u8],
617 fmt: PixelFormat,
618 backend: BackendRequest,
619 ) -> Result<<Self as TileBatchDecodeDevice>::DeviceSurface, Self::Error>
620 where
621 Self: TileBatchDecodeSubmit<
622 Context = <Self as TileBatchDecodeDevice>::Context,
623 DeviceSurface = <Self as TileBatchDecodeDevice>::DeviceSurface,
624 >,
625 {
626 let mut session = <Self as TileBatchDecodeSubmit>::Session::default();
627 <Self as TileBatchDecodeSubmit>::submit_tile_to_device(
628 ctx,
629 &mut session,
630 pool,
631 input,
632 fmt,
633 backend,
634 )?
635 .wait()
636 }
637
638 fn decode_tile_region_to_device(
645 ctx: &mut DecoderContext<<Self as TileBatchDecodeDevice>::Context>,
646 pool: &mut Self::Pool,
647 input: &[u8],
648 fmt: PixelFormat,
649 roi: Rect,
650 backend: BackendRequest,
651 ) -> Result<<Self as TileBatchDecodeDevice>::DeviceSurface, Self::Error>
652 where
653 Self: TileBatchDecodeSubmit<
654 Context = <Self as TileBatchDecodeDevice>::Context,
655 DeviceSurface = <Self as TileBatchDecodeDevice>::DeviceSurface,
656 >,
657 {
658 let mut session = <Self as TileBatchDecodeSubmit>::Session::default();
659 <Self as TileBatchDecodeSubmit>::submit_tile_region_to_device(
660 ctx,
661 &mut session,
662 pool,
663 input,
664 fmt,
665 roi,
666 backend,
667 )?
668 .wait()
669 }
670
671 fn decode_tile_scaled_to_device(
678 ctx: &mut DecoderContext<<Self as TileBatchDecodeDevice>::Context>,
679 pool: &mut Self::Pool,
680 input: &[u8],
681 fmt: PixelFormat,
682 scale: Downscale,
683 backend: BackendRequest,
684 ) -> Result<<Self as TileBatchDecodeDevice>::DeviceSurface, Self::Error>
685 where
686 Self: TileBatchDecodeSubmit<
687 Context = <Self as TileBatchDecodeDevice>::Context,
688 DeviceSurface = <Self as TileBatchDecodeDevice>::DeviceSurface,
689 >,
690 {
691 let mut session = <Self as TileBatchDecodeSubmit>::Session::default();
692 <Self as TileBatchDecodeSubmit>::submit_tile_scaled_to_device(
693 ctx,
694 &mut session,
695 pool,
696 input,
697 fmt,
698 scale,
699 backend,
700 )?
701 .wait()
702 }
703
704 fn decode_tile_region_scaled_to_device(
711 ctx: &mut DecoderContext<<Self as TileBatchDecodeDevice>::Context>,
712 pool: &mut Self::Pool,
713 input: &[u8],
714 fmt: PixelFormat,
715 roi: Rect,
716 scale: Downscale,
717 backend: BackendRequest,
718 ) -> Result<<Self as TileBatchDecodeDevice>::DeviceSurface, Self::Error>
719 where
720 Self: TileBatchDecodeSubmit<
721 Context = <Self as TileBatchDecodeDevice>::Context,
722 DeviceSurface = <Self as TileBatchDecodeDevice>::DeviceSurface,
723 >,
724 {
725 let mut session = <Self as TileBatchDecodeSubmit>::Session::default();
726 <Self as TileBatchDecodeSubmit>::submit_tile_region_scaled_to_device(
727 ctx,
728 &mut session,
729 pool,
730 TileRegionScaledDeviceDecodeRequest {
731 input,
732 fmt,
733 roi,
734 scale,
735 backend,
736 },
737 )?
738 .wait()
739 }
740}
741
742pub trait TileBatchDecodeManyDevice: ImageCodec {
744 type Context: CodecContext;
746 type DeviceSurface: DeviceSurface;
748
749 fn decode_tiles_to_device(
756 ctx: &mut DecoderContext<Self::Context>,
757 pool: &mut Self::Pool,
758 inputs: &[&[u8]],
759 fmt: PixelFormat,
760 backend: BackendRequest,
761 ) -> Result<Vec<Self::DeviceSurface>, Self::Error>;
762}
763
764pub trait TileBatchDecodeSubmit: ImageCodec {
766 type Context: CodecContext;
768 type Session: Default + Send;
770 type DeviceSurface: DeviceSurface;
772 type SubmittedSurface: DeviceSubmission<Output = Self::DeviceSurface, Error = Self::Error>;
774
775 fn submit_tile_to_device(
782 ctx: &mut DecoderContext<Self::Context>,
783 session: &mut Self::Session,
784 pool: &mut Self::Pool,
785 input: &[u8],
786 fmt: PixelFormat,
787 backend: BackendRequest,
788 ) -> Result<Self::SubmittedSurface, Self::Error>;
789
790 fn submit_tile_region_to_device(
797 ctx: &mut DecoderContext<Self::Context>,
798 session: &mut Self::Session,
799 pool: &mut Self::Pool,
800 input: &[u8],
801 fmt: PixelFormat,
802 roi: Rect,
803 backend: BackendRequest,
804 ) -> Result<Self::SubmittedSurface, Self::Error>;
805
806 fn submit_tile_scaled_to_device(
813 ctx: &mut DecoderContext<Self::Context>,
814 session: &mut Self::Session,
815 pool: &mut Self::Pool,
816 input: &[u8],
817 fmt: PixelFormat,
818 scale: Downscale,
819 backend: BackendRequest,
820 ) -> Result<Self::SubmittedSurface, Self::Error>;
821
822 fn submit_tile_region_scaled_to_device(
829 ctx: &mut DecoderContext<Self::Context>,
830 session: &mut Self::Session,
831 pool: &mut Self::Pool,
832 request: TileRegionScaledDeviceDecodeRequest<'_>,
833 ) -> Result<Self::SubmittedSurface, Self::Error>;
834}
835
836pub trait TileDecompress {
839 type Error: CodecError;
841 type Pool: ScratchPool;
843
844 fn expected_size(input: &[u8]) -> Result<Option<usize>, Self::Error>;
850
851 fn decompress_into(
858 pool: &mut Self::Pool,
859 input: &[u8],
860 out: &mut [u8],
861 ) -> Result<usize, Self::Error>;
862}
863
864#[cfg(test)]
865mod tests;