blob: 7af2cd656b9c353f546d1e352522f87ce7d19c6b [file] [log] [blame]
Robert Phillips459b2952019-05-23 09:38:27 -04001/*
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
Brian Salomon77a684f2019-08-01 14:38:04 -04008#include "src/gpu/GrDataUtils.h"
9
Mike Klein8aa0edf2020-10-16 11:04:18 -050010#include "include/private/SkTPin.h"
Mike Klein04984312020-05-19 12:41:05 -050011#include "include/third_party/skcms/skcms.h"
Brian Salomonf30b1c12019-06-20 12:25:02 -040012#include "src/core/SkColorSpaceXformSteps.h"
Robert Phillips99dead92020-01-27 16:11:57 -050013#include "src/core/SkCompressedDataUtils.h"
Brian Salomon77a684f2019-08-01 14:38:04 -040014#include "src/core/SkConvertPixels.h"
Mike Reed13711eb2020-07-14 17:16:32 -040015#include "src/core/SkMipmap.h"
Brian Salomonf30b1c12019-06-20 12:25:02 -040016#include "src/core/SkTLazy.h"
Brian Salomonc42eb662019-06-24 17:13:00 -040017#include "src/core/SkTraceEvent.h"
Robert Phillipsb5e331a2019-05-28 10:58:09 -040018#include "src/core/SkUtils.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040019#include "src/gpu/GrColor.h"
Brian Salomonf2ebdd92019-09-30 12:15:30 -040020#include "src/gpu/GrImageInfo.h"
Robert Phillips459b2952019-05-23 09:38:27 -040021
Robert Phillips8043f322019-05-31 08:11:36 -040022struct ETC1Block {
23 uint32_t fHigh;
24 uint32_t fLow;
25};
26
Robert Phillipsd4f68312020-01-31 10:15:05 -050027constexpr uint32_t kDiffBit = 0x2; // set -> differential; not-set -> individual
28
29static inline int extend_5To8bits(int b) {
30 int c = b & 0x1f;
31 return (c << 3) | (c >> 2);
32}
33
Robert Phillips8f259a02019-12-20 11:32:27 -050034static const int kNumETC1ModifierTables = 8;
35static const int kNumETC1PixelIndices = 4;
Robert Phillips459b2952019-05-23 09:38:27 -040036
37// The index of each row in this table is the ETC1 table codeword
38// The index of each column in this table is the ETC1 pixel index value
Robert Phillips8f259a02019-12-20 11:32:27 -050039static const int kETC1ModifierTables[kNumETC1ModifierTables][kNumETC1PixelIndices] = {
Robert Phillips459b2952019-05-23 09:38:27 -040040 /* 0 */ { 2, 8, -2, -8 },
41 /* 1 */ { 5, 17, -5, -17 },
42 /* 2 */ { 9, 29, -9, -29 },
43 /* 3 */ { 13, 42, -13, -42 },
44 /* 4 */ { 18, 60, -18, -60 },
45 /* 5 */ { 24, 80, -24, -80 },
46 /* 6 */ { 33, 106, -33, -106 },
47 /* 7 */ { 47, 183, -47, -183 }
48};
49
Robert Phillips459b2952019-05-23 09:38:27 -040050// Evaluate one of the entries in 'kModifierTables' to see how close it can get (r8,g8,b8) to
51// the original color (rOrig, gOrib, bOrig).
52static int test_table_entry(int rOrig, int gOrig, int bOrig,
53 int r8, int g8, int b8,
54 int table, int offset) {
55 SkASSERT(0 <= table && table < 8);
56 SkASSERT(0 <= offset && offset < 4);
57
Robert Phillips8f259a02019-12-20 11:32:27 -050058 r8 = SkTPin<int>(r8 + kETC1ModifierTables[table][offset], 0, 255);
59 g8 = SkTPin<int>(g8 + kETC1ModifierTables[table][offset], 0, 255);
60 b8 = SkTPin<int>(b8 + kETC1ModifierTables[table][offset], 0, 255);
Robert Phillips459b2952019-05-23 09:38:27 -040061
62 return SkTAbs(rOrig - r8) + SkTAbs(gOrig - g8) + SkTAbs(bOrig - b8);
63}
64
65// Create an ETC1 compressed block that is filled with 'col'
66static void create_etc1_block(SkColor col, ETC1Block* block) {
Robert Phillips48257d72019-12-16 14:20:53 -050067 uint32_t high = 0;
68 uint32_t low = 0;
Robert Phillips459b2952019-05-23 09:38:27 -040069
70 int rOrig = SkColorGetR(col);
71 int gOrig = SkColorGetG(col);
72 int bOrig = SkColorGetB(col);
73
74 int r5 = SkMulDiv255Round(31, rOrig);
75 int g5 = SkMulDiv255Round(31, gOrig);
76 int b5 = SkMulDiv255Round(31, bOrig);
77
Robert Phillipsd4f68312020-01-31 10:15:05 -050078 int r8 = extend_5To8bits(r5);
79 int g8 = extend_5To8bits(g5);
80 int b8 = extend_5To8bits(b5);
Robert Phillips459b2952019-05-23 09:38:27 -040081
Robert Phillipsd4f68312020-01-31 10:15:05 -050082 // We always encode solid color textures in differential mode (i.e., with a 555 base color) but
83 // with zero diffs (i.e., bits 26-24, 18-16 and 10-8 are left 0).
84 high |= (r5 << 27) | (g5 << 19) | (b5 << 11) | kDiffBit;
Robert Phillips459b2952019-05-23 09:38:27 -040085
86 int bestTableIndex = 0, bestPixelIndex = 0;
87 int bestSoFar = 1024;
Robert Phillips8f259a02019-12-20 11:32:27 -050088 for (int tableIndex = 0; tableIndex < kNumETC1ModifierTables; ++tableIndex) {
89 for (int pixelIndex = 0; pixelIndex < kNumETC1PixelIndices; ++pixelIndex) {
Robert Phillips459b2952019-05-23 09:38:27 -040090 int score = test_table_entry(rOrig, gOrig, bOrig, r8, g8, b8,
91 tableIndex, pixelIndex);
92
93 if (bestSoFar > score) {
94 bestSoFar = score;
95 bestTableIndex = tableIndex;
96 bestPixelIndex = pixelIndex;
97 }
98 }
99 }
100
Robert Phillips48257d72019-12-16 14:20:53 -0500101 high |= (bestTableIndex << 5) | (bestTableIndex << 2);
Robert Phillips459b2952019-05-23 09:38:27 -0400102
Robert Phillips48257d72019-12-16 14:20:53 -0500103 if (bestPixelIndex & 0x1) {
104 low |= 0xFFFF;
Robert Phillips459b2952019-05-23 09:38:27 -0400105 }
Robert Phillips48257d72019-12-16 14:20:53 -0500106 if (bestPixelIndex & 0x2) {
107 low |= 0xFFFF0000;
108 }
109
110 block->fHigh = SkBSwap32(high);
111 block->fLow = SkBSwap32(low);
Robert Phillips459b2952019-05-23 09:38:27 -0400112}
113
Robert Phillips162e04b2020-01-28 14:22:43 -0500114static int num_4x4_blocks(int size) {
115 return ((size + 3) & ~3) >> 2;
Jim Van Verthe3671012019-09-18 09:53:31 -0400116}
117
118static int num_ETC1_blocks(int w, int h) {
Robert Phillips162e04b2020-01-28 14:22:43 -0500119 w = num_4x4_blocks(w);
120 h = num_4x4_blocks(h);
Robert Phillips459b2952019-05-23 09:38:27 -0400121
122 return w * h;
123}
124
Robert Phillips8f259a02019-12-20 11:32:27 -0500125struct BC1Block {
126 uint16_t fColor0;
127 uint16_t fColor1;
128 uint32_t fIndices;
129};
130
Robert Phillipsac908022020-01-14 16:54:17 -0500131static uint16_t to565(SkColor col) {
Robert Phillips8f259a02019-12-20 11:32:27 -0500132 int r5 = SkMulDiv255Round(31, SkColorGetR(col));
133 int g6 = SkMulDiv255Round(63, SkColorGetG(col));
134 int b5 = SkMulDiv255Round(31, SkColorGetB(col));
135
Robert Phillipsac908022020-01-14 16:54:17 -0500136 return (r5 << 11) | (g6 << 5) | b5;
137}
138
139// Create a BC1 compressed block that has two colors but is initialized to 'col0'
140static void create_BC1_block(SkColor col0, SkColor col1, BC1Block* block) {
141 block->fColor0 = to565(col0);
142 block->fColor1 = to565(col1);
Robert Phillipsd095b9f2020-02-03 16:12:51 -0500143 SkASSERT(block->fColor0 <= block->fColor1); // we always assume transparent blocks
144
Robert Phillipsb0855272020-01-15 12:56:52 -0500145 if (col0 == SK_ColorTRANSPARENT) {
146 // This sets all 16 pixels to just use color3 (under the assumption
147 // that this is a kBC1_RGBA8_UNORM texture. Note that in this case
148 // fColor0 will be opaque black.
149 block->fIndices = 0xFFFFFFFF;
150 } else {
151 // This sets all 16 pixels to just use 'fColor0'
152 block->fIndices = 0;
153 }
Robert Phillips8f259a02019-12-20 11:32:27 -0500154}
155
Greg Danielc89a7ee2020-10-12 16:50:18 -0400156size_t GrNumBlocks(SkImage::CompressionType type, SkISize baseDimensions) {
157 switch (type) {
158 case SkImage::CompressionType::kNone:
159 return baseDimensions.width() * baseDimensions.height();
160 case SkImage::CompressionType::kETC2_RGB8_UNORM:
161 case SkImage::CompressionType::kBC1_RGB8_UNORM:
162 case SkImage::CompressionType::kBC1_RGBA8_UNORM: {
163 int numBlocksWidth = num_4x4_blocks(baseDimensions.width());
164 int numBlocksHeight = num_4x4_blocks(baseDimensions.height());
165
166 return numBlocksWidth * numBlocksHeight;
167 }
168 }
169 SkUNREACHABLE;
170}
171
Jim Van Verthe3671012019-09-18 09:53:31 -0400172size_t GrCompressedRowBytes(SkImage::CompressionType type, int width) {
173 switch (type) {
Robert Phillipsab2b7222019-12-10 10:05:06 -0500174 case SkImage::CompressionType::kNone:
175 return 0;
Robert Phillipsc558f722020-01-13 13:02:26 -0500176 case SkImage::CompressionType::kETC2_RGB8_UNORM:
Robert Phillipsb0855272020-01-15 12:56:52 -0500177 case SkImage::CompressionType::kBC1_RGB8_UNORM:
178 case SkImage::CompressionType::kBC1_RGBA8_UNORM: {
Robert Phillips162e04b2020-01-28 14:22:43 -0500179 int numBlocksWidth = num_4x4_blocks(width);
Robert Phillips8f259a02019-12-20 11:32:27 -0500180
181 static_assert(sizeof(ETC1Block) == sizeof(BC1Block));
Jim Van Verthe3671012019-09-18 09:53:31 -0400182 return numBlocksWidth * sizeof(ETC1Block);
Robert Phillipsb0855272020-01-15 12:56:52 -0500183 }
Jim Van Verthe3671012019-09-18 09:53:31 -0400184 }
Robert Phillipsab2b7222019-12-10 10:05:06 -0500185 SkUNREACHABLE;
Jim Van Verthe3671012019-09-18 09:53:31 -0400186}
187
Robert Phillips41acc0e2020-01-06 13:29:53 -0500188SkISize GrCompressedDimensions(SkImage::CompressionType type, SkISize baseDimensions) {
189 switch (type) {
190 case SkImage::CompressionType::kNone:
191 return baseDimensions;
Robert Phillipsc558f722020-01-13 13:02:26 -0500192 case SkImage::CompressionType::kETC2_RGB8_UNORM:
Robert Phillipsb0855272020-01-15 12:56:52 -0500193 case SkImage::CompressionType::kBC1_RGB8_UNORM:
194 case SkImage::CompressionType::kBC1_RGBA8_UNORM: {
Robert Phillips162e04b2020-01-28 14:22:43 -0500195 int numBlocksWidth = num_4x4_blocks(baseDimensions.width());
196 int numBlocksHeight = num_4x4_blocks(baseDimensions.height());
Robert Phillips41acc0e2020-01-06 13:29:53 -0500197
198 // Each BC1_RGB8_UNORM and ETC1 block has 16 pixels
199 return { 4 * numBlocksWidth, 4 * numBlocksHeight };
Robert Phillipsb0855272020-01-15 12:56:52 -0500200 }
Robert Phillips41acc0e2020-01-06 13:29:53 -0500201 }
202 SkUNREACHABLE;
203}
204
Robert Phillips28a5a432019-06-07 12:46:21 -0400205// Fill in 'dest' with ETC1 blocks derived from 'colorf'
Robert Phillips48257d72019-12-16 14:20:53 -0500206static void fillin_ETC1_with_color(SkISize dimensions, const SkColor4f& colorf, char* dest) {
Robert Phillips459b2952019-05-23 09:38:27 -0400207 SkColor color = colorf.toSkColor();
208
209 ETC1Block block;
210 create_etc1_block(color, &block);
211
Robert Phillips48257d72019-12-16 14:20:53 -0500212 int numBlocks = num_ETC1_blocks(dimensions.width(), dimensions.height());
Robert Phillips8043f322019-05-31 08:11:36 -0400213
Robert Phillips459b2952019-05-23 09:38:27 -0400214 for (int i = 0; i < numBlocks; ++i) {
Robert Phillips48257d72019-12-16 14:20:53 -0500215 memcpy(dest, &block, sizeof(ETC1Block));
216 dest += sizeof(ETC1Block);
Robert Phillips459b2952019-05-23 09:38:27 -0400217 }
218}
219
Robert Phillips8f259a02019-12-20 11:32:27 -0500220// Fill in 'dest' with BC1 blocks derived from 'colorf'
221static void fillin_BC1_with_color(SkISize dimensions, const SkColor4f& colorf, char* dest) {
222 SkColor color = colorf.toSkColor();
223
224 BC1Block block;
Robert Phillipsac908022020-01-14 16:54:17 -0500225 create_BC1_block(color, color, &block);
Robert Phillips8f259a02019-12-20 11:32:27 -0500226
227 int numBlocks = num_ETC1_blocks(dimensions.width(), dimensions.height());
228
229 for (int i = 0; i < numBlocks; ++i) {
230 memcpy(dest, &block, sizeof(BC1Block));
231 dest += sizeof(BC1Block);
232 }
233}
234
Robert Phillipse0735522020-01-31 11:03:32 -0500235#if GR_TEST_UTILS
236
Robert Phillipsac908022020-01-14 16:54:17 -0500237// Fill in 'dstPixels' with BC1 blocks derived from the 'pixmap'.
238void GrTwoColorBC1Compress(const SkPixmap& pixmap, SkColor otherColor, char* dstPixels) {
Robert Phillips99dead92020-01-27 16:11:57 -0500239 BC1Block* dstBlocks = reinterpret_cast<BC1Block*>(dstPixels);
Robert Phillipsac908022020-01-14 16:54:17 -0500240 SkASSERT(pixmap.colorType() == SkColorType::kRGBA_8888_SkColorType);
241
242 BC1Block block;
243
244 // black -> fColor0, otherColor -> fColor1
245 create_BC1_block(SK_ColorBLACK, otherColor, &block);
246
Robert Phillips162e04b2020-01-28 14:22:43 -0500247 int numXBlocks = num_4x4_blocks(pixmap.width());
248 int numYBlocks = num_4x4_blocks(pixmap.height());
Robert Phillipsac908022020-01-14 16:54:17 -0500249
250 for (int y = 0; y < numYBlocks; ++y) {
251 for (int x = 0; x < numXBlocks; ++x) {
252 int shift = 0;
253 int offsetX = 4 * x, offsetY = 4 * y;
Robert Phillips162e04b2020-01-28 14:22:43 -0500254 block.fIndices = 0; // init all the pixels to color0 (i.e., opaque black)
Robert Phillipsac908022020-01-14 16:54:17 -0500255 for (int i = 0; i < 4; ++i) {
Robert Phillips162e04b2020-01-28 14:22:43 -0500256 for (int j = 0; j < 4; ++j, shift += 2) {
Robert Phillipsac908022020-01-14 16:54:17 -0500257 if (offsetX + j >= pixmap.width() || offsetY + i >= pixmap.height()) {
Robert Phillips162e04b2020-01-28 14:22:43 -0500258 // This can happen for the topmost levels of a mipmap and for
259 // non-multiple of 4 textures
Robert Phillipsac908022020-01-14 16:54:17 -0500260 continue;
261 }
262
263 SkColor tmp = pixmap.getColor(offsetX + j, offsetY + i);
264 if (tmp == SK_ColorTRANSPARENT) {
265 // For RGBA BC1 images color3 is set to transparent black
266 block.fIndices |= 3 << shift;
267 } else if (tmp != SK_ColorBLACK) {
268 block.fIndices |= 1 << shift; // color1
269 }
Robert Phillipsac908022020-01-14 16:54:17 -0500270 }
271 }
272
273 dstBlocks[y*numXBlocks + x] = block;
274 }
275 }
276}
277
Robert Phillipse0735522020-01-31 11:03:32 -0500278#endif
279
Brian Salomon85c3d682019-11-04 15:04:54 -0500280size_t GrComputeTightCombinedBufferSize(size_t bytesPerPixel, SkISize baseDimensions,
Brian Salomonbb8dde82019-06-27 10:52:13 -0400281 SkTArray<size_t>* individualMipOffsets, int mipLevelCount) {
Robert Phillips28a5a432019-06-07 12:46:21 -0400282 SkASSERT(individualMipOffsets && !individualMipOffsets->count());
283 SkASSERT(mipLevelCount >= 1);
284
285 individualMipOffsets->push_back(0);
286
Brian Salomon85c3d682019-11-04 15:04:54 -0500287 size_t combinedBufferSize = baseDimensions.width() * bytesPerPixel * baseDimensions.height();
288 SkISize levelDimensions = baseDimensions;
Robert Phillips28a5a432019-06-07 12:46:21 -0400289
290 // The Vulkan spec for copying a buffer to an image requires that the alignment must be at
291 // least 4 bytes and a multiple of the bytes per pixel of the image config.
292 SkASSERT(bytesPerPixel == 1 || bytesPerPixel == 2 || bytesPerPixel == 3 ||
293 bytesPerPixel == 4 || bytesPerPixel == 8 || bytesPerPixel == 16);
294 int desiredAlignment = (bytesPerPixel == 3) ? 12 : (bytesPerPixel > 4 ? bytesPerPixel : 4);
295
296 for (int currentMipLevel = 1; currentMipLevel < mipLevelCount; ++currentMipLevel) {
Brian Osman788b9162020-02-07 10:36:46 -0500297 levelDimensions = {std::max(1, levelDimensions.width() /2),
298 std::max(1, levelDimensions.height()/2)};
Robert Phillips28a5a432019-06-07 12:46:21 -0400299
Brian Salomon85c3d682019-11-04 15:04:54 -0500300 size_t trimmedSize = levelDimensions.area() * bytesPerPixel;
Robert Phillips28a5a432019-06-07 12:46:21 -0400301 const size_t alignmentDiff = combinedBufferSize % desiredAlignment;
302 if (alignmentDiff != 0) {
303 combinedBufferSize += desiredAlignment - alignmentDiff;
304 }
305 SkASSERT((0 == combinedBufferSize % 4) && (0 == combinedBufferSize % bytesPerPixel));
306
307 individualMipOffsets->push_back(combinedBufferSize);
308 combinedBufferSize += trimmedSize;
309 }
310
311 SkASSERT(individualMipOffsets->count() == mipLevelCount);
312 return combinedBufferSize;
313}
314
Robert Phillips48257d72019-12-16 14:20:53 -0500315void GrFillInCompressedData(SkImage::CompressionType type, SkISize dimensions,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400316 GrMipmapped mipMapped, char* dstPixels, const SkColor4f& colorf) {
Brian Salomonbb8dde82019-06-27 10:52:13 -0400317 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
Robert Phillips48257d72019-12-16 14:20:53 -0500318
319 int numMipLevels = 1;
Brian Salomon7e67dca2020-07-21 09:27:25 -0400320 if (mipMapped == GrMipmapped::kYes) {
Mike Reed13711eb2020-07-14 17:16:32 -0400321 numMipLevels = SkMipmap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
Robert Phillips48257d72019-12-16 14:20:53 -0500322 }
323
Robert Phillips8f259a02019-12-20 11:32:27 -0500324 size_t offset = 0;
Robert Phillips48257d72019-12-16 14:20:53 -0500325
Robert Phillips8f259a02019-12-20 11:32:27 -0500326 for (int i = 0; i < numMipLevels; ++i) {
Robert Phillips99dead92020-01-27 16:11:57 -0500327 size_t levelSize = SkCompressedDataSize(type, dimensions, nullptr, false);
Robert Phillips48257d72019-12-16 14:20:53 -0500328
Robert Phillipsc558f722020-01-13 13:02:26 -0500329 if (SkImage::CompressionType::kETC2_RGB8_UNORM == type) {
Robert Phillips48257d72019-12-16 14:20:53 -0500330 fillin_ETC1_with_color(dimensions, colorf, &dstPixels[offset]);
Robert Phillips8f259a02019-12-20 11:32:27 -0500331 } else {
Robert Phillipsb0855272020-01-15 12:56:52 -0500332 SkASSERT(type == SkImage::CompressionType::kBC1_RGB8_UNORM ||
333 type == SkImage::CompressionType::kBC1_RGBA8_UNORM);
Robert Phillips8f259a02019-12-20 11:32:27 -0500334 fillin_BC1_with_color(dimensions, colorf, &dstPixels[offset]);
Robert Phillips48257d72019-12-16 14:20:53 -0500335 }
Robert Phillips8f259a02019-12-20 11:32:27 -0500336
337 offset += levelSize;
Brian Osman788b9162020-02-07 10:36:46 -0500338 dimensions = {std::max(1, dimensions.width()/2), std::max(1, dimensions.height()/2)};
Brian Salomonbb8dde82019-06-27 10:52:13 -0400339 }
340}
341
Brian Salomon85c3d682019-11-04 15:04:54 -0500342static GrSwizzle get_load_and_src_swizzle(GrColorType ct, SkRasterPipeline::StockStage* load,
Greg Daniele877dce2019-07-11 10:52:43 -0400343 bool* isNormalized, bool* isSRGB) {
Brian Salomonf30b1c12019-06-20 12:25:02 -0400344 GrSwizzle swizzle("rgba");
345 *isNormalized = true;
Greg Daniele877dce2019-07-11 10:52:43 -0400346 *isSRGB = false;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400347 switch (ct) {
348 case GrColorType::kAlpha_8: *load = SkRasterPipeline::load_a8; break;
Robert Phillips429f0d32019-09-11 17:03:28 -0400349 case GrColorType::kAlpha_16: *load = SkRasterPipeline::load_a16; break;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400350 case GrColorType::kBGR_565: *load = SkRasterPipeline::load_565; break;
351 case GrColorType::kABGR_4444: *load = SkRasterPipeline::load_4444; break;
Greg Daniel746460e2020-06-30 13:13:53 -0400352 case GrColorType::kARGB_4444: swizzle = GrSwizzle("bgra");
353 *load = SkRasterPipeline::load_4444; break;
354 case GrColorType::kBGRA_4444: swizzle = GrSwizzle("gbar");
355 *load = SkRasterPipeline::load_4444; break;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400356 case GrColorType::kRGBA_8888: *load = SkRasterPipeline::load_8888; break;
357 case GrColorType::kRG_88: *load = SkRasterPipeline::load_rg88; break;
358 case GrColorType::kRGBA_1010102: *load = SkRasterPipeline::load_1010102; break;
Robert Phillips9a30ee02020-04-29 08:58:39 -0400359 case GrColorType::kBGRA_1010102: *load = SkRasterPipeline::load_1010102;
360 swizzle = GrSwizzle("bgra");
361 break;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400362 case GrColorType::kAlpha_F16: *load = SkRasterPipeline::load_af16; break;
363 case GrColorType::kRGBA_F16_Clamped: *load = SkRasterPipeline::load_f16; break;
364 case GrColorType::kRG_1616: *load = SkRasterPipeline::load_rg1616; break;
365 case GrColorType::kRGBA_16161616: *load = SkRasterPipeline::load_16161616; break;
366
Greg Daniele877dce2019-07-11 10:52:43 -0400367 case GrColorType::kRGBA_8888_SRGB: *load = SkRasterPipeline::load_8888;
368 *isSRGB = true;
369 break;
Brian Salomone14cfbe2019-06-24 15:00:58 -0400370 case GrColorType::kRG_F16: *load = SkRasterPipeline::load_rgf16;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400371 *isNormalized = false;
372 break;
373 case GrColorType::kRGBA_F16: *load = SkRasterPipeline::load_f16;
374 *isNormalized = false;
375 break;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400376 case GrColorType::kRGBA_F32: *load = SkRasterPipeline::load_f32;
377 *isNormalized = false;
378 break;
Brian Salomon8f8354a2019-07-31 20:12:02 -0400379 case GrColorType::kAlpha_8xxx: *load = SkRasterPipeline::load_8888;
380 swizzle = GrSwizzle("000r");
381 break;
382 case GrColorType::kAlpha_F32xxx: *load = SkRasterPipeline::load_f32;
383 swizzle = GrSwizzle("000r");
384 break;
385 case GrColorType::kGray_8xxx: *load = SkRasterPipeline::load_8888;
386 swizzle = GrSwizzle("rrr1");
387 break;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400388 case GrColorType::kGray_8: *load = SkRasterPipeline::load_a8;
389 swizzle = GrSwizzle("aaa1");
390 break;
Brian Salomon01ff5382020-12-15 16:06:26 -0500391 case GrColorType::kGrayAlpha_88: *load = SkRasterPipeline::load_rg88;
392 swizzle = GrSwizzle("rrrg");
393 break;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400394 case GrColorType::kBGRA_8888: *load = SkRasterPipeline::load_8888;
395 swizzle = GrSwizzle("bgra");
396 break;
397 case GrColorType::kRGB_888x: *load = SkRasterPipeline::load_8888;
398 swizzle = GrSwizzle("rgb1");
399 break;
400
Brian Salomon85c3d682019-11-04 15:04:54 -0500401 // These are color types we don't expect to ever have to load.
402 case GrColorType::kRGB_888:
403 case GrColorType::kR_8:
404 case GrColorType::kR_16:
405 case GrColorType::kR_F16:
406 case GrColorType::kGray_F16:
Brian Salomonf30b1c12019-06-20 12:25:02 -0400407 case GrColorType::kUnknown:
Brian Salomonf30b1c12019-06-20 12:25:02 -0400408 SK_ABORT("unexpected CT");
409 }
410 return swizzle;
411}
412
Brian Salomon01ff5382020-12-15 16:06:26 -0500413enum class LumMode {
414 kNone,
415 kToRGB,
416 kToAlpha
417};
418
Brian Salomonf30b1c12019-06-20 12:25:02 -0400419static GrSwizzle get_dst_swizzle_and_store(GrColorType ct, SkRasterPipeline::StockStage* store,
Brian Salomon01ff5382020-12-15 16:06:26 -0500420 LumMode* lumMode, bool* isNormalized, bool* isSRGB) {
Brian Salomonf30b1c12019-06-20 12:25:02 -0400421 GrSwizzle swizzle("rgba");
422 *isNormalized = true;
Greg Daniele877dce2019-07-11 10:52:43 -0400423 *isSRGB = false;
Brian Salomon01ff5382020-12-15 16:06:26 -0500424 *lumMode = LumMode::kNone;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400425 switch (ct) {
426 case GrColorType::kAlpha_8: *store = SkRasterPipeline::store_a8; break;
Robert Phillips429f0d32019-09-11 17:03:28 -0400427 case GrColorType::kAlpha_16: *store = SkRasterPipeline::store_a16; break;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400428 case GrColorType::kBGR_565: *store = SkRasterPipeline::store_565; break;
429 case GrColorType::kABGR_4444: *store = SkRasterPipeline::store_4444; break;
Greg Daniel746460e2020-06-30 13:13:53 -0400430 case GrColorType::kARGB_4444: swizzle = GrSwizzle("bgra");
431 *store = SkRasterPipeline::store_4444; break;
432 case GrColorType::kBGRA_4444: swizzle = GrSwizzle("argb");
433 *store = SkRasterPipeline::store_4444; break;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400434 case GrColorType::kRGBA_8888: *store = SkRasterPipeline::store_8888; break;
435 case GrColorType::kRG_88: *store = SkRasterPipeline::store_rg88; break;
436 case GrColorType::kRGBA_1010102: *store = SkRasterPipeline::store_1010102; break;
Robert Phillips9a30ee02020-04-29 08:58:39 -0400437 case GrColorType::kBGRA_1010102: swizzle = GrSwizzle("bgra");
438 *store = SkRasterPipeline::store_1010102;
439 break;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400440 case GrColorType::kRGBA_F16_Clamped: *store = SkRasterPipeline::store_f16; break;
441 case GrColorType::kRG_1616: *store = SkRasterPipeline::store_rg1616; break;
442 case GrColorType::kRGBA_16161616: *store = SkRasterPipeline::store_16161616; break;
443
Greg Daniele877dce2019-07-11 10:52:43 -0400444 case GrColorType::kRGBA_8888_SRGB: *store = SkRasterPipeline::store_8888;
445 *isSRGB = true;
446 break;
Brian Salomone14cfbe2019-06-24 15:00:58 -0400447 case GrColorType::kRG_F16: *store = SkRasterPipeline::store_rgf16;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400448 *isNormalized = false;
449 break;
450 case GrColorType::kAlpha_F16: *store = SkRasterPipeline::store_af16;
451 *isNormalized = false;
452 break;
453 case GrColorType::kRGBA_F16: *store = SkRasterPipeline::store_f16;
454 *isNormalized = false;
455 break;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400456 case GrColorType::kRGBA_F32: *store = SkRasterPipeline::store_f32;
457 *isNormalized = false;
458 break;
Brian Salomon8f8354a2019-07-31 20:12:02 -0400459 case GrColorType::kAlpha_8xxx: *store = SkRasterPipeline::store_8888;
460 swizzle = GrSwizzle("a000");
461 break;
462 case GrColorType::kAlpha_F32xxx: *store = SkRasterPipeline::store_f32;
463 swizzle = GrSwizzle("a000");
464 break;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400465 case GrColorType::kBGRA_8888: swizzle = GrSwizzle("bgra");
466 *store = SkRasterPipeline::store_8888;
467 break;
468 case GrColorType::kRGB_888x: swizzle = GrSwizzle("rgb1");
469 *store = SkRasterPipeline::store_8888;
470 break;
Brian Salomon85c3d682019-11-04 15:04:54 -0500471 case GrColorType::kR_8: swizzle = GrSwizzle("agbr");
472 *store = SkRasterPipeline::store_a8;
473 break;
474 case GrColorType::kR_16: swizzle = GrSwizzle("agbr");
475 *store = SkRasterPipeline::store_a16;
476 break;
477 case GrColorType::kR_F16: swizzle = GrSwizzle("agbr");
478 *store = SkRasterPipeline::store_af16;
479 break;
Brian Salomon01ff5382020-12-15 16:06:26 -0500480 case GrColorType::kGray_F16: *lumMode = LumMode::kToAlpha;
Brian Salomon85c3d682019-11-04 15:04:54 -0500481 *store = SkRasterPipeline::store_af16;
482 break;
Brian Salomon01ff5382020-12-15 16:06:26 -0500483 case GrColorType::kGray_8: *lumMode = LumMode::kToAlpha;
Brian Salomon998937c2019-10-29 09:34:52 -0400484 *store = SkRasterPipeline::store_a8;
485 break;
Brian Salomon01ff5382020-12-15 16:06:26 -0500486 case GrColorType::kGrayAlpha_88: *lumMode = LumMode::kToRGB;
487 swizzle = GrSwizzle("ragb");
488 *store = SkRasterPipeline::store_rg88;
489 break;
490 case GrColorType::kGray_8xxx: *lumMode = LumMode::kToRGB;
Brian Salomon998937c2019-10-29 09:34:52 -0400491 *store = SkRasterPipeline::store_8888;
Brian Salomon01ff5382020-12-15 16:06:26 -0500492 swizzle = GrSwizzle("r000");
Brian Salomon998937c2019-10-29 09:34:52 -0400493 break;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400494
Brian Salomon85c3d682019-11-04 15:04:54 -0500495 // These are color types we don't expect to ever have to store.
496 case GrColorType::kRGB_888: // This is handled specially in GrConvertPixels.
Brian Salomonf30b1c12019-06-20 12:25:02 -0400497 case GrColorType::kUnknown:
Brian Salomonf30b1c12019-06-20 12:25:02 -0400498 SK_ABORT("unexpected CT");
499 }
500 return swizzle;
501}
502
503static inline void append_clamp_gamut(SkRasterPipeline* pipeline) {
504 // SkRasterPipeline may not know our color type and also doesn't like caller to directly
505 // append clamp_gamut. Fake it out.
506 static SkImageInfo fakeII = SkImageInfo::MakeN32Premul(1, 1);
507 pipeline->append_gamut_clamp_if_normalized(fakeII);
508}
509
Brian Salomonf2ebdd92019-09-30 12:15:30 -0400510bool GrConvertPixels(const GrImageInfo& dstInfo, void* dst, size_t dstRB,
511 const GrImageInfo& srcInfo, const void* src, size_t srcRB,
Brian Salomon8f8354a2019-07-31 20:12:02 -0400512 bool flipY) {
Brian Salomonc42eb662019-06-24 17:13:00 -0400513 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
Brian Salomon85c3d682019-11-04 15:04:54 -0500514 if (srcInfo.colorType() == GrColorType::kRGB_888) {
515 // We don't expect to have to convert from this format.
516 return false;
517 }
Brian Salomondd4087d2020-12-23 20:36:44 -0500518 if (srcInfo.dimensions().isEmpty() || dstInfo.dimensions().isEmpty()) {
519 return false;
520 }
521 if (srcInfo.colorType() == GrColorType::kUnknown ||
522 dstInfo.colorType() == GrColorType::kUnknown) {
Brian Salomonf30b1c12019-06-20 12:25:02 -0400523 return false;
524 }
Brian Salomon1d435302019-07-01 13:05:28 -0400525 if (!src || !dst) {
Brian Salomonf30b1c12019-06-20 12:25:02 -0400526 return false;
527 }
Brian Salomon85c3d682019-11-04 15:04:54 -0500528 if (dstInfo.dimensions() != srcInfo.dimensions()) {
Brian Salomonf30b1c12019-06-20 12:25:02 -0400529 return false;
530 }
Brian Salomon1d435302019-07-01 13:05:28 -0400531 if (dstRB < dstInfo.minRowBytes() || srcRB < srcInfo.minRowBytes()) {
Brian Salomonf30b1c12019-06-20 12:25:02 -0400532 return false;
533 }
Brian Salomon85c3d682019-11-04 15:04:54 -0500534 if (dstInfo.colorType() == GrColorType::kRGB_888) {
535 // SkRasterPipeline doesn't handle writing to RGB_888. So we have it write to RGB_888x and
536 // then do another conversion that does the 24bit packing.
537 auto tempDstInfo = dstInfo.makeColorType(GrColorType::kRGB_888x);
538 auto tempRB = tempDstInfo.minRowBytes();
539 std::unique_ptr<char[]> tempDst(new char[tempRB * tempDstInfo.height()]);
540 if (!GrConvertPixels(tempDstInfo, tempDst.get(), tempRB, srcInfo, src, srcRB, flipY)) {
541 return false;
542 }
543 auto* tRow = reinterpret_cast<const char*>(tempDst.get());
544 auto* dRow = reinterpret_cast<char*>(dst);
545 for (int y = 0; y < dstInfo.height(); ++y, tRow += tempRB, dRow += dstRB) {
546 for (int x = 0; x < dstInfo.width(); ++x) {
547 auto t = reinterpret_cast<const uint32_t*>(tRow + x * sizeof(uint32_t));
548 auto d = reinterpret_cast<uint32_t*>(dRow + x * 3);
549 memcpy(d, t, 3);
550 }
551 }
552 return true;
553 }
Brian Salomon1d435302019-07-01 13:05:28 -0400554
555 size_t srcBpp = srcInfo.bpp();
556 size_t dstBpp = dstInfo.bpp();
557
Brian Salomonf30b1c12019-06-20 12:25:02 -0400558 // SkRasterPipeline operates on row-pixels not row-bytes.
Brian Salomon1d435302019-07-01 13:05:28 -0400559 SkASSERT(dstRB % dstBpp == 0);
560 SkASSERT(srcRB % srcBpp == 0);
Brian Salomonf30b1c12019-06-20 12:25:02 -0400561
Brian Salomon77a684f2019-08-01 14:38:04 -0400562 bool premul = srcInfo.alphaType() == kUnpremul_SkAlphaType &&
563 dstInfo.alphaType() == kPremul_SkAlphaType;
564 bool unpremul = srcInfo.alphaType() == kPremul_SkAlphaType &&
565 dstInfo.alphaType() == kUnpremul_SkAlphaType;
566 bool alphaOrCSConversion =
567 premul || unpremul || !SkColorSpace::Equals(srcInfo.colorSpace(), dstInfo.colorSpace());
568
569 if (srcInfo.colorType() == dstInfo.colorType() && !alphaOrCSConversion) {
570 size_t tightRB = dstBpp * dstInfo.width();
571 if (flipY) {
572 dst = static_cast<char*>(dst) + dstRB * (dstInfo.height() - 1);
573 for (int y = 0; y < dstInfo.height(); ++y) {
574 memcpy(dst, src, tightRB);
575 src = static_cast<const char*>(src) + srcRB;
576 dst = static_cast< char*>(dst) - dstRB;
577 }
578 } else {
579 SkRectMemcpy(dst, dstRB, src, srcRB, tightRB, srcInfo.height());
580 }
581 return true;
582 }
583
Brian Salomonf30b1c12019-06-20 12:25:02 -0400584 SkRasterPipeline::StockStage load;
585 bool srcIsNormalized;
Greg Daniele877dce2019-07-11 10:52:43 -0400586 bool srcIsSRGB;
Brian Salomon85c3d682019-11-04 15:04:54 -0500587 auto loadSwizzle =
588 get_load_and_src_swizzle(srcInfo.colorType(), &load, &srcIsNormalized, &srcIsSRGB);
Brian Salomonf30b1c12019-06-20 12:25:02 -0400589
590 SkRasterPipeline::StockStage store;
Brian Salomon01ff5382020-12-15 16:06:26 -0500591 LumMode lumMode;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400592 bool dstIsNormalized;
Greg Daniele877dce2019-07-11 10:52:43 -0400593 bool dstIsSRGB;
Brian Salomon01ff5382020-12-15 16:06:26 -0500594 auto storeSwizzle = get_dst_swizzle_and_store(dstInfo.colorType(), &store, &lumMode,
Brian Salomon998937c2019-10-29 09:34:52 -0400595 &dstIsNormalized, &dstIsSRGB);
Brian Salomonf30b1c12019-06-20 12:25:02 -0400596
Brian Salomonf30b1c12019-06-20 12:25:02 -0400597 bool clampGamut;
598 SkTLazy<SkColorSpaceXformSteps> steps;
599 GrSwizzle loadStoreSwizzle;
600 if (alphaOrCSConversion) {
Brian Salomon1d435302019-07-01 13:05:28 -0400601 steps.init(srcInfo.colorSpace(), srcInfo.alphaType(),
602 dstInfo.colorSpace(), dstInfo.alphaType());
603 clampGamut = dstIsNormalized && dstInfo.alphaType() == kPremul_SkAlphaType;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400604 } else {
Brian Salomon1d435302019-07-01 13:05:28 -0400605 clampGamut =
606 dstIsNormalized && !srcIsNormalized && dstInfo.alphaType() == kPremul_SkAlphaType;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400607 if (!clampGamut) {
608 loadStoreSwizzle = GrSwizzle::Concat(loadSwizzle, storeSwizzle);
609 }
610 }
611 int cnt = 1;
Brian Salomon1d435302019-07-01 13:05:28 -0400612 int height = srcInfo.height();
613 SkRasterPipeline_MemoryCtx srcCtx{const_cast<void*>(src), SkToInt(srcRB / srcBpp)},
614 dstCtx{ dst , SkToInt(dstRB / dstBpp)};
Brian Salomonf30b1c12019-06-20 12:25:02 -0400615
Brian Salomon1d435302019-07-01 13:05:28 -0400616 if (flipY) {
Brian Salomonf30b1c12019-06-20 12:25:02 -0400617 // It *almost* works to point the src at the last row and negate the stride and run the
618 // whole rectangle. However, SkRasterPipeline::run()'s control loop uses size_t loop
619 // variables so it winds up relying on unsigned overflow math. It works out in practice
620 // but UBSAN says "no!" as it's technically undefined and in theory a compiler could emit
621 // code that didn't do what is intended. So we go one row at a time. :(
Brian Salomon1d435302019-07-01 13:05:28 -0400622 srcCtx.pixels = static_cast<char*>(srcCtx.pixels) + srcRB * (height - 1);
Brian Salomonf30b1c12019-06-20 12:25:02 -0400623 std::swap(cnt, height);
624 }
Greg Daniele877dce2019-07-11 10:52:43 -0400625
Brian Salomon01ff5382020-12-15 16:06:26 -0500626 bool hasConversion = alphaOrCSConversion || clampGamut || lumMode != LumMode::kNone;
Greg Daniele877dce2019-07-11 10:52:43 -0400627
628 if (srcIsSRGB && dstIsSRGB && !hasConversion) {
629 // No need to convert from srgb if we are just going to immediately convert it back.
630 srcIsSRGB = dstIsSRGB = false;
631 }
632
633 hasConversion = hasConversion || srcIsSRGB || dstIsSRGB;
634
Brian Salomonf30b1c12019-06-20 12:25:02 -0400635 for (int i = 0; i < cnt; ++i) {
636 SkRasterPipeline_<256> pipeline;
637 pipeline.append(load, &srcCtx);
Greg Daniele877dce2019-07-11 10:52:43 -0400638 if (hasConversion) {
Brian Salomonf30b1c12019-06-20 12:25:02 -0400639 loadSwizzle.apply(&pipeline);
Greg Daniele877dce2019-07-11 10:52:43 -0400640 if (srcIsSRGB) {
Mike Klein04984312020-05-19 12:41:05 -0500641 pipeline.append_transfer_function(*skcms_sRGB_TransferFunction());
Greg Daniele877dce2019-07-11 10:52:43 -0400642 }
643 if (alphaOrCSConversion) {
Mike Kleinec8e0bf2020-05-22 11:42:38 -0500644 steps->apply(&pipeline);
Greg Daniele877dce2019-07-11 10:52:43 -0400645 }
Brian Salomonf30b1c12019-06-20 12:25:02 -0400646 if (clampGamut) {
647 append_clamp_gamut(&pipeline);
648 }
Brian Salomon01ff5382020-12-15 16:06:26 -0500649 switch (lumMode) {
650 case LumMode::kNone:
651 break;
652 case LumMode::kToRGB:
653 pipeline.append(SkRasterPipeline::StockStage::bt709_luminance_or_luma_to_rgb);
654 break;
655 case LumMode::kToAlpha:
656 pipeline.append(SkRasterPipeline::StockStage::bt709_luminance_or_luma_to_alpha);
657 // If we ever need to store srgb-encoded gray (e.g. GL_SLUMINANCE8) then we
658 // should use ToRGB and then a swizzle stage rather than ToAlpha. The subsequent
659 // transfer function stage ignores the alpha channel (where we just stashed the
660 // gray).
661 SkASSERT(!dstIsSRGB);
662 break;
Brian Salomon998937c2019-10-29 09:34:52 -0400663 }
Greg Daniele877dce2019-07-11 10:52:43 -0400664 if (dstIsSRGB) {
Mike Klein04984312020-05-19 12:41:05 -0500665 pipeline.append_transfer_function(*skcms_sRGB_Inverse_TransferFunction());
Greg Daniele877dce2019-07-11 10:52:43 -0400666 }
Brian Salomonf30b1c12019-06-20 12:25:02 -0400667 storeSwizzle.apply(&pipeline);
668 } else {
Greg Daniele877dce2019-07-11 10:52:43 -0400669 loadStoreSwizzle.apply(&pipeline);
Brian Salomonf30b1c12019-06-20 12:25:02 -0400670 }
671 pipeline.append(store, &dstCtx);
Brian Salomon1d435302019-07-01 13:05:28 -0400672 pipeline.run(0, 0, srcInfo.width(), height);
673 srcCtx.pixels = static_cast<char*>(srcCtx.pixels) - srcRB;
674 dstCtx.pixels = static_cast<char*>(dstCtx.pixels) + dstRB;
Brian Salomonf30b1c12019-06-20 12:25:02 -0400675 }
676 return true;
677}
Robert Phillipsc80b0e92019-07-23 10:27:09 -0400678
Brian Salomon85c3d682019-11-04 15:04:54 -0500679bool GrClearImage(const GrImageInfo& dstInfo, void* dst, size_t dstRB, SkColor4f color) {
Brian Salomon998937c2019-10-29 09:34:52 -0400680 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
Brian Salomon998937c2019-10-29 09:34:52 -0400681
Brian Salomon85c3d682019-11-04 15:04:54 -0500682 if (!dstInfo.isValid()) {
683 return false;
Brian Salomon998937c2019-10-29 09:34:52 -0400684 }
Brian Salomon85c3d682019-11-04 15:04:54 -0500685 if (!dst) {
686 return false;
687 }
688 if (dstRB < dstInfo.minRowBytes()) {
689 return false;
690 }
691 if (dstInfo.colorType() == GrColorType::kRGB_888) {
692 // SkRasterPipeline doesn't handle writing to RGB_888. So we handle that specially here.
693 uint32_t rgba = color.toBytes_RGBA();
694 for (int y = 0; y < dstInfo.height(); ++y) {
695 char* d = static_cast<char*>(dst) + y * dstRB;
696 for (int x = 0; x < dstInfo.width(); ++x, d += 3) {
697 memcpy(d, &rgba, 3);
698 }
699 }
700 return true;
701 }
702
Brian Salomon01ff5382020-12-15 16:06:26 -0500703 LumMode lumMode;
Brian Salomon85c3d682019-11-04 15:04:54 -0500704 bool isNormalized;
705 bool dstIsSRGB;
706 SkRasterPipeline::StockStage store;
Brian Salomon01ff5382020-12-15 16:06:26 -0500707 GrSwizzle storeSwizzle = get_dst_swizzle_and_store(dstInfo.colorType(), &store, &lumMode,
Brian Salomon85c3d682019-11-04 15:04:54 -0500708 &isNormalized, &dstIsSRGB);
709 char block[64];
710 SkArenaAlloc alloc(block, sizeof(block), 1024);
711 SkRasterPipeline_<256> pipeline;
712 pipeline.append_constant_color(&alloc, color);
Brian Salomon01ff5382020-12-15 16:06:26 -0500713 switch (lumMode) {
714 case LumMode::kNone:
715 break;
716 case LumMode::kToRGB:
717 pipeline.append(SkRasterPipeline::StockStage::bt709_luminance_or_luma_to_rgb);
718 break;
719 case LumMode::kToAlpha:
720 pipeline.append(SkRasterPipeline::StockStage::bt709_luminance_or_luma_to_alpha);
721 // If we ever need to store srgb-encoded gray (e.g. GL_SLUMINANCE8) then we should use
722 // ToRGB and then a swizzle stage rather than ToAlpha. The subsequent transfer function
723 // stage ignores the alpha channel (where we just stashed the gray).
724 SkASSERT(!dstIsSRGB);
725 break;
Brian Salomon85c3d682019-11-04 15:04:54 -0500726 }
727 if (dstIsSRGB) {
Mike Klein04984312020-05-19 12:41:05 -0500728 pipeline.append_transfer_function(*skcms_sRGB_Inverse_TransferFunction());
Brian Salomon85c3d682019-11-04 15:04:54 -0500729 }
730 storeSwizzle.apply(&pipeline);
731 SkRasterPipeline_MemoryCtx dstCtx{dst, SkToInt(dstRB/dstInfo.bpp())};
732 pipeline.append(store, &dstCtx);
733 pipeline.run(0, 0, dstInfo.width(), dstInfo.height());
734
735 return true;
Brian Salomon998937c2019-10-29 09:34:52 -0400736}
737
Robert Phillipsc80b0e92019-07-23 10:27:09 -0400738GrColorType SkColorTypeAndFormatToGrColorType(const GrCaps* caps,
739 SkColorType skCT,
740 const GrBackendFormat& format) {
741 GrColorType grCT = SkColorTypeToGrColorType(skCT);
742 // Until we support SRGB in the SkColorType we have to do this manual check here to make sure
743 // we use the correct GrColorType.
744 if (caps->isFormatSRGB(format)) {
745 if (grCT != GrColorType::kRGBA_8888) {
746 return GrColorType::kUnknown;
747 }
748 grCT = GrColorType::kRGBA_8888_SRGB;
749 }
750 return grCT;
751}