Coverage Report

Created: 2026-07-16 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}