• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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