1 /* 2 * Copyright 2014 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkTextureCompressor.h" 9 #include "SkTextureCompressor_ASTC.h" 10 #include "SkTextureCompressor_LATC.h" 11 #include "SkTextureCompressor_R11EAC.h" 12 13 #include "SkBitmap.h" 14 #include "SkBitmapProcShader.h" 15 #include "SkData.h" 16 #include "SkEndian.h" 17 #include "SkOpts.h" 18 19 #ifndef SK_IGNORE_ETC1_SUPPORT 20 # include "etc1.h" 21 #endif 22 23 // Convert ETC1 functions to our function signatures 24 static bool compress_etc1_565(uint8_t* dst, const uint8_t* src, 25 int width, int height, size_t rowBytes) { 26 #ifndef SK_IGNORE_ETC1_SUPPORT 27 return 0 == etc1_encode_image(src, width, height, 2, SkToInt(rowBytes), dst); 28 #else 29 return false; 30 #endif 31 } 32 33 //////////////////////////////////////////////////////////////////////////////// 34 35 namespace SkTextureCompressor { 36 37 void GetBlockDimensions(Format format, int* dimX, int* dimY, bool matchSpec) { 38 if (nullptr == dimX || nullptr == dimY) { 39 return; 40 } 41 42 if (!matchSpec && SkOpts::fill_block_dimensions(format, dimX, dimY)) { 43 return; 44 } 45 46 // No specialized arguments, return the dimensions as they are in the spec. 47 static const struct FormatDimensions { 48 const int fBlockSizeX; 49 const int fBlockSizeY; 50 } kFormatDimensions[kFormatCnt] = { 51 { 4, 4 }, // kLATC_Format 52 { 4, 4 }, // kR11_EAC_Format 53 { 4, 4 }, // kETC1_Format 54 { 4, 4 }, // kASTC_4x4_Format 55 { 5, 4 }, // kASTC_5x4_Format 56 { 5, 5 }, // kASTC_5x5_Format 57 { 6, 5 }, // kASTC_6x5_Format 58 { 6, 6 }, // kASTC_6x6_Format 59 { 8, 5 }, // kASTC_8x5_Format 60 { 8, 6 }, // kASTC_8x6_Format 61 { 8, 8 }, // kASTC_8x8_Format 62 { 10, 5 }, // kASTC_10x5_Format 63 { 10, 6 }, // kASTC_10x6_Format 64 { 10, 8 }, // kASTC_10x8_Format 65 { 10, 10 }, // kASTC_10x10_Format 66 { 12, 10 }, // kASTC_12x10_Format 67 { 12, 12 }, // kASTC_12x12_Format 68 }; 69 70 *dimX = kFormatDimensions[format].fBlockSizeX; 71 *dimY = kFormatDimensions[format].fBlockSizeY; 72 } 73 74 int GetCompressedDataSize(Format fmt, int width, int height) { 75 int dimX, dimY; 76 GetBlockDimensions(fmt, &dimX, &dimY, true); 77 78 int encodedBlockSize = 0; 79 80 switch (fmt) { 81 // These formats are 64 bits per 4x4 block. 82 case kLATC_Format: 83 case kR11_EAC_Format: 84 case kETC1_Format: 85 encodedBlockSize = 8; 86 break; 87 88 // This format is 128 bits. 89 case kASTC_4x4_Format: 90 case kASTC_5x4_Format: 91 case kASTC_5x5_Format: 92 case kASTC_6x5_Format: 93 case kASTC_6x6_Format: 94 case kASTC_8x5_Format: 95 case kASTC_8x6_Format: 96 case kASTC_8x8_Format: 97 case kASTC_10x5_Format: 98 case kASTC_10x6_Format: 99 case kASTC_10x8_Format: 100 case kASTC_10x10_Format: 101 case kASTC_12x10_Format: 102 case kASTC_12x12_Format: 103 encodedBlockSize = 16; 104 break; 105 106 default: 107 SkFAIL("Unknown compressed format!"); 108 return -1; 109 } 110 111 if(((width % dimX) == 0) && ((height % dimY) == 0)) { 112 const int blocksX = width / dimX; 113 const int blocksY = height / dimY; 114 115 return blocksX * blocksY * encodedBlockSize; 116 } 117 118 return -1; 119 } 120 121 bool CompressBufferToFormat(uint8_t* dst, const uint8_t* src, SkColorType srcColorType, 122 int width, int height, size_t rowBytes, Format format) { 123 SkOpts::TextureCompressor proc = SkOpts::texture_compressor(srcColorType, format); 124 if (proc && proc(dst, src, width, height, rowBytes)) { 125 return true; 126 } 127 128 switch (srcColorType) { 129 case kAlpha_8_SkColorType: 130 if (format == kLATC_Format) { proc = CompressA8ToLATC; } 131 if (format == kR11_EAC_Format) { proc = CompressA8ToR11EAC; } 132 if (format == kASTC_12x12_Format) { proc = CompressA8To12x12ASTC; } 133 break; 134 case kRGB_565_SkColorType: 135 if (format == kETC1_Format) { proc = compress_etc1_565; } 136 break; 137 default: 138 break; 139 } 140 if (proc && proc(dst, src, width, height, rowBytes)) { 141 return true; 142 } 143 144 return false; 145 } 146 147 SkData* CompressBitmapToFormat(const SkPixmap& pixmap, Format format) { 148 int compressedDataSize = GetCompressedDataSize(format, pixmap.width(), pixmap.height()); 149 if (compressedDataSize < 0) { 150 return nullptr; 151 } 152 153 const uint8_t* src = reinterpret_cast<const uint8_t*>(pixmap.addr()); 154 SkData* dst = SkData::NewUninitialized(compressedDataSize); 155 156 if (!CompressBufferToFormat((uint8_t*)dst->writable_data(), src, pixmap.colorType(), 157 pixmap.width(), pixmap.height(), pixmap.rowBytes(), format)) { 158 dst->unref(); 159 dst = nullptr; 160 } 161 return dst; 162 } 163 164 SkBlitter* CreateBlitterForFormat(int width, int height, void* compressedBuffer, 165 SkTBlitterAllocator *allocator, Format format) { 166 switch(format) { 167 case kLATC_Format: 168 return CreateLATCBlitter(width, height, compressedBuffer, allocator); 169 170 case kR11_EAC_Format: 171 return CreateR11EACBlitter(width, height, compressedBuffer, allocator); 172 173 case kASTC_12x12_Format: 174 return CreateASTCBlitter(width, height, compressedBuffer, allocator); 175 176 default: 177 return nullptr; 178 } 179 180 return nullptr; 181 } 182 183 bool DecompressBufferFromFormat(uint8_t* dst, int dstRowBytes, const uint8_t* src, 184 int width, int height, Format format) { 185 int dimX, dimY; 186 GetBlockDimensions(format, &dimX, &dimY, true); 187 188 if (width < 0 || ((width % dimX) != 0) || height < 0 || ((height % dimY) != 0)) { 189 return false; 190 } 191 192 switch(format) { 193 case kLATC_Format: 194 DecompressLATC(dst, dstRowBytes, src, width, height); 195 return true; 196 197 case kR11_EAC_Format: 198 DecompressR11EAC(dst, dstRowBytes, src, width, height); 199 return true; 200 201 #ifndef SK_IGNORE_ETC1_SUPPORT 202 case kETC1_Format: 203 return 0 == etc1_decode_image(src, dst, width, height, 3, dstRowBytes); 204 #endif 205 206 case kASTC_4x4_Format: 207 case kASTC_5x4_Format: 208 case kASTC_5x5_Format: 209 case kASTC_6x5_Format: 210 case kASTC_6x6_Format: 211 case kASTC_8x5_Format: 212 case kASTC_8x6_Format: 213 case kASTC_8x8_Format: 214 case kASTC_10x5_Format: 215 case kASTC_10x6_Format: 216 case kASTC_10x8_Format: 217 case kASTC_10x10_Format: 218 case kASTC_12x10_Format: 219 case kASTC_12x12_Format: 220 DecompressASTC(dst, dstRowBytes, src, width, height, dimX, dimY); 221 return true; 222 223 default: 224 // Do nothing... 225 break; 226 } 227 228 return false; 229 } 230 231 } // namespace SkTextureCompressor 232