• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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             int numBlocks = num_ETC1_blocks(width, height);
122             return numBlocks * sizeof(ETC1Block);
123     }
124     SK_ABORT("Unexpected compression type");
125 }
126 
127 // Fill in 'dest' with ETC1 blocks derived from 'colorf'
fillin_ETC1_with_color(int width,int height,const SkColor4f & colorf,void * dest)128 static void fillin_ETC1_with_color(int width, int height, const SkColor4f& colorf, void* dest) {
129     SkColor color = colorf.toSkColor();
130 
131     ETC1Block block;
132     create_etc1_block(color, &block);
133 
134     int numBlocks = num_ETC1_blocks(width, height);
135 
136     for (int i = 0; i < numBlocks; ++i) {
137         ((ETC1Block*)dest)[i] = block;
138     }
139 }
140 
141 // 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)142 static bool fill_buffer_with_color(GrPixelConfig config, int width, int height,
143                                    const SkColor4f& colorf, void* dest) {
144     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 
153     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);
164 
165             memset(dest, gray8, width * height);
166             break;
167         }
168         case kRGB_565_GrPixelConfig: {
169             uint16_t rgb565 = SkPack888ToRGB16(r, g, b);
170 
171             sk_memset16((uint16_t*) dest, rgb565, width * height);
172             break;
173         }
174         case kRGBA_4444_GrPixelConfig: {
175             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 
183             sk_memset16((uint16_t*) dest, rgba4444, width * height);
184             break;
185         }
186         case kRGBA_8888_GrPixelConfig: {
187             sk_memset32((uint32_t *) dest, color, width * height);
188             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 
202             sk_memset32((uint32_t *) dest, opaque, width * height);
203             break;
204         }
205         case kRG_88_GrPixelConfig: {
206             uint16_t rg88 = (r << 8) | g;
207 
208             sk_memset16((uint16_t*) dest, rg88, width * height);
209             break;
210         }
211         case kBGRA_8888_GrPixelConfig: {
212             GrColor swizzled = GrColorPackRGBA(b, g, r, a);
213 
214             sk_memset32((uint32_t *) dest, swizzled, width * height);
215             break;
216         }
217         case kSRGBA_8888_GrPixelConfig: {
218             sk_memset32((uint32_t *) dest, color, width * height);
219             break;
220         }
221         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 
229             sk_memset32((uint32_t *) dest, rgba1010102, width * height);
230             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         }
239         case kAlpha_half_as_Lum_GrPixelConfig:                  // fall through
240         case kAlpha_half_as_Red_GrPixelConfig:                  // fall through
241         case kAlpha_half_GrPixelConfig: {
242             SkHalf alphaHalf = SkFloatToHalf(colorf.fA);
243 
244             sk_memset16((uint16_t *) dest, alphaHalf, width * height);
245             break;
246         }
247         case kRGBA_half_GrPixelConfig:                          // fall through
248         case kRGBA_half_Clamped_GrPixelConfig: {
249             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);
257             break;
258         }
259         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         }
273         // 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         }
293         default:
294             return false;
295             break;
296     }
297 
298     return true;
299 }
300 
GrComputeTightCombinedBufferSize(size_t bytesPerPixel,int baseWidth,int baseHeight,SkTArray<size_t> * individualMipOffsets,int mipLevelCount)301 size_t GrComputeTightCombinedBufferSize(size_t bytesPerPixel, int baseWidth, int baseHeight,
302                                         SkTArray<size_t>* individualMipOffsets, int mipLevelCount) {
303     SkASSERT(individualMipOffsets && !individualMipOffsets->count());
304     SkASSERT(mipLevelCount >= 1);
305 
306     individualMipOffsets->push_back(0);
307 
308     size_t combinedBufferSize = baseWidth * bytesPerPixel * baseHeight;
309     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 
322         size_t trimmedSize = currentWidth * bytesPerPixel * currentHeight;
323         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 
GrFillInData(GrPixelConfig config,int baseWidth,int baseHeight,const SkTArray<size_t> & individualMipOffsets,char * dstPixels,const SkColor4f & colorf)337 void GrFillInData(GrPixelConfig config, int baseWidth, int baseHeight,
338                   const SkTArray<size_t>& individualMipOffsets, char* dstPixels,
339                   const SkColor4f& colorf) {
340     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
341     SkASSERT(!GrPixelConfigIsCompressed(config));
342     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 
349         fill_buffer_with_color(config, currentWidth, currentHeight, colorf, &(dstPixels[offset]));
350         currentWidth = SkTMax(1, currentWidth / 2);
351         currentHeight = SkTMax(1, currentHeight / 2);
352     }
353 }
354 
GrFillInCompressedData(SkImage::CompressionType type,int baseWidth,int baseHeight,char * dstPixels,const SkColor4f & colorf)355 void 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 
get_load_and_get_swizzle(GrColorType ct,SkRasterPipeline::StockStage * load,bool * isNormalized,bool * isSRGB)365 static GrSwizzle get_load_and_get_swizzle(GrColorType ct, SkRasterPipeline::StockStage* load,
366                                           bool* isNormalized, bool* isSRGB) {
367     GrSwizzle swizzle("rgba");
368     *isNormalized = true;
369     *isSRGB = false;
370     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 
382         case GrColorType::kRGBA_8888_SRGB:   *load = SkRasterPipeline::load_8888;
383                                              *isSRGB = true;
384                                              break;
385         case GrColorType::kRG_F16:           *load = SkRasterPipeline::load_rgf16;
386                                              *isNormalized = false;
387                                              break;
388         case GrColorType::kRGBA_F16:         *load = SkRasterPipeline::load_f16;
389                                              *isNormalized = false;
390                                              break;
391         case GrColorType::kRGBA_F32:         *load = SkRasterPipeline::load_f32;
392                                              *isNormalized = false;
393                                              break;
394         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;
403         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:
417             SK_ABORT("unexpected CT");
418     }
419     return swizzle;
420 }
421 
get_dst_swizzle_and_store(GrColorType ct,SkRasterPipeline::StockStage * store,bool * isNormalized,bool * isSRGB)422 static GrSwizzle get_dst_swizzle_and_store(GrColorType ct, SkRasterPipeline::StockStage* store,
423                                            bool* isNormalized, bool* isSRGB) {
424     GrSwizzle swizzle("rgba");
425     *isNormalized = true;
426     *isSRGB = false;
427     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 
438         case GrColorType::kRGBA_8888_SRGB:   *store = SkRasterPipeline::store_8888;
439                                              *isSRGB = true;
440                                              break;
441         case GrColorType::kRG_F16:           *store = SkRasterPipeline::store_rgf16;
442                                              *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;
450         case GrColorType::kRGBA_F32:         *store = SkRasterPipeline::store_f32;
451                                              *isNormalized = false;
452                                              break;
453         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;
459         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
470         case GrColorType::kGray_8xxx:  // not currently supported as output
471         case GrColorType::kUnknown:
472             SK_ABORT("unexpected CT");
473     }
474     return swizzle;
475 }
476 
append_clamp_gamut(SkRasterPipeline * pipeline)477 static 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 
GrConvertPixels(const GrPixelInfo & dstInfo,void * dst,size_t dstRB,const GrPixelInfo & srcInfo,const void * src,size_t srcRB,bool flipY)484 bool GrConvertPixels(const GrPixelInfo& dstInfo,       void* dst, size_t dstRB,
485                      const GrPixelInfo& srcInfo, const void* src, size_t srcRB,
486                      bool flipY) {
487     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
488     if (!srcInfo.isValid() || !dstInfo.isValid()) {
489         return false;
490     }
491     if (!src || !dst) {
492         return false;
493     }
494     if (dstInfo.width() != srcInfo.width() || srcInfo.height() != dstInfo.height()) {
495         return false;
496     }
497     if (GrColorTypeComponentFlags(dstInfo.colorType()) & kGray_SkColorTypeComponentFlag) {
498         // We don't currently support conversion to Gray.
499         return false;
500     }
501     if (dstRB < dstInfo.minRowBytes() || srcRB < srcInfo.minRowBytes()) {
502         return false;
503     }
504 
505     size_t srcBpp = srcInfo.bpp();
506     size_t dstBpp = dstInfo.bpp();
507 
508     // SkRasterPipeline operates on row-pixels not row-bytes.
509     SkASSERT(dstRB % dstBpp == 0);
510     SkASSERT(srcRB % srcBpp == 0);
511 
512     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 
534     SkRasterPipeline::StockStage load;
535     bool srcIsNormalized;
536     bool srcIsSRGB;
537     auto loadSwizzle = get_load_and_get_swizzle(srcInfo.colorType(), &load, &srcIsNormalized,
538                                                 &srcIsSRGB);
539 
540     SkRasterPipeline::StockStage store;
541     bool dstIsNormalized;
542     bool dstIsSRGB;
543     auto storeSwizzle = get_dst_swizzle_and_store(dstInfo.colorType(), &store, &dstIsNormalized,
544                                                   &dstIsSRGB);
545 
546     bool clampGamut;
547     SkTLazy<SkColorSpaceXformSteps> steps;
548     GrSwizzle loadStoreSwizzle;
549     if (alphaOrCSConversion) {
550         steps.init(srcInfo.colorSpace(), srcInfo.alphaType(),
551                    dstInfo.colorSpace(), dstInfo.alphaType());
552         clampGamut = dstIsNormalized && dstInfo.alphaType() == kPremul_SkAlphaType;
553     } else {
554         clampGamut =
555                 dstIsNormalized && !srcIsNormalized && dstInfo.alphaType() == kPremul_SkAlphaType;
556         if (!clampGamut) {
557             loadStoreSwizzle = GrSwizzle::Concat(loadSwizzle, storeSwizzle);
558         }
559     }
560     int cnt = 1;
561     int height = srcInfo.height();
562     SkRasterPipeline_MemoryCtx srcCtx{const_cast<void*>(src), SkToInt(srcRB / srcBpp)},
563                                dstCtx{                  dst , SkToInt(dstRB / dstBpp)};
564 
565     if (flipY) {
566         // 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. :(
571         srcCtx.pixels = static_cast<char*>(srcCtx.pixels) + srcRB * (height - 1);
572         std::swap(cnt, height);
573     }
574 
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 
584     for (int i = 0; i < cnt; ++i) {
585         SkRasterPipeline_<256> pipeline;
586         pipeline.append(load, &srcCtx);
587         if (hasConversion) {
588             loadSwizzle.apply(&pipeline);
589             if (srcIsSRGB) {
590                 pipeline.append(SkRasterPipeline::from_srgb);
591             }
592             if (alphaOrCSConversion) {
593                 steps->apply(&pipeline, srcIsNormalized);
594             }
595             if (clampGamut) {
596                 append_clamp_gamut(&pipeline);
597             }
598             // 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             }
605             storeSwizzle.apply(&pipeline);
606         } else {
607             loadStoreSwizzle.apply(&pipeline);
608         }
609         pipeline.append(store, &dstCtx);
610         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;
613     }
614     return true;
615 }
616 
SkColorTypeAndFormatToGrColorType(const GrCaps * caps,SkColorType skCT,const GrBackendFormat & format)617 GrColorType 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 }
631