Home | History | Annotate | Download | only in utils
      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
     25 static bool compress_etc1_565(uint8_t* dst, const uint8_t* src,
     26                               int width, int height, int rowBytes) {
     27 #ifndef SK_IGNORE_ETC1_SUPPORT
     28     return 0 == etc1_encode_image(src, width, height, 2, rowBytes, dst);
     29 #else
     30     return false;
     31 #endif
     32 }
     33 
     34 ////////////////////////////////////////////////////////////////////////////////
     35 
     36 namespace SkTextureCompressor {
     37 
     38 void 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 
     75 int 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 
    122 bool CompressBufferToFormat(uint8_t* dst, const uint8_t* src, SkColorType srcColorType,
    123                             int width, int height, int 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 
    176 SkData* 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 
    195 SkBlitter* 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 
    214 bool 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