react-native-alpha-video-gpu 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +949 -2
  3. package/THIRD_PARTY_NOTICES.md +14 -0
  4. package/android/src/main/AndroidManifest.xml +9 -0
  5. package/android/src/main/cpp/CMakeLists.txt +41 -0
  6. package/android/src/main/cpp/alphavideogpu_jni.cpp +1168 -0
  7. package/android/src/main/cpp/astc_decomp.cpp +1550 -0
  8. package/android/src/main/cpp/astc_decomp.h +41 -0
  9. package/android/src/main/cpp/source_jni.cpp +242 -0
  10. package/android/src/main/cpp/source_jni.h +13 -0
  11. package/android/src/main/java/dev/mediacache/alphavideo/gpu/AlphaVideoGpuNative.java +43 -0
  12. package/android/src/main/java/dev/mediacache/alphavideo/gpu/AlphaVideoGpuReader.java +209 -0
  13. package/android/src/main/java/dev/mediacache/alphavideo/gpu/AlphaVideoGpuSource.java +328 -0
  14. package/android/src/main/java/dev/mediacache/alphavideo/gpu/AlphaVideoGpuView.java +2126 -0
  15. package/android/src/main/java/dev/mediacache/alphavideo/gpu/Fetcher.java +37 -0
  16. package/android/src/main/java/dev/mediacache/alphavideo/gpu/HttpFetcher.java +156 -0
  17. package/android/src/main/java/dev/mediacache/alphavideo/gpu/Ktx2Metadata.java +78 -0
  18. package/android/src/main/java/dev/mediacache/alphavideo/gpu/RangeSourceLink.java +54 -0
  19. package/android/src/main/java/dev/mediacache/alphavideo/gpu/ZstdSeekTable.java +120 -0
  20. package/android/src/rangesource/java/dev/mediacache/alphavideo/gpu/AppDataSource.java +50 -0
  21. package/ios/Sources/AlphaVideoGPU/AlphaVideoGpuSource.h +63 -0
  22. package/ios/Sources/AlphaVideoGPU/AlphaVideoGpuSource.mm +522 -0
  23. package/ios/Sources/AlphaVideoGPU/AlphaVideoGpuView.mm +2722 -0
  24. package/ios/Sources/AlphaVideoGPU/astc_decomp.cpp +1550 -0
  25. package/ios/Sources/AlphaVideoGPU/astc_decomp.h +41 -0
  26. package/ios/Sources/AlphaVideoGPU/include/AlphaVideoGPU.h +110 -0
  27. package/ios/Sources/AlphaVideoGPU/zstd_seek.h +250 -0
  28. package/package.json +77 -4
  29. package/react-native/android/build.gradle +92 -0
  30. package/react-native/android/src/main/AndroidManifest.xml +9 -0
  31. package/react-native/android/src/main/java/dev/mediacache/alphavideo/gpu/reactnative/AlphaVideoGpuPackage.java +26 -0
  32. package/react-native/android/src/main/java/dev/mediacache/alphavideo/gpu/reactnative/AlphaVideoGpuViewManager.java +187 -0
  33. package/react-native/android/src/main/java/dev/mediacache/alphavideo/gpu/reactnative/PlayerEventForwarder.java +107 -0
  34. package/react-native/android/src/newarch/java/dev/mediacache/alphavideo/gpu/reactnative/AlphaVideoGpuViewManagerSpec.java +23 -0
  35. package/react-native/android/src/norangesource/java/dev/mediacache/alphavideo/gpu/AppDataSource.java +15 -0
  36. package/react-native/android/src/oldarch/java/dev/mediacache/alphavideo/gpu/reactnative/AlphaVideoGpuViewManagerSpec.java +56 -0
  37. package/react-native/ios/RNAlphaVideoGpuViewComponentView.mm +176 -0
  38. package/react-native/ios/RNAlphaVideoGpuViewManager.mm +175 -0
  39. package/react-native/src/AlphaVideoGpuView.js +2 -0
  40. package/react-native/src/AlphaVideoGpuView.web.tsx +264 -0
  41. package/react-native/src/AlphaVideoGpuViewNativeComponent.ts +128 -0
  42. package/react-native/src/AlphaVideoGpuViewNativeComponent.web.ts +2 -0
  43. package/react-native/src/index.d.ts +95 -0
  44. package/react-native/src/index.js +162 -0
  45. package/react-native-alpha-video-gpu.podspec +37 -0
  46. package/react-native.config.js +12 -0
  47. package/third_party/licenses/Apache-2.0.txt +208 -0
  48. package/third_party/range-source/LICENSE +21 -0
  49. package/third_party/range-source/README.md +10 -0
  50. package/third_party/range-source/include/range_source.h +395 -0
  51. package/third_party/range-source/include/range_source_download.h +309 -0
  52. package/third_party/zstd/LICENSE +30 -0
  53. package/third_party/zstd/zstd.c +38717 -0
  54. package/third_party/zstd/zstd.h +2450 -0
@@ -0,0 +1,1550 @@
1
+ // basisu_astc_decomp.cpp: Only used for ASTC decompression, to validate the transcoder's output.
2
+ // This version does not support HDR.
3
+
4
+ /*-------------------------------------------------------------------------
5
+ * drawElements Quality Program Tester Core
6
+ * ----------------------------------------
7
+ *
8
+ * Copyright 2016 The Android Open Source Project
9
+ *
10
+ * Licensed under the Apache License, Version 2.0 (the "License");
11
+ * you may not use this file except in compliance with the License.
12
+ * You may obtain a copy of the License at
13
+ *
14
+ * http://www.apache.org/licenses/LICENSE-2.0
15
+ *
16
+ * Unless required by applicable law or agreed to in writing, software
17
+ * distributed under the License is distributed on an "AS IS" BASIS,
18
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
+ * See the License for the specific language governing permissions and
20
+ * limitations under the License.
21
+ *
22
+ * rg: Removed external dependencies, remarked out HDR support because
23
+ * we don't need it, minor fix to decompress() so it converts non-sRGB
24
+ * output to 8-bits correctly. I've compared this decoder's output
25
+ * vs. astc-codec with random inputs on 4x4 blocks, and after fixing a few obvious
26
+ * bugs in astc-codec where it didn't correctly follow the spec they match so
27
+ * I'm assuming they are both correct for 4x4 now.
28
+ * HDR support should be easily added back in, but as we don't need it
29
+ * I'm leaving this for someone else.
30
+ *
31
+ *//*!
32
+ * \file
33
+ * \brief ASTC Utilities.
34
+ *//*--------------------------------------------------------------------*/
35
+ #include "astc_decomp.h"
36
+ #include <assert.h>
37
+ #include <algorithm>
38
+
39
+ #define DE_LENGTH_OF_ARRAY(x) (sizeof(x)/sizeof(x[0]))
40
+ #define DE_UNREF(x) (void)x
41
+
42
+ typedef uint8_t deUint8;
43
+ typedef int8_t deInt8;
44
+ typedef uint32_t deUint32;
45
+ typedef int32_t deInt32;
46
+ typedef uint16_t deUint16;
47
+ typedef int16_t deInt16;
48
+ typedef int64_t deInt64;
49
+ typedef uint64_t deUint64;
50
+
51
+ #define DE_ASSERT assert
52
+
53
+ namespace basisu
54
+ {
55
+ static bool inBounds(int v, int l, int h)
56
+ {
57
+ return (v >= l) && (v < h);
58
+ }
59
+
60
+ static bool inRange(int v, int l, int h)
61
+ {
62
+ return (v >= l) && (v <= h);
63
+ }
64
+
65
+ template<typename T>
66
+ static inline T max(T a, T b)
67
+ {
68
+ return (a > b) ? a : b;
69
+ }
70
+
71
+ template<typename T>
72
+ static inline T min(T a, T b)
73
+ {
74
+ return (a < b) ? a : b;
75
+ }
76
+
77
+ template<typename T>
78
+ static inline T astc_clamp(T a, T l, T h)
79
+ {
80
+ if (a < l)
81
+ return l;
82
+ else if (a > h)
83
+ return h;
84
+ return a;
85
+ }
86
+
87
+ struct UVec4
88
+ {
89
+ uint32_t m_c[4];
90
+
91
+ UVec4()
92
+ {
93
+ m_c[0] = 0;
94
+ m_c[1] = 0;
95
+ m_c[2] = 0;
96
+ m_c[3] = 0;
97
+ }
98
+
99
+ UVec4(uint32_t x, uint32_t y, uint32_t z, uint32_t w)
100
+ {
101
+ m_c[0] = x;
102
+ m_c[1] = y;
103
+ m_c[2] = z;
104
+ m_c[3] = w;
105
+ }
106
+
107
+ uint32_t x() const { return m_c[0]; }
108
+ uint32_t y() const { return m_c[1]; }
109
+ uint32_t z() const { return m_c[2]; }
110
+ uint32_t w() const { return m_c[3]; }
111
+
112
+ uint32_t& x() { return m_c[0]; }
113
+ uint32_t& y() { return m_c[1]; }
114
+ uint32_t& z() { return m_c[2]; }
115
+ uint32_t& w() { return m_c[3]; }
116
+
117
+ uint32_t operator[] (uint32_t idx) const { assert(idx < 4); return m_c[idx]; }
118
+ uint32_t& operator[] (uint32_t idx) { assert(idx < 4); return m_c[idx]; }
119
+ };
120
+
121
+ struct IVec4
122
+ {
123
+ int32_t m_c[4];
124
+
125
+ IVec4()
126
+ {
127
+ m_c[0] = 0;
128
+ m_c[1] = 0;
129
+ m_c[2] = 0;
130
+ m_c[3] = 0;
131
+ }
132
+
133
+ IVec4(int32_t x, int32_t y, int32_t z, int32_t w)
134
+ {
135
+ m_c[0] = x;
136
+ m_c[1] = y;
137
+ m_c[2] = z;
138
+ m_c[3] = w;
139
+ }
140
+
141
+ int32_t x() const { return m_c[0]; }
142
+ int32_t y() const { return m_c[1]; }
143
+ int32_t z() const { return m_c[2]; }
144
+ int32_t w() const { return m_c[3]; }
145
+
146
+ int32_t& x() { return m_c[0]; }
147
+ int32_t& y() { return m_c[1]; }
148
+ int32_t& z() { return m_c[2]; }
149
+ int32_t& w() { return m_c[3]; }
150
+
151
+ UVec4 asUint() const
152
+ {
153
+ return UVec4(std::max(0, m_c[0]), std::max(0, m_c[1]), std::max(0, m_c[2]), std::max(0, m_c[3]));
154
+ }
155
+
156
+ int32_t operator[] (uint32_t idx) const { assert(idx < 4); return m_c[idx]; }
157
+ int32_t& operator[] (uint32_t idx) { assert(idx < 4); return m_c[idx]; }
158
+ };
159
+
160
+ struct IVec3
161
+ {
162
+ int32_t m_c[3];
163
+
164
+ IVec3()
165
+ {
166
+ m_c[0] = 0;
167
+ m_c[1] = 0;
168
+ m_c[2] = 0;
169
+ }
170
+
171
+ IVec3(int32_t x, int32_t y, int32_t z)
172
+ {
173
+ m_c[0] = x;
174
+ m_c[1] = y;
175
+ m_c[2] = z;
176
+ }
177
+
178
+ int32_t x() const { return m_c[0]; }
179
+ int32_t y() const { return m_c[1]; }
180
+ int32_t z() const { return m_c[2]; }
181
+
182
+ int32_t& x() { return m_c[0]; }
183
+ int32_t& y() { return m_c[1]; }
184
+ int32_t& z() { return m_c[2]; }
185
+
186
+ int32_t operator[] (uint32_t idx) const { assert(idx < 3); return m_c[idx]; }
187
+ int32_t& operator[] (uint32_t idx) { assert(idx < 3); return m_c[idx]; }
188
+ };
189
+
190
+ static uint32_t deDivRoundUp32(uint32_t a, uint32_t b)
191
+ {
192
+ return (a + b - 1) / b;
193
+ }
194
+
195
+ static bool deInBounds32(uint32_t v, uint32_t l, uint32_t h)
196
+ {
197
+ return (v >= l) && (v < h);
198
+ }
199
+
200
+ namespace astc
201
+ {
202
+ using std::vector;
203
+ namespace
204
+ {
205
+ // Common utilities
206
+ enum
207
+ {
208
+ MAX_BLOCK_WIDTH = 12,
209
+ MAX_BLOCK_HEIGHT = 12
210
+ };
211
+ inline deUint32 getBit (deUint32 src, int ndx)
212
+ {
213
+ DE_ASSERT(basisu::inBounds(ndx, 0, 32));
214
+ return (src >> ndx) & 1;
215
+ }
216
+ inline deUint32 getBits (deUint32 src, int low, int high)
217
+ {
218
+ const int numBits = (high-low) + 1;
219
+ DE_ASSERT(basisu::inRange(numBits, 1, 32));
220
+ if (numBits < 32)
221
+ return (deUint32)((src >> low) & ((1u<<numBits)-1));
222
+ else
223
+ return (deUint32)((src >> low) & 0xFFFFFFFFu);
224
+ }
225
+ inline bool isBitSet (deUint32 src, int ndx)
226
+ {
227
+ return getBit(src, ndx) != 0;
228
+ }
229
+ inline deUint32 reverseBits (deUint32 src, int numBits)
230
+ {
231
+ DE_ASSERT(basisu::inRange(numBits, 0, 32));
232
+ deUint32 result = 0;
233
+ for (int i = 0; i < numBits; i++)
234
+ result |= ((src >> i) & 1) << (numBits-1-i);
235
+ return result;
236
+ }
237
+ inline deUint32 bitReplicationScale (deUint32 src, int numSrcBits, int numDstBits)
238
+ {
239
+ DE_ASSERT(numSrcBits <= numDstBits);
240
+ DE_ASSERT((src & ((1<<numSrcBits)-1)) == src);
241
+ deUint32 dst = 0;
242
+ for (int shift = numDstBits-numSrcBits; shift > -numSrcBits; shift -= numSrcBits)
243
+ dst |= shift >= 0 ? src << shift : src >> -shift;
244
+ return dst;
245
+ }
246
+
247
+ inline deInt32 signExtend (deInt32 src, int numSrcBits)
248
+ {
249
+ DE_ASSERT(basisu::inRange(numSrcBits, 2, 31));
250
+ const bool negative = (src & (1 << (numSrcBits-1))) != 0;
251
+ return src | (negative ? ~((1 << numSrcBits) - 1) : 0);
252
+ }
253
+
254
+ //inline bool isFloat16InfOrNan (deFloat16 v)
255
+ //{
256
+ // return getBits(v, 10, 14) == 31;
257
+ //}
258
+
259
+ enum ISEMode
260
+ {
261
+ ISEMODE_TRIT = 0,
262
+ ISEMODE_QUINT,
263
+ ISEMODE_PLAIN_BIT,
264
+ ISEMODE_LAST
265
+ };
266
+ struct ISEParams
267
+ {
268
+ ISEMode mode;
269
+ int numBits;
270
+ ISEParams (ISEMode mode_, int numBits_) : mode(mode_), numBits(numBits_) {}
271
+ };
272
+ inline int computeNumRequiredBits (const ISEParams& iseParams, int numValues)
273
+ {
274
+ switch (iseParams.mode)
275
+ {
276
+ case ISEMODE_TRIT: return deDivRoundUp32(numValues*8, 5) + numValues*iseParams.numBits;
277
+ case ISEMODE_QUINT: return deDivRoundUp32(numValues*7, 3) + numValues*iseParams.numBits;
278
+ case ISEMODE_PLAIN_BIT: return numValues*iseParams.numBits;
279
+ default:
280
+ DE_ASSERT(false);
281
+ return -1;
282
+ }
283
+ }
284
+ ISEParams computeMaximumRangeISEParams (int numAvailableBits, int numValuesInSequence)
285
+ {
286
+ int curBitsForTritMode = 6;
287
+ int curBitsForQuintMode = 5;
288
+ int curBitsForPlainBitMode = 8;
289
+ while (true)
290
+ {
291
+ DE_ASSERT(curBitsForTritMode > 0 || curBitsForQuintMode > 0 || curBitsForPlainBitMode > 0);
292
+ const int tritRange = curBitsForTritMode > 0 ? (3 << curBitsForTritMode) - 1 : -1;
293
+ const int quintRange = curBitsForQuintMode > 0 ? (5 << curBitsForQuintMode) - 1 : -1;
294
+ const int plainBitRange = curBitsForPlainBitMode > 0 ? (1 << curBitsForPlainBitMode) - 1 : -1;
295
+ const int maxRange = basisu::max(basisu::max(tritRange, quintRange), plainBitRange);
296
+ if (maxRange == tritRange)
297
+ {
298
+ const ISEParams params(ISEMODE_TRIT, curBitsForTritMode);
299
+ if (computeNumRequiredBits(params, numValuesInSequence) <= numAvailableBits)
300
+ return ISEParams(ISEMODE_TRIT, curBitsForTritMode);
301
+ curBitsForTritMode--;
302
+ }
303
+ else if (maxRange == quintRange)
304
+ {
305
+ const ISEParams params(ISEMODE_QUINT, curBitsForQuintMode);
306
+ if (computeNumRequiredBits(params, numValuesInSequence) <= numAvailableBits)
307
+ return ISEParams(ISEMODE_QUINT, curBitsForQuintMode);
308
+ curBitsForQuintMode--;
309
+ }
310
+ else
311
+ {
312
+ const ISEParams params(ISEMODE_PLAIN_BIT, curBitsForPlainBitMode);
313
+ DE_ASSERT(maxRange == plainBitRange);
314
+ if (computeNumRequiredBits(params, numValuesInSequence) <= numAvailableBits)
315
+ return ISEParams(ISEMODE_PLAIN_BIT, curBitsForPlainBitMode);
316
+ curBitsForPlainBitMode--;
317
+ }
318
+ }
319
+ }
320
+ inline int computeNumColorEndpointValues (deUint32 endpointMode)
321
+ {
322
+ DE_ASSERT(endpointMode < 16);
323
+ return (endpointMode/4 + 1) * 2;
324
+ }
325
+ // Decompression utilities
326
+ enum DecompressResult
327
+ {
328
+ DECOMPRESS_RESULT_VALID_BLOCK = 0, //!< Decompressed valid block
329
+ DECOMPRESS_RESULT_ERROR, //!< Encountered error while decompressing, error color written
330
+ DECOMPRESS_RESULT_LAST
331
+ };
332
+ // A helper for getting bits from a 128-bit block.
333
+ class Block128
334
+ {
335
+ private:
336
+ typedef deUint64 Word;
337
+ enum
338
+ {
339
+ WORD_BYTES = sizeof(Word),
340
+ WORD_BITS = 8*WORD_BYTES,
341
+ NUM_WORDS = 128 / WORD_BITS
342
+ };
343
+ //DE_STATIC_ASSERT(128 % WORD_BITS == 0);
344
+ public:
345
+ Block128 (const deUint8* src)
346
+ {
347
+ for (int wordNdx = 0; wordNdx < NUM_WORDS; wordNdx++)
348
+ {
349
+ m_words[wordNdx] = 0;
350
+ for (int byteNdx = 0; byteNdx < WORD_BYTES; byteNdx++)
351
+ m_words[wordNdx] |= (Word)src[wordNdx*WORD_BYTES + byteNdx] << (8*byteNdx);
352
+ }
353
+ }
354
+ deUint32 getBit (int ndx) const
355
+ {
356
+ DE_ASSERT(basisu::inBounds(ndx, 0, 128));
357
+ return (m_words[ndx / WORD_BITS] >> (ndx % WORD_BITS)) & 1;
358
+ }
359
+ deUint32 getBits (int low, int high) const
360
+ {
361
+ DE_ASSERT(basisu::inBounds(low, 0, 128));
362
+ DE_ASSERT(basisu::inBounds(high, 0, 128));
363
+ DE_ASSERT(basisu::inRange(high-low+1, 0, 32));
364
+ if (high-low+1 == 0)
365
+ return 0;
366
+ const int word0Ndx = low / WORD_BITS;
367
+ const int word1Ndx = high / WORD_BITS;
368
+ // \note "foo << bar << 1" done instead of "foo << (bar+1)" to avoid overflow, i.e. shift amount being too big.
369
+ if (word0Ndx == word1Ndx)
370
+ return (deUint32)((m_words[word0Ndx] & ((((Word)1 << high%WORD_BITS << 1) - 1))) >> ((Word)low % WORD_BITS));
371
+ else
372
+ {
373
+ DE_ASSERT(word1Ndx == word0Ndx + 1);
374
+ return (deUint32)(m_words[word0Ndx] >> (low%WORD_BITS)) |
375
+ (deUint32)((m_words[word1Ndx] & (((Word)1 << high%WORD_BITS << 1) - 1)) << (high-low - high%WORD_BITS));
376
+ }
377
+ }
378
+ bool isBitSet (int ndx) const
379
+ {
380
+ DE_ASSERT(basisu::inBounds(ndx, 0, 128));
381
+ return getBit(ndx) != 0;
382
+ }
383
+ private:
384
+ Word m_words[NUM_WORDS];
385
+ };
386
+ // A helper for sequential access into a Block128.
387
+ class BitAccessStream
388
+ {
389
+ public:
390
+ BitAccessStream (const Block128& src, int startNdxInSrc, int length, bool forward)
391
+ : m_src (src)
392
+ , m_startNdxInSrc (startNdxInSrc)
393
+ , m_length (length)
394
+ , m_forward (forward)
395
+ , m_ndx (0)
396
+ {
397
+ }
398
+ // Get the next num bits. Bits at positions greater than or equal to m_length are zeros.
399
+ deUint32 getNext (int num)
400
+ {
401
+ if (num == 0 || m_ndx >= m_length)
402
+ return 0;
403
+ const int end = m_ndx + num;
404
+ const int numBitsFromSrc = basisu::max(0, basisu::min(m_length, end) - m_ndx);
405
+ const int low = m_ndx;
406
+ const int high = m_ndx + numBitsFromSrc - 1;
407
+ m_ndx += num;
408
+ return m_forward ? m_src.getBits(m_startNdxInSrc + low, m_startNdxInSrc + high)
409
+ : reverseBits(m_src.getBits(m_startNdxInSrc - high, m_startNdxInSrc - low), numBitsFromSrc);
410
+ }
411
+ private:
412
+ const Block128& m_src;
413
+ const int m_startNdxInSrc;
414
+ const int m_length;
415
+ const bool m_forward;
416
+ int m_ndx;
417
+ };
418
+ struct ISEDecodedResult
419
+ {
420
+ deUint32 m;
421
+ deUint32 tq; //!< Trit or quint value, depending on ISE mode.
422
+ deUint32 v;
423
+ };
424
+ // Data from an ASTC block's "block mode" part (i.e. bits [0,10]).
425
+ struct ASTCBlockMode
426
+ {
427
+ bool isError;
428
+ // \note Following fields only relevant if !isError.
429
+ bool isVoidExtent;
430
+ // \note Following fields only relevant if !isVoidExtent.
431
+ bool isDualPlane;
432
+ int weightGridWidth;
433
+ int weightGridHeight;
434
+ ISEParams weightISEParams;
435
+ ASTCBlockMode (void)
436
+ : isError (true)
437
+ , isVoidExtent (true)
438
+ , isDualPlane (true)
439
+ , weightGridWidth (-1)
440
+ , weightGridHeight (-1)
441
+ , weightISEParams (ISEMODE_LAST, -1)
442
+ {
443
+ }
444
+ };
445
+ inline int computeNumWeights (const ASTCBlockMode& mode)
446
+ {
447
+ return mode.weightGridWidth * mode.weightGridHeight * (mode.isDualPlane ? 2 : 1);
448
+ }
449
+ struct ColorEndpointPair
450
+ {
451
+ UVec4 e0;
452
+ UVec4 e1;
453
+ };
454
+ struct TexelWeightPair
455
+ {
456
+ deUint32 w[2];
457
+ };
458
+ ASTCBlockMode getASTCBlockMode (deUint32 blockModeData)
459
+ {
460
+ ASTCBlockMode blockMode;
461
+ blockMode.isError = true; // \note Set to false later, if not error.
462
+ blockMode.isVoidExtent = getBits(blockModeData, 0, 8) == 0x1fc;
463
+ if (!blockMode.isVoidExtent)
464
+ {
465
+ if ((getBits(blockModeData, 0, 1) == 0 && getBits(blockModeData, 6, 8) == 7) || getBits(blockModeData, 0, 3) == 0)
466
+ return blockMode; // Invalid ("reserved").
467
+ deUint32 r = (deUint32)-1; // \note Set in the following branches.
468
+ if (getBits(blockModeData, 0, 1) == 0)
469
+ {
470
+ const deUint32 r0 = getBit(blockModeData, 4);
471
+ const deUint32 r1 = getBit(blockModeData, 2);
472
+ const deUint32 r2 = getBit(blockModeData, 3);
473
+ const deUint32 i78 = getBits(blockModeData, 7, 8);
474
+ r = (r2 << 2) | (r1 << 1) | (r0 << 0);
475
+ if (i78 == 3)
476
+ {
477
+ const bool i5 = isBitSet(blockModeData, 5);
478
+ blockMode.weightGridWidth = i5 ? 10 : 6;
479
+ blockMode.weightGridHeight = i5 ? 6 : 10;
480
+ }
481
+ else
482
+ {
483
+ const deUint32 a = getBits(blockModeData, 5, 6);
484
+ switch (i78)
485
+ {
486
+ case 0: blockMode.weightGridWidth = 12; blockMode.weightGridHeight = a + 2; break;
487
+ case 1: blockMode.weightGridWidth = a + 2; blockMode.weightGridHeight = 12; break;
488
+ case 2: blockMode.weightGridWidth = a + 6; blockMode.weightGridHeight = getBits(blockModeData, 9, 10) + 6; break;
489
+ default: DE_ASSERT(false);
490
+ }
491
+ }
492
+ }
493
+ else
494
+ {
495
+ const deUint32 r0 = getBit(blockModeData, 4);
496
+ const deUint32 r1 = getBit(blockModeData, 0);
497
+ const deUint32 r2 = getBit(blockModeData, 1);
498
+ const deUint32 i23 = getBits(blockModeData, 2, 3);
499
+ const deUint32 a = getBits(blockModeData, 5, 6);
500
+ r = (r2 << 2) | (r1 << 1) | (r0 << 0);
501
+ if (i23 == 3)
502
+ {
503
+ const deUint32 b = getBit(blockModeData, 7);
504
+ const bool i8 = isBitSet(blockModeData, 8);
505
+ blockMode.weightGridWidth = i8 ? b+2 : a+2;
506
+ blockMode.weightGridHeight = i8 ? a+2 : b+6;
507
+ }
508
+ else
509
+ {
510
+ const deUint32 b = getBits(blockModeData, 7, 8);
511
+ switch (i23)
512
+ {
513
+ case 0: blockMode.weightGridWidth = b + 4; blockMode.weightGridHeight = a + 2; break;
514
+ case 1: blockMode.weightGridWidth = b + 8; blockMode.weightGridHeight = a + 2; break;
515
+ case 2: blockMode.weightGridWidth = a + 2; blockMode.weightGridHeight = b + 8; break;
516
+ default: DE_ASSERT(false);
517
+ }
518
+ }
519
+ }
520
+ const bool zeroDH = getBits(blockModeData, 0, 1) == 0 && getBits(blockModeData, 7, 8) == 2;
521
+ const bool h = zeroDH ? 0 : isBitSet(blockModeData, 9);
522
+ blockMode.isDualPlane = zeroDH ? 0 : isBitSet(blockModeData, 10);
523
+ {
524
+ ISEMode& m = blockMode.weightISEParams.mode;
525
+ int& b = blockMode.weightISEParams.numBits;
526
+ m = ISEMODE_PLAIN_BIT;
527
+ b = 0;
528
+ if (h)
529
+ {
530
+ switch (r)
531
+ {
532
+ case 2: m = ISEMODE_QUINT; b = 1; break;
533
+ case 3: m = ISEMODE_TRIT; b = 2; break;
534
+ case 4: b = 4; break;
535
+ case 5: m = ISEMODE_QUINT; b = 2; break;
536
+ case 6: m = ISEMODE_TRIT; b = 3; break;
537
+ case 7: b = 5; break;
538
+ default: DE_ASSERT(false);
539
+ }
540
+ }
541
+ else
542
+ {
543
+ switch (r)
544
+ {
545
+ case 2: b = 1; break;
546
+ case 3: m = ISEMODE_TRIT; break;
547
+ case 4: b = 2; break;
548
+ case 5: m = ISEMODE_QUINT; break;
549
+ case 6: m = ISEMODE_TRIT; b = 1; break;
550
+ case 7: b = 3; break;
551
+ default: DE_ASSERT(false);
552
+ }
553
+ }
554
+ }
555
+ }
556
+ blockMode.isError = false;
557
+ return blockMode;
558
+ }
559
+ inline void setASTCErrorColorBlock (void* dst, int blockWidth, int blockHeight, bool isSRGB)
560
+ {
561
+ if (isSRGB)
562
+ {
563
+ deUint8* const dstU = (deUint8*)dst;
564
+ for (int i = 0; i < blockWidth*blockHeight; i++)
565
+ {
566
+ dstU[4*i + 0] = 0xff;
567
+ dstU[4*i + 1] = 0;
568
+ dstU[4*i + 2] = 0xff;
569
+ dstU[4*i + 3] = 0xff;
570
+ }
571
+ }
572
+ else
573
+ {
574
+ float* const dstF = (float*)dst;
575
+ for (int i = 0; i < blockWidth*blockHeight; i++)
576
+ {
577
+ dstF[4*i + 0] = 1.0f;
578
+ dstF[4*i + 1] = 0.0f;
579
+ dstF[4*i + 2] = 1.0f;
580
+ dstF[4*i + 3] = 1.0f;
581
+ }
582
+ }
583
+ }
584
+ DecompressResult decodeVoidExtentBlock (void* dst, const Block128& blockData, int blockWidth, int blockHeight, bool isSRGB, bool isLDRMode)
585
+ {
586
+ const deUint32 minSExtent = blockData.getBits(12, 24);
587
+ const deUint32 maxSExtent = blockData.getBits(25, 37);
588
+ const deUint32 minTExtent = blockData.getBits(38, 50);
589
+ const deUint32 maxTExtent = blockData.getBits(51, 63);
590
+ const bool allExtentsAllOnes = minSExtent == 0x1fff && maxSExtent == 0x1fff && minTExtent == 0x1fff && maxTExtent == 0x1fff;
591
+ const bool isHDRBlock = blockData.isBitSet(9);
592
+ if ((isLDRMode && isHDRBlock) || (!allExtentsAllOnes && (minSExtent >= maxSExtent || minTExtent >= maxTExtent)))
593
+ {
594
+ setASTCErrorColorBlock(dst, blockWidth, blockHeight, isSRGB);
595
+ return DECOMPRESS_RESULT_ERROR;
596
+ }
597
+ const deUint32 rgba[4] =
598
+ {
599
+ blockData.getBits(64, 79),
600
+ blockData.getBits(80, 95),
601
+ blockData.getBits(96, 111),
602
+ blockData.getBits(112, 127)
603
+ };
604
+ if (isSRGB)
605
+ {
606
+ deUint8* const dstU = (deUint8*)dst;
607
+ for (int i = 0; i < blockWidth*blockHeight; i++)
608
+ for (int c = 0; c < 4; c++)
609
+ dstU[i*4 + c] = (deUint8)((rgba[c] & 0xff00) >> 8);
610
+ }
611
+ else
612
+ {
613
+ float* const dstF = (float*)dst;
614
+ if (isHDRBlock)
615
+ {
616
+ // rg - REMOVING HDR SUPPORT FOR NOW
617
+ #if 0
618
+ for (int c = 0; c < 4; c++)
619
+ {
620
+ if (isFloat16InfOrNan((deFloat16)rgba[c]))
621
+ throw InternalError("Infinity or NaN color component in HDR void extent block in ASTC texture (behavior undefined by ASTC specification)");
622
+ }
623
+ for (int i = 0; i < blockWidth*blockHeight; i++)
624
+ for (int c = 0; c < 4; c++)
625
+ dstF[i*4 + c] = deFloat16To32((deFloat16)rgba[c]);
626
+ #endif
627
+ }
628
+ else
629
+ {
630
+ for (int i = 0; i < blockWidth*blockHeight; i++)
631
+ for (int c = 0; c < 4; c++)
632
+ dstF[i*4 + c] = rgba[c] == 65535 ? 1.0f : (float)rgba[c] / 65536.0f;
633
+ }
634
+ }
635
+ return DECOMPRESS_RESULT_VALID_BLOCK;
636
+ }
637
+ void decodeColorEndpointModes (deUint32* endpointModesDst, const Block128& blockData, int numPartitions, int extraCemBitsStart)
638
+ {
639
+ if (numPartitions == 1)
640
+ endpointModesDst[0] = blockData.getBits(13, 16);
641
+ else
642
+ {
643
+ const deUint32 highLevelSelector = blockData.getBits(23, 24);
644
+ if (highLevelSelector == 0)
645
+ {
646
+ const deUint32 mode = blockData.getBits(25, 28);
647
+ for (int i = 0; i < numPartitions; i++)
648
+ endpointModesDst[i] = mode;
649
+ }
650
+ else
651
+ {
652
+ for (int partNdx = 0; partNdx < numPartitions; partNdx++)
653
+ {
654
+ const deUint32 cemClass = highLevelSelector - (blockData.isBitSet(25 + partNdx) ? 0 : 1);
655
+ const deUint32 lowBit0Ndx = numPartitions + 2*partNdx;
656
+ const deUint32 lowBit1Ndx = numPartitions + 2*partNdx + 1;
657
+ const deUint32 lowBit0 = blockData.getBit(lowBit0Ndx < 4 ? 25+lowBit0Ndx : extraCemBitsStart+lowBit0Ndx-4);
658
+ const deUint32 lowBit1 = blockData.getBit(lowBit1Ndx < 4 ? 25+lowBit1Ndx : extraCemBitsStart+lowBit1Ndx-4);
659
+ endpointModesDst[partNdx] = (cemClass << 2) | (lowBit1 << 1) | lowBit0;
660
+ }
661
+ }
662
+ }
663
+ }
664
+ int computeNumColorEndpointValues (const deUint32* endpointModes, int numPartitions)
665
+ {
666
+ int result = 0;
667
+ for (int i = 0; i < numPartitions; i++)
668
+ result += computeNumColorEndpointValues(endpointModes[i]);
669
+ return result;
670
+ }
671
+ void decodeISETritBlock (ISEDecodedResult* dst, int numValues, BitAccessStream& data, int numBits)
672
+ {
673
+ DE_ASSERT(basisu::inRange(numValues, 1, 5));
674
+ deUint32 m[5];
675
+ m[0] = data.getNext(numBits);
676
+ deUint32 T01 = data.getNext(2);
677
+ m[1] = data.getNext(numBits);
678
+ deUint32 T23 = data.getNext(2);
679
+ m[2] = data.getNext(numBits);
680
+ deUint32 T4 = data.getNext(1);
681
+ m[3] = data.getNext(numBits);
682
+ deUint32 T56 = data.getNext(2);
683
+ m[4] = data.getNext(numBits);
684
+ deUint32 T7 = data.getNext(1);
685
+ switch (numValues)
686
+ {
687
+ // \note Fall-throughs.
688
+ case 1: T23 = 0;
689
+ case 2: T4 = 0;
690
+ case 3: T56 = 0;
691
+ case 4: T7 = 0;
692
+ case 5: break;
693
+ default:
694
+ DE_ASSERT(false);
695
+ }
696
+ const deUint32 T = (T7 << 7) | (T56 << 5) | (T4 << 4) | (T23 << 2) | (T01 << 0);
697
+ static const deUint32 tritsFromT[256][5] =
698
+ {
699
+ { 0,0,0,0,0 }, { 1,0,0,0,0 }, { 2,0,0,0,0 }, { 0,0,2,0,0 }, { 0,1,0,0,0 }, { 1,1,0,0,0 }, { 2,1,0,0,0 }, { 1,0,2,0,0 }, { 0,2,0,0,0 }, { 1,2,0,0,0 }, { 2,2,0,0,0 }, { 2,0,2,0,0 }, { 0,2,2,0,0 }, { 1,2,2,0,0 }, { 2,2,2,0,0 }, { 2,0,2,0,0 },
700
+ { 0,0,1,0,0 }, { 1,0,1,0,0 }, { 2,0,1,0,0 }, { 0,1,2,0,0 }, { 0,1,1,0,0 }, { 1,1,1,0,0 }, { 2,1,1,0,0 }, { 1,1,2,0,0 }, { 0,2,1,0,0 }, { 1,2,1,0,0 }, { 2,2,1,0,0 }, { 2,1,2,0,0 }, { 0,0,0,2,2 }, { 1,0,0,2,2 }, { 2,0,0,2,2 }, { 0,0,2,2,2 },
701
+ { 0,0,0,1,0 }, { 1,0,0,1,0 }, { 2,0,0,1,0 }, { 0,0,2,1,0 }, { 0,1,0,1,0 }, { 1,1,0,1,0 }, { 2,1,0,1,0 }, { 1,0,2,1,0 }, { 0,2,0,1,0 }, { 1,2,0,1,0 }, { 2,2,0,1,0 }, { 2,0,2,1,0 }, { 0,2,2,1,0 }, { 1,2,2,1,0 }, { 2,2,2,1,0 }, { 2,0,2,1,0 },
702
+ { 0,0,1,1,0 }, { 1,0,1,1,0 }, { 2,0,1,1,0 }, { 0,1,2,1,0 }, { 0,1,1,1,0 }, { 1,1,1,1,0 }, { 2,1,1,1,0 }, { 1,1,2,1,0 }, { 0,2,1,1,0 }, { 1,2,1,1,0 }, { 2,2,1,1,0 }, { 2,1,2,1,0 }, { 0,1,0,2,2 }, { 1,1,0,2,2 }, { 2,1,0,2,2 }, { 1,0,2,2,2 },
703
+ { 0,0,0,2,0 }, { 1,0,0,2,0 }, { 2,0,0,2,0 }, { 0,0,2,2,0 }, { 0,1,0,2,0 }, { 1,1,0,2,0 }, { 2,1,0,2,0 }, { 1,0,2,2,0 }, { 0,2,0,2,0 }, { 1,2,0,2,0 }, { 2,2,0,2,0 }, { 2,0,2,2,0 }, { 0,2,2,2,0 }, { 1,2,2,2,0 }, { 2,2,2,2,0 }, { 2,0,2,2,0 },
704
+ { 0,0,1,2,0 }, { 1,0,1,2,0 }, { 2,0,1,2,0 }, { 0,1,2,2,0 }, { 0,1,1,2,0 }, { 1,1,1,2,0 }, { 2,1,1,2,0 }, { 1,1,2,2,0 }, { 0,2,1,2,0 }, { 1,2,1,2,0 }, { 2,2,1,2,0 }, { 2,1,2,2,0 }, { 0,2,0,2,2 }, { 1,2,0,2,2 }, { 2,2,0,2,2 }, { 2,0,2,2,2 },
705
+ { 0,0,0,0,2 }, { 1,0,0,0,2 }, { 2,0,0,0,2 }, { 0,0,2,0,2 }, { 0,1,0,0,2 }, { 1,1,0,0,2 }, { 2,1,0,0,2 }, { 1,0,2,0,2 }, { 0,2,0,0,2 }, { 1,2,0,0,2 }, { 2,2,0,0,2 }, { 2,0,2,0,2 }, { 0,2,2,0,2 }, { 1,2,2,0,2 }, { 2,2,2,0,2 }, { 2,0,2,0,2 },
706
+ { 0,0,1,0,2 }, { 1,0,1,0,2 }, { 2,0,1,0,2 }, { 0,1,2,0,2 }, { 0,1,1,0,2 }, { 1,1,1,0,2 }, { 2,1,1,0,2 }, { 1,1,2,0,2 }, { 0,2,1,0,2 }, { 1,2,1,0,2 }, { 2,2,1,0,2 }, { 2,1,2,0,2 }, { 0,2,2,2,2 }, { 1,2,2,2,2 }, { 2,2,2,2,2 }, { 2,0,2,2,2 },
707
+ { 0,0,0,0,1 }, { 1,0,0,0,1 }, { 2,0,0,0,1 }, { 0,0,2,0,1 }, { 0,1,0,0,1 }, { 1,1,0,0,1 }, { 2,1,0,0,1 }, { 1,0,2,0,1 }, { 0,2,0,0,1 }, { 1,2,0,0,1 }, { 2,2,0,0,1 }, { 2,0,2,0,1 }, { 0,2,2,0,1 }, { 1,2,2,0,1 }, { 2,2,2,0,1 }, { 2,0,2,0,1 },
708
+ { 0,0,1,0,1 }, { 1,0,1,0,1 }, { 2,0,1,0,1 }, { 0,1,2,0,1 }, { 0,1,1,0,1 }, { 1,1,1,0,1 }, { 2,1,1,0,1 }, { 1,1,2,0,1 }, { 0,2,1,0,1 }, { 1,2,1,0,1 }, { 2,2,1,0,1 }, { 2,1,2,0,1 }, { 0,0,1,2,2 }, { 1,0,1,2,2 }, { 2,0,1,2,2 }, { 0,1,2,2,2 },
709
+ { 0,0,0,1,1 }, { 1,0,0,1,1 }, { 2,0,0,1,1 }, { 0,0,2,1,1 }, { 0,1,0,1,1 }, { 1,1,0,1,1 }, { 2,1,0,1,1 }, { 1,0,2,1,1 }, { 0,2,0,1,1 }, { 1,2,0,1,1 }, { 2,2,0,1,1 }, { 2,0,2,1,1 }, { 0,2,2,1,1 }, { 1,2,2,1,1 }, { 2,2,2,1,1 }, { 2,0,2,1,1 },
710
+ { 0,0,1,1,1 }, { 1,0,1,1,1 }, { 2,0,1,1,1 }, { 0,1,2,1,1 }, { 0,1,1,1,1 }, { 1,1,1,1,1 }, { 2,1,1,1,1 }, { 1,1,2,1,1 }, { 0,2,1,1,1 }, { 1,2,1,1,1 }, { 2,2,1,1,1 }, { 2,1,2,1,1 }, { 0,1,1,2,2 }, { 1,1,1,2,2 }, { 2,1,1,2,2 }, { 1,1,2,2,2 },
711
+ { 0,0,0,2,1 }, { 1,0,0,2,1 }, { 2,0,0,2,1 }, { 0,0,2,2,1 }, { 0,1,0,2,1 }, { 1,1,0,2,1 }, { 2,1,0,2,1 }, { 1,0,2,2,1 }, { 0,2,0,2,1 }, { 1,2,0,2,1 }, { 2,2,0,2,1 }, { 2,0,2,2,1 }, { 0,2,2,2,1 }, { 1,2,2,2,1 }, { 2,2,2,2,1 }, { 2,0,2,2,1 },
712
+ { 0,0,1,2,1 }, { 1,0,1,2,1 }, { 2,0,1,2,1 }, { 0,1,2,2,1 }, { 0,1,1,2,1 }, { 1,1,1,2,1 }, { 2,1,1,2,1 }, { 1,1,2,2,1 }, { 0,2,1,2,1 }, { 1,2,1,2,1 }, { 2,2,1,2,1 }, { 2,1,2,2,1 }, { 0,2,1,2,2 }, { 1,2,1,2,2 }, { 2,2,1,2,2 }, { 2,1,2,2,2 },
713
+ { 0,0,0,1,2 }, { 1,0,0,1,2 }, { 2,0,0,1,2 }, { 0,0,2,1,2 }, { 0,1,0,1,2 }, { 1,1,0,1,2 }, { 2,1,0,1,2 }, { 1,0,2,1,2 }, { 0,2,0,1,2 }, { 1,2,0,1,2 }, { 2,2,0,1,2 }, { 2,0,2,1,2 }, { 0,2,2,1,2 }, { 1,2,2,1,2 }, { 2,2,2,1,2 }, { 2,0,2,1,2 },
714
+ { 0,0,1,1,2 }, { 1,0,1,1,2 }, { 2,0,1,1,2 }, { 0,1,2,1,2 }, { 0,1,1,1,2 }, { 1,1,1,1,2 }, { 2,1,1,1,2 }, { 1,1,2,1,2 }, { 0,2,1,1,2 }, { 1,2,1,1,2 }, { 2,2,1,1,2 }, { 2,1,2,1,2 }, { 0,2,2,2,2 }, { 1,2,2,2,2 }, { 2,2,2,2,2 }, { 2,1,2,2,2 }
715
+ };
716
+ const deUint32 (& trits)[5] = tritsFromT[T];
717
+ for (int i = 0; i < numValues; i++)
718
+ {
719
+ dst[i].m = m[i];
720
+ dst[i].tq = trits[i];
721
+ dst[i].v = (trits[i] << numBits) + m[i];
722
+ }
723
+ }
724
+ void decodeISEQuintBlock (ISEDecodedResult* dst, int numValues, BitAccessStream& data, int numBits)
725
+ {
726
+ DE_ASSERT(basisu::inRange(numValues, 1, 3));
727
+ deUint32 m[3];
728
+ m[0] = data.getNext(numBits);
729
+ deUint32 Q012 = data.getNext(3);
730
+ m[1] = data.getNext(numBits);
731
+ deUint32 Q34 = data.getNext(2);
732
+ m[2] = data.getNext(numBits);
733
+ deUint32 Q56 = data.getNext(2);
734
+ switch (numValues)
735
+ {
736
+ // \note Fall-throughs.
737
+ case 1: Q34 = 0;
738
+ case 2: Q56 = 0;
739
+ case 3: break;
740
+ default:
741
+ DE_ASSERT(false);
742
+ }
743
+ const deUint32 Q = (Q56 << 5) | (Q34 << 3) | (Q012 << 0);
744
+ static const deUint32 quintsFromQ[256][3] =
745
+ {
746
+ { 0,0,0 }, { 1,0,0 }, { 2,0,0 }, { 3,0,0 }, { 4,0,0 }, { 0,4,0 }, { 4,4,0 }, { 4,4,4 }, { 0,1,0 }, { 1,1,0 }, { 2,1,0 }, { 3,1,0 }, { 4,1,0 }, { 1,4,0 }, { 4,4,1 }, { 4,4,4 },
747
+ { 0,2,0 }, { 1,2,0 }, { 2,2,0 }, { 3,2,0 }, { 4,2,0 }, { 2,4,0 }, { 4,4,2 }, { 4,4,4 }, { 0,3,0 }, { 1,3,0 }, { 2,3,0 }, { 3,3,0 }, { 4,3,0 }, { 3,4,0 }, { 4,4,3 }, { 4,4,4 },
748
+ { 0,0,1 }, { 1,0,1 }, { 2,0,1 }, { 3,0,1 }, { 4,0,1 }, { 0,4,1 }, { 4,0,4 }, { 0,4,4 }, { 0,1,1 }, { 1,1,1 }, { 2,1,1 }, { 3,1,1 }, { 4,1,1 }, { 1,4,1 }, { 4,1,4 }, { 1,4,4 },
749
+ { 0,2,1 }, { 1,2,1 }, { 2,2,1 }, { 3,2,1 }, { 4,2,1 }, { 2,4,1 }, { 4,2,4 }, { 2,4,4 }, { 0,3,1 }, { 1,3,1 }, { 2,3,1 }, { 3,3,1 }, { 4,3,1 }, { 3,4,1 }, { 4,3,4 }, { 3,4,4 },
750
+ { 0,0,2 }, { 1,0,2 }, { 2,0,2 }, { 3,0,2 }, { 4,0,2 }, { 0,4,2 }, { 2,0,4 }, { 3,0,4 }, { 0,1,2 }, { 1,1,2 }, { 2,1,2 }, { 3,1,2 }, { 4,1,2 }, { 1,4,2 }, { 2,1,4 }, { 3,1,4 },
751
+ { 0,2,2 }, { 1,2,2 }, { 2,2,2 }, { 3,2,2 }, { 4,2,2 }, { 2,4,2 }, { 2,2,4 }, { 3,2,4 }, { 0,3,2 }, { 1,3,2 }, { 2,3,2 }, { 3,3,2 }, { 4,3,2 }, { 3,4,2 }, { 2,3,4 }, { 3,3,4 },
752
+ { 0,0,3 }, { 1,0,3 }, { 2,0,3 }, { 3,0,3 }, { 4,0,3 }, { 0,4,3 }, { 0,0,4 }, { 1,0,4 }, { 0,1,3 }, { 1,1,3 }, { 2,1,3 }, { 3,1,3 }, { 4,1,3 }, { 1,4,3 }, { 0,1,4 }, { 1,1,4 },
753
+ { 0,2,3 }, { 1,2,3 }, { 2,2,3 }, { 3,2,3 }, { 4,2,3 }, { 2,4,3 }, { 0,2,4 }, { 1,2,4 }, { 0,3,3 }, { 1,3,3 }, { 2,3,3 }, { 3,3,3 }, { 4,3,3 }, { 3,4,3 }, { 0,3,4 }, { 1,3,4 }
754
+ };
755
+ const deUint32 (& quints)[3] = quintsFromQ[Q];
756
+ for (int i = 0; i < numValues; i++)
757
+ {
758
+ dst[i].m = m[i];
759
+ dst[i].tq = quints[i];
760
+ dst[i].v = (quints[i] << numBits) + m[i];
761
+ }
762
+ }
763
+ inline void decodeISEBitBlock (ISEDecodedResult* dst, BitAccessStream& data, int numBits)
764
+ {
765
+ dst[0].m = data.getNext(numBits);
766
+ dst[0].v = dst[0].m;
767
+ }
768
+ void decodeISE (ISEDecodedResult* dst, int numValues, BitAccessStream& data, const ISEParams& params)
769
+ {
770
+ if (params.mode == ISEMODE_TRIT)
771
+ {
772
+ const int numBlocks = deDivRoundUp32(numValues, 5);
773
+ for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
774
+ {
775
+ const int numValuesInBlock = blockNdx == numBlocks-1 ? numValues - 5*(numBlocks-1) : 5;
776
+ decodeISETritBlock(&dst[5*blockNdx], numValuesInBlock, data, params.numBits);
777
+ }
778
+ }
779
+ else if (params.mode == ISEMODE_QUINT)
780
+ {
781
+ const int numBlocks = deDivRoundUp32(numValues, 3);
782
+ for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
783
+ {
784
+ const int numValuesInBlock = blockNdx == numBlocks-1 ? numValues - 3*(numBlocks-1) : 3;
785
+ decodeISEQuintBlock(&dst[3*blockNdx], numValuesInBlock, data, params.numBits);
786
+ }
787
+ }
788
+ else
789
+ {
790
+ DE_ASSERT(params.mode == ISEMODE_PLAIN_BIT);
791
+ for (int i = 0; i < numValues; i++)
792
+ decodeISEBitBlock(&dst[i], data, params.numBits);
793
+ }
794
+ }
795
+ void unquantizeColorEndpoints (deUint32* dst, const ISEDecodedResult* iseResults, int numEndpoints, const ISEParams& iseParams)
796
+ {
797
+ if (iseParams.mode == ISEMODE_TRIT || iseParams.mode == ISEMODE_QUINT)
798
+ {
799
+ const int rangeCase = iseParams.numBits*2 - (iseParams.mode == ISEMODE_TRIT ? 2 : 1);
800
+ DE_ASSERT(basisu::inRange(rangeCase, 0, 10));
801
+ static const deUint32 Ca[11] = { 204, 113, 93, 54, 44, 26, 22, 13, 11, 6, 5 };
802
+ const deUint32 C = Ca[rangeCase];
803
+ for (int endpointNdx = 0; endpointNdx < numEndpoints; endpointNdx++)
804
+ {
805
+ const deUint32 a = getBit(iseResults[endpointNdx].m, 0);
806
+ const deUint32 b = getBit(iseResults[endpointNdx].m, 1);
807
+ const deUint32 c = getBit(iseResults[endpointNdx].m, 2);
808
+ const deUint32 d = getBit(iseResults[endpointNdx].m, 3);
809
+ const deUint32 e = getBit(iseResults[endpointNdx].m, 4);
810
+ const deUint32 f = getBit(iseResults[endpointNdx].m, 5);
811
+ const deUint32 A = a == 0 ? 0 : (1<<9)-1;
812
+ const deUint32 B = rangeCase == 0 ? 0
813
+ : rangeCase == 1 ? 0
814
+ : rangeCase == 2 ? (b << 8) | (b << 4) | (b << 2) | (b << 1)
815
+ : rangeCase == 3 ? (b << 8) | (b << 3) | (b << 2)
816
+ : rangeCase == 4 ? (c << 8) | (b << 7) | (c << 3) | (b << 2) | (c << 1) | (b << 0)
817
+ : rangeCase == 5 ? (c << 8) | (b << 7) | (c << 2) | (b << 1) | (c << 0)
818
+ : rangeCase == 6 ? (d << 8) | (c << 7) | (b << 6) | (d << 2) | (c << 1) | (b << 0)
819
+ : rangeCase == 7 ? (d << 8) | (c << 7) | (b << 6) | (d << 1) | (c << 0)
820
+ : rangeCase == 8 ? (e << 8) | (d << 7) | (c << 6) | (b << 5) | (e << 1) | (d << 0)
821
+ : rangeCase == 9 ? (e << 8) | (d << 7) | (c << 6) | (b << 5) | (e << 0)
822
+ : rangeCase == 10 ? (f << 8) | (e << 7) | (d << 6) | (c << 5) | (b << 4) | (f << 0)
823
+ : (deUint32)-1;
824
+ DE_ASSERT(B != (deUint32)-1);
825
+ dst[endpointNdx] = (((iseResults[endpointNdx].tq*C + B) ^ A) >> 2) | (A & 0x80);
826
+ }
827
+ }
828
+ else
829
+ {
830
+ DE_ASSERT(iseParams.mode == ISEMODE_PLAIN_BIT);
831
+ for (int endpointNdx = 0; endpointNdx < numEndpoints; endpointNdx++)
832
+ dst[endpointNdx] = bitReplicationScale(iseResults[endpointNdx].v, iseParams.numBits, 8);
833
+ }
834
+ }
835
+ inline void bitTransferSigned (deInt32& a, deInt32& b)
836
+ {
837
+ b >>= 1;
838
+ b |= a & 0x80;
839
+ a >>= 1;
840
+ a &= 0x3f;
841
+ if (isBitSet(a, 5))
842
+ a -= 0x40;
843
+ }
844
+ inline UVec4 clampedRGBA (const IVec4& rgba)
845
+ {
846
+ return UVec4(basisu::astc_clamp(rgba.x(), 0, 0xff),
847
+ basisu::astc_clamp(rgba.y(), 0, 0xff),
848
+ basisu::astc_clamp(rgba.z(), 0, 0xff),
849
+ basisu::astc_clamp(rgba.w(), 0, 0xff));
850
+ }
851
+ inline IVec4 blueContract (int r, int g, int b, int a)
852
+ {
853
+ return IVec4((r+b)>>1, (g+b)>>1, b, a);
854
+ }
855
+ inline bool isColorEndpointModeHDR (deUint32 mode)
856
+ {
857
+ return mode == 2 ||
858
+ mode == 3 ||
859
+ mode == 7 ||
860
+ mode == 11 ||
861
+ mode == 14 ||
862
+ mode == 15;
863
+ }
864
+ void decodeHDREndpointMode7 (UVec4& e0, UVec4& e1, deUint32 v0, deUint32 v1, deUint32 v2, deUint32 v3)
865
+ {
866
+ const deUint32 m10 = getBit(v1, 7) | (getBit(v2, 7) << 1);
867
+ const deUint32 m23 = getBits(v0, 6, 7);
868
+ const deUint32 majComp = m10 != 3 ? m10
869
+ : m23 != 3 ? m23
870
+ : 0;
871
+ const deUint32 mode = m10 != 3 ? m23
872
+ : m23 != 3 ? 4
873
+ : 5;
874
+ deInt32 red = (deInt32)getBits(v0, 0, 5);
875
+ deInt32 green = (deInt32)getBits(v1, 0, 4);
876
+ deInt32 blue = (deInt32)getBits(v2, 0, 4);
877
+ deInt32 scale = (deInt32)getBits(v3, 0, 4);
878
+ {
879
+ #define SHOR(DST_VAR, SHIFT, BIT_VAR) (DST_VAR) |= (BIT_VAR) << (SHIFT)
880
+ #define ASSIGN_X_BITS(V0,S0, V1,S1, V2,S2, V3,S3, V4,S4, V5,S5, V6,S6) do { SHOR(V0,S0,x0); SHOR(V1,S1,x1); SHOR(V2,S2,x2); SHOR(V3,S3,x3); SHOR(V4,S4,x4); SHOR(V5,S5,x5); SHOR(V6,S6,x6); } while (false)
881
+ const deUint32 x0 = getBit(v1, 6);
882
+ const deUint32 x1 = getBit(v1, 5);
883
+ const deUint32 x2 = getBit(v2, 6);
884
+ const deUint32 x3 = getBit(v2, 5);
885
+ const deUint32 x4 = getBit(v3, 7);
886
+ const deUint32 x5 = getBit(v3, 6);
887
+ const deUint32 x6 = getBit(v3, 5);
888
+ deInt32& R = red;
889
+ deInt32& G = green;
890
+ deInt32& B = blue;
891
+ deInt32& S = scale;
892
+ switch (mode)
893
+ {
894
+ case 0: ASSIGN_X_BITS(R,9, R,8, R,7, R,10, R,6, S,6, S,5); break;
895
+ case 1: ASSIGN_X_BITS(R,8, G,5, R,7, B,5, R,6, R,10, R,9); break;
896
+ case 2: ASSIGN_X_BITS(R,9, R,8, R,7, R,6, S,7, S,6, S,5); break;
897
+ case 3: ASSIGN_X_BITS(R,8, G,5, R,7, B,5, R,6, S,6, S,5); break;
898
+ case 4: ASSIGN_X_BITS(G,6, G,5, B,6, B,5, R,6, R,7, S,5); break;
899
+ case 5: ASSIGN_X_BITS(G,6, G,5, B,6, B,5, R,6, S,6, S,5); break;
900
+ default:
901
+ DE_ASSERT(false);
902
+ }
903
+ #undef ASSIGN_X_BITS
904
+ #undef SHOR
905
+ }
906
+ static const int shiftAmounts[] = { 1, 1, 2, 3, 4, 5 };
907
+ DE_ASSERT(mode < DE_LENGTH_OF_ARRAY(shiftAmounts));
908
+ red <<= shiftAmounts[mode];
909
+ green <<= shiftAmounts[mode];
910
+ blue <<= shiftAmounts[mode];
911
+ scale <<= shiftAmounts[mode];
912
+ if (mode != 5)
913
+ {
914
+ green = red - green;
915
+ blue = red - blue;
916
+ }
917
+ if (majComp == 1)
918
+ std::swap(red, green);
919
+ else if (majComp == 2)
920
+ std::swap(red, blue);
921
+ e0 = UVec4(basisu::astc_clamp(red - scale, 0, 0xfff),
922
+ basisu::astc_clamp(green - scale, 0, 0xfff),
923
+ basisu::astc_clamp(blue - scale, 0, 0xfff),
924
+ 0x780);
925
+ e1 = UVec4(basisu::astc_clamp(red, 0, 0xfff),
926
+ basisu::astc_clamp(green, 0, 0xfff),
927
+ basisu::astc_clamp(blue, 0, 0xfff),
928
+ 0x780);
929
+ }
930
+ void decodeHDREndpointMode11 (UVec4& e0, UVec4& e1, deUint32 v0, deUint32 v1, deUint32 v2, deUint32 v3, deUint32 v4, deUint32 v5)
931
+ {
932
+ const deUint32 major = (getBit(v5, 7) << 1) | getBit(v4, 7);
933
+ if (major == 3)
934
+ {
935
+ e0 = UVec4(v0<<4, v2<<4, getBits(v4,0,6)<<5, 0x780);
936
+ e1 = UVec4(v1<<4, v3<<4, getBits(v5,0,6)<<5, 0x780);
937
+ }
938
+ else
939
+ {
940
+ const deUint32 mode = (getBit(v3, 7) << 2) | (getBit(v2, 7) << 1) | getBit(v1, 7);
941
+ deInt32 a = (deInt32)((getBit(v1, 6) << 8) | v0);
942
+ deInt32 c = (deInt32)(getBits(v1, 0, 5));
943
+ deInt32 b0 = (deInt32)(getBits(v2, 0, 5));
944
+ deInt32 b1 = (deInt32)(getBits(v3, 0, 5));
945
+ deInt32 d0 = (deInt32)(getBits(v4, 0, 4));
946
+ deInt32 d1 = (deInt32)(getBits(v5, 0, 4));
947
+ {
948
+ #define SHOR(DST_VAR, SHIFT, BIT_VAR) (DST_VAR) |= (BIT_VAR) << (SHIFT)
949
+ #define ASSIGN_X_BITS(V0,S0, V1,S1, V2,S2, V3,S3, V4,S4, V5,S5) do { SHOR(V0,S0,x0); SHOR(V1,S1,x1); SHOR(V2,S2,x2); SHOR(V3,S3,x3); SHOR(V4,S4,x4); SHOR(V5,S5,x5); } while (false)
950
+ const deUint32 x0 = getBit(v2, 6);
951
+ const deUint32 x1 = getBit(v3, 6);
952
+ const deUint32 x2 = getBit(v4, 6);
953
+ const deUint32 x3 = getBit(v5, 6);
954
+ const deUint32 x4 = getBit(v4, 5);
955
+ const deUint32 x5 = getBit(v5, 5);
956
+ switch (mode)
957
+ {
958
+ case 0: ASSIGN_X_BITS(b0,6, b1,6, d0,6, d1,6, d0,5, d1,5); break;
959
+ case 1: ASSIGN_X_BITS(b0,6, b1,6, b0,7, b1,7, d0,5, d1,5); break;
960
+ case 2: ASSIGN_X_BITS(a,9, c,6, d0,6, d1,6, d0,5, d1,5); break;
961
+ case 3: ASSIGN_X_BITS(b0,6, b1,6, a,9, c,6, d0,5, d1,5); break;
962
+ case 4: ASSIGN_X_BITS(b0,6, b1,6, b0,7, b1,7, a,9, a,10); break;
963
+ case 5: ASSIGN_X_BITS(a,9, a,10, c,7, c,6, d0,5, d1,5); break;
964
+ case 6: ASSIGN_X_BITS(b0,6, b1,6, a,11, c,6, a,9, a,10); break;
965
+ case 7: ASSIGN_X_BITS(a,9, a,10, a,11, c,6, d0,5, d1,5); break;
966
+ default:
967
+ DE_ASSERT(false);
968
+ }
969
+ #undef ASSIGN_X_BITS
970
+ #undef SHOR
971
+ }
972
+ static const int numDBits[] = { 7, 6, 7, 6, 5, 6, 5, 6 };
973
+ DE_ASSERT(mode < DE_LENGTH_OF_ARRAY(numDBits));
974
+ d0 = signExtend(d0, numDBits[mode]);
975
+ d1 = signExtend(d1, numDBits[mode]);
976
+ const int shiftAmount = (mode >> 1) ^ 3;
977
+ a <<= shiftAmount;
978
+ c <<= shiftAmount;
979
+ b0 <<= shiftAmount;
980
+ b1 <<= shiftAmount;
981
+ d0 <<= shiftAmount;
982
+ d1 <<= shiftAmount;
983
+ e0 = UVec4(basisu::astc_clamp(a-c, 0, 0xfff),
984
+ basisu::astc_clamp(a-b0-c-d0, 0, 0xfff),
985
+ basisu::astc_clamp(a-b1-c-d1, 0, 0xfff),
986
+ 0x780);
987
+ e1 = UVec4(basisu::astc_clamp(a, 0, 0xfff),
988
+ basisu::astc_clamp(a-b0, 0, 0xfff),
989
+ basisu::astc_clamp(a-b1, 0, 0xfff),
990
+ 0x780);
991
+ if (major == 1)
992
+ {
993
+ std::swap(e0.x(), e0.y());
994
+ std::swap(e1.x(), e1.y());
995
+ }
996
+ else if (major == 2)
997
+ {
998
+ std::swap(e0.x(), e0.z());
999
+ std::swap(e1.x(), e1.z());
1000
+ }
1001
+ }
1002
+ }
1003
+ void decodeHDREndpointMode15(UVec4& e0, UVec4& e1, deUint32 v0, deUint32 v1, deUint32 v2, deUint32 v3, deUint32 v4, deUint32 v5, deUint32 v6In, deUint32 v7In)
1004
+ {
1005
+ decodeHDREndpointMode11(e0, e1, v0, v1, v2, v3, v4, v5);
1006
+ const deUint32 mode = (getBit(v7In, 7) << 1) | getBit(v6In, 7);
1007
+ deInt32 v6 = (deInt32)getBits(v6In, 0, 6);
1008
+ deInt32 v7 = (deInt32)getBits(v7In, 0, 6);
1009
+ if (mode == 3)
1010
+ {
1011
+ e0.w() = v6 << 5;
1012
+ e1.w() = v7 << 5;
1013
+ }
1014
+ else
1015
+ {
1016
+ v6 |= (v7 << (mode+1)) & 0x780;
1017
+ v7 &= (0x3f >> mode);
1018
+ v7 ^= 0x20 >> mode;
1019
+ v7 -= 0x20 >> mode;
1020
+ v6 <<= 4-mode;
1021
+ v7 <<= 4-mode;
1022
+ v7 += v6;
1023
+ v7 = basisu::astc_clamp(v7, 0, 0xfff);
1024
+ e0.w() = v6;
1025
+ e1.w() = v7;
1026
+ }
1027
+ }
1028
+ void decodeColorEndpoints (ColorEndpointPair* dst, const deUint32* unquantizedEndpoints, const deUint32* endpointModes, int numPartitions)
1029
+ {
1030
+ int unquantizedNdx = 0;
1031
+ for (int partitionNdx = 0; partitionNdx < numPartitions; partitionNdx++)
1032
+ {
1033
+ const deUint32 endpointMode = endpointModes[partitionNdx];
1034
+ const deUint32* v = &unquantizedEndpoints[unquantizedNdx];
1035
+ UVec4& e0 = dst[partitionNdx].e0;
1036
+ UVec4& e1 = dst[partitionNdx].e1;
1037
+ unquantizedNdx += computeNumColorEndpointValues(endpointMode);
1038
+ switch (endpointMode)
1039
+ {
1040
+ case 0:
1041
+ e0 = UVec4(v[0], v[0], v[0], 0xff);
1042
+ e1 = UVec4(v[1], v[1], v[1], 0xff);
1043
+ break;
1044
+ case 1:
1045
+ {
1046
+ const deUint32 L0 = (v[0] >> 2) | (getBits(v[1], 6, 7) << 6);
1047
+ const deUint32 L1 = basisu::min(0xffu, L0 + getBits(v[1], 0, 5));
1048
+ e0 = UVec4(L0, L0, L0, 0xff);
1049
+ e1 = UVec4(L1, L1, L1, 0xff);
1050
+ break;
1051
+ }
1052
+ case 2:
1053
+ {
1054
+ const deUint32 v1Gr = v[1] >= v[0];
1055
+ const deUint32 y0 = v1Gr ? v[0]<<4 : (v[1]<<4) + 8;
1056
+ const deUint32 y1 = v1Gr ? v[1]<<4 : (v[0]<<4) - 8;
1057
+ e0 = UVec4(y0, y0, y0, 0x780);
1058
+ e1 = UVec4(y1, y1, y1, 0x780);
1059
+ break;
1060
+ }
1061
+ case 3:
1062
+ {
1063
+ const bool m = isBitSet(v[0], 7);
1064
+ const deUint32 y0 = m ? (getBits(v[1], 5, 7) << 9) | (getBits(v[0], 0, 6) << 2)
1065
+ : (getBits(v[1], 4, 7) << 8) | (getBits(v[0], 0, 6) << 1);
1066
+ const deUint32 d = m ? getBits(v[1], 0, 4) << 2
1067
+ : getBits(v[1], 0, 3) << 1;
1068
+ const deUint32 y1 = basisu::min(0xfffu, y0+d);
1069
+ e0 = UVec4(y0, y0, y0, 0x780);
1070
+ e1 = UVec4(y1, y1, y1, 0x780);
1071
+ break;
1072
+ }
1073
+ case 4:
1074
+ e0 = UVec4(v[0], v[0], v[0], v[2]);
1075
+ e1 = UVec4(v[1], v[1], v[1], v[3]);
1076
+ break;
1077
+ case 5:
1078
+ {
1079
+ deInt32 v0 = (deInt32)v[0];
1080
+ deInt32 v1 = (deInt32)v[1];
1081
+ deInt32 v2 = (deInt32)v[2];
1082
+ deInt32 v3 = (deInt32)v[3];
1083
+ bitTransferSigned(v1, v0);
1084
+ bitTransferSigned(v3, v2);
1085
+ e0 = clampedRGBA(IVec4(v0, v0, v0, v2));
1086
+ e1 = clampedRGBA(IVec4(v0+v1, v0+v1, v0+v1, v2+v3));
1087
+ break;
1088
+ }
1089
+ case 6:
1090
+ e0 = UVec4((v[0]*v[3]) >> 8, (v[1]*v[3]) >> 8, (v[2]*v[3]) >> 8, 0xff);
1091
+ e1 = UVec4(v[0], v[1], v[2], 0xff);
1092
+ break;
1093
+ case 7:
1094
+ decodeHDREndpointMode7(e0, e1, v[0], v[1], v[2], v[3]);
1095
+ break;
1096
+ case 8:
1097
+ if (v[1]+v[3]+v[5] >= v[0]+v[2]+v[4])
1098
+ {
1099
+ e0 = UVec4(v[0], v[2], v[4], 0xff);
1100
+ e1 = UVec4(v[1], v[3], v[5], 0xff);
1101
+ }
1102
+ else
1103
+ {
1104
+ e0 = blueContract(v[1], v[3], v[5], 0xff).asUint();
1105
+ e1 = blueContract(v[0], v[2], v[4], 0xff).asUint();
1106
+ }
1107
+ break;
1108
+ case 9:
1109
+ {
1110
+ deInt32 v0 = (deInt32)v[0];
1111
+ deInt32 v1 = (deInt32)v[1];
1112
+ deInt32 v2 = (deInt32)v[2];
1113
+ deInt32 v3 = (deInt32)v[3];
1114
+ deInt32 v4 = (deInt32)v[4];
1115
+ deInt32 v5 = (deInt32)v[5];
1116
+ bitTransferSigned(v1, v0);
1117
+ bitTransferSigned(v3, v2);
1118
+ bitTransferSigned(v5, v4);
1119
+ if (v1+v3+v5 >= 0)
1120
+ {
1121
+ e0 = clampedRGBA(IVec4(v0, v2, v4, 0xff));
1122
+ e1 = clampedRGBA(IVec4(v0+v1, v2+v3, v4+v5, 0xff));
1123
+ }
1124
+ else
1125
+ {
1126
+ e0 = clampedRGBA(blueContract(v0+v1, v2+v3, v4+v5, 0xff));
1127
+ e1 = clampedRGBA(blueContract(v0, v2, v4, 0xff));
1128
+ }
1129
+ break;
1130
+ }
1131
+ case 10:
1132
+ e0 = UVec4((v[0]*v[3]) >> 8, (v[1]*v[3]) >> 8, (v[2]*v[3]) >> 8, v[4]);
1133
+ e1 = UVec4(v[0], v[1], v[2], v[5]);
1134
+ break;
1135
+ case 11:
1136
+ decodeHDREndpointMode11(e0, e1, v[0], v[1], v[2], v[3], v[4], v[5]);
1137
+ break;
1138
+ case 12:
1139
+ if (v[1]+v[3]+v[5] >= v[0]+v[2]+v[4])
1140
+ {
1141
+ e0 = UVec4(v[0], v[2], v[4], v[6]);
1142
+ e1 = UVec4(v[1], v[3], v[5], v[7]);
1143
+ }
1144
+ else
1145
+ {
1146
+ e0 = clampedRGBA(blueContract(v[1], v[3], v[5], v[7]));
1147
+ e1 = clampedRGBA(blueContract(v[0], v[2], v[4], v[6]));
1148
+ }
1149
+ break;
1150
+ case 13:
1151
+ {
1152
+ deInt32 v0 = (deInt32)v[0];
1153
+ deInt32 v1 = (deInt32)v[1];
1154
+ deInt32 v2 = (deInt32)v[2];
1155
+ deInt32 v3 = (deInt32)v[3];
1156
+ deInt32 v4 = (deInt32)v[4];
1157
+ deInt32 v5 = (deInt32)v[5];
1158
+ deInt32 v6 = (deInt32)v[6];
1159
+ deInt32 v7 = (deInt32)v[7];
1160
+ bitTransferSigned(v1, v0);
1161
+ bitTransferSigned(v3, v2);
1162
+ bitTransferSigned(v5, v4);
1163
+ bitTransferSigned(v7, v6);
1164
+ if (v1+v3+v5 >= 0)
1165
+ {
1166
+ e0 = clampedRGBA(IVec4(v0, v2, v4, v6));
1167
+ e1 = clampedRGBA(IVec4(v0+v1, v2+v3, v4+v5, v6+v7));
1168
+ }
1169
+ else
1170
+ {
1171
+ e0 = clampedRGBA(blueContract(v0+v1, v2+v3, v4+v5, v6+v7));
1172
+ e1 = clampedRGBA(blueContract(v0, v2, v4, v6));
1173
+ }
1174
+ break;
1175
+ }
1176
+ case 14:
1177
+ decodeHDREndpointMode11(e0, e1, v[0], v[1], v[2], v[3], v[4], v[5]);
1178
+ e0.w() = v[6];
1179
+ e1.w() = v[7];
1180
+ break;
1181
+ case 15:
1182
+ decodeHDREndpointMode15(e0, e1, v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
1183
+ break;
1184
+ default:
1185
+ DE_ASSERT(false);
1186
+ }
1187
+ }
1188
+ }
1189
+ void computeColorEndpoints (ColorEndpointPair* dst, const Block128& blockData, const deUint32* endpointModes, int numPartitions, int numColorEndpointValues, const ISEParams& iseParams, int numBitsAvailable)
1190
+ {
1191
+ const int colorEndpointDataStart = numPartitions == 1 ? 17 : 29;
1192
+ ISEDecodedResult colorEndpointData[18];
1193
+ {
1194
+ BitAccessStream dataStream(blockData, colorEndpointDataStart, numBitsAvailable, true);
1195
+ decodeISE(&colorEndpointData[0], numColorEndpointValues, dataStream, iseParams);
1196
+ }
1197
+ {
1198
+ deUint32 unquantizedEndpoints[18];
1199
+ unquantizeColorEndpoints(&unquantizedEndpoints[0], &colorEndpointData[0], numColorEndpointValues, iseParams);
1200
+ decodeColorEndpoints(dst, &unquantizedEndpoints[0], &endpointModes[0], numPartitions);
1201
+ }
1202
+ }
1203
+ void unquantizeWeights (deUint32 dst[64], const ISEDecodedResult* weightGrid, const ASTCBlockMode& blockMode)
1204
+ {
1205
+ const int numWeights = computeNumWeights(blockMode);
1206
+ const ISEParams& iseParams = blockMode.weightISEParams;
1207
+ if (iseParams.mode == ISEMODE_TRIT || iseParams.mode == ISEMODE_QUINT)
1208
+ {
1209
+ const int rangeCase = iseParams.numBits*2 + (iseParams.mode == ISEMODE_QUINT ? 1 : 0);
1210
+ if (rangeCase == 0 || rangeCase == 1)
1211
+ {
1212
+ static const deUint32 map0[3] = { 0, 32, 63 };
1213
+ static const deUint32 map1[5] = { 0, 16, 32, 47, 63 };
1214
+ const deUint32* const map = rangeCase == 0 ? &map0[0] : &map1[0];
1215
+ for (int i = 0; i < numWeights; i++)
1216
+ {
1217
+ DE_ASSERT(weightGrid[i].v < (rangeCase == 0 ? 3u : 5u));
1218
+ dst[i] = map[weightGrid[i].v];
1219
+ }
1220
+ }
1221
+ else
1222
+ {
1223
+ DE_ASSERT(rangeCase <= 6);
1224
+ static const deUint32 Ca[5] = { 50, 28, 23, 13, 11 };
1225
+ const deUint32 C = Ca[rangeCase-2];
1226
+ for (int weightNdx = 0; weightNdx < numWeights; weightNdx++)
1227
+ {
1228
+ const deUint32 a = getBit(weightGrid[weightNdx].m, 0);
1229
+ const deUint32 b = getBit(weightGrid[weightNdx].m, 1);
1230
+ const deUint32 c = getBit(weightGrid[weightNdx].m, 2);
1231
+ const deUint32 A = a == 0 ? 0 : (1<<7)-1;
1232
+ const deUint32 B = rangeCase == 2 ? 0
1233
+ : rangeCase == 3 ? 0
1234
+ : rangeCase == 4 ? (b << 6) | (b << 2) | (b << 0)
1235
+ : rangeCase == 5 ? (b << 6) | (b << 1)
1236
+ : rangeCase == 6 ? (c << 6) | (b << 5) | (c << 1) | (b << 0)
1237
+ : (deUint32)-1;
1238
+ dst[weightNdx] = (((weightGrid[weightNdx].tq*C + B) ^ A) >> 2) | (A & 0x20);
1239
+ }
1240
+ }
1241
+ }
1242
+ else
1243
+ {
1244
+ DE_ASSERT(iseParams.mode == ISEMODE_PLAIN_BIT);
1245
+ for (int weightNdx = 0; weightNdx < numWeights; weightNdx++)
1246
+ dst[weightNdx] = bitReplicationScale(weightGrid[weightNdx].v, iseParams.numBits, 6);
1247
+ }
1248
+ for (int weightNdx = 0; weightNdx < numWeights; weightNdx++)
1249
+ dst[weightNdx] += dst[weightNdx] > 32 ? 1 : 0;
1250
+ // Initialize nonexistent weights to poison values
1251
+ for (int weightNdx = numWeights; weightNdx < 64; weightNdx++)
1252
+ dst[weightNdx] = ~0u;
1253
+ }
1254
+ void interpolateWeights (TexelWeightPair* dst, const deUint32 (&unquantizedWeights) [64], int blockWidth, int blockHeight, const ASTCBlockMode& blockMode)
1255
+ {
1256
+ const int numWeightsPerTexel = blockMode.isDualPlane ? 2 : 1;
1257
+ const deUint32 scaleX = (1024 + blockWidth/2) / (blockWidth-1);
1258
+ const deUint32 scaleY = (1024 + blockHeight/2) / (blockHeight-1);
1259
+ DE_ASSERT(blockMode.weightGridWidth*blockMode.weightGridHeight*numWeightsPerTexel <= DE_LENGTH_OF_ARRAY(unquantizedWeights));
1260
+ for (int texelY = 0; texelY < blockHeight; texelY++)
1261
+ {
1262
+ for (int texelX = 0; texelX < blockWidth; texelX++)
1263
+ {
1264
+ const deUint32 gX = (scaleX*texelX*(blockMode.weightGridWidth-1) + 32) >> 6;
1265
+ const deUint32 gY = (scaleY*texelY*(blockMode.weightGridHeight-1) + 32) >> 6;
1266
+ const deUint32 jX = gX >> 4;
1267
+ const deUint32 jY = gY >> 4;
1268
+ const deUint32 fX = gX & 0xf;
1269
+ const deUint32 fY = gY & 0xf;
1270
+ const deUint32 w11 = (fX*fY + 8) >> 4;
1271
+ const deUint32 w10 = fY - w11;
1272
+ const deUint32 w01 = fX - w11;
1273
+ const deUint32 w00 = 16 - fX - fY + w11;
1274
+ const deUint32 i00 = jY*blockMode.weightGridWidth + jX;
1275
+ const deUint32 i01 = i00 + 1;
1276
+ const deUint32 i10 = i00 + blockMode.weightGridWidth;
1277
+ const deUint32 i11 = i00 + blockMode.weightGridWidth + 1;
1278
+ // These addresses can be out of bounds, but respective weights will be 0 then.
1279
+ DE_ASSERT(deInBounds32(i00, 0, blockMode.weightGridWidth*blockMode.weightGridHeight) || w00 == 0);
1280
+ DE_ASSERT(deInBounds32(i01, 0, blockMode.weightGridWidth*blockMode.weightGridHeight) || w01 == 0);
1281
+ DE_ASSERT(deInBounds32(i10, 0, blockMode.weightGridWidth*blockMode.weightGridHeight) || w10 == 0);
1282
+ DE_ASSERT(deInBounds32(i11, 0, blockMode.weightGridWidth*blockMode.weightGridHeight) || w11 == 0);
1283
+ for (int texelWeightNdx = 0; texelWeightNdx < numWeightsPerTexel; texelWeightNdx++)
1284
+ {
1285
+ // & 0x3f clamps address to bounds of unquantizedWeights
1286
+ const deUint32 p00 = unquantizedWeights[(i00 * numWeightsPerTexel + texelWeightNdx) & 0x3f];
1287
+ const deUint32 p01 = unquantizedWeights[(i01 * numWeightsPerTexel + texelWeightNdx) & 0x3f];
1288
+ const deUint32 p10 = unquantizedWeights[(i10 * numWeightsPerTexel + texelWeightNdx) & 0x3f];
1289
+ const deUint32 p11 = unquantizedWeights[(i11 * numWeightsPerTexel + texelWeightNdx) & 0x3f];
1290
+ dst[texelY*blockWidth + texelX].w[texelWeightNdx] = (p00*w00 + p01*w01 + p10*w10 + p11*w11 + 8) >> 4;
1291
+ }
1292
+ }
1293
+ }
1294
+ }
1295
+ void computeTexelWeights (TexelWeightPair* dst, const Block128& blockData, int blockWidth, int blockHeight, const ASTCBlockMode& blockMode)
1296
+ {
1297
+ ISEDecodedResult weightGrid[64];
1298
+ {
1299
+ BitAccessStream dataStream(blockData, 127, computeNumRequiredBits(blockMode.weightISEParams, computeNumWeights(blockMode)), false);
1300
+ decodeISE(&weightGrid[0], computeNumWeights(blockMode), dataStream, blockMode.weightISEParams);
1301
+ }
1302
+ {
1303
+ deUint32 unquantizedWeights[64];
1304
+ unquantizeWeights(&unquantizedWeights[0], &weightGrid[0], blockMode);
1305
+ interpolateWeights(dst, unquantizedWeights, blockWidth, blockHeight, blockMode);
1306
+ }
1307
+ }
1308
+ inline deUint32 hash52 (deUint32 v)
1309
+ {
1310
+ deUint32 p = v;
1311
+ p ^= p >> 15; p -= p << 17; p += p << 7; p += p << 4;
1312
+ p ^= p >> 5; p += p << 16; p ^= p >> 7; p ^= p >> 3;
1313
+ p ^= p << 6; p ^= p >> 17;
1314
+ return p;
1315
+ }
1316
+ int computeTexelPartition (deUint32 seedIn, deUint32 xIn, deUint32 yIn, deUint32 zIn, int numPartitions, bool smallBlock)
1317
+ {
1318
+ DE_ASSERT(zIn == 0);
1319
+ const deUint32 x = smallBlock ? xIn << 1 : xIn;
1320
+ const deUint32 y = smallBlock ? yIn << 1 : yIn;
1321
+ const deUint32 z = smallBlock ? zIn << 1 : zIn;
1322
+ const deUint32 seed = seedIn + 1024*(numPartitions-1);
1323
+ const deUint32 rnum = hash52(seed);
1324
+ deUint8 seed1 = (deUint8)( rnum & 0xf);
1325
+ deUint8 seed2 = (deUint8)((rnum >> 4) & 0xf);
1326
+ deUint8 seed3 = (deUint8)((rnum >> 8) & 0xf);
1327
+ deUint8 seed4 = (deUint8)((rnum >> 12) & 0xf);
1328
+ deUint8 seed5 = (deUint8)((rnum >> 16) & 0xf);
1329
+ deUint8 seed6 = (deUint8)((rnum >> 20) & 0xf);
1330
+ deUint8 seed7 = (deUint8)((rnum >> 24) & 0xf);
1331
+ deUint8 seed8 = (deUint8)((rnum >> 28) & 0xf);
1332
+ deUint8 seed9 = (deUint8)((rnum >> 18) & 0xf);
1333
+ deUint8 seed10 = (deUint8)((rnum >> 22) & 0xf);
1334
+ deUint8 seed11 = (deUint8)((rnum >> 26) & 0xf);
1335
+ deUint8 seed12 = (deUint8)(((rnum >> 30) | (rnum << 2)) & 0xf);
1336
+ seed1 = (deUint8)(seed1 * seed1 );
1337
+ seed2 = (deUint8)(seed2 * seed2 );
1338
+ seed3 = (deUint8)(seed3 * seed3 );
1339
+ seed4 = (deUint8)(seed4 * seed4 );
1340
+ seed5 = (deUint8)(seed5 * seed5 );
1341
+ seed6 = (deUint8)(seed6 * seed6 );
1342
+ seed7 = (deUint8)(seed7 * seed7 );
1343
+ seed8 = (deUint8)(seed8 * seed8 );
1344
+ seed9 = (deUint8)(seed9 * seed9 );
1345
+ seed10 = (deUint8)(seed10 * seed10);
1346
+ seed11 = (deUint8)(seed11 * seed11);
1347
+ seed12 = (deUint8)(seed12 * seed12);
1348
+ const int shA = (seed & 2) != 0 ? 4 : 5;
1349
+ const int shB = numPartitions == 3 ? 6 : 5;
1350
+ const int sh1 = (seed & 1) != 0 ? shA : shB;
1351
+ const int sh2 = (seed & 1) != 0 ? shB : shA;
1352
+ const int sh3 = (seed & 0x10) != 0 ? sh1 : sh2;
1353
+ seed1 = (deUint8)(seed1 >> sh1);
1354
+ seed2 = (deUint8)(seed2 >> sh2);
1355
+ seed3 = (deUint8)(seed3 >> sh1);
1356
+ seed4 = (deUint8)(seed4 >> sh2);
1357
+ seed5 = (deUint8)(seed5 >> sh1);
1358
+ seed6 = (deUint8)(seed6 >> sh2);
1359
+ seed7 = (deUint8)(seed7 >> sh1);
1360
+ seed8 = (deUint8)(seed8 >> sh2);
1361
+ seed9 = (deUint8)(seed9 >> sh3);
1362
+ seed10 = (deUint8)(seed10 >> sh3);
1363
+ seed11 = (deUint8)(seed11 >> sh3);
1364
+ seed12 = (deUint8)(seed12 >> sh3);
1365
+ const int a = 0x3f & (seed1*x + seed2*y + seed11*z + (rnum >> 14));
1366
+ const int b = 0x3f & (seed3*x + seed4*y + seed12*z + (rnum >> 10));
1367
+ const int c = numPartitions >= 3 ? 0x3f & (seed5*x + seed6*y + seed9*z + (rnum >> 6)) : 0;
1368
+ const int d = numPartitions >= 4 ? 0x3f & (seed7*x + seed8*y + seed10*z + (rnum >> 2)) : 0;
1369
+ return a >= b && a >= c && a >= d ? 0
1370
+ : b >= c && b >= d ? 1
1371
+ : c >= d ? 2
1372
+ : 3;
1373
+ }
1374
+ DecompressResult setTexelColors (void* dst, ColorEndpointPair* colorEndpoints, TexelWeightPair* texelWeights, int ccs, deUint32 partitionIndexSeed,
1375
+ int numPartitions, int blockWidth, int blockHeight, bool isSRGB, bool isLDRMode, const deUint32* colorEndpointModes)
1376
+ {
1377
+ const bool smallBlock = blockWidth*blockHeight < 31;
1378
+ DecompressResult result = DECOMPRESS_RESULT_VALID_BLOCK;
1379
+ bool isHDREndpoint[4];
1380
+ for (int i = 0; i < numPartitions; i++)
1381
+ {
1382
+ isHDREndpoint[i] = isColorEndpointModeHDR(colorEndpointModes[i]);
1383
+
1384
+ // rg - REMOVING HDR SUPPORT FOR NOW
1385
+ if (isHDREndpoint[i])
1386
+ return DECOMPRESS_RESULT_ERROR;
1387
+ }
1388
+
1389
+ for (int texelY = 0; texelY < blockHeight; texelY++)
1390
+ for (int texelX = 0; texelX < blockWidth; texelX++)
1391
+ {
1392
+ const int texelNdx = texelY*blockWidth + texelX;
1393
+ const int colorEndpointNdx = numPartitions == 1 ? 0 : computeTexelPartition(partitionIndexSeed, texelX, texelY, 0, numPartitions, smallBlock);
1394
+ DE_ASSERT(colorEndpointNdx < numPartitions);
1395
+ const UVec4& e0 = colorEndpoints[colorEndpointNdx].e0;
1396
+ const UVec4& e1 = colorEndpoints[colorEndpointNdx].e1;
1397
+ const TexelWeightPair& weight = texelWeights[texelNdx];
1398
+ if (isLDRMode && isHDREndpoint[colorEndpointNdx])
1399
+ {
1400
+ if (isSRGB)
1401
+ {
1402
+ ((deUint8*)dst)[texelNdx*4 + 0] = 0xff;
1403
+ ((deUint8*)dst)[texelNdx*4 + 1] = 0;
1404
+ ((deUint8*)dst)[texelNdx*4 + 2] = 0xff;
1405
+ ((deUint8*)dst)[texelNdx*4 + 3] = 0xff;
1406
+ }
1407
+ else
1408
+ {
1409
+ ((float*)dst)[texelNdx*4 + 0] = 1.0f;
1410
+ ((float*)dst)[texelNdx*4 + 1] = 0;
1411
+ ((float*)dst)[texelNdx*4 + 2] = 1.0f;
1412
+ ((float*)dst)[texelNdx*4 + 3] = 1.0f;
1413
+ }
1414
+ result = DECOMPRESS_RESULT_ERROR;
1415
+ }
1416
+ else
1417
+ {
1418
+ for (int channelNdx = 0; channelNdx < 4; channelNdx++)
1419
+ {
1420
+ if (!isHDREndpoint[colorEndpointNdx] || (channelNdx == 3 && colorEndpointModes[colorEndpointNdx] == 14)) // \note Alpha for mode 14 is treated the same as LDR.
1421
+ {
1422
+ const deUint32 c0 = (e0[channelNdx] << 8) | (isSRGB ? 0x80 : e0[channelNdx]);
1423
+ const deUint32 c1 = (e1[channelNdx] << 8) | (isSRGB ? 0x80 : e1[channelNdx]);
1424
+ const deUint32 w = weight.w[ccs == channelNdx ? 1 : 0];
1425
+ const deUint32 c = (c0*(64-w) + c1*w + 32) / 64;
1426
+ if (isSRGB)
1427
+ ((deUint8*)dst)[texelNdx*4 + channelNdx] = (deUint8)((c & 0xff00) >> 8);
1428
+ else
1429
+ ((float*)dst)[texelNdx*4 + channelNdx] = c == 65535 ? 1.0f : (float)c / 65536.0f;
1430
+ }
1431
+ else
1432
+ {
1433
+ //DE_STATIC_ASSERT((basisu::meta::TypesSame<deFloat16, deUint16>::Value));
1434
+ // rg - REMOVING HDR SUPPORT FOR NOW
1435
+ #if 0
1436
+ const deUint32 c0 = e0[channelNdx] << 4;
1437
+ const deUint32 c1 = e1[channelNdx] << 4;
1438
+ const deUint32 w = weight.w[ccs == channelNdx ? 1 : 0];
1439
+ const deUint32 c = (c0*(64-w) + c1*w + 32) / 64;
1440
+ const deUint32 e = getBits(c, 11, 15);
1441
+ const deUint32 m = getBits(c, 0, 10);
1442
+ const deUint32 mt = m < 512 ? 3*m
1443
+ : m >= 1536 ? 5*m - 2048
1444
+ : 4*m - 512;
1445
+ const deFloat16 cf = (deFloat16)((e << 10) + (mt >> 3));
1446
+ ((float*)dst)[texelNdx*4 + channelNdx] = deFloat16To32(isFloat16InfOrNan(cf) ? 0x7bff : cf);
1447
+ #endif
1448
+ }
1449
+ }
1450
+ }
1451
+ }
1452
+ return result;
1453
+ }
1454
+ DecompressResult decompressBlock (void* dst, const Block128& blockData, int blockWidth, int blockHeight, bool isSRGB, bool isLDR)
1455
+ {
1456
+ DE_ASSERT(isLDR || !isSRGB);
1457
+ // Decode block mode.
1458
+ const ASTCBlockMode blockMode = getASTCBlockMode(blockData.getBits(0, 10));
1459
+ // Check for block mode errors.
1460
+ if (blockMode.isError)
1461
+ {
1462
+ setASTCErrorColorBlock(dst, blockWidth, blockHeight, isSRGB);
1463
+ return DECOMPRESS_RESULT_ERROR;
1464
+ }
1465
+ // Separate path for void-extent.
1466
+ if (blockMode.isVoidExtent)
1467
+ return decodeVoidExtentBlock(dst, blockData, blockWidth, blockHeight, isSRGB, isLDR);
1468
+ // Compute weight grid values.
1469
+ const int numWeights = computeNumWeights(blockMode);
1470
+ const int numWeightDataBits = computeNumRequiredBits(blockMode.weightISEParams, numWeights);
1471
+ const int numPartitions = (int)blockData.getBits(11, 12) + 1;
1472
+ // Check for errors in weight grid, partition and dual-plane parameters.
1473
+ if (numWeights > 64 ||
1474
+ numWeightDataBits > 96 ||
1475
+ numWeightDataBits < 24 ||
1476
+ blockMode.weightGridWidth > blockWidth ||
1477
+ blockMode.weightGridHeight > blockHeight ||
1478
+ (numPartitions == 4 && blockMode.isDualPlane))
1479
+ {
1480
+ setASTCErrorColorBlock(dst, blockWidth, blockHeight, isSRGB);
1481
+ return DECOMPRESS_RESULT_ERROR;
1482
+ }
1483
+ // Compute number of bits available for color endpoint data.
1484
+ const bool isSingleUniqueCem = numPartitions == 1 || blockData.getBits(23, 24) == 0;
1485
+ const int numConfigDataBits = (numPartitions == 1 ? 17 : isSingleUniqueCem ? 29 : 25 + 3*numPartitions) +
1486
+ (blockMode.isDualPlane ? 2 : 0);
1487
+ const int numBitsForColorEndpoints = 128 - numWeightDataBits - numConfigDataBits;
1488
+ const int extraCemBitsStart = 127 - numWeightDataBits - (isSingleUniqueCem ? -1
1489
+ : numPartitions == 4 ? 7
1490
+ : numPartitions == 3 ? 4
1491
+ : numPartitions == 2 ? 1
1492
+ : 0);
1493
+ // Decode color endpoint modes.
1494
+ deUint32 colorEndpointModes[4];
1495
+ decodeColorEndpointModes(&colorEndpointModes[0], blockData, numPartitions, extraCemBitsStart);
1496
+ const int numColorEndpointValues = computeNumColorEndpointValues(colorEndpointModes, numPartitions);
1497
+ // Check for errors in color endpoint value count.
1498
+ if (numColorEndpointValues > 18 || numBitsForColorEndpoints < (int)deDivRoundUp32(13*numColorEndpointValues, 5))
1499
+ {
1500
+ setASTCErrorColorBlock(dst, blockWidth, blockHeight, isSRGB);
1501
+ return DECOMPRESS_RESULT_ERROR;
1502
+ }
1503
+ // Compute color endpoints.
1504
+ ColorEndpointPair colorEndpoints[4];
1505
+ computeColorEndpoints(&colorEndpoints[0], blockData, &colorEndpointModes[0], numPartitions, numColorEndpointValues,
1506
+ computeMaximumRangeISEParams(numBitsForColorEndpoints, numColorEndpointValues), numBitsForColorEndpoints);
1507
+ // Compute texel weights.
1508
+ TexelWeightPair texelWeights[MAX_BLOCK_WIDTH*MAX_BLOCK_HEIGHT];
1509
+ computeTexelWeights(&texelWeights[0], blockData, blockWidth, blockHeight, blockMode);
1510
+ // Set texel colors.
1511
+ const int ccs = blockMode.isDualPlane ? (int)blockData.getBits(extraCemBitsStart-2, extraCemBitsStart-1) : -1;
1512
+ const deUint32 partitionIndexSeed = numPartitions > 1 ? blockData.getBits(13, 22) : (deUint32)-1;
1513
+ return setTexelColors(dst, &colorEndpoints[0], &texelWeights[0], ccs, partitionIndexSeed, numPartitions, blockWidth, blockHeight, isSRGB, isLDR, &colorEndpointModes[0]);
1514
+ }
1515
+
1516
+ } // anonymous
1517
+
1518
+ bool decompress(uint8_t *pDst, const uint8_t * data, bool isSRGB, int blockWidth, int blockHeight)
1519
+ {
1520
+ // rg - We only support LDR here, although adding back in HDR would be easy.
1521
+ const bool isLDR = true;
1522
+ DE_ASSERT(isLDR || !isSRGB);
1523
+
1524
+ float linear[MAX_BLOCK_WIDTH * MAX_BLOCK_HEIGHT * 4];
1525
+
1526
+ const Block128 blockData(data);
1527
+ if (decompressBlock(isSRGB ? (void*)pDst : (void*)& linear[0],
1528
+ blockData, blockWidth, blockHeight, isSRGB, isLDR) != DECOMPRESS_RESULT_VALID_BLOCK)
1529
+ return false;
1530
+
1531
+ if (!isSRGB)
1532
+ {
1533
+ int pix = 0;
1534
+ for (int i = 0; i < blockHeight; i++)
1535
+ {
1536
+ for (int j = 0; j < blockWidth; j++, pix++)
1537
+ {
1538
+ pDst[4 * pix + 0] = (uint8_t)(basisu::astc_clamp<int>((int)(linear[pix * 4 + 0] * 65536.0f + .5f), 0, 65535) >> 8);
1539
+ pDst[4 * pix + 1] = (uint8_t)(basisu::astc_clamp<int>((int)(linear[pix * 4 + 1] * 65536.0f + .5f), 0, 65535) >> 8);
1540
+ pDst[4 * pix + 2] = (uint8_t)(basisu::astc_clamp<int>((int)(linear[pix * 4 + 2] * 65536.0f + .5f), 0, 65535) >> 8);
1541
+ pDst[4 * pix + 3] = (uint8_t)(basisu::astc_clamp<int>((int)(linear[pix * 4 + 3] * 65536.0f + .5f), 0, 65535) >> 8);
1542
+ }
1543
+ }
1544
+ }
1545
+
1546
+ return true;
1547
+ }
1548
+
1549
+ } // astc
1550
+ } // basisu