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