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