blob: e308f6e480caa48027c338ccd575ded9b7169e41 [file] [log] [blame]
krajcevskiae614402014-06-10 14:52:28 -07001/*
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"
krajcevskib2ef1812014-07-25 07:33:01 -07009#include "SkTextureCompressor_ASTC.h"
krajcevski6c354882014-07-22 07:44:00 -070010#include "SkTextureCompressor_LATC.h"
krajcevskib2ef1812014-07-25 07:33:01 -070011#include "SkTextureCompressor_R11EAC.h"
krajcevskiae614402014-06-10 14:52:28 -070012
13#include "SkBitmap.h"
krajcevskib8ccc2f2014-08-07 08:15:14 -070014#include "SkBitmapProcShader.h"
krajcevskiae614402014-06-10 14:52:28 -070015#include "SkData.h"
16#include "SkEndian.h"
mtkleinb6394742015-08-06 08:17:16 -070017#include "SkOpts.h"
krajcevski630598c2014-07-14 12:00:04 -070018
krajcevskie90c9002014-08-05 07:37:26 -070019#ifndef SK_IGNORE_ETC1_SUPPORT
20# include "etc1.h"
21#endif
22
23// Convert ETC1 functions to our function signatures
24static bool compress_etc1_565(uint8_t* dst, const uint8_t* src,
bsalomon98806072014-12-12 15:11:17 -080025 int width, int height, size_t rowBytes) {
krajcevskie90c9002014-08-05 07:37:26 -070026#ifndef SK_IGNORE_ETC1_SUPPORT
bsalomon98806072014-12-12 15:11:17 -080027 return 0 == etc1_encode_image(src, width, height, 2, SkToInt(rowBytes), dst);
krajcevskie90c9002014-08-05 07:37:26 -070028#else
29 return false;
30#endif
31}
32
krajcevskiae614402014-06-10 14:52:28 -070033////////////////////////////////////////////////////////////////////////////////
krajcevskiae614402014-06-10 14:52:28 -070034
35namespace SkTextureCompressor {
36
krajcevski4ad76e32014-07-31 14:12:50 -070037void GetBlockDimensions(Format format, int* dimX, int* dimY, bool matchSpec) {
halcanary96fcdcc2015-08-27 07:41:13 -070038 if (nullptr == dimX || nullptr == dimY) {
krajcevski25a67bc2014-07-29 11:44:26 -070039 return;
40 }
41
mtkleinb6394742015-08-06 08:17:16 -070042 if (!matchSpec && SkOpts::fill_block_dimensions(format, dimX, dimY)) {
krajcevski25a67bc2014-07-29 11:44:26 -070043 return;
44 }
45
krajcevski4ad76e32014-07-31 14:12:50 -070046 // No specialized arguments, return the dimensions as they are in the spec.
krajcevski95b1b3d2014-08-07 12:58:38 -070047 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 };
krajcevski25a67bc2014-07-29 11:44:26 -070069
krajcevski95b1b3d2014-08-07 12:58:38 -070070 *dimX = kFormatDimensions[format].fBlockSizeX;
71 *dimY = kFormatDimensions[format].fBlockSizeY;
krajcevski25a67bc2014-07-29 11:44:26 -070072}
73
krajcevski6c354882014-07-22 07:44:00 -070074int GetCompressedDataSize(Format fmt, int width, int height) {
krajcevski25a67bc2014-07-29 11:44:26 -070075 int dimX, dimY;
krajcevski4ad76e32014-07-31 14:12:50 -070076 GetBlockDimensions(fmt, &dimX, &dimY, true);
77
krajcevskib2ef1812014-07-25 07:33:01 -070078 int encodedBlockSize = 0;
mtkleinb6394742015-08-06 08:17:16 -070079
krajcevskieecc35f2014-06-20 11:43:00 -070080 switch (fmt) {
krajcevski1459be52014-07-09 09:15:45 -070081 // These formats are 64 bits per 4x4 block.
krajcevski50495572014-08-04 09:47:31 -070082 case kLATC_Format:
krajcevskie90c9002014-08-05 07:37:26 -070083 case kR11_EAC_Format:
84 case kETC1_Format:
krajcevskib2ef1812014-07-25 07:33:01 -070085 encodedBlockSize = 8;
86 break;
krajcevskieecc35f2014-06-20 11:43:00 -070087
krajcevski95b1b3d2014-08-07 12:58:38 -070088 // 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:
krajcevskib2ef1812014-07-25 07:33:01 -0700102 case kASTC_12x12_Format:
krajcevskib2ef1812014-07-25 07:33:01 -0700103 encodedBlockSize = 16;
104 break;
krajcevskieecc35f2014-06-20 11:43:00 -0700105
106 default:
107 SkFAIL("Unknown compressed format!");
krajcevski6c354882014-07-22 07:44:00 -0700108 return -1;
krajcevskieecc35f2014-06-20 11:43:00 -0700109 }
krajcevskib2ef1812014-07-25 07:33:01 -0700110
krajcevski25a67bc2014-07-29 11:44:26 -0700111 if(((width % dimX) == 0) && ((height % dimY) == 0)) {
112 const int blocksX = width / dimX;
113 const int blocksY = height / dimY;
krajcevskib2ef1812014-07-25 07:33:01 -0700114
115 return blocksX * blocksY * encodedBlockSize;
116 }
117
118 return -1;
krajcevskieecc35f2014-06-20 11:43:00 -0700119}
120
krajcevskieecc35f2014-06-20 11:43:00 -0700121bool CompressBufferToFormat(uint8_t* dst, const uint8_t* src, SkColorType srcColorType,
mtkleinb6394742015-08-06 08:17:16 -0700122 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;
krajcevski630598c2014-07-14 12:00:04 -0700126 }
krajcevskieecc35f2014-06-20 11:43:00 -0700127
mtkleinb6394742015-08-06 08:17:16 -0700128 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; }
krajcevski630598c2014-07-14 12:00:04 -0700133 break;
mtkleinb6394742015-08-06 08:17:16 -0700134 case kRGB_565_SkColorType:
135 if (format == kETC1_Format) { proc = compress_etc1_565; }
krajcevskie90c9002014-08-05 07:37:26 -0700136 break;
mtkleinb6394742015-08-06 08:17:16 -0700137 default:
138 break;
krajcevski630598c2014-07-14 12:00:04 -0700139 }
mtkleinb6394742015-08-06 08:17:16 -0700140 if (proc && proc(dst, src, width, height, rowBytes)) {
141 return true;
krajcevskieecc35f2014-06-20 11:43:00 -0700142 }
143
144 return false;
145}
krajcevskiae614402014-06-10 14:52:28 -0700146
reed41e010c2015-06-09 12:16:53 -0700147SkData* CompressBitmapToFormat(const SkPixmap& pixmap, Format format) {
148 int compressedDataSize = GetCompressedDataSize(format, pixmap.width(), pixmap.height());
krajcevski6c354882014-07-22 07:44:00 -0700149 if (compressedDataSize < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -0700150 return nullptr;
krajcevski6c354882014-07-22 07:44:00 -0700151 }
152
reed41e010c2015-06-09 12:16:53 -0700153 const uint8_t* src = reinterpret_cast<const uint8_t*>(pixmap.addr());
reed33a30502014-09-11 08:42:36 -0700154 SkData* dst = SkData::NewUninitialized(compressedDataSize);
krajcevski6c354882014-07-22 07:44:00 -0700155
reed41e010c2015-06-09 12:16:53 -0700156 if (!CompressBufferToFormat((uint8_t*)dst->writable_data(), src, pixmap.colorType(),
157 pixmap.width(), pixmap.height(), pixmap.rowBytes(), format)) {
reed33a30502014-09-11 08:42:36 -0700158 dst->unref();
halcanary96fcdcc2015-08-27 07:41:13 -0700159 dst = nullptr;
krajcevskiae614402014-06-10 14:52:28 -0700160 }
reed33a30502014-09-11 08:42:36 -0700161 return dst;
krajcevskiae614402014-06-10 14:52:28 -0700162}
163
krajcevskib8ccc2f2014-08-07 08:15:14 -0700164SkBlitter* CreateBlitterForFormat(int width, int height, void* compressedBuffer,
165 SkTBlitterAllocator *allocator, Format format) {
krajcevski6c354882014-07-22 07:44:00 -0700166 switch(format) {
167 case kLATC_Format:
krajcevskib8ccc2f2014-08-07 08:15:14 -0700168 return CreateLATCBlitter(width, height, compressedBuffer, allocator);
krajcevskiad1df152014-07-21 11:44:37 -0700169
krajcevski6c354882014-07-22 07:44:00 -0700170 case kR11_EAC_Format:
krajcevskib8ccc2f2014-08-07 08:15:14 -0700171 return CreateR11EACBlitter(width, height, compressedBuffer, allocator);
krajcevski6c354882014-07-22 07:44:00 -0700172
krajcevski10a350c2014-07-29 07:24:58 -0700173 case kASTC_12x12_Format:
krajcevskib8ccc2f2014-08-07 08:15:14 -0700174 return CreateASTCBlitter(width, height, compressedBuffer, allocator);
krajcevski10a350c2014-07-29 07:24:58 -0700175
krajcevski6c354882014-07-22 07:44:00 -0700176 default:
halcanary96fcdcc2015-08-27 07:41:13 -0700177 return nullptr;
krajcevskiad1df152014-07-21 11:44:37 -0700178 }
179
halcanary96fcdcc2015-08-27 07:41:13 -0700180 return nullptr;
krajcevskiad1df152014-07-21 11:44:37 -0700181}
182
krajcevski4ad76e32014-07-31 14:12:50 -0700183bool 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
krajcevskie90c9002014-08-05 07:37:26 -0700201#ifndef SK_IGNORE_ETC1_SUPPORT
202 case kETC1_Format:
203 return 0 == etc1_decode_image(src, dst, width, height, 3, dstRowBytes);
204#endif
krajcevski95b1b3d2014-08-07 12:58:38 -0700205
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:
krajcevski4ad76e32014-07-31 14:12:50 -0700219 case kASTC_12x12_Format:
krajcevski95b1b3d2014-08-07 12:58:38 -0700220 DecompressASTC(dst, dstRowBytes, src, width, height, dimX, dimY);
221 return true;
krajcevskie90c9002014-08-05 07:37:26 -0700222
223 default:
224 // Do nothing...
225 break;
krajcevski4ad76e32014-07-31 14:12:50 -0700226 }
227
228 return false;
229}
230
krajcevskiae614402014-06-10 14:52:28 -0700231} // namespace SkTextureCompressor