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__anon659343cc0111::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__anon659343cc0111::BC_color::Color67 Color()
68 {
69 c[0] = c[1] = c[2] = 0;
70 c[3] = 0xFF000000;
71 }
72
extract565__anon659343cc0111::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__anon659343cc0111::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__anon659343cc0111::BC_color::Color85 void clearAlpha()
86 {
87 c[3] = 0;
88 }
89
operator *__anon659343cc0111::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 /__anon659343cc0111::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 >>__anon659343cc0111::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 +__anon659343cc0111::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__anon659343cc0111::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__anon659343cc0111::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__anon659343cc0111::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__anon659343cc0111::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__anon659343cc0111::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 const uint16_t a = halfFloat1;
318
RGBA__anon659343cc0111::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 =__anon659343cc0111::BC6H::Color::RGBA326 RGBA &operator=(const RGBA &other)
327 {
328 if(this != &other)
329 {
330 this->r = other.r;
331 this->g = other.g;
332 this->b = other.b;
333 }
334
335 return *this;
336 }
337 };
338
Color(uint16_t r,uint16_t g,uint16_t b)339 Color(uint16_t r, uint16_t g, uint16_t b)
340 : rgba(r, g, b)
341 {
342 }
343
Color(int r,int g,int b)344 Color(int r, int g, int b)
345 : rgba((uint16_t)r, (uint16_t)g, (uint16_t)b)
346 {
347 }
348
Color()349 Color()
350 {
351 }
352
operator =(const Color & other)353 Color &operator=(const Color &other)
354 {
355 if(this != &other)
356 {
357 this->rgba = other.rgba;
358 }
359 return *this;
360 }
361
362 RGBA rgba;
363 uint16_t channel[4];
364 };
365 static_assert(sizeof(Color) == 8, "BC6h::Color must be 8 bytes long");
366
extendSign(int32_t val,size_t size)367 inline int32_t extendSign(int32_t val, size_t size)
368 {
369 // Suppose we have a 2-bit integer being stored in 4 bit variable:
370 // x = 0b00AB
371 //
372 // In order to sign extend x, we need to turn the 0s into A's:
373 // x_extend = 0bAAAB
374 //
375 // We can do that by flipping A in x then subtracting 0b0010 from x.
376 // Suppose A is 1:
377 // x = 0b001B
378 // x_flip = 0b000B
379 // x_minus = 0b111B
380 // Since A is flipped to 0, subtracting the mask sets it and all the bits above it to 1.
381 // And if A is 0:
382 // x = 0b000B
383 // x_flip = 0b001B
384 // x_minus = 0b000B
385 // We unset the bit we flipped, and touch no other bit
386 uint16_t mask = 1u << (size - 1);
387 return (val ^ mask) - mask;
388 }
389
390 static int constexpr RGBfChannels = 3;
391 struct RGBf
392 {
393 uint16_t channel[RGBfChannels];
394 size_t size[RGBfChannels];
395 bool isSigned;
396
RGBf__anon659343cc0111::BC6H::RGBf397 RGBf()
398 {
399 static_assert(RGBfChannels == 3, "RGBf must have exactly 3 channels");
400 static_assert(sizeof(channel) / sizeof(channel[0]) == RGBfChannels, "RGBf must have exactly 3 channels");
401 static_assert(sizeof(channel) / sizeof(channel[0]) == sizeof(size) / sizeof(size[0]), "RGBf requires equally sized arrays for channels and channel sizes");
402
403 for(int i = 0; i < RGBfChannels; i++)
404 {
405 channel[i] = 0;
406 size[i] = 0;
407 }
408
409 isSigned = false;
410 }
411
extendSign__anon659343cc0111::BC6H::RGBf412 void extendSign()
413 {
414 for(int i = 0; i < RGBfChannels; i++)
415 {
416 channel[i] = BC6H::extendSign(channel[i], size[i]);
417 }
418 }
419
420 // Assuming this is the delta, take the base-endpoint and transform this into
421 // a proper endpoint.
422 //
423 // The final computed endpoint is truncated to the base-endpoint's size;
resolveDelta__anon659343cc0111::BC6H::RGBf424 void resolveDelta(RGBf base)
425 {
426 for(int i = 0; i < RGBfChannels; i++)
427 {
428 size[i] = base.size[i];
429 channel[i] = (base.channel[i] + channel[i]) & ((1 << base.size[i]) - 1);
430 }
431
432 // Per the spec:
433 // "For signed formats, the results of the delta calculation must be sign
434 // extended as well."
435 if(isSigned)
436 {
437 extendSign();
438 }
439 }
440
unquantize__anon659343cc0111::BC6H::RGBf441 void unquantize()
442 {
443 if(isSigned)
444 {
445 unquantizeSigned();
446 }
447 else
448 {
449 unquantizeUnsigned();
450 }
451 }
452
unquantizeUnsigned__anon659343cc0111::BC6H::RGBf453 void unquantizeUnsigned()
454 {
455 for(int i = 0; i < RGBfChannels; i++)
456 {
457 if(size[i] >= 15 || channel[i] == 0)
458 {
459 continue;
460 }
461 else if(channel[i] == ((1u << size[i]) - 1))
462 {
463 channel[i] = 0xFFFFu;
464 }
465 else
466 {
467 // Need 32 bits to avoid overflow
468 uint32_t tmp = channel[i];
469 channel[i] = (uint16_t)(((tmp << 16) + 0x8000) >> size[i]);
470 }
471 size[i] = 16;
472 }
473 }
474
unquantizeSigned__anon659343cc0111::BC6H::RGBf475 void unquantizeSigned()
476 {
477 for(int i = 0; i < RGBfChannels; i++)
478 {
479 if(size[i] >= 16 || channel[i] == 0)
480 {
481 continue;
482 }
483
484 int16_t value = sw::bit_cast<int16_t>(channel[i]);
485 int32_t result = value;
486 bool signBit = value < 0;
487 if(signBit)
488 {
489 value = -value;
490 }
491
492 if(value >= ((1 << (size[i] - 1)) - 1))
493 {
494 result = 0x7FFF;
495 }
496 else
497 {
498 // Need 32 bits to avoid overflow
499 int32_t tmp = value;
500 result = (((tmp << 15) + 0x4000) >> (size[i] - 1));
501 }
502
503 if(signBit)
504 {
505 result = -result;
506 }
507
508 channel[i] = (uint16_t)result;
509 size[i] = 16;
510 }
511 }
512 };
513
514 struct Data
515 {
516 uint64_t low64;
517 uint64_t high64;
518
519 Data() = default;
Data__anon659343cc0111::BC6H::Data520 Data(uint64_t low64, uint64_t high64)
521 : low64(low64)
522 , high64(high64)
523 {
524 }
525
526 // Consumes the lowest N bits from from low64 and high64 where N is:
527 // abs(MSB - LSB)
528 // MSB and LSB come from the block description of the BC6h spec and specify
529 // the location of the bits in the returned bitstring.
530 //
531 // If MSB < LSB, then the bits are reversed. Otherwise, the bitstring is read and
532 // shifted without further modification.
533 //
consumeBits__anon659343cc0111::BC6H::Data534 uint32_t consumeBits(uint32_t MSB, uint32_t LSB)
535 {
536 bool reversed = MSB < LSB;
537 if(reversed)
538 {
539 std::swap(MSB, LSB);
540 }
541 ASSERT(MSB - LSB + 1 < sizeof(uint32_t) * 8);
542
543 uint32_t numBits = MSB - LSB + 1;
544 uint32_t mask = (1 << numBits) - 1;
545 // Read the low N bits
546 uint32_t bits = (low64 & mask);
547
548 low64 >>= numBits;
549 // Put the low N bits of high64 into the high 64-N bits of low64
550 low64 |= (high64 & mask) << (sizeof(high64) * 8 - numBits);
551 high64 >>= numBits;
552
553 if(reversed)
554 {
555 uint32_t tmp = 0;
556 for(uint32_t numSwaps = 0; numSwaps < numBits; numSwaps++)
557 {
558 tmp <<= 1;
559 tmp |= (bits & 1);
560 bits >>= 1;
561 }
562
563 bits = tmp;
564 }
565
566 return bits << LSB;
567 }
568 };
569
570 struct IndexInfo
571 {
572 uint64_t value;
573 int numBits;
574 };
575
576 // Interpolates between two endpoints, then does a final unquantization step
interpolate(RGBf e0,RGBf e1,const IndexInfo & index,bool isSigned)577 Color interpolate(RGBf e0, RGBf e1, const IndexInfo &index, bool isSigned)
578 {
579 static constexpr uint32_t weights3[] = { 0, 9, 18, 27, 37, 46, 55, 64 };
580 static constexpr uint32_t weights4[] = { 0, 4, 9, 13, 17, 21, 26, 30,
581 34, 38, 43, 47, 51, 55, 60, 64 };
582 static constexpr uint32_t const *weightsN[] = {
583 nullptr, nullptr, nullptr, weights3, weights4
584 };
585 auto weights = weightsN[index.numBits];
586 ASSERT_MSG(weights != nullptr, "Unexpected number of index bits: %d", (int)index.numBits);
587 Color color;
588 uint32_t e0Weight = 64 - weights[index.value];
589 uint32_t e1Weight = weights[index.value];
590
591 for(int i = 0; i < RGBfChannels; i++)
592 {
593 int32_t e0Channel = e0.channel[i];
594 int32_t e1Channel = e1.channel[i];
595
596 if(isSigned)
597 {
598 e0Channel = extendSign(e0Channel, 16);
599 e1Channel = extendSign(e1Channel, 16);
600 }
601
602 int32_t e0Value = e0Channel * e0Weight;
603 int32_t e1Value = e1Channel * e1Weight;
604
605 uint32_t tmp = ((e0Value + e1Value + 32) >> 6);
606
607 // Need to unquantize value to limit it to the legal range of half-precision
608 // floats. We do this by scaling by 31/32 or 31/64 depending on if the value
609 // is signed or unsigned.
610 if(isSigned)
611 {
612 tmp = ((tmp & 0x80000000) != 0) ? (((~tmp + 1) * 31) >> 5) | 0x8000 : (tmp * 31) >> 5;
613 // Don't return -0.0f, just normalize it to 0.0f.
614 if(tmp == 0x8000)
615 tmp = 0;
616 }
617 else
618 {
619 tmp = (tmp * 31) >> 6;
620 }
621
622 color.channel[i] = (uint16_t)tmp;
623 }
624
625 return color;
626 }
627
628 enum DataType
629 {
630 // Endpoints
631 EP0 = 0,
632 EP1 = 1,
633 EP2 = 2,
634 EP3 = 3,
635 Mode,
636 Partition,
637 };
638
639 enum Channel
640 {
641 R = 0,
642 G = 1,
643 B = 2,
644 None,
645 };
646
647 struct DeltaBits
648 {
649 size_t channel[3];
650
DeltaBits__anon659343cc0111::BC6H::DeltaBits651 DeltaBits()
652 {
653 channel[R] = 0;
654 channel[G] = 0;
655 channel[B] = 0;
656 }
657
DeltaBits__anon659343cc0111::BC6H::DeltaBits658 DeltaBits(int r, int g, int b)
659 {
660 channel[R] = r;
661 channel[G] = g;
662 channel[B] = b;
663 }
664 };
665
666 struct ModeDesc
667 {
668 int number;
669 bool hasDelta;
670 int partitionCount;
671 int endpointBits;
672 int numEndpoints;
673 DeltaBits deltaBits;
674
ModeDesc__anon659343cc0111::BC6H::ModeDesc675 ModeDesc()
676 : number(-1)
677 , hasDelta(false)
678 , partitionCount(0)
679 , endpointBits(0)
680 , numEndpoints(0)
681 {
682 }
683
ModeDesc__anon659343cc0111::BC6H::ModeDesc684 ModeDesc(int number, bool hasDelta, int partitionCount, int endpointBits, DeltaBits deltaBits)
685 : number(number)
686 , hasDelta(hasDelta)
687 , partitionCount(partitionCount)
688 , endpointBits(endpointBits)
689 , deltaBits(deltaBits)
690 {
691 numEndpoints = partitionCount * 2;
692 }
693 };
694
695 struct BlockDesc
696 {
697 DataType type;
698 Channel channel;
699 int MSB;
700 int LSB;
701 ModeDesc modeDesc;
702
703 BlockDesc() = default;
704
BlockDesc__anon659343cc0111::BC6H::BlockDesc705 BlockDesc(DataType type, Channel channel, int MSB, int LSB, ModeDesc modeDesc)
706 : type(type)
707 , channel(channel)
708 , MSB(MSB)
709 , LSB(LSB)
710 , modeDesc(modeDesc)
711 {
712 }
713
BlockDesc__anon659343cc0111::BC6H::BlockDesc714 BlockDesc(DataType type, Channel channel, int MSB, int LSB)
715 : type(type)
716 , channel(channel)
717 , MSB(MSB)
718 , LSB(LSB)
719 {
720 }
721 };
722
723 // Table describing the bitfields for each mode from the LSB to the MSB before
724 // the index data starts.
725 //
726 // The numbers come from the BC6h block description. The basic format is a list of bitfield
727 // descriptors of the form:
728 // {Type, Channel, MSB, LSB}
729 // * Type describes which endpoint this is, or if this is a mode or a partition number.
730 // * Channel describes one of the 3 color channels within an endpoint
731 // * MSB and LSB specificy:
732 // * The size of the bitfield being read
733 // * The position of the bitfield within the variable it is being read to
734 // * And if the bitfield is stored in reverse bit order
735 // If MSB < LSB then the bitfield is stored in reverse order. The size of the bitfield
736 // is abs(MSB-LSB+1). And the position of the bitfield within the variable is
737 // min(LSB, MSB).
738 //
739 // Invalid or reserved modes do not have any fields within them.
740 static const std::vector<BlockDesc> blockDescs[32] = {
741 // clang-format off
742 // Mode 0
743 { { Mode, None, 1, 0, { 0, true, 2, 10, { 5, 5, 5 } } },
744 { EP2, G, 4, 4 }, { EP2, B, 4, 4 }, { EP3, B, 4, 4 },
745 { EP0, R, 9, 0 }, { EP0, G, 9, 0 }, { EP0, B, 9, 0 },
746 { EP1, R, 4, 0 }, { EP3, G, 4, 4 }, { EP2, G, 3, 0 },
747 { EP1, G, 4, 0 }, { EP3, B, 0, 0 }, { EP3, G, 3, 0 },
748 { EP1, B, 4, 0 }, { EP3, B, 1, 1 }, { EP2, B, 3, 0 },
749 { EP2, R, 4, 0 }, { EP3, B, 2, 2 }, { EP3, R, 4, 0 },
750 { EP3, B, 3, 3 },
751 { Partition, None, 4, 0 } },
752 // Mode 1
753 { { Mode, None, 1, 0, { 1, true, 2, 7, { 6, 6, 6 } } },
754 { EP2, G, 5, 5 }, { EP3, G, 5, 4 }, { EP0, R, 6, 0 },
755 { EP3, B, 1, 0 }, { EP2, B, 4, 4 }, { EP0, G, 6, 0 },
756 { EP2, B, 5, 5 }, { EP3, B, 2, 2 }, { EP2, G, 4, 4 },
757 { EP0, B, 6, 0 }, { EP3, B, 3, 3 }, { EP3, B, 5, 5 },
758 { EP3, B, 4, 4 }, { EP1, R, 5, 0 }, { EP2, G, 3, 0 },
759 { EP1, G, 5, 0 }, { EP3, G, 3, 0 }, { EP1, B, 5, 0 },
760 { EP2, B, 3, 0 }, { EP2, R, 5, 0 }, { EP3, R, 5, 0 },
761 { Partition, None, 4, 0 } },
762 // Mode 2
763 { { Mode, None, 4, 0, { 2, true, 2, 11, { 5, 4, 4 } } },
764 { EP0, R, 9, 0 }, { EP0, G, 9, 0 }, { EP0, B, 9, 0 },
765 { EP1, R, 4, 0 }, { EP0, R, 10, 10 }, { EP2, G, 3, 0 },
766 { EP1, G, 3, 0 }, { EP0, G, 10, 10 }, { EP3, B, 0, 0 },
767 { EP3, G, 3, 0 }, { EP1, B, 3, 0 }, { EP0, B, 10, 10 },
768 { EP3, B, 1, 1 }, { EP2, B, 3, 0 }, { EP2, R, 4, 0 },
769 { EP3, B, 2, 2 }, { EP3, R, 4, 0 }, { EP3, B, 3, 3 },
770 { Partition, None, 4, 0 } },
771 // Mode 3
772 {
773 { Mode, None, 4, 0, { 3, false, 1, 10, { 0, 0, 0 } } },
774 { EP0, R, 9, 0 }, { EP0, G, 9, 0 }, { EP0, B, 9, 0 },
775 { EP1, R, 9, 0 }, { EP1, G, 9, 0 }, { EP1, B, 9, 0 },
776 },
777 // Mode 4: Illegal
778 {},
779 // Mode 5: Illegal
780 {},
781 // Mode 6
782 { { Mode, None, 4, 0, { 6, true, 2, 11, { 4, 5, 4 } } },
783 { EP0, R, 9, 0 }, { EP0, G, 9, 0 }, { EP0, B, 9, 0 },
784 { EP1, R, 3, 0 }, { EP0, R, 10, 10 }, { EP3, G, 4, 4 },
785 { EP2, G, 3, 0 }, { EP1, G, 4, 0 }, { EP0, G, 10, 10 },
786 { EP3, G, 3, 0 }, { EP1, B, 3, 0 }, { EP0, B, 10, 10 },
787 { EP3, B, 1, 1 }, { EP2, B, 3, 0 }, { EP2, R, 3, 0 },
788 { EP3, B, 0, 0 }, { EP3, B, 2, 2 }, { EP3, R, 3, 0 },
789 { EP2, G, 4, 4 }, { EP3, B, 3, 3 },
790 { Partition, None, 4, 0 } },
791 // Mode 7
792 {
793 { Mode, None, 4, 0, { 7, true, 1, 11, { 9, 9, 9 } } },
794 { EP0, R, 9, 0 }, { EP0, G, 9, 0 }, { EP0, B, 9, 0 },
795 { EP1, R, 8, 0 }, { EP0, R, 10, 10 }, { EP1, G, 8, 0 },
796 { EP0, G, 10, 10 }, { EP1, B, 8, 0 }, { EP0, B, 10, 10 },
797 },
798 // Mode 8: Illegal
799 {},
800 // Mode 9: Illegal
801 {},
802 // Mode 10
803 { { Mode, None, 4, 0, { 10, true, 2, 11, { 4, 4, 5 } } },
804 { EP0, R, 9, 0 }, { EP0, G, 9, 0 }, { EP0, B, 9, 0 },
805 { EP1, R, 3, 0 }, { EP0, R, 10, 10 }, { EP2, B, 4, 4 },
806 { EP2, G, 3, 0 }, { EP1, G, 3, 0 }, { EP0, G, 10, 10 },
807 { EP3, B, 0, 0 }, { EP3, G, 3, 0 }, { EP1, B, 4, 0 },
808 { EP0, B, 10, 10 }, { EP2, B, 3, 0 }, { EP2, R, 3, 0 },
809 { EP3, B, 1, 1 }, { EP3, B, 2, 2 }, { EP3, R, 3, 0 },
810 { EP3, B, 4, 4 }, { EP3, B, 3, 3 },
811 { Partition, None, 4, 0 } },
812 // Mode 11
813 {
814 { Mode, None, 4, 0, { 11, true, 1, 12, { 8, 8, 8 } } },
815 { EP0, R, 9, 0 }, { EP0, G, 9, 0 }, { EP0, B, 9, 0 },
816 { EP1, R, 7, 0 }, { EP0, R, 10, 11 }, { EP1, G, 7, 0 },
817 { EP0, G, 10, 11 }, { EP1, B, 7, 0 }, { EP0, B, 10, 11 },
818 },
819 // Mode 12: Illegal
820 {},
821 // Mode 13: Illegal
822 {},
823 // Mode 14
824 { { Mode, None, 4, 0, { 14, true, 2, 9, { 5, 5, 5 } } },
825 { EP0, R, 8, 0 }, { EP2, B, 4, 4 }, { EP0, G, 8, 0 },
826 { EP2, G, 4, 4 }, { EP0, B, 8, 0 }, { EP3, B, 4, 4 },
827 { EP1, R, 4, 0 }, { EP3, G, 4, 4 }, { EP2, G, 3, 0 },
828 { EP1, G, 4, 0 }, { EP3, B, 0, 0 }, { EP3, G, 3, 0 },
829 { EP1, B, 4, 0 }, { EP3, B, 1, 1 }, { EP2, B, 3, 0 },
830 { EP2, R, 4, 0 }, { EP3, B, 2, 2 }, { EP3, R, 4, 0 },
831 { EP3, B, 3, 3 },
832 { Partition, None, 4, 0 } },
833 // Mode 15
834 {
835 { Mode, None, 4, 0, { 15, true, 1, 16, { 4, 4, 4 } } },
836 { EP0, R, 9, 0 }, { EP0, G, 9, 0 }, { EP0, B, 9, 0 },
837 { EP1, R, 3, 0 }, { EP0, R, 10, 15 }, { EP1, G, 3, 0 },
838 { EP0, G, 10, 15 }, { EP1, B, 3, 0 }, { EP0, B, 10, 15 },
839 },
840 // Mode 16: Illegal
841 {},
842 // Mode 17: Illegal
843 {},
844 // Mode 18
845 { { Mode, None, 4, 0, { 18, true, 2, 8, { 6, 5, 5 } } },
846 { EP0, R, 7, 0 }, { EP3, G, 4, 4 }, { EP2, B, 4, 4 },
847 { EP0, G, 7, 0 }, { EP3, B, 2, 2 }, { EP2, G, 4, 4 },
848 { EP0, B, 7, 0 }, { EP3, B, 3, 3 }, { EP3, B, 4, 4 },
849 { EP1, R, 5, 0 }, { EP2, G, 3, 0 }, { EP1, G, 4, 0 },
850 { EP3, B, 0, 0 }, { EP3, G, 3, 0 }, { EP1, B, 4, 0 },
851 { EP3, B, 1, 1 }, { EP2, B, 3, 0 }, { EP2, R, 5, 0 },
852 { EP3, R, 5, 0 },
853 { Partition, None, 4, 0 } },
854 // Mode 19: Reserved
855 {},
856 // Mode 20: Illegal
857 {},
858 // Mode 21: Illegal
859 {},
860 // Mode 22:
861 { { Mode, None, 4, 0, { 22, true, 2, 8, { 5, 6, 5 } } },
862 { EP0, R, 7, 0 }, { EP3, B, 0, 0 }, { EP2, B, 4, 4 },
863 { EP0, G, 7, 0 }, { EP2, G, 5, 5 }, { EP2, G, 4, 4 },
864 { EP0, B, 7, 0 }, { EP3, G, 5, 5 }, { EP3, B, 4, 4 },
865 { EP1, R, 4, 0 }, { EP3, G, 4, 4 }, { EP2, G, 3, 0 },
866 { EP1, G, 5, 0 }, { EP3, G, 3, 0 }, { EP1, B, 4, 0 },
867 { EP3, B, 1, 1 }, { EP2, B, 3, 0 }, { EP2, R, 4, 0 },
868 { EP3, B, 2, 2 }, { EP3, R, 4, 0 }, { EP3, B, 3, 3 },
869 { Partition, None, 4, 0 } },
870 // Mode 23: Reserved
871 {},
872 // Mode 24: Illegal
873 {},
874 // Mode 25: Illegal
875 {},
876 // Mode 26
877 { { Mode, None, 4, 0, { 26, true, 2, 8, { 5, 5, 6 } } },
878 { EP0, R, 7, 0 }, { EP3, B, 1, 1 }, { EP2, B, 4, 4 },
879 { EP0, G, 7, 0 }, { EP2, B, 5, 5 }, { EP2, G, 4, 4 },
880 { EP0, B, 7, 0 }, { EP3, B, 5, 5 }, { EP3, B, 4, 4 },
881 { EP1, R, 4, 0 }, { EP3, G, 4, 4 }, { EP2, G, 3, 0 },
882 { EP1, G, 4, 0 }, { EP3, B, 0, 0 }, { EP3, G, 3, 0 },
883 { EP1, B, 5, 0 }, { EP2, B, 3, 0 }, { EP2, R, 4, 0 },
884 { EP3, B, 2, 2 }, { EP3, R, 4, 0 }, { EP3, B, 3, 3 },
885 { Partition, None, 4, 0 } },
886 // Mode 27: Reserved
887 {},
888 // Mode 28: Illegal
889 {},
890 // Mode 29: Illegal
891 {},
892 // Mode 30
893 { { Mode, None, 4, 0, { 30, false, 2, 6, { 0, 0, 0 } } },
894 { EP0, R, 5, 0 }, { EP3, G, 4, 4 }, { EP3, B, 0, 0 },
895 { EP3, B, 1, 1 }, { EP2, B, 4, 4 }, { EP0, G, 5, 0 },
896 { EP2, G, 5, 5 }, { EP2, B, 5, 5 }, { EP3, B, 2, 2 },
897 { EP2, G, 4, 4 }, { EP0, B, 5, 0 }, { EP3, G, 5, 5 },
898 { EP3, B, 3, 3 }, { EP3, B, 5, 5 }, { EP3, B, 4, 4 },
899 { EP1, R, 5, 0 }, { EP2, G, 3, 0 }, { EP1, G, 5, 0 },
900 { EP3, G, 3, 0 }, { EP1, B, 5, 0 }, { EP2, B, 3, 0 },
901 { EP2, R, 5, 0 }, { EP3, R, 5, 0 },
902 { Partition, None, 4, 0 } },
903 // Mode 31: Reserved
904 {},
905 // clang-format on
906 };
907
908 struct Block
909 {
910 uint64_t low64;
911 uint64_t high64;
912
decode__anon659343cc0111::BC6H::Block913 void decode(uint8_t *dst, int dstX, int dstY, int dstWidth, int dstHeight, size_t dstPitch, size_t dstBpp, bool isSigned) const
914 {
915 uint8_t mode = 0;
916 Data data(low64, high64);
917 ASSERT(dstBpp == sizeof(Color));
918
919 if((data.low64 & 0x2) == 0)
920 {
921 mode = data.consumeBits(1, 0);
922 }
923 else
924 {
925 mode = data.consumeBits(4, 0);
926 }
927
928 // Illegal or reserved mode
929 if(blockDescs[mode].size() == 0)
930 {
931 for(int y = 0; y < 4 && y + dstY < dstHeight; y++)
932 {
933 for(int x = 0; x < 4 && x + dstX < dstWidth; x++)
934 {
935 auto out = reinterpret_cast<Color *>(dst + sizeof(Color) * x + dstPitch * y);
936 out->rgba = { 0, 0, 0 };
937 }
938 }
939 return;
940 }
941
942 RGBf e[4];
943 e[0].isSigned = e[1].isSigned = e[2].isSigned = e[3].isSigned = isSigned;
944
945 int partition = 0;
946 ModeDesc modeDesc;
947 // For assertion checks
948 modeDesc.number = -1;
949 for(auto desc : blockDescs[mode])
950 {
951 switch(desc.type)
952 {
953 case Mode:
954 modeDesc = desc.modeDesc;
955 ASSERT(modeDesc.number == mode);
956
957 e[0].size[0] = e[0].size[1] = e[0].size[2] = modeDesc.endpointBits;
958 for(int i = 0; i < RGBfChannels; i++)
959 {
960 if(modeDesc.hasDelta)
961 {
962 e[1].size[i] = e[2].size[i] = e[3].size[i] = modeDesc.deltaBits.channel[i];
963 }
964 else
965 {
966 e[1].size[i] = e[2].size[i] = e[3].size[i] = modeDesc.endpointBits;
967 }
968 }
969 break;
970 case Partition:
971 partition |= data.consumeBits(desc.MSB, desc.LSB);
972 break;
973 case EP0:
974 case EP1:
975 case EP2:
976 case EP3:
977 e[desc.type].channel[desc.channel] |= data.consumeBits(desc.MSB, desc.LSB);
978 break;
979 default:
980 ASSERT_MSG(false, "Unexpected enum value: %d", (int)desc.type);
981 return;
982 }
983 }
984
985 ASSERT_MSG(modeDesc.number != -1, "Failed to decode mode %d", mode);
986
987 // Sign extension
988 if(isSigned)
989 {
990 for(int ep = 0; ep < modeDesc.numEndpoints; ep++)
991 {
992 e[ep].extendSign();
993 }
994 }
995 else if(modeDesc.hasDelta)
996 {
997 // Don't sign-extend the base endpoint in an unsigned format.
998 for(int ep = 1; ep < modeDesc.numEndpoints; ep++)
999 {
1000 e[ep].extendSign();
1001 }
1002 }
1003
1004 // Turn the deltas into endpoints
1005 if(modeDesc.hasDelta)
1006 {
1007 for(int ep = 1; ep < modeDesc.numEndpoints; ep++)
1008 {
1009 e[ep].resolveDelta(e[0]);
1010 }
1011 }
1012
1013 for(int ep = 0; ep < modeDesc.numEndpoints; ep++)
1014 {
1015 e[ep].unquantize();
1016 }
1017
1018 // Get the indices, calculate final colors, and output
1019 for(int y = 0; y < 4; y++)
1020 {
1021 for(int x = 0; x < 4; x++)
1022 {
1023 int pixelNum = x + y * 4;
1024 IndexInfo idx;
1025 bool isAnchor = false;
1026 int firstEndpoint = 0;
1027 // Bc6H can have either 1 or 2 petitions depending on the mode.
1028 // The number of petitions affects the number of indices with implicit
1029 // leading 0 bits and the number of bits per index.
1030 if(modeDesc.partitionCount == 1)
1031 {
1032 idx.numBits = 4;
1033 // There's an implicit leading 0 bit for the first idx
1034 isAnchor = (pixelNum == 0);
1035 }
1036 else
1037 {
1038 idx.numBits = 3;
1039 // There are 2 indices with implicit leading 0-bits.
1040 isAnchor = ((pixelNum == 0) || (pixelNum == AnchorTable2[partition]));
1041 firstEndpoint = PartitionTable2[partition][pixelNum] * 2;
1042 }
1043
1044 idx.value = data.consumeBits(idx.numBits - isAnchor - 1, 0);
1045
1046 // Don't exit the loop early, we need to consume these index bits regardless if
1047 // we actually output them or not.
1048 if((y + dstY >= dstHeight) || (x + dstX >= dstWidth))
1049 {
1050 continue;
1051 }
1052
1053 Color color = interpolate(e[firstEndpoint], e[firstEndpoint + 1], idx, isSigned);
1054 auto out = reinterpret_cast<Color *>(dst + dstBpp * x + dstPitch * y);
1055 *out = color;
1056 }
1057 }
1058 }
1059 };
1060
1061 } // namespace BC6H
1062
1063 namespace BC7 {
1064 // https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_compression_bptc.txt
1065 // https://docs.microsoft.com/en-us/windows/win32/direct3d11/bc7-format
1066
1067 struct Bitfield
1068 {
1069 int offset;
1070 int count;
Then__anon659343cc0111::BC7::Bitfield1071 constexpr Bitfield Then(const int bits) { return { offset + count, bits }; }
operator ==__anon659343cc0111::BC7::Bitfield1072 constexpr bool operator==(const Bitfield &rhs)
1073 {
1074 return offset == rhs.offset && count == rhs.count;
1075 }
1076 };
1077
1078 struct Mode
1079 {
1080 const int IDX; // Mode index
1081 const int NS; // Number of subsets in each partition
1082 const int PB; // Partition bits
1083 const int RB; // Rotation bits
1084 const int ISB; // Index selection bits
1085 const int CB; // Color bits
1086 const int AB; // Alpha bits
1087 const int EPB; // Endpoint P-bits
1088 const int SPB; // Shared P-bits
1089 const int IB; // Primary index bits per element
1090 const int IBC; // Primary index bits total
1091 const int IB2; // Secondary index bits per element
1092
NumColors__anon659343cc0111::BC7::Mode1093 constexpr int NumColors() const { return NS * 2; }
Partition__anon659343cc0111::BC7::Mode1094 constexpr Bitfield Partition() const { return { IDX + 1, PB }; }
Rotation__anon659343cc0111::BC7::Mode1095 constexpr Bitfield Rotation() const { return Partition().Then(RB); }
IndexSelection__anon659343cc0111::BC7::Mode1096 constexpr Bitfield IndexSelection() const { return Rotation().Then(ISB); }
Red__anon659343cc0111::BC7::Mode1097 constexpr Bitfield Red(int idx) const
1098 {
1099 return IndexSelection().Then(CB * idx).Then(CB);
1100 }
Green__anon659343cc0111::BC7::Mode1101 constexpr Bitfield Green(int idx) const
1102 {
1103 return Red(NumColors() - 1).Then(CB * idx).Then(CB);
1104 }
Blue__anon659343cc0111::BC7::Mode1105 constexpr Bitfield Blue(int idx) const
1106 {
1107 return Green(NumColors() - 1).Then(CB * idx).Then(CB);
1108 }
Alpha__anon659343cc0111::BC7::Mode1109 constexpr Bitfield Alpha(int idx) const
1110 {
1111 return Blue(NumColors() - 1).Then(AB * idx).Then(AB);
1112 }
EndpointPBit__anon659343cc0111::BC7::Mode1113 constexpr Bitfield EndpointPBit(int idx) const
1114 {
1115 return Alpha(NumColors() - 1).Then(EPB * idx).Then(EPB);
1116 }
SharedPBit0__anon659343cc0111::BC7::Mode1117 constexpr Bitfield SharedPBit0() const
1118 {
1119 return EndpointPBit(NumColors() - 1).Then(SPB);
1120 }
SharedPBit1__anon659343cc0111::BC7::Mode1121 constexpr Bitfield SharedPBit1() const
1122 {
1123 return SharedPBit0().Then(SPB);
1124 }
PrimaryIndex__anon659343cc0111::BC7::Mode1125 constexpr Bitfield PrimaryIndex(int offset, int count) const
1126 {
1127 return SharedPBit1().Then(offset).Then(count);
1128 }
SecondaryIndex__anon659343cc0111::BC7::Mode1129 constexpr Bitfield SecondaryIndex(int offset, int count) const
1130 {
1131 return SharedPBit1().Then(IBC + offset).Then(count);
1132 }
1133 };
1134
1135 static constexpr Mode Modes[] = {
1136 // IDX NS PB RB ISB CB AB EPB SPB IB IBC, IB2
1137 /**/ { 0x0, 0x3, 0x4, 0x0, 0x0, 0x4, 0x0, 0x1, 0x0, 0x3, 0x2d, 0x0 },
1138 /**/ { 0x1, 0x2, 0x6, 0x0, 0x0, 0x6, 0x0, 0x0, 0x1, 0x3, 0x2e, 0x0 },
1139 /**/ { 0x2, 0x3, 0x6, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x2, 0x1d, 0x0 },
1140 /**/ { 0x3, 0x2, 0x6, 0x0, 0x0, 0x7, 0x0, 0x1, 0x0, 0x2, 0x1e, 0x0 },
1141 /**/ { 0x4, 0x1, 0x0, 0x2, 0x1, 0x5, 0x6, 0x0, 0x0, 0x2, 0x1f, 0x3 },
1142 /**/ { 0x5, 0x1, 0x0, 0x2, 0x0, 0x7, 0x8, 0x0, 0x0, 0x2, 0x1f, 0x2 },
1143 /**/ { 0x6, 0x1, 0x0, 0x0, 0x0, 0x7, 0x7, 0x1, 0x0, 0x4, 0x3f, 0x0 },
1144 /**/ { 0x7, 0x2, 0x6, 0x0, 0x0, 0x5, 0x5, 0x1, 0x0, 0x2, 0x1e, 0x0 },
1145 /**/ { -1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x00, 0x0 },
1146 };
1147
1148 static_assert(Modes[0].NumColors() == 6, "BC7 static assertion failed");
1149 static_assert(Modes[0].Partition() == Bitfield{ 1, 4 }, "BC7 static assertion failed");
1150 static_assert(Modes[0].Red(0) == Bitfield{ 5, 4 }, "BC7 static assertion failed");
1151 static_assert(Modes[0].Red(5) == Bitfield{ 25, 4 }, "BC7 static assertion failed");
1152 static_assert(Modes[0].Green(0) == Bitfield{ 29, 4 }, "BC7 static assertion failed");
1153 static_assert(Modes[0].Green(5) == Bitfield{ 49, 4 }, "BC7 static assertion failed");
1154 static_assert(Modes[0].Blue(0) == Bitfield{ 53, 4 }, "BC7 static assertion failed");
1155 static_assert(Modes[0].Blue(5) == Bitfield{ 73, 4 }, "BC7 static assertion failed");
1156 static_assert(Modes[0].EndpointPBit(0) == Bitfield{ 77, 1 }, "BC7 static assertion failed");
1157 static_assert(Modes[0].EndpointPBit(5) == Bitfield{ 82, 1 }, "BC7 static assertion failed");
1158 static_assert(Modes[0].PrimaryIndex(0, 2) == Bitfield{ 83, 2 }, "BC7 static asassertionsert failed");
1159 static_assert(Modes[0].PrimaryIndex(43, 1) == Bitfield{ 126, 1 }, "BC7 static assertion failed");
1160
1161 static constexpr int MaxPartitions = 64;
1162 static constexpr int MaxSubsets = 3;
1163
1164 static constexpr uint8_t PartitionTable2[MaxPartitions][16] = {
1165 { 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 },
1166 { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 },
1167 { 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
1168 { 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1 },
1169 { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1 },
1170 { 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
1171 { 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
1172 { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1 },
1173 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1 },
1174 { 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
1175 { 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
1176 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1 },
1177 { 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
1178 { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 },
1179 { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
1180 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 },
1181 { 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1 },
1182 { 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
1183 { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0 },
1184 { 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0 },
1185 { 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
1186 { 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0 },
1187 { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 },
1188 { 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1 },
1189 { 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0 },
1190 { 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 },
1191 { 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0 },
1192 { 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0 },
1193 { 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0 },
1194 { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 },
1195 { 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0 },
1196 { 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0 },
1197 { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 },
1198 { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1 },
1199 { 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0 },
1200 { 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0 },
1201 { 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0 },
1202 { 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0 },
1203 { 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1 },
1204 { 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1 },
1205 { 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0 },
1206 { 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0 },
1207 { 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0 },
1208 { 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0 },
1209 { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 },
1210 { 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1 },
1211 { 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1 },
1212 { 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0 },
1213 { 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 },
1214 { 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0 },
1215 { 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0 },
1216 { 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0 },
1217 { 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1 },
1218 { 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1 },
1219 { 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0 },
1220 { 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0 },
1221 { 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1 },
1222 { 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1 },
1223 { 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1 },
1224 { 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1 },
1225 { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 },
1226 { 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 },
1227 { 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0 },
1228 { 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1 },
1229 };
1230
1231 static constexpr uint8_t PartitionTable3[MaxPartitions][16] = {
1232 { 0, 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 1, 2, 2, 2, 2 },
1233 { 0, 0, 0, 1, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1 },
1234 { 0, 0, 0, 0, 2, 0, 0, 1, 2, 2, 1, 1, 2, 2, 1, 1 },
1235 { 0, 2, 2, 2, 0, 0, 2, 2, 0, 0, 1, 1, 0, 1, 1, 1 },
1236 { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2 },
1237 { 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 2, 2 },
1238 { 0, 0, 2, 2, 0, 0, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1 },
1239 { 0, 0, 1, 1, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1 },
1240 { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2 },
1241 { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2 },
1242 { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2 },
1243 { 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2 },
1244 { 0, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 2 },
1245 { 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 2 },
1246 { 0, 0, 1, 1, 0, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2 },
1247 { 0, 0, 1, 1, 2, 0, 0, 1, 2, 2, 0, 0, 2, 2, 2, 0 },
1248 { 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 2, 1, 1, 2, 2 },
1249 { 0, 1, 1, 1, 0, 0, 1, 1, 2, 0, 0, 1, 2, 2, 0, 0 },
1250 { 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2 },
1251 { 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 1, 1, 1, 1 },
1252 { 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2 },
1253 { 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, 2, 1, 2, 2, 2, 1 },
1254 { 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 2, 0, 1, 2, 2 },
1255 { 0, 0, 0, 0, 1, 1, 0, 0, 2, 2, 1, 0, 2, 2, 1, 0 },
1256 { 0, 1, 2, 2, 0, 1, 2, 2, 0, 0, 1, 1, 0, 0, 0, 0 },
1257 { 0, 0, 1, 2, 0, 0, 1, 2, 1, 1, 2, 2, 2, 2, 2, 2 },
1258 { 0, 1, 1, 0, 1, 2, 2, 1, 1, 2, 2, 1, 0, 1, 1, 0 },
1259 { 0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 2, 1, 1, 2, 2, 1 },
1260 { 0, 0, 2, 2, 1, 1, 0, 2, 1, 1, 0, 2, 0, 0, 2, 2 },
1261 { 0, 1, 1, 0, 0, 1, 1, 0, 2, 0, 0, 2, 2, 2, 2, 2 },
1262 { 0, 0, 1, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 0, 1, 1 },
1263 { 0, 0, 0, 0, 2, 0, 0, 0, 2, 2, 1, 1, 2, 2, 2, 1 },
1264 { 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 2, 2, 2 },
1265 { 0, 2, 2, 2, 0, 0, 2, 2, 0, 0, 1, 2, 0, 0, 1, 1 },
1266 { 0, 0, 1, 1, 0, 0, 1, 2, 0, 0, 2, 2, 0, 2, 2, 2 },
1267 { 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0 },
1268 { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0, 0 },
1269 { 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0 },
1270 { 0, 1, 2, 0, 2, 0, 1, 2, 1, 2, 0, 1, 0, 1, 2, 0 },
1271 { 0, 0, 1, 1, 2, 2, 0, 0, 1, 1, 2, 2, 0, 0, 1, 1 },
1272 { 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0, 0, 1, 1 },
1273 { 0, 1, 0, 1, 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2 },
1274 { 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 1, 2, 1, 2, 1 },
1275 { 0, 0, 2, 2, 1, 1, 2, 2, 0, 0, 2, 2, 1, 1, 2, 2 },
1276 { 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 1, 1 },
1277 { 0, 2, 2, 0, 1, 2, 2, 1, 0, 2, 2, 0, 1, 2, 2, 1 },
1278 { 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 1 },
1279 { 0, 0, 0, 0, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1 },
1280 { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 2, 2, 2, 2 },
1281 { 0, 2, 2, 2, 0, 1, 1, 1, 0, 2, 2, 2, 0, 1, 1, 1 },
1282 { 0, 0, 0, 2, 1, 1, 1, 2, 0, 0, 0, 2, 1, 1, 1, 2 },
1283 { 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2 },
1284 { 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2 },
1285 { 0, 0, 0, 2, 1, 1, 1, 2, 1, 1, 1, 2, 0, 0, 0, 2 },
1286 { 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 2, 2 },
1287 { 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 1, 2 },
1288 { 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 2 },
1289 { 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2, 2 },
1290 { 0, 0, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 0, 0, 2, 2 },
1291 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2 },
1292 { 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 1 },
1293 { 0, 2, 2, 2, 1, 2, 2, 2, 0, 2, 2, 2, 1, 2, 2, 2 },
1294 { 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
1295 { 0, 1, 1, 1, 2, 0, 1, 1, 2, 2, 0, 1, 2, 2, 2, 0 },
1296 };
1297
1298 static constexpr uint8_t AnchorTable2[MaxPartitions] = {
1299 // clang-format off
1300 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
1301 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
1302 0xf, 0x2, 0x8, 0x2, 0x2, 0x8, 0x8, 0xf,
1303 0x2, 0x8, 0x2, 0x2, 0x8, 0x8, 0x2, 0x2,
1304 0xf, 0xf, 0x6, 0x8, 0x2, 0x8, 0xf, 0xf,
1305 0x2, 0x8, 0x2, 0x2, 0x2, 0xf, 0xf, 0x6,
1306 0x6, 0x2, 0x6, 0x8, 0xf, 0xf, 0x2, 0x2,
1307 0xf, 0xf, 0xf, 0xf, 0xf, 0x2, 0x2, 0xf,
1308 // clang-format on
1309 };
1310
1311 static constexpr uint8_t AnchorTable3a[MaxPartitions] = {
1312 // clang-format off
1313 0x3, 0x3, 0xf, 0xf, 0x8, 0x3, 0xf, 0xf,
1314 0x8, 0x8, 0x6, 0x6, 0x6, 0x5, 0x3, 0x3,
1315 0x3, 0x3, 0x8, 0xf, 0x3, 0x3, 0x6, 0xa,
1316 0x5, 0x8, 0x8, 0x6, 0x8, 0x5, 0xf, 0xf,
1317 0x8, 0xf, 0x3, 0x5, 0x6, 0xa, 0x8, 0xf,
1318 0xf, 0x3, 0xf, 0x5, 0xf, 0xf, 0xf, 0xf,
1319 0x3, 0xf, 0x5, 0x5, 0x5, 0x8, 0x5, 0xa,
1320 0x5, 0xa, 0x8, 0xd, 0xf, 0xc, 0x3, 0x3,
1321 // clang-format on
1322 };
1323
1324 static constexpr uint8_t AnchorTable3b[MaxPartitions] = {
1325 // clang-format off
1326 0xf, 0x8, 0x8, 0x3, 0xf, 0xf, 0x3, 0x8,
1327 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x8,
1328 0xf, 0x8, 0xf, 0x3, 0xf, 0x8, 0xf, 0x8,
1329 0x3, 0xf, 0x6, 0xa, 0xf, 0xf, 0xa, 0x8,
1330 0xf, 0x3, 0xf, 0xa, 0xa, 0x8, 0x9, 0xa,
1331 0x6, 0xf, 0x8, 0xf, 0x3, 0x6, 0x6, 0x8,
1332 0xf, 0x3, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
1333 0xf, 0xf, 0xf, 0xf, 0x3, 0xf, 0xf, 0x8,
1334 // clang-format on
1335 };
1336
1337 struct Color
1338 {
1339 struct RGB
1340 {
1341 RGB() = default;
RGB__anon659343cc0111::BC7::Color::RGB1342 RGB(uint8_t r, uint8_t g, uint8_t b)
1343 : b(b)
1344 , g(g)
1345 , r(r)
1346 {}
RGB__anon659343cc0111::BC7::Color::RGB1347 RGB(int r, int g, int b)
1348 : b(static_cast<uint8_t>(b))
1349 , g(static_cast<uint8_t>(g))
1350 , r(static_cast<uint8_t>(r))
1351 {}
1352
operator <<__anon659343cc0111::BC7::Color::RGB1353 RGB operator<<(int shift) const { return { r << shift, g << shift, b << shift }; }
operator >>__anon659343cc0111::BC7::Color::RGB1354 RGB operator>>(int shift) const { return { r >> shift, g >> shift, b >> shift }; }
operator |__anon659343cc0111::BC7::Color::RGB1355 RGB operator|(int bits) const { return { r | bits, g | bits, b | bits }; }
operator |__anon659343cc0111::BC7::Color::RGB1356 RGB operator|(const RGB &rhs) const { return { r | rhs.r, g | rhs.g, b | rhs.b }; }
operator +__anon659343cc0111::BC7::Color::RGB1357 RGB operator+(const RGB &rhs) const { return { r + rhs.r, g + rhs.g, b + rhs.b }; }
1358
1359 uint8_t b;
1360 uint8_t g;
1361 uint8_t r;
1362 };
1363
1364 RGB rgb;
1365 uint8_t a;
1366 };
1367
1368 static_assert(sizeof(Color) == 4, "Color size must be 4 bytes");
1369
1370 struct Block
1371 {
Get__anon659343cc0111::BC7::Block1372 constexpr uint64_t Get(const Bitfield &bf) const
1373 {
1374 uint64_t mask = (1ULL << bf.count) - 1;
1375 if(bf.offset + bf.count <= 64)
1376 {
1377 return (low >> bf.offset) & mask;
1378 }
1379 if(bf.offset >= 64)
1380 {
1381 return (high >> (bf.offset - 64)) & mask;
1382 }
1383 return ((low >> bf.offset) | (high << (64 - bf.offset))) & mask;
1384 }
1385
mode__anon659343cc0111::BC7::Block1386 const Mode &mode() const
1387 {
1388 if((low & 0b00000001) != 0) { return Modes[0]; }
1389 if((low & 0b00000010) != 0) { return Modes[1]; }
1390 if((low & 0b00000100) != 0) { return Modes[2]; }
1391 if((low & 0b00001000) != 0) { return Modes[3]; }
1392 if((low & 0b00010000) != 0) { return Modes[4]; }
1393 if((low & 0b00100000) != 0) { return Modes[5]; }
1394 if((low & 0b01000000) != 0) { return Modes[6]; }
1395 if((low & 0b10000000) != 0) { return Modes[7]; }
1396 return Modes[8]; // Invalid mode
1397 }
1398
1399 struct IndexInfo
1400 {
1401 uint64_t value;
1402 int numBits;
1403 };
1404
interpolate__anon659343cc0111::BC7::Block1405 uint8_t interpolate(uint8_t e0, uint8_t e1, const IndexInfo &index) const
1406 {
1407 static constexpr uint16_t weights2[] = { 0, 21, 43, 64 };
1408 static constexpr uint16_t weights3[] = { 0, 9, 18, 27, 37, 46, 55, 64 };
1409 static constexpr uint16_t weights4[] = { 0, 4, 9, 13, 17, 21, 26, 30,
1410 34, 38, 43, 47, 51, 55, 60, 64 };
1411 static constexpr uint16_t const *weightsN[] = {
1412 nullptr, nullptr, weights2, weights3, weights4
1413 };
1414 auto weights = weightsN[index.numBits];
1415 ASSERT_MSG(weights != nullptr, "Unexpected number of index bits: %d", (int)index.numBits);
1416 return (uint8_t)(((64 - weights[index.value]) * uint16_t(e0) + weights[index.value] * uint16_t(e1) + 32) >> 6);
1417 }
1418
decode__anon659343cc0111::BC7::Block1419 void decode(uint8_t *dst, int dstX, int dstY, int dstWidth, int dstHeight, size_t dstPitch) const
1420 {
1421 auto const &mode = this->mode();
1422
1423 if(mode.IDX < 0) // Invalid mode:
1424 {
1425 for(int y = 0; y < 4 && y + dstY < dstHeight; y++)
1426 {
1427 for(int x = 0; x < 4 && x + dstX < dstWidth; x++)
1428 {
1429 auto out = reinterpret_cast<Color *>(dst + sizeof(Color) * x + dstPitch * y);
1430 out->rgb = { 0, 0, 0 };
1431 out->a = 0;
1432 }
1433 }
1434 return;
1435 }
1436
1437 using Endpoint = std::array<Color, 2>;
1438 std::array<Endpoint, MaxSubsets> subsets;
1439
1440 for(int i = 0; i < mode.NS; i++)
1441 {
1442 auto &subset = subsets[i];
1443 subset[0].rgb.r = Get(mode.Red(i * 2 + 0));
1444 subset[0].rgb.g = Get(mode.Green(i * 2 + 0));
1445 subset[0].rgb.b = Get(mode.Blue(i * 2 + 0));
1446 subset[0].a = (mode.AB > 0) ? Get(mode.Alpha(i * 2 + 0)) : 255;
1447
1448 subset[1].rgb.r = Get(mode.Red(i * 2 + 1));
1449 subset[1].rgb.g = Get(mode.Green(i * 2 + 1));
1450 subset[1].rgb.b = Get(mode.Blue(i * 2 + 1));
1451 subset[1].a = (mode.AB > 0) ? Get(mode.Alpha(i * 2 + 1)) : 255;
1452 }
1453
1454 if(mode.SPB > 0)
1455 {
1456 auto pbit0 = Get(mode.SharedPBit0());
1457 auto pbit1 = Get(mode.SharedPBit1());
1458 subsets[0][0].rgb = (subsets[0][0].rgb << 1) | pbit0;
1459 subsets[0][1].rgb = (subsets[0][1].rgb << 1) | pbit0;
1460 subsets[1][0].rgb = (subsets[1][0].rgb << 1) | pbit1;
1461 subsets[1][1].rgb = (subsets[1][1].rgb << 1) | pbit1;
1462 }
1463
1464 if(mode.EPB > 0)
1465 {
1466 for(int i = 0; i < mode.NS; i++)
1467 {
1468 auto &subset = subsets[i];
1469 auto pbit0 = Get(mode.EndpointPBit(i * 2 + 0));
1470 auto pbit1 = Get(mode.EndpointPBit(i * 2 + 1));
1471 subset[0].rgb = (subset[0].rgb << 1) | pbit0;
1472 subset[1].rgb = (subset[1].rgb << 1) | pbit1;
1473 if(mode.AB > 0)
1474 {
1475 subset[0].a = (subset[0].a << 1) | pbit0;
1476 subset[1].a = (subset[1].a << 1) | pbit1;
1477 }
1478 }
1479 }
1480
1481 auto const colorBits = mode.CB + mode.SPB + mode.EPB;
1482 auto const alphaBits = mode.AB + mode.SPB + mode.EPB;
1483
1484 for(int i = 0; i < mode.NS; i++)
1485 {
1486 auto &subset = subsets[i];
1487 subset[0].rgb = subset[0].rgb << (8 - colorBits);
1488 subset[1].rgb = subset[1].rgb << (8 - colorBits);
1489 subset[0].rgb = subset[0].rgb | (subset[0].rgb >> colorBits);
1490 subset[1].rgb = subset[1].rgb | (subset[1].rgb >> colorBits);
1491
1492 if(mode.AB > 0)
1493 {
1494 subset[0].a = subset[0].a << (8 - alphaBits);
1495 subset[1].a = subset[1].a << (8 - alphaBits);
1496 subset[0].a = subset[0].a | (subset[0].a >> alphaBits);
1497 subset[1].a = subset[1].a | (subset[1].a >> alphaBits);
1498 }
1499 }
1500
1501 int colorIndexBitOffset = 0;
1502 int alphaIndexBitOffset = 0;
1503 for(int y = 0; y < 4; y++)
1504 {
1505 for(int x = 0; x < 4; x++)
1506 {
1507 auto texelIdx = y * 4 + x;
1508 auto partitionIdx = Get(mode.Partition());
1509 ASSERT(partitionIdx < MaxPartitions);
1510 auto subsetIdx = subsetIndex(mode, partitionIdx, texelIdx);
1511 ASSERT(subsetIdx < MaxSubsets);
1512 auto const &subset = subsets[subsetIdx];
1513
1514 auto anchorIdx = anchorIndex(mode, partitionIdx, subsetIdx);
1515 auto isAnchor = anchorIdx == texelIdx;
1516 auto colorIdx = colorIndex(mode, isAnchor, colorIndexBitOffset);
1517 auto alphaIdx = alphaIndex(mode, isAnchor, alphaIndexBitOffset);
1518
1519 if(y + dstY >= dstHeight || x + dstX >= dstWidth)
1520 {
1521 // Don't be tempted to skip early at the loops:
1522 // The calls to colorIndex() and alphaIndex() adjust bit
1523 // offsets that need to be carefully tracked.
1524 continue;
1525 }
1526
1527 Color output;
1528 output.rgb.r = interpolate(subset[0].rgb.r, subset[1].rgb.r, colorIdx);
1529 output.rgb.g = interpolate(subset[0].rgb.g, subset[1].rgb.g, colorIdx);
1530 output.rgb.b = interpolate(subset[0].rgb.b, subset[1].rgb.b, colorIdx);
1531 output.a = interpolate(subset[0].a, subset[1].a, alphaIdx);
1532
1533 switch(Get(mode.Rotation()))
1534 {
1535 default:
1536 break;
1537 case 1:
1538 std::swap(output.a, output.rgb.r);
1539 break;
1540 case 2:
1541 std::swap(output.a, output.rgb.g);
1542 break;
1543 case 3:
1544 std::swap(output.a, output.rgb.b);
1545 break;
1546 }
1547
1548 auto out = reinterpret_cast<Color *>(dst + sizeof(Color) * x + dstPitch * y);
1549 *out = output;
1550 }
1551 }
1552 }
1553
subsetIndex__anon659343cc0111::BC7::Block1554 int subsetIndex(const Mode &mode, int partitionIdx, int texelIndex) const
1555 {
1556 switch(mode.NS)
1557 {
1558 default:
1559 return 0;
1560 case 2:
1561 return PartitionTable2[partitionIdx][texelIndex];
1562 case 3:
1563 return PartitionTable3[partitionIdx][texelIndex];
1564 }
1565 }
1566
anchorIndex__anon659343cc0111::BC7::Block1567 int anchorIndex(const Mode &mode, int partitionIdx, int subsetIdx) const
1568 {
1569 // ARB_texture_compression_bptc states:
1570 // "In partition zero, the anchor index is always index zero.
1571 // In other partitions, the anchor index is specified by tables
1572 // Table.A2 and Table.A3.""
1573 // Note: This is really confusing - I believe they meant subset instead
1574 // of partition here.
1575 switch(subsetIdx)
1576 {
1577 default:
1578 return 0;
1579 case 1:
1580 return mode.NS == 2 ? AnchorTable2[partitionIdx] : AnchorTable3a[partitionIdx];
1581 case 2:
1582 return AnchorTable3b[partitionIdx];
1583 }
1584 }
1585
colorIndex__anon659343cc0111::BC7::Block1586 IndexInfo colorIndex(const Mode &mode, bool isAnchor,
1587 int &indexBitOffset) const
1588 {
1589 // ARB_texture_compression_bptc states:
1590 // "The index value for interpolating color comes from the secondary
1591 // index for the texel if the format has an index selection bit and its
1592 // value is one and from the primary index otherwise.""
1593 auto idx = Get(mode.IndexSelection());
1594 ASSERT(idx <= 1);
1595 bool secondary = idx == 1;
1596 auto numBits = secondary ? mode.IB2 : mode.IB;
1597 auto numReadBits = numBits - (isAnchor ? 1 : 0);
1598 auto index =
1599 Get(secondary ? mode.SecondaryIndex(indexBitOffset, numReadBits)
1600 : mode.PrimaryIndex(indexBitOffset, numReadBits));
1601 indexBitOffset += numReadBits;
1602 return { index, numBits };
1603 }
1604
alphaIndex__anon659343cc0111::BC7::Block1605 IndexInfo alphaIndex(const Mode &mode, bool isAnchor,
1606 int &indexBitOffset) const
1607 {
1608 // ARB_texture_compression_bptc states:
1609 // "The alpha index comes from the secondary index if the block has a
1610 // secondary index and the block either doesn't have an index selection
1611 // bit or that bit is zero and the primary index otherwise."
1612 auto idx = Get(mode.IndexSelection());
1613 ASSERT(idx <= 1);
1614 bool secondary = (mode.IB2 != 0) && (idx == 0);
1615 auto numBits = secondary ? mode.IB2 : mode.IB;
1616 auto numReadBits = numBits - (isAnchor ? 1 : 0);
1617 auto index =
1618 Get(secondary ? mode.SecondaryIndex(indexBitOffset, numReadBits)
1619 : mode.PrimaryIndex(indexBitOffset, numReadBits));
1620 indexBitOffset += numReadBits;
1621 return { index, numBits };
1622 }
1623
1624 // Assumes little-endian
1625 uint64_t low;
1626 uint64_t high;
1627 };
1628
1629 } // namespace BC7
1630 } // anonymous namespace
1631
1632 // 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)1633 bool BC_Decoder::Decode(const uint8_t *src, uint8_t *dst, int w, int h, int dstPitch, int dstBpp, int n, bool isNoAlphaU)
1634 {
1635 static_assert(sizeof(BC_color) == 8, "BC_color must be 8 bytes");
1636 static_assert(sizeof(BC_channel) == 8, "BC_channel must be 8 bytes");
1637 static_assert(sizeof(BC_alpha) == 8, "BC_alpha must be 8 bytes");
1638
1639 const int dx = BlockWidth * dstBpp;
1640 const int dy = BlockHeight * dstPitch;
1641 const bool isAlpha = (n == 1) && !isNoAlphaU;
1642 const bool isSigned = ((n == 4) || (n == 5) || (n == 6)) && !isNoAlphaU;
1643
1644 switch(n)
1645 {
1646 case 1: // BC1
1647 {
1648 const BC_color *color = reinterpret_cast<const BC_color *>(src);
1649 for(int y = 0; y < h; y += BlockHeight, dst += dy)
1650 {
1651 uint8_t *dstRow = dst;
1652 for(int x = 0; x < w; x += BlockWidth, ++color, dstRow += dx)
1653 {
1654 color->decode(dstRow, x, y, w, h, dstPitch, dstBpp, isAlpha, false);
1655 }
1656 }
1657 }
1658 break;
1659 case 2: // BC2
1660 {
1661 const BC_alpha *alpha = reinterpret_cast<const BC_alpha *>(src);
1662 const BC_color *color = reinterpret_cast<const BC_color *>(src + 8);
1663 for(int y = 0; y < h; y += BlockHeight, dst += dy)
1664 {
1665 uint8_t *dstRow = dst;
1666 for(int x = 0; x < w; x += BlockWidth, alpha += 2, color += 2, dstRow += dx)
1667 {
1668 color->decode(dstRow, x, y, w, h, dstPitch, dstBpp, isAlpha, true);
1669 alpha->decode(dstRow, x, y, w, h, dstPitch, dstBpp);
1670 }
1671 }
1672 }
1673 break;
1674 case 3: // BC3
1675 {
1676 const BC_channel *alpha = reinterpret_cast<const BC_channel *>(src);
1677 const BC_color *color = reinterpret_cast<const BC_color *>(src + 8);
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, alpha += 2, color += 2, dstRow += dx)
1682 {
1683 color->decode(dstRow, x, y, w, h, dstPitch, dstBpp, isAlpha, true);
1684 alpha->decode(dstRow, x, y, w, h, dstPitch, dstBpp, 3, isSigned);
1685 }
1686 }
1687 }
1688 break;
1689 case 4: // BC4
1690 {
1691 const BC_channel *red = reinterpret_cast<const BC_channel *>(src);
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, ++red, dstRow += dx)
1696 {
1697 red->decode(dstRow, x, y, w, h, dstPitch, dstBpp, 0, isSigned);
1698 }
1699 }
1700 }
1701 break;
1702 case 5: // BC5
1703 {
1704 const BC_channel *red = reinterpret_cast<const BC_channel *>(src);
1705 const BC_channel *green = reinterpret_cast<const BC_channel *>(src + 8);
1706 for(int y = 0; y < h; y += BlockHeight, dst += dy)
1707 {
1708 uint8_t *dstRow = dst;
1709 for(int x = 0; x < w; x += BlockWidth, red += 2, green += 2, dstRow += dx)
1710 {
1711 red->decode(dstRow, x, y, w, h, dstPitch, dstBpp, 0, isSigned);
1712 green->decode(dstRow, x, y, w, h, dstPitch, dstBpp, 1, isSigned);
1713 }
1714 }
1715 }
1716 break;
1717 case 6: // BC6H
1718 {
1719 const BC6H::Block *block = reinterpret_cast<const BC6H::Block *>(src);
1720 for(int y = 0; y < h; y += BlockHeight, dst += dy)
1721 {
1722 uint8_t *dstRow = dst;
1723 for(int x = 0; x < w; x += BlockWidth, ++block, dstRow += dx)
1724 {
1725 block->decode(dstRow, x, y, w, h, dstPitch, dstBpp, isSigned);
1726 }
1727 }
1728 }
1729 break;
1730 case 7: // BC7
1731 {
1732 const BC7::Block *block = reinterpret_cast<const BC7::Block *>(src);
1733 for(int y = 0; y < h; y += BlockHeight, dst += dy)
1734 {
1735 uint8_t *dstRow = dst;
1736 for(int x = 0; x < w; x += BlockWidth, ++block, dstRow += dx)
1737 {
1738 block->decode(dstRow, x, y, w, h, dstPitch);
1739 }
1740 }
1741 }
1742 break;
1743 default:
1744 return false;
1745 }
1746
1747 return true;
1748 }
1749