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 */
29enum 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
54static 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
85struct 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
94const 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
261void 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
345void 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
391int 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