Move loops that chain together effects into GrGLShaderBuilder from GrGLProgram.

R=robertphillips@google.com

Review URL: https://codereview.chromium.org/14925010

git-svn-id: http://skia.googlecode.com/svn/trunk@9073 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/gl/GrGLEffectMatrix.cpp b/src/gpu/gl/GrGLEffectMatrix.cpp
index 7e7a9c9..523b37e 100644
--- a/src/gpu/gl/GrGLEffectMatrix.cpp
+++ b/src/gpu/gl/GrGLEffectMatrix.cpp
@@ -87,7 +87,7 @@
                                    &uniName);
     }
 
-    const char* varyingName = "StageCoord";
+    const char* varyingName = "MatrixCoord";
     SkString suffixedVaryingName;
     if (NULL != suffix) {
         suffixedVaryingName.append(varyingName);
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 1b4baa4..1b9c3a2 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -485,35 +485,21 @@
     bool needColor, needFilterColor;
     need_blend_inputs(filterColorCoeff, colorCoeff, &needFilterColor, &needColor);
 
-    if (needColor) {
-        ///////////////////////////////////////////////////////////////////////////
-        // compute the color
-        // if we have color stages string them together, feeding the output color
-        // of each to the next and generating code for each stage.
-        SkString outColor;
-        for (int s = 0; s < fDesc.fFirstCoverageStage; ++s) {
-            if (GrGLEffect::kNoEffectKey != fDesc.fEffectKeys[s]) {
-                if (kZeros_GrSLConstantVec == knownColorValue) {
-                    // Effects have no way to communicate zeros, they treat an empty string as ones.
-                    inColor = "initialColor";
-                    builder.fsCodeAppendf("\tvec4 %s = %s;\n", inColor.c_str(), GrGLSLZerosVecf(4));
-                }
-                // create var to hold stage result
-                outColor = "color";
-                outColor.appendS32(s);
-                builder.fsCodeAppendf("\tvec4 %s;\n", outColor.c_str());
+    // used in order for builder to return the per-stage uniform handles.
+    SkTArray<GrGLUniformManager::UniformHandle, true>* stageUniformArrays[GrDrawState::kNumStages];
 
-                builder.setCurrentStage(s);
-                fEffects[s] = builder.createAndEmitGLEffect(*stages[s],
-                                                            fDesc.fEffectKeys[s],
-                                                            inColor.size() ? inColor.c_str() : NULL,
-                                                            outColor.c_str(),
-                                                            &fUniformHandles.fEffectSamplerUnis[s]);
-                builder.setNonStage();
-                inColor = outColor;
-                knownColorValue = kNone_GrSLConstantVec;
-            }
+    if (needColor) {
+        for (int s = 0; s < fDesc.fFirstCoverageStage; ++s) {
+            stageUniformArrays[s] = &fUniformHandles.fEffectSamplerUnis[s];
         }
+
+        builder.emitEffects(stages,
+                            fDesc.fEffectKeys,
+                            fDesc.fFirstCoverageStage,
+                            &inColor,
+                            &knownColorValue,
+                            stageUniformArrays,
+                            fEffects);
     }
 
     // Insert the color filter. This will soon be replaced by a color effect.
@@ -540,37 +526,21 @@
 
     ///////////////////////////////////////////////////////////////////////////
     // compute the partial coverage
-
-    // incoming coverage to current stage being processed.
     SkString inCoverage;
     GrSLConstantVec knownCoverageValue = this->genInputCoverage(&builder, &inCoverage);
 
-    SkString outCoverage;
-    for (int s = fDesc.fFirstCoverageStage; s < GrDrawState::kNumStages; ++s) {
-        if (fDesc.fEffectKeys[s]) {
-            if (kZeros_GrSLConstantVec == knownCoverageValue) {
-                // Effects have no way to communicate zeros, they treat an empty string as ones.
-                inCoverage = "initialCoverage";
-                builder.fsCodeAppendf("\tvec4 %s = %s;\n", inCoverage.c_str(), GrGLSLZerosVecf(4));
-            }
-            // create var to hold stage output
-            outCoverage = "coverage";
-            outCoverage.appendS32(s);
-            builder.fsCodeAppendf("\tvec4 %s;\n", outCoverage.c_str());
-
-            builder.setCurrentStage(s);
-            fEffects[s] = builder.createAndEmitGLEffect(
-                                            *stages[s],
-                                            fDesc.fEffectKeys[s],
-                                            inCoverage.size() ? inCoverage.c_str() : NULL,
-                                            outCoverage.c_str(),
-                                            &fUniformHandles.fEffectSamplerUnis[s]);
-            builder.setNonStage();
-            inCoverage = outCoverage;
-            knownCoverageValue = kNone_GrSLConstantVec;
-        }
+    for (int s = fDesc.fFirstCoverageStage, i = 0; s < GrDrawState::kNumStages; ++s, ++i) {
+        stageUniformArrays[i] = &fUniformHandles.fEffectSamplerUnis[s];
     }
 
+    builder.emitEffects(stages + fDesc.fFirstCoverageStage,
+                        fDesc.fEffectKeys + fDesc.fFirstCoverageStage,
+                        GrDrawState::kNumStages - fDesc.fFirstCoverageStage,
+                        &inCoverage,
+                        &knownCoverageValue,
+                        stageUniformArrays,
+                        fEffects + fDesc.fFirstCoverageStage);
+
     // discard if coverage is zero
     if (fDesc.fDiscardIfZeroCoverage && kOnes_GrSLConstantVec != knownCoverageValue) {
         if (kZeros_GrSLConstantVec == knownCoverageValue) {
diff --git a/src/gpu/gl/GrGLProgramDesc.h b/src/gpu/gl/GrGLProgramDesc.h
index 8d7ca8d..45714a0 100644
--- a/src/gpu/gl/GrGLProgramDesc.h
+++ b/src/gpu/gl/GrGLProgramDesc.h
@@ -39,7 +39,7 @@
     void setRandom(SkMWCRandom*,
                    const GrGpuGL* gpu,
                    const GrTexture* dummyDstTexture,
-                   const GrEffectStage stages[GrDrawState::kNumStages],
+                   const GrEffectStage* stages[GrDrawState::kNumStages],
                    int currAttribIndex);
 
     /**
diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp
index b379c78..c1732b2 100644
--- a/src/gpu/gl/GrGLShaderBuilder.cpp
+++ b/src/gpu/gl/GrGLShaderBuilder.cpp
@@ -103,7 +103,6 @@
     , fFSOutputs(kMaxFSOutputs)
     , fCtxInfo(ctxInfo)
     , fUniformManager(uniformManager)
-    , fCurrentStageIdx(kNonStageIdx)
     , fFSFeaturesAddedMask(0)
 #if GR_GL_EXPERIMENTAL_GS
     , fUsesGS(desc.fExperimentalGS)
@@ -215,6 +214,21 @@
     }
 }
 
+void GrGLShaderBuilder::nameVariable(SkString* out, char prefix, const char* name) {
+    if ('\0' == prefix) {
+        *out = name;
+    } else {
+        out->printf("%c%s", prefix, name);
+    }
+    if (fCodeStage.inStageCode()) {
+        if (out->endsWith('_')) {
+            // Names containing "__" are reserved.
+            out->append("x");
+        }
+        out->appendf("_Stage%d", fCodeStage.stageIndex());
+    }
+}
+
 const char* GrGLShaderBuilder::dstColor() {
     static const char kFBFetchColorName[] = "gl_LastFragData[0]";
     GrGLCaps::FBFetchType fetchType = fCtxInfo.caps()->fbFetchType();
@@ -364,12 +378,7 @@
     GrAssert(h2 == h);
     uni.fVariable.setType(type);
     uni.fVariable.setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
-    SkString* uniName = uni.fVariable.accessName();
-    if (kNonStageIdx == fCurrentStageIdx) {
-        uniName->printf("u%s", name);
-    } else {
-        uniName->printf("u%s%d", name, fCurrentStageIdx);
-    }
+    this->nameVariable(uni.fVariable.accessName(), 'u', name);
     uni.fVariable.setArrayCount(count);
     uni.fVisibility = visibility;
 
@@ -415,11 +424,8 @@
     fVSOutputs.push_back();
     fVSOutputs.back().setType(type);
     fVSOutputs.back().setTypeModifier(GrGLShaderVar::kVaryingOut_TypeModifier);
-    if (kNonStageIdx == fCurrentStageIdx) {
-        fVSOutputs.back().accessName()->printf("v%s", name);
-    } else {
-        fVSOutputs.back().accessName()->printf("v%s%d", name, fCurrentStageIdx);
-    }
+    this->nameVariable(fVSOutputs.back().accessName(), 'v', name);
+
     if (vsOutName) {
         *vsOutName = fVSOutputs.back().getName().c_str();
     }
@@ -436,11 +442,7 @@
         fGSOutputs.push_back();
         fGSOutputs.back().setType(type);
         fGSOutputs.back().setTypeModifier(GrGLShaderVar::kVaryingOut_TypeModifier);
-        if (kNonStageIdx == fCurrentStageIdx) {
-            fGSOutputs.back().accessName()->printf("g%s", name);
-        } else {
-            fGSOutputs.back().accessName()->printf("g%s%d", name, fCurrentStageIdx);
-        }
+        this->nameVariable(fGSOutputs.back().accessName(), 'g', name);
         fsName = fGSOutputs.back().accessName();
     } else {
         fsName = fVSOutputs.back().accessName();
@@ -470,18 +472,16 @@
     } else {
         static const char* kCoordName = "fragCoordYDown";
         if (!fSetupFragPosition) {
+            // temporarily change the stage index because we're inserting non-stage code.
+            CodeStage::AutoStageRestore csar(&fCodeStage, NULL);
+
             GrAssert(GrGLUniformManager::kInvalidUniformHandle == fRTHeightUniform);
             const char* rtHeightName;
 
-            // temporarily change the stage index because we're inserting a uniform whose name
-            // shouldn't be mangled to be stage-specific.
-            int oldStageIdx = fCurrentStageIdx;
-            fCurrentStageIdx = kNonStageIdx;
             fRTHeightUniform = this->addUniform(kFragment_ShaderType,
                                                 kFloat_GrSLType,
                                                 "RTHeight",
                                                 &rtHeightName);
-            fCurrentStageIdx = oldStageIdx;
 
             this->fFSCode.prependf("\tvec4 %s = vec4(gl_FragCoord.x, %s - gl_FragCoord.y, gl_FragCoord.zw);\n",
                                    kCoordName, rtHeightName);
@@ -514,11 +514,7 @@
                                      SkString* outName) {
     GrAssert(kFragment_ShaderType == shader);
     fFSFunctions.append(GrGLSLTypeString(returnType));
-    if (kNonStageIdx != fCurrentStageIdx) {
-        outName->printf("%s_%d", name, fCurrentStageIdx);
-    } else {
-        *outName = name;
-    }
+    this->nameVariable(outName, '\0', name);
     fFSFunctions.appendf(" %s", outName->c_str());
     fFSFunctions.append("(");
     for (int i = 0; i < argCnt; ++i) {
@@ -623,52 +619,86 @@
     fUniformManager.getUniformLocations(programID, fUniforms);
 }
 
-GrGLEffect* GrGLShaderBuilder::createAndEmitGLEffect(
-                                const GrEffectStage& stage,
-                                GrGLEffect::EffectKey key,
-                                const char* fsInColor,
-                                const char* fsOutColor,
-                                SkTArray<GrGLUniformManager::UniformHandle, true>* samplerHandles) {
-    GrAssert(NULL != stage.getEffect());
+void GrGLShaderBuilder::emitEffects(
+                        const GrEffectStage* effectStages[],
+                        const GrBackendEffectFactory::EffectKey effectKeys[],
+                        int effectCnt,
+                        SkString* fsInOutColor,
+                        GrSLConstantVec* fsInOutColorKnownValue,
+                        SkTArray<GrGLUniformManager::UniformHandle, true>* effectSamplerHandles[],
+                        GrGLEffect* glEffects[]) {
+    bool effectEmitted = false;
 
-    const GrEffectRef& effect = *stage.getEffect();
-    int numTextures = effect->numTextures();
-    SkSTArray<8, GrGLShaderBuilder::TextureSampler> textureSamplers;
-    textureSamplers.push_back_n(numTextures);
-    for (int i = 0; i < numTextures; ++i) {
-        textureSamplers[i].init(this, &effect->textureAccess(i), i);
-        samplerHandles->push_back(textureSamplers[i].fSamplerUniform);
-    }
-    GrDrawEffect drawEffect(stage, this->hasExplicitLocalCoords());
+    SkString inColor = *fsInOutColor;
+    SkString outColor;
 
-    int numAttributes = stage.getVertexAttribIndexCount();
-    const int* attributeIndices = stage.getVertexAttribIndices();
-    SkSTArray<GrEffect::kMaxVertexAttribs, SkString> attributeNames;
-    for (int i = 0; i < numAttributes; ++i) {
-        SkString attributeName("aAttr");
-        attributeName.appendS32(attributeIndices[i]);
-
-        if (this->addAttribute(effect->vertexAttribType(i), attributeName.c_str())) {
-            fEffectAttributes.push_back().set(attributeIndices[i], attributeName);
+    for (int e = 0; e < effectCnt; ++e) {
+        if (NULL == effectStages[e] || GrGLEffect::kNoEffectKey == effectKeys[e]) {
+            continue;
         }
+
+        GrAssert(NULL != effectStages[e]->getEffect());
+        const GrEffectStage& stage = *effectStages[e];
+        const GrEffectRef& effect = *stage.getEffect();
+
+        CodeStage::AutoStageRestore csar(&fCodeStage, &stage);
+
+        int numTextures = effect->numTextures();
+        SkSTArray<8, GrGLShaderBuilder::TextureSampler> textureSamplers;
+        textureSamplers.push_back_n(numTextures);
+        for (int t = 0; t < numTextures; ++t) {
+            textureSamplers[t].init(this, &effect->textureAccess(t), t);
+            effectSamplerHandles[e]->push_back(textureSamplers[t].fSamplerUniform);
+        }
+        GrDrawEffect drawEffect(stage, this->hasExplicitLocalCoords());
+
+        int numAttributes = stage.getVertexAttribIndexCount();
+        const int* attributeIndices = stage.getVertexAttribIndices();
+        SkSTArray<GrEffect::kMaxVertexAttribs, SkString> attributeNames;
+        for (int a = 0; a < numAttributes; ++a) {
+            // TODO: Make addAttribute mangle the name.
+            SkString attributeName("aAttr");
+            attributeName.appendS32(attributeIndices[a]);
+            if (this->addAttribute(effect->vertexAttribType(a), attributeName.c_str())) {
+                fEffectAttributes.push_back().set(attributeIndices[a], attributeName);
+            }
+        }
+
+        glEffects[e] = effect->getFactory().createGLInstance(drawEffect);
+
+        if (kZeros_GrSLConstantVec == *fsInOutColorKnownValue) {
+            // Effects have no way to communicate zeros, they treat an empty string as ones.
+            this->nameVariable(&inColor, '\0', "input");
+            this->fsCodeAppendf("\tvec4 %s = %s;\n", inColor.c_str(), GrGLSLZerosVecf(4));
+        }
+
+        // create var to hold stage result
+        this->nameVariable(&outColor, '\0', "output");
+        this->fsCodeAppendf("\tvec4 %s;\n", outColor.c_str());
+
+        // Enclose custom code in a block to avoid namespace conflicts
+        SkString openBrace;
+        openBrace.printf("\t{ // Stage %d: %s\n", fCodeStage.stageIndex(), glEffects[e]->name());
+        this->fVSCode.append(openBrace);
+        this->fFSCode.append(openBrace);
+
+        glEffects[e]->emitCode(this,
+                               drawEffect,
+                               effectKeys[e],
+                               outColor.c_str(),
+                               inColor.isEmpty() ? NULL : inColor.c_str(),
+                               textureSamplers);
+        this->fVSCode.append("\t}\n");
+        this->fFSCode.append("\t}\n");
+
+        inColor = outColor;
+        *fsInOutColorKnownValue = kNone_GrSLConstantVec;
+        effectEmitted = true;
     }
 
-    GrGLEffect* glEffect = effect->getFactory().createGLInstance(drawEffect);
-
-    // Enclose custom code in a block to avoid namespace conflicts
-    this->fVSCode.appendf("\t{ // %s\n", glEffect->name());
-    this->fFSCode.appendf("\t{ // %s \n", glEffect->name());
-
-    glEffect->emitCode(this,
-                       drawEffect,
-                       key,
-                       fsOutColor,
-                       fsInColor,
-                       textureSamplers);
-    this->fVSCode.appendf("\t}\n");
-    this->fFSCode.appendf("\t}\n");
-
-    return glEffect;
+    if (effectEmitted) {
+        *fsInOutColor = outColor;
+    }
 }
 
 const SkString* GrGLShaderBuilder::getEffectAttributeName(int attributeIndex) const {
diff --git a/src/gpu/gl/GrGLShaderBuilder.h b/src/gpu/gl/GrGLShaderBuilder.h
index 9021a0d..765a2ed 100644
--- a/src/gpu/gl/GrGLShaderBuilder.h
+++ b/src/gpu/gl/GrGLShaderBuilder.h
@@ -71,7 +71,7 @@
 
             GrAssert(NULL != builder);
             SkString name;
-            name.printf("Sampler%d_", idx);
+            name.printf("Sampler%d", idx);
             fSamplerUniform = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
                                                   kSampler2D_GrSLType,
                                                   name.c_str());
@@ -275,16 +275,24 @@
     /** Called after building is complete to get the final shader string. */
     void getShader(ShaderType, SkString*) const;
 
-    void setCurrentStage(int stageIdx) { fCurrentStageIdx = stageIdx; }
-    void setNonStage() { fCurrentStageIdx = kNonStageIdx; }
-    // TODO: move remainder of shader code generation to this class and call this privately
-    // Handles of sampler uniforms generated for the effect are appended to samplerHandles.
-    GrGLEffect* createAndEmitGLEffect(
-                                const GrEffectStage& stage,
-                                GrBackendEffectFactory::EffectKey key,
-                                const char* fsInColor, // NULL means no incoming color
-                                const char* fsOutColor,
-                                SkTArray<GrGLUniformManager::UniformHandle, true>* samplerHandles);
+    /**
+     * Adds code for effects. effectStages contains the effects to add. effectKeys[i] is the key
+     * generated from effectStages[i]. An entry in effectStages can be NULL, in which case it is
+     * skipped. Moreover, if the corresponding key is GrGLEffect::NoEffectKey then it is skipped.
+     * inOutFSColor specifies the input color to the first stage and is updated to be the
+     * output color of the last stage. fsInOutColorKnownValue specifies whether the input color
+     * has a known constant value and is updated to refer to the status of the output color.
+     * The handles to texture samplers for effectStage[i] are added to effectSamplerHandles[i]. The
+     * glEffects array is updated to contain the GrGLEffect generated for each entry in
+     * effectStages.
+     */
+    void emitEffects(const GrEffectStage* effectStages[],
+                     const GrBackendEffectFactory::EffectKey effectKeys[],
+                     int effectCnt,
+                     SkString*  inOutFSColor,
+                     GrSLConstantVec* fsInOutColorKnownValue,
+                     SkTArray<GrGLUniformManager::UniformHandle, true>* effectSamplerHandles[],
+                     GrGLEffect* glEffects[]);
 
     GrGLUniformManager::UniformHandle getRTHeightUniform() const { return fRTHeightUniform; }
     GrGLUniformManager::UniformHandle getDstCopyTopLeftUniform() const {
@@ -338,9 +346,56 @@
     VarArray    fFSOutputs;
 
 private:
-    enum {
-        kNonStageIdx = -1,
-    };
+    class CodeStage : GrNoncopyable {
+    public:
+        CodeStage() : fNextIndex(0), fCurrentIndex(-1), fEffectStage(NULL) {}
+
+        bool inStageCode() const {
+            this->validate();
+            return NULL != fEffectStage;
+        }
+
+        const GrEffectStage* effectStage() const {
+            this->validate();
+            return fEffectStage;
+        }
+
+        int stageIndex() const {
+            this->validate(); 
+            return fCurrentIndex;
+        }
+
+        class AutoStageRestore : GrNoncopyable {
+        public:
+            AutoStageRestore(CodeStage* codeStage, const GrEffectStage* newStage) {
+                GrAssert(NULL != codeStage);
+                fSavedIndex = codeStage->fCurrentIndex;
+                fSavedEffectStage = codeStage->fEffectStage;
+
+                if (NULL == newStage) {
+                    codeStage->fCurrentIndex = -1;
+                } else {
+                    codeStage->fCurrentIndex = codeStage->fNextIndex++;
+                }
+                codeStage->fEffectStage = newStage;
+
+                fCodeStage = codeStage;
+            }
+            ~AutoStageRestore() {
+                fCodeStage->fCurrentIndex = fSavedIndex;
+                fCodeStage->fEffectStage = fSavedEffectStage;
+            }
+        private:
+            CodeStage*              fCodeStage;
+            int                     fSavedIndex;
+            const GrEffectStage*    fSavedEffectStage;
+        };
+    private:
+        void validate() const { GrAssert((NULL == fEffectStage) == (-1 == fCurrentIndex)); }
+        int                     fNextIndex;
+        int                     fCurrentIndex;
+        const GrEffectStage*    fEffectStage;
+    } fCodeStage;
 
     /**
      * Features that should only be enabled by GrGLShaderBuilder itself.
@@ -356,6 +411,11 @@
     // the enables separately for each shader.
     void addFSFeature(uint32_t featureBit, const char* extensionName);
 
+    // Generates a name for a variable. The generated string will be name prefixed by the prefix
+    // char (unless the prefix is '\0'). It also mangles the name to be stage-specific if we're
+    // generating stage code.
+    void nameVariable(SkString* out, char prefix, const char* name);
+
     // Interpretation of DstReadKey when generating code
     enum {
         kNoDstRead_DstReadKey         = 0,
@@ -366,7 +426,6 @@
 
     const GrGLContextInfo&              fCtxInfo;
     GrGLUniformManager&                 fUniformManager;
-    int                                 fCurrentStageIdx;
     uint32_t                            fFSFeaturesAddedMask;
     SkString                            fFSFunctions;
     SkString                            fFSExtensions;