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 "include/private/SkSLString.h"
13 #include "src/core/SkRuntimeEffectPriv.h"
14 #include "src/core/SkVM.h"
15 #include "src/gpu/GrBaseContextPriv.h"
16 #include "src/gpu/GrColorInfo.h"
17 #include "src/gpu/GrTexture.h"
18 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
19 #include "src/gpu/glsl/GrGLSLProgramBuilder.h"
20 #include "src/sksl/SkSLUtil.h"
21 #include "src/sksl/codegen/SkSLPipelineStageCodeGenerator.h"
22 #include "src/sksl/ir/SkSLVarDeclarations.h"
23 
24 class GrSkSLFP::Impl : public ProgramImpl {
25 public:
26     void emitCode(EmitArgs& args) override {
27         const GrSkSLFP& fp            = args.fFp.cast<GrSkSLFP>();
28         const SkSL::Program& program  = *fp.fEffect->fBaseProgram;
29 
30         class FPCallbacks : public SkSL::PipelineStage::Callbacks {
31         public:
FPCallbacks(Impl* self, EmitArgs& args, const char* inputColor, const SkSL::Context& context, const uint8_t* uniformData, const GrSkSLFP::UniformFlags* uniformFlags)32             FPCallbacks(Impl* self,
33                         EmitArgs& args,
34                         const char* inputColor,
35                         const SkSL::Context& context,
36                         const uint8_t* uniformData,
37                         const GrSkSLFP::UniformFlags* uniformFlags)
38                     : fSelf(self)
39                     , fArgs(args)
40                     , fInputColor(inputColor)
41                     , fContext(context)
42                     , fUniformData(uniformData)
43                     , fUniformFlags(uniformFlags) {}
44 
45             using String = SkSL::String;
46 
47             String declareUniform(const SkSL::VarDeclaration* decl) override {
48                 const SkSL::Variable& var = decl->var();
49                 if (var.type().isOpaque()) {
50                     // Nothing to do. The only opaque types we should see are children, and those
51                     // are handled specially, above.
52                     SkASSERT(var.type().isEffectChild());
53                     return String(var.name());
54                 }
55 
56                 const SkSL::Type* type = &var.type();
57                 size_t sizeInBytes = type->slotCount() * sizeof(float);
58                 const float* floatData = reinterpret_cast<const float*>(fUniformData);
59                 const int* intData = reinterpret_cast<const int*>(fUniformData);
60                 fUniformData += sizeInBytes;
61 
62                 bool isArray = false;
63                 if (type->isArray()) {
64                     type = &type->componentType();
65                     isArray = true;
66                 }
67 
68                 GrSLType gpuType;
69                 SkAssertResult(SkSL::type_to_grsltype(fContext, *type, &gpuType));
70 
71                 if (*fUniformFlags++ & GrSkSLFP::kSpecialize_Flag) {
72                     SkASSERTF(!isArray, "specializing array uniforms is not allowed");
73                     String value = GrGLSLTypeString(gpuType);
74                     value.append("(");
75 
76                     bool isFloat = GrSLTypeIsFloatType(gpuType);
77                     size_t slots = type->slotCount();
78                     for (size_t i = 0; i < slots; ++i) {
79                         value.append(isFloat ? SkSL::to_string(floatData[i])
80                                              : SkSL::to_string(intData[i]));
81                         value.append(",");
82                     }
83                     value.back() = ')';
84                     return value;
85                 }
86 
87                 const char* uniformName = nullptr;
88                 auto handle =
89                         fArgs.fUniformHandler->addUniformArray(&fArgs.fFp.cast<GrSkSLFP>(),
90                                                                kFragment_GrShaderFlag,
91                                                                gpuType,
92                                                                SkString(var.name()).c_str(),
93                                                                isArray ? var.type().columns() : 0,
94                                                                &uniformName);
95                 fSelf->fUniformHandles.push_back(handle);
96                 return String(uniformName);
97             }
98 
99             String getMangledName(const char* name) override {
100                 return String(fArgs.fFragBuilder->getMangledFunctionName(name).c_str());
101             }
102 
103             void defineFunction(const char* decl, const char* body, bool isMain) override {
104                 if (isMain) {
105                     fArgs.fFragBuilder->codeAppend(body);
106                 } else {
107                     fArgs.fFragBuilder->emitFunction(decl, body);
108                 }
109             }
110 
111             void declareFunction(const char* decl) override {
112                 fArgs.fFragBuilder->emitFunctionPrototype(decl);
113             }
114 
115             void defineStruct(const char* definition) override {
116                 fArgs.fFragBuilder->definitionAppend(definition);
117             }
118 
119             void declareGlobal(const char* declaration) override {
120                 fArgs.fFragBuilder->definitionAppend(declaration);
121             }
122 
123             String sampleShader(int index, String coords) override {
124                 // If the child was sampled using the coords passed to main (and they are never
125                 // modified), then we will have marked the child as PassThrough. The code generator
126                 // doesn't know that, and still supplies coords. Inside invokeChild, we assert that
127                 // any coords passed for a PassThrough child match args.fSampleCoords exactly.
128                 //
129                 // Normally, this is valid. Here, we *copied* the sample coords to a local variable
130                 // (so that they're mutable in the runtime effect SkSL). Thus, the coords string we
131                 // get here is the name of the local copy, and fSampleCoords still points to the
132                 // unmodified original (which might be a varying, for example).
133                 // To prevent the assert, we pass the empty string in this case. Note that for
134                 // children sampled like this, invokeChild doesn't even use the coords parameter,
135                 // except for that assert.
136                 const GrFragmentProcessor* child = fArgs.fFp.childProcessor(index);
137                 if (child && child->sampleUsage().isPassThrough()) {
138                     coords.clear();
139                 }
140                 return String(fSelf->invokeChild(index, fInputColor, fArgs, coords).c_str());
141             }
142 
143             String sampleColorFilter(int index, String color) override {
144                 return String(fSelf->invokeChild(index,
145                                                  color.empty() ? fInputColor : color.c_str(),
146                                                  fArgs)
147                                       .c_str());
148             }
149 
150             String sampleBlender(int index, String src, String dst) override {
151                 if (!fSelf->childProcessor(index)) {
152                     return String::printf("blend_src_over(%s, %s)", src.c_str(), dst.c_str());
153                 }
154                 return String(fSelf->invokeChild(index, src.c_str(), dst.c_str(), fArgs).c_str());
155             }
156 
157             Impl*                         fSelf;
158             EmitArgs&                     fArgs;
159             const char*                   fInputColor;
160             const SkSL::Context&          fContext;
161             const uint8_t*                fUniformData;
162             const GrSkSLFP::UniformFlags* fUniformFlags;
163             int                           fUniformIndex = 0;
164         };
165 
166         // If we have an input child, we invoke it now, and make the result of that be the "input
167         // color" for all other purposes later (eg, the default passed via sample calls, etc.)
168         if (fp.fInputChildIndex >= 0) {
169             args.fFragBuilder->codeAppendf("%s = %s;\n",
170                                            args.fInputColor,
171                                            this->invokeChild(fp.fInputChildIndex, args).c_str());
172         }
173 
174         if (fp.fEffect->allowBlender()) {
175             // If we have an dest-color child, we invoke it now, and make the result of that be the
176             // "dest color" for all other purposes later.
177             if (fp.fDestColorChildIndex >= 0) {
178                 args.fFragBuilder->codeAppendf(
179                         "%s = %s;\n",
180                         args.fDestColor,
181                         this->invokeChild(fp.fDestColorChildIndex, args.fDestColor, args).c_str());
182             }
183         } else {
184             // We're not making a blender, so we don't expect a dest-color child FP to exist.
185             SkASSERT(fp.fDestColorChildIndex < 0);
186         }
187 
188         // Snap off a global copy of the input color at the start of main. We need this when
189         // we call child processors (particularly from helper functions, which can't "see" the
190         // parameter to main). Even from within main, if the code mutates the parameter, calls to
191         // sample should still be passing the original color (by default).
192         SkString inputColorName;
193         if (fp.fEffect->samplesOutsideMain()) {
194             GrShaderVar inputColorCopy(args.fFragBuilder->getMangledFunctionName("inColor"),
195                                        kHalf4_GrSLType);
196             args.fFragBuilder->declareGlobal(inputColorCopy);
197             inputColorName = inputColorCopy.getName();
198             args.fFragBuilder->codeAppendf("%s = %s;\n", inputColorName.c_str(), args.fInputColor);
199         } else {
200             inputColorName = args.fFragBuilder->newTmpVarName("inColor");
201             args.fFragBuilder->codeAppendf(
202                     "half4 %s = %s;\n", inputColorName.c_str(), args.fInputColor);
203         }
204 
205         // Copy the incoming coords to a local variable. Code in main might modify the coords
206         // parameter. fSampleCoord could be a varying, so writes to it would be illegal.
207         const char* coords = "float2(0)";
208         SkString coordsVarName;
209         if (fp.usesSampleCoordsDirectly()) {
210             coordsVarName = args.fFragBuilder->newTmpVarName("coords");
211             coords = coordsVarName.c_str();
212             args.fFragBuilder->codeAppendf("float2 %s = %s;\n", coords, args.fSampleCoord);
213         }
214 
215         FPCallbacks callbacks(this,
216                               args,
217                               inputColorName.c_str(),
218                               *program.fContext,
219                               fp.uniformData(),
220                               fp.uniformFlags());
221         SkSL::PipelineStage::ConvertProgram(
222                 program, coords, args.fInputColor, args.fDestColor, &callbacks);
223     }
224 
225 private:
226     void onSetData(const GrGLSLProgramDataManager& pdman,
227                    const GrFragmentProcessor& _proc) override {
228         using Type = SkRuntimeEffect::Uniform::Type;
229         size_t uniIndex = 0;
230         const GrSkSLFP& outer = _proc.cast<GrSkSLFP>();
231         const uint8_t* uniformData = outer.uniformData();
232         const GrSkSLFP::UniformFlags* uniformFlags = outer.uniformFlags();
233         for (const auto& v : outer.fEffect->uniforms()) {
234             if (*uniformFlags++ & GrSkSLFP::kSpecialize_Flag) {
235                 continue;
236             }
237             const UniformHandle handle = fUniformHandles[uniIndex++];
238             auto floatData = [=] { return SkTAddOffset<const float>(uniformData, v.offset); };
239             auto intData = [=] { return SkTAddOffset<const int>(uniformData, v.offset); };
240             switch (v.type) {
241                 case Type::kFloat:  pdman.set1fv(handle, v.count, floatData()); break;
242                 case Type::kFloat2: pdman.set2fv(handle, v.count, floatData()); break;
243                 case Type::kFloat3: pdman.set3fv(handle, v.count, floatData()); break;
244                 case Type::kFloat4: pdman.set4fv(handle, v.count, floatData()); break;
245 
246                 case Type::kFloat2x2: pdman.setMatrix2fv(handle, v.count, floatData()); break;
247                 case Type::kFloat3x3: pdman.setMatrix3fv(handle, v.count, floatData()); break;
248                 case Type::kFloat4x4: pdman.setMatrix4fv(handle, v.count, floatData()); break;
249 
250                 case Type::kInt:  pdman.set1iv(handle, v.count, intData()); break;
251                 case Type::kInt2: pdman.set2iv(handle, v.count, intData()); break;
252                 case Type::kInt3: pdman.set3iv(handle, v.count, intData()); break;
253                 case Type::kInt4: pdman.set4iv(handle, v.count, intData()); break;
254 
255                 default:
256                     SkDEBUGFAIL("Unsupported uniform type");
257                     break;
258             }
259         }
260     }
261 
262     std::vector<UniformHandle> fUniformHandles;
263 };
264 
MakeWithData( sk_sp<SkRuntimeEffect> effect, const char* name, std::unique_ptr<GrFragmentProcessor> inputFP, std::unique_ptr<GrFragmentProcessor> destColorFP, sk_sp<SkData> uniforms, SkSpan<std::unique_ptr<GrFragmentProcessor>> childFPs)265 std::unique_ptr<GrSkSLFP> GrSkSLFP::MakeWithData(
266         sk_sp<SkRuntimeEffect> effect,
267         const char* name,
268         std::unique_ptr<GrFragmentProcessor> inputFP,
269         std::unique_ptr<GrFragmentProcessor> destColorFP,
270         sk_sp<SkData> uniforms,
271         SkSpan<std::unique_ptr<GrFragmentProcessor>> childFPs) {
272     if (uniforms->size() != effect->uniformSize()) {
273         return nullptr;
274     }
275     size_t uniformSize = uniforms->size();
276     size_t uniformFlagSize = effect->uniforms().size() * sizeof(UniformFlags);
277     std::unique_ptr<GrSkSLFP> fp(new (uniformSize + uniformFlagSize)
278                                          GrSkSLFP(std::move(effect), name, OptFlags::kNone));
279     sk_careful_memcpy(fp->uniformData(), uniforms->data(), uniformSize);
280     for (auto& childFP : childFPs) {
281         fp->addChild(std::move(childFP), /*mergeOptFlags=*/true);
282     }
283     if (inputFP) {
284         fp->setInput(std::move(inputFP));
285     }
286     if (destColorFP) {
287         fp->setDestColorFP(std::move(destColorFP));
288     }
289     return fp;
290 }
291 
GrSkSLFP(sk_sp<SkRuntimeEffect> effect, const char* name, OptFlags optFlags)292 GrSkSLFP::GrSkSLFP(sk_sp<SkRuntimeEffect> effect, const char* name, OptFlags optFlags)
293         : INHERITED(kGrSkSLFP_ClassID,
294                     static_cast<OptimizationFlags>(optFlags) |
295                             (effect->getFilterColorProgram()
296                                      ? kConstantOutputForConstantInput_OptimizationFlag
297                                      : kNone_OptimizationFlags))
298         , fEffect(std::move(effect))
299         , fName(name)
300         , fUniformSize(SkToU32(fEffect->uniformSize())) {
301     memset(this->uniformFlags(), 0, fEffect->uniforms().size() * sizeof(UniformFlags));
302     if (fEffect->usesSampleCoords()) {
303         this->setUsesSampleCoordsDirectly();
304     }
305     if (fEffect->allowBlender()) {
306         this->setIsBlendFunction();
307     }
308 }
309 
GrSkSLFP(const GrSkSLFP& other)310 GrSkSLFP::GrSkSLFP(const GrSkSLFP& other)
311         : INHERITED(other)
312         , fEffect(other.fEffect)
313         , fName(other.fName)
314         , fUniformSize(other.fUniformSize)
315         , fInputChildIndex(other.fInputChildIndex) {
316     sk_careful_memcpy(this->uniformFlags(),
317                       other.uniformFlags(),
318                       fEffect->uniforms().size() * sizeof(UniformFlags));
319     sk_careful_memcpy(this->uniformData(), other.uniformData(), fUniformSize);
320 }
321 
addChild(std::unique_ptr<GrFragmentProcessor> child, bool mergeOptFlags)322 void GrSkSLFP::addChild(std::unique_ptr<GrFragmentProcessor> child, bool mergeOptFlags) {
323     SkASSERTF(fInputChildIndex == -1, "all addChild calls must happen before setInput");
324     SkASSERTF(fDestColorChildIndex == -1, "all addChild calls must happen before setDestColorFP");
325     int childIndex = this->numChildProcessors();
326     SkASSERT((size_t)childIndex < fEffect->fSampleUsages.size());
327     if (mergeOptFlags) {
328         this->mergeOptimizationFlags(ProcessorOptimizationFlags(child.get()));
329     }
330     this->registerChild(std::move(child), fEffect->fSampleUsages[childIndex]);
331 }
332 
setInput(std::unique_ptr<GrFragmentProcessor> input)333 void GrSkSLFP::setInput(std::unique_ptr<GrFragmentProcessor> input) {
334     SkASSERTF(fInputChildIndex == -1, "setInput should not be called more than once");
335     fInputChildIndex = this->numChildProcessors();
336     SkASSERT((size_t)fInputChildIndex >= fEffect->fSampleUsages.size());
337     this->mergeOptimizationFlags(ProcessorOptimizationFlags(input.get()));
338     this->registerChild(std::move(input), SkSL::SampleUsage::PassThrough());
339 }
340 
setDestColorFP(std::unique_ptr<GrFragmentProcessor> destColorFP)341 void GrSkSLFP::setDestColorFP(std::unique_ptr<GrFragmentProcessor> destColorFP) {
342     SkASSERTF(fEffect->allowBlender(), "dest colors are only used by blend effects");
343     SkASSERTF(fDestColorChildIndex == -1, "setDestColorFP should not be called more than once");
344     fDestColorChildIndex = this->numChildProcessors();
345     SkASSERT((size_t)fDestColorChildIndex >= fEffect->fSampleUsages.size());
346     this->mergeOptimizationFlags(ProcessorOptimizationFlags(destColorFP.get()));
347     this->registerChild(std::move(destColorFP), SkSL::SampleUsage::PassThrough());
348 }
349 
onMakeProgramImpl() const350 std::unique_ptr<GrFragmentProcessor::ProgramImpl> GrSkSLFP::onMakeProgramImpl() const {
351     return std::make_unique<Impl>();
352 }
353 
getShaderDfxInfo() const354 SkString GrSkSLFP::getShaderDfxInfo() const {
355     const UniformFlags* flags = this->uniformFlags();
356     const uint8_t* uniformData = this->uniformData();
357     size_t uniformCount = fEffect->uniforms().size();
358     auto iter = fEffect->uniforms().begin();
359     SkString specials;
360     for (size_t i = 0; i < uniformCount; ++i, ++iter) {
361         bool specialize = flags[i] & kSpecialize_Flag;
362         specials.appendf("_%d", specialize);
363         if (specialize) {
364             specials.appendf("(");
365             const uint8_t* bytes = reinterpret_cast<const uint8_t*>(uniformData + iter->offset);
366             uint32_t numBytes = iter->sizeInBytes();
367             for (; numBytes --> 0; bytes++) {
368                 specials.appendf("%X_", *bytes);
369             }
370             specials.appendf("%s)", iter->name.c_str());
371         }
372     }
373     SkString format;
374     format.printf("ShaderDfx_GrSkSLFP_%s_%X_%d_%s", name(), fEffect->hash(), fUniformSize, specials.c_str());
375     return format;
376 }
377 
onAddToKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const378 void GrSkSLFP::onAddToKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const {
379     // In the unlikely event of a hash collision, we also include the uniform size in the key.
380     // That ensures that we will (at worst) use the wrong program, but one that expects the same
381     // amount of uniform data.
382     b->add32(fEffect->hash());
383     b->add32(fUniformSize);
384 
385     const UniformFlags* flags = this->uniformFlags();
386     const uint8_t* uniformData = this->uniformData();
387     size_t uniformCount = fEffect->uniforms().size();
388     auto iter = fEffect->uniforms().begin();
389 
390     for (size_t i = 0; i < uniformCount; ++i, ++iter) {
391         bool specialize = flags[i] & kSpecialize_Flag;
392         b->addBool(specialize, "specialize");
393         if (specialize) {
394             b->addBytes(iter->sizeInBytes(), uniformData + iter->offset, iter->name.c_str());
395         }
396     }
397 }
398 
onIsEqual(const GrFragmentProcessor& other) const399 bool GrSkSLFP::onIsEqual(const GrFragmentProcessor& other) const {
400     const GrSkSLFP& sk = other.cast<GrSkSLFP>();
401     const size_t uniformFlagSize = fEffect->uniforms().size() * sizeof(UniformFlags);
402     return fEffect->hash() == sk.fEffect->hash() &&
403            fEffect->uniforms().size() == sk.fEffect->uniforms().size() &&
404            fUniformSize == sk.fUniformSize &&
405            !sk_careful_memcmp(
406                    this->uniformData(), sk.uniformData(), fUniformSize + uniformFlagSize);
407 }
408 
clone() const409 std::unique_ptr<GrFragmentProcessor> GrSkSLFP::clone() const {
410     return std::unique_ptr<GrFragmentProcessor>(new (UniformPayloadSize(fEffect.get()))
411                                                         GrSkSLFP(*this));
412 }
413 
constantOutputForConstantInput(const SkPMColor4f& inputColor) const414 SkPMColor4f GrSkSLFP::constantOutputForConstantInput(const SkPMColor4f& inputColor) const {
415     const SkFilterColorProgram* program = fEffect->getFilterColorProgram();
416     SkASSERT(program);
417 
418     auto evalChild = [&](int index, SkPMColor4f color) {
419         return ConstantOutputForConstantInput(this->childProcessor(index), color);
420     };
421 
422     SkPMColor4f color = (fInputChildIndex >= 0)
423                                 ? ConstantOutputForConstantInput(
424                                           this->childProcessor(fInputChildIndex), inputColor)
425                                 : inputColor;
426     return program->eval(color, this->uniformData(), evalChild);
427 }
428 
429 /**************************************************************************************************/
430 
431 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSkSLFP);
432 
433 #if GR_TEST_UTILS
434 
435 #include "include/effects/SkOverdrawColorFilter.h"
436 #include "src/core/SkColorFilterBase.h"
437 
438 extern const char* SKSL_OVERDRAW_SRC;
439 
TestCreate(GrProcessorTestData* d)440 std::unique_ptr<GrFragmentProcessor> GrSkSLFP::TestCreate(GrProcessorTestData* d) {
441     SkColor colors[SkOverdrawColorFilter::kNumColors];
442     for (SkColor& c : colors) {
443         c = d->fRandom->nextU();
444     }
445     auto filter = SkOverdrawColorFilter::MakeWithSkColors(colors);
446     auto [success, fp] = as_CFB(filter)->asFragmentProcessor(/*inputFP=*/nullptr, d->context(),
447                                                              GrColorInfo{});
448     SkASSERT(success);
449     return std::move(fp);
450 }
451 
452 #endif
453