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