Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/angle
Path: blob/main_old/src/image_util/loadimage_etc.cpp
1693 views
1
//
2
// Copyright 2013 The ANGLE Project Authors. All rights reserved.
3
// Use of this source code is governed by a BSD-style license that can be
4
// found in the LICENSE file.
5
//
6
7
// loadimage_etc.cpp: Decodes ETC and EAC encoded textures.
8
9
#include "image_util/loadimage.h"
10
11
#include <type_traits>
12
#include "common/mathutil.h"
13
14
#include "image_util/imageformats.h"
15
16
namespace angle
17
{
18
namespace
19
{
20
21
using IntensityModifier = const int[4];
22
23
// Table 3.17.2 sorted according to table 3.17.3
24
// clang-format off
25
static IntensityModifier intensityModifierDefault[] =
26
{
27
{ 2, 8, -2, -8 },
28
{ 5, 17, -5, -17 },
29
{ 9, 29, -9, -29 },
30
{ 13, 42, -13, -42 },
31
{ 18, 60, -18, -60 },
32
{ 24, 80, -24, -80 },
33
{ 33, 106, -33, -106 },
34
{ 47, 183, -47, -183 },
35
};
36
// clang-format on
37
38
// Table C.12, intensity modifier for non opaque punchthrough alpha
39
// clang-format off
40
static IntensityModifier intensityModifierNonOpaque[] =
41
{
42
{ 0, 8, 0, -8 },
43
{ 0, 17, 0, -17 },
44
{ 0, 29, 0, -29 },
45
{ 0, 42, 0, -42 },
46
{ 0, 60, 0, -60 },
47
{ 0, 80, 0, -80 },
48
{ 0, 106, 0, -106 },
49
{ 0, 183, 0, -183 },
50
};
51
// clang-format on
52
53
static const int kNumPixelsInBlock = 16;
54
55
struct ETC2Block
56
{
57
// Decodes unsigned single or dual channel ETC2 block to 8-bit color
58
void decodeAsSingleETC2Channel(uint8_t *dest,
59
size_t x,
60
size_t y,
61
size_t w,
62
size_t h,
63
size_t destPixelStride,
64
size_t destRowPitch,
65
bool isSigned) const
66
{
67
for (size_t j = 0; j < 4 && (y + j) < h; j++)
68
{
69
uint8_t *row = dest + (j * destRowPitch);
70
for (size_t i = 0; i < 4 && (x + i) < w; i++)
71
{
72
uint8_t *pixel = row + (i * destPixelStride);
73
if (isSigned)
74
{
75
*pixel = clampSByte(getSingleETC2Channel(i, j, isSigned));
76
}
77
else
78
{
79
*pixel = clampByte(getSingleETC2Channel(i, j, isSigned));
80
}
81
}
82
}
83
}
84
85
// Decodes unsigned single or dual channel EAC block to 16-bit color
86
void decodeAsSingleEACChannel(uint16_t *dest,
87
size_t x,
88
size_t y,
89
size_t w,
90
size_t h,
91
size_t destPixelStride,
92
size_t destRowPitch,
93
bool isSigned,
94
bool isFloat) const
95
{
96
for (size_t j = 0; j < 4 && (y + j) < h; j++)
97
{
98
uint16_t *row = reinterpret_cast<uint16_t *>(reinterpret_cast<uint8_t *>(dest) +
99
(j * destRowPitch));
100
for (size_t i = 0; i < 4 && (x + i) < w; i++)
101
{
102
uint16_t *pixel = row + (i * destPixelStride);
103
if (isSigned)
104
{
105
int16_t tempPixel =
106
renormalizeEAC<int16_t>(getSingleEACChannel(i, j, isSigned));
107
*pixel =
108
isFloat ? gl::float32ToFloat16(float(gl::normalize(tempPixel))) : tempPixel;
109
}
110
else
111
{
112
uint16_t tempPixel =
113
renormalizeEAC<uint16_t>(getSingleEACChannel(i, j, isSigned));
114
*pixel =
115
isFloat ? gl::float32ToFloat16(float(gl::normalize(tempPixel))) : tempPixel;
116
}
117
}
118
}
119
}
120
121
// Decodes RGB block to rgba8
122
void decodeAsRGB(uint8_t *dest,
123
size_t x,
124
size_t y,
125
size_t w,
126
size_t h,
127
size_t destRowPitch,
128
const uint8_t alphaValues[4][4],
129
bool punchThroughAlpha) const
130
{
131
bool opaqueBit = u.idht.mode.idm.diffbit;
132
bool nonOpaquePunchThroughAlpha = punchThroughAlpha && !opaqueBit;
133
// Select mode
134
if (u.idht.mode.idm.diffbit || punchThroughAlpha)
135
{
136
const auto &block = u.idht.mode.idm.colors.diff;
137
int r = (block.R + block.dR);
138
int g = (block.G + block.dG);
139
int b = (block.B + block.dB);
140
if (r < 0 || r > 31)
141
{
142
decodeTBlock(dest, x, y, w, h, destRowPitch, alphaValues,
143
nonOpaquePunchThroughAlpha);
144
}
145
else if (g < 0 || g > 31)
146
{
147
decodeHBlock(dest, x, y, w, h, destRowPitch, alphaValues,
148
nonOpaquePunchThroughAlpha);
149
}
150
else if (b < 0 || b > 31)
151
{
152
decodePlanarBlock(dest, x, y, w, h, destRowPitch, alphaValues);
153
}
154
else
155
{
156
decodeDifferentialBlock(dest, x, y, w, h, destRowPitch, alphaValues,
157
nonOpaquePunchThroughAlpha);
158
}
159
}
160
else
161
{
162
decodeIndividualBlock(dest, x, y, w, h, destRowPitch, alphaValues,
163
nonOpaquePunchThroughAlpha);
164
}
165
}
166
167
// Transcodes RGB block to BC1
168
void transcodeAsBC1(uint8_t *dest,
169
size_t x,
170
size_t y,
171
size_t w,
172
size_t h,
173
const uint8_t alphaValues[4][4],
174
bool punchThroughAlpha) const
175
{
176
bool opaqueBit = u.idht.mode.idm.diffbit;
177
bool nonOpaquePunchThroughAlpha = punchThroughAlpha && !opaqueBit;
178
// Select mode
179
if (u.idht.mode.idm.diffbit || punchThroughAlpha)
180
{
181
const auto &block = u.idht.mode.idm.colors.diff;
182
int r = (block.R + block.dR);
183
int g = (block.G + block.dG);
184
int b = (block.B + block.dB);
185
if (r < 0 || r > 31)
186
{
187
transcodeTBlockToBC1(dest, x, y, w, h, alphaValues, nonOpaquePunchThroughAlpha);
188
}
189
else if (g < 0 || g > 31)
190
{
191
transcodeHBlockToBC1(dest, x, y, w, h, alphaValues, nonOpaquePunchThroughAlpha);
192
}
193
else if (b < 0 || b > 31)
194
{
195
transcodePlanarBlockToBC1(dest, x, y, w, h, alphaValues);
196
}
197
else
198
{
199
transcodeDifferentialBlockToBC1(dest, x, y, w, h, alphaValues,
200
nonOpaquePunchThroughAlpha);
201
}
202
}
203
else
204
{
205
transcodeIndividualBlockToBC1(dest, x, y, w, h, alphaValues,
206
nonOpaquePunchThroughAlpha);
207
}
208
}
209
210
private:
211
union
212
{
213
// Individual, differential, H and T modes
214
struct
215
{
216
union
217
{
218
// Individual and differential modes
219
struct
220
{
221
union
222
{
223
struct // Individual colors
224
{
225
unsigned char R2 : 4;
226
unsigned char R1 : 4;
227
unsigned char G2 : 4;
228
unsigned char G1 : 4;
229
unsigned char B2 : 4;
230
unsigned char B1 : 4;
231
} indiv;
232
struct // Differential colors
233
{
234
signed char dR : 3;
235
unsigned char R : 5;
236
signed char dG : 3;
237
unsigned char G : 5;
238
signed char dB : 3;
239
unsigned char B : 5;
240
} diff;
241
} colors;
242
bool flipbit : 1;
243
bool diffbit : 1;
244
unsigned char cw2 : 3;
245
unsigned char cw1 : 3;
246
} idm;
247
// T mode
248
struct
249
{
250
// Byte 1
251
unsigned char TR1b : 2;
252
unsigned char TunusedB : 1;
253
unsigned char TR1a : 2;
254
unsigned char TunusedA : 3;
255
// Byte 2
256
unsigned char TB1 : 4;
257
unsigned char TG1 : 4;
258
// Byte 3
259
unsigned char TG2 : 4;
260
unsigned char TR2 : 4;
261
// Byte 4
262
unsigned char Tdb : 1;
263
bool Tflipbit : 1;
264
unsigned char Tda : 2;
265
unsigned char TB2 : 4;
266
} tm;
267
// H mode
268
struct
269
{
270
// Byte 1
271
unsigned char HG1a : 3;
272
unsigned char HR1 : 4;
273
unsigned char HunusedA : 1;
274
// Byte 2
275
unsigned char HB1b : 2;
276
unsigned char HunusedC : 1;
277
unsigned char HB1a : 1;
278
unsigned char HG1b : 1;
279
unsigned char HunusedB : 3;
280
// Byte 3
281
unsigned char HG2a : 3;
282
unsigned char HR2 : 4;
283
unsigned char HB1c : 1;
284
// Byte 4
285
unsigned char Hdb : 1;
286
bool Hflipbit : 1;
287
unsigned char Hda : 1;
288
unsigned char HB2 : 4;
289
unsigned char HG2b : 1;
290
} hm;
291
} mode;
292
unsigned char pixelIndexMSB[2];
293
unsigned char pixelIndexLSB[2];
294
} idht;
295
// planar mode
296
struct
297
{
298
// Byte 1
299
unsigned char GO1 : 1;
300
unsigned char RO : 6;
301
unsigned char PunusedA : 1;
302
// Byte 2
303
unsigned char BO1 : 1;
304
unsigned char GO2 : 6;
305
unsigned char PunusedB : 1;
306
// Byte 3
307
unsigned char BO3a : 2;
308
unsigned char PunusedD : 1;
309
unsigned char BO2 : 2;
310
unsigned char PunusedC : 3;
311
// Byte 4
312
unsigned char RH2 : 1;
313
bool Pflipbit : 1;
314
unsigned char RH1 : 5;
315
unsigned char BO3b : 1;
316
// Byte 5
317
unsigned char BHa : 1;
318
unsigned char GH : 7;
319
// Byte 6
320
unsigned char RVa : 3;
321
unsigned char BHb : 5;
322
// Byte 7
323
unsigned char GVa : 5;
324
unsigned char RVb : 3;
325
// Byte 8
326
unsigned char BV : 6;
327
unsigned char GVb : 2;
328
} pblk;
329
// Single channel block
330
struct
331
{
332
union
333
{
334
unsigned char us;
335
signed char s;
336
} base_codeword;
337
unsigned char table_index : 4;
338
unsigned char multiplier : 4;
339
unsigned char mc1 : 2;
340
unsigned char mb : 3;
341
unsigned char ma : 3;
342
unsigned char mf1 : 1;
343
unsigned char me : 3;
344
unsigned char md : 3;
345
unsigned char mc2 : 1;
346
unsigned char mh : 3;
347
unsigned char mg : 3;
348
unsigned char mf2 : 2;
349
unsigned char mk1 : 2;
350
unsigned char mj : 3;
351
unsigned char mi : 3;
352
unsigned char mn1 : 1;
353
unsigned char mm : 3;
354
unsigned char ml : 3;
355
unsigned char mk2 : 1;
356
unsigned char mp : 3;
357
unsigned char mo : 3;
358
unsigned char mn2 : 2;
359
} scblk;
360
} u;
361
362
static unsigned char clampByte(int value)
363
{
364
return static_cast<unsigned char>(gl::clamp(value, 0, 255));
365
}
366
367
static signed char clampSByte(int value)
368
{
369
return static_cast<signed char>(gl::clamp(value, -128, 127));
370
}
371
372
template <typename T>
373
static T renormalizeEAC(int value)
374
{
375
int upper = 0;
376
int lower = 0;
377
int shift = 0;
378
379
if (std::is_same<T, int16_t>::value)
380
{
381
// The spec states that -1024 invalid and should be clamped to -1023
382
upper = 1023;
383
lower = -1023;
384
shift = 5;
385
}
386
else if (std::is_same<T, uint16_t>::value)
387
{
388
upper = 2047;
389
lower = 0;
390
shift = 5;
391
}
392
else
393
{
394
// We currently only support renormalizing int16_t or uint16_t
395
UNREACHABLE();
396
}
397
398
return static_cast<T>(gl::clamp(value, lower, upper)) << shift;
399
}
400
401
static R8G8B8A8 createRGBA(int red, int green, int blue, int alpha)
402
{
403
R8G8B8A8 rgba;
404
rgba.R = clampByte(red);
405
rgba.G = clampByte(green);
406
rgba.B = clampByte(blue);
407
rgba.A = clampByte(alpha);
408
return rgba;
409
}
410
411
static R8G8B8A8 createRGBA(int red, int green, int blue)
412
{
413
return createRGBA(red, green, blue, 255);
414
}
415
416
static int extend_4to8bits(int x) { return (x << 4) | x; }
417
static int extend_5to8bits(int x) { return (x << 3) | (x >> 2); }
418
static int extend_6to8bits(int x) { return (x << 2) | (x >> 4); }
419
static int extend_7to8bits(int x) { return (x << 1) | (x >> 6); }
420
421
void decodeIndividualBlock(uint8_t *dest,
422
size_t x,
423
size_t y,
424
size_t w,
425
size_t h,
426
size_t destRowPitch,
427
const uint8_t alphaValues[4][4],
428
bool nonOpaquePunchThroughAlpha) const
429
{
430
const auto &block = u.idht.mode.idm.colors.indiv;
431
int r1 = extend_4to8bits(block.R1);
432
int g1 = extend_4to8bits(block.G1);
433
int b1 = extend_4to8bits(block.B1);
434
int r2 = extend_4to8bits(block.R2);
435
int g2 = extend_4to8bits(block.G2);
436
int b2 = extend_4to8bits(block.B2);
437
decodeIndividualOrDifferentialBlock(dest, x, y, w, h, destRowPitch, r1, g1, b1, r2, g2, b2,
438
alphaValues, nonOpaquePunchThroughAlpha);
439
}
440
441
void decodeDifferentialBlock(uint8_t *dest,
442
size_t x,
443
size_t y,
444
size_t w,
445
size_t h,
446
size_t destRowPitch,
447
const uint8_t alphaValues[4][4],
448
bool nonOpaquePunchThroughAlpha) const
449
{
450
const auto &block = u.idht.mode.idm.colors.diff;
451
int b1 = extend_5to8bits(block.B);
452
int g1 = extend_5to8bits(block.G);
453
int r1 = extend_5to8bits(block.R);
454
int r2 = extend_5to8bits(block.R + block.dR);
455
int g2 = extend_5to8bits(block.G + block.dG);
456
int b2 = extend_5to8bits(block.B + block.dB);
457
decodeIndividualOrDifferentialBlock(dest, x, y, w, h, destRowPitch, r1, g1, b1, r2, g2, b2,
458
alphaValues, nonOpaquePunchThroughAlpha);
459
}
460
461
void decodeIndividualOrDifferentialBlock(uint8_t *dest,
462
size_t x,
463
size_t y,
464
size_t w,
465
size_t h,
466
size_t destRowPitch,
467
int r1,
468
int g1,
469
int b1,
470
int r2,
471
int g2,
472
int b2,
473
const uint8_t alphaValues[4][4],
474
bool nonOpaquePunchThroughAlpha) const
475
{
476
const IntensityModifier *intensityModifier =
477
nonOpaquePunchThroughAlpha ? intensityModifierNonOpaque : intensityModifierDefault;
478
479
R8G8B8A8 subblockColors0[4];
480
R8G8B8A8 subblockColors1[4];
481
for (size_t modifierIdx = 0; modifierIdx < 4; modifierIdx++)
482
{
483
const int i1 = intensityModifier[u.idht.mode.idm.cw1][modifierIdx];
484
subblockColors0[modifierIdx] = createRGBA(r1 + i1, g1 + i1, b1 + i1);
485
486
const int i2 = intensityModifier[u.idht.mode.idm.cw2][modifierIdx];
487
subblockColors1[modifierIdx] = createRGBA(r2 + i2, g2 + i2, b2 + i2);
488
}
489
490
if (u.idht.mode.idm.flipbit)
491
{
492
uint8_t *curPixel = dest;
493
for (size_t j = 0; j < 2 && (y + j) < h; j++)
494
{
495
R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel);
496
for (size_t i = 0; i < 4 && (x + i) < w; i++)
497
{
498
row[i] = subblockColors0[getIndex(i, j)];
499
row[i].A = alphaValues[j][i];
500
}
501
curPixel += destRowPitch;
502
}
503
for (size_t j = 2; j < 4 && (y + j) < h; j++)
504
{
505
R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel);
506
for (size_t i = 0; i < 4 && (x + i) < w; i++)
507
{
508
row[i] = subblockColors1[getIndex(i, j)];
509
row[i].A = alphaValues[j][i];
510
}
511
curPixel += destRowPitch;
512
}
513
}
514
else
515
{
516
uint8_t *curPixel = dest;
517
for (size_t j = 0; j < 4 && (y + j) < h; j++)
518
{
519
R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel);
520
for (size_t i = 0; i < 2 && (x + i) < w; i++)
521
{
522
row[i] = subblockColors0[getIndex(i, j)];
523
row[i].A = alphaValues[j][i];
524
}
525
for (size_t i = 2; i < 4 && (x + i) < w; i++)
526
{
527
row[i] = subblockColors1[getIndex(i, j)];
528
row[i].A = alphaValues[j][i];
529
}
530
curPixel += destRowPitch;
531
}
532
}
533
if (nonOpaquePunchThroughAlpha)
534
{
535
decodePunchThroughAlphaBlock(dest, x, y, w, h, destRowPitch);
536
}
537
}
538
539
void decodeTBlock(uint8_t *dest,
540
size_t x,
541
size_t y,
542
size_t w,
543
size_t h,
544
size_t destRowPitch,
545
const uint8_t alphaValues[4][4],
546
bool nonOpaquePunchThroughAlpha) const
547
{
548
// Table C.8, distance index for T and H modes
549
const auto &block = u.idht.mode.tm;
550
551
int r1 = extend_4to8bits(block.TR1a << 2 | block.TR1b);
552
int g1 = extend_4to8bits(block.TG1);
553
int b1 = extend_4to8bits(block.TB1);
554
int r2 = extend_4to8bits(block.TR2);
555
int g2 = extend_4to8bits(block.TG2);
556
int b2 = extend_4to8bits(block.TB2);
557
558
static int distance[8] = {3, 6, 11, 16, 23, 32, 41, 64};
559
const int d = distance[block.Tda << 1 | block.Tdb];
560
561
const R8G8B8A8 paintColors[4] = {
562
createRGBA(r1, g1, b1),
563
createRGBA(r2 + d, g2 + d, b2 + d),
564
createRGBA(r2, g2, b2),
565
createRGBA(r2 - d, g2 - d, b2 - d),
566
};
567
568
uint8_t *curPixel = dest;
569
for (size_t j = 0; j < 4 && (y + j) < h; j++)
570
{
571
R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel);
572
for (size_t i = 0; i < 4 && (x + i) < w; i++)
573
{
574
row[i] = paintColors[getIndex(i, j)];
575
row[i].A = alphaValues[j][i];
576
}
577
curPixel += destRowPitch;
578
}
579
580
if (nonOpaquePunchThroughAlpha)
581
{
582
decodePunchThroughAlphaBlock(dest, x, y, w, h, destRowPitch);
583
}
584
}
585
586
void decodeHBlock(uint8_t *dest,
587
size_t x,
588
size_t y,
589
size_t w,
590
size_t h,
591
size_t destRowPitch,
592
const uint8_t alphaValues[4][4],
593
bool nonOpaquePunchThroughAlpha) const
594
{
595
// Table C.8, distance index for T and H modes
596
const auto &block = u.idht.mode.hm;
597
598
int r1 = extend_4to8bits(block.HR1);
599
int g1 = extend_4to8bits(block.HG1a << 1 | block.HG1b);
600
int b1 = extend_4to8bits(block.HB1a << 3 | block.HB1b << 1 | block.HB1c);
601
int r2 = extend_4to8bits(block.HR2);
602
int g2 = extend_4to8bits(block.HG2a << 1 | block.HG2b);
603
int b2 = extend_4to8bits(block.HB2);
604
605
static const int distance[8] = {3, 6, 11, 16, 23, 32, 41, 64};
606
const int orderingTrickBit =
607
((r1 << 16 | g1 << 8 | b1) >= (r2 << 16 | g2 << 8 | b2) ? 1 : 0);
608
const int d = distance[(block.Hda << 2) | (block.Hdb << 1) | orderingTrickBit];
609
610
const R8G8B8A8 paintColors[4] = {
611
createRGBA(r1 + d, g1 + d, b1 + d),
612
createRGBA(r1 - d, g1 - d, b1 - d),
613
createRGBA(r2 + d, g2 + d, b2 + d),
614
createRGBA(r2 - d, g2 - d, b2 - d),
615
};
616
617
uint8_t *curPixel = dest;
618
for (size_t j = 0; j < 4 && (y + j) < h; j++)
619
{
620
R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel);
621
for (size_t i = 0; i < 4 && (x + i) < w; i++)
622
{
623
row[i] = paintColors[getIndex(i, j)];
624
row[i].A = alphaValues[j][i];
625
}
626
curPixel += destRowPitch;
627
}
628
629
if (nonOpaquePunchThroughAlpha)
630
{
631
decodePunchThroughAlphaBlock(dest, x, y, w, h, destRowPitch);
632
}
633
}
634
635
void decodePlanarBlock(uint8_t *dest,
636
size_t x,
637
size_t y,
638
size_t w,
639
size_t h,
640
size_t pitch,
641
const uint8_t alphaValues[4][4]) const
642
{
643
int ro = extend_6to8bits(u.pblk.RO);
644
int go = extend_7to8bits(u.pblk.GO1 << 6 | u.pblk.GO2);
645
int bo =
646
extend_6to8bits(u.pblk.BO1 << 5 | u.pblk.BO2 << 3 | u.pblk.BO3a << 1 | u.pblk.BO3b);
647
int rh = extend_6to8bits(u.pblk.RH1 << 1 | u.pblk.RH2);
648
int gh = extend_7to8bits(u.pblk.GH);
649
int bh = extend_6to8bits(u.pblk.BHa << 5 | u.pblk.BHb);
650
int rv = extend_6to8bits(u.pblk.RVa << 3 | u.pblk.RVb);
651
int gv = extend_7to8bits(u.pblk.GVa << 2 | u.pblk.GVb);
652
int bv = extend_6to8bits(u.pblk.BV);
653
654
uint8_t *curPixel = dest;
655
for (size_t j = 0; j < 4 && (y + j) < h; j++)
656
{
657
R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel);
658
659
int ry = static_cast<int>(j) * (rv - ro) + 2;
660
int gy = static_cast<int>(j) * (gv - go) + 2;
661
int by = static_cast<int>(j) * (bv - bo) + 2;
662
for (size_t i = 0; i < 4 && (x + i) < w; i++)
663
{
664
row[i] = createRGBA(((static_cast<int>(i) * (rh - ro) + ry) >> 2) + ro,
665
((static_cast<int>(i) * (gh - go) + gy) >> 2) + go,
666
((static_cast<int>(i) * (bh - bo) + by) >> 2) + bo,
667
alphaValues[j][i]);
668
}
669
curPixel += pitch;
670
}
671
}
672
673
// Index for individual, differential, H and T modes
674
size_t getIndex(size_t x, size_t y) const
675
{
676
size_t bitIndex = x * 4 + y;
677
size_t bitOffset = bitIndex & 7;
678
size_t lsb = (u.idht.pixelIndexLSB[1 - (bitIndex >> 3)] >> bitOffset) & 1;
679
size_t msb = (u.idht.pixelIndexMSB[1 - (bitIndex >> 3)] >> bitOffset) & 1;
680
return (msb << 1) | lsb;
681
}
682
683
void decodePunchThroughAlphaBlock(uint8_t *dest,
684
size_t x,
685
size_t y,
686
size_t w,
687
size_t h,
688
size_t destRowPitch) const
689
{
690
uint8_t *curPixel = dest;
691
for (size_t j = 0; j < 4 && (y + j) < h; j++)
692
{
693
R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel);
694
for (size_t i = 0; i < 4 && (x + i) < w; i++)
695
{
696
if (getIndex(i, j) == 2) // msb == 1 && lsb == 0
697
{
698
row[i] = createRGBA(0, 0, 0, 0);
699
}
700
}
701
curPixel += destRowPitch;
702
}
703
}
704
705
uint16_t RGB8ToRGB565(const R8G8B8A8 &rgba) const
706
{
707
return (static_cast<uint16_t>(rgba.R >> 3) << 11) |
708
(static_cast<uint16_t>(rgba.G >> 2) << 5) |
709
(static_cast<uint16_t>(rgba.B >> 3) << 0);
710
}
711
712
uint32_t matchBC1Bits(const int *pixelIndices,
713
const int *pixelIndexCounts,
714
const R8G8B8A8 *subblockColors,
715
size_t numColors,
716
const R8G8B8A8 &minColor,
717
const R8G8B8A8 &maxColor,
718
bool nonOpaquePunchThroughAlpha) const
719
{
720
// Project each pixel on the (maxColor, minColor) line to decide which
721
// BC1 code to assign to it.
722
723
uint8_t decodedColors[2][3] = {{maxColor.R, maxColor.G, maxColor.B},
724
{minColor.R, minColor.G, minColor.B}};
725
726
int direction[3];
727
for (int ch = 0; ch < 3; ch++)
728
{
729
direction[ch] = decodedColors[0][ch] - decodedColors[1][ch];
730
}
731
732
int stops[2];
733
for (int i = 0; i < 2; i++)
734
{
735
stops[i] = decodedColors[i][0] * direction[0] + decodedColors[i][1] * direction[1] +
736
decodedColors[i][2] * direction[2];
737
}
738
739
ASSERT(numColors <= kNumPixelsInBlock);
740
741
int encodedColors[kNumPixelsInBlock];
742
if (nonOpaquePunchThroughAlpha)
743
{
744
for (size_t i = 0; i < numColors; i++)
745
{
746
const int count = pixelIndexCounts[i];
747
if (count > 0)
748
{
749
// In non-opaque mode, 3 is for tranparent pixels.
750
751
if (0 == subblockColors[i].A)
752
{
753
encodedColors[i] = 3;
754
}
755
else
756
{
757
const R8G8B8A8 &pixel = subblockColors[i];
758
const int dot = pixel.R * direction[0] + pixel.G * direction[1] +
759
pixel.B * direction[2];
760
const int factor = gl::clamp(
761
static_cast<int>(
762
(static_cast<float>(dot - stops[1]) / (stops[0] - stops[1])) * 2 +
763
0.5f),
764
0, 2);
765
switch (factor)
766
{
767
case 0:
768
encodedColors[i] = 0;
769
break;
770
case 1:
771
encodedColors[i] = 2;
772
break;
773
case 2:
774
default:
775
encodedColors[i] = 1;
776
break;
777
}
778
}
779
}
780
}
781
}
782
else
783
{
784
for (size_t i = 0; i < numColors; i++)
785
{
786
const int count = pixelIndexCounts[i];
787
if (count > 0)
788
{
789
// In opaque mode, the code is from 0 to 3.
790
791
const R8G8B8A8 &pixel = subblockColors[i];
792
const int dot =
793
pixel.R * direction[0] + pixel.G * direction[1] + pixel.B * direction[2];
794
const int factor = gl::clamp(
795
static_cast<int>(
796
(static_cast<float>(dot - stops[1]) / (stops[0] - stops[1])) * 3 +
797
0.5f),
798
0, 3);
799
switch (factor)
800
{
801
case 0:
802
encodedColors[i] = 1;
803
break;
804
case 1:
805
encodedColors[i] = 3;
806
break;
807
case 2:
808
encodedColors[i] = 2;
809
break;
810
case 3:
811
default:
812
encodedColors[i] = 0;
813
break;
814
}
815
}
816
}
817
}
818
819
uint32_t bits = 0;
820
for (int i = kNumPixelsInBlock - 1; i >= 0; i--)
821
{
822
bits <<= 2;
823
bits |= encodedColors[pixelIndices[i]];
824
}
825
826
return bits;
827
}
828
829
void packBC1(void *bc1,
830
const int *pixelIndices,
831
const int *pixelIndexCounts,
832
const R8G8B8A8 *subblockColors,
833
size_t numColors,
834
int minColorIndex,
835
int maxColorIndex,
836
bool nonOpaquePunchThroughAlpha) const
837
{
838
const R8G8B8A8 &minColor = subblockColors[minColorIndex];
839
const R8G8B8A8 &maxColor = subblockColors[maxColorIndex];
840
841
uint32_t bits;
842
uint16_t max16 = RGB8ToRGB565(maxColor);
843
uint16_t min16 = RGB8ToRGB565(minColor);
844
if (max16 != min16)
845
{
846
// Find the best BC1 code for each pixel
847
bits = matchBC1Bits(pixelIndices, pixelIndexCounts, subblockColors, numColors, minColor,
848
maxColor, nonOpaquePunchThroughAlpha);
849
}
850
else
851
{
852
// Same colors, BC1 index 0 is the color in both opaque and transparent mode
853
bits = 0;
854
// BC1 index 3 is transparent
855
if (nonOpaquePunchThroughAlpha)
856
{
857
for (int i = 0; i < kNumPixelsInBlock; i++)
858
{
859
if (0 == subblockColors[pixelIndices[i]].A)
860
{
861
bits |= (3 << (i * 2));
862
}
863
}
864
}
865
}
866
867
if (max16 < min16)
868
{
869
std::swap(max16, min16);
870
871
uint32_t xorMask = 0;
872
if (nonOpaquePunchThroughAlpha)
873
{
874
// In transparent mode switching the colors is doing the
875
// following code swap: 0 <-> 1. 0xA selects the second bit of
876
// each code, bits >> 1 selects the first bit of the code when
877
// the seconds bit is set (case 2 and 3). We invert all the
878
// non-selected bits, that is the first bit when the code is
879
// 0 or 1.
880
xorMask = ~((bits >> 1) | 0xAAAAAAAA);
881
}
882
else
883
{
884
// In opaque mode switching the two colors is doing the
885
// following code swaps: 0 <-> 1 and 2 <-> 3. This is
886
// equivalent to flipping the first bit of each code
887
// (5 = 0b0101)
888
xorMask = 0x55555555;
889
}
890
bits ^= xorMask;
891
}
892
893
struct BC1Block
894
{
895
uint16_t color0;
896
uint16_t color1;
897
uint32_t bits;
898
};
899
900
// Encode the opaqueness in the order of the two BC1 colors
901
BC1Block *dest = reinterpret_cast<BC1Block *>(bc1);
902
if (nonOpaquePunchThroughAlpha)
903
{
904
dest->color0 = min16;
905
dest->color1 = max16;
906
}
907
else
908
{
909
dest->color0 = max16;
910
dest->color1 = min16;
911
}
912
dest->bits = bits;
913
}
914
915
void transcodeIndividualBlockToBC1(uint8_t *dest,
916
size_t x,
917
size_t y,
918
size_t w,
919
size_t h,
920
const uint8_t alphaValues[4][4],
921
bool nonOpaquePunchThroughAlpha) const
922
{
923
const auto &block = u.idht.mode.idm.colors.indiv;
924
int r1 = extend_4to8bits(block.R1);
925
int g1 = extend_4to8bits(block.G1);
926
int b1 = extend_4to8bits(block.B1);
927
int r2 = extend_4to8bits(block.R2);
928
int g2 = extend_4to8bits(block.G2);
929
int b2 = extend_4to8bits(block.B2);
930
transcodeIndividualOrDifferentialBlockToBC1(dest, x, y, w, h, r1, g1, b1, r2, g2, b2,
931
alphaValues, nonOpaquePunchThroughAlpha);
932
}
933
934
void transcodeDifferentialBlockToBC1(uint8_t *dest,
935
size_t x,
936
size_t y,
937
size_t w,
938
size_t h,
939
const uint8_t alphaValues[4][4],
940
bool nonOpaquePunchThroughAlpha) const
941
{
942
const auto &block = u.idht.mode.idm.colors.diff;
943
int b1 = extend_5to8bits(block.B);
944
int g1 = extend_5to8bits(block.G);
945
int r1 = extend_5to8bits(block.R);
946
int r2 = extend_5to8bits(block.R + block.dR);
947
int g2 = extend_5to8bits(block.G + block.dG);
948
int b2 = extend_5to8bits(block.B + block.dB);
949
transcodeIndividualOrDifferentialBlockToBC1(dest, x, y, w, h, r1, g1, b1, r2, g2, b2,
950
alphaValues, nonOpaquePunchThroughAlpha);
951
}
952
953
void extractPixelIndices(int *pixelIndices,
954
int *pixelIndicesCounts,
955
size_t x,
956
size_t y,
957
size_t w,
958
size_t h,
959
bool flipbit,
960
size_t subblockIdx) const
961
{
962
size_t dxBegin = 0;
963
size_t dxEnd = 4;
964
size_t dyBegin = subblockIdx * 2;
965
size_t dyEnd = dyBegin + 2;
966
if (!flipbit)
967
{
968
std::swap(dxBegin, dyBegin);
969
std::swap(dxEnd, dyEnd);
970
}
971
972
for (size_t j = dyBegin; j < dyEnd; j++)
973
{
974
int *row = &pixelIndices[j * 4];
975
for (size_t i = dxBegin; i < dxEnd; i++)
976
{
977
const size_t pixelIndex = subblockIdx * 4 + getIndex(i, j);
978
row[i] = static_cast<int>(pixelIndex);
979
pixelIndicesCounts[pixelIndex]++;
980
}
981
}
982
}
983
984
void selectEndPointPCA(const int *pixelIndexCounts,
985
const R8G8B8A8 *subblockColors,
986
size_t numColors,
987
int *minColorIndex,
988
int *maxColorIndex) const
989
{
990
// determine color distribution
991
int mu[3], min[3], max[3];
992
for (int ch = 0; ch < 3; ch++)
993
{
994
int muv = 0;
995
int minv = 255;
996
int maxv = 0;
997
for (size_t i = 0; i < numColors; i++)
998
{
999
const int count = pixelIndexCounts[i];
1000
if (count > 0)
1001
{
1002
const auto &pixel = subblockColors[i];
1003
if (pixel.A > 0)
1004
{
1005
// Non-transparent pixels
1006
muv += (&pixel.R)[ch] * count;
1007
minv = std::min<int>(minv, (&pixel.R)[ch]);
1008
maxv = std::max<int>(maxv, (&pixel.R)[ch]);
1009
}
1010
}
1011
}
1012
1013
mu[ch] = (muv + kNumPixelsInBlock / 2) / kNumPixelsInBlock;
1014
min[ch] = minv;
1015
max[ch] = maxv;
1016
}
1017
1018
// determine covariance matrix
1019
int cov[6] = {0, 0, 0, 0, 0, 0};
1020
for (size_t i = 0; i < numColors; i++)
1021
{
1022
const int count = pixelIndexCounts[i];
1023
if (count > 0)
1024
{
1025
const auto &pixel = subblockColors[i];
1026
if (pixel.A > 0)
1027
{
1028
int r = pixel.R - mu[0];
1029
int g = pixel.G - mu[1];
1030
int b = pixel.B - mu[2];
1031
1032
cov[0] += r * r * count;
1033
cov[1] += r * g * count;
1034
cov[2] += r * b * count;
1035
cov[3] += g * g * count;
1036
cov[4] += g * b * count;
1037
cov[5] += b * b * count;
1038
}
1039
}
1040
}
1041
1042
// Power iteration algorithm to get the eigenvalues and eigenvector
1043
1044
// Starts with diagonal vector
1045
float vfr = static_cast<float>(max[0] - min[0]);
1046
float vfg = static_cast<float>(max[1] - min[1]);
1047
float vfb = static_cast<float>(max[2] - min[2]);
1048
float eigenvalue = 0.0f;
1049
1050
constexpr size_t kPowerIterations = 4;
1051
for (size_t i = 0; i < kPowerIterations; i++)
1052
{
1053
float r = vfr * cov[0] + vfg * cov[1] + vfb * cov[2];
1054
float g = vfr * cov[1] + vfg * cov[3] + vfb * cov[4];
1055
float b = vfr * cov[2] + vfg * cov[4] + vfb * cov[5];
1056
1057
vfr = r;
1058
vfg = g;
1059
vfb = b;
1060
1061
eigenvalue = sqrt(r * r + g * g + b * b);
1062
if (eigenvalue > 0)
1063
{
1064
float invNorm = 1.0f / eigenvalue;
1065
vfr *= invNorm;
1066
vfg *= invNorm;
1067
vfb *= invNorm;
1068
}
1069
}
1070
1071
int vr, vg, vb;
1072
1073
static const float kDefaultLuminanceThreshold = 4.0f * 255;
1074
static const float kQuantizeRange = 512.0f;
1075
if (eigenvalue < kDefaultLuminanceThreshold) // too small, default to luminance
1076
{
1077
// Luminance weights defined by ITU-R Recommendation BT.601, scaled by 1000
1078
vr = 299;
1079
vg = 587;
1080
vb = 114;
1081
}
1082
else
1083
{
1084
// From the eigenvalue and eigenvector, choose the axis to project
1085
// colors on. When projecting colors we want to do integer computations
1086
// for speed, so we normalize the eigenvector to the [0, 512] range.
1087
float magn = std::max(std::max(std::abs(vfr), std::abs(vfg)), std::abs(vfb));
1088
magn = kQuantizeRange / magn;
1089
vr = static_cast<int>(vfr * magn);
1090
vg = static_cast<int>(vfg * magn);
1091
vb = static_cast<int>(vfb * magn);
1092
}
1093
1094
// Pick colors at extreme points
1095
int minD = INT_MAX;
1096
int maxD = 0;
1097
size_t minIndex = 0;
1098
size_t maxIndex = 0;
1099
for (size_t i = 0; i < numColors; i++)
1100
{
1101
const int count = pixelIndexCounts[i];
1102
if (count > 0)
1103
{
1104
const auto &pixel = subblockColors[i];
1105
if (pixel.A > 0)
1106
{
1107
int dot = pixel.R * vr + pixel.G * vg + pixel.B * vb;
1108
if (dot < minD)
1109
{
1110
minD = dot;
1111
minIndex = i;
1112
}
1113
if (dot > maxD)
1114
{
1115
maxD = dot;
1116
maxIndex = i;
1117
}
1118
}
1119
}
1120
}
1121
1122
*minColorIndex = static_cast<int>(minIndex);
1123
*maxColorIndex = static_cast<int>(maxIndex);
1124
}
1125
1126
void transcodeIndividualOrDifferentialBlockToBC1(uint8_t *dest,
1127
size_t x,
1128
size_t y,
1129
size_t w,
1130
size_t h,
1131
int r1,
1132
int g1,
1133
int b1,
1134
int r2,
1135
int g2,
1136
int b2,
1137
const uint8_t alphaValues[4][4],
1138
bool nonOpaquePunchThroughAlpha) const
1139
{
1140
// A BC1 block has 2 endpoints, pixels is encoded as linear
1141
// interpolations of them. A ETC1/ETC2 individual or differential block
1142
// has 2 subblocks. Each subblock has one color and a modifier. We
1143
// select axis by principal component analysis (PCA) to use as
1144
// our two BC1 endpoints and then map pixels to BC1 by projecting on the
1145
// line between the two endpoints and choosing the right fraction.
1146
1147
// The goal of this algorithm is make it faster than decode ETC to RGBs
1148
// and then encode to BC. To achieve this, we only extract subblock
1149
// colors, pixel indices, and counts of each pixel indices from ETC.
1150
// With those information, we can only encode used subblock colors
1151
// to BC1, and copy the bits to the right pixels.
1152
// Fully decode and encode need to process 16 RGBA pixels. With this
1153
// algorithm, it's 8 pixels at maximum for a individual or
1154
// differential block. Saves us bandwidth and computations.
1155
1156
static const size_t kNumColors = 8;
1157
1158
const IntensityModifier *intensityModifier =
1159
nonOpaquePunchThroughAlpha ? intensityModifierNonOpaque : intensityModifierDefault;
1160
1161
// Compute the colors that pixels can have in each subblock both for
1162
// the decoding of the RGBA data and BC1 encoding
1163
R8G8B8A8 subblockColors[kNumColors];
1164
for (size_t modifierIdx = 0; modifierIdx < 4; modifierIdx++)
1165
{
1166
if (nonOpaquePunchThroughAlpha && (modifierIdx == 2))
1167
{
1168
// In ETC opaque punch through formats, individual and
1169
// differential blocks take index 2 as transparent pixel.
1170
// Thus we don't need to compute its color, just assign it
1171
// as black.
1172
subblockColors[modifierIdx] = createRGBA(0, 0, 0, 0);
1173
subblockColors[4 + modifierIdx] = createRGBA(0, 0, 0, 0);
1174
}
1175
else
1176
{
1177
const int i1 = intensityModifier[u.idht.mode.idm.cw1][modifierIdx];
1178
subblockColors[modifierIdx] = createRGBA(r1 + i1, g1 + i1, b1 + i1);
1179
1180
const int i2 = intensityModifier[u.idht.mode.idm.cw2][modifierIdx];
1181
subblockColors[4 + modifierIdx] = createRGBA(r2 + i2, g2 + i2, b2 + i2);
1182
}
1183
}
1184
1185
int pixelIndices[kNumPixelsInBlock];
1186
int pixelIndexCounts[kNumColors] = {0};
1187
// Extract pixel indices from a ETC block.
1188
for (size_t blockIdx = 0; blockIdx < 2; blockIdx++)
1189
{
1190
extractPixelIndices(pixelIndices, pixelIndexCounts, x, y, w, h, u.idht.mode.idm.flipbit,
1191
blockIdx);
1192
}
1193
1194
int minColorIndex, maxColorIndex;
1195
selectEndPointPCA(pixelIndexCounts, subblockColors, kNumColors, &minColorIndex,
1196
&maxColorIndex);
1197
1198
packBC1(dest, pixelIndices, pixelIndexCounts, subblockColors, kNumColors, minColorIndex,
1199
maxColorIndex, nonOpaquePunchThroughAlpha);
1200
}
1201
1202
void transcodeTBlockToBC1(uint8_t *dest,
1203
size_t x,
1204
size_t y,
1205
size_t w,
1206
size_t h,
1207
const uint8_t alphaValues[4][4],
1208
bool nonOpaquePunchThroughAlpha) const
1209
{
1210
static const size_t kNumColors = 4;
1211
1212
// Table C.8, distance index for T and H modes
1213
const auto &block = u.idht.mode.tm;
1214
1215
int r1 = extend_4to8bits(block.TR1a << 2 | block.TR1b);
1216
int g1 = extend_4to8bits(block.TG1);
1217
int b1 = extend_4to8bits(block.TB1);
1218
int r2 = extend_4to8bits(block.TR2);
1219
int g2 = extend_4to8bits(block.TG2);
1220
int b2 = extend_4to8bits(block.TB2);
1221
1222
static int distance[8] = {3, 6, 11, 16, 23, 32, 41, 64};
1223
const int d = distance[block.Tda << 1 | block.Tdb];
1224
1225
// In ETC opaque punch through formats, index == 2 means transparent pixel.
1226
// Thus we don't need to compute its color, just assign it as black.
1227
const R8G8B8A8 paintColors[kNumColors] = {
1228
createRGBA(r1, g1, b1),
1229
createRGBA(r2 + d, g2 + d, b2 + d),
1230
nonOpaquePunchThroughAlpha ? createRGBA(0, 0, 0, 0) : createRGBA(r2, g2, b2),
1231
createRGBA(r2 - d, g2 - d, b2 - d),
1232
};
1233
1234
int pixelIndices[kNumPixelsInBlock];
1235
int pixelIndexCounts[kNumColors] = {0};
1236
for (size_t j = 0; j < 4; j++)
1237
{
1238
int *row = &pixelIndices[j * 4];
1239
for (size_t i = 0; i < 4; i++)
1240
{
1241
const size_t pixelIndex = getIndex(i, j);
1242
row[i] = static_cast<int>(pixelIndex);
1243
pixelIndexCounts[pixelIndex]++;
1244
}
1245
}
1246
1247
int minColorIndex, maxColorIndex;
1248
selectEndPointPCA(pixelIndexCounts, paintColors, kNumColors, &minColorIndex,
1249
&maxColorIndex);
1250
1251
packBC1(dest, pixelIndices, pixelIndexCounts, paintColors, kNumColors, minColorIndex,
1252
maxColorIndex, nonOpaquePunchThroughAlpha);
1253
}
1254
1255
void transcodeHBlockToBC1(uint8_t *dest,
1256
size_t x,
1257
size_t y,
1258
size_t w,
1259
size_t h,
1260
const uint8_t alphaValues[4][4],
1261
bool nonOpaquePunchThroughAlpha) const
1262
{
1263
static const size_t kNumColors = 4;
1264
1265
// Table C.8, distance index for T and H modes
1266
const auto &block = u.idht.mode.hm;
1267
1268
int r1 = extend_4to8bits(block.HR1);
1269
int g1 = extend_4to8bits(block.HG1a << 1 | block.HG1b);
1270
int b1 = extend_4to8bits(block.HB1a << 3 | block.HB1b << 1 | block.HB1c);
1271
int r2 = extend_4to8bits(block.HR2);
1272
int g2 = extend_4to8bits(block.HG2a << 1 | block.HG2b);
1273
int b2 = extend_4to8bits(block.HB2);
1274
1275
static const int distance[8] = {3, 6, 11, 16, 23, 32, 41, 64};
1276
const int orderingTrickBit =
1277
((r1 << 16 | g1 << 8 | b1) >= (r2 << 16 | g2 << 8 | b2) ? 1 : 0);
1278
const int d = distance[(block.Hda << 2) | (block.Hdb << 1) | orderingTrickBit];
1279
1280
// In ETC opaque punch through formats, index == 2 means transparent pixel.
1281
// Thus we don't need to compute its color, just assign it as black.
1282
const R8G8B8A8 paintColors[kNumColors] = {
1283
createRGBA(r1 + d, g1 + d, b1 + d),
1284
createRGBA(r1 - d, g1 - d, b1 - d),
1285
nonOpaquePunchThroughAlpha ? createRGBA(0, 0, 0, 0)
1286
: createRGBA(r2 + d, g2 + d, b2 + d),
1287
createRGBA(r2 - d, g2 - d, b2 - d),
1288
};
1289
1290
int pixelIndices[kNumPixelsInBlock];
1291
int pixelIndexCounts[kNumColors] = {0};
1292
for (size_t j = 0; j < 4; j++)
1293
{
1294
int *row = &pixelIndices[j * 4];
1295
for (size_t i = 0; i < 4; i++)
1296
{
1297
const size_t pixelIndex = getIndex(i, j);
1298
row[i] = static_cast<int>(pixelIndex);
1299
pixelIndexCounts[pixelIndex]++;
1300
}
1301
}
1302
1303
int minColorIndex, maxColorIndex;
1304
selectEndPointPCA(pixelIndexCounts, paintColors, kNumColors, &minColorIndex,
1305
&maxColorIndex);
1306
1307
packBC1(dest, pixelIndices, pixelIndexCounts, paintColors, kNumColors, minColorIndex,
1308
maxColorIndex, nonOpaquePunchThroughAlpha);
1309
}
1310
1311
void transcodePlanarBlockToBC1(uint8_t *dest,
1312
size_t x,
1313
size_t y,
1314
size_t w,
1315
size_t h,
1316
const uint8_t alphaValues[4][4]) const
1317
{
1318
static const size_t kNumColors = kNumPixelsInBlock;
1319
1320
R8G8B8A8 rgbaBlock[kNumColors];
1321
decodePlanarBlock(reinterpret_cast<uint8_t *>(rgbaBlock), x, y, w, h, sizeof(R8G8B8A8) * 4,
1322
alphaValues);
1323
1324
// Planar block doesn't have a color table, fill indices as full
1325
int pixelIndices[kNumPixelsInBlock] = {0, 1, 2, 3, 4, 5, 6, 7,
1326
8, 9, 10, 11, 12, 13, 14, 15};
1327
int pixelIndexCounts[kNumColors] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
1328
1329
int minColorIndex, maxColorIndex;
1330
selectEndPointPCA(pixelIndexCounts, rgbaBlock, kNumColors, &minColorIndex, &maxColorIndex);
1331
1332
packBC1(dest, pixelIndices, pixelIndexCounts, rgbaBlock, kNumColors, minColorIndex,
1333
maxColorIndex, false);
1334
}
1335
1336
// Single channel utility functions
1337
int getSingleEACChannel(size_t x, size_t y, bool isSigned) const
1338
{
1339
int codeword = isSigned ? u.scblk.base_codeword.s : u.scblk.base_codeword.us;
1340
int multiplier = (u.scblk.multiplier == 0) ? 1 : u.scblk.multiplier * 8;
1341
return codeword * 8 + 4 + getSingleChannelModifier(x, y) * multiplier;
1342
}
1343
1344
int getSingleETC2Channel(size_t x, size_t y, bool isSigned) const
1345
{
1346
int codeword = isSigned ? u.scblk.base_codeword.s : u.scblk.base_codeword.us;
1347
return codeword + getSingleChannelModifier(x, y) * u.scblk.multiplier;
1348
}
1349
1350
int getSingleChannelIndex(size_t x, size_t y) const
1351
{
1352
ASSERT(x < 4 && y < 4);
1353
1354
// clang-format off
1355
switch (x * 4 + y)
1356
{
1357
case 0: return u.scblk.ma;
1358
case 1: return u.scblk.mb;
1359
case 2: return u.scblk.mc1 << 1 | u.scblk.mc2;
1360
case 3: return u.scblk.md;
1361
case 4: return u.scblk.me;
1362
case 5: return u.scblk.mf1 << 2 | u.scblk.mf2;
1363
case 6: return u.scblk.mg;
1364
case 7: return u.scblk.mh;
1365
case 8: return u.scblk.mi;
1366
case 9: return u.scblk.mj;
1367
case 10: return u.scblk.mk1 << 1 | u.scblk.mk2;
1368
case 11: return u.scblk.ml;
1369
case 12: return u.scblk.mm;
1370
case 13: return u.scblk.mn1 << 2 | u.scblk.mn2;
1371
case 14: return u.scblk.mo;
1372
case 15: return u.scblk.mp;
1373
default: UNREACHABLE(); return 0;
1374
}
1375
// clang-format on
1376
}
1377
1378
int getSingleChannelModifier(size_t x, size_t y) const
1379
{
1380
// clang-format off
1381
static const int modifierTable[16][8] =
1382
{
1383
{ -3, -6, -9, -15, 2, 5, 8, 14 },
1384
{ -3, -7, -10, -13, 2, 6, 9, 12 },
1385
{ -2, -5, -8, -13, 1, 4, 7, 12 },
1386
{ -2, -4, -6, -13, 1, 3, 5, 12 },
1387
{ -3, -6, -8, -12, 2, 5, 7, 11 },
1388
{ -3, -7, -9, -11, 2, 6, 8, 10 },
1389
{ -4, -7, -8, -11, 3, 6, 7, 10 },
1390
{ -3, -5, -8, -11, 2, 4, 7, 10 },
1391
{ -2, -6, -8, -10, 1, 5, 7, 9 },
1392
{ -2, -5, -8, -10, 1, 4, 7, 9 },
1393
{ -2, -4, -8, -10, 1, 3, 7, 9 },
1394
{ -2, -5, -7, -10, 1, 4, 6, 9 },
1395
{ -3, -4, -7, -10, 2, 3, 6, 9 },
1396
{ -1, -2, -3, -10, 0, 1, 2, 9 },
1397
{ -4, -6, -8, -9, 3, 5, 7, 8 },
1398
{ -3, -5, -7, -9, 2, 4, 6, 8 }
1399
};
1400
// clang-format on
1401
1402
return modifierTable[u.scblk.table_index][getSingleChannelIndex(x, y)];
1403
}
1404
};
1405
1406
// clang-format off
1407
static const uint8_t DefaultETCAlphaValues[4][4] =
1408
{
1409
{ 255, 255, 255, 255 },
1410
{ 255, 255, 255, 255 },
1411
{ 255, 255, 255, 255 },
1412
{ 255, 255, 255, 255 },
1413
};
1414
1415
// clang-format on
1416
void LoadR11EACToR8(size_t width,
1417
size_t height,
1418
size_t depth,
1419
const uint8_t *input,
1420
size_t inputRowPitch,
1421
size_t inputDepthPitch,
1422
uint8_t *output,
1423
size_t outputRowPitch,
1424
size_t outputDepthPitch,
1425
bool isSigned)
1426
{
1427
for (size_t z = 0; z < depth; z++)
1428
{
1429
for (size_t y = 0; y < height; y += 4)
1430
{
1431
const ETC2Block *sourceRow =
1432
priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch);
1433
uint8_t *destRow =
1434
priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch);
1435
1436
for (size_t x = 0; x < width; x += 4)
1437
{
1438
const ETC2Block *sourceBlock = sourceRow + (x / 4);
1439
uint8_t *destPixels = destRow + x;
1440
1441
sourceBlock->decodeAsSingleETC2Channel(destPixels, x, y, width, height, 1,
1442
outputRowPitch, isSigned);
1443
}
1444
}
1445
}
1446
}
1447
1448
void LoadRG11EACToRG8(size_t width,
1449
size_t height,
1450
size_t depth,
1451
const uint8_t *input,
1452
size_t inputRowPitch,
1453
size_t inputDepthPitch,
1454
uint8_t *output,
1455
size_t outputRowPitch,
1456
size_t outputDepthPitch,
1457
bool isSigned)
1458
{
1459
for (size_t z = 0; z < depth; z++)
1460
{
1461
for (size_t y = 0; y < height; y += 4)
1462
{
1463
const ETC2Block *sourceRow =
1464
priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch);
1465
uint8_t *destRow =
1466
priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch);
1467
1468
for (size_t x = 0; x < width; x += 4)
1469
{
1470
uint8_t *destPixelsRed = destRow + (x * 2);
1471
const ETC2Block *sourceBlockRed = sourceRow + (x / 2);
1472
sourceBlockRed->decodeAsSingleETC2Channel(destPixelsRed, x, y, width, height, 2,
1473
outputRowPitch, isSigned);
1474
1475
uint8_t *destPixelsGreen = destPixelsRed + 1;
1476
const ETC2Block *sourceBlockGreen = sourceBlockRed + 1;
1477
sourceBlockGreen->decodeAsSingleETC2Channel(destPixelsGreen, x, y, width, height, 2,
1478
outputRowPitch, isSigned);
1479
}
1480
}
1481
}
1482
}
1483
1484
void LoadR11EACToR16(size_t width,
1485
size_t height,
1486
size_t depth,
1487
const uint8_t *input,
1488
size_t inputRowPitch,
1489
size_t inputDepthPitch,
1490
uint8_t *output,
1491
size_t outputRowPitch,
1492
size_t outputDepthPitch,
1493
bool isSigned,
1494
bool isFloat)
1495
{
1496
for (size_t z = 0; z < depth; z++)
1497
{
1498
for (size_t y = 0; y < height; y += 4)
1499
{
1500
const ETC2Block *sourceRow =
1501
priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch);
1502
uint16_t *destRow =
1503
priv::OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch);
1504
1505
for (size_t x = 0; x < width; x += 4)
1506
{
1507
const ETC2Block *sourceBlock = sourceRow + (x / 4);
1508
uint16_t *destPixels = destRow + x;
1509
1510
sourceBlock->decodeAsSingleEACChannel(destPixels, x, y, width, height, 1,
1511
outputRowPitch, isSigned, isFloat);
1512
}
1513
}
1514
}
1515
}
1516
1517
void LoadRG11EACToRG16(size_t width,
1518
size_t height,
1519
size_t depth,
1520
const uint8_t *input,
1521
size_t inputRowPitch,
1522
size_t inputDepthPitch,
1523
uint8_t *output,
1524
size_t outputRowPitch,
1525
size_t outputDepthPitch,
1526
bool isSigned,
1527
bool isFloat)
1528
{
1529
for (size_t z = 0; z < depth; z++)
1530
{
1531
for (size_t y = 0; y < height; y += 4)
1532
{
1533
const ETC2Block *sourceRow =
1534
priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch);
1535
uint16_t *destRow =
1536
priv::OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch);
1537
1538
for (size_t x = 0; x < width; x += 4)
1539
{
1540
uint16_t *destPixelsRed = destRow + (x * 2);
1541
const ETC2Block *sourceBlockRed = sourceRow + (x / 2);
1542
sourceBlockRed->decodeAsSingleEACChannel(destPixelsRed, x, y, width, height, 2,
1543
outputRowPitch, isSigned, isFloat);
1544
1545
uint16_t *destPixelsGreen = destPixelsRed + 1;
1546
const ETC2Block *sourceBlockGreen = sourceBlockRed + 1;
1547
sourceBlockGreen->decodeAsSingleEACChannel(destPixelsGreen, x, y, width, height, 2,
1548
outputRowPitch, isSigned, isFloat);
1549
}
1550
}
1551
}
1552
}
1553
1554
void LoadETC2RGB8ToRGBA8(size_t width,
1555
size_t height,
1556
size_t depth,
1557
const uint8_t *input,
1558
size_t inputRowPitch,
1559
size_t inputDepthPitch,
1560
uint8_t *output,
1561
size_t outputRowPitch,
1562
size_t outputDepthPitch,
1563
bool punchthroughAlpha)
1564
{
1565
for (size_t z = 0; z < depth; z++)
1566
{
1567
for (size_t y = 0; y < height; y += 4)
1568
{
1569
const ETC2Block *sourceRow =
1570
priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch);
1571
uint8_t *destRow =
1572
priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch);
1573
1574
for (size_t x = 0; x < width; x += 4)
1575
{
1576
const ETC2Block *sourceBlock = sourceRow + (x / 4);
1577
uint8_t *destPixels = destRow + (x * 4);
1578
1579
sourceBlock->decodeAsRGB(destPixels, x, y, width, height, outputRowPitch,
1580
DefaultETCAlphaValues, punchthroughAlpha);
1581
}
1582
}
1583
}
1584
}
1585
1586
void LoadETC2RGB8ToBC1(size_t width,
1587
size_t height,
1588
size_t depth,
1589
const uint8_t *input,
1590
size_t inputRowPitch,
1591
size_t inputDepthPitch,
1592
uint8_t *output,
1593
size_t outputRowPitch,
1594
size_t outputDepthPitch,
1595
bool punchthroughAlpha)
1596
{
1597
for (size_t z = 0; z < depth; z++)
1598
{
1599
for (size_t y = 0; y < height; y += 4)
1600
{
1601
const ETC2Block *sourceRow =
1602
priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch);
1603
uint8_t *destRow = priv::OffsetDataPointer<uint8_t>(output, y / 4, z, outputRowPitch,
1604
outputDepthPitch);
1605
1606
for (size_t x = 0; x < width; x += 4)
1607
{
1608
const ETC2Block *sourceBlock = sourceRow + (x / 4);
1609
uint8_t *destPixels = destRow + (x * 2);
1610
1611
sourceBlock->transcodeAsBC1(destPixels, x, y, width, height, DefaultETCAlphaValues,
1612
punchthroughAlpha);
1613
}
1614
}
1615
}
1616
}
1617
1618
void LoadETC2RGBA8ToRGBA8(size_t width,
1619
size_t height,
1620
size_t depth,
1621
const uint8_t *input,
1622
size_t inputRowPitch,
1623
size_t inputDepthPitch,
1624
uint8_t *output,
1625
size_t outputRowPitch,
1626
size_t outputDepthPitch,
1627
bool srgb)
1628
{
1629
uint8_t decodedAlphaValues[4][4];
1630
1631
for (size_t z = 0; z < depth; z++)
1632
{
1633
for (size_t y = 0; y < height; y += 4)
1634
{
1635
const ETC2Block *sourceRow =
1636
priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch);
1637
uint8_t *destRow =
1638
priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch);
1639
1640
for (size_t x = 0; x < width; x += 4)
1641
{
1642
const ETC2Block *sourceBlockAlpha = sourceRow + (x / 2);
1643
sourceBlockAlpha->decodeAsSingleETC2Channel(
1644
reinterpret_cast<uint8_t *>(decodedAlphaValues), x, y, width, height, 1, 4,
1645
false);
1646
1647
uint8_t *destPixels = destRow + (x * 4);
1648
const ETC2Block *sourceBlockRGB = sourceBlockAlpha + 1;
1649
sourceBlockRGB->decodeAsRGB(destPixels, x, y, width, height, outputRowPitch,
1650
decodedAlphaValues, false);
1651
}
1652
}
1653
}
1654
}
1655
1656
} // anonymous namespace
1657
1658
void LoadETC1RGB8ToRGBA8(size_t width,
1659
size_t height,
1660
size_t depth,
1661
const uint8_t *input,
1662
size_t inputRowPitch,
1663
size_t inputDepthPitch,
1664
uint8_t *output,
1665
size_t outputRowPitch,
1666
size_t outputDepthPitch)
1667
{
1668
LoadETC2RGB8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1669
outputRowPitch, outputDepthPitch, false);
1670
}
1671
1672
void LoadETC1RGB8ToBC1(size_t width,
1673
size_t height,
1674
size_t depth,
1675
const uint8_t *input,
1676
size_t inputRowPitch,
1677
size_t inputDepthPitch,
1678
uint8_t *output,
1679
size_t outputRowPitch,
1680
size_t outputDepthPitch)
1681
{
1682
LoadETC2RGB8ToBC1(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1683
outputRowPitch, outputDepthPitch, false);
1684
}
1685
1686
void LoadEACR11ToR8(size_t width,
1687
size_t height,
1688
size_t depth,
1689
const uint8_t *input,
1690
size_t inputRowPitch,
1691
size_t inputDepthPitch,
1692
uint8_t *output,
1693
size_t outputRowPitch,
1694
size_t outputDepthPitch)
1695
{
1696
LoadR11EACToR8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1697
outputRowPitch, outputDepthPitch, false);
1698
}
1699
1700
void LoadEACR11SToR8(size_t width,
1701
size_t height,
1702
size_t depth,
1703
const uint8_t *input,
1704
size_t inputRowPitch,
1705
size_t inputDepthPitch,
1706
uint8_t *output,
1707
size_t outputRowPitch,
1708
size_t outputDepthPitch)
1709
{
1710
LoadR11EACToR8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1711
outputRowPitch, outputDepthPitch, true);
1712
}
1713
1714
void LoadEACRG11ToRG8(size_t width,
1715
size_t height,
1716
size_t depth,
1717
const uint8_t *input,
1718
size_t inputRowPitch,
1719
size_t inputDepthPitch,
1720
uint8_t *output,
1721
size_t outputRowPitch,
1722
size_t outputDepthPitch)
1723
{
1724
LoadRG11EACToRG8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1725
outputRowPitch, outputDepthPitch, false);
1726
}
1727
1728
void LoadEACRG11SToRG8(size_t width,
1729
size_t height,
1730
size_t depth,
1731
const uint8_t *input,
1732
size_t inputRowPitch,
1733
size_t inputDepthPitch,
1734
uint8_t *output,
1735
size_t outputRowPitch,
1736
size_t outputDepthPitch)
1737
{
1738
LoadRG11EACToRG8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1739
outputRowPitch, outputDepthPitch, true);
1740
}
1741
1742
void LoadEACR11ToR16(size_t width,
1743
size_t height,
1744
size_t depth,
1745
const uint8_t *input,
1746
size_t inputRowPitch,
1747
size_t inputDepthPitch,
1748
uint8_t *output,
1749
size_t outputRowPitch,
1750
size_t outputDepthPitch)
1751
{
1752
LoadR11EACToR16(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1753
outputRowPitch, outputDepthPitch, false, false);
1754
}
1755
1756
void LoadEACR11SToR16(size_t width,
1757
size_t height,
1758
size_t depth,
1759
const uint8_t *input,
1760
size_t inputRowPitch,
1761
size_t inputDepthPitch,
1762
uint8_t *output,
1763
size_t outputRowPitch,
1764
size_t outputDepthPitch)
1765
{
1766
LoadR11EACToR16(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1767
outputRowPitch, outputDepthPitch, true, false);
1768
}
1769
1770
void LoadEACRG11ToRG16(size_t width,
1771
size_t height,
1772
size_t depth,
1773
const uint8_t *input,
1774
size_t inputRowPitch,
1775
size_t inputDepthPitch,
1776
uint8_t *output,
1777
size_t outputRowPitch,
1778
size_t outputDepthPitch)
1779
{
1780
LoadRG11EACToRG16(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1781
outputRowPitch, outputDepthPitch, false, false);
1782
}
1783
1784
void LoadEACRG11SToRG16(size_t width,
1785
size_t height,
1786
size_t depth,
1787
const uint8_t *input,
1788
size_t inputRowPitch,
1789
size_t inputDepthPitch,
1790
uint8_t *output,
1791
size_t outputRowPitch,
1792
size_t outputDepthPitch)
1793
{
1794
LoadRG11EACToRG16(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1795
outputRowPitch, outputDepthPitch, true, false);
1796
}
1797
1798
void LoadEACR11ToR16F(size_t width,
1799
size_t height,
1800
size_t depth,
1801
const uint8_t *input,
1802
size_t inputRowPitch,
1803
size_t inputDepthPitch,
1804
uint8_t *output,
1805
size_t outputRowPitch,
1806
size_t outputDepthPitch)
1807
{
1808
LoadR11EACToR16(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1809
outputRowPitch, outputDepthPitch, false, true);
1810
}
1811
1812
void LoadEACR11SToR16F(size_t width,
1813
size_t height,
1814
size_t depth,
1815
const uint8_t *input,
1816
size_t inputRowPitch,
1817
size_t inputDepthPitch,
1818
uint8_t *output,
1819
size_t outputRowPitch,
1820
size_t outputDepthPitch)
1821
{
1822
LoadR11EACToR16(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1823
outputRowPitch, outputDepthPitch, true, true);
1824
}
1825
1826
void LoadEACRG11ToRG16F(size_t width,
1827
size_t height,
1828
size_t depth,
1829
const uint8_t *input,
1830
size_t inputRowPitch,
1831
size_t inputDepthPitch,
1832
uint8_t *output,
1833
size_t outputRowPitch,
1834
size_t outputDepthPitch)
1835
{
1836
LoadRG11EACToRG16(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1837
outputRowPitch, outputDepthPitch, false, true);
1838
}
1839
1840
void LoadEACRG11SToRG16F(size_t width,
1841
size_t height,
1842
size_t depth,
1843
const uint8_t *input,
1844
size_t inputRowPitch,
1845
size_t inputDepthPitch,
1846
uint8_t *output,
1847
size_t outputRowPitch,
1848
size_t outputDepthPitch)
1849
{
1850
LoadRG11EACToRG16(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1851
outputRowPitch, outputDepthPitch, true, true);
1852
}
1853
1854
void LoadETC2RGB8ToRGBA8(size_t width,
1855
size_t height,
1856
size_t depth,
1857
const uint8_t *input,
1858
size_t inputRowPitch,
1859
size_t inputDepthPitch,
1860
uint8_t *output,
1861
size_t outputRowPitch,
1862
size_t outputDepthPitch)
1863
{
1864
LoadETC2RGB8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1865
outputRowPitch, outputDepthPitch, false);
1866
}
1867
1868
void LoadETC2RGB8ToBC1(size_t width,
1869
size_t height,
1870
size_t depth,
1871
const uint8_t *input,
1872
size_t inputRowPitch,
1873
size_t inputDepthPitch,
1874
uint8_t *output,
1875
size_t outputRowPitch,
1876
size_t outputDepthPitch)
1877
{
1878
LoadETC2RGB8ToBC1(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1879
outputRowPitch, outputDepthPitch, false);
1880
}
1881
1882
void LoadETC2SRGB8ToRGBA8(size_t width,
1883
size_t height,
1884
size_t depth,
1885
const uint8_t *input,
1886
size_t inputRowPitch,
1887
size_t inputDepthPitch,
1888
uint8_t *output,
1889
size_t outputRowPitch,
1890
size_t outputDepthPitch)
1891
{
1892
LoadETC2RGB8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1893
outputRowPitch, outputDepthPitch, false);
1894
}
1895
1896
void LoadETC2SRGB8ToBC1(size_t width,
1897
size_t height,
1898
size_t depth,
1899
const uint8_t *input,
1900
size_t inputRowPitch,
1901
size_t inputDepthPitch,
1902
uint8_t *output,
1903
size_t outputRowPitch,
1904
size_t outputDepthPitch)
1905
{
1906
LoadETC2RGB8ToBC1(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1907
outputRowPitch, outputDepthPitch, false);
1908
}
1909
1910
void LoadETC2RGB8A1ToRGBA8(size_t width,
1911
size_t height,
1912
size_t depth,
1913
const uint8_t *input,
1914
size_t inputRowPitch,
1915
size_t inputDepthPitch,
1916
uint8_t *output,
1917
size_t outputRowPitch,
1918
size_t outputDepthPitch)
1919
{
1920
LoadETC2RGB8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1921
outputRowPitch, outputDepthPitch, true);
1922
}
1923
1924
void LoadETC2RGB8A1ToBC1(size_t width,
1925
size_t height,
1926
size_t depth,
1927
const uint8_t *input,
1928
size_t inputRowPitch,
1929
size_t inputDepthPitch,
1930
uint8_t *output,
1931
size_t outputRowPitch,
1932
size_t outputDepthPitch)
1933
{
1934
LoadETC2RGB8ToBC1(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1935
outputRowPitch, outputDepthPitch, true);
1936
}
1937
1938
void LoadETC2SRGB8A1ToRGBA8(size_t width,
1939
size_t height,
1940
size_t depth,
1941
const uint8_t *input,
1942
size_t inputRowPitch,
1943
size_t inputDepthPitch,
1944
uint8_t *output,
1945
size_t outputRowPitch,
1946
size_t outputDepthPitch)
1947
{
1948
LoadETC2RGB8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1949
outputRowPitch, outputDepthPitch, true);
1950
}
1951
1952
void LoadETC2SRGB8A1ToBC1(size_t width,
1953
size_t height,
1954
size_t depth,
1955
const uint8_t *input,
1956
size_t inputRowPitch,
1957
size_t inputDepthPitch,
1958
uint8_t *output,
1959
size_t outputRowPitch,
1960
size_t outputDepthPitch)
1961
{
1962
LoadETC2RGB8ToBC1(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1963
outputRowPitch, outputDepthPitch, true);
1964
}
1965
1966
void LoadETC2RGBA8ToRGBA8(size_t width,
1967
size_t height,
1968
size_t depth,
1969
const uint8_t *input,
1970
size_t inputRowPitch,
1971
size_t inputDepthPitch,
1972
uint8_t *output,
1973
size_t outputRowPitch,
1974
size_t outputDepthPitch)
1975
{
1976
LoadETC2RGBA8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1977
outputRowPitch, outputDepthPitch, false);
1978
}
1979
1980
void LoadETC2SRGBA8ToSRGBA8(size_t width,
1981
size_t height,
1982
size_t depth,
1983
const uint8_t *input,
1984
size_t inputRowPitch,
1985
size_t inputDepthPitch,
1986
uint8_t *output,
1987
size_t outputRowPitch,
1988
size_t outputDepthPitch)
1989
{
1990
LoadETC2RGBA8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
1991
outputRowPitch, outputDepthPitch, true);
1992
}
1993
1994
} // namespace angle
1995
1996