xref: /aosp_15_r20/external/skia/src/gpu/ganesh/GrDataUtils.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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