Skip to main content

j2k_metal/decoder/
request.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3use j2k_core::{BackendKind, BackendRequest, Downscale, PixelFormat, Rect};
4
5use crate::{batch, routing, Surface, SurfaceResidency};
6
7/// Decode operation represented in a route report.
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9#[doc(hidden)]
10pub enum DecodeOperation {
11    /// Full-image decode.
12    Full,
13    /// Source-region decode.
14    Region,
15    /// Full-image scaled decode.
16    Scaled,
17    /// Source-region scaled decode.
18    RegionScaled,
19}
20
21/// Geometry operation for a single J2K Metal decode request.
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub enum MetalDecodeOp {
24    /// Full-image decode at native dimensions.
25    Full,
26    /// Source-region decode at native scale.
27    Region(Rect),
28    /// Full-image downscale.
29    Scaled(Downscale),
30    /// Source-region decode with downscale.
31    RegionScaled {
32        /// Source region of interest.
33        roi: Rect,
34        /// Downscale factor applied to the selected region.
35        scale: Downscale,
36    },
37}
38
39impl MetalDecodeOp {
40    pub(crate) const fn report_operation(self) -> DecodeOperation {
41        match self {
42            Self::Full => DecodeOperation::Full,
43            Self::Region(_) => DecodeOperation::Region,
44            Self::Scaled(_) => DecodeOperation::Scaled,
45            Self::RegionScaled { .. } => DecodeOperation::RegionScaled,
46        }
47    }
48
49    pub(crate) const fn batch_op(self) -> batch::BatchOp {
50        match self {
51            Self::Full => batch::BatchOp::Full,
52            Self::Region(roi) => batch::BatchOp::Region(roi),
53            Self::Scaled(scale) => batch::BatchOp::Scaled(scale),
54            Self::RegionScaled { roi, scale } => batch::BatchOp::RegionScaled { roi, scale },
55        }
56    }
57}
58
59/// Single-image J2K Metal decode request.
60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61pub struct MetalDecodeRequest {
62    /// Requested output pixel format.
63    pub fmt: PixelFormat,
64    /// Decode geometry operation.
65    pub op: MetalDecodeOp,
66    /// Backend routing preference for device decode APIs.
67    pub backend: BackendRequest,
68}
69
70impl MetalDecodeRequest {
71    /// Full-image decode request.
72    pub const fn full(fmt: PixelFormat, backend: BackendRequest) -> Self {
73        Self {
74            fmt,
75            op: MetalDecodeOp::Full,
76            backend,
77        }
78    }
79
80    /// Source-region decode request.
81    pub const fn region(fmt: PixelFormat, roi: Rect, backend: BackendRequest) -> Self {
82        Self {
83            fmt,
84            op: MetalDecodeOp::Region(roi),
85            backend,
86        }
87    }
88
89    /// Full-image downscale decode request.
90    pub const fn scaled(fmt: PixelFormat, scale: Downscale, backend: BackendRequest) -> Self {
91        Self {
92            fmt,
93            op: MetalDecodeOp::Scaled(scale),
94            backend,
95        }
96    }
97
98    /// Source-region downscale decode request.
99    pub const fn region_scaled(
100        fmt: PixelFormat,
101        roi: Rect,
102        scale: Downscale,
103        backend: BackendRequest,
104    ) -> Self {
105        Self {
106            fmt,
107            op: MetalDecodeOp::RegionScaled { roi, scale },
108            backend,
109        }
110    }
111}
112
113/// Route details for a completed decode request.
114#[derive(Debug, Clone, Copy, PartialEq, Eq)]
115#[doc(hidden)]
116pub struct DecodeRouteReport {
117    /// Decode operation requested by the caller.
118    pub operation: DecodeOperation,
119    /// Caller backend preference.
120    pub requested_backend: BackendRequest,
121    /// Backend that produced the returned surface.
122    pub selected_backend: BackendKind,
123    /// Requested output pixel format.
124    pub pixel_format: PixelFormat,
125    /// Residency of the returned surface.
126    pub surface_residency: SurfaceResidency,
127    /// Reason `Auto` selected CPU, when applicable.
128    pub fallback_reason: Option<&'static str>,
129}
130
131impl DecodeRouteReport {
132    fn from_surface(
133        operation: DecodeOperation,
134        requested_backend: BackendRequest,
135        pixel_format: PixelFormat,
136        surface: &Surface,
137    ) -> Self {
138        Self {
139            operation,
140            requested_backend,
141            selected_backend: surface.backend,
142            pixel_format,
143            surface_residency: surface.residency,
144            fallback_reason: decode_fallback_reason(requested_backend, surface.backend),
145        }
146    }
147}
148
149/// Decoded surface paired with the route details that produced it.
150#[derive(Clone)]
151#[doc(hidden)]
152pub struct DecodeSurfaceWithReport {
153    /// Returned decoded surface.
154    pub surface: Surface,
155    /// Route report for the completed decode.
156    pub report: DecodeRouteReport,
157}
158
159fn decode_fallback_reason(
160    requested_backend: BackendRequest,
161    selected_backend: BackendKind,
162) -> Option<&'static str> {
163    if requested_backend == BackendRequest::Auto && selected_backend == BackendKind::Cpu {
164        Some(routing::AUTO_DECODE_CPU_FALLBACK_REASON)
165    } else {
166        None
167    }
168}
169
170pub(super) fn surface_with_report(
171    surface: Surface,
172    operation: DecodeOperation,
173    requested_backend: BackendRequest,
174    pixel_format: PixelFormat,
175) -> DecodeSurfaceWithReport {
176    let report =
177        DecodeRouteReport::from_surface(operation, requested_backend, pixel_format, &surface);
178    DecodeSurfaceWithReport { surface, report }
179}