loadimage_etc.cpp (76247B)
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