Path: blob/master/thirdparty/astcenc/astcenc_symbolic_physical.cpp
9896 views
// SPDX-License-Identifier: Apache-2.01// ----------------------------------------------------------------------------2// Copyright 2011-2023 Arm Limited3//4// Licensed under the Apache License, Version 2.0 (the "License"); you may not5// use this file except in compliance with the License. You may obtain a copy6// of the License at:7//8// http://www.apache.org/licenses/LICENSE-2.09//10// Unless required by applicable law or agreed to in writing, software11// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT12// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the13// License for the specific language governing permissions and limitations14// under the License.15// ----------------------------------------------------------------------------1617/**18* @brief Functions for converting between symbolic and physical encodings.19*/2021#include "astcenc_internal.h"2223#include <cassert>2425/**26* @brief Reverse bits in a byte.27*28* @param p The value to reverse.29*30* @return The reversed result.31*/32static inline int bitrev8(int p)33{34p = ((p & 0x0F) << 4) | ((p >> 4) & 0x0F);35p = ((p & 0x33) << 2) | ((p >> 2) & 0x33);36p = ((p & 0x55) << 1) | ((p >> 1) & 0x55);37return p;38}394041/**42* @brief Read up to 8 bits at an arbitrary bit offset.43*44* The stored value is at most 8 bits, but can be stored at an offset of between 0 and 7 bits so may45* span two separate bytes in memory.46*47* @param bitcount The number of bits to read.48* @param bitoffset The bit offset to read from, between 0 and 7.49* @param[in,out] ptr The data pointer to read from.50*51* @return The read value.52*/53static inline int read_bits(54int bitcount,55int bitoffset,56const uint8_t* ptr57) {58int mask = (1 << bitcount) - 1;59ptr += bitoffset >> 3;60bitoffset &= 7;61int value = ptr[0] | (ptr[1] << 8);62value >>= bitoffset;63value &= mask;64return value;65}6667#if !defined(ASTCENC_DECOMPRESS_ONLY)6869/**70* @brief Write up to 8 bits at an arbitrary bit offset.71*72* The stored value is at most 8 bits, but can be stored at an offset of between 0 and 7 bits so73* may span two separate bytes in memory.74*75* @param value The value to write.76* @param bitcount The number of bits to write, starting from LSB.77* @param bitoffset The bit offset to store at, between 0 and 7.78* @param[in,out] ptr The data pointer to write to.79*/80static inline void write_bits(81int value,82int bitcount,83int bitoffset,84uint8_t* ptr85) {86int mask = (1 << bitcount) - 1;87value &= mask;88ptr += bitoffset >> 3;89bitoffset &= 7;90value <<= bitoffset;91mask <<= bitoffset;92mask = ~mask;9394ptr[0] &= mask;95ptr[0] |= value;96ptr[1] &= mask >> 8;97ptr[1] |= value >> 8;98}99100/* See header for documentation. */101void symbolic_to_physical(102const block_size_descriptor& bsd,103const symbolic_compressed_block& scb,104uint8_t pcb[16]105) {106assert(scb.block_type != SYM_BTYPE_ERROR);107108// Constant color block using UNORM16 colors109if (scb.block_type == SYM_BTYPE_CONST_U16)110{111// There is currently no attempt to coalesce larger void-extents112static const uint8_t cbytes[8] { 0xFC, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };113for (unsigned int i = 0; i < 8; i++)114{115pcb[i] = cbytes[i];116}117118for (unsigned int i = 0; i < BLOCK_MAX_COMPONENTS; i++)119{120pcb[2 * i + 8] = scb.constant_color[i] & 0xFF;121pcb[2 * i + 9] = (scb.constant_color[i] >> 8) & 0xFF;122}123124return;125}126127// Constant color block using FP16 colors128if (scb.block_type == SYM_BTYPE_CONST_F16)129{130// There is currently no attempt to coalesce larger void-extents131static const uint8_t cbytes[8] { 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };132for (unsigned int i = 0; i < 8; i++)133{134pcb[i] = cbytes[i];135}136137for (unsigned int i = 0; i < BLOCK_MAX_COMPONENTS; i++)138{139pcb[2 * i + 8] = scb.constant_color[i] & 0xFF;140pcb[2 * i + 9] = (scb.constant_color[i] >> 8) & 0xFF;141}142143return;144}145146unsigned int partition_count = scb.partition_count;147148// Compress the weights.149// They are encoded as an ordinary integer-sequence, then bit-reversed150uint8_t weightbuf[16] { 0 };151152const auto& bm = bsd.get_block_mode(scb.block_mode);153const auto& di = bsd.get_decimation_info(bm.decimation_mode);154int weight_count = di.weight_count;155quant_method weight_quant_method = bm.get_weight_quant_mode();156float weight_quant_levels = static_cast<float>(get_quant_level(weight_quant_method));157int is_dual_plane = bm.is_dual_plane;158159const auto& qat = quant_and_xfer_tables[weight_quant_method];160161int real_weight_count = is_dual_plane ? 2 * weight_count : weight_count;162163int bits_for_weights = get_ise_sequence_bitcount(real_weight_count, weight_quant_method);164165uint8_t weights[64];166if (is_dual_plane)167{168for (int i = 0; i < weight_count; i++)169{170float uqw = static_cast<float>(scb.weights[i]);171float qw = (uqw / 64.0f) * (weight_quant_levels - 1.0f);172int qwi = static_cast<int>(qw + 0.5f);173weights[2 * i] = qat.scramble_map[qwi];174175uqw = static_cast<float>(scb.weights[i + WEIGHTS_PLANE2_OFFSET]);176qw = (uqw / 64.0f) * (weight_quant_levels - 1.0f);177qwi = static_cast<int>(qw + 0.5f);178weights[2 * i + 1] = qat.scramble_map[qwi];179}180}181else182{183for (int i = 0; i < weight_count; i++)184{185float uqw = static_cast<float>(scb.weights[i]);186float qw = (uqw / 64.0f) * (weight_quant_levels - 1.0f);187int qwi = static_cast<int>(qw + 0.5f);188weights[i] = qat.scramble_map[qwi];189}190}191192encode_ise(weight_quant_method, real_weight_count, weights, weightbuf, 0);193194for (int i = 0; i < 16; i++)195{196pcb[i] = static_cast<uint8_t>(bitrev8(weightbuf[15 - i]));197}198199write_bits(scb.block_mode, 11, 0, pcb);200write_bits(partition_count - 1, 2, 11, pcb);201202int below_weights_pos = 128 - bits_for_weights;203204// Encode partition index and color endpoint types for blocks with 2+ partitions205if (partition_count > 1)206{207write_bits(scb.partition_index, 6, 13, pcb);208write_bits(scb.partition_index >> 6, PARTITION_INDEX_BITS - 6, 19, pcb);209210if (scb.color_formats_matched)211{212write_bits(scb.color_formats[0] << 2, 6, 13 + PARTITION_INDEX_BITS, pcb);213}214else215{216// Check endpoint types for each partition to determine the lowest class present217int low_class = 4;218219for (unsigned int i = 0; i < partition_count; i++)220{221int class_of_format = scb.color_formats[i] >> 2;222low_class = astc::min(class_of_format, low_class);223}224225if (low_class == 3)226{227low_class = 2;228}229230int encoded_type = low_class + 1;231int bitpos = 2;232233for (unsigned int i = 0; i < partition_count; i++)234{235int classbit_of_format = (scb.color_formats[i] >> 2) - low_class;236encoded_type |= classbit_of_format << bitpos;237bitpos++;238}239240for (unsigned int i = 0; i < partition_count; i++)241{242int lowbits_of_format = scb.color_formats[i] & 3;243encoded_type |= lowbits_of_format << bitpos;244bitpos += 2;245}246247int encoded_type_lowpart = encoded_type & 0x3F;248int encoded_type_highpart = encoded_type >> 6;249int encoded_type_highpart_size = (3 * partition_count) - 4;250int encoded_type_highpart_pos = 128 - bits_for_weights - encoded_type_highpart_size;251write_bits(encoded_type_lowpart, 6, 13 + PARTITION_INDEX_BITS, pcb);252write_bits(encoded_type_highpart, encoded_type_highpart_size, encoded_type_highpart_pos, pcb);253below_weights_pos -= encoded_type_highpart_size;254}255}256else257{258write_bits(scb.color_formats[0], 4, 13, pcb);259}260261// In dual-plane mode, encode the color component of the second plane of weights262if (is_dual_plane)263{264write_bits(scb.plane2_component, 2, below_weights_pos - 2, pcb);265}266267// Encode the color components268uint8_t values_to_encode[32];269int valuecount_to_encode = 0;270271const uint8_t* pack_table = color_uquant_to_scrambled_pquant_tables[scb.quant_mode - QUANT_6];272for (unsigned int i = 0; i < scb.partition_count; i++)273{274int vals = 2 * (scb.color_formats[i] >> 2) + 2;275assert(vals <= 8);276for (int j = 0; j < vals; j++)277{278values_to_encode[j + valuecount_to_encode] = pack_table[scb.color_values[i][j]];279}280valuecount_to_encode += vals;281}282283encode_ise(scb.get_color_quant_mode(), valuecount_to_encode, values_to_encode, pcb,284scb.partition_count == 1 ? 17 : 19 + PARTITION_INDEX_BITS);285}286287#endif288289/* See header for documentation. */290void physical_to_symbolic(291const block_size_descriptor& bsd,292const uint8_t pcb[16],293symbolic_compressed_block& scb294) {295uint8_t bswapped[16];296297scb.block_type = SYM_BTYPE_NONCONST;298299// Extract header fields300int block_mode = read_bits(11, 0, pcb);301if ((block_mode & 0x1FF) == 0x1FC)302{303// Constant color block304305// Check what format the data has306if (block_mode & 0x200)307{308scb.block_type = SYM_BTYPE_CONST_F16;309}310else311{312scb.block_type = SYM_BTYPE_CONST_U16;313}314315scb.partition_count = 0;316for (int i = 0; i < 4; i++)317{318scb.constant_color[i] = pcb[2 * i + 8] | (pcb[2 * i + 9] << 8);319}320321// Additionally, check that the void-extent322if (bsd.zdim == 1)323{324// 2D void-extent325int rsvbits = read_bits(2, 10, pcb);326if (rsvbits != 3)327{328scb.block_type = SYM_BTYPE_ERROR;329return;330}331332// Low values span 3 bytes so need two read_bits calls333int vx_low_s = read_bits(8, 12, pcb) | (read_bits(5, 12 + 8, pcb) << 8);334int vx_high_s = read_bits(13, 25, pcb);335int vx_low_t = read_bits(8, 38, pcb) | (read_bits(5, 38 + 8, pcb) << 8);336int vx_high_t = read_bits(13, 51, pcb);337338int all_ones = vx_low_s == 0x1FFF && vx_high_s == 0x1FFF &&339vx_low_t == 0x1FFF && vx_high_t == 0x1FFF;340341if ((vx_low_s >= vx_high_s || vx_low_t >= vx_high_t) && !all_ones)342{343scb.block_type = SYM_BTYPE_ERROR;344return;345}346}347else348{349// 3D void-extent350int vx_low_s = read_bits(9, 10, pcb);351int vx_high_s = read_bits(9, 19, pcb);352int vx_low_t = read_bits(9, 28, pcb);353int vx_high_t = read_bits(9, 37, pcb);354int vx_low_r = read_bits(9, 46, pcb);355int vx_high_r = read_bits(9, 55, pcb);356357int all_ones = vx_low_s == 0x1FF && vx_high_s == 0x1FF &&358vx_low_t == 0x1FF && vx_high_t == 0x1FF &&359vx_low_r == 0x1FF && vx_high_r == 0x1FF;360361if ((vx_low_s >= vx_high_s || vx_low_t >= vx_high_t || vx_low_r >= vx_high_r) && !all_ones)362{363scb.block_type = SYM_BTYPE_ERROR;364return;365}366}367368return;369}370371unsigned int packed_index = bsd.block_mode_packed_index[block_mode];372if (packed_index == BLOCK_BAD_BLOCK_MODE)373{374scb.block_type = SYM_BTYPE_ERROR;375return;376}377378const auto& bm = bsd.get_block_mode(block_mode);379const auto& di = bsd.get_decimation_info(bm.decimation_mode);380381int weight_count = di.weight_count;382promise(weight_count > 0);383384quant_method weight_quant_method = static_cast<quant_method>(bm.quant_mode);385int is_dual_plane = bm.is_dual_plane;386387int real_weight_count = is_dual_plane ? 2 * weight_count : weight_count;388389int partition_count = read_bits(2, 11, pcb) + 1;390promise(partition_count > 0);391392scb.block_mode = static_cast<uint16_t>(block_mode);393scb.partition_count = static_cast<uint8_t>(partition_count);394395for (int i = 0; i < 16; i++)396{397bswapped[i] = static_cast<uint8_t>(bitrev8(pcb[15 - i]));398}399400int bits_for_weights = get_ise_sequence_bitcount(real_weight_count, weight_quant_method);401402int below_weights_pos = 128 - bits_for_weights;403404uint8_t indices[64];405const auto& qat = quant_and_xfer_tables[weight_quant_method];406407decode_ise(weight_quant_method, real_weight_count, bswapped, indices, 0);408409if (is_dual_plane)410{411for (int i = 0; i < weight_count; i++)412{413scb.weights[i] = qat.unscramble_and_unquant_map[indices[2 * i]];414scb.weights[i + WEIGHTS_PLANE2_OFFSET] = qat.unscramble_and_unquant_map[indices[2 * i + 1]];415}416}417else418{419for (int i = 0; i < weight_count; i++)420{421scb.weights[i] = qat.unscramble_and_unquant_map[indices[i]];422}423}424425if (is_dual_plane && partition_count == 4)426{427scb.block_type = SYM_BTYPE_ERROR;428return;429}430431scb.color_formats_matched = 0;432433// Determine the format of each endpoint pair434int color_formats[BLOCK_MAX_PARTITIONS];435int encoded_type_highpart_size = 0;436if (partition_count == 1)437{438color_formats[0] = read_bits(4, 13, pcb);439scb.partition_index = 0;440}441else442{443encoded_type_highpart_size = (3 * partition_count) - 4;444below_weights_pos -= encoded_type_highpart_size;445int encoded_type = read_bits(6, 13 + PARTITION_INDEX_BITS, pcb) |446(read_bits(encoded_type_highpart_size, below_weights_pos, pcb) << 6);447int baseclass = encoded_type & 0x3;448if (baseclass == 0)449{450for (int i = 0; i < partition_count; i++)451{452color_formats[i] = (encoded_type >> 2) & 0xF;453}454455below_weights_pos += encoded_type_highpart_size;456scb.color_formats_matched = 1;457encoded_type_highpart_size = 0;458}459else460{461int bitpos = 2;462baseclass--;463464for (int i = 0; i < partition_count; i++)465{466color_formats[i] = (((encoded_type >> bitpos) & 1) + baseclass) << 2;467bitpos++;468}469470for (int i = 0; i < partition_count; i++)471{472color_formats[i] |= (encoded_type >> bitpos) & 3;473bitpos += 2;474}475}476scb.partition_index = static_cast<uint16_t>(read_bits(10, 13, pcb));477}478479for (int i = 0; i < partition_count; i++)480{481scb.color_formats[i] = static_cast<uint8_t>(color_formats[i]);482}483484// Determine number of color endpoint integers485int color_integer_count = 0;486for (int i = 0; i < partition_count; i++)487{488int endpoint_class = color_formats[i] >> 2;489color_integer_count += (endpoint_class + 1) * 2;490}491492if (color_integer_count > 18)493{494scb.block_type = SYM_BTYPE_ERROR;495return;496}497498// Determine the color endpoint format to use499static const int color_bits_arr[5] { -1, 115 - 4, 113 - 4 - PARTITION_INDEX_BITS, 113 - 4 - PARTITION_INDEX_BITS, 113 - 4 - PARTITION_INDEX_BITS };500int color_bits = color_bits_arr[partition_count] - bits_for_weights - encoded_type_highpart_size;501if (is_dual_plane)502{503color_bits -= 2;504}505506if (color_bits < 0)507{508color_bits = 0;509}510511int color_quant_level = quant_mode_table[color_integer_count >> 1][color_bits];512if (color_quant_level < QUANT_6)513{514scb.block_type = SYM_BTYPE_ERROR;515return;516}517518// Unpack the integer color values and assign to endpoints519scb.quant_mode = static_cast<quant_method>(color_quant_level);520521uint8_t values_to_decode[32];522decode_ise(static_cast<quant_method>(color_quant_level), color_integer_count, pcb,523values_to_decode, (partition_count == 1 ? 17 : 19 + PARTITION_INDEX_BITS));524525int valuecount_to_decode = 0;526const uint8_t* unpack_table = color_scrambled_pquant_to_uquant_tables[scb.quant_mode - QUANT_6];527for (int i = 0; i < partition_count; i++)528{529int vals = 2 * (color_formats[i] >> 2) + 2;530for (int j = 0; j < vals; j++)531{532scb.color_values[i][j] = unpack_table[values_to_decode[j + valuecount_to_decode]];533}534valuecount_to_decode += vals;535}536537// Fetch component for second-plane in the case of dual plane of weights.538scb.plane2_component = -1;539if (is_dual_plane)540{541scb.plane2_component = static_cast<int8_t>(read_bits(2, below_weights_pos - 2, pcb));542}543}544545546