xref: /aosp_15_r20/external/skia/src/gpu/ganesh/effects/GrSkSLFP.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2018 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/effects/GrSkSLFP.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkAlphaType.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkData.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurfaceProps.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkOverdrawColorFilter.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkRuntimeEffect.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/SkSLSampleUsage.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMalloc.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/gpu/ganesh/GrTypesPriv.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkArenaAlloc.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkRandom.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkColorSpacePriv.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkRasterPipeline.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkRasterPipelineOpContexts.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkRasterPipelineOpList.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkRuntimeEffectPriv.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkSLTypeShared.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/KeyBuilder.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrColorInfo.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrColorSpaceXform.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrFragmentProcessors.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrShaderVar.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/glsl/GrGLSLUniformHandler.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/SkSLString.h"
37*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/SkSLUtil.h"
38*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/codegen/SkSLPipelineStageCodeGenerator.h"
39*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/codegen/SkSLRasterPipelineBuilder.h"
40*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/ir/SkSLProgram.h"
41*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/ir/SkSLType.h"
42*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/ir/SkSLVarDeclarations.h"
43*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/ir/SkSLVariable.h"
44*c8dee2aaSAndroid Build Coastguard Worker 
45*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
46*c8dee2aaSAndroid Build Coastguard Worker 
47*c8dee2aaSAndroid Build Coastguard Worker namespace SkSL { class Context; }
48*c8dee2aaSAndroid Build Coastguard Worker struct GrShaderCaps;
49*c8dee2aaSAndroid Build Coastguard Worker 
50*c8dee2aaSAndroid Build Coastguard Worker class GrSkSLFP::Impl : public ProgramImpl {
51*c8dee2aaSAndroid Build Coastguard Worker public:
emitCode(EmitArgs & args)52*c8dee2aaSAndroid Build Coastguard Worker     void emitCode(EmitArgs& args) override {
53*c8dee2aaSAndroid Build Coastguard Worker         const GrSkSLFP& fp            = args.fFp.cast<GrSkSLFP>();
54*c8dee2aaSAndroid Build Coastguard Worker         const SkSL::Program& program  = *fp.fEffect->fBaseProgram;
55*c8dee2aaSAndroid Build Coastguard Worker 
56*c8dee2aaSAndroid Build Coastguard Worker         class FPCallbacks : public SkSL::PipelineStage::Callbacks {
57*c8dee2aaSAndroid Build Coastguard Worker         public:
58*c8dee2aaSAndroid Build Coastguard Worker             FPCallbacks(Impl* self,
59*c8dee2aaSAndroid Build Coastguard Worker                         EmitArgs& args,
60*c8dee2aaSAndroid Build Coastguard Worker                         const char* inputColor,
61*c8dee2aaSAndroid Build Coastguard Worker                         const SkSL::Context& context,
62*c8dee2aaSAndroid Build Coastguard Worker                         const uint8_t* uniformData,
63*c8dee2aaSAndroid Build Coastguard Worker                         const Specialized* specialized)
64*c8dee2aaSAndroid Build Coastguard Worker                     : fSelf(self)
65*c8dee2aaSAndroid Build Coastguard Worker                     , fArgs(args)
66*c8dee2aaSAndroid Build Coastguard Worker                     , fInputColor(inputColor)
67*c8dee2aaSAndroid Build Coastguard Worker                     , fContext(context)
68*c8dee2aaSAndroid Build Coastguard Worker                     , fUniformData(uniformData)
69*c8dee2aaSAndroid Build Coastguard Worker                     , fSpecialized(specialized) {}
70*c8dee2aaSAndroid Build Coastguard Worker 
71*c8dee2aaSAndroid Build Coastguard Worker             std::string declareUniform(const SkSL::VarDeclaration* decl) override {
72*c8dee2aaSAndroid Build Coastguard Worker                 const SkSL::Variable* var = decl->var();
73*c8dee2aaSAndroid Build Coastguard Worker                 if (var->type().isOpaque()) {
74*c8dee2aaSAndroid Build Coastguard Worker                     // Nothing to do. The only opaque types we should see are children, and those
75*c8dee2aaSAndroid Build Coastguard Worker                     // are handled specially.
76*c8dee2aaSAndroid Build Coastguard Worker                     SkASSERT(var->type().isEffectChild());
77*c8dee2aaSAndroid Build Coastguard Worker                     return std::string(var->name());
78*c8dee2aaSAndroid Build Coastguard Worker                 }
79*c8dee2aaSAndroid Build Coastguard Worker 
80*c8dee2aaSAndroid Build Coastguard Worker                 const SkSL::Type* type = &var->type();
81*c8dee2aaSAndroid Build Coastguard Worker                 size_t sizeInBytes = type->slotCount() * sizeof(float);
82*c8dee2aaSAndroid Build Coastguard Worker                 const float* floatData = reinterpret_cast<const float*>(fUniformData);
83*c8dee2aaSAndroid Build Coastguard Worker                 const int* intData = reinterpret_cast<const int*>(fUniformData);
84*c8dee2aaSAndroid Build Coastguard Worker                 fUniformData += sizeInBytes;
85*c8dee2aaSAndroid Build Coastguard Worker 
86*c8dee2aaSAndroid Build Coastguard Worker                 bool isArray = false;
87*c8dee2aaSAndroid Build Coastguard Worker                 if (type->isArray()) {
88*c8dee2aaSAndroid Build Coastguard Worker                     type = &type->componentType();
89*c8dee2aaSAndroid Build Coastguard Worker                     isArray = true;
90*c8dee2aaSAndroid Build Coastguard Worker                 }
91*c8dee2aaSAndroid Build Coastguard Worker 
92*c8dee2aaSAndroid Build Coastguard Worker                 SkSLType gpuType;
93*c8dee2aaSAndroid Build Coastguard Worker                 SkAssertResult(SkSL::type_to_sksltype(fContext, *type, &gpuType));
94*c8dee2aaSAndroid Build Coastguard Worker 
95*c8dee2aaSAndroid Build Coastguard Worker                 if (*fSpecialized++ == Specialized::kYes) {
96*c8dee2aaSAndroid Build Coastguard Worker                     SkASSERTF(!isArray, "specializing array uniforms is not allowed");
97*c8dee2aaSAndroid Build Coastguard Worker                     std::string value = SkSLTypeString(gpuType);
98*c8dee2aaSAndroid Build Coastguard Worker                     value.append("(");
99*c8dee2aaSAndroid Build Coastguard Worker 
100*c8dee2aaSAndroid Build Coastguard Worker                     bool isFloat = SkSLTypeIsFloatType(gpuType);
101*c8dee2aaSAndroid Build Coastguard Worker                     size_t slots = type->slotCount();
102*c8dee2aaSAndroid Build Coastguard Worker                     for (size_t i = 0; i < slots; ++i) {
103*c8dee2aaSAndroid Build Coastguard Worker                         value.append(isFloat ? skstd::to_string(floatData[i])
104*c8dee2aaSAndroid Build Coastguard Worker                                              : std::to_string(intData[i]));
105*c8dee2aaSAndroid Build Coastguard Worker                         value.append(",");
106*c8dee2aaSAndroid Build Coastguard Worker                     }
107*c8dee2aaSAndroid Build Coastguard Worker                     value.back() = ')';
108*c8dee2aaSAndroid Build Coastguard Worker                     return value;
109*c8dee2aaSAndroid Build Coastguard Worker                 }
110*c8dee2aaSAndroid Build Coastguard Worker 
111*c8dee2aaSAndroid Build Coastguard Worker                 const char* uniformName = nullptr;
112*c8dee2aaSAndroid Build Coastguard Worker                 auto handle =
113*c8dee2aaSAndroid Build Coastguard Worker                         fArgs.fUniformHandler->addUniformArray(&fArgs.fFp.cast<GrSkSLFP>(),
114*c8dee2aaSAndroid Build Coastguard Worker                                                                kFragment_GrShaderFlag,
115*c8dee2aaSAndroid Build Coastguard Worker                                                                gpuType,
116*c8dee2aaSAndroid Build Coastguard Worker                                                                SkString(var->name()).c_str(),
117*c8dee2aaSAndroid Build Coastguard Worker                                                                isArray ? var->type().columns() : 0,
118*c8dee2aaSAndroid Build Coastguard Worker                                                                &uniformName);
119*c8dee2aaSAndroid Build Coastguard Worker                 fSelf->fUniformHandles.push_back(handle);
120*c8dee2aaSAndroid Build Coastguard Worker                 return std::string(uniformName);
121*c8dee2aaSAndroid Build Coastguard Worker             }
122*c8dee2aaSAndroid Build Coastguard Worker 
123*c8dee2aaSAndroid Build Coastguard Worker             std::string getMangledName(const char* name) override {
124*c8dee2aaSAndroid Build Coastguard Worker                 return std::string(fArgs.fFragBuilder->getMangledFunctionName(name).c_str());
125*c8dee2aaSAndroid Build Coastguard Worker             }
126*c8dee2aaSAndroid Build Coastguard Worker 
127*c8dee2aaSAndroid Build Coastguard Worker             void defineFunction(const char* decl, const char* body, bool isMain) override {
128*c8dee2aaSAndroid Build Coastguard Worker                 if (isMain) {
129*c8dee2aaSAndroid Build Coastguard Worker                     fArgs.fFragBuilder->codeAppend(body);
130*c8dee2aaSAndroid Build Coastguard Worker                 } else {
131*c8dee2aaSAndroid Build Coastguard Worker                     fArgs.fFragBuilder->emitFunction(decl, body);
132*c8dee2aaSAndroid Build Coastguard Worker                 }
133*c8dee2aaSAndroid Build Coastguard Worker             }
134*c8dee2aaSAndroid Build Coastguard Worker 
135*c8dee2aaSAndroid Build Coastguard Worker             void declareFunction(const char* decl) override {
136*c8dee2aaSAndroid Build Coastguard Worker                 fArgs.fFragBuilder->emitFunctionPrototype(decl);
137*c8dee2aaSAndroid Build Coastguard Worker             }
138*c8dee2aaSAndroid Build Coastguard Worker 
139*c8dee2aaSAndroid Build Coastguard Worker             void defineStruct(const char* definition) override {
140*c8dee2aaSAndroid Build Coastguard Worker                 fArgs.fFragBuilder->definitionAppend(definition);
141*c8dee2aaSAndroid Build Coastguard Worker             }
142*c8dee2aaSAndroid Build Coastguard Worker 
143*c8dee2aaSAndroid Build Coastguard Worker             void declareGlobal(const char* declaration) override {
144*c8dee2aaSAndroid Build Coastguard Worker                 fArgs.fFragBuilder->definitionAppend(declaration);
145*c8dee2aaSAndroid Build Coastguard Worker             }
146*c8dee2aaSAndroid Build Coastguard Worker 
147*c8dee2aaSAndroid Build Coastguard Worker             std::string sampleShader(int index, std::string coords) override {
148*c8dee2aaSAndroid Build Coastguard Worker                 // If the child was sampled using the coords passed to main (and they are never
149*c8dee2aaSAndroid Build Coastguard Worker                 // modified), then we will have marked the child as PassThrough. The code generator
150*c8dee2aaSAndroid Build Coastguard Worker                 // doesn't know that, and still supplies coords. Inside invokeChild, we assert that
151*c8dee2aaSAndroid Build Coastguard Worker                 // any coords passed for a PassThrough child match args.fSampleCoords exactly.
152*c8dee2aaSAndroid Build Coastguard Worker                 //
153*c8dee2aaSAndroid Build Coastguard Worker                 // Normally, this is valid. Here, we *copied* the sample coords to a local variable
154*c8dee2aaSAndroid Build Coastguard Worker                 // (so that they're mutable in the runtime effect SkSL). Thus, the coords string we
155*c8dee2aaSAndroid Build Coastguard Worker                 // get here is the name of the local copy, and fSampleCoords still points to the
156*c8dee2aaSAndroid Build Coastguard Worker                 // unmodified original (which might be a varying, for example).
157*c8dee2aaSAndroid Build Coastguard Worker                 // To prevent the assert, we pass the empty string in this case. Note that for
158*c8dee2aaSAndroid Build Coastguard Worker                 // children sampled like this, invokeChild doesn't even use the coords parameter,
159*c8dee2aaSAndroid Build Coastguard Worker                 // except for that assert.
160*c8dee2aaSAndroid Build Coastguard Worker                 const GrFragmentProcessor* child = fArgs.fFp.childProcessor(index);
161*c8dee2aaSAndroid Build Coastguard Worker                 if (child && child->sampleUsage().isPassThrough()) {
162*c8dee2aaSAndroid Build Coastguard Worker                     coords.clear();
163*c8dee2aaSAndroid Build Coastguard Worker                 }
164*c8dee2aaSAndroid Build Coastguard Worker                 return child ? std::string(fSelf->invokeChild(index, fInputColor, fArgs, coords)
165*c8dee2aaSAndroid Build Coastguard Worker                                                    .c_str())
166*c8dee2aaSAndroid Build Coastguard Worker                              : std::string("half4(0)");
167*c8dee2aaSAndroid Build Coastguard Worker             }
168*c8dee2aaSAndroid Build Coastguard Worker 
169*c8dee2aaSAndroid Build Coastguard Worker             std::string sampleColorFilter(int index, std::string color) override {
170*c8dee2aaSAndroid Build Coastguard Worker                 return std::string(fSelf->invokeChild(index,
171*c8dee2aaSAndroid Build Coastguard Worker                                                       color.empty() ? fInputColor : color.c_str(),
172*c8dee2aaSAndroid Build Coastguard Worker                                                       fArgs)
173*c8dee2aaSAndroid Build Coastguard Worker                                            .c_str());
174*c8dee2aaSAndroid Build Coastguard Worker             }
175*c8dee2aaSAndroid Build Coastguard Worker 
176*c8dee2aaSAndroid Build Coastguard Worker             std::string sampleBlender(int index, std::string src, std::string dst) override {
177*c8dee2aaSAndroid Build Coastguard Worker                 if (!fSelf->childProcessor(index)) {
178*c8dee2aaSAndroid Build Coastguard Worker                     return SkSL::String::printf("blend_src_over(%s, %s)", src.c_str(), dst.c_str());
179*c8dee2aaSAndroid Build Coastguard Worker                 }
180*c8dee2aaSAndroid Build Coastguard Worker                 return std::string(
181*c8dee2aaSAndroid Build Coastguard Worker                         fSelf->invokeChild(index, src.c_str(), dst.c_str(), fArgs).c_str());
182*c8dee2aaSAndroid Build Coastguard Worker             }
183*c8dee2aaSAndroid Build Coastguard Worker 
184*c8dee2aaSAndroid Build Coastguard Worker             // These intrinsics take and return 3-component vectors, but child FPs operate on
185*c8dee2aaSAndroid Build Coastguard Worker             // 4-component vectors. We use swizzles here to paper over the difference.
186*c8dee2aaSAndroid Build Coastguard Worker             std::string toLinearSrgb(std::string color) override {
187*c8dee2aaSAndroid Build Coastguard Worker                 const GrSkSLFP& fp = fArgs.fFp.cast<GrSkSLFP>();
188*c8dee2aaSAndroid Build Coastguard Worker                 if (fp.fToLinearSrgbChildIndex < 0) {
189*c8dee2aaSAndroid Build Coastguard Worker                     return color;
190*c8dee2aaSAndroid Build Coastguard Worker                 }
191*c8dee2aaSAndroid Build Coastguard Worker                 color = SkSL::String::printf("(%s).rgb1", color.c_str());
192*c8dee2aaSAndroid Build Coastguard Worker                 SkString xformedColor = fSelf->invokeChild(
193*c8dee2aaSAndroid Build Coastguard Worker                         fp.fToLinearSrgbChildIndex, color.c_str(), fArgs);
194*c8dee2aaSAndroid Build Coastguard Worker                 return SkSL::String::printf("(%s).rgb", xformedColor.c_str());
195*c8dee2aaSAndroid Build Coastguard Worker             }
196*c8dee2aaSAndroid Build Coastguard Worker 
197*c8dee2aaSAndroid Build Coastguard Worker             std::string fromLinearSrgb(std::string color) override {
198*c8dee2aaSAndroid Build Coastguard Worker                 const GrSkSLFP& fp = fArgs.fFp.cast<GrSkSLFP>();
199*c8dee2aaSAndroid Build Coastguard Worker                 if (fp.fFromLinearSrgbChildIndex < 0) {
200*c8dee2aaSAndroid Build Coastguard Worker                     return color;
201*c8dee2aaSAndroid Build Coastguard Worker                 }
202*c8dee2aaSAndroid Build Coastguard Worker                 color = SkSL::String::printf("(%s).rgb1", color.c_str());
203*c8dee2aaSAndroid Build Coastguard Worker                 SkString xformedColor = fSelf->invokeChild(
204*c8dee2aaSAndroid Build Coastguard Worker                         fp.fFromLinearSrgbChildIndex, color.c_str(), fArgs);
205*c8dee2aaSAndroid Build Coastguard Worker                 return SkSL::String::printf("(%s).rgb", xformedColor.c_str());
206*c8dee2aaSAndroid Build Coastguard Worker             }
207*c8dee2aaSAndroid Build Coastguard Worker 
208*c8dee2aaSAndroid Build Coastguard Worker             Impl*                         fSelf;
209*c8dee2aaSAndroid Build Coastguard Worker             EmitArgs&                     fArgs;
210*c8dee2aaSAndroid Build Coastguard Worker             const char*                   fInputColor;
211*c8dee2aaSAndroid Build Coastguard Worker             const SkSL::Context&          fContext;
212*c8dee2aaSAndroid Build Coastguard Worker             const uint8_t*                fUniformData;
213*c8dee2aaSAndroid Build Coastguard Worker             const Specialized*            fSpecialized;
214*c8dee2aaSAndroid Build Coastguard Worker             int                           fUniformIndex = 0;
215*c8dee2aaSAndroid Build Coastguard Worker         };
216*c8dee2aaSAndroid Build Coastguard Worker 
217*c8dee2aaSAndroid Build Coastguard Worker         // If we have an input child, we invoke it now, and make the result of that be the "input
218*c8dee2aaSAndroid Build Coastguard Worker         // color" for all other purposes later (eg, the default passed via sample calls, etc.)
219*c8dee2aaSAndroid Build Coastguard Worker         if (fp.fInputChildIndex >= 0) {
220*c8dee2aaSAndroid Build Coastguard Worker             args.fFragBuilder->codeAppendf("%s = %s;\n",
221*c8dee2aaSAndroid Build Coastguard Worker                                            args.fInputColor,
222*c8dee2aaSAndroid Build Coastguard Worker                                            this->invokeChild(fp.fInputChildIndex, args).c_str());
223*c8dee2aaSAndroid Build Coastguard Worker         }
224*c8dee2aaSAndroid Build Coastguard Worker 
225*c8dee2aaSAndroid Build Coastguard Worker         if (fp.fEffect->allowBlender()) {
226*c8dee2aaSAndroid Build Coastguard Worker             // If we have an dest-color child, we invoke it now, and make the result of that be the
227*c8dee2aaSAndroid Build Coastguard Worker             // "dest color" for all other purposes later.
228*c8dee2aaSAndroid Build Coastguard Worker             if (fp.fDestColorChildIndex >= 0) {
229*c8dee2aaSAndroid Build Coastguard Worker                 args.fFragBuilder->codeAppendf(
230*c8dee2aaSAndroid Build Coastguard Worker                         "%s = %s;\n",
231*c8dee2aaSAndroid Build Coastguard Worker                         args.fDestColor,
232*c8dee2aaSAndroid Build Coastguard Worker                         this->invokeChild(fp.fDestColorChildIndex, args.fDestColor, args).c_str());
233*c8dee2aaSAndroid Build Coastguard Worker             }
234*c8dee2aaSAndroid Build Coastguard Worker         } else {
235*c8dee2aaSAndroid Build Coastguard Worker             // We're not making a blender, so we don't expect a dest-color child FP to exist.
236*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(fp.fDestColorChildIndex < 0);
237*c8dee2aaSAndroid Build Coastguard Worker         }
238*c8dee2aaSAndroid Build Coastguard Worker 
239*c8dee2aaSAndroid Build Coastguard Worker         // Snap off a global copy of the input color at the start of main. We need this when
240*c8dee2aaSAndroid Build Coastguard Worker         // we call child processors (particularly from helper functions, which can't "see" the
241*c8dee2aaSAndroid Build Coastguard Worker         // parameter to main). Even from within main, if the code mutates the parameter, calls to
242*c8dee2aaSAndroid Build Coastguard Worker         // sample should still be passing the original color (by default).
243*c8dee2aaSAndroid Build Coastguard Worker         SkString inputColorName;
244*c8dee2aaSAndroid Build Coastguard Worker         if (fp.fEffect->samplesOutsideMain()) {
245*c8dee2aaSAndroid Build Coastguard Worker             GrShaderVar inputColorCopy(args.fFragBuilder->getMangledFunctionName("inColor"),
246*c8dee2aaSAndroid Build Coastguard Worker                                        SkSLType::kHalf4);
247*c8dee2aaSAndroid Build Coastguard Worker             args.fFragBuilder->declareGlobal(inputColorCopy);
248*c8dee2aaSAndroid Build Coastguard Worker             inputColorName = inputColorCopy.getName();
249*c8dee2aaSAndroid Build Coastguard Worker             args.fFragBuilder->codeAppendf("%s = %s;\n", inputColorName.c_str(), args.fInputColor);
250*c8dee2aaSAndroid Build Coastguard Worker         } else {
251*c8dee2aaSAndroid Build Coastguard Worker             inputColorName = args.fFragBuilder->newTmpVarName("inColor");
252*c8dee2aaSAndroid Build Coastguard Worker             args.fFragBuilder->codeAppendf(
253*c8dee2aaSAndroid Build Coastguard Worker                     "half4 %s = %s;\n", inputColorName.c_str(), args.fInputColor);
254*c8dee2aaSAndroid Build Coastguard Worker         }
255*c8dee2aaSAndroid Build Coastguard Worker 
256*c8dee2aaSAndroid Build Coastguard Worker         // Copy the incoming coords to a local variable. Code in main might modify the coords
257*c8dee2aaSAndroid Build Coastguard Worker         // parameter. fSampleCoord could be a varying, so writes to it would be illegal.
258*c8dee2aaSAndroid Build Coastguard Worker         const char* coords = "float2(0)";
259*c8dee2aaSAndroid Build Coastguard Worker         SkString coordsVarName;
260*c8dee2aaSAndroid Build Coastguard Worker         if (fp.usesSampleCoordsDirectly()) {
261*c8dee2aaSAndroid Build Coastguard Worker             coordsVarName = args.fFragBuilder->newTmpVarName("coords");
262*c8dee2aaSAndroid Build Coastguard Worker             coords = coordsVarName.c_str();
263*c8dee2aaSAndroid Build Coastguard Worker             args.fFragBuilder->codeAppendf("float2 %s = %s;\n", coords, args.fSampleCoord);
264*c8dee2aaSAndroid Build Coastguard Worker         }
265*c8dee2aaSAndroid Build Coastguard Worker 
266*c8dee2aaSAndroid Build Coastguard Worker         FPCallbacks callbacks(this,
267*c8dee2aaSAndroid Build Coastguard Worker                               args,
268*c8dee2aaSAndroid Build Coastguard Worker                               inputColorName.c_str(),
269*c8dee2aaSAndroid Build Coastguard Worker                               *program.fContext,
270*c8dee2aaSAndroid Build Coastguard Worker                               fp.uniformData(),
271*c8dee2aaSAndroid Build Coastguard Worker                               fp.specialized());
272*c8dee2aaSAndroid Build Coastguard Worker         SkSL::PipelineStage::ConvertProgram(
273*c8dee2aaSAndroid Build Coastguard Worker                 program, coords, args.fInputColor, args.fDestColor, &callbacks);
274*c8dee2aaSAndroid Build Coastguard Worker     }
275*c8dee2aaSAndroid Build Coastguard Worker 
276*c8dee2aaSAndroid Build Coastguard Worker private:
onSetData(const GrGLSLProgramDataManager & pdman,const GrFragmentProcessor & _proc)277*c8dee2aaSAndroid Build Coastguard Worker     void onSetData(const GrGLSLProgramDataManager& pdman,
278*c8dee2aaSAndroid Build Coastguard Worker                    const GrFragmentProcessor& _proc) override {
279*c8dee2aaSAndroid Build Coastguard Worker         const GrSkSLFP& outer = _proc.cast<GrSkSLFP>();
280*c8dee2aaSAndroid Build Coastguard Worker         pdman.setRuntimeEffectUniforms(outer.fEffect->uniforms(),
281*c8dee2aaSAndroid Build Coastguard Worker                                        SkSpan(fUniformHandles),
282*c8dee2aaSAndroid Build Coastguard Worker                                        SkSpan(outer.specialized(), outer.uniformCount()),
283*c8dee2aaSAndroid Build Coastguard Worker                                        outer.uniformData());
284*c8dee2aaSAndroid Build Coastguard Worker     }
285*c8dee2aaSAndroid Build Coastguard Worker 
286*c8dee2aaSAndroid Build Coastguard Worker     std::vector<UniformHandle> fUniformHandles;
287*c8dee2aaSAndroid Build Coastguard Worker };
288*c8dee2aaSAndroid Build Coastguard Worker 
MakeWithData(sk_sp<SkRuntimeEffect> effect,const char * name,sk_sp<SkColorSpace> dstColorSpace,std::unique_ptr<GrFragmentProcessor> inputFP,std::unique_ptr<GrFragmentProcessor> destColorFP,const sk_sp<const SkData> & uniforms,SkSpan<std::unique_ptr<GrFragmentProcessor>> childFPs)289*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<GrSkSLFP> GrSkSLFP::MakeWithData(
290*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkRuntimeEffect> effect,
291*c8dee2aaSAndroid Build Coastguard Worker         const char* name,
292*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkColorSpace> dstColorSpace,
293*c8dee2aaSAndroid Build Coastguard Worker         std::unique_ptr<GrFragmentProcessor> inputFP,
294*c8dee2aaSAndroid Build Coastguard Worker         std::unique_ptr<GrFragmentProcessor> destColorFP,
295*c8dee2aaSAndroid Build Coastguard Worker         const sk_sp<const SkData>& uniforms,
296*c8dee2aaSAndroid Build Coastguard Worker         SkSpan<std::unique_ptr<GrFragmentProcessor>> childFPs) {
297*c8dee2aaSAndroid Build Coastguard Worker     if (uniforms->size() != effect->uniformSize()) {
298*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
299*c8dee2aaSAndroid Build Coastguard Worker     }
300*c8dee2aaSAndroid Build Coastguard Worker     size_t uniformSize = uniforms->size();
301*c8dee2aaSAndroid Build Coastguard Worker     size_t specializedSize = effect->uniforms().size() * sizeof(Specialized);
302*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<GrSkSLFP> fp(new (uniformSize + specializedSize)
303*c8dee2aaSAndroid Build Coastguard Worker                                          GrSkSLFP(std::move(effect), name, OptFlags::kNone));
304*c8dee2aaSAndroid Build Coastguard Worker     sk_careful_memcpy(fp->uniformData(), uniforms->data(), uniformSize);
305*c8dee2aaSAndroid Build Coastguard Worker     for (auto& childFP : childFPs) {
306*c8dee2aaSAndroid Build Coastguard Worker         fp->addChild(std::move(childFP), /*mergeOptFlags=*/true);
307*c8dee2aaSAndroid Build Coastguard Worker     }
308*c8dee2aaSAndroid Build Coastguard Worker     if (inputFP) {
309*c8dee2aaSAndroid Build Coastguard Worker         fp->setInput(std::move(inputFP));
310*c8dee2aaSAndroid Build Coastguard Worker     }
311*c8dee2aaSAndroid Build Coastguard Worker     if (destColorFP) {
312*c8dee2aaSAndroid Build Coastguard Worker         fp->setDestColorFP(std::move(destColorFP));
313*c8dee2aaSAndroid Build Coastguard Worker     }
314*c8dee2aaSAndroid Build Coastguard Worker     if (fp->fEffect->usesColorTransform() && dstColorSpace) {
315*c8dee2aaSAndroid Build Coastguard Worker         fp->addColorTransformChildren(dstColorSpace.get());
316*c8dee2aaSAndroid Build Coastguard Worker     }
317*c8dee2aaSAndroid Build Coastguard Worker     return fp;
318*c8dee2aaSAndroid Build Coastguard Worker }
319*c8dee2aaSAndroid Build Coastguard Worker 
DetermineOptimizationFlags(OptFlags of,SkRuntimeEffect * effect)320*c8dee2aaSAndroid Build Coastguard Worker GrFragmentProcessor::OptimizationFlags GrSkSLFP::DetermineOptimizationFlags(
321*c8dee2aaSAndroid Build Coastguard Worker         OptFlags of, SkRuntimeEffect* effect) {
322*c8dee2aaSAndroid Build Coastguard Worker     OptimizationFlags optFlags = static_cast<OptimizationFlags>(of);
323*c8dee2aaSAndroid Build Coastguard Worker     if (SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect)) {
324*c8dee2aaSAndroid Build Coastguard Worker         optFlags |= kConstantOutputForConstantInput_OptimizationFlag;
325*c8dee2aaSAndroid Build Coastguard Worker     }
326*c8dee2aaSAndroid Build Coastguard Worker     return optFlags;
327*c8dee2aaSAndroid Build Coastguard Worker }
328*c8dee2aaSAndroid Build Coastguard Worker 
GrSkSLFP(sk_sp<SkRuntimeEffect> effect,const char * name,OptFlags optFlags)329*c8dee2aaSAndroid Build Coastguard Worker GrSkSLFP::GrSkSLFP(sk_sp<SkRuntimeEffect> effect, const char* name, OptFlags optFlags)
330*c8dee2aaSAndroid Build Coastguard Worker         : INHERITED(kGrSkSLFP_ClassID, DetermineOptimizationFlags(optFlags, effect.get()))
331*c8dee2aaSAndroid Build Coastguard Worker         , fEffect(std::move(effect))
332*c8dee2aaSAndroid Build Coastguard Worker         , fName(name)
333*c8dee2aaSAndroid Build Coastguard Worker         , fUniformSize(SkToU32(fEffect->uniformSize())) {
334*c8dee2aaSAndroid Build Coastguard Worker     std::fill_n(this->specialized(), this->uniformCount(), Specialized::kNo);
335*c8dee2aaSAndroid Build Coastguard Worker     if (fEffect->usesSampleCoords()) {
336*c8dee2aaSAndroid Build Coastguard Worker         this->setUsesSampleCoordsDirectly();
337*c8dee2aaSAndroid Build Coastguard Worker     }
338*c8dee2aaSAndroid Build Coastguard Worker     if (fEffect->allowBlender()) {
339*c8dee2aaSAndroid Build Coastguard Worker         this->setIsBlendFunction();
340*c8dee2aaSAndroid Build Coastguard Worker     }
341*c8dee2aaSAndroid Build Coastguard Worker }
342*c8dee2aaSAndroid Build Coastguard Worker 
GrSkSLFP(const GrSkSLFP & other)343*c8dee2aaSAndroid Build Coastguard Worker GrSkSLFP::GrSkSLFP(const GrSkSLFP& other)
344*c8dee2aaSAndroid Build Coastguard Worker         : INHERITED(other)
345*c8dee2aaSAndroid Build Coastguard Worker         , fEffect(other.fEffect)
346*c8dee2aaSAndroid Build Coastguard Worker         , fName(other.fName)
347*c8dee2aaSAndroid Build Coastguard Worker         , fUniformSize(other.fUniformSize)
348*c8dee2aaSAndroid Build Coastguard Worker         , fInputChildIndex(other.fInputChildIndex)
349*c8dee2aaSAndroid Build Coastguard Worker         , fDestColorChildIndex(other.fDestColorChildIndex)
350*c8dee2aaSAndroid Build Coastguard Worker         , fToLinearSrgbChildIndex(other.fToLinearSrgbChildIndex)
351*c8dee2aaSAndroid Build Coastguard Worker         , fFromLinearSrgbChildIndex(other.fFromLinearSrgbChildIndex) {
352*c8dee2aaSAndroid Build Coastguard Worker     std::copy_n(other.specialized(), this->uniformCount(), this->specialized());
353*c8dee2aaSAndroid Build Coastguard Worker     sk_careful_memcpy(this->uniformData(), other.uniformData(), fUniformSize);
354*c8dee2aaSAndroid Build Coastguard Worker }
355*c8dee2aaSAndroid Build Coastguard Worker 
addChild(std::unique_ptr<GrFragmentProcessor> child,bool mergeOptFlags)356*c8dee2aaSAndroid Build Coastguard Worker void GrSkSLFP::addChild(std::unique_ptr<GrFragmentProcessor> child, bool mergeOptFlags) {
357*c8dee2aaSAndroid Build Coastguard Worker     SkASSERTF(fInputChildIndex == -1, "all addChild calls must happen before setInput");
358*c8dee2aaSAndroid Build Coastguard Worker     SkASSERTF(fDestColorChildIndex == -1, "all addChild calls must happen before setDestColorFP");
359*c8dee2aaSAndroid Build Coastguard Worker     int childIndex = this->numChildProcessors();
360*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT((size_t)childIndex < fEffect->fSampleUsages.size());
361*c8dee2aaSAndroid Build Coastguard Worker     if (mergeOptFlags) {
362*c8dee2aaSAndroid Build Coastguard Worker         this->mergeOptimizationFlags(ProcessorOptimizationFlags(child.get()));
363*c8dee2aaSAndroid Build Coastguard Worker     }
364*c8dee2aaSAndroid Build Coastguard Worker     this->clearConstantOutputForConstantInputFlag();
365*c8dee2aaSAndroid Build Coastguard Worker     this->registerChild(std::move(child), fEffect->fSampleUsages[childIndex]);
366*c8dee2aaSAndroid Build Coastguard Worker }
367*c8dee2aaSAndroid Build Coastguard Worker 
setInput(std::unique_ptr<GrFragmentProcessor> input)368*c8dee2aaSAndroid Build Coastguard Worker void GrSkSLFP::setInput(std::unique_ptr<GrFragmentProcessor> input) {
369*c8dee2aaSAndroid Build Coastguard Worker     SkASSERTF(fInputChildIndex == -1, "setInput should not be called more than once");
370*c8dee2aaSAndroid Build Coastguard Worker     fInputChildIndex = this->numChildProcessors();
371*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT((size_t)fInputChildIndex >= fEffect->fSampleUsages.size());
372*c8dee2aaSAndroid Build Coastguard Worker     this->mergeOptimizationFlags(ProcessorOptimizationFlags(input.get()));
373*c8dee2aaSAndroid Build Coastguard Worker     this->registerChild(std::move(input), SkSL::SampleUsage::PassThrough());
374*c8dee2aaSAndroid Build Coastguard Worker }
375*c8dee2aaSAndroid Build Coastguard Worker 
setDestColorFP(std::unique_ptr<GrFragmentProcessor> destColorFP)376*c8dee2aaSAndroid Build Coastguard Worker void GrSkSLFP::setDestColorFP(std::unique_ptr<GrFragmentProcessor> destColorFP) {
377*c8dee2aaSAndroid Build Coastguard Worker     SkASSERTF(fEffect->allowBlender(), "dest colors are only used by blend effects");
378*c8dee2aaSAndroid Build Coastguard Worker     SkASSERTF(fDestColorChildIndex == -1, "setDestColorFP should not be called more than once");
379*c8dee2aaSAndroid Build Coastguard Worker     fDestColorChildIndex = this->numChildProcessors();
380*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT((size_t)fDestColorChildIndex >= fEffect->fSampleUsages.size());
381*c8dee2aaSAndroid Build Coastguard Worker     this->mergeOptimizationFlags(ProcessorOptimizationFlags(destColorFP.get()));
382*c8dee2aaSAndroid Build Coastguard Worker     this->registerChild(std::move(destColorFP), SkSL::SampleUsage::PassThrough());
383*c8dee2aaSAndroid Build Coastguard Worker }
384*c8dee2aaSAndroid Build Coastguard Worker 
addColorTransformChildren(SkColorSpace * dstColorSpace)385*c8dee2aaSAndroid Build Coastguard Worker void GrSkSLFP::addColorTransformChildren(SkColorSpace* dstColorSpace) {
386*c8dee2aaSAndroid Build Coastguard Worker     SkASSERTF(fToLinearSrgbChildIndex == -1 && fFromLinearSrgbChildIndex == -1,
387*c8dee2aaSAndroid Build Coastguard Worker               "addColorTransformChildren should not be called more than once");
388*c8dee2aaSAndroid Build Coastguard Worker 
389*c8dee2aaSAndroid Build Coastguard Worker     // We use child FPs for the color transforms. They're really just code snippets that get
390*c8dee2aaSAndroid Build Coastguard Worker     // invoked, but each one injects a collection of uniforms and helper functions. Doing it
391*c8dee2aaSAndroid Build Coastguard Worker     // this way leverages per-FP name mangling to avoid conflicts.
392*c8dee2aaSAndroid Build Coastguard Worker     auto workingToLinear = GrColorSpaceXformEffect::Make(nullptr,
393*c8dee2aaSAndroid Build Coastguard Worker                                                          dstColorSpace,
394*c8dee2aaSAndroid Build Coastguard Worker                                                          kUnpremul_SkAlphaType,
395*c8dee2aaSAndroid Build Coastguard Worker                                                          sk_srgb_linear_singleton(),
396*c8dee2aaSAndroid Build Coastguard Worker                                                          kUnpremul_SkAlphaType);
397*c8dee2aaSAndroid Build Coastguard Worker     auto linearToWorking = GrColorSpaceXformEffect::Make(nullptr,
398*c8dee2aaSAndroid Build Coastguard Worker                                                          sk_srgb_linear_singleton(),
399*c8dee2aaSAndroid Build Coastguard Worker                                                          kUnpremul_SkAlphaType,
400*c8dee2aaSAndroid Build Coastguard Worker                                                          dstColorSpace,
401*c8dee2aaSAndroid Build Coastguard Worker                                                          kUnpremul_SkAlphaType);
402*c8dee2aaSAndroid Build Coastguard Worker 
403*c8dee2aaSAndroid Build Coastguard Worker     fToLinearSrgbChildIndex = this->numChildProcessors();
404*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT((size_t)fToLinearSrgbChildIndex >= fEffect->fSampleUsages.size());
405*c8dee2aaSAndroid Build Coastguard Worker     this->registerChild(std::move(workingToLinear), SkSL::SampleUsage::PassThrough());
406*c8dee2aaSAndroid Build Coastguard Worker 
407*c8dee2aaSAndroid Build Coastguard Worker     fFromLinearSrgbChildIndex = this->numChildProcessors();
408*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT((size_t)fFromLinearSrgbChildIndex >= fEffect->fSampleUsages.size());
409*c8dee2aaSAndroid Build Coastguard Worker     this->registerChild(std::move(linearToWorking), SkSL::SampleUsage::PassThrough());
410*c8dee2aaSAndroid Build Coastguard Worker }
411*c8dee2aaSAndroid Build Coastguard Worker 
onMakeProgramImpl() const412*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<GrFragmentProcessor::ProgramImpl> GrSkSLFP::onMakeProgramImpl() const {
413*c8dee2aaSAndroid Build Coastguard Worker     return std::make_unique<Impl>();
414*c8dee2aaSAndroid Build Coastguard Worker }
415*c8dee2aaSAndroid Build Coastguard Worker 
onAddToKey(const GrShaderCaps & caps,skgpu::KeyBuilder * b) const416*c8dee2aaSAndroid Build Coastguard Worker void GrSkSLFP::onAddToKey(const GrShaderCaps& caps, skgpu::KeyBuilder* b) const {
417*c8dee2aaSAndroid Build Coastguard Worker     // In the unlikely event of a hash collision, we also include the uniform size in the key.
418*c8dee2aaSAndroid Build Coastguard Worker     // That ensures that we will (at worst) use the wrong program, but one that expects the same
419*c8dee2aaSAndroid Build Coastguard Worker     // amount of uniform data.
420*c8dee2aaSAndroid Build Coastguard Worker     b->add32(fEffect->hash());
421*c8dee2aaSAndroid Build Coastguard Worker     b->add32(fUniformSize);
422*c8dee2aaSAndroid Build Coastguard Worker 
423*c8dee2aaSAndroid Build Coastguard Worker     const Specialized* specialized = this->specialized();
424*c8dee2aaSAndroid Build Coastguard Worker     const uint8_t* uniformData = this->uniformData();
425*c8dee2aaSAndroid Build Coastguard Worker     size_t uniformCount = this->uniformCount();
426*c8dee2aaSAndroid Build Coastguard Worker     auto iter = fEffect->uniforms().begin();
427*c8dee2aaSAndroid Build Coastguard Worker 
428*c8dee2aaSAndroid Build Coastguard Worker     for (size_t i = 0; i < uniformCount; ++i, ++iter) {
429*c8dee2aaSAndroid Build Coastguard Worker         bool specialize = specialized[i] == Specialized::kYes;
430*c8dee2aaSAndroid Build Coastguard Worker         b->addBool(specialize, "specialize");
431*c8dee2aaSAndroid Build Coastguard Worker         if (specialize) {
432*c8dee2aaSAndroid Build Coastguard Worker             b->addBytes(iter->sizeInBytes(), uniformData + iter->offset, iter->name);
433*c8dee2aaSAndroid Build Coastguard Worker         }
434*c8dee2aaSAndroid Build Coastguard Worker     }
435*c8dee2aaSAndroid Build Coastguard Worker }
436*c8dee2aaSAndroid Build Coastguard Worker 
onIsEqual(const GrFragmentProcessor & other) const437*c8dee2aaSAndroid Build Coastguard Worker bool GrSkSLFP::onIsEqual(const GrFragmentProcessor& other) const {
438*c8dee2aaSAndroid Build Coastguard Worker     const GrSkSLFP& sk = other.cast<GrSkSLFP>();
439*c8dee2aaSAndroid Build Coastguard Worker     const size_t specializedSize = this->uniformCount() * sizeof(Specialized);
440*c8dee2aaSAndroid Build Coastguard Worker     return fEffect->hash() == sk.fEffect->hash() &&
441*c8dee2aaSAndroid Build Coastguard Worker            this->uniformCount() == sk.uniformCount() &&
442*c8dee2aaSAndroid Build Coastguard Worker            fUniformSize == sk.fUniformSize &&
443*c8dee2aaSAndroid Build Coastguard Worker            !sk_careful_memcmp(this->uniformData(),
444*c8dee2aaSAndroid Build Coastguard Worker                               sk.uniformData(),
445*c8dee2aaSAndroid Build Coastguard Worker                               fUniformSize + specializedSize);
446*c8dee2aaSAndroid Build Coastguard Worker }
447*c8dee2aaSAndroid Build Coastguard Worker 
clone() const448*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<GrFragmentProcessor> GrSkSLFP::clone() const {
449*c8dee2aaSAndroid Build Coastguard Worker     return std::unique_ptr<GrFragmentProcessor>(new (UniformPayloadSize(fEffect.get()))
450*c8dee2aaSAndroid Build Coastguard Worker                                                         GrSkSLFP(*this));
451*c8dee2aaSAndroid Build Coastguard Worker }
452*c8dee2aaSAndroid Build Coastguard Worker 
constantOutputForConstantInput(const SkPMColor4f & inputColor) const453*c8dee2aaSAndroid Build Coastguard Worker SkPMColor4f GrSkSLFP::constantOutputForConstantInput(const SkPMColor4f& inputColor) const {
454*c8dee2aaSAndroid Build Coastguard Worker     SkPMColor4f color = (fInputChildIndex >= 0)
455*c8dee2aaSAndroid Build Coastguard Worker             ? ConstantOutputForConstantInput(this->childProcessor(fInputChildIndex), inputColor)
456*c8dee2aaSAndroid Build Coastguard Worker             : inputColor;
457*c8dee2aaSAndroid Build Coastguard Worker 
458*c8dee2aaSAndroid Build Coastguard Worker     class ConstantOutputForConstantInput_SkRPCallbacks : public SkSL::RP::Callbacks {
459*c8dee2aaSAndroid Build Coastguard Worker     public:
460*c8dee2aaSAndroid Build Coastguard Worker         bool appendShader(int index) override {
461*c8dee2aaSAndroid Build Coastguard Worker            SkDEBUGFAIL("constant-output-for-constant-input unsupported when child shaders present");
462*c8dee2aaSAndroid Build Coastguard Worker            return false;
463*c8dee2aaSAndroid Build Coastguard Worker         }
464*c8dee2aaSAndroid Build Coastguard Worker         bool appendColorFilter(int index) override {
465*c8dee2aaSAndroid Build Coastguard Worker            SkDEBUGFAIL("constant-output-for-constant-input unsupported when child shaders present");
466*c8dee2aaSAndroid Build Coastguard Worker            return false;
467*c8dee2aaSAndroid Build Coastguard Worker         }
468*c8dee2aaSAndroid Build Coastguard Worker         bool appendBlender(int index) override {
469*c8dee2aaSAndroid Build Coastguard Worker            SkDEBUGFAIL("constant-output-for-constant-input unsupported when child shaders present");
470*c8dee2aaSAndroid Build Coastguard Worker            return false;
471*c8dee2aaSAndroid Build Coastguard Worker         }
472*c8dee2aaSAndroid Build Coastguard Worker         void toLinearSrgb(const void* color) override { /* identity color conversion */ }
473*c8dee2aaSAndroid Build Coastguard Worker         void fromLinearSrgb(const void* color) override { /* identity color conversion */ }
474*c8dee2aaSAndroid Build Coastguard Worker     };
475*c8dee2aaSAndroid Build Coastguard Worker 
476*c8dee2aaSAndroid Build Coastguard Worker     if (const SkSL::RP::Program* program = fEffect->getRPProgram(/*debugTrace=*/nullptr)) {
477*c8dee2aaSAndroid Build Coastguard Worker         // No color conversion is happening here, so we can use untransformed uniforms.
478*c8dee2aaSAndroid Build Coastguard Worker         SkSpan<const float> uniforms{reinterpret_cast<const float*>(this->uniformData()),
479*c8dee2aaSAndroid Build Coastguard Worker                                      fUniformSize / sizeof(float)};
480*c8dee2aaSAndroid Build Coastguard Worker         SkSTArenaAlloc<2048> alloc;  // sufficient for a tiny SkSL program
481*c8dee2aaSAndroid Build Coastguard Worker         SkRasterPipeline pipeline(&alloc);
482*c8dee2aaSAndroid Build Coastguard Worker         pipeline.appendConstantColor(&alloc, color.vec());
483*c8dee2aaSAndroid Build Coastguard Worker         ConstantOutputForConstantInput_SkRPCallbacks callbacks;
484*c8dee2aaSAndroid Build Coastguard Worker         if (program->appendStages(&pipeline, &alloc, &callbacks, uniforms)) {
485*c8dee2aaSAndroid Build Coastguard Worker             SkPMColor4f outputColor;
486*c8dee2aaSAndroid Build Coastguard Worker             SkRasterPipeline_MemoryCtx outputCtx = {&outputColor, 0};
487*c8dee2aaSAndroid Build Coastguard Worker             pipeline.append(SkRasterPipelineOp::store_f32, &outputCtx);
488*c8dee2aaSAndroid Build Coastguard Worker             pipeline.run(0, 0, 1, 1);
489*c8dee2aaSAndroid Build Coastguard Worker             return outputColor;
490*c8dee2aaSAndroid Build Coastguard Worker         }
491*c8dee2aaSAndroid Build Coastguard Worker     }
492*c8dee2aaSAndroid Build Coastguard Worker 
493*c8dee2aaSAndroid Build Coastguard Worker     // We weren't able to run the Raster Pipeline program.
494*c8dee2aaSAndroid Build Coastguard Worker     return color;
495*c8dee2aaSAndroid Build Coastguard Worker }
496*c8dee2aaSAndroid Build Coastguard Worker 
497*c8dee2aaSAndroid Build Coastguard Worker /**************************************************************************************************/
498*c8dee2aaSAndroid Build Coastguard Worker 
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSkSLFP)499*c8dee2aaSAndroid Build Coastguard Worker GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSkSLFP)
500*c8dee2aaSAndroid Build Coastguard Worker 
501*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
502*c8dee2aaSAndroid Build Coastguard Worker 
503*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<GrFragmentProcessor> GrSkSLFP::TestCreate(GrProcessorTestData* d) {
504*c8dee2aaSAndroid Build Coastguard Worker     SkColor colors[SkOverdrawColorFilter::kNumColors];
505*c8dee2aaSAndroid Build Coastguard Worker     for (SkColor& c : colors) {
506*c8dee2aaSAndroid Build Coastguard Worker         c = d->fRandom->nextU();
507*c8dee2aaSAndroid Build Coastguard Worker     }
508*c8dee2aaSAndroid Build Coastguard Worker     auto filter = SkOverdrawColorFilter::MakeWithSkColors(colors);
509*c8dee2aaSAndroid Build Coastguard Worker     SkSurfaceProps props; // default props for testing
510*c8dee2aaSAndroid Build Coastguard Worker     auto [success, fp] = GrFragmentProcessors::Make(
511*c8dee2aaSAndroid Build Coastguard Worker             d->context(), filter.get(), /*inputFP=*/nullptr, GrColorInfo{}, props);
512*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(success);
513*c8dee2aaSAndroid Build Coastguard Worker     return std::move(fp);
514*c8dee2aaSAndroid Build Coastguard Worker }
515*c8dee2aaSAndroid Build Coastguard Worker 
516*c8dee2aaSAndroid Build Coastguard Worker #endif
517