j2k_native/j2c/decode/
workspace.rs1use super::{DecompositionStorage, OutputRegion, TileDecodeContext};
6#[cfg(feature = "parallel")]
7use crate::HtCodeBlockDecodeWorkspace;
8#[cfg(feature = "parallel")]
9use alloc::vec::Vec;
10
11#[cfg(feature = "parallel")]
12pub(in crate::j2c::decode) struct HtTaskWorkspace {
13 pub(in crate::j2c::decode) workspace: HtCodeBlockDecodeWorkspace,
14 pub(in crate::j2c::decode) prepared_width: u32,
16 pub(in crate::j2c::decode) prepared_height: u32,
17}
18
19#[cfg(feature = "parallel")]
20pub(in crate::j2c::decode) fn ht_task_workspace_bytes(
21 slots: &Vec<HtTaskWorkspace>,
22) -> crate::Result<usize> {
23 let mut bytes = slots
24 .capacity()
25 .checked_mul(core::mem::size_of::<HtTaskWorkspace>())
26 .ok_or(crate::ValidationError::ImageTooLarge)?;
27 for slot in slots {
28 bytes = bytes
29 .checked_add(slot.workspace.allocated_bytes()?)
30 .ok_or(crate::ValidationError::ImageTooLarge)?;
31 }
32 Ok(bytes)
33}
34
35#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
37pub enum CpuDecodeParallelism {
38 #[default]
40 Auto,
41 Serial,
43}
44
45#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
47pub struct DecoderWorkspaceStats {
48 decode_calls: u64,
49 component_owner_reuses: u64,
50 tier1_owner_reuses: u64,
51 idwt_owner_reuses: u64,
52 scratch_capacity_retries: u64,
53 retained_component_bytes: usize,
54 retained_tier1_bytes: usize,
55 retained_idwt_bytes: usize,
56}
57
58impl DecoderWorkspaceStats {
59 #[must_use]
61 pub const fn decode_calls(self) -> u64 {
62 self.decode_calls
63 }
64
65 #[must_use]
67 pub const fn component_owner_reuses(self) -> u64 {
68 self.component_owner_reuses
69 }
70
71 #[must_use]
73 pub const fn tier1_owner_reuses(self) -> u64 {
74 self.tier1_owner_reuses
75 }
76
77 #[must_use]
79 pub const fn idwt_owner_reuses(self) -> u64 {
80 self.idwt_owner_reuses
81 }
82
83 #[must_use]
85 pub const fn scratch_capacity_retries(self) -> u64 {
86 self.scratch_capacity_retries
87 }
88
89 #[must_use]
91 pub const fn retained_component_bytes(self) -> usize {
92 self.retained_component_bytes
93 }
94
95 #[must_use]
97 pub const fn retained_tier1_bytes(self) -> usize {
98 self.retained_tier1_bytes
99 }
100
101 #[must_use]
103 pub const fn retained_idwt_bytes(self) -> usize {
104 self.retained_idwt_bytes
105 }
106
107 #[must_use]
109 pub const fn retained_scratch_bytes(self) -> usize {
110 self.retained_tier1_bytes
111 .saturating_add(self.retained_idwt_bytes)
112 }
113}
114
115#[derive(Default)]
121pub struct DecoderWorkspace {
122 tile_decode_context: TileDecodeContext,
123 pub(super) cpu_decode_parallelism: CpuDecodeParallelism,
124 stats: DecoderWorkspaceStats,
125}
126
127impl DecoderWorkspace {
128 #[must_use]
130 pub const fn stats(&self) -> DecoderWorkspaceStats {
131 self.stats
132 }
133}
134
135pub struct DecoderContext<'a> {
137 pub(crate) tile_decode_context: TileDecodeContext,
138 pub(crate) storage: DecompositionStorage<'a>,
139 pub(super) cpu_decode_parallelism: CpuDecodeParallelism,
140 workspace_stats: DecoderWorkspaceStats,
141}
142
143impl Default for DecoderContext<'_> {
144 fn default() -> Self {
145 Self {
146 tile_decode_context: TileDecodeContext::default(),
147 storage: DecompositionStorage::default(),
148 cpu_decode_parallelism: CpuDecodeParallelism::Auto,
149 workspace_stats: DecoderWorkspaceStats::default(),
150 }
151 }
152}
153
154impl DecoderContext<'_> {
155 #[must_use]
157 pub fn from_workspace(workspace: DecoderWorkspace) -> Self {
158 Self {
159 tile_decode_context: workspace.tile_decode_context,
160 storage: DecompositionStorage::default(),
161 cpu_decode_parallelism: workspace.cpu_decode_parallelism,
162 workspace_stats: workspace.stats,
163 }
164 }
165
166 #[must_use]
168 pub fn into_workspace(mut self) -> DecoderWorkspace {
169 self.storage.release_all_allocations();
170 DecoderWorkspace {
171 tile_decode_context: self.tile_decode_context,
172 cpu_decode_parallelism: self.cpu_decode_parallelism,
173 stats: self.workspace_stats,
174 }
175 }
176
177 #[must_use]
179 pub const fn workspace_stats(&self) -> DecoderWorkspaceStats {
180 self.workspace_stats
181 }
182
183 pub(super) fn record_decode_start(
184 &mut self,
185 retained_component_bytes: usize,
186 retained_tier1_bytes: usize,
187 retained_idwt_bytes: usize,
188 ) {
189 self.workspace_stats.decode_calls = self.workspace_stats.decode_calls.saturating_add(1);
190 if retained_component_bytes != 0 {
191 self.workspace_stats.component_owner_reuses = self
192 .workspace_stats
193 .component_owner_reuses
194 .saturating_add(1);
195 }
196 if retained_tier1_bytes != 0 {
197 self.workspace_stats.tier1_owner_reuses =
198 self.workspace_stats.tier1_owner_reuses.saturating_add(1);
199 }
200 if retained_idwt_bytes != 0 {
201 self.workspace_stats.idwt_owner_reuses =
202 self.workspace_stats.idwt_owner_reuses.saturating_add(1);
203 }
204 }
205
206 pub(super) fn record_scratch_capacity_retry(&mut self) {
207 self.workspace_stats.scratch_capacity_retries = self
208 .workspace_stats
209 .scratch_capacity_retries
210 .saturating_add(1);
211 }
212
213 pub(super) fn record_decode_complete(
214 &mut self,
215 retained_component_bytes: usize,
216 retained_tier1_bytes: usize,
217 retained_idwt_bytes: usize,
218 ) {
219 self.workspace_stats.retained_component_bytes = retained_component_bytes;
220 self.workspace_stats.retained_tier1_bytes = retained_tier1_bytes;
221 self.workspace_stats.retained_idwt_bytes = retained_idwt_bytes;
222 }
223
224 pub(crate) fn release_reusable_allocations(&mut self) {
225 self.tile_decode_context.release_all_allocations();
226 self.storage.release_all_allocations();
227 }
228
229 pub(crate) fn set_output_region(&mut self, output_region: Option<(u32, u32, u32, u32)>) {
230 self.tile_decode_context.output_region = output_region.map(OutputRegion::from_tuple);
231 }
232
233 pub(crate) fn set_round_irreversible_output(&mut self, enabled: bool) {
234 self.tile_decode_context.round_irreversible_output = enabled;
235 }
236
237 #[must_use]
239 pub fn cpu_decode_parallelism(&self) -> CpuDecodeParallelism {
240 self.cpu_decode_parallelism
241 }
242
243 pub fn set_cpu_decode_parallelism(&mut self, parallelism: CpuDecodeParallelism) {
245 self.cpu_decode_parallelism = parallelism;
246 }
247}