j2k_native/j2c/decode/
workspace.rs1use super::{DecompositionStorage, OutputRegion, TileDecodeContext};
6
7#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
9pub enum CpuDecodeParallelism {
10 #[default]
12 Auto,
13 Serial,
15}
16
17#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
19pub struct DecoderWorkspaceStats {
20 decode_calls: u64,
21 component_owner_reuses: u64,
22 tier1_owner_reuses: u64,
23 idwt_owner_reuses: u64,
24 scratch_capacity_retries: u64,
25 retained_component_bytes: usize,
26 retained_tier1_bytes: usize,
27 retained_idwt_bytes: usize,
28}
29
30impl DecoderWorkspaceStats {
31 #[must_use]
33 pub const fn decode_calls(self) -> u64 {
34 self.decode_calls
35 }
36
37 #[must_use]
39 pub const fn component_owner_reuses(self) -> u64 {
40 self.component_owner_reuses
41 }
42
43 #[must_use]
45 pub const fn tier1_owner_reuses(self) -> u64 {
46 self.tier1_owner_reuses
47 }
48
49 #[must_use]
51 pub const fn idwt_owner_reuses(self) -> u64 {
52 self.idwt_owner_reuses
53 }
54
55 #[must_use]
57 pub const fn scratch_capacity_retries(self) -> u64 {
58 self.scratch_capacity_retries
59 }
60
61 #[must_use]
63 pub const fn retained_component_bytes(self) -> usize {
64 self.retained_component_bytes
65 }
66
67 #[must_use]
69 pub const fn retained_tier1_bytes(self) -> usize {
70 self.retained_tier1_bytes
71 }
72
73 #[must_use]
75 pub const fn retained_idwt_bytes(self) -> usize {
76 self.retained_idwt_bytes
77 }
78
79 #[must_use]
81 pub const fn retained_scratch_bytes(self) -> usize {
82 self.retained_tier1_bytes
83 .saturating_add(self.retained_idwt_bytes)
84 }
85}
86
87#[derive(Default)]
93pub struct DecoderWorkspace {
94 tile_decode_context: TileDecodeContext,
95 pub(super) cpu_decode_parallelism: CpuDecodeParallelism,
96 stats: DecoderWorkspaceStats,
97}
98
99impl DecoderWorkspace {
100 #[must_use]
102 pub const fn stats(&self) -> DecoderWorkspaceStats {
103 self.stats
104 }
105}
106
107pub struct DecoderContext<'a> {
109 pub(crate) tile_decode_context: TileDecodeContext,
110 pub(crate) storage: DecompositionStorage<'a>,
111 pub(super) cpu_decode_parallelism: CpuDecodeParallelism,
112 workspace_stats: DecoderWorkspaceStats,
113}
114
115impl Default for DecoderContext<'_> {
116 fn default() -> Self {
117 Self {
118 tile_decode_context: TileDecodeContext::default(),
119 storage: DecompositionStorage::default(),
120 cpu_decode_parallelism: CpuDecodeParallelism::Auto,
121 workspace_stats: DecoderWorkspaceStats::default(),
122 }
123 }
124}
125
126impl DecoderContext<'_> {
127 #[must_use]
129 pub fn from_workspace(workspace: DecoderWorkspace) -> Self {
130 Self {
131 tile_decode_context: workspace.tile_decode_context,
132 storage: DecompositionStorage::default(),
133 cpu_decode_parallelism: workspace.cpu_decode_parallelism,
134 workspace_stats: workspace.stats,
135 }
136 }
137
138 #[must_use]
140 pub fn into_workspace(mut self) -> DecoderWorkspace {
141 self.storage.release_all_allocations();
142 DecoderWorkspace {
143 tile_decode_context: self.tile_decode_context,
144 cpu_decode_parallelism: self.cpu_decode_parallelism,
145 stats: self.workspace_stats,
146 }
147 }
148
149 #[must_use]
151 pub const fn workspace_stats(&self) -> DecoderWorkspaceStats {
152 self.workspace_stats
153 }
154
155 pub(super) fn record_decode_start(
156 &mut self,
157 retained_component_bytes: usize,
158 retained_tier1_bytes: usize,
159 retained_idwt_bytes: usize,
160 ) {
161 self.workspace_stats.decode_calls = self.workspace_stats.decode_calls.saturating_add(1);
162 if retained_component_bytes != 0 {
163 self.workspace_stats.component_owner_reuses = self
164 .workspace_stats
165 .component_owner_reuses
166 .saturating_add(1);
167 }
168 if retained_tier1_bytes != 0 {
169 self.workspace_stats.tier1_owner_reuses =
170 self.workspace_stats.tier1_owner_reuses.saturating_add(1);
171 }
172 if retained_idwt_bytes != 0 {
173 self.workspace_stats.idwt_owner_reuses =
174 self.workspace_stats.idwt_owner_reuses.saturating_add(1);
175 }
176 }
177
178 pub(super) fn record_scratch_capacity_retry(&mut self) {
179 self.workspace_stats.scratch_capacity_retries = self
180 .workspace_stats
181 .scratch_capacity_retries
182 .saturating_add(1);
183 }
184
185 pub(super) fn record_decode_complete(
186 &mut self,
187 retained_component_bytes: usize,
188 retained_tier1_bytes: usize,
189 retained_idwt_bytes: usize,
190 ) {
191 self.workspace_stats.retained_component_bytes = retained_component_bytes;
192 self.workspace_stats.retained_tier1_bytes = retained_tier1_bytes;
193 self.workspace_stats.retained_idwt_bytes = retained_idwt_bytes;
194 }
195
196 pub(crate) fn release_reusable_allocations(&mut self) {
197 self.tile_decode_context.release_all_allocations();
198 self.storage.release_all_allocations();
199 }
200
201 pub(crate) fn set_output_region(&mut self, output_region: Option<(u32, u32, u32, u32)>) {
202 self.tile_decode_context.output_region = output_region.map(OutputRegion::from_tuple);
203 }
204
205 #[must_use]
207 pub fn cpu_decode_parallelism(&self) -> CpuDecodeParallelism {
208 self.cpu_decode_parallelism
209 }
210
211 pub fn set_cpu_decode_parallelism(&mut self, parallelism: CpuDecodeParallelism) {
213 self.cpu_decode_parallelism = parallelism;
214 }
215}