1 /*
2 * Copyright 2019 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "src/gpu/GrDataUtils.h"
9
10 #include "src/core/SkColorSpaceXformSteps.h"
11 #include "src/core/SkConvertPixels.h"
12 #include "src/core/SkTLazy.h"
13 #include "src/core/SkTraceEvent.h"
14 #include "src/core/SkUtils.h"
15 #include "src/gpu/GrColor.h"
16 #include "src/gpu/GrImageInfo.h"
17
18 struct ETC1Block {
19 uint32_t fHigh;
20 uint32_t fLow;
21 };
22
23 static const int kNumModifierTables = 8;
24 static const int kNumPixelIndices = 4;
25
26 // The index of each row in this table is the ETC1 table codeword
27 // The index of each column in this table is the ETC1 pixel index value
28 static const int kModifierTables[kNumModifierTables][kNumPixelIndices] = {
29 /* 0 */ { 2, 8, -2, -8 },
30 /* 1 */ { 5, 17, -5, -17 },
31 /* 2 */ { 9, 29, -9, -29 },
32 /* 3 */ { 13, 42, -13, -42 },
33 /* 4 */ { 18, 60, -18, -60 },
34 /* 5 */ { 24, 80, -24, -80 },
35 /* 6 */ { 33, 106, -33, -106 },
36 /* 7 */ { 47, 183, -47, -183 }
37 };
38
convert_5To8(int b)39 static inline int convert_5To8(int b) {
40 int c = b & 0x1f;
41 return (c << 3) | (c >> 2);
42 }
43
44 // Evaluate one of the entries in 'kModifierTables' to see how close it can get (r8,g8,b8) to
45 // 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)46 static int test_table_entry(int rOrig, int gOrig, int bOrig,
47 int r8, int g8, int b8,
48 int table, int offset) {
49 SkASSERT(0 <= table && table < 8);
50 SkASSERT(0 <= offset && offset < 4);
51
52 r8 = SkTPin<uint8_t>(r8 + kModifierTables[table][offset], 0, 255);
53 g8 = SkTPin<uint8_t>(g8 + kModifierTables[table][offset], 0, 255);
54 b8 = SkTPin<uint8_t>(b8 + kModifierTables[table][offset], 0, 255);
55
56 return SkTAbs(rOrig - r8) + SkTAbs(gOrig - g8) + SkTAbs(bOrig - b8);
57 }
58
59 // Create an ETC1 compressed block that is filled with 'col'
create_etc1_block(SkColor col,ETC1Block * block)60 static void create_etc1_block(SkColor col, ETC1Block* block) {
61 block->fHigh = 0;
62 block->fLow = 0;
63
64 int rOrig = SkColorGetR(col);
65 int gOrig = SkColorGetG(col);
66 int bOrig = SkColorGetB(col);
67
68 int r5 = SkMulDiv255Round(31, rOrig);
69 int g5 = SkMulDiv255Round(31, gOrig);
70 int b5 = SkMulDiv255Round(31, bOrig);
71
72 int r8 = convert_5To8(r5);
73 int g8 = convert_5To8(g5);
74 int b8 = convert_5To8(b5);
75
76 // We always encode solid color textures as 555 + zero diffs
77 block->fHigh |= (r5 << 27) | (g5 << 19) | (b5 << 11) | 0x2;
78
79 int bestTableIndex = 0, bestPixelIndex = 0;
80 int bestSoFar = 1024;
81 for (int tableIndex = 0; tableIndex < kNumModifierTables; ++tableIndex) {
82 for (int pixelIndex = 0; pixelIndex < kNumPixelIndices; ++pixelIndex) {
83 int score = test_table_entry(rOrig, gOrig, bOrig, r8, g8, b8,
84 tableIndex, pixelIndex);
85
86 if (bestSoFar > score) {
87 bestSoFar = score;
88 bestTableIndex = tableIndex;
89 bestPixelIndex = pixelIndex;
90 }
91 }
92 }
93
94 block->fHigh |= (bestTableIndex << 5) | (bestTableIndex << 2);
95
96 for (int i = 0; i < 16; ++i) {
97 block->fLow |= bestPixelIndex << 2*i;
98 }
99 }
100
num_ETC1_blocks_w(int w)101 static int num_ETC1_blocks_w(int w) {
102 if (w < 4) {
103 w = 1;
104 } else {
105 SkASSERT((w & 3) == 0);
106 w >>= 2;
107 }
108 return w;
109 }
110
num_ETC1_blocks(int w,int h)111 static int num_ETC1_blocks(int w, int h) {
112 w = num_ETC1_blocks_w(w);
113
114 if (h < 4) {
115 h = 1;
116 } else {
117 SkASSERT((h & 3) == 0);
118 h >>= 2;
119 }
120
121 return w * h;
122 }
123
GrCompressedDataSize(SkImage::CompressionType type,int width,int height)124 size_t GrCompressedDataSize(SkImage::CompressionType type, int width, int height) {
125 switch (type) {
126 case SkImage::kETC1_CompressionType:
127 int numBlocks = num_ETC1_blocks(width, height);
128 return numBlocks * sizeof(ETC1Block);
129 }
130 SK_ABORT("Unexpected compression type");
131 }
132
GrCompressedRowBytes(SkImage::CompressionType type,int width)133 size_t GrCompressedRowBytes(SkImage::CompressionType type, int width) {
134 switch (type) {
135 case SkImage::kETC1_CompressionType:
136 int numBlocksWidth = num_ETC1_blocks_w(width);
137 return numBlocksWidth * sizeof(ETC1Block);
138 }
139 SK_ABORT("Unexpected compression type");
140 }
141
142 // Fill in 'dest' with ETC1 blocks derived from 'colorf'
fillin_ETC1_with_color(int width,int height,const SkColor4f & colorf,void * dest)143 static void fillin_ETC1_with_color(int width, int height, const SkColor4f& colorf, void* dest) {
144 SkColor color = colorf.toSkColor();
145
146 ETC1Block block;
147 create_etc1_block(color, &block);
148
149 int numBlocks = num_ETC1_blocks(width, height);
150
151 for (int i = 0; i < numBlocks; ++i) {
152 ((ETC1Block*)dest)[i] = block;
153 }
154 }
155
156 // Fill in the width x height 'dest' with the munged version of 'colorf' that matches 'config'
fill_buffer_with_color(GrColorType colorType,int width,int height,const SkColor4f & colorf,void * dest)157 static bool fill_buffer_with_color(GrColorType colorType, int width, int height,
158 const SkColor4f& colorf, void* dest) {
159 GrColor color = colorf.toBytes_RGBA();
160
161 uint8_t r = GrColorUnpackR(color);
162 uint8_t g = GrColorUnpackG(color);
163 uint8_t b = GrColorUnpackB(color);
164 uint8_t a = GrColorUnpackA(color);
165
166 switch (colorType) {
167 case GrColorType::kAlpha_8: {
168 memset(dest, a, width * height);
169 break;
170 }
171 case GrColorType::kGray_8: {
172 uint8_t gray8 = SkComputeLuminance(r, g, b);
173
174 memset(dest, gray8, width * height);
175 break;
176 }
177 case GrColorType::kBGR_565: {
178 uint16_t rgb565 = SkPack888ToRGB16(r, g, b);
179
180 sk_memset16((uint16_t*) dest, rgb565, width * height);
181 break;
182 }
183 case GrColorType::kABGR_4444: {
184 uint8_t r4 = (r >> 4) & 0xF;
185 uint8_t g4 = (g >> 4) & 0xF;
186 uint8_t b4 = (b >> 4) & 0xF;
187 uint8_t a4 = (a >> 4) & 0xF;
188
189 uint16_t rgba4444 = r4 << SK_R4444_SHIFT | g4 << SK_G4444_SHIFT |
190 b4 << SK_B4444_SHIFT | a4 << SK_A4444_SHIFT;
191
192 sk_memset16((uint16_t*) dest, rgba4444, width * height);
193 break;
194 }
195 case GrColorType::kRGBA_8888: {
196 sk_memset32((uint32_t *) dest, color, width * height);
197 break;
198 }
199 case GrColorType::kRGB_888x: {
200 GrColor opaque = GrColorPackRGBA(r, g, b, 0xFF);
201
202 sk_memset32((uint32_t *) dest, opaque, width * height);
203 break;
204 }
205 case GrColorType::kRG_88: {
206 uint16_t rg88 = (g << 8) | r;
207
208 sk_memset16((uint16_t*) dest, rg88, width * height);
209 break;
210 }
211 case GrColorType::kBGRA_8888: {
212 GrColor swizzled = GrColorPackRGBA(b, g, r, a);
213
214 sk_memset32((uint32_t *) dest, swizzled, width * height);
215 break;
216 }
217 case GrColorType::kRGBA_8888_SRGB: {
218 sk_memset32((uint32_t *) dest, color, width * height);
219 break;
220 }
221 case GrColorType::kRGBA_1010102: {
222 uint32_t r10 = SkScalarRoundToInt(colorf.fR * 1023.0f);
223 uint32_t g10 = SkScalarRoundToInt(colorf.fG * 1023.0f);
224 uint32_t b10 = SkScalarRoundToInt(colorf.fB * 1023.0f);
225 uint8_t a2 = SkScalarRoundToInt(colorf.fA * 3.0f);
226
227 uint32_t rgba1010102 = a2 << 30 | b10 << 20 | g10 << 10 | r10;
228
229 sk_memset32((uint32_t *) dest, rgba1010102, width * height);
230 break;
231 }
232 case GrColorType::kAlpha_F16: {
233 SkHalf alphaHalf = SkFloatToHalf(colorf.fA);
234
235 sk_memset16((uint16_t *) dest, alphaHalf, width * height);
236 break;
237 }
238 case GrColorType::kRGBA_F16_Clamped: // fall through
239 case GrColorType::kRGBA_F16: {
240 uint64_t rHalf = SkFloatToHalf(colorf.fR);
241 uint64_t gHalf = SkFloatToHalf(colorf.fG);
242 uint64_t bHalf = SkFloatToHalf(colorf.fB);
243 uint64_t aHalf = SkFloatToHalf(colorf.fA);
244
245 uint64_t rgbaHalf = (aHalf << 48) | (bHalf << 32) | (gHalf << 16) | rHalf;
246
247 sk_memset64((uint64_t *) dest, rgbaHalf, width * height);
248 break;
249 }
250 case GrColorType::kAlpha_16: {
251 uint16_t a16 = SkScalarRoundToInt(colorf.fA * 65535.0f);
252 sk_memset16((uint16_t*) dest, a16, width * height);
253 break;
254 }
255 case GrColorType::kRG_1616: {
256 uint32_t r16 = SkScalarRoundToInt(colorf.fR * 65535.0f);
257 uint32_t g16 = SkScalarRoundToInt(colorf.fG * 65535.0f);
258
259 uint32_t rg1616 = (g16 << 16) | r16;
260
261 sk_memset32((uint32_t*) dest, rg1616, width * height);
262 break;
263 }
264 case GrColorType::kRGBA_16161616: {
265 uint64_t r16 = SkScalarRoundToInt(colorf.fR * 65535.0f);
266 uint64_t g16 = SkScalarRoundToInt(colorf.fG * 65535.0f);
267 uint64_t b16 = SkScalarRoundToInt(colorf.fB * 65535.0f);
268 uint64_t a16 = SkScalarRoundToInt(colorf.fA * 65535.0f);
269
270 uint64_t rgba16161616 = (a16 << 48) | (b16 << 32) | (g16 << 16) | r16;
271 sk_memset64((uint64_t*) dest, rgba16161616, width * height);
272 break;
273 }
274 case GrColorType::kRG_F16: {
275 uint32_t rHalf = SkFloatToHalf(colorf.fR);
276 uint32_t gHalf = SkFloatToHalf(colorf.fG);
277
278 uint32_t rgHalf = (gHalf << 16) | rHalf;
279
280 sk_memset32((uint32_t *) dest, rgHalf, width * height);
281 break;
282 }
283 default:
284 return false;
285 break;
286 }
287
288 return true;
289 }
290
GrComputeTightCombinedBufferSize(size_t bytesPerPixel,int baseWidth,int baseHeight,SkTArray<size_t> * individualMipOffsets,int mipLevelCount)291 size_t GrComputeTightCombinedBufferSize(size_t bytesPerPixel, int baseWidth, int baseHeight,
292 SkTArray<size_t>* individualMipOffsets, int mipLevelCount) {
293 SkASSERT(individualMipOffsets && !individualMipOffsets->count());
294 SkASSERT(mipLevelCount >= 1);
295
296 individualMipOffsets->push_back(0);
297
298 size_t combinedBufferSize = baseWidth * bytesPerPixel * baseHeight;
299 int currentWidth = baseWidth;
300 int currentHeight = baseHeight;
301
302 // The Vulkan spec for copying a buffer to an image requires that the alignment must be at
303 // least 4 bytes and a multiple of the bytes per pixel of the image config.
304 SkASSERT(bytesPerPixel == 1 || bytesPerPixel == 2 || bytesPerPixel == 3 ||
305 bytesPerPixel == 4 || bytesPerPixel == 8 || bytesPerPixel == 16);
306 int desiredAlignment = (bytesPerPixel == 3) ? 12 : (bytesPerPixel > 4 ? bytesPerPixel : 4);
307
308 for (int currentMipLevel = 1; currentMipLevel < mipLevelCount; ++currentMipLevel) {
309 currentWidth = SkTMax(1, currentWidth / 2);
310 currentHeight = SkTMax(1, currentHeight / 2);
311
312 size_t trimmedSize = currentWidth * bytesPerPixel * currentHeight;
313 const size_t alignmentDiff = combinedBufferSize % desiredAlignment;
314 if (alignmentDiff != 0) {
315 combinedBufferSize += desiredAlignment - alignmentDiff;
316 }
317 SkASSERT((0 == combinedBufferSize % 4) && (0 == combinedBufferSize % bytesPerPixel));
318
319 individualMipOffsets->push_back(combinedBufferSize);
320 combinedBufferSize += trimmedSize;
321 }
322
323 SkASSERT(individualMipOffsets->count() == mipLevelCount);
324 return combinedBufferSize;
325 }
326
GrFillInData(GrColorType colorType,int baseWidth,int baseHeight,const SkTArray<size_t> & individualMipOffsets,char * dstPixels,const SkColor4f & colorf)327 void GrFillInData(GrColorType colorType, int baseWidth, int baseHeight,
328 const SkTArray<size_t>& individualMipOffsets, char* dstPixels,
329 const SkColor4f& colorf) {
330 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
331 int mipLevels = individualMipOffsets.count();
332
333 int currentWidth = baseWidth;
334 int currentHeight = baseHeight;
335 for (int currentMipLevel = 0; currentMipLevel < mipLevels; ++currentMipLevel) {
336 size_t offset = individualMipOffsets[currentMipLevel];
337
338 fill_buffer_with_color(colorType, currentWidth, currentHeight, colorf,
339 &(dstPixels[offset]));
340 currentWidth = SkTMax(1, currentWidth / 2);
341 currentHeight = SkTMax(1, currentHeight / 2);
342 }
343 }
344
GrFillInCompressedData(SkImage::CompressionType type,int baseWidth,int baseHeight,char * dstPixels,const SkColor4f & colorf)345 void GrFillInCompressedData(SkImage::CompressionType type, int baseWidth, int baseHeight,
346 char* dstPixels, const SkColor4f& colorf) {
347 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
348 int currentWidth = baseWidth;
349 int currentHeight = baseHeight;
350 if (SkImage::kETC1_CompressionType == type) {
351 fillin_ETC1_with_color(currentWidth, currentHeight, colorf, dstPixels);
352 }
353 }
354
get_load_and_get_swizzle(GrColorType ct,SkRasterPipeline::StockStage * load,bool * isNormalized,bool * isSRGB)355 static GrSwizzle get_load_and_get_swizzle(GrColorType ct, SkRasterPipeline::StockStage* load,
356 bool* isNormalized, bool* isSRGB) {
357 GrSwizzle swizzle("rgba");
358 *isNormalized = true;
359 *isSRGB = false;
360 switch (ct) {
361 case GrColorType::kAlpha_8: *load = SkRasterPipeline::load_a8; break;
362 case GrColorType::kAlpha_16: *load = SkRasterPipeline::load_a16; break;
363 case GrColorType::kBGR_565: *load = SkRasterPipeline::load_565; break;
364 case GrColorType::kABGR_4444: *load = SkRasterPipeline::load_4444; break;
365 case GrColorType::kRGBA_8888: *load = SkRasterPipeline::load_8888; break;
366 case GrColorType::kRG_88: *load = SkRasterPipeline::load_rg88; break;
367 case GrColorType::kRGBA_1010102: *load = SkRasterPipeline::load_1010102; break;
368 case GrColorType::kAlpha_F16: *load = SkRasterPipeline::load_af16; break;
369 case GrColorType::kRGBA_F16_Clamped: *load = SkRasterPipeline::load_f16; break;
370 case GrColorType::kRG_1616: *load = SkRasterPipeline::load_rg1616; break;
371 case GrColorType::kRGBA_16161616: *load = SkRasterPipeline::load_16161616; break;
372
373 case GrColorType::kRGBA_8888_SRGB: *load = SkRasterPipeline::load_8888;
374 *isSRGB = true;
375 break;
376 case GrColorType::kRG_F16: *load = SkRasterPipeline::load_rgf16;
377 *isNormalized = false;
378 break;
379 case GrColorType::kRGBA_F16: *load = SkRasterPipeline::load_f16;
380 *isNormalized = false;
381 break;
382 case GrColorType::kRGBA_F32: *load = SkRasterPipeline::load_f32;
383 *isNormalized = false;
384 break;
385 case GrColorType::kAlpha_8xxx: *load = SkRasterPipeline::load_8888;
386 swizzle = GrSwizzle("000r");
387 break;
388 case GrColorType::kAlpha_F32xxx: *load = SkRasterPipeline::load_f32;
389 swizzle = GrSwizzle("000r");
390 break;
391 case GrColorType::kGray_8xxx: *load = SkRasterPipeline::load_8888;
392 swizzle = GrSwizzle("rrr1");
393 break;
394 case GrColorType::kGray_8: *load = SkRasterPipeline::load_a8;
395 swizzle = GrSwizzle("aaa1");
396 break;
397 case GrColorType::kBGRA_8888: *load = SkRasterPipeline::load_8888;
398 swizzle = GrSwizzle("bgra");
399 break;
400 case GrColorType::kRGB_888x: *load = SkRasterPipeline::load_8888;
401 swizzle = GrSwizzle("rgb1");
402 break;
403
404 case GrColorType::kUnknown:
405 SK_ABORT("unexpected CT");
406 }
407 return swizzle;
408 }
409
get_dst_swizzle_and_store(GrColorType ct,SkRasterPipeline::StockStage * store,bool * isNormalized,bool * isSRGB)410 static GrSwizzle get_dst_swizzle_and_store(GrColorType ct, SkRasterPipeline::StockStage* store,
411 bool* isNormalized, bool* isSRGB) {
412 GrSwizzle swizzle("rgba");
413 *isNormalized = true;
414 *isSRGB = false;
415 switch (ct) {
416 case GrColorType::kAlpha_8: *store = SkRasterPipeline::store_a8; break;
417 case GrColorType::kAlpha_16: *store = SkRasterPipeline::store_a16; break;
418 case GrColorType::kBGR_565: *store = SkRasterPipeline::store_565; break;
419 case GrColorType::kABGR_4444: *store = SkRasterPipeline::store_4444; break;
420 case GrColorType::kRGBA_8888: *store = SkRasterPipeline::store_8888; break;
421 case GrColorType::kRG_88: *store = SkRasterPipeline::store_rg88; break;
422 case GrColorType::kRGBA_1010102: *store = SkRasterPipeline::store_1010102; break;
423 case GrColorType::kRGBA_F16_Clamped: *store = SkRasterPipeline::store_f16; break;
424 case GrColorType::kRG_1616: *store = SkRasterPipeline::store_rg1616; break;
425 case GrColorType::kRGBA_16161616: *store = SkRasterPipeline::store_16161616; break;
426
427 case GrColorType::kRGBA_8888_SRGB: *store = SkRasterPipeline::store_8888;
428 *isSRGB = true;
429 break;
430 case GrColorType::kRG_F16: *store = SkRasterPipeline::store_rgf16;
431 *isNormalized = false;
432 break;
433 case GrColorType::kAlpha_F16: *store = SkRasterPipeline::store_af16;
434 *isNormalized = false;
435 break;
436 case GrColorType::kRGBA_F16: *store = SkRasterPipeline::store_f16;
437 *isNormalized = false;
438 break;
439 case GrColorType::kRGBA_F32: *store = SkRasterPipeline::store_f32;
440 *isNormalized = false;
441 break;
442 case GrColorType::kAlpha_8xxx: *store = SkRasterPipeline::store_8888;
443 swizzle = GrSwizzle("a000");
444 break;
445 case GrColorType::kAlpha_F32xxx: *store = SkRasterPipeline::store_f32;
446 swizzle = GrSwizzle("a000");
447 break;
448 case GrColorType::kBGRA_8888: swizzle = GrSwizzle("bgra");
449 *store = SkRasterPipeline::store_8888;
450 break;
451 case GrColorType::kRGB_888x: swizzle = GrSwizzle("rgb1");
452 *store = SkRasterPipeline::store_8888;
453 break;
454
455 case GrColorType::kGray_8: // not currently supported as output
456 case GrColorType::kGray_8xxx: // not currently supported as output
457 case GrColorType::kUnknown:
458 SK_ABORT("unexpected CT");
459 }
460 return swizzle;
461 }
462
append_clamp_gamut(SkRasterPipeline * pipeline)463 static inline void append_clamp_gamut(SkRasterPipeline* pipeline) {
464 // SkRasterPipeline may not know our color type and also doesn't like caller to directly
465 // append clamp_gamut. Fake it out.
466 static SkImageInfo fakeII = SkImageInfo::MakeN32Premul(1, 1);
467 pipeline->append_gamut_clamp_if_normalized(fakeII);
468 }
469
GrConvertPixels(const GrImageInfo & dstInfo,void * dst,size_t dstRB,const GrImageInfo & srcInfo,const void * src,size_t srcRB,bool flipY)470 bool GrConvertPixels(const GrImageInfo& dstInfo, void* dst, size_t dstRB,
471 const GrImageInfo& srcInfo, const void* src, size_t srcRB,
472 bool flipY) {
473 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
474 if (!srcInfo.isValid() || !dstInfo.isValid()) {
475 return false;
476 }
477 if (!src || !dst) {
478 return false;
479 }
480 if (dstInfo.width() != srcInfo.width() || srcInfo.height() != dstInfo.height()) {
481 return false;
482 }
483 if (GrColorTypeComponentFlags(dstInfo.colorType()) & kGray_SkColorTypeComponentFlag) {
484 // We don't currently support conversion to Gray.
485 return false;
486 }
487 if (dstRB < dstInfo.minRowBytes() || srcRB < srcInfo.minRowBytes()) {
488 return false;
489 }
490
491 size_t srcBpp = srcInfo.bpp();
492 size_t dstBpp = dstInfo.bpp();
493
494 // SkRasterPipeline operates on row-pixels not row-bytes.
495 SkASSERT(dstRB % dstBpp == 0);
496 SkASSERT(srcRB % srcBpp == 0);
497
498 bool premul = srcInfo.alphaType() == kUnpremul_SkAlphaType &&
499 dstInfo.alphaType() == kPremul_SkAlphaType;
500 bool unpremul = srcInfo.alphaType() == kPremul_SkAlphaType &&
501 dstInfo.alphaType() == kUnpremul_SkAlphaType;
502 bool alphaOrCSConversion =
503 premul || unpremul || !SkColorSpace::Equals(srcInfo.colorSpace(), dstInfo.colorSpace());
504
505 if (srcInfo.colorType() == dstInfo.colorType() && !alphaOrCSConversion) {
506 size_t tightRB = dstBpp * dstInfo.width();
507 if (flipY) {
508 dst = static_cast<char*>(dst) + dstRB * (dstInfo.height() - 1);
509 for (int y = 0; y < dstInfo.height(); ++y) {
510 memcpy(dst, src, tightRB);
511 src = static_cast<const char*>(src) + srcRB;
512 dst = static_cast< char*>(dst) - dstRB;
513 }
514 } else {
515 SkRectMemcpy(dst, dstRB, src, srcRB, tightRB, srcInfo.height());
516 }
517 return true;
518 }
519
520 SkRasterPipeline::StockStage load;
521 bool srcIsNormalized;
522 bool srcIsSRGB;
523 auto loadSwizzle = get_load_and_get_swizzle(srcInfo.colorType(), &load, &srcIsNormalized,
524 &srcIsSRGB);
525
526 SkRasterPipeline::StockStage store;
527 bool dstIsNormalized;
528 bool dstIsSRGB;
529 auto storeSwizzle = get_dst_swizzle_and_store(dstInfo.colorType(), &store, &dstIsNormalized,
530 &dstIsSRGB);
531
532 bool clampGamut;
533 SkTLazy<SkColorSpaceXformSteps> steps;
534 GrSwizzle loadStoreSwizzle;
535 if (alphaOrCSConversion) {
536 steps.init(srcInfo.colorSpace(), srcInfo.alphaType(),
537 dstInfo.colorSpace(), dstInfo.alphaType());
538 clampGamut = dstIsNormalized && dstInfo.alphaType() == kPremul_SkAlphaType;
539 } else {
540 clampGamut =
541 dstIsNormalized && !srcIsNormalized && dstInfo.alphaType() == kPremul_SkAlphaType;
542 if (!clampGamut) {
543 loadStoreSwizzle = GrSwizzle::Concat(loadSwizzle, storeSwizzle);
544 }
545 }
546 int cnt = 1;
547 int height = srcInfo.height();
548 SkRasterPipeline_MemoryCtx srcCtx{const_cast<void*>(src), SkToInt(srcRB / srcBpp)},
549 dstCtx{ dst , SkToInt(dstRB / dstBpp)};
550
551 if (flipY) {
552 // It *almost* works to point the src at the last row and negate the stride and run the
553 // whole rectangle. However, SkRasterPipeline::run()'s control loop uses size_t loop
554 // variables so it winds up relying on unsigned overflow math. It works out in practice
555 // but UBSAN says "no!" as it's technically undefined and in theory a compiler could emit
556 // code that didn't do what is intended. So we go one row at a time. :(
557 srcCtx.pixels = static_cast<char*>(srcCtx.pixels) + srcRB * (height - 1);
558 std::swap(cnt, height);
559 }
560
561 bool hasConversion = alphaOrCSConversion || clampGamut;
562
563 if (srcIsSRGB && dstIsSRGB && !hasConversion) {
564 // No need to convert from srgb if we are just going to immediately convert it back.
565 srcIsSRGB = dstIsSRGB = false;
566 }
567
568 hasConversion = hasConversion || srcIsSRGB || dstIsSRGB;
569
570 for (int i = 0; i < cnt; ++i) {
571 SkRasterPipeline_<256> pipeline;
572 pipeline.append(load, &srcCtx);
573 if (hasConversion) {
574 loadSwizzle.apply(&pipeline);
575 if (srcIsSRGB) {
576 pipeline.append(SkRasterPipeline::from_srgb);
577 }
578 if (alphaOrCSConversion) {
579 steps->apply(&pipeline, srcIsNormalized);
580 }
581 if (clampGamut) {
582 append_clamp_gamut(&pipeline);
583 }
584 // If we add support for storing to Gray we would add a luminance to alpha conversion
585 // here. We also wouldn't then need a to_srgb stage after since it would have not effect
586 // on the alpha channel. It would also mean we have an SRGB Gray color type which
587 // doesn't exist currently.
588 if (dstIsSRGB) {
589 pipeline.append(SkRasterPipeline::to_srgb);
590 }
591 storeSwizzle.apply(&pipeline);
592 } else {
593 loadStoreSwizzle.apply(&pipeline);
594 }
595 pipeline.append(store, &dstCtx);
596 pipeline.run(0, 0, srcInfo.width(), height);
597 srcCtx.pixels = static_cast<char*>(srcCtx.pixels) - srcRB;
598 dstCtx.pixels = static_cast<char*>(dstCtx.pixels) + dstRB;
599 }
600 return true;
601 }
602
SkColorTypeAndFormatToGrColorType(const GrCaps * caps,SkColorType skCT,const GrBackendFormat & format)603 GrColorType SkColorTypeAndFormatToGrColorType(const GrCaps* caps,
604 SkColorType skCT,
605 const GrBackendFormat& format) {
606 GrColorType grCT = SkColorTypeToGrColorType(skCT);
607 // Until we support SRGB in the SkColorType we have to do this manual check here to make sure
608 // we use the correct GrColorType.
609 if (caps->isFormatSRGB(format)) {
610 if (grCT != GrColorType::kRGBA_8888) {
611 return GrColorType::kUnknown;
612 }
613 grCT = GrColorType::kRGBA_8888_SRGB;
614 }
615 return grCT;
616 }
617