1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2024 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/DataUtils.h"
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTextureCompressionType.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/GpuTypes.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMath.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTPin.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTemplates.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkMathPriv.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkCompressedDataUtils.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkMipmap.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTraceEvent.h"
20*c8dee2aaSAndroid Build Coastguard Worker
21*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
22*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
23*c8dee2aaSAndroid Build Coastguard Worker #include <cstring>
24*c8dee2aaSAndroid Build Coastguard Worker
25*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
26*c8dee2aaSAndroid Build Coastguard Worker
27*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu {
28*c8dee2aaSAndroid Build Coastguard Worker
29*c8dee2aaSAndroid Build Coastguard Worker struct ETC1Block {
30*c8dee2aaSAndroid Build Coastguard Worker uint32_t fHigh;
31*c8dee2aaSAndroid Build Coastguard Worker uint32_t fLow;
32*c8dee2aaSAndroid Build Coastguard Worker };
33*c8dee2aaSAndroid Build Coastguard Worker
34*c8dee2aaSAndroid Build Coastguard Worker constexpr uint32_t kDiffBit = 0x2; // set -> differential; not-set -> individual
35*c8dee2aaSAndroid Build Coastguard Worker
extend_5To8bits(int b)36*c8dee2aaSAndroid Build Coastguard Worker static inline int extend_5To8bits(int b) {
37*c8dee2aaSAndroid Build Coastguard Worker int c = b & 0x1f;
38*c8dee2aaSAndroid Build Coastguard Worker return (c << 3) | (c >> 2);
39*c8dee2aaSAndroid Build Coastguard Worker }
40*c8dee2aaSAndroid Build Coastguard Worker
41*c8dee2aaSAndroid Build Coastguard Worker static const int kNumETC1ModifierTables = 8;
42*c8dee2aaSAndroid Build Coastguard Worker static const int kNumETC1PixelIndices = 4;
43*c8dee2aaSAndroid Build Coastguard Worker
44*c8dee2aaSAndroid Build Coastguard Worker // The index of each row in this table is the ETC1 table codeword
45*c8dee2aaSAndroid Build Coastguard Worker // The index of each column in this table is the ETC1 pixel index value
46*c8dee2aaSAndroid Build Coastguard Worker static const int kETC1ModifierTables[kNumETC1ModifierTables][kNumETC1PixelIndices] = {
47*c8dee2aaSAndroid Build Coastguard Worker /* 0 */ { 2, 8, -2, -8 },
48*c8dee2aaSAndroid Build Coastguard Worker /* 1 */ { 5, 17, -5, -17 },
49*c8dee2aaSAndroid Build Coastguard Worker /* 2 */ { 9, 29, -9, -29 },
50*c8dee2aaSAndroid Build Coastguard Worker /* 3 */ { 13, 42, -13, -42 },
51*c8dee2aaSAndroid Build Coastguard Worker /* 4 */ { 18, 60, -18, -60 },
52*c8dee2aaSAndroid Build Coastguard Worker /* 5 */ { 24, 80, -24, -80 },
53*c8dee2aaSAndroid Build Coastguard Worker /* 6 */ { 33, 106, -33, -106 },
54*c8dee2aaSAndroid Build Coastguard Worker /* 7 */ { 47, 183, -47, -183 }
55*c8dee2aaSAndroid Build Coastguard Worker };
56*c8dee2aaSAndroid Build Coastguard Worker
57*c8dee2aaSAndroid Build Coastguard Worker // Evaluate one of the entries in 'kModifierTables' to see how close it can get (r8,g8,b8) to
58*c8dee2aaSAndroid Build Coastguard Worker // the original color (rOrig, gOrib, bOrig).
test_table_entry(int rOrig,int gOrig,int bOrig,int r8,int g8,int b8,int table,int offset)59*c8dee2aaSAndroid Build Coastguard Worker static int test_table_entry(int rOrig, int gOrig, int bOrig,
60*c8dee2aaSAndroid Build Coastguard Worker int r8, int g8, int b8,
61*c8dee2aaSAndroid Build Coastguard Worker int table, int offset) {
62*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(0 <= table && table < 8);
63*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(0 <= offset && offset < 4);
64*c8dee2aaSAndroid Build Coastguard Worker
65*c8dee2aaSAndroid Build Coastguard Worker r8 = SkTPin<int>(r8 + kETC1ModifierTables[table][offset], 0, 255);
66*c8dee2aaSAndroid Build Coastguard Worker g8 = SkTPin<int>(g8 + kETC1ModifierTables[table][offset], 0, 255);
67*c8dee2aaSAndroid Build Coastguard Worker b8 = SkTPin<int>(b8 + kETC1ModifierTables[table][offset], 0, 255);
68*c8dee2aaSAndroid Build Coastguard Worker
69*c8dee2aaSAndroid Build Coastguard Worker return SkTAbs(rOrig - r8) + SkTAbs(gOrig - g8) + SkTAbs(bOrig - b8);
70*c8dee2aaSAndroid Build Coastguard Worker }
71*c8dee2aaSAndroid Build Coastguard Worker
72*c8dee2aaSAndroid Build Coastguard Worker // Create an ETC1 compressed block that is filled with 'col'
create_etc1_block(SkColor col,ETC1Block * block)73*c8dee2aaSAndroid Build Coastguard Worker static void create_etc1_block(SkColor col, ETC1Block* block) {
74*c8dee2aaSAndroid Build Coastguard Worker uint32_t high = 0;
75*c8dee2aaSAndroid Build Coastguard Worker uint32_t low = 0;
76*c8dee2aaSAndroid Build Coastguard Worker
77*c8dee2aaSAndroid Build Coastguard Worker int rOrig = SkColorGetR(col);
78*c8dee2aaSAndroid Build Coastguard Worker int gOrig = SkColorGetG(col);
79*c8dee2aaSAndroid Build Coastguard Worker int bOrig = SkColorGetB(col);
80*c8dee2aaSAndroid Build Coastguard Worker
81*c8dee2aaSAndroid Build Coastguard Worker int r5 = SkMulDiv255Round(31, rOrig);
82*c8dee2aaSAndroid Build Coastguard Worker int g5 = SkMulDiv255Round(31, gOrig);
83*c8dee2aaSAndroid Build Coastguard Worker int b5 = SkMulDiv255Round(31, bOrig);
84*c8dee2aaSAndroid Build Coastguard Worker
85*c8dee2aaSAndroid Build Coastguard Worker int r8 = extend_5To8bits(r5);
86*c8dee2aaSAndroid Build Coastguard Worker int g8 = extend_5To8bits(g5);
87*c8dee2aaSAndroid Build Coastguard Worker int b8 = extend_5To8bits(b5);
88*c8dee2aaSAndroid Build Coastguard Worker
89*c8dee2aaSAndroid Build Coastguard Worker // We always encode solid color textures in differential mode (i.e., with a 555 base color) but
90*c8dee2aaSAndroid Build Coastguard Worker // with zero diffs (i.e., bits 26-24, 18-16 and 10-8 are left 0).
91*c8dee2aaSAndroid Build Coastguard Worker high |= (r5 << 27) | (g5 << 19) | (b5 << 11) | kDiffBit;
92*c8dee2aaSAndroid Build Coastguard Worker
93*c8dee2aaSAndroid Build Coastguard Worker int bestTableIndex = 0, bestPixelIndex = 0;
94*c8dee2aaSAndroid Build Coastguard Worker int bestSoFar = 1024;
95*c8dee2aaSAndroid Build Coastguard Worker for (int tableIndex = 0; tableIndex < kNumETC1ModifierTables; ++tableIndex) {
96*c8dee2aaSAndroid Build Coastguard Worker for (int pixelIndex = 0; pixelIndex < kNumETC1PixelIndices; ++pixelIndex) {
97*c8dee2aaSAndroid Build Coastguard Worker int score = test_table_entry(rOrig, gOrig, bOrig, r8, g8, b8,
98*c8dee2aaSAndroid Build Coastguard Worker tableIndex, pixelIndex);
99*c8dee2aaSAndroid Build Coastguard Worker
100*c8dee2aaSAndroid Build Coastguard Worker if (bestSoFar > score) {
101*c8dee2aaSAndroid Build Coastguard Worker bestSoFar = score;
102*c8dee2aaSAndroid Build Coastguard Worker bestTableIndex = tableIndex;
103*c8dee2aaSAndroid Build Coastguard Worker bestPixelIndex = pixelIndex;
104*c8dee2aaSAndroid Build Coastguard Worker }
105*c8dee2aaSAndroid Build Coastguard Worker }
106*c8dee2aaSAndroid Build Coastguard Worker }
107*c8dee2aaSAndroid Build Coastguard Worker
108*c8dee2aaSAndroid Build Coastguard Worker high |= (bestTableIndex << 5) | (bestTableIndex << 2);
109*c8dee2aaSAndroid Build Coastguard Worker
110*c8dee2aaSAndroid Build Coastguard Worker if (bestPixelIndex & 0x1) {
111*c8dee2aaSAndroid Build Coastguard Worker low |= 0xFFFF;
112*c8dee2aaSAndroid Build Coastguard Worker }
113*c8dee2aaSAndroid Build Coastguard Worker if (bestPixelIndex & 0x2) {
114*c8dee2aaSAndroid Build Coastguard Worker low |= 0xFFFF0000;
115*c8dee2aaSAndroid Build Coastguard Worker }
116*c8dee2aaSAndroid Build Coastguard Worker
117*c8dee2aaSAndroid Build Coastguard Worker block->fHigh = SkBSwap32(high);
118*c8dee2aaSAndroid Build Coastguard Worker block->fLow = SkBSwap32(low);
119*c8dee2aaSAndroid Build Coastguard Worker }
120*c8dee2aaSAndroid Build Coastguard Worker
num_4x4_blocks(int size)121*c8dee2aaSAndroid Build Coastguard Worker static int num_4x4_blocks(int size) {
122*c8dee2aaSAndroid Build Coastguard Worker return ((size + 3) & ~3) >> 2;
123*c8dee2aaSAndroid Build Coastguard Worker }
124*c8dee2aaSAndroid Build Coastguard Worker
num_ETC1_blocks(int w,int h)125*c8dee2aaSAndroid Build Coastguard Worker static int num_ETC1_blocks(int w, int h) {
126*c8dee2aaSAndroid Build Coastguard Worker w = num_4x4_blocks(w);
127*c8dee2aaSAndroid Build Coastguard Worker h = num_4x4_blocks(h);
128*c8dee2aaSAndroid Build Coastguard Worker
129*c8dee2aaSAndroid Build Coastguard Worker return w * h;
130*c8dee2aaSAndroid Build Coastguard Worker }
131*c8dee2aaSAndroid Build Coastguard Worker
132*c8dee2aaSAndroid Build Coastguard Worker struct BC1Block {
133*c8dee2aaSAndroid Build Coastguard Worker uint16_t fColor0;
134*c8dee2aaSAndroid Build Coastguard Worker uint16_t fColor1;
135*c8dee2aaSAndroid Build Coastguard Worker uint32_t fIndices;
136*c8dee2aaSAndroid Build Coastguard Worker };
137*c8dee2aaSAndroid Build Coastguard Worker
to565(SkColor col)138*c8dee2aaSAndroid Build Coastguard Worker static uint16_t to565(SkColor col) {
139*c8dee2aaSAndroid Build Coastguard Worker int r5 = SkMulDiv255Round(31, SkColorGetR(col));
140*c8dee2aaSAndroid Build Coastguard Worker int g6 = SkMulDiv255Round(63, SkColorGetG(col));
141*c8dee2aaSAndroid Build Coastguard Worker int b5 = SkMulDiv255Round(31, SkColorGetB(col));
142*c8dee2aaSAndroid Build Coastguard Worker
143*c8dee2aaSAndroid Build Coastguard Worker return (r5 << 11) | (g6 << 5) | b5;
144*c8dee2aaSAndroid Build Coastguard Worker }
145*c8dee2aaSAndroid Build Coastguard Worker
146*c8dee2aaSAndroid Build Coastguard Worker // Create a BC1 compressed block that has two colors but is initialized to 'col0'
create_BC1_block(SkColor col0,SkColor col1,BC1Block * block)147*c8dee2aaSAndroid Build Coastguard Worker static void create_BC1_block(SkColor col0, SkColor col1, BC1Block* block) {
148*c8dee2aaSAndroid Build Coastguard Worker block->fColor0 = to565(col0);
149*c8dee2aaSAndroid Build Coastguard Worker block->fColor1 = to565(col1);
150*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(block->fColor0 <= block->fColor1); // we always assume transparent blocks
151*c8dee2aaSAndroid Build Coastguard Worker
152*c8dee2aaSAndroid Build Coastguard Worker if (col0 == SK_ColorTRANSPARENT) {
153*c8dee2aaSAndroid Build Coastguard Worker // This sets all 16 pixels to just use color3 (under the assumption
154*c8dee2aaSAndroid Build Coastguard Worker // that this is a kBC1_RGBA8_UNORM texture. Note that in this case
155*c8dee2aaSAndroid Build Coastguard Worker // fColor0 will be opaque black.
156*c8dee2aaSAndroid Build Coastguard Worker block->fIndices = 0xFFFFFFFF;
157*c8dee2aaSAndroid Build Coastguard Worker } else {
158*c8dee2aaSAndroid Build Coastguard Worker // This sets all 16 pixels to just use 'fColor0'
159*c8dee2aaSAndroid Build Coastguard Worker block->fIndices = 0;
160*c8dee2aaSAndroid Build Coastguard Worker }
161*c8dee2aaSAndroid Build Coastguard Worker }
162*c8dee2aaSAndroid Build Coastguard Worker
NumCompressedBlocks(SkTextureCompressionType type,SkISize baseDimensions)163*c8dee2aaSAndroid Build Coastguard Worker size_t NumCompressedBlocks(SkTextureCompressionType type, SkISize baseDimensions) {
164*c8dee2aaSAndroid Build Coastguard Worker switch (type) {
165*c8dee2aaSAndroid Build Coastguard Worker case SkTextureCompressionType::kNone:
166*c8dee2aaSAndroid Build Coastguard Worker return baseDimensions.width() * baseDimensions.height();
167*c8dee2aaSAndroid Build Coastguard Worker case SkTextureCompressionType::kETC2_RGB8_UNORM:
168*c8dee2aaSAndroid Build Coastguard Worker case SkTextureCompressionType::kBC1_RGB8_UNORM:
169*c8dee2aaSAndroid Build Coastguard Worker case SkTextureCompressionType::kBC1_RGBA8_UNORM: {
170*c8dee2aaSAndroid Build Coastguard Worker int numBlocksWidth = num_4x4_blocks(baseDimensions.width());
171*c8dee2aaSAndroid Build Coastguard Worker int numBlocksHeight = num_4x4_blocks(baseDimensions.height());
172*c8dee2aaSAndroid Build Coastguard Worker
173*c8dee2aaSAndroid Build Coastguard Worker return numBlocksWidth * numBlocksHeight;
174*c8dee2aaSAndroid Build Coastguard Worker }
175*c8dee2aaSAndroid Build Coastguard Worker }
176*c8dee2aaSAndroid Build Coastguard Worker SkUNREACHABLE;
177*c8dee2aaSAndroid Build Coastguard Worker }
178*c8dee2aaSAndroid Build Coastguard Worker
CompressedRowBytes(SkTextureCompressionType type,int width)179*c8dee2aaSAndroid Build Coastguard Worker size_t CompressedRowBytes(SkTextureCompressionType type, int width) {
180*c8dee2aaSAndroid Build Coastguard Worker switch (type) {
181*c8dee2aaSAndroid Build Coastguard Worker case SkTextureCompressionType::kNone:
182*c8dee2aaSAndroid Build Coastguard Worker return 0;
183*c8dee2aaSAndroid Build Coastguard Worker case SkTextureCompressionType::kETC2_RGB8_UNORM:
184*c8dee2aaSAndroid Build Coastguard Worker case SkTextureCompressionType::kBC1_RGB8_UNORM:
185*c8dee2aaSAndroid Build Coastguard Worker case SkTextureCompressionType::kBC1_RGBA8_UNORM: {
186*c8dee2aaSAndroid Build Coastguard Worker int numBlocksWidth = num_4x4_blocks(width);
187*c8dee2aaSAndroid Build Coastguard Worker
188*c8dee2aaSAndroid Build Coastguard Worker static_assert(sizeof(ETC1Block) == sizeof(BC1Block));
189*c8dee2aaSAndroid Build Coastguard Worker return numBlocksWidth * sizeof(ETC1Block);
190*c8dee2aaSAndroid Build Coastguard Worker }
191*c8dee2aaSAndroid Build Coastguard Worker }
192*c8dee2aaSAndroid Build Coastguard Worker SkUNREACHABLE;
193*c8dee2aaSAndroid Build Coastguard Worker }
194*c8dee2aaSAndroid Build Coastguard Worker
CompressedDimensions(SkTextureCompressionType type,SkISize baseDimensions)195*c8dee2aaSAndroid Build Coastguard Worker SkISize CompressedDimensions(SkTextureCompressionType type, SkISize baseDimensions) {
196*c8dee2aaSAndroid Build Coastguard Worker switch (type) {
197*c8dee2aaSAndroid Build Coastguard Worker case SkTextureCompressionType::kNone:
198*c8dee2aaSAndroid Build Coastguard Worker return baseDimensions;
199*c8dee2aaSAndroid Build Coastguard Worker case SkTextureCompressionType::kETC2_RGB8_UNORM:
200*c8dee2aaSAndroid Build Coastguard Worker case SkTextureCompressionType::kBC1_RGB8_UNORM:
201*c8dee2aaSAndroid Build Coastguard Worker case SkTextureCompressionType::kBC1_RGBA8_UNORM: {
202*c8dee2aaSAndroid Build Coastguard Worker SkISize blockDims = CompressedDimensionsInBlocks(type, baseDimensions);
203*c8dee2aaSAndroid Build Coastguard Worker // Each BC1_RGB8_UNORM and ETC1 block has 16 pixels
204*c8dee2aaSAndroid Build Coastguard Worker return { 4 * blockDims.fWidth, 4 * blockDims.fHeight };
205*c8dee2aaSAndroid Build Coastguard Worker }
206*c8dee2aaSAndroid Build Coastguard Worker }
207*c8dee2aaSAndroid Build Coastguard Worker SkUNREACHABLE;
208*c8dee2aaSAndroid Build Coastguard Worker }
209*c8dee2aaSAndroid Build Coastguard Worker
CompressedDimensionsInBlocks(SkTextureCompressionType type,SkISize baseDimensions)210*c8dee2aaSAndroid Build Coastguard Worker SkISize CompressedDimensionsInBlocks(SkTextureCompressionType type, SkISize baseDimensions) {
211*c8dee2aaSAndroid Build Coastguard Worker switch (type) {
212*c8dee2aaSAndroid Build Coastguard Worker case SkTextureCompressionType::kNone:
213*c8dee2aaSAndroid Build Coastguard Worker return baseDimensions;
214*c8dee2aaSAndroid Build Coastguard Worker case SkTextureCompressionType::kETC2_RGB8_UNORM:
215*c8dee2aaSAndroid Build Coastguard Worker case SkTextureCompressionType::kBC1_RGB8_UNORM:
216*c8dee2aaSAndroid Build Coastguard Worker case SkTextureCompressionType::kBC1_RGBA8_UNORM: {
217*c8dee2aaSAndroid Build Coastguard Worker int numBlocksWidth = num_4x4_blocks(baseDimensions.width());
218*c8dee2aaSAndroid Build Coastguard Worker int numBlocksHeight = num_4x4_blocks(baseDimensions.height());
219*c8dee2aaSAndroid Build Coastguard Worker
220*c8dee2aaSAndroid Build Coastguard Worker // Each BC1_RGB8_UNORM and ETC1 block has 16 pixels
221*c8dee2aaSAndroid Build Coastguard Worker return { numBlocksWidth, numBlocksHeight };
222*c8dee2aaSAndroid Build Coastguard Worker }
223*c8dee2aaSAndroid Build Coastguard Worker }
224*c8dee2aaSAndroid Build Coastguard Worker SkUNREACHABLE;
225*c8dee2aaSAndroid Build Coastguard Worker }
226*c8dee2aaSAndroid Build Coastguard Worker
227*c8dee2aaSAndroid Build Coastguard Worker // Fill in 'dest' with ETC1 blocks derived from 'colorf'
fillin_ETC1_with_color(SkISize dimensions,const SkColor4f & colorf,char * dest)228*c8dee2aaSAndroid Build Coastguard Worker static void fillin_ETC1_with_color(SkISize dimensions, const SkColor4f& colorf, char* dest) {
229*c8dee2aaSAndroid Build Coastguard Worker SkColor color = colorf.toSkColor();
230*c8dee2aaSAndroid Build Coastguard Worker
231*c8dee2aaSAndroid Build Coastguard Worker ETC1Block block;
232*c8dee2aaSAndroid Build Coastguard Worker create_etc1_block(color, &block);
233*c8dee2aaSAndroid Build Coastguard Worker
234*c8dee2aaSAndroid Build Coastguard Worker int numBlocks = num_ETC1_blocks(dimensions.width(), dimensions.height());
235*c8dee2aaSAndroid Build Coastguard Worker
236*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < numBlocks; ++i) {
237*c8dee2aaSAndroid Build Coastguard Worker memcpy(dest, &block, sizeof(ETC1Block));
238*c8dee2aaSAndroid Build Coastguard Worker dest += sizeof(ETC1Block);
239*c8dee2aaSAndroid Build Coastguard Worker }
240*c8dee2aaSAndroid Build Coastguard Worker }
241*c8dee2aaSAndroid Build Coastguard Worker
242*c8dee2aaSAndroid Build Coastguard Worker // Fill in 'dest' with BC1 blocks derived from 'colorf'
fillin_BC1_with_color(SkISize dimensions,const SkColor4f & colorf,char * dest)243*c8dee2aaSAndroid Build Coastguard Worker static void fillin_BC1_with_color(SkISize dimensions, const SkColor4f& colorf, char* dest) {
244*c8dee2aaSAndroid Build Coastguard Worker SkColor color = colorf.toSkColor();
245*c8dee2aaSAndroid Build Coastguard Worker
246*c8dee2aaSAndroid Build Coastguard Worker BC1Block block;
247*c8dee2aaSAndroid Build Coastguard Worker create_BC1_block(color, color, &block);
248*c8dee2aaSAndroid Build Coastguard Worker
249*c8dee2aaSAndroid Build Coastguard Worker int numBlocks = num_ETC1_blocks(dimensions.width(), dimensions.height());
250*c8dee2aaSAndroid Build Coastguard Worker
251*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < numBlocks; ++i) {
252*c8dee2aaSAndroid Build Coastguard Worker memcpy(dest, &block, sizeof(BC1Block));
253*c8dee2aaSAndroid Build Coastguard Worker dest += sizeof(BC1Block);
254*c8dee2aaSAndroid Build Coastguard Worker }
255*c8dee2aaSAndroid Build Coastguard Worker }
256*c8dee2aaSAndroid Build Coastguard Worker
FillInCompressedData(SkTextureCompressionType type,SkISize dimensions,skgpu::Mipmapped mipmapped,char * dstPixels,const SkColor4f & colorf)257*c8dee2aaSAndroid Build Coastguard Worker void FillInCompressedData(SkTextureCompressionType type,
258*c8dee2aaSAndroid Build Coastguard Worker SkISize dimensions,
259*c8dee2aaSAndroid Build Coastguard Worker skgpu::Mipmapped mipmapped,
260*c8dee2aaSAndroid Build Coastguard Worker char* dstPixels,
261*c8dee2aaSAndroid Build Coastguard Worker const SkColor4f& colorf) {
262*c8dee2aaSAndroid Build Coastguard Worker TRACE_EVENT0("skia.gpu", TRACE_FUNC);
263*c8dee2aaSAndroid Build Coastguard Worker
264*c8dee2aaSAndroid Build Coastguard Worker int numMipLevels = 1;
265*c8dee2aaSAndroid Build Coastguard Worker if (mipmapped == skgpu::Mipmapped::kYes) {
266*c8dee2aaSAndroid Build Coastguard Worker numMipLevels = SkMipmap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
267*c8dee2aaSAndroid Build Coastguard Worker }
268*c8dee2aaSAndroid Build Coastguard Worker
269*c8dee2aaSAndroid Build Coastguard Worker size_t offset = 0;
270*c8dee2aaSAndroid Build Coastguard Worker
271*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < numMipLevels; ++i) {
272*c8dee2aaSAndroid Build Coastguard Worker size_t levelSize = SkCompressedDataSize(type, dimensions, nullptr, false);
273*c8dee2aaSAndroid Build Coastguard Worker
274*c8dee2aaSAndroid Build Coastguard Worker if (SkTextureCompressionType::kETC2_RGB8_UNORM == type) {
275*c8dee2aaSAndroid Build Coastguard Worker fillin_ETC1_with_color(dimensions, colorf, &dstPixels[offset]);
276*c8dee2aaSAndroid Build Coastguard Worker } else {
277*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(type == SkTextureCompressionType::kBC1_RGB8_UNORM ||
278*c8dee2aaSAndroid Build Coastguard Worker type == SkTextureCompressionType::kBC1_RGBA8_UNORM);
279*c8dee2aaSAndroid Build Coastguard Worker fillin_BC1_with_color(dimensions, colorf, &dstPixels[offset]);
280*c8dee2aaSAndroid Build Coastguard Worker }
281*c8dee2aaSAndroid Build Coastguard Worker
282*c8dee2aaSAndroid Build Coastguard Worker offset += levelSize;
283*c8dee2aaSAndroid Build Coastguard Worker dimensions = {std::max(1, dimensions.width()/2), std::max(1, dimensions.height()/2)};
284*c8dee2aaSAndroid Build Coastguard Worker }
285*c8dee2aaSAndroid Build Coastguard Worker }
286*c8dee2aaSAndroid Build Coastguard Worker
287*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu
288