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