1 /*
2  * Copyright 2018 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "src/gpu/effects/GrSkSLFP.h"
9 
10 #include "include/effects/SkRuntimeEffect.h"
11 #include "include/private/GrContext_Base.h"
12 #include "src/core/SkVM.h"
13 #include "src/gpu/GrBaseContextPriv.h"
14 #include "src/gpu/GrColorInfo.h"
15 #include "src/gpu/GrTexture.h"
16 #include "src/sksl/SkSLUtil.h"
17 #include "src/sksl/codegen/SkSLPipelineStageCodeGenerator.h"
18 #include "src/sksl/ir/SkSLVarDeclarations.h"
19 
20 #include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
21 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
22 #include "src/gpu/glsl/GrGLSLProgramBuilder.h"
23 
24 class GrGLSLSkSLFP : public GrGLSLFragmentProcessor {
25 public:
emitCode(EmitArgs & args)26     void emitCode(EmitArgs& args) override {
27         const GrSkSLFP& fp            = args.fFp.cast<GrSkSLFP>();
28         const SkSL::Program& program  = *fp.fEffect->fBaseProgram;
29 
30         // We need to ensure that we emit each child's helper function at least once.
31         // Any child FP that isn't sampled won't trigger a call otherwise, leading to asserts later.
32         for (int i = 0; i < this->numChildProcessors(); ++i) {
33             if (this->childProcessor(i)) {
34                 this->emitChildFunction(i, args);
35             }
36         }
37 
38         class FPCallbacks : public SkSL::PipelineStage::Callbacks {
39         public:
40             FPCallbacks(GrGLSLSkSLFP* self,
41                         EmitArgs& args,
42                         const char* inputColor,
43                         const SkSL::Context& context)
44                     : fSelf(self), fArgs(args), fInputColor(inputColor), fContext(context) {}
45 
46             using String = SkSL::String;
47 
48             String declareUniform(const SkSL::VarDeclaration* decl) override {
49                 const SkSL::Variable& var = decl->var();
50                 if (var.type().isOpaque()) {
51                     // Nothing to do. The only opaque types we should see are children, and those
52                     // are handled specially, above.
53                     SkASSERT(var.type().isEffectChild());
54                     return String(var.name());
55                 }
56 
57                 const SkSL::Type* type = &var.type();
58                 bool isArray = false;
59                 if (type->isArray()) {
60                     type = &type->componentType();
61                     isArray = true;
62                 }
63 
64                 GrSLType gpuType;
65                 SkAssertResult(SkSL::type_to_grsltype(fContext, *type, &gpuType));
66                 const char* uniformName = nullptr;
67                 auto handle =
68                         fArgs.fUniformHandler->addUniformArray(&fArgs.fFp.cast<GrSkSLFP>(),
69                                                                kFragment_GrShaderFlag,
70                                                                gpuType,
71                                                                SkString(var.name()).c_str(),
72                                                                isArray ? var.type().columns() : 0,
73                                                                &uniformName);
74                 fSelf->fUniformHandles.push_back(handle);
75                 return String(uniformName);
76             }
77 
78             String getMangledName(const char* name) override {
79                 return String(fArgs.fFragBuilder->getMangledFunctionName(name).c_str());
80             }
81 
82             void defineFunction(const char* decl, const char* body, bool isMain) override {
83                 if (isMain) {
84                     fArgs.fFragBuilder->codeAppend(body);
85                 } else {
86                     fArgs.fFragBuilder->emitFunction(decl, body);
87                 }
88             }
89 
90             void defineStruct(const char* definition) override {
91                 fArgs.fFragBuilder->definitionAppend(definition);
92             }
93 
94             void declareGlobal(const char* declaration) override {
95                 fArgs.fFragBuilder->definitionAppend(declaration);
96             }
97 
98             String sampleChild(int index, String coords, String color) override {
99                 // If the child was sampled using the coords passed to main (and they are never
100                 // modified), then we will have marked the child as PassThrough. The code generator
101                 // doesn't know that, and still supplies coords. Inside invokeChild, we assert that
102                 // any coords passed for a PassThrough child match args.fSampleCoords exactly.
103                 //
104                 // Normally, this is valid. Here, we *copied* the sample coords to a local variable
105                 // (so that they're mutable in the runtime effect SkSL). Thus, the coords string we
106                 // get here is the name of the local copy, and fSampleCoords still points to the
107                 // unmodified original (which might be a varying, for example).
108                 // To prevent the assert, we pass the empty string in this case. Note that for
109                 // children sampled like this, invokeChild doesn't even use the coords parameter,
110                 // except for that assert.
111                 const GrFragmentProcessor* child = fArgs.fFp.childProcessor(index);
112                 if (child && !child->isSampledWithExplicitCoords()) {
113                     coords.clear();
114                 }
115                 return String(fSelf->invokeChild(index,
116                                                  color.empty() ? fInputColor : color.c_str(),
117                                                  fArgs,
118                                                  coords)
119                                       .c_str());
120             }
121 
122             GrGLSLSkSLFP*        fSelf;
123             EmitArgs&            fArgs;
124             const char*          fInputColor;
125             const SkSL::Context& fContext;
126         };
127 
128         // Snap off a global copy of the input color at the start of main. We need this when
129         // we call child processors (particularly from helper functions, which can't "see" the
130         // parameter to main). Even from within main, if the code mutates the parameter, calls to
131         // sample should still be passing the original color (by default).
132         GrShaderVar inputColorCopy(args.fFragBuilder->getMangledFunctionName("inColor"),
133                                    kHalf4_GrSLType);
134         args.fFragBuilder->declareGlobal(inputColorCopy);
135         args.fFragBuilder->codeAppendf("%s = %s;\n", inputColorCopy.c_str(), args.fInputColor);
136 
137         // Callback to define a function (and return its mangled name)
138         SkString coordsVarName = args.fFragBuilder->newTmpVarName("coords");
139         const char* coords = nullptr;
140         if (fp.referencesSampleCoords()) {
141             coords = coordsVarName.c_str();
142             args.fFragBuilder->codeAppendf("float2 %s = %s;\n", coords, args.fSampleCoord);
143         }
144 
145         FPCallbacks callbacks(this, args, inputColorCopy.c_str(), *program.fContext);
146         SkSL::PipelineStage::ConvertProgram(program, coords, args.fInputColor, &callbacks);
147     }
148 
onSetData(const GrGLSLProgramDataManager & pdman,const GrFragmentProcessor & _proc)149     void onSetData(const GrGLSLProgramDataManager& pdman,
150                    const GrFragmentProcessor& _proc) override {
151         using Type = SkRuntimeEffect::Uniform::Type;
152         size_t uniIndex = 0;
153         const GrSkSLFP& outer = _proc.cast<GrSkSLFP>();
154         const uint8_t* uniformData = outer.fUniforms->bytes();
155         for (const auto& v : outer.fEffect->uniforms()) {
156             const UniformHandle handle = fUniformHandles[uniIndex++];
157             auto floatData = [=] { return SkTAddOffset<const float>(uniformData, v.offset); };
158             auto intData = [=] { return SkTAddOffset<const int>(uniformData, v.offset); };
159             switch (v.type) {
160                 case Type::kFloat:  pdman.set1fv(handle, v.count, floatData()); break;
161                 case Type::kFloat2: pdman.set2fv(handle, v.count, floatData()); break;
162                 case Type::kFloat3: pdman.set3fv(handle, v.count, floatData()); break;
163                 case Type::kFloat4: pdman.set4fv(handle, v.count, floatData()); break;
164 
165                 case Type::kFloat2x2: pdman.setMatrix2fv(handle, v.count, floatData()); break;
166                 case Type::kFloat3x3: pdman.setMatrix3fv(handle, v.count, floatData()); break;
167                 case Type::kFloat4x4: pdman.setMatrix4fv(handle, v.count, floatData()); break;
168 
169                 case Type::kInt:  pdman.set1iv(handle, v.count, intData()); break;
170                 case Type::kInt2: pdman.set2iv(handle, v.count, intData()); break;
171                 case Type::kInt3: pdman.set3iv(handle, v.count, intData()); break;
172                 case Type::kInt4: pdman.set4iv(handle, v.count, intData()); break;
173 
174                 default:
175                     SkDEBUGFAIL("Unsupported uniform type");
176                     break;
177             }
178         }
179     }
180 
181     std::vector<UniformHandle> fUniformHandles;
182 };
183 
Make(sk_sp<SkRuntimeEffect> effect,const char * name,sk_sp<SkData> uniforms)184 std::unique_ptr<GrSkSLFP> GrSkSLFP::Make(sk_sp<SkRuntimeEffect> effect,
185                                          const char* name,
186                                          sk_sp<SkData> uniforms) {
187     if (uniforms->size() != effect->uniformSize()) {
188         return nullptr;
189     }
190     return std::unique_ptr<GrSkSLFP>(new GrSkSLFP(std::move(effect), name, std::move(uniforms)));
191 }
192 
GrSkSLFP(sk_sp<SkRuntimeEffect> effect,const char * name,sk_sp<SkData> uniforms)193 GrSkSLFP::GrSkSLFP(sk_sp<SkRuntimeEffect> effect, const char* name, sk_sp<SkData> uniforms)
194         : INHERITED(kGrSkSLFP_ClassID,
195                     effect->getFilterColorInfo().program
196                             ? kConstantOutputForConstantInput_OptimizationFlag
197                             : kNone_OptimizationFlags)
198         , fEffect(std::move(effect))
199         , fName(name)
200         , fUniforms(std::move(uniforms)) {
201     if (fEffect->usesSampleCoords()) {
202         this->setUsesSampleCoordsDirectly();
203     }
204 }
205 
GrSkSLFP(const GrSkSLFP & other)206 GrSkSLFP::GrSkSLFP(const GrSkSLFP& other)
207         : INHERITED(kGrSkSLFP_ClassID, other.optimizationFlags())
208         , fEffect(other.fEffect)
209         , fName(other.fName)
210         , fUniforms(other.fUniforms) {
211     if (fEffect->usesSampleCoords()) {
212         this->setUsesSampleCoordsDirectly();
213     }
214 
215     this->cloneAndRegisterAllChildProcessors(other);
216 }
217 
name() const218 const char* GrSkSLFP::name() const {
219     return fName;
220 }
221 
addChild(std::unique_ptr<GrFragmentProcessor> child)222 void GrSkSLFP::addChild(std::unique_ptr<GrFragmentProcessor> child) {
223     int childIndex = this->numChildProcessors();
224     SkASSERT((size_t)childIndex < fEffect->fSampleUsages.size());
225     this->mergeOptimizationFlags(ProcessorOptimizationFlags(child.get()));
226     this->registerChild(std::move(child), fEffect->fSampleUsages[childIndex]);
227 }
228 
onMakeProgramImpl() const229 std::unique_ptr<GrGLSLFragmentProcessor> GrSkSLFP::onMakeProgramImpl() const {
230     return std::make_unique<GrGLSLSkSLFP>();
231 }
232 
onGetGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const233 void GrSkSLFP::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const {
234     // In the unlikely event of a hash collision, we also include the uniform size in the key.
235     // That ensures that we will (at worst) use the wrong program, but one that expects the same
236     // amount of uniform data.
237     b->add32(fEffect->hash());
238     b->add32(SkToU32(fUniforms->size()));
239 }
240 
onIsEqual(const GrFragmentProcessor & other) const241 bool GrSkSLFP::onIsEqual(const GrFragmentProcessor& other) const {
242     const GrSkSLFP& sk = other.cast<GrSkSLFP>();
243     return fEffect->hash() == sk.fEffect->hash() && fUniforms->equals(sk.fUniforms.get());
244 }
245 
clone() const246 std::unique_ptr<GrFragmentProcessor> GrSkSLFP::clone() const {
247     return std::unique_ptr<GrFragmentProcessor>(new GrSkSLFP(*this));
248 }
249 
constantOutputForConstantInput(const SkPMColor4f & inputColor) const250 SkPMColor4f GrSkSLFP::constantOutputForConstantInput(const SkPMColor4f& inputColor) const {
251     const skvm::Program* program = fEffect->getFilterColorInfo().program;
252     SkASSERT(program);
253 
254     SkSTArray<3, SkPMColor4f, true> childColors;
255     childColors.push_back(inputColor);
256     for (int i = 0; i < this->numChildProcessors(); ++i) {
257         childColors.push_back(ConstantOutputForConstantInput(this->childProcessor(i), inputColor));
258     }
259 
260     SkPMColor4f result;
261     program->eval(1, childColors.begin(), fUniforms->data(), result.vec());
262     return result;
263 }
264 
265 /**************************************************************************************************/
266 
267 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSkSLFP);
268 
269 #if GR_TEST_UTILS
270 
271 #include "include/effects/SkOverdrawColorFilter.h"
272 #include "src/core/SkColorFilterBase.h"
273 
274 extern const char* SKSL_OVERDRAW_SRC;
275 
TestCreate(GrProcessorTestData * d)276 std::unique_ptr<GrFragmentProcessor> GrSkSLFP::TestCreate(GrProcessorTestData* d) {
277     SkColor colors[SkOverdrawColorFilter::kNumColors];
278     for (SkColor& c : colors) {
279         c = d->fRandom->nextU();
280     }
281     auto filter = SkOverdrawColorFilter::MakeWithSkColors(colors);
282     auto [success, fp] = as_CFB(filter)->asFragmentProcessor(/*inputFP=*/nullptr, d->context(),
283                                                              GrColorInfo{});
284     SkASSERT(success);
285     return std::move(fp);
286 }
287 
288 #endif
289 
290 /**************************************************************************************************/
291 
GrRuntimeFPBuilder(sk_sp<SkRuntimeEffect> effect)292 GrRuntimeFPBuilder::GrRuntimeFPBuilder(sk_sp<SkRuntimeEffect> effect)
293         : INHERITED(std::move(effect)) {}
294 
295 GrRuntimeFPBuilder::~GrRuntimeFPBuilder() = default;
296 
makeFP()297 std::unique_ptr<GrFragmentProcessor> GrRuntimeFPBuilder::makeFP() {
298     return this->effect()->makeFP(this->uniforms(),
299                                   this->children(),
300                                   this->numChildren());
301 }
302