• 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/SkCompressedDataUtils.h"
12 #include "src/core/SkConvertPixels.h"
13 #include "src/core/SkMipMap.h"
14 #include "src/core/SkTLazy.h"
15 #include "src/core/SkTraceEvent.h"
16 #include "src/core/SkUtils.h"
17 #include "src/gpu/GrColor.h"
18 #include "src/gpu/GrImageInfo.h"
19 
20 struct ETC1Block {
21     uint32_t fHigh;
22     uint32_t fLow;
23 };
24 
25 constexpr uint32_t kDiffBit = 0x2; // set -> differential; not-set -> individual
26 
extend_5To8bits(int b)27 static inline int extend_5To8bits(int b) {
28     int c = b & 0x1f;
29     return (c << 3) | (c >> 2);
30 }
31 
32 static const int kNumETC1ModifierTables = 8;
33 static const int kNumETC1PixelIndices = 4;
34 
35 // The index of each row in this table is the ETC1 table codeword
36 // The index of each column in this table is the ETC1 pixel index value
37 static const int kETC1ModifierTables[kNumETC1ModifierTables][kNumETC1PixelIndices] = {
38     /* 0 */ { 2,    8,  -2,   -8 },
39     /* 1 */ { 5,   17,  -5,  -17 },
40     /* 2 */ { 9,   29,  -9,  -29 },
41     /* 3 */ { 13,  42, -13,  -42 },
42     /* 4 */ { 18,  60, -18,  -60 },
43     /* 5 */ { 24,  80, -24,  -80 },
44     /* 6 */ { 33, 106, -33, -106 },
45     /* 7 */ { 47, 183, -47, -183 }
46 };
47 
48 // Evaluate one of the entries in 'kModifierTables' to see how close it can get (r8,g8,b8) to
49 // 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)50 static int test_table_entry(int rOrig, int gOrig, int bOrig,
51                             int r8, int g8, int b8,
52                             int table, int offset) {
53     SkASSERT(0 <= table && table < 8);
54     SkASSERT(0 <= offset && offset < 4);
55 
56     r8 = SkTPin<int>(r8 + kETC1ModifierTables[table][offset], 0, 255);
57     g8 = SkTPin<int>(g8 + kETC1ModifierTables[table][offset], 0, 255);
58     b8 = SkTPin<int>(b8 + kETC1ModifierTables[table][offset], 0, 255);
59 
60     return SkTAbs(rOrig - r8) + SkTAbs(gOrig - g8) + SkTAbs(bOrig - b8);
61 }
62 
63 // Create an ETC1 compressed block that is filled with 'col'
create_etc1_block(SkColor col,ETC1Block * block)64 static void create_etc1_block(SkColor col, ETC1Block* block) {
65     uint32_t high = 0;
66     uint32_t low = 0;
67 
68     int rOrig = SkColorGetR(col);
69     int gOrig = SkColorGetG(col);
70     int bOrig = SkColorGetB(col);
71 
72     int r5 = SkMulDiv255Round(31, rOrig);
73     int g5 = SkMulDiv255Round(31, gOrig);
74     int b5 = SkMulDiv255Round(31, bOrig);
75 
76     int r8 = extend_5To8bits(r5);
77     int g8 = extend_5To8bits(g5);
78     int b8 = extend_5To8bits(b5);
79 
80     // We always encode solid color textures in differential mode (i.e., with a 555 base color) but
81     // with zero diffs (i.e., bits 26-24, 18-16 and 10-8 are left 0).
82     high |= (r5 << 27) | (g5 << 19) | (b5 << 11) | kDiffBit;
83 
84     int bestTableIndex = 0, bestPixelIndex = 0;
85     int bestSoFar = 1024;
86     for (int tableIndex = 0; tableIndex < kNumETC1ModifierTables; ++tableIndex) {
87         for (int pixelIndex = 0; pixelIndex < kNumETC1PixelIndices; ++pixelIndex) {
88             int score = test_table_entry(rOrig, gOrig, bOrig, r8, g8, b8,
89                                          tableIndex, pixelIndex);
90 
91             if (bestSoFar > score) {
92                 bestSoFar = score;
93                 bestTableIndex = tableIndex;
94                 bestPixelIndex = pixelIndex;
95             }
96         }
97     }
98 
99     high |= (bestTableIndex << 5) | (bestTableIndex << 2);
100 
101     if (bestPixelIndex & 0x1) {
102         low |= 0xFFFF;
103     }
104     if (bestPixelIndex & 0x2) {
105         low |= 0xFFFF0000;
106     }
107 
108     block->fHigh = SkBSwap32(high);
109     block->fLow = SkBSwap32(low);
110 }
111 
num_4x4_blocks(int size)112 static int num_4x4_blocks(int size) {
113     return ((size + 3) & ~3) >> 2;
114 }
115 
num_ETC1_blocks(int w,int h)116 static int num_ETC1_blocks(int w, int h) {
117     w = num_4x4_blocks(w);
118     h = num_4x4_blocks(h);
119 
120     return w * h;
121 }
122 
123 struct BC1Block {
124     uint16_t fColor0;
125     uint16_t fColor1;
126     uint32_t fIndices;
127 };
128 
to565(SkColor col)129 static uint16_t to565(SkColor col) {
130     int r5 = SkMulDiv255Round(31, SkColorGetR(col));
131     int g6 = SkMulDiv255Round(63, SkColorGetG(col));
132     int b5 = SkMulDiv255Round(31, SkColorGetB(col));
133 
134     return (r5 << 11) | (g6 << 5) | b5;
135 }
136 
137 // Create a BC1 compressed block that has two colors but is initialized to 'col0'
create_BC1_block(SkColor col0,SkColor col1,BC1Block * block)138 static void create_BC1_block(SkColor col0, SkColor col1, BC1Block* block) {
139     block->fColor0 = to565(col0);
140     block->fColor1 = to565(col1);
141     SkASSERT(block->fColor0 <= block->fColor1); // we always assume transparent blocks
142 
143     if (col0 == SK_ColorTRANSPARENT) {
144         // This sets all 16 pixels to just use color3 (under the assumption
145         // that this is a kBC1_RGBA8_UNORM texture. Note that in this case
146         // fColor0 will be opaque black.
147         block->fIndices = 0xFFFFFFFF;
148     } else {
149         // This sets all 16 pixels to just use 'fColor0'
150         block->fIndices = 0;
151     }
152 }
153 
GrCompressedRowBytes(SkImage::CompressionType type,int width)154 size_t GrCompressedRowBytes(SkImage::CompressionType type, int width) {
155     switch (type) {
156         case SkImage::CompressionType::kNone:
157             return 0;
158         case SkImage::CompressionType::kETC2_RGB8_UNORM:
159         case SkImage::CompressionType::kBC1_RGB8_UNORM:
160         case SkImage::CompressionType::kBC1_RGBA8_UNORM: {
161             int numBlocksWidth = num_4x4_blocks(width);
162 
163             static_assert(sizeof(ETC1Block) == sizeof(BC1Block));
164             return numBlocksWidth * sizeof(ETC1Block);
165         }
166     }
167     SkUNREACHABLE;
168 }
169 
GrCompressedDimensions(SkImage::CompressionType type,SkISize baseDimensions)170 SkISize GrCompressedDimensions(SkImage::CompressionType type, SkISize baseDimensions) {
171     switch (type) {
172         case SkImage::CompressionType::kNone:
173             return baseDimensions;
174         case SkImage::CompressionType::kETC2_RGB8_UNORM:
175         case SkImage::CompressionType::kBC1_RGB8_UNORM:
176         case SkImage::CompressionType::kBC1_RGBA8_UNORM: {
177             int numBlocksWidth = num_4x4_blocks(baseDimensions.width());
178             int numBlocksHeight = num_4x4_blocks(baseDimensions.height());
179 
180             // Each BC1_RGB8_UNORM and ETC1 block has 16 pixels
181             return { 4 * numBlocksWidth, 4 * numBlocksHeight };
182         }
183     }
184     SkUNREACHABLE;
185 }
186 
187 // Fill in 'dest' with ETC1 blocks derived from 'colorf'
fillin_ETC1_with_color(SkISize dimensions,const SkColor4f & colorf,char * dest)188 static void fillin_ETC1_with_color(SkISize dimensions, const SkColor4f& colorf, char* dest) {
189     SkColor color = colorf.toSkColor();
190 
191     ETC1Block block;
192     create_etc1_block(color, &block);
193 
194     int numBlocks = num_ETC1_blocks(dimensions.width(), dimensions.height());
195 
196     for (int i = 0; i < numBlocks; ++i) {
197         memcpy(dest, &block, sizeof(ETC1Block));
198         dest += sizeof(ETC1Block);
199     }
200 }
201 
202 // Fill in 'dest' with BC1 blocks derived from 'colorf'
fillin_BC1_with_color(SkISize dimensions,const SkColor4f & colorf,char * dest)203 static void fillin_BC1_with_color(SkISize dimensions, const SkColor4f& colorf, char* dest) {
204     SkColor color = colorf.toSkColor();
205 
206     BC1Block block;
207     create_BC1_block(color, color, &block);
208 
209     int numBlocks = num_ETC1_blocks(dimensions.width(), dimensions.height());
210 
211     for (int i = 0; i < numBlocks; ++i) {
212         memcpy(dest, &block, sizeof(BC1Block));
213         dest += sizeof(BC1Block);
214     }
215 }
216 
217 #if GR_TEST_UTILS
218 
219 // Fill in 'dstPixels' with BC1 blocks derived from the 'pixmap'.
GrTwoColorBC1Compress(const SkPixmap & pixmap,SkColor otherColor,char * dstPixels)220 void GrTwoColorBC1Compress(const SkPixmap& pixmap, SkColor otherColor, char* dstPixels) {
221     BC1Block* dstBlocks = reinterpret_cast<BC1Block*>(dstPixels);
222     SkASSERT(pixmap.colorType() == SkColorType::kRGBA_8888_SkColorType);
223 
224     BC1Block block;
225 
226     // black -> fColor0, otherColor -> fColor1
227     create_BC1_block(SK_ColorBLACK, otherColor, &block);
228 
229     int numXBlocks = num_4x4_blocks(pixmap.width());
230     int numYBlocks = num_4x4_blocks(pixmap.height());
231 
232     for (int y = 0; y < numYBlocks; ++y) {
233         for (int x = 0; x < numXBlocks; ++x) {
234             int shift = 0;
235             int offsetX = 4 * x, offsetY = 4 * y;
236             block.fIndices = 0;  // init all the pixels to color0 (i.e., opaque black)
237             for (int i = 0; i < 4; ++i) {
238                 for (int j = 0; j < 4; ++j, shift += 2) {
239                     if (offsetX + j >= pixmap.width() || offsetY + i >= pixmap.height()) {
240                         // This can happen for the topmost levels of a mipmap and for
241                         // non-multiple of 4 textures
242                         continue;
243                     }
244 
245                     SkColor tmp = pixmap.getColor(offsetX + j, offsetY + i);
246                     if (tmp == SK_ColorTRANSPARENT) {
247                         // For RGBA BC1 images color3 is set to transparent black
248                         block.fIndices |= 3 << shift;
249                     } else if (tmp != SK_ColorBLACK) {
250                         block.fIndices |= 1 << shift; // color1
251                     }
252                 }
253             }
254 
255             dstBlocks[y*numXBlocks + x] = block;
256         }
257     }
258 }
259 
260 #endif
261 
GrComputeTightCombinedBufferSize(size_t bytesPerPixel,SkISize baseDimensions,SkTArray<size_t> * individualMipOffsets,int mipLevelCount)262 size_t GrComputeTightCombinedBufferSize(size_t bytesPerPixel, SkISize baseDimensions,
263                                         SkTArray<size_t>* individualMipOffsets, int mipLevelCount) {
264     SkASSERT(individualMipOffsets && !individualMipOffsets->count());
265     SkASSERT(mipLevelCount >= 1);
266 
267     individualMipOffsets->push_back(0);
268 
269     size_t combinedBufferSize = baseDimensions.width() * bytesPerPixel * baseDimensions.height();
270     SkISize levelDimensions = baseDimensions;
271 
272     // The Vulkan spec for copying a buffer to an image requires that the alignment must be at
273     // least 4 bytes and a multiple of the bytes per pixel of the image config.
274     SkASSERT(bytesPerPixel == 1 || bytesPerPixel == 2 || bytesPerPixel == 3 ||
275              bytesPerPixel == 4 || bytesPerPixel == 8 || bytesPerPixel == 16);
276     int desiredAlignment = (bytesPerPixel == 3) ? 12 : (bytesPerPixel > 4 ? bytesPerPixel : 4);
277 
278     for (int currentMipLevel = 1; currentMipLevel < mipLevelCount; ++currentMipLevel) {
279         levelDimensions = {std::max(1, levelDimensions.width() /2),
280                            std::max(1, levelDimensions.height()/2)};
281 
282         size_t trimmedSize = levelDimensions.area() * bytesPerPixel;
283         const size_t alignmentDiff = combinedBufferSize % desiredAlignment;
284         if (alignmentDiff != 0) {
285             combinedBufferSize += desiredAlignment - alignmentDiff;
286         }
287         SkASSERT((0 == combinedBufferSize % 4) && (0 == combinedBufferSize % bytesPerPixel));
288 
289         individualMipOffsets->push_back(combinedBufferSize);
290         combinedBufferSize += trimmedSize;
291     }
292 
293     SkASSERT(individualMipOffsets->count() == mipLevelCount);
294     return combinedBufferSize;
295 }
296 
GrFillInCompressedData(SkImage::CompressionType type,SkISize dimensions,GrMipMapped mipMapped,char * dstPixels,const SkColor4f & colorf)297 void GrFillInCompressedData(SkImage::CompressionType type, SkISize dimensions,
298                             GrMipMapped mipMapped, char* dstPixels, const SkColor4f& colorf) {
299     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
300 
301     int numMipLevels = 1;
302     if (mipMapped == GrMipMapped::kYes) {
303         numMipLevels = SkMipMap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
304     }
305 
306     size_t offset = 0;
307 
308     for (int i = 0; i < numMipLevels; ++i) {
309         size_t levelSize = SkCompressedDataSize(type, dimensions, nullptr, false);
310 
311         if (SkImage::CompressionType::kETC2_RGB8_UNORM == type) {
312             fillin_ETC1_with_color(dimensions, colorf, &dstPixels[offset]);
313         } else {
314             SkASSERT(type == SkImage::CompressionType::kBC1_RGB8_UNORM ||
315                      type == SkImage::CompressionType::kBC1_RGBA8_UNORM);
316             fillin_BC1_with_color(dimensions, colorf, &dstPixels[offset]);
317         }
318 
319         offset += levelSize;
320         dimensions = {std::max(1, dimensions.width()/2), std::max(1, dimensions.height()/2)};
321     }
322 }
323 
get_load_and_src_swizzle(GrColorType ct,SkRasterPipeline::StockStage * load,bool * isNormalized,bool * isSRGB)324 static GrSwizzle get_load_and_src_swizzle(GrColorType ct, SkRasterPipeline::StockStage* load,
325                                           bool* isNormalized, bool* isSRGB) {
326     GrSwizzle swizzle("rgba");
327     *isNormalized = true;
328     *isSRGB = false;
329     switch (ct) {
330         case GrColorType::kAlpha_8:          *load = SkRasterPipeline::load_a8;       break;
331         case GrColorType::kAlpha_16:         *load = SkRasterPipeline::load_a16;      break;
332         case GrColorType::kBGR_565:          *load = SkRasterPipeline::load_565;      break;
333         case GrColorType::kABGR_4444:        *load = SkRasterPipeline::load_4444;     break;
334         case GrColorType::kRGBA_8888:        *load = SkRasterPipeline::load_8888;     break;
335         case GrColorType::kRG_88:            *load = SkRasterPipeline::load_rg88;     break;
336         case GrColorType::kRGBA_1010102:     *load = SkRasterPipeline::load_1010102;  break;
337         case GrColorType::kAlpha_F16:        *load = SkRasterPipeline::load_af16;     break;
338         case GrColorType::kRGBA_F16_Clamped: *load = SkRasterPipeline::load_f16;      break;
339         case GrColorType::kRG_1616:          *load = SkRasterPipeline::load_rg1616;   break;
340         case GrColorType::kRGBA_16161616:    *load = SkRasterPipeline::load_16161616; break;
341 
342         case GrColorType::kRGBA_8888_SRGB:   *load = SkRasterPipeline::load_8888;
343                                              *isSRGB = true;
344                                              break;
345         case GrColorType::kRG_F16:           *load = SkRasterPipeline::load_rgf16;
346                                              *isNormalized = false;
347                                              break;
348         case GrColorType::kRGBA_F16:         *load = SkRasterPipeline::load_f16;
349                                              *isNormalized = false;
350                                              break;
351         case GrColorType::kRGBA_F32:         *load = SkRasterPipeline::load_f32;
352                                              *isNormalized = false;
353                                              break;
354         case GrColorType::kAlpha_8xxx:       *load = SkRasterPipeline::load_8888;
355                                              swizzle = GrSwizzle("000r");
356                                              break;
357         case GrColorType::kAlpha_F32xxx:     *load = SkRasterPipeline::load_f32;
358                                              swizzle = GrSwizzle("000r");
359                                              break;
360         case GrColorType::kGray_8xxx:       *load = SkRasterPipeline::load_8888;
361                                              swizzle = GrSwizzle("rrr1");
362                                              break;
363         case GrColorType::kGray_8:           *load = SkRasterPipeline::load_a8;
364                                              swizzle = GrSwizzle("aaa1");
365                                              break;
366         case GrColorType::kBGRA_8888:        *load = SkRasterPipeline::load_8888;
367                                              swizzle = GrSwizzle("bgra");
368                                              break;
369         case GrColorType::kRGB_888x:         *load = SkRasterPipeline::load_8888;
370                                              swizzle = GrSwizzle("rgb1");
371                                              break;
372 
373         // These are color types we don't expect to ever have to load.
374         case GrColorType::kRGB_888:
375         case GrColorType::kR_8:
376         case GrColorType::kR_16:
377         case GrColorType::kR_F16:
378         case GrColorType::kGray_F16:
379         case GrColorType::kUnknown:
380             SK_ABORT("unexpected CT");
381     }
382     return swizzle;
383 }
384 
get_dst_swizzle_and_store(GrColorType ct,SkRasterPipeline::StockStage * store,bool * doLumToAlpha,bool * isNormalized,bool * isSRGB)385 static GrSwizzle get_dst_swizzle_and_store(GrColorType ct, SkRasterPipeline::StockStage* store,
386                                            bool* doLumToAlpha, bool* isNormalized, bool* isSRGB) {
387     GrSwizzle swizzle("rgba");
388     *isNormalized = true;
389     *isSRGB = false;
390     *doLumToAlpha = false;
391     switch (ct) {
392         case GrColorType::kAlpha_8:          *store = SkRasterPipeline::store_a8;       break;
393         case GrColorType::kAlpha_16:         *store = SkRasterPipeline::store_a16;      break;
394         case GrColorType::kBGR_565:          *store = SkRasterPipeline::store_565;      break;
395         case GrColorType::kABGR_4444:        *store = SkRasterPipeline::store_4444;     break;
396         case GrColorType::kRGBA_8888:        *store = SkRasterPipeline::store_8888;     break;
397         case GrColorType::kRG_88:            *store = SkRasterPipeline::store_rg88;     break;
398         case GrColorType::kRGBA_1010102:     *store = SkRasterPipeline::store_1010102;  break;
399         case GrColorType::kRGBA_F16_Clamped: *store = SkRasterPipeline::store_f16;      break;
400         case GrColorType::kRG_1616:          *store = SkRasterPipeline::store_rg1616;   break;
401         case GrColorType::kRGBA_16161616:    *store = SkRasterPipeline::store_16161616; break;
402 
403         case GrColorType::kRGBA_8888_SRGB:   *store = SkRasterPipeline::store_8888;
404                                              *isSRGB = true;
405                                              break;
406         case GrColorType::kRG_F16:           *store = SkRasterPipeline::store_rgf16;
407                                              *isNormalized = false;
408                                              break;
409         case GrColorType::kAlpha_F16:        *store = SkRasterPipeline::store_af16;
410                                              *isNormalized = false;
411                                              break;
412         case GrColorType::kRGBA_F16:         *store = SkRasterPipeline::store_f16;
413                                              *isNormalized = false;
414                                              break;
415         case GrColorType::kRGBA_F32:         *store = SkRasterPipeline::store_f32;
416                                              *isNormalized = false;
417                                              break;
418         case GrColorType::kAlpha_8xxx:       *store = SkRasterPipeline::store_8888;
419                                              swizzle = GrSwizzle("a000");
420                                              break;
421         case GrColorType::kAlpha_F32xxx:     *store = SkRasterPipeline::store_f32;
422                                              swizzle = GrSwizzle("a000");
423                                              break;
424         case GrColorType::kBGRA_8888:        swizzle = GrSwizzle("bgra");
425                                              *store = SkRasterPipeline::store_8888;
426                                              break;
427         case GrColorType::kRGB_888x:         swizzle = GrSwizzle("rgb1");
428                                              *store = SkRasterPipeline::store_8888;
429                                              break;
430         case GrColorType::kR_8:              swizzle = GrSwizzle("agbr");
431                                              *store = SkRasterPipeline::store_a8;
432                                              break;
433         case GrColorType::kR_16:             swizzle = GrSwizzle("agbr");
434                                              *store = SkRasterPipeline::store_a16;
435                                              break;
436         case GrColorType::kR_F16:            swizzle = GrSwizzle("agbr");
437                                              *store = SkRasterPipeline::store_af16;
438                                              break;
439         case GrColorType::kGray_F16:         *doLumToAlpha = true;
440                                              *store = SkRasterPipeline::store_af16;
441                                              break;
442         case GrColorType::kGray_8:           *doLumToAlpha = true;
443                                              *store = SkRasterPipeline::store_a8;
444                                              break;
445         case GrColorType::kGray_8xxx:        *doLumToAlpha = true;
446                                              *store = SkRasterPipeline::store_8888;
447                                              swizzle = GrSwizzle("a000");
448                                              break;
449 
450         // These are color types we don't expect to ever have to store.
451         case GrColorType::kRGB_888:  // This is handled specially in GrConvertPixels.
452         case GrColorType::kUnknown:
453             SK_ABORT("unexpected CT");
454     }
455     return swizzle;
456 }
457 
append_clamp_gamut(SkRasterPipeline * pipeline)458 static inline void append_clamp_gamut(SkRasterPipeline* pipeline) {
459     // SkRasterPipeline may not know our color type and also doesn't like caller to directly
460     // append clamp_gamut. Fake it out.
461     static SkImageInfo fakeII = SkImageInfo::MakeN32Premul(1, 1);
462     pipeline->append_gamut_clamp_if_normalized(fakeII);
463 }
464 
GrConvertPixels(const GrImageInfo & dstInfo,void * dst,size_t dstRB,const GrImageInfo & srcInfo,const void * src,size_t srcRB,bool flipY)465 bool GrConvertPixels(const GrImageInfo& dstInfo,       void* dst, size_t dstRB,
466                      const GrImageInfo& srcInfo, const void* src, size_t srcRB,
467                      bool flipY) {
468     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
469     if (srcInfo.colorType() == GrColorType::kRGB_888) {
470         // We don't expect to have to convert from this format.
471         return false;
472     }
473     if (!srcInfo.isValid() || !dstInfo.isValid()) {
474         return false;
475     }
476     if (!src || !dst) {
477         return false;
478     }
479     if (dstInfo.dimensions() != srcInfo.dimensions()) {
480         return false;
481     }
482     if (dstRB < dstInfo.minRowBytes() || srcRB < srcInfo.minRowBytes()) {
483         return false;
484     }
485     if (dstInfo.colorType() == GrColorType::kRGB_888) {
486         // SkRasterPipeline doesn't handle writing to RGB_888. So we have it write to RGB_888x and
487         // then do another conversion that does the 24bit packing.
488         auto tempDstInfo = dstInfo.makeColorType(GrColorType::kRGB_888x);
489         auto tempRB = tempDstInfo.minRowBytes();
490         std::unique_ptr<char[]> tempDst(new char[tempRB * tempDstInfo.height()]);
491         if (!GrConvertPixels(tempDstInfo, tempDst.get(), tempRB, srcInfo, src, srcRB, flipY)) {
492             return false;
493         }
494         auto* tRow = reinterpret_cast<const char*>(tempDst.get());
495         auto* dRow = reinterpret_cast<char*>(dst);
496         for (int y = 0; y < dstInfo.height(); ++y, tRow += tempRB, dRow += dstRB) {
497             for (int x = 0; x < dstInfo.width(); ++x) {
498                 auto t = reinterpret_cast<const uint32_t*>(tRow + x * sizeof(uint32_t));
499                 auto d = reinterpret_cast<uint32_t*>(dRow + x * 3);
500                 memcpy(d, t, 3);
501             }
502         }
503         return true;
504     }
505 
506     size_t srcBpp = srcInfo.bpp();
507     size_t dstBpp = dstInfo.bpp();
508 
509     // SkRasterPipeline operates on row-pixels not row-bytes.
510     SkASSERT(dstRB % dstBpp == 0);
511     SkASSERT(srcRB % srcBpp == 0);
512 
513     bool premul   = srcInfo.alphaType() == kUnpremul_SkAlphaType &&
514                     dstInfo.alphaType() == kPremul_SkAlphaType;
515     bool unpremul = srcInfo.alphaType() == kPremul_SkAlphaType &&
516                     dstInfo.alphaType() == kUnpremul_SkAlphaType;
517     bool alphaOrCSConversion =
518             premul || unpremul || !SkColorSpace::Equals(srcInfo.colorSpace(), dstInfo.colorSpace());
519 
520     if (srcInfo.colorType() == dstInfo.colorType() && !alphaOrCSConversion) {
521         size_t tightRB = dstBpp * dstInfo.width();
522         if (flipY) {
523             dst = static_cast<char*>(dst) + dstRB * (dstInfo.height() - 1);
524             for (int y = 0; y < dstInfo.height(); ++y) {
525                 memcpy(dst, src, tightRB);
526                 src = static_cast<const char*>(src) + srcRB;
527                 dst = static_cast<      char*>(dst) - dstRB;
528             }
529         } else {
530             SkRectMemcpy(dst, dstRB, src, srcRB, tightRB, srcInfo.height());
531         }
532         return true;
533     }
534 
535     SkRasterPipeline::StockStage load;
536     bool srcIsNormalized;
537     bool srcIsSRGB;
538     auto loadSwizzle =
539             get_load_and_src_swizzle(srcInfo.colorType(), &load, &srcIsNormalized, &srcIsSRGB);
540 
541     SkRasterPipeline::StockStage store;
542     bool doLumToAlpha;
543     bool dstIsNormalized;
544     bool dstIsSRGB;
545     auto storeSwizzle = get_dst_swizzle_and_store(dstInfo.colorType(), &store, &doLumToAlpha,
546                                                   &dstIsNormalized, &dstIsSRGB);
547 
548     bool clampGamut;
549     SkTLazy<SkColorSpaceXformSteps> steps;
550     GrSwizzle loadStoreSwizzle;
551     if (alphaOrCSConversion) {
552         steps.init(srcInfo.colorSpace(), srcInfo.alphaType(),
553                    dstInfo.colorSpace(), dstInfo.alphaType());
554         clampGamut = dstIsNormalized && dstInfo.alphaType() == kPremul_SkAlphaType;
555     } else {
556         clampGamut =
557                 dstIsNormalized && !srcIsNormalized && dstInfo.alphaType() == kPremul_SkAlphaType;
558         if (!clampGamut) {
559             loadStoreSwizzle = GrSwizzle::Concat(loadSwizzle, storeSwizzle);
560         }
561     }
562     int cnt = 1;
563     int height = srcInfo.height();
564     SkRasterPipeline_MemoryCtx srcCtx{const_cast<void*>(src), SkToInt(srcRB / srcBpp)},
565                                dstCtx{                  dst , SkToInt(dstRB / dstBpp)};
566 
567     if (flipY) {
568         // It *almost* works to point the src at the last row and negate the stride and run the
569         // whole rectangle. However, SkRasterPipeline::run()'s control loop uses size_t loop
570         // variables so it winds up relying on unsigned overflow math. It works out in practice
571         // but UBSAN says "no!" as it's technically undefined and in theory a compiler could emit
572         // code that didn't do what is intended. So we go one row at a time. :(
573         srcCtx.pixels = static_cast<char*>(srcCtx.pixels) + srcRB * (height - 1);
574         std::swap(cnt, height);
575     }
576 
577     bool hasConversion = alphaOrCSConversion || clampGamut || doLumToAlpha;
578 
579     if (srcIsSRGB && dstIsSRGB && !hasConversion) {
580         // No need to convert from srgb if we are just going to immediately convert it back.
581         srcIsSRGB = dstIsSRGB = false;
582     }
583 
584     hasConversion = hasConversion || srcIsSRGB || dstIsSRGB;
585 
586     for (int i = 0; i < cnt; ++i) {
587         SkRasterPipeline_<256> pipeline;
588         pipeline.append(load, &srcCtx);
589         if (hasConversion) {
590             loadSwizzle.apply(&pipeline);
591             if (srcIsSRGB) {
592                 pipeline.append(SkRasterPipeline::from_srgb);
593             }
594             if (alphaOrCSConversion) {
595                 steps->apply(&pipeline, srcIsNormalized);
596             }
597             if (clampGamut) {
598                 append_clamp_gamut(&pipeline);
599             }
600             if (doLumToAlpha) {
601                 pipeline.append(SkRasterPipeline::StockStage::bt709_luminance_or_luma_to_alpha);
602                 // If we ever needed to convert from linear-encoded gray to sRGB-encoded
603                 // gray we'd have a problem here because the subsequent to_srgb stage
604                 // ignores the alpha channel (where we just stashed the gray). There are
605                 // several ways that could be fixed but given our current set of color types
606                 // this should never happen.
607                 SkASSERT(!dstIsSRGB);
608             }
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 
GrClearImage(const GrImageInfo & dstInfo,void * dst,size_t dstRB,SkColor4f color)624 bool GrClearImage(const GrImageInfo& dstInfo, void* dst, size_t dstRB, SkColor4f color) {
625     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
626 
627     if (!dstInfo.isValid()) {
628         return false;
629     }
630     if (!dst) {
631         return false;
632     }
633     if (dstRB < dstInfo.minRowBytes()) {
634         return false;
635     }
636     if (dstInfo.colorType() == GrColorType::kRGB_888) {
637         // SkRasterPipeline doesn't handle writing to RGB_888. So we handle that specially here.
638         uint32_t rgba = color.toBytes_RGBA();
639         for (int y = 0; y < dstInfo.height(); ++y) {
640             char* d = static_cast<char*>(dst) + y * dstRB;
641             for (int x = 0; x < dstInfo.width(); ++x, d += 3) {
642                 memcpy(d, &rgba, 3);
643             }
644         }
645         return true;
646     }
647 
648     bool doLumToAlpha;
649     bool isNormalized;
650     bool dstIsSRGB;
651     SkRasterPipeline::StockStage store;
652     GrSwizzle storeSwizzle = get_dst_swizzle_and_store(dstInfo.colorType(), &store, &doLumToAlpha,
653                                                        &isNormalized, &dstIsSRGB);
654     char block[64];
655     SkArenaAlloc alloc(block, sizeof(block), 1024);
656     SkRasterPipeline_<256> pipeline;
657     pipeline.append_constant_color(&alloc, color);
658     if (doLumToAlpha) {
659         pipeline.append(SkRasterPipeline::StockStage::bt709_luminance_or_luma_to_alpha);
660         // If we ever needed to convert from linear-encoded gray to sRGB-encoded
661         // gray we'd have a problem here because the subsequent to_srgb stage
662         // ignores the alpha channel (where we just stashed the gray). There are
663         // several ways that could be fixed but given our current set of color types
664         // this should never happen.
665         SkASSERT(!dstIsSRGB);
666     }
667     if (dstIsSRGB) {
668         pipeline.append(SkRasterPipeline::to_srgb);
669     }
670     storeSwizzle.apply(&pipeline);
671     SkRasterPipeline_MemoryCtx dstCtx{dst, SkToInt(dstRB/dstInfo.bpp())};
672     pipeline.append(store, &dstCtx);
673     pipeline.run(0, 0, dstInfo.width(), dstInfo.height());
674 
675     return true;
676 }
677 
SkColorTypeAndFormatToGrColorType(const GrCaps * caps,SkColorType skCT,const GrBackendFormat & format)678 GrColorType SkColorTypeAndFormatToGrColorType(const GrCaps* caps,
679                                               SkColorType skCT,
680                                               const GrBackendFormat& format) {
681     GrColorType grCT = SkColorTypeToGrColorType(skCT);
682     // Until we support SRGB in the SkColorType we have to do this manual check here to make sure
683     // we use the correct GrColorType.
684     if (caps->isFormatSRGB(format)) {
685         if (grCT != GrColorType::kRGBA_8888) {
686             return GrColorType::kUnknown;
687         }
688         grCT = GrColorType::kRGBA_8888_SRGB;
689     }
690     return grCT;
691 }
692