Key shader on whether frag pos read is relative to top-left or bottom-left

R=robertphillips@google.com

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

git-svn-id: http://skia.googlecode.com/svn/trunk@9113 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h
index 91a8723..230b2fa 100644
--- a/src/gpu/GrDrawState.h
+++ b/src/gpu/GrDrawState.h
@@ -451,7 +451,7 @@
     /**
      * Checks whether any of the effects will read the dst pixel color.
      */
-    bool willEffectReadDst() const {
+    bool willEffectReadDstColor() const {
         for (int s = 0; s < kNumStages; ++s) {
             if (this->isStageEnabled(s) && (*this->getStage(s).getEffect())->willReadDstColor()) {
                 return true;
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index 7268015..aa475b3 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -407,7 +407,7 @@
 }
 
 bool GrDrawTarget::setupDstReadIfNecessary(DrawInfo* info) {
-    if (this->caps()->dstReadInShaderSupport() || !this->getDrawState().willEffectReadDst()) {
+    if (this->caps()->dstReadInShaderSupport() || !this->getDrawState().willEffectReadDstColor()) {
         return true;
     }
     GrRenderTarget* rt = this->drawState()->getRenderTarget();
@@ -639,7 +639,7 @@
         }
     }
     SkTLazy<SkRect> bounds;
-    if (this->getDrawState().willEffectReadDst()) {
+    if (this->getDrawState().willEffectReadDstColor()) {
         bounds.init();
         this->getDrawState().getViewMatrix().mapRect(bounds.get(), rect);
     }
diff --git a/src/gpu/gl/GrGLProgramDesc.cpp b/src/gpu/gl/GrGLProgramDesc.cpp
index a1cd85e..532923a 100644
--- a/src/gpu/gl/GrGLProgramDesc.cpp
+++ b/src/gpu/gl/GrGLProgramDesc.cpp
@@ -76,6 +76,7 @@
     }
 
     bool readsDst = false;
+    bool readFragPosition = false;
     int lastEnabledStage = -1;
 
     for (int s = 0; s < GrDrawState::kNumStages; ++s) {
@@ -90,6 +91,9 @@
             if (effect->willReadDstColor()) {
                 readsDst = true;
             }
+            if (effect->willReadFragmentPosition()) {
+                readFragPosition = true;
+            }
         } else {
             desc->fEffectKeys[s] = 0;
         }
@@ -101,10 +105,17 @@
         if (NULL != dstCopy) {
             dstCopyTexture = dstCopy->texture();
         }
-        desc->fDstRead = GrGLShaderBuilder::KeyForDstRead(dstCopyTexture, gpu->glCaps());
-        GrAssert(0 != desc->fDstRead);
+        desc->fDstReadKey = GrGLShaderBuilder::KeyForDstRead(dstCopyTexture, gpu->glCaps());
+        GrAssert(0 != desc->fDstReadKey);
     } else {
-        desc->fDstRead = 0;
+        desc->fDstReadKey = 0;
+    }
+
+    if (readFragPosition) {
+        desc->fFragPosKey = GrGLShaderBuilder::KeyForFragmentPosition(drawState.getRenderTarget(),
+                                                                      gpu->glCaps());
+    } else {
+        desc->fFragPosKey = 0;
     }
 
     desc->fCoverageOutput = kModulate_CoverageOutput;
diff --git a/src/gpu/gl/GrGLProgramDesc.h b/src/gpu/gl/GrGLProgramDesc.h
index 45714a0..b49cb72 100644
--- a/src/gpu/gl/GrGLProgramDesc.h
+++ b/src/gpu/gl/GrGLProgramDesc.h
@@ -79,7 +79,7 @@
         // (1 - colorRGB) as the secondary output. Only set if dual source blending is supported.
         kSecondaryCoverageISC_CoverageOutput,
         // Combines the coverage, dst, and color as coverage * color + (1 - coverage) * dst. This
-        // can only be set if fDstRead is set.
+        // can only be set if fDstReadKey is non-zero.
         kCombineWithDst_CoverageOutput,
 
         kCoverageOutputCnt
@@ -105,9 +105,12 @@
     bool                     fExperimentalGS;
 #endif
 
-    GrGLShaderBuilder::DstReadKey fDstRead;             // set by GrGLShaderBuilder if there
+    GrGLShaderBuilder::DstReadKey fDstReadKey;          // set by GrGLShaderBuilder if there
                                                         // are effects that must read the dst.
                                                         // Otherwise, 0.
+    GrGLShaderBuilder::FragPosKey fFragPosKey;          // set by GrGLShaderBuilder if there are
+                                                        // effects that read the fragment position.
+                                                        // Otherwise, 0.
 
     // should the FS discard if the coverage is zero (to avoid stencil manipulation)
     SkBool8                     fDiscardIfZeroCoverage;
diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp
index 98d7e4c..ddcc615 100644
--- a/src/gpu/gl/GrGLShaderBuilder.cpp
+++ b/src/gpu/gl/GrGLShaderBuilder.cpp
@@ -112,7 +112,8 @@
     , fSetupFragPosition(false)
     , fRTHeightUniform(GrGLUniformManager::kInvalidUniformHandle)
     , fDstCopyTopLeftUniform (GrGLUniformManager::kInvalidUniformHandle)
-    , fDstCopyScaleUniform (GrGLUniformManager::kInvalidUniformHandle) {
+    , fDstCopyScaleUniform (GrGLUniformManager::kInvalidUniformHandle)
+    , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == desc.fFragPosKey) {
 
     fPositionVar = &fVSAttrs.push_back();
     fPositionVar->set(kVec2f_GrSLType, GrGLShaderVar::kAttribute_TypeModifier, "aPosition");
@@ -125,13 +126,13 @@
         fLocalCoordsVar = fPositionVar;
     }
     // Emit code to read the dst copy textue if necessary.
-    if (kNoDstRead_DstReadKey != desc.fDstRead &&
+    if (kNoDstRead_DstReadKey != desc.fDstReadKey &&
         GrGLCaps::kNone_FBFetchType == ctxInfo.caps()->fbFetchType()) {
-        bool topDown = SkToBool(kTopLeftOrigin_DstReadKeyBit & desc.fDstRead);
+        bool topDown = SkToBool(kTopLeftOrigin_DstReadKeyBit & desc.fDstReadKey);
         const char* dstCopyTopLeftName;
         const char* dstCopyCoordScaleName;
         uint32_t configMask;
-        if (SkToBool(kUseAlphaConfig_DstReadKeyBit & desc.fDstRead)) {
+        if (SkToBool(kUseAlphaConfig_DstReadKeyBit & desc.fDstReadKey)) {
             configMask = kA_GrColorComponentFlag;
         } else {
             configMask = kRGBA_GrColorComponentFlags;
@@ -351,6 +352,16 @@
     return static_cast<DstReadKey>(key);
 }
 
+GrGLShaderBuilder::FragPosKey GrGLShaderBuilder::KeyForFragmentPosition(const GrRenderTarget* dst,
+                                                                        const GrGLCaps&) {
+    if (kTopLeft_GrSurfaceOrigin == dst->origin()) {
+        return kTopLeftFragPosRead_FragPosKey;
+    } else {
+        return kBottomLeftFragPosRead_FragPosKey;
+    }
+}
+
+
 const GrGLenum* GrGLShaderBuilder::GetTexParamSwizzle(GrPixelConfig config, const GrGLCaps& caps) {
     if (caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(config)) {
         if (caps.textureRedSupport()) {
@@ -473,8 +484,16 @@
             return "";
         }
     }
-#if 1
-    if (fCtxInfo.caps()->fragCoordConventionsSupport()) {
+    if (fTopLeftFragPosRead) {
+        if (!fSetupFragPosition) {
+            fFSInputs.push_back().set(kVec4f_GrSLType,
+                                      GrGLShaderVar::kIn_TypeModifier,
+                                      "gl_FragCoord",
+                                      GrGLShaderVar::kDefault_Precision);
+            fSetupFragPosition = true;
+        }
+        return "gl_FragCoord";
+    } else if (fCtxInfo.caps()->fragCoordConventionsSupport()) {
         if (!fSetupFragPosition) {
             SkAssertResult(this->enablePrivateFeature(kFragCoordConventions_GLSLPrivateFeature));
             fFSInputs.push_back().set(kVec4f_GrSLType,
@@ -506,18 +525,6 @@
         GrAssert(GrGLUniformManager::kInvalidUniformHandle != fRTHeightUniform);
         return kCoordName;
     }
-#else
-    // This is the path we'll need to use once we have support for TopLeft
-    // render targets.
-    if (!fSetupFragPosition) {
-        fFSInputs.push_back().set(kVec4f_GrSLType,
-                                  GrGLShaderVar::kIn_TypeModifier,
-                                  "gl_FragCoord",
-                                  GrGLShaderVar::kDefault_Precision);
-        fSetupFragPosition = true;
-    }
-    return "gl_FragCoord";
-#endif
 }
 
 
diff --git a/src/gpu/gl/GrGLShaderBuilder.h b/src/gpu/gl/GrGLShaderBuilder.h
index 6e990aa..b67846a 100644
--- a/src/gpu/gl/GrGLShaderBuilder.h
+++ b/src/gpu/gl/GrGLShaderBuilder.h
@@ -193,12 +193,18 @@
                                                                  const GrGLCaps&);
 
     typedef uint8_t DstReadKey;
+    typedef uint8_t FragPosKey;
 
     /**  Returns a key for adding code to read the copy-of-dst color in service of effects that
          require reading the dst. It must not return 0 because 0 indicates that there is no dst
-         copy read at all. */
+         copy read at all (in which case this function should not be called). */
     static DstReadKey KeyForDstRead(const GrTexture* dstCopy, const GrGLCaps&);
 
+    /** Returns a key for reading the fragment location. This should only be called if there is an
+        effect that will requires the fragment position. If the fragment position is not required,
+        the key is 0. */
+    static FragPosKey KeyForFragmentPosition(const GrRenderTarget* dst, const GrGLCaps&);
+
     /** If texture swizzling is available using tex parameters then it is preferred over mangling
         the generated shader code. This potentially allows greater reuse of cached shaders. */
     static const GrGLenum* GetTexParamSwizzle(GrPixelConfig config, const GrGLCaps& caps);
@@ -424,6 +430,12 @@
         kTopLeftOrigin_DstReadKeyBit  = 0x4, // Set if dst-copy origin is top-left.
     };
 
+    enum {
+        kNoFragPosRead_FragPosKey           = 0,  // The fragment positition will not be needed.
+        kTopLeftFragPosRead_FragPosKey      = 0x1,// Read frag pos relative to top-left.
+        kBottomLeftFragPosRead_FragPosKey   = 0x2,// Read frag pos relative to bottom-left.
+    };
+
     const GrGLContextInfo&              fCtxInfo;
     GrGLUniformManager&                 fUniformManager;
     uint32_t                            fFSFeaturesAddedMask;
@@ -443,6 +455,8 @@
     GrGLUniformManager::UniformHandle   fDstCopyTopLeftUniform;
     GrGLUniformManager::UniformHandle   fDstCopyScaleUniform;
 
+    bool                                fTopLeftFragPosRead;
+
     SkSTArray<10, AttributePair, true>  fEffectAttributes;
 
     GrGLShaderVar*                      fPositionVar;
diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp
index d996cd7..73d6db2 100644
--- a/tests/GLProgramsTest.cpp
+++ b/tests/GLProgramsTest.cpp
@@ -70,7 +70,7 @@
     }
 
     if (dstRead) {
-        this->fDstRead = GrGLShaderBuilder::KeyForDstRead(dstTexture, gpu->glCaps());
+        this->fDstReadKey = GrGLShaderBuilder::KeyForDstRead(dstTexture, gpu->glCaps());
     }
 
     CoverageOutput coverageOutput;