• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
compress_etc1_565(uint8_t * dst,const uint8_t * src,int width,int height,size_t rowBytes)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 
GetBlockDimensions(Format format,int * dimX,int * dimY,bool matchSpec)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 
GetCompressedDataSize(Format fmt,int width,int height)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 
CompressBufferToFormat(uint8_t * dst,const uint8_t * src,SkColorType srcColorType,int width,int height,size_t rowBytes,Format format)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 
CompressBitmapToFormat(const SkPixmap & pixmap,Format format)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 
CreateBlitterForFormat(int width,int height,void * compressedBuffer,SkTBlitterAllocator * allocator,Format format)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 
DecompressBufferFromFormat(uint8_t * dst,int dstRowBytes,const uint8_t * src,int width,int height,Format format)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