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