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