/src/astc-encoder/Source/astcenc_block_sizes.cpp
Line | Count | Source |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // ---------------------------------------------------------------------------- |
3 | | // Copyright 2011-2026 Arm Limited |
4 | | // |
5 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not |
6 | | // use this file except in compliance with the License. You may obtain a copy |
7 | | // of the License at: |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, software |
12 | | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
13 | | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
14 | | // License for the specific language governing permissions and limitations |
15 | | // under the License. |
16 | | // ---------------------------------------------------------------------------- |
17 | | |
18 | | /** |
19 | | * @brief Functions to generate block size descriptor and decimation tables. |
20 | | */ |
21 | | |
22 | | #include "astcenc_internal.h" |
23 | | |
24 | | /** |
25 | | * @brief Decode the properties of an encoded 2D block mode. |
26 | | * |
27 | | * @param block_mode The encoded block mode. |
28 | | * @param[out] weights_x The number of weights in the X dimension. |
29 | | * @param[out] weights_y The number of weights in the Y dimension. |
30 | | * @param[out] is_dual_plane True if this block mode has two weight planes. |
31 | | * @param[out] quant_mode The quantization level for the weights. |
32 | | * @param[out] weight_bits The storage bit count for the weights. |
33 | | * |
34 | | * @return Returns true if a valid mode, false otherwise. |
35 | | */ |
36 | | static bool decode_block_mode_2d( |
37 | | unsigned int block_mode, |
38 | | unsigned int& weights_x, |
39 | | unsigned int& weights_y, |
40 | | bool& is_dual_plane, |
41 | | unsigned int& quant_mode, |
42 | | unsigned int& weight_bits |
43 | 25.6M | ) { |
44 | 25.6M | unsigned int base_quant_mode = (block_mode >> 4) & 1; |
45 | 25.6M | unsigned int H = (block_mode >> 9) & 1; |
46 | 25.6M | unsigned int D = (block_mode >> 10) & 1; |
47 | 25.6M | unsigned int A = (block_mode >> 5) & 0x3; |
48 | | |
49 | 25.6M | weights_x = 0; |
50 | 25.6M | weights_y = 0; |
51 | | |
52 | 25.6M | if ((block_mode & 3) != 0) |
53 | 19.2M | { |
54 | 19.2M | base_quant_mode |= (block_mode & 3) << 1; |
55 | 19.2M | unsigned int B = (block_mode >> 7) & 3; |
56 | 19.2M | switch ((block_mode >> 2) & 3) |
57 | 19.2M | { |
58 | 4.72M | case 0: |
59 | 4.72M | weights_x = B + 4; |
60 | 4.72M | weights_y = A + 2; |
61 | 4.72M | break; |
62 | 4.82M | case 1: |
63 | 4.82M | weights_x = B + 8; |
64 | 4.82M | weights_y = A + 2; |
65 | 4.82M | break; |
66 | 4.85M | case 2: |
67 | 4.85M | weights_x = A + 2; |
68 | 4.85M | weights_y = B + 8; |
69 | 4.85M | break; |
70 | 4.82M | case 3: |
71 | 4.82M | B &= 1; |
72 | 4.82M | if (block_mode & 0x100) |
73 | 2.41M | { |
74 | 2.41M | weights_x = B + 2; |
75 | 2.41M | weights_y = A + 2; |
76 | 2.41M | } |
77 | 2.40M | else |
78 | 2.40M | { |
79 | 2.40M | weights_x = A + 2; |
80 | 2.40M | weights_y = B + 6; |
81 | 2.40M | } |
82 | 4.82M | break; |
83 | 19.2M | } |
84 | 19.2M | } |
85 | 6.45M | else |
86 | 6.45M | { |
87 | 6.45M | base_quant_mode |= ((block_mode >> 2) & 3) << 1; |
88 | 6.45M | if (((block_mode >> 2) & 3) == 0) |
89 | 1.62M | { |
90 | 1.62M | return false; |
91 | 1.62M | } |
92 | | |
93 | 4.83M | unsigned int B = (block_mode >> 9) & 3; |
94 | 4.83M | switch ((block_mode >> 7) & 3) |
95 | 4.83M | { |
96 | 1.21M | case 0: |
97 | 1.21M | weights_x = 12; |
98 | 1.21M | weights_y = A + 2; |
99 | 1.21M | break; |
100 | 1.21M | case 1: |
101 | 1.21M | weights_x = A + 2; |
102 | 1.21M | weights_y = 12; |
103 | 1.21M | break; |
104 | 1.18M | case 2: |
105 | 1.18M | weights_x = A + 6; |
106 | 1.18M | weights_y = B + 6; |
107 | 1.18M | D = 0; |
108 | 1.18M | H = 0; |
109 | 1.18M | break; |
110 | 1.21M | case 3: |
111 | 1.21M | switch ((block_mode >> 5) & 3) |
112 | 1.21M | { |
113 | 303k | case 0: |
114 | 303k | weights_x = 6; |
115 | 303k | weights_y = 10; |
116 | 303k | break; |
117 | 302k | case 1: |
118 | 302k | weights_x = 10; |
119 | 302k | weights_y = 6; |
120 | 302k | break; |
121 | 304k | case 2: |
122 | 609k | case 3: |
123 | 609k | return false; |
124 | 1.21M | } |
125 | 606k | break; |
126 | 4.83M | } |
127 | 4.83M | } |
128 | | |
129 | 23.4M | unsigned int weight_count = weights_x * weights_y * (D + 1); |
130 | 23.4M | quant_mode = (base_quant_mode - 2) + 6 * H; |
131 | 23.4M | is_dual_plane = D != 0; |
132 | | |
133 | 23.4M | weight_bits = get_ise_sequence_bitcount(weight_count, static_cast<quant_method>(quant_mode)); |
134 | 23.4M | return (weight_count <= BLOCK_MAX_WEIGHTS && |
135 | 19.2M | weight_bits >= BLOCK_MIN_WEIGHT_BITS && |
136 | 18.1M | weight_bits <= BLOCK_MAX_WEIGHT_BITS); |
137 | 25.6M | } |
138 | | |
139 | | /** |
140 | | * @brief Decode the properties of an encoded 3D block mode. |
141 | | * |
142 | | * @param block_mode The encoded block mode. |
143 | | * @param[out] weights_x The number of weights in the X dimension. |
144 | | * @param[out] weights_y The number of weights in the Y dimension. |
145 | | * @param[out] weights_z The number of weights in the Z dimension. |
146 | | * @param[out] is_dual_plane True if this block mode has two weight planes. |
147 | | * @param[out] quant_mode The quantization level for the weights. |
148 | | * @param[out] weight_bits The storage bit count for the weights. |
149 | | * |
150 | | * @return Returns true if a valid mode, false otherwise. |
151 | | */ |
152 | | static bool decode_block_mode_3d( |
153 | | unsigned int block_mode, |
154 | | unsigned int& weights_x, |
155 | | unsigned int& weights_y, |
156 | | unsigned int& weights_z, |
157 | | bool& is_dual_plane, |
158 | | unsigned int& quant_mode, |
159 | | unsigned int& weight_bits |
160 | 3.66k | ) { |
161 | 3.66k | unsigned int base_quant_mode = (block_mode >> 4) & 1; |
162 | 3.66k | unsigned int H = (block_mode >> 9) & 1; |
163 | 3.66k | unsigned int D = (block_mode >> 10) & 1; |
164 | 3.66k | unsigned int A = (block_mode >> 5) & 0x3; |
165 | | |
166 | 3.66k | weights_x = 0; |
167 | 3.66k | weights_y = 0; |
168 | 3.66k | weights_z = 0; |
169 | | |
170 | 3.66k | if ((block_mode & 3) != 0) |
171 | 2.74k | { |
172 | 2.74k | base_quant_mode |= (block_mode & 3) << 1; |
173 | 2.74k | unsigned int B = (block_mode >> 7) & 3; |
174 | 2.74k | unsigned int C = (block_mode >> 2) & 0x3; |
175 | 2.74k | weights_x = A + 2; |
176 | 2.74k | weights_y = B + 2; |
177 | 2.74k | weights_z = C + 2; |
178 | 2.74k | } |
179 | 913 | else |
180 | 913 | { |
181 | 913 | base_quant_mode |= ((block_mode >> 2) & 3) << 1; |
182 | 913 | if (((block_mode >> 2) & 3) == 0) |
183 | 256 | { |
184 | 256 | return false; |
185 | 256 | } |
186 | | |
187 | 657 | int B = (block_mode >> 9) & 3; |
188 | 657 | if (((block_mode >> 7) & 3) != 3) |
189 | 492 | { |
190 | 492 | D = 0; |
191 | 492 | H = 0; |
192 | 492 | } |
193 | 657 | switch ((block_mode >> 7) & 3) |
194 | 657 | { |
195 | 164 | case 0: |
196 | 164 | weights_x = 6; |
197 | 164 | weights_y = B + 2; |
198 | 164 | weights_z = A + 2; |
199 | 164 | break; |
200 | 164 | case 1: |
201 | 164 | weights_x = A + 2; |
202 | 164 | weights_y = 6; |
203 | 164 | weights_z = B + 2; |
204 | 164 | break; |
205 | 164 | case 2: |
206 | 164 | weights_x = A + 2; |
207 | 164 | weights_y = B + 2; |
208 | 164 | weights_z = 6; |
209 | 164 | break; |
210 | 165 | case 3: |
211 | 165 | weights_x = 2; |
212 | 165 | weights_y = 2; |
213 | 165 | weights_z = 2; |
214 | 165 | switch ((block_mode >> 5) & 3) |
215 | 165 | { |
216 | 39 | case 0: |
217 | 39 | weights_x = 6; |
218 | 39 | break; |
219 | 39 | case 1: |
220 | 39 | weights_y = 6; |
221 | 39 | break; |
222 | 39 | case 2: |
223 | 39 | weights_z = 6; |
224 | 39 | break; |
225 | 48 | case 3: |
226 | 48 | return false; |
227 | 165 | } |
228 | 117 | break; |
229 | 657 | } |
230 | 657 | } |
231 | | |
232 | 3.35k | unsigned int weight_count = weights_x * weights_y * weights_z * (D + 1); |
233 | 3.35k | quant_mode = (base_quant_mode - 2) + 6 * H; |
234 | 3.35k | is_dual_plane = D != 0; |
235 | | |
236 | 3.35k | weight_bits = get_ise_sequence_bitcount(weight_count, static_cast<quant_method>(quant_mode)); |
237 | 3.35k | return (weight_count <= BLOCK_MAX_WEIGHTS && |
238 | 1.98k | weight_bits >= BLOCK_MIN_WEIGHT_BITS && |
239 | 1.94k | weight_bits <= BLOCK_MAX_WEIGHT_BITS); |
240 | 3.66k | } |
241 | | |
242 | | /** |
243 | | * @brief Create a 2D decimation entry for a block-size and weight-decimation pair. |
244 | | * |
245 | | * @param texels_x The number of texels in the X dimension. |
246 | | * @param texels_y The number of texels in the Y dimension. |
247 | | * @param weights_x The number of weights in the X dimension. |
248 | | * @param weights_y The number of weights in the Y dimension. |
249 | | * @param[out] di The decimation info structure to populate. |
250 | | * @param[out] wb The decimation table init scratch working buffers. |
251 | | */ |
252 | | static void init_decimation_info_2d( |
253 | | unsigned int texels_x, |
254 | | unsigned int texels_y, |
255 | | unsigned int weights_x, |
256 | | unsigned int weights_y, |
257 | | decimation_info& di, |
258 | | dt_init_working_buffers& wb |
259 | 81.0k | ) { |
260 | 81.0k | unsigned int texels_per_block = texels_x * texels_y; |
261 | 81.0k | unsigned int weights_per_block = weights_x * weights_y; |
262 | | |
263 | 81.0k | #if !defined(ASTCENC_DECOMPRESS_ONLY) |
264 | 81.0k | uint8_t max_texel_count_of_weight = 0; |
265 | 81.0k | #endif |
266 | | |
267 | 81.0k | promise(weights_per_block > 0); |
268 | 81.0k | promise(texels_per_block > 0); |
269 | 81.0k | promise(texels_x > 0); |
270 | 81.0k | promise(texels_y > 0); |
271 | | |
272 | 2.01M | for (unsigned int i = 0; i < weights_per_block; i++) |
273 | 1.93M | { |
274 | 1.93M | wb.texel_count_of_weight[i] = 0; |
275 | 1.93M | } |
276 | | |
277 | 6.39M | for (unsigned int i = 0; i < texels_per_block; i++) |
278 | 6.31M | { |
279 | 6.31M | wb.weight_count_of_texel[i] = 0; |
280 | 6.31M | } |
281 | | |
282 | 720k | for (unsigned int y = 0; y < texels_y; y++) |
283 | 639k | { |
284 | 6.95M | for (unsigned int x = 0; x < texels_x; x++) |
285 | 6.31M | { |
286 | 6.31M | unsigned int texel = y * texels_x + x; |
287 | | |
288 | 6.31M | unsigned int x_weight = (((1024 + texels_x / 2) / (texels_x - 1)) * x * (weights_x - 1) + 32) >> 6; |
289 | 6.31M | unsigned int y_weight = (((1024 + texels_y / 2) / (texels_y - 1)) * y * (weights_y - 1) + 32) >> 6; |
290 | | |
291 | 6.31M | unsigned int x_weight_frac = x_weight & 0xF; |
292 | 6.31M | unsigned int y_weight_frac = y_weight & 0xF; |
293 | 6.31M | unsigned int x_weight_int = x_weight >> 4; |
294 | 6.31M | unsigned int y_weight_int = y_weight >> 4; |
295 | | |
296 | 6.31M | unsigned int qweight[4]; |
297 | 6.31M | qweight[0] = x_weight_int + y_weight_int * weights_x; |
298 | 6.31M | qweight[1] = qweight[0] + 1; |
299 | 6.31M | qweight[2] = qweight[0] + weights_x; |
300 | 6.31M | qweight[3] = qweight[2] + 1; |
301 | | |
302 | | // Truncated-precision bilinear interpolation |
303 | 6.31M | unsigned int prod = x_weight_frac * y_weight_frac; |
304 | | |
305 | 6.31M | unsigned int weight[4]; |
306 | 6.31M | weight[3] = (prod + 8) >> 4; |
307 | 6.31M | weight[1] = x_weight_frac - weight[3]; |
308 | 6.31M | weight[2] = y_weight_frac - weight[3]; |
309 | 6.31M | weight[0] = 16 - x_weight_frac - y_weight_frac + weight[3]; |
310 | | |
311 | 31.5M | for (unsigned int i = 0; i < 4; i++) |
312 | 25.2M | { |
313 | 25.2M | if (weight[i] != 0) |
314 | 17.5M | { |
315 | 17.5M | wb.grid_weights_of_texel[texel][wb.weight_count_of_texel[texel]] = static_cast<uint8_t>(qweight[i]); |
316 | 17.5M | wb.weights_of_texel[texel][wb.weight_count_of_texel[texel]] = static_cast<uint8_t>(weight[i]); |
317 | 17.5M | wb.weight_count_of_texel[texel]++; |
318 | 17.5M | wb.texels_of_weight[qweight[i]][wb.texel_count_of_weight[qweight[i]]] = static_cast<uint8_t>(texel); |
319 | 17.5M | wb.texel_weights_of_weight[qweight[i]][wb.texel_count_of_weight[qweight[i]]] = static_cast<uint8_t>(weight[i]); |
320 | 17.5M | wb.texel_count_of_weight[qweight[i]]++; |
321 | 17.5M | #if !defined(ASTCENC_DECOMPRESS_ONLY) |
322 | 17.5M | max_texel_count_of_weight = astc::max(max_texel_count_of_weight, wb.texel_count_of_weight[qweight[i]]); |
323 | 17.5M | #endif |
324 | 17.5M | } |
325 | 25.2M | } |
326 | 6.31M | } |
327 | 639k | } |
328 | | |
329 | 81.0k | uint8_t max_texel_weight_count = 0; |
330 | 6.39M | for (unsigned int i = 0; i < texels_per_block; i++) |
331 | 6.31M | { |
332 | 6.31M | di.texel_weight_count[i] = wb.weight_count_of_texel[i]; |
333 | 6.31M | max_texel_weight_count = astc::max(max_texel_weight_count, di.texel_weight_count[i]); |
334 | | |
335 | 23.8M | for (unsigned int j = 0; j < wb.weight_count_of_texel[i]; j++) |
336 | 17.5M | { |
337 | 17.5M | di.texel_weight_contribs_int_tr[j][i] = wb.weights_of_texel[i][j]; |
338 | 17.5M | #if !defined(ASTCENC_DECOMPRESS_ONLY) |
339 | 17.5M | di.texel_weight_contribs_float_tr[j][i] = static_cast<float>(wb.weights_of_texel[i][j]) * (1.0f / WEIGHTS_TEXEL_SUM); |
340 | 17.5M | #endif |
341 | 17.5M | di.texel_weights_tr[j][i] = wb.grid_weights_of_texel[i][j]; |
342 | 17.5M | } |
343 | | |
344 | | // Init all 4 entries so we can rely on zeros for vectorization |
345 | 14.0M | for (unsigned int j = wb.weight_count_of_texel[i]; j < 4; j++) |
346 | 7.74M | { |
347 | 7.74M | di.texel_weight_contribs_int_tr[j][i] = 0; |
348 | 7.74M | #if !defined(ASTCENC_DECOMPRESS_ONLY) |
349 | 7.74M | di.texel_weight_contribs_float_tr[j][i] = 0.0f; |
350 | 7.74M | #endif |
351 | 7.74M | di.texel_weights_tr[j][i] = 0; |
352 | 7.74M | } |
353 | 6.31M | } |
354 | | |
355 | 81.0k | di.max_texel_weight_count = max_texel_weight_count; |
356 | | |
357 | 81.0k | #if !defined(ASTCENC_DECOMPRESS_ONLY) |
358 | 2.01M | for (unsigned int i = 0; i < weights_per_block; i++) |
359 | 1.93M | { |
360 | 1.93M | unsigned int texel_count_wt = wb.texel_count_of_weight[i]; |
361 | 1.93M | di.weight_texel_count[i] = static_cast<uint8_t>(texel_count_wt); |
362 | | |
363 | 19.4M | for (unsigned int j = 0; j < texel_count_wt; j++) |
364 | 17.5M | { |
365 | 17.5M | uint8_t texel = wb.texels_of_weight[i][j]; |
366 | | |
367 | | // Create transposed versions of these for better vectorization |
368 | 17.5M | di.weight_texels_tr[j][i] = texel; |
369 | 17.5M | di.weights_texel_contribs_tr[j][i] = static_cast<float>(wb.texel_weights_of_weight[i][j]); |
370 | | |
371 | | // Store the per-texel contribution of this weight for each texel it contributes to |
372 | 17.5M | di.texel_contrib_for_weight[j][i] = 0.0f; |
373 | 36.6M | for (unsigned int k = 0; k < 4; k++) |
374 | 36.6M | { |
375 | 36.6M | uint8_t dttw = di.texel_weights_tr[k][texel]; |
376 | 36.6M | float dttwf = di.texel_weight_contribs_float_tr[k][texel]; |
377 | 36.6M | if (dttw == i && dttwf != 0.0f) |
378 | 17.5M | { |
379 | 17.5M | di.texel_contrib_for_weight[j][i] = di.texel_weight_contribs_float_tr[k][texel]; |
380 | 17.5M | break; |
381 | 17.5M | } |
382 | 36.6M | } |
383 | 17.5M | } |
384 | | |
385 | | // Initialize array tail so we can over-fetch with SIMD later to avoid loop tails |
386 | | // Match last texel in active lane in SIMD group, for better gathers |
387 | 1.93M | uint8_t last_texel = di.weight_texels_tr[texel_count_wt - 1][i]; |
388 | 9.26M | for (unsigned int j = texel_count_wt; j < max_texel_count_of_weight; j++) |
389 | 7.32M | { |
390 | 7.32M | di.weight_texels_tr[j][i] = last_texel; |
391 | 7.32M | di.weights_texel_contribs_tr[j][i] = 0.0f; |
392 | 7.32M | } |
393 | 1.93M | } |
394 | 81.0k | #endif |
395 | | |
396 | | // Initialize array tail so we can over-fetch with SIMD later to avoid loop tails |
397 | 81.0k | size_t texels_per_block_simd = round_up_to_simd_multiple_vla(texels_per_block); |
398 | 105k | for (size_t i = texels_per_block; i < texels_per_block_simd; i++) |
399 | 24.0k | { |
400 | 24.0k | di.texel_weight_count[i] = 0; |
401 | | |
402 | 120k | for (size_t j = 0; j < 4; j++) |
403 | 96.2k | { |
404 | 96.2k | #if !defined(ASTCENC_DECOMPRESS_ONLY) |
405 | 96.2k | di.texel_weight_contribs_float_tr[j][i] = 0; |
406 | 96.2k | #endif |
407 | 96.2k | di.texel_weights_tr[j][i] = 0; |
408 | 96.2k | di.texel_weight_contribs_int_tr[j][i] = 0; |
409 | 96.2k | } |
410 | 24.0k | } |
411 | | |
412 | 81.0k | #if !defined(ASTCENC_DECOMPRESS_ONLY) |
413 | | // Initialize array tail so we can over-fetch with SIMD later to avoid loop tails |
414 | | // Match last texel in active lane in SIMD group, for better gathers |
415 | 81.0k | unsigned int last_texel_count_wt = wb.texel_count_of_weight[weights_per_block - 1]; |
416 | 81.0k | uint8_t last_texel = di.weight_texels_tr[last_texel_count_wt - 1][weights_per_block - 1]; |
417 | | |
418 | 81.0k | size_t weights_per_block_simd = round_up_to_simd_multiple_vla(weights_per_block); |
419 | 155k | for (size_t i = weights_per_block; i < weights_per_block_simd; i++) |
420 | 74.0k | { |
421 | 74.0k | di.weight_texel_count[i] = 0; |
422 | | |
423 | 1.40M | for (size_t j = 0; j < max_texel_count_of_weight; j++) |
424 | 1.33M | { |
425 | 1.33M | di.weight_texels_tr[j][i] = last_texel; |
426 | 1.33M | di.weights_texel_contribs_tr[j][i] = 0.0f; |
427 | 1.33M | } |
428 | 74.0k | } |
429 | 81.0k | #endif |
430 | | |
431 | 81.0k | di.texel_count = static_cast<uint8_t>(texels_per_block); |
432 | 81.0k | di.weight_count = static_cast<uint8_t>(weights_per_block); |
433 | 81.0k | di.weight_x = static_cast<uint8_t>(weights_x); |
434 | 81.0k | di.weight_y = static_cast<uint8_t>(weights_y); |
435 | 81.0k | di.weight_z = 1; |
436 | 81.0k | } |
437 | | |
438 | | /** |
439 | | * @brief Create a 3D decimation entry for a block-size and weight-decimation pair. |
440 | | * |
441 | | * @param texels_x The number of texels in the X dimension. |
442 | | * @param texels_y The number of texels in the Y dimension. |
443 | | * @param texels_z The number of texels in the Z dimension. |
444 | | * @param weights_x The number of weights in the X dimension. |
445 | | * @param weights_y The number of weights in the Y dimension. |
446 | | * @param weights_z The number of weights in the Z dimension. |
447 | | * @param[out] di The decimation info structure to populate. |
448 | | @param[out] wb The decimation table init scratch working buffers. |
449 | | */ |
450 | | static void init_decimation_info_3d( |
451 | | unsigned int texels_x, |
452 | | unsigned int texels_y, |
453 | | unsigned int texels_z, |
454 | | unsigned int weights_x, |
455 | | unsigned int weights_y, |
456 | | unsigned int weights_z, |
457 | | decimation_info& di, |
458 | | dt_init_working_buffers& wb |
459 | 78 | ) { |
460 | 78 | unsigned int texels_per_block = texels_x * texels_y * texels_z; |
461 | 78 | unsigned int weights_per_block = weights_x * weights_y * weights_z; |
462 | | |
463 | 78 | #if !defined(ASTCENC_DECOMPRESS_ONLY) |
464 | 78 | uint8_t max_texel_count_of_weight = 0; |
465 | 78 | #endif |
466 | | |
467 | 78 | promise(weights_per_block > 0); |
468 | 78 | promise(texels_per_block > 0); |
469 | | |
470 | 3.03k | for (unsigned int i = 0; i < weights_per_block; i++) |
471 | 2.95k | { |
472 | 2.95k | wb.texel_count_of_weight[i] = 0; |
473 | 2.95k | } |
474 | | |
475 | 16.9k | for (unsigned int i = 0; i < texels_per_block; i++) |
476 | 16.8k | { |
477 | 16.8k | wb.weight_count_of_texel[i] = 0; |
478 | 16.8k | } |
479 | | |
480 | 546 | for (unsigned int z = 0; z < texels_z; z++) |
481 | 468 | { |
482 | 3.27k | for (unsigned int y = 0; y < texels_y; y++) |
483 | 2.80k | { |
484 | 19.6k | for (unsigned int x = 0; x < texels_x; x++) |
485 | 16.8k | { |
486 | 16.8k | int texel = (z * texels_y + y) * texels_x + x; |
487 | | |
488 | 16.8k | int x_weight = (((1024 + texels_x / 2) / (texels_x - 1)) * x * (weights_x - 1) + 32) >> 6; |
489 | 16.8k | int y_weight = (((1024 + texels_y / 2) / (texels_y - 1)) * y * (weights_y - 1) + 32) >> 6; |
490 | 16.8k | int z_weight = (((1024 + texels_z / 2) / (texels_z - 1)) * z * (weights_z - 1) + 32) >> 6; |
491 | | |
492 | 16.8k | int x_weight_frac = x_weight & 0xF; |
493 | 16.8k | int y_weight_frac = y_weight & 0xF; |
494 | 16.8k | int z_weight_frac = z_weight & 0xF; |
495 | 16.8k | int x_weight_int = x_weight >> 4; |
496 | 16.8k | int y_weight_int = y_weight >> 4; |
497 | 16.8k | int z_weight_int = z_weight >> 4; |
498 | 16.8k | int qweight[4]; |
499 | 16.8k | int weight[4]; |
500 | 16.8k | qweight[0] = (z_weight_int * weights_y + y_weight_int) * weights_x + x_weight_int; |
501 | 16.8k | qweight[3] = ((z_weight_int + 1) * weights_y + (y_weight_int + 1)) * weights_x + (x_weight_int + 1); |
502 | | |
503 | | // simplex interpolation |
504 | 16.8k | int fs = x_weight_frac; |
505 | 16.8k | int ft = y_weight_frac; |
506 | 16.8k | int fp = z_weight_frac; |
507 | | |
508 | 16.8k | int cas = ((fs > ft) << 2) + ((ft > fp) << 1) + ((fs > fp)); |
509 | 16.8k | int N = weights_x; |
510 | 16.8k | int NM = weights_x * weights_y; |
511 | | |
512 | 16.8k | int s1, s2, w0, w1, w2, w3; |
513 | 16.8k | switch (cas) |
514 | 16.8k | { |
515 | 1.15k | case 7: |
516 | 1.15k | s1 = 1; |
517 | 1.15k | s2 = N; |
518 | 1.15k | w0 = 16 - fs; |
519 | 1.15k | w1 = fs - ft; |
520 | 1.15k | w2 = ft - fp; |
521 | 1.15k | w3 = fp; |
522 | 1.15k | break; |
523 | 2.10k | case 3: |
524 | 2.10k | s1 = N; |
525 | 2.10k | s2 = 1; |
526 | 2.10k | w0 = 16 - ft; |
527 | 2.10k | w1 = ft - fs; |
528 | 2.10k | w2 = fs - fp; |
529 | 2.10k | w3 = fp; |
530 | 2.10k | break; |
531 | 3.10k | case 5: |
532 | 3.10k | s1 = 1; |
533 | 3.10k | s2 = NM; |
534 | 3.10k | w0 = 16 - fs; |
535 | 3.10k | w1 = fs - fp; |
536 | 3.10k | w2 = fp - ft; |
537 | 3.10k | w3 = ft; |
538 | 3.10k | break; |
539 | 2.10k | case 4: |
540 | 2.10k | s1 = NM; |
541 | 2.10k | s2 = 1; |
542 | 2.10k | w0 = 16 - fp; |
543 | 2.10k | w1 = fp - fs; |
544 | 2.10k | w2 = fs - ft; |
545 | 2.10k | w3 = ft; |
546 | 2.10k | break; |
547 | 3.10k | case 2: |
548 | 3.10k | s1 = N; |
549 | 3.10k | s2 = NM; |
550 | 3.10k | w0 = 16 - ft; |
551 | 3.10k | w1 = ft - fp; |
552 | 3.10k | w2 = fp - fs; |
553 | 3.10k | w3 = fs; |
554 | 3.10k | break; |
555 | 5.28k | case 0: |
556 | 5.28k | s1 = NM; |
557 | 5.28k | s2 = N; |
558 | 5.28k | w0 = 16 - fp; |
559 | 5.28k | w1 = fp - ft; |
560 | 5.28k | w2 = ft - fs; |
561 | 5.28k | w3 = fs; |
562 | 5.28k | break; |
563 | 0 | default: |
564 | 0 | s1 = NM; |
565 | 0 | s2 = N; |
566 | 0 | w0 = 16 - fp; |
567 | 0 | w1 = fp - ft; |
568 | 0 | w2 = ft - fs; |
569 | 0 | w3 = fs; |
570 | 0 | break; |
571 | 16.8k | } |
572 | | |
573 | 16.8k | qweight[1] = qweight[0] + s1; |
574 | 16.8k | qweight[2] = qweight[1] + s2; |
575 | 16.8k | weight[0] = w0; |
576 | 16.8k | weight[1] = w1; |
577 | 16.8k | weight[2] = w2; |
578 | 16.8k | weight[3] = w3; |
579 | | |
580 | 84.2k | for (unsigned int i = 0; i < 4; i++) |
581 | 67.3k | { |
582 | 67.3k | if (weight[i] != 0) |
583 | 42.8k | { |
584 | 42.8k | wb.grid_weights_of_texel[texel][wb.weight_count_of_texel[texel]] = static_cast<uint8_t>(qweight[i]); |
585 | 42.8k | wb.weights_of_texel[texel][wb.weight_count_of_texel[texel]] = static_cast<uint8_t>(weight[i]); |
586 | 42.8k | wb.weight_count_of_texel[texel]++; |
587 | 42.8k | wb.texels_of_weight[qweight[i]][wb.texel_count_of_weight[qweight[i]]] = static_cast<uint8_t>(texel); |
588 | 42.8k | wb.texel_weights_of_weight[qweight[i]][wb.texel_count_of_weight[qweight[i]]] = static_cast<uint8_t>(weight[i]); |
589 | 42.8k | wb.texel_count_of_weight[qweight[i]]++; |
590 | 42.8k | #if !defined(ASTCENC_DECOMPRESS_ONLY) |
591 | 42.8k | max_texel_count_of_weight = astc::max(max_texel_count_of_weight, wb.texel_count_of_weight[qweight[i]]); |
592 | 42.8k | #endif |
593 | 42.8k | } |
594 | 67.3k | } |
595 | 16.8k | } |
596 | 2.80k | } |
597 | 468 | } |
598 | | |
599 | 78 | uint8_t max_texel_weight_count = 0; |
600 | 16.9k | for (unsigned int i = 0; i < texels_per_block; i++) |
601 | 16.8k | { |
602 | 16.8k | di.texel_weight_count[i] = wb.weight_count_of_texel[i]; |
603 | 16.8k | max_texel_weight_count = astc::max(max_texel_weight_count, di.texel_weight_count[i]); |
604 | | |
605 | | // Init all 4 entries so we can rely on zeros for vectorization |
606 | 84.2k | for (unsigned int j = 0; j < 4; j++) |
607 | 67.3k | { |
608 | 67.3k | di.texel_weight_contribs_int_tr[j][i] = 0; |
609 | 67.3k | #if !defined(ASTCENC_DECOMPRESS_ONLY) |
610 | 67.3k | di.texel_weight_contribs_float_tr[j][i] = 0.0f; |
611 | 67.3k | #endif |
612 | 67.3k | di.texel_weights_tr[j][i] = 0; |
613 | 67.3k | } |
614 | | |
615 | 59.6k | for (unsigned int j = 0; j < wb.weight_count_of_texel[i]; j++) |
616 | 42.8k | { |
617 | 42.8k | di.texel_weight_contribs_int_tr[j][i] = wb.weights_of_texel[i][j]; |
618 | 42.8k | #if !defined(ASTCENC_DECOMPRESS_ONLY) |
619 | 42.8k | di.texel_weight_contribs_float_tr[j][i] = static_cast<float>(wb.weights_of_texel[i][j]) * (1.0f / WEIGHTS_TEXEL_SUM); |
620 | 42.8k | #endif |
621 | 42.8k | di.texel_weights_tr[j][i] = wb.grid_weights_of_texel[i][j]; |
622 | 42.8k | } |
623 | 16.8k | } |
624 | | |
625 | 78 | di.max_texel_weight_count = max_texel_weight_count; |
626 | | |
627 | 78 | #if !defined(ASTCENC_DECOMPRESS_ONLY) |
628 | 3.03k | for (unsigned int i = 0; i < weights_per_block; i++) |
629 | 2.95k | { |
630 | 2.95k | unsigned int texel_count_wt = wb.texel_count_of_weight[i]; |
631 | 2.95k | di.weight_texel_count[i] = static_cast<uint8_t>(texel_count_wt); |
632 | | |
633 | 45.7k | for (unsigned int j = 0; j < texel_count_wt; j++) |
634 | 42.8k | { |
635 | 42.8k | unsigned int texel = wb.texels_of_weight[i][j]; |
636 | | |
637 | | // Create transposed versions of these for better vectorization |
638 | 42.8k | di.weight_texels_tr[j][i] = static_cast<uint8_t>(texel); |
639 | 42.8k | di.weights_texel_contribs_tr[j][i] = static_cast<float>(wb.texel_weights_of_weight[i][j]); |
640 | | |
641 | | // Store the per-texel contribution of this weight for each texel it contributes to |
642 | 42.8k | di.texel_contrib_for_weight[j][i] = 0.0f; |
643 | 80.2k | for (unsigned int k = 0; k < 4; k++) |
644 | 80.2k | { |
645 | 80.2k | uint8_t dttw = di.texel_weights_tr[k][texel]; |
646 | 80.2k | float dttwf = di.texel_weight_contribs_float_tr[k][texel]; |
647 | 80.2k | if (dttw == i && dttwf != 0.0f) |
648 | 42.8k | { |
649 | 42.8k | di.texel_contrib_for_weight[j][i] = di.texel_weight_contribs_float_tr[k][texel]; |
650 | 42.8k | break; |
651 | 42.8k | } |
652 | 80.2k | } |
653 | 42.8k | } |
654 | | |
655 | | // Initialize array tail so we can over-fetch with SIMD later to avoid loop tails |
656 | | // Match last texel in active lane in SIMD group, for better gathers |
657 | 2.95k | uint8_t last_texel = di.weight_texels_tr[texel_count_wt - 1][i]; |
658 | 25.4k | for (unsigned int j = texel_count_wt; j < max_texel_count_of_weight; j++) |
659 | 22.5k | { |
660 | 22.5k | di.weight_texels_tr[j][i] = last_texel; |
661 | 22.5k | di.weights_texel_contribs_tr[j][i] = 0.0f; |
662 | 22.5k | } |
663 | 2.95k | } |
664 | 78 | #endif |
665 | | |
666 | | // Initialize array tail so we can over-fetch with SIMD later to avoid loop tails |
667 | 78 | size_t texels_per_block_simd = round_up_to_simd_multiple_vla(texels_per_block); |
668 | 78 | for (size_t i = texels_per_block; i < texels_per_block_simd; i++) |
669 | 0 | { |
670 | 0 | di.texel_weight_count[i] = 0; |
671 | |
|
672 | 0 | for (size_t j = 0; j < 4; j++) |
673 | 0 | { |
674 | 0 | #if !defined(ASTCENC_DECOMPRESS_ONLY) |
675 | 0 | di.texel_weight_contribs_float_tr[j][i] = 0; |
676 | 0 | #endif |
677 | 0 | di.texel_weights_tr[j][i] = 0; |
678 | 0 | di.texel_weight_contribs_int_tr[j][i] = 0; |
679 | 0 | } |
680 | 0 | } |
681 | | |
682 | 78 | #if !defined(ASTCENC_DECOMPRESS_ONLY) |
683 | | // Initialize array tail so we can over-fetch with SIMD later to avoid loop tails |
684 | | // Match last texel in active lane in SIMD group, for better gathers |
685 | 78 | int last_texel_count_wt = wb.texel_count_of_weight[weights_per_block - 1]; |
686 | 78 | uint8_t last_texel = di.weight_texels_tr[last_texel_count_wt - 1][weights_per_block - 1]; |
687 | | |
688 | 78 | size_t weights_per_block_simd = round_up_to_simd_multiple_vla(weights_per_block); |
689 | 118 | for (size_t i = weights_per_block; i < weights_per_block_simd; i++) |
690 | 40 | { |
691 | 40 | di.weight_texel_count[i] = 0; |
692 | | |
693 | 1.15k | for (size_t j = 0; j < max_texel_count_of_weight; j++) |
694 | 1.11k | { |
695 | 1.11k | di.weight_texels_tr[j][i] = last_texel; |
696 | 1.11k | di.weights_texel_contribs_tr[j][i] = 0.0f; |
697 | 1.11k | } |
698 | 40 | } |
699 | 78 | #endif |
700 | | |
701 | 78 | di.texel_count = static_cast<uint8_t>(texels_per_block); |
702 | 78 | di.weight_count = static_cast<uint8_t>(weights_per_block); |
703 | 78 | di.weight_x = static_cast<uint8_t>(weights_x); |
704 | 78 | di.weight_y = static_cast<uint8_t>(weights_y); |
705 | 78 | di.weight_z = static_cast<uint8_t>(weights_z); |
706 | 78 | } |
707 | | |
708 | | #if !defined(ASTCENC_DECOMPRESS_ONLY) |
709 | | /** |
710 | | * @brief Assign the texels to use for kmeans clustering. |
711 | | * |
712 | | * The max limit is @c BLOCK_MAX_KMEANS_TEXELS; above this a random selection is used. |
713 | | * The @c bsd.texel_count is an input and must be populated beforehand. |
714 | | * |
715 | | * @param[in,out] bsd The block size descriptor to populate. |
716 | | */ |
717 | | static void assign_kmeans_texels( |
718 | | block_size_descriptor& bsd |
719 | 3.49k | ) { |
720 | | // Use all texels for kmeans on a small block |
721 | 3.49k | if (bsd.texel_count <= BLOCK_MAX_KMEANS_TEXELS) |
722 | 2.97k | { |
723 | 78.5k | for (uint8_t i = 0; i < bsd.texel_count; i++) |
724 | 75.5k | { |
725 | 75.5k | bsd.kmeans_texels[i] = i; |
726 | 75.5k | } |
727 | | |
728 | 2.97k | return; |
729 | 2.97k | } |
730 | | |
731 | | // Select a random subset of BLOCK_MAX_KMEANS_TEXELS for kmeans on a large block |
732 | 525 | uint64_t rng_state[2]; |
733 | 525 | astc::rand_init(rng_state); |
734 | | |
735 | | // Initialize array used for tracking used indices |
736 | 525 | bool seen[BLOCK_MAX_TEXELS]; |
737 | 62.5k | for (uint8_t i = 0; i < bsd.texel_count; i++) |
738 | 62.0k | { |
739 | 62.0k | seen[i] = false; |
740 | 62.0k | } |
741 | | |
742 | | // Assign 64 random indices, retrying if we see repeats |
743 | 525 | unsigned int arr_elements_set = 0; |
744 | 48.9k | while (arr_elements_set < BLOCK_MAX_KMEANS_TEXELS) |
745 | 48.3k | { |
746 | 48.3k | uint8_t texel = static_cast<uint8_t>(astc::rand(rng_state)); |
747 | 48.3k | texel = texel % bsd.texel_count; |
748 | 48.3k | if (!seen[texel]) |
749 | 33.6k | { |
750 | 33.6k | bsd.kmeans_texels[arr_elements_set++] = texel; |
751 | 33.6k | seen[texel] = true; |
752 | 33.6k | } |
753 | 48.3k | } |
754 | 525 | } |
755 | | #endif |
756 | | |
757 | | /** |
758 | | * @brief Allocate a single 2D decimation table entry. |
759 | | * |
760 | | * @param texels_x The number of texels in the X dimension. |
761 | | * @param texels_y The number of texels in the Y dimension. |
762 | | * @param weights_x The number of weights in the X dimension. |
763 | | * @param weights_y The number of weights in the Y dimension. |
764 | | * @param bsd The block size descriptor we are populating. |
765 | | * @param wb The decimation table init scratch working buffers. |
766 | | * @param index The packed array index to populate. |
767 | | */ |
768 | | static void construct_dt_entry_2d( |
769 | | unsigned int texels_x, |
770 | | unsigned int texels_y, |
771 | | unsigned int weights_x, |
772 | | unsigned int weights_y, |
773 | | block_size_descriptor& bsd, |
774 | | dt_init_working_buffers& wb, |
775 | | unsigned int index |
776 | 81.0k | ) { |
777 | 81.0k | unsigned int weight_count = weights_x * weights_y; |
778 | 81.0k | assert(weight_count <= BLOCK_MAX_WEIGHTS); |
779 | | |
780 | 81.0k | bool try_2planes = (2 * weight_count) <= BLOCK_MAX_WEIGHTS; |
781 | | |
782 | 81.0k | decimation_info& di = bsd.decimation_tables[index]; |
783 | 81.0k | init_decimation_info_2d(texels_x, texels_y, weights_x, weights_y, di, wb); |
784 | | |
785 | 81.0k | int maxprec_1plane = -1; |
786 | 81.0k | int maxprec_2planes = -1; |
787 | 1.05M | for (int i = 0; i < 12; i++) |
788 | 972k | { |
789 | 972k | unsigned int bits_1plane = get_ise_sequence_bitcount(weight_count, static_cast<quant_method>(i)); |
790 | 972k | if (bits_1plane >= BLOCK_MIN_WEIGHT_BITS && bits_1plane <= BLOCK_MAX_WEIGHT_BITS) |
791 | 567k | { |
792 | 567k | maxprec_1plane = i; |
793 | 567k | } |
794 | | |
795 | 972k | if (try_2planes) |
796 | 722k | { |
797 | 722k | unsigned int bits_2planes = get_ise_sequence_bitcount(2 * weight_count, static_cast<quant_method>(i)); |
798 | 722k | if (bits_2planes >= BLOCK_MIN_WEIGHT_BITS && bits_2planes <= BLOCK_MAX_WEIGHT_BITS) |
799 | 388k | { |
800 | 388k | maxprec_2planes = i; |
801 | 388k | } |
802 | 722k | } |
803 | 972k | } |
804 | | |
805 | | // At least one of the two should be valid ... |
806 | 81.0k | assert(maxprec_1plane >= 0 || maxprec_2planes >= 0); |
807 | 81.0k | bsd.decimation_modes[index].maxprec_1plane = static_cast<int8_t>(maxprec_1plane); |
808 | 81.0k | bsd.decimation_modes[index].maxprec_2planes = static_cast<int8_t>(maxprec_2planes); |
809 | 81.0k | bsd.decimation_modes[index].refprec_1plane = 0; |
810 | 81.0k | bsd.decimation_modes[index].refprec_2planes = 0; |
811 | 81.0k | } |
812 | | |
813 | | /** |
814 | | * @brief Allocate block modes and decimation tables for a single 2D block size. |
815 | | * |
816 | | * @param texels_x The number of texels in the X dimension. |
817 | | * @param texels_y The number of texels in the Y dimension. |
818 | | * @param can_omit_modes Can we discard modes that astcenc won't use, even if legal? |
819 | | * @param mode_cutoff Percentile cutoff in range [0,1]. Low values more likely to be used. |
820 | | * @param[out] bsd The block size descriptor to populate. |
821 | | */ |
822 | | static void construct_block_size_descriptor_2d( |
823 | | unsigned int texels_x, |
824 | | unsigned int texels_y, |
825 | | bool can_omit_modes, |
826 | | float mode_cutoff, |
827 | | block_size_descriptor& bsd |
828 | 3.49k | ) { |
829 | | // Store a remap table for storing packed decimation modes. |
830 | | // Indexing uses [Y * 16 + X] and max size for each axis is 12. |
831 | 3.49k | static const unsigned int MAX_DMI = 12 * 16 + 12; |
832 | 3.49k | int decimation_mode_index[MAX_DMI]; |
833 | | |
834 | 3.49k | dt_init_working_buffers* wb = new dt_init_working_buffers; |
835 | | |
836 | 3.49k | bsd.dim_x = static_cast<uint8_t>(texels_x); |
837 | 3.49k | bsd.dim_y = static_cast<uint8_t>(texels_y); |
838 | 3.49k | bsd.dim_z = 1; |
839 | 3.49k | bsd.texel_count = static_cast<uint8_t>(texels_x * texels_y); |
840 | | |
841 | 716k | for (unsigned int i = 0; i < MAX_DMI; i++) |
842 | 712k | { |
843 | 712k | decimation_mode_index[i] = -1; |
844 | 712k | } |
845 | | |
846 | | // Gather all the decimation grids that can be used with the current block |
847 | 3.49k | #if !defined(ASTCENC_DECOMPRESS_ONLY) |
848 | 3.49k | const float *percentiles = get_2d_percentile_table(texels_x, texels_y); |
849 | 3.49k | float always_cutoff = 0.0f; |
850 | | #else |
851 | | // Unused in decompress-only builds |
852 | | (void)can_omit_modes; |
853 | | (void)mode_cutoff; |
854 | | #endif |
855 | | |
856 | | // Construct the list of block formats referencing the decimation tables |
857 | 3.49k | unsigned int packed_bm_idx = 0; |
858 | 3.49k | unsigned int packed_dm_idx = 0; |
859 | | |
860 | | // Trackers |
861 | 3.49k | unsigned int bm_counts[4] { 0 }; |
862 | 3.49k | unsigned int dm_counts[4] { 0 }; |
863 | | |
864 | | // Clear the list to a known-bad value |
865 | 7.16M | for (unsigned int i = 0; i < WEIGHTS_MAX_BLOCK_MODES; i++) |
866 | 7.15M | { |
867 | 7.15M | bsd.block_mode_packed_index[i] = BLOCK_BAD_BLOCK_MODE; |
868 | 7.15M | } |
869 | | |
870 | | // Iterate four times to build a usefully ordered list: |
871 | | // - Pass 0 - keep selected single plane "always" block modes |
872 | | // - Pass 1 - keep selected single plane "non-always" block modes |
873 | | // - Pass 2 - keep select dual plane block modes |
874 | | // - Pass 3 - keep everything else that's legal |
875 | 3.49k | unsigned int limit = can_omit_modes ? 3 : 4; |
876 | 16.1k | for (unsigned int j = 0; j < limit; j ++) |
877 | 12.6k | { |
878 | 26.0M | for (unsigned int i = 0; i < WEIGHTS_MAX_BLOCK_MODES; i++) |
879 | 25.9M | { |
880 | | // Skip modes we've already included in a previous pass |
881 | 25.9M | if (bsd.block_mode_packed_index[i] != BLOCK_BAD_BLOCK_MODE) |
882 | 316k | { |
883 | 316k | continue; |
884 | 316k | } |
885 | | |
886 | | // Decode parameters |
887 | 25.6M | unsigned int weights_x; |
888 | 25.6M | unsigned int weights_y; |
889 | 25.6M | bool is_dual_plane; |
890 | 25.6M | unsigned int quant_mode; |
891 | 25.6M | unsigned int weight_bits; |
892 | 25.6M | bool valid = decode_block_mode_2d(i, weights_x, weights_y, is_dual_plane, quant_mode, weight_bits); |
893 | | |
894 | | // Always skip invalid encodings for the current block size |
895 | 25.6M | if (!valid || (weights_x > texels_x) || (weights_y > texels_y)) |
896 | 21.9M | { |
897 | 21.9M | continue; |
898 | 21.9M | } |
899 | | |
900 | | // Selectively skip dual plane encodings |
901 | 3.71M | if (((j <= 1) && is_dual_plane) || (j == 2 && !is_dual_plane)) |
902 | 1.39M | { |
903 | 1.39M | continue; |
904 | 1.39M | } |
905 | | |
906 | | // Always skip encodings we can't physically encode based on |
907 | | // generic encoding bit availability |
908 | 2.31M | if (is_dual_plane) |
909 | 740k | { |
910 | | // This is the only check we need as only support 1 partition |
911 | 740k | if ((109 - weight_bits) <= 0) |
912 | 0 | { |
913 | 0 | continue; |
914 | 0 | } |
915 | 740k | } |
916 | 1.57M | else |
917 | 1.57M | { |
918 | | // This is conservative - fewer bits may be available for > 1 partition |
919 | 1.57M | if ((111 - weight_bits) <= 0) |
920 | 0 | { |
921 | 0 | continue; |
922 | 0 | } |
923 | 1.57M | } |
924 | | |
925 | | // Selectively skip encodings based on percentile |
926 | 2.31M | bool percentile_hit = false; |
927 | 2.31M | #if !defined(ASTCENC_DECOMPRESS_ONLY) |
928 | 2.31M | if (j == 0) |
929 | 617k | { |
930 | 617k | percentile_hit = percentiles[i] <= always_cutoff; |
931 | 617k | } |
932 | 1.69M | else |
933 | 1.69M | { |
934 | 1.69M | percentile_hit = percentiles[i] <= mode_cutoff; |
935 | 1.69M | } |
936 | 2.31M | #endif |
937 | | |
938 | 2.31M | if (j != 3 && !percentile_hit) |
939 | 1.48M | { |
940 | 1.48M | continue; |
941 | 1.48M | } |
942 | | |
943 | | // Allocate and initialize the decimation table entry if we've not used it yet |
944 | 825k | int decimation_mode = decimation_mode_index[weights_y * 16 + weights_x]; |
945 | 825k | if (decimation_mode < 0) |
946 | 81.0k | { |
947 | 81.0k | construct_dt_entry_2d(texels_x, texels_y, weights_x, weights_y, bsd, *wb, packed_dm_idx); |
948 | 81.0k | decimation_mode_index[weights_y * 16 + weights_x] = packed_dm_idx; |
949 | 81.0k | decimation_mode = packed_dm_idx; |
950 | | |
951 | 81.0k | dm_counts[j]++; |
952 | 81.0k | packed_dm_idx++; |
953 | 81.0k | } |
954 | | |
955 | 825k | auto& bm = bsd.block_modes[packed_bm_idx]; |
956 | | |
957 | 825k | bm.decimation_mode = static_cast<uint8_t>(decimation_mode); |
958 | 825k | bm.quant_mode = static_cast<uint8_t>(quant_mode); |
959 | 825k | bm.is_dual_plane = static_cast<uint8_t>(is_dual_plane); |
960 | 825k | bm.weight_bits = static_cast<uint8_t>(weight_bits); |
961 | 825k | bm.mode_index = static_cast<uint16_t>(i); |
962 | | |
963 | 825k | auto& dm = bsd.decimation_modes[decimation_mode]; |
964 | | |
965 | 825k | if (is_dual_plane) |
966 | 334k | { |
967 | 334k | dm.set_ref_2plane(bm.get_weight_quant_mode()); |
968 | 334k | } |
969 | 490k | else |
970 | 490k | { |
971 | 490k | dm.set_ref_1plane(bm.get_weight_quant_mode()); |
972 | 490k | } |
973 | | |
974 | 825k | bsd.block_mode_packed_index[i] = static_cast<uint16_t>(packed_bm_idx); |
975 | | |
976 | 825k | packed_bm_idx++; |
977 | 825k | bm_counts[j]++; |
978 | 825k | } |
979 | 12.6k | } |
980 | | |
981 | 3.49k | bsd.block_mode_count_1plane_always = bm_counts[0]; |
982 | 3.49k | bsd.block_mode_count_1plane_selected = bm_counts[0] + bm_counts[1]; |
983 | 3.49k | bsd.block_mode_count_1plane_2plane_selected = bm_counts[0] + bm_counts[1] + bm_counts[2]; |
984 | 3.49k | bsd.block_mode_count_all = bm_counts[0] + bm_counts[1] + bm_counts[2] + bm_counts[3]; |
985 | | |
986 | 3.49k | bsd.decimation_mode_count_always = dm_counts[0]; |
987 | 3.49k | bsd.decimation_mode_count_selected = dm_counts[0] + dm_counts[1] + dm_counts[2]; |
988 | 3.49k | bsd.decimation_mode_count_all = dm_counts[0] + dm_counts[1] + dm_counts[2] + dm_counts[3]; |
989 | | |
990 | 3.49k | #if !defined(ASTCENC_DECOMPRESS_ONLY) |
991 | 3.49k | assert(bsd.block_mode_count_1plane_always > 0); |
992 | 3.49k | assert(bsd.decimation_mode_count_always > 0); |
993 | | |
994 | 3.49k | delete[] percentiles; |
995 | 3.49k | #endif |
996 | | |
997 | | // Ensure the end of the array contains valid data (should never get read) |
998 | 226k | for (unsigned int i = bsd.decimation_mode_count_all; i < WEIGHTS_MAX_DECIMATION_MODES; i++) |
999 | 222k | { |
1000 | 222k | bsd.decimation_modes[i].maxprec_1plane = -1; |
1001 | 222k | bsd.decimation_modes[i].maxprec_2planes = -1; |
1002 | 222k | bsd.decimation_modes[i].refprec_1plane = 0; |
1003 | 222k | bsd.decimation_modes[i].refprec_2planes = 0; |
1004 | 222k | } |
1005 | | |
1006 | 3.49k | #if !defined(ASTCENC_DECOMPRESS_ONLY) |
1007 | | // Determine the texels to use for kmeans clustering. |
1008 | 3.49k | assign_kmeans_texels(bsd); |
1009 | 3.49k | #endif |
1010 | | |
1011 | 3.49k | delete wb; |
1012 | 3.49k | } |
1013 | | |
1014 | | /** |
1015 | | * @brief Allocate block modes and decimation tables for a single 3D block size. |
1016 | | * |
1017 | | * TODO: This function doesn't include all of the heuristics that we use for 2D block sizes such as |
1018 | | * the percentile mode cutoffs. If 3D becomes more widely used we should look at this. |
1019 | | * |
1020 | | * @param texels_x The number of texels in the X dimension. |
1021 | | * @param texels_y The number of texels in the Y dimension. |
1022 | | * @param texels_z The number of texels in the Z dimension. |
1023 | | * @param[out] bsd The block size descriptor to populate. |
1024 | | */ |
1025 | | static void construct_block_size_descriptor_3d( |
1026 | | unsigned int texels_x, |
1027 | | unsigned int texels_y, |
1028 | | unsigned int texels_z, |
1029 | | block_size_descriptor& bsd |
1030 | 1 | ) { |
1031 | | // Store a remap table for storing packed decimation modes. |
1032 | | // Indexing uses [Z * 64 + Y * 8 + X] and max size for each axis is 6. |
1033 | 1 | static constexpr unsigned int MAX_DMI = 6 * 64 + 6 * 8 + 6; |
1034 | 1 | int decimation_mode_index[MAX_DMI]; |
1035 | 1 | unsigned int decimation_mode_count = 0; |
1036 | | |
1037 | 1 | dt_init_working_buffers* wb = new dt_init_working_buffers; |
1038 | | |
1039 | 1 | bsd.dim_x = static_cast<uint8_t>(texels_x); |
1040 | 1 | bsd.dim_y = static_cast<uint8_t>(texels_y); |
1041 | 1 | bsd.dim_z = static_cast<uint8_t>(texels_z); |
1042 | 1 | bsd.texel_count = static_cast<uint8_t>(texels_x * texels_y * texels_z); |
1043 | | |
1044 | 439 | for (unsigned int i = 0; i < MAX_DMI; i++) |
1045 | 438 | { |
1046 | 438 | decimation_mode_index[i] = -1; |
1047 | 438 | } |
1048 | | |
1049 | | // gather all the infill-modes that can be used with the current block size |
1050 | 6 | for (unsigned int weights_x = 2; weights_x <= texels_x; weights_x++) |
1051 | 5 | { |
1052 | 30 | for (unsigned int weights_y = 2; weights_y <= texels_y; weights_y++) |
1053 | 25 | { |
1054 | 150 | for (unsigned int weights_z = 2; weights_z <= texels_z; weights_z++) |
1055 | 125 | { |
1056 | 125 | unsigned int weight_count = weights_x * weights_y * weights_z; |
1057 | 125 | if (weight_count > BLOCK_MAX_WEIGHTS) |
1058 | 47 | { |
1059 | 47 | continue; |
1060 | 47 | } |
1061 | | |
1062 | 78 | decimation_info& di = bsd.decimation_tables[decimation_mode_count]; |
1063 | 78 | decimation_mode_index[weights_z * 64 + weights_y * 8 + weights_x] = decimation_mode_count; |
1064 | 78 | init_decimation_info_3d(texels_x, texels_y, texels_z, weights_x, weights_y, weights_z, di, *wb); |
1065 | | |
1066 | 78 | int maxprec_1plane = -1; |
1067 | 78 | int maxprec_2planes = -1; |
1068 | 1.01k | for (unsigned int i = 0; i < 12; i++) |
1069 | 936 | { |
1070 | 936 | unsigned int bits_1plane = get_ise_sequence_bitcount(weight_count, static_cast<quant_method>(i)); |
1071 | 936 | if (bits_1plane >= BLOCK_MIN_WEIGHT_BITS && bits_1plane <= BLOCK_MAX_WEIGHT_BITS) |
1072 | 417 | { |
1073 | 417 | maxprec_1plane = i; |
1074 | 417 | } |
1075 | | |
1076 | 936 | unsigned int bits_2planes = get_ise_sequence_bitcount(2 * weight_count, static_cast<quant_method>(i)); |
1077 | 936 | if (bits_2planes >= BLOCK_MIN_WEIGHT_BITS && bits_2planes <= BLOCK_MAX_WEIGHT_BITS) |
1078 | 154 | { |
1079 | 154 | maxprec_2planes = i; |
1080 | 154 | } |
1081 | 936 | } |
1082 | | |
1083 | 78 | if ((2 * weight_count) > BLOCK_MAX_WEIGHTS) |
1084 | 46 | { |
1085 | 46 | maxprec_2planes = -1; |
1086 | 46 | } |
1087 | | |
1088 | 78 | bsd.decimation_modes[decimation_mode_count].maxprec_1plane = static_cast<int8_t>(maxprec_1plane); |
1089 | 78 | bsd.decimation_modes[decimation_mode_count].maxprec_2planes = static_cast<int8_t>(maxprec_2planes); |
1090 | 78 | bsd.decimation_modes[decimation_mode_count].refprec_1plane = maxprec_1plane == -1 ? 0 : 0xFFFF; |
1091 | 78 | bsd.decimation_modes[decimation_mode_count].refprec_2planes = maxprec_2planes == -1 ? 0 : 0xFFFF; |
1092 | 78 | decimation_mode_count++; |
1093 | 78 | } |
1094 | 25 | } |
1095 | 5 | } |
1096 | | |
1097 | | // Ensure the end of the array contains valid data (should never get read) |
1098 | 10 | for (unsigned int i = decimation_mode_count; i < WEIGHTS_MAX_DECIMATION_MODES; i++) |
1099 | 9 | { |
1100 | 9 | bsd.decimation_modes[i].maxprec_1plane = -1; |
1101 | 9 | bsd.decimation_modes[i].maxprec_2planes = -1; |
1102 | 9 | bsd.decimation_modes[i].refprec_1plane = 0; |
1103 | 9 | bsd.decimation_modes[i].refprec_2planes = 0; |
1104 | 9 | } |
1105 | | |
1106 | 1 | bsd.decimation_mode_count_always = 0; // Skipped for 3D modes |
1107 | 1 | bsd.decimation_mode_count_selected = decimation_mode_count; |
1108 | 1 | bsd.decimation_mode_count_all = decimation_mode_count; |
1109 | | |
1110 | | // Construct the list of block formats referencing the decimation tables |
1111 | | |
1112 | | // Clear the list to a known-bad value |
1113 | 2.04k | for (unsigned int i = 0; i < WEIGHTS_MAX_BLOCK_MODES; i++) |
1114 | 2.04k | { |
1115 | 2.04k | bsd.block_mode_packed_index[i] = BLOCK_BAD_BLOCK_MODE; |
1116 | 2.04k | } |
1117 | | |
1118 | 1 | unsigned int packed_idx = 0; |
1119 | 1 | unsigned int bm_counts[2] { 0 }; |
1120 | | |
1121 | | // Iterate two times to build a usefully ordered list: |
1122 | | // - Pass 0 - keep valid single plane block modes |
1123 | | // - Pass 1 - keep valid dual plane block modes |
1124 | 3 | for (unsigned int j = 0; j < 2; j++) |
1125 | 2 | { |
1126 | 4.09k | for (unsigned int i = 0; i < WEIGHTS_MAX_BLOCK_MODES; i++) |
1127 | 4.09k | { |
1128 | | // Skip modes we've already included in a previous pass |
1129 | 4.09k | if (bsd.block_mode_packed_index[i] != BLOCK_BAD_BLOCK_MODE) |
1130 | 435 | { |
1131 | 435 | continue; |
1132 | 435 | } |
1133 | | |
1134 | 3.66k | unsigned int weights_x; |
1135 | 3.66k | unsigned int weights_y; |
1136 | 3.66k | unsigned int weights_z; |
1137 | 3.66k | bool is_dual_plane; |
1138 | 3.66k | unsigned int quant_mode; |
1139 | 3.66k | unsigned int weight_bits; |
1140 | | |
1141 | 3.66k | bool valid = decode_block_mode_3d(i, weights_x, weights_y, weights_z, is_dual_plane, quant_mode, weight_bits); |
1142 | | // Skip invalid encodings |
1143 | 3.66k | if (!valid || weights_x > texels_x || weights_y > texels_y || weights_z > texels_z) |
1144 | 2.97k | { |
1145 | 2.97k | continue; |
1146 | 2.97k | } |
1147 | | |
1148 | | // Skip encodings in the wrong iteration |
1149 | 689 | if ((j == 0 && is_dual_plane) || (j == 1 && !is_dual_plane)) |
1150 | 127 | { |
1151 | 127 | continue; |
1152 | 127 | } |
1153 | | |
1154 | | // Always skip encodings we can't physically encode based on bit availability |
1155 | 562 | if (is_dual_plane) |
1156 | 127 | { |
1157 | | // This is the only check we need as only support 1 partition |
1158 | 127 | if ((109 - weight_bits) <= 0) |
1159 | 0 | { |
1160 | 0 | continue; |
1161 | 0 | } |
1162 | 127 | } |
1163 | 435 | else |
1164 | 435 | { |
1165 | | // This is conservative - fewer bits may be available for > 1 partition |
1166 | 435 | if ((111 - weight_bits) <= 0) |
1167 | 0 | { |
1168 | 0 | continue; |
1169 | 0 | } |
1170 | 435 | } |
1171 | | |
1172 | 562 | int decimation_mode = decimation_mode_index[weights_z * 64 + weights_y * 8 + weights_x]; |
1173 | 562 | bsd.block_modes[packed_idx].decimation_mode = static_cast<uint8_t>(decimation_mode); |
1174 | 562 | bsd.block_modes[packed_idx].quant_mode = static_cast<uint8_t>(quant_mode); |
1175 | 562 | bsd.block_modes[packed_idx].weight_bits = static_cast<uint8_t>(weight_bits); |
1176 | 562 | bsd.block_modes[packed_idx].is_dual_plane = static_cast<uint8_t>(is_dual_plane); |
1177 | 562 | bsd.block_modes[packed_idx].mode_index = static_cast<uint16_t>(i); |
1178 | | |
1179 | 562 | bsd.block_mode_packed_index[i] = static_cast<uint16_t>(packed_idx); |
1180 | 562 | bm_counts[j]++; |
1181 | 562 | packed_idx++; |
1182 | 562 | } |
1183 | 2 | } |
1184 | | |
1185 | 1 | bsd.block_mode_count_1plane_always = 0; // Skipped for 3D modes |
1186 | 1 | bsd.block_mode_count_1plane_selected = bm_counts[0]; |
1187 | 1 | bsd.block_mode_count_1plane_2plane_selected = bm_counts[0] + bm_counts[1]; |
1188 | 1 | bsd.block_mode_count_all = bm_counts[0] + bm_counts[1]; |
1189 | | |
1190 | 1 | #if !defined(ASTCENC_DECOMPRESS_ONLY) |
1191 | | // Determine the texels to use for kmeans clustering. |
1192 | 1 | assign_kmeans_texels(bsd); |
1193 | 1 | #endif |
1194 | | |
1195 | 1 | delete wb; |
1196 | 1 | } |
1197 | | |
1198 | | /* See header for documentation. */ |
1199 | | void init_block_size_descriptor( |
1200 | | unsigned int texels_x, |
1201 | | unsigned int texels_y, |
1202 | | unsigned int texels_z, |
1203 | | bool can_omit_modes, |
1204 | | unsigned int partition_count_cutoff, |
1205 | | float mode_cutoff, |
1206 | | block_size_descriptor& bsd |
1207 | 3.49k | ) { |
1208 | 3.49k | if (texels_z > 1) |
1209 | 1 | { |
1210 | 1 | construct_block_size_descriptor_3d(texels_x, texels_y, texels_z, bsd); |
1211 | 1 | } |
1212 | 3.49k | else |
1213 | 3.49k | { |
1214 | 3.49k | construct_block_size_descriptor_2d(texels_x, texels_y, can_omit_modes, mode_cutoff, bsd); |
1215 | 3.49k | } |
1216 | | |
1217 | 3.49k | init_partition_tables(bsd, can_omit_modes, partition_count_cutoff); |
1218 | 3.49k | } |