// SPDX-License-Identifier: Apache-2.0 // ---------------------------------------------------------------------------- // Copyright 2011-2023 Arm Limited // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy // of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. // ---------------------------------------------------------------------------- #if !defined(ASTCENC_DECOMPRESS_ONLY) /** * @brief Functions for color quantization. * * The design of the color quantization functionality requires the caller to use higher level error * analysis to determine the base encoding that should be used. This earlier analysis will select * the basic type of the endpoint that should be used: * * * Mode: LDR or HDR * * Quantization level * * Channel count: L, LA, RGB, or RGBA * * Endpoint 2 type: Direct color endcode, or scaled from endpoint 1. * * However, this leaves a number of decisions about exactly how to pack the endpoints open. In * particular we need to determine if blue contraction can be used, or/and if delta encoding can be * used. If they can be applied these will allow us to maintain higher precision in the endpoints * without needing additional storage. */ #include <stdio.h> #include <assert.h> #include "astcenc_internal.h" /** * @brief Compute the error of an LDR RGB or RGBA encoding. * * @param uquant0 The original endpoint 0 color. * @param uquant1 The original endpoint 1 color. * @param quant0 The unpacked quantized endpoint 0 color. * @param quant1 The unpacked quantized endpoint 1 color. * * @return The MSE of the encoding. */ static float get_rgba_encoding_error( vfloat4 uquant0, vfloat4 uquant1, vint4 quant0, vint4 quant1 ) { … } /** * @brief Determine the quantized value given a quantization level. * * @param quant_level The quantization level to use. * @param value The value to convert. This must be in the 0-255 range. * * @return The unpacked quantized value, returned in 0-255 range. */ static inline uint8_t quant_color( quant_method quant_level, int value ) { … } /** * @brief Determine the quantized value given a quantization level. * * @param quant_level The quantization level to use. * @param value The value to convert. This must be in the 0-255 range. * * @return The unpacked quantized value, returned in 0-255 range. */ static inline vint4 quant_color3( quant_method quant_level, vint4 value ) { … } /** * @brief Determine the quantized value given a quantization level and residual. * * @param quant_level The quantization level to use. * @param value The value to convert. This must be in the 0-255 range. * @param valuef The original value before rounding, used to compute a residual. * * @return The unpacked quantized value, returned in 0-255 range. */ static inline uint8_t quant_color( quant_method quant_level, int value, float valuef ) { … } /** * @brief Determine the quantized value given a quantization level and residual. * * @param quant_level The quantization level to use. * @param value The value to convert. This must be in the 0-255 range. * @param valuef The original value before rounding, used to compute a residual. * * @return The unpacked quantized value, returned in 0-255 range. */ static inline vint4 quant_color3( quant_method quant_level, vint4 value, vfloat4 valuef ) { … } /** * @brief Quantize an LDR RGB color. * * Since this is a fall-back encoding, we cannot actually fail but must produce a sensible result. * For this encoding @c color0 cannot be larger than @c color1. If @c color0 is actually larger * than @c color1, @c color0 is reduced and @c color1 is increased until the constraint is met. * * @param color0 The input unquantized color0 endpoint. * @param color1 The input unquantized color1 endpoint. * @param[out] color0_out The output quantized color0 endpoint. * @param[out] color1_out The output quantized color1 endpoint. * @param quant_level The quantization level to use. */ static void quantize_rgb( vfloat4 color0, vfloat4 color1, vint4& color0_out, vint4& color1_out, quant_method quant_level ) { … } /** * @brief Quantize an LDR RGBA color. * * Since this is a fall-back encoding, we cannot actually fail but must produce a sensible result. * For this encoding @c color0.rgb cannot be larger than @c color1.rgb (this indicates blue * contraction). If @c color0.rgb is actually larger than @c color1.rgb, @c color0.rgb is reduced * and @c color1.rgb is increased until the constraint is met. * * @param color0 The input unquantized color0 endpoint. * @param color1 The input unquantized color1 endpoint. * @param[out] color0_out The output quantized color0 endpoint. * @param[out] color1_out The output quantized color1 endpoint. * @param quant_level The quantization level to use. */ static void quantize_rgba( vfloat4 color0, vfloat4 color1, vint4& color0_out, vint4& color1_out, quant_method quant_level ) { … } /** * @brief Try to quantize an LDR RGB color using blue-contraction. * * Blue-contraction is only usable if encoded color 1 is larger than color 0. * * @param color0 The input unquantized color0 endpoint. * @param color1 The input unquantized color1 endpoint. * @param[out] color0_out The output quantized color0 endpoint. * @param[out] color1_out The output quantized color1 endpoint. * @param quant_level The quantization level to use. * * @return Returns @c false on failure, @c true on success. */ static bool try_quantize_rgb_blue_contract( vfloat4 color0, vfloat4 color1, vint4& color0_out, vint4& color1_out, quant_method quant_level ) { … } /** * @brief Try to quantize an LDR RGBA color using blue-contraction. * * Blue-contraction is only usable if encoded color 1 RGB is larger than color 0 RGB. * * @param color0 The input unquantized color0 endpoint. * @param color1 The input unquantized color1 endpoint. * @param[out] color0_out The output quantized color0 endpoint. * @param[out] color1_out The output quantized color1 endpoint. * @param quant_level The quantization level to use. * * @return Returns @c false on failure, @c true on success. */ static bool try_quantize_rgba_blue_contract( vfloat4 color0, vfloat4 color1, vint4& color0_out, vint4& color1_out, quant_method quant_level ) { … } /** * @brief Try to quantize an LDR RGB color using delta encoding. * * At decode time we move one bit from the offset to the base and seize another bit as a sign bit; * we then unquantize both values as if they contain one extra bit. If the sum of the offsets is * non-negative, then we encode a regular delta. * * @param color0 The input unquantized color0 endpoint. * @param color1 The input unquantized color1 endpoint. * @param[out] color0_out The output quantized color0 endpoint. * @param[out] color1_out The output quantized color1 endpoint. * @param quant_level The quantization level to use. * * @return Returns @c false on failure, @c true on success. */ static bool try_quantize_rgb_delta( vfloat4 color0, vfloat4 color1, vint4& color0_out, vint4& color1_out, quant_method quant_level ) { … } /** * @brief Try to quantize an LDR RGB color using delta encoding and blue-contraction. * * Blue-contraction is only usable if encoded color 1 RGB is larger than color 0 RGB. * * @param color0 The input unquantized color0 endpoint. * @param color1 The input unquantized color1 endpoint. * @param[out] color0_out The output quantized color0 endpoint. * @param[out] color1_out The output quantized color1 endpoint. * @param quant_level The quantization level to use. * * @return Returns @c false on failure, @c true on success. */ static bool try_quantize_rgb_delta_blue_contract( vfloat4 color0, vfloat4 color1, vint4& color0_out, vint4& color1_out, quant_method quant_level ) { … } /** * @brief Try to quantize an LDR A color using delta encoding. * * At decode time we move one bit from the offset to the base and seize another bit as a sign bit; * we then unquantize both values as if they contain one extra bit. If the sum of the offsets is * non-negative, then we encode a regular delta. * * This function only compressed the alpha - the other elements in the output array are not touched. * * @param color0 The input unquantized color0 endpoint. * @param color1 The input unquantized color1 endpoint. * @param[out] color0_out The output quantized color0 endpoint; must preserve lane 0/1/2. * @param[out] color1_out The output quantized color1 endpoint; must preserve lane 0/1/2. * @param quant_level The quantization level to use. * * @return Returns @c false on failure, @c true on success. */ static bool try_quantize_alpha_delta( vfloat4 color0, vfloat4 color1, vint4& color0_out, vint4& color1_out, quant_method quant_level ) { … } /** * @brief Try to quantize an LDR LA color using delta encoding. * * At decode time we move one bit from the offset to the base and seize another bit as a sign bit; * we then unquantize both values as if they contain one extra bit. If the sum of the offsets is * non-negative, then we encode a regular delta. * * This function only compressed the alpha - the other elements in the output array are not touched. * * @param color0 The input unquantized color0 endpoint. * @param color1 The input unquantized color1 endpoint. * @param[out] output The output endpoints, returned as (l0, l1, a0, a1). * @param quant_level The quantization level to use. * * @return Returns @c false on failure, @c true on success. */ static bool try_quantize_luminance_alpha_delta( vfloat4 color0, vfloat4 color1, uint8_t output[4], quant_method quant_level ) { … } /** * @brief Try to quantize an LDR RGBA color using delta encoding. * * At decode time we move one bit from the offset to the base and seize another bit as a sign bit; * we then unquantize both values as if they contain one extra bit. If the sum of the offsets is * non-negative, then we encode a regular delta. * * This function only compressed the alpha - the other elements in the output array are not touched. * * @param color0 The input unquantized color0 endpoint. * @param color1 The input unquantized color1 endpoint. * @param[out] color0_out The output quantized color0 endpoint * @param[out] color1_out The output quantized color1 endpoint * @param quant_level The quantization level to use. * * @return Returns @c false on failure, @c true on success. */ static bool try_quantize_rgba_delta( vfloat4 color0, vfloat4 color1, vint4& color0_out, vint4& color1_out, quant_method quant_level ) { … } /** * @brief Try to quantize an LDR RGBA color using delta and blue contract encoding. * * At decode time we move one bit from the offset to the base and seize another bit as a sign bit; * we then unquantize both values as if they contain one extra bit. If the sum of the offsets is * non-negative, then we encode a regular delta. * * This function only compressed the alpha - the other elements in the output array are not touched. * * @param color0 The input unquantized color0 endpoint. * @param color1 The input unquantized color1 endpoint. * @param[out] color0_out The output quantized color0 endpoint * @param[out] color1_out The output quantized color1 endpoint * @param quant_level The quantization level to use. * * @return Returns @c false on failure, @c true on success. */ static bool try_quantize_rgba_delta_blue_contract( vfloat4 color0, vfloat4 color1, vint4& color0_out, vint4& color1_out, quant_method quant_level ) { … } /** * @brief Quantize an LDR RGB color using scale encoding. * * @param color The input unquantized color endpoint and scale factor. * @param[out] output The output endpoints, returned as (r0, g0, b0, s). * @param quant_level The quantization level to use. */ static void quantize_rgbs( vfloat4 color, uint8_t output[4], quant_method quant_level ) { … } /** * @brief Quantize an LDR RGBA color using scale encoding. * * @param color0 The input unquantized color0 alpha endpoint. * @param color1 The input unquantized color1 alpha endpoint. * @param color The input unquantized color endpoint and scale factor. * @param[out] output The output endpoints, returned as (r0, g0, b0, s, a0, a1). * @param quant_level The quantization level to use. */ static void quantize_rgbs_alpha( vfloat4 color0, vfloat4 color1, vfloat4 color, uint8_t output[6], quant_method quant_level ) { … } /** * @brief Quantize a LDR L color. * * @param color0 The input unquantized color0 endpoint. * @param color1 The input unquantized color1 endpoint. * @param[out] output The output endpoints, returned as (l0, l1). * @param quant_level The quantization level to use. */ static void quantize_luminance( vfloat4 color0, vfloat4 color1, uint8_t output[2], quant_method quant_level ) { … } /** * @brief Quantize a LDR LA color. * * @param color0 The input unquantized color0 endpoint. * @param color1 The input unquantized color1 endpoint. * @param[out] output The output endpoints, returned as (l0, l1, a0, a1). * @param quant_level The quantization level to use. */ static void quantize_luminance_alpha( vfloat4 color0, vfloat4 color1, uint8_t output[4], quant_method quant_level ) { … } /** * @brief Quantize and unquantize a value ensuring top two bits are the same. * * @param quant_level The quantization level to use. * @param value The input unquantized value. * @param[out] quant_value The quantized value. */ static inline void quantize_and_unquantize_retain_top_two_bits( quant_method quant_level, uint8_t value, uint8_t& quant_value ) { … } /** * @brief Quantize and unquantize a value ensuring top four bits are the same. * * @param quant_level The quantization level to use. * @param value The input unquantized value. * @param[out] quant_value The quantized value in 0-255 range. */ static inline void quantize_and_unquantize_retain_top_four_bits( quant_method quant_level, uint8_t value, uint8_t& quant_value ) { … } /** * @brief Quantize a HDR RGB color using RGB + offset. * * @param color The input unquantized color endpoint and offset. * @param[out] output The output endpoints, returned as packed RGBS with some mode bits. * @param quant_level The quantization level to use. */ static void quantize_hdr_rgbo( vfloat4 color, uint8_t output[4], quant_method quant_level ) { … } /** * @brief Quantize a HDR RGB color using direct RGB encoding. * * @param color0 The input unquantized color0 endpoint. * @param color1 The input unquantized color1 endpoint. * @param[out] output The output endpoints, returned as packed RGB+RGB pairs with mode bits. * @param quant_level The quantization level to use. */ static void quantize_hdr_rgb( vfloat4 color0, vfloat4 color1, uint8_t output[6], quant_method quant_level ) { … } /** * @brief Quantize a HDR RGB + LDR A color using direct RGBA encoding. * * @param color0 The input unquantized color0 endpoint. * @param color1 The input unquantized color1 endpoint. * @param[out] output The output endpoints, returned as packed RGBA+RGBA pairs with mode bits. * @param quant_level The quantization level to use. */ static void quantize_hdr_rgb_ldr_alpha( vfloat4 color0, vfloat4 color1, uint8_t output[8], quant_method quant_level ) { … } /** * @brief Quantize a HDR L color using the large range encoding. * * @param color0 The input unquantized color0 endpoint. * @param color1 The input unquantized color1 endpoint. * @param[out] output The output endpoints, returned as packed (l0, l1). * @param quant_level The quantization level to use. */ static void quantize_hdr_luminance_large_range( vfloat4 color0, vfloat4 color1, uint8_t output[2], quant_method quant_level ) { … } /** * @brief Quantize a HDR L color using the small range encoding. * * @param color0 The input unquantized color0 endpoint. * @param color1 The input unquantized color1 endpoint. * @param[out] output The output endpoints, returned as packed (l0, l1) with mode bits. * @param quant_level The quantization level to use. * * @return Returns @c false on failure, @c true on success. */ static bool try_quantize_hdr_luminance_small_range( vfloat4 color0, vfloat4 color1, uint8_t output[2], quant_method quant_level ) { … } /** * @brief Quantize a HDR A color using either delta or direct RGBA encoding. * * @param alpha0 The input unquantized color0 endpoint. * @param alpha1 The input unquantized color1 endpoint. * @param[out] output The output endpoints, returned as packed RGBA+RGBA pairs with mode bits. * @param quant_level The quantization level to use. */ static void quantize_hdr_alpha( float alpha0, float alpha1, uint8_t output[2], quant_method quant_level ) { … } /** * @brief Quantize a HDR RGBA color using either delta or direct RGBA encoding. * * @param color0 The input unquantized color0 endpoint. * @param color1 The input unquantized color1 endpoint. * @param[out] output The output endpoints, returned as packed RGBA+RGBA pairs with mode bits. * @param quant_level The quantization level to use. */ static void quantize_hdr_rgb_alpha( vfloat4 color0, vfloat4 color1, uint8_t output[8], quant_method quant_level ) { … } /* See header for documentation. */ uint8_t pack_color_endpoints( vfloat4 color0, vfloat4 color1, vfloat4 rgbs_color, vfloat4 rgbo_color, int format, uint8_t* output, quant_method quant_level ) { … } #endif