Make GrGLShaderBuilder store a GenProgramOutput

R=robertphillips@google.com

Author: bsalomon@google.com

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

git-svn-id: http://skia.googlecode.com/svn/trunk/src@14982 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/gl/GrGLProgram.cpp b/gpu/gl/GrGLProgram.cpp
index 1d85b0a..d4448b4 100644
--- a/gpu/gl/GrGLProgram.cpp
+++ b/gpu/gl/GrGLProgram.cpp
@@ -48,8 +48,8 @@
     , fGpu(gpu)
     , fUniformManager(SkRef(uman))
     , fUniformHandles(builderOutput.fUniformHandles)
-    , fHasVertexShader(builderOutput.fHasVS)
-    , fNumTexCoordSets(builderOutput.fNumTexCoordSets) {
+    , fHasVertexShader(builderOutput.fHasVertexShader)
+    , fTexCoordSetCnt(builderOutput.fTexCoordSetCnt) {
     this->initSamplerUniforms();
 }
 
@@ -151,7 +151,7 @@
     // custom shaders, it's ignored, so we don't need to change the texgen
     // settings in that case.
     if (!fHasVertexShader) {
-        fGpu->flushPathTexGenSettings(fNumTexCoordSets);
+        fGpu->flushPathTexGenSettings(fTexCoordSetCnt);
     }
 }
 
diff --git a/gpu/gl/GrGLProgram.h b/gpu/gl/GrGLProgram.h
index 4d5ce0f..68bb8ff 100644
--- a/gpu/gl/GrGLProgram.h
+++ b/gpu/gl/GrGLProgram.h
@@ -203,7 +203,7 @@
     GrGLShaderBuilder::UniformHandles   fUniformHandles;
 
     bool                                fHasVertexShader;
-    int                                 fNumTexCoordSets;
+    int                                 fTexCoordSetCnt;
 
     typedef SkRefCnt INHERITED;
 };
diff --git a/gpu/gl/GrGLShaderBuilder.cpp b/gpu/gl/GrGLShaderBuilder.cpp
index 79cb52f..93364e1 100644
--- a/gpu/gl/GrGLShaderBuilder.cpp
+++ b/gpu/gl/GrGLShaderBuilder.cpp
@@ -95,34 +95,27 @@
                                    const GrEffectStage* inColorStages[],
                                    const GrEffectStage* inCoverageStages[],
                                    GenProgramOutput* output) {
+    SkAutoTDelete<GrGLShaderBuilder> builder;
     if (desc.getHeader().fHasVertexCode ||!gpu->shouldUseFixedFunctionTexturing()) {
-        GrGLFullShaderBuilder fullBuilder(gpu, uman, desc);
-        if (fullBuilder.genProgram(inColorStages, inCoverageStages, output)) {
-            output->fHasVS = true;
-            output->fUniformHandles.fViewMatrixUni = fullBuilder.getViewMatrixUniform();
-            output->fUniformHandles.fRTAdjustmentUni = fullBuilder.getRTAdjustmentVecUniform();
-            return true;
-        }
+        builder.reset(SkNEW_ARGS(GrGLFullShaderBuilder, (gpu, uman, desc)));
     } else {
-        GrGLFragmentOnlyShaderBuilder fragmentOnlyBuilder(gpu, uman, desc);
-        if (fragmentOnlyBuilder.genProgram(inColorStages, inCoverageStages, output)) {
-            output->fHasVS = false;
-            output->fNumTexCoordSets = fragmentOnlyBuilder.getNumTexCoordSets();
-            return true;
-        }
+        builder.reset(SkNEW_ARGS(GrGLFragmentOnlyShaderBuilder, (gpu, uman, desc)));
+    }
+    if (builder->genProgram(inColorStages, inCoverageStages)) {
+        *output = builder->getOutput();
+        return true;
     }
     return false;
 }
 
 bool GrGLShaderBuilder::genProgram(const GrEffectStage* colorStages[],
-                                   const GrEffectStage* coverageStages[],
-                                   GenProgramOutput* output) {
+                                   const GrEffectStage* coverageStages[]) {
     const GrGLProgramDesc::KeyHeader& header = this->desc().getHeader();
 
     // incoming color to current stage being processed.
     GrGLSLExpr4 inColor = this->getInputColor();
 
-    output->fColorEffects =
+    fOutput.fColorEffects =
         this->createAndEmitEffects(colorStages,
                                    this->desc().getEffectKeys(),
                                    this->desc().numColorEffects(),
@@ -132,7 +125,7 @@
     // compute the partial coverage
     GrGLSLExpr4 inCoverage = this->getInputCoverage();
 
-    output->fCoverageEffects =
+    fOutput.fCoverageEffects =
         this->createAndEmitEffects(coverageStages,
                                     this->desc().getEffectKeys() + this->desc().numColorEffects(),
                                     this->desc().numCoverageEffects(),
@@ -170,17 +163,10 @@
     }
     this->fsCodeAppendf("\t%s = %s;\n", this->getColorOutputName(), fragColor.c_str());
 
-    if (!this->finish(&output->fProgramID)) {
+    if (!this->finish()) {
         return false;
     }
 
-    output->fUniformHandles.fRTHeightUni = fRTHeightUniform;
-    output->fUniformHandles.fColorUni = fColorUniform;
-    output->fUniformHandles.fCoverageUni = fCoverageUniform;
-    output->fUniformHandles.fDstCopyTopLeftUni = fDstCopyTopLeftUniform;
-    output->fUniformHandles.fDstCopyScaleUni = fDstCopyScaleUniform;
-    output->fUniformHandles.fDstCopySamplerUni = fDstCopySamplerUniform;
-
     return true;
 }
 
@@ -197,9 +183,9 @@
     , fFSOutputs(kMaxFSOutputs)
     , fUniforms(kVarsPerBlock)
     , fSetupFragPosition(false)
+    , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == desc.getHeader().fFragPosKey)
     , fHasCustomColorOutput(false)
-    , fHasSecondaryOutput(false)
-    , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == desc.getHeader().fFragPosKey) {
+    , fHasSecondaryOutput(false) {
 
     const GrGLProgramDesc::KeyHeader& header = desc.getHeader();
 
@@ -209,23 +195,22 @@
         bool topDown = SkToBool(kTopLeftOrigin_DstReadKeyBit & header.fDstReadKey);
         const char* dstCopyTopLeftName;
         const char* dstCopyCoordScaleName;
+        const char* dstCopySamplerName;
         uint32_t configMask;
         if (SkToBool(kUseAlphaConfig_DstReadKeyBit & header.fDstReadKey)) {
             configMask = kA_GrColorComponentFlag;
         } else {
             configMask = kRGBA_GrColorComponentFlags;
         }
-        fDstCopySamplerUniform = this->addUniform(kFragment_Visibility,
-                                                  kSampler2D_GrSLType,
-                                                  "DstCopySampler");
-        fDstCopyTopLeftUniform = this->addUniform(kFragment_Visibility,
-                                                  kVec2f_GrSLType,
-                                                  "DstCopyUpperLeft",
-                                                  &dstCopyTopLeftName);
-        fDstCopyScaleUniform     = this->addUniform(kFragment_Visibility,
-                                                    kVec2f_GrSLType,
-                                                    "DstCopyCoordScale",
-                                                    &dstCopyCoordScaleName);
+        fOutput.fUniformHandles.fDstCopySamplerUni =
+            this->addUniform(kFragment_Visibility, kSampler2D_GrSLType, "DstCopySampler",
+                             &dstCopySamplerName);
+        fOutput.fUniformHandles.fDstCopyTopLeftUni =
+            this->addUniform(kFragment_Visibility, kVec2f_GrSLType, "DstCopyUpperLeft",
+                             &dstCopyTopLeftName);
+        fOutput.fUniformHandles.fDstCopyScaleUni =
+            this->addUniform(kFragment_Visibility, kVec2f_GrSLType, "DstCopyCoordScale",
+                             &dstCopyCoordScaleName);
         const char* fragPos = this->fragmentPosition();
         this->fsCodeAppend("\t// Read color from copy of the destination.\n");
         this->fsCodeAppendf("\tvec2 _dstTexCoord = (%s.xy - %s) * %s;\n",
@@ -236,7 +221,7 @@
         this->fsCodeAppendf("\tvec4 %s = ", kDstCopyColorName);
         append_texture_lookup(&fFSCode,
                               fGpu,
-                              this->getUniformCStr(fDstCopySamplerUniform),
+                              dstCopySamplerName,
                               "_dstTexCoord",
                               configMask,
                               "rgba");
@@ -245,8 +230,9 @@
 
     if (GrGLProgramDesc::kUniform_ColorInput == header.fColorInput) {
         const char* name;
-        fColorUniform = this->addUniform(GrGLShaderBuilder::kFragment_Visibility,
-                                         kVec4f_GrSLType, "Color", &name);
+        fOutput.fUniformHandles.fColorUni =
+            this->addUniform(GrGLShaderBuilder::kFragment_Visibility, kVec4f_GrSLType, "Color",
+                             &name);
         fInputColor = GrGLSLExpr4(name);
     } else if (GrGLProgramDesc::kSolidWhite_ColorInput == header.fColorInput) {
         fInputColor = GrGLSLExpr4(1);
@@ -256,8 +242,9 @@
 
     if (GrGLProgramDesc::kUniform_ColorInput == header.fCoverageInput) {
         const char* name;
-        fCoverageUniform = this->addUniform(GrGLShaderBuilder::kFragment_Visibility,
-                                            kVec4f_GrSLType, "Coverage", &name);
+        fOutput.fUniformHandles.fCoverageUni =
+            this->addUniform(GrGLShaderBuilder::kFragment_Visibility, kVec4f_GrSLType, "Coverage",
+                             &name);
         fInputCoverage = GrGLSLExpr4(name);
     } else if (GrGLProgramDesc::kSolidWhite_ColorInput == header.fCoverageInput) {
         fInputCoverage = GrGLSLExpr4(1);
@@ -360,7 +347,7 @@
     } else if (GrGLCaps::kNV_FBFetchType == fetchType) {
         SkAssertResult(this->enablePrivateFeature(kNVShaderFramebufferFetch_GLSLPrivateFeature));
         return kFBFetchColorName;
-    } else if (fDstCopySamplerUniform.isValid()) {
+    } else if (fOutput.fUniformHandles.fDstCopySamplerUni.isValid()) {
         return kDstCopyColorName;
     } else {
         return "";
@@ -525,19 +512,17 @@
             // temporarily change the stage index because we're inserting non-stage code.
             CodeStage::AutoStageRestore csar(&fCodeStage, NULL);
 
-            SkASSERT(!fRTHeightUniform.isValid());
+            SkASSERT(!fOutput.fUniformHandles.fRTHeightUni.isValid());
             const char* rtHeightName;
 
-            fRTHeightUniform = this->addUniform(kFragment_Visibility,
-                                                kFloat_GrSLType,
-                                                "RTHeight",
-                                                &rtHeightName);
+            fOutput.fUniformHandles.fRTHeightUni =
+                this->addUniform(kFragment_Visibility, kFloat_GrSLType, "RTHeight", &rtHeightName);
 
             this->fFSCode.prependf("\tvec4 %s = vec4(gl_FragCoord.x, %s - gl_FragCoord.y, gl_FragCoord.zw);\n",
                                    kCoordName, rtHeightName);
             fSetupFragPosition = true;
         }
-        SkASSERT(fRTHeightUniform.isValid());
+        SkASSERT(fOutput.fUniformHandles.fRTHeightUni.isValid());
         return kCoordName;
     }
 }
@@ -667,26 +652,26 @@
     return dual_source_output_name();
 }
 
-bool GrGLShaderBuilder::finish(GrGLuint* outProgramId) {
-    GrGLuint programId = 0;
-    GL_CALL_RET(programId, CreateProgram());
-    if (!programId) {
+bool GrGLShaderBuilder::finish() {
+    SkASSERT(0 == fOutput.fProgramID);
+    GL_CALL_RET(fOutput.fProgramID, CreateProgram());
+    if (!fOutput.fProgramID) {
         return false;
     }
 
     SkTDArray<GrGLuint> shadersToDelete;
 
-    if (!this->compileAndAttachShaders(programId, &shadersToDelete)) {
-        GL_CALL(DeleteProgram(programId));
+    if (!this->compileAndAttachShaders(fOutput.fProgramID, &shadersToDelete)) {
+        GL_CALL(DeleteProgram(fOutput.fProgramID));
         return false;
     }
 
-    this->bindProgramLocations(programId);
+    this->bindProgramLocations(fOutput.fProgramID);
     if (fUniformManager->isUsingBindUniform()) {
-      fUniformManager->getUniformLocations(programId, fUniforms);
+        fUniformManager->getUniformLocations(fOutput.fProgramID, fUniforms);
     }
 
-    GL_CALL(LinkProgram(programId));
+    GL_CALL(LinkProgram(fOutput.fProgramID));
 
     // Calling GetProgramiv is expensive in Chromium. Assume success in release builds.
     bool checkLinked = !fGpu->ctxInfo().isChromium();
@@ -695,36 +680,36 @@
 #endif
     if (checkLinked) {
         GrGLint linked = GR_GL_INIT_ZERO;
-        GL_CALL(GetProgramiv(programId, GR_GL_LINK_STATUS, &linked));
+        GL_CALL(GetProgramiv(fOutput.fProgramID, GR_GL_LINK_STATUS, &linked));
         if (!linked) {
             GrGLint infoLen = GR_GL_INIT_ZERO;
-            GL_CALL(GetProgramiv(programId, GR_GL_INFO_LOG_LENGTH, &infoLen));
+            GL_CALL(GetProgramiv(fOutput.fProgramID, GR_GL_INFO_LOG_LENGTH, &infoLen));
             SkAutoMalloc log(sizeof(char)*(infoLen+1));  // outside if for debugger
             if (infoLen > 0) {
                 // retrieve length even though we don't need it to workaround
                 // bug in chrome cmd buffer param validation.
                 GrGLsizei length = GR_GL_INIT_ZERO;
-                GL_CALL(GetProgramInfoLog(programId,
+                GL_CALL(GetProgramInfoLog(fOutput.fProgramID,
                                           infoLen+1,
                                           &length,
                                           (char*)log.get()));
                 GrPrintf((char*)log.get());
             }
             SkDEBUGFAIL("Error linking program");
-            GL_CALL(DeleteProgram(programId));
+            GL_CALL(DeleteProgram(fOutput.fProgramID));
+            fOutput.fProgramID = 0;
             return false;
         }
     }
 
     if (!fUniformManager->isUsingBindUniform()) {
-      fUniformManager->getUniformLocations(programId, fUniforms);
+        fUniformManager->getUniformLocations(fOutput.fProgramID, fUniforms);
     }
 
     for (int i = 0; i < shadersToDelete.count(); ++i) {
       GL_CALL(DeleteShader(shadersToDelete[i]));
     }
 
-    *outProgramId = programId;
     return true;
 }
 
@@ -840,6 +825,8 @@
 
     const GrGLProgramDesc::KeyHeader& header = this->desc().getHeader();
 
+    fOutput.fHasVertexShader = true;
+
     fPositionVar = &fVSAttrs.push_back();
     fPositionVar->set(kVec2f_GrSLType, GrGLShaderVar::kAttribute_TypeModifier, "aPosition");
     if (-1 != header.fLocalCoordAttributeIndex) {
@@ -852,11 +839,13 @@
     }
 
     const char* viewMName;
-    fViewMatrixUniform = this->addUniform(GrGLShaderBuilder::kVertex_Visibility,
-                                          kMat33f_GrSLType, "ViewM", &viewMName);
+    fOutput.fUniformHandles.fViewMatrixUni =
+        this->addUniform(GrGLShaderBuilder::kVertex_Visibility, kMat33f_GrSLType, "ViewM",
+                          &viewMName);
     const char* rtAdjustName;
-    fRTAdustmentVecUniform = this->addUniform(GrGLShaderBuilder::kVertex_Visibility,
-                                              kVec4f_GrSLType, "rtAdjustment", &rtAdjustName);
+    fOutput.fUniformHandles.fRTAdjustmentUni =
+        this->addUniform(GrGLShaderBuilder::kVertex_Visibility, kVec4f_GrSLType, "rtAdjustment",
+                         &rtAdjustName);
 
     // Transform the position into Skia's device coords.
     this->vsCodeAppendf("\tvec3 pos3 = %s * vec3(%s, 1);\n",
@@ -1072,8 +1061,7 @@
 GrGLFragmentOnlyShaderBuilder::GrGLFragmentOnlyShaderBuilder(GrGpuGL* gpu,
                                                              GrGLUniformManager* uniformManager,
                                                              const GrGLProgramDesc& desc)
-    : INHERITED(gpu, uniformManager, desc)
-    , fNumTexCoordSets(0) {
+    : INHERITED(gpu, uniformManager, desc) {
 
     SkASSERT(!desc.getHeader().fHasVertexCode);
     SkASSERT(gpu->glCaps().pathRenderingSupport());
@@ -1082,9 +1070,9 @@
 }
 
 int GrGLFragmentOnlyShaderBuilder::addTexCoordSets(int count) {
-    int firstFreeCoordSet = fNumTexCoordSets;
-    fNumTexCoordSets += count;
-    SkASSERT(gpu()->glCaps().maxFixedFunctionTextureCoords() >= fNumTexCoordSets);
+    int firstFreeCoordSet = fOutput.fTexCoordSetCnt;
+    fOutput.fTexCoordSetCnt += count;
+    SkASSERT(gpu()->glCaps().maxFixedFunctionTextureCoords() >= fOutput.fTexCoordSetCnt);
     return firstFreeCoordSet;
 }
 
diff --git a/gpu/gl/GrGLShaderBuilder.h b/gpu/gl/GrGLShaderBuilder.h
index f3a63af..42186de 100644
--- a/gpu/gl/GrGLShaderBuilder.h
+++ b/gpu/gl/GrGLShaderBuilder.h
@@ -61,12 +61,19 @@
     };
 
     struct GenProgramOutput {
+        GenProgramOutput()
+            : fColorEffects(NULL)
+            , fCoverageEffects(NULL)
+            , fHasVertexShader(false)
+            , fTexCoordSetCnt(0)
+            , fProgramID(0) {}
+
         GrGLProgramEffects* fColorEffects;
         GrGLProgramEffects* fCoverageEffects;
-        UniformHandles fUniformHandles;
-        bool fHasVS;
-        int fNumTexCoordSets;
-        GrGLuint fProgramID;
+        UniformHandles      fUniformHandles;
+        bool                fHasVertexShader;
+        int                 fTexCoordSetCnt;
+        GrGLuint            fProgramID;
     };
 
     static bool GenProgram(GrGpuGL* gpu,
@@ -159,8 +166,7 @@
         uniform should be accessible. At least one bit must be set. Geometry shader uniforms are not
         supported at this time. The actual uniform name will be mangled. If outName is not NULL then
         it will refer to the final uniform name after return. Use the addUniformArray variant to add
-        an array of uniforms.
-    */
+        an array of uniforms. */
     GrGLUniformManager::UniformHandle addUniform(uint32_t visibility,
                                                  GrSLType type,
                                                  const char* name,
@@ -252,6 +258,10 @@
     void appendDecls(const VarArray&, SkString*) const;
     void appendUniformDecls(ShaderVisibility, SkString*) const;
 
+    const GenProgramOutput& getOutput() const { return fOutput; }
+
+    GenProgramOutput fOutput;
+
 private:
     class CodeStage : SkNoncopyable {
     public:
@@ -304,9 +314,7 @@
         const GrEffectStage*    fEffectStage;
     } fCodeStage;
 
-    bool genProgram(const GrEffectStage* colorStages[],
-                    const GrEffectStage* coverageStages[],
-                    GenProgramOutput* output);
+    bool genProgram(const GrEffectStage* colorStages[], const GrEffectStage* coverageStages[]);
 
     /**
     * Adds code for effects and returns a GrGLProgramEffects* object. The caller is responsible for
@@ -327,7 +335,11 @@
     /** Gets the name of the primary color output. */
     const char* getColorOutputName() const;
 
-    bool finish(GrGLuint* outProgramId);
+    /**
+     * Compiles all the shaders, links them into a program, and writes the program id to the output
+     * struct.
+     **/
+    bool finish();
 
     const GrGLSLExpr4& getInputColor() const {
         return fInputColor;
@@ -353,10 +365,10 @@
 
     // Interpretation of DstReadKey when generating code
     enum {
-        kNoDstRead_DstReadKey         = 0,
-        kYesDstRead_DstReadKeyBit     = 0x1, // Set if we do a dst-copy-read.
-        kUseAlphaConfig_DstReadKeyBit = 0x2, // Set if dst-copy config is alpha only.
-        kTopLeftOrigin_DstReadKeyBit  = 0x4, // Set if dst-copy origin is top-left.
+        kNoDstRead_DstReadKey           = 0,
+        kYesDstRead_DstReadKeyBit       = 0x1, // Set if we do a dst-copy-read.
+        kUseAlphaConfig_DstReadKeyBit   = 0x2, // Set if dst-copy config is alpha only.
+        kTopLeftOrigin_DstReadKeyBit    = 0x4, // Set if dst-copy origin is top-left.
     };
 
     enum {
@@ -378,21 +390,13 @@
     SkString                                fFSCode;
 
     bool                                    fSetupFragPosition;
-    GrGLUniformManager::UniformHandle       fDstCopySamplerUniform;
+    bool                                    fTopLeftFragPosRead;
 
     GrGLSLExpr4                             fInputColor;
     GrGLSLExpr4                             fInputCoverage;
 
     bool                                    fHasCustomColorOutput;
     bool                                    fHasSecondaryOutput;
-
-    GrGLUniformManager::UniformHandle       fRTHeightUniform;
-    GrGLUniformManager::UniformHandle       fDstCopyTopLeftUniform;
-    GrGLUniformManager::UniformHandle       fDstCopyScaleUniform;
-    GrGLUniformManager::UniformHandle       fColorUniform;
-    GrGLUniformManager::UniformHandle       fCoverageUniform;
-
-    bool                                    fTopLeftFragPosRead;
 };
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -443,17 +447,6 @@
     bool addEffectAttribute(int attributeIndex, GrSLType type, const SkString& name);
     const SkString* getEffectAttributeName(int attributeIndex) const;
 
-    /**
-     * The view matrix uniform is only valid in the VS. It is always mat33.
-     */
-    GrGLUniformManager::UniformHandle getViewMatrixUniform() const {
-        return fViewMatrixUniform;
-    }
-
-    GrGLUniformManager::UniformHandle getRTAdjustmentVecUniform() const {
-        return fRTAdustmentVecUniform;
-    }
-
 private:
     virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[],
                                                      const EffectKey effectKeys[],
@@ -480,8 +473,6 @@
     };
     SkSTArray<10, AttributePair, true>  fEffectAttributes;
 
-    GrGLUniformManager::UniformHandle   fViewMatrixUniform;
-    GrGLUniformManager::UniformHandle   fRTAdustmentVecUniform;
     GrGLShaderVar*                      fPositionVar;
     GrGLShaderVar*                      fLocalCoordsVar;
 
@@ -494,7 +485,6 @@
 public:
     GrGLFragmentOnlyShaderBuilder(GrGpuGL*, GrGLUniformManager*, const GrGLProgramDesc&);
 
-    int getNumTexCoordSets() const { return fNumTexCoordSets; }
     int addTexCoordSets(int count);
 
 private:
@@ -504,8 +494,6 @@
                                                      int effectCnt,
                                                      GrGLSLExpr4* inOutFSColor) SK_OVERRIDE;
 
-    int fNumTexCoordSets;
-
     typedef GrGLShaderBuilder INHERITED;
 };