1cc1dc7a3Sopenharmony_ci// SPDX-License-Identifier: Apache-2.0
2cc1dc7a3Sopenharmony_ci// ----------------------------------------------------------------------------
3cc1dc7a3Sopenharmony_ci// Copyright 2011-2023 Arm Limited
4cc1dc7a3Sopenharmony_ci//
5cc1dc7a3Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License"); you may not
6cc1dc7a3Sopenharmony_ci// use this file except in compliance with the License. You may obtain a copy
7cc1dc7a3Sopenharmony_ci// of the License at:
8cc1dc7a3Sopenharmony_ci//
9cc1dc7a3Sopenharmony_ci//     http://www.apache.org/licenses/LICENSE-2.0
10cc1dc7a3Sopenharmony_ci//
11cc1dc7a3Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software
12cc1dc7a3Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13cc1dc7a3Sopenharmony_ci// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14cc1dc7a3Sopenharmony_ci// License for the specific language governing permissions and limitations
15cc1dc7a3Sopenharmony_ci// under the License.
16cc1dc7a3Sopenharmony_ci// ----------------------------------------------------------------------------
17cc1dc7a3Sopenharmony_ci
18cc1dc7a3Sopenharmony_ci/**
19cc1dc7a3Sopenharmony_ci * @brief Functions for converting between symbolic and physical encodings.
20cc1dc7a3Sopenharmony_ci */
21cc1dc7a3Sopenharmony_ci
22cc1dc7a3Sopenharmony_ci#include "astcenc_internal.h"
23cc1dc7a3Sopenharmony_ci
24cc1dc7a3Sopenharmony_ci#include <cassert>
25cc1dc7a3Sopenharmony_ci
26cc1dc7a3Sopenharmony_ci/**
27cc1dc7a3Sopenharmony_ci * @brief Reverse bits in a byte.
28cc1dc7a3Sopenharmony_ci *
29cc1dc7a3Sopenharmony_ci * @param p   The value to reverse.
30cc1dc7a3Sopenharmony_ci  *
31cc1dc7a3Sopenharmony_ci * @return The reversed result.
32cc1dc7a3Sopenharmony_ci */
33cc1dc7a3Sopenharmony_cistatic inline int bitrev8(int p)
34cc1dc7a3Sopenharmony_ci{
35cc1dc7a3Sopenharmony_ci	p = ((p & 0x0F) << 4) | ((p >> 4) & 0x0F);
36cc1dc7a3Sopenharmony_ci	p = ((p & 0x33) << 2) | ((p >> 2) & 0x33);
37cc1dc7a3Sopenharmony_ci	p = ((p & 0x55) << 1) | ((p >> 1) & 0x55);
38cc1dc7a3Sopenharmony_ci	return p;
39cc1dc7a3Sopenharmony_ci}
40cc1dc7a3Sopenharmony_ci
41cc1dc7a3Sopenharmony_ci
42cc1dc7a3Sopenharmony_ci/**
43cc1dc7a3Sopenharmony_ci * @brief Read up to 8 bits at an arbitrary bit offset.
44cc1dc7a3Sopenharmony_ci *
45cc1dc7a3Sopenharmony_ci * The stored value is at most 8 bits, but can be stored at an offset of between 0 and 7 bits so may
46cc1dc7a3Sopenharmony_ci * span two separate bytes in memory.
47cc1dc7a3Sopenharmony_ci *
48cc1dc7a3Sopenharmony_ci * @param         bitcount    The number of bits to read.
49cc1dc7a3Sopenharmony_ci * @param         bitoffset   The bit offset to read from, between 0 and 7.
50cc1dc7a3Sopenharmony_ci * @param[in,out] ptr         The data pointer to read from.
51cc1dc7a3Sopenharmony_ci *
52cc1dc7a3Sopenharmony_ci * @return The read value.
53cc1dc7a3Sopenharmony_ci */
54cc1dc7a3Sopenharmony_cistatic inline int read_bits(
55cc1dc7a3Sopenharmony_ci	int bitcount,
56cc1dc7a3Sopenharmony_ci	int bitoffset,
57cc1dc7a3Sopenharmony_ci	const uint8_t* ptr
58cc1dc7a3Sopenharmony_ci) {
59cc1dc7a3Sopenharmony_ci	int mask = (1 << bitcount) - 1;
60cc1dc7a3Sopenharmony_ci	ptr += bitoffset >> 3;
61cc1dc7a3Sopenharmony_ci	bitoffset &= 7;
62cc1dc7a3Sopenharmony_ci	int value = ptr[0] | (ptr[1] << 8);
63cc1dc7a3Sopenharmony_ci	value >>= bitoffset;
64cc1dc7a3Sopenharmony_ci	value &= mask;
65cc1dc7a3Sopenharmony_ci	return value;
66cc1dc7a3Sopenharmony_ci}
67cc1dc7a3Sopenharmony_ci
68cc1dc7a3Sopenharmony_ci#if !defined(ASTCENC_DECOMPRESS_ONLY)
69cc1dc7a3Sopenharmony_ci
70cc1dc7a3Sopenharmony_ci/**
71cc1dc7a3Sopenharmony_ci * @brief Write up to 8 bits at an arbitrary bit offset.
72cc1dc7a3Sopenharmony_ci *
73cc1dc7a3Sopenharmony_ci * The stored value is at most 8 bits, but can be stored at an offset of between 0 and 7 bits so
74cc1dc7a3Sopenharmony_ci * may span two separate bytes in memory.
75cc1dc7a3Sopenharmony_ci *
76cc1dc7a3Sopenharmony_ci * @param         value       The value to write.
77cc1dc7a3Sopenharmony_ci * @param         bitcount    The number of bits to write, starting from LSB.
78cc1dc7a3Sopenharmony_ci * @param         bitoffset   The bit offset to store at, between 0 and 7.
79cc1dc7a3Sopenharmony_ci * @param[in,out] ptr         The data pointer to write to.
80cc1dc7a3Sopenharmony_ci */
81cc1dc7a3Sopenharmony_cistatic inline void write_bits(
82cc1dc7a3Sopenharmony_ci	int value,
83cc1dc7a3Sopenharmony_ci	int bitcount,
84cc1dc7a3Sopenharmony_ci	int bitoffset,
85cc1dc7a3Sopenharmony_ci	uint8_t* ptr
86cc1dc7a3Sopenharmony_ci) {
87cc1dc7a3Sopenharmony_ci	int mask = (1 << bitcount) - 1;
88cc1dc7a3Sopenharmony_ci	value &= mask;
89cc1dc7a3Sopenharmony_ci	ptr += bitoffset >> 3;
90cc1dc7a3Sopenharmony_ci	bitoffset &= 7;
91cc1dc7a3Sopenharmony_ci	value <<= bitoffset;
92cc1dc7a3Sopenharmony_ci	mask <<= bitoffset;
93cc1dc7a3Sopenharmony_ci	mask = ~mask;
94cc1dc7a3Sopenharmony_ci
95cc1dc7a3Sopenharmony_ci	ptr[0] &= mask;
96cc1dc7a3Sopenharmony_ci	ptr[0] |= value;
97cc1dc7a3Sopenharmony_ci	ptr[1] &= mask >> 8;
98cc1dc7a3Sopenharmony_ci	ptr[1] |= value >> 8;
99cc1dc7a3Sopenharmony_ci}
100cc1dc7a3Sopenharmony_ci
101cc1dc7a3Sopenharmony_cistatic const int HIGH_SPEED_PROFILE_COLOR_BYTES = 8;
102cc1dc7a3Sopenharmony_cistatic const int HIGH_SPEED_PROFILE_WEIGHT_BYTES = 16;
103cc1dc7a3Sopenharmony_ci/* See header for documentation. */
104cc1dc7a3Sopenharmony_civoid symbolic_to_physical(
105cc1dc7a3Sopenharmony_ci	const block_size_descriptor& bsd,
106cc1dc7a3Sopenharmony_ci	const symbolic_compressed_block& scb,
107cc1dc7a3Sopenharmony_ci	uint8_t pcb[16]
108cc1dc7a3Sopenharmony_ci) {
109cc1dc7a3Sopenharmony_ci	assert(scb.block_type != SYM_BTYPE_ERROR);
110cc1dc7a3Sopenharmony_ci	// Constant color block using UNORM16 colors
111cc1dc7a3Sopenharmony_ci	if (scb.block_type == SYM_BTYPE_CONST_U16 && scb.privateProfile != HIGH_SPEED_PROFILE)
112cc1dc7a3Sopenharmony_ci	{
113cc1dc7a3Sopenharmony_ci		// There is currently no attempt to coalesce larger void-extents
114cc1dc7a3Sopenharmony_ci		static const uint8_t cbytes[8] { 0xFC, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
115cc1dc7a3Sopenharmony_ci		for (unsigned int i = 0; i < 8; i++)
116cc1dc7a3Sopenharmony_ci		{
117cc1dc7a3Sopenharmony_ci			pcb[i] = cbytes[i];
118cc1dc7a3Sopenharmony_ci		}
119cc1dc7a3Sopenharmony_ci
120cc1dc7a3Sopenharmony_ci		for (unsigned int i = 0; i < BLOCK_MAX_COMPONENTS; i++)
121cc1dc7a3Sopenharmony_ci		{
122cc1dc7a3Sopenharmony_ci			pcb[2 * i + 8] = scb.constant_color[i] & 0xFF;
123cc1dc7a3Sopenharmony_ci			pcb[2 * i + 9] = (scb.constant_color[i] >> 8) & 0xFF;
124cc1dc7a3Sopenharmony_ci		}
125cc1dc7a3Sopenharmony_ci
126cc1dc7a3Sopenharmony_ci		return;
127cc1dc7a3Sopenharmony_ci	}
128cc1dc7a3Sopenharmony_ci
129cc1dc7a3Sopenharmony_ci	// Constant color block using FP16 colors
130cc1dc7a3Sopenharmony_ci	if (scb.block_type == SYM_BTYPE_CONST_F16 && scb.privateProfile != HIGH_SPEED_PROFILE)
131cc1dc7a3Sopenharmony_ci	{
132cc1dc7a3Sopenharmony_ci		// There is currently no attempt to coalesce larger void-extents
133cc1dc7a3Sopenharmony_ci		static const uint8_t cbytes[8]  { 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
134cc1dc7a3Sopenharmony_ci		for (unsigned int i = 0; i < 8; i++)
135cc1dc7a3Sopenharmony_ci		{
136cc1dc7a3Sopenharmony_ci			pcb[i] = cbytes[i];
137cc1dc7a3Sopenharmony_ci		}
138cc1dc7a3Sopenharmony_ci
139cc1dc7a3Sopenharmony_ci		for (unsigned int i = 0; i < BLOCK_MAX_COMPONENTS; i++)
140cc1dc7a3Sopenharmony_ci		{
141cc1dc7a3Sopenharmony_ci			pcb[2 * i + 8] = scb.constant_color[i] & 0xFF;
142cc1dc7a3Sopenharmony_ci			pcb[2 * i + 9] = (scb.constant_color[i] >> 8) & 0xFF;
143cc1dc7a3Sopenharmony_ci		}
144cc1dc7a3Sopenharmony_ci
145cc1dc7a3Sopenharmony_ci		return;
146cc1dc7a3Sopenharmony_ci	}
147cc1dc7a3Sopenharmony_ci
148cc1dc7a3Sopenharmony_ci	unsigned int partition_count = scb.partition_count;
149cc1dc7a3Sopenharmony_ci
150cc1dc7a3Sopenharmony_ci	// Compress the weights.
151cc1dc7a3Sopenharmony_ci	// They are encoded as an ordinary integer-sequence, then bit-reversed
152cc1dc7a3Sopenharmony_ci	uint8_t weightbuf[16] { 0 };
153cc1dc7a3Sopenharmony_ci
154cc1dc7a3Sopenharmony_ci	const auto& bm = bsd.get_block_mode(scb.block_mode);
155cc1dc7a3Sopenharmony_ci	const auto& di = bsd.get_decimation_info(bm.decimation_mode);
156cc1dc7a3Sopenharmony_ci	int weight_count = di.weight_count;
157cc1dc7a3Sopenharmony_ci	quant_method weight_quant_method = bm.get_weight_quant_mode();
158cc1dc7a3Sopenharmony_ci	float weight_quant_levels = static_cast<float>(get_quant_level(weight_quant_method));
159cc1dc7a3Sopenharmony_ci	int is_dual_plane = bm.is_dual_plane;
160cc1dc7a3Sopenharmony_ci
161cc1dc7a3Sopenharmony_ci	const auto& qat = quant_and_xfer_tables[weight_quant_method];
162cc1dc7a3Sopenharmony_ci
163cc1dc7a3Sopenharmony_ci	if (scb.privateProfile == HIGH_SPEED_PROFILE)
164cc1dc7a3Sopenharmony_ci	{
165cc1dc7a3Sopenharmony_ci		uint8_t weights[64];
166cc1dc7a3Sopenharmony_ci		for (int i = 0; i < weight_count; i++)
167cc1dc7a3Sopenharmony_ci		{
168cc1dc7a3Sopenharmony_ci			float uqw = static_cast<float>(scb.weights[i]);
169cc1dc7a3Sopenharmony_ci			float qw = (uqw / 64.0f) * (weight_quant_levels - 1.0f);
170cc1dc7a3Sopenharmony_ci			int qwi = static_cast<int>(qw + 0.5f);
171cc1dc7a3Sopenharmony_ci			weights[i] = qat.scramble_map[qwi];
172cc1dc7a3Sopenharmony_ci		}
173cc1dc7a3Sopenharmony_ci		encode_ise(QUANT_6, HIGH_SPEED_PROFILE_WEIGHT_BYTES, weights, weightbuf, 0);
174cc1dc7a3Sopenharmony_ci		for (int i = 0; i < HIGH_SPEED_PROFILE_WEIGHT_BYTES; i++)
175cc1dc7a3Sopenharmony_ci		{
176cc1dc7a3Sopenharmony_ci			pcb[i] = static_cast<uint8_t>(bitrev8(weightbuf[HIGH_SPEED_PROFILE_WEIGHT_BYTES - 1 - i]));
177cc1dc7a3Sopenharmony_ci		}
178cc1dc7a3Sopenharmony_ci		pcb[0] = 0x43; // the first byte of every block stream is 0x43 for HIGH_SPEED_PROFILE
179cc1dc7a3Sopenharmony_ci		pcb[1] = 0x80; // the second byte of every block stream is 0x80 for HIGH_SPEED_PROFILE
180cc1dc7a3Sopenharmony_ci		pcb[2] = 0x01; // the third (2 idx) byte of every block stream is 0x01 for HIGH_SPEED_PROFILE
181cc1dc7a3Sopenharmony_ci		uint8_t values_to_encode[HIGH_SPEED_PROFILE_COLOR_BYTES];
182cc1dc7a3Sopenharmony_ci		for (int j = 0; j < HIGH_SPEED_PROFILE_COLOR_BYTES; j++)
183cc1dc7a3Sopenharmony_ci		{
184cc1dc7a3Sopenharmony_ci			values_to_encode[j] = scb.color_values[0][j];
185cc1dc7a3Sopenharmony_ci		}
186cc1dc7a3Sopenharmony_ci		encode_ise(scb.get_color_quant_mode(), HIGH_SPEED_PROFILE_COLOR_BYTES,
187cc1dc7a3Sopenharmony_ci			values_to_encode, pcb, 17); // the color is starting from 17th bit for HIGH_SPEED_PROFILE
188cc1dc7a3Sopenharmony_ci		return;
189cc1dc7a3Sopenharmony_ci	}
190cc1dc7a3Sopenharmony_ci
191cc1dc7a3Sopenharmony_ci	int real_weight_count = is_dual_plane ? 2 * weight_count : weight_count;
192cc1dc7a3Sopenharmony_ci
193cc1dc7a3Sopenharmony_ci	int bits_for_weights = get_ise_sequence_bitcount(real_weight_count, weight_quant_method);
194cc1dc7a3Sopenharmony_ci
195cc1dc7a3Sopenharmony_ci	uint8_t weights[64];
196cc1dc7a3Sopenharmony_ci	if (is_dual_plane)
197cc1dc7a3Sopenharmony_ci	{
198cc1dc7a3Sopenharmony_ci		for (int i = 0; i < weight_count; i++)
199cc1dc7a3Sopenharmony_ci		{
200cc1dc7a3Sopenharmony_ci			float uqw = static_cast<float>(scb.weights[i]);
201cc1dc7a3Sopenharmony_ci			float qw = (uqw / 64.0f) * (weight_quant_levels - 1.0f);
202cc1dc7a3Sopenharmony_ci			int qwi = static_cast<int>(qw + 0.5f);
203cc1dc7a3Sopenharmony_ci			weights[2 * i] = qat.scramble_map[qwi];
204cc1dc7a3Sopenharmony_ci
205cc1dc7a3Sopenharmony_ci			uqw = static_cast<float>(scb.weights[i + WEIGHTS_PLANE2_OFFSET]);
206cc1dc7a3Sopenharmony_ci			qw = (uqw / 64.0f) * (weight_quant_levels - 1.0f);
207cc1dc7a3Sopenharmony_ci			qwi = static_cast<int>(qw + 0.5f);
208cc1dc7a3Sopenharmony_ci			weights[2 * i + 1] = qat.scramble_map[qwi];
209cc1dc7a3Sopenharmony_ci		}
210cc1dc7a3Sopenharmony_ci	}
211cc1dc7a3Sopenharmony_ci	else
212cc1dc7a3Sopenharmony_ci	{
213cc1dc7a3Sopenharmony_ci		for (int i = 0; i < weight_count; i++)
214cc1dc7a3Sopenharmony_ci		{
215cc1dc7a3Sopenharmony_ci			float uqw = static_cast<float>(scb.weights[i]);
216cc1dc7a3Sopenharmony_ci			float qw = (uqw / 64.0f) * (weight_quant_levels - 1.0f);
217cc1dc7a3Sopenharmony_ci			int qwi = static_cast<int>(qw + 0.5f);
218cc1dc7a3Sopenharmony_ci			weights[i] = qat.scramble_map[qwi];
219cc1dc7a3Sopenharmony_ci		}
220cc1dc7a3Sopenharmony_ci	}
221cc1dc7a3Sopenharmony_ci
222cc1dc7a3Sopenharmony_ci	encode_ise(weight_quant_method, real_weight_count, weights, weightbuf, 0);
223cc1dc7a3Sopenharmony_ci
224cc1dc7a3Sopenharmony_ci	for (int i = 0; i < 16; i++)
225cc1dc7a3Sopenharmony_ci	{
226cc1dc7a3Sopenharmony_ci		pcb[i] = static_cast<uint8_t>(bitrev8(weightbuf[15 - i]));
227cc1dc7a3Sopenharmony_ci	}
228cc1dc7a3Sopenharmony_ci
229cc1dc7a3Sopenharmony_ci	write_bits(scb.block_mode, 11, 0, pcb);
230cc1dc7a3Sopenharmony_ci	write_bits(partition_count - 1, 2, 11, pcb);
231cc1dc7a3Sopenharmony_ci
232cc1dc7a3Sopenharmony_ci	int below_weights_pos = 128 - bits_for_weights;
233cc1dc7a3Sopenharmony_ci
234cc1dc7a3Sopenharmony_ci	// Encode partition index and color endpoint types for blocks with 2+ partitions
235cc1dc7a3Sopenharmony_ci	if (partition_count > 1)
236cc1dc7a3Sopenharmony_ci	{
237cc1dc7a3Sopenharmony_ci		write_bits(scb.partition_index, 6, 13, pcb);
238cc1dc7a3Sopenharmony_ci		write_bits(scb.partition_index >> 6, PARTITION_INDEX_BITS - 6, 19, pcb);
239cc1dc7a3Sopenharmony_ci
240cc1dc7a3Sopenharmony_ci		if (scb.color_formats_matched)
241cc1dc7a3Sopenharmony_ci		{
242cc1dc7a3Sopenharmony_ci			write_bits(scb.color_formats[0] << 2, 6, 13 + PARTITION_INDEX_BITS, pcb);
243cc1dc7a3Sopenharmony_ci		}
244cc1dc7a3Sopenharmony_ci		else
245cc1dc7a3Sopenharmony_ci		{
246cc1dc7a3Sopenharmony_ci			// Check endpoint types for each partition to determine the lowest class present
247cc1dc7a3Sopenharmony_ci			int low_class = 4;
248cc1dc7a3Sopenharmony_ci
249cc1dc7a3Sopenharmony_ci			for (unsigned int i = 0; i < partition_count; i++)
250cc1dc7a3Sopenharmony_ci			{
251cc1dc7a3Sopenharmony_ci				int class_of_format = scb.color_formats[i] >> 2;
252cc1dc7a3Sopenharmony_ci				low_class = astc::min(class_of_format, low_class);
253cc1dc7a3Sopenharmony_ci			}
254cc1dc7a3Sopenharmony_ci
255cc1dc7a3Sopenharmony_ci			if (low_class == 3)
256cc1dc7a3Sopenharmony_ci			{
257cc1dc7a3Sopenharmony_ci				low_class = 2;
258cc1dc7a3Sopenharmony_ci			}
259cc1dc7a3Sopenharmony_ci
260cc1dc7a3Sopenharmony_ci			int encoded_type = low_class + 1;
261cc1dc7a3Sopenharmony_ci			int bitpos = 2;
262cc1dc7a3Sopenharmony_ci
263cc1dc7a3Sopenharmony_ci			for (unsigned int i = 0; i < partition_count; i++)
264cc1dc7a3Sopenharmony_ci			{
265cc1dc7a3Sopenharmony_ci				int classbit_of_format = (scb.color_formats[i] >> 2) - low_class;
266cc1dc7a3Sopenharmony_ci				encoded_type |= classbit_of_format << bitpos;
267cc1dc7a3Sopenharmony_ci				bitpos++;
268cc1dc7a3Sopenharmony_ci			}
269cc1dc7a3Sopenharmony_ci
270cc1dc7a3Sopenharmony_ci			for (unsigned int i = 0; i < partition_count; i++)
271cc1dc7a3Sopenharmony_ci			{
272cc1dc7a3Sopenharmony_ci				int lowbits_of_format = scb.color_formats[i] & 3;
273cc1dc7a3Sopenharmony_ci				encoded_type |= lowbits_of_format << bitpos;
274cc1dc7a3Sopenharmony_ci				bitpos += 2;
275cc1dc7a3Sopenharmony_ci			}
276cc1dc7a3Sopenharmony_ci
277cc1dc7a3Sopenharmony_ci			int encoded_type_lowpart = encoded_type & 0x3F;
278cc1dc7a3Sopenharmony_ci			int encoded_type_highpart = encoded_type >> 6;
279cc1dc7a3Sopenharmony_ci			int encoded_type_highpart_size = (3 * partition_count) - 4;
280cc1dc7a3Sopenharmony_ci			int encoded_type_highpart_pos = 128 - bits_for_weights - encoded_type_highpart_size;
281cc1dc7a3Sopenharmony_ci			write_bits(encoded_type_lowpart, 6, 13 + PARTITION_INDEX_BITS, pcb);
282cc1dc7a3Sopenharmony_ci			write_bits(encoded_type_highpart, encoded_type_highpart_size, encoded_type_highpart_pos, pcb);
283cc1dc7a3Sopenharmony_ci			below_weights_pos -= encoded_type_highpart_size;
284cc1dc7a3Sopenharmony_ci		}
285cc1dc7a3Sopenharmony_ci	}
286cc1dc7a3Sopenharmony_ci	else
287cc1dc7a3Sopenharmony_ci	{
288cc1dc7a3Sopenharmony_ci		write_bits(scb.color_formats[0], 4, 13, pcb);
289cc1dc7a3Sopenharmony_ci	}
290cc1dc7a3Sopenharmony_ci
291cc1dc7a3Sopenharmony_ci	// In dual-plane mode, encode the color component of the second plane of weights
292cc1dc7a3Sopenharmony_ci	if (is_dual_plane)
293cc1dc7a3Sopenharmony_ci	{
294cc1dc7a3Sopenharmony_ci		write_bits(scb.plane2_component, 2, below_weights_pos - 2, pcb);
295cc1dc7a3Sopenharmony_ci	}
296cc1dc7a3Sopenharmony_ci
297cc1dc7a3Sopenharmony_ci	// Encode the color components
298cc1dc7a3Sopenharmony_ci	uint8_t values_to_encode[32];
299cc1dc7a3Sopenharmony_ci	int valuecount_to_encode = 0;
300cc1dc7a3Sopenharmony_ci
301cc1dc7a3Sopenharmony_ci	const uint8_t* pack_table = color_uquant_to_scrambled_pquant_tables[scb.quant_mode - QUANT_6];
302cc1dc7a3Sopenharmony_ci	for (unsigned int i = 0; i < scb.partition_count; i++)
303cc1dc7a3Sopenharmony_ci	{
304cc1dc7a3Sopenharmony_ci		int vals = 2 * (scb.color_formats[i] >> 2) + 2;
305cc1dc7a3Sopenharmony_ci		assert(vals <= 8);
306cc1dc7a3Sopenharmony_ci		for (int j = 0; j < vals; j++)
307cc1dc7a3Sopenharmony_ci		{
308cc1dc7a3Sopenharmony_ci			values_to_encode[j + valuecount_to_encode] = pack_table[scb.color_values[i][j]];
309cc1dc7a3Sopenharmony_ci		}
310cc1dc7a3Sopenharmony_ci		valuecount_to_encode += vals;
311cc1dc7a3Sopenharmony_ci	}
312cc1dc7a3Sopenharmony_ci
313cc1dc7a3Sopenharmony_ci	encode_ise(scb.get_color_quant_mode(), valuecount_to_encode, values_to_encode, pcb,
314cc1dc7a3Sopenharmony_ci	           scb.partition_count == 1 ? 17 : 19 + PARTITION_INDEX_BITS);
315cc1dc7a3Sopenharmony_ci}
316cc1dc7a3Sopenharmony_ci
317cc1dc7a3Sopenharmony_ci#endif
318cc1dc7a3Sopenharmony_ci
319cc1dc7a3Sopenharmony_ci/* See header for documentation. */
320cc1dc7a3Sopenharmony_civoid physical_to_symbolic(
321cc1dc7a3Sopenharmony_ci	const block_size_descriptor& bsd,
322cc1dc7a3Sopenharmony_ci	const uint8_t pcb[16],
323cc1dc7a3Sopenharmony_ci	symbolic_compressed_block& scb
324cc1dc7a3Sopenharmony_ci) {
325cc1dc7a3Sopenharmony_ci	uint8_t bswapped[16];
326cc1dc7a3Sopenharmony_ci
327cc1dc7a3Sopenharmony_ci	scb.block_type = SYM_BTYPE_NONCONST;
328cc1dc7a3Sopenharmony_ci
329cc1dc7a3Sopenharmony_ci	// Extract header fields
330cc1dc7a3Sopenharmony_ci	int block_mode = read_bits(11, 0, pcb);
331cc1dc7a3Sopenharmony_ci	if ((block_mode & 0x1FF) == 0x1FC)
332cc1dc7a3Sopenharmony_ci	{
333cc1dc7a3Sopenharmony_ci		// Constant color block
334cc1dc7a3Sopenharmony_ci
335cc1dc7a3Sopenharmony_ci		// Check what format the data has
336cc1dc7a3Sopenharmony_ci		if (block_mode & 0x200)
337cc1dc7a3Sopenharmony_ci		{
338cc1dc7a3Sopenharmony_ci			scb.block_type = SYM_BTYPE_CONST_F16;
339cc1dc7a3Sopenharmony_ci		}
340cc1dc7a3Sopenharmony_ci		else
341cc1dc7a3Sopenharmony_ci		{
342cc1dc7a3Sopenharmony_ci			scb.block_type = SYM_BTYPE_CONST_U16;
343cc1dc7a3Sopenharmony_ci		}
344cc1dc7a3Sopenharmony_ci
345cc1dc7a3Sopenharmony_ci		scb.partition_count = 0;
346cc1dc7a3Sopenharmony_ci		for (int i = 0; i < 4; i++)
347cc1dc7a3Sopenharmony_ci		{
348cc1dc7a3Sopenharmony_ci			scb.constant_color[i] = pcb[2 * i + 8] | (pcb[2 * i + 9] << 8);
349cc1dc7a3Sopenharmony_ci		}
350cc1dc7a3Sopenharmony_ci
351cc1dc7a3Sopenharmony_ci		// Additionally, check that the void-extent
352cc1dc7a3Sopenharmony_ci		if (bsd.zdim == 1)
353cc1dc7a3Sopenharmony_ci		{
354cc1dc7a3Sopenharmony_ci			// 2D void-extent
355cc1dc7a3Sopenharmony_ci			int rsvbits = read_bits(2, 10, pcb);
356cc1dc7a3Sopenharmony_ci			if (rsvbits != 3)
357cc1dc7a3Sopenharmony_ci			{
358cc1dc7a3Sopenharmony_ci				scb.block_type = SYM_BTYPE_ERROR;
359cc1dc7a3Sopenharmony_ci				return;
360cc1dc7a3Sopenharmony_ci			}
361cc1dc7a3Sopenharmony_ci
362cc1dc7a3Sopenharmony_ci			int vx_low_s = read_bits(8, 12, pcb) | (read_bits(5, 12 + 8, pcb) << 8);
363cc1dc7a3Sopenharmony_ci			int vx_high_s = read_bits(8, 25, pcb) | (read_bits(5, 25 + 8, pcb) << 8);
364cc1dc7a3Sopenharmony_ci			int vx_low_t = read_bits(8, 38, pcb) | (read_bits(5, 38 + 8, pcb) << 8);
365cc1dc7a3Sopenharmony_ci			int vx_high_t = read_bits(8, 51, pcb) | (read_bits(5, 51 + 8, pcb) << 8);
366cc1dc7a3Sopenharmony_ci
367cc1dc7a3Sopenharmony_ci			int all_ones = vx_low_s == 0x1FFF && vx_high_s == 0x1FFF && vx_low_t == 0x1FFF && vx_high_t == 0x1FFF;
368cc1dc7a3Sopenharmony_ci
369cc1dc7a3Sopenharmony_ci			if ((vx_low_s >= vx_high_s || vx_low_t >= vx_high_t) && !all_ones)
370cc1dc7a3Sopenharmony_ci			{
371cc1dc7a3Sopenharmony_ci				scb.block_type = SYM_BTYPE_ERROR;
372cc1dc7a3Sopenharmony_ci				return;
373cc1dc7a3Sopenharmony_ci			}
374cc1dc7a3Sopenharmony_ci		}
375cc1dc7a3Sopenharmony_ci		else
376cc1dc7a3Sopenharmony_ci		{
377cc1dc7a3Sopenharmony_ci			// 3D void-extent
378cc1dc7a3Sopenharmony_ci			int vx_low_s = read_bits(9, 10, pcb);
379cc1dc7a3Sopenharmony_ci			int vx_high_s = read_bits(9, 19, pcb);
380cc1dc7a3Sopenharmony_ci			int vx_low_t = read_bits(9, 28, pcb);
381cc1dc7a3Sopenharmony_ci			int vx_high_t = read_bits(9, 37, pcb);
382cc1dc7a3Sopenharmony_ci			int vx_low_p = read_bits(9, 46, pcb);
383cc1dc7a3Sopenharmony_ci			int vx_high_p = read_bits(9, 55, pcb);
384cc1dc7a3Sopenharmony_ci
385cc1dc7a3Sopenharmony_ci			int all_ones = vx_low_s == 0x1FF && vx_high_s == 0x1FF && vx_low_t == 0x1FF && vx_high_t == 0x1FF && vx_low_p == 0x1FF && vx_high_p == 0x1FF;
386cc1dc7a3Sopenharmony_ci
387cc1dc7a3Sopenharmony_ci			if ((vx_low_s >= vx_high_s || vx_low_t >= vx_high_t || vx_low_p >= vx_high_p) && !all_ones)
388cc1dc7a3Sopenharmony_ci			{
389cc1dc7a3Sopenharmony_ci				scb.block_type = SYM_BTYPE_ERROR;
390cc1dc7a3Sopenharmony_ci				return;
391cc1dc7a3Sopenharmony_ci			}
392cc1dc7a3Sopenharmony_ci		}
393cc1dc7a3Sopenharmony_ci
394cc1dc7a3Sopenharmony_ci		return;
395cc1dc7a3Sopenharmony_ci	}
396cc1dc7a3Sopenharmony_ci
397cc1dc7a3Sopenharmony_ci	unsigned int packed_index = bsd.block_mode_packed_index[block_mode];
398cc1dc7a3Sopenharmony_ci	if (packed_index == BLOCK_BAD_BLOCK_MODE)
399cc1dc7a3Sopenharmony_ci	{
400cc1dc7a3Sopenharmony_ci		scb.block_type = SYM_BTYPE_ERROR;
401cc1dc7a3Sopenharmony_ci		return;
402cc1dc7a3Sopenharmony_ci	}
403cc1dc7a3Sopenharmony_ci
404cc1dc7a3Sopenharmony_ci	const auto& bm = bsd.get_block_mode(block_mode);
405cc1dc7a3Sopenharmony_ci	const auto& di = bsd.get_decimation_info(bm.decimation_mode);
406cc1dc7a3Sopenharmony_ci
407cc1dc7a3Sopenharmony_ci	int weight_count = di.weight_count;
408cc1dc7a3Sopenharmony_ci	promise(weight_count > 0);
409cc1dc7a3Sopenharmony_ci
410cc1dc7a3Sopenharmony_ci	quant_method weight_quant_method = static_cast<quant_method>(bm.quant_mode);
411cc1dc7a3Sopenharmony_ci	int is_dual_plane = bm.is_dual_plane;
412cc1dc7a3Sopenharmony_ci
413cc1dc7a3Sopenharmony_ci	int real_weight_count = is_dual_plane ? 2 * weight_count : weight_count;
414cc1dc7a3Sopenharmony_ci
415cc1dc7a3Sopenharmony_ci	int partition_count = read_bits(2, 11, pcb) + 1;
416cc1dc7a3Sopenharmony_ci	promise(partition_count > 0);
417cc1dc7a3Sopenharmony_ci
418cc1dc7a3Sopenharmony_ci	scb.block_mode = static_cast<uint16_t>(block_mode);
419cc1dc7a3Sopenharmony_ci	scb.partition_count = static_cast<uint8_t>(partition_count);
420cc1dc7a3Sopenharmony_ci
421cc1dc7a3Sopenharmony_ci	for (int i = 0; i < 16; i++)
422cc1dc7a3Sopenharmony_ci	{
423cc1dc7a3Sopenharmony_ci		bswapped[i] = static_cast<uint8_t>(bitrev8(pcb[15 - i]));
424cc1dc7a3Sopenharmony_ci	}
425cc1dc7a3Sopenharmony_ci
426cc1dc7a3Sopenharmony_ci	int bits_for_weights = get_ise_sequence_bitcount(real_weight_count, weight_quant_method);
427cc1dc7a3Sopenharmony_ci
428cc1dc7a3Sopenharmony_ci	int below_weights_pos = 128 - bits_for_weights;
429cc1dc7a3Sopenharmony_ci
430cc1dc7a3Sopenharmony_ci	uint8_t indices[64];
431cc1dc7a3Sopenharmony_ci	const auto& qat = quant_and_xfer_tables[weight_quant_method];
432cc1dc7a3Sopenharmony_ci
433cc1dc7a3Sopenharmony_ci	decode_ise(weight_quant_method, real_weight_count, bswapped, indices, 0);
434cc1dc7a3Sopenharmony_ci
435cc1dc7a3Sopenharmony_ci	if (is_dual_plane)
436cc1dc7a3Sopenharmony_ci	{
437cc1dc7a3Sopenharmony_ci		for (int i = 0; i < weight_count; i++)
438cc1dc7a3Sopenharmony_ci		{
439cc1dc7a3Sopenharmony_ci			scb.weights[i] = qat.unscramble_and_unquant_map[indices[2 * i]];
440cc1dc7a3Sopenharmony_ci			scb.weights[i + WEIGHTS_PLANE2_OFFSET] = qat.unscramble_and_unquant_map[indices[2 * i + 1]];
441cc1dc7a3Sopenharmony_ci		}
442cc1dc7a3Sopenharmony_ci	}
443cc1dc7a3Sopenharmony_ci	else
444cc1dc7a3Sopenharmony_ci	{
445cc1dc7a3Sopenharmony_ci		for (int i = 0; i < weight_count; i++)
446cc1dc7a3Sopenharmony_ci		{
447cc1dc7a3Sopenharmony_ci			scb.weights[i] = qat.unscramble_and_unquant_map[indices[i]];
448cc1dc7a3Sopenharmony_ci		}
449cc1dc7a3Sopenharmony_ci	}
450cc1dc7a3Sopenharmony_ci
451cc1dc7a3Sopenharmony_ci	if (is_dual_plane && partition_count == 4)
452cc1dc7a3Sopenharmony_ci	{
453cc1dc7a3Sopenharmony_ci		scb.block_type = SYM_BTYPE_ERROR;
454cc1dc7a3Sopenharmony_ci		return;
455cc1dc7a3Sopenharmony_ci	}
456cc1dc7a3Sopenharmony_ci
457cc1dc7a3Sopenharmony_ci	scb.color_formats_matched = 0;
458cc1dc7a3Sopenharmony_ci
459cc1dc7a3Sopenharmony_ci	// Determine the format of each endpoint pair
460cc1dc7a3Sopenharmony_ci	int color_formats[BLOCK_MAX_PARTITIONS];
461cc1dc7a3Sopenharmony_ci	int encoded_type_highpart_size = 0;
462cc1dc7a3Sopenharmony_ci	if (partition_count == 1)
463cc1dc7a3Sopenharmony_ci	{
464cc1dc7a3Sopenharmony_ci		color_formats[0] = read_bits(4, 13, pcb);
465cc1dc7a3Sopenharmony_ci		scb.partition_index = 0;
466cc1dc7a3Sopenharmony_ci	}
467cc1dc7a3Sopenharmony_ci	else
468cc1dc7a3Sopenharmony_ci	{
469cc1dc7a3Sopenharmony_ci		encoded_type_highpart_size = (3 * partition_count) - 4;
470cc1dc7a3Sopenharmony_ci		below_weights_pos -= encoded_type_highpart_size;
471cc1dc7a3Sopenharmony_ci		int encoded_type = read_bits(6, 13 + PARTITION_INDEX_BITS, pcb) |
472cc1dc7a3Sopenharmony_ci		                  (read_bits(encoded_type_highpart_size, below_weights_pos, pcb) << 6);
473cc1dc7a3Sopenharmony_ci		int baseclass = encoded_type & 0x3;
474cc1dc7a3Sopenharmony_ci		if (baseclass == 0)
475cc1dc7a3Sopenharmony_ci		{
476cc1dc7a3Sopenharmony_ci			for (int i = 0; i < partition_count; i++)
477cc1dc7a3Sopenharmony_ci			{
478cc1dc7a3Sopenharmony_ci				color_formats[i] = (encoded_type >> 2) & 0xF;
479cc1dc7a3Sopenharmony_ci			}
480cc1dc7a3Sopenharmony_ci
481cc1dc7a3Sopenharmony_ci			below_weights_pos += encoded_type_highpart_size;
482cc1dc7a3Sopenharmony_ci			scb.color_formats_matched = 1;
483cc1dc7a3Sopenharmony_ci			encoded_type_highpart_size = 0;
484cc1dc7a3Sopenharmony_ci		}
485cc1dc7a3Sopenharmony_ci		else
486cc1dc7a3Sopenharmony_ci		{
487cc1dc7a3Sopenharmony_ci			int bitpos = 2;
488cc1dc7a3Sopenharmony_ci			baseclass--;
489cc1dc7a3Sopenharmony_ci
490cc1dc7a3Sopenharmony_ci			for (int i = 0; i < partition_count; i++)
491cc1dc7a3Sopenharmony_ci			{
492cc1dc7a3Sopenharmony_ci				color_formats[i] = (((encoded_type >> bitpos) & 1) + baseclass) << 2;
493cc1dc7a3Sopenharmony_ci				bitpos++;
494cc1dc7a3Sopenharmony_ci			}
495cc1dc7a3Sopenharmony_ci
496cc1dc7a3Sopenharmony_ci			for (int i = 0; i < partition_count; i++)
497cc1dc7a3Sopenharmony_ci			{
498cc1dc7a3Sopenharmony_ci				color_formats[i] |= (encoded_type >> bitpos) & 3;
499cc1dc7a3Sopenharmony_ci				bitpos += 2;
500cc1dc7a3Sopenharmony_ci			}
501cc1dc7a3Sopenharmony_ci		}
502cc1dc7a3Sopenharmony_ci		scb.partition_index = static_cast<uint16_t>(read_bits(6, 13, pcb) |
503cc1dc7a3Sopenharmony_ci		                                            (read_bits(PARTITION_INDEX_BITS - 6, 19, pcb) << 6));
504cc1dc7a3Sopenharmony_ci	}
505cc1dc7a3Sopenharmony_ci
506cc1dc7a3Sopenharmony_ci	for (int i = 0; i < partition_count; i++)
507cc1dc7a3Sopenharmony_ci	{
508cc1dc7a3Sopenharmony_ci		scb.color_formats[i] = static_cast<uint8_t>(color_formats[i]);
509cc1dc7a3Sopenharmony_ci	}
510cc1dc7a3Sopenharmony_ci
511cc1dc7a3Sopenharmony_ci	// Determine number of color endpoint integers
512cc1dc7a3Sopenharmony_ci	int color_integer_count = 0;
513cc1dc7a3Sopenharmony_ci	for (int i = 0; i < partition_count; i++)
514cc1dc7a3Sopenharmony_ci	{
515cc1dc7a3Sopenharmony_ci		int endpoint_class = color_formats[i] >> 2;
516cc1dc7a3Sopenharmony_ci		color_integer_count += (endpoint_class + 1) * 2;
517cc1dc7a3Sopenharmony_ci	}
518cc1dc7a3Sopenharmony_ci
519cc1dc7a3Sopenharmony_ci	if (color_integer_count > 18)
520cc1dc7a3Sopenharmony_ci	{
521cc1dc7a3Sopenharmony_ci		scb.block_type = SYM_BTYPE_ERROR;
522cc1dc7a3Sopenharmony_ci		return;
523cc1dc7a3Sopenharmony_ci	}
524cc1dc7a3Sopenharmony_ci
525cc1dc7a3Sopenharmony_ci	// Determine the color endpoint format to use
526cc1dc7a3Sopenharmony_ci	static const int color_bits_arr[5] { -1, 115 - 4, 113 - 4 - PARTITION_INDEX_BITS, 113 - 4 - PARTITION_INDEX_BITS, 113 - 4 - PARTITION_INDEX_BITS };
527cc1dc7a3Sopenharmony_ci	int color_bits = color_bits_arr[partition_count] - bits_for_weights - encoded_type_highpart_size;
528cc1dc7a3Sopenharmony_ci	if (is_dual_plane)
529cc1dc7a3Sopenharmony_ci	{
530cc1dc7a3Sopenharmony_ci		color_bits -= 2;
531cc1dc7a3Sopenharmony_ci	}
532cc1dc7a3Sopenharmony_ci
533cc1dc7a3Sopenharmony_ci	if (color_bits < 0)
534cc1dc7a3Sopenharmony_ci	{
535cc1dc7a3Sopenharmony_ci		color_bits = 0;
536cc1dc7a3Sopenharmony_ci	}
537cc1dc7a3Sopenharmony_ci
538cc1dc7a3Sopenharmony_ci	int color_quant_level = quant_mode_table[color_integer_count >> 1][color_bits];
539cc1dc7a3Sopenharmony_ci	if (color_quant_level < QUANT_6)
540cc1dc7a3Sopenharmony_ci	{
541cc1dc7a3Sopenharmony_ci		scb.block_type = SYM_BTYPE_ERROR;
542cc1dc7a3Sopenharmony_ci		return;
543cc1dc7a3Sopenharmony_ci	}
544cc1dc7a3Sopenharmony_ci
545cc1dc7a3Sopenharmony_ci	// Unpack the integer color values and assign to endpoints
546cc1dc7a3Sopenharmony_ci	scb.quant_mode = static_cast<quant_method>(color_quant_level);
547cc1dc7a3Sopenharmony_ci
548cc1dc7a3Sopenharmony_ci	uint8_t values_to_decode[32];
549cc1dc7a3Sopenharmony_ci	decode_ise(static_cast<quant_method>(color_quant_level), color_integer_count, pcb,
550cc1dc7a3Sopenharmony_ci	           values_to_decode, (partition_count == 1 ? 17 : 19 + PARTITION_INDEX_BITS));
551cc1dc7a3Sopenharmony_ci
552cc1dc7a3Sopenharmony_ci	int valuecount_to_decode = 0;
553cc1dc7a3Sopenharmony_ci	const uint8_t* unpack_table = color_scrambled_pquant_to_uquant_tables[scb.quant_mode - QUANT_6];
554cc1dc7a3Sopenharmony_ci	for (int i = 0; i < partition_count; i++)
555cc1dc7a3Sopenharmony_ci	{
556cc1dc7a3Sopenharmony_ci		int vals = 2 * (color_formats[i] >> 2) + 2;
557cc1dc7a3Sopenharmony_ci		for (int j = 0; j < vals; j++)
558cc1dc7a3Sopenharmony_ci		{
559cc1dc7a3Sopenharmony_ci			scb.color_values[i][j] = unpack_table[values_to_decode[j + valuecount_to_decode]];
560cc1dc7a3Sopenharmony_ci		}
561cc1dc7a3Sopenharmony_ci		valuecount_to_decode += vals;
562cc1dc7a3Sopenharmony_ci	}
563cc1dc7a3Sopenharmony_ci
564cc1dc7a3Sopenharmony_ci	// Fetch component for second-plane in the case of dual plane of weights.
565cc1dc7a3Sopenharmony_ci	scb.plane2_component = -1;
566cc1dc7a3Sopenharmony_ci	if (is_dual_plane)
567cc1dc7a3Sopenharmony_ci	{
568cc1dc7a3Sopenharmony_ci		scb.plane2_component = static_cast<int8_t>(read_bits(2, below_weights_pos - 2, pcb));
569cc1dc7a3Sopenharmony_ci	}
570cc1dc7a3Sopenharmony_ci}
571