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