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