blob: 481571485cad84d4970e364e85853f8c8af2458f [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
13static const int kNumModifierTables = 8;
14static const int kNumPixelIndices = 4;
15
16// The index of each row in this table is the ETC1 table codeword
17// The index of each column in this table is the ETC1 pixel index value
18static const int kModifierTables[kNumModifierTables][kNumPixelIndices] = {
19 /* 0 */ { 2, 8, -2, -8 },
20 /* 1 */ { 5, 17, -5, -17 },
21 /* 2 */ { 9, 29, -9, -29 },
22 /* 3 */ { 13, 42, -13, -42 },
23 /* 4 */ { 18, 60, -18, -60 },
24 /* 5 */ { 24, 80, -24, -80 },
25 /* 6 */ { 33, 106, -33, -106 },
26 /* 7 */ { 47, 183, -47, -183 }
27};
28
29static inline int convert_5To8(int b) {
30 int c = b & 0x1f;
31 return (c << 3) | (c >> 2);
32}
33
34// Evaluate one of the entries in 'kModifierTables' to see how close it can get (r8,g8,b8) to
35// the original color (rOrig, gOrib, bOrig).
36static int test_table_entry(int rOrig, int gOrig, int bOrig,
37 int r8, int g8, int b8,
38 int table, int offset) {
39 SkASSERT(0 <= table && table < 8);
40 SkASSERT(0 <= offset && offset < 4);
41
42 r8 = SkTPin<uint8_t>(r8 + kModifierTables[table][offset], 0, 255);
43 g8 = SkTPin<uint8_t>(g8 + kModifierTables[table][offset], 0, 255);
44 b8 = SkTPin<uint8_t>(b8 + kModifierTables[table][offset], 0, 255);
45
46 return SkTAbs(rOrig - r8) + SkTAbs(gOrig - g8) + SkTAbs(bOrig - b8);
47}
48
49// Create an ETC1 compressed block that is filled with 'col'
50static void create_etc1_block(SkColor col, ETC1Block* block) {
51 block->fHigh = 0;
52 block->fLow = 0;
53
54 int rOrig = SkColorGetR(col);
55 int gOrig = SkColorGetG(col);
56 int bOrig = SkColorGetB(col);
57
58 int r5 = SkMulDiv255Round(31, rOrig);
59 int g5 = SkMulDiv255Round(31, gOrig);
60 int b5 = SkMulDiv255Round(31, bOrig);
61
62 int r8 = convert_5To8(r5);
63 int g8 = convert_5To8(g5);
64 int b8 = convert_5To8(b5);
65
66 // We always encode solid color textures as 555 + zero diffs
67 block->fHigh |= (r5 << 27) | (g5 << 19) | (b5 << 11) | 0x2;
68
69 int bestTableIndex = 0, bestPixelIndex = 0;
70 int bestSoFar = 1024;
71 for (int tableIndex = 0; tableIndex < kNumModifierTables; ++tableIndex) {
72 for (int pixelIndex = 0; pixelIndex < kNumPixelIndices; ++pixelIndex) {
73 int score = test_table_entry(rOrig, gOrig, bOrig, r8, g8, b8,
74 tableIndex, pixelIndex);
75
76 if (bestSoFar > score) {
77 bestSoFar = score;
78 bestTableIndex = tableIndex;
79 bestPixelIndex = pixelIndex;
80 }
81 }
82 }
83
84 block->fHigh |= (bestTableIndex << 5) | (bestTableIndex << 2);
85
86 for (int i = 0; i < 16; ++i) {
87 block->fLow |= bestPixelIndex << 2*i;
88 }
89}
90
91int GrNumETC1Blocks(int w, int h) {
92 if (w < 4) {
93 w = 1;
94 } else {
95 SkASSERT((w & 3) == 0);
96 w >>= 2;
97 }
98
99 if (h < 4) {
100 h = 1;
101 } else {
102 SkASSERT((h & 3) == 0);
103 h >>= 2;
104 }
105
106 return w * h;
107}
108
Robert Phillipse3bd6732019-05-29 14:20:35 -0400109void GrFillInETC1WithColor(const SkColor4f& colorf, void* dest, int numBlocks) {
Robert Phillips459b2952019-05-23 09:38:27 -0400110 SkColor color = colorf.toSkColor();
111
112 ETC1Block block;
113 create_etc1_block(color, &block);
114
115 for (int i = 0; i < numBlocks; ++i) {
Robert Phillipse3bd6732019-05-29 14:20:35 -0400116 ((ETC1Block*)dest)[i] = block;
Robert Phillips459b2952019-05-23 09:38:27 -0400117 }
118}
119
120bool GrFillBufferWithColor(GrPixelConfig config, int width, int height,
121 const SkColor4f& colorf, void* dest) {
122 SkASSERT(kRGB_ETC1_GrPixelConfig != config);
123
124 GrColor color = colorf.toBytes_RGBA();
125
126 uint8_t r = GrColorUnpackR(color);
127 uint8_t g = GrColorUnpackG(color);
128 uint8_t b = GrColorUnpackB(color);
129 uint8_t a = GrColorUnpackA(color);
130
Robert Phillips459b2952019-05-23 09:38:27 -0400131 switch (config) {
132 case kAlpha_8_GrPixelConfig: // fall through
133 case kAlpha_8_as_Alpha_GrPixelConfig: // fall through
134 case kAlpha_8_as_Red_GrPixelConfig: {
135 memset(dest, a, width * height);
136 break;
137 }
138 case kGray_8_GrPixelConfig: // fall through
139 case kGray_8_as_Lum_GrPixelConfig: // fall through
140 case kGray_8_as_Red_GrPixelConfig: {
141 uint8_t gray8 = SkComputeLuminance(r, g, b);
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400142
Robert Phillips459b2952019-05-23 09:38:27 -0400143 memset(dest, gray8, width * height);
144 break;
145 }
146 case kRGB_565_GrPixelConfig: {
Robert Phillips459b2952019-05-23 09:38:27 -0400147 uint16_t rgb565 = SkPack888ToRGB16(r, g, b);
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400148
149 sk_memset16((uint16_t*) dest, rgb565, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400150 break;
151 }
152 case kRGBA_4444_GrPixelConfig: {
Robert Phillips459b2952019-05-23 09:38:27 -0400153 uint8_t r4 = (r >> 4) & 0xF;
154 uint8_t g4 = (g >> 4) & 0xF;
155 uint8_t b4 = (b >> 4) & 0xF;
156 uint8_t a4 = (a >> 4) & 0xF;
157
158 uint16_t rgba4444 = r4 << SK_R4444_SHIFT | g4 << SK_G4444_SHIFT |
159 b4 << SK_B4444_SHIFT | a4 << SK_A4444_SHIFT;
160
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400161 sk_memset16((uint16_t*) dest, rgba4444, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400162 break;
163 }
164 case kRGBA_8888_GrPixelConfig: {
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400165 sk_memset32((uint32_t *) dest, color, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400166 break;
167 }
168 case kRGB_888_GrPixelConfig: {
169 uint8_t* dest8 = (uint8_t*) dest;
170 for (int i = 0; i < width * height; ++i, dest8 += 3) {
171 dest8[0] = r;
172 dest8[1] = g;
173 dest8[2] = b;
174 }
175 break;
176 }
177 case kRGB_888X_GrPixelConfig: {
178 GrColor opaque = GrColorPackRGBA(r, g, b, 0xFF);
179
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400180 sk_memset32((uint32_t *) dest, opaque, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400181 break;
182 }
183 case kRG_88_GrPixelConfig: {
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400184 uint16_t rg88 = (r << 8) | g;
185
186 sk_memset16((uint16_t*) dest, rg88, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400187 break;
188 }
189 case kBGRA_8888_GrPixelConfig: {
190 GrColor swizzled = GrColorPackRGBA(b, g, r, a);
191
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400192 sk_memset32((uint32_t *) dest, swizzled, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400193 break;
194 }
195 case kSRGBA_8888_GrPixelConfig: {
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400196 sk_memset32((uint32_t *) dest, color, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400197 break;
198 }
199 case kSBGRA_8888_GrPixelConfig: {
Robert Phillips459b2952019-05-23 09:38:27 -0400200 GrColor swizzled = GrColorPackRGBA(b, g, r, a);
201
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400202 sk_memset32((uint32_t *) dest, swizzled, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400203 break;
204 }
205 case kRGBA_1010102_GrPixelConfig: {
206 uint32_t r10 = SkScalarRoundToInt(colorf.fR * 1023.0f);
207 uint32_t g10 = SkScalarRoundToInt(colorf.fG * 1023.0f);
208 uint32_t b10 = SkScalarRoundToInt(colorf.fB * 1023.0f);
209 uint8_t a2 = SkScalarRoundToInt(colorf.fA * 3.0f);
210
211 uint32_t rgba1010102 = a2 << 30 | b10 << 20 | g10 << 10 | r10;
212
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400213 sk_memset32((uint32_t *) dest, rgba1010102, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400214 break;
215 }
216 case kRGBA_float_GrPixelConfig: {
217 SkColor4f* destColor = (SkColor4f*) dest;
218 for (int i = 0; i < width * height; ++i) {
219 destColor[i] = colorf;
220 }
221 break;
222 }
223 case kRG_float_GrPixelConfig: {
224 float* destFloat = (float*) dest;
225 for (int i = 0; i < width * height; ++i, destFloat += 2) {
226 destFloat[0] = colorf.fR;
227 destFloat[1] = colorf.fG;
228 }
229 break;
230 }
231 case kAlpha_half_as_Red_GrPixelConfig: // fall through
232 case kAlpha_half_GrPixelConfig: {
Robert Phillips459b2952019-05-23 09:38:27 -0400233 SkHalf alphaHalf = SkFloatToHalf(colorf.fA);
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400234
235 sk_memset16((uint16_t *) dest, alphaHalf, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400236 break;
237 }
238 case kRGBA_half_GrPixelConfig: // fall through
239 case kRGBA_half_Clamped_GrPixelConfig: {
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400240 uint64_t rHalf = SkFloatToHalf(colorf.fR);
241 uint64_t gHalf = SkFloatToHalf(colorf.fG);
242 uint64_t bHalf = SkFloatToHalf(colorf.fB);
243 uint64_t aHalf = SkFloatToHalf(colorf.fA);
244
245 uint64_t rgbaHalf = (aHalf << 48) | (bHalf << 32) | (gHalf << 16) | rHalf;
246
247 sk_memset64((uint64_t *) dest, rgbaHalf, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400248 break;
249 }
250 default:
251 return false;
252 break;
253 }
254
255 return true;
256}