Child fragment processors are now written as separate functions
instead of inline

Bug: skia:
Change-Id: I3c6c876fea9cfcc311fc09c0fdf0375b776004aa
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/210632
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
diff --git a/src/gpu/GrColorSpaceXform.cpp b/src/gpu/GrColorSpaceXform.cpp
index 39118a6..187e582 100644
--- a/src/gpu/GrColorSpaceXform.cpp
+++ b/src/gpu/GrColorSpaceXform.cpp
@@ -65,11 +65,12 @@
         fColorSpaceHelper.emitCode(uniformHandler, csxe.colorXform());
 
         if (this->numChildProcessors()) {
-            SkString childColor("src_color");
-            this->emitChild(0, &childColor, args);
+            const char* childColor = "src_color";
+            fragBuilder->codeAppendf("half4 %s;\n", childColor);
+            this->invokeChild(0, childColor, args);
 
             SkString xformedColor;
-            fragBuilder->appendColorGamutXform(&xformedColor, childColor.c_str(), &fColorSpaceHelper);
+            fragBuilder->appendColorGamutXform(&xformedColor, childColor, &fColorSpaceHelper);
             fragBuilder->codeAppendf("%s = %s * %s;", args.fOutputColor, xformedColor.c_str(),
                                      args.fInputColor);
         } else {
diff --git a/src/gpu/GrFragmentProcessor.cpp b/src/gpu/GrFragmentProcessor.cpp
index 7205f08..1cc5e71 100644
--- a/src/gpu/GrFragmentProcessor.cpp
+++ b/src/gpu/GrFragmentProcessor.cpp
@@ -241,7 +241,7 @@
             public:
                 void emitCode(EmitArgs& args) override {
                     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
-                    this->emitChild(0, args);
+                    this->invokeChild(0, args);
                     fragBuilder->codeAppendf("%s.rgb *= %s.rgb;", args.fOutputColor,
                                                                 args.fInputColor);
                     fragBuilder->codeAppendf("%s *= %s.a;", args.fOutputColor, args.fInputColor);
@@ -318,15 +318,19 @@
                 void emitCode(EmitArgs& args) override {
                     // First guy's input might be nil.
                     SkString temp("out0");
-                    this->emitChild(0, args.fInputColor, &temp, args);
+                    GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+                    fragBuilder->codeAppendf("half4 %s;\n", temp.c_str());
+                    this->invokeChild(0, args.fInputColor, temp.c_str(), args);
                     SkString input = temp;
                     for (int i = 1; i < this->numChildProcessors() - 1; ++i) {
                         temp.printf("out%d", i);
-                        this->emitChild(i, input.c_str(), &temp, args);
+                        fragBuilder->codeAppendf("half4 %s;\n", temp.c_str());
+                        this->invokeChild(i, input.c_str(), temp.c_str(), args);
                         input = temp;
                     }
                     // Last guy writes to our output variable.
-                    this->emitChild(this->numChildProcessors() - 1, input.c_str(), args);
+                    this->invokeChild(this->numChildProcessors() - 1, input.c_str(),
+                                      args.fOutputColor, args);
                 }
             };
             return new GLFP;
diff --git a/src/gpu/effects/GrSkSLFP.cpp b/src/gpu/effects/GrSkSLFP.cpp
index f8fe85d..cece9c1 100644
--- a/src/gpu/effects/GrSkSLFP.cpp
+++ b/src/gpu/effects/GrSkSLFP.cpp
@@ -159,12 +159,14 @@
                                                                    SkSL::String(v->fName).c_str()));
             }
         }
+        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
         std::vector<SkString> childNames;
         for (int i = 0; i < this->numChildProcessors(); ++i) {
-            childNames.push_back(SkStringPrintf("_child%d", i));
-            this->emitChild(i, &childNames[i], args);
+            SkString name = SkStringPrintf("_child%d", i);
+            fragBuilder->codeAppendf("half4 %s;\n", name.c_str());
+            childNames.push_back(std::move(name));
+            this->invokeChild(i, childNames[i].c_str(), args);
         }
-        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
         int substringStartIndex = 0;
         int formatArgIndex = 0;
         for (size_t i = 0; i < fGLSL.length(); ++i) {
diff --git a/src/gpu/effects/GrXfermodeFragmentProcessor.cpp b/src/gpu/effects/GrXfermodeFragmentProcessor.cpp
index 1424939..e4f4c0b 100644
--- a/src/gpu/effects/GrXfermodeFragmentProcessor.cpp
+++ b/src/gpu/effects/GrXfermodeFragmentProcessor.cpp
@@ -220,20 +220,18 @@
     }
 
     // declare outputColor and emit the code for each of the two children
-    SkString srcColor("xfer_src");
-    this->emitChild(0, inputColor, &srcColor, args);
+    const char* srcColor = "xfer_src";
+    fragBuilder->codeAppendf("half4 %s;\n", srcColor);
+    this->invokeChild(0, inputColor, srcColor, args);
 
-    SkString dstColor("xfer_dst");
-    this->emitChild(1, inputColor, &dstColor, args);
+    const char* dstColor = "xfer_dst";
+    fragBuilder->codeAppendf("half4 %s;\n", dstColor);
+    this->invokeChild(1, inputColor, dstColor, args);
 
     // emit blend code
     SkBlendMode mode = cs.getMode();
     fragBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkBlendMode_Name(mode));
-    GrGLSLBlend::AppendMode(fragBuilder,
-                            srcColor.c_str(),
-                            dstColor.c_str(),
-                            args.fOutputColor,
-                            mode);
+    GrGLSLBlend::AppendMode(fragBuilder, srcColor, dstColor, args.fOutputColor, mode);
 
     // re-multiply the output color by the input color's alpha
     if (args.fInputColor) {
@@ -438,16 +436,18 @@
         SkBlendMode mode = args.fFp.cast<ComposeOneFragmentProcessor>().mode();
         ComposeOneFragmentProcessor::Child child =
             args.fFp.cast<ComposeOneFragmentProcessor>().child();
-        SkString childColor("child");
-        this->emitChild(0, &childColor, args);
+        const char* childColor = "child";
+        fragBuilder->codeAppendf("half4 %s;\n", childColor);
+        this->invokeChild(0, childColor, args);
 
         // emit blend code
         fragBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkBlendMode_Name(mode));
-        const char* childStr = childColor.c_str();
         if (ComposeOneFragmentProcessor::kDst_Child == child) {
-            GrGLSLBlend::AppendMode(fragBuilder, args.fInputColor, childStr, args.fOutputColor, mode);
+            GrGLSLBlend::AppendMode(fragBuilder, args.fInputColor, childColor, args.fOutputColor,
+                                    mode);
         } else {
-            GrGLSLBlend::AppendMode(fragBuilder, childStr, args.fInputColor, args.fOutputColor, mode);
+            GrGLSLBlend::AppendMode(fragBuilder, childColor, args.fInputColor, args.fOutputColor,
+                                    mode);
         }
     }
 
diff --git a/src/gpu/effects/generated/GrComposeLerpEffect.cpp b/src/gpu/effects/generated/GrComposeLerpEffect.cpp
index c9b4d3b..72a46d2 100644
--- a/src/gpu/effects/generated/GrComposeLerpEffect.cpp
+++ b/src/gpu/effects/generated/GrComposeLerpEffect.cpp
@@ -27,23 +27,19 @@
         (void)weight;
         weightVar =
                 args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType, "weight");
-        SkString _child0("_child0");
+        fragBuilder->codeAppendf("half4 _process284;");
         if (_outer.child1_index >= 0) {
-            this->emitChild(_outer.child1_index, &_child0, args);
-        } else {
-            fragBuilder->codeAppendf("half4 %s;", _child0.c_str());
+            this->invokeChild(_outer.child1_index, "_process284", args);
         }
-        SkString _child1("_child1");
+        fragBuilder->codeAppendf("half4 _process353;");
         if (_outer.child2_index >= 0) {
-            this->emitChild(_outer.child2_index, &_child1, args);
-        } else {
-            fragBuilder->codeAppendf("half4 %s;", _child1.c_str());
+            this->invokeChild(_outer.child2_index, "_process353", args);
         }
-        fragBuilder->codeAppendf("%s = mix(%s ? %s : %s, %s ? %s : %s, half(%s));\n",
-                                 args.fOutputColor, _outer.child1_index >= 0 ? "true" : "false",
-                                 _child0.c_str(), args.fInputColor,
-                                 _outer.child2_index >= 0 ? "true" : "false", _child1.c_str(),
-                                 args.fInputColor, args.fUniformHandler->getUniformCStr(weightVar));
+        fragBuilder->codeAppendf(
+                "%s = mix(%s ? _process284 : %s, %s ? _process353 : %s, half(%s));\n",
+                args.fOutputColor, _outer.child1_index >= 0 ? "true" : "false", args.fInputColor,
+                _outer.child2_index >= 0 ? "true" : "false", args.fInputColor,
+                args.fUniformHandler->getUniformCStr(weightVar));
     }
 
 private:
diff --git a/src/gpu/effects/generated/GrComposeLerpRedEffect.cpp b/src/gpu/effects/generated/GrComposeLerpRedEffect.cpp
index d75b411..a2f051b 100644
--- a/src/gpu/effects/generated/GrComposeLerpRedEffect.cpp
+++ b/src/gpu/effects/generated/GrComposeLerpRedEffect.cpp
@@ -23,24 +23,20 @@
         GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
         const GrComposeLerpRedEffect& _outer = args.fFp.cast<GrComposeLerpRedEffect>();
         (void)_outer;
-        SkString _child0("_child0");
+        fragBuilder->codeAppendf("half4 _process286;");
         if (_outer.child1_index >= 0) {
-            this->emitChild(_outer.child1_index, &_child0, args);
-        } else {
-            fragBuilder->codeAppendf("half4 %s;", _child0.c_str());
+            this->invokeChild(_outer.child1_index, "_process286", args);
         }
-        SkString _child1("_child1");
+        fragBuilder->codeAppendf("half4 _process355;");
         if (_outer.child2_index >= 0) {
-            this->emitChild(_outer.child2_index, &_child1, args);
-        } else {
-            fragBuilder->codeAppendf("half4 %s;", _child1.c_str());
+            this->invokeChild(_outer.child2_index, "_process355", args);
         }
-        SkString _child2("_child2");
-        this->emitChild(_outer.lerp_index, &_child2, args);
-        fragBuilder->codeAppendf("%s = mix(%s ? %s : %s, %s ? %s : %s, %s.x);\n", args.fOutputColor,
-                                 _outer.child1_index >= 0 ? "true" : "false", _child0.c_str(),
-                                 args.fInputColor, _outer.child2_index >= 0 ? "true" : "false",
-                                 _child1.c_str(), args.fInputColor, _child2.c_str());
+        fragBuilder->codeAppendf("half4 _process407;");
+        this->invokeChild(_outer.lerp_index, "_process407", args);
+        fragBuilder->codeAppendf(
+                "%s = mix(%s ? _process286 : %s, %s ? _process355 : %s, _process407.x);\n",
+                args.fOutputColor, _outer.child1_index >= 0 ? "true" : "false", args.fInputColor,
+                _outer.child2_index >= 0 ? "true" : "false", args.fInputColor);
     }
 
 private:
diff --git a/src/gpu/effects/generated/GrMixerEffect.cpp b/src/gpu/effects/generated/GrMixerEffect.cpp
index af5a7af..4ffa89c 100644
--- a/src/gpu/effects/generated/GrMixerEffect.cpp
+++ b/src/gpu/effects/generated/GrMixerEffect.cpp
@@ -28,19 +28,17 @@
         weightVar =
                 args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType, "weight");
         SkString _input0 = SkStringPrintf("%s", args.fInputColor);
-        SkString _child0("_child0");
-        this->emitChild(_outer.fp0_index, _input0.c_str(), &_child0, args);
-        fragBuilder->codeAppendf("half4 in0 = %s;", _child0.c_str());
+        fragBuilder->codeAppendf("half4 _process1272;");
+        this->invokeChild(_outer.fp0_index, _input0.c_str(), "_process1272", args);
+        fragBuilder->codeAppendf("half4 in0 = _process1272;");
         SkString _input1 = SkStringPrintf("%s", args.fInputColor);
-        SkString _child1("_child1");
+        fragBuilder->codeAppendf("half4 _process1330;");
         if (_outer.fp1_index >= 0) {
-            this->emitChild(_outer.fp1_index, _input1.c_str(), &_child1, args);
-        } else {
-            fragBuilder->codeAppendf("half4 %s;", _child1.c_str());
+            this->invokeChild(_outer.fp1_index, _input1.c_str(), "_process1330", args);
         }
-        fragBuilder->codeAppendf("\nhalf4 in1 = %s ? %s : %s;\n%s = mix(in0, in1, %s);\n",
-                                 _outer.fp1_index >= 0 ? "true" : "false", _child1.c_str(),
-                                 args.fInputColor, args.fOutputColor,
+        fragBuilder->codeAppendf("\nhalf4 in1 = %s ? _process1330 : %s;\n%s = mix(in0, in1, %s);\n",
+                                 _outer.fp1_index >= 0 ? "true" : "false", args.fInputColor,
+                                 args.fOutputColor,
                                  args.fUniformHandler->getUniformCStr(weightVar));
     }
 
diff --git a/src/gpu/effects/generated/GrOverrideInputFragmentProcessor.cpp b/src/gpu/effects/generated/GrOverrideInputFragmentProcessor.cpp
index 9d7934e..b2f8339 100644
--- a/src/gpu/effects/generated/GrOverrideInputFragmentProcessor.cpp
+++ b/src/gpu/effects/generated/GrOverrideInputFragmentProcessor.cpp
@@ -43,9 +43,9 @@
                 _outer.literalColor.fR, _outer.literalColor.fG, _outer.literalColor.fB,
                 _outer.literalColor.fA);
         SkString _input0("constColor");
-        SkString _child0("_child0");
-        this->emitChild(_outer.fp_index, _input0.c_str(), &_child0, args);
-        fragBuilder->codeAppendf("\n%s = %s;\n", args.fOutputColor, _child0.c_str());
+        fragBuilder->codeAppendf("half4 _process1986;");
+        this->invokeChild(_outer.fp_index, _input0.c_str(), "_process1986", args);
+        fragBuilder->codeAppendf("\n%s = _process1986;\n", args.fOutputColor);
     }
 
 private:
diff --git a/src/gpu/glsl/GrGLSLFragmentProcessor.cpp b/src/gpu/glsl/GrGLSLFragmentProcessor.cpp
index 4101860..d0ae1d6 100644
--- a/src/gpu/glsl/GrGLSLFragmentProcessor.cpp
+++ b/src/gpu/glsl/GrGLSLFragmentProcessor.cpp
@@ -16,42 +16,27 @@
     this->onSetData(pdman, processor);
 }
 
-void GrGLSLFragmentProcessor::emitChild(int childIndex, const char* inputColor, EmitArgs& args) {
-    this->internalEmitChild(childIndex, inputColor, args.fOutputColor, args);
-}
-
-void GrGLSLFragmentProcessor::emitChild(int childIndex, const char* inputColor,
-                                        SkString* outputColor, EmitArgs& args) {
+void GrGLSLFragmentProcessor::invokeChild(int childIndex, const char* inputColor,
+                                          const char* outputColor, EmitArgs& args) {
     SkASSERT(outputColor);
     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
-    outputColor->append(fragBuilder->getMangleString());
-    fragBuilder->codeAppendf("half4 %s;", outputColor->c_str());
-    this->internalEmitChild(childIndex, inputColor, outputColor->c_str(), args);
+    while (childIndex >= (int) fFunctionNames.size()) {
+        fFunctionNames.emplace_back();
+    }
+    if (fFunctionNames[childIndex].size() == 0) {
+        this->internalEmitChild(childIndex, outputColor, args);
+    }
+    fragBuilder->codeAppendf("%s = %s(%s);", outputColor, fFunctionNames[childIndex].c_str(),
+                             inputColor ? inputColor : "half4(1)");
 }
 
-void GrGLSLFragmentProcessor::internalEmitChild(int childIndex, const char* inputColor,
-                                                const char* outputColor, EmitArgs& args) {
+void GrGLSLFragmentProcessor::internalEmitChild(int childIndex, const char* outputColor,
+                                                EmitArgs& args) {
     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
 
-    fragBuilder->onBeforeChildProcEmitCode();  // call first so mangleString is updated
-
-    // Prepare a mangled input color variable if the default is not used,
-    // inputName remains the empty string if no variable is needed.
-    SkString inputName;
-    if (inputColor&& strcmp("half4(1.0)", inputColor) != 0 && strcmp("half4(1)", inputColor) != 0) {
-        // The input name is based off of the current mangle string, and
-        // since this is called after onBeforeChildProcEmitCode(), it will be
-        // unique to the child processor (exactly what we want for its input).
-        inputName.appendf("_childInput%s", fragBuilder->getMangleString().c_str());
-        fragBuilder->codeAppendf("half4 %s = %s;", inputName.c_str(), inputColor);
-    }
-
     const GrFragmentProcessor& childProc = args.fFp.childProcessor(childIndex);
 
-    // emit the code for the child in its own scope
-    fragBuilder->codeAppend("{\n");
-    fragBuilder->codeAppendf("// Child Index %d (mangle: %s): %s\n", childIndex,
-                             fragBuilder->getMangleString().c_str(), childProc.name());
+    // emit the code for the child in its own function
     TransformedCoordVars coordVars = args.fTransformedCoords.childInputs(childIndex);
     TextureSamplers textureSamplers = args.fTexSamplers.childInputs(childIndex);
 
@@ -60,14 +45,13 @@
                        args.fUniformHandler,
                        args.fShaderCaps,
                        childProc,
-                       outputColor,
-                       inputName.size() > 0 ? inputName.c_str() : nullptr,
+                       "_result",
+                       "_input",
                        coordVars,
                        textureSamplers);
-    this->childProcessor(childIndex)->emitCode(childArgs);
-    fragBuilder->codeAppend("}\n");
-
-    fragBuilder->onAfterChildProcEmitCode();
+    fFunctionNames[childIndex] = fragBuilder->writeProcessorFunction(
+                                                                   this->childProcessor(childIndex),
+                                                                   childArgs);
 }
 
 //////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/glsl/GrGLSLFragmentProcessor.h b/src/gpu/glsl/GrGLSLFragmentProcessor.h
index 4a8ce70..3a1e645 100644
--- a/src/gpu/glsl/GrGLSLFragmentProcessor.h
+++ b/src/gpu/glsl/GrGLSLFragmentProcessor.h
@@ -136,32 +136,29 @@
         return fChildProcessors[index];
     }
 
-    // Emit the child with the default input color (solid white)
-    inline void emitChild(int childIndex, SkString* outputColor, EmitArgs& parentArgs) {
-        this->emitChild(childIndex, nullptr, outputColor, parentArgs);
+    // Invoke the child with the default input color (solid white)
+    inline void invokeChild(int childIndex, const char* outputColor, EmitArgs& parentArgs) {
+        this->invokeChild(childIndex, nullptr, outputColor, parentArgs);
     }
 
     /** Will emit the code of a child proc in its own scope. Pass in the parent's EmitArgs and
-     *  emitChild will automatically extract the coords and samplers of that child and pass them
+     *  invokeChild will automatically extract the coords and samplers of that child and pass them
      *  on to the child's emitCode(). Also, any uniforms or functions emitted by the child will
-     *  have their names mangled to prevent redefinitions. The output color name is also mangled
-     *  therefore in an in/out param. It will be declared in mangled form by emitChild(). It is
-     *  legal to pass nullptr as inputColor, since all fragment processors are required to work
-     *  without an input color.
+     *  have their names mangled to prevent redefinitions. The outputColor is the name of a
+     *  variable in which to store the resulting color. It is assumed to have already been declared
+     *  and is not declared by invokeChild. It is legal to pass nullptr as inputColor, since all
+     *  fragment processors are required to work without an input color.
      */
-    void emitChild(int childIndex, const char* inputColor, SkString* outputColor,
-                   EmitArgs& parentArgs);
+    void invokeChild(int childIndex, const char* inputColor, const char* outputColor,
+                     EmitArgs& parentArgs);
 
     // Use the parent's output color to hold child's output, and use the
     // default input color of solid white
-    inline void emitChild(int childIndex, EmitArgs& args) {
+    inline void invokeChild(int childIndex, EmitArgs& args) {
         // null pointer cast required to disambiguate the function call
-        this->emitChild(childIndex, (const char*) nullptr, args);
+        this->invokeChild(childIndex, args.fOutputColor, args);
     }
 
-    /** Variation that uses the parent's output color variable to hold the child's output.*/
-    void emitChild(int childIndex, const char* inputColor, EmitArgs& parentArgs);
-
     /**
      * Pre-order traversal of a GLSLFP hierarchy, or of multiple trees with roots in an array of
      * GLSLFPS. This agrees with the traversal order of GrFragmentProcessor::Iter
@@ -189,7 +186,10 @@
     virtual void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) {}
 
 private:
-    void internalEmitChild(int, const char*, const char*, EmitArgs&);
+    void internalEmitChild(int, const char*, EmitArgs&);
+
+    // one per child; either not present or empty string if not yet emitted
+    SkTArray<SkString> fFunctionNames;
 
     SkTArray<GrGLSLFragmentProcessor*, true> fChildProcessors;
 
diff --git a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
index f41f0f1..53aa098 100644
--- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
@@ -156,6 +156,26 @@
     this->codeAppendf("}");
 }
 
+SkString GrGLSLFPFragmentBuilder::writeProcessorFunction(GrGLSLFragmentProcessor* fp,
+                                                         GrGLSLFragmentProcessor::EmitArgs& args) {
+    this->onBeforeChildProcEmitCode();
+    this->nextStage();
+    this->codeAppendf("half4 %s;\n", args.fOutputColor);
+    fp->emitCode(args);
+    this->codeAppendf("return %s;", args.fOutputColor);
+    GrShaderVar inColor(args.fInputColor, kHalf4_GrSLType);
+    SkString result;
+    this->emitFunction(kHalf4_GrSLType,
+                       "stage",
+                       1,
+                       &inColor,
+                       this->code().c_str(),
+                       &result);
+    this->deleteStage();
+    this->onAfterChildProcEmitCode();
+    return result;
+}
+
 const char* GrGLSLFragmentShaderBuilder::dstColor() {
     SkDEBUGCODE(fHasReadDstColorThisStage_DebugOnly = true;)
 
diff --git a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
index 050029c..7e48b7c 100644
--- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
+++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
@@ -11,6 +11,7 @@
 #include "include/gpu/GrBlend.h"
 #include "src/gpu/GrProcessor.h"
 #include "src/gpu/glsl/GrGLSLShaderBuilder.h"
+#include "GrGLSLFragmentProcessor.h"
 
 class GrRenderTarget;
 class GrGLSLVarying;
@@ -97,6 +98,9 @@
     virtual void onBeforeChildProcEmitCode() = 0;
     virtual void onAfterChildProcEmitCode() = 0;
 
+    virtual SkString writeProcessorFunction(GrGLSLFragmentProcessor* fp,
+                                            GrGLSLFragmentProcessor::EmitArgs& args);
+
     virtual const SkString& getMangleString() const = 0;
 
     virtual void forceHighPrecision() = 0;
diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.cpp b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
index d1b5bac..7e6f2a5 100644
--- a/src/gpu/glsl/GrGLSLProgramBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
@@ -206,8 +206,8 @@
                                            input.c_str(),
                                            coords,
                                            textureSamplers);
-
-    fragProc->emitCode(args);
+    SkString funcName = fFS.writeProcessorFunction(fragProc, args);
+    fFS.codeAppendf("%s = %s(%s);", output.c_str(), funcName.c_str(), input.c_str());
 
     // We have to check that effects and the code they emit are consistent, ie if an effect
     // asks for dst color, then the emit code needs to follow suit
diff --git a/src/gpu/glsl/GrGLSLShaderBuilder.h b/src/gpu/glsl/GrGLSLShaderBuilder.h
index a203d3a..2e1c0ca 100644
--- a/src/gpu/glsl/GrGLSLShaderBuilder.h
+++ b/src/gpu/glsl/GrGLSLShaderBuilder.h
@@ -152,6 +152,18 @@
         GrGLSLShaderBuilder* fBuilder;
     };
 
+    void nextStage() {
+        fShaderStrings.push_back();
+        fCodeIndex++;
+    }
+
+    void deleteStage() {
+        fShaderStrings.pop_back();
+        fCodeIndex--;
+    }
+
+    SkString& code() { return fShaderStrings[fCodeIndex]; }
+
 protected:
     typedef GrTAllocator<GrShaderVar> VarArray;
     void appendDecls(const VarArray& vars, SkString* out) const;
@@ -193,11 +205,6 @@
 
     void compileAndAppendLayoutQualifiers();
 
-    void nextStage() {
-        fShaderStrings.push_back();
-        fCodeIndex++;
-    }
-
     SkString& versionDecl() { return fShaderStrings[kVersionDecl]; }
     SkString& extensions() { return fShaderStrings[kExtensions]; }
     SkString& definitions() { return fShaderStrings[kDefinitions]; }
@@ -208,7 +215,6 @@
     SkString& outputs() { return fShaderStrings[kOutputs]; }
     SkString& functions() { return fShaderStrings[kFunctions]; }
     SkString& main() { return fShaderStrings[kMain]; }
-    SkString& code() { return fShaderStrings[fCodeIndex]; }
 
     virtual void onFinalize() = 0;
 
@@ -231,9 +237,6 @@
     GrGLSLProgramBuilder* fProgramBuilder;
     SkSL::String fCompilerString;
     SkSTArray<kPrealloc, SkString> fShaderStrings;
-    SkString fCode;
-    SkString fFunctions;
-    SkString fExtensions;
 
     VarArray fInputs;
     VarArray fOutputs;
diff --git a/src/gpu/gradients/generated/GrClampedGradientEffect.cpp b/src/gpu/gradients/generated/GrClampedGradientEffect.cpp
index 7bb2452..d88c4b9 100644
--- a/src/gpu/gradients/generated/GrClampedGradientEffect.cpp
+++ b/src/gpu/gradients/generated/GrClampedGradientEffect.cpp
@@ -35,24 +35,23 @@
                                                               kHalf4_GrSLType, "leftBorderColor");
         rightBorderColorVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag,
                                                                kHalf4_GrSLType, "rightBorderColor");
-        SkString _child1("_child1");
-        this->emitChild(_outer.gradLayout_index, &_child1, args);
+        fragBuilder->codeAppendf("half4 _process1093;");
+        this->invokeChild(_outer.gradLayout_index, "_process1093", args);
         fragBuilder->codeAppendf(
-                "half4 t = %s;\nif (!%s && t.y < 0.0) {\n    %s = half4(0.0);\n} else if (t.x < "
-                "0.0) {\n    %s = %s;\n} else if (t.x > 1.0) {\n    %s = %s;\n} else {",
-                _child1.c_str(),
+                "half4 t = _process1093;\nif (!%s && t.y < 0.0) {\n    %s = half4(0.0);\n} else if "
+                "(t.x < 0.0) {\n    %s = %s;\n} else if (t.x > 1.0) {\n    %s = %s;\n} else {",
                 (_outer.childProcessor(_outer.gradLayout_index).preservesOpaqueInput() ? "true"
                                                                                        : "false"),
                 args.fOutputColor, args.fOutputColor,
                 args.fUniformHandler->getUniformCStr(leftBorderColorVar), args.fOutputColor,
                 args.fUniformHandler->getUniformCStr(rightBorderColorVar));
         SkString _input0("t");
-        SkString _child0("_child0");
-        this->emitChild(_outer.colorizer_index, _input0.c_str(), &_child0, args);
-        fragBuilder->codeAppendf("\n    %s = %s;\n}\n@if (%s) {\n    %s.xyz *= %s.w;\n}\n",
-                                 args.fOutputColor, _child0.c_str(),
-                                 (_outer.makePremul ? "true" : "false"), args.fOutputColor,
-                                 args.fOutputColor);
+        fragBuilder->codeAppendf("half4 _process1762;");
+        this->invokeChild(_outer.colorizer_index, _input0.c_str(), "_process1762", args);
+        fragBuilder->codeAppendf(
+                "\n    %s = _process1762;\n}\n@if (%s) {\n    %s.xyz *= %s.w;\n}\n",
+                args.fOutputColor, (_outer.makePremul ? "true" : "false"), args.fOutputColor,
+                args.fOutputColor);
     }
 
 private:
diff --git a/src/gpu/gradients/generated/GrTiledGradientEffect.cpp b/src/gpu/gradients/generated/GrTiledGradientEffect.cpp
index cf5d583..28a0832 100644
--- a/src/gpu/gradients/generated/GrTiledGradientEffect.cpp
+++ b/src/gpu/gradients/generated/GrTiledGradientEffect.cpp
@@ -29,25 +29,24 @@
         (void)makePremul;
         auto colorsAreOpaque = _outer.colorsAreOpaque;
         (void)colorsAreOpaque;
-        SkString _child1("_child1");
-        this->emitChild(_outer.gradLayout_index, &_child1, args);
+        fragBuilder->codeAppendf("half4 _process447;");
+        this->invokeChild(_outer.gradLayout_index, "_process447", args);
         fragBuilder->codeAppendf(
-                "half4 t = %s;\nif (!%s && t.y < 0.0) {\n    %s = half4(0.0);\n} else {\n    @if "
-                "(%s) {\n        half t_1 = t.x - 1.0;\n        half tiled_t = (t_1 - 2.0 * "
+                "half4 t = _process447;\nif (!%s && t.y < 0.0) {\n    %s = half4(0.0);\n} else {\n "
+                "   @if (%s) {\n        half t_1 = t.x - 1.0;\n        half tiled_t = (t_1 - 2.0 * "
                 "floor(t_1 * 0.5)) - 1.0;\n        if (sk_Caps.mustDoOpBetweenFloorAndAbs) {\n     "
                 "       tiled_t = clamp(tiled_t, -1.0, 1.0);\n        }\n        t.x = "
                 "abs(tiled_t);\n    } else {\n        t.x = fract(t.x);\n    }",
-                _child1.c_str(),
                 (_outer.childProcessor(_outer.gradLayout_index).preservesOpaqueInput() ? "true"
                                                                                        : "false"),
                 args.fOutputColor, (_outer.mirror ? "true" : "false"));
         SkString _input0("t");
-        SkString _child0("_child0");
-        this->emitChild(_outer.colorizer_index, _input0.c_str(), &_child0, args);
-        fragBuilder->codeAppendf("\n    %s = %s;\n}\n@if (%s) {\n    %s.xyz *= %s.w;\n}\n",
-                                 args.fOutputColor, _child0.c_str(),
-                                 (_outer.makePremul ? "true" : "false"), args.fOutputColor,
-                                 args.fOutputColor);
+        fragBuilder->codeAppendf("half4 _process1459;");
+        this->invokeChild(_outer.colorizer_index, _input0.c_str(), "_process1459", args);
+        fragBuilder->codeAppendf(
+                "\n    %s = _process1459;\n}\n@if (%s) {\n    %s.xyz *= %s.w;\n}\n",
+                args.fOutputColor, (_outer.makePremul ? "true" : "false"), args.fOutputColor,
+                args.fOutputColor);
     }
 
 private: