16c354881b63935626a0700366937530d38b8b1e8krajcevski/* 26c354881b63935626a0700366937530d38b8b1e8krajcevski * Copyright 2014 Google Inc. 36c354881b63935626a0700366937530d38b8b1e8krajcevski * 46c354881b63935626a0700366937530d38b8b1e8krajcevski * Use of this source code is governed by a BSD-style license that can be 56c354881b63935626a0700366937530d38b8b1e8krajcevski * found in the LICENSE file. 66c354881b63935626a0700366937530d38b8b1e8krajcevski */ 76c354881b63935626a0700366937530d38b8b1e8krajcevski 86c354881b63935626a0700366937530d38b8b1e8krajcevski#include "SkTextureCompressor_LATC.h" 9b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski#include "SkTextureCompressor_Blitter.h" 106c354881b63935626a0700366937530d38b8b1e8krajcevski 11b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski#include "SkBlitter.h" 126c354881b63935626a0700366937530d38b8b1e8krajcevski#include "SkEndian.h" 136c354881b63935626a0700366937530d38b8b1e8krajcevski 14b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski// Compression options. In general, the slow version is much more accurate, but 15b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski// much slower. The fast option is much faster, but much less accurate. YMMV. 16b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski#define COMPRESS_LATC_SLOW 0 17b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski#define COMPRESS_LATC_FAST 1 18b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski 19b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski//////////////////////////////////////////////////////////////////////////////// 20b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski 214ad76e35111585f4da662d54943f23792dd1e0aekrajcevski// Generates an LATC palette. LATC constructs 224ad76e35111585f4da662d54943f23792dd1e0aekrajcevski// a palette of eight colors from LUM0 and LUM1 using the algorithm: 234ad76e35111585f4da662d54943f23792dd1e0aekrajcevski// 244ad76e35111585f4da662d54943f23792dd1e0aekrajcevski// LUM0, if lum0 > lum1 and code(x,y) == 0 254ad76e35111585f4da662d54943f23792dd1e0aekrajcevski// LUM1, if lum0 > lum1 and code(x,y) == 1 264ad76e35111585f4da662d54943f23792dd1e0aekrajcevski// (6*LUM0+ LUM1)/7, if lum0 > lum1 and code(x,y) == 2 274ad76e35111585f4da662d54943f23792dd1e0aekrajcevski// (5*LUM0+2*LUM1)/7, if lum0 > lum1 and code(x,y) == 3 284ad76e35111585f4da662d54943f23792dd1e0aekrajcevski// (4*LUM0+3*LUM1)/7, if lum0 > lum1 and code(x,y) == 4 294ad76e35111585f4da662d54943f23792dd1e0aekrajcevski// (3*LUM0+4*LUM1)/7, if lum0 > lum1 and code(x,y) == 5 304ad76e35111585f4da662d54943f23792dd1e0aekrajcevski// (2*LUM0+5*LUM1)/7, if lum0 > lum1 and code(x,y) == 6 314ad76e35111585f4da662d54943f23792dd1e0aekrajcevski// ( LUM0+6*LUM1)/7, if lum0 > lum1 and code(x,y) == 7 324ad76e35111585f4da662d54943f23792dd1e0aekrajcevski// 334ad76e35111585f4da662d54943f23792dd1e0aekrajcevski// LUM0, if lum0 <= lum1 and code(x,y) == 0 344ad76e35111585f4da662d54943f23792dd1e0aekrajcevski// LUM1, if lum0 <= lum1 and code(x,y) == 1 354ad76e35111585f4da662d54943f23792dd1e0aekrajcevski// (4*LUM0+ LUM1)/5, if lum0 <= lum1 and code(x,y) == 2 364ad76e35111585f4da662d54943f23792dd1e0aekrajcevski// (3*LUM0+2*LUM1)/5, if lum0 <= lum1 and code(x,y) == 3 374ad76e35111585f4da662d54943f23792dd1e0aekrajcevski// (2*LUM0+3*LUM1)/5, if lum0 <= lum1 and code(x,y) == 4 384ad76e35111585f4da662d54943f23792dd1e0aekrajcevski// ( LUM0+4*LUM1)/5, if lum0 <= lum1 and code(x,y) == 5 394ad76e35111585f4da662d54943f23792dd1e0aekrajcevski// 0, if lum0 <= lum1 and code(x,y) == 6 404ad76e35111585f4da662d54943f23792dd1e0aekrajcevski// 255, if lum0 <= lum1 and code(x,y) == 7 414ad76e35111585f4da662d54943f23792dd1e0aekrajcevski 424ad76e35111585f4da662d54943f23792dd1e0aekrajcevskistatic const int kLATCPaletteSize = 8; 434ad76e35111585f4da662d54943f23792dd1e0aekrajcevskistatic void generate_latc_palette(uint8_t palette[], uint8_t lum0, uint8_t lum1) { 444ad76e35111585f4da662d54943f23792dd1e0aekrajcevski palette[0] = lum0; 454ad76e35111585f4da662d54943f23792dd1e0aekrajcevski palette[1] = lum1; 464ad76e35111585f4da662d54943f23792dd1e0aekrajcevski if (lum0 > lum1) { 474ad76e35111585f4da662d54943f23792dd1e0aekrajcevski for (int i = 1; i < 7; i++) { 484ad76e35111585f4da662d54943f23792dd1e0aekrajcevski palette[i+1] = ((7-i)*lum0 + i*lum1) / 7; 494ad76e35111585f4da662d54943f23792dd1e0aekrajcevski } 504ad76e35111585f4da662d54943f23792dd1e0aekrajcevski } else { 514ad76e35111585f4da662d54943f23792dd1e0aekrajcevski for (int i = 1; i < 5; i++) { 524ad76e35111585f4da662d54943f23792dd1e0aekrajcevski palette[i+1] = ((5-i)*lum0 + i*lum1) / 5; 534ad76e35111585f4da662d54943f23792dd1e0aekrajcevski } 544ad76e35111585f4da662d54943f23792dd1e0aekrajcevski palette[6] = 0; 554ad76e35111585f4da662d54943f23792dd1e0aekrajcevski palette[7] = 255; 564ad76e35111585f4da662d54943f23792dd1e0aekrajcevski } 574ad76e35111585f4da662d54943f23792dd1e0aekrajcevski} 584ad76e35111585f4da662d54943f23792dd1e0aekrajcevski 594ad76e35111585f4da662d54943f23792dd1e0aekrajcevski//////////////////////////////////////////////////////////////////////////////// 604ad76e35111585f4da662d54943f23792dd1e0aekrajcevski 61b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski#if COMPRESS_LATC_SLOW 62b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski 636c354881b63935626a0700366937530d38b8b1e8krajcevski//////////////////////////////////////////////////////////////////////////////// 646c354881b63935626a0700366937530d38b8b1e8krajcevski// 656c354881b63935626a0700366937530d38b8b1e8krajcevski// Utility Functions 666c354881b63935626a0700366937530d38b8b1e8krajcevski// 676c354881b63935626a0700366937530d38b8b1e8krajcevski//////////////////////////////////////////////////////////////////////////////// 686c354881b63935626a0700366937530d38b8b1e8krajcevski 696c354881b63935626a0700366937530d38b8b1e8krajcevski// Absolute difference between two values. More correct than SkTAbs(a - b) 706c354881b63935626a0700366937530d38b8b1e8krajcevski// because it works on unsigned values. 716c354881b63935626a0700366937530d38b8b1e8krajcevskitemplate <typename T> inline T abs_diff(const T &a, const T &b) { 726c354881b63935626a0700366937530d38b8b1e8krajcevski return (a > b) ? (a - b) : (b - a); 736c354881b63935626a0700366937530d38b8b1e8krajcevski} 746c354881b63935626a0700366937530d38b8b1e8krajcevski 756c354881b63935626a0700366937530d38b8b1e8krajcevskistatic bool is_extremal(uint8_t pixel) { 766c354881b63935626a0700366937530d38b8b1e8krajcevski return 0 == pixel || 255 == pixel; 776c354881b63935626a0700366937530d38b8b1e8krajcevski} 786c354881b63935626a0700366937530d38b8b1e8krajcevski 796c354881b63935626a0700366937530d38b8b1e8krajcevskitypedef uint64_t (*A84x4To64BitProc)(const uint8_t block[]); 806c354881b63935626a0700366937530d38b8b1e8krajcevski 816c354881b63935626a0700366937530d38b8b1e8krajcevski// This function is used by both R11 EAC and LATC to compress 4x4 blocks 826c354881b63935626a0700366937530d38b8b1e8krajcevski// of 8-bit alpha into 64-bit values that comprise the compressed data. 836c354881b63935626a0700366937530d38b8b1e8krajcevski// For both formats, we need to make sure that the dimensions of the 846c354881b63935626a0700366937530d38b8b1e8krajcevski// src pixels are divisible by 4, and copy 4x4 blocks one at a time 856c354881b63935626a0700366937530d38b8b1e8krajcevski// for compression. 866c354881b63935626a0700366937530d38b8b1e8krajcevskistatic bool compress_4x4_a8_to_64bit(uint8_t* dst, const uint8_t* src, 876c354881b63935626a0700366937530d38b8b1e8krajcevski int width, int height, int rowBytes, 886c354881b63935626a0700366937530d38b8b1e8krajcevski A84x4To64BitProc proc) { 896c354881b63935626a0700366937530d38b8b1e8krajcevski // Make sure that our data is well-formed enough to be considered for compression 906c354881b63935626a0700366937530d38b8b1e8krajcevski if (0 == width || 0 == height || (width % 4) != 0 || (height % 4) != 0) { 916c354881b63935626a0700366937530d38b8b1e8krajcevski return false; 926c354881b63935626a0700366937530d38b8b1e8krajcevski } 936c354881b63935626a0700366937530d38b8b1e8krajcevski 946c354881b63935626a0700366937530d38b8b1e8krajcevski int blocksX = width >> 2; 956c354881b63935626a0700366937530d38b8b1e8krajcevski int blocksY = height >> 2; 966c354881b63935626a0700366937530d38b8b1e8krajcevski 976c354881b63935626a0700366937530d38b8b1e8krajcevski uint8_t block[16]; 986c354881b63935626a0700366937530d38b8b1e8krajcevski uint64_t* encPtr = reinterpret_cast<uint64_t*>(dst); 996c354881b63935626a0700366937530d38b8b1e8krajcevski for (int y = 0; y < blocksY; ++y) { 1006c354881b63935626a0700366937530d38b8b1e8krajcevski for (int x = 0; x < blocksX; ++x) { 1016c354881b63935626a0700366937530d38b8b1e8krajcevski // Load block 1026c354881b63935626a0700366937530d38b8b1e8krajcevski for (int k = 0; k < 4; ++k) { 1036c354881b63935626a0700366937530d38b8b1e8krajcevski memcpy(block + k*4, src + k*rowBytes + 4*x, 4); 1046c354881b63935626a0700366937530d38b8b1e8krajcevski } 1056c354881b63935626a0700366937530d38b8b1e8krajcevski 1066c354881b63935626a0700366937530d38b8b1e8krajcevski // Compress it 1076c354881b63935626a0700366937530d38b8b1e8krajcevski *encPtr = proc(block); 1086c354881b63935626a0700366937530d38b8b1e8krajcevski ++encPtr; 1096c354881b63935626a0700366937530d38b8b1e8krajcevski } 1106c354881b63935626a0700366937530d38b8b1e8krajcevski src += 4 * rowBytes; 1116c354881b63935626a0700366937530d38b8b1e8krajcevski } 1126c354881b63935626a0700366937530d38b8b1e8krajcevski 1136c354881b63935626a0700366937530d38b8b1e8krajcevski return true; 1146c354881b63935626a0700366937530d38b8b1e8krajcevski} 1156c354881b63935626a0700366937530d38b8b1e8krajcevski 1166c354881b63935626a0700366937530d38b8b1e8krajcevski//////////////////////////////////////////////////////////////////////////////// 1176c354881b63935626a0700366937530d38b8b1e8krajcevski// 1186c354881b63935626a0700366937530d38b8b1e8krajcevski// LATC compressor 1196c354881b63935626a0700366937530d38b8b1e8krajcevski// 1206c354881b63935626a0700366937530d38b8b1e8krajcevski//////////////////////////////////////////////////////////////////////////////// 1216c354881b63935626a0700366937530d38b8b1e8krajcevski 1226c354881b63935626a0700366937530d38b8b1e8krajcevski// LATC compressed texels down into square 4x4 blocks 1236c354881b63935626a0700366937530d38b8b1e8krajcevskistatic const int kLATCBlockSize = 4; 1246c354881b63935626a0700366937530d38b8b1e8krajcevskistatic const int kLATCPixelsPerBlock = kLATCBlockSize * kLATCBlockSize; 1256c354881b63935626a0700366937530d38b8b1e8krajcevski 1266c354881b63935626a0700366937530d38b8b1e8krajcevski// Compress a block by using the bounding box of the pixels. It is assumed that 1276c354881b63935626a0700366937530d38b8b1e8krajcevski// there are no extremal pixels in this block otherwise we would have used 1286c354881b63935626a0700366937530d38b8b1e8krajcevski// compressBlockBBIgnoreExtremal. 1296c354881b63935626a0700366937530d38b8b1e8krajcevskistatic uint64_t compress_latc_block_bb(const uint8_t pixels[]) { 1306c354881b63935626a0700366937530d38b8b1e8krajcevski uint8_t minVal = 255; 1316c354881b63935626a0700366937530d38b8b1e8krajcevski uint8_t maxVal = 0; 1326c354881b63935626a0700366937530d38b8b1e8krajcevski for (int i = 0; i < kLATCPixelsPerBlock; ++i) { 1336c354881b63935626a0700366937530d38b8b1e8krajcevski minVal = SkTMin(pixels[i], minVal); 1346c354881b63935626a0700366937530d38b8b1e8krajcevski maxVal = SkTMax(pixels[i], maxVal); 1356c354881b63935626a0700366937530d38b8b1e8krajcevski } 1366c354881b63935626a0700366937530d38b8b1e8krajcevski 1376c354881b63935626a0700366937530d38b8b1e8krajcevski SkASSERT(!is_extremal(minVal)); 1386c354881b63935626a0700366937530d38b8b1e8krajcevski SkASSERT(!is_extremal(maxVal)); 1396c354881b63935626a0700366937530d38b8b1e8krajcevski 1406c354881b63935626a0700366937530d38b8b1e8krajcevski uint8_t palette[kLATCPaletteSize]; 1416c354881b63935626a0700366937530d38b8b1e8krajcevski generate_latc_palette(palette, maxVal, minVal); 1426c354881b63935626a0700366937530d38b8b1e8krajcevski 1436c354881b63935626a0700366937530d38b8b1e8krajcevski uint64_t indices = 0; 1446c354881b63935626a0700366937530d38b8b1e8krajcevski for (int i = kLATCPixelsPerBlock - 1; i >= 0; --i) { 1456c354881b63935626a0700366937530d38b8b1e8krajcevski 1466c354881b63935626a0700366937530d38b8b1e8krajcevski // Find the best palette index 1476c354881b63935626a0700366937530d38b8b1e8krajcevski uint8_t bestError = abs_diff(pixels[i], palette[0]); 1486c354881b63935626a0700366937530d38b8b1e8krajcevski uint8_t idx = 0; 1496c354881b63935626a0700366937530d38b8b1e8krajcevski for (int j = 1; j < kLATCPaletteSize; ++j) { 1506c354881b63935626a0700366937530d38b8b1e8krajcevski uint8_t error = abs_diff(pixels[i], palette[j]); 1516c354881b63935626a0700366937530d38b8b1e8krajcevski if (error < bestError) { 1526c354881b63935626a0700366937530d38b8b1e8krajcevski bestError = error; 1536c354881b63935626a0700366937530d38b8b1e8krajcevski idx = j; 1546c354881b63935626a0700366937530d38b8b1e8krajcevski } 1556c354881b63935626a0700366937530d38b8b1e8krajcevski } 1566c354881b63935626a0700366937530d38b8b1e8krajcevski 1576c354881b63935626a0700366937530d38b8b1e8krajcevski indices <<= 3; 1586c354881b63935626a0700366937530d38b8b1e8krajcevski indices |= idx; 1596c354881b63935626a0700366937530d38b8b1e8krajcevski } 1606c354881b63935626a0700366937530d38b8b1e8krajcevski 1616c354881b63935626a0700366937530d38b8b1e8krajcevski return 1626c354881b63935626a0700366937530d38b8b1e8krajcevski SkEndian_SwapLE64( 1636c354881b63935626a0700366937530d38b8b1e8krajcevski static_cast<uint64_t>(maxVal) | 1646c354881b63935626a0700366937530d38b8b1e8krajcevski (static_cast<uint64_t>(minVal) << 8) | 1656c354881b63935626a0700366937530d38b8b1e8krajcevski (indices << 16)); 1666c354881b63935626a0700366937530d38b8b1e8krajcevski} 1676c354881b63935626a0700366937530d38b8b1e8krajcevski 1686c354881b63935626a0700366937530d38b8b1e8krajcevski// Compress a block by using the bounding box of the pixels without taking into 1696c354881b63935626a0700366937530d38b8b1e8krajcevski// account the extremal values. The generated palette will contain extremal values 1706c354881b63935626a0700366937530d38b8b1e8krajcevski// and fewer points along the line segment to interpolate. 1716c354881b63935626a0700366937530d38b8b1e8krajcevskistatic uint64_t compress_latc_block_bb_ignore_extremal(const uint8_t pixels[]) { 1726c354881b63935626a0700366937530d38b8b1e8krajcevski uint8_t minVal = 255; 1736c354881b63935626a0700366937530d38b8b1e8krajcevski uint8_t maxVal = 0; 1746c354881b63935626a0700366937530d38b8b1e8krajcevski for (int i = 0; i < kLATCPixelsPerBlock; ++i) { 1756c354881b63935626a0700366937530d38b8b1e8krajcevski if (is_extremal(pixels[i])) { 1766c354881b63935626a0700366937530d38b8b1e8krajcevski continue; 1776c354881b63935626a0700366937530d38b8b1e8krajcevski } 1786c354881b63935626a0700366937530d38b8b1e8krajcevski 1796c354881b63935626a0700366937530d38b8b1e8krajcevski minVal = SkTMin(pixels[i], minVal); 1806c354881b63935626a0700366937530d38b8b1e8krajcevski maxVal = SkTMax(pixels[i], maxVal); 1816c354881b63935626a0700366937530d38b8b1e8krajcevski } 1826c354881b63935626a0700366937530d38b8b1e8krajcevski 1836c354881b63935626a0700366937530d38b8b1e8krajcevski SkASSERT(!is_extremal(minVal)); 1846c354881b63935626a0700366937530d38b8b1e8krajcevski SkASSERT(!is_extremal(maxVal)); 1856c354881b63935626a0700366937530d38b8b1e8krajcevski 1866c354881b63935626a0700366937530d38b8b1e8krajcevski uint8_t palette[kLATCPaletteSize]; 1876c354881b63935626a0700366937530d38b8b1e8krajcevski generate_latc_palette(palette, minVal, maxVal); 1886c354881b63935626a0700366937530d38b8b1e8krajcevski 1896c354881b63935626a0700366937530d38b8b1e8krajcevski uint64_t indices = 0; 1906c354881b63935626a0700366937530d38b8b1e8krajcevski for (int i = kLATCPixelsPerBlock - 1; i >= 0; --i) { 1916c354881b63935626a0700366937530d38b8b1e8krajcevski 1926c354881b63935626a0700366937530d38b8b1e8krajcevski // Find the best palette index 1936c354881b63935626a0700366937530d38b8b1e8krajcevski uint8_t idx = 0; 1946c354881b63935626a0700366937530d38b8b1e8krajcevski if (is_extremal(pixels[i])) { 1956c354881b63935626a0700366937530d38b8b1e8krajcevski if (0xFF == pixels[i]) { 1966c354881b63935626a0700366937530d38b8b1e8krajcevski idx = 7; 1976c354881b63935626a0700366937530d38b8b1e8krajcevski } else if (0 == pixels[i]) { 1986c354881b63935626a0700366937530d38b8b1e8krajcevski idx = 6; 1996c354881b63935626a0700366937530d38b8b1e8krajcevski } else { 2006c354881b63935626a0700366937530d38b8b1e8krajcevski SkFAIL("Pixel is extremal but not really?!"); 2016c354881b63935626a0700366937530d38b8b1e8krajcevski } 2026c354881b63935626a0700366937530d38b8b1e8krajcevski } else { 2036c354881b63935626a0700366937530d38b8b1e8krajcevski uint8_t bestError = abs_diff(pixels[i], palette[0]); 2046c354881b63935626a0700366937530d38b8b1e8krajcevski for (int j = 1; j < kLATCPaletteSize - 2; ++j) { 2056c354881b63935626a0700366937530d38b8b1e8krajcevski uint8_t error = abs_diff(pixels[i], palette[j]); 2066c354881b63935626a0700366937530d38b8b1e8krajcevski if (error < bestError) { 2076c354881b63935626a0700366937530d38b8b1e8krajcevski bestError = error; 2086c354881b63935626a0700366937530d38b8b1e8krajcevski idx = j; 2096c354881b63935626a0700366937530d38b8b1e8krajcevski } 2106c354881b63935626a0700366937530d38b8b1e8krajcevski } 2116c354881b63935626a0700366937530d38b8b1e8krajcevski } 2126c354881b63935626a0700366937530d38b8b1e8krajcevski 2136c354881b63935626a0700366937530d38b8b1e8krajcevski indices <<= 3; 2146c354881b63935626a0700366937530d38b8b1e8krajcevski indices |= idx; 2156c354881b63935626a0700366937530d38b8b1e8krajcevski } 2166c354881b63935626a0700366937530d38b8b1e8krajcevski 2176c354881b63935626a0700366937530d38b8b1e8krajcevski return 2186c354881b63935626a0700366937530d38b8b1e8krajcevski SkEndian_SwapLE64( 2196c354881b63935626a0700366937530d38b8b1e8krajcevski static_cast<uint64_t>(minVal) | 2206c354881b63935626a0700366937530d38b8b1e8krajcevski (static_cast<uint64_t>(maxVal) << 8) | 2216c354881b63935626a0700366937530d38b8b1e8krajcevski (indices << 16)); 2226c354881b63935626a0700366937530d38b8b1e8krajcevski} 2236c354881b63935626a0700366937530d38b8b1e8krajcevski 2246c354881b63935626a0700366937530d38b8b1e8krajcevski 2256c354881b63935626a0700366937530d38b8b1e8krajcevski// Compress LATC block. Each 4x4 block of pixels is decompressed by LATC from two 2266c354881b63935626a0700366937530d38b8b1e8krajcevski// values LUM0 and LUM1, and an index into the generated palette. Details of how 2276c354881b63935626a0700366937530d38b8b1e8krajcevski// the palette is generated can be found in the comments of generatePalette above. 2286c354881b63935626a0700366937530d38b8b1e8krajcevski// 2296c354881b63935626a0700366937530d38b8b1e8krajcevski// We choose which palette type to use based on whether or not 'pixels' contains 2306c354881b63935626a0700366937530d38b8b1e8krajcevski// any extremal values (0 or 255). If there are extremal values, then we use the 2316c354881b63935626a0700366937530d38b8b1e8krajcevski// palette that has the extremal values built in. Otherwise, we use the full bounding 2326c354881b63935626a0700366937530d38b8b1e8krajcevski// box. 2336c354881b63935626a0700366937530d38b8b1e8krajcevski 2346c354881b63935626a0700366937530d38b8b1e8krajcevskistatic uint64_t compress_latc_block(const uint8_t pixels[]) { 2356c354881b63935626a0700366937530d38b8b1e8krajcevski // Collect unique pixels 2366c354881b63935626a0700366937530d38b8b1e8krajcevski int nUniquePixels = 0; 2376c354881b63935626a0700366937530d38b8b1e8krajcevski uint8_t uniquePixels[kLATCPixelsPerBlock]; 2386c354881b63935626a0700366937530d38b8b1e8krajcevski for (int i = 0; i < kLATCPixelsPerBlock; ++i) { 2396c354881b63935626a0700366937530d38b8b1e8krajcevski bool foundPixel = false; 2406c354881b63935626a0700366937530d38b8b1e8krajcevski for (int j = 0; j < nUniquePixels; ++j) { 2416c354881b63935626a0700366937530d38b8b1e8krajcevski foundPixel = foundPixel || uniquePixels[j] == pixels[i]; 2426c354881b63935626a0700366937530d38b8b1e8krajcevski } 2436c354881b63935626a0700366937530d38b8b1e8krajcevski 2446c354881b63935626a0700366937530d38b8b1e8krajcevski if (!foundPixel) { 2456c354881b63935626a0700366937530d38b8b1e8krajcevski uniquePixels[nUniquePixels] = pixels[i]; 2466c354881b63935626a0700366937530d38b8b1e8krajcevski ++nUniquePixels; 2476c354881b63935626a0700366937530d38b8b1e8krajcevski } 2486c354881b63935626a0700366937530d38b8b1e8krajcevski } 2496c354881b63935626a0700366937530d38b8b1e8krajcevski 2506c354881b63935626a0700366937530d38b8b1e8krajcevski // If there's only one unique pixel, then our compression is easy. 2516c354881b63935626a0700366937530d38b8b1e8krajcevski if (1 == nUniquePixels) { 2526c354881b63935626a0700366937530d38b8b1e8krajcevski return SkEndian_SwapLE64(pixels[0] | (pixels[0] << 8)); 2536c354881b63935626a0700366937530d38b8b1e8krajcevski 2546c354881b63935626a0700366937530d38b8b1e8krajcevski // Similarly, if there are only two unique pixels, then our compression is 2556c354881b63935626a0700366937530d38b8b1e8krajcevski // easy again: place the pixels in the block header, and assign the indices 2566c354881b63935626a0700366937530d38b8b1e8krajcevski // with one or zero depending on which pixel they belong to. 2576c354881b63935626a0700366937530d38b8b1e8krajcevski } else if (2 == nUniquePixels) { 2586c354881b63935626a0700366937530d38b8b1e8krajcevski uint64_t outBlock = 0; 2596c354881b63935626a0700366937530d38b8b1e8krajcevski for (int i = kLATCPixelsPerBlock - 1; i >= 0; --i) { 2606c354881b63935626a0700366937530d38b8b1e8krajcevski int idx = 0; 2616c354881b63935626a0700366937530d38b8b1e8krajcevski if (pixels[i] == uniquePixels[1]) { 2626c354881b63935626a0700366937530d38b8b1e8krajcevski idx = 1; 2636c354881b63935626a0700366937530d38b8b1e8krajcevski } 2646c354881b63935626a0700366937530d38b8b1e8krajcevski 2656c354881b63935626a0700366937530d38b8b1e8krajcevski outBlock <<= 3; 2666c354881b63935626a0700366937530d38b8b1e8krajcevski outBlock |= idx; 2676c354881b63935626a0700366937530d38b8b1e8krajcevski } 2686c354881b63935626a0700366937530d38b8b1e8krajcevski outBlock <<= 16; 2696c354881b63935626a0700366937530d38b8b1e8krajcevski outBlock |= (uniquePixels[0] | (uniquePixels[1] << 8)); 2706c354881b63935626a0700366937530d38b8b1e8krajcevski return SkEndian_SwapLE64(outBlock); 2716c354881b63935626a0700366937530d38b8b1e8krajcevski } 2726c354881b63935626a0700366937530d38b8b1e8krajcevski 2736c354881b63935626a0700366937530d38b8b1e8krajcevski // Count non-maximal pixel values 2746c354881b63935626a0700366937530d38b8b1e8krajcevski int nonExtremalPixels = 0; 2756c354881b63935626a0700366937530d38b8b1e8krajcevski for (int i = 0; i < nUniquePixels; ++i) { 2766c354881b63935626a0700366937530d38b8b1e8krajcevski if (!is_extremal(uniquePixels[i])) { 2776c354881b63935626a0700366937530d38b8b1e8krajcevski ++nonExtremalPixels; 2786c354881b63935626a0700366937530d38b8b1e8krajcevski } 2796c354881b63935626a0700366937530d38b8b1e8krajcevski } 2806c354881b63935626a0700366937530d38b8b1e8krajcevski 2816c354881b63935626a0700366937530d38b8b1e8krajcevski // If all the pixels are nonmaximal then compute the palette using 2826c354881b63935626a0700366937530d38b8b1e8krajcevski // the bounding box of all the pixels. 2836c354881b63935626a0700366937530d38b8b1e8krajcevski if (nonExtremalPixels == nUniquePixels) { 2846c354881b63935626a0700366937530d38b8b1e8krajcevski // This is really just for correctness, in all of my tests we 2856c354881b63935626a0700366937530d38b8b1e8krajcevski // never take this step. We don't lose too much perf here because 2866c354881b63935626a0700366937530d38b8b1e8krajcevski // most of the processing in this function is worth it for the 2876c354881b63935626a0700366937530d38b8b1e8krajcevski // 1 == nUniquePixels optimization. 2886c354881b63935626a0700366937530d38b8b1e8krajcevski return compress_latc_block_bb(pixels); 2896c354881b63935626a0700366937530d38b8b1e8krajcevski } else { 2906c354881b63935626a0700366937530d38b8b1e8krajcevski return compress_latc_block_bb_ignore_extremal(pixels); 2916c354881b63935626a0700366937530d38b8b1e8krajcevski } 2926c354881b63935626a0700366937530d38b8b1e8krajcevski} 2936c354881b63935626a0700366937530d38b8b1e8krajcevski 294b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski#endif // COMPRESS_LATC_SLOW 295b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski 296b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski//////////////////////////////////////////////////////////////////////////////// 297b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski 298b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski#if COMPRESS_LATC_FAST 299b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski 300a10555a354cf294bde217044472d33c3161df249krajcevski// Take the top three bits of each index and pack them into the low 12 301b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski// bits of the integer. 302a10555a354cf294bde217044472d33c3161df249krajcevskistatic inline uint32_t pack_index(uint32_t x) { 303a10555a354cf294bde217044472d33c3161df249krajcevski // Pack it in... 304a10555a354cf294bde217044472d33c3161df249krajcevski#if defined (SK_CPU_BENDIAN) 305a10555a354cf294bde217044472d33c3161df249krajcevski return 306a10555a354cf294bde217044472d33c3161df249krajcevski (x >> 24) | 307a10555a354cf294bde217044472d33c3161df249krajcevski ((x >> 13) & 0x38) | 308a10555a354cf294bde217044472d33c3161df249krajcevski ((x >> 2) & 0x1C0) | 309a10555a354cf294bde217044472d33c3161df249krajcevski ((x << 9) & 0xE00); 310a10555a354cf294bde217044472d33c3161df249krajcevski#else 311a10555a354cf294bde217044472d33c3161df249krajcevski return 312a10555a354cf294bde217044472d33c3161df249krajcevski (x & 0x7) | 313a10555a354cf294bde217044472d33c3161df249krajcevski ((x >> 5) & 0x38) | 314a10555a354cf294bde217044472d33c3161df249krajcevski ((x >> 10) & 0x1C0) | 315a10555a354cf294bde217044472d33c3161df249krajcevski ((x >> 15) & 0xE00); 316a10555a354cf294bde217044472d33c3161df249krajcevski#endif 317a10555a354cf294bde217044472d33c3161df249krajcevski} 318a10555a354cf294bde217044472d33c3161df249krajcevski 319a10555a354cf294bde217044472d33c3161df249krajcevski// Converts each 8-bit byte in the integer into an LATC index, and then packs 320a10555a354cf294bde217044472d33c3161df249krajcevski// the indices into the low 12 bits of the integer. 321b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevskistatic inline uint32_t convert_index(uint32_t x) { 322b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski // Since the palette is 323b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski // 255, 0, 219, 182, 146, 109, 73, 36 324b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski // we need to map the high three bits of each byte in the integer 325b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski // from 326b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski // 0 1 2 3 4 5 6 7 327b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski // to 328b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski // 1 7 6 5 4 3 2 0 329b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski // 330b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski // This first operation takes the mapping from 331b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski // 0 1 2 3 4 5 6 7 --> 7 6 5 4 3 2 1 0 332b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski x = 0x07070707 - ((x >> 5) & 0x07070707); 333b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski 334b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski // mask is 1 if index is non-zero 335b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski const uint32_t mask = (x | (x >> 1) | (x >> 2)) & 0x01010101; 336b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski 337b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski // add mask: 338b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski // 7 6 5 4 3 2 1 0 --> 8 7 6 5 4 3 2 0 339b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski x = (x + mask); 340b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski 341b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski // Handle overflow: 342b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski // 8 7 6 5 4 3 2 0 --> 9 7 6 5 4 3 2 0 343b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski x |= (x >> 3) & 0x01010101; 344b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski 345b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski // Mask out high bits: 346b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski // 9 7 6 5 4 3 2 0 --> 1 7 6 5 4 3 2 0 347b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski x &= 0x07070707; 348a10555a354cf294bde217044472d33c3161df249krajcevski 349a10555a354cf294bde217044472d33c3161df249krajcevski return pack_index(x); 350b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski} 351b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski 352b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevskitypedef uint64_t (*PackIndicesProc)(const uint8_t* alpha, int rowBytes); 353b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevskitemplate<PackIndicesProc packIndicesProc> 354b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevskistatic void compress_a8_latc_block(uint8_t** dstPtr, const uint8_t* src, int rowBytes) { 355b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski *(reinterpret_cast<uint64_t*>(*dstPtr)) = 356b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski SkEndian_SwapLE64(0xFF | (packIndicesProc(src, rowBytes) << 16)); 357b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski *dstPtr += 8; 358b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski} 359b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski 360b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevskiinline uint64_t PackRowMajor(const uint8_t *indices, int rowBytes) { 361b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski uint64_t result = 0; 362b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski for (int i = 0; i < 4; ++i) { 363b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski const uint32_t idx = *(reinterpret_cast<const uint32_t*>(indices + i*rowBytes)); 364b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski result |= static_cast<uint64_t>(convert_index(idx)) << 12*i; 365b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski } 366b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski return result; 367b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski} 368b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski 369b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevskiinline uint64_t PackColumnMajor(const uint8_t *indices, int rowBytes) { 370b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski // !SPEED! Blarg, this is kind of annoying. SSE4 can make this 371b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski // a LOT faster. 372b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski uint8_t transposed[16]; 373b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski for (int i = 0; i < 4; ++i) { 374b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski for (int j = 0; j < 4; ++j) { 375b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski transposed[j*4+i] = indices[i*rowBytes + j]; 376b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski } 377b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski } 378b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski 379b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski return PackRowMajor(transposed, 4); 380b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski} 381b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski 382b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevskistatic bool compress_4x4_a8_latc(uint8_t* dst, const uint8_t* src, 383b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski int width, int height, int rowBytes) { 384b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski 385b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski if (width < 0 || ((width % 4) != 0) || height < 0 || ((height % 4) != 0)) { 386b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski return false; 387b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski } 388b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski 389b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski uint8_t** dstPtr = &dst; 390b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski for (int y = 0; y < height; y += 4) { 391b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski for (int x = 0; x < width; x += 4) { 392b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski compress_a8_latc_block<PackRowMajor>(dstPtr, src + y*rowBytes + x, rowBytes); 393b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski } 394b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski } 395b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski 396b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski return true; 397b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski} 398b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski 399b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevskivoid CompressA8LATCBlockVertical(uint8_t* dst, const uint8_t block[]) { 400b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski compress_a8_latc_block<PackColumnMajor>(&dst, block, 4); 401b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski} 402b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski 403b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski#endif // COMPRESS_LATC_FAST 404b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski 4054ad76e35111585f4da662d54943f23792dd1e0aekrajcevskivoid decompress_latc_block(uint8_t* dst, int dstRowBytes, const uint8_t* src) { 4064ad76e35111585f4da662d54943f23792dd1e0aekrajcevski uint64_t block = SkEndian_SwapLE64(*(reinterpret_cast<const uint64_t *>(src))); 4074ad76e35111585f4da662d54943f23792dd1e0aekrajcevski uint8_t lum0 = block & 0xFF; 4084ad76e35111585f4da662d54943f23792dd1e0aekrajcevski uint8_t lum1 = (block >> 8) & 0xFF; 4094ad76e35111585f4da662d54943f23792dd1e0aekrajcevski 4104ad76e35111585f4da662d54943f23792dd1e0aekrajcevski uint8_t palette[kLATCPaletteSize]; 4114ad76e35111585f4da662d54943f23792dd1e0aekrajcevski generate_latc_palette(palette, lum0, lum1); 4124ad76e35111585f4da662d54943f23792dd1e0aekrajcevski 4134ad76e35111585f4da662d54943f23792dd1e0aekrajcevski block >>= 16; 4144ad76e35111585f4da662d54943f23792dd1e0aekrajcevski for (int j = 0; j < 4; ++j) { 4154ad76e35111585f4da662d54943f23792dd1e0aekrajcevski for (int i = 0; i < 4; ++i) { 4164ad76e35111585f4da662d54943f23792dd1e0aekrajcevski dst[i] = palette[block & 0x7]; 4174ad76e35111585f4da662d54943f23792dd1e0aekrajcevski block >>= 3; 4184ad76e35111585f4da662d54943f23792dd1e0aekrajcevski } 4194ad76e35111585f4da662d54943f23792dd1e0aekrajcevski dst += dstRowBytes; 4204ad76e35111585f4da662d54943f23792dd1e0aekrajcevski } 4214ad76e35111585f4da662d54943f23792dd1e0aekrajcevski} 4224ad76e35111585f4da662d54943f23792dd1e0aekrajcevski 42345a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski// This is the type passed as the CompressorType argument of the compressed 42445a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski// blitter for the LATC format. The static functions required to be in this 42545a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski// struct are documented in SkTextureCompressor_Blitter.h 42645a0bf505914adf0ee8c69e2647230618bbb3a63krajcevskistruct CompressorLATC { 42745a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski static inline void CompressA8Vertical(uint8_t* dst, const uint8_t block[]) { 42845a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski compress_a8_latc_block<PackColumnMajor>(&dst, block, 4); 42945a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski } 43045a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski 43145a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski static inline void CompressA8Horizontal(uint8_t* dst, const uint8_t* src, 43245a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski int srcRowBytes) { 43345a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski compress_a8_latc_block<PackRowMajor>(&dst, src, srcRowBytes); 43445a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski } 43545a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski 436a10555a354cf294bde217044472d33c3161df249krajcevski#if PEDANTIC_BLIT_RECT 437a10555a354cf294bde217044472d33c3161df249krajcevski static inline void UpdateBlock(uint8_t* dst, const uint8_t* src, int srcRowBytes, 438a10555a354cf294bde217044472d33c3161df249krajcevski const uint8_t* mask) { 439a10555a354cf294bde217044472d33c3161df249krajcevski // Pack the mask 440a10555a354cf294bde217044472d33c3161df249krajcevski uint64_t cmpMask = 0; 441a10555a354cf294bde217044472d33c3161df249krajcevski for (int i = 0; i < 4; ++i) { 442a10555a354cf294bde217044472d33c3161df249krajcevski const uint32_t idx = *(reinterpret_cast<const uint32_t*>(src + i*srcRowBytes)); 443a10555a354cf294bde217044472d33c3161df249krajcevski cmpMask |= static_cast<uint64_t>(pack_index(idx)) << 12*i; 444a10555a354cf294bde217044472d33c3161df249krajcevski } 445a10555a354cf294bde217044472d33c3161df249krajcevski cmpMask = SkEndian_SwapLE64(cmpMask << 16); // avoid header 446a10555a354cf294bde217044472d33c3161df249krajcevski 447a10555a354cf294bde217044472d33c3161df249krajcevski uint64_t cmpSrc; 448a10555a354cf294bde217044472d33c3161df249krajcevski uint8_t *cmpSrcPtr = reinterpret_cast<uint8_t*>(&cmpSrc); 449a10555a354cf294bde217044472d33c3161df249krajcevski compress_a8_latc_block<PackRowMajor>(&cmpSrcPtr, src, srcRowBytes); 450a10555a354cf294bde217044472d33c3161df249krajcevski 451a10555a354cf294bde217044472d33c3161df249krajcevski // Mask out header 452a10555a354cf294bde217044472d33c3161df249krajcevski cmpSrc = cmpSrc & cmpMask; 453a10555a354cf294bde217044472d33c3161df249krajcevski 454a10555a354cf294bde217044472d33c3161df249krajcevski // Read destination encoding 455a10555a354cf294bde217044472d33c3161df249krajcevski uint64_t *cmpDst = reinterpret_cast<uint64_t*>(dst); 456a10555a354cf294bde217044472d33c3161df249krajcevski 457a10555a354cf294bde217044472d33c3161df249krajcevski // If the destination is the encoding for a blank block, then we need 458a10555a354cf294bde217044472d33c3161df249krajcevski // to properly set the header 459a10555a354cf294bde217044472d33c3161df249krajcevski if (0 == cmpDst) { 460a10555a354cf294bde217044472d33c3161df249krajcevski *cmpDst = SkTEndian_SwapLE64(0x24924924924900FFULL); 461a10555a354cf294bde217044472d33c3161df249krajcevski } 462a10555a354cf294bde217044472d33c3161df249krajcevski 463a10555a354cf294bde217044472d33c3161df249krajcevski // Set the new indices 464a10555a354cf294bde217044472d33c3161df249krajcevski *cmpDst &= ~cmpMask; 465a10555a354cf294bde217044472d33c3161df249krajcevski *cmpDst |= cmpSrc; 46645a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski } 467a10555a354cf294bde217044472d33c3161df249krajcevski#endif // PEDANTIC_BLIT_RECT 46845a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski}; 46945a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski 4706c354881b63935626a0700366937530d38b8b1e8krajcevski//////////////////////////////////////////////////////////////////////////////// 4716c354881b63935626a0700366937530d38b8b1e8krajcevski 4726c354881b63935626a0700366937530d38b8b1e8krajcevskinamespace SkTextureCompressor { 4736c354881b63935626a0700366937530d38b8b1e8krajcevski 4746c354881b63935626a0700366937530d38b8b1e8krajcevskibool CompressA8ToLATC(uint8_t* dst, const uint8_t* src, int width, int height, int rowBytes) { 475b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski#if COMPRESS_LATC_FAST 476b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski return compress_4x4_a8_latc(dst, src, width, height, rowBytes); 477b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski#elif COMPRESS_LATC_SLOW 4786c354881b63935626a0700366937530d38b8b1e8krajcevski return compress_4x4_a8_to_64bit(dst, src, width, height, rowBytes, compress_latc_block); 479b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski#else 480b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski#error "Must choose either fast or slow LATC compression" 481b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski#endif 4826c354881b63935626a0700366937530d38b8b1e8krajcevski} 4836c354881b63935626a0700366937530d38b8b1e8krajcevski 484b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevskiSkBlitter* CreateLATCBlitter(int width, int height, void* outputBuffer, 485b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski SkTBlitterAllocator* allocator) { 486b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski if ((width % 4) != 0 || (height % 4) != 0) { 487b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski return NULL; 488b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski } 489b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski 490b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski#if COMPRESS_LATC_FAST 491b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski // Memset the output buffer to an encoding that decodes to zero. We must do this 492b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski // in order to avoid having uninitialized values in the buffer if the blitter 493b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski // decides not to write certain scanlines (and skip entire rows of blocks). 494b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski // In the case of LATC, if everything is zero, then LUM0 and LUM1 are also zero, 495b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski // and they will only be non-zero (0xFF) if the index is 7. So bzero will do just fine. 496b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski // (8 bytes per block) * (w * h / 16 blocks) = w * h / 2 497b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski sk_bzero(outputBuffer, width * height / 2); 498b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski 499b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski return allocator->createT< 50045a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski SkTCompressedAlphaBlitter<4, 8, CompressorLATC>, int, int, void* > 501b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski (width, height, outputBuffer); 502b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski#elif COMPRESS_LATC_SLOW 5036c354881b63935626a0700366937530d38b8b1e8krajcevski // TODO (krajcevski) 5046c354881b63935626a0700366937530d38b8b1e8krajcevski return NULL; 505b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski#endif 5066c354881b63935626a0700366937530d38b8b1e8krajcevski} 5076c354881b63935626a0700366937530d38b8b1e8krajcevski 5084ad76e35111585f4da662d54943f23792dd1e0aekrajcevskivoid DecompressLATC(uint8_t* dst, int dstRowBytes, const uint8_t* src, int width, int height) { 5094ad76e35111585f4da662d54943f23792dd1e0aekrajcevski for (int j = 0; j < height; j += 4) { 5104ad76e35111585f4da662d54943f23792dd1e0aekrajcevski for (int i = 0; i < width; i += 4) { 5114ad76e35111585f4da662d54943f23792dd1e0aekrajcevski decompress_latc_block(dst + i, dstRowBytes, src); 5124ad76e35111585f4da662d54943f23792dd1e0aekrajcevski src += 8; 5134ad76e35111585f4da662d54943f23792dd1e0aekrajcevski } 5144ad76e35111585f4da662d54943f23792dd1e0aekrajcevski dst += 4 * dstRowBytes; 5154ad76e35111585f4da662d54943f23792dd1e0aekrajcevski } 5164ad76e35111585f4da662d54943f23792dd1e0aekrajcevski} 5174ad76e35111585f4da662d54943f23792dd1e0aekrajcevski 5186c354881b63935626a0700366937530d38b8b1e8krajcevski} // SkTextureCompressor 519