1 // Copyright 2019 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "BC_Decoder.hpp"
16
17 #include "System/Debug.hpp"
18 #include "System/Math.hpp"
19
20 #include <algorithm>
21 #include <array>
22 #include <cstddef>
23 #include <vector>
24
25 #include <assert.h>
26 #include <stdint.h>
27
28 namespace {
29 static constexpr int BlockWidth = 4;
30 static constexpr int BlockHeight = 4;
31
32 struct BC_color
33 {
decode__anone5e484780111::BC_color34 void decode(uint8_t *dst, int x, int y, int dstW, int dstH, int dstPitch, int dstBpp, bool hasAlphaChannel, bool hasSeparateAlpha) const
35 {
36 Color c[4];
37 c[0].extract565(c0);
38 c[1].extract565(c1);
39 if(hasSeparateAlpha || (c0 > c1))
40 {
41 c[2] = ((c[0] * 2) + c[1]) / 3;
42 c[3] = ((c[1] * 2) + c[0]) / 3;
43 }
44 else
45 {
46 c[2] = (c[0] + c[1]) >> 1;
47 if(hasAlphaChannel)
48 {
49 c[3].clearAlpha();
50 }
51 }
52
53 for(int j = 0; j < BlockHeight && (y + j) < dstH; j++)
54 {
55 int dstOffset = j * dstPitch;
56 int idxOffset = j * BlockHeight;
57 for(int i = 0; i < BlockWidth && (x + i) < dstW; i++, idxOffset++, dstOffset += dstBpp)
58 {
59 *reinterpret_cast<unsigned int *>(dst + dstOffset) = c[getIdx(idxOffset)].pack8888();
60 }
61 }
62 }
63
64 private:
65 struct Color
66 {
Color__anone5e484780111::BC_color::Color67 Color()
68 {
69 c[0] = c[1] = c[2] = 0;
70 c[3] = 0xFF000000;
71 }
72
extract565__anone5e484780111::BC_color::Color73 void extract565(const unsigned int c565)
74 {
75 c[0] = ((c565 & 0x0000001F) << 3) | ((c565 & 0x0000001C) >> 2);
76 c[1] = ((c565 & 0x000007E0) >> 3) | ((c565 & 0x00000600) >> 9);
77 c[2] = ((c565 & 0x0000F800) >> 8) | ((c565 & 0x0000E000) >> 13);
78 }
79
pack8888__anone5e484780111::BC_color::Color80 unsigned int pack8888() const
81 {
82 return ((c[2] & 0xFF) << 16) | ((c[1] & 0xFF) << 8) | (c[0] & 0xFF) | c[3];
83 }
84
clearAlpha__anone5e484780111::BC_color::Color85 void clearAlpha()
86 {
87 c[3] = 0;
88 }
89
operator *__anone5e484780111::BC_color::Color90 Color operator*(int factor) const
91 {
92 Color res;
93 for(int i = 0; i < 4; ++i)
94 {
95 res.c[i] = c[i] * factor;
96 }
97 return res;
98 }
99
operator /__anone5e484780111::BC_color::Color100 Color operator/(int factor) const
101 {
102 Color res;
103 for(int i = 0; i < 4; ++i)
104 {
105 res.c[i] = c[i] / factor;
106 }
107 return res;
108 }
109
operator >>__anone5e484780111::BC_color::Color110 Color operator>>(int shift) const
111 {
112 Color res;
113 for(int i = 0; i < 4; ++i)
114 {
115 res.c[i] = c[i] >> shift;
116 }
117 return res;
118 }
119
operator +__anone5e484780111::BC_color::Color120 Color operator+(Color const &obj) const
121 {
122 Color res;
123 for(int i = 0; i < 4; ++i)
124 {
125 res.c[i] = c[i] + obj.c[i];
126 }
127 return res;
128 }
129
130 private:
131 int c[4];
132 };
133
getIdx__anone5e484780111::BC_color134 unsigned int getIdx(int i) const
135 {
136 int offset = i << 1; // 2 bytes per index
137 return (idx & (0x3 << offset)) >> offset;
138 }
139
140 unsigned short c0;
141 unsigned short c1;
142 unsigned int idx;
143 };
144
145 struct BC_channel
146 {
decode__anone5e484780111::BC_channel147 void decode(uint8_t *dst, int x, int y, int dstW, int dstH, int dstPitch, int dstBpp, int channel, bool isSigned) const
148 {
149 int c[8] = { 0 };
150
151 if(isSigned)
152 {
153 c[0] = static_cast<signed char>(data & 0xFF);
154 c[1] = static_cast<signed char>((data & 0xFF00) >> 8);
155 }
156 else
157 {
158 c[0] = static_cast<uint8_t>(data & 0xFF);
159 c[1] = static_cast<uint8_t>((data & 0xFF00) >> 8);
160 }
161
162 if(c[0] > c[1])
163 {
164 for(int i = 2; i < 8; ++i)
165 {
166 c[i] = ((8 - i) * c[0] + (i - 1) * c[1]) / 7;
167 }
168 }
169 else
170 {
171 for(int i = 2; i < 6; ++i)
172 {
173 c[i] = ((6 - i) * c[0] + (i - 1) * c[1]) / 5;
174 }
175 c[6] = isSigned ? -128 : 0;
176 c[7] = isSigned ? 127 : 255;
177 }
178
179 for(int j = 0; j < BlockHeight && (y + j) < dstH; j++)
180 {
181 for(int i = 0; i < BlockWidth && (x + i) < dstW; i++)
182 {
183 dst[channel + (i * dstBpp) + (j * dstPitch)] = static_cast<uint8_t>(c[getIdx((j * BlockHeight) + i)]);
184 }
185 }
186 }
187
188 private:
getIdx__anone5e484780111::BC_channel189 uint8_t getIdx(int i) const
190 {
191 int offset = i * 3 + 16;
192 return static_cast<uint8_t>((data & (0x7ull << offset)) >> offset);
193 }
194
195 uint64_t data;
196 };
197
198 struct BC_alpha
199 {
decode__anone5e484780111::BC_alpha200 void decode(uint8_t *dst, int x, int y, int dstW, int dstH, int dstPitch, int dstBpp) const
201 {
202 dst += 3; // Write only to alpha (channel 3)
203 for(int j = 0; j < BlockHeight && (y + j) < dstH; j++, dst += dstPitch)
204 {
205 uint8_t *dstRow = dst;
206 for(int i = 0; i < BlockWidth && (x + i) < dstW; i++, dstRow += dstBpp)
207 {
208 *dstRow = getAlpha(j * BlockHeight + i);
209 }
210 }
211 }
212
213 private:
getAlpha__anone5e484780111::BC_alpha214 uint8_t getAlpha(int i) const
215 {
216 int offset = i << 2;
217 int alpha = (data & (0xFull << offset)) >> offset;
218 return static_cast<uint8_t>(alpha | (alpha << 4));
219 }
220
221 uint64_t data;
222 };
223
224 namespace BC6H {
225
226 static constexpr int MaxPartitions = 64;
227
228 static constexpr uint8_t PartitionTable2[MaxPartitions][16] = {
229 { 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 },
230 { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 },
231 { 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
232 { 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1 },
233 { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1 },
234 { 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
235 { 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
236 { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1 },
237 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1 },
238 { 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
239 { 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
240 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1 },
241 { 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
242 { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 },
243 { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
244 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 },
245 { 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1 },
246 { 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
247 { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0 },
248 { 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0 },
249 { 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
250 { 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0 },
251 { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 },
252 { 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1 },
253 { 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0 },
254 { 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 },
255 { 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0 },
256 { 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0 },
257 { 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0 },
258 { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 },
259 { 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0 },
260 { 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0 },
261 { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 },
262 { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1 },
263 { 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0 },
264 { 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0 },
265 { 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0 },
266 { 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0 },
267 { 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1 },
268 { 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1 },
269 { 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0 },
270 { 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0 },
271 { 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0 },
272 { 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0 },
273 { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 },
274 { 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1 },
275 { 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1 },
276 { 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0 },
277 { 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 },
278 { 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0 },
279 { 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0 },
280 { 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0 },
281 { 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1 },
282 { 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1 },
283 { 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0 },
284 { 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0 },
285 { 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1 },
286 { 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1 },
287 { 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1 },
288 { 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1 },
289 { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 },
290 { 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 },
291 { 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0 },
292 { 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1 },
293 };
294
295 static constexpr uint8_t AnchorTable2[MaxPartitions] = {
296 // clang-format off
297 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
298 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
299 0xf, 0x2, 0x8, 0x2, 0x2, 0x8, 0x8, 0xf,
300 0x2, 0x8, 0x2, 0x2, 0x8, 0x8, 0x2, 0x2,
301 0xf, 0xf, 0x6, 0x8, 0x2, 0x8, 0xf, 0xf,
302 0x2, 0x8, 0x2, 0x2, 0x2, 0xf, 0xf, 0x6,
303 0x6, 0x2, 0x6, 0x8, 0xf, 0xf, 0x2, 0x2,
304 0xf, 0xf, 0xf, 0xf, 0xf, 0x2, 0x2, 0xf,
305 // clang-format on
306 };
307
308 // 1.0f in half-precision floating point format
309 static constexpr uint16_t halfFloat1 = 0x3C00;
310 union Color
311 {
312 struct RGBA
313 {
314 uint16_t r = 0;
315 uint16_t g = 0;
316 uint16_t b = 0;
317 uint16_t a = halfFloat1;
318
RGBA__anone5e484780111::BC6H::Color::RGBA319 RGBA(uint16_t r, uint16_t g, uint16_t b)
320 : r(r)
321 , g(g)
322 , b(b)
323 {
324 }
325
operator =__anone5e484780111::BC6H::Color::RGBA326 RGBA &operator=(const RGBA &other)
327 {
328 this->r = other.r;
329 this->g = other.g;
330 this->b = other.b;
331 this->a = halfFloat1;
332
333 return *this;
334 }
335 };
336
Color(uint16_t r,uint16_t g,uint16_t b)337 Color(uint16_t r, uint16_t g, uint16_t b)
338 : rgba(r, g, b)
339 {
340 }
341
Color(int r,int g,int b)342 Color(int r, int g, int b)
343 : rgba((uint16_t)r, (uint16_t)g, (uint16_t)b)
344 {
345 }
346
Color()347 Color()
348 {
349 }
350
Color(const Color & other)351 Color(const Color &other)
352 {
353 this->rgba = other.rgba;
354 }
355
operator =(const Color & other)356 Color &operator=(const Color &other)
357 {
358 this->rgba = other.rgba;
359
360 return *this;
361 }
362
363 RGBA rgba;
364 uint16_t channel[4];
365 };
366 static_assert(sizeof(Color) == 8, "BC6h::Color must be 8 bytes long");
367
extendSign(int32_t val,size_t size)368 inline int32_t extendSign(int32_t val, size_t size)
369 {
370 // Suppose we have a 2-bit integer being stored in 4 bit variable:
371 // x = 0b00AB
372 //
373 // In order to sign extend x, we need to turn the 0s into A's:
374 // x_extend = 0bAAAB
375 //
376 // We can do that by flipping A in x then subtracting 0b0010 from x.
377 // Suppose A is 1:
378 // x = 0b001B
379 // x_flip = 0b000B
380 // x_minus = 0b111B
381 // Since A is flipped to 0, subtracting the mask sets it and all the bits above it to 1.
382 // And if A is 0:
383 // x = 0b000B
384 // x_flip = 0b001B
385 // x_minus = 0b000B
386 // We unset the bit we flipped, and touch no other bit
387 uint16_t mask = 1u << (size - 1);
388 return (val ^ mask) - mask;
389 }
390
391 static int constexpr RGBfChannels = 3;
392 struct RGBf
393 {
394 uint16_t channel[RGBfChannels];
395 size_t size[RGBfChannels];
396 bool isSigned;
397
RGBf__anone5e484780111::BC6H::RGBf398 RGBf()
399 {
400 static_assert(RGBfChannels == 3, "RGBf must have exactly 3 channels");
401 static_assert(sizeof(channel) / sizeof(channel[0]) == RGBfChannels, "RGBf must have exactly 3 channels");
402 static_assert(sizeof(channel) / sizeof(channel[0]) == sizeof(size) / sizeof(size[0]), "RGBf requires equally sized arrays for channels and channel sizes");
403
404 for(int i = 0; i < RGBfChannels; i++)
405 {
406 channel[i] = 0;
407 size[i] = 0;
408 }
409
410 isSigned = false;
411 }
412
extendSign__anone5e484780111::BC6H::RGBf413 void extendSign()
414 {
415 for(int i = 0; i < RGBfChannels; i++)
416 {
417 channel[i] = BC6H::extendSign(channel[i], size[i]);
418 }
419 }
420
421 // Assuming this is the delta, take the base-endpoint and transform this into
422 // a proper endpoint.
423 //
424 // The final computed endpoint is truncated to the base-endpoint's size;
resolveDelta__anone5e484780111::BC6H::RGBf425 void resolveDelta(RGBf base)
426 {
427 for(int i = 0; i < RGBfChannels; i++)
428 {
429 size[i] = base.size[i];
430 channel[i] = (base.channel[i] + channel[i]) & ((1 << base.size[i]) - 1);
431 }
432
433 // Per the spec:
434 // "For signed formats, the results of the delta calculation must be sign
435 // extended as well."
436 if(isSigned)
437 {
438 extendSign();
439 }
440 }
441
unquantize__anone5e484780111::BC6H::RGBf442 void unquantize()
443 {
444 if(isSigned)
445 {
446 unquantizeSigned();
447 }
448 else
449 {
450 unquantizeUnsigned();
451 }
452 }
453
unquantizeUnsigned__anone5e484780111::BC6H::RGBf454 void unquantizeUnsigned()
455 {
456 for(int i = 0; i < RGBfChannels; i++)
457 {
458 if(size[i] >= 15 || channel[i] == 0)
459 {
460 continue;
461 }
462 else if(channel[i] == ((1u << size[i]) - 1))
463 {
464 channel[i] = 0xFFFFu;
465 }
466 else
467 {
468 // Need 32 bits to avoid overflow
469 uint32_t tmp = channel[i];
470 channel[i] = (uint16_t)(((tmp << 16) + 0x8000) >> size[i]);
471 }
472 size[i] = 16;
473 }
474 }
475
unquantizeSigned__anone5e484780111::BC6H::RGBf476 void unquantizeSigned()
477 {
478 for(int i = 0; i < RGBfChannels; i++)
479 {
480 if(size[i] >= 16 || channel[i] == 0)
481 {
482 continue;
483 }
484
485 int16_t value = sw::bit_cast<int16_t>(channel[i]);
486 int32_t result = value;
487 bool signBit = value < 0;
488 if(signBit)
489 {
490 value = -value;
491 }
492
493 if(value >= ((1 << (size[i] - 1)) - 1))
494 {
495 result = 0x7FFF;
496 }
497 else
498 {
499 // Need 32 bits to avoid overflow
500 int32_t tmp = value;
501 result = (((tmp << 15) + 0x4000) >> (size[i] - 1));
502 }
503
504 if(signBit)
505 {
506 result = -result;
507 }
508
509 channel[i] = (uint16_t)result;
510 size[i] = 16;
511 }
512 }
513 };
514
515 struct Data
516 {
517 uint64_t low64;
518 uint64_t high64;
519
520 Data() = default;
Data__anone5e484780111::BC6H::Data521 Data(uint64_t low64, uint64_t high64)
522 : low64(low64)
523 , high64(high64)
524 {
525 }
526
527 // Consumes the lowest N bits from from low64 and high64 where N is:
528 // abs(MSB - LSB)
529 // MSB and LSB come from the block description of the BC6h spec and specify
530 // the location of the bits in the returned bitstring.
531 //
532 // If MSB < LSB, then the bits are reversed. Otherwise, the bitstring is read and
533 // shifted without further modification.
534 //
consumeBits__anone5e484780111::BC6H::Data535 uint32_t consumeBits(uint32_t MSB, uint32_t LSB)
536 {
537 bool reversed = MSB < LSB;
538 if(reversed)
539 {
540 std::swap(MSB, LSB);
541 }
542 ASSERT(MSB - LSB + 1 < sizeof(uint32_t) * 8);
543
544 uint32_t numBits = MSB - LSB + 1;
545 uint32_t mask = (1 << numBits) - 1;
546 // Read the low N bits
547 uint32_t bits = (low64 & mask);
548
549 low64 >>= numBits;
550 // Put the low N bits of high64 into the high 64-N bits of low64
551 low64 |= (high64 & mask) << (sizeof(high64) * 8 - numBits);
552 high64 >>= numBits;
553
554 if(reversed)
555 {
556 uint32_t tmp = 0;
557 for(uint32_t numSwaps = 0; numSwaps < numBits; numSwaps++)
558 {
559 tmp <<= 1;
560 tmp |= (bits & 1);
561 bits >>= 1;
562 }
563
564 bits = tmp;
565 }
566
567 return bits << LSB;
568 }
569 };
570
571 struct IndexInfo
572 {
573 uint64_t value;
574 int numBits;
575 };
576
577 // Interpolates between two endpoints, then does a final unquantization step
interpolate(RGBf e0,RGBf e1,const IndexInfo & index,bool isSigned)578 Color interpolate(RGBf e0, RGBf e1, const IndexInfo &index, bool isSigned)
579 {
580 static constexpr uint32_t weights3[] = { 0, 9, 18, 27, 37, 46, 55, 64 };
581 static constexpr uint32_t weights4[] = { 0, 4, 9, 13, 17, 21, 26, 30,
582 34, 38, 43, 47, 51, 55, 60, 64 };
583 static constexpr uint32_t const *weightsN[] = {
584 nullptr, nullptr, nullptr, weights3, weights4
585 };
586 auto weights = weightsN[index.numBits];
587 ASSERT_MSG(weights != nullptr, "Unexpected number of index bits: %d", (int)index.numBits);
588 Color color;
589 uint32_t e0Weight = 64 - weights[index.value];
590 uint32_t e1Weight = weights[index.value];
591
592 for(int i = 0; i < RGBfChannels; i++)
593 {
594 int32_t e0Channel = e0.channel[i];
595 int32_t e1Channel = e1.channel[i];
596
597 if(isSigned)
598 {
599 e0Channel = extendSign(e0Channel, 16);
600 e1Channel = extendSign(e1Channel, 16);
601 }
602
603 int32_t e0Value = e0Channel * e0Weight;
604 int32_t e1Value = e1Channel * e1Weight;
605
606 uint32_t tmp = ((e0Value + e1Value + 32) >> 6);
607
608 // Need to unquantize value to limit it to the legal range of half-precision
609 // floats. We do this by scaling by 31/32 or 31/64 depending on if the value
610 // is signed or unsigned.
611 if(isSigned)
612 {
613 tmp = ((tmp & 0x80000000) != 0) ? (((~tmp + 1) * 31) >> 5) | 0x8000 : (tmp * 31) >> 5;
614 // Don't return -0.0f, just normalize it to 0.0f.
615 if(tmp == 0x8000)
616 tmp = 0;
617 }
618 else
619 {
620 tmp = (tmp * 31) >> 6;
621 }
622
623 color.channel[i] = (uint16_t)tmp;
624 }
625
626 return color;
627 }
628
629 enum DataType
630 {
631 // Endpoints
632 EP0 = 0,
633 EP1 = 1,
634 EP2 = 2,
635 EP3 = 3,
636 Mode,
637 Partition,
638 End,
639 };
640
641 enum Channel
642 {
643 R = 0,
644 G = 1,
645 B = 2,
646 None,
647 };
648
649 struct DeltaBits
650 {
651 size_t channel[3];
652
DeltaBits__anone5e484780111::BC6H::DeltaBits653 constexpr DeltaBits()
654 : channel{ 0, 0, 0 }
655 {
656 }
657
DeltaBits__anone5e484780111::BC6H::DeltaBits658 constexpr DeltaBits(size_t r, size_t g, size_t b)
659 : channel{ r, g, b }
660 {
661 }
662 };
663
664 struct ModeDesc
665 {
666 int number;
667 bool hasDelta;
668 int partitionCount;
669 int endpointBits;
670 DeltaBits deltaBits;
671
ModeDesc__anone5e484780111::BC6H::ModeDesc672 constexpr ModeDesc()
673 : number(-1)
674 , hasDelta(false)
675 , partitionCount(0)
676 , endpointBits(0)
677 {
678 }
679
ModeDesc__anone5e484780111::BC6H::ModeDesc680 constexpr ModeDesc(int number, bool hasDelta, int partitionCount, int endpointBits, DeltaBits deltaBits)
681 : number(number)
682 , hasDelta(hasDelta)
683 , partitionCount(partitionCount)
684 , endpointBits(endpointBits)
685 , deltaBits(deltaBits)
686 {
687 }
688 };
689
690 struct BlockDesc
691 {
692 DataType type;
693 Channel channel;
694 int MSB;
695 int LSB;
696 ModeDesc modeDesc;
697
BlockDesc__anone5e484780111::BC6H::BlockDesc698 constexpr BlockDesc()
699 : type(End)
700 , channel(None)
701 , MSB(0)
702 , LSB(0)
703 , modeDesc()
704 {
705 }
706
BlockDesc__anone5e484780111::BC6H::BlockDesc707 constexpr BlockDesc(const DataType type, Channel channel, int MSB, int LSB, ModeDesc modeDesc)
708 : type(type)
709 , channel(channel)
710 , MSB(MSB)
711 , LSB(LSB)
712 , modeDesc(modeDesc)
713 {
714 }
715
BlockDesc__anone5e484780111::BC6H::BlockDesc716 constexpr BlockDesc(DataType type, Channel channel, int MSB, int LSB)
717 : type(type)
718 , channel(channel)
719 , MSB(MSB)
720 , LSB(LSB)
721 , modeDesc()
722 {
723 }
724 };
725
726 // Turns a legal mode into an index into the BlockDesc table.
727 // Illegal or reserved modes return -1.
modeToIndex(uint8_t mode)728 static int modeToIndex(uint8_t mode)
729 {
730 if(mode <= 3)
731 {
732 return mode;
733 }
734 else if((mode & 0x2) != 0)
735 {
736 if(mode <= 18)
737 {
738 // Turns 6 into 4, 7 into 5, 10 into 6, etc.
739 return (mode / 2) + 1 + (mode & 0x1);
740 }
741 else if(mode == 22 || mode == 26 || mode == 30)
742 {
743 // Turns 22 into 11, 26 into 12, etc.
744 return mode / 4 + 6;
745 }
746 }
747
748 return -1;
749 }
750
751 // Returns a description of the bitfields for each mode from the LSB
752 // to the MSB before the index data starts.
753 //
754 // The numbers come from the BC6h block description. Each BlockDesc in the
755 // {Type, Channel, MSB, LSB}
756 // * Type describes which endpoint this is, or if this is a mode, a partition
757 // number, or the end of the block description.
758 // * Channel describes one of the 3 color channels within an endpoint
759 // * MSB and LSB specificy:
760 // * The size of the bitfield being read
761 // * The position of the bitfield within the variable it is being read to
762 // * If the bitfield is stored in reverse bit order
763 // If MSB < LSB then the bitfield is stored in reverse order. The size of
764 // the bitfield is abs(MSB-LSB+1). And the position of the bitfield within
765 // the variable is min(LSB, MSB).
766 //
767 // Invalid or reserved modes return an empty list.
768 static constexpr int NumBlocks = 14;
769 // The largest number of descriptions within a block.
770 static constexpr int MaxBlockDescIndex = 26;
771 static constexpr BlockDesc blockDescs[NumBlocks][MaxBlockDescIndex] = {
772 // clang-format off
773 // Mode 0, Index 0
774 {
775 { Mode, None, 1, 0, { 0, true, 2, 10, { 5, 5, 5 } } },
776 { EP2, G, 4, 4 }, { EP2, B, 4, 4 }, { EP3, B, 4, 4 },
777 { EP0, R, 9, 0 }, { EP0, G, 9, 0 }, { EP0, B, 9, 0 },
778 { EP1, R, 4, 0 }, { EP3, G, 4, 4 }, { EP2, G, 3, 0 },
779 { EP1, G, 4, 0 }, { EP3, B, 0, 0 }, { EP3, G, 3, 0 },
780 { EP1, B, 4, 0 }, { EP3, B, 1, 1 }, { EP2, B, 3, 0 },
781 { EP2, R, 4, 0 }, { EP3, B, 2, 2 }, { EP3, R, 4, 0 },
782 { EP3, B, 3, 3 },
783 { Partition, None, 4, 0 },
784 { End, None, 0, 0},
785 },
786 // Mode 1, Index 1
787 {
788 { Mode, None, 1, 0, { 1, true, 2, 7, { 6, 6, 6 } } },
789 { EP2, G, 5, 5 }, { EP3, G, 5, 4 }, { EP0, R, 6, 0 },
790 { EP3, B, 1, 0 }, { EP2, B, 4, 4 }, { EP0, G, 6, 0 },
791 { EP2, B, 5, 5 }, { EP3, B, 2, 2 }, { EP2, G, 4, 4 },
792 { EP0, B, 6, 0 }, { EP3, B, 3, 3 }, { EP3, B, 5, 5 },
793 { EP3, B, 4, 4 }, { EP1, R, 5, 0 }, { EP2, G, 3, 0 },
794 { EP1, G, 5, 0 }, { EP3, G, 3, 0 }, { EP1, B, 5, 0 },
795 { EP2, B, 3, 0 }, { EP2, R, 5, 0 }, { EP3, R, 5, 0 },
796 { Partition, None, 4, 0 },
797 { End, None, 0, 0},
798 },
799 // Mode 2, Index 2
800 {
801 { Mode, None, 4, 0, { 2, true, 2, 11, { 5, 4, 4 } } },
802 { EP0, R, 9, 0 }, { EP0, G, 9, 0 }, { EP0, B, 9, 0 },
803 { EP1, R, 4, 0 }, { EP0, R, 10, 10 }, { EP2, G, 3, 0 },
804 { EP1, G, 3, 0 }, { EP0, G, 10, 10 }, { EP3, B, 0, 0 },
805 { EP3, G, 3, 0 }, { EP1, B, 3, 0 }, { EP0, B, 10, 10 },
806 { EP3, B, 1, 1 }, { EP2, B, 3, 0 }, { EP2, R, 4, 0 },
807 { EP3, B, 2, 2 }, { EP3, R, 4, 0 }, { EP3, B, 3, 3 },
808 { Partition, None, 4, 0 },
809 { End, None, 0, 0},
810 },
811 // Mode 3, Index 3
812 {
813 { Mode, None, 4, 0, { 3, false, 1, 10, { 0, 0, 0 } } },
814 { EP0, R, 9, 0 }, { EP0, G, 9, 0 }, { EP0, B, 9, 0 },
815 { EP1, R, 9, 0 }, { EP1, G, 9, 0 }, { EP1, B, 9, 0 },
816 { End, None, 0, 0},
817 },
818 // Mode 6, Index 4
819 {
820 { Mode, None, 4, 0, { 6, true, 2, 11, { 4, 5, 4 } } }, // 1 1
821 { EP0, R, 9, 0 }, { EP0, G, 9, 0 }, { EP0, B, 9, 0 },
822 { EP1, R, 3, 0 }, { EP0, R, 10, 10 }, { EP3, G, 4, 4 },
823 { EP2, G, 3, 0 }, { EP1, G, 4, 0 }, { EP0, G, 10, 10 },
824 { EP3, G, 3, 0 }, { EP1, B, 3, 0 }, { EP0, B, 10, 10 },
825 { EP3, B, 1, 1 }, { EP2, B, 3, 0 }, { EP2, R, 3, 0 },
826 { EP3, B, 0, 0 }, { EP3, B, 2, 2 }, { EP3, R, 3, 0 }, // 18 19
827 { EP2, G, 4, 4 }, { EP3, B, 3, 3 }, // 2 21
828 { Partition, None, 4, 0 },
829 { End, None, 0, 0},
830 },
831 // Mode 7, Index 5
832 {
833 { Mode, None, 4, 0, { 7, true, 1, 11, { 9, 9, 9 } } },
834 { EP0, R, 9, 0 }, { EP0, G, 9, 0 }, { EP0, B, 9, 0 },
835 { EP1, R, 8, 0 }, { EP0, R, 10, 10 }, { EP1, G, 8, 0 },
836 { EP0, G, 10, 10 }, { EP1, B, 8, 0 }, { EP0, B, 10, 10 },
837 { End, None, 0, 0},
838 },
839 // Mode 10, Index 6
840 {
841 { Mode, None, 4, 0, { 10, true, 2, 11, { 4, 4, 5 } } },
842 { EP0, R, 9, 0 }, { EP0, G, 9, 0 }, { EP0, B, 9, 0 },
843 { EP1, R, 3, 0 }, { EP0, R, 10, 10 }, { EP2, B, 4, 4 },
844 { EP2, G, 3, 0 }, { EP1, G, 3, 0 }, { EP0, G, 10, 10 },
845 { EP3, B, 0, 0 }, { EP3, G, 3, 0 }, { EP1, B, 4, 0 },
846 { EP0, B, 10, 10 }, { EP2, B, 3, 0 }, { EP2, R, 3, 0 },
847 { EP3, B, 1, 1 }, { EP3, B, 2, 2 }, { EP3, R, 3, 0 },
848 { EP3, B, 4, 4 }, { EP3, B, 3, 3 },
849 { Partition, None, 4, 0 },
850 { End, None, 0, 0},
851 },
852 // Mode 11, Index 7
853 {
854 { Mode, None, 4, 0, { 11, true, 1, 12, { 8, 8, 8 } } },
855 { EP0, R, 9, 0 }, { EP0, G, 9, 0 }, { EP0, B, 9, 0 },
856 { EP1, R, 7, 0 }, { EP0, R, 10, 11 }, { EP1, G, 7, 0 },
857 { EP0, G, 10, 11 }, { EP1, B, 7, 0 }, { EP0, B, 10, 11 },
858 { End, None, 0, 0},
859 },
860 // Mode 14, Index 8
861 {
862 { Mode, None, 4, 0, { 14, true, 2, 9, { 5, 5, 5 } } },
863 { EP0, R, 8, 0 }, { EP2, B, 4, 4 }, { EP0, G, 8, 0 },
864 { EP2, G, 4, 4 }, { EP0, B, 8, 0 }, { EP3, B, 4, 4 },
865 { EP1, R, 4, 0 }, { EP3, G, 4, 4 }, { EP2, G, 3, 0 },
866 { EP1, G, 4, 0 }, { EP3, B, 0, 0 }, { EP3, G, 3, 0 },
867 { EP1, B, 4, 0 }, { EP3, B, 1, 1 }, { EP2, B, 3, 0 },
868 { EP2, R, 4, 0 }, { EP3, B, 2, 2 }, { EP3, R, 4, 0 },
869 { EP3, B, 3, 3 },
870 { Partition, None, 4, 0 },
871 { End, None, 0, 0},
872 },
873 // Mode 15, Index 9
874 {
875 { Mode, None, 4, 0, { 15, true, 1, 16, { 4, 4, 4 } } },
876 { EP0, R, 9, 0 }, { EP0, G, 9, 0 }, { EP0, B, 9, 0 },
877 { EP1, R, 3, 0 }, { EP0, R, 10, 15 }, { EP1, G, 3, 0 },
878 { EP0, G, 10, 15 }, { EP1, B, 3, 0 }, { EP0, B, 10, 15 },
879 { End, None, 0, 0},
880 },
881 // Mode 18, Index 10
882 {
883 { Mode, None, 4, 0, { 18, true, 2, 8, { 6, 5, 5 } } },
884 { EP0, R, 7, 0 }, { EP3, G, 4, 4 }, { EP2, B, 4, 4 },
885 { EP0, G, 7, 0 }, { EP3, B, 2, 2 }, { EP2, G, 4, 4 },
886 { EP0, B, 7, 0 }, { EP3, B, 3, 3 }, { EP3, B, 4, 4 },
887 { EP1, R, 5, 0 }, { EP2, G, 3, 0 }, { EP1, G, 4, 0 },
888 { EP3, B, 0, 0 }, { EP3, G, 3, 0 }, { EP1, B, 4, 0 },
889 { EP3, B, 1, 1 }, { EP2, B, 3, 0 }, { EP2, R, 5, 0 },
890 { EP3, R, 5, 0 },
891 { Partition, None, 4, 0 },
892 { End, None, 0, 0},
893 },
894 // Mode 22, Index 11
895 {
896 { Mode, None, 4, 0, { 22, true, 2, 8, { 5, 6, 5 } } },
897 { EP0, R, 7, 0 }, { EP3, B, 0, 0 }, { EP2, B, 4, 4 },
898 { EP0, G, 7, 0 }, { EP2, G, 5, 5 }, { EP2, G, 4, 4 },
899 { EP0, B, 7, 0 }, { EP3, G, 5, 5 }, { EP3, B, 4, 4 },
900 { EP1, R, 4, 0 }, { EP3, G, 4, 4 }, { EP2, G, 3, 0 },
901 { EP1, G, 5, 0 }, { EP3, G, 3, 0 }, { EP1, B, 4, 0 },
902 { EP3, B, 1, 1 }, { EP2, B, 3, 0 }, { EP2, R, 4, 0 },
903 { EP3, B, 2, 2 }, { EP3, R, 4, 0 }, { EP3, B, 3, 3 },
904 { Partition, None, 4, 0 },
905 { End, None, 0, 0},
906 },
907 // Mode 26, Index 12
908 {
909 { Mode, None, 4, 0, { 26, true, 2, 8, { 5, 5, 6 } } },
910 { EP0, R, 7, 0 }, { EP3, B, 1, 1 }, { EP2, B, 4, 4 },
911 { EP0, G, 7, 0 }, { EP2, B, 5, 5 }, { EP2, G, 4, 4 },
912 { EP0, B, 7, 0 }, { EP3, B, 5, 5 }, { EP3, B, 4, 4 },
913 { EP1, R, 4, 0 }, { EP3, G, 4, 4 }, { EP2, G, 3, 0 },
914 { EP1, G, 4, 0 }, { EP3, B, 0, 0 }, { EP3, G, 3, 0 },
915 { EP1, B, 5, 0 }, { EP2, B, 3, 0 }, { EP2, R, 4, 0 },
916 { EP3, B, 2, 2 }, { EP3, R, 4, 0 }, { EP3, B, 3, 3 },
917 { Partition, None, 4, 0 },
918 { End, None, 0, 0},
919 },
920 // Mode 30, Index 13
921 {
922 { Mode, None, 4, 0, { 30, false, 2, 6, { 0, 0, 0 } } },
923 { EP0, R, 5, 0 }, { EP3, G, 4, 4 }, { EP3, B, 0, 0 },
924 { EP3, B, 1, 1 }, { EP2, B, 4, 4 }, { EP0, G, 5, 0 },
925 { EP2, G, 5, 5 }, { EP2, B, 5, 5 }, { EP3, B, 2, 2 },
926 { EP2, G, 4, 4 }, { EP0, B, 5, 0 }, { EP3, G, 5, 5 },
927 { EP3, B, 3, 3 }, { EP3, B, 5, 5 }, { EP3, B, 4, 4 },
928 { EP1, R, 5, 0 }, { EP2, G, 3, 0 }, { EP1, G, 5, 0 },
929 { EP3, G, 3, 0 }, { EP1, B, 5, 0 }, { EP2, B, 3, 0 },
930 { EP2, R, 5, 0 }, { EP3, R, 5, 0 },
931 { Partition, None, 4, 0 },
932 { End, None, 0, 0},
933 }
934 // clang-format on
935 };
936
937 struct Block
938 {
939 uint64_t low64;
940 uint64_t high64;
941
decode__anone5e484780111::BC6H::Block942 void decode(uint8_t *dst, int dstX, int dstY, int dstWidth, int dstHeight, size_t dstPitch, size_t dstBpp, bool isSigned) const
943 {
944 uint8_t mode = 0;
945 Data data(low64, high64);
946 ASSERT(dstBpp == sizeof(Color));
947
948 if((data.low64 & 0x2) == 0)
949 {
950 mode = data.consumeBits(1, 0);
951 }
952 else
953 {
954 mode = data.consumeBits(4, 0);
955 }
956
957 int blockIndex = modeToIndex(mode);
958 // Handle illegal or reserved mode
959 if(blockIndex == -1)
960 {
961 for(int y = 0; y < 4 && y + dstY < dstHeight; y++)
962 {
963 for(int x = 0; x < 4 && x + dstX < dstWidth; x++)
964 {
965 auto out = reinterpret_cast<Color *>(dst + sizeof(Color) * x + dstPitch * y);
966 out->rgba = { 0, 0, 0 };
967 }
968 }
969 return;
970 }
971 const BlockDesc *blockDesc = blockDescs[blockIndex];
972
973 RGBf e[4];
974 e[0].isSigned = e[1].isSigned = e[2].isSigned = e[3].isSigned = isSigned;
975
976 int partition = 0;
977 ModeDesc modeDesc;
978 for(int index = 0; blockDesc[index].type != End; index++)
979 {
980 const BlockDesc desc = blockDesc[index];
981
982 switch(desc.type)
983 {
984 case Mode:
985 modeDesc = desc.modeDesc;
986 ASSERT(modeDesc.number == mode);
987
988 e[0].size[0] = e[0].size[1] = e[0].size[2] = modeDesc.endpointBits;
989 for(int i = 0; i < RGBfChannels; i++)
990 {
991 if(modeDesc.hasDelta)
992 {
993 e[1].size[i] = e[2].size[i] = e[3].size[i] = modeDesc.deltaBits.channel[i];
994 }
995 else
996 {
997 e[1].size[i] = e[2].size[i] = e[3].size[i] = modeDesc.endpointBits;
998 }
999 }
1000 break;
1001 case Partition:
1002 partition |= data.consumeBits(desc.MSB, desc.LSB);
1003 break;
1004 case EP0:
1005 case EP1:
1006 case EP2:
1007 case EP3:
1008 e[desc.type].channel[desc.channel] |= data.consumeBits(desc.MSB, desc.LSB);
1009 break;
1010 default:
1011 ASSERT_MSG(false, "Unexpected enum value: %d", (int)desc.type);
1012 return;
1013 }
1014 }
1015
1016 // Sign extension
1017 if(isSigned)
1018 {
1019 for(int ep = 0; ep < modeDesc.partitionCount * 2; ep++)
1020 {
1021 e[ep].extendSign();
1022 }
1023 }
1024 else if(modeDesc.hasDelta)
1025 {
1026 // Don't sign-extend the base endpoint in an unsigned format.
1027 for(int ep = 1; ep < modeDesc.partitionCount * 2; ep++)
1028 {
1029 e[ep].extendSign();
1030 }
1031 }
1032
1033 // Turn the deltas into endpoints
1034 if(modeDesc.hasDelta)
1035 {
1036 for(int ep = 1; ep < modeDesc.partitionCount * 2; ep++)
1037 {
1038 e[ep].resolveDelta(e[0]);
1039 }
1040 }
1041
1042 for(int ep = 0; ep < modeDesc.partitionCount * 2; ep++)
1043 {
1044 e[ep].unquantize();
1045 }
1046
1047 // Get the indices, calculate final colors, and output
1048 for(int y = 0; y < 4; y++)
1049 {
1050 for(int x = 0; x < 4; x++)
1051 {
1052 int pixelNum = x + y * 4;
1053 IndexInfo idx;
1054 bool isAnchor = false;
1055 int firstEndpoint = 0;
1056 // Bc6H can have either 1 or 2 petitions depending on the mode.
1057 // The number of petitions affects the number of indices with implicit
1058 // leading 0 bits and the number of bits per index.
1059 if(modeDesc.partitionCount == 1)
1060 {
1061 idx.numBits = 4;
1062 // There's an implicit leading 0 bit for the first idx
1063 isAnchor = (pixelNum == 0);
1064 }
1065 else
1066 {
1067 idx.numBits = 3;
1068 // There are 2 indices with implicit leading 0-bits.
1069 isAnchor = ((pixelNum == 0) || (pixelNum == AnchorTable2[partition]));
1070 firstEndpoint = PartitionTable2[partition][pixelNum] * 2;
1071 }
1072
1073 idx.value = data.consumeBits(idx.numBits - isAnchor - 1, 0);
1074
1075 // Don't exit the loop early, we need to consume these index bits regardless if
1076 // we actually output them or not.
1077 if((y + dstY >= dstHeight) || (x + dstX >= dstWidth))
1078 {
1079 continue;
1080 }
1081
1082 Color color = interpolate(e[firstEndpoint], e[firstEndpoint + 1], idx, isSigned);
1083 auto out = reinterpret_cast<Color *>(dst + dstBpp * x + dstPitch * y);
1084 *out = color;
1085 }
1086 }
1087 }
1088 };
1089
1090 } // namespace BC6H
1091
1092 namespace BC7 {
1093 // https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_compression_bptc.txt
1094 // https://docs.microsoft.com/en-us/windows/win32/direct3d11/bc7-format
1095
1096 struct Bitfield
1097 {
1098 int offset;
1099 int count;
Then__anone5e484780111::BC7::Bitfield1100 constexpr Bitfield Then(const int bits) { return { offset + count, bits }; }
operator ==__anone5e484780111::BC7::Bitfield1101 constexpr bool operator==(const Bitfield &rhs)
1102 {
1103 return offset == rhs.offset && count == rhs.count;
1104 }
1105 };
1106
1107 struct Mode
1108 {
1109 const int IDX; // Mode index
1110 const int NS; // Number of subsets in each partition
1111 const int PB; // Partition bits
1112 const int RB; // Rotation bits
1113 const int ISB; // Index selection bits
1114 const int CB; // Color bits
1115 const int AB; // Alpha bits
1116 const int EPB; // Endpoint P-bits
1117 const int SPB; // Shared P-bits
1118 const int IB; // Primary index bits per element
1119 const int IBC; // Primary index bits total
1120 const int IB2; // Secondary index bits per element
1121
NumColors__anone5e484780111::BC7::Mode1122 constexpr int NumColors() const { return NS * 2; }
Partition__anone5e484780111::BC7::Mode1123 constexpr Bitfield Partition() const { return { IDX + 1, PB }; }
Rotation__anone5e484780111::BC7::Mode1124 constexpr Bitfield Rotation() const { return Partition().Then(RB); }
IndexSelection__anone5e484780111::BC7::Mode1125 constexpr Bitfield IndexSelection() const { return Rotation().Then(ISB); }
Red__anone5e484780111::BC7::Mode1126 constexpr Bitfield Red(int idx) const
1127 {
1128 return IndexSelection().Then(CB * idx).Then(CB);
1129 }
Green__anone5e484780111::BC7::Mode1130 constexpr Bitfield Green(int idx) const
1131 {
1132 return Red(NumColors() - 1).Then(CB * idx).Then(CB);
1133 }
Blue__anone5e484780111::BC7::Mode1134 constexpr Bitfield Blue(int idx) const
1135 {
1136 return Green(NumColors() - 1).Then(CB * idx).Then(CB);
1137 }
Alpha__anone5e484780111::BC7::Mode1138 constexpr Bitfield Alpha(int idx) const
1139 {
1140 return Blue(NumColors() - 1).Then(AB * idx).Then(AB);
1141 }
EndpointPBit__anone5e484780111::BC7::Mode1142 constexpr Bitfield EndpointPBit(int idx) const
1143 {
1144 return Alpha(NumColors() - 1).Then(EPB * idx).Then(EPB);
1145 }
SharedPBit0__anone5e484780111::BC7::Mode1146 constexpr Bitfield SharedPBit0() const
1147 {
1148 return EndpointPBit(NumColors() - 1).Then(SPB);
1149 }
SharedPBit1__anone5e484780111::BC7::Mode1150 constexpr Bitfield SharedPBit1() const
1151 {
1152 return SharedPBit0().Then(SPB);
1153 }
PrimaryIndex__anone5e484780111::BC7::Mode1154 constexpr Bitfield PrimaryIndex(int offset, int count) const
1155 {
1156 return SharedPBit1().Then(offset).Then(count);
1157 }
SecondaryIndex__anone5e484780111::BC7::Mode1158 constexpr Bitfield SecondaryIndex(int offset, int count) const
1159 {
1160 return SharedPBit1().Then(IBC + offset).Then(count);
1161 }
1162 };
1163
1164 static constexpr Mode Modes[] = {
1165 // IDX NS PB RB ISB CB AB EPB SPB IB IBC, IB2
1166 /**/ { 0x0, 0x3, 0x4, 0x0, 0x0, 0x4, 0x0, 0x1, 0x0, 0x3, 0x2d, 0x0 },
1167 /**/ { 0x1, 0x2, 0x6, 0x0, 0x0, 0x6, 0x0, 0x0, 0x1, 0x3, 0x2e, 0x0 },
1168 /**/ { 0x2, 0x3, 0x6, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x2, 0x1d, 0x0 },
1169 /**/ { 0x3, 0x2, 0x6, 0x0, 0x0, 0x7, 0x0, 0x1, 0x0, 0x2, 0x1e, 0x0 },
1170 /**/ { 0x4, 0x1, 0x0, 0x2, 0x1, 0x5, 0x6, 0x0, 0x0, 0x2, 0x1f, 0x3 },
1171 /**/ { 0x5, 0x1, 0x0, 0x2, 0x0, 0x7, 0x8, 0x0, 0x0, 0x2, 0x1f, 0x2 },
1172 /**/ { 0x6, 0x1, 0x0, 0x0, 0x0, 0x7, 0x7, 0x1, 0x0, 0x4, 0x3f, 0x0 },
1173 /**/ { 0x7, 0x2, 0x6, 0x0, 0x0, 0x5, 0x5, 0x1, 0x0, 0x2, 0x1e, 0x0 },
1174 /**/ { -1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x00, 0x0 },
1175 };
1176
1177 static_assert(Modes[0].NumColors() == 6, "BC7 static assertion failed");
1178 static_assert(Modes[0].Partition() == Bitfield{ 1, 4 }, "BC7 static assertion failed");
1179 static_assert(Modes[0].Red(0) == Bitfield{ 5, 4 }, "BC7 static assertion failed");
1180 static_assert(Modes[0].Red(5) == Bitfield{ 25, 4 }, "BC7 static assertion failed");
1181 static_assert(Modes[0].Green(0) == Bitfield{ 29, 4 }, "BC7 static assertion failed");
1182 static_assert(Modes[0].Green(5) == Bitfield{ 49, 4 }, "BC7 static assertion failed");
1183 static_assert(Modes[0].Blue(0) == Bitfield{ 53, 4 }, "BC7 static assertion failed");
1184 static_assert(Modes[0].Blue(5) == Bitfield{ 73, 4 }, "BC7 static assertion failed");
1185 static_assert(Modes[0].EndpointPBit(0) == Bitfield{ 77, 1 }, "BC7 static assertion failed");
1186 static_assert(Modes[0].EndpointPBit(5) == Bitfield{ 82, 1 }, "BC7 static assertion failed");
1187 static_assert(Modes[0].PrimaryIndex(0, 2) == Bitfield{ 83, 2 }, "BC7 static asassertionsert failed");
1188 static_assert(Modes[0].PrimaryIndex(43, 1) == Bitfield{ 126, 1 }, "BC7 static assertion failed");
1189
1190 static constexpr int MaxPartitions = 64;
1191 static constexpr int MaxSubsets = 3;
1192
1193 static constexpr uint8_t PartitionTable2[MaxPartitions][16] = {
1194 { 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 },
1195 { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 },
1196 { 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
1197 { 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1 },
1198 { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1 },
1199 { 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
1200 { 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
1201 { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1 },
1202 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1 },
1203 { 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
1204 { 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
1205 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1 },
1206 { 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
1207 { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 },
1208 { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
1209 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 },
1210 { 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1 },
1211 { 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
1212 { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0 },
1213 { 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0 },
1214 { 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
1215 { 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0 },
1216 { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 },
1217 { 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1 },
1218 { 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0 },
1219 { 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 },
1220 { 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0 },
1221 { 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0 },
1222 { 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0 },
1223 { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 },
1224 { 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0 },
1225 { 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0 },
1226 { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 },
1227 { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1 },
1228 { 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0 },
1229 { 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0 },
1230 { 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0 },
1231 { 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0 },
1232 { 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1 },
1233 { 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1 },
1234 { 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0 },
1235 { 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0 },
1236 { 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0 },
1237 { 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0 },
1238 { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 },
1239 { 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1 },
1240 { 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1 },
1241 { 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0 },
1242 { 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 },
1243 { 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0 },
1244 { 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0 },
1245 { 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0 },
1246 { 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1 },
1247 { 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1 },
1248 { 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0 },
1249 { 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0 },
1250 { 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1 },
1251 { 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1 },
1252 { 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1 },
1253 { 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1 },
1254 { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 },
1255 { 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 },
1256 { 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0 },
1257 { 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1 },
1258 };
1259
1260 static constexpr uint8_t PartitionTable3[MaxPartitions][16] = {
1261 { 0, 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 1, 2, 2, 2, 2 },
1262 { 0, 0, 0, 1, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1 },
1263 { 0, 0, 0, 0, 2, 0, 0, 1, 2, 2, 1, 1, 2, 2, 1, 1 },
1264 { 0, 2, 2, 2, 0, 0, 2, 2, 0, 0, 1, 1, 0, 1, 1, 1 },
1265 { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2 },
1266 { 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 2, 2 },
1267 { 0, 0, 2, 2, 0, 0, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1 },
1268 { 0, 0, 1, 1, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1 },
1269 { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2 },
1270 { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2 },
1271 { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2 },
1272 { 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2 },
1273 { 0, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 2 },
1274 { 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 2 },
1275 { 0, 0, 1, 1, 0, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2 },
1276 { 0, 0, 1, 1, 2, 0, 0, 1, 2, 2, 0, 0, 2, 2, 2, 0 },
1277 { 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 2, 1, 1, 2, 2 },
1278 { 0, 1, 1, 1, 0, 0, 1, 1, 2, 0, 0, 1, 2, 2, 0, 0 },
1279 { 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2 },
1280 { 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 1, 1, 1, 1 },
1281 { 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2 },
1282 { 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, 2, 1, 2, 2, 2, 1 },
1283 { 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 2, 0, 1, 2, 2 },
1284 { 0, 0, 0, 0, 1, 1, 0, 0, 2, 2, 1, 0, 2, 2, 1, 0 },
1285 { 0, 1, 2, 2, 0, 1, 2, 2, 0, 0, 1, 1, 0, 0, 0, 0 },
1286 { 0, 0, 1, 2, 0, 0, 1, 2, 1, 1, 2, 2, 2, 2, 2, 2 },
1287 { 0, 1, 1, 0, 1, 2, 2, 1, 1, 2, 2, 1, 0, 1, 1, 0 },
1288 { 0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 2, 1, 1, 2, 2, 1 },
1289 { 0, 0, 2, 2, 1, 1, 0, 2, 1, 1, 0, 2, 0, 0, 2, 2 },
1290 { 0, 1, 1, 0, 0, 1, 1, 0, 2, 0, 0, 2, 2, 2, 2, 2 },
1291 { 0, 0, 1, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 0, 1, 1 },
1292 { 0, 0, 0, 0, 2, 0, 0, 0, 2, 2, 1, 1, 2, 2, 2, 1 },
1293 { 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 2, 2, 2 },
1294 { 0, 2, 2, 2, 0, 0, 2, 2, 0, 0, 1, 2, 0, 0, 1, 1 },
1295 { 0, 0, 1, 1, 0, 0, 1, 2, 0, 0, 2, 2, 0, 2, 2, 2 },
1296 { 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0 },
1297 { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0, 0 },
1298 { 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0 },
1299 { 0, 1, 2, 0, 2, 0, 1, 2, 1, 2, 0, 1, 0, 1, 2, 0 },
1300 { 0, 0, 1, 1, 2, 2, 0, 0, 1, 1, 2, 2, 0, 0, 1, 1 },
1301 { 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0, 0, 1, 1 },
1302 { 0, 1, 0, 1, 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2 },
1303 { 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 1, 2, 1, 2, 1 },
1304 { 0, 0, 2, 2, 1, 1, 2, 2, 0, 0, 2, 2, 1, 1, 2, 2 },
1305 { 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 1, 1 },
1306 { 0, 2, 2, 0, 1, 2, 2, 1, 0, 2, 2, 0, 1, 2, 2, 1 },
1307 { 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 1 },
1308 { 0, 0, 0, 0, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1 },
1309 { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 2, 2, 2, 2 },
1310 { 0, 2, 2, 2, 0, 1, 1, 1, 0, 2, 2, 2, 0, 1, 1, 1 },
1311 { 0, 0, 0, 2, 1, 1, 1, 2, 0, 0, 0, 2, 1, 1, 1, 2 },
1312 { 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2 },
1313 { 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2 },
1314 { 0, 0, 0, 2, 1, 1, 1, 2, 1, 1, 1, 2, 0, 0, 0, 2 },
1315 { 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 2, 2 },
1316 { 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 1, 2 },
1317 { 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 2 },
1318 { 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2, 2 },
1319 { 0, 0, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 0, 0, 2, 2 },
1320 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2 },
1321 { 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 1 },
1322 { 0, 2, 2, 2, 1, 2, 2, 2, 0, 2, 2, 2, 1, 2, 2, 2 },
1323 { 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
1324 { 0, 1, 1, 1, 2, 0, 1, 1, 2, 2, 0, 1, 2, 2, 2, 0 },
1325 };
1326
1327 static constexpr uint8_t AnchorTable2[MaxPartitions] = {
1328 // clang-format off
1329 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
1330 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
1331 0xf, 0x2, 0x8, 0x2, 0x2, 0x8, 0x8, 0xf,
1332 0x2, 0x8, 0x2, 0x2, 0x8, 0x8, 0x2, 0x2,
1333 0xf, 0xf, 0x6, 0x8, 0x2, 0x8, 0xf, 0xf,
1334 0x2, 0x8, 0x2, 0x2, 0x2, 0xf, 0xf, 0x6,
1335 0x6, 0x2, 0x6, 0x8, 0xf, 0xf, 0x2, 0x2,
1336 0xf, 0xf, 0xf, 0xf, 0xf, 0x2, 0x2, 0xf,
1337 // clang-format on
1338 };
1339
1340 static constexpr uint8_t AnchorTable3a[MaxPartitions] = {
1341 // clang-format off
1342 0x3, 0x3, 0xf, 0xf, 0x8, 0x3, 0xf, 0xf,
1343 0x8, 0x8, 0x6, 0x6, 0x6, 0x5, 0x3, 0x3,
1344 0x3, 0x3, 0x8, 0xf, 0x3, 0x3, 0x6, 0xa,
1345 0x5, 0x8, 0x8, 0x6, 0x8, 0x5, 0xf, 0xf,
1346 0x8, 0xf, 0x3, 0x5, 0x6, 0xa, 0x8, 0xf,
1347 0xf, 0x3, 0xf, 0x5, 0xf, 0xf, 0xf, 0xf,
1348 0x3, 0xf, 0x5, 0x5, 0x5, 0x8, 0x5, 0xa,
1349 0x5, 0xa, 0x8, 0xd, 0xf, 0xc, 0x3, 0x3,
1350 // clang-format on
1351 };
1352
1353 static constexpr uint8_t AnchorTable3b[MaxPartitions] = {
1354 // clang-format off
1355 0xf, 0x8, 0x8, 0x3, 0xf, 0xf, 0x3, 0x8,
1356 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x8,
1357 0xf, 0x8, 0xf, 0x3, 0xf, 0x8, 0xf, 0x8,
1358 0x3, 0xf, 0x6, 0xa, 0xf, 0xf, 0xa, 0x8,
1359 0xf, 0x3, 0xf, 0xa, 0xa, 0x8, 0x9, 0xa,
1360 0x6, 0xf, 0x8, 0xf, 0x3, 0x6, 0x6, 0x8,
1361 0xf, 0x3, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
1362 0xf, 0xf, 0xf, 0xf, 0x3, 0xf, 0xf, 0x8,
1363 // clang-format on
1364 };
1365
1366 struct Color
1367 {
1368 struct RGB
1369 {
1370 RGB() = default;
RGB__anone5e484780111::BC7::Color::RGB1371 RGB(uint8_t r, uint8_t g, uint8_t b)
1372 : b(b)
1373 , g(g)
1374 , r(r)
1375 {}
RGB__anone5e484780111::BC7::Color::RGB1376 RGB(int r, int g, int b)
1377 : b(static_cast<uint8_t>(b))
1378 , g(static_cast<uint8_t>(g))
1379 , r(static_cast<uint8_t>(r))
1380 {}
1381
operator <<__anone5e484780111::BC7::Color::RGB1382 RGB operator<<(int shift) const { return { r << shift, g << shift, b << shift }; }
operator >>__anone5e484780111::BC7::Color::RGB1383 RGB operator>>(int shift) const { return { r >> shift, g >> shift, b >> shift }; }
operator |__anone5e484780111::BC7::Color::RGB1384 RGB operator|(int bits) const { return { r | bits, g | bits, b | bits }; }
operator |__anone5e484780111::BC7::Color::RGB1385 RGB operator|(const RGB &rhs) const { return { r | rhs.r, g | rhs.g, b | rhs.b }; }
operator +__anone5e484780111::BC7::Color::RGB1386 RGB operator+(const RGB &rhs) const { return { r + rhs.r, g + rhs.g, b + rhs.b }; }
1387
1388 uint8_t b;
1389 uint8_t g;
1390 uint8_t r;
1391 };
1392
1393 RGB rgb;
1394 uint8_t a;
1395 };
1396
1397 static_assert(sizeof(Color) == 4, "Color size must be 4 bytes");
1398
1399 struct Block
1400 {
Get__anone5e484780111::BC7::Block1401 constexpr uint64_t Get(const Bitfield &bf) const
1402 {
1403 uint64_t mask = (1ULL << bf.count) - 1;
1404 if(bf.offset + bf.count <= 64)
1405 {
1406 return (low >> bf.offset) & mask;
1407 }
1408 if(bf.offset >= 64)
1409 {
1410 return (high >> (bf.offset - 64)) & mask;
1411 }
1412 return ((low >> bf.offset) | (high << (64 - bf.offset))) & mask;
1413 }
1414
mode__anone5e484780111::BC7::Block1415 const Mode &mode() const
1416 {
1417 if((low & 0b00000001) != 0) { return Modes[0]; }
1418 if((low & 0b00000010) != 0) { return Modes[1]; }
1419 if((low & 0b00000100) != 0) { return Modes[2]; }
1420 if((low & 0b00001000) != 0) { return Modes[3]; }
1421 if((low & 0b00010000) != 0) { return Modes[4]; }
1422 if((low & 0b00100000) != 0) { return Modes[5]; }
1423 if((low & 0b01000000) != 0) { return Modes[6]; }
1424 if((low & 0b10000000) != 0) { return Modes[7]; }
1425 return Modes[8]; // Invalid mode
1426 }
1427
1428 struct IndexInfo
1429 {
1430 uint64_t value;
1431 int numBits;
1432 };
1433
interpolate__anone5e484780111::BC7::Block1434 uint8_t interpolate(uint8_t e0, uint8_t e1, const IndexInfo &index) const
1435 {
1436 static constexpr uint16_t weights2[] = { 0, 21, 43, 64 };
1437 static constexpr uint16_t weights3[] = { 0, 9, 18, 27, 37, 46, 55, 64 };
1438 static constexpr uint16_t weights4[] = { 0, 4, 9, 13, 17, 21, 26, 30,
1439 34, 38, 43, 47, 51, 55, 60, 64 };
1440 static constexpr uint16_t const *weightsN[] = {
1441 nullptr, nullptr, weights2, weights3, weights4
1442 };
1443 auto weights = weightsN[index.numBits];
1444 ASSERT_MSG(weights != nullptr, "Unexpected number of index bits: %d", (int)index.numBits);
1445 return (uint8_t)(((64 - weights[index.value]) * uint16_t(e0) + weights[index.value] * uint16_t(e1) + 32) >> 6);
1446 }
1447
decode__anone5e484780111::BC7::Block1448 void decode(uint8_t *dst, int dstX, int dstY, int dstWidth, int dstHeight, size_t dstPitch) const
1449 {
1450 auto const &mode = this->mode();
1451
1452 if(mode.IDX < 0) // Invalid mode:
1453 {
1454 for(int y = 0; y < 4 && y + dstY < dstHeight; y++)
1455 {
1456 for(int x = 0; x < 4 && x + dstX < dstWidth; x++)
1457 {
1458 auto out = reinterpret_cast<Color *>(dst + sizeof(Color) * x + dstPitch * y);
1459 out->rgb = { 0, 0, 0 };
1460 out->a = 0;
1461 }
1462 }
1463 return;
1464 }
1465
1466 using Endpoint = std::array<Color, 2>;
1467 std::array<Endpoint, MaxSubsets> subsets;
1468
1469 for(int i = 0; i < mode.NS; i++)
1470 {
1471 auto &subset = subsets[i];
1472 subset[0].rgb.r = Get(mode.Red(i * 2 + 0));
1473 subset[0].rgb.g = Get(mode.Green(i * 2 + 0));
1474 subset[0].rgb.b = Get(mode.Blue(i * 2 + 0));
1475 subset[0].a = (mode.AB > 0) ? Get(mode.Alpha(i * 2 + 0)) : 255;
1476
1477 subset[1].rgb.r = Get(mode.Red(i * 2 + 1));
1478 subset[1].rgb.g = Get(mode.Green(i * 2 + 1));
1479 subset[1].rgb.b = Get(mode.Blue(i * 2 + 1));
1480 subset[1].a = (mode.AB > 0) ? Get(mode.Alpha(i * 2 + 1)) : 255;
1481 }
1482
1483 if(mode.SPB > 0)
1484 {
1485 auto pbit0 = Get(mode.SharedPBit0());
1486 auto pbit1 = Get(mode.SharedPBit1());
1487 subsets[0][0].rgb = (subsets[0][0].rgb << 1) | pbit0;
1488 subsets[0][1].rgb = (subsets[0][1].rgb << 1) | pbit0;
1489 subsets[1][0].rgb = (subsets[1][0].rgb << 1) | pbit1;
1490 subsets[1][1].rgb = (subsets[1][1].rgb << 1) | pbit1;
1491 }
1492
1493 if(mode.EPB > 0)
1494 {
1495 for(int i = 0; i < mode.NS; i++)
1496 {
1497 auto &subset = subsets[i];
1498 auto pbit0 = Get(mode.EndpointPBit(i * 2 + 0));
1499 auto pbit1 = Get(mode.EndpointPBit(i * 2 + 1));
1500 subset[0].rgb = (subset[0].rgb << 1) | pbit0;
1501 subset[1].rgb = (subset[1].rgb << 1) | pbit1;
1502 if(mode.AB > 0)
1503 {
1504 subset[0].a = (subset[0].a << 1) | pbit0;
1505 subset[1].a = (subset[1].a << 1) | pbit1;
1506 }
1507 }
1508 }
1509
1510 auto const colorBits = mode.CB + mode.SPB + mode.EPB;
1511 auto const alphaBits = mode.AB + mode.SPB + mode.EPB;
1512
1513 for(int i = 0; i < mode.NS; i++)
1514 {
1515 auto &subset = subsets[i];
1516 subset[0].rgb = subset[0].rgb << (8 - colorBits);
1517 subset[1].rgb = subset[1].rgb << (8 - colorBits);
1518 subset[0].rgb = subset[0].rgb | (subset[0].rgb >> colorBits);
1519 subset[1].rgb = subset[1].rgb | (subset[1].rgb >> colorBits);
1520
1521 if(mode.AB > 0)
1522 {
1523 subset[0].a = subset[0].a << (8 - alphaBits);
1524 subset[1].a = subset[1].a << (8 - alphaBits);
1525 subset[0].a = subset[0].a | (subset[0].a >> alphaBits);
1526 subset[1].a = subset[1].a | (subset[1].a >> alphaBits);
1527 }
1528 }
1529
1530 int colorIndexBitOffset = 0;
1531 int alphaIndexBitOffset = 0;
1532 for(int y = 0; y < 4; y++)
1533 {
1534 for(int x = 0; x < 4; x++)
1535 {
1536 auto texelIdx = y * 4 + x;
1537 auto partitionIdx = Get(mode.Partition());
1538 ASSERT(partitionIdx < MaxPartitions);
1539 auto subsetIdx = subsetIndex(mode, partitionIdx, texelIdx);
1540 ASSERT(subsetIdx < MaxSubsets);
1541 auto const &subset = subsets[subsetIdx];
1542
1543 auto anchorIdx = anchorIndex(mode, partitionIdx, subsetIdx);
1544 auto isAnchor = anchorIdx == texelIdx;
1545 auto colorIdx = colorIndex(mode, isAnchor, colorIndexBitOffset);
1546 auto alphaIdx = alphaIndex(mode, isAnchor, alphaIndexBitOffset);
1547
1548 if(y + dstY >= dstHeight || x + dstX >= dstWidth)
1549 {
1550 // Don't be tempted to skip early at the loops:
1551 // The calls to colorIndex() and alphaIndex() adjust bit
1552 // offsets that need to be carefully tracked.
1553 continue;
1554 }
1555
1556 Color output;
1557 output.rgb.r = interpolate(subset[0].rgb.r, subset[1].rgb.r, colorIdx);
1558 output.rgb.g = interpolate(subset[0].rgb.g, subset[1].rgb.g, colorIdx);
1559 output.rgb.b = interpolate(subset[0].rgb.b, subset[1].rgb.b, colorIdx);
1560 output.a = interpolate(subset[0].a, subset[1].a, alphaIdx);
1561
1562 switch(Get(mode.Rotation()))
1563 {
1564 default:
1565 break;
1566 case 1:
1567 std::swap(output.a, output.rgb.r);
1568 break;
1569 case 2:
1570 std::swap(output.a, output.rgb.g);
1571 break;
1572 case 3:
1573 std::swap(output.a, output.rgb.b);
1574 break;
1575 }
1576
1577 auto out = reinterpret_cast<Color *>(dst + sizeof(Color) * x + dstPitch * y);
1578 *out = output;
1579 }
1580 }
1581 }
1582
subsetIndex__anone5e484780111::BC7::Block1583 int subsetIndex(const Mode &mode, int partitionIdx, int texelIndex) const
1584 {
1585 switch(mode.NS)
1586 {
1587 default:
1588 return 0;
1589 case 2:
1590 return PartitionTable2[partitionIdx][texelIndex];
1591 case 3:
1592 return PartitionTable3[partitionIdx][texelIndex];
1593 }
1594 }
1595
anchorIndex__anone5e484780111::BC7::Block1596 int anchorIndex(const Mode &mode, int partitionIdx, int subsetIdx) const
1597 {
1598 // ARB_texture_compression_bptc states:
1599 // "In partition zero, the anchor index is always index zero.
1600 // In other partitions, the anchor index is specified by tables
1601 // Table.A2 and Table.A3.""
1602 // Note: This is really confusing - I believe they meant subset instead
1603 // of partition here.
1604 switch(subsetIdx)
1605 {
1606 default:
1607 return 0;
1608 case 1:
1609 return mode.NS == 2 ? AnchorTable2[partitionIdx] : AnchorTable3a[partitionIdx];
1610 case 2:
1611 return AnchorTable3b[partitionIdx];
1612 }
1613 }
1614
colorIndex__anone5e484780111::BC7::Block1615 IndexInfo colorIndex(const Mode &mode, bool isAnchor,
1616 int &indexBitOffset) const
1617 {
1618 // ARB_texture_compression_bptc states:
1619 // "The index value for interpolating color comes from the secondary
1620 // index for the texel if the format has an index selection bit and its
1621 // value is one and from the primary index otherwise.""
1622 auto idx = Get(mode.IndexSelection());
1623 ASSERT(idx <= 1);
1624 bool secondary = idx == 1;
1625 auto numBits = secondary ? mode.IB2 : mode.IB;
1626 auto numReadBits = numBits - (isAnchor ? 1 : 0);
1627 auto index =
1628 Get(secondary ? mode.SecondaryIndex(indexBitOffset, numReadBits)
1629 : mode.PrimaryIndex(indexBitOffset, numReadBits));
1630 indexBitOffset += numReadBits;
1631 return { index, numBits };
1632 }
1633
alphaIndex__anone5e484780111::BC7::Block1634 IndexInfo alphaIndex(const Mode &mode, bool isAnchor,
1635 int &indexBitOffset) const
1636 {
1637 // ARB_texture_compression_bptc states:
1638 // "The alpha index comes from the secondary index if the block has a
1639 // secondary index and the block either doesn't have an index selection
1640 // bit or that bit is zero and the primary index otherwise."
1641 auto idx = Get(mode.IndexSelection());
1642 ASSERT(idx <= 1);
1643 bool secondary = (mode.IB2 != 0) && (idx == 0);
1644 auto numBits = secondary ? mode.IB2 : mode.IB;
1645 auto numReadBits = numBits - (isAnchor ? 1 : 0);
1646 auto index =
1647 Get(secondary ? mode.SecondaryIndex(indexBitOffset, numReadBits)
1648 : mode.PrimaryIndex(indexBitOffset, numReadBits));
1649 indexBitOffset += numReadBits;
1650 return { index, numBits };
1651 }
1652
1653 // Assumes little-endian
1654 uint64_t low;
1655 uint64_t high;
1656 };
1657
1658 } // namespace BC7
1659 } // anonymous namespace
1660
1661 // Decodes 1 to 4 channel images to 8 bit output
Decode(const uint8_t * src,uint8_t * dst,int w,int h,int dstPitch,int dstBpp,int n,bool isNoAlphaU)1662 bool BC_Decoder::Decode(const uint8_t *src, uint8_t *dst, int w, int h, int dstPitch, int dstBpp, int n, bool isNoAlphaU)
1663 {
1664 static_assert(sizeof(BC_color) == 8, "BC_color must be 8 bytes");
1665 static_assert(sizeof(BC_channel) == 8, "BC_channel must be 8 bytes");
1666 static_assert(sizeof(BC_alpha) == 8, "BC_alpha must be 8 bytes");
1667
1668 const int dx = BlockWidth * dstBpp;
1669 const int dy = BlockHeight * dstPitch;
1670 const bool isAlpha = (n == 1) && !isNoAlphaU;
1671 const bool isSigned = ((n == 4) || (n == 5) || (n == 6)) && !isNoAlphaU;
1672
1673 switch(n)
1674 {
1675 case 1: // BC1
1676 {
1677 const BC_color *color = reinterpret_cast<const BC_color *>(src);
1678 for(int y = 0; y < h; y += BlockHeight, dst += dy)
1679 {
1680 uint8_t *dstRow = dst;
1681 for(int x = 0; x < w; x += BlockWidth, ++color, dstRow += dx)
1682 {
1683 color->decode(dstRow, x, y, w, h, dstPitch, dstBpp, isAlpha, false);
1684 }
1685 }
1686 }
1687 break;
1688 case 2: // BC2
1689 {
1690 const BC_alpha *alpha = reinterpret_cast<const BC_alpha *>(src);
1691 const BC_color *color = reinterpret_cast<const BC_color *>(src + 8);
1692 for(int y = 0; y < h; y += BlockHeight, dst += dy)
1693 {
1694 uint8_t *dstRow = dst;
1695 for(int x = 0; x < w; x += BlockWidth, alpha += 2, color += 2, dstRow += dx)
1696 {
1697 color->decode(dstRow, x, y, w, h, dstPitch, dstBpp, isAlpha, true);
1698 alpha->decode(dstRow, x, y, w, h, dstPitch, dstBpp);
1699 }
1700 }
1701 }
1702 break;
1703 case 3: // BC3
1704 {
1705 const BC_channel *alpha = reinterpret_cast<const BC_channel *>(src);
1706 const BC_color *color = reinterpret_cast<const BC_color *>(src + 8);
1707 for(int y = 0; y < h; y += BlockHeight, dst += dy)
1708 {
1709 uint8_t *dstRow = dst;
1710 for(int x = 0; x < w; x += BlockWidth, alpha += 2, color += 2, dstRow += dx)
1711 {
1712 color->decode(dstRow, x, y, w, h, dstPitch, dstBpp, isAlpha, true);
1713 alpha->decode(dstRow, x, y, w, h, dstPitch, dstBpp, 3, isSigned);
1714 }
1715 }
1716 }
1717 break;
1718 case 4: // BC4
1719 {
1720 const BC_channel *red = reinterpret_cast<const BC_channel *>(src);
1721 for(int y = 0; y < h; y += BlockHeight, dst += dy)
1722 {
1723 uint8_t *dstRow = dst;
1724 for(int x = 0; x < w; x += BlockWidth, ++red, dstRow += dx)
1725 {
1726 red->decode(dstRow, x, y, w, h, dstPitch, dstBpp, 0, isSigned);
1727 }
1728 }
1729 }
1730 break;
1731 case 5: // BC5
1732 {
1733 const BC_channel *red = reinterpret_cast<const BC_channel *>(src);
1734 const BC_channel *green = reinterpret_cast<const BC_channel *>(src + 8);
1735 for(int y = 0; y < h; y += BlockHeight, dst += dy)
1736 {
1737 uint8_t *dstRow = dst;
1738 for(int x = 0; x < w; x += BlockWidth, red += 2, green += 2, dstRow += dx)
1739 {
1740 red->decode(dstRow, x, y, w, h, dstPitch, dstBpp, 0, isSigned);
1741 green->decode(dstRow, x, y, w, h, dstPitch, dstBpp, 1, isSigned);
1742 }
1743 }
1744 }
1745 break;
1746 case 6: // BC6H
1747 {
1748 const BC6H::Block *block = reinterpret_cast<const BC6H::Block *>(src);
1749 for(int y = 0; y < h; y += BlockHeight, dst += dy)
1750 {
1751 uint8_t *dstRow = dst;
1752 for(int x = 0; x < w; x += BlockWidth, ++block, dstRow += dx)
1753 {
1754 block->decode(dstRow, x, y, w, h, dstPitch, dstBpp, isSigned);
1755 }
1756 }
1757 }
1758 break;
1759 case 7: // BC7
1760 {
1761 const BC7::Block *block = reinterpret_cast<const BC7::Block *>(src);
1762 for(int y = 0; y < h; y += BlockHeight, dst += dy)
1763 {
1764 uint8_t *dstRow = dst;
1765 for(int x = 0; x < w; x += BlockWidth, ++block, dstRow += dx)
1766 {
1767 block->decode(dstRow, x, y, w, h, dstPitch);
1768 }
1769 }
1770 }
1771 break;
1772 default:
1773 return false;
1774 }
1775
1776 return true;
1777 }
1778