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