// SPDX-License-Identifier: Apache-2.0 // ---------------------------------------------------------------------------- // Copyright 2011-2024 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 angular-sum algorithm for weight alignment. * * This algorithm works as follows: * - we compute a complex number P as (cos s*i, sin s*i) for each weight, * where i is the input value and s is a scaling factor based on the spacing between the weights. * - we then add together complex numbers for all the weights. * - we then compute the length and angle of the resulting sum. * * This should produce the following results: * - perfect alignment results in a vector whose length is equal to the sum of lengths of all inputs * - even distribution results in a vector of length 0. * - all samples identical results in perfect alignment for every scaling. * * For each scaling factor within a given set, we compute an alignment factor from 0 to 1. This * should then result in some scalings standing out as having particularly good alignment factors; * we can use this to produce a set of candidate scale/shift values for various quantization levels; * we should then actually try them and see what happens. */ #include "astcenc_internal.h" #include "astcenc_vecmathlib.h" #include <stdio.h> #include <cassert> #include <cstring> static constexpr unsigned int ANGULAR_STEPS { … }; static_assert …; static_assert …; // Store a reduced sin/cos table for 64 possible weight values; this causes // slight quality loss compared to using sin() and cos() directly. Must be 2^N. static constexpr unsigned int SINCOS_STEPS { … }; static const uint8_t steps_for_quant_level[12] { … }; ASTCENC_ALIGNAS static float sin_table[SINCOS_STEPS][ANGULAR_STEPS]; ASTCENC_ALIGNAS static float cos_table[SINCOS_STEPS][ANGULAR_STEPS]; #if defined(ASTCENC_DIAGNOSTICS) static bool print_once { true }; #endif /* See header for documentation. */ void prepare_angular_tables() { … } /** * @brief Compute the angular alignment factors and offsets. * * @param weight_count The number of (decimated) weights. * @param dec_weight_ideal_value The ideal decimated unquantized weight values. * @param max_angular_steps The maximum number of steps to be tested. * @param[out] offsets The output angular offsets array. */ static void compute_angular_offsets( unsigned int weight_count, const float* dec_weight_ideal_value, unsigned int max_angular_steps, float* offsets ) { … } /** * @brief For a given step size compute the lowest and highest weight. * * Compute the lowest and highest weight that results from quantizing using the given stepsize and * offset, and then compute the resulting error. The cut errors indicate the error that results from * forcing samples that should have had one weight value one step up or down. * * @param weight_count The number of (decimated) weights. * @param dec_weight_ideal_value The ideal decimated unquantized weight values. * @param max_angular_steps The maximum number of steps to be tested. * @param max_quant_steps The maximum quantization level to be tested. * @param offsets The angular offsets array. * @param[out] lowest_weight Per angular step, the lowest weight. * @param[out] weight_span Per angular step, the span between lowest and highest weight. * @param[out] error Per angular step, the error. * @param[out] cut_low_weight_error Per angular step, the low weight cut error. * @param[out] cut_high_weight_error Per angular step, the high weight cut error. */ static void compute_lowest_and_highest_weight( unsigned int weight_count, const float* dec_weight_ideal_value, unsigned int max_angular_steps, unsigned int max_quant_steps, const float* offsets, float* lowest_weight, int* weight_span, float* error, float* cut_low_weight_error, float* cut_high_weight_error ) { … } /** * @brief The main function for the angular algorithm. * * @param weight_count The number of (decimated) weights. * @param dec_weight_ideal_value The ideal decimated unquantized weight values. * @param max_quant_level The maximum quantization level to be tested. * @param[out] low_value Per angular step, the lowest weight value. * @param[out] high_value Per angular step, the highest weight value. */ static void compute_angular_endpoints_for_quant_levels( unsigned int weight_count, const float* dec_weight_ideal_value, unsigned int max_quant_level, float low_value[TUNE_MAX_ANGULAR_QUANT + 1], float high_value[TUNE_MAX_ANGULAR_QUANT + 1] ) { … } /* See header for documentation. */ void compute_angular_endpoints_1plane( bool only_always, const block_size_descriptor& bsd, const float* dec_weight_ideal_value, unsigned int max_weight_quant, compression_working_buffers& tmpbuf ) { … } /* See header for documentation. */ void compute_angular_endpoints_2planes( const block_size_descriptor& bsd, const float* dec_weight_ideal_value, unsigned int max_weight_quant, compression_working_buffers& tmpbuf ) { … } #endif