1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright (C) 2014 Intel Corporation 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21bf215546Sopenharmony_ci * DEALINGS IN THE SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci/* 25bf215546Sopenharmony_ci * Included by texcompress_bptc and gallium to define BPTC decoding routines. 26bf215546Sopenharmony_ci */ 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci#ifndef TEXCOMPRESS_BPTC_TMP_H 29bf215546Sopenharmony_ci#define TEXCOMPRESS_BPTC_TMP_H 30bf215546Sopenharmony_ci 31bf215546Sopenharmony_ci#include "util/format_srgb.h" 32bf215546Sopenharmony_ci#include "util/half_float.h" 33bf215546Sopenharmony_ci#include "macros.h" 34bf215546Sopenharmony_ci 35bf215546Sopenharmony_ci#define BLOCK_SIZE 4 36bf215546Sopenharmony_ci#define N_PARTITIONS 64 37bf215546Sopenharmony_ci#define BLOCK_BYTES 16 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_cistruct bptc_unorm_mode { 40bf215546Sopenharmony_ci int n_subsets; 41bf215546Sopenharmony_ci int n_partition_bits; 42bf215546Sopenharmony_ci bool has_rotation_bits; 43bf215546Sopenharmony_ci bool has_index_selection_bit; 44bf215546Sopenharmony_ci int n_color_bits; 45bf215546Sopenharmony_ci int n_alpha_bits; 46bf215546Sopenharmony_ci bool has_endpoint_pbits; 47bf215546Sopenharmony_ci bool has_shared_pbits; 48bf215546Sopenharmony_ci int n_index_bits; 49bf215546Sopenharmony_ci int n_secondary_index_bits; 50bf215546Sopenharmony_ci}; 51bf215546Sopenharmony_ci 52bf215546Sopenharmony_cistruct bptc_float_bitfield { 53bf215546Sopenharmony_ci int8_t endpoint; 54bf215546Sopenharmony_ci uint8_t component; 55bf215546Sopenharmony_ci uint8_t offset; 56bf215546Sopenharmony_ci uint8_t n_bits; 57bf215546Sopenharmony_ci bool reverse; 58bf215546Sopenharmony_ci}; 59bf215546Sopenharmony_ci 60bf215546Sopenharmony_cistruct bptc_float_mode { 61bf215546Sopenharmony_ci bool reserved; 62bf215546Sopenharmony_ci bool transformed_endpoints; 63bf215546Sopenharmony_ci int n_partition_bits; 64bf215546Sopenharmony_ci int n_endpoint_bits; 65bf215546Sopenharmony_ci int n_index_bits; 66bf215546Sopenharmony_ci int n_delta_bits[3]; 67bf215546Sopenharmony_ci struct bptc_float_bitfield bitfields[24]; 68bf215546Sopenharmony_ci}; 69bf215546Sopenharmony_ci 70bf215546Sopenharmony_cistruct bit_writer { 71bf215546Sopenharmony_ci uint8_t buf; 72bf215546Sopenharmony_ci int pos; 73bf215546Sopenharmony_ci uint8_t *dst; 74bf215546Sopenharmony_ci}; 75bf215546Sopenharmony_ci 76bf215546Sopenharmony_cistatic const struct bptc_unorm_mode 77bf215546Sopenharmony_cibptc_unorm_modes[] = { 78bf215546Sopenharmony_ci /* 0 */ { 3, 4, false, false, 4, 0, true, false, 3, 0 }, 79bf215546Sopenharmony_ci /* 1 */ { 2, 6, false, false, 6, 0, false, true, 3, 0 }, 80bf215546Sopenharmony_ci /* 2 */ { 3, 6, false, false, 5, 0, false, false, 2, 0 }, 81bf215546Sopenharmony_ci /* 3 */ { 2, 6, false, false, 7, 0, true, false, 2, 0 }, 82bf215546Sopenharmony_ci /* 4 */ { 1, 0, true, true, 5, 6, false, false, 2, 3 }, 83bf215546Sopenharmony_ci /* 5 */ { 1, 0, true, false, 7, 8, false, false, 2, 2 }, 84bf215546Sopenharmony_ci /* 6 */ { 1, 0, false, false, 7, 7, true, false, 4, 0 }, 85bf215546Sopenharmony_ci /* 7 */ { 2, 6, false, false, 5, 5, true, false, 2, 0 } 86bf215546Sopenharmony_ci}; 87bf215546Sopenharmony_ci 88bf215546Sopenharmony_cistatic const struct bptc_float_mode 89bf215546Sopenharmony_cibptc_float_modes[] = { 90bf215546Sopenharmony_ci /* 00 */ 91bf215546Sopenharmony_ci { false, true, 5, 10, 3, { 5, 5, 5 }, 92bf215546Sopenharmony_ci { { 2, 1, 4, 1, false }, { 2, 2, 4, 1, false }, { 3, 2, 4, 1, false }, 93bf215546Sopenharmony_ci { 0, 0, 0, 10, false }, { 0, 1, 0, 10, false }, { 0, 2, 0, 10, false }, 94bf215546Sopenharmony_ci { 1, 0, 0, 5, false }, { 3, 1, 4, 1, false }, { 2, 1, 0, 4, false }, 95bf215546Sopenharmony_ci { 1, 1, 0, 5, false }, { 3, 2, 0, 1, false }, { 3, 1, 0, 4, false }, 96bf215546Sopenharmony_ci { 1, 2, 0, 5, false }, { 3, 2, 1, 1, false }, { 2, 2, 0, 4, false }, 97bf215546Sopenharmony_ci { 2, 0, 0, 5, false }, { 3, 2, 2, 1, false }, { 3, 0, 0, 5, false }, 98bf215546Sopenharmony_ci { 3, 2, 3, 1, false }, 99bf215546Sopenharmony_ci { -1 } } 100bf215546Sopenharmony_ci }, 101bf215546Sopenharmony_ci /* 01 */ 102bf215546Sopenharmony_ci { false, true, 5, 7, 3, { 6, 6, 6 }, 103bf215546Sopenharmony_ci { { 2, 1, 5, 1, false }, { 3, 1, 4, 1, false }, { 3, 1, 5, 1, false }, 104bf215546Sopenharmony_ci { 0, 0, 0, 7, false }, { 3, 2, 0, 1, false }, { 3, 2, 1, 1, false }, 105bf215546Sopenharmony_ci { 2, 2, 4, 1, false }, { 0, 1, 0, 7, false }, { 2, 2, 5, 1, false }, 106bf215546Sopenharmony_ci { 3, 2, 2, 1, false }, { 2, 1, 4, 1, false }, { 0, 2, 0, 7, false }, 107bf215546Sopenharmony_ci { 3, 2, 3, 1, false }, { 3, 2, 5, 1, false }, { 3, 2, 4, 1, false }, 108bf215546Sopenharmony_ci { 1, 0, 0, 6, false }, { 2, 1, 0, 4, false }, { 1, 1, 0, 6, false }, 109bf215546Sopenharmony_ci { 3, 1, 0, 4, false }, { 1, 2, 0, 6, false }, { 2, 2, 0, 4, false }, 110bf215546Sopenharmony_ci { 2, 0, 0, 6, false }, 111bf215546Sopenharmony_ci { 3, 0, 0, 6, false }, 112bf215546Sopenharmony_ci { -1 } } 113bf215546Sopenharmony_ci }, 114bf215546Sopenharmony_ci /* 00010 */ 115bf215546Sopenharmony_ci { false, true, 5, 11, 3, { 5, 4, 4 }, 116bf215546Sopenharmony_ci { { 0, 0, 0, 10, false }, { 0, 1, 0, 10, false }, { 0, 2, 0, 10, false }, 117bf215546Sopenharmony_ci { 1, 0, 0, 5, false }, { 0, 0, 10, 1, false }, { 2, 1, 0, 4, false }, 118bf215546Sopenharmony_ci { 1, 1, 0, 4, false }, { 0, 1, 10, 1, false }, { 3, 2, 0, 1, false }, 119bf215546Sopenharmony_ci { 3, 1, 0, 4, false }, { 1, 2, 0, 4, false }, { 0, 2, 10, 1, false }, 120bf215546Sopenharmony_ci { 3, 2, 1, 1, false }, { 2, 2, 0, 4, false }, { 2, 0, 0, 5, false }, 121bf215546Sopenharmony_ci { 3, 2, 2, 1, false }, { 3, 0, 0, 5, false }, { 3, 2, 3, 1, false }, 122bf215546Sopenharmony_ci { -1 } } 123bf215546Sopenharmony_ci }, 124bf215546Sopenharmony_ci /* 00011 */ 125bf215546Sopenharmony_ci { false, false, 0, 10, 4, { 10, 10, 10 }, 126bf215546Sopenharmony_ci { { 0, 0, 0, 10, false }, { 0, 1, 0, 10, false }, { 0, 2, 0, 10, false }, 127bf215546Sopenharmony_ci { 1, 0, 0, 10, false }, { 1, 1, 0, 10, false }, { 1, 2, 0, 10, false }, 128bf215546Sopenharmony_ci { -1 } } 129bf215546Sopenharmony_ci }, 130bf215546Sopenharmony_ci /* 00110 */ 131bf215546Sopenharmony_ci { false, true, 5, 11, 3, { 4, 5, 4 }, 132bf215546Sopenharmony_ci { { 0, 0, 0, 10, false }, { 0, 1, 0, 10, false }, { 0, 2, 0, 10, false }, 133bf215546Sopenharmony_ci { 1, 0, 0, 4, false }, { 0, 0, 10, 1, false }, { 3, 1, 4, 1, false }, 134bf215546Sopenharmony_ci { 2, 1, 0, 4, false }, { 1, 1, 0, 5, false }, { 0, 1, 10, 1, false }, 135bf215546Sopenharmony_ci { 3, 1, 0, 4, false }, { 1, 2, 0, 4, false }, { 0, 2, 10, 1, false }, 136bf215546Sopenharmony_ci { 3, 2, 1, 1, false }, { 2, 2, 0, 4, false }, { 2, 0, 0, 4, false }, 137bf215546Sopenharmony_ci { 3, 2, 0, 1, false }, { 3, 2, 2, 1, false }, { 3, 0, 0, 4, false }, 138bf215546Sopenharmony_ci { 2, 1, 4, 1, false }, { 3, 2, 3, 1, false }, 139bf215546Sopenharmony_ci { -1 } } 140bf215546Sopenharmony_ci }, 141bf215546Sopenharmony_ci /* 00111 */ 142bf215546Sopenharmony_ci { false, true, 0, 11, 4, { 9, 9, 9 }, 143bf215546Sopenharmony_ci { { 0, 0, 0, 10, false }, { 0, 1, 0, 10, false }, { 0, 2, 0, 10, false }, 144bf215546Sopenharmony_ci { 1, 0, 0, 9, false }, { 0, 0, 10, 1, false }, { 1, 1, 0, 9, false }, 145bf215546Sopenharmony_ci { 0, 1, 10, 1, false }, { 1, 2, 0, 9, false }, { 0, 2, 10, 1, false }, 146bf215546Sopenharmony_ci { -1 } } 147bf215546Sopenharmony_ci }, 148bf215546Sopenharmony_ci /* 01010 */ 149bf215546Sopenharmony_ci { false, true, 5, 11, 3, { 4, 4, 5 }, 150bf215546Sopenharmony_ci { { 0, 0, 0, 10, false }, { 0, 1, 0, 10, false }, { 0, 2, 0, 10, false }, 151bf215546Sopenharmony_ci { 1, 0, 0, 4, false }, { 0, 0, 10, 1, false }, { 2, 2, 4, 1, false }, 152bf215546Sopenharmony_ci { 2, 1, 0, 4, false }, { 1, 1, 0, 4, false }, { 0, 1, 10, 1, false }, 153bf215546Sopenharmony_ci { 3, 2, 0, 1, false }, { 3, 1, 0, 4, false }, { 1, 2, 0, 5, false }, 154bf215546Sopenharmony_ci { 0, 2, 10, 1, false }, { 2, 2, 0, 4, false }, { 2, 0, 0, 4, false }, 155bf215546Sopenharmony_ci { 3, 2, 1, 1, false }, { 3, 2, 2, 1, false }, { 3, 0, 0, 4, false }, 156bf215546Sopenharmony_ci { 3, 2, 4, 1, false }, { 3, 2, 3, 1, false }, 157bf215546Sopenharmony_ci { -1 } } 158bf215546Sopenharmony_ci }, 159bf215546Sopenharmony_ci /* 01011 */ 160bf215546Sopenharmony_ci { false, true, 0, 12, 4, { 8, 8, 8 }, 161bf215546Sopenharmony_ci { { 0, 0, 0, 10, false }, { 0, 1, 0, 10, false }, { 0, 2, 0, 10, false }, 162bf215546Sopenharmony_ci { 1, 0, 0, 8, false }, { 0, 0, 10, 2, true }, { 1, 1, 0, 8, false }, 163bf215546Sopenharmony_ci { 0, 1, 10, 2, true }, { 1, 2, 0, 8, false }, { 0, 2, 10, 2, true }, 164bf215546Sopenharmony_ci { -1 } } 165bf215546Sopenharmony_ci }, 166bf215546Sopenharmony_ci /* 01110 */ 167bf215546Sopenharmony_ci { false, true, 5, 9, 3, { 5, 5, 5 }, 168bf215546Sopenharmony_ci { { 0, 0, 0, 9, false }, { 2, 2, 4, 1, false }, { 0, 1, 0, 9, false }, 169bf215546Sopenharmony_ci { 2, 1, 4, 1, false }, { 0, 2, 0, 9, false }, { 3, 2, 4, 1, false }, 170bf215546Sopenharmony_ci { 1, 0, 0, 5, false }, { 3, 1, 4, 1, false }, { 2, 1, 0, 4, false }, 171bf215546Sopenharmony_ci { 1, 1, 0, 5, false }, { 3, 2, 0, 1, false }, { 3, 1, 0, 4, false }, 172bf215546Sopenharmony_ci { 1, 2, 0, 5, false }, { 3, 2, 1, 1, false }, { 2, 2, 0, 4, false }, 173bf215546Sopenharmony_ci { 2, 0, 0, 5, false }, { 3, 2, 2, 1, false }, { 3, 0, 0, 5, false }, 174bf215546Sopenharmony_ci { 3, 2, 3, 1, false }, 175bf215546Sopenharmony_ci { -1 } } 176bf215546Sopenharmony_ci }, 177bf215546Sopenharmony_ci /* 01111 */ 178bf215546Sopenharmony_ci { false, true, 0, 16, 4, { 4, 4, 4 }, 179bf215546Sopenharmony_ci { { 0, 0, 0, 10, false }, { 0, 1, 0, 10, false }, { 0, 2, 0, 10, false }, 180bf215546Sopenharmony_ci { 1, 0, 0, 4, false }, { 0, 0, 10, 6, true }, { 1, 1, 0, 4, false }, 181bf215546Sopenharmony_ci { 0, 1, 10, 6, true }, { 1, 2, 0, 4, false }, { 0, 2, 10, 6, true }, 182bf215546Sopenharmony_ci { -1 } } 183bf215546Sopenharmony_ci }, 184bf215546Sopenharmony_ci /* 10010 */ 185bf215546Sopenharmony_ci { false, true, 5, 8, 3, { 6, 5, 5 }, 186bf215546Sopenharmony_ci { { 0, 0, 0, 8, false }, { 3, 1, 4, 1, false }, { 2, 2, 4, 1, false }, 187bf215546Sopenharmony_ci { 0, 1, 0, 8, false }, { 3, 2, 2, 1, false }, { 2, 1, 4, 1, false }, 188bf215546Sopenharmony_ci { 0, 2, 0, 8, false }, { 3, 2, 3, 1, false }, { 3, 2, 4, 1, false }, 189bf215546Sopenharmony_ci { 1, 0, 0, 6, false }, { 2, 1, 0, 4, false }, { 1, 1, 0, 5, false }, 190bf215546Sopenharmony_ci { 3, 2, 0, 1, false }, { 3, 1, 0, 4, false }, { 1, 2, 0, 5, false }, 191bf215546Sopenharmony_ci { 3, 2, 1, 1, false }, { 2, 2, 0, 4, false }, { 2, 0, 0, 6, false }, 192bf215546Sopenharmony_ci { 3, 0, 0, 6, false }, 193bf215546Sopenharmony_ci { -1 } } 194bf215546Sopenharmony_ci }, 195bf215546Sopenharmony_ci /* 10011 */ 196bf215546Sopenharmony_ci { true /* reserved */ }, 197bf215546Sopenharmony_ci /* 10110 */ 198bf215546Sopenharmony_ci { false, true, 5, 8, 3, { 5, 6, 5 }, 199bf215546Sopenharmony_ci { { 0, 0, 0, 8, false }, { 3, 2, 0, 1, false }, { 2, 2, 4, 1, false }, 200bf215546Sopenharmony_ci { 0, 1, 0, 8, false }, { 2, 1, 5, 1, false }, { 2, 1, 4, 1, false }, 201bf215546Sopenharmony_ci { 0, 2, 0, 8, false }, { 3, 1, 5, 1, false }, { 3, 2, 4, 1, false }, 202bf215546Sopenharmony_ci { 1, 0, 0, 5, false }, { 3, 1, 4, 1, false }, { 2, 1, 0, 4, false }, 203bf215546Sopenharmony_ci { 1, 1, 0, 6, false }, { 3, 1, 0, 4, false }, { 1, 2, 0, 5, false }, 204bf215546Sopenharmony_ci { 3, 2, 1, 1, false }, { 2, 2, 0, 4, false }, { 2, 0, 0, 5, false }, 205bf215546Sopenharmony_ci { 3, 2, 2, 1, false }, { 3, 0, 0, 5, false }, { 3, 2, 3, 1, false }, 206bf215546Sopenharmony_ci { -1 } } 207bf215546Sopenharmony_ci }, 208bf215546Sopenharmony_ci /* 10111 */ 209bf215546Sopenharmony_ci { true /* reserved */ }, 210bf215546Sopenharmony_ci /* 11010 */ 211bf215546Sopenharmony_ci { false, true, 5, 8, 3, { 5, 5, 6 }, 212bf215546Sopenharmony_ci { { 0, 0, 0, 8, false }, { 3, 2, 1, 1, false }, { 2, 2, 4, 1, false }, 213bf215546Sopenharmony_ci { 0, 1, 0, 8, false }, { 2, 2, 5, 1, false }, { 2, 1, 4, 1, false }, 214bf215546Sopenharmony_ci { 0, 2, 0, 8, false }, { 3, 2, 5, 1, false }, { 3, 2, 4, 1, false }, 215bf215546Sopenharmony_ci { 1, 0, 0, 5, false }, { 3, 1, 4, 1, false }, { 2, 1, 0, 4, false }, 216bf215546Sopenharmony_ci { 1, 1, 0, 5, false }, { 3, 2, 0, 1, false }, { 3, 1, 0, 4, false }, 217bf215546Sopenharmony_ci { 1, 2, 0, 6, false }, { 2, 2, 0, 4, false }, { 2, 0, 0, 5, false }, 218bf215546Sopenharmony_ci { 3, 2, 2, 1, false }, { 3, 0, 0, 5, false }, { 3, 2, 3, 1, false }, 219bf215546Sopenharmony_ci { -1 } } 220bf215546Sopenharmony_ci }, 221bf215546Sopenharmony_ci /* 11011 */ 222bf215546Sopenharmony_ci { true /* reserved */ }, 223bf215546Sopenharmony_ci /* 11110 */ 224bf215546Sopenharmony_ci { false, false, 5, 6, 3, { 6, 6, 6 }, 225bf215546Sopenharmony_ci { { 0, 0, 0, 6, false }, { 3, 1, 4, 1, false }, { 3, 2, 0, 1, false }, 226bf215546Sopenharmony_ci { 3, 2, 1, 1, false }, { 2, 2, 4, 1, false }, { 0, 1, 0, 6, false }, 227bf215546Sopenharmony_ci { 2, 1, 5, 1, false }, { 2, 2, 5, 1, false }, { 3, 2, 2, 1, false }, 228bf215546Sopenharmony_ci { 2, 1, 4, 1, false }, { 0, 2, 0, 6, false }, { 3, 1, 5, 1, false }, 229bf215546Sopenharmony_ci { 3, 2, 3, 1, false }, { 3, 2, 5, 1, false }, { 3, 2, 4, 1, false }, 230bf215546Sopenharmony_ci { 1, 0, 0, 6, false }, { 2, 1, 0, 4, false }, { 1, 1, 0, 6, false }, 231bf215546Sopenharmony_ci { 3, 1, 0, 4, false }, { 1, 2, 0, 6, false }, { 2, 2, 0, 4, false }, 232bf215546Sopenharmony_ci { 2, 0, 0, 6, false }, { 3, 0, 0, 6, false }, 233bf215546Sopenharmony_ci { -1 } } 234bf215546Sopenharmony_ci }, 235bf215546Sopenharmony_ci /* 11111 */ 236bf215546Sopenharmony_ci { true /* reserved */ }, 237bf215546Sopenharmony_ci}; 238bf215546Sopenharmony_ci 239bf215546Sopenharmony_ci/* This partition table is used when the mode has two subsets. Each 240bf215546Sopenharmony_ci * partition is represented by a 32-bit value which gives 2 bits per texel 241bf215546Sopenharmony_ci * within the block. The value of the two bits represents which subset to use 242bf215546Sopenharmony_ci * (0 or 1). 243bf215546Sopenharmony_ci */ 244bf215546Sopenharmony_cistatic const uint32_t 245bf215546Sopenharmony_cipartition_table1[N_PARTITIONS] = { 246bf215546Sopenharmony_ci 0x50505050U, 0x40404040U, 0x54545454U, 0x54505040U, 247bf215546Sopenharmony_ci 0x50404000U, 0x55545450U, 0x55545040U, 0x54504000U, 248bf215546Sopenharmony_ci 0x50400000U, 0x55555450U, 0x55544000U, 0x54400000U, 249bf215546Sopenharmony_ci 0x55555440U, 0x55550000U, 0x55555500U, 0x55000000U, 250bf215546Sopenharmony_ci 0x55150100U, 0x00004054U, 0x15010000U, 0x00405054U, 251bf215546Sopenharmony_ci 0x00004050U, 0x15050100U, 0x05010000U, 0x40505054U, 252bf215546Sopenharmony_ci 0x00404050U, 0x05010100U, 0x14141414U, 0x05141450U, 253bf215546Sopenharmony_ci 0x01155440U, 0x00555500U, 0x15014054U, 0x05414150U, 254bf215546Sopenharmony_ci 0x44444444U, 0x55005500U, 0x11441144U, 0x05055050U, 255bf215546Sopenharmony_ci 0x05500550U, 0x11114444U, 0x41144114U, 0x44111144U, 256bf215546Sopenharmony_ci 0x15055054U, 0x01055040U, 0x05041050U, 0x05455150U, 257bf215546Sopenharmony_ci 0x14414114U, 0x50050550U, 0x41411414U, 0x00141400U, 258bf215546Sopenharmony_ci 0x00041504U, 0x00105410U, 0x10541000U, 0x04150400U, 259bf215546Sopenharmony_ci 0x50410514U, 0x41051450U, 0x05415014U, 0x14054150U, 260bf215546Sopenharmony_ci 0x41050514U, 0x41505014U, 0x40011554U, 0x54150140U, 261bf215546Sopenharmony_ci 0x50505500U, 0x00555050U, 0x15151010U, 0x54540404U, 262bf215546Sopenharmony_ci}; 263bf215546Sopenharmony_ci 264bf215546Sopenharmony_ci/* This partition table is used when the mode has three subsets. In this case 265bf215546Sopenharmony_ci * the values can be 0, 1 or 2. 266bf215546Sopenharmony_ci */ 267bf215546Sopenharmony_cistatic const uint32_t 268bf215546Sopenharmony_cipartition_table2[N_PARTITIONS] = { 269bf215546Sopenharmony_ci 0xaa685050U, 0x6a5a5040U, 0x5a5a4200U, 0x5450a0a8U, 270bf215546Sopenharmony_ci 0xa5a50000U, 0xa0a05050U, 0x5555a0a0U, 0x5a5a5050U, 271bf215546Sopenharmony_ci 0xaa550000U, 0xaa555500U, 0xaaaa5500U, 0x90909090U, 272bf215546Sopenharmony_ci 0x94949494U, 0xa4a4a4a4U, 0xa9a59450U, 0x2a0a4250U, 273bf215546Sopenharmony_ci 0xa5945040U, 0x0a425054U, 0xa5a5a500U, 0x55a0a0a0U, 274bf215546Sopenharmony_ci 0xa8a85454U, 0x6a6a4040U, 0xa4a45000U, 0x1a1a0500U, 275bf215546Sopenharmony_ci 0x0050a4a4U, 0xaaa59090U, 0x14696914U, 0x69691400U, 276bf215546Sopenharmony_ci 0xa08585a0U, 0xaa821414U, 0x50a4a450U, 0x6a5a0200U, 277bf215546Sopenharmony_ci 0xa9a58000U, 0x5090a0a8U, 0xa8a09050U, 0x24242424U, 278bf215546Sopenharmony_ci 0x00aa5500U, 0x24924924U, 0x24499224U, 0x50a50a50U, 279bf215546Sopenharmony_ci 0x500aa550U, 0xaaaa4444U, 0x66660000U, 0xa5a0a5a0U, 280bf215546Sopenharmony_ci 0x50a050a0U, 0x69286928U, 0x44aaaa44U, 0x66666600U, 281bf215546Sopenharmony_ci 0xaa444444U, 0x54a854a8U, 0x95809580U, 0x96969600U, 282bf215546Sopenharmony_ci 0xa85454a8U, 0x80959580U, 0xaa141414U, 0x96960000U, 283bf215546Sopenharmony_ci 0xaaaa1414U, 0xa05050a0U, 0xa0a5a5a0U, 0x96000000U, 284bf215546Sopenharmony_ci 0x40804080U, 0xa9a8a9a8U, 0xaaaaaa44U, 0x2a4a5254U 285bf215546Sopenharmony_ci}; 286bf215546Sopenharmony_ci 287bf215546Sopenharmony_cistatic const uint8_t 288bf215546Sopenharmony_cianchor_indices[][N_PARTITIONS] = { 289bf215546Sopenharmony_ci /* Anchor index values for the second subset of two-subset partitioning */ 290bf215546Sopenharmony_ci { 291bf215546Sopenharmony_ci 0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf, 292bf215546Sopenharmony_ci 0xf,0x2,0x8,0x2,0x2,0x8,0x8,0xf,0x2,0x8,0x2,0x2,0x8,0x8,0x2,0x2, 293bf215546Sopenharmony_ci 0xf,0xf,0x6,0x8,0x2,0x8,0xf,0xf,0x2,0x8,0x2,0x2,0x2,0xf,0xf,0x6, 294bf215546Sopenharmony_ci 0x6,0x2,0x6,0x8,0xf,0xf,0x2,0x2,0xf,0xf,0xf,0xf,0xf,0x2,0x2,0xf 295bf215546Sopenharmony_ci }, 296bf215546Sopenharmony_ci 297bf215546Sopenharmony_ci /* Anchor index values for the second subset of three-subset partitioning */ 298bf215546Sopenharmony_ci { 299bf215546Sopenharmony_ci 0x3,0x3,0xf,0xf,0x8,0x3,0xf,0xf,0x8,0x8,0x6,0x6,0x6,0x5,0x3,0x3, 300bf215546Sopenharmony_ci 0x3,0x3,0x8,0xf,0x3,0x3,0x6,0xa,0x5,0x8,0x8,0x6,0x8,0x5,0xf,0xf, 301bf215546Sopenharmony_ci 0x8,0xf,0x3,0x5,0x6,0xa,0x8,0xf,0xf,0x3,0xf,0x5,0xf,0xf,0xf,0xf, 302bf215546Sopenharmony_ci 0x3,0xf,0x5,0x5,0x5,0x8,0x5,0xa,0x5,0xa,0x8,0xd,0xf,0xc,0x3,0x3 303bf215546Sopenharmony_ci }, 304bf215546Sopenharmony_ci 305bf215546Sopenharmony_ci /* Anchor index values for the third subset of three-subset 306bf215546Sopenharmony_ci * partitioning 307bf215546Sopenharmony_ci */ 308bf215546Sopenharmony_ci { 309bf215546Sopenharmony_ci 0xf,0x8,0x8,0x3,0xf,0xf,0x3,0x8,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0x8, 310bf215546Sopenharmony_ci 0xf,0x8,0xf,0x3,0xf,0x8,0xf,0x8,0x3,0xf,0x6,0xa,0xf,0xf,0xa,0x8, 311bf215546Sopenharmony_ci 0xf,0x3,0xf,0xa,0xa,0x8,0x9,0xa,0x6,0xf,0x8,0xf,0x3,0x6,0x6,0x8, 312bf215546Sopenharmony_ci 0xf,0x3,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0x3,0xf,0xf,0x8 313bf215546Sopenharmony_ci } 314bf215546Sopenharmony_ci}; 315bf215546Sopenharmony_ci 316bf215546Sopenharmony_cistatic int 317bf215546Sopenharmony_ciextract_bits(const uint8_t *block, 318bf215546Sopenharmony_ci int offset, 319bf215546Sopenharmony_ci int n_bits) 320bf215546Sopenharmony_ci{ 321bf215546Sopenharmony_ci int byte_index = offset / 8; 322bf215546Sopenharmony_ci int bit_index = offset % 8; 323bf215546Sopenharmony_ci int n_bits_in_byte = MIN2(n_bits, 8 - bit_index); 324bf215546Sopenharmony_ci int result = 0; 325bf215546Sopenharmony_ci int bit = 0; 326bf215546Sopenharmony_ci 327bf215546Sopenharmony_ci while (true) { 328bf215546Sopenharmony_ci result |= ((block[byte_index] >> bit_index) & 329bf215546Sopenharmony_ci ((1 << n_bits_in_byte) - 1)) << bit; 330bf215546Sopenharmony_ci 331bf215546Sopenharmony_ci n_bits -= n_bits_in_byte; 332bf215546Sopenharmony_ci 333bf215546Sopenharmony_ci if (n_bits <= 0) 334bf215546Sopenharmony_ci return result; 335bf215546Sopenharmony_ci 336bf215546Sopenharmony_ci bit += n_bits_in_byte; 337bf215546Sopenharmony_ci byte_index++; 338bf215546Sopenharmony_ci bit_index = 0; 339bf215546Sopenharmony_ci n_bits_in_byte = MIN2(n_bits, 8); 340bf215546Sopenharmony_ci } 341bf215546Sopenharmony_ci} 342bf215546Sopenharmony_ci 343bf215546Sopenharmony_cistatic uint8_t 344bf215546Sopenharmony_ciexpand_component(uint8_t byte, 345bf215546Sopenharmony_ci int n_bits) 346bf215546Sopenharmony_ci{ 347bf215546Sopenharmony_ci /* Expands a n-bit quantity into a byte by copying the most-significant 348bf215546Sopenharmony_ci * bits into the unused least-significant bits. 349bf215546Sopenharmony_ci */ 350bf215546Sopenharmony_ci return byte << (8 - n_bits) | (byte >> (2 * n_bits - 8)); 351bf215546Sopenharmony_ci} 352bf215546Sopenharmony_ci 353bf215546Sopenharmony_cistatic int 354bf215546Sopenharmony_ciextract_unorm_endpoints(const struct bptc_unorm_mode *mode, 355bf215546Sopenharmony_ci const uint8_t *block, 356bf215546Sopenharmony_ci int bit_offset, 357bf215546Sopenharmony_ci uint8_t endpoints[][4]) 358bf215546Sopenharmony_ci{ 359bf215546Sopenharmony_ci int component; 360bf215546Sopenharmony_ci int subset; 361bf215546Sopenharmony_ci int endpoint; 362bf215546Sopenharmony_ci int pbit; 363bf215546Sopenharmony_ci int n_components; 364bf215546Sopenharmony_ci 365bf215546Sopenharmony_ci /* Extract each color component */ 366bf215546Sopenharmony_ci for (component = 0; component < 3; component++) { 367bf215546Sopenharmony_ci for (subset = 0; subset < mode->n_subsets; subset++) { 368bf215546Sopenharmony_ci for (endpoint = 0; endpoint < 2; endpoint++) { 369bf215546Sopenharmony_ci endpoints[subset * 2 + endpoint][component] = 370bf215546Sopenharmony_ci extract_bits(block, bit_offset, mode->n_color_bits); 371bf215546Sopenharmony_ci bit_offset += mode->n_color_bits; 372bf215546Sopenharmony_ci } 373bf215546Sopenharmony_ci } 374bf215546Sopenharmony_ci } 375bf215546Sopenharmony_ci 376bf215546Sopenharmony_ci /* Extract the alpha values */ 377bf215546Sopenharmony_ci if (mode->n_alpha_bits > 0) { 378bf215546Sopenharmony_ci for (subset = 0; subset < mode->n_subsets; subset++) { 379bf215546Sopenharmony_ci for (endpoint = 0; endpoint < 2; endpoint++) { 380bf215546Sopenharmony_ci endpoints[subset * 2 + endpoint][3] = 381bf215546Sopenharmony_ci extract_bits(block, bit_offset, mode->n_alpha_bits); 382bf215546Sopenharmony_ci bit_offset += mode->n_alpha_bits; 383bf215546Sopenharmony_ci } 384bf215546Sopenharmony_ci } 385bf215546Sopenharmony_ci 386bf215546Sopenharmony_ci n_components = 4; 387bf215546Sopenharmony_ci } else { 388bf215546Sopenharmony_ci for (subset = 0; subset < mode->n_subsets; subset++) 389bf215546Sopenharmony_ci for (endpoint = 0; endpoint < 2; endpoint++) 390bf215546Sopenharmony_ci endpoints[subset * 2 + endpoint][3] = 255; 391bf215546Sopenharmony_ci 392bf215546Sopenharmony_ci n_components = 3; 393bf215546Sopenharmony_ci } 394bf215546Sopenharmony_ci 395bf215546Sopenharmony_ci /* Add in the p-bits */ 396bf215546Sopenharmony_ci if (mode->has_endpoint_pbits) { 397bf215546Sopenharmony_ci for (subset = 0; subset < mode->n_subsets; subset++) { 398bf215546Sopenharmony_ci for (endpoint = 0; endpoint < 2; endpoint++) { 399bf215546Sopenharmony_ci pbit = extract_bits(block, bit_offset, 1); 400bf215546Sopenharmony_ci bit_offset += 1; 401bf215546Sopenharmony_ci 402bf215546Sopenharmony_ci for (component = 0; component < n_components; component++) { 403bf215546Sopenharmony_ci endpoints[subset * 2 + endpoint][component] <<= 1; 404bf215546Sopenharmony_ci endpoints[subset * 2 + endpoint][component] |= pbit; 405bf215546Sopenharmony_ci } 406bf215546Sopenharmony_ci } 407bf215546Sopenharmony_ci } 408bf215546Sopenharmony_ci } else if (mode->has_shared_pbits) { 409bf215546Sopenharmony_ci for (subset = 0; subset < mode->n_subsets; subset++) { 410bf215546Sopenharmony_ci pbit = extract_bits(block, bit_offset, 1); 411bf215546Sopenharmony_ci bit_offset += 1; 412bf215546Sopenharmony_ci 413bf215546Sopenharmony_ci for (endpoint = 0; endpoint < 2; endpoint++) { 414bf215546Sopenharmony_ci for (component = 0; component < n_components; component++) { 415bf215546Sopenharmony_ci endpoints[subset * 2 + endpoint][component] <<= 1; 416bf215546Sopenharmony_ci endpoints[subset * 2 + endpoint][component] |= pbit; 417bf215546Sopenharmony_ci } 418bf215546Sopenharmony_ci } 419bf215546Sopenharmony_ci } 420bf215546Sopenharmony_ci } 421bf215546Sopenharmony_ci 422bf215546Sopenharmony_ci /* Expand the n-bit values to a byte */ 423bf215546Sopenharmony_ci for (subset = 0; subset < mode->n_subsets; subset++) { 424bf215546Sopenharmony_ci for (endpoint = 0; endpoint < 2; endpoint++) { 425bf215546Sopenharmony_ci for (component = 0; component < 3; component++) { 426bf215546Sopenharmony_ci endpoints[subset * 2 + endpoint][component] = 427bf215546Sopenharmony_ci expand_component(endpoints[subset * 2 + endpoint][component], 428bf215546Sopenharmony_ci mode->n_color_bits + 429bf215546Sopenharmony_ci mode->has_endpoint_pbits + 430bf215546Sopenharmony_ci mode->has_shared_pbits); 431bf215546Sopenharmony_ci } 432bf215546Sopenharmony_ci 433bf215546Sopenharmony_ci if (mode->n_alpha_bits > 0) { 434bf215546Sopenharmony_ci endpoints[subset * 2 + endpoint][3] = 435bf215546Sopenharmony_ci expand_component(endpoints[subset * 2 + endpoint][3], 436bf215546Sopenharmony_ci mode->n_alpha_bits + 437bf215546Sopenharmony_ci mode->has_endpoint_pbits + 438bf215546Sopenharmony_ci mode->has_shared_pbits); 439bf215546Sopenharmony_ci } 440bf215546Sopenharmony_ci } 441bf215546Sopenharmony_ci } 442bf215546Sopenharmony_ci 443bf215546Sopenharmony_ci return bit_offset; 444bf215546Sopenharmony_ci} 445bf215546Sopenharmony_ci 446bf215546Sopenharmony_cistatic bool 447bf215546Sopenharmony_ciis_anchor(int n_subsets, 448bf215546Sopenharmony_ci int partition_num, 449bf215546Sopenharmony_ci int texel) 450bf215546Sopenharmony_ci{ 451bf215546Sopenharmony_ci if (texel == 0) 452bf215546Sopenharmony_ci return true; 453bf215546Sopenharmony_ci 454bf215546Sopenharmony_ci switch (n_subsets) { 455bf215546Sopenharmony_ci case 1: 456bf215546Sopenharmony_ci return false; 457bf215546Sopenharmony_ci case 2: 458bf215546Sopenharmony_ci return anchor_indices[0][partition_num] == texel; 459bf215546Sopenharmony_ci case 3: 460bf215546Sopenharmony_ci return (anchor_indices[1][partition_num] == texel || 461bf215546Sopenharmony_ci anchor_indices[2][partition_num] == texel); 462bf215546Sopenharmony_ci default: 463bf215546Sopenharmony_ci assert(false); 464bf215546Sopenharmony_ci return false; 465bf215546Sopenharmony_ci } 466bf215546Sopenharmony_ci} 467bf215546Sopenharmony_ci 468bf215546Sopenharmony_cistatic int 469bf215546Sopenharmony_cicount_anchors_before_texel(int n_subsets, 470bf215546Sopenharmony_ci int partition_num, 471bf215546Sopenharmony_ci int texel) 472bf215546Sopenharmony_ci{ 473bf215546Sopenharmony_ci int count = 1; 474bf215546Sopenharmony_ci 475bf215546Sopenharmony_ci if (texel == 0) 476bf215546Sopenharmony_ci return 0; 477bf215546Sopenharmony_ci 478bf215546Sopenharmony_ci switch (n_subsets) { 479bf215546Sopenharmony_ci case 1: 480bf215546Sopenharmony_ci break; 481bf215546Sopenharmony_ci case 2: 482bf215546Sopenharmony_ci if (texel > anchor_indices[0][partition_num]) 483bf215546Sopenharmony_ci count++; 484bf215546Sopenharmony_ci break; 485bf215546Sopenharmony_ci case 3: 486bf215546Sopenharmony_ci if (texel > anchor_indices[1][partition_num]) 487bf215546Sopenharmony_ci count++; 488bf215546Sopenharmony_ci if (texel > anchor_indices[2][partition_num]) 489bf215546Sopenharmony_ci count++; 490bf215546Sopenharmony_ci break; 491bf215546Sopenharmony_ci default: 492bf215546Sopenharmony_ci assert(false); 493bf215546Sopenharmony_ci return 0; 494bf215546Sopenharmony_ci } 495bf215546Sopenharmony_ci 496bf215546Sopenharmony_ci return count; 497bf215546Sopenharmony_ci} 498bf215546Sopenharmony_ci 499bf215546Sopenharmony_cistatic int32_t 500bf215546Sopenharmony_ciinterpolate(int32_t a, int32_t b, 501bf215546Sopenharmony_ci int index, 502bf215546Sopenharmony_ci int index_bits) 503bf215546Sopenharmony_ci{ 504bf215546Sopenharmony_ci static const uint8_t weights2[] = { 0, 21, 43, 64 }; 505bf215546Sopenharmony_ci static const uint8_t weights3[] = { 0, 9, 18, 27, 37, 46, 55, 64 }; 506bf215546Sopenharmony_ci static const uint8_t weights4[] = 507bf215546Sopenharmony_ci { 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64 }; 508bf215546Sopenharmony_ci static const uint8_t *weights[] = { 509bf215546Sopenharmony_ci NULL, NULL, weights2, weights3, weights4 510bf215546Sopenharmony_ci }; 511bf215546Sopenharmony_ci int weight; 512bf215546Sopenharmony_ci 513bf215546Sopenharmony_ci weight = weights[index_bits][index]; 514bf215546Sopenharmony_ci 515bf215546Sopenharmony_ci return ((64 - weight) * a + weight * b + 32) >> 6; 516bf215546Sopenharmony_ci} 517bf215546Sopenharmony_ci 518bf215546Sopenharmony_cistatic void 519bf215546Sopenharmony_ciapply_rotation(int rotation, 520bf215546Sopenharmony_ci uint8_t *result) 521bf215546Sopenharmony_ci{ 522bf215546Sopenharmony_ci uint8_t t; 523bf215546Sopenharmony_ci 524bf215546Sopenharmony_ci if (rotation == 0) 525bf215546Sopenharmony_ci return; 526bf215546Sopenharmony_ci 527bf215546Sopenharmony_ci rotation--; 528bf215546Sopenharmony_ci 529bf215546Sopenharmony_ci t = result[rotation]; 530bf215546Sopenharmony_ci result[rotation] = result[3]; 531bf215546Sopenharmony_ci result[3] = t; 532bf215546Sopenharmony_ci} 533bf215546Sopenharmony_ci 534bf215546Sopenharmony_cistatic void 535bf215546Sopenharmony_cifetch_rgba_unorm_from_block(const uint8_t *block, 536bf215546Sopenharmony_ci uint8_t *result, 537bf215546Sopenharmony_ci int texel) 538bf215546Sopenharmony_ci{ 539bf215546Sopenharmony_ci int mode_num = ffs(block[0]); 540bf215546Sopenharmony_ci const struct bptc_unorm_mode *mode; 541bf215546Sopenharmony_ci int bit_offset, secondary_bit_offset; 542bf215546Sopenharmony_ci int partition_num; 543bf215546Sopenharmony_ci int subset_num; 544bf215546Sopenharmony_ci int rotation; 545bf215546Sopenharmony_ci int index_selection; 546bf215546Sopenharmony_ci int index_bits; 547bf215546Sopenharmony_ci int indices[2]; 548bf215546Sopenharmony_ci int index; 549bf215546Sopenharmony_ci int anchors_before_texel; 550bf215546Sopenharmony_ci bool anchor; 551bf215546Sopenharmony_ci uint8_t endpoints[3 * 2][4]; 552bf215546Sopenharmony_ci uint32_t subsets; 553bf215546Sopenharmony_ci int component; 554bf215546Sopenharmony_ci 555bf215546Sopenharmony_ci if (mode_num == 0) { 556bf215546Sopenharmony_ci /* According to the spec this mode is reserved and shouldn't be used. */ 557bf215546Sopenharmony_ci memset(result, 0, 4); 558bf215546Sopenharmony_ci return; 559bf215546Sopenharmony_ci } 560bf215546Sopenharmony_ci 561bf215546Sopenharmony_ci mode = bptc_unorm_modes + mode_num - 1; 562bf215546Sopenharmony_ci bit_offset = mode_num; 563bf215546Sopenharmony_ci 564bf215546Sopenharmony_ci partition_num = extract_bits(block, bit_offset, mode->n_partition_bits); 565bf215546Sopenharmony_ci bit_offset += mode->n_partition_bits; 566bf215546Sopenharmony_ci 567bf215546Sopenharmony_ci switch (mode->n_subsets) { 568bf215546Sopenharmony_ci case 1: 569bf215546Sopenharmony_ci subsets = 0; 570bf215546Sopenharmony_ci break; 571bf215546Sopenharmony_ci case 2: 572bf215546Sopenharmony_ci subsets = partition_table1[partition_num]; 573bf215546Sopenharmony_ci break; 574bf215546Sopenharmony_ci case 3: 575bf215546Sopenharmony_ci subsets = partition_table2[partition_num]; 576bf215546Sopenharmony_ci break; 577bf215546Sopenharmony_ci default: 578bf215546Sopenharmony_ci assert(false); 579bf215546Sopenharmony_ci return; 580bf215546Sopenharmony_ci } 581bf215546Sopenharmony_ci 582bf215546Sopenharmony_ci if (mode->has_rotation_bits) { 583bf215546Sopenharmony_ci rotation = extract_bits(block, bit_offset, 2); 584bf215546Sopenharmony_ci bit_offset += 2; 585bf215546Sopenharmony_ci } else { 586bf215546Sopenharmony_ci rotation = 0; 587bf215546Sopenharmony_ci } 588bf215546Sopenharmony_ci 589bf215546Sopenharmony_ci if (mode->has_index_selection_bit) { 590bf215546Sopenharmony_ci index_selection = extract_bits(block, bit_offset, 1); 591bf215546Sopenharmony_ci bit_offset++; 592bf215546Sopenharmony_ci } else { 593bf215546Sopenharmony_ci index_selection = 0; 594bf215546Sopenharmony_ci } 595bf215546Sopenharmony_ci 596bf215546Sopenharmony_ci bit_offset = extract_unorm_endpoints(mode, block, bit_offset, endpoints); 597bf215546Sopenharmony_ci 598bf215546Sopenharmony_ci anchors_before_texel = count_anchors_before_texel(mode->n_subsets, 599bf215546Sopenharmony_ci partition_num, texel); 600bf215546Sopenharmony_ci 601bf215546Sopenharmony_ci /* Calculate the offset to the secondary index */ 602bf215546Sopenharmony_ci secondary_bit_offset = (bit_offset + 603bf215546Sopenharmony_ci BLOCK_SIZE * BLOCK_SIZE * mode->n_index_bits - 604bf215546Sopenharmony_ci mode->n_subsets + 605bf215546Sopenharmony_ci mode->n_secondary_index_bits * texel - 606bf215546Sopenharmony_ci anchors_before_texel); 607bf215546Sopenharmony_ci 608bf215546Sopenharmony_ci /* Calculate the offset to the primary index for this texel */ 609bf215546Sopenharmony_ci bit_offset += mode->n_index_bits * texel - anchors_before_texel; 610bf215546Sopenharmony_ci 611bf215546Sopenharmony_ci subset_num = (subsets >> (texel * 2)) & 3; 612bf215546Sopenharmony_ci 613bf215546Sopenharmony_ci anchor = is_anchor(mode->n_subsets, partition_num, texel); 614bf215546Sopenharmony_ci 615bf215546Sopenharmony_ci index_bits = mode->n_index_bits; 616bf215546Sopenharmony_ci if (anchor) 617bf215546Sopenharmony_ci index_bits--; 618bf215546Sopenharmony_ci indices[0] = extract_bits(block, bit_offset, index_bits); 619bf215546Sopenharmony_ci 620bf215546Sopenharmony_ci if (mode->n_secondary_index_bits) { 621bf215546Sopenharmony_ci index_bits = mode->n_secondary_index_bits; 622bf215546Sopenharmony_ci if (anchor) 623bf215546Sopenharmony_ci index_bits--; 624bf215546Sopenharmony_ci indices[1] = extract_bits(block, secondary_bit_offset, index_bits); 625bf215546Sopenharmony_ci } 626bf215546Sopenharmony_ci 627bf215546Sopenharmony_ci index = indices[index_selection]; 628bf215546Sopenharmony_ci index_bits = (index_selection ? 629bf215546Sopenharmony_ci mode->n_secondary_index_bits : 630bf215546Sopenharmony_ci mode->n_index_bits); 631bf215546Sopenharmony_ci 632bf215546Sopenharmony_ci for (component = 0; component < 3; component++) 633bf215546Sopenharmony_ci result[component] = interpolate(endpoints[subset_num * 2][component], 634bf215546Sopenharmony_ci endpoints[subset_num * 2 + 1][component], 635bf215546Sopenharmony_ci index, 636bf215546Sopenharmony_ci index_bits); 637bf215546Sopenharmony_ci 638bf215546Sopenharmony_ci /* Alpha uses the opposite index from the color components */ 639bf215546Sopenharmony_ci if (mode->n_secondary_index_bits && !index_selection) { 640bf215546Sopenharmony_ci index = indices[1]; 641bf215546Sopenharmony_ci index_bits = mode->n_secondary_index_bits; 642bf215546Sopenharmony_ci } else { 643bf215546Sopenharmony_ci index = indices[0]; 644bf215546Sopenharmony_ci index_bits = mode->n_index_bits; 645bf215546Sopenharmony_ci } 646bf215546Sopenharmony_ci 647bf215546Sopenharmony_ci result[3] = interpolate(endpoints[subset_num * 2][3], 648bf215546Sopenharmony_ci endpoints[subset_num * 2 + 1][3], 649bf215546Sopenharmony_ci index, 650bf215546Sopenharmony_ci index_bits); 651bf215546Sopenharmony_ci 652bf215546Sopenharmony_ci apply_rotation(rotation, result); 653bf215546Sopenharmony_ci} 654bf215546Sopenharmony_ci 655bf215546Sopenharmony_ci#ifdef BPTC_BLOCK_DECODE 656bf215546Sopenharmony_cistatic void 657bf215546Sopenharmony_cidecompress_rgba_unorm_block(int src_width, int src_height, 658bf215546Sopenharmony_ci const uint8_t *block, 659bf215546Sopenharmony_ci uint8_t *dst_row, int dst_rowstride) 660bf215546Sopenharmony_ci{ 661bf215546Sopenharmony_ci int mode_num = ffs(block[0]); 662bf215546Sopenharmony_ci const struct bptc_unorm_mode *mode; 663bf215546Sopenharmony_ci int bit_offset_head, bit_offset, secondary_bit_offset; 664bf215546Sopenharmony_ci int partition_num; 665bf215546Sopenharmony_ci int subset_num; 666bf215546Sopenharmony_ci int rotation; 667bf215546Sopenharmony_ci int index_selection; 668bf215546Sopenharmony_ci int index_bits; 669bf215546Sopenharmony_ci int indices[2]; 670bf215546Sopenharmony_ci int index; 671bf215546Sopenharmony_ci int anchors_before_texel; 672bf215546Sopenharmony_ci bool anchor; 673bf215546Sopenharmony_ci uint8_t endpoints[3 * 2][4]; 674bf215546Sopenharmony_ci uint32_t subsets; 675bf215546Sopenharmony_ci int component; 676bf215546Sopenharmony_ci unsigned x, y; 677bf215546Sopenharmony_ci 678bf215546Sopenharmony_ci if (mode_num == 0) { 679bf215546Sopenharmony_ci /* According to the spec this mode is reserved and shouldn't be used. */ 680bf215546Sopenharmony_ci for(y = 0; y < src_height; y += 1) { 681bf215546Sopenharmony_ci uint8_t *result = dst_row; 682bf215546Sopenharmony_ci memset(result, 0, 4 * src_width); 683bf215546Sopenharmony_ci dst_row += dst_rowstride; 684bf215546Sopenharmony_ci } 685bf215546Sopenharmony_ci return; 686bf215546Sopenharmony_ci } 687bf215546Sopenharmony_ci 688bf215546Sopenharmony_ci mode = bptc_unorm_modes + mode_num - 1; 689bf215546Sopenharmony_ci bit_offset_head = mode_num; 690bf215546Sopenharmony_ci 691bf215546Sopenharmony_ci partition_num = extract_bits(block, bit_offset_head, mode->n_partition_bits); 692bf215546Sopenharmony_ci bit_offset_head += mode->n_partition_bits; 693bf215546Sopenharmony_ci 694bf215546Sopenharmony_ci switch (mode->n_subsets) { 695bf215546Sopenharmony_ci case 1: 696bf215546Sopenharmony_ci subsets = 0; 697bf215546Sopenharmony_ci break; 698bf215546Sopenharmony_ci case 2: 699bf215546Sopenharmony_ci subsets = partition_table1[partition_num]; 700bf215546Sopenharmony_ci break; 701bf215546Sopenharmony_ci case 3: 702bf215546Sopenharmony_ci subsets = partition_table2[partition_num]; 703bf215546Sopenharmony_ci break; 704bf215546Sopenharmony_ci default: 705bf215546Sopenharmony_ci assert(false); 706bf215546Sopenharmony_ci return; 707bf215546Sopenharmony_ci } 708bf215546Sopenharmony_ci 709bf215546Sopenharmony_ci if (mode->has_rotation_bits) { 710bf215546Sopenharmony_ci rotation = extract_bits(block, bit_offset_head, 2); 711bf215546Sopenharmony_ci bit_offset_head += 2; 712bf215546Sopenharmony_ci } else { 713bf215546Sopenharmony_ci rotation = 0; 714bf215546Sopenharmony_ci } 715bf215546Sopenharmony_ci 716bf215546Sopenharmony_ci if (mode->has_index_selection_bit) { 717bf215546Sopenharmony_ci index_selection = extract_bits(block, bit_offset_head, 1); 718bf215546Sopenharmony_ci bit_offset_head++; 719bf215546Sopenharmony_ci } else { 720bf215546Sopenharmony_ci index_selection = 0; 721bf215546Sopenharmony_ci } 722bf215546Sopenharmony_ci 723bf215546Sopenharmony_ci bit_offset_head = extract_unorm_endpoints(mode, block, bit_offset_head, endpoints); 724bf215546Sopenharmony_ci 725bf215546Sopenharmony_ci for(y = 0; y < src_height; y += 1) { 726bf215546Sopenharmony_ci uint8_t *result = dst_row; 727bf215546Sopenharmony_ci for(x = 0; x < src_width; x += 1) { 728bf215546Sopenharmony_ci int texel; 729bf215546Sopenharmony_ci texel = x + y * 4; 730bf215546Sopenharmony_ci bit_offset = bit_offset_head; 731bf215546Sopenharmony_ci 732bf215546Sopenharmony_ci anchors_before_texel = count_anchors_before_texel(mode->n_subsets, 733bf215546Sopenharmony_ci partition_num, 734bf215546Sopenharmony_ci texel); 735bf215546Sopenharmony_ci 736bf215546Sopenharmony_ci /* Calculate the offset to the secondary index */ 737bf215546Sopenharmony_ci secondary_bit_offset = (bit_offset + 738bf215546Sopenharmony_ci BLOCK_SIZE * BLOCK_SIZE * mode->n_index_bits - 739bf215546Sopenharmony_ci mode->n_subsets + 740bf215546Sopenharmony_ci mode->n_secondary_index_bits * texel - 741bf215546Sopenharmony_ci anchors_before_texel); 742bf215546Sopenharmony_ci 743bf215546Sopenharmony_ci /* Calculate the offset to the primary index for this texel */ 744bf215546Sopenharmony_ci bit_offset += mode->n_index_bits * texel - anchors_before_texel; 745bf215546Sopenharmony_ci 746bf215546Sopenharmony_ci subset_num = (subsets >> (texel * 2)) & 3; 747bf215546Sopenharmony_ci 748bf215546Sopenharmony_ci anchor = is_anchor(mode->n_subsets, partition_num, texel); 749bf215546Sopenharmony_ci 750bf215546Sopenharmony_ci index_bits = mode->n_index_bits; 751bf215546Sopenharmony_ci if (anchor) 752bf215546Sopenharmony_ci index_bits--; 753bf215546Sopenharmony_ci indices[0] = extract_bits(block, bit_offset, index_bits); 754bf215546Sopenharmony_ci 755bf215546Sopenharmony_ci if (mode->n_secondary_index_bits) { 756bf215546Sopenharmony_ci index_bits = mode->n_secondary_index_bits; 757bf215546Sopenharmony_ci if (anchor) 758bf215546Sopenharmony_ci index_bits--; 759bf215546Sopenharmony_ci indices[1] = extract_bits(block, secondary_bit_offset, index_bits); 760bf215546Sopenharmony_ci } 761bf215546Sopenharmony_ci 762bf215546Sopenharmony_ci index = indices[index_selection]; 763bf215546Sopenharmony_ci index_bits = (index_selection ? 764bf215546Sopenharmony_ci mode->n_secondary_index_bits : 765bf215546Sopenharmony_ci mode->n_index_bits); 766bf215546Sopenharmony_ci 767bf215546Sopenharmony_ci for (component = 0; component < 3; component++) 768bf215546Sopenharmony_ci result[component] = interpolate(endpoints[subset_num * 2][component], 769bf215546Sopenharmony_ci endpoints[subset_num * 2 + 1][component], 770bf215546Sopenharmony_ci index, 771bf215546Sopenharmony_ci index_bits); 772bf215546Sopenharmony_ci 773bf215546Sopenharmony_ci /* Alpha uses the opposite index from the color components */ 774bf215546Sopenharmony_ci if (mode->n_secondary_index_bits && !index_selection) { 775bf215546Sopenharmony_ci index = indices[1]; 776bf215546Sopenharmony_ci index_bits = mode->n_secondary_index_bits; 777bf215546Sopenharmony_ci } else { 778bf215546Sopenharmony_ci index = indices[0]; 779bf215546Sopenharmony_ci index_bits = mode->n_index_bits; 780bf215546Sopenharmony_ci } 781bf215546Sopenharmony_ci 782bf215546Sopenharmony_ci result[3] = interpolate(endpoints[subset_num * 2][3], 783bf215546Sopenharmony_ci endpoints[subset_num * 2 + 1][3], 784bf215546Sopenharmony_ci index, 785bf215546Sopenharmony_ci index_bits); 786bf215546Sopenharmony_ci 787bf215546Sopenharmony_ci apply_rotation(rotation, result); 788bf215546Sopenharmony_ci result += 4; 789bf215546Sopenharmony_ci } 790bf215546Sopenharmony_ci dst_row += dst_rowstride; 791bf215546Sopenharmony_ci } 792bf215546Sopenharmony_ci} 793bf215546Sopenharmony_ci 794bf215546Sopenharmony_cistatic void 795bf215546Sopenharmony_cidecompress_rgba_unorm(int width, int height, 796bf215546Sopenharmony_ci const uint8_t *src, int src_rowstride, 797bf215546Sopenharmony_ci uint8_t *dst, int dst_rowstride) 798bf215546Sopenharmony_ci{ 799bf215546Sopenharmony_ci int src_row_diff; 800bf215546Sopenharmony_ci int y, x; 801bf215546Sopenharmony_ci 802bf215546Sopenharmony_ci if (src_rowstride >= width * 4) 803bf215546Sopenharmony_ci src_row_diff = src_rowstride - ((width + 3) & ~3) * 4; 804bf215546Sopenharmony_ci else 805bf215546Sopenharmony_ci src_row_diff = 0; 806bf215546Sopenharmony_ci 807bf215546Sopenharmony_ci for (y = 0; y < height; y += BLOCK_SIZE) { 808bf215546Sopenharmony_ci for (x = 0; x < width; x += BLOCK_SIZE) { 809bf215546Sopenharmony_ci decompress_rgba_unorm_block(MIN2(width - x, BLOCK_SIZE), 810bf215546Sopenharmony_ci MIN2(height - y, BLOCK_SIZE), 811bf215546Sopenharmony_ci src, 812bf215546Sopenharmony_ci dst + x * 4 + y * dst_rowstride, 813bf215546Sopenharmony_ci dst_rowstride); 814bf215546Sopenharmony_ci src += BLOCK_BYTES; 815bf215546Sopenharmony_ci } 816bf215546Sopenharmony_ci src += src_row_diff; 817bf215546Sopenharmony_ci } 818bf215546Sopenharmony_ci} 819bf215546Sopenharmony_ci#endif // BPTC_BLOCK_DECODE 820bf215546Sopenharmony_ci 821bf215546Sopenharmony_cistatic int 822bf215546Sopenharmony_cisigned_unquantize(int value, int n_endpoint_bits) 823bf215546Sopenharmony_ci{ 824bf215546Sopenharmony_ci bool sign; 825bf215546Sopenharmony_ci 826bf215546Sopenharmony_ci if (n_endpoint_bits >= 16) 827bf215546Sopenharmony_ci return value; 828bf215546Sopenharmony_ci 829bf215546Sopenharmony_ci if (value == 0) 830bf215546Sopenharmony_ci return 0; 831bf215546Sopenharmony_ci 832bf215546Sopenharmony_ci sign = false; 833bf215546Sopenharmony_ci 834bf215546Sopenharmony_ci if (value < 0) { 835bf215546Sopenharmony_ci sign = true; 836bf215546Sopenharmony_ci value = -value; 837bf215546Sopenharmony_ci } 838bf215546Sopenharmony_ci 839bf215546Sopenharmony_ci if (value >= (1 << (n_endpoint_bits - 1)) - 1) 840bf215546Sopenharmony_ci value = 0x7fff; 841bf215546Sopenharmony_ci else 842bf215546Sopenharmony_ci value = ((value << 15) + 0x4000) >> (n_endpoint_bits - 1); 843bf215546Sopenharmony_ci 844bf215546Sopenharmony_ci if (sign) 845bf215546Sopenharmony_ci value = -value; 846bf215546Sopenharmony_ci 847bf215546Sopenharmony_ci return value; 848bf215546Sopenharmony_ci} 849bf215546Sopenharmony_ci 850bf215546Sopenharmony_cistatic int 851bf215546Sopenharmony_ciunsigned_unquantize(int value, int n_endpoint_bits) 852bf215546Sopenharmony_ci{ 853bf215546Sopenharmony_ci if (n_endpoint_bits >= 15) 854bf215546Sopenharmony_ci return value; 855bf215546Sopenharmony_ci 856bf215546Sopenharmony_ci if (value == 0) 857bf215546Sopenharmony_ci return 0; 858bf215546Sopenharmony_ci 859bf215546Sopenharmony_ci if (value == (1 << n_endpoint_bits) - 1) 860bf215546Sopenharmony_ci return 0xffff; 861bf215546Sopenharmony_ci 862bf215546Sopenharmony_ci return ((value << 15) + 0x4000) >> (n_endpoint_bits - 1); 863bf215546Sopenharmony_ci} 864bf215546Sopenharmony_ci 865bf215546Sopenharmony_cistatic int 866bf215546Sopenharmony_ciextract_float_endpoints(const struct bptc_float_mode *mode, 867bf215546Sopenharmony_ci const uint8_t *block, 868bf215546Sopenharmony_ci int bit_offset, 869bf215546Sopenharmony_ci int32_t endpoints[][3], 870bf215546Sopenharmony_ci bool is_signed) 871bf215546Sopenharmony_ci{ 872bf215546Sopenharmony_ci const struct bptc_float_bitfield *bitfield; 873bf215546Sopenharmony_ci int endpoint, component; 874bf215546Sopenharmony_ci int n_endpoints; 875bf215546Sopenharmony_ci int value; 876bf215546Sopenharmony_ci int i; 877bf215546Sopenharmony_ci 878bf215546Sopenharmony_ci if (mode->n_partition_bits) 879bf215546Sopenharmony_ci n_endpoints = 4; 880bf215546Sopenharmony_ci else 881bf215546Sopenharmony_ci n_endpoints = 2; 882bf215546Sopenharmony_ci 883bf215546Sopenharmony_ci memset(endpoints, 0, sizeof endpoints[0][0] * n_endpoints * 3); 884bf215546Sopenharmony_ci 885bf215546Sopenharmony_ci for (bitfield = mode->bitfields; bitfield->endpoint != -1; bitfield++) { 886bf215546Sopenharmony_ci value = extract_bits(block, bit_offset, bitfield->n_bits); 887bf215546Sopenharmony_ci bit_offset += bitfield->n_bits; 888bf215546Sopenharmony_ci 889bf215546Sopenharmony_ci if (bitfield->reverse) { 890bf215546Sopenharmony_ci for (i = 0; i < bitfield->n_bits; i++) { 891bf215546Sopenharmony_ci if (value & (1 << i)) 892bf215546Sopenharmony_ci endpoints[bitfield->endpoint][bitfield->component] |= 893bf215546Sopenharmony_ci 1 << ((bitfield->n_bits - 1 - i) + bitfield->offset); 894bf215546Sopenharmony_ci } 895bf215546Sopenharmony_ci } else { 896bf215546Sopenharmony_ci endpoints[bitfield->endpoint][bitfield->component] |= 897bf215546Sopenharmony_ci value << bitfield->offset; 898bf215546Sopenharmony_ci } 899bf215546Sopenharmony_ci } 900bf215546Sopenharmony_ci 901bf215546Sopenharmony_ci if (mode->transformed_endpoints) { 902bf215546Sopenharmony_ci /* The endpoints are specified as signed offsets from e0 */ 903bf215546Sopenharmony_ci for (endpoint = 1; endpoint < n_endpoints; endpoint++) { 904bf215546Sopenharmony_ci for (component = 0; component < 3; component++) { 905bf215546Sopenharmony_ci value = util_sign_extend(endpoints[endpoint][component], 906bf215546Sopenharmony_ci mode->n_delta_bits[component]); 907bf215546Sopenharmony_ci endpoints[endpoint][component] = 908bf215546Sopenharmony_ci ((endpoints[0][component] + value) & 909bf215546Sopenharmony_ci ((1 << mode->n_endpoint_bits) - 1)); 910bf215546Sopenharmony_ci } 911bf215546Sopenharmony_ci } 912bf215546Sopenharmony_ci } 913bf215546Sopenharmony_ci 914bf215546Sopenharmony_ci if (is_signed) { 915bf215546Sopenharmony_ci for (endpoint = 0; endpoint < n_endpoints; endpoint++) { 916bf215546Sopenharmony_ci for (component = 0; component < 3; component++) { 917bf215546Sopenharmony_ci value = util_sign_extend(endpoints[endpoint][component], 918bf215546Sopenharmony_ci mode->n_endpoint_bits); 919bf215546Sopenharmony_ci endpoints[endpoint][component] = 920bf215546Sopenharmony_ci signed_unquantize(value, mode->n_endpoint_bits); 921bf215546Sopenharmony_ci } 922bf215546Sopenharmony_ci } 923bf215546Sopenharmony_ci } else { 924bf215546Sopenharmony_ci for (endpoint = 0; endpoint < n_endpoints; endpoint++) { 925bf215546Sopenharmony_ci for (component = 0; component < 3; component++) { 926bf215546Sopenharmony_ci endpoints[endpoint][component] = 927bf215546Sopenharmony_ci unsigned_unquantize(endpoints[endpoint][component], 928bf215546Sopenharmony_ci mode->n_endpoint_bits); 929bf215546Sopenharmony_ci } 930bf215546Sopenharmony_ci } 931bf215546Sopenharmony_ci } 932bf215546Sopenharmony_ci 933bf215546Sopenharmony_ci return bit_offset; 934bf215546Sopenharmony_ci} 935bf215546Sopenharmony_ci 936bf215546Sopenharmony_cistatic int32_t 937bf215546Sopenharmony_cifinish_unsigned_unquantize(int32_t value) 938bf215546Sopenharmony_ci{ 939bf215546Sopenharmony_ci return value * 31 / 64; 940bf215546Sopenharmony_ci} 941bf215546Sopenharmony_ci 942bf215546Sopenharmony_cistatic int32_t 943bf215546Sopenharmony_cifinish_signed_unquantize(int32_t value) 944bf215546Sopenharmony_ci{ 945bf215546Sopenharmony_ci if (value < 0) 946bf215546Sopenharmony_ci return (-value * 31 / 32) | 0x8000; 947bf215546Sopenharmony_ci else 948bf215546Sopenharmony_ci return value * 31 / 32; 949bf215546Sopenharmony_ci} 950bf215546Sopenharmony_ci 951bf215546Sopenharmony_cistatic void 952bf215546Sopenharmony_cifetch_rgb_float_from_block(const uint8_t *block, 953bf215546Sopenharmony_ci float *result, 954bf215546Sopenharmony_ci int texel, 955bf215546Sopenharmony_ci bool is_signed) 956bf215546Sopenharmony_ci{ 957bf215546Sopenharmony_ci int mode_num; 958bf215546Sopenharmony_ci const struct bptc_float_mode *mode; 959bf215546Sopenharmony_ci int bit_offset; 960bf215546Sopenharmony_ci int partition_num; 961bf215546Sopenharmony_ci int subset_num; 962bf215546Sopenharmony_ci int index_bits; 963bf215546Sopenharmony_ci int index; 964bf215546Sopenharmony_ci int anchors_before_texel; 965bf215546Sopenharmony_ci int32_t endpoints[2 * 2][3]; 966bf215546Sopenharmony_ci uint32_t subsets; 967bf215546Sopenharmony_ci int n_subsets; 968bf215546Sopenharmony_ci int component; 969bf215546Sopenharmony_ci int32_t value; 970bf215546Sopenharmony_ci 971bf215546Sopenharmony_ci if (block[0] & 0x2) { 972bf215546Sopenharmony_ci mode_num = (((block[0] >> 1) & 0xe) | (block[0] & 1)) + 2; 973bf215546Sopenharmony_ci bit_offset = 5; 974bf215546Sopenharmony_ci } else { 975bf215546Sopenharmony_ci mode_num = block[0] & 3; 976bf215546Sopenharmony_ci bit_offset = 2; 977bf215546Sopenharmony_ci } 978bf215546Sopenharmony_ci 979bf215546Sopenharmony_ci mode = bptc_float_modes + mode_num; 980bf215546Sopenharmony_ci 981bf215546Sopenharmony_ci if (mode->reserved) { 982bf215546Sopenharmony_ci memset(result, 0, sizeof result[0] * 3); 983bf215546Sopenharmony_ci result[3] = 1.0f; 984bf215546Sopenharmony_ci return; 985bf215546Sopenharmony_ci } 986bf215546Sopenharmony_ci 987bf215546Sopenharmony_ci bit_offset = extract_float_endpoints(mode, block, bit_offset, 988bf215546Sopenharmony_ci endpoints, is_signed); 989bf215546Sopenharmony_ci 990bf215546Sopenharmony_ci if (mode->n_partition_bits) { 991bf215546Sopenharmony_ci partition_num = extract_bits(block, bit_offset, mode->n_partition_bits); 992bf215546Sopenharmony_ci bit_offset += mode->n_partition_bits; 993bf215546Sopenharmony_ci 994bf215546Sopenharmony_ci subsets = partition_table1[partition_num]; 995bf215546Sopenharmony_ci n_subsets = 2; 996bf215546Sopenharmony_ci } else { 997bf215546Sopenharmony_ci partition_num = 0; 998bf215546Sopenharmony_ci subsets = 0; 999bf215546Sopenharmony_ci n_subsets = 1; 1000bf215546Sopenharmony_ci } 1001bf215546Sopenharmony_ci 1002bf215546Sopenharmony_ci anchors_before_texel = 1003bf215546Sopenharmony_ci count_anchors_before_texel(n_subsets, partition_num, texel); 1004bf215546Sopenharmony_ci 1005bf215546Sopenharmony_ci /* Calculate the offset to the primary index for this texel */ 1006bf215546Sopenharmony_ci bit_offset += mode->n_index_bits * texel - anchors_before_texel; 1007bf215546Sopenharmony_ci 1008bf215546Sopenharmony_ci subset_num = (subsets >> (texel * 2)) & 3; 1009bf215546Sopenharmony_ci 1010bf215546Sopenharmony_ci index_bits = mode->n_index_bits; 1011bf215546Sopenharmony_ci if (is_anchor(n_subsets, partition_num, texel)) 1012bf215546Sopenharmony_ci index_bits--; 1013bf215546Sopenharmony_ci index = extract_bits(block, bit_offset, index_bits); 1014bf215546Sopenharmony_ci 1015bf215546Sopenharmony_ci for (component = 0; component < 3; component++) { 1016bf215546Sopenharmony_ci value = interpolate(endpoints[subset_num * 2][component], 1017bf215546Sopenharmony_ci endpoints[subset_num * 2 + 1][component], 1018bf215546Sopenharmony_ci index, 1019bf215546Sopenharmony_ci mode->n_index_bits); 1020bf215546Sopenharmony_ci 1021bf215546Sopenharmony_ci if (is_signed) 1022bf215546Sopenharmony_ci value = finish_signed_unquantize(value); 1023bf215546Sopenharmony_ci else 1024bf215546Sopenharmony_ci value = finish_unsigned_unquantize(value); 1025bf215546Sopenharmony_ci 1026bf215546Sopenharmony_ci result[component] = _mesa_half_to_float(value); 1027bf215546Sopenharmony_ci } 1028bf215546Sopenharmony_ci 1029bf215546Sopenharmony_ci result[3] = 1.0f; 1030bf215546Sopenharmony_ci} 1031bf215546Sopenharmony_ci 1032bf215546Sopenharmony_ci#ifdef BPTC_BLOCK_DECODE 1033bf215546Sopenharmony_cistatic void 1034bf215546Sopenharmony_cidecompress_rgb_float_block(unsigned src_width, unsigned src_height, 1035bf215546Sopenharmony_ci const uint8_t *block, 1036bf215546Sopenharmony_ci float *dst_row, unsigned dst_rowstride, 1037bf215546Sopenharmony_ci bool is_signed) 1038bf215546Sopenharmony_ci{ 1039bf215546Sopenharmony_ci int mode_num; 1040bf215546Sopenharmony_ci const struct bptc_float_mode *mode; 1041bf215546Sopenharmony_ci int bit_offset_head, bit_offset; 1042bf215546Sopenharmony_ci int partition_num; 1043bf215546Sopenharmony_ci int subset_num; 1044bf215546Sopenharmony_ci int index_bits; 1045bf215546Sopenharmony_ci int index; 1046bf215546Sopenharmony_ci int anchors_before_texel; 1047bf215546Sopenharmony_ci int32_t endpoints[2 * 2][3]; 1048bf215546Sopenharmony_ci uint32_t subsets; 1049bf215546Sopenharmony_ci int n_subsets; 1050bf215546Sopenharmony_ci int component; 1051bf215546Sopenharmony_ci int32_t value; 1052bf215546Sopenharmony_ci unsigned x, y; 1053bf215546Sopenharmony_ci 1054bf215546Sopenharmony_ci if (block[0] & 0x2) { 1055bf215546Sopenharmony_ci mode_num = (((block[0] >> 1) & 0xe) | (block[0] & 1)) + 2; 1056bf215546Sopenharmony_ci bit_offset_head = 5; 1057bf215546Sopenharmony_ci } else { 1058bf215546Sopenharmony_ci mode_num = block[0] & 3; 1059bf215546Sopenharmony_ci bit_offset_head = 2; 1060bf215546Sopenharmony_ci } 1061bf215546Sopenharmony_ci 1062bf215546Sopenharmony_ci mode = bptc_float_modes + mode_num; 1063bf215546Sopenharmony_ci 1064bf215546Sopenharmony_ci if (mode->reserved) { 1065bf215546Sopenharmony_ci for(y = 0; y < src_height; y += 1) { 1066bf215546Sopenharmony_ci float *result = dst_row; 1067bf215546Sopenharmony_ci memset(result, 0, sizeof result[0] * 4 * src_width); 1068bf215546Sopenharmony_ci for(x = 0; x < src_width; x += 1) { 1069bf215546Sopenharmony_ci result[3] = 1.0f; 1070bf215546Sopenharmony_ci result += 4; 1071bf215546Sopenharmony_ci } 1072bf215546Sopenharmony_ci dst_row += dst_rowstride / sizeof dst_row[0]; 1073bf215546Sopenharmony_ci } 1074bf215546Sopenharmony_ci return; 1075bf215546Sopenharmony_ci } 1076bf215546Sopenharmony_ci 1077bf215546Sopenharmony_ci bit_offset_head = extract_float_endpoints(mode, block, bit_offset_head, 1078bf215546Sopenharmony_ci endpoints, is_signed); 1079bf215546Sopenharmony_ci 1080bf215546Sopenharmony_ci if (mode->n_partition_bits) { 1081bf215546Sopenharmony_ci partition_num = extract_bits(block, bit_offset_head, mode->n_partition_bits); 1082bf215546Sopenharmony_ci bit_offset_head += mode->n_partition_bits; 1083bf215546Sopenharmony_ci 1084bf215546Sopenharmony_ci subsets = partition_table1[partition_num]; 1085bf215546Sopenharmony_ci n_subsets = 2; 1086bf215546Sopenharmony_ci } else { 1087bf215546Sopenharmony_ci partition_num = 0; 1088bf215546Sopenharmony_ci subsets = 0; 1089bf215546Sopenharmony_ci n_subsets = 1; 1090bf215546Sopenharmony_ci } 1091bf215546Sopenharmony_ci 1092bf215546Sopenharmony_ci for(y = 0; y < src_height; y += 1) { 1093bf215546Sopenharmony_ci float *result = dst_row; 1094bf215546Sopenharmony_ci for(x = 0; x < src_width; x += 1) { 1095bf215546Sopenharmony_ci int texel; 1096bf215546Sopenharmony_ci 1097bf215546Sopenharmony_ci bit_offset = bit_offset_head; 1098bf215546Sopenharmony_ci 1099bf215546Sopenharmony_ci texel = x + y * 4; 1100bf215546Sopenharmony_ci 1101bf215546Sopenharmony_ci anchors_before_texel = 1102bf215546Sopenharmony_ci count_anchors_before_texel(n_subsets, partition_num, texel); 1103bf215546Sopenharmony_ci 1104bf215546Sopenharmony_ci /* Calculate the offset to the primary index for this texel */ 1105bf215546Sopenharmony_ci bit_offset += mode->n_index_bits * texel - anchors_before_texel; 1106bf215546Sopenharmony_ci 1107bf215546Sopenharmony_ci subset_num = (subsets >> (texel * 2)) & 3; 1108bf215546Sopenharmony_ci 1109bf215546Sopenharmony_ci index_bits = mode->n_index_bits; 1110bf215546Sopenharmony_ci if (is_anchor(n_subsets, partition_num, texel)) 1111bf215546Sopenharmony_ci index_bits--; 1112bf215546Sopenharmony_ci index = extract_bits(block, bit_offset, index_bits); 1113bf215546Sopenharmony_ci 1114bf215546Sopenharmony_ci for (component = 0; component < 3; component++) { 1115bf215546Sopenharmony_ci value = interpolate(endpoints[subset_num * 2][component], 1116bf215546Sopenharmony_ci endpoints[subset_num * 2 + 1][component], 1117bf215546Sopenharmony_ci index, 1118bf215546Sopenharmony_ci mode->n_index_bits); 1119bf215546Sopenharmony_ci 1120bf215546Sopenharmony_ci if (is_signed) 1121bf215546Sopenharmony_ci value = finish_signed_unquantize(value); 1122bf215546Sopenharmony_ci else 1123bf215546Sopenharmony_ci value = finish_unsigned_unquantize(value); 1124bf215546Sopenharmony_ci 1125bf215546Sopenharmony_ci result[component] = _mesa_half_to_float(value); 1126bf215546Sopenharmony_ci } 1127bf215546Sopenharmony_ci 1128bf215546Sopenharmony_ci result[3] = 1.0f; 1129bf215546Sopenharmony_ci result += 4; 1130bf215546Sopenharmony_ci } 1131bf215546Sopenharmony_ci dst_row += dst_rowstride / sizeof dst_row[0]; 1132bf215546Sopenharmony_ci } 1133bf215546Sopenharmony_ci} 1134bf215546Sopenharmony_ci 1135bf215546Sopenharmony_cistatic void 1136bf215546Sopenharmony_cidecompress_rgb_float(int width, int height, 1137bf215546Sopenharmony_ci const uint8_t *src, int src_rowstride, 1138bf215546Sopenharmony_ci float *dst, int dst_rowstride, bool is_signed) 1139bf215546Sopenharmony_ci{ 1140bf215546Sopenharmony_ci int src_row_diff; 1141bf215546Sopenharmony_ci int y, x; 1142bf215546Sopenharmony_ci 1143bf215546Sopenharmony_ci if (src_rowstride >= width * 4) 1144bf215546Sopenharmony_ci src_row_diff = src_rowstride - ((width + 3) & ~3) * 4; 1145bf215546Sopenharmony_ci else 1146bf215546Sopenharmony_ci src_row_diff = 0; 1147bf215546Sopenharmony_ci 1148bf215546Sopenharmony_ci for (y = 0; y < height; y += BLOCK_SIZE) { 1149bf215546Sopenharmony_ci for (x = 0; x < width; x += BLOCK_SIZE) { 1150bf215546Sopenharmony_ci decompress_rgb_float_block(MIN2(width - x, BLOCK_SIZE), 1151bf215546Sopenharmony_ci MIN2(height - y, BLOCK_SIZE), 1152bf215546Sopenharmony_ci src, 1153bf215546Sopenharmony_ci (dst + x * 4 + 1154bf215546Sopenharmony_ci (y * dst_rowstride / sizeof dst[0])), 1155bf215546Sopenharmony_ci dst_rowstride, is_signed); 1156bf215546Sopenharmony_ci src += BLOCK_BYTES; 1157bf215546Sopenharmony_ci } 1158bf215546Sopenharmony_ci src += src_row_diff; 1159bf215546Sopenharmony_ci } 1160bf215546Sopenharmony_ci} 1161bf215546Sopenharmony_ci#endif // BPTC_BLOCK_DECODE 1162bf215546Sopenharmony_ci 1163bf215546Sopenharmony_cistatic void 1164bf215546Sopenharmony_ciwrite_bits(struct bit_writer *writer, int n_bits, int value) 1165bf215546Sopenharmony_ci{ 1166bf215546Sopenharmony_ci do { 1167bf215546Sopenharmony_ci if (n_bits + writer->pos >= 8) { 1168bf215546Sopenharmony_ci *(writer->dst++) = writer->buf | (value << writer->pos); 1169bf215546Sopenharmony_ci writer->buf = 0; 1170bf215546Sopenharmony_ci value >>= (8 - writer->pos); 1171bf215546Sopenharmony_ci n_bits -= (8 - writer->pos); 1172bf215546Sopenharmony_ci writer->pos = 0; 1173bf215546Sopenharmony_ci } else { 1174bf215546Sopenharmony_ci writer->buf |= value << writer->pos; 1175bf215546Sopenharmony_ci writer->pos += n_bits; 1176bf215546Sopenharmony_ci break; 1177bf215546Sopenharmony_ci } 1178bf215546Sopenharmony_ci } while (n_bits > 0); 1179bf215546Sopenharmony_ci} 1180bf215546Sopenharmony_ci 1181bf215546Sopenharmony_cistatic void 1182bf215546Sopenharmony_ciget_average_luminance_alpha_unorm(int width, int height, 1183bf215546Sopenharmony_ci const uint8_t *src, int src_rowstride, 1184bf215546Sopenharmony_ci int *average_luminance, int *average_alpha) 1185bf215546Sopenharmony_ci{ 1186bf215546Sopenharmony_ci int luminance_sum = 0, alpha_sum = 0; 1187bf215546Sopenharmony_ci int y, x; 1188bf215546Sopenharmony_ci 1189bf215546Sopenharmony_ci for (y = 0; y < height; y++) { 1190bf215546Sopenharmony_ci for (x = 0; x < width; x++) { 1191bf215546Sopenharmony_ci luminance_sum += src[0] + src[1] + src[2]; 1192bf215546Sopenharmony_ci alpha_sum += src[3]; 1193bf215546Sopenharmony_ci src += 4; 1194bf215546Sopenharmony_ci } 1195bf215546Sopenharmony_ci src += src_rowstride - width * 4; 1196bf215546Sopenharmony_ci } 1197bf215546Sopenharmony_ci 1198bf215546Sopenharmony_ci *average_luminance = luminance_sum / (width * height); 1199bf215546Sopenharmony_ci *average_alpha = alpha_sum / (width * height); 1200bf215546Sopenharmony_ci} 1201bf215546Sopenharmony_ci 1202bf215546Sopenharmony_cistatic void 1203bf215546Sopenharmony_ciget_rgba_endpoints_unorm(int width, int height, 1204bf215546Sopenharmony_ci const uint8_t *src, int src_rowstride, 1205bf215546Sopenharmony_ci int average_luminance, int average_alpha, 1206bf215546Sopenharmony_ci uint8_t endpoints[][4]) 1207bf215546Sopenharmony_ci{ 1208bf215546Sopenharmony_ci int endpoint_luminances[2]; 1209bf215546Sopenharmony_ci int midpoint; 1210bf215546Sopenharmony_ci int sums[2][4]; 1211bf215546Sopenharmony_ci int endpoint; 1212bf215546Sopenharmony_ci int luminance; 1213bf215546Sopenharmony_ci uint8_t temp[3]; 1214bf215546Sopenharmony_ci const uint8_t *p = src; 1215bf215546Sopenharmony_ci int rgb_left_endpoint_count = 0; 1216bf215546Sopenharmony_ci int alpha_left_endpoint_count = 0; 1217bf215546Sopenharmony_ci int y, x, i; 1218bf215546Sopenharmony_ci 1219bf215546Sopenharmony_ci memset(sums, 0, sizeof sums); 1220bf215546Sopenharmony_ci 1221bf215546Sopenharmony_ci for (y = 0; y < height; y++) { 1222bf215546Sopenharmony_ci for (x = 0; x < width; x++) { 1223bf215546Sopenharmony_ci luminance = p[0] + p[1] + p[2]; 1224bf215546Sopenharmony_ci if (luminance < average_luminance) { 1225bf215546Sopenharmony_ci endpoint = 0; 1226bf215546Sopenharmony_ci rgb_left_endpoint_count++; 1227bf215546Sopenharmony_ci } else { 1228bf215546Sopenharmony_ci endpoint = 1; 1229bf215546Sopenharmony_ci } 1230bf215546Sopenharmony_ci for (i = 0; i < 3; i++) 1231bf215546Sopenharmony_ci sums[endpoint][i] += p[i]; 1232bf215546Sopenharmony_ci 1233bf215546Sopenharmony_ci if (p[2] < average_alpha) { 1234bf215546Sopenharmony_ci endpoint = 0; 1235bf215546Sopenharmony_ci alpha_left_endpoint_count++; 1236bf215546Sopenharmony_ci } else { 1237bf215546Sopenharmony_ci endpoint = 1; 1238bf215546Sopenharmony_ci } 1239bf215546Sopenharmony_ci sums[endpoint][3] += p[3]; 1240bf215546Sopenharmony_ci 1241bf215546Sopenharmony_ci p += 4; 1242bf215546Sopenharmony_ci } 1243bf215546Sopenharmony_ci 1244bf215546Sopenharmony_ci p += src_rowstride - width * 4; 1245bf215546Sopenharmony_ci } 1246bf215546Sopenharmony_ci 1247bf215546Sopenharmony_ci if (rgb_left_endpoint_count == 0 || 1248bf215546Sopenharmony_ci rgb_left_endpoint_count == width * height) { 1249bf215546Sopenharmony_ci for (i = 0; i < 3; i++) 1250bf215546Sopenharmony_ci endpoints[0][i] = endpoints[1][i] = 1251bf215546Sopenharmony_ci (sums[0][i] + sums[1][i]) / (width * height); 1252bf215546Sopenharmony_ci } else { 1253bf215546Sopenharmony_ci for (i = 0; i < 3; i++) { 1254bf215546Sopenharmony_ci endpoints[0][i] = sums[0][i] / rgb_left_endpoint_count; 1255bf215546Sopenharmony_ci endpoints[1][i] = (sums[1][i] / 1256bf215546Sopenharmony_ci (width * height - rgb_left_endpoint_count)); 1257bf215546Sopenharmony_ci } 1258bf215546Sopenharmony_ci } 1259bf215546Sopenharmony_ci 1260bf215546Sopenharmony_ci if (alpha_left_endpoint_count == 0 || 1261bf215546Sopenharmony_ci alpha_left_endpoint_count == width * height) { 1262bf215546Sopenharmony_ci endpoints[0][3] = endpoints[1][3] = 1263bf215546Sopenharmony_ci (sums[0][3] + sums[1][3]) / (width * height); 1264bf215546Sopenharmony_ci } else { 1265bf215546Sopenharmony_ci endpoints[0][3] = sums[0][3] / alpha_left_endpoint_count; 1266bf215546Sopenharmony_ci endpoints[1][3] = (sums[1][3] / 1267bf215546Sopenharmony_ci (width * height - alpha_left_endpoint_count)); 1268bf215546Sopenharmony_ci } 1269bf215546Sopenharmony_ci 1270bf215546Sopenharmony_ci /* We may need to swap the endpoints to ensure the most-significant bit of 1271bf215546Sopenharmony_ci * the first index is zero */ 1272bf215546Sopenharmony_ci 1273bf215546Sopenharmony_ci for (endpoint = 0; endpoint < 2; endpoint++) { 1274bf215546Sopenharmony_ci endpoint_luminances[endpoint] = 1275bf215546Sopenharmony_ci endpoints[endpoint][0] + 1276bf215546Sopenharmony_ci endpoints[endpoint][1] + 1277bf215546Sopenharmony_ci endpoints[endpoint][2]; 1278bf215546Sopenharmony_ci } 1279bf215546Sopenharmony_ci midpoint = (endpoint_luminances[0] + endpoint_luminances[1]) / 2; 1280bf215546Sopenharmony_ci 1281bf215546Sopenharmony_ci if ((src[0] + src[1] + src[2] <= midpoint) != 1282bf215546Sopenharmony_ci (endpoint_luminances[0] <= midpoint)) { 1283bf215546Sopenharmony_ci memcpy(temp, endpoints[0], 3); 1284bf215546Sopenharmony_ci memcpy(endpoints[0], endpoints[1], 3); 1285bf215546Sopenharmony_ci memcpy(endpoints[1], temp, 3); 1286bf215546Sopenharmony_ci } 1287bf215546Sopenharmony_ci 1288bf215546Sopenharmony_ci /* Same for the alpha endpoints */ 1289bf215546Sopenharmony_ci 1290bf215546Sopenharmony_ci midpoint = (endpoints[0][3] + endpoints[1][3]) / 2; 1291bf215546Sopenharmony_ci 1292bf215546Sopenharmony_ci if ((src[3] <= midpoint) != (endpoints[0][3] <= midpoint)) { 1293bf215546Sopenharmony_ci temp[0] = endpoints[0][3]; 1294bf215546Sopenharmony_ci endpoints[0][3] = endpoints[1][3]; 1295bf215546Sopenharmony_ci endpoints[1][3] = temp[0]; 1296bf215546Sopenharmony_ci } 1297bf215546Sopenharmony_ci} 1298bf215546Sopenharmony_ci 1299bf215546Sopenharmony_cistatic void 1300bf215546Sopenharmony_ciwrite_rgb_indices_unorm(struct bit_writer *writer, 1301bf215546Sopenharmony_ci int src_width, int src_height, 1302bf215546Sopenharmony_ci const uint8_t *src, int src_rowstride, 1303bf215546Sopenharmony_ci uint8_t endpoints[][4]) 1304bf215546Sopenharmony_ci{ 1305bf215546Sopenharmony_ci int luminance; 1306bf215546Sopenharmony_ci int endpoint_luminances[2]; 1307bf215546Sopenharmony_ci int endpoint; 1308bf215546Sopenharmony_ci int index; 1309bf215546Sopenharmony_ci int y, x; 1310bf215546Sopenharmony_ci 1311bf215546Sopenharmony_ci for (endpoint = 0; endpoint < 2; endpoint++) { 1312bf215546Sopenharmony_ci endpoint_luminances[endpoint] = 1313bf215546Sopenharmony_ci endpoints[endpoint][0] + 1314bf215546Sopenharmony_ci endpoints[endpoint][1] + 1315bf215546Sopenharmony_ci endpoints[endpoint][2]; 1316bf215546Sopenharmony_ci } 1317bf215546Sopenharmony_ci 1318bf215546Sopenharmony_ci /* If the endpoints have the same luminance then we'll just use index 0 for 1319bf215546Sopenharmony_ci * all of the texels */ 1320bf215546Sopenharmony_ci if (endpoint_luminances[0] == endpoint_luminances[1]) { 1321bf215546Sopenharmony_ci write_bits(writer, BLOCK_SIZE * BLOCK_SIZE * 2 - 1, 0); 1322bf215546Sopenharmony_ci return; 1323bf215546Sopenharmony_ci } 1324bf215546Sopenharmony_ci 1325bf215546Sopenharmony_ci for (y = 0; y < src_height; y++) { 1326bf215546Sopenharmony_ci for (x = 0; x < src_width; x++) { 1327bf215546Sopenharmony_ci luminance = src[0] + src[1] + src[2]; 1328bf215546Sopenharmony_ci 1329bf215546Sopenharmony_ci index = ((luminance - endpoint_luminances[0]) * 3 / 1330bf215546Sopenharmony_ci (endpoint_luminances[1] - endpoint_luminances[0])); 1331bf215546Sopenharmony_ci if (index < 0) 1332bf215546Sopenharmony_ci index = 0; 1333bf215546Sopenharmony_ci else if (index > 3) 1334bf215546Sopenharmony_ci index = 3; 1335bf215546Sopenharmony_ci 1336bf215546Sopenharmony_ci assert(x != 0 || y != 0 || index < 2); 1337bf215546Sopenharmony_ci 1338bf215546Sopenharmony_ci write_bits(writer, (x == 0 && y == 0) ? 1 : 2, index); 1339bf215546Sopenharmony_ci 1340bf215546Sopenharmony_ci src += 4; 1341bf215546Sopenharmony_ci } 1342bf215546Sopenharmony_ci 1343bf215546Sopenharmony_ci /* Pad the indices out to the block size */ 1344bf215546Sopenharmony_ci if (src_width < BLOCK_SIZE) 1345bf215546Sopenharmony_ci write_bits(writer, 2 * (BLOCK_SIZE - src_width), 0); 1346bf215546Sopenharmony_ci 1347bf215546Sopenharmony_ci src += src_rowstride - src_width * 4; 1348bf215546Sopenharmony_ci } 1349bf215546Sopenharmony_ci 1350bf215546Sopenharmony_ci /* Pad the indices out to the block size */ 1351bf215546Sopenharmony_ci if (src_height < BLOCK_SIZE) 1352bf215546Sopenharmony_ci write_bits(writer, 2 * BLOCK_SIZE * (BLOCK_SIZE - src_height), 0); 1353bf215546Sopenharmony_ci} 1354bf215546Sopenharmony_ci 1355bf215546Sopenharmony_cistatic void 1356bf215546Sopenharmony_ciwrite_alpha_indices_unorm(struct bit_writer *writer, 1357bf215546Sopenharmony_ci int src_width, int src_height, 1358bf215546Sopenharmony_ci const uint8_t *src, int src_rowstride, 1359bf215546Sopenharmony_ci uint8_t endpoints[][4]) 1360bf215546Sopenharmony_ci{ 1361bf215546Sopenharmony_ci int index; 1362bf215546Sopenharmony_ci int y, x; 1363bf215546Sopenharmony_ci 1364bf215546Sopenharmony_ci /* If the endpoints have the same alpha then we'll just use index 0 for 1365bf215546Sopenharmony_ci * all of the texels */ 1366bf215546Sopenharmony_ci if (endpoints[0][3] == endpoints[1][3]) { 1367bf215546Sopenharmony_ci write_bits(writer, BLOCK_SIZE * BLOCK_SIZE * 3 - 1, 0); 1368bf215546Sopenharmony_ci return; 1369bf215546Sopenharmony_ci } 1370bf215546Sopenharmony_ci 1371bf215546Sopenharmony_ci for (y = 0; y < src_height; y++) { 1372bf215546Sopenharmony_ci for (x = 0; x < src_width; x++) { 1373bf215546Sopenharmony_ci index = (((int) src[3] - (int) endpoints[0][3]) * 7 / 1374bf215546Sopenharmony_ci ((int) endpoints[1][3] - endpoints[0][3])); 1375bf215546Sopenharmony_ci if (index < 0) 1376bf215546Sopenharmony_ci index = 0; 1377bf215546Sopenharmony_ci else if (index > 7) 1378bf215546Sopenharmony_ci index = 7; 1379bf215546Sopenharmony_ci 1380bf215546Sopenharmony_ci assert(x != 0 || y != 0 || index < 4); 1381bf215546Sopenharmony_ci 1382bf215546Sopenharmony_ci /* The first index has one less bit */ 1383bf215546Sopenharmony_ci write_bits(writer, (x == 0 && y == 0) ? 2 : 3, index); 1384bf215546Sopenharmony_ci 1385bf215546Sopenharmony_ci src += 4; 1386bf215546Sopenharmony_ci } 1387bf215546Sopenharmony_ci 1388bf215546Sopenharmony_ci /* Pad the indices out to the block size */ 1389bf215546Sopenharmony_ci if (src_width < BLOCK_SIZE) 1390bf215546Sopenharmony_ci write_bits(writer, 3 * (BLOCK_SIZE - src_width), 0); 1391bf215546Sopenharmony_ci 1392bf215546Sopenharmony_ci src += src_rowstride - src_width * 4; 1393bf215546Sopenharmony_ci } 1394bf215546Sopenharmony_ci 1395bf215546Sopenharmony_ci /* Pad the indices out to the block size */ 1396bf215546Sopenharmony_ci if (src_height < BLOCK_SIZE) 1397bf215546Sopenharmony_ci write_bits(writer, 3 * BLOCK_SIZE * (BLOCK_SIZE - src_height), 0); 1398bf215546Sopenharmony_ci} 1399bf215546Sopenharmony_ci 1400bf215546Sopenharmony_cistatic void 1401bf215546Sopenharmony_cicompress_rgba_unorm_block(int src_width, int src_height, 1402bf215546Sopenharmony_ci const uint8_t *src, int src_rowstride, 1403bf215546Sopenharmony_ci uint8_t *dst) 1404bf215546Sopenharmony_ci{ 1405bf215546Sopenharmony_ci int average_luminance, average_alpha; 1406bf215546Sopenharmony_ci uint8_t endpoints[2][4]; 1407bf215546Sopenharmony_ci struct bit_writer writer; 1408bf215546Sopenharmony_ci int component, endpoint; 1409bf215546Sopenharmony_ci 1410bf215546Sopenharmony_ci get_average_luminance_alpha_unorm(src_width, src_height, src, src_rowstride, 1411bf215546Sopenharmony_ci &average_luminance, &average_alpha); 1412bf215546Sopenharmony_ci get_rgba_endpoints_unorm(src_width, src_height, src, src_rowstride, 1413bf215546Sopenharmony_ci average_luminance, average_alpha, 1414bf215546Sopenharmony_ci endpoints); 1415bf215546Sopenharmony_ci 1416bf215546Sopenharmony_ci writer.dst = dst; 1417bf215546Sopenharmony_ci writer.pos = 0; 1418bf215546Sopenharmony_ci writer.buf = 0; 1419bf215546Sopenharmony_ci 1420bf215546Sopenharmony_ci write_bits(&writer, 5, 0x10); /* mode 4 */ 1421bf215546Sopenharmony_ci write_bits(&writer, 2, 0); /* rotation 0 */ 1422bf215546Sopenharmony_ci write_bits(&writer, 1, 0); /* index selection bit */ 1423bf215546Sopenharmony_ci 1424bf215546Sopenharmony_ci /* Write the color endpoints */ 1425bf215546Sopenharmony_ci for (component = 0; component < 3; component++) 1426bf215546Sopenharmony_ci for (endpoint = 0; endpoint < 2; endpoint++) 1427bf215546Sopenharmony_ci write_bits(&writer, 5, endpoints[endpoint][component] >> 3); 1428bf215546Sopenharmony_ci 1429bf215546Sopenharmony_ci /* Write the alpha endpoints */ 1430bf215546Sopenharmony_ci for (endpoint = 0; endpoint < 2; endpoint++) 1431bf215546Sopenharmony_ci write_bits(&writer, 6, endpoints[endpoint][3] >> 2); 1432bf215546Sopenharmony_ci 1433bf215546Sopenharmony_ci write_rgb_indices_unorm(&writer, 1434bf215546Sopenharmony_ci src_width, src_height, 1435bf215546Sopenharmony_ci src, src_rowstride, 1436bf215546Sopenharmony_ci endpoints); 1437bf215546Sopenharmony_ci write_alpha_indices_unorm(&writer, 1438bf215546Sopenharmony_ci src_width, src_height, 1439bf215546Sopenharmony_ci src, src_rowstride, 1440bf215546Sopenharmony_ci endpoints); 1441bf215546Sopenharmony_ci} 1442bf215546Sopenharmony_ci 1443bf215546Sopenharmony_cistatic void 1444bf215546Sopenharmony_cicompress_rgba_unorm(int width, int height, 1445bf215546Sopenharmony_ci const uint8_t *src, int src_rowstride, 1446bf215546Sopenharmony_ci uint8_t *dst, int dst_rowstride) 1447bf215546Sopenharmony_ci{ 1448bf215546Sopenharmony_ci int dst_row_diff; 1449bf215546Sopenharmony_ci int y, x; 1450bf215546Sopenharmony_ci 1451bf215546Sopenharmony_ci if (dst_rowstride >= width * 4) 1452bf215546Sopenharmony_ci dst_row_diff = dst_rowstride - ((width + 3) & ~3) * 4; 1453bf215546Sopenharmony_ci else 1454bf215546Sopenharmony_ci dst_row_diff = 0; 1455bf215546Sopenharmony_ci 1456bf215546Sopenharmony_ci for (y = 0; y < height; y += BLOCK_SIZE) { 1457bf215546Sopenharmony_ci for (x = 0; x < width; x += BLOCK_SIZE) { 1458bf215546Sopenharmony_ci compress_rgba_unorm_block(MIN2(width - x, BLOCK_SIZE), 1459bf215546Sopenharmony_ci MIN2(height - y, BLOCK_SIZE), 1460bf215546Sopenharmony_ci src + x * 4 + y * src_rowstride, 1461bf215546Sopenharmony_ci src_rowstride, 1462bf215546Sopenharmony_ci dst); 1463bf215546Sopenharmony_ci dst += BLOCK_BYTES; 1464bf215546Sopenharmony_ci } 1465bf215546Sopenharmony_ci dst += dst_row_diff; 1466bf215546Sopenharmony_ci } 1467bf215546Sopenharmony_ci} 1468bf215546Sopenharmony_ci 1469bf215546Sopenharmony_cistatic float 1470bf215546Sopenharmony_ciget_average_luminance_float(int width, int height, 1471bf215546Sopenharmony_ci const float *src, int src_rowstride) 1472bf215546Sopenharmony_ci{ 1473bf215546Sopenharmony_ci float luminance_sum = 0; 1474bf215546Sopenharmony_ci int y, x; 1475bf215546Sopenharmony_ci 1476bf215546Sopenharmony_ci for (y = 0; y < height; y++) { 1477bf215546Sopenharmony_ci for (x = 0; x < width; x++) { 1478bf215546Sopenharmony_ci luminance_sum += src[0] + src[1] + src[2]; 1479bf215546Sopenharmony_ci src += 3; 1480bf215546Sopenharmony_ci } 1481bf215546Sopenharmony_ci src += (src_rowstride - width * 3 * sizeof (float)) / sizeof (float); 1482bf215546Sopenharmony_ci } 1483bf215546Sopenharmony_ci 1484bf215546Sopenharmony_ci return luminance_sum / (width * height); 1485bf215546Sopenharmony_ci} 1486bf215546Sopenharmony_ci 1487bf215546Sopenharmony_cistatic float 1488bf215546Sopenharmony_ciclamp_value(float value, bool is_signed) 1489bf215546Sopenharmony_ci{ 1490bf215546Sopenharmony_ci if (value > 65504.0f) 1491bf215546Sopenharmony_ci return 65504.0f; 1492bf215546Sopenharmony_ci 1493bf215546Sopenharmony_ci if (is_signed) { 1494bf215546Sopenharmony_ci if (value < -65504.0f) 1495bf215546Sopenharmony_ci return -65504.0f; 1496bf215546Sopenharmony_ci else 1497bf215546Sopenharmony_ci return value; 1498bf215546Sopenharmony_ci } 1499bf215546Sopenharmony_ci 1500bf215546Sopenharmony_ci if (value < 0.0f) 1501bf215546Sopenharmony_ci return 0.0f; 1502bf215546Sopenharmony_ci 1503bf215546Sopenharmony_ci return value; 1504bf215546Sopenharmony_ci} 1505bf215546Sopenharmony_ci 1506bf215546Sopenharmony_cistatic void 1507bf215546Sopenharmony_ciget_endpoints_float(int width, int height, 1508bf215546Sopenharmony_ci const float *src, int src_rowstride, 1509bf215546Sopenharmony_ci float average_luminance, float endpoints[][3], 1510bf215546Sopenharmony_ci bool is_signed) 1511bf215546Sopenharmony_ci{ 1512bf215546Sopenharmony_ci float endpoint_luminances[2]; 1513bf215546Sopenharmony_ci float midpoint; 1514bf215546Sopenharmony_ci float sums[2][3]; 1515bf215546Sopenharmony_ci int endpoint, component; 1516bf215546Sopenharmony_ci float luminance; 1517bf215546Sopenharmony_ci float temp[3]; 1518bf215546Sopenharmony_ci const float *p = src; 1519bf215546Sopenharmony_ci int left_endpoint_count = 0; 1520bf215546Sopenharmony_ci int y, x, i; 1521bf215546Sopenharmony_ci 1522bf215546Sopenharmony_ci memset(sums, 0, sizeof sums); 1523bf215546Sopenharmony_ci 1524bf215546Sopenharmony_ci for (y = 0; y < height; y++) { 1525bf215546Sopenharmony_ci for (x = 0; x < width; x++) { 1526bf215546Sopenharmony_ci luminance = p[0] + p[1] + p[2]; 1527bf215546Sopenharmony_ci if (luminance < average_luminance) { 1528bf215546Sopenharmony_ci endpoint = 0; 1529bf215546Sopenharmony_ci left_endpoint_count++; 1530bf215546Sopenharmony_ci } else { 1531bf215546Sopenharmony_ci endpoint = 1; 1532bf215546Sopenharmony_ci } 1533bf215546Sopenharmony_ci for (i = 0; i < 3; i++) 1534bf215546Sopenharmony_ci sums[endpoint][i] += p[i]; 1535bf215546Sopenharmony_ci 1536bf215546Sopenharmony_ci p += 3; 1537bf215546Sopenharmony_ci } 1538bf215546Sopenharmony_ci 1539bf215546Sopenharmony_ci p += (src_rowstride - width * 3 * sizeof (float)) / sizeof (float); 1540bf215546Sopenharmony_ci } 1541bf215546Sopenharmony_ci 1542bf215546Sopenharmony_ci if (left_endpoint_count == 0 || 1543bf215546Sopenharmony_ci left_endpoint_count == width * height) { 1544bf215546Sopenharmony_ci for (i = 0; i < 3; i++) 1545bf215546Sopenharmony_ci endpoints[0][i] = endpoints[1][i] = 1546bf215546Sopenharmony_ci (sums[0][i] + sums[1][i]) / (width * height); 1547bf215546Sopenharmony_ci } else { 1548bf215546Sopenharmony_ci for (i = 0; i < 3; i++) { 1549bf215546Sopenharmony_ci endpoints[0][i] = sums[0][i] / left_endpoint_count; 1550bf215546Sopenharmony_ci endpoints[1][i] = sums[1][i] / (width * height - left_endpoint_count); 1551bf215546Sopenharmony_ci } 1552bf215546Sopenharmony_ci } 1553bf215546Sopenharmony_ci 1554bf215546Sopenharmony_ci /* Clamp the endpoints to the range of a half float and strip out 1555bf215546Sopenharmony_ci * infinities */ 1556bf215546Sopenharmony_ci for (endpoint = 0; endpoint < 2; endpoint++) { 1557bf215546Sopenharmony_ci for (component = 0; component < 3; component++) { 1558bf215546Sopenharmony_ci endpoints[endpoint][component] = 1559bf215546Sopenharmony_ci clamp_value(endpoints[endpoint][component], is_signed); 1560bf215546Sopenharmony_ci } 1561bf215546Sopenharmony_ci } 1562bf215546Sopenharmony_ci 1563bf215546Sopenharmony_ci /* We may need to swap the endpoints to ensure the most-significant bit of 1564bf215546Sopenharmony_ci * the first index is zero */ 1565bf215546Sopenharmony_ci 1566bf215546Sopenharmony_ci for (endpoint = 0; endpoint < 2; endpoint++) { 1567bf215546Sopenharmony_ci endpoint_luminances[endpoint] = 1568bf215546Sopenharmony_ci endpoints[endpoint][0] + 1569bf215546Sopenharmony_ci endpoints[endpoint][1] + 1570bf215546Sopenharmony_ci endpoints[endpoint][2]; 1571bf215546Sopenharmony_ci } 1572bf215546Sopenharmony_ci midpoint = (endpoint_luminances[0] + endpoint_luminances[1]) / 2.0f; 1573bf215546Sopenharmony_ci 1574bf215546Sopenharmony_ci if ((src[0] + src[1] + src[2] <= midpoint) != 1575bf215546Sopenharmony_ci (endpoint_luminances[0] <= midpoint)) { 1576bf215546Sopenharmony_ci memcpy(temp, endpoints[0], sizeof temp); 1577bf215546Sopenharmony_ci memcpy(endpoints[0], endpoints[1], sizeof temp); 1578bf215546Sopenharmony_ci memcpy(endpoints[1], temp, sizeof temp); 1579bf215546Sopenharmony_ci } 1580bf215546Sopenharmony_ci} 1581bf215546Sopenharmony_ci 1582bf215546Sopenharmony_cistatic void 1583bf215546Sopenharmony_ciwrite_rgb_indices_float(struct bit_writer *writer, 1584bf215546Sopenharmony_ci int src_width, int src_height, 1585bf215546Sopenharmony_ci const float *src, int src_rowstride, 1586bf215546Sopenharmony_ci float endpoints[][3]) 1587bf215546Sopenharmony_ci{ 1588bf215546Sopenharmony_ci float luminance; 1589bf215546Sopenharmony_ci float endpoint_luminances[2]; 1590bf215546Sopenharmony_ci int endpoint; 1591bf215546Sopenharmony_ci int index; 1592bf215546Sopenharmony_ci int y, x; 1593bf215546Sopenharmony_ci 1594bf215546Sopenharmony_ci for (endpoint = 0; endpoint < 2; endpoint++) { 1595bf215546Sopenharmony_ci endpoint_luminances[endpoint] = 1596bf215546Sopenharmony_ci endpoints[endpoint][0] + 1597bf215546Sopenharmony_ci endpoints[endpoint][1] + 1598bf215546Sopenharmony_ci endpoints[endpoint][2]; 1599bf215546Sopenharmony_ci } 1600bf215546Sopenharmony_ci 1601bf215546Sopenharmony_ci /* If the endpoints have the same luminance then we'll just use index 0 for 1602bf215546Sopenharmony_ci * all of the texels */ 1603bf215546Sopenharmony_ci if (endpoint_luminances[0] == endpoint_luminances[1]) { 1604bf215546Sopenharmony_ci write_bits(writer, BLOCK_SIZE * BLOCK_SIZE * 4 - 1, 0); 1605bf215546Sopenharmony_ci return; 1606bf215546Sopenharmony_ci } 1607bf215546Sopenharmony_ci 1608bf215546Sopenharmony_ci for (y = 0; y < src_height; y++) { 1609bf215546Sopenharmony_ci for (x = 0; x < src_width; x++) { 1610bf215546Sopenharmony_ci luminance = src[0] + src[1] + src[2]; 1611bf215546Sopenharmony_ci 1612bf215546Sopenharmony_ci index = ((luminance - endpoint_luminances[0]) * 15 / 1613bf215546Sopenharmony_ci (endpoint_luminances[1] - endpoint_luminances[0])); 1614bf215546Sopenharmony_ci if (index < 0) 1615bf215546Sopenharmony_ci index = 0; 1616bf215546Sopenharmony_ci else if (index > 15) 1617bf215546Sopenharmony_ci index = 15; 1618bf215546Sopenharmony_ci 1619bf215546Sopenharmony_ci assert(x != 0 || y != 0 || index < 8); 1620bf215546Sopenharmony_ci 1621bf215546Sopenharmony_ci write_bits(writer, (x == 0 && y == 0) ? 3 : 4, index); 1622bf215546Sopenharmony_ci 1623bf215546Sopenharmony_ci src += 3; 1624bf215546Sopenharmony_ci } 1625bf215546Sopenharmony_ci 1626bf215546Sopenharmony_ci /* Pad the indices out to the block size */ 1627bf215546Sopenharmony_ci if (src_width < BLOCK_SIZE) 1628bf215546Sopenharmony_ci write_bits(writer, 4 * (BLOCK_SIZE - src_width), 0); 1629bf215546Sopenharmony_ci 1630bf215546Sopenharmony_ci src += (src_rowstride - src_width * 3 * sizeof (float)) / sizeof (float); 1631bf215546Sopenharmony_ci } 1632bf215546Sopenharmony_ci 1633bf215546Sopenharmony_ci /* Pad the indices out to the block size */ 1634bf215546Sopenharmony_ci if (src_height < BLOCK_SIZE) 1635bf215546Sopenharmony_ci write_bits(writer, 4 * BLOCK_SIZE * (BLOCK_SIZE - src_height), 0); 1636bf215546Sopenharmony_ci} 1637bf215546Sopenharmony_ci 1638bf215546Sopenharmony_cistatic int 1639bf215546Sopenharmony_ciget_endpoint_value(float value, bool is_signed) 1640bf215546Sopenharmony_ci{ 1641bf215546Sopenharmony_ci bool sign = false; 1642bf215546Sopenharmony_ci int half; 1643bf215546Sopenharmony_ci 1644bf215546Sopenharmony_ci if (is_signed) { 1645bf215546Sopenharmony_ci half = _mesa_float_to_half(value); 1646bf215546Sopenharmony_ci 1647bf215546Sopenharmony_ci if (half & 0x8000) { 1648bf215546Sopenharmony_ci half &= 0x7fff; 1649bf215546Sopenharmony_ci sign = true; 1650bf215546Sopenharmony_ci } 1651bf215546Sopenharmony_ci 1652bf215546Sopenharmony_ci half = (32 * half / 31) >> 6; 1653bf215546Sopenharmony_ci 1654bf215546Sopenharmony_ci if (sign) 1655bf215546Sopenharmony_ci half = -half & ((1 << 10) - 1); 1656bf215546Sopenharmony_ci 1657bf215546Sopenharmony_ci return half; 1658bf215546Sopenharmony_ci } else { 1659bf215546Sopenharmony_ci if (value <= 0.0f) 1660bf215546Sopenharmony_ci return 0; 1661bf215546Sopenharmony_ci 1662bf215546Sopenharmony_ci half = _mesa_float_to_half(value); 1663bf215546Sopenharmony_ci 1664bf215546Sopenharmony_ci return (64 * half / 31) >> 6; 1665bf215546Sopenharmony_ci } 1666bf215546Sopenharmony_ci} 1667bf215546Sopenharmony_ci 1668bf215546Sopenharmony_cistatic void 1669bf215546Sopenharmony_cicompress_rgb_float_block(int src_width, int src_height, 1670bf215546Sopenharmony_ci const float *src, int src_rowstride, 1671bf215546Sopenharmony_ci uint8_t *dst, 1672bf215546Sopenharmony_ci bool is_signed) 1673bf215546Sopenharmony_ci{ 1674bf215546Sopenharmony_ci float average_luminance; 1675bf215546Sopenharmony_ci float endpoints[2][3]; 1676bf215546Sopenharmony_ci struct bit_writer writer; 1677bf215546Sopenharmony_ci int component, endpoint; 1678bf215546Sopenharmony_ci int endpoint_value; 1679bf215546Sopenharmony_ci 1680bf215546Sopenharmony_ci average_luminance = 1681bf215546Sopenharmony_ci get_average_luminance_float(src_width, src_height, src, src_rowstride); 1682bf215546Sopenharmony_ci get_endpoints_float(src_width, src_height, src, src_rowstride, 1683bf215546Sopenharmony_ci average_luminance, endpoints, is_signed); 1684bf215546Sopenharmony_ci 1685bf215546Sopenharmony_ci writer.dst = dst; 1686bf215546Sopenharmony_ci writer.pos = 0; 1687bf215546Sopenharmony_ci writer.buf = 0; 1688bf215546Sopenharmony_ci 1689bf215546Sopenharmony_ci write_bits(&writer, 5, 3); /* mode 3 */ 1690bf215546Sopenharmony_ci 1691bf215546Sopenharmony_ci /* Write the endpoints */ 1692bf215546Sopenharmony_ci for (endpoint = 0; endpoint < 2; endpoint++) { 1693bf215546Sopenharmony_ci for (component = 0; component < 3; component++) { 1694bf215546Sopenharmony_ci endpoint_value = 1695bf215546Sopenharmony_ci get_endpoint_value(endpoints[endpoint][component], is_signed); 1696bf215546Sopenharmony_ci write_bits(&writer, 10, endpoint_value); 1697bf215546Sopenharmony_ci } 1698bf215546Sopenharmony_ci } 1699bf215546Sopenharmony_ci 1700bf215546Sopenharmony_ci write_rgb_indices_float(&writer, 1701bf215546Sopenharmony_ci src_width, src_height, 1702bf215546Sopenharmony_ci src, src_rowstride, 1703bf215546Sopenharmony_ci endpoints); 1704bf215546Sopenharmony_ci} 1705bf215546Sopenharmony_ci 1706bf215546Sopenharmony_cistatic void 1707bf215546Sopenharmony_cicompress_rgb_float(int width, int height, 1708bf215546Sopenharmony_ci const float *src, int src_rowstride, 1709bf215546Sopenharmony_ci uint8_t *dst, int dst_rowstride, 1710bf215546Sopenharmony_ci bool is_signed) 1711bf215546Sopenharmony_ci{ 1712bf215546Sopenharmony_ci int dst_row_diff; 1713bf215546Sopenharmony_ci int y, x; 1714bf215546Sopenharmony_ci 1715bf215546Sopenharmony_ci if (dst_rowstride >= width * 4) 1716bf215546Sopenharmony_ci dst_row_diff = dst_rowstride - ((width + 3) & ~3) * 4; 1717bf215546Sopenharmony_ci else 1718bf215546Sopenharmony_ci dst_row_diff = 0; 1719bf215546Sopenharmony_ci 1720bf215546Sopenharmony_ci for (y = 0; y < height; y += BLOCK_SIZE) { 1721bf215546Sopenharmony_ci for (x = 0; x < width; x += BLOCK_SIZE) { 1722bf215546Sopenharmony_ci compress_rgb_float_block(MIN2(width - x, BLOCK_SIZE), 1723bf215546Sopenharmony_ci MIN2(height - y, BLOCK_SIZE), 1724bf215546Sopenharmony_ci src + x * 3 + 1725bf215546Sopenharmony_ci y * src_rowstride / sizeof (float), 1726bf215546Sopenharmony_ci src_rowstride, 1727bf215546Sopenharmony_ci dst, 1728bf215546Sopenharmony_ci is_signed); 1729bf215546Sopenharmony_ci dst += BLOCK_BYTES; 1730bf215546Sopenharmony_ci } 1731bf215546Sopenharmony_ci dst += dst_row_diff; 1732bf215546Sopenharmony_ci } 1733bf215546Sopenharmony_ci} 1734bf215546Sopenharmony_ci 1735bf215546Sopenharmony_ci#endif 1736