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