1use alloc::vec::Vec;
4
5use crate::{
6 accelerator::{DeviceMemoryRange, ExecutionStats, SurfaceResidency},
7 backend::{BackendKind, BackendRequest},
8 context::{CodecContext, DecoderContext},
9 error::CodecError,
10 pixel::PixelFormat,
11 row_sink::RowSink,
12 sample::Sample,
13 scale::Downscale,
14 scratch::ScratchPool,
15 types::{DecodeOutcome, DecodeRequest, Info, Rect},
16};
17
18#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
21pub enum DecodeRowsError<D, E>
22where
23 D: core::error::Error + 'static,
24 E: core::error::Error + 'static,
25{
26 #[error(transparent)]
27 Decode(D),
29 #[error(transparent)]
30 Sink(E),
32}
33
34pub trait ImageCodec {
36 type Error: CodecError;
38 type Warning: core::fmt::Debug + core::fmt::Display + Send + Sync + 'static;
40 type Pool: ScratchPool;
42}
43
44pub trait DeviceSurface {
46 fn backend_kind(&self) -> BackendKind;
48 fn residency(&self) -> SurfaceResidency {
50 SurfaceResidency::for_backend(self.backend_kind())
51 }
52 fn dimensions(&self) -> (u32, u32);
54 fn pixel_format(&self) -> PixelFormat;
56 fn byte_len(&self) -> usize;
58 fn execution_stats(&self) -> ExecutionStats {
60 ExecutionStats::default()
61 }
62 fn memory_range(&self) -> Option<DeviceMemoryRange> {
64 None
65 }
66}
67
68pub trait DeviceSubmission {
70 type Output;
72 type Error;
74
75 fn wait(self) -> Result<Self::Output, Self::Error>;
77}
78
79#[derive(Debug)]
81pub struct ReadySubmission<T, E>(Result<T, E>);
82
83impl<T, E> ReadySubmission<T, E> {
84 pub fn from_result(result: Result<T, E>) -> Self {
86 Self(result)
87 }
88}
89
90impl<T, E> DeviceSubmission for ReadySubmission<T, E> {
91 type Output = T;
92 type Error = E;
93
94 fn wait(self) -> Result<Self::Output, Self::Error> {
95 self.0
96 }
97}
98
99pub trait DeviceSubmitSession {
101 fn record_submit(&mut self);
103}
104
105pub fn submit_ready_device<S, T, E>(
107 session: &mut S,
108 submit: impl FnOnce(&mut S) -> Result<T, E>,
109) -> ReadySubmission<T, E>
110where
111 S: DeviceSubmitSession + ?Sized,
112{
113 session.record_submit();
114 ReadySubmission::from_result(submit(session))
115}
116
117pub trait ImageDecode<'a>: ImageCodec + Sized + 'a {
119 type View: 'a;
121
122 fn inspect(input: &'a [u8]) -> Result<Info, Self::Error>;
124 fn parse(input: &'a [u8]) -> Result<Self::View, Self::Error>;
126 fn from_view(view: Self::View) -> Result<Self, Self::Error>;
128
129 fn decode_into(
131 &mut self,
132 out: &mut [u8],
133 stride: usize,
134 fmt: PixelFormat,
135 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
136
137 fn decode_into_with_scratch(
139 &mut self,
140 pool: &mut Self::Pool,
141 out: &mut [u8],
142 stride: usize,
143 fmt: PixelFormat,
144 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
145
146 fn decode_region_into(
148 &mut self,
149 pool: &mut Self::Pool,
150 out: &mut [u8],
151 stride: usize,
152 fmt: PixelFormat,
153 roi: Rect,
154 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
155
156 fn decode_scaled_into(
158 &mut self,
159 pool: &mut Self::Pool,
160 out: &mut [u8],
161 stride: usize,
162 fmt: PixelFormat,
163 scale: Downscale,
164 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
165
166 fn decode_region_scaled_into(
168 &mut self,
169 pool: &mut Self::Pool,
170 out: &mut [u8],
171 stride: usize,
172 fmt: PixelFormat,
173 roi: Rect,
174 scale: Downscale,
175 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
176
177 fn decode_request_into(
179 &mut self,
180 pool: &mut Self::Pool,
181 out: &mut [u8],
182 stride: usize,
183 fmt: PixelFormat,
184 request: DecodeRequest,
185 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error> {
186 match (request.roi, request.scale) {
187 (None, Downscale::None) => self.decode_into_with_scratch(pool, out, stride, fmt),
188 (Some(roi), Downscale::None) => self.decode_region_into(pool, out, stride, fmt, roi),
189 (None, scale) => self.decode_scaled_into(pool, out, stride, fmt, scale),
190 (Some(roi), scale) => {
191 self.decode_region_scaled_into(pool, out, stride, fmt, roi, scale)
192 }
193 }
194 }
195}
196
197pub trait ImageDecodeSubmit<'a>: ImageDecode<'a> {
199 type Session: Default + Send;
201 type DeviceSurface: DeviceSurface;
203 type SubmittedSurface: DeviceSubmission<Output = Self::DeviceSurface, Error = Self::Error>;
205
206 fn submit_to_device(
208 &mut self,
209 session: &mut Self::Session,
210 fmt: PixelFormat,
211 backend: BackendRequest,
212 ) -> Result<Self::SubmittedSurface, Self::Error>;
213
214 fn submit_region_to_device(
216 &mut self,
217 session: &mut Self::Session,
218 fmt: PixelFormat,
219 roi: Rect,
220 backend: BackendRequest,
221 ) -> Result<Self::SubmittedSurface, Self::Error>;
222
223 fn submit_scaled_to_device(
225 &mut self,
226 session: &mut Self::Session,
227 fmt: PixelFormat,
228 scale: Downscale,
229 backend: BackendRequest,
230 ) -> Result<Self::SubmittedSurface, Self::Error>;
231
232 fn submit_region_scaled_to_device(
234 &mut self,
235 session: &mut Self::Session,
236 fmt: PixelFormat,
237 roi: Rect,
238 scale: Downscale,
239 backend: BackendRequest,
240 ) -> Result<Self::SubmittedSurface, Self::Error>;
241
242 fn submit_request_to_device(
244 &mut self,
245 session: &mut Self::Session,
246 fmt: PixelFormat,
247 backend: BackendRequest,
248 request: DecodeRequest,
249 ) -> Result<Self::SubmittedSurface, Self::Error> {
250 match (request.roi, request.scale) {
251 (None, Downscale::None) => self.submit_to_device(session, fmt, backend),
252 (Some(roi), Downscale::None) => {
253 self.submit_region_to_device(session, fmt, roi, backend)
254 }
255 (None, scale) => self.submit_scaled_to_device(session, fmt, scale, backend),
256 (Some(roi), scale) => {
257 self.submit_region_scaled_to_device(session, fmt, roi, scale, backend)
258 }
259 }
260 }
261}
262
263pub trait ImageDecodeDevice<'a>: ImageDecode<'a> {
265 type DeviceSurface: DeviceSurface;
267
268 fn decode_to_device(
270 &mut self,
271 fmt: PixelFormat,
272 backend: BackendRequest,
273 ) -> Result<<Self as ImageDecodeDevice<'a>>::DeviceSurface, Self::Error>
274 where
275 Self: ImageDecodeSubmit<'a, DeviceSurface = <Self as ImageDecodeDevice<'a>>::DeviceSurface>,
276 {
277 let mut session = <Self as ImageDecodeSubmit<'a>>::Session::default();
278 <Self as ImageDecodeSubmit<'a>>::submit_to_device(self, &mut session, fmt, backend)?.wait()
279 }
280
281 fn decode_region_to_device(
283 &mut self,
284 fmt: PixelFormat,
285 roi: Rect,
286 backend: BackendRequest,
287 ) -> Result<<Self as ImageDecodeDevice<'a>>::DeviceSurface, Self::Error>
288 where
289 Self: ImageDecodeSubmit<'a, DeviceSurface = <Self as ImageDecodeDevice<'a>>::DeviceSurface>,
290 {
291 let mut session = <Self as ImageDecodeSubmit<'a>>::Session::default();
292 <Self as ImageDecodeSubmit<'a>>::submit_region_to_device(
293 self,
294 &mut session,
295 fmt,
296 roi,
297 backend,
298 )?
299 .wait()
300 }
301
302 fn decode_scaled_to_device(
304 &mut self,
305 fmt: PixelFormat,
306 scale: Downscale,
307 backend: BackendRequest,
308 ) -> Result<<Self as ImageDecodeDevice<'a>>::DeviceSurface, Self::Error>
309 where
310 Self: ImageDecodeSubmit<'a, DeviceSurface = <Self as ImageDecodeDevice<'a>>::DeviceSurface>,
311 {
312 let mut session = <Self as ImageDecodeSubmit<'a>>::Session::default();
313 <Self as ImageDecodeSubmit<'a>>::submit_scaled_to_device(
314 self,
315 &mut session,
316 fmt,
317 scale,
318 backend,
319 )?
320 .wait()
321 }
322
323 fn decode_region_scaled_to_device(
325 &mut self,
326 fmt: PixelFormat,
327 roi: Rect,
328 scale: Downscale,
329 backend: BackendRequest,
330 ) -> Result<<Self as ImageDecodeDevice<'a>>::DeviceSurface, Self::Error>
331 where
332 Self: ImageDecodeSubmit<'a, DeviceSurface = <Self as ImageDecodeDevice<'a>>::DeviceSurface>,
333 {
334 let mut session = <Self as ImageDecodeSubmit<'a>>::Session::default();
335 <Self as ImageDecodeSubmit<'a>>::submit_region_scaled_to_device(
336 self,
337 &mut session,
338 fmt,
339 roi,
340 scale,
341 backend,
342 )?
343 .wait()
344 }
345}
346
347pub trait ImageDecodeRows<'a, S: Sample>: ImageDecode<'a> {
349 fn decode_rows<R: RowSink<S>>(
351 &mut self,
352 sink: &mut R,
353 ) -> Result<DecodeOutcome<Self::Warning>, DecodeRowsError<Self::Error, R::Error>>;
354}
355
356pub trait TileBatchDecode: ImageCodec {
358 type Context: CodecContext;
360
361 fn decode_tile<'a>(
363 ctx: &mut DecoderContext<Self::Context>,
364 pool: &mut Self::Pool,
365 input: &'a [u8],
366 out: &mut [u8],
367 stride: usize,
368 fmt: PixelFormat,
369 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
370
371 fn decode_tile_region<'a>(
373 ctx: &mut DecoderContext<Self::Context>,
374 pool: &mut Self::Pool,
375 input: &'a [u8],
376 out: &mut [u8],
377 stride: usize,
378 fmt: PixelFormat,
379 roi: Rect,
380 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
381
382 fn decode_tile_scaled<'a>(
384 ctx: &mut DecoderContext<Self::Context>,
385 pool: &mut Self::Pool,
386 input: &'a [u8],
387 out: &mut [u8],
388 stride: usize,
389 fmt: PixelFormat,
390 scale: Downscale,
391 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
392
393 #[allow(clippy::too_many_arguments)]
395 fn decode_tile_region_scaled<'a>(
396 ctx: &mut DecoderContext<Self::Context>,
397 pool: &mut Self::Pool,
398 input: &'a [u8],
399 out: &mut [u8],
400 stride: usize,
401 fmt: PixelFormat,
402 roi: Rect,
403 scale: Downscale,
404 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
405
406 fn decode_tile_request<'a>(
408 ctx: &mut DecoderContext<Self::Context>,
409 pool: &mut Self::Pool,
410 input: &'a [u8],
411 out: &mut [u8],
412 stride: usize,
413 fmt: PixelFormat,
414 request: DecodeRequest,
415 ) -> Result<DecodeOutcome<Self::Warning>, Self::Error> {
416 match (request.roi, request.scale) {
417 (None, Downscale::None) => Self::decode_tile(ctx, pool, input, out, stride, fmt),
418 (Some(roi), Downscale::None) => {
419 Self::decode_tile_region(ctx, pool, input, out, stride, fmt, roi)
420 }
421 (None, scale) => Self::decode_tile_scaled(ctx, pool, input, out, stride, fmt, scale),
422 (Some(roi), scale) => {
423 Self::decode_tile_region_scaled(ctx, pool, input, out, stride, fmt, roi, scale)
424 }
425 }
426 }
427}
428
429pub trait TileBatchDecodeDevice: ImageCodec {
431 type Context: CodecContext;
433 type DeviceSurface: DeviceSurface;
435
436 fn decode_tile_to_device<'a>(
438 ctx: &mut DecoderContext<<Self as TileBatchDecodeDevice>::Context>,
439 pool: &mut Self::Pool,
440 input: &'a [u8],
441 fmt: PixelFormat,
442 backend: BackendRequest,
443 ) -> Result<<Self as TileBatchDecodeDevice>::DeviceSurface, Self::Error>
444 where
445 Self: TileBatchDecodeSubmit<
446 Context = <Self as TileBatchDecodeDevice>::Context,
447 DeviceSurface = <Self as TileBatchDecodeDevice>::DeviceSurface,
448 >,
449 {
450 let mut session = <Self as TileBatchDecodeSubmit>::Session::default();
451 <Self as TileBatchDecodeSubmit>::submit_tile_to_device(
452 ctx,
453 &mut session,
454 pool,
455 input,
456 fmt,
457 backend,
458 )?
459 .wait()
460 }
461
462 fn decode_tile_region_to_device<'a>(
464 ctx: &mut DecoderContext<<Self as TileBatchDecodeDevice>::Context>,
465 pool: &mut Self::Pool,
466 input: &'a [u8],
467 fmt: PixelFormat,
468 roi: Rect,
469 backend: BackendRequest,
470 ) -> Result<<Self as TileBatchDecodeDevice>::DeviceSurface, Self::Error>
471 where
472 Self: TileBatchDecodeSubmit<
473 Context = <Self as TileBatchDecodeDevice>::Context,
474 DeviceSurface = <Self as TileBatchDecodeDevice>::DeviceSurface,
475 >,
476 {
477 let mut session = <Self as TileBatchDecodeSubmit>::Session::default();
478 <Self as TileBatchDecodeSubmit>::submit_tile_region_to_device(
479 ctx,
480 &mut session,
481 pool,
482 input,
483 fmt,
484 roi,
485 backend,
486 )?
487 .wait()
488 }
489
490 fn decode_tile_scaled_to_device<'a>(
492 ctx: &mut DecoderContext<<Self as TileBatchDecodeDevice>::Context>,
493 pool: &mut Self::Pool,
494 input: &'a [u8],
495 fmt: PixelFormat,
496 scale: Downscale,
497 backend: BackendRequest,
498 ) -> Result<<Self as TileBatchDecodeDevice>::DeviceSurface, Self::Error>
499 where
500 Self: TileBatchDecodeSubmit<
501 Context = <Self as TileBatchDecodeDevice>::Context,
502 DeviceSurface = <Self as TileBatchDecodeDevice>::DeviceSurface,
503 >,
504 {
505 let mut session = <Self as TileBatchDecodeSubmit>::Session::default();
506 <Self as TileBatchDecodeSubmit>::submit_tile_scaled_to_device(
507 ctx,
508 &mut session,
509 pool,
510 input,
511 fmt,
512 scale,
513 backend,
514 )?
515 .wait()
516 }
517
518 fn decode_tile_region_scaled_to_device<'a>(
520 ctx: &mut DecoderContext<<Self as TileBatchDecodeDevice>::Context>,
521 pool: &mut Self::Pool,
522 input: &'a [u8],
523 fmt: PixelFormat,
524 roi: Rect,
525 scale: Downscale,
526 backend: BackendRequest,
527 ) -> Result<<Self as TileBatchDecodeDevice>::DeviceSurface, Self::Error>
528 where
529 Self: TileBatchDecodeSubmit<
530 Context = <Self as TileBatchDecodeDevice>::Context,
531 DeviceSurface = <Self as TileBatchDecodeDevice>::DeviceSurface,
532 >,
533 {
534 let mut session = <Self as TileBatchDecodeSubmit>::Session::default();
535 <Self as TileBatchDecodeSubmit>::submit_tile_region_scaled_to_device(
536 ctx,
537 &mut session,
538 pool,
539 input,
540 fmt,
541 roi,
542 scale,
543 backend,
544 )?
545 .wait()
546 }
547}
548
549pub trait TileBatchDecodeManyDevice: ImageCodec {
551 type Context: CodecContext;
553 type DeviceSurface: DeviceSurface;
555
556 fn decode_tiles_to_device(
558 ctx: &mut DecoderContext<Self::Context>,
559 pool: &mut Self::Pool,
560 inputs: &[&[u8]],
561 fmt: PixelFormat,
562 backend: BackendRequest,
563 ) -> Result<Vec<Self::DeviceSurface>, Self::Error>;
564}
565
566pub trait TileBatchDecodeSubmit: ImageCodec {
568 type Context: CodecContext;
570 type Session: Default + Send;
572 type DeviceSurface: DeviceSurface;
574 type SubmittedSurface: DeviceSubmission<Output = Self::DeviceSurface, Error = Self::Error>;
576
577 fn submit_tile_to_device<'a>(
579 ctx: &mut DecoderContext<Self::Context>,
580 session: &mut Self::Session,
581 pool: &mut Self::Pool,
582 input: &'a [u8],
583 fmt: PixelFormat,
584 backend: BackendRequest,
585 ) -> Result<Self::SubmittedSurface, Self::Error>;
586
587 fn submit_tile_region_to_device<'a>(
589 ctx: &mut DecoderContext<Self::Context>,
590 session: &mut Self::Session,
591 pool: &mut Self::Pool,
592 input: &'a [u8],
593 fmt: PixelFormat,
594 roi: Rect,
595 backend: BackendRequest,
596 ) -> Result<Self::SubmittedSurface, Self::Error>;
597
598 fn submit_tile_scaled_to_device<'a>(
600 ctx: &mut DecoderContext<Self::Context>,
601 session: &mut Self::Session,
602 pool: &mut Self::Pool,
603 input: &'a [u8],
604 fmt: PixelFormat,
605 scale: Downscale,
606 backend: BackendRequest,
607 ) -> Result<Self::SubmittedSurface, Self::Error>;
608
609 #[allow(clippy::too_many_arguments)]
611 fn submit_tile_region_scaled_to_device<'a>(
612 ctx: &mut DecoderContext<Self::Context>,
613 session: &mut Self::Session,
614 pool: &mut Self::Pool,
615 input: &'a [u8],
616 fmt: PixelFormat,
617 roi: Rect,
618 scale: Downscale,
619 backend: BackendRequest,
620 ) -> Result<Self::SubmittedSurface, Self::Error>;
621
622 fn submit_tile_request_to_device<'a>(
624 ctx: &mut DecoderContext<Self::Context>,
625 session: &mut Self::Session,
626 pool: &mut Self::Pool,
627 input: &'a [u8],
628 fmt: PixelFormat,
629 backend: BackendRequest,
630 request: DecodeRequest,
631 ) -> Result<Self::SubmittedSurface, Self::Error> {
632 match (request.roi, request.scale) {
633 (None, Downscale::None) => {
634 Self::submit_tile_to_device(ctx, session, pool, input, fmt, backend)
635 }
636 (Some(roi), Downscale::None) => {
637 Self::submit_tile_region_to_device(ctx, session, pool, input, fmt, roi, backend)
638 }
639 (None, scale) => {
640 Self::submit_tile_scaled_to_device(ctx, session, pool, input, fmt, scale, backend)
641 }
642 (Some(roi), scale) => Self::submit_tile_region_scaled_to_device(
643 ctx, session, pool, input, fmt, roi, scale, backend,
644 ),
645 }
646 }
647}
648
649pub trait TileDecompress {
652 type Error: CodecError;
654 type Pool: ScratchPool;
656
657 fn expected_size(input: &[u8]) -> Result<Option<usize>, Self::Error>;
659
660 fn decompress_into(
662 pool: &mut Self::Pool,
663 input: &[u8],
664 out: &mut [u8],
665 ) -> Result<usize, Self::Error>;
666}