blob: b03a79af6d058f6b736de379203fab9ae28c39fe [file] [log] [blame]
Robert Phillips459b2952019-05-23 09:38:27 -04001/*
2 * Copyright 2019 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 "GrDataUtils.h"
9
10#include "include/private/GrColor.h"
Robert Phillipsb5e331a2019-05-28 10:58:09 -040011#include "src/core/SkUtils.h"
Robert Phillips459b2952019-05-23 09:38:27 -040012
Robert Phillips8043f322019-05-31 08:11:36 -040013struct ETC1Block {
14 uint32_t fHigh;
15 uint32_t fLow;
16};
17
Robert Phillips459b2952019-05-23 09:38:27 -040018static const int kNumModifierTables = 8;
19static const int kNumPixelIndices = 4;
20
21// The index of each row in this table is the ETC1 table codeword
22// The index of each column in this table is the ETC1 pixel index value
23static const int kModifierTables[kNumModifierTables][kNumPixelIndices] = {
24 /* 0 */ { 2, 8, -2, -8 },
25 /* 1 */ { 5, 17, -5, -17 },
26 /* 2 */ { 9, 29, -9, -29 },
27 /* 3 */ { 13, 42, -13, -42 },
28 /* 4 */ { 18, 60, -18, -60 },
29 /* 5 */ { 24, 80, -24, -80 },
30 /* 6 */ { 33, 106, -33, -106 },
31 /* 7 */ { 47, 183, -47, -183 }
32};
33
34static inline int convert_5To8(int b) {
35 int c = b & 0x1f;
36 return (c << 3) | (c >> 2);
37}
38
39// Evaluate one of the entries in 'kModifierTables' to see how close it can get (r8,g8,b8) to
40// the original color (rOrig, gOrib, bOrig).
41static int test_table_entry(int rOrig, int gOrig, int bOrig,
42 int r8, int g8, int b8,
43 int table, int offset) {
44 SkASSERT(0 <= table && table < 8);
45 SkASSERT(0 <= offset && offset < 4);
46
47 r8 = SkTPin<uint8_t>(r8 + kModifierTables[table][offset], 0, 255);
48 g8 = SkTPin<uint8_t>(g8 + kModifierTables[table][offset], 0, 255);
49 b8 = SkTPin<uint8_t>(b8 + kModifierTables[table][offset], 0, 255);
50
51 return SkTAbs(rOrig - r8) + SkTAbs(gOrig - g8) + SkTAbs(bOrig - b8);
52}
53
54// Create an ETC1 compressed block that is filled with 'col'
55static void create_etc1_block(SkColor col, ETC1Block* block) {
56 block->fHigh = 0;
57 block->fLow = 0;
58
59 int rOrig = SkColorGetR(col);
60 int gOrig = SkColorGetG(col);
61 int bOrig = SkColorGetB(col);
62
63 int r5 = SkMulDiv255Round(31, rOrig);
64 int g5 = SkMulDiv255Round(31, gOrig);
65 int b5 = SkMulDiv255Round(31, bOrig);
66
67 int r8 = convert_5To8(r5);
68 int g8 = convert_5To8(g5);
69 int b8 = convert_5To8(b5);
70
71 // We always encode solid color textures as 555 + zero diffs
72 block->fHigh |= (r5 << 27) | (g5 << 19) | (b5 << 11) | 0x2;
73
74 int bestTableIndex = 0, bestPixelIndex = 0;
75 int bestSoFar = 1024;
76 for (int tableIndex = 0; tableIndex < kNumModifierTables; ++tableIndex) {
77 for (int pixelIndex = 0; pixelIndex < kNumPixelIndices; ++pixelIndex) {
78 int score = test_table_entry(rOrig, gOrig, bOrig, r8, g8, b8,
79 tableIndex, pixelIndex);
80
81 if (bestSoFar > score) {
82 bestSoFar = score;
83 bestTableIndex = tableIndex;
84 bestPixelIndex = pixelIndex;
85 }
86 }
87 }
88
89 block->fHigh |= (bestTableIndex << 5) | (bestTableIndex << 2);
90
91 for (int i = 0; i < 16; ++i) {
92 block->fLow |= bestPixelIndex << 2*i;
93 }
94}
95
Robert Phillips8043f322019-05-31 08:11:36 -040096static int num_ETC1_blocks(int w, int h) {
Robert Phillips459b2952019-05-23 09:38:27 -040097 if (w < 4) {
98 w = 1;
99 } else {
100 SkASSERT((w & 3) == 0);
101 w >>= 2;
102 }
103
104 if (h < 4) {
105 h = 1;
106 } else {
107 SkASSERT((h & 3) == 0);
108 h >>= 2;
109 }
110
111 return w * h;
112}
113
Robert Phillips8043f322019-05-31 08:11:36 -0400114size_t GrETC1CompressedDataSize(int width, int height) {
115 int numBlocks = num_ETC1_blocks(width, height);
116
117 return numBlocks * sizeof(ETC1Block);
118}
119
120void GrFillInETC1WithColor(int width, int height, const SkColor4f& colorf, void* dest) {
Robert Phillips459b2952019-05-23 09:38:27 -0400121 SkColor color = colorf.toSkColor();
122
123 ETC1Block block;
124 create_etc1_block(color, &block);
125
Robert Phillips8043f322019-05-31 08:11:36 -0400126 int numBlocks = num_ETC1_blocks(width, height);
127
Robert Phillips459b2952019-05-23 09:38:27 -0400128 for (int i = 0; i < numBlocks; ++i) {
Robert Phillipse3bd6732019-05-29 14:20:35 -0400129 ((ETC1Block*)dest)[i] = block;
Robert Phillips459b2952019-05-23 09:38:27 -0400130 }
131}
132
133bool GrFillBufferWithColor(GrPixelConfig config, int width, int height,
134 const SkColor4f& colorf, void* dest) {
135 SkASSERT(kRGB_ETC1_GrPixelConfig != config);
136
137 GrColor color = colorf.toBytes_RGBA();
138
139 uint8_t r = GrColorUnpackR(color);
140 uint8_t g = GrColorUnpackG(color);
141 uint8_t b = GrColorUnpackB(color);
142 uint8_t a = GrColorUnpackA(color);
143
Robert Phillips459b2952019-05-23 09:38:27 -0400144 switch (config) {
145 case kAlpha_8_GrPixelConfig: // fall through
146 case kAlpha_8_as_Alpha_GrPixelConfig: // fall through
147 case kAlpha_8_as_Red_GrPixelConfig: {
148 memset(dest, a, width * height);
149 break;
150 }
151 case kGray_8_GrPixelConfig: // fall through
152 case kGray_8_as_Lum_GrPixelConfig: // fall through
153 case kGray_8_as_Red_GrPixelConfig: {
154 uint8_t gray8 = SkComputeLuminance(r, g, b);
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400155
Robert Phillips459b2952019-05-23 09:38:27 -0400156 memset(dest, gray8, width * height);
157 break;
158 }
159 case kRGB_565_GrPixelConfig: {
Robert Phillips459b2952019-05-23 09:38:27 -0400160 uint16_t rgb565 = SkPack888ToRGB16(r, g, b);
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400161
162 sk_memset16((uint16_t*) dest, rgb565, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400163 break;
164 }
165 case kRGBA_4444_GrPixelConfig: {
Robert Phillips459b2952019-05-23 09:38:27 -0400166 uint8_t r4 = (r >> 4) & 0xF;
167 uint8_t g4 = (g >> 4) & 0xF;
168 uint8_t b4 = (b >> 4) & 0xF;
169 uint8_t a4 = (a >> 4) & 0xF;
170
171 uint16_t rgba4444 = r4 << SK_R4444_SHIFT | g4 << SK_G4444_SHIFT |
172 b4 << SK_B4444_SHIFT | a4 << SK_A4444_SHIFT;
173
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400174 sk_memset16((uint16_t*) dest, rgba4444, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400175 break;
176 }
177 case kRGBA_8888_GrPixelConfig: {
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400178 sk_memset32((uint32_t *) dest, color, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400179 break;
180 }
181 case kRGB_888_GrPixelConfig: {
182 uint8_t* dest8 = (uint8_t*) dest;
183 for (int i = 0; i < width * height; ++i, dest8 += 3) {
184 dest8[0] = r;
185 dest8[1] = g;
186 dest8[2] = b;
187 }
188 break;
189 }
190 case kRGB_888X_GrPixelConfig: {
191 GrColor opaque = GrColorPackRGBA(r, g, b, 0xFF);
192
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400193 sk_memset32((uint32_t *) dest, opaque, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400194 break;
195 }
196 case kRG_88_GrPixelConfig: {
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400197 uint16_t rg88 = (r << 8) | g;
198
199 sk_memset16((uint16_t*) dest, rg88, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400200 break;
201 }
202 case kBGRA_8888_GrPixelConfig: {
203 GrColor swizzled = GrColorPackRGBA(b, g, r, a);
204
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400205 sk_memset32((uint32_t *) dest, swizzled, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400206 break;
207 }
208 case kSRGBA_8888_GrPixelConfig: {
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400209 sk_memset32((uint32_t *) dest, color, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400210 break;
211 }
212 case kSBGRA_8888_GrPixelConfig: {
Robert Phillips459b2952019-05-23 09:38:27 -0400213 GrColor swizzled = GrColorPackRGBA(b, g, r, a);
214
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400215 sk_memset32((uint32_t *) dest, swizzled, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400216 break;
217 }
218 case kRGBA_1010102_GrPixelConfig: {
219 uint32_t r10 = SkScalarRoundToInt(colorf.fR * 1023.0f);
220 uint32_t g10 = SkScalarRoundToInt(colorf.fG * 1023.0f);
221 uint32_t b10 = SkScalarRoundToInt(colorf.fB * 1023.0f);
222 uint8_t a2 = SkScalarRoundToInt(colorf.fA * 3.0f);
223
224 uint32_t rgba1010102 = a2 << 30 | b10 << 20 | g10 << 10 | r10;
225
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400226 sk_memset32((uint32_t *) dest, rgba1010102, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400227 break;
228 }
229 case kRGBA_float_GrPixelConfig: {
230 SkColor4f* destColor = (SkColor4f*) dest;
231 for (int i = 0; i < width * height; ++i) {
232 destColor[i] = colorf;
233 }
234 break;
235 }
236 case kRG_float_GrPixelConfig: {
237 float* destFloat = (float*) dest;
238 for (int i = 0; i < width * height; ++i, destFloat += 2) {
239 destFloat[0] = colorf.fR;
240 destFloat[1] = colorf.fG;
241 }
242 break;
243 }
244 case kAlpha_half_as_Red_GrPixelConfig: // fall through
245 case kAlpha_half_GrPixelConfig: {
Robert Phillips459b2952019-05-23 09:38:27 -0400246 SkHalf alphaHalf = SkFloatToHalf(colorf.fA);
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400247
248 sk_memset16((uint16_t *) dest, alphaHalf, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400249 break;
250 }
251 case kRGBA_half_GrPixelConfig: // fall through
252 case kRGBA_half_Clamped_GrPixelConfig: {
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400253 uint64_t rHalf = SkFloatToHalf(colorf.fR);
254 uint64_t gHalf = SkFloatToHalf(colorf.fG);
255 uint64_t bHalf = SkFloatToHalf(colorf.fB);
256 uint64_t aHalf = SkFloatToHalf(colorf.fA);
257
258 uint64_t rgbaHalf = (aHalf << 48) | (bHalf << 32) | (gHalf << 16) | rHalf;
259
260 sk_memset64((uint64_t *) dest, rgbaHalf, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400261 break;
262 }
263 default:
264 return false;
265 break;
266 }
267
268 return true;
269}