use alloc::vec::Vec;
use crate::{
accelerator::{DeviceMemoryRange, ExecutionStats, SurfaceResidency},
backend::{BackendKind, BackendRequest},
context::{CodecContext, DecoderContext},
error::CodecError,
pixel::PixelFormat,
row_sink::RowSink,
sample::Sample,
scale::Downscale,
scratch::ScratchPool,
types::{DecodeOutcome, DecodeRequest, Info, Rect},
};
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum DecodeRowsError<D, E>
where
D: core::error::Error + 'static,
E: core::error::Error + 'static,
{
#[error(transparent)]
Decode(D),
#[error(transparent)]
Sink(E),
}
pub trait ImageCodec {
type Error: CodecError;
type Warning: core::fmt::Debug + core::fmt::Display + Send + Sync + 'static;
type Pool: ScratchPool;
}
pub trait DeviceSurface {
fn backend_kind(&self) -> BackendKind;
fn residency(&self) -> SurfaceResidency {
SurfaceResidency::for_backend(self.backend_kind())
}
fn dimensions(&self) -> (u32, u32);
fn pixel_format(&self) -> PixelFormat;
fn byte_len(&self) -> usize;
fn execution_stats(&self) -> ExecutionStats {
ExecutionStats::default()
}
fn memory_range(&self) -> Option<DeviceMemoryRange> {
None
}
}
pub trait DeviceSubmission {
type Output;
type Error;
fn wait(self) -> Result<Self::Output, Self::Error>;
}
#[derive(Debug)]
pub struct ReadySubmission<T, E>(Result<T, E>);
impl<T, E> ReadySubmission<T, E> {
pub fn from_result(result: Result<T, E>) -> Self {
Self(result)
}
}
impl<T, E> DeviceSubmission for ReadySubmission<T, E> {
type Output = T;
type Error = E;
fn wait(self) -> Result<Self::Output, Self::Error> {
self.0
}
}
pub trait DeviceSubmitSession {
fn record_submit(&mut self);
}
pub fn submit_ready_device<S, T, E>(
session: &mut S,
submit: impl FnOnce(&mut S) -> Result<T, E>,
) -> ReadySubmission<T, E>
where
S: DeviceSubmitSession + ?Sized,
{
session.record_submit();
ReadySubmission::from_result(submit(session))
}
pub trait ImageDecode<'a>: ImageCodec + Sized + 'a {
type View: 'a;
fn inspect(input: &'a [u8]) -> Result<Info, Self::Error>;
fn parse(input: &'a [u8]) -> Result<Self::View, Self::Error>;
fn from_view(view: Self::View) -> Result<Self, Self::Error>;
fn decode_into(
&mut self,
out: &mut [u8],
stride: usize,
fmt: PixelFormat,
) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
fn decode_into_with_scratch(
&mut self,
pool: &mut Self::Pool,
out: &mut [u8],
stride: usize,
fmt: PixelFormat,
) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
fn decode_region_into(
&mut self,
pool: &mut Self::Pool,
out: &mut [u8],
stride: usize,
fmt: PixelFormat,
roi: Rect,
) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
fn decode_scaled_into(
&mut self,
pool: &mut Self::Pool,
out: &mut [u8],
stride: usize,
fmt: PixelFormat,
scale: Downscale,
) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
fn decode_region_scaled_into(
&mut self,
pool: &mut Self::Pool,
out: &mut [u8],
stride: usize,
fmt: PixelFormat,
roi: Rect,
scale: Downscale,
) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
fn decode_request_into(
&mut self,
pool: &mut Self::Pool,
out: &mut [u8],
stride: usize,
fmt: PixelFormat,
request: DecodeRequest,
) -> Result<DecodeOutcome<Self::Warning>, Self::Error> {
match (request.roi, request.scale) {
(None, Downscale::None) => self.decode_into_with_scratch(pool, out, stride, fmt),
(Some(roi), Downscale::None) => self.decode_region_into(pool, out, stride, fmt, roi),
(None, scale) => self.decode_scaled_into(pool, out, stride, fmt, scale),
(Some(roi), scale) => {
self.decode_region_scaled_into(pool, out, stride, fmt, roi, scale)
}
}
}
}
pub trait ImageDecodeSubmit<'a>: ImageDecode<'a> {
type Session: Default + Send;
type DeviceSurface: DeviceSurface;
type SubmittedSurface: DeviceSubmission<Output = Self::DeviceSurface, Error = Self::Error>;
fn submit_to_device(
&mut self,
session: &mut Self::Session,
fmt: PixelFormat,
backend: BackendRequest,
) -> Result<Self::SubmittedSurface, Self::Error>;
fn submit_region_to_device(
&mut self,
session: &mut Self::Session,
fmt: PixelFormat,
roi: Rect,
backend: BackendRequest,
) -> Result<Self::SubmittedSurface, Self::Error>;
fn submit_scaled_to_device(
&mut self,
session: &mut Self::Session,
fmt: PixelFormat,
scale: Downscale,
backend: BackendRequest,
) -> Result<Self::SubmittedSurface, Self::Error>;
fn submit_region_scaled_to_device(
&mut self,
session: &mut Self::Session,
fmt: PixelFormat,
roi: Rect,
scale: Downscale,
backend: BackendRequest,
) -> Result<Self::SubmittedSurface, Self::Error>;
fn submit_request_to_device(
&mut self,
session: &mut Self::Session,
fmt: PixelFormat,
backend: BackendRequest,
request: DecodeRequest,
) -> Result<Self::SubmittedSurface, Self::Error> {
match (request.roi, request.scale) {
(None, Downscale::None) => self.submit_to_device(session, fmt, backend),
(Some(roi), Downscale::None) => {
self.submit_region_to_device(session, fmt, roi, backend)
}
(None, scale) => self.submit_scaled_to_device(session, fmt, scale, backend),
(Some(roi), scale) => {
self.submit_region_scaled_to_device(session, fmt, roi, scale, backend)
}
}
}
}
pub trait ImageDecodeDevice<'a>: ImageDecode<'a> {
type DeviceSurface: DeviceSurface;
fn decode_to_device(
&mut self,
fmt: PixelFormat,
backend: BackendRequest,
) -> Result<<Self as ImageDecodeDevice<'a>>::DeviceSurface, Self::Error>
where
Self: ImageDecodeSubmit<'a, DeviceSurface = <Self as ImageDecodeDevice<'a>>::DeviceSurface>,
{
let mut session = <Self as ImageDecodeSubmit<'a>>::Session::default();
<Self as ImageDecodeSubmit<'a>>::submit_to_device(self, &mut session, fmt, backend)?.wait()
}
fn decode_region_to_device(
&mut self,
fmt: PixelFormat,
roi: Rect,
backend: BackendRequest,
) -> Result<<Self as ImageDecodeDevice<'a>>::DeviceSurface, Self::Error>
where
Self: ImageDecodeSubmit<'a, DeviceSurface = <Self as ImageDecodeDevice<'a>>::DeviceSurface>,
{
let mut session = <Self as ImageDecodeSubmit<'a>>::Session::default();
<Self as ImageDecodeSubmit<'a>>::submit_region_to_device(
self,
&mut session,
fmt,
roi,
backend,
)?
.wait()
}
fn decode_scaled_to_device(
&mut self,
fmt: PixelFormat,
scale: Downscale,
backend: BackendRequest,
) -> Result<<Self as ImageDecodeDevice<'a>>::DeviceSurface, Self::Error>
where
Self: ImageDecodeSubmit<'a, DeviceSurface = <Self as ImageDecodeDevice<'a>>::DeviceSurface>,
{
let mut session = <Self as ImageDecodeSubmit<'a>>::Session::default();
<Self as ImageDecodeSubmit<'a>>::submit_scaled_to_device(
self,
&mut session,
fmt,
scale,
backend,
)?
.wait()
}
fn decode_region_scaled_to_device(
&mut self,
fmt: PixelFormat,
roi: Rect,
scale: Downscale,
backend: BackendRequest,
) -> Result<<Self as ImageDecodeDevice<'a>>::DeviceSurface, Self::Error>
where
Self: ImageDecodeSubmit<'a, DeviceSurface = <Self as ImageDecodeDevice<'a>>::DeviceSurface>,
{
let mut session = <Self as ImageDecodeSubmit<'a>>::Session::default();
<Self as ImageDecodeSubmit<'a>>::submit_region_scaled_to_device(
self,
&mut session,
fmt,
roi,
scale,
backend,
)?
.wait()
}
}
pub trait ImageDecodeRows<'a, S: Sample>: ImageDecode<'a> {
fn decode_rows<R: RowSink<S>>(
&mut self,
sink: &mut R,
) -> Result<DecodeOutcome<Self::Warning>, DecodeRowsError<Self::Error, R::Error>>;
}
pub trait TileBatchDecode: ImageCodec {
type Context: CodecContext;
fn decode_tile<'a>(
ctx: &mut DecoderContext<Self::Context>,
pool: &mut Self::Pool,
input: &'a [u8],
out: &mut [u8],
stride: usize,
fmt: PixelFormat,
) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
fn decode_tile_region<'a>(
ctx: &mut DecoderContext<Self::Context>,
pool: &mut Self::Pool,
input: &'a [u8],
out: &mut [u8],
stride: usize,
fmt: PixelFormat,
roi: Rect,
) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
fn decode_tile_scaled<'a>(
ctx: &mut DecoderContext<Self::Context>,
pool: &mut Self::Pool,
input: &'a [u8],
out: &mut [u8],
stride: usize,
fmt: PixelFormat,
scale: Downscale,
) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
#[allow(clippy::too_many_arguments)]
fn decode_tile_region_scaled<'a>(
ctx: &mut DecoderContext<Self::Context>,
pool: &mut Self::Pool,
input: &'a [u8],
out: &mut [u8],
stride: usize,
fmt: PixelFormat,
roi: Rect,
scale: Downscale,
) -> Result<DecodeOutcome<Self::Warning>, Self::Error>;
fn decode_tile_request<'a>(
ctx: &mut DecoderContext<Self::Context>,
pool: &mut Self::Pool,
input: &'a [u8],
out: &mut [u8],
stride: usize,
fmt: PixelFormat,
request: DecodeRequest,
) -> Result<DecodeOutcome<Self::Warning>, Self::Error> {
match (request.roi, request.scale) {
(None, Downscale::None) => Self::decode_tile(ctx, pool, input, out, stride, fmt),
(Some(roi), Downscale::None) => {
Self::decode_tile_region(ctx, pool, input, out, stride, fmt, roi)
}
(None, scale) => Self::decode_tile_scaled(ctx, pool, input, out, stride, fmt, scale),
(Some(roi), scale) => {
Self::decode_tile_region_scaled(ctx, pool, input, out, stride, fmt, roi, scale)
}
}
}
}
pub trait TileBatchDecodeDevice: ImageCodec {
type Context: CodecContext;
type DeviceSurface: DeviceSurface;
fn decode_tile_to_device<'a>(
ctx: &mut DecoderContext<<Self as TileBatchDecodeDevice>::Context>,
pool: &mut Self::Pool,
input: &'a [u8],
fmt: PixelFormat,
backend: BackendRequest,
) -> Result<<Self as TileBatchDecodeDevice>::DeviceSurface, Self::Error>
where
Self: TileBatchDecodeSubmit<
Context = <Self as TileBatchDecodeDevice>::Context,
DeviceSurface = <Self as TileBatchDecodeDevice>::DeviceSurface,
>,
{
let mut session = <Self as TileBatchDecodeSubmit>::Session::default();
<Self as TileBatchDecodeSubmit>::submit_tile_to_device(
ctx,
&mut session,
pool,
input,
fmt,
backend,
)?
.wait()
}
fn decode_tile_region_to_device<'a>(
ctx: &mut DecoderContext<<Self as TileBatchDecodeDevice>::Context>,
pool: &mut Self::Pool,
input: &'a [u8],
fmt: PixelFormat,
roi: Rect,
backend: BackendRequest,
) -> Result<<Self as TileBatchDecodeDevice>::DeviceSurface, Self::Error>
where
Self: TileBatchDecodeSubmit<
Context = <Self as TileBatchDecodeDevice>::Context,
DeviceSurface = <Self as TileBatchDecodeDevice>::DeviceSurface,
>,
{
let mut session = <Self as TileBatchDecodeSubmit>::Session::default();
<Self as TileBatchDecodeSubmit>::submit_tile_region_to_device(
ctx,
&mut session,
pool,
input,
fmt,
roi,
backend,
)?
.wait()
}
fn decode_tile_scaled_to_device<'a>(
ctx: &mut DecoderContext<<Self as TileBatchDecodeDevice>::Context>,
pool: &mut Self::Pool,
input: &'a [u8],
fmt: PixelFormat,
scale: Downscale,
backend: BackendRequest,
) -> Result<<Self as TileBatchDecodeDevice>::DeviceSurface, Self::Error>
where
Self: TileBatchDecodeSubmit<
Context = <Self as TileBatchDecodeDevice>::Context,
DeviceSurface = <Self as TileBatchDecodeDevice>::DeviceSurface,
>,
{
let mut session = <Self as TileBatchDecodeSubmit>::Session::default();
<Self as TileBatchDecodeSubmit>::submit_tile_scaled_to_device(
ctx,
&mut session,
pool,
input,
fmt,
scale,
backend,
)?
.wait()
}
fn decode_tile_region_scaled_to_device<'a>(
ctx: &mut DecoderContext<<Self as TileBatchDecodeDevice>::Context>,
pool: &mut Self::Pool,
input: &'a [u8],
fmt: PixelFormat,
roi: Rect,
scale: Downscale,
backend: BackendRequest,
) -> Result<<Self as TileBatchDecodeDevice>::DeviceSurface, Self::Error>
where
Self: TileBatchDecodeSubmit<
Context = <Self as TileBatchDecodeDevice>::Context,
DeviceSurface = <Self as TileBatchDecodeDevice>::DeviceSurface,
>,
{
let mut session = <Self as TileBatchDecodeSubmit>::Session::default();
<Self as TileBatchDecodeSubmit>::submit_tile_region_scaled_to_device(
ctx,
&mut session,
pool,
input,
fmt,
roi,
scale,
backend,
)?
.wait()
}
}
pub trait TileBatchDecodeManyDevice: ImageCodec {
type Context: CodecContext;
type DeviceSurface: DeviceSurface;
fn decode_tiles_to_device(
ctx: &mut DecoderContext<Self::Context>,
pool: &mut Self::Pool,
inputs: &[&[u8]],
fmt: PixelFormat,
backend: BackendRequest,
) -> Result<Vec<Self::DeviceSurface>, Self::Error>;
}
pub trait TileBatchDecodeSubmit: ImageCodec {
type Context: CodecContext;
type Session: Default + Send;
type DeviceSurface: DeviceSurface;
type SubmittedSurface: DeviceSubmission<Output = Self::DeviceSurface, Error = Self::Error>;
fn submit_tile_to_device<'a>(
ctx: &mut DecoderContext<Self::Context>,
session: &mut Self::Session,
pool: &mut Self::Pool,
input: &'a [u8],
fmt: PixelFormat,
backend: BackendRequest,
) -> Result<Self::SubmittedSurface, Self::Error>;
fn submit_tile_region_to_device<'a>(
ctx: &mut DecoderContext<Self::Context>,
session: &mut Self::Session,
pool: &mut Self::Pool,
input: &'a [u8],
fmt: PixelFormat,
roi: Rect,
backend: BackendRequest,
) -> Result<Self::SubmittedSurface, Self::Error>;
fn submit_tile_scaled_to_device<'a>(
ctx: &mut DecoderContext<Self::Context>,
session: &mut Self::Session,
pool: &mut Self::Pool,
input: &'a [u8],
fmt: PixelFormat,
scale: Downscale,
backend: BackendRequest,
) -> Result<Self::SubmittedSurface, Self::Error>;
#[allow(clippy::too_many_arguments)]
fn submit_tile_region_scaled_to_device<'a>(
ctx: &mut DecoderContext<Self::Context>,
session: &mut Self::Session,
pool: &mut Self::Pool,
input: &'a [u8],
fmt: PixelFormat,
roi: Rect,
scale: Downscale,
backend: BackendRequest,
) -> Result<Self::SubmittedSurface, Self::Error>;
fn submit_tile_request_to_device<'a>(
ctx: &mut DecoderContext<Self::Context>,
session: &mut Self::Session,
pool: &mut Self::Pool,
input: &'a [u8],
fmt: PixelFormat,
backend: BackendRequest,
request: DecodeRequest,
) -> Result<Self::SubmittedSurface, Self::Error> {
match (request.roi, request.scale) {
(None, Downscale::None) => {
Self::submit_tile_to_device(ctx, session, pool, input, fmt, backend)
}
(Some(roi), Downscale::None) => {
Self::submit_tile_region_to_device(ctx, session, pool, input, fmt, roi, backend)
}
(None, scale) => {
Self::submit_tile_scaled_to_device(ctx, session, pool, input, fmt, scale, backend)
}
(Some(roi), scale) => Self::submit_tile_region_scaled_to_device(
ctx, session, pool, input, fmt, roi, scale, backend,
),
}
}
}
pub trait TileDecompress {
type Error: CodecError;
type Pool: ScratchPool;
fn expected_size(input: &[u8]) -> Result<Option<usize>, Self::Error>;
fn decompress_into(
pool: &mut Self::Pool,
input: &[u8],
out: &mut [u8],
) -> Result<usize, Self::Error>;
}