1 // SPDX-License-Identifier: Apache-2.0
2 // ----------------------------------------------------------------------------
3 // Copyright 2023 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 // This is a utility tool to generate quant tables
19 #include <algorithm>
20 #include <array>
21 #include <bitset>
22 #include <set>
23
24 /**
25 * @brief The ASTC quantization methods.
26 *
27 * Note, the values here are used directly in the encoding in the format so do not rearrange.
28 */
29 enum quant_method
30 {
31 QUANT_2 = 0,
32 QUANT_3 = 1,
33 QUANT_4 = 2,
34 QUANT_5 = 3,
35 QUANT_6 = 4,
36 QUANT_8 = 5,
37 QUANT_10 = 6,
38 QUANT_12 = 7,
39 QUANT_16 = 8,
40 QUANT_20 = 9,
41 QUANT_24 = 10,
42 QUANT_32 = 11,
43 QUANT_40 = 12,
44 QUANT_48 = 13,
45 QUANT_64 = 14,
46 QUANT_80 = 15,
47 QUANT_96 = 16,
48 QUANT_128 = 17,
49 QUANT_160 = 18,
50 QUANT_192 = 19,
51 QUANT_256 = 20
52 };
53
get_quant_level(quant_method method)54 static inline unsigned int get_quant_level(quant_method method)
55 {
56 switch (method)
57 {
58 case QUANT_2: return 2;
59 case QUANT_3: return 3;
60 case QUANT_4: return 4;
61 case QUANT_5: return 5;
62 case QUANT_6: return 6;
63 case QUANT_8: return 8;
64 case QUANT_10: return 10;
65 case QUANT_12: return 12;
66 case QUANT_16: return 16;
67 case QUANT_20: return 20;
68 case QUANT_24: return 24;
69 case QUANT_32: return 32;
70 case QUANT_40: return 40;
71 case QUANT_48: return 48;
72 case QUANT_64: return 64;
73 case QUANT_80: return 80;
74 case QUANT_96: return 96;
75 case QUANT_128: return 128;
76 case QUANT_160: return 160;
77 case QUANT_192: return 192;
78 case QUANT_256: return 256;
79 }
80
81 // Unreachable - the enum is fully described
82 return 0;
83 }
84
85 struct quant_config {
86 quant_method quant;
87 unsigned int bits;
88 unsigned int trits;
89 unsigned int quints;
90 unsigned int C;
91 unsigned int masks[6];
92 };
93
94 const std::array<quant_config, 17> quant_configs {{
95 {
96 QUANT_6,
97 1, 1, 0,
98 204,
99 {
100 0b000000000,
101 0b000000000,
102 0b000000000,
103 0b000000000,
104 0b000000000,
105 0b000000000
106 }
107 }, {
108 QUANT_8,
109 3, 0, 0,
110 0,
111 { 0 }
112 }, {
113 QUANT_10,
114 1, 0, 1,
115 113,
116 {
117 0b000000000,
118 0b000000000,
119 0b000000000,
120 0b000000000,
121 0b000000000,
122 0b000000000
123 }
124 }, {
125 QUANT_12,
126 2, 1, 0,
127 93,
128 {
129 0b000000000,
130 0b100010110,
131 0b000000000,
132 0b000000000,
133 0b000000000,
134 0b000000000
135 }
136 }, {
137 QUANT_16,
138 4, 0, 0,
139 0,
140 { 0 }
141 }, {
142 QUANT_20,
143 2, 0, 1,
144 54,
145 {
146 0b000000000,
147 0b100001100,
148 0b000000000,
149 0b000000000,
150 0b000000000,
151 0b000000000
152 }
153 }, {
154 QUANT_24,
155 3, 1, 0,
156 44,
157 {
158 0b000000000,
159 0b010000101,
160 0b100001010,
161 0b000000000,
162 0b000000000,
163 0b000000000
164 }
165 }, {
166 QUANT_32,
167 5, 0, 0,
168 0,
169 { 0 }
170 },
171 {
172 QUANT_40,
173 3, 0, 1,
174 26,
175 {
176 0b000000000,
177 0b010000010,
178 0b100000101,
179 0b000000000,
180 0b000000000,
181 0b000000000
182 }
183 }, {
184 QUANT_48,
185 4, 1, 0,
186 22,
187 {
188 0b000000000,
189 0b001000001,
190 0b010000010,
191 0b100000100,
192 0b000000000,
193 0b000000000
194 }
195 }, {
196 QUANT_64,
197 6, 0, 0,
198 0,
199 { 0 }
200 }, {
201 QUANT_80,
202 4, 0, 1,
203 13,
204 {
205 0b000000000,
206 0b001000000,
207 0b010000001,
208 0b100000010,
209 0b000000000,
210 0b000000000
211 }
212 }, {
213 QUANT_96,
214 5, 1, 0,
215 11,
216 {
217 0b000000000,
218 0b000100000,
219 0b001000000,
220 0b010000001,
221 0b100000010,
222 0b000000000
223 }
224 }, {
225 QUANT_128,
226 7, 0, 0,
227 0,
228 { 0 }
229 }, {
230 QUANT_160,
231 5, 0, 1,
232 6,
233 {
234 0b000000000,
235 0b000100000,
236 0b001000000,
237 0b010000000,
238 0b100000001,
239 0b000000000
240 }
241 }, {
242 QUANT_192,
243 6, 1, 0,
244 5,
245 {
246 0b000000000,
247 0b000010000,
248 0b000100000,
249 0b001000000,
250 0b010000000,
251 0b100000001
252 }
253 }, {
254 QUANT_256,
255 8, 0, 0,
256 0,
257 { 0 }
258 }
259 }};
260
generate_unpacked_quant( const quant_config& config, std::set<unsigned int>& set )261 void generate_unpacked_quant(
262 const quant_config& config,
263 std::set<unsigned int>& set
264 ) {
265 unsigned int levels = get_quant_level(config.quant);
266 unsigned int emitted = 0;
267
268 // Value has 1 trit and N bits
269 if (config.trits)
270 {
271 for (unsigned int D = 0; D < 3; D++)
272 {
273 unsigned int max_bits = 1 << config.bits;
274 for (unsigned int bits = 0; bits < max_bits; bits++)
275 {
276 unsigned int A = (bits & 1) * 0b111111111;
277 unsigned int B = 0;
278 unsigned int bit = bits;
279 for (const auto& mask_n: config.masks)
280 {
281 unsigned int bit_n = bit & 1;
282 bit >>= 1;
283 B += bit_n * mask_n;
284 }
285
286 unsigned int T = D * config.C + B;
287 T = T ^ A;
288 T = (A & 0x80) | (T >> 2);
289 set.insert(T);
290 }
291 }
292 }
293 // Value has 1 quint and N bits
294 else if (config.quints)
295 {
296 for (unsigned int D = 0; D < 5; D++)
297 {
298 unsigned int max_bits = 1 << config.bits;
299 for (unsigned int bits = 0; bits < max_bits; bits++)
300 {
301 unsigned int A = (bits & 1) * 0b111111111;
302 unsigned int B = 0;
303 unsigned int bit = bits;
304 for (const auto& mask_n: config.masks)
305 {
306 unsigned int bit_n = bit & 1;
307 bit >>= 1;
308 B += bit_n * mask_n;
309 }
310
311 unsigned int T = D * config.C + B;
312 T = T ^ A;
313 T = (A & 0x80) | (T >> 2);
314 set.insert(T);
315 }
316 }
317 }
318 // Value has N bits
319 else
320 {
321 unsigned int max_bits = 1 << config.bits;
322 for (unsigned int bits = 0; bits < max_bits; bits++)
323 {
324 unsigned int T = bits << (8 - config.bits);
325 int bits_remaining = 8 - config.bits;
326
327 while (bits_remaining > 0)
328 {
329 int shift = bits_remaining - config.bits;
330 bits_remaining -= config.bits;
331 if (shift > 0)
332 {
333 T |= bits << shift;
334 }
335 else
336 {
337 T |= bits >> -shift;
338 }
339 }
340 set.insert(T);
341 }
342 }
343 }
344
generate_unquant_to_unpacked_quant( const quant_config& config, const std::set<unsigned int>& set )345 void generate_unquant_to_unpacked_quant(
346 const quant_config& config,
347 const std::set<unsigned int>& set
348 ) {
349 for (unsigned int i = 0; i < 256; i++)
350 {
351 unsigned int min_dist = 256;
352 unsigned int val_lo = 256;
353 unsigned int val_hi = 0;
354
355 for (const auto& val: set)
356 {
357 unsigned int dist = std::max(i, val) - std::min(i, val);
358
359 if (dist < min_dist)
360 {
361 min_dist = dist;
362 val_lo = val;
363 val_hi = val;
364 }
365 else if (dist == min_dist)
366 {
367 val_lo = std::min(val_lo, val);
368 val_hi = std::max(val_hi, val);
369 }
370 }
371
372 if ((i % 16) == 0)
373 {
374 printf("\t\t");
375 }
376
377 printf("%3u, %3u", val_lo, val_hi);
378
379 if (i != 255)
380 {
381 printf(", ");
382 }
383
384 if ((i % 16) == 15)
385 {
386 printf("\n");
387 }
388 }
389 }
390
main(void)391 int main(void)
392 {
393 printf("const uint8_t color_unquant_to_uquant_tables[17][512] {\n");
394 for (size_t i = 0; i < quant_configs.size(); i++)
395 {
396 const auto& config = quant_configs[i];
397 std::set<unsigned int> set;
398
399 printf("\t{ // QUANT_%u\n", get_quant_level(config.quant));
400 generate_unpacked_quant(config, set);
401 generate_unquant_to_unpacked_quant(config, set);
402 printf("\t},\n");
403 }
404 printf("};\n");
405 return 0;
406 }
407