separate arrays for color and coverage effects.

R=robertphillips@google.com

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

git-svn-id: http://skia.googlecode.com/svn/trunk@9465 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 1039b3b..8a24d60 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -38,8 +38,9 @@
 
 GrGLProgram* GrGLProgram::Create(const GrGLContext& gl,
                                  const GrGLProgramDesc& desc,
-                                 const GrEffectStage* stages[]) {
-    GrGLProgram* program = SkNEW_ARGS(GrGLProgram, (gl, desc, stages));
+                                 const GrEffectStage* colorStages[],
+                                 const GrEffectStage* coverageStages[]) {
+    GrGLProgram* program = SkNEW_ARGS(GrGLProgram, (gl, desc, colorStages, coverageStages));
     if (!program->succeeded()) {
         delete program;
         program = NULL;
@@ -49,7 +50,8 @@
 
 GrGLProgram::GrGLProgram(const GrGLContext& gl,
                          const GrGLProgramDesc& desc,
-                         const GrEffectStage* stages[])
+                         const GrEffectStage* colorStages[],
+                         const GrEffectStage* coverageStages[])
 : fContext(gl)
 , fUniformManager(gl) {
     fDesc = desc;
@@ -63,9 +65,10 @@
     fColor = GrColor_ILLEGAL;
     fColorFilterColor = GrColor_ILLEGAL;
 
-    fEffectStates.reset(desc.numTotalEffects());
+    fColorEffects.reset(desc.numColorEffects());
+    fCoverageEffects.reset(desc.numCoverageEffects());
 
-    this->genProgram(stages);
+    this->genProgram(colorStages, coverageStages);
 }
 
 GrGLProgram::~GrGLProgram() {
@@ -432,7 +435,8 @@
     return true;
 }
 
-bool GrGLProgram::genProgram(const GrEffectStage* stages[]) {
+bool GrGLProgram::genProgram(const GrEffectStage* colorStages[],
+                             const GrEffectStage* coverageStages[]) {
     GrAssert(0 == fProgramID);
 
     const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader();
@@ -491,10 +495,10 @@
 
     if (needColor) {
         for (int e = 0; e < fDesc.numColorEffects(); ++e) {
-            effectUniformArrays[e] = &fEffectStates[e].fSamplerUnis;
+            effectUniformArrays[e] = &fColorEffects[e].fSamplerUnis;
         }
 
-        builder.emitEffects(stages,
+        builder.emitEffects(colorStages,
                             fDesc.effectKeys(),
                             fDesc.numColorEffects(),
                             &inColor,
@@ -503,7 +507,7 @@
                             glEffects.get());
 
         for (int e = 0; e < fDesc.numColorEffects(); ++e) {
-            fEffectStates[e].fGLEffect = glEffects[e];
+            fColorEffects[e].fGLEffect = glEffects[e];
         }
     }
 
@@ -535,10 +539,10 @@
     GrSLConstantVec knownCoverageValue = this->genInputCoverage(&builder, &inCoverage);
 
     for (int e = 0; e < fDesc.numCoverageEffects(); ++e) {
-        effectUniformArrays[e] = &fEffectStates[e + fDesc.numColorEffects()].fSamplerUnis;
+        effectUniformArrays[e] = &fCoverageEffects[e].fSamplerUnis;
     }
 
-    builder.emitEffects(stages + fDesc.numColorEffects(),
+    builder.emitEffects(coverageStages,
                         fDesc.getEffectKeys() + fDesc.numColorEffects(),
                         fDesc.numCoverageEffects(),
                         &inCoverage,
@@ -546,7 +550,7 @@
                         effectUniformArrays.get(),
                         glEffects.get());
     for (int e = 0; e < fDesc.numCoverageEffects(); ++e) {
-        fEffectStates[e + fDesc.numColorEffects()].fGLEffect = glEffects[e];
+        fCoverageEffects[e].fGLEffect = glEffects[e];
     }
 
     // discard if coverage is zero
@@ -754,24 +758,56 @@
         fDstCopyTexUnit = texUnitIdx++;
     }
 
-    for (int e = 0; e < fEffectStates.count(); ++e) {
-        int numSamplers = fEffectStates[e].fSamplerUnis.count();
-        fEffectStates[e].fTextureUnits.reset(numSamplers);
-        for (int s = 0; s < numSamplers; ++s) {
-            UniformHandle handle = fEffectStates[e].fSamplerUnis[s];
-            if (GrGLUniformManager::kInvalidUniformHandle != handle) {
-                fUniformManager.setSampler(handle, texUnitIdx);
-                fEffectStates[e].fTextureUnits[s] = texUnitIdx++;
-            }
+    for (int e = 0; e < fColorEffects.count(); ++e) {
+        this->initEffectSamplerUniforms(&fColorEffects[e], &texUnitIdx);
+    }
+
+    for (int e = 0; e < fCoverageEffects.count(); ++e) {
+        this->initEffectSamplerUniforms(&fCoverageEffects[e], &texUnitIdx);
+    }
+}
+
+void GrGLProgram::initEffectSamplerUniforms(EffectAndSamplers* effect, int* texUnitIdx) {
+    int numSamplers = effect->fSamplerUnis.count();
+    effect->fTextureUnits.reset(numSamplers);
+    for (int s = 0; s < numSamplers; ++s) {
+        UniformHandle handle = effect->fSamplerUnis[s];
+        if (GrGLUniformManager::kInvalidUniformHandle != handle) {
+            fUniformManager.setSampler(handle, *texUnitIdx);
+            effect->fTextureUnits[s] = (*texUnitIdx)++;
         }
     }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
+void GrGLProgram::setEffectData(GrGpuGL* gpu,
+                                const GrEffectStage& stage,
+                                const EffectAndSamplers& effect) {
+
+    // Let the GrGLEffect set its data.
+    bool explicitLocalCoords = -1 != fDesc.getHeader().fLocalCoordAttributeIndex;
+    GrDrawEffect drawEffect(stage, explicitLocalCoords);
+    effect.fGLEffect->setData(fUniformManager, drawEffect);
+
+    // Bind the texures for the effect.
+    int numSamplers = effect.fSamplerUnis.count();
+    GrAssert((*stage.getEffect())->numTextures() == numSamplers);
+    for (int s = 0; s < numSamplers; ++s) {
+        UniformHandle handle = effect.fSamplerUnis[s];
+        if (GrGLUniformManager::kInvalidUniformHandle != handle) {
+            const GrTextureAccess& access = (*stage.getEffect())->textureAccess(s);
+            GrGLTexture* texture = static_cast<GrGLTexture*>(access.getTexture());
+            int unit = effect.fTextureUnits[s];
+            gpu->bindTexture(unit, access.getParams(), texture);
+        }
+    }
+}
+
 void GrGLProgram::setData(GrGpuGL* gpu,
                           GrDrawState::BlendOptFlags blendOpts,
-                          const GrEffectStage* stages[],
+                          const GrEffectStage* colorStages[],
+                          const GrEffectStage* coverageStages[],
                           const GrDeviceCoordTexture* dstCopy,
                           SharedGLState* sharedState) {
     const GrDrawState& drawState = gpu->getDrawState();
@@ -828,26 +864,17 @@
         GrAssert(GrGLUniformManager::kInvalidUniformHandle == fUniformHandles.fDstCopySamplerUni);
     }
 
-    int numEffects = fDesc.numTotalEffects();
-    for (int e = 0; e < numEffects; ++e) {
-        GrAssert(NULL != stages[e]);
+    for (int e = 0; e < fColorEffects.count(); ++e) {
         // We may have omitted the GrGLEffect because of the color filter logic in genProgram.
         // This can be removed when the color filter is an effect.
-        if (NULL != fEffectStates[e].fGLEffect) {
-            bool explicitLocalCoords = -1 != fDesc.getHeader().fLocalCoordAttributeIndex;
-            GrDrawEffect drawEffect(*stages[e], explicitLocalCoords);
-            fEffectStates[e].fGLEffect->setData(fUniformManager, drawEffect);
-            int numSamplers = fEffectStates[e].fSamplerUnis.count();
-            GrAssert((*stages[e]->getEffect())->numTextures() == numSamplers);
-            for (int s = 0; s < numSamplers; ++s) {
-                UniformHandle handle = fEffectStates[e].fSamplerUnis[s];
-                if (GrGLUniformManager::kInvalidUniformHandle != handle) {
-                    const GrTextureAccess& access = (*stages[e]->getEffect())->textureAccess(s);
-                    GrGLTexture* texture = static_cast<GrGLTexture*>(access.getTexture());
-                    int unit = fEffectStates[e].fTextureUnits[s];
-                    gpu->bindTexture(unit, access.getParams(), texture);
-                }
-            }
+        if (NULL != fColorEffects[e].fGLEffect) {
+            this->setEffectData(gpu, *colorStages[e], fColorEffects[e]);
+        }
+    }
+
+    for (int e = 0; e < fCoverageEffects.count(); ++e) {
+        if (NULL != fCoverageEffects[e].fGLEffect) {
+            this->setEffectData(gpu, *coverageStages[e], fCoverageEffects[e]);
         }
     }
 }
diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h
index ce43b71..3534552 100644
--- a/src/gpu/gl/GrGLProgram.h
+++ b/src/gpu/gl/GrGLProgram.h
@@ -38,7 +38,8 @@
 
     static GrGLProgram* Create(const GrGLContext& gl,
                                const GrGLProgramDesc& desc,
-                               const GrEffectStage* stages[]);
+                               const GrEffectStage* colorStages[],
+                               const GrEffectStage* coverageStages[]);
 
     virtual ~GrGLProgram();
 
@@ -103,59 +104,19 @@
     /**
      * This function uploads uniforms and calls each GrGLEffect's setData. It is called before a
      * draw occurs using the program after the program has already been bound. It also uses the
-     * GrGpuGL object to bind the textures required by the GrGLEffects.
+     * GrGpuGL object to bind the textures required by the GrGLEffects. The color and coverage
+     * stages come from GrGLProgramDesc::Build().
      */
     void setData(GrGpuGL*,
                  GrDrawState::BlendOptFlags,
-                 const GrEffectStage* stages[],       // output of GrGLProgramDesc:Build()
+                 const GrEffectStage* colorStages[],
+                 const GrEffectStage* coverageStages[],
                  const GrDeviceCoordTexture* dstCopy, // can be NULL
                  SharedGLState*);
 
 private:
-    GrGLProgram(const GrGLContext& gl,
-                const GrGLProgramDesc& desc,
-                const GrEffectStage* stages[]);
-
-    bool succeeded() const { return 0 != fProgramID; }
-
-    /**
-     * This is the heavy initialization routine for building a GLProgram. stages is all the enabled
-     * color stages followed by all the enabled coverage stages as output by
-     * GrGLProgramDesc::Build()
-     */
-    bool genProgram(const GrEffectStage* stages[]);
-
-    GrSLConstantVec genInputColor(GrGLShaderBuilder* builder, SkString* inColor);
-
-    GrSLConstantVec genInputCoverage(GrGLShaderBuilder* builder, SkString* inCoverage);
-
-    void genGeometryShader(GrGLShaderBuilder* segments) const;
-
     typedef GrGLUniformManager::UniformHandle UniformHandle;
 
-    // Creates a GL program ID, binds shader attributes to GL vertex attrs, and links the program
-    bool bindOutputsAttribsAndLinkProgram(const GrGLShaderBuilder& builder,
-                                          bool bindColorOut,
-                                          bool bindDualSrcOut);
-
-    // Sets the texture units for samplers
-    void initSamplerUniforms();
-
-    bool compileShaders(const GrGLShaderBuilder& builder);
-
-    const char* adjustInColor(const SkString& inColor) const;
-
-    // Helper for setData(). Makes GL calls to specify the initial color when there is not
-    // per-vertex colors.
-    void setColor(const GrDrawState&, GrColor color, SharedGLState*);
-
-    // Helper for setData(). Makes GL calls to specify the initial coverage when there is not
-    // per-vertex coverages.
-    void setCoverage(const GrDrawState&, GrColor coverage, SharedGLState*);
-
-    // Helper for setData() that sets the view matrix and loads the render target height uniform
-    void setMatrixAndRenderTargetHeight(const GrDrawState&);
-
     // handles for uniforms (aside from per-effect samplers)
     struct UniformHandles {
         UniformHandle       fViewMatrixUni;
@@ -195,6 +156,52 @@
         TextureUnitSArray   fTextureUnits; // texture unit used for each entry of fSamplerUnis
     };
 
+    GrGLProgram(const GrGLContext& gl,
+                const GrGLProgramDesc& desc,
+                const GrEffectStage* colorStages[],
+                const GrEffectStage* coverageStages[]);
+
+    bool succeeded() const { return 0 != fProgramID; }
+
+    /**
+     * This is the heavy initialization routine for building a GLProgram. colorStages and
+     * coverageStages correspond to the output of GrGLProgramDesc::Build().
+     */
+    bool genProgram(const GrEffectStage* colorStages[], const GrEffectStage* coverageStages[]);
+
+    GrSLConstantVec genInputColor(GrGLShaderBuilder* builder, SkString* inColor);
+
+    GrSLConstantVec genInputCoverage(GrGLShaderBuilder* builder, SkString* inCoverage);
+
+    void genGeometryShader(GrGLShaderBuilder* segments) const;
+
+    // Creates a GL program ID, binds shader attributes to GL vertex attrs, and links the program
+    bool bindOutputsAttribsAndLinkProgram(const GrGLShaderBuilder& builder,
+                                          bool bindColorOut,
+                                          bool bindDualSrcOut);
+
+    // Sets the texture units for samplers
+    void initSamplerUniforms();
+    void initEffectSamplerUniforms(EffectAndSamplers* effect, int* texUnitIdx);
+
+    bool compileShaders(const GrGLShaderBuilder& builder);
+
+    const char* adjustInColor(const SkString& inColor) const;
+
+    // Helper for setData().
+    void setEffectData(GrGpuGL* gpu, const GrEffectStage& stage, const EffectAndSamplers& effect);
+
+    // Helper for setData(). Makes GL calls to specify the initial color when there is not
+    // per-vertex colors.
+    void setColor(const GrDrawState&, GrColor color, SharedGLState*);
+
+    // Helper for setData(). Makes GL calls to specify the initial coverage when there is not
+    // per-vertex coverages.
+    void setCoverage(const GrDrawState&, GrColor coverage, SharedGLState*);
+
+    // Helper for setData() that sets the view matrix and loads the render target height uniform
+    void setMatrixAndRenderTargetHeight(const GrDrawState&);
+
     // GL IDs
     GrGLuint                    fVShaderID;
     GrGLuint                    fGShaderID;
@@ -208,7 +215,8 @@
     GrColor                     fColorFilterColor;
     int                         fDstCopyTexUnit;
 
-    SkTArray<EffectAndSamplers> fEffectStates;
+    SkTArray<EffectAndSamplers> fColorEffects;
+    SkTArray<EffectAndSamplers> fCoverageEffects;
 
     GrGLProgramDesc             fDesc;
     const GrGLContext&          fContext;
diff --git a/src/gpu/gl/GrGLProgramDesc.cpp b/src/gpu/gl/GrGLProgramDesc.cpp
index d040658..4f00118 100644
--- a/src/gpu/gl/GrGLProgramDesc.cpp
+++ b/src/gpu/gl/GrGLProgramDesc.cpp
@@ -21,8 +21,12 @@
                             GrBlendCoeff dstCoeff,
                             const GrGpuGL* gpu,
                             const GrDeviceCoordTexture* dstCopy,
-                            const GrEffectStage* stages[],
+                            SkTArray<const GrEffectStage*, true>* colorStages,
+                            SkTArray<const GrEffectStage*, true>* coverageStages,
                             GrGLProgramDesc* desc) {
+    colorStages->reset();
+    coverageStages->reset();
+
     // This should already have been caught
     GrAssert(!(GrDrawState::kSkipDraw_BlendOptFlag & blendOpts));
 
@@ -51,26 +55,22 @@
     // effects as color in desc. Two things will allow simplication of this mess: GrDrawState will
     // have tight lists of color and coverage stages rather than a fixed size array with NULLS and
     // the xfermode-color filter will be removed.
-    int colorEffectCnt = 0;
-    int coverageEffectCnt = 0;
     if (!skipColor) {
         for (int s = 0; s < drawState.getFirstCoverageStage(); ++s) {
             if (drawState.isStageEnabled(s)) {
-                stages[colorEffectCnt] = &drawState.getStage(s);
-                ++colorEffectCnt;
+                colorStages->push_back(&drawState.getStage(s));
             }
         }
     }
     if (!skipCoverage) {
         for (int s = drawState.getFirstCoverageStage(); s < GrDrawState::kNumStages; ++s) {
             if (drawState.isStageEnabled(s)) {
-                stages[colorEffectCnt + coverageEffectCnt] = &drawState.getStage(s);
-                ++coverageEffectCnt;
+                coverageStages->push_back(&drawState.getStage(s));
             }
         }
     }
 
-    size_t newKeyLength = KeyLength(colorEffectCnt + coverageEffectCnt);
+    size_t newKeyLength = KeyLength(colorStages->count() + coverageStages->count());
     bool allocChanged;
     desc->fKey.reset(newKeyLength, SkAutoMalloc::kAlloc_OnShrink, &allocChanged);
     if (allocChanged || !desc->fInitialized) {
@@ -189,7 +189,7 @@
 
     // If we do have coverage determine whether it matters.
     bool separateCoverageFromColor = false;
-    if (!drawState.isCoverageDrawing() && (coverageEffectCnt > 0 || requiresCoverageAttrib)) {
+    if (!drawState.isCoverageDrawing() && (coverageStages->count() > 0 || requiresCoverageAttrib)) {
         // color filter is applied between color/coverage computation
         if (SkXfermode::kDst_Mode != header->fColorFilterXfermode) {
             separateCoverageFromColor = true;
@@ -225,11 +225,13 @@
         }
     }
     if (separateCoverageFromColor) {
-        header->fColorEffectCnt = colorEffectCnt;
-        header->fCoverageEffectCnt = coverageEffectCnt;
+        header->fColorEffectCnt = colorStages->count();
+        header->fCoverageEffectCnt = coverageStages->count();
     } else {
-        header->fColorEffectCnt = colorEffectCnt + coverageEffectCnt;
+        header->fColorEffectCnt = colorStages->count() + coverageStages->count();
         header->fCoverageEffectCnt = 0;
+        colorStages->push_back_n(coverageStages->count(), coverageStages->begin());
+        coverageStages->reset();
     }
 
     *desc->checksum() = 0;
diff --git a/src/gpu/gl/GrGLProgramDesc.h b/src/gpu/gl/GrGLProgramDesc.h
index 0cf3b22..e85133c 100644
--- a/src/gpu/gl/GrGLProgramDesc.h
+++ b/src/gpu/gl/GrGLProgramDesc.h
@@ -55,7 +55,9 @@
     /**
      * Builds a program descriptor from a GrDrawState. Whether the primitive type is points, the
      * output of GrDrawState::getBlendOpts, and the caps of the GrGpuGL are also inputs. It also
-     * writes a tightly packed array of GrEffectStage* from the drawState.
+     * outputs the color and coverage stages referenced by the generated descriptor. This may
+     * not contain all stages from the draw state and coverage stages from the drawState may
+     * be treated as color stages in the output.
      */
     static void Build(const GrDrawState&,
                       bool isPoints,
@@ -64,7 +66,8 @@
                       GrBlendCoeff dstCoeff,
                       const GrGpuGL* gpu,
                       const GrDeviceCoordTexture* dstCopy,
-                      const GrEffectStage* outStages[GrDrawState::kNumStages],
+                      SkTArray<const GrEffectStage*, true>* outColorStages,
+                      SkTArray<const GrEffectStage*, true>* outCoverageStages,
                       GrGLProgramDesc* outDesc);
 
     int numColorEffects() const {
diff --git a/src/gpu/gl/GrGpuGL.h b/src/gpu/gl/GrGpuGL.h
index 85cace7..c644fbb 100644
--- a/src/gpu/gl/GrGpuGL.h
+++ b/src/gpu/gl/GrGpuGL.h
@@ -178,7 +178,9 @@
         ~ProgramCache();
 
         void abandon();
-        GrGLProgram* getProgram(const GrGLProgramDesc& desc, const GrEffectStage* stages[]);
+        GrGLProgram* getProgram(const GrGLProgramDesc& desc,
+                                const GrEffectStage* colorStages[],
+                                const GrEffectStage* coverageStages[]);
 
     private:
         enum {
diff --git a/src/gpu/gl/GrGpuGL_program.cpp b/src/gpu/gl/GrGpuGL_program.cpp
index 5dab982..5da8ecf 100644
--- a/src/gpu/gl/GrGpuGL_program.cpp
+++ b/src/gpu/gl/GrGpuGL_program.cpp
@@ -84,7 +84,8 @@
 }
 
 GrGLProgram* GrGpuGL::ProgramCache::getProgram(const GrGLProgramDesc& desc,
-                                               const GrEffectStage* stages[]) {
+                                               const GrEffectStage* colorStages[],
+                                               const GrEffectStage* coverageStages[]) {
 #ifdef PROGRAM_CACHE_STATS
     ++fTotalRequests;
 #endif
@@ -119,7 +120,7 @@
 #ifdef PROGRAM_CACHE_STATS
         ++fCacheMisses;
 #endif
-        GrGLProgram* program = GrGLProgram::Create(fGL, desc, stages);
+        GrGLProgram* program = GrGLProgram::Create(fGL, desc, colorStages, coverageStages);
         if (NULL == program) {
             return NULL;
         }
@@ -273,7 +274,8 @@
             return false;
         }
 
-        const GrEffectStage* stages[GrDrawState::kNumStages];
+        SkSTArray<8, const GrEffectStage*, true> colorStages;
+        SkSTArray<8, const GrEffectStage*, true> coverageStages;
         GrGLProgramDesc desc;
         GrGLProgramDesc::Build(this->getDrawState(),
                                kDrawPoints_DrawType == type,
@@ -282,10 +284,13 @@
                                dstCoeff,
                                this,
                                dstCopy,
-                               stages,
+                               &colorStages,
+                               &coverageStages,
                                &desc);
 
-        fCurrentProgram.reset(fProgramCache->getProgram(desc, stages));
+        fCurrentProgram.reset(fProgramCache->getProgram(desc,
+                                                        colorStages.begin(),
+                                                        coverageStages.begin()));
         if (NULL == fCurrentProgram.get()) {
             GrAssert(!"Failed to create program!");
             return false;
@@ -301,7 +306,12 @@
         fCurrentProgram->overrideBlend(&srcCoeff, &dstCoeff);
         this->flushBlend(kDrawLines_DrawType == type, srcCoeff, dstCoeff);
 
-        fCurrentProgram->setData(this, blendOpts, stages, dstCopy, &fSharedGLProgramState);
+        fCurrentProgram->setData(this,
+                                 blendOpts,
+                                 colorStages.begin(),
+                                 coverageStages.begin(),
+                                 dstCopy,
+                                 &fSharedGLProgramState);
     }
     this->flushStencil(type);
     this->flushScissor();