• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #if !defined(ASTCENC_DECOMPRESS_ONLY)
19 
20 /**
21  * @brief Functions for color quantization.
22  *
23  * The design of the color quantization functionality requires the caller to use higher level error
24  * analysis to determine the base encoding that should be used. This earlier analysis will select
25  * the basic type of the endpoint that should be used:
26  *
27  *     * Mode: LDR or HDR
28  *     * Quantization level
29  *     * Channel count: L, LA, RGB, or RGBA
30  *     * Endpoint 2 type: Direct color endcode, or scaled from endpoint 1.
31  *
32  * However, this leaves a number of decisions about exactly how to pack the endpoints open. In
33  * particular we need to determine if blue contraction can be used, or/and if delta encoding can be
34  * used. If they can be applied these will allow us to maintain higher precision in the endpoints
35  * without needing additional storage.
36  */
37 
38 #include <stdio.h>
39 #include <assert.h>
40 
41 #include "astcenc_internal.h"
42 
43 /**
44  * @brief Determine the quantized value given a quantization level.
45  *
46  * @param quant_level   The quantization level to use.
47  * @param value         The value to convert. This may be outside of the 0-255 range and will be
48  *                      clamped before the value is looked up.
49  *
50  * @return The encoded quantized value. These are not necessarily in the order; the compressor
51  *         scrambles the values slightly to make hardware implementation easier.
52  */
quant_color_clamp(quant_method quant_level,int value)53 static inline int quant_color_clamp(
54 	quant_method quant_level,
55 	int value
56 ) {
57 	value = astc::clamp(value, 0, 255);
58 	return color_quant_tables[quant_level - QUANT_6][value];
59 }
60 
61 /**
62  * @brief Determine the quantized value given a quantization level.
63  *
64  * @param quant_level   The quantization level to use.
65  * @param value         The value to convert. This may be outside of the 0-255 range and will be
66  *                      clamped before the value is looked up.
67  *
68  * @return The encoded quantized value. These are not necessarily in the order; the compressor
69  *         scrambles the values slightly to make hardware implementation easier.
70  */
quant_color(quant_method quant_level,int value)71 static inline int quant_color(
72 	quant_method quant_level,
73 	int value
74 ) {
75 	return color_quant_tables[quant_level - QUANT_6][value];
76 }
77 
78 /**
79  * @brief Determine the unquantized value given a quantization level.
80  *
81  * @param quant_level   The quantization level to use.
82  * @param value         The value to convert.
83  *
84  * @return The encoded quantized value. These are not necessarily in the order; the compressor
85  *         scrambles the values slightly to make hardware implementation easier.
86  */
unquant_color(quant_method quant_level,int value)87 static inline int unquant_color(
88 	quant_method quant_level,
89 	int value
90 ) {
91 	return color_unquant_tables[quant_level - QUANT_6][value];
92 }
93 
94 /**
95  * @brief Quantize an LDR RGB color.
96  *
97  * Since this is a fall-back encoding, we cannot actually fail but must produce a sensible result.
98  * For this encoding @c color0 cannot be larger than @c color1. If @c color0 is actually larger
99  * than @c color1, @c color0 is reduced and @c color1 is increased until the constraint is met.
100  *
101  * @param      color0        The input unquantized color0 endpoint.
102  * @param      color1        The input unquantized color1 endpoint.
103  * @param[out] output        The output endpoints, returned as (r0, r1, g0, g1, b0, b1).
104  * @param      quant_level   The quantization level to use.
105  */
quantize_rgb(vfloat4 color0,vfloat4 color1,uint8_t output[6],quant_method quant_level)106 static void quantize_rgb(
107 	vfloat4 color0,
108 	vfloat4 color1,
109 	uint8_t output[6],
110 	quant_method quant_level
111 ) {
112 	float scale = 1.0f / 257.0f;
113 
114 	float r0 = astc::clamp255f(color0.lane<0>() * scale);
115 	float g0 = astc::clamp255f(color0.lane<1>() * scale);
116 	float b0 = astc::clamp255f(color0.lane<2>() * scale);
117 
118 	float r1 = astc::clamp255f(color1.lane<0>() * scale);
119 	float g1 = astc::clamp255f(color1.lane<1>() * scale);
120 	float b1 = astc::clamp255f(color1.lane<2>() * scale);
121 
122 	int ri0, gi0, bi0, ri1, gi1, bi1;
123 	int ri0b, gi0b, bi0b, ri1b, gi1b, bi1b;
124 	float rgb0_addon = 0.5f;
125 	float rgb1_addon = 0.5f;
126 	do
127 	{
128 		ri0 = quant_color_clamp(quant_level, astc::flt2int_rd(r0 + rgb0_addon));
129 		gi0 = quant_color_clamp(quant_level, astc::flt2int_rd(g0 + rgb0_addon));
130 		bi0 = quant_color_clamp(quant_level, astc::flt2int_rd(b0 + rgb0_addon));
131 		ri1 = quant_color_clamp(quant_level, astc::flt2int_rd(r1 + rgb1_addon));
132 		gi1 = quant_color_clamp(quant_level, astc::flt2int_rd(g1 + rgb1_addon));
133 		bi1 = quant_color_clamp(quant_level, astc::flt2int_rd(b1 + rgb1_addon));
134 
135 		ri0b = unquant_color(quant_level, ri0);
136 		gi0b = unquant_color(quant_level, gi0);
137 		bi0b = unquant_color(quant_level, bi0);
138 		ri1b = unquant_color(quant_level, ri1);
139 		gi1b = unquant_color(quant_level, gi1);
140 		bi1b = unquant_color(quant_level, bi1);
141 
142 		rgb0_addon -= 0.2f;
143 		rgb1_addon += 0.2f;
144 	} while (ri0b + gi0b + bi0b > ri1b + gi1b + bi1b);
145 
146 	output[0] = static_cast<uint8_t>(ri0);
147 	output[1] = static_cast<uint8_t>(ri1);
148 	output[2] = static_cast<uint8_t>(gi0);
149 	output[3] = static_cast<uint8_t>(gi1);
150 	output[4] = static_cast<uint8_t>(bi0);
151 	output[5] = static_cast<uint8_t>(bi1);
152 }
153 
154 /**
155  * @brief Quantize an LDR RGBA color.
156  *
157  * Since this is a fall-back encoding, we cannot actually fail but must produce a sensible result.
158  * For this encoding @c color0.rgb cannot be larger than @c color1.rgb (this indicates blue
159  * contraction). If @c color0.rgb is actually larger than @c color1.rgb, @c color0.rgb is reduced
160  * and @c color1.rgb is increased until the constraint is met.
161  *
162  * @param      color0        The input unquantized color0 endpoint.
163  * @param      color1        The input unquantized color1 endpoint.
164  * @param[out] output        The output endpoints, returned as (r0, r1, g0, g1, b0, b1, a0, a1).
165  * @param      quant_level   The quantization level to use.
166  */
quantize_rgba(vfloat4 color0,vfloat4 color1,uint8_t output[8],quant_method quant_level)167 static void quantize_rgba(
168 	vfloat4 color0,
169 	vfloat4 color1,
170 	uint8_t output[8],
171 	quant_method quant_level
172 ) {
173 	float scale = 1.0f / 257.0f;
174 
175 	float a0 = astc::clamp255f(color0.lane<3>() * scale);
176 	float a1 = astc::clamp255f(color1.lane<3>() * scale);
177 
178 	output[6] = quant_color(quant_level, astc::flt2int_rtn(a0));
179 	output[7] = quant_color(quant_level, astc::flt2int_rtn(a1));
180 
181 	quantize_rgb(color0, color1, output, quant_level);
182 }
183 
184 /**
185  * @brief Try to quantize an LDR RGB color using blue-contraction.
186  *
187  * Blue-contraction is only usable if encoded color 1 is larger than color 0.
188  *
189  * @param      color0        The input unquantized color0 endpoint.
190  * @param      color1        The input unquantized color1 endpoint.
191  * @param[out] output        The output endpoints, returned as (r1, r0, g1, g0, b1, b0).
192  * @param      quant_level   The quantization level to use.
193  *
194  * @return Returns @c false on failure, @c true on success.
195  */
try_quantize_rgb_blue_contract(vfloat4 color0,vfloat4 color1,uint8_t output[6],quant_method quant_level)196 static bool try_quantize_rgb_blue_contract(
197 	vfloat4 color0,
198 	vfloat4 color1,
199 	uint8_t output[6],
200 	quant_method quant_level
201 ) {
202 	float scale = 1.0f / 257.0f;
203 
204 	float r0 = color0.lane<0>() * scale;
205 	float g0 = color0.lane<1>() * scale;
206 	float b0 = color0.lane<2>() * scale;
207 
208 	float r1 = color1.lane<0>() * scale;
209 	float g1 = color1.lane<1>() * scale;
210 	float b1 = color1.lane<2>() * scale;
211 
212 	// Apply inverse blue-contraction. This can produce an overflow; which means BC cannot be used.
213 	r0 += (r0 - b0);
214 	g0 += (g0 - b0);
215 	r1 += (r1 - b1);
216 	g1 += (g1 - b1);
217 
218 	if (r0 < 0.0f || r0 > 255.0f || g0 < 0.0f || g0 > 255.0f || b0 < 0.0f || b0 > 255.0f ||
219 		r1 < 0.0f || r1 > 255.0f || g1 < 0.0f || g1 > 255.0f || b1 < 0.0f || b1 > 255.0f)
220 	{
221 		return false;
222 	}
223 
224 	// Quantize the inverse-blue-contracted color
225 	int ri0 = quant_color(quant_level, astc::flt2int_rtn(r0));
226 	int gi0 = quant_color(quant_level, astc::flt2int_rtn(g0));
227 	int bi0 = quant_color(quant_level, astc::flt2int_rtn(b0));
228 
229 	int ri1 = quant_color(quant_level, astc::flt2int_rtn(r1));
230 	int gi1 = quant_color(quant_level, astc::flt2int_rtn(g1));
231 	int bi1 = quant_color(quant_level, astc::flt2int_rtn(b1));
232 
233 	// Then unquantize again
234 	int ru0 = unquant_color(quant_level, ri0);
235 	int gu0 = unquant_color(quant_level, gi0);
236 	int bu0 = unquant_color(quant_level, bi0);
237 
238 	int ru1 = unquant_color(quant_level, ri1);
239 	int gu1 = unquant_color(quant_level, gi1);
240 	int bu1 = unquant_color(quant_level, bi1);
241 
242 	// If color #1 is not larger than color #0 then blue-contraction cannot be used. Note that
243 	// blue-contraction and quantization change this order, which is why we must test aftwards.
244 	if (ru1 + gu1 + bu1 <= ru0 + gu0 + bu0)
245 	{
246 		return false;
247 	}
248 
249 	output[0] = static_cast<uint8_t>(ri1);
250 	output[1] = static_cast<uint8_t>(ri0);
251 	output[2] = static_cast<uint8_t>(gi1);
252 	output[3] = static_cast<uint8_t>(gi0);
253 	output[4] = static_cast<uint8_t>(bi1);
254 	output[5] = static_cast<uint8_t>(bi0);
255 
256 	return true;
257 }
258 
259 /**
260  * @brief Try to quantize an LDR RGBA color using blue-contraction.
261  *
262  * Blue-contraction is only usable if encoded color 1 RGB is larger than color 0 RGB.
263  *
264  * @param      color0        The input unquantized color0 endpoint.
265  * @param      color1        The input unquantized color1 endpoint.
266  * @param[out] output        The output endpoints, returned as (r1, r0, g1, g0, b1, b0, a1, a0).
267  * @param      quant_level   The quantization level to use.
268  *
269  * @return Returns @c false on failure, @c true on success.
270  */
try_quantize_rgba_blue_contract(vfloat4 color0,vfloat4 color1,uint8_t output[8],quant_method quant_level)271 static int try_quantize_rgba_blue_contract(
272 	vfloat4 color0,
273 	vfloat4 color1,
274 	uint8_t output[8],
275 	quant_method quant_level
276 ) {
277 	float scale = 1.0f / 257.0f;
278 
279 	float a0 = astc::clamp255f(color0.lane<3>() * scale);
280 	float a1 = astc::clamp255f(color1.lane<3>() * scale);
281 
282 	output[6] = quant_color(quant_level, astc::flt2int_rtn(a1));
283 	output[7] = quant_color(quant_level, astc::flt2int_rtn(a0));
284 
285 	return try_quantize_rgb_blue_contract(color0, color1, output, quant_level);
286 }
287 
288 /**
289  * @brief Try to quantize an LDR RGB color using delta encoding.
290  *
291  * At decode time we move one bit from the offset to the base and seize another bit as a sign bit;
292  * we then unquantize both values as if they contain one extra bit. If the sum of the offsets is
293  * non-negative, then we encode a regular delta.
294  *
295  * @param      color0        The input unquantized color0 endpoint.
296  * @param      color1        The input unquantized color1 endpoint.
297  * @param[out] output        The output endpoints, returned as (r0, r1, g0, g1, b0, b1).
298  * @param      quant_level   The quantization level to use.
299  *
300  * @return Returns @c false on failure, @c true on success.
301  */
try_quantize_rgb_delta(vfloat4 color0,vfloat4 color1,uint8_t output[6],quant_method quant_level)302 static bool try_quantize_rgb_delta(
303 	vfloat4 color0,
304 	vfloat4 color1,
305 	uint8_t output[6],
306 	quant_method quant_level
307 ) {
308 	float scale = 1.0f / 257.0f;
309 
310 	float r0 = astc::clamp255f(color0.lane<0>() * scale);
311 	float g0 = astc::clamp255f(color0.lane<1>() * scale);
312 	float b0 = astc::clamp255f(color0.lane<2>() * scale);
313 
314 	float r1 = astc::clamp255f(color1.lane<0>() * scale);
315 	float g1 = astc::clamp255f(color1.lane<1>() * scale);
316 	float b1 = astc::clamp255f(color1.lane<2>() * scale);
317 
318 	// Transform r0 to unorm9
319 	int r0a = astc::flt2int_rtn(r0);
320 	int g0a = astc::flt2int_rtn(g0);
321 	int b0a = astc::flt2int_rtn(b0);
322 
323 	r0a <<= 1;
324 	g0a <<= 1;
325 	b0a <<= 1;
326 
327 	// Mask off the top bit
328 	int r0b = r0a & 0xFF;
329 	int g0b = g0a & 0xFF;
330 	int b0b = b0a & 0xFF;
331 
332 	// Quantize then unquantize in order to get a value that we take differences against
333 	int r0be = quant_color(quant_level, r0b);
334 	int g0be = quant_color(quant_level, g0b);
335 	int b0be = quant_color(quant_level, b0b);
336 
337 	r0b = unquant_color(quant_level, r0be);
338 	g0b = unquant_color(quant_level, g0be);
339 	b0b = unquant_color(quant_level, b0be);
340 
341 	r0b |= r0a & 0x100;
342 	g0b |= g0a & 0x100;
343 	b0b |= b0a & 0x100;
344 
345 	// Get hold of the second value
346 	int r1d = astc::flt2int_rtn(r1);
347 	int g1d = astc::flt2int_rtn(g1);
348 	int b1d = astc::flt2int_rtn(b1);
349 
350 	r1d <<= 1;
351 	g1d <<= 1;
352 	b1d <<= 1;
353 
354 	// ... and take differences
355 	r1d -= r0b;
356 	g1d -= g0b;
357 	b1d -= b0b;
358 
359 	// Check if the difference is too large to be encodable
360 	if (r1d > 63 || g1d > 63 || b1d > 63 || r1d < -64 || g1d < -64 || b1d < -64)
361 	{
362 		return false;
363 	}
364 
365 	// Insert top bit of the base into the offset
366 	r1d &= 0x7F;
367 	g1d &= 0x7F;
368 	b1d &= 0x7F;
369 
370 	r1d |= (r0b & 0x100) >> 1;
371 	g1d |= (g0b & 0x100) >> 1;
372 	b1d |= (b0b & 0x100) >> 1;
373 
374 	// Then quantize and unquantize; if this causes either top two bits to flip, then encoding fails
375 	// since we have then corrupted either the top bit of the base or the sign bit of the offset
376 	int r1de = quant_color(quant_level, r1d);
377 	int g1de = quant_color(quant_level, g1d);
378 	int b1de = quant_color(quant_level, b1d);
379 
380 	int r1du = unquant_color(quant_level, r1de);
381 	int g1du = unquant_color(quant_level, g1de);
382 	int b1du = unquant_color(quant_level, b1de);
383 
384 	if (((r1d ^ r1du) | (g1d ^ g1du) | (b1d ^ b1du)) & 0xC0)
385 	{
386 		return false;
387 	}
388 
389 	// Check that the sum of the encoded offsets is nonnegative, else encoding fails
390 	r1du &= 0x7f;
391 	g1du &= 0x7f;
392 	b1du &= 0x7f;
393 
394 	if (r1du & 0x40)
395 	{
396 		r1du -= 0x80;
397 	}
398 
399 	if (g1du & 0x40)
400 	{
401 		g1du -= 0x80;
402 	}
403 
404 	if (b1du & 0x40)
405 	{
406 		b1du -= 0x80;
407 	}
408 
409 	if (r1du + g1du + b1du < 0)
410 	{
411 		return false;
412 	}
413 
414 	// Check that the offsets produce legitimate sums as well
415 	r1du += r0b;
416 	g1du += g0b;
417 	b1du += b0b;
418 	if (r1du < 0 || r1du > 0x1FF || g1du < 0 || g1du > 0x1FF || b1du < 0 || b1du > 0x1FF)
419 	{
420 		return false;
421 	}
422 
423 	output[0] = static_cast<uint8_t>(r0be);
424 	output[1] = static_cast<uint8_t>(r1de);
425 	output[2] = static_cast<uint8_t>(g0be);
426 	output[3] = static_cast<uint8_t>(g1de);
427 	output[4] = static_cast<uint8_t>(b0be);
428 	output[5] = static_cast<uint8_t>(b1de);
429 
430 	return true;
431 }
432 
try_quantize_rgb_delta_blue_contract(vfloat4 color0,vfloat4 color1,uint8_t output[6],quant_method quant_level)433 static bool try_quantize_rgb_delta_blue_contract(
434 	vfloat4 color0,
435 	vfloat4 color1,
436 	uint8_t output[6],
437 	quant_method quant_level
438 ) {
439 	// Note: Switch around endpoint colors already at start
440 	float scale = 1.0f / 257.0f;
441 
442 	float r1 = color0.lane<0>() * scale;
443 	float g1 = color0.lane<1>() * scale;
444 	float b1 = color0.lane<2>() * scale;
445 
446 	float r0 = color1.lane<0>() * scale;
447 	float g0 = color1.lane<1>() * scale;
448 	float b0 = color1.lane<2>() * scale;
449 
450 	// Apply inverse blue-contraction. This can produce an overflow; which means BC cannot be used.
451 	r0 += (r0 - b0);
452 	g0 += (g0 - b0);
453 	r1 += (r1 - b1);
454 	g1 += (g1 - b1);
455 
456 	if (r0 < 0.0f || r0 > 255.0f || g0 < 0.0f || g0 > 255.0f || b0 < 0.0f || b0 > 255.0f ||
457 	    r1 < 0.0f || r1 > 255.0f || g1 < 0.0f || g1 > 255.0f || b1 < 0.0f || b1 > 255.0f)
458 	{
459 		return false;
460 	}
461 
462 	// Transform r0 to unorm9
463 	int r0a = astc::flt2int_rtn(r0);
464 	int g0a = astc::flt2int_rtn(g0);
465 	int b0a = astc::flt2int_rtn(b0);
466 	r0a <<= 1;
467 	g0a <<= 1;
468 	b0a <<= 1;
469 
470 	// Mask off the top bit
471 	int r0b = r0a & 0xFF;
472 	int g0b = g0a & 0xFF;
473 	int b0b = b0a & 0xFF;
474 
475 	// Quantize, then unquantize in order to get a value that we take differences against.
476 	int r0be = quant_color(quant_level, r0b);
477 	int g0be = quant_color(quant_level, g0b);
478 	int b0be = quant_color(quant_level, b0b);
479 
480 	r0b = unquant_color(quant_level, r0be);
481 	g0b = unquant_color(quant_level, g0be);
482 	b0b = unquant_color(quant_level, b0be);
483 
484 	r0b |= r0a & 0x100;
485 	g0b |= g0a & 0x100;
486 	b0b |= b0a & 0x100;
487 
488 	// Get hold of the second value
489 	int r1d = astc::flt2int_rtn(r1);
490 	int g1d = astc::flt2int_rtn(g1);
491 	int b1d = astc::flt2int_rtn(b1);
492 
493 	r1d <<= 1;
494 	g1d <<= 1;
495 	b1d <<= 1;
496 
497 	// .. and take differences!
498 	r1d -= r0b;
499 	g1d -= g0b;
500 	b1d -= b0b;
501 
502 	// Check if the difference is too large to be encodable
503 	if (r1d > 63 || g1d > 63 || b1d > 63 || r1d < -64 || g1d < -64 || b1d < -64)
504 	{
505 		return false;
506 	}
507 
508 	// Insert top bit of the base into the offset
509 	r1d &= 0x7F;
510 	g1d &= 0x7F;
511 	b1d &= 0x7F;
512 
513 	r1d |= (r0b & 0x100) >> 1;
514 	g1d |= (g0b & 0x100) >> 1;
515 	b1d |= (b0b & 0x100) >> 1;
516 
517 	// Then quantize and  unquantize; if this causes any of the top two bits to flip,
518 	// then encoding fails, since we have then corrupted either the top bit of the base
519 	// or the sign bit of the offset.
520 	int r1de = quant_color(quant_level, r1d);
521 	int g1de = quant_color(quant_level, g1d);
522 	int b1de = quant_color(quant_level, b1d);
523 
524 	int r1du = unquant_color(quant_level, r1de);
525 	int g1du = unquant_color(quant_level, g1de);
526 	int b1du = unquant_color(quant_level, b1de);
527 
528 	if (((r1d ^ r1du) | (g1d ^ g1du) | (b1d ^ b1du)) & 0xC0)
529 	{
530 		return false;
531 	}
532 
533 	// Check that the sum of the encoded offsets is negative, else encoding fails
534 	// Note that this is inverse of the test for non-blue-contracted RGB.
535 	r1du &= 0x7f;
536 	g1du &= 0x7f;
537 	b1du &= 0x7f;
538 
539 	if (r1du & 0x40)
540 	{
541 		r1du -= 0x80;
542 	}
543 
544 	if (g1du & 0x40)
545 	{
546 		g1du -= 0x80;
547 	}
548 
549 	if (b1du & 0x40)
550 	{
551 		b1du -= 0x80;
552 	}
553 
554 	if (r1du + g1du + b1du >= 0)
555 	{
556 		return false;
557 	}
558 
559 	// Check that the offsets produce legitimate sums as well
560 	r1du += r0b;
561 	g1du += g0b;
562 	b1du += b0b;
563 
564 	if (r1du < 0 || r1du > 0x1FF || g1du < 0 || g1du > 0x1FF || b1du < 0 || b1du > 0x1FF)
565 	{
566 		return false;
567 	}
568 
569 	output[0] = static_cast<uint8_t>(r0be);
570 	output[1] = static_cast<uint8_t>(r1de);
571 	output[2] = static_cast<uint8_t>(g0be);
572 	output[3] = static_cast<uint8_t>(g1de);
573 	output[4] = static_cast<uint8_t>(b0be);
574 	output[5] = static_cast<uint8_t>(b1de);
575 
576 	return true;
577 }
578 
579 /**
580  * @brief Try to quantize an LDR A color using delta encoding.
581  *
582  * At decode time we move one bit from the offset to the base and seize another bit as a sign bit;
583  * we then unquantize both values as if they contain one extra bit. If the sum of the offsets is
584  * non-negative, then we encode a regular delta.
585  *
586  * This function only compressed the alpha - the other elements in the output array are not touched.
587  *
588  * @param      color0        The input unquantized color0 endpoint.
589  * @param      color1        The input unquantized color1 endpoint.
590  * @param[out] output        The output endpoints, returned as (x, x, x, x, x, x, a0, a1).
591  * @param      quant_level   The quantization level to use.
592  *
593  * @return Returns @c false on failure, @c true on success.
594  */
try_quantize_alpha_delta(vfloat4 color0,vfloat4 color1,uint8_t output[8],quant_method quant_level)595 static bool try_quantize_alpha_delta(
596 	vfloat4 color0,
597 	vfloat4 color1,
598 	uint8_t output[8],
599 	quant_method quant_level
600 ) {
601 	float scale = 1.0f / 257.0f;
602 
603 	float a0 = astc::clamp255f(color0.lane<3>() * scale);
604 	float a1 = astc::clamp255f(color1.lane<3>() * scale);
605 
606 	int a0a = astc::flt2int_rtn(a0);
607 	a0a <<= 1;
608 	int a0b = a0a & 0xFF;
609 	int a0be = quant_color(quant_level, a0b);
610 	a0b = unquant_color(quant_level, a0be);
611 	a0b |= a0a & 0x100;
612 	int a1d = astc::flt2int_rtn(a1);
613 	a1d <<= 1;
614 	a1d -= a0b;
615 
616 	if (a1d > 63 || a1d < -64)
617 	{
618 		return false;
619 	}
620 
621 	a1d &= 0x7F;
622 	a1d |= (a0b & 0x100) >> 1;
623 
624 	int a1de = quant_color(quant_level, a1d);
625 	int a1du = unquant_color(quant_level, a1de);
626 	if ((a1d ^ a1du) & 0xC0)
627 	{
628 		return false;
629 	}
630 
631 	a1du &= 0x7F;
632 	if (a1du & 0x40)
633 	{
634 		a1du -= 0x80;
635 	}
636 
637 	a1du += a0b;
638 	if (a1du < 0 || a1du > 0x1FF)
639 	{
640 		return false;
641 	}
642 
643 	output[6] = static_cast<uint8_t>(a0be);
644 	output[7] = static_cast<uint8_t>(a1de);
645 
646 	return true;
647 }
648 
649 /**
650  * @brief Try to quantize an LDR LA color using delta encoding.
651  *
652  * At decode time we move one bit from the offset to the base and seize another bit as a sign bit;
653  * we then unquantize both values as if they contain one extra bit. If the sum of the offsets is
654  * non-negative, then we encode a regular delta.
655  *
656  * This function only compressed the alpha - the other elements in the output array are not touched.
657  *
658  * @param      color0        The input unquantized color0 endpoint.
659  * @param      color1        The input unquantized color1 endpoint.
660  * @param[out] output        The output endpoints, returned as (l0, l1, a0, a1).
661  * @param      quant_level   The quantization level to use.
662  *
663  * @return Returns @c false on failure, @c true on success.
664  */
try_quantize_luminance_alpha_delta(vfloat4 color0,vfloat4 color1,uint8_t output[4],quant_method quant_level)665 static bool try_quantize_luminance_alpha_delta(
666 	vfloat4 color0,
667 	vfloat4 color1,
668 	uint8_t output[4],
669 	quant_method quant_level
670 ) {
671 	float scale = 1.0f / 257.0f;
672 
673 	float l0 = astc::clamp255f(hadd_rgb_s(color0) * ((1.0f / 3.0f) * scale));
674 	float l1 = astc::clamp255f(hadd_rgb_s(color1) * ((1.0f / 3.0f) * scale));
675 
676 	float a0 = astc::clamp255f(color0.lane<3>() * scale);
677 	float a1 = astc::clamp255f(color1.lane<3>() * scale);
678 
679 	int l0a = astc::flt2int_rtn(l0);
680 	int a0a = astc::flt2int_rtn(a0);
681 	l0a <<= 1;
682 	a0a <<= 1;
683 
684 	int l0b = l0a & 0xFF;
685 	int a0b = a0a & 0xFF;
686 	int l0be = quant_color(quant_level, l0b);
687 	int a0be = quant_color(quant_level, a0b);
688 	l0b = unquant_color(quant_level, l0be);
689 	a0b = unquant_color(quant_level, a0be);
690 	l0b |= l0a & 0x100;
691 	a0b |= a0a & 0x100;
692 
693 	int l1d = astc::flt2int_rtn(l1);
694 	int a1d = astc::flt2int_rtn(a1);
695 	l1d <<= 1;
696 	a1d <<= 1;
697 	l1d -= l0b;
698 	a1d -= a0b;
699 
700 	if (l1d > 63 || l1d < -64)
701 	{
702 		return false;
703 	}
704 
705 	if (a1d > 63 || a1d < -64)
706 	{
707 		return false;
708 	}
709 
710 	l1d &= 0x7F;
711 	a1d &= 0x7F;
712 	l1d |= (l0b & 0x100) >> 1;
713 	a1d |= (a0b & 0x100) >> 1;
714 
715 	int l1de = quant_color(quant_level, l1d);
716 	int a1de = quant_color(quant_level, a1d);
717 	int l1du = unquant_color(quant_level, l1de);
718 	int a1du = unquant_color(quant_level, a1de);
719 
720 	if ((l1d ^ l1du) & 0xC0)
721 	{
722 		return false;
723 	}
724 
725 	if ((a1d ^ a1du) & 0xC0)
726 	{
727 		return false;
728 	}
729 
730 	l1du &= 0x7F;
731 	a1du &= 0x7F;
732 
733 	if (l1du & 0x40)
734 	{
735 		l1du -= 0x80;
736 	}
737 
738 	if (a1du & 0x40)
739 	{
740 		a1du -= 0x80;
741 	}
742 
743 	l1du += l0b;
744 	a1du += a0b;
745 
746 	if (l1du < 0 || l1du > 0x1FF)
747 	{
748 		return false;
749 	}
750 
751 	if (a1du < 0 || a1du > 0x1FF)
752 	{
753 		return false;
754 	}
755 
756 	output[0] = static_cast<uint8_t>(l0be);
757 	output[1] = static_cast<uint8_t>(l1de);
758 	output[2] = static_cast<uint8_t>(a0be);
759 	output[3] = static_cast<uint8_t>(a1de);
760 
761 	return true;
762 }
763 
764 /**
765  * @brief Try to quantize an LDR RGBA color using delta encoding.
766  *
767  * At decode time we move one bit from the offset to the base and seize another bit as a sign bit;
768  * we then unquantize both values as if they contain one extra bit. If the sum of the offsets is
769  * non-negative, then we encode a regular delta.
770  *
771  * This function only compressed the alpha - the other elements in the output array are not touched.
772  *
773  * @param      color0        The input unquantized color0 endpoint.
774  * @param      color1        The input unquantized color1 endpoint.
775  * @param[out] output        The output endpoints, returned as (r0, r1, b0, b1, g0, g1, a0, a1).
776  * @param      quant_level   The quantization level to use.
777  *
778  * @return Returns @c false on failure, @c true on success.
779  */
try_quantize_rgba_delta(vfloat4 color0,vfloat4 color1,uint8_t output[8],quant_method quant_level)780 static bool try_quantize_rgba_delta(
781 	vfloat4 color0,
782 	vfloat4 color1,
783 	uint8_t output[8],
784 	quant_method quant_level
785 ) {
786 	return try_quantize_rgb_delta(color0, color1, output, quant_level) &&
787 	       try_quantize_alpha_delta(color0, color1, output, quant_level);
788 }
789 
790 
791 /**
792  * @brief Try to quantize an LDR RGBA color using delta and blue contract encoding.
793  *
794  * At decode time we move one bit from the offset to the base and seize another bit as a sign bit;
795  * we then unquantize both values as if they contain one extra bit. If the sum of the offsets is
796  * non-negative, then we encode a regular delta.
797  *
798  * This function only compressed the alpha - the other elements in the output array are not touched.
799  *
800  * @param      color0       The input unquantized color0 endpoint.
801  * @param      color1       The input unquantized color1 endpoint.
802  * @param[out] output       The output endpoints, returned as (r0, r1, b0, b1, g0, g1, a0, a1).
803  * @param      quant_level  The quantization level to use.
804  *
805  * @return Returns @c false on failure, @c true on success.
806  */
try_quantize_rgba_delta_blue_contract(vfloat4 color0,vfloat4 color1,uint8_t output[8],quant_method quant_level)807 static bool try_quantize_rgba_delta_blue_contract(
808 	vfloat4 color0,
809 	vfloat4 color1,
810 	uint8_t output[8],
811 	quant_method quant_level
812 ) {
813 	// Note that we swap the color0 and color1 ordering for alpha to match RGB blue-contract
814 	return try_quantize_rgb_delta_blue_contract(color0, color1, output, quant_level) &&
815 	       try_quantize_alpha_delta(color1, color0, output, quant_level);
816 }
817 
818 /**
819  * @brief Quantize an LDR RGB color using scale encoding.
820  *
821  * @param      color         The input unquantized color endpoint and scale factor.
822  * @param[out] output        The output endpoints, returned as (r0, g0, b0, s).
823  * @param      quant_level   The quantization level to use.
824  */
quantize_rgbs(vfloat4 color,uint8_t output[4],quant_method quant_level)825 static void quantize_rgbs(
826 	vfloat4 color,
827 	uint8_t output[4],
828 	quant_method quant_level
829 ) {
830 	float scale = 1.0f / 257.0f;
831 
832 	float r = astc::clamp255f(color.lane<0>() * scale);
833 	float g = astc::clamp255f(color.lane<1>() * scale);
834 	float b = astc::clamp255f(color.lane<2>() * scale);
835 
836 	int ri = quant_color(quant_level, astc::flt2int_rtn(r));
837 	int gi = quant_color(quant_level, astc::flt2int_rtn(g));
838 	int bi = quant_color(quant_level, astc::flt2int_rtn(b));
839 
840 	int ru = unquant_color(quant_level, ri);
841 	int gu = unquant_color(quant_level, gi);
842 	int bu = unquant_color(quant_level, bi);
843 
844 	float oldcolorsum = hadd_rgb_s(color) * scale;
845 	float newcolorsum = static_cast<float>(ru + gu + bu);
846 
847 	float scalea = astc::clamp1f(color.lane<3>() * (oldcolorsum + 1e-10f) / (newcolorsum + 1e-10f));
848 	int scale_idx = astc::flt2int_rtn(scalea * 256.0f);
849 	scale_idx = astc::clamp(scale_idx, 0, 255);
850 
851 	output[0] = static_cast<uint8_t>(ri);
852 	output[1] = static_cast<uint8_t>(gi);
853 	output[2] = static_cast<uint8_t>(bi);
854 	output[3] = quant_color(quant_level, scale_idx);
855 }
856 
857 /**
858  * @brief Quantize an LDR RGBA color using scale encoding.
859  *
860  * @param      color        The input unquantized color endpoint and scale factor.
861  * @param[out] output       The output endpoints, returned as (r0, g0, b0, s, a0, a1).
862  * @param      quant_level  The quantization level to use.
863  */
quantize_rgbs_alpha(vfloat4 color0,vfloat4 color1,vfloat4 color,uint8_t output[6],quant_method quant_level)864 static void quantize_rgbs_alpha(
865 	vfloat4 color0,
866 	vfloat4 color1,
867 	vfloat4 color,
868 	uint8_t output[6],
869 	quant_method quant_level
870 ) {
871 	float scale = 1.0f / 257.0f;
872 
873 	float a0 = astc::clamp255f(color0.lane<3>() * scale);
874 	float a1 = astc::clamp255f(color1.lane<3>() * scale);
875 
876 	output[4] = quant_color(quant_level, astc::flt2int_rtn(a0));
877 	output[5] = quant_color(quant_level, astc::flt2int_rtn(a1));
878 
879 	quantize_rgbs(color, output, quant_level);
880 }
881 
882 /**
883  * @brief Quantize a LDR L color.
884  *
885  * @param      color0        The input unquantized color0 endpoint.
886  * @param      color1        The input unquantized color1 endpoint.
887  * @param[out] output        The output endpoints, returned as (l0, l1).
888  * @param      quant_level   The quantization level to use.
889  */
quantize_luminance(vfloat4 color0,vfloat4 color1,uint8_t output[2],quant_method quant_level)890 static void quantize_luminance(
891 	vfloat4 color0,
892 	vfloat4 color1,
893 	uint8_t output[2],
894 	quant_method quant_level
895 ) {
896 	float scale = 1.0f / 257.0f;
897 
898 	color0 = color0 * scale;
899 	color1 = color1 * scale;
900 
901 	float lum0 = astc::clamp255f(hadd_rgb_s(color0) * (1.0f / 3.0f));
902 	float lum1 = astc::clamp255f(hadd_rgb_s(color1) * (1.0f / 3.0f));
903 
904 	if (lum0 > lum1)
905 	{
906 		float avg = (lum0 + lum1) * 0.5f;
907 		lum0 = avg;
908 		lum1 = avg;
909 	}
910 
911 	output[0] = quant_color(quant_level, astc::flt2int_rtn(lum0));
912 	output[1] = quant_color(quant_level, astc::flt2int_rtn(lum1));
913 }
914 
915 /**
916  * @brief Quantize a LDR LA color.
917  *
918  * @param      color0        The input unquantized color0 endpoint.
919  * @param      color1        The input unquantized color1 endpoint.
920  * @param[out] output        The output endpoints, returned as (l0, l1, a0, a1).
921  * @param      quant_level   The quantization level to use.
922  */
quantize_luminance_alpha(vfloat4 color0,vfloat4 color1,uint8_t output[4],quant_method quant_level)923 static void quantize_luminance_alpha(
924 	vfloat4 color0,
925 	vfloat4 color1,
926 	uint8_t output[4],
927 	quant_method quant_level
928 ) {
929 	float scale = 1.0f / 257.0f;
930 
931 	color0 = color0 * scale;
932 	color1 = color1 * scale;
933 
934 	float lum0 = astc::clamp255f(hadd_rgb_s(color0) * (1.0f / 3.0f));
935 	float lum1 = astc::clamp255f(hadd_rgb_s(color1) * (1.0f / 3.0f));
936 
937 	float a0 = astc::clamp255f(color0.lane<3>());
938 	float a1 = astc::clamp255f(color1.lane<3>());
939 
940 	// If endpoints are close then pull apart slightly; this gives > 8 bit normal map precision.
941 	if (quant_level > 18)
942 	{
943 		if (fabsf(lum0 - lum1) < 3.0f)
944 		{
945 			if (lum0 < lum1)
946 			{
947 				lum0 -= 0.5f;
948 				lum1 += 0.5f;
949 			}
950 			else
951 			{
952 				lum0 += 0.5f;
953 				lum1 -= 0.5f;
954 			}
955 
956 			lum0 = astc::clamp255f(lum0);
957 			lum1 = astc::clamp255f(lum1);
958 		}
959 
960 		if (fabsf(a0 - a1) < 3.0f)
961 		{
962 			if (a0 < a1)
963 			{
964 				a0 -= 0.5f;
965 				a1 += 0.5f;
966 			}
967 			else
968 			{
969 				a0 += 0.5f;
970 				a1 -= 0.5f;
971 			}
972 
973 			a0 = astc::clamp255f(a0);
974 			a1 = astc::clamp255f(a1);
975 		}
976 	}
977 
978 	output[0] = quant_color(quant_level, astc::flt2int_rtn(lum0));
979 	output[1] = quant_color(quant_level, astc::flt2int_rtn(lum1));
980 	output[2] = quant_color(quant_level, astc::flt2int_rtn(a0));
981 	output[3] = quant_color(quant_level, astc::flt2int_rtn(a1));
982 }
983 
984 /**
985  * @brief Quantize and unquantize a value ensuring top two bits are the same.
986  *
987  * @param      quant_level     The quantization level to use.
988  * @param      value           The input unquantized value.
989  * @param[out] quant_value     The quantized value.
990  * @param[out] unquant_value   The unquantized value after quantization.
991  */
quantize_and_unquantize_retain_top_two_bits(quant_method quant_level,uint8_t value,uint8_t & quant_value,uint8_t & unquant_value)992 static inline void quantize_and_unquantize_retain_top_two_bits(
993 	quant_method quant_level,
994 	uint8_t value,
995 	uint8_t& quant_value,
996 	uint8_t& unquant_value
997 ) {
998 	int perform_loop;
999 	uint8_t quantval;
1000 	uint8_t uquantval;
1001 
1002 	do
1003 	{
1004 		quantval = quant_color(quant_level, value);
1005 		uquantval = unquant_color(quant_level, quantval);
1006 
1007 		// Perform looping if the top two bits were modified by quant/unquant
1008 		perform_loop = (value & 0xC0) != (uquantval & 0xC0);
1009 
1010 		if ((uquantval & 0xC0) > (value & 0xC0))
1011 		{
1012 			// Quant/unquant rounded UP so that the top two bits changed;
1013 			// decrement the input in hopes that this will avoid rounding up.
1014 			value--;
1015 		}
1016 		else if ((uquantval & 0xC0) < (value & 0xC0))
1017 		{
1018 			// Quant/unquant rounded DOWN so that the top two bits changed;
1019 			// decrement the input in hopes that this will avoid rounding down.
1020 			value--;
1021 		}
1022 	} while (perform_loop);
1023 
1024 	quant_value = quantval;
1025 	unquant_value = uquantval;
1026 }
1027 
1028 /**
1029  * @brief Quantize and unquantize a value ensuring top four bits are the same.
1030  *
1031  * @param      quant_level     The quantization level to use.
1032  * @param      value           The input unquantized value.
1033  * @param[out] quant_value     The quantized value.
1034  * @param[out] unquant_value   The unquantized value after quantization.
1035  */
quantize_and_unquantize_retain_top_four_bits(quant_method quant_level,uint8_t value,uint8_t & quant_value,uint8_t & unquant_value)1036 static inline void quantize_and_unquantize_retain_top_four_bits(
1037 	quant_method quant_level,
1038 	uint8_t value,
1039 	uint8_t& quant_value,
1040 	uint8_t& unquant_value
1041 ) {
1042 	uint8_t perform_loop;
1043 	uint8_t quantval;
1044 	uint8_t uquantval;
1045 
1046 	do
1047 	{
1048 		quantval = quant_color(quant_level, value);
1049 		uquantval = unquant_color(quant_level, quantval);
1050 
1051 		// Perform looping if the top four bits were modified by quant/unquant
1052 		perform_loop = (value & 0xF0) != (uquantval & 0xF0);
1053 
1054 		if ((uquantval & 0xF0) > (value & 0xF0))
1055 		{
1056 			// Quant/unquant rounded UP so that the top four bits changed;
1057 			// decrement the input value in hopes that this will avoid rounding up.
1058 			value--;
1059 		}
1060 		else if ((uquantval & 0xF0) < (value & 0xF0))
1061 		{
1062 			// Quant/unquant rounded DOWN so that the top four bits changed;
1063 			// decrement the input value in hopes that this will avoid rounding down.
1064 			value--;
1065 		}
1066 	} while (perform_loop);
1067 
1068 	quant_value = quantval;
1069 	unquant_value = uquantval;
1070 }
1071 
1072 /**
1073  * @brief Quantize a HDR RGB color using RGB + offset.
1074  *
1075  * @param      color         The input unquantized color endpoint and offset.
1076  * @param[out] output        The output endpoints, returned as packed RGBS with some mode bits.
1077  * @param      quant_level   The quantization level to use.
1078  */
quantize_hdr_rgbo(vfloat4 color,uint8_t output[4],quant_method quant_level)1079 static void quantize_hdr_rgbo(
1080 	vfloat4 color,
1081 	uint8_t output[4],
1082 	quant_method quant_level
1083 ) {
1084 	color.set_lane<0>(color.lane<0>() + color.lane<3>());
1085 	color.set_lane<1>(color.lane<1>() + color.lane<3>());
1086 	color.set_lane<2>(color.lane<2>() + color.lane<3>());
1087 
1088 	color = clamp(0.0f, 65535.0f, color);
1089 
1090 	vfloat4 color_bak = color;
1091 
1092 	int majcomp;
1093 	if (color.lane<0>() > color.lane<1>() && color.lane<0>() > color.lane<2>())
1094 	{
1095 		majcomp = 0;			// red is largest component
1096 	}
1097 	else if (color.lane<1>() > color.lane<2>())
1098 	{
1099 		majcomp = 1;			// green is largest component
1100 	}
1101 	else
1102 	{
1103 		majcomp = 2;			// blue is largest component
1104 	}
1105 
1106 	// swap around the red component and the largest component.
1107 	switch (majcomp)
1108 	{
1109 	case 1:
1110 		color = color.swz<1, 0, 2, 3>();
1111 		break;
1112 	case 2:
1113 		color = color.swz<2, 1, 0, 3>();
1114 		break;
1115 	default:
1116 		break;
1117 	}
1118 
1119 	static const int mode_bits[5][3] {
1120 		{11, 5, 7},
1121 		{11, 6, 5},
1122 		{10, 5, 8},
1123 		{9, 6, 7},
1124 		{8, 7, 6}
1125 	};
1126 
1127 	static const float mode_cutoffs[5][2] {
1128 		{1024, 4096},
1129 		{2048, 1024},
1130 		{2048, 16384},
1131 		{8192, 16384},
1132 		{32768, 16384}
1133 	};
1134 
1135 	static const float mode_rscales[5] {
1136 		32.0f,
1137 		32.0f,
1138 		64.0f,
1139 		128.0f,
1140 		256.0f,
1141 	};
1142 
1143 	static const float mode_scales[5] {
1144 		1.0f / 32.0f,
1145 		1.0f / 32.0f,
1146 		1.0f / 64.0f,
1147 		1.0f / 128.0f,
1148 		1.0f / 256.0f,
1149 	};
1150 
1151 	float r_base = color.lane<0>();
1152 	float g_base = color.lane<0>() - color.lane<1>() ;
1153 	float b_base = color.lane<0>() - color.lane<2>() ;
1154 	float s_base = color.lane<3>() ;
1155 
1156 	for (int mode = 0; mode < 5; mode++)
1157 	{
1158 		if (g_base > mode_cutoffs[mode][0] || b_base > mode_cutoffs[mode][0] || s_base > mode_cutoffs[mode][1])
1159 		{
1160 			continue;
1161 		}
1162 
1163 		// Encode the mode into a 4-bit vector
1164 		int mode_enc = mode < 4 ? (mode | (majcomp << 2)) : (majcomp | 0xC);
1165 
1166 		float mode_scale = mode_scales[mode];
1167 		float mode_rscale = mode_rscales[mode];
1168 
1169 		int gb_intcutoff = 1 << mode_bits[mode][1];
1170 		int s_intcutoff = 1 << mode_bits[mode][2];
1171 
1172 		// Quantize and unquantize R
1173 		int r_intval = astc::flt2int_rtn(r_base * mode_scale);
1174 
1175 		int r_lowbits = r_intval & 0x3f;
1176 
1177 		r_lowbits |= (mode_enc & 3) << 6;
1178 
1179 		uint8_t r_quantval;
1180 		uint8_t r_uquantval;
1181 		quantize_and_unquantize_retain_top_two_bits(
1182 		    quant_level, static_cast<uint8_t>(r_lowbits), r_quantval, r_uquantval);
1183 
1184 		r_intval = (r_intval & ~0x3f) | (r_uquantval & 0x3f);
1185 		float r_fval = static_cast<float>(r_intval) * mode_rscale;
1186 
1187 		// Recompute G and B, then quantize and unquantize them
1188 		float g_fval = r_fval - color.lane<1>() ;
1189 		float b_fval = r_fval - color.lane<2>() ;
1190 
1191 		g_fval = astc::clamp(g_fval, 0.0f, 65535.0f);
1192 		b_fval = astc::clamp(b_fval, 0.0f, 65535.0f);
1193 
1194 		int g_intval = astc::flt2int_rtn(g_fval * mode_scale);
1195 		int b_intval = astc::flt2int_rtn(b_fval * mode_scale);
1196 
1197 		if (g_intval >= gb_intcutoff || b_intval >= gb_intcutoff)
1198 		{
1199 			continue;
1200 		}
1201 
1202 		int g_lowbits = g_intval & 0x1f;
1203 		int b_lowbits = b_intval & 0x1f;
1204 
1205 		int bit0 = 0;
1206 		int bit1 = 0;
1207 		int bit2 = 0;
1208 		int bit3 = 0;
1209 
1210 		switch (mode)
1211 		{
1212 		case 0:
1213 		case 2:
1214 			bit0 = (r_intval >> 9) & 1;
1215 			break;
1216 		case 1:
1217 		case 3:
1218 			bit0 = (r_intval >> 8) & 1;
1219 			break;
1220 		case 4:
1221 		case 5:
1222 			bit0 = (g_intval >> 6) & 1;
1223 			break;
1224 		}
1225 
1226 		switch (mode)
1227 		{
1228 		case 0:
1229 		case 1:
1230 		case 2:
1231 		case 3:
1232 			bit2 = (r_intval >> 7) & 1;
1233 			break;
1234 		case 4:
1235 		case 5:
1236 			bit2 = (b_intval >> 6) & 1;
1237 			break;
1238 		}
1239 
1240 		switch (mode)
1241 		{
1242 		case 0:
1243 		case 2:
1244 			bit1 = (r_intval >> 8) & 1;
1245 			break;
1246 		case 1:
1247 		case 3:
1248 		case 4:
1249 		case 5:
1250 			bit1 = (g_intval >> 5) & 1;
1251 			break;
1252 		}
1253 
1254 		switch (mode)
1255 		{
1256 		case 0:
1257 			bit3 = (r_intval >> 10) & 1;
1258 			break;
1259 		case 2:
1260 			bit3 = (r_intval >> 6) & 1;
1261 			break;
1262 		case 1:
1263 		case 3:
1264 		case 4:
1265 		case 5:
1266 			bit3 = (b_intval >> 5) & 1;
1267 			break;
1268 		}
1269 
1270 		g_lowbits |= (mode_enc & 0x4) << 5;
1271 		b_lowbits |= (mode_enc & 0x8) << 4;
1272 
1273 		g_lowbits |= bit0 << 6;
1274 		g_lowbits |= bit1 << 5;
1275 		b_lowbits |= bit2 << 6;
1276 		b_lowbits |= bit3 << 5;
1277 
1278 		uint8_t g_quantval;
1279 		uint8_t b_quantval;
1280 		uint8_t g_uquantval;
1281 		uint8_t b_uquantval;
1282 
1283 		quantize_and_unquantize_retain_top_four_bits(
1284 		    quant_level, static_cast<uint8_t>(g_lowbits), g_quantval, g_uquantval);
1285 		quantize_and_unquantize_retain_top_four_bits(
1286 		    quant_level, static_cast<uint8_t>(b_lowbits), b_quantval, b_uquantval);
1287 
1288 		g_intval = (g_intval & ~0x1f) | (g_uquantval & 0x1f);
1289 		b_intval = (b_intval & ~0x1f) | (b_uquantval & 0x1f);
1290 
1291 		g_fval = static_cast<float>(g_intval) * mode_rscale;
1292 		b_fval = static_cast<float>(b_intval) * mode_rscale;
1293 
1294 		// Recompute the scale value, based on the errors introduced to red, green and blue
1295 
1296 		// If the error is positive, then the R,G,B errors combined have raised the color
1297 		// value overall; as such, the scale value needs to be increased.
1298 		float rgb_errorsum = (r_fval - color.lane<0>() ) + (r_fval - g_fval - color.lane<1>() ) + (r_fval - b_fval - color.lane<2>() );
1299 
1300 		float s_fval = s_base + rgb_errorsum * (1.0f / 3.0f);
1301 		s_fval = astc::clamp(s_fval, 0.0f, 1e9f);
1302 
1303 		int s_intval = astc::flt2int_rtn(s_fval * mode_scale);
1304 
1305 		if (s_intval >= s_intcutoff)
1306 		{
1307 			continue;
1308 		}
1309 
1310 		int s_lowbits = s_intval & 0x1f;
1311 
1312 		int bit4;
1313 		int bit5;
1314 		int bit6;
1315 		switch (mode)
1316 		{
1317 		case 1:
1318 			bit6 = (r_intval >> 9) & 1;
1319 			break;
1320 		default:
1321 			bit6 = (s_intval >> 5) & 1;
1322 			break;
1323 		}
1324 
1325 		switch (mode)
1326 		{
1327 		case 4:
1328 			bit5 = (r_intval >> 7) & 1;
1329 			break;
1330 		case 1:
1331 			bit5 = (r_intval >> 10) & 1;
1332 			break;
1333 		default:
1334 			bit5 = (s_intval >> 6) & 1;
1335 			break;
1336 		}
1337 
1338 		switch (mode)
1339 		{
1340 		case 2:
1341 			bit4 = (s_intval >> 7) & 1;
1342 			break;
1343 		default:
1344 			bit4 = (r_intval >> 6) & 1;
1345 			break;
1346 		}
1347 
1348 		s_lowbits |= bit6 << 5;
1349 		s_lowbits |= bit5 << 6;
1350 		s_lowbits |= bit4 << 7;
1351 
1352 		uint8_t s_quantval;
1353 		uint8_t s_uquantval;
1354 
1355 		quantize_and_unquantize_retain_top_four_bits(
1356 		    quant_level, static_cast<uint8_t>(s_lowbits), s_quantval, s_uquantval);
1357 
1358 		output[0] = r_quantval;
1359 		output[1] = g_quantval;
1360 		output[2] = b_quantval;
1361 		output[3] = s_quantval;
1362 		return;
1363 	}
1364 
1365 	// Failed to encode any of the modes above? In that case encode using mode #5
1366 	float vals[4];
1367 	vals[0] = color_bak.lane<0>();
1368 	vals[1] = color_bak.lane<1>();
1369 	vals[2] = color_bak.lane<2>();
1370 	vals[3] = color_bak.lane<3>();
1371 
1372 	int ivals[4];
1373 	float cvals[3];
1374 
1375 	for (int i = 0; i < 3; i++)
1376 	{
1377 		vals[i] = astc::clamp(vals[i], 0.0f, 65020.0f);
1378 		ivals[i] = astc::flt2int_rtn(vals[i] * (1.0f / 512.0f));
1379 		cvals[i] = static_cast<float>(ivals[i]) * 512.0f;
1380 	}
1381 
1382 	float rgb_errorsum = (cvals[0] - vals[0]) + (cvals[1] - vals[1]) + (cvals[2] - vals[2]);
1383 	vals[3] += rgb_errorsum * (1.0f / 3.0f);
1384 
1385 	vals[3] = astc::clamp(vals[3], 0.0f, 65020.0f);
1386 	ivals[3] = astc::flt2int_rtn(vals[3] * (1.0f / 512.0f));
1387 
1388 	int encvals[4];
1389 	encvals[0] = (ivals[0] & 0x3f) | 0xC0;
1390 	encvals[1] = (ivals[1] & 0x7f) | 0x80;
1391 	encvals[2] = (ivals[2] & 0x7f) | 0x80;
1392 	encvals[3] = (ivals[3] & 0x7f) | ((ivals[0] & 0x40) << 1);
1393 
1394 	for (uint8_t i = 0; i < 4; i++)
1395 	{
1396 		uint8_t dummy;
1397 		quantize_and_unquantize_retain_top_four_bits(
1398 		    quant_level, static_cast<uint8_t>(encvals[i]), output[i], dummy);
1399 	}
1400 
1401 	return;
1402 }
1403 
1404 /**
1405  * @brief Quantize a HDR RGB color using direct RGB encoding.
1406  *
1407  * @param      color0        The input unquantized color0 endpoint.
1408  * @param      color1        The input unquantized color1 endpoint.
1409  * @param[out] output        The output endpoints, returned as packed RGB+RGB pairs with mode bits.
1410  * @param      quant_level   The quantization level to use.
1411  */
quantize_hdr_rgb(vfloat4 color0,vfloat4 color1,uint8_t output[6],quant_method quant_level)1412 static void quantize_hdr_rgb(
1413 	vfloat4 color0,
1414 	vfloat4 color1,
1415 	uint8_t output[6],
1416 	quant_method quant_level
1417 ) {
1418 	// Note: color*.lane<3> is not used so we can ignore it
1419 	color0 = clamp(0.0f, 65535.0f, color0);
1420 	color1 = clamp(0.0f, 65535.0f, color1);
1421 
1422 	vfloat4 color0_bak = color0;
1423 	vfloat4 color1_bak = color1;
1424 
1425 	int majcomp;
1426 	if (color1.lane<0>() > color1.lane<1>() && color1.lane<0>() > color1.lane<2>())
1427 	{
1428 		majcomp = 0;
1429 	}
1430 	else if (color1.lane<1>() > color1.lane<2>())
1431 	{
1432 		majcomp = 1;
1433 	}
1434 	else
1435 	{
1436 		majcomp = 2;
1437 	}
1438 
1439 	// Swizzle the components
1440 	switch (majcomp)
1441 	{
1442 	case 1:  // red-green swap
1443 		color0 = color0.swz<1, 0, 2, 3>();
1444 		color1 = color1.swz<1, 0, 2, 3>();
1445 		break;
1446 	case 2:  // red-blue swap
1447 		color0 = color0.swz<2, 1, 0, 3>();
1448 		color1 = color1.swz<2, 1, 0, 3>();
1449 		break;
1450 	default:
1451 		break;
1452 	}
1453 
1454 	float a_base = color1.lane<0>();
1455 	a_base = astc::clamp(a_base, 0.0f, 65535.0f);
1456 
1457 	float b0_base = a_base - color1.lane<1>();
1458 	float b1_base = a_base - color1.lane<2>();
1459 	float c_base = a_base - color0.lane<0>();
1460 	float d0_base = a_base - b0_base - c_base - color0.lane<1>();
1461 	float d1_base = a_base - b1_base - c_base - color0.lane<2>();
1462 
1463 	// Number of bits in the various fields in the various modes
1464 	static const int mode_bits[8][4] {
1465 		{9, 7, 6, 7},
1466 		{9, 8, 6, 6},
1467 		{10, 6, 7, 7},
1468 		{10, 7, 7, 6},
1469 		{11, 8, 6, 5},
1470 		{11, 6, 8, 6},
1471 		{12, 7, 7, 5},
1472 		{12, 6, 7, 6}
1473 	};
1474 
1475 	// Cutoffs to use for the computed values of a,b,c,d, assuming the
1476 	// range 0..65535 are LNS values corresponding to fp16.
1477 	static const float mode_cutoffs[8][4] {
1478 		{16384, 8192, 8192, 8},	// mode 0: 9,7,6,7
1479 		{32768, 8192, 4096, 8},	// mode 1: 9,8,6,6
1480 		{4096, 8192, 4096, 4},	// mode 2: 10,6,7,7
1481 		{8192, 8192, 2048, 4},	// mode 3: 10,7,7,6
1482 		{8192, 2048, 512, 2},	// mode 4: 11,8,6,5
1483 		{2048, 8192, 1024, 2},	// mode 5: 11,6,8,6
1484 		{2048, 2048, 256, 1},	// mode 6: 12,7,7,5
1485 		{1024, 2048, 512, 1},	// mode 7: 12,6,7,6
1486 	};
1487 
1488 	static const float mode_scales[8] {
1489 		1.0f / 128.0f,
1490 		1.0f / 128.0f,
1491 		1.0f / 64.0f,
1492 		1.0f / 64.0f,
1493 		1.0f / 32.0f,
1494 		1.0f / 32.0f,
1495 		1.0f / 16.0f,
1496 		1.0f / 16.0f,
1497 	};
1498 
1499 	// Scaling factors when going from what was encoded in the mode to 16 bits.
1500 	static const float mode_rscales[8] {
1501 		128.0f,
1502 		128.0f,
1503 		64.0f,
1504 		64.0f,
1505 		32.0f,
1506 		32.0f,
1507 		16.0f,
1508 		16.0f
1509 	};
1510 
1511 	// Try modes one by one, with the highest-precision mode first.
1512 	for (int mode = 7; mode >= 0; mode--)
1513 	{
1514 		// For each mode, test if we can in fact accommodate the computed b, c, and d values.
1515 		// If we clearly can't, then we skip to the next mode.
1516 
1517 		float b_cutoff = mode_cutoffs[mode][0];
1518 		float c_cutoff = mode_cutoffs[mode][1];
1519 		float d_cutoff = mode_cutoffs[mode][2];
1520 
1521 		if (b0_base > b_cutoff || b1_base > b_cutoff || c_base > c_cutoff || fabsf(d0_base) > d_cutoff || fabsf(d1_base) > d_cutoff)
1522 		{
1523 			continue;
1524 		}
1525 
1526 		float mode_scale = mode_scales[mode];
1527 		float mode_rscale = mode_rscales[mode];
1528 
1529 		int b_intcutoff = 1 << mode_bits[mode][1];
1530 		int c_intcutoff = 1 << mode_bits[mode][2];
1531 		int d_intcutoff = 1 << (mode_bits[mode][3] - 1);
1532 
1533 		// Quantize and unquantize A, with the assumption that its high bits can be handled safely.
1534 		int a_intval = astc::flt2int_rtn(a_base * mode_scale);
1535 		int a_lowbits = a_intval & 0xFF;
1536 
1537 		int a_quantval = quant_color(quant_level, a_lowbits);
1538 		int a_uquantval = unquant_color(quant_level, a_quantval);
1539 		a_intval = (a_intval & ~0xFF) | a_uquantval;
1540 		float a_fval = static_cast<float>(a_intval) * mode_rscale;
1541 
1542 		// Recompute C, then quantize and unquantize it
1543 		float c_fval = a_fval - color0.lane<0>();
1544 		c_fval = astc::clamp(c_fval, 0.0f, 65535.0f);
1545 
1546 		int c_intval = astc::flt2int_rtn(c_fval * mode_scale);
1547 
1548 		if (c_intval >= c_intcutoff)
1549 		{
1550 			continue;
1551 		}
1552 
1553 		int c_lowbits = c_intval & 0x3f;
1554 
1555 		c_lowbits |= (mode & 1) << 7;
1556 		c_lowbits |= (a_intval & 0x100) >> 2;
1557 
1558 		uint8_t c_quantval;
1559 		uint8_t c_uquantval;
1560 
1561 		quantize_and_unquantize_retain_top_two_bits(
1562 		    quant_level, static_cast<uint8_t>(c_lowbits), c_quantval, c_uquantval);
1563 
1564 		c_intval = (c_intval & ~0x3F) | (c_uquantval & 0x3F);
1565 		c_fval = static_cast<float>(c_intval) * mode_rscale;
1566 
1567 		// Recompute B0 and B1, then quantize and unquantize them
1568 		float b0_fval = a_fval - color1.lane<1>();
1569 		float b1_fval = a_fval - color1.lane<2>();
1570 
1571 		b0_fval = astc::clamp(b0_fval, 0.0f, 65535.0f);
1572 		b1_fval = astc::clamp(b1_fval, 0.0f, 65535.0f);
1573 		int b0_intval = astc::flt2int_rtn(b0_fval * mode_scale);
1574 		int b1_intval = astc::flt2int_rtn(b1_fval * mode_scale);
1575 
1576 		if (b0_intval >= b_intcutoff || b1_intval >= b_intcutoff)
1577 		{
1578 			continue;
1579 		}
1580 
1581 		int b0_lowbits = b0_intval & 0x3f;
1582 		int b1_lowbits = b1_intval & 0x3f;
1583 
1584 		int bit0 = 0;
1585 		int bit1 = 0;
1586 		switch (mode)
1587 		{
1588 		case 0:
1589 		case 1:
1590 		case 3:
1591 		case 4:
1592 		case 6:
1593 			bit0 = (b0_intval >> 6) & 1;
1594 			break;
1595 		case 2:
1596 		case 5:
1597 		case 7:
1598 			bit0 = (a_intval >> 9) & 1;
1599 			break;
1600 		}
1601 
1602 		switch (mode)
1603 		{
1604 		case 0:
1605 		case 1:
1606 		case 3:
1607 		case 4:
1608 		case 6:
1609 			bit1 = (b1_intval >> 6) & 1;
1610 			break;
1611 		case 2:
1612 			bit1 = (c_intval >> 6) & 1;
1613 			break;
1614 		case 5:
1615 		case 7:
1616 			bit1 = (a_intval >> 10) & 1;
1617 			break;
1618 		}
1619 
1620 		b0_lowbits |= bit0 << 6;
1621 		b1_lowbits |= bit1 << 6;
1622 
1623 		b0_lowbits |= ((mode >> 1) & 1) << 7;
1624 		b1_lowbits |= ((mode >> 2) & 1) << 7;
1625 
1626 		uint8_t b0_quantval;
1627 		uint8_t b1_quantval;
1628 		uint8_t b0_uquantval;
1629 		uint8_t b1_uquantval;
1630 
1631 		quantize_and_unquantize_retain_top_two_bits(
1632 		    quant_level, static_cast<uint8_t>(b0_lowbits), b0_quantval, b0_uquantval);
1633 		quantize_and_unquantize_retain_top_two_bits(
1634 		    quant_level, static_cast<uint8_t>(b1_lowbits), b1_quantval, b1_uquantval);
1635 
1636 		b0_intval = (b0_intval & ~0x3f) | (b0_uquantval & 0x3f);
1637 		b1_intval = (b1_intval & ~0x3f) | (b1_uquantval & 0x3f);
1638 		b0_fval = static_cast<float>(b0_intval) * mode_rscale;
1639 		b1_fval = static_cast<float>(b1_intval) * mode_rscale;
1640 
1641 		// Recompute D0 and D1, then quantize and unquantize them
1642 		float d0_fval = a_fval - b0_fval - c_fval - color0.lane<1>();
1643 		float d1_fval = a_fval - b1_fval - c_fval - color0.lane<2>();
1644 
1645 		d0_fval = astc::clamp(d0_fval, -65535.0f, 65535.0f);
1646 		d1_fval = astc::clamp(d1_fval, -65535.0f, 65535.0f);
1647 
1648 		int d0_intval = astc::flt2int_rtn(d0_fval * mode_scale);
1649 		int d1_intval = astc::flt2int_rtn(d1_fval * mode_scale);
1650 
1651 		if (abs(d0_intval) >= d_intcutoff || abs(d1_intval) >= d_intcutoff)
1652 		{
1653 			continue;
1654 		}
1655 
1656 		int d0_lowbits = d0_intval & 0x1f;
1657 		int d1_lowbits = d1_intval & 0x1f;
1658 
1659 		int bit2 = 0;
1660 		int bit3 = 0;
1661 		int bit4;
1662 		int bit5;
1663 		switch (mode)
1664 		{
1665 		case 0:
1666 		case 2:
1667 			bit2 = (d0_intval >> 6) & 1;
1668 			break;
1669 		case 1:
1670 		case 4:
1671 			bit2 = (b0_intval >> 7) & 1;
1672 			break;
1673 		case 3:
1674 			bit2 = (a_intval >> 9) & 1;
1675 			break;
1676 		case 5:
1677 			bit2 = (c_intval >> 7) & 1;
1678 			break;
1679 		case 6:
1680 		case 7:
1681 			bit2 = (a_intval >> 11) & 1;
1682 			break;
1683 		}
1684 		switch (mode)
1685 		{
1686 		case 0:
1687 		case 2:
1688 			bit3 = (d1_intval >> 6) & 1;
1689 			break;
1690 		case 1:
1691 		case 4:
1692 			bit3 = (b1_intval >> 7) & 1;
1693 			break;
1694 		case 3:
1695 		case 5:
1696 		case 6:
1697 		case 7:
1698 			bit3 = (c_intval >> 6) & 1;
1699 			break;
1700 		}
1701 
1702 		switch (mode)
1703 		{
1704 		case 4:
1705 		case 6:
1706 			bit4 = (a_intval >> 9) & 1;
1707 			bit5 = (a_intval >> 10) & 1;
1708 			break;
1709 		default:
1710 			bit4 = (d0_intval >> 5) & 1;
1711 			bit5 = (d1_intval >> 5) & 1;
1712 			break;
1713 		}
1714 
1715 		d0_lowbits |= bit2 << 6;
1716 		d1_lowbits |= bit3 << 6;
1717 		d0_lowbits |= bit4 << 5;
1718 		d1_lowbits |= bit5 << 5;
1719 
1720 		d0_lowbits |= (majcomp & 1) << 7;
1721 		d1_lowbits |= ((majcomp >> 1) & 1) << 7;
1722 
1723 		uint8_t d0_quantval;
1724 		uint8_t d1_quantval;
1725 		uint8_t d0_uquantval;
1726 		uint8_t d1_uquantval;
1727 
1728 		quantize_and_unquantize_retain_top_four_bits(
1729 		    quant_level, static_cast<uint8_t>(d0_lowbits), d0_quantval, d0_uquantval);
1730 		quantize_and_unquantize_retain_top_four_bits(
1731 		    quant_level, static_cast<uint8_t>(d1_lowbits), d1_quantval, d1_uquantval);
1732 
1733 		output[0] = static_cast<uint8_t>(a_quantval);
1734 		output[1] = c_quantval;
1735 		output[2] = b0_quantval;
1736 		output[3] = b1_quantval;
1737 		output[4] = d0_quantval;
1738 		output[5] = d1_quantval;
1739 		return;
1740 	}
1741 
1742 	// If neither of the modes fit we will use a flat representation for storing data, using 8 bits
1743 	// for red and green, and 7 bits for blue. This gives color accuracy roughly similar to LDR
1744 	// 4:4:3 which is not at all great but usable. This representation is used if the light color is
1745 	// more than 4x the color value of the dark color.
1746 	float vals[6];
1747 	vals[0] = color0_bak.lane<0>();
1748 	vals[1] = color1_bak.lane<0>();
1749 	vals[2] = color0_bak.lane<1>();
1750 	vals[3] = color1_bak.lane<1>();
1751 	vals[4] = color0_bak.lane<2>();
1752 	vals[5] = color1_bak.lane<2>();
1753 
1754 	for (int i = 0; i < 6; i++)
1755 	{
1756 		vals[i] = astc::clamp(vals[i], 0.0f, 65020.0f);
1757 	}
1758 
1759 	for (int i = 0; i < 4; i++)
1760 	{
1761 		int idx = astc::flt2int_rtn(vals[i] * 1.0f / 256.0f);
1762 		output[i] = quant_color(quant_level, idx);
1763 	}
1764 
1765 	for (int i = 4; i < 6; i++)
1766 	{
1767 		uint8_t dummy;
1768 		int idx = astc::flt2int_rtn(vals[i] * 1.0f / 512.0f) + 128;
1769 		quantize_and_unquantize_retain_top_two_bits(
1770 		    quant_level, static_cast<uint8_t>(idx), output[i], dummy);
1771 	}
1772 
1773 	return;
1774 }
1775 
1776 /**
1777  * @brief Quantize a HDR RGB + LDR A color using direct RGBA encoding.
1778  *
1779  * @param      color0        The input unquantized color0 endpoint.
1780  * @param      color1        The input unquantized color1 endpoint.
1781  * @param[out] output        The output endpoints, returned as packed RGBA+RGBA pairs with mode bits.
1782  * @param      quant_level   The quantization level to use.
1783  */
quantize_hdr_rgb_ldr_alpha(vfloat4 color0,vfloat4 color1,uint8_t output[8],quant_method quant_level)1784 static void quantize_hdr_rgb_ldr_alpha(
1785 	vfloat4 color0,
1786 	vfloat4 color1,
1787 	uint8_t output[8],
1788 	quant_method quant_level
1789 ) {
1790 	float scale = 1.0f / 257.0f;
1791 
1792 	float a0 = astc::clamp255f(color0.lane<3>() * scale);
1793 	float a1 = astc::clamp255f(color1.lane<3>() * scale);
1794 
1795 	output[6] = quant_color(quant_level, astc::flt2int_rtn(a0));
1796 	output[7] = quant_color(quant_level, astc::flt2int_rtn(a1));
1797 
1798 	quantize_hdr_rgb(color0, color1, output, quant_level);
1799 }
1800 
1801 /**
1802  * @brief Quantize a HDR L color using the large range encoding.
1803  *
1804  * @param      color0        The input unquantized color0 endpoint.
1805  * @param      color1        The input unquantized color1 endpoint.
1806  * @param[out] output        The output endpoints, returned as packed (l0, l1).
1807  * @param      quant_level   The quantization level to use.
1808  */
quantize_hdr_luminance_large_range(vfloat4 color0,vfloat4 color1,uint8_t output[2],quant_method quant_level)1809 static void quantize_hdr_luminance_large_range(
1810 	vfloat4 color0,
1811 	vfloat4 color1,
1812 	uint8_t output[2],
1813 	quant_method quant_level
1814 ) {
1815 	float lum0 = hadd_rgb_s(color0) * (1.0f / 3.0f);
1816 	float lum1 = hadd_rgb_s(color1) * (1.0f / 3.0f);
1817 
1818 	if (lum1 < lum0)
1819 	{
1820 		float avg = (lum0 + lum1) * 0.5f;
1821 		lum0 = avg;
1822 		lum1 = avg;
1823 	}
1824 
1825 	int ilum1 = astc::flt2int_rtn(lum1);
1826 	int ilum0 = astc::flt2int_rtn(lum0);
1827 
1828 	// Find the closest encodable point in the upper half of the code-point space
1829 	int upper_v0 = (ilum0 + 128) >> 8;
1830 	int upper_v1 = (ilum1 + 128) >> 8;
1831 
1832 	upper_v0 = astc::clamp(upper_v0, 0, 255);
1833 	upper_v1 = astc::clamp(upper_v1, 0, 255);
1834 
1835 	// Find the closest encodable point in the lower half of the code-point space
1836 	int lower_v0 = (ilum1 + 256) >> 8;
1837 	int lower_v1 = ilum0 >> 8;
1838 
1839 	lower_v0 = astc::clamp(lower_v0, 0, 255);
1840 	lower_v1 = astc::clamp(lower_v1, 0, 255);
1841 
1842 	// Determine the distance between the point in code-point space and the input value
1843 	int upper0_dec = upper_v0 << 8;
1844 	int upper1_dec = upper_v1 << 8;
1845 	int lower0_dec = (lower_v1 << 8) + 128;
1846 	int lower1_dec = (lower_v0 << 8) - 128;
1847 
1848 	int upper0_diff = upper0_dec - ilum0;
1849 	int upper1_diff = upper1_dec - ilum1;
1850 	int lower0_diff = lower0_dec - ilum0;
1851 	int lower1_diff = lower1_dec - ilum1;
1852 
1853 	int upper_error = (upper0_diff * upper0_diff) + (upper1_diff * upper1_diff);
1854 	int lower_error = (lower0_diff * lower0_diff) + (lower1_diff * lower1_diff);
1855 
1856 	int v0, v1;
1857 	if (upper_error < lower_error)
1858 	{
1859 		v0 = upper_v0;
1860 		v1 = upper_v1;
1861 	}
1862 	else
1863 	{
1864 		v0 = lower_v0;
1865 		v1 = lower_v1;
1866 	}
1867 
1868 	// OK; encode
1869 	output[0] = quant_color(quant_level, v0);
1870 	output[1] = quant_color(quant_level, v1);
1871 }
1872 
1873 /**
1874  * @brief Quantize a HDR L color using the small range encoding.
1875  *
1876  * @param      color0        The input unquantized color0 endpoint.
1877  * @param      color1        The input unquantized color1 endpoint.
1878  * @param[out] output        The output endpoints, returned as packed (l0, l1) with mode bits.
1879  * @param      quant_level   The quantization level to use.
1880  *
1881  * @return Returns @c false on failure, @c true on success.
1882  */
try_quantize_hdr_luminance_small_range(vfloat4 color0,vfloat4 color1,uint8_t output[2],quant_method quant_level)1883 static bool try_quantize_hdr_luminance_small_range(
1884 	vfloat4 color0,
1885 	vfloat4 color1,
1886 	uint8_t output[2],
1887 	quant_method quant_level
1888 ) {
1889 	float lum0 = hadd_rgb_s(color0) * (1.0f / 3.0f);
1890 	float lum1 = hadd_rgb_s(color1) * (1.0f / 3.0f);
1891 
1892 	if (lum1 < lum0)
1893 	{
1894 		float avg = (lum0 + lum1) * 0.5f;
1895 		lum0 = avg;
1896 		lum1 = avg;
1897 	}
1898 
1899 	int ilum1 = astc::flt2int_rtn(lum1);
1900 	int ilum0 = astc::flt2int_rtn(lum0);
1901 
1902 	// Difference of more than a factor-of-2 results in immediate failure
1903 	if (ilum1 - ilum0 > 2048)
1904 	{
1905 		return false;
1906 	}
1907 
1908 	int lowval, highval, diffval;
1909 	int v0, v1;
1910 	int v0e, v1e;
1911 	int v0d, v1d;
1912 
1913 	// Try to encode the high-precision submode
1914 	lowval = (ilum0 + 16) >> 5;
1915 	highval = (ilum1 + 16) >> 5;
1916 
1917 	lowval = astc::clamp(lowval, 0, 2047);
1918 	highval = astc::clamp(highval, 0, 2047);
1919 
1920 	v0 = lowval & 0x7F;
1921 	v0e = quant_color(quant_level, v0);
1922 	v0d = unquant_color(quant_level, v0e);
1923 
1924 	if (v0d < 0x80)
1925 	{
1926 		lowval = (lowval & ~0x7F) | v0d;
1927 		diffval = highval - lowval;
1928 		if (diffval >= 0 && diffval <= 15)
1929 		{
1930 			v1 = ((lowval >> 3) & 0xF0) | diffval;
1931 			v1e = quant_color(quant_level, v1);
1932 			v1d = unquant_color(quant_level, v1e);
1933 			if ((v1d & 0xF0) == (v1 & 0xF0))
1934 			{
1935 				output[0] = static_cast<uint8_t>(v0e);
1936 				output[1] = static_cast<uint8_t>(v1e);
1937 				return true;
1938 			}
1939 		}
1940 	}
1941 
1942 	// Try to encode the low-precision submode
1943 	lowval = (ilum0 + 32) >> 6;
1944 	highval = (ilum1 + 32) >> 6;
1945 
1946 	lowval = astc::clamp(lowval, 0, 1023);
1947 	highval = astc::clamp(highval, 0, 1023);
1948 
1949 	v0 = (lowval & 0x7F) | 0x80;
1950 	v0e = quant_color(quant_level, v0);
1951 	v0d = unquant_color(quant_level, v0e);
1952 	if ((v0d & 0x80) == 0)
1953 	{
1954 		return false;
1955 	}
1956 
1957 	lowval = (lowval & ~0x7F) | (v0d & 0x7F);
1958 	diffval = highval - lowval;
1959 	if (diffval < 0 || diffval > 31)
1960 	{
1961 		return false;
1962 	}
1963 
1964 	v1 = ((lowval >> 2) & 0xE0) | diffval;
1965 	v1e = quant_color(quant_level, v1);
1966 	v1d = unquant_color(quant_level, v1e);
1967 	if ((v1d & 0xE0) != (v1 & 0xE0))
1968 	{
1969 		return false;
1970 	}
1971 
1972 	output[0] = static_cast<uint8_t>(v0e);
1973 	output[1] = static_cast<uint8_t>(v1e);
1974 	return true;
1975 }
1976 
1977 /**
1978  * @brief Quantize a HDR A color using either delta or direct RGBA encoding.
1979  *
1980  * @param      alpha0        The input unquantized color0 endpoint.
1981  * @param      alpha1        The input unquantized color1 endpoint.
1982  * @param[out] output        The output endpoints, returned as packed RGBA+RGBA pairs with mode bits.
1983  * @param      quant_level   The quantization level to use.
1984  */
quantize_hdr_alpha(float alpha0,float alpha1,uint8_t output[2],quant_method quant_level)1985 static void quantize_hdr_alpha(
1986 	float alpha0,
1987 	float alpha1,
1988 	uint8_t output[2],
1989 	quant_method quant_level
1990 ) {
1991 	alpha0 = astc::clamp(alpha0, 0.0f, 65280.0f);
1992 	alpha1 = astc::clamp(alpha1, 0.0f, 65280.0f);
1993 
1994 	int ialpha0 = astc::flt2int_rtn(alpha0);
1995 	int ialpha1 = astc::flt2int_rtn(alpha1);
1996 
1997 	int val0, val1, diffval;
1998 	int v6, v7;
1999 	int v6e, v7e;
2000 	int v6d, v7d;
2001 
2002 	// Try to encode one of the delta submodes, in decreasing-precision order
2003 	for (int i = 2; i >= 0; i--)
2004 	{
2005 		val0 = (ialpha0 + (128 >> i)) >> (8 - i);
2006 		val1 = (ialpha1 + (128 >> i)) >> (8 - i);
2007 
2008 		v6 = (val0 & 0x7F) | ((i & 1) << 7);
2009 		v6e = quant_color(quant_level, v6);
2010 		v6d = unquant_color(quant_level, v6e);
2011 
2012 		if ((v6 ^ v6d) & 0x80)
2013 		{
2014 			continue;
2015 		}
2016 
2017 		val0 = (val0 & ~0x7f) | (v6d & 0x7f);
2018 		diffval = val1 - val0;
2019 		int cutoff = 32 >> i;
2020 		int mask = 2 * cutoff - 1;
2021 
2022 		if (diffval < -cutoff || diffval >= cutoff)
2023 		{
2024 			continue;
2025 		}
2026 
2027 		v7 = ((i & 2) << 6) | ((val0 >> 7) << (6 - i)) | (diffval & mask);
2028 		v7e = quant_color(quant_level, v7);
2029 		v7d = unquant_color(quant_level, v7e);
2030 
2031 		static const int testbits[3] { 0xE0, 0xF0, 0xF8 };
2032 
2033 		if ((v7 ^ v7d) & testbits[i])
2034 		{
2035 			continue;
2036 		}
2037 
2038 		output[0] = static_cast<uint8_t>(v6e);
2039 		output[1] = static_cast<uint8_t>(v7e);
2040 		return;
2041 	}
2042 
2043 	// Could not encode any of the delta modes; instead encode a flat value
2044 	val0 = (ialpha0 + 256) >> 9;
2045 	val1 = (ialpha1 + 256) >> 9;
2046 	v6 = val0 | 0x80;
2047 	v7 = val1 | 0x80;
2048 
2049 	output[0] = quant_color(quant_level, v6);
2050 	output[1] = quant_color(quant_level, v7);
2051 
2052 	return;
2053 }
2054 
2055 /**
2056  * @brief Quantize a HDR RGBA color using either delta or direct RGBA encoding.
2057  *
2058  * @param      color0        The input unquantized color0 endpoint.
2059  * @param      color1        The input unquantized color1 endpoint.
2060  * @param[out] output        The output endpoints, returned as packed RGBA+RGBA pairs with mode bits.
2061  * @param      quant_level   The quantization level to use.
2062  */
quantize_hdr_rgb_alpha(vfloat4 color0,vfloat4 color1,uint8_t output[8],quant_method quant_level)2063 static void quantize_hdr_rgb_alpha(
2064 	vfloat4 color0,
2065 	vfloat4 color1,
2066 	uint8_t output[8],
2067 	quant_method quant_level
2068 ) {
2069 	quantize_hdr_rgb(color0, color1, output, quant_level);
2070 	quantize_hdr_alpha(color0.lane<3>(), color1.lane<3>(), output + 6, quant_level);
2071 }
2072 
2073 /* See header for documentation. */
pack_color_endpoints(QualityProfile privateProfile,vfloat4 color0,vfloat4 color1,vfloat4 rgbs_color,vfloat4 rgbo_color,int format,uint8_t * output,quant_method quant_level)2074 uint8_t pack_color_endpoints(
2075 	QualityProfile privateProfile,
2076 	vfloat4 color0,
2077 	vfloat4 color1,
2078 	vfloat4 rgbs_color,
2079 	vfloat4 rgbo_color,
2080 	int format,
2081 	uint8_t* output,
2082 	quant_method quant_level
2083 ) {
2084 	assert(QUANT_6 <= quant_level && quant_level <= QUANT_256);
2085 
2086 	// We do not support negative colors
2087 	color0 = max(color0, 0.0f);
2088 	color1 = max(color1, 0.0f);
2089 
2090 	uint8_t retval = 0;
2091 
2092 	switch (format)
2093 	{
2094 	case FMT_RGB:
2095 		if (quant_level <= 18)
2096 		{
2097 			if (try_quantize_rgb_delta_blue_contract(color0, color1, output, quant_level))
2098 			{
2099 				retval = FMT_RGB_DELTA;
2100 				break;
2101 			}
2102 			if (try_quantize_rgb_delta(color0, color1, output, quant_level))
2103 			{
2104 				retval = FMT_RGB_DELTA;
2105 				break;
2106 			}
2107 		}
2108 		if (try_quantize_rgb_blue_contract(color0, color1, output, quant_level))
2109 		{
2110 			retval = FMT_RGB;
2111 			break;
2112 		}
2113 		quantize_rgb(color0, color1, output, quant_level);
2114 		retval = FMT_RGB;
2115 		break;
2116 
2117 	case FMT_RGBA:
2118 		if ((privateProfile == HIGH_QUALITY_PROFILE) && (quant_level <= 18)) // only full quality profile to try
2119 		{
2120 			if (try_quantize_rgba_delta_blue_contract(color0, color1, output, quant_level))
2121 			{
2122 				retval = FMT_RGBA_DELTA;
2123 				break;
2124 			}
2125 			if (try_quantize_rgba_delta(color0, color1, output, quant_level))
2126 			{
2127 				retval = FMT_RGBA_DELTA;
2128 				break;
2129 			}
2130 		}
2131 		if (try_quantize_rgba_blue_contract(color0, color1, output, quant_level))
2132 		{
2133 			retval = FMT_RGBA;
2134 			break;
2135 		}
2136 		quantize_rgba(color0, color1, output, quant_level);
2137 		retval = FMT_RGBA;
2138 		break;
2139 
2140 	case FMT_RGB_SCALE:
2141 		quantize_rgbs(rgbs_color, output, quant_level);
2142 		retval = FMT_RGB_SCALE;
2143 		break;
2144 
2145 	case FMT_HDR_RGB_SCALE:
2146 		quantize_hdr_rgbo(rgbo_color, output, quant_level);
2147 		retval = FMT_HDR_RGB_SCALE;
2148 		break;
2149 
2150 	case FMT_HDR_RGB:
2151 		quantize_hdr_rgb(color0, color1, output, quant_level);
2152 		retval = FMT_HDR_RGB;
2153 		break;
2154 
2155 	case FMT_RGB_SCALE_ALPHA:
2156 		quantize_rgbs_alpha(color0, color1, rgbs_color, output, quant_level);
2157 		retval = FMT_RGB_SCALE_ALPHA;
2158 		break;
2159 
2160 	case FMT_HDR_LUMINANCE_SMALL_RANGE:
2161 	case FMT_HDR_LUMINANCE_LARGE_RANGE:
2162 		if (try_quantize_hdr_luminance_small_range(color0, color1, output, quant_level))
2163 		{
2164 			retval = FMT_HDR_LUMINANCE_SMALL_RANGE;
2165 			break;
2166 		}
2167 		quantize_hdr_luminance_large_range(color0, color1, output, quant_level);
2168 		retval = FMT_HDR_LUMINANCE_LARGE_RANGE;
2169 		break;
2170 
2171 	case FMT_LUMINANCE:
2172 		quantize_luminance(color0, color1, output, quant_level);
2173 		retval = FMT_LUMINANCE;
2174 		break;
2175 
2176 	case FMT_LUMINANCE_ALPHA:
2177 		if (quant_level <= 18)
2178 		{
2179 			if (try_quantize_luminance_alpha_delta(color0, color1, output, quant_level))
2180 			{
2181 				retval = FMT_LUMINANCE_ALPHA_DELTA;
2182 				break;
2183 			}
2184 		}
2185 		quantize_luminance_alpha(color0, color1, output, quant_level);
2186 		retval = FMT_LUMINANCE_ALPHA;
2187 		break;
2188 
2189 	case FMT_HDR_RGB_LDR_ALPHA:
2190 		quantize_hdr_rgb_ldr_alpha(color0, color1, output, quant_level);
2191 		retval = FMT_HDR_RGB_LDR_ALPHA;
2192 		break;
2193 
2194 	case FMT_HDR_RGBA:
2195 		quantize_hdr_rgb_alpha(color0, color1, output, quant_level);
2196 		retval = FMT_HDR_RGBA;
2197 		break;
2198 	}
2199 
2200 	return retval;
2201 }
2202 
2203 #endif
2204