1 /*
2 * Copyright 2019 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "src/gpu/ganesh/GrDataUtils.h"
9
10 #include "include/core/SkAlphaType.h"
11 #include "include/core/SkColorSpace.h"
12 #include "include/core/SkColorType.h"
13 #include "include/core/SkPixmap.h"
14 #include "include/core/SkSize.h"
15 #include "include/private/base/SkAssert.h"
16 #include "include/private/base/SkMath.h"
17 #include "include/private/base/SkTemplates.h"
18 #include "include/private/base/SkTo.h"
19 #include "include/private/gpu/ganesh/GrTypesPriv.h"
20 #include "modules/skcms/skcms.h"
21 #include "src/base/SkArenaAlloc.h"
22 #include "src/base/SkRectMemcpy.h"
23 #include "src/base/SkTLazy.h"
24 #include "src/core/SkColorSpaceXformSteps.h"
25 #include "src/core/SkRasterPipeline.h"
26 #include "src/core/SkRasterPipelineOpContexts.h"
27 #include "src/core/SkRasterPipelineOpList.h"
28 #include "src/core/SkTraceEvent.h"
29 #include "src/gpu/Swizzle.h"
30 #include "src/gpu/ganesh/GrImageInfo.h"
31 #include "src/gpu/ganesh/GrPixmap.h"
32
33 #include <algorithm>
34 #include <cstdint>
35 #include <cstring>
36 #include <functional>
37
38 using namespace skia_private;
39
40 #if defined(GPU_TEST_UTILS)
41
42 // The following four helpers are copied from src/gpu/DataUtils.cpp to support the test only
43 // GrTwoColorBC1Compress function. Ideally we would copy the test function into DataUtils.cpp
44 // instead, but we're currently trying to avoid using the GPU_TEST_UTILS define in src/gpu.
45
num_4x4_blocks(int size)46 static int num_4x4_blocks(int size) {
47 return ((size + 3) & ~3) >> 2;
48 }
49
50 struct BC1Block {
51 uint16_t fColor0;
52 uint16_t fColor1;
53 uint32_t fIndices;
54 };
55
to565(SkColor col)56 static uint16_t to565(SkColor col) {
57 int r5 = SkMulDiv255Round(31, SkColorGetR(col));
58 int g6 = SkMulDiv255Round(63, SkColorGetG(col));
59 int b5 = SkMulDiv255Round(31, SkColorGetB(col));
60
61 return (r5 << 11) | (g6 << 5) | b5;
62 }
63
64 // Create a BC1 compressed block that has two colors but is initialized to 'col0'
create_BC1_block(SkColor col0,SkColor col1,BC1Block * block)65 static void create_BC1_block(SkColor col0, SkColor col1, BC1Block* block) {
66 block->fColor0 = to565(col0);
67 block->fColor1 = to565(col1);
68 SkASSERT(block->fColor0 <= block->fColor1); // we always assume transparent blocks
69
70 if (col0 == SK_ColorTRANSPARENT) {
71 // This sets all 16 pixels to just use color3 (under the assumption
72 // that this is a kBC1_RGBA8_UNORM texture. Note that in this case
73 // fColor0 will be opaque black.
74 block->fIndices = 0xFFFFFFFF;
75 } else {
76 // This sets all 16 pixels to just use 'fColor0'
77 block->fIndices = 0;
78 }
79 }
80
81 // Fill in 'dstPixels' with BC1 blocks derived from the 'pixmap'.
GrTwoColorBC1Compress(const SkPixmap & pixmap,SkColor otherColor,char * dstPixels)82 void GrTwoColorBC1Compress(const SkPixmap& pixmap, SkColor otherColor, char* dstPixels) {
83 BC1Block* dstBlocks = reinterpret_cast<BC1Block*>(dstPixels);
84 SkASSERT(pixmap.colorType() == SkColorType::kRGBA_8888_SkColorType);
85
86 BC1Block block;
87
88 // black -> fColor0, otherColor -> fColor1
89 create_BC1_block(SK_ColorBLACK, otherColor, &block);
90
91 int numXBlocks = num_4x4_blocks(pixmap.width());
92 int numYBlocks = num_4x4_blocks(pixmap.height());
93
94 for (int y = 0; y < numYBlocks; ++y) {
95 for (int x = 0; x < numXBlocks; ++x) {
96 int shift = 0;
97 int offsetX = 4 * x, offsetY = 4 * y;
98 block.fIndices = 0; // init all the pixels to color0 (i.e., opaque black)
99 for (int i = 0; i < 4; ++i) {
100 for (int j = 0; j < 4; ++j, shift += 2) {
101 if (offsetX + j >= pixmap.width() || offsetY + i >= pixmap.height()) {
102 // This can happen for the topmost levels of a mipmap and for
103 // non-multiple of 4 textures
104 continue;
105 }
106
107 SkColor tmp = pixmap.getColor(offsetX + j, offsetY + i);
108 if (tmp == SK_ColorTRANSPARENT) {
109 // For RGBA BC1 images color3 is set to transparent black
110 block.fIndices |= 3 << shift;
111 } else if (tmp != SK_ColorBLACK) {
112 block.fIndices |= 1 << shift; // color1
113 }
114 }
115 }
116
117 dstBlocks[y*numXBlocks + x] = block;
118 }
119 }
120 }
121
122 #endif
123
GrComputeTightCombinedBufferSize(size_t bytesPerPixel,SkISize baseDimensions,TArray<size_t> * individualMipOffsets,int mipLevelCount)124 size_t GrComputeTightCombinedBufferSize(size_t bytesPerPixel, SkISize baseDimensions,
125 TArray<size_t>* individualMipOffsets, int mipLevelCount) {
126 SkASSERT(individualMipOffsets && individualMipOffsets->empty());
127 SkASSERT(mipLevelCount >= 1);
128
129 individualMipOffsets->push_back(0);
130
131 size_t combinedBufferSize = baseDimensions.width() * bytesPerPixel * baseDimensions.height();
132 SkISize levelDimensions = baseDimensions;
133
134 // The Vulkan spec for copying a buffer to an image requires that the alignment must be at
135 // least 4 bytes and a multiple of the bytes per pixel of the image config.
136 SkASSERT(bytesPerPixel == 1 || bytesPerPixel == 2 || bytesPerPixel == 3 ||
137 bytesPerPixel == 4 || bytesPerPixel == 8 || bytesPerPixel == 16);
138 int desiredAlignment = (bytesPerPixel == 3) ? 12 : (bytesPerPixel > 4 ? bytesPerPixel : 4);
139
140 for (int currentMipLevel = 1; currentMipLevel < mipLevelCount; ++currentMipLevel) {
141 levelDimensions = {std::max(1, levelDimensions.width() /2),
142 std::max(1, levelDimensions.height()/2)};
143
144 size_t trimmedSize = levelDimensions.area() * bytesPerPixel;
145 const size_t alignmentDiff = combinedBufferSize % desiredAlignment;
146 if (alignmentDiff != 0) {
147 combinedBufferSize += desiredAlignment - alignmentDiff;
148 }
149 SkASSERT((0 == combinedBufferSize % 4) && (0 == combinedBufferSize % bytesPerPixel));
150
151 individualMipOffsets->push_back(combinedBufferSize);
152 combinedBufferSize += trimmedSize;
153 }
154
155 SkASSERT(individualMipOffsets->size() == mipLevelCount);
156 return combinedBufferSize;
157 }
158
get_load_and_src_swizzle(GrColorType ct,SkRasterPipelineOp * load,bool * isNormalized,bool * isSRGB)159 static skgpu::Swizzle get_load_and_src_swizzle(GrColorType ct, SkRasterPipelineOp* load,
160 bool* isNormalized, bool* isSRGB) {
161 skgpu::Swizzle swizzle("rgba");
162 *isNormalized = true;
163 *isSRGB = false;
164 switch (ct) {
165 case GrColorType::kAlpha_8: *load = SkRasterPipelineOp::load_a8; break;
166 case GrColorType::kAlpha_16: *load = SkRasterPipelineOp::load_a16; break;
167 case GrColorType::kBGR_565: *load = SkRasterPipelineOp::load_565; break;
168 case GrColorType::kRGB_565: swizzle = skgpu::Swizzle("bgr1");
169 *load = SkRasterPipelineOp::load_565; break;
170 case GrColorType::kABGR_4444: *load = SkRasterPipelineOp::load_4444; break;
171 case GrColorType::kARGB_4444: swizzle = skgpu::Swizzle("bgra");
172 *load = SkRasterPipelineOp::load_4444; break;
173 case GrColorType::kBGRA_4444: swizzle = skgpu::Swizzle("gbar");
174 *load = SkRasterPipelineOp::load_4444; break;
175 case GrColorType::kRGBA_8888: *load = SkRasterPipelineOp::load_8888; break;
176 case GrColorType::kRG_88: *load = SkRasterPipelineOp::load_rg88; break;
177 case GrColorType::kRGBA_1010102: *load = SkRasterPipelineOp::load_1010102; break;
178 case GrColorType::kBGRA_1010102: *load = SkRasterPipelineOp::load_1010102;
179 swizzle = skgpu::Swizzle("bgra");
180 break;
181 case GrColorType::kRGB_101010x: *load = SkRasterPipelineOp::load_1010102;
182 swizzle = skgpu::Swizzle("rgb1");
183 break;
184 case GrColorType::kRGBA_10x6: *load = SkRasterPipelineOp::load_10x6; break;
185 case GrColorType::kAlpha_F16: *load = SkRasterPipelineOp::load_af16; break;
186 case GrColorType::kRGBA_F16_Clamped: *load = SkRasterPipelineOp::load_f16; break;
187 case GrColorType::kRG_1616: *load = SkRasterPipelineOp::load_rg1616; break;
188 case GrColorType::kRGBA_16161616: *load = SkRasterPipelineOp::load_16161616; break;
189
190 case GrColorType::kRGBA_8888_SRGB: *load = SkRasterPipelineOp::load_8888;
191 *isSRGB = true;
192 break;
193 case GrColorType::kRG_F16: *load = SkRasterPipelineOp::load_rgf16;
194 *isNormalized = false;
195 break;
196 case GrColorType::kRGBA_F16: *load = SkRasterPipelineOp::load_f16;
197 *isNormalized = false;
198 break;
199 case GrColorType::kRGB_F16F16F16x: *load = SkRasterPipelineOp::load_f16;
200 *isNormalized = false;
201 swizzle = skgpu::Swizzle("rgb1");
202 break;
203 case GrColorType::kRGBA_F32: *load = SkRasterPipelineOp::load_f32;
204 *isNormalized = false;
205 break;
206 case GrColorType::kAlpha_8xxx: *load = SkRasterPipelineOp::load_8888;
207 swizzle = skgpu::Swizzle("000r");
208 break;
209 case GrColorType::kAlpha_F32xxx: *load = SkRasterPipelineOp::load_f32;
210 swizzle = skgpu::Swizzle("000r");
211 break;
212 case GrColorType::kGray_8xxx: *load = SkRasterPipelineOp::load_8888;
213 swizzle = skgpu::Swizzle("rrr1");
214 break;
215 case GrColorType::kGray_8: *load = SkRasterPipelineOp::load_a8;
216 swizzle = skgpu::Swizzle("aaa1");
217 break;
218 case GrColorType::kR_8xxx: *load = SkRasterPipelineOp::load_8888;
219 swizzle = skgpu::Swizzle("r001");
220 break;
221 case GrColorType::kR_8: *load = SkRasterPipelineOp::load_a8;
222 swizzle = skgpu::Swizzle("a001");
223 break;
224 case GrColorType::kGrayAlpha_88: *load = SkRasterPipelineOp::load_rg88;
225 swizzle = skgpu::Swizzle("rrrg");
226 break;
227 case GrColorType::kBGRA_8888: *load = SkRasterPipelineOp::load_8888;
228 swizzle = skgpu::Swizzle("bgra");
229 break;
230 case GrColorType::kRGB_888x: *load = SkRasterPipelineOp::load_8888;
231 swizzle = skgpu::Swizzle("rgb1");
232 break;
233
234 // These are color types we don't expect to ever have to load.
235 case GrColorType::kRGB_888:
236 case GrColorType::kR_16:
237 case GrColorType::kR_F16:
238 case GrColorType::kGray_F16:
239 case GrColorType::kUnknown:
240 SK_ABORT("unexpected CT");
241 }
242 return swizzle;
243 }
244
245 enum class LumMode {
246 kNone,
247 kToRGB,
248 kToAlpha
249 };
250
get_dst_swizzle_and_store(GrColorType ct,SkRasterPipelineOp * store,LumMode * lumMode,bool * isNormalized,bool * isSRGB)251 static skgpu::Swizzle get_dst_swizzle_and_store(GrColorType ct, SkRasterPipelineOp* store,
252 LumMode* lumMode, bool* isNormalized,
253 bool* isSRGB) {
254 skgpu::Swizzle swizzle("rgba");
255 *isNormalized = true;
256 *isSRGB = false;
257 *lumMode = LumMode::kNone;
258 switch (ct) {
259 case GrColorType::kAlpha_8: *store = SkRasterPipelineOp::store_a8; break;
260 case GrColorType::kAlpha_16: *store = SkRasterPipelineOp::store_a16; break;
261 case GrColorType::kBGR_565: *store = SkRasterPipelineOp::store_565; break;
262 case GrColorType::kRGB_565: swizzle = skgpu::Swizzle("bgr1");
263 *store = SkRasterPipelineOp::store_565; break;
264 case GrColorType::kABGR_4444: *store = SkRasterPipelineOp::store_4444; break;
265 case GrColorType::kARGB_4444: swizzle = skgpu::Swizzle("bgra");
266 *store = SkRasterPipelineOp::store_4444; break;
267 case GrColorType::kBGRA_4444: swizzle = skgpu::Swizzle("argb");
268 *store = SkRasterPipelineOp::store_4444; break;
269 case GrColorType::kRGBA_8888: *store = SkRasterPipelineOp::store_8888; break;
270 case GrColorType::kRG_88: *store = SkRasterPipelineOp::store_rg88; break;
271 case GrColorType::kRGBA_1010102: *store = SkRasterPipelineOp::store_1010102; break;
272 case GrColorType::kBGRA_1010102: swizzle = skgpu::Swizzle("bgra");
273 *store = SkRasterPipelineOp::store_1010102;
274 break;
275 case GrColorType::kRGB_101010x: swizzle = skgpu::Swizzle("rgb1");
276 *store = SkRasterPipelineOp::store_1010102;
277 break;
278 case GrColorType::kRGBA_10x6: *store = SkRasterPipelineOp::store_10x6; break;
279 case GrColorType::kRGBA_F16_Clamped: *store = SkRasterPipelineOp::store_f16; break;
280 case GrColorType::kRG_1616: *store = SkRasterPipelineOp::store_rg1616; break;
281 case GrColorType::kRGBA_16161616: *store = SkRasterPipelineOp::store_16161616; break;
282
283 case GrColorType::kRGBA_8888_SRGB: *store = SkRasterPipelineOp::store_8888;
284 *isSRGB = true;
285 break;
286 case GrColorType::kRG_F16: *store = SkRasterPipelineOp::store_rgf16;
287 *isNormalized = false;
288 break;
289 case GrColorType::kAlpha_F16: *store = SkRasterPipelineOp::store_af16;
290 *isNormalized = false;
291 break;
292 case GrColorType::kRGBA_F16: *store = SkRasterPipelineOp::store_f16;
293 *isNormalized = false;
294 break;
295 case GrColorType::kRGB_F16F16F16x: swizzle = skgpu::Swizzle("rgb1");
296 *store = SkRasterPipelineOp::store_f16;
297 *isNormalized = false;
298 break;
299 case GrColorType::kRGBA_F32: *store = SkRasterPipelineOp::store_f32;
300 *isNormalized = false;
301 break;
302 case GrColorType::kAlpha_8xxx: *store = SkRasterPipelineOp::store_8888;
303 swizzle = skgpu::Swizzle("a000");
304 break;
305 case GrColorType::kAlpha_F32xxx: *store = SkRasterPipelineOp::store_f32;
306 swizzle = skgpu::Swizzle("a000");
307 break;
308 case GrColorType::kBGRA_8888: swizzle = skgpu::Swizzle("bgra");
309 *store = SkRasterPipelineOp::store_8888;
310 break;
311 case GrColorType::kRGB_888x: swizzle = skgpu::Swizzle("rgb1");
312 *store = SkRasterPipelineOp::store_8888;
313 break;
314 case GrColorType::kR_8xxx: swizzle = skgpu::Swizzle("r001");
315 *store = SkRasterPipelineOp::store_8888;
316 break;
317 case GrColorType::kR_8: swizzle = skgpu::Swizzle("agbr");
318 *store = SkRasterPipelineOp::store_a8;
319 break;
320 case GrColorType::kR_16: swizzle = skgpu::Swizzle("agbr");
321 *store = SkRasterPipelineOp::store_a16;
322 break;
323 case GrColorType::kR_F16: swizzle = skgpu::Swizzle("agbr");
324 *store = SkRasterPipelineOp::store_af16;
325 break;
326 case GrColorType::kGray_F16: *lumMode = LumMode::kToAlpha;
327 *store = SkRasterPipelineOp::store_af16;
328 break;
329 case GrColorType::kGray_8: *lumMode = LumMode::kToAlpha;
330 *store = SkRasterPipelineOp::store_a8;
331 break;
332 case GrColorType::kGrayAlpha_88: *lumMode = LumMode::kToRGB;
333 swizzle = skgpu::Swizzle("ragb");
334 *store = SkRasterPipelineOp::store_rg88;
335 break;
336 case GrColorType::kGray_8xxx: *lumMode = LumMode::kToRGB;
337 *store = SkRasterPipelineOp::store_8888;
338 swizzle = skgpu::Swizzle("r000");
339 break;
340
341 // These are color types we don't expect to ever have to store.
342 case GrColorType::kRGB_888: // This is handled specially in GrConvertPixels.
343 case GrColorType::kUnknown:
344 SK_ABORT("unexpected CT");
345 }
346 return swizzle;
347 }
348
GrConvertPixels(const GrPixmap & dst,const GrCPixmap & src,bool flipY)349 bool GrConvertPixels(const GrPixmap& dst, const GrCPixmap& src, bool flipY) {
350 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
351 if (src.dimensions().isEmpty() || dst.dimensions().isEmpty()) {
352 return false;
353 }
354 if (src.colorType() == GrColorType::kUnknown || dst.colorType() == GrColorType::kUnknown) {
355 return false;
356 }
357 if (!src.hasPixels() || !dst.hasPixels()) {
358 return false;
359 }
360 if (dst.dimensions() != src.dimensions()) {
361 return false;
362 }
363 if (dst.colorType() == GrColorType::kRGB_888) {
364 // SkRasterPipeline doesn't handle writing to RGB_888. So we have it write to RGB_888x and
365 // then do another conversion that does the 24bit packing. We could be cleverer and skip the
366 // temp pixmap if this is the only conversion but this is rare so keeping it simple.
367 GrPixmap temp = GrPixmap::Allocate(dst.info().makeColorType(GrColorType::kRGB_888x));
368 if (!GrConvertPixels(temp, src, flipY)) {
369 return false;
370 }
371 auto* tRow = reinterpret_cast<const char*>(temp.addr());
372 auto* dRow = reinterpret_cast<char*>(dst.addr());
373 for (int y = 0; y < dst.height(); ++y, tRow += temp.rowBytes(), dRow += dst.rowBytes()) {
374 for (int x = 0; x < dst.width(); ++x) {
375 auto t = tRow + x*sizeof(uint32_t);
376 auto d = dRow + x*3;
377 memcpy(d, t, 3);
378 }
379 }
380 return true;
381 } else if (src.colorType() == GrColorType::kRGB_888) {
382 // SkRasterPipeline doesn't handle reading from RGB_888. So convert it to RGB_888x and then
383 // do a recursive call if there is any remaining conversion.
384 GrPixmap temp = GrPixmap::Allocate(src.info().makeColorType(GrColorType::kRGB_888x));
385 auto* sRow = reinterpret_cast<const char*>(src.addr());
386 auto* tRow = reinterpret_cast<char*>(temp.addr());
387 for (int y = 0; y < src.height(); ++y, sRow += src.rowBytes(), tRow += temp.rowBytes()) {
388 for (int x = 0; x < src.width(); ++x) {
389 auto s = sRow + x*3;
390 auto t = tRow + x*sizeof(uint32_t);
391 memcpy(t, s, 3);
392 t[3] = static_cast<char>(0xFF);
393 }
394 }
395 return GrConvertPixels(dst, temp, flipY);
396 }
397
398 size_t srcBpp = src.info().bpp();
399 size_t dstBpp = dst.info().bpp();
400
401 // SkRasterPipeline operates on row-pixels not row-bytes.
402 SkASSERT(dst.rowBytes() % dstBpp == 0);
403 SkASSERT(src.rowBytes() % srcBpp == 0);
404
405 bool premul = src.alphaType() == kUnpremul_SkAlphaType &&
406 dst.alphaType() == kPremul_SkAlphaType;
407 bool unpremul = src.alphaType() == kPremul_SkAlphaType &&
408 dst.alphaType() == kUnpremul_SkAlphaType;
409 bool alphaOrCSConversion =
410 premul || unpremul || !SkColorSpace::Equals(src.colorSpace(), dst.colorSpace());
411
412 if (src.colorType() == dst.colorType() && !alphaOrCSConversion) {
413 size_t tightRB = dstBpp * dst.width();
414 if (flipY) {
415 auto s = static_cast<const char*>(src.addr());
416 auto d = SkTAddOffset<char>(dst.addr(), dst.rowBytes()*(dst.height() - 1));
417 for (int y = 0; y < dst.height(); ++y, d -= dst.rowBytes(), s += src.rowBytes()) {
418 memcpy(d, s, tightRB);
419 }
420 } else {
421 SkRectMemcpy(dst.addr(), dst.rowBytes(),
422 src.addr(), src.rowBytes(),
423 tightRB, src.height());
424 }
425 return true;
426 }
427
428 SkRasterPipelineOp load;
429 bool srcIsNormalized;
430 bool srcIsSRGB;
431 auto loadSwizzle = get_load_and_src_swizzle(src.colorType(),
432 &load,
433 &srcIsNormalized,
434 &srcIsSRGB);
435
436 SkRasterPipelineOp store;
437 LumMode lumMode;
438 bool dstIsNormalized;
439 bool dstIsSRGB;
440 auto storeSwizzle = get_dst_swizzle_and_store(dst.colorType(),
441 &store,
442 &lumMode,
443 &dstIsNormalized,
444 &dstIsSRGB);
445
446 SkTLazy<SkColorSpaceXformSteps> steps;
447 skgpu::Swizzle loadStoreSwizzle;
448 if (alphaOrCSConversion) {
449 steps.init(src.colorSpace(), src.alphaType(), dst.colorSpace(), dst.alphaType());
450 } else {
451 loadStoreSwizzle = skgpu::Swizzle::Concat(loadSwizzle, storeSwizzle);
452 }
453 int cnt = 1;
454 int height = src.height();
455 SkRasterPipeline_MemoryCtx
456 srcCtx{const_cast<void*>(src.addr()), SkToInt(src.rowBytes()/srcBpp)},
457 dstCtx{ dst.addr(), SkToInt(dst.rowBytes()/dstBpp)};
458
459 if (flipY) {
460 // It *almost* works to point the src at the last row and negate the stride and run the
461 // whole rectangle. However, SkRasterPipeline::run()'s control loop uses size_t loop
462 // variables so it winds up relying on unsigned overflow math. It works out in practice
463 // but UBSAN says "no!" as it's technically undefined and in theory a compiler could emit
464 // code that didn't do what is intended. So we go one row at a time. :(
465 srcCtx.pixels = static_cast<char*>(srcCtx.pixels) + src.rowBytes()*(height - 1);
466 std::swap(cnt, height);
467 }
468
469 bool hasConversion = alphaOrCSConversion || lumMode != LumMode::kNone;
470
471 if (srcIsSRGB && dstIsSRGB && !hasConversion) {
472 // No need to convert from srgb if we are just going to immediately convert it back.
473 srcIsSRGB = dstIsSRGB = false;
474 }
475
476 hasConversion = hasConversion || srcIsSRGB || dstIsSRGB;
477
478 SkRasterPipeline_<256> pipeline;
479 pipeline.append(load, &srcCtx);
480 if (hasConversion) {
481 loadSwizzle.apply(&pipeline);
482 if (srcIsSRGB) {
483 pipeline.appendTransferFunction(*skcms_sRGB_TransferFunction());
484 }
485 if (alphaOrCSConversion) {
486 steps->apply(&pipeline);
487 }
488 switch (lumMode) {
489 case LumMode::kNone:
490 break;
491 case LumMode::kToRGB:
492 pipeline.append(SkRasterPipelineOp::bt709_luminance_or_luma_to_rgb);
493 break;
494 case LumMode::kToAlpha:
495 pipeline.append(SkRasterPipelineOp::bt709_luminance_or_luma_to_alpha);
496 // If we ever need to store srgb-encoded gray (e.g. GL_SLUMINANCE8) then we
497 // should use ToRGB and then a swizzle stage rather than ToAlpha. The subsequent
498 // transfer function stage ignores the alpha channel (where we just stashed the
499 // gray).
500 SkASSERT(!dstIsSRGB);
501 break;
502 }
503 if (dstIsSRGB) {
504 pipeline.appendTransferFunction(*skcms_sRGB_Inverse_TransferFunction());
505 }
506 storeSwizzle.apply(&pipeline);
507 } else {
508 loadStoreSwizzle.apply(&pipeline);
509 }
510 pipeline.append(store, &dstCtx);
511 auto pipelineFn = pipeline.compile();
512 for (int i = 0; i < cnt; ++i) {
513 pipelineFn(0, 0, src.width(), height);
514 srcCtx.pixels = static_cast<char*>(srcCtx.pixels) - src.rowBytes();
515 dstCtx.pixels = static_cast<char*>(dstCtx.pixels) + dst.rowBytes();
516 }
517
518 return true;
519 }
520
GrClearImage(const GrImageInfo & dstInfo,void * dst,size_t dstRB,std::array<float,4> color)521 bool GrClearImage(const GrImageInfo& dstInfo, void* dst, size_t dstRB, std::array<float, 4> color) {
522 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
523
524 if (!dstInfo.isValid()) {
525 return false;
526 }
527 if (!dst) {
528 return false;
529 }
530 if (dstRB < dstInfo.minRowBytes()) {
531 return false;
532 }
533 if (dstInfo.colorType() == GrColorType::kRGB_888) {
534 // SkRasterPipeline doesn't handle writing to RGB_888. So we handle that specially here.
535 uint32_t rgba = SkColor4f{color[0], color[1], color[2], color[3]}.toBytes_RGBA();
536 for (int y = 0; y < dstInfo.height(); ++y) {
537 char* d = static_cast<char*>(dst) + y * dstRB;
538 for (int x = 0; x < dstInfo.width(); ++x, d += 3) {
539 memcpy(d, &rgba, 3);
540 }
541 }
542 return true;
543 }
544
545 LumMode lumMode;
546 bool isNormalized;
547 bool dstIsSRGB;
548 SkRasterPipelineOp store;
549 skgpu::Swizzle storeSwizzle = get_dst_swizzle_and_store(dstInfo.colorType(), &store, &lumMode,
550 &isNormalized, &dstIsSRGB);
551 char block[64];
552 SkArenaAlloc alloc(block, sizeof(block), 1024);
553 SkRasterPipeline_<256> pipeline;
554 pipeline.appendConstantColor(&alloc, color.data());
555 switch (lumMode) {
556 case LumMode::kNone:
557 break;
558 case LumMode::kToRGB:
559 pipeline.append(SkRasterPipelineOp::bt709_luminance_or_luma_to_rgb);
560 break;
561 case LumMode::kToAlpha:
562 pipeline.append(SkRasterPipelineOp::bt709_luminance_or_luma_to_alpha);
563 // If we ever need to store srgb-encoded gray (e.g. GL_SLUMINANCE8) then we should use
564 // ToRGB and then a swizzle stage rather than ToAlpha. The subsequent transfer function
565 // stage ignores the alpha channel (where we just stashed the gray).
566 SkASSERT(!dstIsSRGB);
567 break;
568 }
569 if (dstIsSRGB) {
570 pipeline.appendTransferFunction(*skcms_sRGB_Inverse_TransferFunction());
571 }
572 storeSwizzle.apply(&pipeline);
573 SkRasterPipeline_MemoryCtx dstCtx{dst, SkToInt(dstRB/dstInfo.bpp())};
574 pipeline.append(store, &dstCtx);
575 pipeline.run(0, 0, dstInfo.width(), dstInfo.height());
576
577 return true;
578 }
579