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