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 #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