blob: e9e4d2e826c1167c274a64246a8ac33a20621bfa [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"
halcanary4dbbd042016-06-07 17:21:10 -070017#include "SkMathPriv.h"
mtkleinb6394742015-08-06 08:17:16 -070018#include "SkOpts.h"
krajcevski630598c2014-07-14 12:00:04 -070019
krajcevskie90c9002014-08-05 07:37:26 -070020#ifndef SK_IGNORE_ETC1_SUPPORT
21# include "etc1.h"
22#endif
23
24// Convert ETC1 functions to our function signatures
25static bool compress_etc1_565(uint8_t* dst, const uint8_t* src,
bsalomon98806072014-12-12 15:11:17 -080026 int width, int height, size_t rowBytes) {
krajcevskie90c9002014-08-05 07:37:26 -070027#ifndef SK_IGNORE_ETC1_SUPPORT
bsalomon98806072014-12-12 15:11:17 -080028 return 0 == etc1_encode_image(src, width, height, 2, SkToInt(rowBytes), dst);
krajcevskie90c9002014-08-05 07:37:26 -070029#else
30 return false;
31#endif
32}
33
krajcevskiae614402014-06-10 14:52:28 -070034////////////////////////////////////////////////////////////////////////////////
krajcevskiae614402014-06-10 14:52:28 -070035
36namespace SkTextureCompressor {
37
krajcevski4ad76e32014-07-31 14:12:50 -070038void GetBlockDimensions(Format format, int* dimX, int* dimY, bool matchSpec) {
halcanary96fcdcc2015-08-27 07:41:13 -070039 if (nullptr == dimX || nullptr == dimY) {
krajcevski25a67bc2014-07-29 11:44:26 -070040 return;
41 }
42
mtkleinb6394742015-08-06 08:17:16 -070043 if (!matchSpec && SkOpts::fill_block_dimensions(format, dimX, dimY)) {
krajcevski25a67bc2014-07-29 11:44:26 -070044 return;
45 }
46
krajcevski4ad76e32014-07-31 14:12:50 -070047 // No specialized arguments, return the dimensions as they are in the spec.
krajcevski95b1b3d2014-08-07 12:58:38 -070048 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 };
krajcevski25a67bc2014-07-29 11:44:26 -070070
krajcevski95b1b3d2014-08-07 12:58:38 -070071 *dimX = kFormatDimensions[format].fBlockSizeX;
72 *dimY = kFormatDimensions[format].fBlockSizeY;
krajcevski25a67bc2014-07-29 11:44:26 -070073}
74
krajcevski6c354882014-07-22 07:44:00 -070075int GetCompressedDataSize(Format fmt, int width, int height) {
krajcevski25a67bc2014-07-29 11:44:26 -070076 int dimX, dimY;
krajcevski4ad76e32014-07-31 14:12:50 -070077 GetBlockDimensions(fmt, &dimX, &dimY, true);
78
krajcevskib2ef1812014-07-25 07:33:01 -070079 int encodedBlockSize = 0;
mtkleinb6394742015-08-06 08:17:16 -070080
krajcevskieecc35f2014-06-20 11:43:00 -070081 switch (fmt) {
krajcevski1459be52014-07-09 09:15:45 -070082 // These formats are 64 bits per 4x4 block.
krajcevski50495572014-08-04 09:47:31 -070083 case kLATC_Format:
krajcevskie90c9002014-08-05 07:37:26 -070084 case kR11_EAC_Format:
85 case kETC1_Format:
krajcevskib2ef1812014-07-25 07:33:01 -070086 encodedBlockSize = 8;
87 break;
krajcevskieecc35f2014-06-20 11:43:00 -070088
krajcevski95b1b3d2014-08-07 12:58:38 -070089 // 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:
krajcevskib2ef1812014-07-25 07:33:01 -0700103 case kASTC_12x12_Format:
krajcevskib2ef1812014-07-25 07:33:01 -0700104 encodedBlockSize = 16;
105 break;
krajcevskieecc35f2014-06-20 11:43:00 -0700106
107 default:
108 SkFAIL("Unknown compressed format!");
krajcevski6c354882014-07-22 07:44:00 -0700109 return -1;
krajcevskieecc35f2014-06-20 11:43:00 -0700110 }
krajcevskib2ef1812014-07-25 07:33:01 -0700111
krajcevski25a67bc2014-07-29 11:44:26 -0700112 if(((width % dimX) == 0) && ((height % dimY) == 0)) {
113 const int blocksX = width / dimX;
114 const int blocksY = height / dimY;
krajcevskib2ef1812014-07-25 07:33:01 -0700115
116 return blocksX * blocksY * encodedBlockSize;
117 }
118
119 return -1;
krajcevskieecc35f2014-06-20 11:43:00 -0700120}
121
krajcevskieecc35f2014-06-20 11:43:00 -0700122bool CompressBufferToFormat(uint8_t* dst, const uint8_t* src, SkColorType srcColorType,
mtkleinb6394742015-08-06 08:17:16 -0700123 int width, int height, size_t rowBytes, Format format) {
124 SkOpts::TextureCompressor proc = SkOpts::texture_compressor(srcColorType, format);
125 if (proc && proc(dst, src, width, height, rowBytes)) {
126 return true;
krajcevski630598c2014-07-14 12:00:04 -0700127 }
krajcevskieecc35f2014-06-20 11:43:00 -0700128
mtkleinb6394742015-08-06 08:17:16 -0700129 switch (srcColorType) {
130 case kAlpha_8_SkColorType:
131 if (format == kLATC_Format) { proc = CompressA8ToLATC; }
132 if (format == kR11_EAC_Format) { proc = CompressA8ToR11EAC; }
133 if (format == kASTC_12x12_Format) { proc = CompressA8To12x12ASTC; }
krajcevski630598c2014-07-14 12:00:04 -0700134 break;
mtkleinb6394742015-08-06 08:17:16 -0700135 case kRGB_565_SkColorType:
136 if (format == kETC1_Format) { proc = compress_etc1_565; }
krajcevskie90c9002014-08-05 07:37:26 -0700137 break;
mtkleinb6394742015-08-06 08:17:16 -0700138 default:
139 break;
krajcevski630598c2014-07-14 12:00:04 -0700140 }
mtkleinb6394742015-08-06 08:17:16 -0700141 if (proc && proc(dst, src, width, height, rowBytes)) {
142 return true;
krajcevskieecc35f2014-06-20 11:43:00 -0700143 }
144
145 return false;
146}
krajcevskiae614402014-06-10 14:52:28 -0700147
bungeman38d909e2016-08-02 14:40:46 -0700148sk_sp<SkData> CompressBitmapToFormat(const SkPixmap& pixmap, Format format) {
reed41e010c2015-06-09 12:16:53 -0700149 int compressedDataSize = GetCompressedDataSize(format, pixmap.width(), pixmap.height());
krajcevski6c354882014-07-22 07:44:00 -0700150 if (compressedDataSize < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -0700151 return nullptr;
krajcevski6c354882014-07-22 07:44:00 -0700152 }
153
reed41e010c2015-06-09 12:16:53 -0700154 const uint8_t* src = reinterpret_cast<const uint8_t*>(pixmap.addr());
bungeman38d909e2016-08-02 14:40:46 -0700155 sk_sp<SkData> dst(SkData::MakeUninitialized(compressedDataSize));
krajcevski6c354882014-07-22 07:44:00 -0700156
reed41e010c2015-06-09 12:16:53 -0700157 if (!CompressBufferToFormat((uint8_t*)dst->writable_data(), src, pixmap.colorType(),
158 pixmap.width(), pixmap.height(), pixmap.rowBytes(), format)) {
bungeman38d909e2016-08-02 14:40:46 -0700159 return 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