1 // SPDX-License-Identifier: Apache-2.0
2 // ----------------------------------------------------------------------------
3 // Copyright 2011-2021 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 #include <utility>
19
20 /**
21 * @brief Functions for color unquantization.
22 */
23
24 #include "astcenc_internal.h"
25
26 /**
27 * @brief Unquantize a color.
28 *
29 * This function uses a lookup table as the quantization is encoded to make
30 * hardware implementations easier, and is not a simple lerp.
31 *
32 * @param quant_level The quantization level to use.
33 * @param inputq The input quantized color.
34 *
35 * @return The unquantized color.
36 */
unquant_color(quant_method quant_level,vint4 inputq)37 static ASTCENC_SIMD_INLINE vint4 unquant_color(
38 quant_method quant_level,
39 vint4 inputq
40 ) {
41 const uint8_t* unq = color_unquant_tables[quant_level - QUANT_6];
42 return vint4(unq[inputq.lane<0>()], unq[inputq.lane<1>()],
43 unq[inputq.lane<2>()], unq[inputq.lane<3>()]);
44 }
45
46 /**
47 * @brief Determine the quantized value given a quantization level.
48 *
49 * @param quant_level The quantization level to use.
50 * @param value The value to convert. This may be outside of the 0-255 range and will be
51 * clamped before the value is looked up.
52 *
53 * @return The encoded quantized value. These are not necessarily in order; the compressor
54 * scrambles the values slightly to make hardware implementation easier.
55 */
unquant_color(quant_method quant_level,int value)56 static inline uint8_t unquant_color(
57 quant_method quant_level,
58 int value
59 ) {
60 return color_unquant_tables[quant_level - QUANT_6][value];
61 }
62
63 /**
64 * @brief Un-blue-contract a color.
65 *
66 * This function reverses any applied blue contraction.
67 *
68 * @param input The input color that has been blue-contracted.
69 *
70 * @return The uncontracted color.
71 */
uncontract_color(vint4 input)72 static ASTCENC_SIMD_INLINE vint4 uncontract_color(
73 vint4 input
74 ) {
75 vmask4 mask(true, true, false, false);
76 vint4 bc0 = asr<1>(input + input.lane<2>());
77 return select(input, bc0, mask);
78 }
79
80 /**
81 * @brief Unpack an LDR RGBA color that uses delta encoding.
82 *
83 * @param input0q The raw quantized endpoint 0 color.
84 * @param input1q The raw quantized endpoint 1 color deltas.
85 * @param quant_level The quantization level to use.
86 * @param[out] output0 The unpacked and unquantized endpoint 0 color.
87 * @param[out] output1 The unpacked and unquantized endpoint 1 color.
88 */
rgba_delta_unpack(vint4 input0q,vint4 input1q,quant_method quant_level,vint4 & output0,vint4 & output1)89 static void rgba_delta_unpack(
90 vint4 input0q,
91 vint4 input1q,
92 quant_method quant_level,
93 vint4& output0,
94 vint4& output1
95 ) {
96 // Unquantize color endpoints
97 vint4 input0 = unquant_color(quant_level, input0q);
98 vint4 input1 = unquant_color(quant_level, input1q);
99
100 // Apply bit transfer
101 bit_transfer_signed(input1, input0);
102
103 // Apply blue-uncontraction if needed
104 int rgb_sum = hadd_rgb_s(input1);
105 input1 = input1 + input0;
106 if (rgb_sum < 0)
107 {
108 input0 = uncontract_color(input0);
109 input1 = uncontract_color(input1);
110 std::swap(input0, input1);
111 }
112
113 output0 = clamp(0, 255, input0);
114 output1 = clamp(0, 255, input1);
115 }
116
117 /**
118 * @brief Unpack an LDR RGB color that uses delta encoding.
119 *
120 * Output alpha set to 255.
121 *
122 * @param input0q The raw quantized endpoint 0 color.
123 * @param input1q The raw quantized endpoint 1 color deltas.
124 * @param quant_level The quantization level to use.
125 * @param[out] output0 The unpacked and unquantized endpoint 0 color.
126 * @param[out] output1 The unpacked and unquantized endpoint 1 color.
127 */
rgb_delta_unpack(vint4 input0q,vint4 input1q,quant_method quant_level,vint4 & output0,vint4 & output1)128 static void rgb_delta_unpack(
129 vint4 input0q,
130 vint4 input1q,
131 quant_method quant_level,
132 vint4& output0,
133 vint4& output1
134 ) {
135 rgba_delta_unpack(input0q, input1q, quant_level, output0, output1);
136 output0.set_lane<3>(255);
137 output1.set_lane<3>(255);
138 }
139
140 /**
141 * @brief Unpack an LDR RGBA color that uses direct encoding.
142 *
143 * @param input0q The raw quantized endpoint 0 color.
144 * @param input1q The raw quantized endpoint 1 color.
145 * @param quant_level The quantization level to use.
146 * @param[out] output0 The unpacked and unquantized endpoint 0 color.
147 * @param[out] output1 The unpacked and unquantized endpoint 1 color.
148 */
rgba_unpack(vint4 input0q,vint4 input1q,quant_method quant_level,vint4 & output0,vint4 & output1)149 static void rgba_unpack(
150 vint4 input0q,
151 vint4 input1q,
152 quant_method quant_level,
153 vint4& output0,
154 vint4& output1
155 ) {
156 // Unquantize color endpoints
157 vint4 input0 = unquant_color(quant_level, input0q);
158 vint4 input1 = unquant_color(quant_level, input1q);
159
160 // Apply blue-uncontraction if needed
161 if (hadd_rgb_s(input0) > hadd_rgb_s(input1))
162 {
163 input0 = uncontract_color(input0);
164 input1 = uncontract_color(input1);
165 std::swap(input0, input1);
166 }
167
168 output0 = input0;
169 output1 = input1;
170 }
171
172 /**
173 * @brief Unpack an LDR RGB color that uses direct encoding.
174 *
175 * Output alpha set to 255.
176 *
177 * @param input0q The raw quantized endpoint 0 color.
178 * @param input1q The raw quantized endpoint 1 color.
179 * @param quant_level The quantization level to use.
180 * @param[out] output0 The unpacked and unquantized endpoint 0 color.
181 * @param[out] output1 The unpacked and unquantized endpoint 1 color.
182 */
rgb_unpack(vint4 input0q,vint4 input1q,quant_method quant_level,vint4 & output0,vint4 & output1)183 static void rgb_unpack(
184 vint4 input0q,
185 vint4 input1q,
186 quant_method quant_level,
187 vint4& output0,
188 vint4& output1
189 ) {
190 rgba_unpack(input0q, input1q, quant_level, output0, output1);
191 output0.set_lane<3>(255);
192 output1.set_lane<3>(255);
193 }
194
195 /**
196 * @brief Unpack an LDR RGBA color that uses scaled encoding.
197 *
198 * Note only the RGB channels use the scaled encoding, alpha uses direct.
199 *
200 * @param input0q The raw quantized endpoint 0 color.
201 * @param alpha1q The raw quantized endpoint 1 alpha value.
202 * @param scaleq The raw quantized scale.
203 * @param quant_level The quantization level to use.
204 * @param[out] output0 The unpacked and unquantized endpoint 0 color.
205 * @param[out] output1 The unpacked and unquantized endpoint 1 color.
206 */
rgb_scale_alpha_unpack(vint4 input0q,uint8_t alpha1q,uint8_t scaleq,quant_method quant_level,vint4 & output0,vint4 & output1)207 static void rgb_scale_alpha_unpack(
208 vint4 input0q,
209 uint8_t alpha1q,
210 uint8_t scaleq,
211 quant_method quant_level,
212 vint4& output0,
213 vint4& output1
214 ) {
215 // Unquantize color endpoints
216 vint4 input = unquant_color(quant_level, input0q);
217 uint8_t alpha1 = unquant_color(quant_level, alpha1q);
218 uint8_t scale = unquant_color(quant_level, scaleq);
219
220 output1 = input;
221 output1.set_lane<3>(alpha1);
222
223 output0 = asr<8>(input * scale);
224 output0.set_lane<3>(input.lane<3>());
225 }
226
227 /**
228 * @brief Unpack an LDR RGB color that uses scaled encoding.
229 *
230 * Output alpha is 255.
231 *
232 * @param input0q The raw quantized endpoint 0 color.
233 * @param scaleq The raw quantized scale.
234 * @param quant_level The quantization level to use.
235 * @param[out] output0 The unpacked and unquantized endpoint 0 color.
236 * @param[out] output1 The unpacked and unquantized endpoint 1 color.
237 */
rgb_scale_unpack(vint4 input0q,int scaleq,quant_method quant_level,vint4 & output0,vint4 & output1)238 static void rgb_scale_unpack(
239 vint4 input0q,
240 int scaleq,
241 quant_method quant_level,
242 vint4& output0,
243 vint4& output1
244 ) {
245 vint4 input = unquant_color(quant_level, input0q);
246 int scale = unquant_color(quant_level, scaleq);
247
248 output1 = input;
249 output1.set_lane<3>(255);
250
251 output0 = asr<8>(input * scale);
252 output0.set_lane<3>(255);
253 }
254
255 /**
256 * @brief Unpack an LDR L color that uses direct encoding.
257 *
258 * Output alpha is 255.
259 *
260 * @param input The raw quantized endpoints.
261 * @param quant_level The quantization level to use.
262 * @param[out] output0 The unpacked and unquantized endpoint 0 color.
263 * @param[out] output1 The unpacked and unquantized endpoint 1 color.
264 */
luminance_unpack(const uint8_t input[2],quant_method quant_level,vint4 & output0,vint4 & output1)265 static void luminance_unpack(
266 const uint8_t input[2],
267 quant_method quant_level,
268 vint4& output0,
269 vint4& output1
270 ) {
271 int lum0 = unquant_color(quant_level, input[0]);
272 int lum1 = unquant_color(quant_level, input[1]);
273 output0 = vint4(lum0, lum0, lum0, 255);
274 output1 = vint4(lum1, lum1, lum1, 255);
275 }
276
277 /**
278 * @brief Unpack an LDR L color that uses delta encoding.
279 *
280 * Output alpha is 255.
281 *
282 * @param input The raw quantized endpoints (L0, L1).
283 * @param quant_level The quantization level to use.
284 * @param[out] output0 The unpacked and unquantized endpoint 0 color.
285 * @param[out] output1 The unpacked and unquantized endpoint 1 color.
286 */
luminance_delta_unpack(const uint8_t input[2],quant_method quant_level,vint4 & output0,vint4 & output1)287 static void luminance_delta_unpack(
288 const uint8_t input[2],
289 quant_method quant_level,
290 vint4& output0,
291 vint4& output1
292 ) {
293 int v0 = unquant_color(quant_level, input[0]);
294 int v1 = unquant_color(quant_level, input[1]);
295 int l0 = (v0 >> 2) | (v1 & 0xC0);
296 int l1 = l0 + (v1 & 0x3F);
297
298 l1 = astc::min(l1, 255);
299
300 output0 = vint4(l0, l0, l0, 255);
301 output1 = vint4(l1, l1, l1, 255);
302 }
303
304 /**
305 * @brief Unpack an LDR LA color that uses direct encoding.
306 *
307 * @param input The raw quantized endpoints (L0, L1, A0, A1).
308 * @param quant_level The quantization level to use.
309 * @param[out] output0 The unpacked and unquantized endpoint 0 color.
310 * @param[out] output1 The unpacked and unquantized endpoint 1 color.
311 */
luminance_alpha_unpack(const uint8_t input[4],quant_method quant_level,vint4 & output0,vint4 & output1)312 static void luminance_alpha_unpack(
313 const uint8_t input[4],
314 quant_method quant_level,
315 vint4& output0,
316 vint4& output1
317 ) {
318 int lum0 = unquant_color(quant_level, input[0]);
319 int lum1 = unquant_color(quant_level, input[1]);
320 int alpha0 = unquant_color(quant_level, input[2]);
321 int alpha1 = unquant_color(quant_level, input[3]);
322 output0 = vint4(lum0, lum0, lum0, alpha0);
323 output1 = vint4(lum1, lum1, lum1, alpha1);
324 }
325
326 /**
327 * @brief Unpack an LDR LA color that uses delta encoding.
328 *
329 * @param input The raw quantized endpoints (L0, L1, A0, A1).
330 * @param quant_level The quantization level to use.
331 * @param[out] output0 The unpacked and unquantized endpoint 0 color.
332 * @param[out] output1 The unpacked and unquantized endpoint 1 color.
333 */
luminance_alpha_delta_unpack(const uint8_t input[4],quant_method quant_level,vint4 & output0,vint4 & output1)334 static void luminance_alpha_delta_unpack(
335 const uint8_t input[4],
336 quant_method quant_level,
337 vint4& output0,
338 vint4& output1
339 ) {
340 int lum0 = unquant_color(quant_level, input[0]);
341 int lum1 = unquant_color(quant_level, input[1]);
342 int alpha0 = unquant_color(quant_level, input[2]);
343 int alpha1 = unquant_color(quant_level, input[3]);
344
345 lum0 |= (lum1 & 0x80) << 1;
346 alpha0 |= (alpha1 & 0x80) << 1;
347 lum1 &= 0x7F;
348 alpha1 &= 0x7F;
349 if (lum1 & 0x40)
350 lum1 -= 0x80;
351 if (alpha1 & 0x40)
352 alpha1 -= 0x80;
353
354 lum0 >>= 1;
355 lum1 >>= 1;
356 alpha0 >>= 1;
357 alpha1 >>= 1;
358 lum1 += lum0;
359 alpha1 += alpha0;
360
361 lum1 = astc::clamp(lum1, 0, 255);
362 alpha1 = astc::clamp(alpha1, 0, 255);
363
364 output0 = vint4(lum0, lum0, lum0, alpha0);
365 output1 = vint4(lum1, lum1, lum1, alpha1);
366 }
367
368 /**
369 * @brief Unpack an HDR RGB + offset encoding.
370 *
371 * @param input The raw quantized endpoints (packed and modal).
372 * @param quant_level The quantization level to use.
373 * @param[out] output0 The unpacked and unquantized endpoint 0 color.
374 * @param[out] output1 The unpacked and unquantized endpoint 1 color.
375 */
hdr_rgbo_unpack(const uint8_t input[4],quant_method quant_level,vint4 & output0,vint4 & output1)376 static void hdr_rgbo_unpack(
377 const uint8_t input[4],
378 quant_method quant_level,
379 vint4& output0,
380 vint4& output1
381 ) {
382 int v0 = unquant_color(quant_level, input[0]);
383 int v1 = unquant_color(quant_level, input[1]);
384 int v2 = unquant_color(quant_level, input[2]);
385 int v3 = unquant_color(quant_level, input[3]);
386
387 int modeval = ((v0 & 0xC0) >> 6) | (((v1 & 0x80) >> 7) << 2) | (((v2 & 0x80) >> 7) << 3);
388
389 int majcomp;
390 int mode;
391 if ((modeval & 0xC) != 0xC)
392 {
393 majcomp = modeval >> 2;
394 mode = modeval & 3;
395 }
396 else if (modeval != 0xF)
397 {
398 majcomp = modeval & 3;
399 mode = 4;
400 }
401 else
402 {
403 majcomp = 0;
404 mode = 5;
405 }
406
407 int red = v0 & 0x3F;
408 int green = v1 & 0x1F;
409 int blue = v2 & 0x1F;
410 int scale = v3 & 0x1F;
411
412 int bit0 = (v1 >> 6) & 1;
413 int bit1 = (v1 >> 5) & 1;
414 int bit2 = (v2 >> 6) & 1;
415 int bit3 = (v2 >> 5) & 1;
416 int bit4 = (v3 >> 7) & 1;
417 int bit5 = (v3 >> 6) & 1;
418 int bit6 = (v3 >> 5) & 1;
419
420 int ohcomp = 1 << mode;
421
422 if (ohcomp & 0x30)
423 green |= bit0 << 6;
424 if (ohcomp & 0x3A)
425 green |= bit1 << 5;
426 if (ohcomp & 0x30)
427 blue |= bit2 << 6;
428 if (ohcomp & 0x3A)
429 blue |= bit3 << 5;
430
431 if (ohcomp & 0x3D)
432 scale |= bit6 << 5;
433 if (ohcomp & 0x2D)
434 scale |= bit5 << 6;
435 if (ohcomp & 0x04)
436 scale |= bit4 << 7;
437
438 if (ohcomp & 0x3B)
439 red |= bit4 << 6;
440 if (ohcomp & 0x04)
441 red |= bit3 << 6;
442
443 if (ohcomp & 0x10)
444 red |= bit5 << 7;
445 if (ohcomp & 0x0F)
446 red |= bit2 << 7;
447
448 if (ohcomp & 0x05)
449 red |= bit1 << 8;
450 if (ohcomp & 0x0A)
451 red |= bit0 << 8;
452
453 if (ohcomp & 0x05)
454 red |= bit0 << 9;
455 if (ohcomp & 0x02)
456 red |= bit6 << 9;
457
458 if (ohcomp & 0x01)
459 red |= bit3 << 10;
460 if (ohcomp & 0x02)
461 red |= bit5 << 10;
462
463 // expand to 12 bits.
464 static const int shamts[6] { 1, 1, 2, 3, 4, 5 };
465 int shamt = shamts[mode];
466 red <<= shamt;
467 green <<= shamt;
468 blue <<= shamt;
469 scale <<= shamt;
470
471 // on modes 0 to 4, the values stored for "green" and "blue" are differentials,
472 // not absolute values.
473 if (mode != 5)
474 {
475 green = red - green;
476 blue = red - blue;
477 }
478
479 // switch around components.
480 int temp;
481 switch (majcomp)
482 {
483 case 1:
484 temp = red;
485 red = green;
486 green = temp;
487 break;
488 case 2:
489 temp = red;
490 red = blue;
491 blue = temp;
492 break;
493 default:
494 break;
495 }
496
497 int red0 = red - scale;
498 int green0 = green - scale;
499 int blue0 = blue - scale;
500
501 // clamp to [0,0xFFF].
502 if (red < 0)
503 red = 0;
504 if (green < 0)
505 green = 0;
506 if (blue < 0)
507 blue = 0;
508
509 if (red0 < 0)
510 red0 = 0;
511 if (green0 < 0)
512 green0 = 0;
513 if (blue0 < 0)
514 blue0 = 0;
515
516 output0 = vint4(red0 << 4, green0 << 4, blue0 << 4, 0x7800);
517 output1 = vint4(red << 4, green << 4, blue << 4, 0x7800);
518 }
519
520 /**
521 * @brief Unpack an HDR RGB direct encoding.
522 *
523 * @param input The raw quantized endpoints (packed and modal).
524 * @param quant_level The quantization level to use.
525 * @param[out] output0 The unpacked and unquantized endpoint 0 color.
526 * @param[out] output1 The unpacked and unquantized endpoint 1 color.
527 */
hdr_rgb_unpack(const uint8_t input[6],quant_method quant_level,vint4 & output0,vint4 & output1)528 static void hdr_rgb_unpack(
529 const uint8_t input[6],
530 quant_method quant_level,
531 vint4& output0,
532 vint4& output1
533 ) {
534
535 int v0 = unquant_color(quant_level, input[0]);
536 int v1 = unquant_color(quant_level, input[1]);
537 int v2 = unquant_color(quant_level, input[2]);
538 int v3 = unquant_color(quant_level, input[3]);
539 int v4 = unquant_color(quant_level, input[4]);
540 int v5 = unquant_color(quant_level, input[5]);
541
542 // extract all the fixed-placement bitfields
543 int modeval = ((v1 & 0x80) >> 7) | (((v2 & 0x80) >> 7) << 1) | (((v3 & 0x80) >> 7) << 2);
544
545 int majcomp = ((v4 & 0x80) >> 7) | (((v5 & 0x80) >> 7) << 1);
546
547 if (majcomp == 3)
548 {
549 output0 = vint4(v0 << 8, v2 << 8, (v4 & 0x7F) << 9, 0x7800);
550 output1 = vint4(v1 << 8, v3 << 8, (v5 & 0x7F) << 9, 0x7800);
551 return;
552 }
553
554 int a = v0 | ((v1 & 0x40) << 2);
555 int b0 = v2 & 0x3f;
556 int b1 = v3 & 0x3f;
557 int c = v1 & 0x3f;
558 int d0 = v4 & 0x7f;
559 int d1 = v5 & 0x7f;
560
561 // get hold of the number of bits in 'd0' and 'd1'
562 static const int dbits_tab[8] { 7, 6, 7, 6, 5, 6, 5, 6 };
563 int dbits = dbits_tab[modeval];
564
565 // extract six variable-placement bits
566 int bit0 = (v2 >> 6) & 1;
567 int bit1 = (v3 >> 6) & 1;
568 int bit2 = (v4 >> 6) & 1;
569 int bit3 = (v5 >> 6) & 1;
570 int bit4 = (v4 >> 5) & 1;
571 int bit5 = (v5 >> 5) & 1;
572
573 // and prepend the variable-placement bits depending on mode.
574 int ohmod = 1 << modeval; // one-hot-mode
575 if (ohmod & 0xA4)
576 a |= bit0 << 9;
577 if (ohmod & 0x8)
578 a |= bit2 << 9;
579 if (ohmod & 0x50)
580 a |= bit4 << 9;
581
582 if (ohmod & 0x50)
583 a |= bit5 << 10;
584 if (ohmod & 0xA0)
585 a |= bit1 << 10;
586
587 if (ohmod & 0xC0)
588 a |= bit2 << 11;
589
590 if (ohmod & 0x4)
591 c |= bit1 << 6;
592 if (ohmod & 0xE8)
593 c |= bit3 << 6;
594
595 if (ohmod & 0x20)
596 c |= bit2 << 7;
597
598 if (ohmod & 0x5B)
599 {
600 b0 |= bit0 << 6;
601 b1 |= bit1 << 6;
602 }
603
604 if (ohmod & 0x12)
605 {
606 b0 |= bit2 << 7;
607 b1 |= bit3 << 7;
608 }
609
610 if (ohmod & 0xAF)
611 {
612 d0 |= bit4 << 5;
613 d1 |= bit5 << 5;
614 }
615
616 if (ohmod & 0x5)
617 {
618 d0 |= bit2 << 6;
619 d1 |= bit3 << 6;
620 }
621
622 // sign-extend 'd0' and 'd1'
623 // note: this code assumes that signed right-shift actually sign-fills, not zero-fills.
624 int32_t d0x = d0;
625 int32_t d1x = d1;
626 int sx_shamt = 32 - dbits;
627 d0x <<= sx_shamt;
628 d0x >>= sx_shamt;
629 d1x <<= sx_shamt;
630 d1x >>= sx_shamt;
631 d0 = d0x;
632 d1 = d1x;
633
634 // expand all values to 12 bits, with left-shift as needed.
635 int val_shamt = (modeval >> 1) ^ 3;
636 a <<= val_shamt;
637 b0 <<= val_shamt;
638 b1 <<= val_shamt;
639 c <<= val_shamt;
640 d0 <<= val_shamt;
641 d1 <<= val_shamt;
642
643 // then compute the actual color values.
644 int red1 = a;
645 int green1 = a - b0;
646 int blue1 = a - b1;
647 int red0 = a - c;
648 int green0 = a - b0 - c - d0;
649 int blue0 = a - b1 - c - d1;
650
651 // clamp the color components to [0,2^12 - 1]
652 red0 = astc::clamp(red0, 0, 4095);
653 green0 = astc::clamp(green0, 0, 4095);
654 blue0 = astc::clamp(blue0, 0, 4095);
655
656 red1 = astc::clamp(red1, 0, 4095);
657 green1 = astc::clamp(green1, 0, 4095);
658 blue1 = astc::clamp(blue1, 0, 4095);
659
660 // switch around the color components
661 int temp0, temp1;
662 switch (majcomp)
663 {
664 case 1: // switch around red and green
665 temp0 = red0;
666 temp1 = red1;
667 red0 = green0;
668 red1 = green1;
669 green0 = temp0;
670 green1 = temp1;
671 break;
672 case 2: // switch around red and blue
673 temp0 = red0;
674 temp1 = red1;
675 red0 = blue0;
676 red1 = blue1;
677 blue0 = temp0;
678 blue1 = temp1;
679 break;
680 case 0: // no switch
681 break;
682 }
683
684 output0 = vint4(red0 << 4, green0 << 4, blue0 << 4, 0x7800);
685 output1 = vint4(red1 << 4, green1 << 4, blue1 << 4, 0x7800);
686 }
687
688 /**
689 * @brief Unpack an HDR RGB + LDR A direct encoding.
690 *
691 * @param input The raw quantized endpoints (packed and modal).
692 * @param quant_level The quantization level to use.
693 * @param[out] output0 The unpacked and unquantized endpoint 0 color.
694 * @param[out] output1 The unpacked and unquantized endpoint 1 color.
695 */
hdr_rgb_ldr_alpha_unpack(const uint8_t input[8],quant_method quant_level,vint4 & output0,vint4 & output1)696 static void hdr_rgb_ldr_alpha_unpack(
697 const uint8_t input[8],
698 quant_method quant_level,
699 vint4& output0,
700 vint4& output1
701 ) {
702 hdr_rgb_unpack(input, quant_level, output0, output1);
703
704 int v6 = unquant_color(quant_level, input[6]);
705 int v7 = unquant_color(quant_level, input[7]);
706 output0.set_lane<3>(v6);
707 output1.set_lane<3>(v7);
708 }
709
710 /**
711 * @brief Unpack an HDR L (small range) direct encoding.
712 *
713 * @param input The raw quantized endpoints (packed and modal).
714 * @param quant_level The quantization level to use.
715 * @param[out] output0 The unpacked and unquantized endpoint 0 color.
716 * @param[out] output1 The unpacked and unquantized endpoint 1 color.
717 */
hdr_luminance_small_range_unpack(const uint8_t input[2],quant_method quant_level,vint4 & output0,vint4 & output1)718 static void hdr_luminance_small_range_unpack(
719 const uint8_t input[2],
720 quant_method quant_level,
721 vint4& output0,
722 vint4& output1
723 ) {
724 int v0 = unquant_color(quant_level, input[0]);
725 int v1 = unquant_color(quant_level, input[1]);
726
727 int y0, y1;
728 if (v0 & 0x80)
729 {
730 y0 = ((v1 & 0xE0) << 4) | ((v0 & 0x7F) << 2);
731 y1 = (v1 & 0x1F) << 2;
732 }
733 else
734 {
735 y0 = ((v1 & 0xF0) << 4) | ((v0 & 0x7F) << 1);
736 y1 = (v1 & 0xF) << 1;
737 }
738
739 y1 += y0;
740 if (y1 > 0xFFF)
741 y1 = 0xFFF;
742
743 output0 = vint4(y0 << 4, y0 << 4, y0 << 4, 0x7800);
744 output1 = vint4(y1 << 4, y1 << 4, y1 << 4, 0x7800);
745 }
746
747 /**
748 * @brief Unpack an HDR L (large range) direct encoding.
749 *
750 * @param input The raw quantized endpoints (packed and modal).
751 * @param quant_level The quantization level to use.
752 * @param[out] output0 The unpacked and unquantized endpoint 0 color.
753 * @param[out] output1 The unpacked and unquantized endpoint 1 color.
754 */
hdr_luminance_large_range_unpack(const uint8_t input[2],quant_method quant_level,vint4 & output0,vint4 & output1)755 static void hdr_luminance_large_range_unpack(
756 const uint8_t input[2],
757 quant_method quant_level,
758 vint4& output0,
759 vint4& output1
760 ) {
761 int v0 = unquant_color(quant_level, input[0]);
762 int v1 = unquant_color(quant_level, input[1]);
763
764 int y0, y1;
765 if (v1 >= v0)
766 {
767 y0 = v0 << 4;
768 y1 = v1 << 4;
769 }
770 else
771 {
772 y0 = (v1 << 4) + 8;
773 y1 = (v0 << 4) - 8;
774 }
775
776 output0 = vint4(y0 << 4, y0 << 4, y0 << 4, 0x7800);
777 output1 = vint4(y1 << 4, y1 << 4, y1 << 4, 0x7800);
778 }
779
780 /**
781 * @brief Unpack an HDR A direct encoding.
782 *
783 * @param input The raw quantized endpoints (packed and modal).
784 * @param quant_level The quantization level to use.
785 * @param[out] output0 The unpacked and unquantized endpoint 0 color.
786 * @param[out] output1 The unpacked and unquantized endpoint 1 color.
787 */
hdr_alpha_unpack(const uint8_t input[2],quant_method quant_level,int & output0,int & output1)788 static void hdr_alpha_unpack(
789 const uint8_t input[2],
790 quant_method quant_level,
791 int& output0,
792 int& output1
793 ) {
794
795 int v6 = unquant_color(quant_level, input[0]);
796 int v7 = unquant_color(quant_level, input[1]);
797
798 int selector = ((v6 >> 7) & 1) | ((v7 >> 6) & 2);
799 v6 &= 0x7F;
800 v7 &= 0x7F;
801 if (selector == 3)
802 {
803 output0 = v6 << 5;
804 output1 = v7 << 5;
805 }
806 else
807 {
808 v6 |= (v7 << (selector + 1)) & 0x780;
809 v7 &= (0x3f >> selector);
810 v7 ^= 32 >> selector;
811 v7 -= 32 >> selector;
812 v6 <<= (4 - selector);
813 v7 <<= (4 - selector);
814 v7 += v6;
815
816 if (v7 < 0)
817 v7 = 0;
818 else if (v7 > 0xFFF)
819 v7 = 0xFFF;
820
821 output0 = v6;
822 output1 = v7;
823 }
824
825 output0 <<= 4;
826 output1 <<= 4;
827 }
828
829 /**
830 * @brief Unpack an HDR RGBA direct encoding.
831 *
832 * @param input The raw quantized endpoints (packed and modal).
833 * @param quant_level The quantization level to use.
834 * @param[out] output0 The unpacked and unquantized endpoint 0 color.
835 * @param[out] output1 The unpacked and unquantized endpoint 1 color.
836 */
hdr_rgb_hdr_alpha_unpack(const uint8_t input[8],quant_method quant_level,vint4 & output0,vint4 & output1)837 static void hdr_rgb_hdr_alpha_unpack(
838 const uint8_t input[8],
839 quant_method quant_level,
840 vint4& output0,
841 vint4& output1
842 ) {
843 hdr_rgb_unpack(input, quant_level, output0, output1);
844
845 int alpha0, alpha1;
846 hdr_alpha_unpack(input + 6, quant_level, alpha0, alpha1);
847
848 output0.set_lane<3>(alpha0);
849 output1.set_lane<3>(alpha1);
850 }
851
852 /* See header for documentation. */
unpack_color_endpoints(astcenc_profile decode_mode,int format,quant_method quant_level,const uint8_t * input,bool & rgb_hdr,bool & alpha_hdr,vint4 & output0,vint4 & output1)853 void unpack_color_endpoints(
854 astcenc_profile decode_mode,
855 int format,
856 quant_method quant_level,
857 const uint8_t* input,
858 bool& rgb_hdr,
859 bool& alpha_hdr,
860 vint4& output0,
861 vint4& output1
862 ) {
863 // Assume no NaNs and LDR endpoints unless set later
864 rgb_hdr = false;
865 alpha_hdr = false;
866
867 bool alpha_hdr_default = false;
868
869 switch (format)
870 {
871 case FMT_LUMINANCE:
872 luminance_unpack(input, quant_level, output0, output1);
873 break;
874
875 case FMT_LUMINANCE_DELTA:
876 luminance_delta_unpack(input, quant_level, output0, output1);
877 break;
878
879 case FMT_HDR_LUMINANCE_SMALL_RANGE:
880 rgb_hdr = true;
881 alpha_hdr_default = true;
882 hdr_luminance_small_range_unpack(input, quant_level, output0, output1);
883 break;
884
885 case FMT_HDR_LUMINANCE_LARGE_RANGE:
886 rgb_hdr = true;
887 alpha_hdr_default = true;
888 hdr_luminance_large_range_unpack(input, quant_level, output0, output1);
889 break;
890
891 case FMT_LUMINANCE_ALPHA:
892 luminance_alpha_unpack(input, quant_level, output0, output1);
893 break;
894
895 case FMT_LUMINANCE_ALPHA_DELTA:
896 luminance_alpha_delta_unpack(input, quant_level, output0, output1);
897 break;
898
899 case FMT_RGB_SCALE:
900 {
901 vint4 input0q(input[0], input[1], input[2], 0);
902 uint8_t scale = input[3];
903 rgb_scale_unpack(input0q, scale, quant_level, output0, output1);
904 }
905 break;
906
907 case FMT_RGB_SCALE_ALPHA:
908 {
909 vint4 input0q(input[0], input[1], input[2], input[4]);
910 uint8_t alpha1q = input[5];
911 uint8_t scaleq = input[3];
912 rgb_scale_alpha_unpack(input0q, alpha1q, scaleq, quant_level, output0, output1);
913 }
914 break;
915
916 case FMT_HDR_RGB_SCALE:
917 rgb_hdr = true;
918 alpha_hdr_default = true;
919 hdr_rgbo_unpack(input, quant_level,output0, output1);
920 break;
921
922 case FMT_RGB:
923 {
924 vint4 input0q(input[0], input[2], input[4], 0);
925 vint4 input1q(input[1], input[3], input[5], 0);
926 rgb_unpack(input0q, input1q, quant_level, output0, output1);
927 }
928 break;
929
930 case FMT_RGB_DELTA:
931 {
932 vint4 input0q(input[0], input[2], input[4], 0);
933 vint4 input1q(input[1], input[3], input[5], 0);
934 rgb_delta_unpack(input0q, input1q, quant_level, output0, output1);
935 }
936 break;
937
938 case FMT_HDR_RGB:
939 rgb_hdr = true;
940 alpha_hdr_default = true;
941 hdr_rgb_unpack(input, quant_level, output0, output1);
942 break;
943
944 case FMT_RGBA:
945 {
946 vint4 input0q(input[0], input[2], input[4], input[6]);
947 vint4 input1q(input[1], input[3], input[5], input[7]);
948 rgba_unpack(input0q, input1q, quant_level, output0, output1);
949 }
950 break;
951
952 case FMT_RGBA_DELTA:
953 {
954 vint4 input0q(input[0], input[2], input[4], input[6]);
955 vint4 input1q(input[1], input[3], input[5], input[7]);
956 rgba_delta_unpack(input0q, input1q, quant_level, output0, output1);
957 }
958 break;
959
960 case FMT_HDR_RGB_LDR_ALPHA:
961 rgb_hdr = true;
962 hdr_rgb_ldr_alpha_unpack(input, quant_level, output0, output1);
963 break;
964
965 case FMT_HDR_RGBA:
966 rgb_hdr = true;
967 alpha_hdr = true;
968 hdr_rgb_hdr_alpha_unpack(input, quant_level, output0, output1);
969 break;
970 }
971
972 // Assign a correct default alpha
973 if (alpha_hdr_default)
974 {
975 if (decode_mode == ASTCENC_PRF_HDR)
976 {
977 output0.set_lane<3>(0x7800);
978 output1.set_lane<3>(0x7800);
979 alpha_hdr = true;
980 }
981 else
982 {
983 output0.set_lane<3>(0x00FF);
984 output1.set_lane<3>(0x00FF);
985 alpha_hdr = false;
986 }
987 }
988
989 vint4 ldr_scale(257);
990 vint4 hdr_scale(1);
991 vint4 output_scale = ldr_scale;
992
993 // An LDR profile image
994 if ((decode_mode == ASTCENC_PRF_LDR) ||
995 (decode_mode == ASTCENC_PRF_LDR_SRGB))
996 {
997 // Also matches HDR alpha, as cannot have HDR alpha without HDR RGB
998 if (rgb_hdr == true)
999 {
1000 output0 = vint4(0xFF00, 0x0000, 0xFF00, 0xFF00);
1001 output1 = vint4(0xFF00, 0x0000, 0xFF00, 0xFF00);
1002 output_scale = hdr_scale;
1003
1004 rgb_hdr = false;
1005 alpha_hdr = false;
1006 }
1007 }
1008 // An HDR profile image
1009 else
1010 {
1011 vmask4 hdr_lanes(rgb_hdr, rgb_hdr, rgb_hdr, alpha_hdr);
1012 output_scale = select(ldr_scale, hdr_scale, hdr_lanes);
1013 }
1014
1015 output0 = output0 * output_scale;
1016 output1 = output1 * output_scale;
1017 }
1018