1 /*
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 "src/gpu/GrDataUtils.h"
9
10 #include "src/core/SkColorSpaceXformSteps.h"
11 #include "src/core/SkConvertPixels.h"
12 #include "src/core/SkTLazy.h"
13 #include "src/core/SkTraceEvent.h"
14 #include "src/core/SkUtils.h"
15 #include "src/gpu/GrColor.h"
16
17 struct ETC1Block {
18 uint32_t fHigh;
19 uint32_t fLow;
20 };
21
22 static const int kNumModifierTables = 8;
23 static 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
27 static 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
convert_5To8(int b)38 static 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).
test_table_entry(int rOrig,int gOrig,int bOrig,int r8,int g8,int b8,int table,int offset)45 static 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'
create_etc1_block(SkColor col,ETC1Block * block)59 static 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
num_ETC1_blocks(int w,int h)100 static int num_ETC1_blocks(int w, int h) {
101 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
GrCompressedDataSize(SkImage::CompressionType type,int width,int height)118 size_t GrCompressedDataSize(SkImage::CompressionType type, int width, int height) {
119 switch (type) {
120 case SkImage::kETC1_CompressionType:
121 {
122 int numBlocks = num_ETC1_blocks(width, height);
123 return numBlocks * sizeof(ETC1Block);
124 }
125 case SkImage::kASTC_CompressionType:
126 {
127 int size = std::ceil(width / 4.0f) * std::ceil(height / 4.0f) * 16;
128 return size;
129 }
130 }
131 SK_ABORT("Unexpected compression type");
132 }
133
134 // Fill in 'dest' with ETC1 blocks derived from 'colorf'
fillin_ETC1_with_color(int width,int height,const SkColor4f & colorf,void * dest)135 static void fillin_ETC1_with_color(int width, int height, const SkColor4f& colorf, void* dest) {
136 SkColor color = colorf.toSkColor();
137
138 ETC1Block block;
139 create_etc1_block(color, &block);
140
141 int numBlocks = num_ETC1_blocks(width, height);
142
143 for (int i = 0; i < numBlocks; ++i) {
144 ((ETC1Block*)dest)[i] = block;
145 }
146 }
147
148 // Fill in the width x height 'dest' with the munged version of 'colorf' that matches 'config'
fill_buffer_with_color(GrPixelConfig config,int width,int height,const SkColor4f & colorf,void * dest)149 static bool fill_buffer_with_color(GrPixelConfig config, int width, int height,
150 const SkColor4f& colorf, void* dest) {
151 SkASSERT(kRGB_ETC1_GrPixelConfig != config);
152
153 GrColor color = colorf.toBytes_RGBA();
154
155 uint8_t r = GrColorUnpackR(color);
156 uint8_t g = GrColorUnpackG(color);
157 uint8_t b = GrColorUnpackB(color);
158 uint8_t a = GrColorUnpackA(color);
159
160 switch (config) {
161 case kAlpha_8_GrPixelConfig: // fall through
162 case kAlpha_8_as_Alpha_GrPixelConfig: // fall through
163 case kAlpha_8_as_Red_GrPixelConfig: {
164 memset(dest, a, width * height);
165 break;
166 }
167 case kGray_8_GrPixelConfig: // fall through
168 case kGray_8_as_Lum_GrPixelConfig: // fall through
169 case kGray_8_as_Red_GrPixelConfig: {
170 uint8_t gray8 = SkComputeLuminance(r, g, b);
171
172 memset(dest, gray8, width * height);
173 break;
174 }
175 case kRGB_565_GrPixelConfig: {
176 uint16_t rgb565 = SkPack888ToRGB16(r, g, b);
177
178 sk_memset16((uint16_t*) dest, rgb565, width * height);
179 break;
180 }
181 case kRGBA_4444_GrPixelConfig: {
182 uint8_t r4 = (r >> 4) & 0xF;
183 uint8_t g4 = (g >> 4) & 0xF;
184 uint8_t b4 = (b >> 4) & 0xF;
185 uint8_t a4 = (a >> 4) & 0xF;
186
187 uint16_t rgba4444 = r4 << SK_R4444_SHIFT | g4 << SK_G4444_SHIFT |
188 b4 << SK_B4444_SHIFT | a4 << SK_A4444_SHIFT;
189
190 sk_memset16((uint16_t*) dest, rgba4444, width * height);
191 break;
192 }
193 case kRGBA_8888_GrPixelConfig: {
194 sk_memset32((uint32_t *) dest, color, width * height);
195 break;
196 }
197 case kRGB_888_GrPixelConfig: {
198 uint8_t* dest8 = (uint8_t*) dest;
199 for (int i = 0; i < width * height; ++i, dest8 += 3) {
200 dest8[0] = r;
201 dest8[1] = g;
202 dest8[2] = b;
203 }
204 break;
205 }
206 case kRGB_888X_GrPixelConfig: {
207 GrColor opaque = GrColorPackRGBA(r, g, b, 0xFF);
208
209 sk_memset32((uint32_t *) dest, opaque, width * height);
210 break;
211 }
212 case kRG_88_GrPixelConfig: {
213 uint16_t rg88 = (r << 8) | g;
214
215 sk_memset16((uint16_t*) dest, rg88, width * height);
216 break;
217 }
218 case kBGRA_8888_GrPixelConfig: {
219 GrColor swizzled = GrColorPackRGBA(b, g, r, a);
220
221 sk_memset32((uint32_t *) dest, swizzled, width * height);
222 break;
223 }
224 case kSRGBA_8888_GrPixelConfig: {
225 sk_memset32((uint32_t *) dest, color, width * height);
226 break;
227 }
228 case kRGBA_1010102_GrPixelConfig: {
229 uint32_t r10 = SkScalarRoundToInt(colorf.fR * 1023.0f);
230 uint32_t g10 = SkScalarRoundToInt(colorf.fG * 1023.0f);
231 uint32_t b10 = SkScalarRoundToInt(colorf.fB * 1023.0f);
232 uint8_t a2 = SkScalarRoundToInt(colorf.fA * 3.0f);
233
234 uint32_t rgba1010102 = a2 << 30 | b10 << 20 | g10 << 10 | r10;
235
236 sk_memset32((uint32_t *) dest, rgba1010102, width * height);
237 break;
238 }
239 case kRGBA_float_GrPixelConfig: {
240 SkColor4f* destColor = (SkColor4f*) dest;
241 for (int i = 0; i < width * height; ++i) {
242 destColor[i] = colorf;
243 }
244 break;
245 }
246 case kAlpha_half_as_Lum_GrPixelConfig: // fall through
247 case kAlpha_half_as_Red_GrPixelConfig: // fall through
248 case kAlpha_half_GrPixelConfig: {
249 SkHalf alphaHalf = SkFloatToHalf(colorf.fA);
250
251 sk_memset16((uint16_t *) dest, alphaHalf, width * height);
252 break;
253 }
254 case kRGBA_half_GrPixelConfig: // fall through
255 case kRGBA_half_Clamped_GrPixelConfig: {
256 uint64_t rHalf = SkFloatToHalf(colorf.fR);
257 uint64_t gHalf = SkFloatToHalf(colorf.fG);
258 uint64_t bHalf = SkFloatToHalf(colorf.fB);
259 uint64_t aHalf = SkFloatToHalf(colorf.fA);
260
261 uint64_t rgbaHalf = (aHalf << 48) | (bHalf << 32) | (gHalf << 16) | rHalf;
262
263 sk_memset64((uint64_t *) dest, rgbaHalf, width * height);
264 break;
265 }
266 case kR_16_GrPixelConfig: {
267 uint16_t r16 = SkScalarRoundToInt(colorf.fR * 65535.0f);
268 sk_memset16((uint16_t*) dest, r16, width * height);
269 break;
270 }
271 case kRG_1616_GrPixelConfig: {
272 uint16_t r16 = SkScalarRoundToInt(colorf.fR * 65535.0f);
273 uint16_t g16 = SkScalarRoundToInt(colorf.fG * 65535.0f);
274
275 uint32_t rg1616 = r16 << 16 | g16;
276
277 sk_memset32((uint32_t*) dest, rg1616, width * height);
278 break;
279 }
280 // Experimental (for Y416 and mutant P016/P010)
281 case kRGBA_16161616_GrPixelConfig: {
282 uint64_t r16 = SkScalarRoundToInt(colorf.fR * 65535.0f);
283 uint64_t g16 = SkScalarRoundToInt(colorf.fG * 65535.0f);
284 uint64_t b16 = SkScalarRoundToInt(colorf.fB * 65535.0f);
285 uint64_t a16 = SkScalarRoundToInt(colorf.fA * 65535.0f);
286
287 uint64_t rgba16161616 = (a16 << 48) | (b16 << 32) | (g16 << 16) | r16;
288 sk_memset64((uint64_t*) dest, rgba16161616, width * height);
289 break;
290 }
291 case kRG_half_GrPixelConfig: {
292 uint32_t rHalf = SkFloatToHalf(colorf.fR);
293 uint32_t gHalf = SkFloatToHalf(colorf.fG);
294
295 uint32_t rgHalf = (rHalf << 16) | gHalf;
296
297 sk_memset32((uint32_t *) dest, rgHalf, width * height);
298 break;
299 }
300 default:
301 return false;
302 break;
303 }
304
305 return true;
306 }
307
GrComputeTightCombinedBufferSize(size_t bytesPerPixel,int baseWidth,int baseHeight,SkTArray<size_t> * individualMipOffsets,int mipLevelCount)308 size_t GrComputeTightCombinedBufferSize(size_t bytesPerPixel, int baseWidth, int baseHeight,
309 SkTArray<size_t>* individualMipOffsets, int mipLevelCount) {
310 SkASSERT(individualMipOffsets && !individualMipOffsets->count());
311 SkASSERT(mipLevelCount >= 1);
312
313 individualMipOffsets->push_back(0);
314
315 size_t combinedBufferSize = baseWidth * bytesPerPixel * baseHeight;
316 int currentWidth = baseWidth;
317 int currentHeight = baseHeight;
318
319 // The Vulkan spec for copying a buffer to an image requires that the alignment must be at
320 // least 4 bytes and a multiple of the bytes per pixel of the image config.
321 SkASSERT(bytesPerPixel == 1 || bytesPerPixel == 2 || bytesPerPixel == 3 ||
322 bytesPerPixel == 4 || bytesPerPixel == 8 || bytesPerPixel == 16);
323 int desiredAlignment = (bytesPerPixel == 3) ? 12 : (bytesPerPixel > 4 ? bytesPerPixel : 4);
324
325 for (int currentMipLevel = 1; currentMipLevel < mipLevelCount; ++currentMipLevel) {
326 currentWidth = SkTMax(1, currentWidth / 2);
327 currentHeight = SkTMax(1, currentHeight / 2);
328
329 size_t trimmedSize = currentWidth * bytesPerPixel * currentHeight;
330 const size_t alignmentDiff = combinedBufferSize % desiredAlignment;
331 if (alignmentDiff != 0) {
332 combinedBufferSize += desiredAlignment - alignmentDiff;
333 }
334 SkASSERT((0 == combinedBufferSize % 4) && (0 == combinedBufferSize % bytesPerPixel));
335
336 individualMipOffsets->push_back(combinedBufferSize);
337 combinedBufferSize += trimmedSize;
338 }
339
340 SkASSERT(individualMipOffsets->count() == mipLevelCount);
341 return combinedBufferSize;
342 }
343
GrFillInData(GrPixelConfig config,int baseWidth,int baseHeight,const SkTArray<size_t> & individualMipOffsets,char * dstPixels,const SkColor4f & colorf)344 void GrFillInData(GrPixelConfig config, int baseWidth, int baseHeight,
345 const SkTArray<size_t>& individualMipOffsets, char* dstPixels,
346 const SkColor4f& colorf) {
347 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
348 SkASSERT(!GrPixelConfigIsCompressed(config));
349 int mipLevels = individualMipOffsets.count();
350
351 int currentWidth = baseWidth;
352 int currentHeight = baseHeight;
353 for (int currentMipLevel = 0; currentMipLevel < mipLevels; ++currentMipLevel) {
354 size_t offset = individualMipOffsets[currentMipLevel];
355
356 fill_buffer_with_color(config, currentWidth, currentHeight, colorf, &(dstPixels[offset]));
357 currentWidth = SkTMax(1, currentWidth / 2);
358 currentHeight = SkTMax(1, currentHeight / 2);
359 }
360 }
361
GrFillInCompressedData(SkImage::CompressionType type,int baseWidth,int baseHeight,char * dstPixels,const SkColor4f & colorf)362 void GrFillInCompressedData(SkImage::CompressionType type, int baseWidth, int baseHeight,
363 char* dstPixels, const SkColor4f& colorf) {
364 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
365 int currentWidth = baseWidth;
366 int currentHeight = baseHeight;
367 if (SkImage::kETC1_CompressionType == type) {
368 fillin_ETC1_with_color(currentWidth, currentHeight, colorf, dstPixels);
369 }
370 }
371
get_load_and_get_swizzle(GrColorType ct,SkRasterPipeline::StockStage * load,bool * isNormalized,bool * isSRGB)372 static GrSwizzle get_load_and_get_swizzle(GrColorType ct, SkRasterPipeline::StockStage* load,
373 bool* isNormalized, bool* isSRGB) {
374 GrSwizzle swizzle("rgba");
375 *isNormalized = true;
376 *isSRGB = false;
377 switch (ct) {
378 case GrColorType::kAlpha_8: *load = SkRasterPipeline::load_a8; break;
379 case GrColorType::kBGR_565: *load = SkRasterPipeline::load_565; break;
380 case GrColorType::kABGR_4444: *load = SkRasterPipeline::load_4444; break;
381 case GrColorType::kRGBA_8888: *load = SkRasterPipeline::load_8888; break;
382 case GrColorType::kRG_88: *load = SkRasterPipeline::load_rg88; break;
383 case GrColorType::kRGBA_1010102: *load = SkRasterPipeline::load_1010102; break;
384 case GrColorType::kAlpha_F16: *load = SkRasterPipeline::load_af16; break;
385 case GrColorType::kRGBA_F16_Clamped: *load = SkRasterPipeline::load_f16; break;
386 case GrColorType::kRG_1616: *load = SkRasterPipeline::load_rg1616; break;
387 case GrColorType::kRGBA_16161616: *load = SkRasterPipeline::load_16161616; break;
388
389 case GrColorType::kRGBA_8888_SRGB: *load = SkRasterPipeline::load_8888;
390 *isSRGB = true;
391 break;
392 case GrColorType::kRG_F16: *load = SkRasterPipeline::load_rgf16;
393 *isNormalized = false;
394 break;
395 case GrColorType::kRGBA_F16: *load = SkRasterPipeline::load_f16;
396 *isNormalized = false;
397 break;
398 case GrColorType::kRGBA_F32: *load = SkRasterPipeline::load_f32;
399 *isNormalized = false;
400 break;
401 case GrColorType::kAlpha_8xxx: *load = SkRasterPipeline::load_8888;
402 swizzle = GrSwizzle("000r");
403 break;
404 case GrColorType::kAlpha_F32xxx: *load = SkRasterPipeline::load_f32;
405 swizzle = GrSwizzle("000r");
406 break;
407 case GrColorType::kGray_8xxx: *load = SkRasterPipeline::load_8888;
408 swizzle = GrSwizzle("rrr1");
409 break;
410 case GrColorType::kR_16: *load = SkRasterPipeline::load_a16;
411 swizzle = GrSwizzle("a001");
412 break;
413 case GrColorType::kGray_8: *load = SkRasterPipeline::load_a8;
414 swizzle = GrSwizzle("aaa1");
415 break;
416 case GrColorType::kBGRA_8888: *load = SkRasterPipeline::load_8888;
417 swizzle = GrSwizzle("bgra");
418 break;
419 case GrColorType::kRGB_888x: *load = SkRasterPipeline::load_8888;
420 swizzle = GrSwizzle("rgb1");
421 break;
422
423 case GrColorType::kUnknown:
424 SK_ABORT("unexpected CT");
425 }
426 return swizzle;
427 }
428
get_dst_swizzle_and_store(GrColorType ct,SkRasterPipeline::StockStage * store,bool * isNormalized,bool * isSRGB)429 static GrSwizzle get_dst_swizzle_and_store(GrColorType ct, SkRasterPipeline::StockStage* store,
430 bool* isNormalized, bool* isSRGB) {
431 GrSwizzle swizzle("rgba");
432 *isNormalized = true;
433 *isSRGB = false;
434 switch (ct) {
435 case GrColorType::kAlpha_8: *store = SkRasterPipeline::store_a8; break;
436 case GrColorType::kBGR_565: *store = SkRasterPipeline::store_565; break;
437 case GrColorType::kABGR_4444: *store = SkRasterPipeline::store_4444; break;
438 case GrColorType::kRGBA_8888: *store = SkRasterPipeline::store_8888; break;
439 case GrColorType::kRG_88: *store = SkRasterPipeline::store_rg88; break;
440 case GrColorType::kRGBA_1010102: *store = SkRasterPipeline::store_1010102; break;
441 case GrColorType::kRGBA_F16_Clamped: *store = SkRasterPipeline::store_f16; break;
442 case GrColorType::kRG_1616: *store = SkRasterPipeline::store_rg1616; break;
443 case GrColorType::kRGBA_16161616: *store = SkRasterPipeline::store_16161616; break;
444
445 case GrColorType::kRGBA_8888_SRGB: *store = SkRasterPipeline::store_8888;
446 *isSRGB = true;
447 break;
448 case GrColorType::kRG_F16: *store = SkRasterPipeline::store_rgf16;
449 *isNormalized = false;
450 break;
451 case GrColorType::kAlpha_F16: *store = SkRasterPipeline::store_af16;
452 *isNormalized = false;
453 break;
454 case GrColorType::kRGBA_F16: *store = SkRasterPipeline::store_f16;
455 *isNormalized = false;
456 break;
457 case GrColorType::kRGBA_F32: *store = SkRasterPipeline::store_f32;
458 *isNormalized = false;
459 break;
460 case GrColorType::kAlpha_8xxx: *store = SkRasterPipeline::store_8888;
461 swizzle = GrSwizzle("a000");
462 break;
463 case GrColorType::kAlpha_F32xxx: *store = SkRasterPipeline::store_f32;
464 swizzle = GrSwizzle("a000");
465 break;
466 case GrColorType::kR_16: swizzle = GrSwizzle("000r");
467 *store = SkRasterPipeline::store_a16;
468 break;
469 case GrColorType::kBGRA_8888: swizzle = GrSwizzle("bgra");
470 *store = SkRasterPipeline::store_8888;
471 break;
472 case GrColorType::kRGB_888x: swizzle = GrSwizzle("rgb1");
473 *store = SkRasterPipeline::store_8888;
474 break;
475
476 case GrColorType::kGray_8: // not currently supported as output
477 case GrColorType::kGray_8xxx: // not currently supported as output
478 case GrColorType::kUnknown:
479 SK_ABORT("unexpected CT");
480 }
481 return swizzle;
482 }
483
append_clamp_gamut(SkRasterPipeline * pipeline)484 static inline void append_clamp_gamut(SkRasterPipeline* pipeline) {
485 // SkRasterPipeline may not know our color type and also doesn't like caller to directly
486 // append clamp_gamut. Fake it out.
487 static SkImageInfo fakeII = SkImageInfo::MakeN32Premul(1, 1);
488 pipeline->append_gamut_clamp_if_normalized(fakeII);
489 }
490
GrConvertPixels(const GrPixelInfo & dstInfo,void * dst,size_t dstRB,const GrPixelInfo & srcInfo,const void * src,size_t srcRB,bool flipY)491 bool GrConvertPixels(const GrPixelInfo& dstInfo, void* dst, size_t dstRB,
492 const GrPixelInfo& srcInfo, const void* src, size_t srcRB,
493 bool flipY) {
494 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
495 if (!srcInfo.isValid() || !dstInfo.isValid()) {
496 return false;
497 }
498 if (!src || !dst) {
499 return false;
500 }
501 if (dstInfo.width() != srcInfo.width() || srcInfo.height() != dstInfo.height()) {
502 return false;
503 }
504 if (GrColorTypeComponentFlags(dstInfo.colorType()) & kGray_SkColorTypeComponentFlag) {
505 // We don't currently support conversion to Gray.
506 return false;
507 }
508 if (dstRB < dstInfo.minRowBytes() || srcRB < srcInfo.minRowBytes()) {
509 return false;
510 }
511
512 size_t srcBpp = srcInfo.bpp();
513 size_t dstBpp = dstInfo.bpp();
514
515 // SkRasterPipeline operates on row-pixels not row-bytes.
516 SkASSERT(dstRB % dstBpp == 0);
517 SkASSERT(srcRB % srcBpp == 0);
518
519 bool premul = srcInfo.alphaType() == kUnpremul_SkAlphaType &&
520 dstInfo.alphaType() == kPremul_SkAlphaType;
521 bool unpremul = srcInfo.alphaType() == kPremul_SkAlphaType &&
522 dstInfo.alphaType() == kUnpremul_SkAlphaType;
523 bool alphaOrCSConversion =
524 premul || unpremul || !SkColorSpace::Equals(srcInfo.colorSpace(), dstInfo.colorSpace());
525
526 if (srcInfo.colorType() == dstInfo.colorType() && !alphaOrCSConversion) {
527 size_t tightRB = dstBpp * dstInfo.width();
528 if (flipY) {
529 dst = static_cast<char*>(dst) + dstRB * (dstInfo.height() - 1);
530 for (int y = 0; y < dstInfo.height(); ++y) {
531 memcpy(dst, src, tightRB);
532 src = static_cast<const char*>(src) + srcRB;
533 dst = static_cast< char*>(dst) - dstRB;
534 }
535 } else {
536 SkRectMemcpy(dst, dstRB, src, srcRB, tightRB, srcInfo.height());
537 }
538 return true;
539 }
540
541 SkRasterPipeline::StockStage load;
542 bool srcIsNormalized;
543 bool srcIsSRGB;
544 auto loadSwizzle = get_load_and_get_swizzle(srcInfo.colorType(), &load, &srcIsNormalized,
545 &srcIsSRGB);
546
547 SkRasterPipeline::StockStage store;
548 bool dstIsNormalized;
549 bool dstIsSRGB;
550 auto storeSwizzle = get_dst_swizzle_and_store(dstInfo.colorType(), &store, &dstIsNormalized,
551 &dstIsSRGB);
552
553 bool clampGamut;
554 SkTLazy<SkColorSpaceXformSteps> steps;
555 GrSwizzle loadStoreSwizzle;
556 if (alphaOrCSConversion) {
557 steps.init(srcInfo.colorSpace(), srcInfo.alphaType(),
558 dstInfo.colorSpace(), dstInfo.alphaType());
559 clampGamut = dstIsNormalized && dstInfo.alphaType() == kPremul_SkAlphaType;
560 } else {
561 clampGamut =
562 dstIsNormalized && !srcIsNormalized && dstInfo.alphaType() == kPremul_SkAlphaType;
563 if (!clampGamut) {
564 loadStoreSwizzle = GrSwizzle::Concat(loadSwizzle, storeSwizzle);
565 }
566 }
567 int cnt = 1;
568 int height = srcInfo.height();
569 SkRasterPipeline_MemoryCtx srcCtx{const_cast<void*>(src), SkToInt(srcRB / srcBpp)},
570 dstCtx{ dst , SkToInt(dstRB / dstBpp)};
571
572 if (flipY) {
573 // It *almost* works to point the src at the last row and negate the stride and run the
574 // whole rectangle. However, SkRasterPipeline::run()'s control loop uses size_t loop
575 // variables so it winds up relying on unsigned overflow math. It works out in practice
576 // but UBSAN says "no!" as it's technically undefined and in theory a compiler could emit
577 // code that didn't do what is intended. So we go one row at a time. :(
578 srcCtx.pixels = static_cast<char*>(srcCtx.pixels) + srcRB * (height - 1);
579 std::swap(cnt, height);
580 }
581
582 bool hasConversion = alphaOrCSConversion || clampGamut;
583
584 if (srcIsSRGB && dstIsSRGB && !hasConversion) {
585 // No need to convert from srgb if we are just going to immediately convert it back.
586 srcIsSRGB = dstIsSRGB = false;
587 }
588
589 hasConversion = hasConversion || srcIsSRGB || dstIsSRGB;
590
591 for (int i = 0; i < cnt; ++i) {
592 SkRasterPipeline_<256> pipeline;
593 pipeline.append(load, &srcCtx);
594 if (hasConversion) {
595 loadSwizzle.apply(&pipeline);
596 if (srcIsSRGB) {
597 pipeline.append(SkRasterPipeline::from_srgb);
598 }
599 if (alphaOrCSConversion) {
600 steps->apply(&pipeline, srcIsNormalized);
601 }
602 if (clampGamut) {
603 append_clamp_gamut(&pipeline);
604 }
605 // If we add support for storing to Gray we would add a luminance to alpha conversion
606 // here. We also wouldn't then need a to_srgb stage after since it would have not effect
607 // on the alpha channel. It would also mean we have an SRGB Gray color type which
608 // doesn't exist currently.
609 if (dstIsSRGB) {
610 pipeline.append(SkRasterPipeline::to_srgb);
611 }
612 storeSwizzle.apply(&pipeline);
613 } else {
614 loadStoreSwizzle.apply(&pipeline);
615 }
616 pipeline.append(store, &dstCtx);
617 pipeline.run(0, 0, srcInfo.width(), height);
618 srcCtx.pixels = static_cast<char*>(srcCtx.pixels) - srcRB;
619 dstCtx.pixels = static_cast<char*>(dstCtx.pixels) + dstRB;
620 }
621 return true;
622 }
623
SkColorTypeAndFormatToGrColorType(const GrCaps * caps,SkColorType skCT,const GrBackendFormat & format)624 GrColorType SkColorTypeAndFormatToGrColorType(const GrCaps* caps,
625 SkColorType skCT,
626 const GrBackendFormat& format) {
627 GrColorType grCT = SkColorTypeToGrColorType(skCT);
628 // Until we support SRGB in the SkColorType we have to do this manual check here to make sure
629 // we use the correct GrColorType.
630 if (caps->isFormatSRGB(format)) {
631 if (grCT != GrColorType::kRGBA_8888) {
632 return GrColorType::kUnknown;
633 }
634 grCT = GrColorType::kRGBA_8888_SRGB;
635 }
636 return grCT;
637 }
638