Automatically handle converting gl_FragCoord to Skia's y-down device coords.
authorbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Mon, 22 Oct 2012 17:40:14 +0000 (17:40 +0000)
committerbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Mon, 22 Oct 2012 17:40:14 +0000 (17:40 +0000)
NOTE: THIS WILL LIKELY REQUIRE GM REBASELINING.

R=robertphillips@google.com,senorblanco@chromium.org
Review URL: https://codereview.appspot.com/6744061

git-svn-id: http://skia.googlecode.com/svn/trunk@6030 2bbb7eff-a529-9590-31e7-b0007b416f81

src/effects/SkLightingImageFilter.cpp
src/gpu/GrAAHairLinePathRenderer.cpp
src/gpu/GrContext.cpp
src/gpu/gl/GrGLCaps.cpp
src/gpu/gl/GrGLCaps.h
src/gpu/gl/GrGLProgram.cpp
src/gpu/gl/GrGLProgram.h
src/gpu/gl/GrGLShaderBuilder.cpp
src/gpu/gl/GrGLShaderBuilder.h

index ddb31936ca1029dcfc58c8bae7e968850ab9a5e4..f9383715de8dc00de38b011b41d938d4aa31deb2 100644 (file)
@@ -42,14 +42,7 @@ void setUniformPoint3(const GrGLUniformManager& uman, UniformHandle uni, const S
 }
 
 void setUniformNormal3(const GrGLUniformManager& uman, UniformHandle uni, const SkPoint3& point) {
-    setUniformPoint3(uman, uni, SkPoint3(point.fX, -point.fY, point.fZ));
-}
-
-void setUniformPoint3FlipY(const GrGLUniformManager& uman,
-                           UniformHandle uni,
-                           const SkPoint3& point,
-                           int height) {
-    setUniformPoint3(uman, uni, SkPoint3(point.fX, height-point.fY, point.fZ));
+    setUniformPoint3(uman, uni, SkPoint3(point.fX, point.fY, point.fZ));
 }
 #endif
 
@@ -376,7 +369,7 @@ public:
     virtual void setupVariables(GrGLShaderBuilder* builder);
     virtual void emitVS(SkString* out) const {}
     virtual void emitFuncs(GrGLShaderBuilder* builder) {}
-    virtual void emitSurfaceToLight(const GrGLShaderBuilder*,
+    virtual void emitSurfaceToLight(GrGLShaderBuilder*,
                                     SkString* out,
                                     const char* z) const = 0;
     virtual void emitLightColor(GrGLShaderBuilder*,
@@ -397,7 +390,7 @@ public:
     virtual ~GrGLDistantLight() {}
     virtual void setupVariables(GrGLShaderBuilder* builder) SK_OVERRIDE;
     virtual void setData(const GrGLUniformManager&, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
-    virtual void emitSurfaceToLight(const GrGLShaderBuilder*,
+    virtual void emitSurfaceToLight(GrGLShaderBuilder*,
                                     SkString* out,
                                     const char* z) const SK_OVERRIDE;
 private:
@@ -413,7 +406,7 @@ public:
     virtual void setupVariables(GrGLShaderBuilder* builder) SK_OVERRIDE;
     virtual void setData(const GrGLUniformManager&, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
     virtual void emitVS(SkString* out) const SK_OVERRIDE;
-    virtual void emitSurfaceToLight(const GrGLShaderBuilder*,
+    virtual void emitSurfaceToLight(GrGLShaderBuilder*,
                                     SkString* out,
                                     const char* z) const SK_OVERRIDE;
 private:
@@ -431,7 +424,7 @@ public:
     virtual void setData(const GrGLUniformManager&, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
     virtual void emitVS(SkString* out) const SK_OVERRIDE;
     virtual void emitFuncs(GrGLShaderBuilder* builder);
-    virtual void emitSurfaceToLight(const GrGLShaderBuilder* builder,
+    virtual void emitSurfaceToLight(GrGLShaderBuilder* builder,
                                     SkString* out,
                                     const char* z) const SK_OVERRIDE;
     virtual void emitLightColor(GrGLShaderBuilder*,
@@ -1133,7 +1126,7 @@ void GrGLLightingEffect::emitFS(GrGLShaderBuilder* builder,
                           "pointToNormal",
                           SK_ARRAY_COUNT(gPointToNormalArgs),
                           gPointToNormalArgs,
-                          "\treturn normalize(vec3(-x * scale, -y * scale, 1));\n",
+                          "\treturn normalize(vec3(-x * scale, y * scale, 1));\n",
                           &pointToNormalName);
 
     static const GrGLShaderVar gInteriorNormalArgs[] =  {
@@ -1364,7 +1357,7 @@ void GrGLDistantLight::setData(const GrGLUniformManager& uman,
     setUniformNormal3(uman, fDirectionUni, distantLight->direction());
 }
 
-void GrGLDistantLight::emitSurfaceToLight(const GrGLShaderBuilder* builder,
+void GrGLDistantLight::emitSurfaceToLight(GrGLShaderBuilder* builder,
                                           SkString* out,
                                           const char* z) const {
     const char* dir = builder->getUniformCStr(fDirectionUni);
@@ -1385,17 +1378,17 @@ void GrGLPointLight::setData(const GrGLUniformManager& uman,
     INHERITED::setData(uman, rt, light);
     SkASSERT(light->type() == SkLight::kPoint_LightType);
     const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
-    setUniformPoint3FlipY(uman, fLocationUni, pointLight->location(), rt->height());
+    setUniformPoint3(uman, fLocationUni, pointLight->location());
 }
 
 void GrGLPointLight::emitVS(SkString* out) const {
 }
 
-void GrGLPointLight::emitSurfaceToLight(const GrGLShaderBuilder* builder,
+void GrGLPointLight::emitSurfaceToLight(GrGLShaderBuilder* builder,
                                         SkString* out,
                                         const char* z) const {
     const char* loc = builder->getUniformCStr(fLocationUni);
-    out->appendf("normalize(%s - vec3(gl_FragCoord.xy, %s))", loc, z);
+    out->appendf("normalize(%s - vec3(%s.xy, %s))", loc, builder->fragmentPosition(), z);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1422,7 +1415,7 @@ void GrGLSpotLight::setData(const GrGLUniformManager& uman,
     INHERITED::setData(uman, rt, light);
     SkASSERT(light->type() == SkLight::kSpot_LightType);
     const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
-    setUniformPoint3FlipY(uman, fLocationUni, spotLight->location(), rt->height());
+    setUniformPoint3(uman, fLocationUni, spotLight->location());
     uman.set1f(fExponentUni, spotLight->specularExponent());
     uman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
     uman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
@@ -1463,11 +1456,11 @@ void GrGLSpotLight::emitFuncs(GrGLShaderBuilder* builder) {
                           &fLightColorFunc);
 }
 
-void GrGLSpotLight::emitSurfaceToLight(const GrGLShaderBuilder* builder,
+void GrGLSpotLight::emitSurfaceToLight(GrGLShaderBuilder* builder,
                                        SkString* out,
                                        const char* z) const {
     const char* location= builder->getUniformCStr(fLocationUni);
-    out->appendf("normalize(%s - vec3(gl_FragCoord.xy, %s))", location, z);
+    out->appendf("normalize(%s - vec3(%s.xy, %s))", location, builder->fragmentPosition(), z);
 }
 
 void GrGLSpotLight::emitLightColor(GrGLShaderBuilder* builder,
index 06d8e71f98b88d6fd4cecfc245ebb3cacbcb8c84..411b0e32b61984aa593bfea83639eef235e10aa4 100644 (file)
@@ -458,16 +458,7 @@ void add_line(const SkPoint p[2],
     if (orthVec.setLength(SK_Scalar1)) {
         orthVec.setOrthog(orthVec);
 
-        // the values we pass down to the frag shader
-        // have to be in y-points-up space;
-        SkVector normal;
-        normal.fX = orthVec.fX;
-        normal.fY = -orthVec.fY;
-        SkPoint aYDown;
-        aYDown.fX = a.fX;
-        aYDown.fY = rtHeight - a.fY;
-
-        SkScalar lineC = -(aYDown.dot(normal));
+        SkScalar lineC = -(a.dot(orthVec));
         for (int i = 0; i < kVertsPerLineSeg; ++i) {
             (*vert)[i].fPos = (i < 2) ? a : b;
             if (0 == i || 3 == i) {
@@ -475,8 +466,8 @@ void add_line(const SkPoint p[2],
             } else {
                 (*vert)[i].fPos += orthVec;
             }
-            (*vert)[i].fLine.fA = normal.fX;
-            (*vert)[i].fLine.fB = normal.fY;
+            (*vert)[i].fLine.fA = orthVec.fX;
+            (*vert)[i].fLine.fB = orthVec.fY;
             (*vert)[i].fLine.fC = lineC;
         }
         if (NULL != toSrc) {
index 81f971727483af06b78d9366e4860540a01d1b83..e729e6d4ca446eea57d13b0e70d370bab17991a2 100644 (file)
@@ -1061,9 +1061,7 @@ void GrContext::drawOval(const GrPaint& paint,
     verts[3].fPos = SkPoint::Make(R, B);
 
     for (int i = 0; i < 4; ++i) {
-        // this goes to fragment shader, it should be in y-points-up space.
-        verts[i].fCenter = SkPoint::Make(center.fX, rt->height() - center.fY);
-
+        verts[i].fCenter = center;
         verts[i].fOuterRadius = outerRadius;
         verts[i].fInnerRadius = innerRadius;
     }
index 52c480ad3f0ea92860286b2ce24f7241f9bcc46c..646961b39b41390e7ffc9a3082cc789cc2d5beea 100644 (file)
@@ -36,6 +36,7 @@ void GrGLCaps::reset() {
     fTextureRedSupport = false;
     fImagingSupport = false;
     fTwoFormatLimit = false;
+    fFragCoordsConventionSupport = false;
 }
 
 GrGLCaps::GrGLCaps(const GrGLCaps& caps) {
@@ -65,6 +66,7 @@ GrGLCaps& GrGLCaps::operator = (const GrGLCaps& caps) {
     fTextureRedSupport = caps.fTextureRedSupport;
     fImagingSupport = caps.fImagingSupport;
     fTwoFormatLimit = caps.fTwoFormatLimit;
+    fFragCoordsConventionSupport = caps.fFragCoordsConventionSupport;
 
     return *this;
 }
@@ -158,6 +160,9 @@ void GrGLCaps::init(const GrGLContextInfo& ctxInfo) {
     // can change based on which render target is bound
     fTwoFormatLimit = kES2_GrGLBinding == binding;
 
+    fFragCoordsConventionSupport = ctxInfo.glslGeneration() >= k150_GrGLSLGeneration ||
+                                   ctxInfo.hasExtension("GL_ARB_fragment_coord_conventions");
+
     this->initFSAASupport(ctxInfo);
     this->initStencilFormats(ctxInfo);
 }
index 1cc50c22207c564e153d703f7c7647a9eeb759ce..9dfbf23cb473aaf5dffc5de664b35da0e694bf95 100644 (file)
@@ -216,6 +216,9 @@ public:
     /// Is GL_ARB_IMAGING supported
     bool imagingSupport() const { return fImagingSupport; }
 
+    /// Is GL_ARB_fragment_coord_conventions supported?
+    bool fragCoordConventionsSupport() const { return fFragCoordsConventionSupport; }
+
     // Does ReadPixels support the provided format/type combo?
     bool readPixelsSupported(const GrGLInterface* intf,
                              GrGLenum format,
@@ -293,6 +296,7 @@ private:
     bool fTextureRedSupport : 1;
     bool fImagingSupport  : 1;
     bool fTwoFormatLimit : 1;
+    bool fFragCoordsConventionSupport : 1;
 };
 
 #endif
index 066da357a1cacf0494a06b7cdd6246291a3b5217..8824114b90d26768a80b624f8d800523c3bff7dc 100644 (file)
@@ -77,6 +77,7 @@ GrGLProgram::GrGLProgram(const GrGLContextInfo& gl,
     fViewportSize.set(-1, -1);
     fColor = GrColor_ILLEGAL;
     fColorFilterColor = GrColor_ILLEGAL;
+    fRTHeight = -1;
 
     for (int s = 0; s < GrDrawState::kNumStages; ++s) {
         fProgramStage[s] = NULL;
@@ -234,56 +235,57 @@ static void addColorFilter(SkString* fsCode, const char * outputVar,
 }
 
 bool GrGLProgram::genEdgeCoverage(SkString* coverageVar,
-                                  GrGLShaderBuilder* segments) const {
+                                  GrGLShaderBuilder* builder) const {
     if (fDesc.fVertexLayout & GrDrawTarget::kEdge_VertexLayoutBit) {
         const char *vsName, *fsName;
-        segments->addVarying(kVec4f_GrSLType, "Edge", &vsName, &fsName);
-        segments->fVSAttrs.push_back().set(kVec4f_GrSLType,
-            GrGLShaderVar::kAttribute_TypeModifier, EDGE_ATTR_NAME);
-        segments->fVSCode.appendf("\t%s = " EDGE_ATTR_NAME ";\n", vsName);
+        builder->addVarying(kVec4f_GrSLType, "Edge", &vsName, &fsName);
+        builder->fVSAttrs.push_back().set(kVec4f_GrSLType,
+                                          GrGLShaderVar::kAttribute_TypeModifier,
+                                          EDGE_ATTR_NAME);
+        builder->fVSCode.appendf("\t%s = " EDGE_ATTR_NAME ";\n", vsName);
         switch (fDesc.fVertexEdgeType) {
         case GrDrawState::kHairLine_EdgeType:
-            segments->fFSCode.appendf("\tfloat edgeAlpha = abs(dot(vec3(gl_FragCoord.xy,1), %s.xyz));\n", fsName);
-            segments->fFSCode.append("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
+            builder->fFSCode.appendf("\tfloat edgeAlpha = abs(dot(vec3(%s.xy,1), %s.xyz));\n", builder->fragmentPosition(), fsName);
+            builder->fFSCode.append("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
             break;
         case GrDrawState::kQuad_EdgeType:
-            segments->fFSCode.append("\tfloat edgeAlpha;\n");
+            builder->fFSCode.append("\tfloat edgeAlpha;\n");
             // keep the derivative instructions outside the conditional
-            segments->fFSCode.appendf("\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
-            segments->fFSCode.appendf("\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
-            segments->fFSCode.appendf("\tif (%s.z > 0.0 && %s.w > 0.0) {\n", fsName, fsName);
+            builder->fFSCode.appendf("\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
+            builder->fFSCode.appendf("\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
+            builder->fFSCode.appendf("\tif (%s.z > 0.0 && %s.w > 0.0) {\n", fsName, fsName);
             // today we know z and w are in device space. We could use derivatives
-            segments->fFSCode.appendf("\t\tedgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);\n", fsName, fsName);
-            segments->fFSCode.append ("\t} else {\n");
-            segments->fFSCode.appendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
-                                      "\t\t               2.0*%s.x*duvdy.x - duvdy.y);\n",
-                                      fsName, fsName);
-            segments->fFSCode.appendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName, fsName);
-            segments->fFSCode.append("\t\tedgeAlpha = clamp(0.5 - edgeAlpha / length(gF), 0.0, 1.0);\n"
-                                      "\t}\n");
+            builder->fFSCode.appendf("\t\tedgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);\n", fsName, fsName);
+            builder->fFSCode.append ("\t} else {\n");
+            builder->fFSCode.appendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
+                                     "\t\t               2.0*%s.x*duvdy.x - duvdy.y);\n",
+                                     fsName, fsName);
+            builder->fFSCode.appendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName, fsName);
+            builder->fFSCode.append("\t\tedgeAlpha = clamp(0.5 - edgeAlpha / length(gF), 0.0, 1.0);\n"
+                                    "\t}\n");
             if (kES2_GrGLBinding == fContextInfo.binding()) {
-                segments->fHeader.printf("#extension GL_OES_standard_derivatives: enable\n");
+                builder->fHeader.printf("#extension GL_OES_standard_derivatives: enable\n");
             }
             break;
         case GrDrawState::kHairQuad_EdgeType:
-            segments->fFSCode.appendf("\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
-            segments->fFSCode.appendf("\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
-            segments->fFSCode.appendf("\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
-                                      "\t               2.0*%s.x*duvdy.x - duvdy.y);\n",
-                                      fsName, fsName);
-            segments->fFSCode.appendf("\tfloat edgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName, fsName);
-            segments->fFSCode.append("\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / dot(gF, gF));\n");
-            segments->fFSCode.append("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
+            builder->fFSCode.appendf("\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
+            builder->fFSCode.appendf("\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
+            builder->fFSCode.appendf("\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
+                                     "\t               2.0*%s.x*duvdy.x - duvdy.y);\n",
+                                     fsName, fsName);
+            builder->fFSCode.appendf("\tfloat edgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName, fsName);
+            builder->fFSCode.append("\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / dot(gF, gF));\n");
+            builder->fFSCode.append("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
             if (kES2_GrGLBinding == fContextInfo.binding()) {
-                segments->fHeader.printf("#extension GL_OES_standard_derivatives: enable\n");
+                builder->fHeader.printf("#extension GL_OES_standard_derivatives: enable\n");
             }
             break;
         case GrDrawState::kCircle_EdgeType:
-            segments->fFSCode.append("\tfloat edgeAlpha;\n");
-            segments->fFSCode.appendf("\tfloat d = distance(gl_FragCoord.xy, %s.xy);\n", fsName);
-            segments->fFSCode.appendf("\tfloat outerAlpha = smoothstep(d - 0.5, d + 0.5, %s.z);\n", fsName);
-            segments->fFSCode.appendf("\tfloat innerAlpha = %s.w == 0.0 ? 1.0 : smoothstep(%s.w - 0.5, %s.w + 0.5, d);\n", fsName, fsName, fsName);
-            segments->fFSCode.append("\tedgeAlpha = outerAlpha * innerAlpha;\n");
+            builder->fFSCode.append("\tfloat edgeAlpha;\n");
+            builder->fFSCode.appendf("\tfloat d = distance(%s.xy, %s.xy);\n", builder->fragmentPosition(), fsName);
+            builder->fFSCode.appendf("\tfloat outerAlpha = smoothstep(d - 0.5, d + 0.5, %s.z);\n", fsName);
+            builder->fFSCode.appendf("\tfloat innerAlpha = %s.w == 0.0 ? 1.0 : smoothstep(%s.w - 0.5, %s.w + 0.5, d);\n", fsName, fsName, fsName);
+            builder->fFSCode.append("\tedgeAlpha = outerAlpha * innerAlpha;\n");
             break;
         default:
             GrCrash("Unknown Edge Type!");
@@ -807,6 +809,7 @@ bool GrGLProgram::genProgram(const GrCustomStage** customStages) {
 
     builder.finished(fProgramID);
     this->initSamplerUniforms();
+    fUniforms.fRTHeight = builder.getRTHeightUniform();
 
     return true;
 }
@@ -964,7 +967,13 @@ GrGLProgramStage* GrGLProgram::GenStageCode(const GrCustomStage* stage,
     return glStage;
 }
 
-void GrGLProgram::setData(const GrDrawState& drawState) const {
+void GrGLProgram::setData(const GrDrawState& drawState) {
+    int rtHeight = drawState.getRenderTarget()->height();
+    if (GrGLUniformManager::kInvalidUniformHandle != fUniforms.fRTHeight &&
+        rtHeight != fRTHeight) {
+        fUniformManager.set1f(fUniforms.fRTHeight, GrIntToScalar(rtHeight));
+        fRTHeight = rtHeight;
+    }
     for (int s = 0; s < GrDrawState::kNumStages; ++s) {
         if (NULL != fProgramStage[s]) {
             const GrSamplerState& sampler = drawState.getSampler(s);
index 5f504f25cb49390329211eccdc44f34286d2b186..dd3378b89cf945a6675fd3fb78be02e3bb39b92d 100644 (file)
@@ -72,7 +72,7 @@ public:
      * This function uploads uniforms and calls each GrCustomStage's setData. It is called before a
      * draw occurs using the program after the program has already been bound.
      */
-    void setData(const GrDrawState& drawState) const;
+    void setData(const GrDrawState& drawState);
 
     // Parameters that affect code generation
     // These structs should be kept compact; they are the input to an
@@ -221,12 +221,16 @@ private:
         UniformHandle fColorUni;
         UniformHandle fCoverageUni;
         UniformHandle fColorFilterUni;
+        // We use the render target height to provide a y-down frag coord when specifying
+        // origin_upper_left is not supported.
+        UniformHandle fRTHeight;
         StageUniforms fStages[GrDrawState::kNumStages];
         Uniforms() {
             fViewMatrixUni = GrGLUniformManager::kInvalidUniformHandle;
             fColorUni = GrGLUniformManager::kInvalidUniformHandle;
             fCoverageUni = GrGLUniformManager::kInvalidUniformHandle;
             fColorFilterUni = GrGLUniformManager::kInvalidUniformHandle;
+            fRTHeight = GrGLUniformManager::kInvalidUniformHandle;
         }
     };
 
@@ -246,6 +250,7 @@ private:
     GrColor                     fColor;
     GrColor                     fCoverage;
     GrColor                     fColorFilterColor;
+    int                         fRTHeight;
     /// When it is sent to GL, the texture matrix will be flipped if the texture orientation
     /// (below) requires.
     GrMatrix                    fTextureMatrices[GrDrawState::kNumStages];
index 3ce118ccc960cd9abe55242995bd462df2fadd2a..93a848d021b737a27f6560b465b8b7e2f81f9fa3 100644 (file)
@@ -93,13 +93,15 @@ GrGLShaderBuilder::GrGLShaderBuilder(const GrGLContextInfo& ctx, GrGLUniformMana
     , fContext(ctx)
     , fUniformManager(uniformManager)
     , fCurrentStage(kNonStageIdx)
+    , fSetupFragPosition(false)
+    , fRTHeightUniform(GrGLUniformManager::kInvalidUniformHandle)
     , fTexCoordVaryingType(kVoid_GrSLType) {
 }
 
 void GrGLShaderBuilder::setupTextureAccess(const char* varyingFSName, GrSLType varyingType) {
     // FIXME: We don't know how the custom stage will manipulate the coords. So we give up on using
     // projective texturing and always give the stage 2D coords. This will be fixed when custom
-    // stages are repsonsible for setting up their own tex coords / tex matrices.
+    // stages are responsible for setting up their own tex coords / tex matrices.
     switch (varyingType) {
         case kVec2f_GrSLType:
             fDefaultTexCoordsName = varyingFSName;
@@ -283,6 +285,39 @@ void GrGLShaderBuilder::addVarying(GrSLType type,
     }
 }
 
+const char* GrGLShaderBuilder::fragmentPosition() {
+    if (fContext.caps().fragCoordConventionsSupport()) {
+        if (!fSetupFragPosition) {
+            this->fFSHeader.append("layout(origin_upper_left) in vec4 gl_FragCoord;\n");
+            fSetupFragPosition = true;
+        }
+        return "gl_FragCoord";        
+    } else {
+        static const char* kCoordName = "fragCoordYDown";
+        if (!fSetupFragPosition) {
+            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 = fCurrentStage;
+            fCurrentStage = kNonStageIdx;
+            fRTHeightUniform = this->addUniform(kFragment_ShaderType,
+                                                kFloat_GrSLType,
+                                                "RTHeight",
+                                                &rtHeightName);
+            fCurrentStage = oldStageIdx;
+        
+            this->fFSCode.prependf("\tvec4 %s = vec4(gl_FragCoord.x, %s - gl_FragCoord.y, gl_FragCoord.zw);\n",
+                                   kCoordName, rtHeightName);
+            fSetupFragPosition = true;
+        }
+        GrAssert(GrGLUniformManager::kInvalidUniformHandle != fRTHeightUniform);
+        return kCoordName;
+    }
+}
+
+
 void GrGLShaderBuilder::emitFunction(ShaderType shader,
                                      GrSLType returnType,
                                      const char* name,
@@ -381,6 +416,7 @@ void GrGLShaderBuilder::getShader(ShaderType type, SkString* shaderStr) const {
             append_default_precision_qualifier(kDefaultFragmentPrecision,
                                                fContext.binding(),
                                                shaderStr);
+            shaderStr->append(fFSHeader);
             this->appendUniformDecls(kFragment_ShaderType, shaderStr);
             this->appendDecls(fFSInputs, shaderStr);
             // We shouldn't have declared outputs on 1.10
index f143af39a7689c23615106f2c783bdc75505671b..aa88cf2b15063a9bfcf9bebd34d3d3af9c761ae9 100644 (file)
@@ -129,7 +129,7 @@ public:
         the generated shader code. This potentially allows greater reuse of cached shaders. */
     static const GrGLenum* GetTexParamSwizzle(GrPixelConfig config, const GrGLCaps& caps);
 
-    /** Add a uniform variable to the current program, that has visibilty in one or more shaders.
+    /** Add a uniform variable to the current program, that has visibility in one or more shaders.
         visibility is a bitfield of ShaderType values indicating from which shaders the 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
@@ -151,7 +151,7 @@ public:
     const GrGLShaderVar& getUniformVariable(GrGLUniformManager::UniformHandle) const;
 
     /**
-     * Shorcut for getUniformVariable(u).c_str()
+     * Shortcut for getUniformVariable(u).c_str()
      */
     const char* getUniformCStr(GrGLUniformManager::UniformHandle u) const {
         return this->getUniformVariable(u).c_str();
@@ -165,6 +165,10 @@ public:
                     const char** vsOutName = NULL,
                     const char** fsInName = NULL);
 
+    /** Returns a variable name that represents the position of the fragment in the FS. The position
+        is in device space (e.g. 0,0 is the top left and pixel centers are at half-integers). */
+    const char* fragmentPosition();
+
     /** Called after building is complete to get the final shader string. */
     void getShader(ShaderType, SkString*) const;
 
@@ -180,6 +184,8 @@ public:
     void setCurrentStage(int stage) { fCurrentStage = stage; }
     void setNonStage() { fCurrentStage = kNonStageIdx; }
 
+    GrGLUniformManager::UniformHandle getRTHeightUniform() const { return fRTHeightUniform; }
+
 private:
 
     typedef GrTAllocator<GrGLShaderVar> VarArray;
@@ -211,10 +217,14 @@ private:
         kNonStageIdx = -1,
     };
 
-    const GrGLContextInfo&  fContext;
-    GrGLUniformManager&     fUniformManager;
-    int                     fCurrentStage;
-    SkString                fFSFunctions;
+    const GrGLContextInfo&              fContext;
+    GrGLUniformManager&                 fUniformManager;
+    int                                 fCurrentStage;
+    SkString                            fFSFunctions;
+    SkString                            fFSHeader;
+
+    bool                                fSetupFragPosition;
+    GrGLUniformManager::UniformHandle   fRTHeightUniform;
 
     /// Per-stage settings - only valid while we're inside GrGLProgram::genStageCode().
     //@{