blob: 91956e31ae48c3ef2621d59ae6f3be05e7e5b311 [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
Brian Salomon77a684f2019-08-01 14:38:04 -04008#include "src/gpu/GrDataUtils.h"
9
Brian Salomonf30b1c12019-06-20 12:25:02 -040010#include "src/core/SkColorSpaceXformSteps.h"
Brian Salomon77a684f2019-08-01 14:38:04 -040011#include "src/core/SkConvertPixels.h"
Brian Salomonf30b1c12019-06-20 12:25:02 -040012#include "src/core/SkTLazy.h"
Brian Salomonc42eb662019-06-24 17:13:00 -040013#include "src/core/SkTraceEvent.h"
Robert Phillipsb5e331a2019-05-28 10:58:09 -040014#include "src/core/SkUtils.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040015#include "src/gpu/GrColor.h"
Robert Phillips459b2952019-05-23 09:38:27 -040016
Robert Phillips8043f322019-05-31 08:11:36 -040017struct ETC1Block {
18 uint32_t fHigh;
19 uint32_t fLow;
20};
21
Robert Phillips459b2952019-05-23 09:38:27 -040022static const int kNumModifierTables = 8;
23static const int kNumPixelIndices = 4;
24
25// The index of each row in this table is the ETC1 table codeword
26// The index of each column in this table is the ETC1 pixel index value
27static const int kModifierTables[kNumModifierTables][kNumPixelIndices] = {
28 /* 0 */ { 2, 8, -2, -8 },
29 /* 1 */ { 5, 17, -5, -17 },
30 /* 2 */ { 9, 29, -9, -29 },
31 /* 3 */ { 13, 42, -13, -42 },
32 /* 4 */ { 18, 60, -18, -60 },
33 /* 5 */ { 24, 80, -24, -80 },
34 /* 6 */ { 33, 106, -33, -106 },
35 /* 7 */ { 47, 183, -47, -183 }
36};
37
38static inline int convert_5To8(int b) {
39 int c = b & 0x1f;
40 return (c << 3) | (c >> 2);
41}
42
43// Evaluate one of the entries in 'kModifierTables' to see how close it can get (r8,g8,b8) to
44// the original color (rOrig, gOrib, bOrig).
45static int test_table_entry(int rOrig, int gOrig, int bOrig,
46 int r8, int g8, int b8,
47 int table, int offset) {
48 SkASSERT(0 <= table && table < 8);
49 SkASSERT(0 <= offset && offset < 4);
50
51 r8 = SkTPin<uint8_t>(r8 + kModifierTables[table][offset], 0, 255);
52 g8 = SkTPin<uint8_t>(g8 + kModifierTables[table][offset], 0, 255);
53 b8 = SkTPin<uint8_t>(b8 + kModifierTables[table][offset], 0, 255);
54
55 return SkTAbs(rOrig - r8) + SkTAbs(gOrig - g8) + SkTAbs(bOrig - b8);
56}
57
58// Create an ETC1 compressed block that is filled with 'col'
59static void create_etc1_block(SkColor col, ETC1Block* block) {
60 block->fHigh = 0;
61 block->fLow = 0;
62
63 int rOrig = SkColorGetR(col);
64 int gOrig = SkColorGetG(col);
65 int bOrig = SkColorGetB(col);
66
67 int r5 = SkMulDiv255Round(31, rOrig);
68 int g5 = SkMulDiv255Round(31, gOrig);
69 int b5 = SkMulDiv255Round(31, bOrig);
70
71 int r8 = convert_5To8(r5);
72 int g8 = convert_5To8(g5);
73 int b8 = convert_5To8(b5);
74
75 // We always encode solid color textures as 555 + zero diffs
76 block->fHigh |= (r5 << 27) | (g5 << 19) | (b5 << 11) | 0x2;
77
78 int bestTableIndex = 0, bestPixelIndex = 0;
79 int bestSoFar = 1024;
80 for (int tableIndex = 0; tableIndex < kNumModifierTables; ++tableIndex) {
81 for (int pixelIndex = 0; pixelIndex < kNumPixelIndices; ++pixelIndex) {
82 int score = test_table_entry(rOrig, gOrig, bOrig, r8, g8, b8,
83 tableIndex, pixelIndex);
84
85 if (bestSoFar > score) {
86 bestSoFar = score;
87 bestTableIndex = tableIndex;
88 bestPixelIndex = pixelIndex;
89 }
90 }
91 }
92
93 block->fHigh |= (bestTableIndex << 5) | (bestTableIndex << 2);
94
95 for (int i = 0; i < 16; ++i) {
96 block->fLow |= bestPixelIndex << 2*i;
97 }
98}
99
Robert Phillips8043f322019-05-31 08:11:36 -0400100static int num_ETC1_blocks(int w, int h) {
Robert Phillips459b2952019-05-23 09:38:27 -0400101 if (w < 4) {
102 w = 1;
103 } else {
104 SkASSERT((w & 3) == 0);
105 w >>= 2;
106 }
107
108 if (h < 4) {
109 h = 1;
110 } else {
111 SkASSERT((h & 3) == 0);
112 h >>= 2;
113 }
114
115 return w * h;
116}
117
Brian Salomonbb8dde82019-06-27 10:52:13 -0400118size_t GrCompressedDataSize(SkImage::CompressionType type, int width, int height) {
119 switch (type) {
120 case SkImage::kETC1_CompressionType:
121 int numBlocks = num_ETC1_blocks(width, height);
122 return numBlocks * sizeof(ETC1Block);
123 }
124 SK_ABORT("Unexpected compression type");
Robert Phillips8043f322019-05-31 08:11:36 -0400125}
126
Robert Phillips28a5a432019-06-07 12:46:21 -0400127// Fill in 'dest' with ETC1 blocks derived from 'colorf'
128static void fillin_ETC1_with_color(int width, int height, const SkColor4f& colorf, void* dest) {
Robert Phillips459b2952019-05-23 09:38:27 -0400129 SkColor color = colorf.toSkColor();
130
131 ETC1Block block;
132 create_etc1_block(color, &block);
133
Robert Phillips8043f322019-05-31 08:11:36 -0400134 int numBlocks = num_ETC1_blocks(width, height);
135
Robert Phillips459b2952019-05-23 09:38:27 -0400136 for (int i = 0; i < numBlocks; ++i) {
Robert Phillipse3bd6732019-05-29 14:20:35 -0400137 ((ETC1Block*)dest)[i] = block;
Robert Phillips459b2952019-05-23 09:38:27 -0400138 }
139}
140
Robert Phillips28a5a432019-06-07 12:46:21 -0400141// Fill in the width x height 'dest' with the munged version of 'colorf' that matches 'config'
142static bool fill_buffer_with_color(GrPixelConfig config, int width, int height,
143 const SkColor4f& colorf, void* dest) {
Robert Phillips459b2952019-05-23 09:38:27 -0400144 SkASSERT(kRGB_ETC1_GrPixelConfig != config);
145
146 GrColor color = colorf.toBytes_RGBA();
147
148 uint8_t r = GrColorUnpackR(color);
149 uint8_t g = GrColorUnpackG(color);
150 uint8_t b = GrColorUnpackB(color);
151 uint8_t a = GrColorUnpackA(color);
152
Robert Phillips459b2952019-05-23 09:38:27 -0400153 switch (config) {
154 case kAlpha_8_GrPixelConfig: // fall through
155 case kAlpha_8_as_Alpha_GrPixelConfig: // fall through
156 case kAlpha_8_as_Red_GrPixelConfig: {
157 memset(dest, a, width * height);
158 break;
159 }
160 case kGray_8_GrPixelConfig: // fall through
161 case kGray_8_as_Lum_GrPixelConfig: // fall through
162 case kGray_8_as_Red_GrPixelConfig: {
163 uint8_t gray8 = SkComputeLuminance(r, g, b);
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400164
Robert Phillips459b2952019-05-23 09:38:27 -0400165 memset(dest, gray8, width * height);
166 break;
167 }
168 case kRGB_565_GrPixelConfig: {
Robert Phillips459b2952019-05-23 09:38:27 -0400169 uint16_t rgb565 = SkPack888ToRGB16(r, g, b);
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400170
171 sk_memset16((uint16_t*) dest, rgb565, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400172 break;
173 }
174 case kRGBA_4444_GrPixelConfig: {
Robert Phillips459b2952019-05-23 09:38:27 -0400175 uint8_t r4 = (r >> 4) & 0xF;
176 uint8_t g4 = (g >> 4) & 0xF;
177 uint8_t b4 = (b >> 4) & 0xF;
178 uint8_t a4 = (a >> 4) & 0xF;
179
180 uint16_t rgba4444 = r4 << SK_R4444_SHIFT | g4 << SK_G4444_SHIFT |
181 b4 << SK_B4444_SHIFT | a4 << SK_A4444_SHIFT;
182
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400183 sk_memset16((uint16_t*) dest, rgba4444, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400184 break;
185 }
186 case kRGBA_8888_GrPixelConfig: {
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400187 sk_memset32((uint32_t *) dest, color, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400188 break;
189 }
190 case kRGB_888_GrPixelConfig: {
191 uint8_t* dest8 = (uint8_t*) dest;
192 for (int i = 0; i < width * height; ++i, dest8 += 3) {
193 dest8[0] = r;
194 dest8[1] = g;
195 dest8[2] = b;
196 }
197 break;
198 }
199 case kRGB_888X_GrPixelConfig: {
200 GrColor opaque = GrColorPackRGBA(r, g, b, 0xFF);
201
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400202 sk_memset32((uint32_t *) dest, opaque, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400203 break;
204 }
205 case kRG_88_GrPixelConfig: {
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400206 uint16_t rg88 = (g << 8) | r;
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400207
208 sk_memset16((uint16_t*) dest, rg88, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400209 break;
210 }
211 case kBGRA_8888_GrPixelConfig: {
212 GrColor swizzled = GrColorPackRGBA(b, g, r, a);
213
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400214 sk_memset32((uint32_t *) dest, swizzled, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400215 break;
216 }
217 case kSRGBA_8888_GrPixelConfig: {
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400218 sk_memset32((uint32_t *) dest, color, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400219 break;
220 }
Robert Phillips459b2952019-05-23 09:38:27 -0400221 case kRGBA_1010102_GrPixelConfig: {
222 uint32_t r10 = SkScalarRoundToInt(colorf.fR * 1023.0f);
223 uint32_t g10 = SkScalarRoundToInt(colorf.fG * 1023.0f);
224 uint32_t b10 = SkScalarRoundToInt(colorf.fB * 1023.0f);
225 uint8_t a2 = SkScalarRoundToInt(colorf.fA * 3.0f);
226
227 uint32_t rgba1010102 = a2 << 30 | b10 << 20 | g10 << 10 | r10;
228
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400229 sk_memset32((uint32_t *) dest, rgba1010102, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400230 break;
231 }
232 case kRGBA_float_GrPixelConfig: {
233 SkColor4f* destColor = (SkColor4f*) dest;
234 for (int i = 0; i < width * height; ++i) {
235 destColor[i] = colorf;
236 }
237 break;
238 }
Robert Phillipsebab03f2019-07-22 08:48:18 -0400239 case kAlpha_half_as_Lum_GrPixelConfig: // fall through
Robert Phillips459b2952019-05-23 09:38:27 -0400240 case kAlpha_half_as_Red_GrPixelConfig: // fall through
241 case kAlpha_half_GrPixelConfig: {
Robert Phillips459b2952019-05-23 09:38:27 -0400242 SkHalf alphaHalf = SkFloatToHalf(colorf.fA);
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400243
244 sk_memset16((uint16_t *) dest, alphaHalf, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400245 break;
246 }
247 case kRGBA_half_GrPixelConfig: // fall through
248 case kRGBA_half_Clamped_GrPixelConfig: {
Robert Phillipsb5e331a2019-05-28 10:58:09 -0400249 uint64_t rHalf = SkFloatToHalf(colorf.fR);
250 uint64_t gHalf = SkFloatToHalf(colorf.fG);
251 uint64_t bHalf = SkFloatToHalf(colorf.fB);
252 uint64_t aHalf = SkFloatToHalf(colorf.fA);
253
254 uint64_t rgbaHalf = (aHalf << 48) | (bHalf << 32) | (gHalf << 16) | rHalf;
255
256 sk_memset64((uint64_t *) dest, rgbaHalf, width * height);
Robert Phillips459b2952019-05-23 09:38:27 -0400257 break;
258 }
Robert Phillipsfe18de52019-06-06 17:21:50 -0400259 case kR_16_GrPixelConfig: {
260 uint16_t r16 = SkScalarRoundToInt(colorf.fR * 65535.0f);
261 sk_memset16((uint16_t*) dest, r16, width * height);
262 break;
263 }
264 case kRG_1616_GrPixelConfig: {
265 uint16_t r16 = SkScalarRoundToInt(colorf.fR * 65535.0f);
266 uint16_t g16 = SkScalarRoundToInt(colorf.fG * 65535.0f);
267
268 uint32_t rg1616 = r16 << 16 | g16;
269
270 sk_memset32((uint32_t*) dest, rg1616, width * height);
271 break;
272 }
Robert Phillips66a46032019-06-18 08:00:42 -0400273 // Experimental (for Y416 and mutant P016/P010)
274 case kRGBA_16161616_GrPixelConfig: {
275 uint64_t r16 = SkScalarRoundToInt(colorf.fR * 65535.0f);
276 uint64_t g16 = SkScalarRoundToInt(colorf.fG * 65535.0f);
277 uint64_t b16 = SkScalarRoundToInt(colorf.fB * 65535.0f);
278 uint64_t a16 = SkScalarRoundToInt(colorf.fA * 65535.0f);
279
280 uint64_t rgba16161616 = (a16 << 48) | (b16 << 32) | (g16 << 16) | r16;
281 sk_memset64((uint64_t*) dest, rgba16161616, width * height);
282 break;
283 }
284 case kRG_half_GrPixelConfig: {
285 uint32_t rHalf = SkFloatToHalf(colorf.fR);
286 uint32_t gHalf = SkFloatToHalf(colorf.fG);
287
288 uint32_t rgHalf = (rHalf << 16) | gHalf;
289
290 sk_memset32((uint32_t *) dest, rgHalf, width * height);
291 break;
292 }
Robert Phillips459b2952019-05-23 09:38:27 -0400293 default:
294 return false;
295 break;
296 }
297
298 return true;
299}
Robert Phillips28a5a432019-06-07 12:46:21 -0400300
Brian Salomonbb8dde82019-06-27 10:52:13 -0400301size_t GrComputeTightCombinedBufferSize(size_t bytesPerPixel, int baseWidth, int baseHeight,
302 SkTArray<size_t>* individualMipOffsets, int mipLevelCount) {
Robert Phillips28a5a432019-06-07 12:46:21 -0400303 SkASSERT(individualMipOffsets && !individualMipOffsets->count());
304 SkASSERT(mipLevelCount >= 1);
305
306 individualMipOffsets->push_back(0);
307
308 size_t combinedBufferSize = baseWidth * bytesPerPixel * baseHeight;
Robert Phillips28a5a432019-06-07 12:46:21 -0400309 int currentWidth = baseWidth;
310 int currentHeight = baseHeight;
311
312 // The Vulkan spec for copying a buffer to an image requires that the alignment must be at
313 // least 4 bytes and a multiple of the bytes per pixel of the image config.
314 SkASSERT(bytesPerPixel == 1 || bytesPerPixel == 2 || bytesPerPixel == 3 ||
315 bytesPerPixel == 4 || bytesPerPixel == 8 || bytesPerPixel == 16);
316 int desiredAlignment = (bytesPerPixel == 3) ? 12 : (bytesPerPixel > 4 ? bytesPerPixel : 4);
317
318 for (int currentMipLevel = 1; currentMipLevel < mipLevelCount; ++currentMipLevel) {
319 currentWidth = SkTMax(1, currentWidth / 2);
320 currentHeight = SkTMax(1, currentHeight / 2);
321
Brian Salomonbb8dde82019-06-27 10:52:13 -0400322 size_t trimmedSize = currentWidth * bytesPerPixel * currentHeight;
Robert Phillips28a5a432019-06-07 12:46:21 -0400323 const size_t alignmentDiff = combinedBufferSize % desiredAlignment;
324 if (alignmentDiff != 0) {
325 combinedBufferSize += desiredAlignment - alignmentDiff;
326 }
327 SkASSERT((0 == combinedBufferSize % 4) && (0 == combinedBufferSize % bytesPerPixel));
328
329 individualMipOffsets->push_back(combinedBufferSize);
330 combinedBufferSize += trimmedSize;
331 }
332
333 SkASSERT(individualMipOffsets->count() == mipLevelCount);
334 return combinedBufferSize;
335}
336
Brian Salomonbb8dde82019-06-27 10:52:13 -0400337void GrFillInData(GrPixelConfig config, int baseWidth, int baseHeight,
Robert Phillips28a5a432019-06-07 12:46:21 -0400338 const SkTArray<size_t>& individualMipOffsets, char* dstPixels,
339 const SkColor4f& colorf) {
Brian Salomonc42eb662019-06-24 17:13:00 -0400340 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
Brian Salomonbb8dde82019-06-27 10:52:13 -0400341 SkASSERT(!GrPixelConfigIsCompressed(config));
Robert Phillips28a5a432019-06-07 12:46:21 -0400342 int mipLevels = individualMipOffsets.count();
343
344 int currentWidth = baseWidth;
345 int currentHeight = baseHeight;
346 for (int currentMipLevel = 0; currentMipLevel < mipLevels; ++currentMipLevel) {
347 size_t offset = individualMipOffsets[currentMipLevel];
348
Brian Salomonbb8dde82019-06-27 10:52:13 -0400349 fill_buffer_with_color(config, currentWidth, currentHeight, colorf, &(dstPixels[offset]));
Robert Phillips28a5a432019-06-07 12:46:21 -0400350 currentWidth = SkTMax(1, currentWidth / 2);
351 currentHeight = SkTMax(1, currentHeight / 2);
352 }
353}
354
Brian Salomonbb8dde82019-06-27 10:52:13 -0400355void GrFillInCompressedData(SkImage::CompressionType type, int baseWidth, int baseHeight,
356 char* dstPixels, const SkColor4f& colorf) {
357 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
358 int currentWidth = baseWidth;
359 int currentHeight = baseHeight;
360 if (SkImage::kETC1_CompressionType == type) {
361 fillin_ETC1_with_color(currentWidth, currentHeight, colorf, dstPixels);
362 }
363}
364
Brian Salomonf30b1c12019-06-20 12:25:02 -0400365static GrSwizzle get_load_and_get_swizzle(GrColorType ct, SkRasterPipeline::StockStage* load,
Greg Daniele877dce2019-07-11 10:52:43 -0400366 bool* isNormalized, bool* isSRGB) {
Brian Salomonf30b1c12019-06-20 12:25:02 -0400367 GrSwizzle swizzle("rgba");
368 *isNormalized = true;
Greg Daniele877dce2019-07-11 10:52:43 -0400369 *isSRGB = false;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400370 switch (ct) {
371 case GrColorType::kAlpha_8: *load = SkRasterPipeline::load_a8; break;
372 case GrColorType::kBGR_565: *load = SkRasterPipeline::load_565; break;
373 case GrColorType::kABGR_4444: *load = SkRasterPipeline::load_4444; break;
374 case GrColorType::kRGBA_8888: *load = SkRasterPipeline::load_8888; break;
375 case GrColorType::kRG_88: *load = SkRasterPipeline::load_rg88; break;
376 case GrColorType::kRGBA_1010102: *load = SkRasterPipeline::load_1010102; break;
377 case GrColorType::kAlpha_F16: *load = SkRasterPipeline::load_af16; break;
378 case GrColorType::kRGBA_F16_Clamped: *load = SkRasterPipeline::load_f16; break;
379 case GrColorType::kRG_1616: *load = SkRasterPipeline::load_rg1616; break;
380 case GrColorType::kRGBA_16161616: *load = SkRasterPipeline::load_16161616; break;
381
Greg Daniele877dce2019-07-11 10:52:43 -0400382 case GrColorType::kRGBA_8888_SRGB: *load = SkRasterPipeline::load_8888;
383 *isSRGB = true;
384 break;
Brian Salomone14cfbe2019-06-24 15:00:58 -0400385 case GrColorType::kRG_F16: *load = SkRasterPipeline::load_rgf16;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400386 *isNormalized = false;
387 break;
388 case GrColorType::kRGBA_F16: *load = SkRasterPipeline::load_f16;
389 *isNormalized = false;
390 break;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400391 case GrColorType::kRGBA_F32: *load = SkRasterPipeline::load_f32;
392 *isNormalized = false;
393 break;
Brian Salomon8f8354a2019-07-31 20:12:02 -0400394 case GrColorType::kAlpha_8xxx: *load = SkRasterPipeline::load_8888;
395 swizzle = GrSwizzle("000r");
396 break;
397 case GrColorType::kAlpha_F32xxx: *load = SkRasterPipeline::load_f32;
398 swizzle = GrSwizzle("000r");
399 break;
400 case GrColorType::kGray_8xxx: *load = SkRasterPipeline::load_8888;
401 swizzle = GrSwizzle("rrr1");
402 break;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400403 case GrColorType::kR_16: *load = SkRasterPipeline::load_a16;
404 swizzle = GrSwizzle("a001");
405 break;
406 case GrColorType::kGray_8: *load = SkRasterPipeline::load_a8;
407 swizzle = GrSwizzle("aaa1");
408 break;
409 case GrColorType::kBGRA_8888: *load = SkRasterPipeline::load_8888;
410 swizzle = GrSwizzle("bgra");
411 break;
412 case GrColorType::kRGB_888x: *load = SkRasterPipeline::load_8888;
413 swizzle = GrSwizzle("rgb1");
414 break;
415
416 case GrColorType::kUnknown:
Brian Salomonf30b1c12019-06-20 12:25:02 -0400417 SK_ABORT("unexpected CT");
418 }
419 return swizzle;
420}
421
422static GrSwizzle get_dst_swizzle_and_store(GrColorType ct, SkRasterPipeline::StockStage* store,
Greg Daniele877dce2019-07-11 10:52:43 -0400423 bool* isNormalized, bool* isSRGB) {
Brian Salomonf30b1c12019-06-20 12:25:02 -0400424 GrSwizzle swizzle("rgba");
425 *isNormalized = true;
Greg Daniele877dce2019-07-11 10:52:43 -0400426 *isSRGB = false;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400427 switch (ct) {
428 case GrColorType::kAlpha_8: *store = SkRasterPipeline::store_a8; break;
429 case GrColorType::kBGR_565: *store = SkRasterPipeline::store_565; break;
430 case GrColorType::kABGR_4444: *store = SkRasterPipeline::store_4444; break;
431 case GrColorType::kRGBA_8888: *store = SkRasterPipeline::store_8888; break;
432 case GrColorType::kRG_88: *store = SkRasterPipeline::store_rg88; break;
433 case GrColorType::kRGBA_1010102: *store = SkRasterPipeline::store_1010102; break;
434 case GrColorType::kRGBA_F16_Clamped: *store = SkRasterPipeline::store_f16; break;
435 case GrColorType::kRG_1616: *store = SkRasterPipeline::store_rg1616; break;
436 case GrColorType::kRGBA_16161616: *store = SkRasterPipeline::store_16161616; break;
437
Greg Daniele877dce2019-07-11 10:52:43 -0400438 case GrColorType::kRGBA_8888_SRGB: *store = SkRasterPipeline::store_8888;
439 *isSRGB = true;
440 break;
Brian Salomone14cfbe2019-06-24 15:00:58 -0400441 case GrColorType::kRG_F16: *store = SkRasterPipeline::store_rgf16;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400442 *isNormalized = false;
443 break;
444 case GrColorType::kAlpha_F16: *store = SkRasterPipeline::store_af16;
445 *isNormalized = false;
446 break;
447 case GrColorType::kRGBA_F16: *store = SkRasterPipeline::store_f16;
448 *isNormalized = false;
449 break;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400450 case GrColorType::kRGBA_F32: *store = SkRasterPipeline::store_f32;
451 *isNormalized = false;
452 break;
Brian Salomon8f8354a2019-07-31 20:12:02 -0400453 case GrColorType::kAlpha_8xxx: *store = SkRasterPipeline::store_8888;
454 swizzle = GrSwizzle("a000");
455 break;
456 case GrColorType::kAlpha_F32xxx: *store = SkRasterPipeline::store_f32;
457 swizzle = GrSwizzle("a000");
458 break;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400459 case GrColorType::kR_16: swizzle = GrSwizzle("000r");
460 *store = SkRasterPipeline::store_a16;
461 break;
462 case GrColorType::kBGRA_8888: swizzle = GrSwizzle("bgra");
463 *store = SkRasterPipeline::store_8888;
464 break;
465 case GrColorType::kRGB_888x: swizzle = GrSwizzle("rgb1");
466 *store = SkRasterPipeline::store_8888;
467 break;
468
469 case GrColorType::kGray_8: // not currently supported as output
Brian Salomon8f8354a2019-07-31 20:12:02 -0400470 case GrColorType::kGray_8xxx: // not currently supported as output
Brian Salomonf30b1c12019-06-20 12:25:02 -0400471 case GrColorType::kUnknown:
Brian Salomonf30b1c12019-06-20 12:25:02 -0400472 SK_ABORT("unexpected CT");
473 }
474 return swizzle;
475}
476
477static inline void append_clamp_gamut(SkRasterPipeline* pipeline) {
478 // SkRasterPipeline may not know our color type and also doesn't like caller to directly
479 // append clamp_gamut. Fake it out.
480 static SkImageInfo fakeII = SkImageInfo::MakeN32Premul(1, 1);
481 pipeline->append_gamut_clamp_if_normalized(fakeII);
482}
483
Brian Salomon1d435302019-07-01 13:05:28 -0400484bool GrConvertPixels(const GrPixelInfo& dstInfo, void* dst, size_t dstRB,
485 const GrPixelInfo& srcInfo, const void* src, size_t srcRB,
Brian Salomon8f8354a2019-07-31 20:12:02 -0400486 bool flipY) {
Brian Salomonc42eb662019-06-24 17:13:00 -0400487 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
Brian Salomon1d435302019-07-01 13:05:28 -0400488 if (!srcInfo.isValid() || !dstInfo.isValid()) {
Brian Salomonf30b1c12019-06-20 12:25:02 -0400489 return false;
490 }
Brian Salomon1d435302019-07-01 13:05:28 -0400491 if (!src || !dst) {
Brian Salomonf30b1c12019-06-20 12:25:02 -0400492 return false;
493 }
Brian Salomon1d435302019-07-01 13:05:28 -0400494 if (dstInfo.width() != srcInfo.width() || srcInfo.height() != dstInfo.height()) {
495 return false;
496 }
497 if (GrColorTypeComponentFlags(dstInfo.colorType()) & kGray_SkColorTypeComponentFlag) {
Brian Salomonf30b1c12019-06-20 12:25:02 -0400498 // We don't currently support conversion to Gray.
499 return false;
500 }
Brian Salomon1d435302019-07-01 13:05:28 -0400501 if (dstRB < dstInfo.minRowBytes() || srcRB < srcInfo.minRowBytes()) {
Brian Salomonf30b1c12019-06-20 12:25:02 -0400502 return false;
503 }
Brian Salomon1d435302019-07-01 13:05:28 -0400504
505 size_t srcBpp = srcInfo.bpp();
506 size_t dstBpp = dstInfo.bpp();
507
Brian Salomonf30b1c12019-06-20 12:25:02 -0400508 // SkRasterPipeline operates on row-pixels not row-bytes.
Brian Salomon1d435302019-07-01 13:05:28 -0400509 SkASSERT(dstRB % dstBpp == 0);
510 SkASSERT(srcRB % srcBpp == 0);
Brian Salomonf30b1c12019-06-20 12:25:02 -0400511
Brian Salomon77a684f2019-08-01 14:38:04 -0400512 bool premul = srcInfo.alphaType() == kUnpremul_SkAlphaType &&
513 dstInfo.alphaType() == kPremul_SkAlphaType;
514 bool unpremul = srcInfo.alphaType() == kPremul_SkAlphaType &&
515 dstInfo.alphaType() == kUnpremul_SkAlphaType;
516 bool alphaOrCSConversion =
517 premul || unpremul || !SkColorSpace::Equals(srcInfo.colorSpace(), dstInfo.colorSpace());
518
519 if (srcInfo.colorType() == dstInfo.colorType() && !alphaOrCSConversion) {
520 size_t tightRB = dstBpp * dstInfo.width();
521 if (flipY) {
522 dst = static_cast<char*>(dst) + dstRB * (dstInfo.height() - 1);
523 for (int y = 0; y < dstInfo.height(); ++y) {
524 memcpy(dst, src, tightRB);
525 src = static_cast<const char*>(src) + srcRB;
526 dst = static_cast< char*>(dst) - dstRB;
527 }
528 } else {
529 SkRectMemcpy(dst, dstRB, src, srcRB, tightRB, srcInfo.height());
530 }
531 return true;
532 }
533
Brian Salomonf30b1c12019-06-20 12:25:02 -0400534 SkRasterPipeline::StockStage load;
535 bool srcIsNormalized;
Greg Daniele877dce2019-07-11 10:52:43 -0400536 bool srcIsSRGB;
537 auto loadSwizzle = get_load_and_get_swizzle(srcInfo.colorType(), &load, &srcIsNormalized,
538 &srcIsSRGB);
Brian Salomonf30b1c12019-06-20 12:25:02 -0400539
540 SkRasterPipeline::StockStage store;
541 bool dstIsNormalized;
Greg Daniele877dce2019-07-11 10:52:43 -0400542 bool dstIsSRGB;
543 auto storeSwizzle = get_dst_swizzle_and_store(dstInfo.colorType(), &store, &dstIsNormalized,
544 &dstIsSRGB);
Brian Salomonf30b1c12019-06-20 12:25:02 -0400545
Brian Salomonf30b1c12019-06-20 12:25:02 -0400546 bool clampGamut;
547 SkTLazy<SkColorSpaceXformSteps> steps;
548 GrSwizzle loadStoreSwizzle;
549 if (alphaOrCSConversion) {
Brian Salomon1d435302019-07-01 13:05:28 -0400550 steps.init(srcInfo.colorSpace(), srcInfo.alphaType(),
551 dstInfo.colorSpace(), dstInfo.alphaType());
552 clampGamut = dstIsNormalized && dstInfo.alphaType() == kPremul_SkAlphaType;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400553 } else {
Brian Salomon1d435302019-07-01 13:05:28 -0400554 clampGamut =
555 dstIsNormalized && !srcIsNormalized && dstInfo.alphaType() == kPremul_SkAlphaType;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400556 if (!clampGamut) {
557 loadStoreSwizzle = GrSwizzle::Concat(loadSwizzle, storeSwizzle);
558 }
559 }
560 int cnt = 1;
Brian Salomon1d435302019-07-01 13:05:28 -0400561 int height = srcInfo.height();
562 SkRasterPipeline_MemoryCtx srcCtx{const_cast<void*>(src), SkToInt(srcRB / srcBpp)},
563 dstCtx{ dst , SkToInt(dstRB / dstBpp)};
Brian Salomonf30b1c12019-06-20 12:25:02 -0400564
Brian Salomon1d435302019-07-01 13:05:28 -0400565 if (flipY) {
Brian Salomonf30b1c12019-06-20 12:25:02 -0400566 // It *almost* works to point the src at the last row and negate the stride and run the
567 // whole rectangle. However, SkRasterPipeline::run()'s control loop uses size_t loop
568 // variables so it winds up relying on unsigned overflow math. It works out in practice
569 // but UBSAN says "no!" as it's technically undefined and in theory a compiler could emit
570 // code that didn't do what is intended. So we go one row at a time. :(
Brian Salomon1d435302019-07-01 13:05:28 -0400571 srcCtx.pixels = static_cast<char*>(srcCtx.pixels) + srcRB * (height - 1);
Brian Salomonf30b1c12019-06-20 12:25:02 -0400572 std::swap(cnt, height);
573 }
Greg Daniele877dce2019-07-11 10:52:43 -0400574
575 bool hasConversion = alphaOrCSConversion || clampGamut;
576
577 if (srcIsSRGB && dstIsSRGB && !hasConversion) {
578 // No need to convert from srgb if we are just going to immediately convert it back.
579 srcIsSRGB = dstIsSRGB = false;
580 }
581
582 hasConversion = hasConversion || srcIsSRGB || dstIsSRGB;
583
Brian Salomonf30b1c12019-06-20 12:25:02 -0400584 for (int i = 0; i < cnt; ++i) {
585 SkRasterPipeline_<256> pipeline;
586 pipeline.append(load, &srcCtx);
Greg Daniele877dce2019-07-11 10:52:43 -0400587 if (hasConversion) {
Brian Salomonf30b1c12019-06-20 12:25:02 -0400588 loadSwizzle.apply(&pipeline);
Greg Daniele877dce2019-07-11 10:52:43 -0400589 if (srcIsSRGB) {
590 pipeline.append(SkRasterPipeline::from_srgb);
591 }
592 if (alphaOrCSConversion) {
593 steps->apply(&pipeline, srcIsNormalized);
594 }
Brian Salomonf30b1c12019-06-20 12:25:02 -0400595 if (clampGamut) {
596 append_clamp_gamut(&pipeline);
597 }
Greg Daniele877dce2019-07-11 10:52:43 -0400598 // If we add support for storing to Gray we would add a luminance to alpha conversion
599 // here. We also wouldn't then need a to_srgb stage after since it would have not effect
600 // on the alpha channel. It would also mean we have an SRGB Gray color type which
601 // doesn't exist currently.
602 if (dstIsSRGB) {
603 pipeline.append(SkRasterPipeline::to_srgb);
604 }
Brian Salomonf30b1c12019-06-20 12:25:02 -0400605 storeSwizzle.apply(&pipeline);
606 } else {
Greg Daniele877dce2019-07-11 10:52:43 -0400607 loadStoreSwizzle.apply(&pipeline);
Brian Salomonf30b1c12019-06-20 12:25:02 -0400608 }
609 pipeline.append(store, &dstCtx);
Brian Salomon1d435302019-07-01 13:05:28 -0400610 pipeline.run(0, 0, srcInfo.width(), height);
611 srcCtx.pixels = static_cast<char*>(srcCtx.pixels) - srcRB;
612 dstCtx.pixels = static_cast<char*>(dstCtx.pixels) + dstRB;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400613 }
614 return true;
615}
Robert Phillipsc80b0e92019-07-23 10:27:09 -0400616
Robert Phillipsc80b0e92019-07-23 10:27:09 -0400617GrColorType SkColorTypeAndFormatToGrColorType(const GrCaps* caps,
618 SkColorType skCT,
619 const GrBackendFormat& format) {
620 GrColorType grCT = SkColorTypeToGrColorType(skCT);
621 // Until we support SRGB in the SkColorType we have to do this manual check here to make sure
622 // we use the correct GrColorType.
623 if (caps->isFormatSRGB(format)) {
624 if (grCT != GrColorType::kRGBA_8888) {
625 return GrColorType::kUnknown;
626 }
627 grCT = GrColorType::kRGBA_8888_SRGB;
628 }
629 return grCT;
630}