| // 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 for generating partition tables on demand. | |
| */ | |
| #include "astc_codec_internals.h" | |
| /* | |
| Produce a canonicalized representation of a partition pattern | |
| The largest possible such representation is 432 bits, equal to 7 uint64_t values. | |
| */ | |
| static void gen_canonicalized_partition_table( | |
| int texel_count, | |
| const uint8_t* partition_table, | |
| uint64_t canonicalized[7] | |
| ) { | |
| int i; | |
| for (i = 0; i < 7; i++) | |
| canonicalized[i] = 0; | |
| int mapped_index[4]; | |
| int map_weight_count = 0; | |
| for (i = 0; i < 4; i++) | |
| mapped_index[i] = -1; | |
| for (i = 0; i < texel_count; i++) | |
| { | |
| int index = partition_table[i]; | |
| if (mapped_index[index] == -1) | |
| mapped_index[index] = map_weight_count++; | |
| uint64_t xlat_index = mapped_index[index]; | |
| canonicalized[i >> 5] |= xlat_index << (2 * (i & 0x1F)); | |
| } | |
| } | |
| static int compare_canonicalized_partition_tables( | |
| const uint64_t part1[7], | |
| const uint64_t part2[7] | |
| ) { | |
| if (part1[0] != part2[0]) | |
| return 0; | |
| if (part1[1] != part2[1]) | |
| return 0; | |
| if (part1[2] != part2[2]) | |
| return 0; | |
| if (part1[3] != part2[3]) | |
| return 0; | |
| if (part1[4] != part2[4]) | |
| return 0; | |
| if (part1[5] != part2[5]) | |
| return 0; | |
| if (part1[6] != part2[6]) | |
| return 0; | |
| return 1; | |
| } | |
| /* | |
| For a partition table, detect partitionss that are equivalent, then mark them as invalid. This reduces the number of partitions that the codec has to consider and thus improves encode | |
| performance. */ | |
| static void partition_table_zap_equal_elements( | |
| int texel_count, | |
| partition_info* pi | |
| ) { | |
| int partition_tables_zapped = 0; | |
| int i, j; | |
| uint64_t *canonicalizeds = new uint64_t[PARTITION_COUNT * 7]; | |
| for (i = 0; i < PARTITION_COUNT; i++) | |
| { | |
| gen_canonicalized_partition_table(texel_count, pi[i].partition_of_texel, canonicalizeds + i * 7); | |
| } | |
| for (i = 0; i < PARTITION_COUNT; i++) | |
| { | |
| for (j = 0; j < i; j++) | |
| { | |
| if (compare_canonicalized_partition_tables(canonicalizeds + 7 * i, canonicalizeds + 7 * j)) | |
| { | |
| pi[i].partition_count = 0; | |
| partition_tables_zapped++; | |
| break; | |
| } | |
| } | |
| } | |
| delete[]canonicalizeds; | |
| } | |
| static uint32_t hash52(uint32_t inp) | |
| { | |
| inp ^= inp >> 15; | |
| inp *= 0xEEDE0891; // (2^4+1)*(2^7+1)*(2^17-1) | |
| inp ^= inp >> 5; | |
| inp += inp << 16; | |
| inp ^= inp >> 7; | |
| inp ^= inp >> 3; | |
| inp ^= inp << 6; | |
| inp ^= inp >> 17; | |
| return inp; | |
| } | |
| static int select_partition( | |
| int seed, | |
| int x, | |
| int y, | |
| int z, | |
| int partitioncount, | |
| int small_block | |
| ) { | |
| if (small_block) | |
| { | |
| x <<= 1; | |
| y <<= 1; | |
| z <<= 1; | |
| } | |
| seed += (partitioncount - 1) * 1024; | |
| uint32_t rnum = hash52(seed); | |
| uint8_t seed1 = rnum & 0xF; | |
| uint8_t seed2 = (rnum >> 4) & 0xF; | |
| uint8_t seed3 = (rnum >> 8) & 0xF; | |
| uint8_t seed4 = (rnum >> 12) & 0xF; | |
| uint8_t seed5 = (rnum >> 16) & 0xF; | |
| uint8_t seed6 = (rnum >> 20) & 0xF; | |
| uint8_t seed7 = (rnum >> 24) & 0xF; | |
| uint8_t seed8 = (rnum >> 28) & 0xF; | |
| uint8_t seed9 = (rnum >> 18) & 0xF; | |
| uint8_t seed10 = (rnum >> 22) & 0xF; | |
| uint8_t seed11 = (rnum >> 26) & 0xF; | |
| uint8_t seed12 = ((rnum >> 30) | (rnum << 2)) & 0xF; | |
| // squaring all the seeds in order to bias their distribution | |
| // towards lower values. | |
| seed1 *= seed1; | |
| seed2 *= seed2; | |
| seed3 *= seed3; | |
| seed4 *= seed4; | |
| seed5 *= seed5; | |
| seed6 *= seed6; | |
| seed7 *= seed7; | |
| seed8 *= seed8; | |
| seed9 *= seed9; | |
| seed10 *= seed10; | |
| seed11 *= seed11; | |
| seed12 *= seed12; | |
| int sh1, sh2, sh3; | |
| if (seed & 1) | |
| { | |
| sh1 = (seed & 2 ? 4 : 5); | |
| sh2 = (partitioncount == 3 ? 6 : 5); | |
| } | |
| else | |
| { | |
| sh1 = (partitioncount == 3 ? 6 : 5); | |
| sh2 = (seed & 2 ? 4 : 5); | |
| } | |
| sh3 = (seed & 0x10) ? sh1 : sh2; | |
| seed1 >>= sh1; | |
| seed2 >>= sh2; | |
| seed3 >>= sh1; | |
| seed4 >>= sh2; | |
| seed5 >>= sh1; | |
| seed6 >>= sh2; | |
| seed7 >>= sh1; | |
| seed8 >>= sh2; | |
| seed9 >>= sh3; | |
| seed10 >>= sh3; | |
| seed11 >>= sh3; | |
| seed12 >>= sh3; | |
| int a = seed1 * x + seed2 * y + seed11 * z + (rnum >> 14); | |
| int b = seed3 * x + seed4 * y + seed12 * z + (rnum >> 10); | |
| int c = seed5 * x + seed6 * y + seed9 * z + (rnum >> 6); | |
| int d = seed7 * x + seed8 * y + seed10 * z + (rnum >> 2); | |
| // apply the saw | |
| a &= 0x3F; | |
| b &= 0x3F; | |
| c &= 0x3F; | |
| d &= 0x3F; | |
| // remove some of the components if we are to output < 4 partitions. | |
| if (partitioncount <= 3) | |
| d = 0; | |
| if (partitioncount <= 2) | |
| c = 0; | |
| if (partitioncount <= 1) | |
| b = 0; | |
| int partition; | |
| if (a >= b && a >= c && a >= d) | |
| partition = 0; | |
| else if (b >= c && b >= d) | |
| partition = 1; | |
| else if (c >= d) | |
| partition = 2; | |
| else | |
| partition = 3; | |
| return partition; | |
| } | |
| static void generate_one_partition_table( | |
| const block_size_descriptor* bsd, | |
| int partition_count, | |
| int partition_index, | |
| partition_info* pt | |
| ) { | |
| int texels_per_block = bsd->texel_count; | |
| int small_block = texels_per_block < 32; | |
| uint8_t *partition_of_texel = pt->partition_of_texel; | |
| int x, y, z, i; | |
| for (z = 0; z < bsd->zdim; z++) | |
| for (y = 0; y < bsd->ydim; y++) | |
| for (x = 0; x < bsd->xdim; x++) | |
| { | |
| uint8_t part = select_partition(partition_index, x, y, z, partition_count, small_block); | |
| *partition_of_texel++ = part; | |
| } | |
| int counts[4]; | |
| for (i = 0; i < 4; i++) | |
| counts[i] = 0; | |
| for (i = 0; i < texels_per_block; i++) | |
| { | |
| int partition = pt->partition_of_texel[i]; | |
| counts[partition]++; | |
| } | |
| if (counts[0] == 0) | |
| pt->partition_count = 0; | |
| else if (counts[1] == 0) | |
| pt->partition_count = 1; | |
| else if (counts[2] == 0) | |
| pt->partition_count = 2; | |
| else if (counts[3] == 0) | |
| pt->partition_count = 3; | |
| else | |
| pt->partition_count = 4; | |
| } | |
| /* Public function, see header file for detailed documentation */ | |
| void init_partition_tables( | |
| block_size_descriptor* bsd | |
| ) { | |
| partition_info *par_tab2 = bsd->partitions; | |
| partition_info *par_tab3 = par_tab2 + PARTITION_COUNT; | |
| partition_info *par_tab4 = par_tab3 + PARTITION_COUNT; | |
| partition_info *par_tab1 = par_tab4 + PARTITION_COUNT; | |
| generate_one_partition_table(bsd, 1, 0, par_tab1); | |
| for (int i = 0; i < 1024; i++) | |
| { | |
| generate_one_partition_table(bsd, 2, i, par_tab2 + i); | |
| generate_one_partition_table(bsd, 3, i, par_tab3 + i); | |
| generate_one_partition_table(bsd, 4, i, par_tab4 + i); | |
| } | |
| partition_table_zap_equal_elements(bsd->texel_count, par_tab2); | |
| partition_table_zap_equal_elements(bsd->texel_count, par_tab3); | |
| partition_table_zap_equal_elements(bsd->texel_count, par_tab4); | |
| } |