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