blob: 8a7dac6dafa5997a05a011ee9beb55d6aa4309dc [file] [log] [blame]
// SPDX-License-Identifier: Apache-2.0
// ----------------------------------------------------------------------------
// Copyright 2011-2020 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.
// ----------------------------------------------------------------------------
/**
* @brief Functions to decompress a symbolic block.
*/
#include "astc_codec_internals.h"
static int compute_value_of_texel_int(
int texel_to_get,
const decimation_table* it,
const int* weights
) {
int i;
int summed_value = 8;
int weights_to_evaluate = it->texel_num_weights[texel_to_get];
for (i = 0; i < weights_to_evaluate; i++)
{
summed_value += weights[it->texel_weights[texel_to_get][i]] * it->texel_weights_int[texel_to_get][i];
}
return summed_value >> 4;
}
static uint4 lerp_color_int(
astc_decode_mode decode_mode,
uint4 color0,
uint4 color1,
int weight,
int plane2_weight,
int plane2_color_component // -1 in 1-plane mode
) {
int4 ecolor0 = int4(color0.x, color0.y, color0.z, color0.w);
int4 ecolor1 = int4(color1.x, color1.y, color1.z, color1.w);
int4 eweight1 = int4(weight, weight, weight, weight);
switch (plane2_color_component)
{
case 0:
eweight1.x = plane2_weight;
break;
case 1:
eweight1.y = plane2_weight;
break;
case 2:
eweight1.z = plane2_weight;
break;
case 3:
eweight1.w = plane2_weight;
break;
default:
break;
}
int4 eweight0 = int4(64, 64, 64, 64) - eweight1;
if (decode_mode == DECODE_LDR_SRGB)
{
ecolor0 = int4(ecolor0.x >> 8, ecolor0.y >> 8, ecolor0.z >> 8, ecolor0.w >> 8);
ecolor1 = int4(ecolor1.x >> 8, ecolor1.y >> 8, ecolor1.z >> 8, ecolor1.w >> 8);
}
int4 color = (ecolor0 * eweight0) + (ecolor1 * eweight1) + int4(32, 32, 32, 32);
color = int4(color.x >> 6, color.y >> 6, color.z >> 6, color.w >> 6);
if (decode_mode == DECODE_LDR_SRGB)
color = color * 257;
return uint4(color.x, color.y, color.z, color.w);
}
void decompress_symbolic_block(
astc_decode_mode decode_mode,
const block_size_descriptor* bsd,
int xpos,
int ypos,
int zpos,
const symbolic_compressed_block* scb,
imageblock* blk
) {
blk->xpos = xpos;
blk->ypos = ypos;
blk->zpos = zpos;
int i;
// if we detected an error-block, blow up immediately.
if (scb->error_block)
{
if (decode_mode == DECODE_LDR_SRGB)
{
for (i = 0; i < bsd->texel_count; i++)
{
blk->orig_data[4 * i] = 1.0f;
blk->orig_data[4 * i + 1] = 0.0f;
blk->orig_data[4 * i + 2] = 1.0f;
blk->orig_data[4 * i + 3] = 1.0f;
blk->rgb_lns[i] = 0;
blk->alpha_lns[i] = 0;
blk->nan_texel[i] = 0;
}
}
else
{
for (i = 0; i < bsd->texel_count; i++)
{
blk->orig_data[4 * i] = 0.0f;
blk->orig_data[4 * i + 1] = 0.0f;
blk->orig_data[4 * i + 2] = 0.0f;
blk->orig_data[4 * i + 3] = 0.0f;
blk->rgb_lns[i] = 0;
blk->alpha_lns[i] = 0;
blk->nan_texel[i] = 1;
}
}
imageblock_initialize_work_from_orig(blk, bsd->texel_count);
update_imageblock_flags(blk, bsd->xdim, bsd->ydim, bsd->zdim);
return;
}
if (scb->block_mode < 0)
{
float red = 0, green = 0, blue = 0, alpha = 0;
int use_lns = 0;
int use_nan = 0;
if (scb->block_mode == -2)
{
// For sRGB decoding, we should return only the top 8 bits.
int mask = (decode_mode == DECODE_LDR_SRGB) ? 0xFF00 : 0xFFFF;
red = sf16_to_float(unorm16_to_sf16(scb->constant_color[0] & mask));
green = sf16_to_float(unorm16_to_sf16(scb->constant_color[1] & mask));
blue = sf16_to_float(unorm16_to_sf16(scb->constant_color[2] & mask));
alpha = sf16_to_float(unorm16_to_sf16(scb->constant_color[3] & mask));
use_lns = 0;
use_nan = 0;
}
else
{
switch (decode_mode)
{
case DECODE_LDR_SRGB:
red = 1.0f;
green = 0.0f;
blue = 1.0f;
alpha = 1.0f;
use_lns = 0;
use_nan = 0;
break;
case DECODE_LDR:
red = 0.0f;
green = 0.0f;
blue = 0.0f;
alpha = 0.0f;
use_lns = 0;
use_nan = 1;
break;
case DECODE_HDR:
// constant-color block; unpack from FP16 to FP32.
red = sf16_to_float(scb->constant_color[0]);
green = sf16_to_float(scb->constant_color[1]);
blue = sf16_to_float(scb->constant_color[2]);
alpha = sf16_to_float(scb->constant_color[3]);
use_lns = 1;
use_nan = 0;
break;
}
}
for (i = 0; i < bsd->texel_count; i++)
{
blk->orig_data[4 * i] = red;
blk->orig_data[4 * i + 1] = green;
blk->orig_data[4 * i + 2] = blue;
blk->orig_data[4 * i + 3] = alpha;
blk->rgb_lns[i] = use_lns;
blk->alpha_lns[i] = use_lns;
blk->nan_texel[i] = use_nan;
}
imageblock_initialize_work_from_orig(blk, bsd->texel_count);
update_imageblock_flags(blk, bsd->xdim, bsd->ydim, bsd->zdim);
return;
}
// get the appropriate partition-table entry
int partition_count = scb->partition_count;
const partition_info *pt = get_partition_table(bsd, partition_count);
pt += scb->partition_index;
// get the appropriate block descriptor
const decimation_table *const *ixtab2 = bsd->decimation_tables;
const decimation_table *it = ixtab2[bsd->block_modes[scb->block_mode].decimation_mode];
int is_dual_plane = bsd->block_modes[scb->block_mode].is_dual_plane;
int weight_quantization_level = bsd->block_modes[scb->block_mode].quantization_mode;
// decode the color endpoints
uint4 color_endpoint0[4];
uint4 color_endpoint1[4];
int rgb_hdr_endpoint[4];
int alpha_hdr_endpoint[4];
int nan_endpoint[4];
for (i = 0; i < partition_count; i++)
unpack_color_endpoints(decode_mode,
scb->color_formats[i],
scb->color_quantization_level,
scb->color_values[i],
&(rgb_hdr_endpoint[i]),
&(alpha_hdr_endpoint[i]),
&(nan_endpoint[i]),
&(color_endpoint0[i]),
&(color_endpoint1[i]));
// first unquantize the weights
int uq_plane1_weights[MAX_WEIGHTS_PER_BLOCK];
int uq_plane2_weights[MAX_WEIGHTS_PER_BLOCK];
int weight_count = it->num_weights;
const quantization_and_transfer_table *qat = &(quant_and_xfer_tables[weight_quantization_level]);
for (i = 0; i < weight_count; i++)
{
uq_plane1_weights[i] = qat->unquantized_value[scb->plane1_weights[i]];
}
if (is_dual_plane)
{
for (i = 0; i < weight_count; i++)
uq_plane2_weights[i] = qat->unquantized_value[scb->plane2_weights[i]];
}
// then undecimate them.
int weights[MAX_TEXELS_PER_BLOCK];
int plane2_weights[MAX_TEXELS_PER_BLOCK];
for (i = 0; i < bsd->texel_count; i++)
weights[i] = compute_value_of_texel_int(i, it, uq_plane1_weights);
if (is_dual_plane)
for (i = 0; i < bsd->texel_count; i++)
plane2_weights[i] = compute_value_of_texel_int(i, it, uq_plane2_weights);
int plane2_color_component = scb->plane2_color_component;
// now that we have endpoint colors and weights, we can unpack actual colors for
// each texel.
for (i = 0; i < bsd->texel_count; i++)
{
int partition = pt->partition_of_texel[i];
uint4 color = lerp_color_int(decode_mode,
color_endpoint0[partition],
color_endpoint1[partition],
weights[i],
plane2_weights[i],
is_dual_plane ? plane2_color_component : -1);
blk->rgb_lns[i] = rgb_hdr_endpoint[partition];
blk->alpha_lns[i] = alpha_hdr_endpoint[partition];
blk->nan_texel[i] = nan_endpoint[partition];
blk->data_r[i] = (float)color.x;
blk->data_g[i] = (float)color.y;
blk->data_b[i] = (float)color.z;
blk->data_a[i] = (float)color.w;
}
imageblock_initialize_orig_from_work(blk, bsd->texel_count);
update_imageblock_flags(blk, bsd->xdim, bsd->ydim, bsd->zdim);
}