Add new SampleBlender callback to SkVMCodeGenerator.

This CL doesn't actually allow the callbacks to be invoked from SkSL
yet, but the callbacks now exist and are now threaded through the
various callsites which will need them.

Change-Id: I00f43ff94de9da8d93daf2e59885eea6f87c2e3e
Bug: skia:12257
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/431696
Commit-Queue: John Stiles <johnstiles@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/fuzz/oss_fuzz/FuzzSKSL2Pipeline.cpp b/fuzz/oss_fuzz/FuzzSKSL2Pipeline.cpp
index 40398a2..7e3d987 100644
--- a/fuzz/oss_fuzz/FuzzSKSL2Pipeline.cpp
+++ b/fuzz/oss_fuzz/FuzzSKSL2Pipeline.cpp
@@ -49,6 +49,10 @@
             result += ")";
             return result;
         }
+
+        String sampleBlender(int index, String src, String dst) override {
+            return "sample(" + SkSL::to_string(index) + ", " + src + ", " + dst + ")";
+        }
     };
 
     Callbacks callbacks;
diff --git a/src/core/SkRuntimeEffect.cpp b/src/core/SkRuntimeEffect.cpp
index 77448af..22d300b 100644
--- a/src/core/SkRuntimeEffect.cpp
+++ b/src/core/SkRuntimeEffect.cpp
@@ -624,7 +624,8 @@
                                              inputColor,
                                              inputColor,
                                              /*sampleShader=*/nullptr,
-                                             sampleColorFilter);
+                                             sampleColorFilter,
+                                             /*sampleBlender=*/nullptr);
 
     // Then store the result to the *third* arg ptr
     p.store({skvm::PixelFormat::FLOAT, 32, 32, 32, 32, 0, 32, 64, 96}, p.arg(16), result);
@@ -823,6 +824,10 @@
             }
             return color;
         };
+        auto sampleBlender = [&](int ix, skvm::Color src, skvm::Color dst) {
+            // TODO(skia:12257): implement sample(blender, src, dst)
+            return src;
+        };
 
         std::vector<skvm::Val> uniform = make_skvm_uniforms(p, uniforms, fEffect->uniformSize(),
                                                             *inputs);
@@ -832,7 +837,7 @@
         skvm::Coord zeroCoord = { p->splat(0.0f), p->splat(0.0f) };
         return SkSL::ProgramToSkVM(*fEffect->fBaseProgram, fEffect->fMain, p, SkMakeSpan(uniform),
                                    /*device=*/zeroCoord, /*local=*/zeroCoord, c, c, sampleShader,
-                                   sampleColorFilter);
+                                   sampleColorFilter, sampleBlender);
     }
 
     SkPMColor4f onFilterColor4f(const SkPMColor4f& color, SkColorSpace* dstCS) const override {
@@ -1011,12 +1016,17 @@
             }
             return color;
         };
+        auto sampleBlender = [&](int ix, skvm::Color src, skvm::Color dst) {
+            // TODO(skia:12257): implement sample(blender, src, dst)
+            return src;
+        };
 
         std::vector<skvm::Val> uniform = make_skvm_uniforms(p, uniforms, fEffect->uniformSize(),
                                                             *inputs);
 
         return SkSL::ProgramToSkVM(*fEffect->fBaseProgram, fEffect->fMain, p, SkMakeSpan(uniform),
-                                   device, local, paint, paint, sampleShader, sampleColorFilter);
+                                   device, local, paint, paint, sampleShader, sampleColorFilter,
+                                   sampleBlender);
     }
 
     void flatten(SkWriteBuffer& buffer) const override {
@@ -1131,6 +1141,10 @@
             }
             return color;
         };
+        auto sampleBlender = [&](int ix, skvm::Color src, skvm::Color dst) {
+            // TODO(skia:12257): implement sample(blender, src, dst)
+            return src;
+        };
 
         std::vector<skvm::Val> uniform = make_skvm_uniforms(p, uniforms, fEffect->uniformSize(),
                                                             *inputs);
@@ -1139,7 +1153,7 @@
         skvm::Coord zeroCoord = {p->splat(0.0f), p->splat(0.0f)};
         return SkSL::ProgramToSkVM(*fEffect->fBaseProgram, fEffect->fMain, p, SkMakeSpan(uniform),
                                   /*device=*/zeroCoord, /*local=*/zeroCoord, src, dst,
-                                  sampleShader, sampleColorFilter);
+                                  sampleShader, sampleColorFilter, sampleBlender);
     }
 
 #if SK_SUPPORT_GPU
diff --git a/src/gpu/effects/GrSkSLFP.cpp b/src/gpu/effects/GrSkSLFP.cpp
index 244cdba..30e14b9 100644
--- a/src/gpu/effects/GrSkSLFP.cpp
+++ b/src/gpu/effects/GrSkSLFP.cpp
@@ -153,6 +153,11 @@
                                       .c_str());
             }
 
+            String sampleBlender(int index, String src, String dst) override {
+                // TODO(skia:12257): invokeChild does not yet allow sampling from a blender
+                return "half4(1)";
+            }
+
             GrGLSLSkSLFP*                 fSelf;
             EmitArgs&                     fArgs;
             const char*                   fInputColor;
diff --git a/src/sksl/SkSLMain.cpp b/src/sksl/SkSLMain.cpp
index 199bf81..edb0f76 100644
--- a/src/sksl/SkSLMain.cpp
+++ b/src/sksl/SkSLMain.cpp
@@ -434,6 +434,11 @@
                             return result;
                         }
 
+                        String sampleBlender(int index, String src, String dst) override {
+                            return "sample(child_" + SkSL::to_string(index) + ", " + src + ", " +
+                                   dst + ")";
+                        }
+
                         String fOutput;
                     };
                     // The .stage output looks almost like valid SkSL, but not quite.
diff --git a/src/sksl/codegen/SkSLPipelineStageCodeGenerator.h b/src/sksl/codegen/SkSLPipelineStageCodeGenerator.h
index bd87a34..8394650 100644
--- a/src/sksl/codegen/SkSLPipelineStageCodeGenerator.h
+++ b/src/sksl/codegen/SkSLPipelineStageCodeGenerator.h
@@ -30,6 +30,7 @@
         virtual String declareUniform(const VarDeclaration*) = 0;
         virtual String sampleShader(int index, String coords) = 0;
         virtual String sampleColorFilter(int index, String color) = 0;
+        virtual String sampleBlender(int index, String src, String dst) = 0;
     };
 
     /*
diff --git a/src/sksl/codegen/SkSLVMCodeGenerator.cpp b/src/sksl/codegen/SkSLVMCodeGenerator.cpp
index 5cb849b..ae5d2aea 100644
--- a/src/sksl/codegen/SkSLVMCodeGenerator.cpp
+++ b/src/sksl/codegen/SkSLVMCodeGenerator.cpp
@@ -117,7 +117,8 @@
                   skvm::Coord device,
                   skvm::Coord local,
                   SampleShaderFn sampleShader,
-                  SampleColorFilterFn sampleColorFilter);
+                  SampleColorFilterFn sampleColorFilter,
+                  SampleBlenderFn sampleBlender);
 
     void writeFunction(const FunctionDefinition& function,
                        SkSpan<skvm::Val> arguments,
@@ -220,6 +221,7 @@
     const skvm::Coord fLocalCoord;
     const SampleShaderFn fSampleShader;
     const SampleColorFilterFn fSampleColorFilter;
+    const SampleBlenderFn fSampleBlender;
 
     // [Variable, first slot in fSlots]
     std::unordered_map<const Variable*, size_t> fVariableMap;
@@ -277,12 +279,14 @@
                              skvm::Coord device,
                              skvm::Coord local,
                              SampleShaderFn sampleShader,
-                             SampleColorFilterFn sampleColorFilter)
+                             SampleColorFilterFn sampleColorFilter,
+                             SampleBlenderFn sampleBlender)
         : fProgram(program)
         , fBuilder(builder)
         , fLocalCoord(local)
         , fSampleShader(std::move(sampleShader))
-        , fSampleColorFilter(std::move(sampleColorFilter)) {
+        , fSampleColorFilter(std::move(sampleColorFilter))
+        , fSampleBlender(std::move(sampleBlender)) {
     fConditionMask = fLoopMask = fBuilder->splat(0xffff'ffff);
 
     // Now, add storage for each global variable (including uniforms) to fSlots, and entries in
@@ -297,7 +301,7 @@
             SkASSERT(fVariableMap.find(&var) == fVariableMap.end());
 
             // For most variables, fVariableMap stores an index into fSlots, but for children,
-            // fVariableMap stores the index to pass to fSample(Shader|ColorFilter)
+            // fVariableMap stores the index to pass to fSample(Shader|ColorFilter|Blender)
             if (var.type().isEffectChild()) {
                 fVariableMap[&var] = fpCount++;
                 continue;
@@ -1548,7 +1552,8 @@
                           skvm::Color inputColor,
                           skvm::Color destColor,
                           SampleShaderFn sampleShader,
-                          SampleColorFilterFn sampleColorFilter) {
+                          SampleColorFilterFn sampleColorFilter,
+                          SampleBlenderFn sampleBlender) {
     skvm::Val zero = builder->splat(0.0f).id;
     skvm::Val result[4] = {zero,zero,zero,zero};
 
@@ -1586,7 +1591,7 @@
     SkASSERT(argSlots <= SK_ARRAY_COUNT(args));
 
     SkVMGenerator generator(program, builder, uniforms, device, local, std::move(sampleShader),
-                            std::move(sampleColorFilter));
+                            std::move(sampleColorFilter), std::move(sampleBlender));
     generator.writeFunction(function, {args, argSlots}, SkMakeSpan(result));
 
     return skvm::Color{{builder, result[0]},
@@ -1627,7 +1632,8 @@
     skvm::F32 zero = b->splat(0.0f);
     skvm::Coord zeroCoord = {zero, zero};
     SkVMGenerator generator(program, b, uniforms, /*device=*/zeroCoord, /*local=*/zeroCoord,
-                            /*sampleShader=*/nullptr, /*sampleColorFilter=*/nullptr);
+                            /*sampleShader=*/nullptr, /*sampleColorFilter=*/nullptr,
+                            /*sampleBlender=*/nullptr);
     generator.writeFunction(function, SkMakeSpan(argVals), SkMakeSpan(returnVals));
 
     // generateCode has updated the contents of 'argVals' for any 'out' or 'inout' parameters.
@@ -1761,7 +1767,8 @@
 
     skvm::Color result = SkSL::ProgramToSkVM(program, *main, builder, SkMakeSpan(uniformVals),
                                              device, local, inColor, destColor, sampleShader,
-                                             /*sampleColorFilter=*/nullptr);
+                                             /*sampleColorFilter=*/nullptr,
+                                             /*sampleBlender=*/nullptr);
 
     storeF(builder->varying<float>(), result.r);
     storeF(builder->varying<float>(), result.g);
diff --git a/src/sksl/codegen/SkSLVMCodeGenerator.h b/src/sksl/codegen/SkSLVMCodeGenerator.h
index 01ad9f7..743a580 100644
--- a/src/sksl/codegen/SkSLVMCodeGenerator.h
+++ b/src/sksl/codegen/SkSLVMCodeGenerator.h
@@ -22,6 +22,7 @@
 
 using SampleShaderFn = std::function<skvm::Color(int, skvm::Coord)>;
 using SampleColorFilterFn = std::function<skvm::Color(int, skvm::Color)>;
+using SampleBlenderFn = std::function<skvm::Color(int, skvm::Color, skvm::Color)>;
 
 // Convert 'function' to skvm instructions in 'builder', for use by blends, shaders, & color filters
 skvm::Color ProgramToSkVM(const Program& program,
@@ -33,7 +34,8 @@
                           skvm::Color inputColor,
                           skvm::Color destColor,
                           SampleShaderFn sampleShader,
-                          SampleColorFilterFn sampleColorFilter);
+                          SampleColorFilterFn sampleColorFilter,
+                          SampleBlenderFn sampleBlender);
 
 struct SkVMSignature {
     size_t fParameterSlots = 0;