• 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         {
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