Flutter Engine
The Flutter Engine
DataUtils.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2024 Google LLC
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 "src/gpu/DataUtils.h"
9
16#include "src/base/SkMathPriv.h"
18#include "src/core/SkMipmap.h"
20
21#include <algorithm>
22#include <cstdint>
23#include <cstring>
24
25using namespace skia_private;
26
27namespace skgpu {
28
29struct ETC1Block {
30 uint32_t fHigh;
31 uint32_t fLow;
32};
33
34constexpr uint32_t kDiffBit = 0x2; // set -> differential; not-set -> individual
35
36static inline int extend_5To8bits(int b) {
37 int c = b & 0x1f;
38 return (c << 3) | (c >> 2);
39}
40
41static const int kNumETC1ModifierTables = 8;
42static const int kNumETC1PixelIndices = 4;
43
44// The index of each row in this table is the ETC1 table codeword
45// The index of each column in this table is the ETC1 pixel index value
47 /* 0 */ { 2, 8, -2, -8 },
48 /* 1 */ { 5, 17, -5, -17 },
49 /* 2 */ { 9, 29, -9, -29 },
50 /* 3 */ { 13, 42, -13, -42 },
51 /* 4 */ { 18, 60, -18, -60 },
52 /* 5 */ { 24, 80, -24, -80 },
53 /* 6 */ { 33, 106, -33, -106 },
54 /* 7 */ { 47, 183, -47, -183 }
55};
56
57// Evaluate one of the entries in 'kModifierTables' to see how close it can get (r8,g8,b8) to
58// the original color (rOrig, gOrib, bOrig).
59static int test_table_entry(int rOrig, int gOrig, int bOrig,
60 int r8, int g8, int b8,
61 int table, int offset) {
62 SkASSERT(0 <= table && table < 8);
63 SkASSERT(0 <= offset && offset < 4);
64
65 r8 = SkTPin<int>(r8 + kETC1ModifierTables[table][offset], 0, 255);
66 g8 = SkTPin<int>(g8 + kETC1ModifierTables[table][offset], 0, 255);
67 b8 = SkTPin<int>(b8 + kETC1ModifierTables[table][offset], 0, 255);
68
69 return SkTAbs(rOrig - r8) + SkTAbs(gOrig - g8) + SkTAbs(bOrig - b8);
70}
71
72// Create an ETC1 compressed block that is filled with 'col'
73static void create_etc1_block(SkColor col, ETC1Block* block) {
74 uint32_t high = 0;
75 uint32_t low = 0;
76
77 int rOrig = SkColorGetR(col);
78 int gOrig = SkColorGetG(col);
79 int bOrig = SkColorGetB(col);
80
81 int r5 = SkMulDiv255Round(31, rOrig);
82 int g5 = SkMulDiv255Round(31, gOrig);
83 int b5 = SkMulDiv255Round(31, bOrig);
84
85 int r8 = extend_5To8bits(r5);
86 int g8 = extend_5To8bits(g5);
87 int b8 = extend_5To8bits(b5);
88
89 // We always encode solid color textures in differential mode (i.e., with a 555 base color) but
90 // with zero diffs (i.e., bits 26-24, 18-16 and 10-8 are left 0).
91 high |= (r5 << 27) | (g5 << 19) | (b5 << 11) | kDiffBit;
92
93 int bestTableIndex = 0, bestPixelIndex = 0;
94 int bestSoFar = 1024;
95 for (int tableIndex = 0; tableIndex < kNumETC1ModifierTables; ++tableIndex) {
96 for (int pixelIndex = 0; pixelIndex < kNumETC1PixelIndices; ++pixelIndex) {
97 int score = test_table_entry(rOrig, gOrig, bOrig, r8, g8, b8,
98 tableIndex, pixelIndex);
99
100 if (bestSoFar > score) {
101 bestSoFar = score;
102 bestTableIndex = tableIndex;
103 bestPixelIndex = pixelIndex;
104 }
105 }
106 }
107
108 high |= (bestTableIndex << 5) | (bestTableIndex << 2);
109
110 if (bestPixelIndex & 0x1) {
111 low |= 0xFFFF;
112 }
113 if (bestPixelIndex & 0x2) {
114 low |= 0xFFFF0000;
115 }
116
117 block->fHigh = SkBSwap32(high);
118 block->fLow = SkBSwap32(low);
119}
120
121static int num_4x4_blocks(int size) {
122 return ((size + 3) & ~3) >> 2;
123}
124
125static int num_ETC1_blocks(int w, int h) {
126 w = num_4x4_blocks(w);
127 h = num_4x4_blocks(h);
128
129 return w * h;
130}
131
132struct BC1Block {
133 uint16_t fColor0;
134 uint16_t fColor1;
135 uint32_t fIndices;
136};
137
138static uint16_t to565(SkColor col) {
139 int r5 = SkMulDiv255Round(31, SkColorGetR(col));
140 int g6 = SkMulDiv255Round(63, SkColorGetG(col));
141 int b5 = SkMulDiv255Round(31, SkColorGetB(col));
142
143 return (r5 << 11) | (g6 << 5) | b5;
144}
145
146// Create a BC1 compressed block that has two colors but is initialized to 'col0'
147static void create_BC1_block(SkColor col0, SkColor col1, BC1Block* block) {
148 block->fColor0 = to565(col0);
149 block->fColor1 = to565(col1);
150 SkASSERT(block->fColor0 <= block->fColor1); // we always assume transparent blocks
151
152 if (col0 == SK_ColorTRANSPARENT) {
153 // This sets all 16 pixels to just use color3 (under the assumption
154 // that this is a kBC1_RGBA8_UNORM texture. Note that in this case
155 // fColor0 will be opaque black.
156 block->fIndices = 0xFFFFFFFF;
157 } else {
158 // This sets all 16 pixels to just use 'fColor0'
159 block->fIndices = 0;
160 }
161}
162
164 switch (type) {
166 return baseDimensions.width() * baseDimensions.height();
170 int numBlocksWidth = num_4x4_blocks(baseDimensions.width());
171 int numBlocksHeight = num_4x4_blocks(baseDimensions.height());
172
173 return numBlocksWidth * numBlocksHeight;
174 }
175 }
177}
178
180 switch (type) {
182 return 0;
186 int numBlocksWidth = num_4x4_blocks(width);
187
188 static_assert(sizeof(ETC1Block) == sizeof(BC1Block));
189 return numBlocksWidth * sizeof(ETC1Block);
190 }
191 }
193}
194
196 switch (type) {
198 return baseDimensions;
202 SkISize blockDims = CompressedDimensionsInBlocks(type, baseDimensions);
203 // Each BC1_RGB8_UNORM and ETC1 block has 16 pixels
204 return { 4 * blockDims.fWidth, 4 * blockDims.fHeight };
205 }
206 }
208}
209
211 switch (type) {
213 return baseDimensions;
217 int numBlocksWidth = num_4x4_blocks(baseDimensions.width());
218 int numBlocksHeight = num_4x4_blocks(baseDimensions.height());
219
220 // Each BC1_RGB8_UNORM and ETC1 block has 16 pixels
221 return { numBlocksWidth, numBlocksHeight };
222 }
223 }
225}
226
227// Fill in 'dest' with ETC1 blocks derived from 'colorf'
228static void fillin_ETC1_with_color(SkISize dimensions, const SkColor4f& colorf, char* dest) {
229 SkColor color = colorf.toSkColor();
230
231 ETC1Block block;
232 create_etc1_block(color, &block);
233
234 int numBlocks = num_ETC1_blocks(dimensions.width(), dimensions.height());
235
236 for (int i = 0; i < numBlocks; ++i) {
237 memcpy(dest, &block, sizeof(ETC1Block));
238 dest += sizeof(ETC1Block);
239 }
240}
241
242// Fill in 'dest' with BC1 blocks derived from 'colorf'
243static void fillin_BC1_with_color(SkISize dimensions, const SkColor4f& colorf, char* dest) {
244 SkColor color = colorf.toSkColor();
245
246 BC1Block block;
247 create_BC1_block(color, color, &block);
248
249 int numBlocks = num_ETC1_blocks(dimensions.width(), dimensions.height());
250
251 for (int i = 0; i < numBlocks; ++i) {
252 memcpy(dest, &block, sizeof(BC1Block));
253 dest += sizeof(BC1Block);
254 }
255}
256
258 SkISize dimensions,
259 skgpu::Mipmapped mipmapped,
260 char* dstPixels,
261 const SkColor4f& colorf) {
262 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
263
264 int numMipLevels = 1;
265 if (mipmapped == skgpu::Mipmapped::kYes) {
266 numMipLevels = SkMipmap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
267 }
268
269 size_t offset = 0;
270
271 for (int i = 0; i < numMipLevels; ++i) {
272 size_t levelSize = SkCompressedDataSize(type, dimensions, nullptr, false);
273
275 fillin_ETC1_with_color(dimensions, colorf, &dstPixels[offset]);
276 } else {
279 fillin_BC1_with_color(dimensions, colorf, &dstPixels[offset]);
280 }
281
282 offset += levelSize;
283 dimensions = {std::max(1, dimensions.width()/2), std::max(1, dimensions.height()/2)};
284 }
285}
286
287} // namespace skgpu
#define SkUNREACHABLE
Definition: SkAssert.h:135
#define SkASSERT(cond)
Definition: SkAssert.h:116
#define SkColorGetR(color)
Definition: SkColor.h:65
#define SkColorGetG(color)
Definition: SkColor.h:69
uint32_t SkColor
Definition: SkColor.h:37
constexpr SkColor SK_ColorTRANSPARENT
Definition: SkColor.h:99
#define SkColorGetB(color)
Definition: SkColor.h:73
size_t SkCompressedDataSize(SkTextureCompressionType type, SkISize dimensions, TArray< size_t > *individualMipOffsets, bool mipmapped)
static uint32_t SkBSwap32(uint32_t v)
Definition: SkMathPriv.h:123
static U8CPU SkMulDiv255Round(U16CPU a, U16CPU b)
Definition: SkMath.h:73
static T SkTAbs(T value)
Definition: SkTemplates.h:43
SkTextureCompressionType
#define TRACE_FUNC
Definition: SkTraceEvent.h:30
SI F table(const skcms_Curve *curve, F v)
GLenum type
static int ComputeLevelCount(int baseWidth, int baseHeight)
Definition: SkMipmap.cpp:134
DlColor color
static bool b
static float max(float r, float g, float b)
Definition: hsl.cpp:49
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
Definition: GpuTools.h:21
void FillInCompressedData(SkTextureCompressionType type, SkISize dimensions, skgpu::Mipmapped mipmapped, char *dstPixels, const SkColor4f &colorf)
Definition: DataUtils.cpp:257
static const int kNumETC1PixelIndices
Definition: DataUtils.cpp:42
SkISize CompressedDimensionsInBlocks(SkTextureCompressionType type, SkISize baseDimensions)
Definition: DataUtils.cpp:210
static void create_etc1_block(SkColor col, ETC1Block *block)
Definition: DataUtils.cpp:73
static int test_table_entry(int rOrig, int gOrig, int bOrig, int r8, int g8, int b8, int table, int offset)
Definition: DataUtils.cpp:59
static void create_BC1_block(SkColor col0, SkColor col1, BC1Block *block)
Definition: DataUtils.cpp:147
constexpr uint32_t kDiffBit
Definition: DataUtils.cpp:34
static uint16_t to565(SkColor col)
Definition: DataUtils.cpp:138
size_t CompressedRowBytes(SkTextureCompressionType type, int width)
Definition: DataUtils.cpp:179
static const int kNumETC1ModifierTables
Definition: DataUtils.cpp:41
static int extend_5To8bits(int b)
Definition: DataUtils.cpp:36
Mipmapped
Definition: GpuTypes.h:53
size_t NumCompressedBlocks(SkTextureCompressionType type, SkISize baseDimensions)
Definition: DataUtils.cpp:163
static int num_4x4_blocks(int size)
Definition: DataUtils.cpp:121
static void fillin_ETC1_with_color(SkISize dimensions, const SkColor4f &colorf, char *dest)
Definition: DataUtils.cpp:228
static void fillin_BC1_with_color(SkISize dimensions, const SkColor4f &colorf, char *dest)
Definition: DataUtils.cpp:243
static int num_ETC1_blocks(int w, int h)
Definition: DataUtils.cpp:125
SkISize CompressedDimensions(SkTextureCompressionType type, SkISize baseDimensions)
Definition: DataUtils.cpp:195
static const int kETC1ModifierTables[kNumETC1ModifierTables][kNumETC1PixelIndices]
Definition: DataUtils.cpp:46
dest
Definition: zip.py:79
SkScalar w
SkScalar h
int32_t width
SeparatedVector2 offset
Definition: SkSize.h:16
int32_t fHeight
Definition: SkSize.h:18
int32_t fWidth
Definition: SkSize.h:17
constexpr int32_t width() const
Definition: SkSize.h:36
constexpr int32_t height() const
Definition: SkSize.h:37
uint16_t fColor0
Definition: DataUtils.cpp:133
uint32_t fIndices
Definition: DataUtils.cpp:135
uint16_t fColor1
Definition: DataUtils.cpp:134
uint32_t fHigh
Definition: DataUtils.cpp:30
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:131