Revert "Replaced all calls to fragmentPosition() with sk_FragCoord"

This reverts commit de4d301881e7fd084f1f0b359ec6f9b2bf8bd4c5.

Reason for revert: several Chrome rendering bugs on Mac

BUG=skia:

Change-Id: I492082b0b7e7c902ede4b598c5809f604d210ce1
Reviewed-on: https://skia-review.googlesource.com/7887
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
diff --git a/include/gpu/GrProcessor.h b/include/gpu/GrProcessor.h
index 388bd54..fa6574d 100644
--- a/include/gpu/GrProcessor.h
+++ b/include/gpu/GrProcessor.h
@@ -105,7 +105,8 @@
      */
     enum RequiredFeatures {
         kNone_RequiredFeatures             = 0,
-        kSampleLocations_RequiredFeature   = 1 << 0
+        kFragmentPosition_RequiredFeature  = 1 << 0,
+        kSampleLocations_RequiredFeature   = 1 << 1
     };
 
     GR_DECL_BITFIELD_OPS_FRIENDS(RequiredFeatures);
@@ -147,6 +148,7 @@
      * must call these methods from its constructor. Otherwise, requests to use these features will
      * be denied.
      */
+    void setWillReadFragmentPosition() { fRequiredFeatures |= kFragmentPosition_RequiredFeature; }
     void setWillUseSampleLocations() { fRequiredFeatures |= kSampleLocations_RequiredFeature; }
 
     void combineRequiredFeatures(const GrProcessor& other) {
diff --git a/src/effects/GrCircleBlurFragmentProcessor.cpp b/src/effects/GrCircleBlurFragmentProcessor.cpp
index c54a71c..d161195 100644
--- a/src/effects/GrCircleBlurFragmentProcessor.cpp
+++ b/src/effects/GrCircleBlurFragmentProcessor.cpp
@@ -47,6 +47,7 @@
                                                     &dataName);
 
     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+    const char *fragmentPos = fragBuilder->fragmentPosition();
 
     if (args.fInputColor) {
         fragBuilder->codeAppendf("vec4 src=%s;", args.fInputColor);
@@ -56,9 +57,9 @@
 
     // We just want to compute "(length(vec) - %s.z + 0.5) * %s.w" but need to rearrange
     // for precision.
-    fragBuilder->codeAppendf("vec2 vec = vec2( (sk_FragCoord.x - %s.x) * %s.w, "
-                                              "(sk_FragCoord.y - %s.y) * %s.w );",
-                             dataName, dataName, dataName, dataName);
+    fragBuilder->codeAppendf("vec2 vec = vec2( (%s.x - %s.x) * %s.w , (%s.y - %s.y) * %s.w );",
+                             fragmentPos, dataName, dataName,
+                             fragmentPos, dataName, dataName);
     fragBuilder->codeAppendf("float dist = length(vec) + (0.5 - %s.z) * %s.w;",
                              dataName, dataName);
 
@@ -95,6 +96,7 @@
         , fBlurProfileSampler(blurProfile, GrSamplerParams::kBilerp_FilterMode) {
     this->initClassID<GrCircleBlurFragmentProcessor>();
     this->addTextureSampler(&fBlurProfileSampler);
+    this->setWillReadFragmentPosition();
 }
 
 GrGLSLFragmentProcessor* GrCircleBlurFragmentProcessor::onCreateGLSLInstance() const {
diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp
index f41648d..225d6f6 100644
--- a/src/effects/SkBlurMaskFilter.cpp
+++ b/src/effects/SkBlurMaskFilter.cpp
@@ -904,6 +904,7 @@
                                                      &profileSizeName);
 
     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+    const char *fragmentPos = fragBuilder->fragmentPosition();
 
     if (args.fInputColor) {
         fragBuilder->codeAppendf("vec4 src=%s;", args.fInputColor);
@@ -911,8 +912,8 @@
         fragBuilder->codeAppendf("vec4 src=vec4(1);");
     }
 
-    fragBuilder->codeAppendf("%s vec2 translatedPos = sk_FragCoord.xy - %s.xy;",
-                             precisionString.c_str(), rectName);
+    fragBuilder->codeAppendf("%s vec2 translatedPos = %s.xy - %s.xy;", precisionString.c_str(),
+                             fragmentPos, rectName);
     fragBuilder->codeAppendf("%s float width = %s.z - %s.x;", precisionString.c_str(), rectName,
                              rectName);
     fragBuilder->codeAppendf("%s float height = %s.w - %s.y;", precisionString.c_str(), rectName,
@@ -983,6 +984,7 @@
         , fPrecision(precision) {
     this->initClassID<GrRectBlurEffect>();
     this->addTextureSampler(&fBlurProfileSampler);
+    this->setWillReadFragmentPosition();
 }
 
 void GrRectBlurEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
@@ -1216,6 +1218,7 @@
         , fNinePatchSampler(ninePatchTexture) {
     this->initClassID<GrRRectBlurEffect>();
     this->addTextureSampler(&fNinePatchSampler);
+    this->setWillReadFragmentPosition();
 }
 
 bool GrRRectBlurEffect::onIsEqual(const GrFragmentProcessor& other) const {
@@ -1283,11 +1286,12 @@
                                                     &blurRadiusName);
 
     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+    const char* fragmentPos = fragBuilder->fragmentPosition();
 
     // warp the fragment position to the appropriate part of the 9patch blur texture
 
     fragBuilder->codeAppendf("vec2 rectCenter = (%s.xy + %s.zw)/2.0;", rectName, rectName);
-    fragBuilder->codeAppendf("vec2 translatedFragPos = sk_FragCoord.xy - %s.xy;", rectName);
+    fragBuilder->codeAppendf("vec2 translatedFragPos = %s.xy - %s.xy;", fragmentPos, rectName);
     fragBuilder->codeAppendf("float threshold = %s + 2.0*%s;", cornerRadiusName, blurRadiusName);
     fragBuilder->codeAppendf("vec2 middle = %s.zw - %s.xy - 2.0*threshold;", rectName, rectName);
 
diff --git a/src/effects/SkLightingImageFilter.cpp b/src/effects/SkLightingImageFilter.cpp
index fc7b29b..92057f0 100644
--- a/src/effects/SkLightingImageFilter.cpp
+++ b/src/effects/SkLightingImageFilter.cpp
@@ -770,6 +770,8 @@
     virtual bool isEqual(const SkImageFilterLight& other) const {
         return fColor == other.fColor;
     }
+    // Called to know whether the generated GrGLLight will require access to the fragment position.
+    virtual bool requiresFragmentPosition() const = 0;
     virtual SkImageFilterLight* transform(const SkMatrix& matrix) const = 0;
 
     // Defined below SkLight's subclasses.
@@ -818,6 +820,7 @@
         return nullptr;
 #endif
     }
+    bool requiresFragmentPosition() const override { return false; }
 
     bool isEqual(const SkImageFilterLight& other) const override {
         if (other.type() != kDistant_LightType) {
@@ -876,6 +879,7 @@
         return nullptr;
 #endif
     }
+    bool requiresFragmentPosition() const override { return true; }
     bool isEqual(const SkImageFilterLight& other) const override {
         if (other.type() != kPoint_LightType) {
             return false;
@@ -989,6 +993,7 @@
         return nullptr;
 #endif
     }
+    bool requiresFragmentPosition() const override { return true; }
     LightType type() const override { return kSpot_LightType; }
     const SkPoint3& location() const { return fLocation; }
     const SkPoint3& target() const { return fTarget; }
@@ -1710,6 +1715,9 @@
         , fBoundaryMode(boundaryMode)
         , fDomain(create_domain(texture, srcBounds, GrTextureDomain::kDecal_Mode)) {
     fLight->ref();
+    if (light->requiresFragmentPosition()) {
+        this->setWillReadFragmentPosition();
+    }
 }
 
 GrLightingEffect::~GrLightingEffect() {
@@ -2094,8 +2102,8 @@
     fLocationUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
                                               kVec3f_GrSLType, kDefault_GrSLPrecision,
                                               "LightLocation", &loc);
-    fragBuilder->codeAppendf("normalize(%s - vec3(sk_FragCoord.xy, %s))",
-                             loc, z);
+    fragBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
+                             loc, fragBuilder->fragmentPosition(), z);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -2121,8 +2129,8 @@
                                               kVec3f_GrSLType, kDefault_GrSLPrecision,
                                               "LightLocation", &location);
 
-    fragBuilder->codeAppendf("normalize(%s - vec3(sk_FragCoord.xy, %s))",
-                             location, z);
+    fragBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
+                             location, fragBuilder->fragmentPosition(), z);
 }
 
 void GrGLSpotLight::emitLightColor(GrGLSLUniformHandler* uniformHandler,
diff --git a/src/effects/SkRRectsGaussianEdgeMaskFilter.cpp b/src/effects/SkRRectsGaussianEdgeMaskFilter.cpp
index 223887b..f6b2ce3 100644
--- a/src/effects/SkRRectsGaussianEdgeMaskFilter.cpp
+++ b/src/effects/SkRRectsGaussianEdgeMaskFilter.cpp
@@ -209,6 +209,7 @@
     RRectsGaussianEdgeFP(const SkRRect& first, const SkRRect& second, SkScalar radius)
             : INHERITED(kNone_OptimizationFlags), fFirst(first), fSecond(second), fRadius(radius) {
         this->initClassID<RRectsGaussianEdgeFP>();
+        this->setWillReadFragmentPosition();
 
         fFirstMode = ComputeMode(fFirst);
         fSecondMode = ComputeMode(fSecond);
@@ -232,8 +233,8 @@
 
             // Positive distance is towards the center of the circle.
             // Map all the cases to the lower right quadrant.
-            fragBuilder->codeAppendf("vec2 delta = abs(sk_FragCoord.xy - %s.%s);",
-                                     posName, indices);
+            fragBuilder->codeAppendf("vec2 delta = abs(%s.xy - %s.%s);",
+                                     fragBuilder->fragmentPosition(), posName, indices);
 
             switch (mode) {
                 case kCircle_Mode:
diff --git a/src/gpu/GrProgramDesc.cpp b/src/gpu/GrProgramDesc.cpp
index 080ba5e..87a4a27 100644
--- a/src/gpu/GrProgramDesc.cpp
+++ b/src/gpu/GrProgramDesc.cpp
@@ -195,10 +195,15 @@
     // make sure any padding in the header is zeroed.
     memset(header, 0, kHeaderSize);
 
-    header->fSurfaceOriginKey = 0;
-
     GrRenderTarget* rt = pipeline.getRenderTarget();
 
+    if (requiredFeatures & (GrProcessor::kFragmentPosition_RequiredFeature |
+                            GrProcessor::kSampleLocations_RequiredFeature)) {
+        header->fSurfaceOriginKey = GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin(rt->origin());
+    } else {
+        header->fSurfaceOriginKey = 0;
+    }
+
     if (requiredFeatures & GrProcessor::kSampleLocations_RequiredFeature) {
         SkASSERT(pipeline.isHWAntialiasState());
         header->fSamplePatternKey =
diff --git a/src/gpu/GrProgramDesc.h b/src/gpu/GrProgramDesc.h
index a20cdfc..2a26f2d 100644
--- a/src/gpu/GrProgramDesc.h
+++ b/src/gpu/GrProgramDesc.h
@@ -12,7 +12,6 @@
 #include "GrTypesPriv.h"
 #include "SkOpts.h"
 #include "SkTArray.h"
-#include "glsl/GrGLSLFragmentShaderBuilder.h"
 
 class GrShaderCaps;
 class GrPipeline;
@@ -81,11 +80,6 @@
         return !(*this == other);
     }
 
-    void setSurfaceOriginKey(int key) {
-        KeyHeader* header = this->atOffset<KeyHeader, kHeaderOffset>();
-        header->fSurfaceOriginKey = key;
-    }
-
     static bool Less(const GrProgramDesc& a, const GrProgramDesc& b) {
         SkASSERT(SkIsAlign4(a.keyLength()));
         int l = a.keyLength() >> 2;
diff --git a/src/gpu/GrXferProcessor.cpp b/src/gpu/GrXferProcessor.cpp
index d88259d..df1f35e 100644
--- a/src/gpu/GrXferProcessor.cpp
+++ b/src/gpu/GrXferProcessor.cpp
@@ -27,6 +27,7 @@
         fDstTexture.reset(dstTexture->texture());
         fDstTextureOffset = dstTexture->offset();
         this->addTextureSampler(&fDstTexture);
+        this->setWillReadFragmentPosition();
     }
 }
 
diff --git a/src/gpu/effects/GrConvexPolyEffect.cpp b/src/gpu/effects/GrConvexPolyEffect.cpp
index db8c2d9..da77eb8 100644
--- a/src/gpu/effects/GrConvexPolyEffect.cpp
+++ b/src/gpu/effects/GrConvexPolyEffect.cpp
@@ -34,6 +34,7 @@
     AARectEffect(GrPrimitiveEdgeType edgeType, const SkRect& rect)
             : INHERITED(kModulatesInput_OptimizationFlag), fRect(rect), fEdgeType(edgeType) {
         this->initClassID<AARectEffect>();
+        this->setWillReadFragmentPosition();
     }
 
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
@@ -114,27 +115,24 @@
                                                     &rectName);
 
     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+    const char* fragmentPos = fragBuilder->fragmentPosition();
     if (GrProcessorEdgeTypeIsAA(aare.getEdgeType())) {
         // The amount of coverage removed in x and y by the edges is computed as a pair of negative
         // numbers, xSub and ySub.
         fragBuilder->codeAppend("\t\tfloat xSub, ySub;\n");
-        fragBuilder->codeAppendf("\t\txSub = min(sk_FragCoord.x - %s.x, 0.0);\n", rectName);
-        fragBuilder->codeAppendf("\t\txSub += min(%s.z - sk_FragCoord.x, 0.0);\n", rectName);
-        fragBuilder->codeAppendf("\t\tySub = min(sk_FragCoord.y - %s.y, 0.0);\n", rectName);
-        fragBuilder->codeAppendf("\t\tySub += min(%s.w - sk_FragCoord.y, 0.0);\n", rectName);
+        fragBuilder->codeAppendf("\t\txSub = min(%s.x - %s.x, 0.0);\n", fragmentPos, rectName);
+        fragBuilder->codeAppendf("\t\txSub += min(%s.z - %s.x, 0.0);\n", rectName, fragmentPos);
+        fragBuilder->codeAppendf("\t\tySub = min(%s.y - %s.y, 0.0);\n", fragmentPos, rectName);
+        fragBuilder->codeAppendf("\t\tySub += min(%s.w - %s.y, 0.0);\n", rectName, fragmentPos);
         // Now compute coverage in x and y and multiply them to get the fraction of the pixel
         // covered.
         fragBuilder->codeAppendf("\t\tfloat alpha = (1.0 + max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));\n");
     } else {
         fragBuilder->codeAppendf("\t\tfloat alpha = 1.0;\n");
-        fragBuilder->codeAppendf("\t\talpha *= (sk_FragCoord.x - %s.x) > -0.5 ? 1.0 : 0.0;\n",
-                                 rectName);
-        fragBuilder->codeAppendf("\t\talpha *= (%s.z - sk_FragCoord.x) > -0.5 ? 1.0 : 0.0;\n",
-                                 rectName);
-        fragBuilder->codeAppendf("\t\talpha *= (sk_FragCoord.y - %s.y) > -0.5 ? 1.0 : 0.0;\n",
-                                 rectName);
-        fragBuilder->codeAppendf("\t\talpha *= (%s.w - sk_FragCoord.y) > -0.5 ? 1.0 : 0.0;\n",
-                                 rectName);
+        fragBuilder->codeAppendf("\t\talpha *= (%s.x - %s.x) > -0.5 ? 1.0 : 0.0;\n", fragmentPos, rectName);
+        fragBuilder->codeAppendf("\t\talpha *= (%s.z - %s.x) > -0.5 ? 1.0 : 0.0;\n", rectName, fragmentPos);
+        fragBuilder->codeAppendf("\t\talpha *= (%s.y - %s.y) > -0.5 ? 1.0 : 0.0;\n", fragmentPos, rectName);
+        fragBuilder->codeAppendf("\t\talpha *= (%s.w - %s.y) > -0.5 ? 1.0 : 0.0;\n", rectName, fragmentPos);
     }
 
     if (GrProcessorEdgeTypeIsInverseFill(aare.getEdgeType())) {
@@ -203,10 +201,10 @@
     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
     fragBuilder->codeAppend("\t\tfloat alpha = 1.0;\n");
     fragBuilder->codeAppend("\t\tfloat edge;\n");
+    const char* fragmentPos = fragBuilder->fragmentPosition();
     for (int i = 0; i < cpe.getEdgeCount(); ++i) {
-        fragBuilder->codeAppendf("\t\tedge = dot(%s[%d], vec3(sk_FragCoord.x, sk_FragCoord.y, "
-                                                             "1));\n",
-                                 edgeArrayName, i);
+        fragBuilder->codeAppendf("\t\tedge = dot(%s[%d], vec3(%s.x, %s.y, 1));\n",
+                                 edgeArrayName, i, fragmentPos, fragmentPos);
         if (GrProcessorEdgeTypeIsAA(cpe.getEdgeType())) {
             fragBuilder->codeAppend("\t\tedge = clamp(edge, 0.0, 1.0);\n");
         } else {
@@ -351,6 +349,7 @@
     for (int i = 0; i < n; ++i) {
         fEdges[3 * i + 2] += SK_ScalarHalf;
     }
+    this->setWillReadFragmentPosition();
 }
 
 bool GrConvexPolyEffect::onIsEqual(const GrFragmentProcessor& other) const {
diff --git a/src/gpu/effects/GrDitherEffect.cpp b/src/gpu/effects/GrDitherEffect.cpp
index 34a1565..a2394aa 100644
--- a/src/gpu/effects/GrDitherEffect.cpp
+++ b/src/gpu/effects/GrDitherEffect.cpp
@@ -26,7 +26,10 @@
     const char* name() const override { return "Dither"; }
 
 private:
-    DitherEffect() : INHERITED(kNone_OptimizationFlags) { this->initClassID<DitherEffect>(); }
+    DitherEffect() : INHERITED(kNone_OptimizationFlags) {
+        this->initClassID<DitherEffect>();
+        this->setWillReadFragmentPosition();
+    }
 
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
 
@@ -78,8 +81,8 @@
     // For each channel c, add the random offset to the pixel to either bump
     // it up or let it remain constant during quantization.
     fragBuilder->codeAppendf("\t\tfloat r = "
-                             "fract(sin(dot(sk_FragCoord.xy, vec2(12.9898,78.233))) * "
-                                                            "43758.5453);\n");
+                             "fract(sin(dot(%s.xy ,vec2(12.9898,78.233))) * 43758.5453);\n",
+                             fragBuilder->fragmentPosition());
     fragBuilder->codeAppendf("\t\t%s = (1.0/255.0) * vec4(r, r, r, r) + %s;\n",
                              args.fOutputColor, GrGLSLExpr4(args.fInputColor).c_str());
 }
diff --git a/src/gpu/effects/GrOvalEffect.cpp b/src/gpu/effects/GrOvalEffect.cpp
index b64ac56..6ad6e7b 100644
--- a/src/gpu/effects/GrOvalEffect.cpp
+++ b/src/gpu/effects/GrOvalEffect.cpp
@@ -66,6 +66,7 @@
 CircleEffect::CircleEffect(GrPrimitiveEdgeType edgeType, const SkPoint& c, SkScalar r)
         : INHERITED(kModulatesInput_OptimizationFlag), fCenter(c), fRadius(r), fEdgeType(edgeType) {
     this->initClassID<CircleEffect>();
+    this->setWillReadFragmentPosition();
 }
 
 bool CircleEffect::onIsEqual(const GrFragmentProcessor& other) const {
@@ -123,6 +124,7 @@
                                                       &circleName);
 
     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+    const char* fragmentPos = fragBuilder->fragmentPosition();
 
     SkASSERT(kHairlineAA_GrProcessorEdgeType != ce.getEdgeType());
     // TODO: Right now the distance to circle caclulation is performed in a space normalized to the
@@ -130,13 +132,11 @@
     // mediump. It'd be nice to only to this on mediump devices but we currently don't have the
     // caps here.
     if (GrProcessorEdgeTypeIsInverseFill(ce.getEdgeType())) {
-        fragBuilder->codeAppendf("float d = (length((%s.xy - sk_FragCoord.xy) * %s.w) - 1.0) * "
-                                            "%s.z;",
-                                 circleName, circleName, circleName);
+        fragBuilder->codeAppendf("float d = (length((%s.xy - %s.xy) * %s.w) - 1.0) * %s.z;",
+                                 circleName, fragmentPos, circleName, circleName);
     } else {
-        fragBuilder->codeAppendf("float d = (1.0 - length((%s.xy - sk_FragCoord.xy) *  %s.w)) * "
-                                                  "%s.z;",
-                                 circleName, circleName, circleName);
+        fragBuilder->codeAppendf("float d = (1.0 - length((%s.xy - %s.xy) *  %s.w)) * %s.z;",
+                                 circleName, fragmentPos, circleName, circleName);
     }
     if (GrProcessorEdgeTypeIsAA(ce.getEdgeType())) {
         fragBuilder->codeAppend("d = clamp(d, 0.0, 1.0);");
@@ -237,6 +237,7 @@
         , fRadii(SkVector::Make(rx, ry))
         , fEdgeType(edgeType) {
     this->initClassID<EllipseEffect>();
+    this->setWillReadFragmentPosition();
 }
 
 bool EllipseEffect::onIsEqual(const GrFragmentProcessor& other) const {
@@ -308,9 +309,10 @@
     }
 
     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+    const char* fragmentPos = fragBuilder->fragmentPosition();
 
     // d is the offset to the ellipse center
-    fragBuilder->codeAppendf("vec2 d = sk_FragCoord.xy - %s.xy;", ellipseName);
+    fragBuilder->codeAppendf("vec2 d = %s.xy - %s.xy;", fragmentPos, ellipseName);
     if (scaleName) {
         fragBuilder->codeAppendf("d *= %s.y;", scaleName);
     }
diff --git a/src/gpu/effects/GrRRectEffect.cpp b/src/gpu/effects/GrRRectEffect.cpp
index dabf11a..468deae 100644
--- a/src/gpu/effects/GrRRectEffect.cpp
+++ b/src/gpu/effects/GrRRectEffect.cpp
@@ -100,6 +100,7 @@
         , fEdgeType(edgeType)
         , fCircularCornerFlags(circularCornerFlags) {
     this->initClassID<CircularRRectEffect>();
+    this->setWillReadFragmentPosition();
 }
 
 bool CircularRRectEffect::onIsEqual(const GrFragmentProcessor& other) const {
@@ -180,6 +181,7 @@
     }
 
     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+    const char* fragmentPos = fragBuilder->fragmentPosition();
     // At each quarter-circle corner we compute a vector that is the offset of the fragment position
     // from the circle center. The vector is pinned in x and y to be in the quarter-plane relevant
     // to that corner. This means that points near the interior near the rrect top edge will have
@@ -197,86 +199,84 @@
     // alphas together.
     switch (crre.getCircularCornerFlags()) {
         case CircularRRectEffect::kAll_CornerFlags:
-            fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - sk_FragCoord.xy;", rectName);
-            fragBuilder->codeAppendf("vec2 dxy1 = sk_FragCoord.xy - %s.zw;", rectName);
+            fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - %s.xy;", rectName, fragmentPos);
+            fragBuilder->codeAppendf("vec2 dxy1 = %s.xy - %s.zw;", fragmentPos, rectName);
             fragBuilder->codeAppend("vec2 dxy = max(max(dxy0, dxy1), 0.0);");
             fragBuilder->codeAppendf("float alpha = %s;", clampedCircleDistance.c_str());
             break;
         case CircularRRectEffect::kTopLeft_CornerFlag:
-            fragBuilder->codeAppendf("vec2 dxy = max(%s.xy - sk_FragCoord.xy, 0.0);",
-                                     rectName);
-            fragBuilder->codeAppendf("float rightAlpha = clamp(%s.z - sk_FragCoord.x, 0.0, 1.0);",
-                                     rectName);
-            fragBuilder->codeAppendf("float bottomAlpha = clamp(%s.w - sk_FragCoord.y, 0.0, 1.0);",
-                                     rectName);
+            fragBuilder->codeAppendf("vec2 dxy = max(%s.xy - %s.xy, 0.0);",
+                                     rectName, fragmentPos);
+            fragBuilder->codeAppendf("float rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);",
+                                     rectName, fragmentPos);
+            fragBuilder->codeAppendf("float bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);",
+                                     rectName, fragmentPos);
             fragBuilder->codeAppendf("float alpha = bottomAlpha * rightAlpha * %s;",
                                      clampedCircleDistance.c_str());
             break;
         case CircularRRectEffect::kTopRight_CornerFlag:
-            fragBuilder->codeAppendf("vec2 dxy = max(vec2(sk_FragCoord.x - %s.z, "
-                                                         "%s.y - sk_FragCoord.y), 0.0);",
-                                     rectName, rectName);
-            fragBuilder->codeAppendf("float leftAlpha = clamp(sk_FragCoord.x - %s.x, 0.0, 1.0);",
-                                     rectName);
-            fragBuilder->codeAppendf("float bottomAlpha = clamp(%s.w - sk_FragCoord.y, 0.0, 1.0);",
-                                     rectName);
+            fragBuilder->codeAppendf("vec2 dxy = max(vec2(%s.x - %s.z, %s.y - %s.y), 0.0);",
+                                     fragmentPos, rectName, rectName, fragmentPos);
+            fragBuilder->codeAppendf("float leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);",
+                                     fragmentPos, rectName);
+            fragBuilder->codeAppendf("float bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);",
+                                     rectName, fragmentPos);
             fragBuilder->codeAppendf("float alpha = bottomAlpha * leftAlpha * %s;",
                                      clampedCircleDistance.c_str());
             break;
         case CircularRRectEffect::kBottomRight_CornerFlag:
-            fragBuilder->codeAppendf("vec2 dxy = max(sk_FragCoord.xy - %s.zw, 0.0);",
-                                     rectName);
-            fragBuilder->codeAppendf("float leftAlpha = clamp(sk_FragCoord.x - %s.x, 0.0, 1.0);",
-                                     rectName);
-            fragBuilder->codeAppendf("float topAlpha = clamp(sk_FragCoord.y - %s.y, 0.0, 1.0);",
-                                     rectName);
+            fragBuilder->codeAppendf("vec2 dxy = max(%s.xy - %s.zw, 0.0);",
+                                     fragmentPos, rectName);
+            fragBuilder->codeAppendf("float leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);",
+                                     fragmentPos, rectName);
+            fragBuilder->codeAppendf("float topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);",
+                                     fragmentPos, rectName);
             fragBuilder->codeAppendf("float alpha = topAlpha * leftAlpha * %s;",
                                      clampedCircleDistance.c_str());
             break;
         case CircularRRectEffect::kBottomLeft_CornerFlag:
-            fragBuilder->codeAppendf("vec2 dxy = max(vec2(%s.x - sk_FragCoord.x, sk_FragCoord.y - "
-                                     "%s.w), 0.0);",
-                                     rectName, rectName);
-            fragBuilder->codeAppendf("float rightAlpha = clamp(%s.z - sk_FragCoord.x, 0.0, 1.0);",
-                                     rectName);
-            fragBuilder->codeAppendf("float topAlpha = clamp(sk_FragCoord.y - %s.y, 0.0, 1.0);",
-                                     rectName);
+            fragBuilder->codeAppendf("vec2 dxy = max(vec2(%s.x - %s.x, %s.y - %s.w), 0.0);",
+                                     rectName, fragmentPos, fragmentPos, rectName);
+            fragBuilder->codeAppendf("float rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);",
+                                     rectName, fragmentPos);
+            fragBuilder->codeAppendf("float topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);",
+                                     fragmentPos, rectName);
             fragBuilder->codeAppendf("float alpha = topAlpha * rightAlpha * %s;",
                                      clampedCircleDistance.c_str());
             break;
         case CircularRRectEffect::kLeft_CornerFlags:
-            fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - sk_FragCoord.xy;", rectName);
-            fragBuilder->codeAppendf("float dy1 = sk_FragCoord.y - %s.w;", rectName);
+            fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - %s.xy;", rectName, fragmentPos);
+            fragBuilder->codeAppendf("float dy1 = %s.y - %s.w;", fragmentPos, rectName);
             fragBuilder->codeAppend("vec2 dxy = max(vec2(dxy0.x, max(dxy0.y, dy1)), 0.0);");
-            fragBuilder->codeAppendf("float rightAlpha = clamp(%s.z - sk_FragCoord.x, 0.0, 1.0);",
-                                     rectName);
+            fragBuilder->codeAppendf("float rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);",
+                                     rectName, fragmentPos);
             fragBuilder->codeAppendf("float alpha = rightAlpha * %s;",
                                      clampedCircleDistance.c_str());
             break;
         case CircularRRectEffect::kTop_CornerFlags:
-            fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - sk_FragCoord.xy;", rectName);
-            fragBuilder->codeAppendf("float dx1 = sk_FragCoord.x - %s.z;", rectName);
+            fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - %s.xy;", rectName, fragmentPos);
+            fragBuilder->codeAppendf("float dx1 = %s.x - %s.z;", fragmentPos, rectName);
             fragBuilder->codeAppend("vec2 dxy = max(vec2(max(dxy0.x, dx1), dxy0.y), 0.0);");
-            fragBuilder->codeAppendf("float bottomAlpha = clamp(%s.w - sk_FragCoord.y, 0.0, 1.0);",
-                                     rectName);
+            fragBuilder->codeAppendf("float bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);",
+                                     rectName, fragmentPos);
             fragBuilder->codeAppendf("float alpha = bottomAlpha * %s;",
                                      clampedCircleDistance.c_str());
             break;
         case CircularRRectEffect::kRight_CornerFlags:
-            fragBuilder->codeAppendf("float dy0 = %s.y - sk_FragCoord.y;", rectName);
-            fragBuilder->codeAppendf("vec2 dxy1 = sk_FragCoord.xy - %s.zw;", rectName);
+            fragBuilder->codeAppendf("float dy0 = %s.y - %s.y;", rectName, fragmentPos);
+            fragBuilder->codeAppendf("vec2 dxy1 = %s.xy - %s.zw;", fragmentPos, rectName);
             fragBuilder->codeAppend("vec2 dxy = max(vec2(dxy1.x, max(dy0, dxy1.y)), 0.0);");
-            fragBuilder->codeAppendf("float leftAlpha = clamp(sk_FragCoord.x - %s.x, 0.0, 1.0);",
-                                     rectName);
+            fragBuilder->codeAppendf("float leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);",
+                                     fragmentPos, rectName);
             fragBuilder->codeAppendf("float alpha = leftAlpha * %s;",
                                      clampedCircleDistance.c_str());
             break;
         case CircularRRectEffect::kBottom_CornerFlags:
-            fragBuilder->codeAppendf("float dx0 = %s.x - sk_FragCoord.x;", rectName);
-            fragBuilder->codeAppendf("vec2 dxy1 = sk_FragCoord.xy - %s.zw;", rectName);
+            fragBuilder->codeAppendf("float dx0 = %s.x - %s.x;", rectName, fragmentPos);
+            fragBuilder->codeAppendf("vec2 dxy1 = %s.xy - %s.zw;", fragmentPos, rectName);
             fragBuilder->codeAppend("vec2 dxy = max(vec2(max(dx0, dxy1.x), dxy1.y), 0.0);");
-            fragBuilder->codeAppendf("float topAlpha = clamp(sk_FragCoord.y - %s.y, 0.0, 1.0);",
-                                     rectName);
+            fragBuilder->codeAppendf("float topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);",
+                                     fragmentPos, rectName);
             fragBuilder->codeAppendf("float alpha = topAlpha * %s;",
                                      clampedCircleDistance.c_str());
             break;
@@ -436,6 +436,7 @@
 EllipticalRRectEffect::EllipticalRRectEffect(GrPrimitiveEdgeType edgeType, const SkRRect& rrect)
         : INHERITED(kModulatesInput_OptimizationFlag), fRRect(rrect), fEdgeType(edgeType) {
     this->initClassID<EllipticalRRectEffect>();
+    this->setWillReadFragmentPosition();
 }
 
 bool EllipticalRRectEffect::onIsEqual(const GrFragmentProcessor& other) const {
@@ -519,6 +520,7 @@
                                                    &rectName);
 
     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+    const char* fragmentPos = fragBuilder->fragmentPosition();
     // At each quarter-ellipse corner we compute a vector that is the offset of the fragment pos
     // to the ellipse center. The vector is pinned in x and y to be in the quarter-plane relevant
     // to that corner. This means that points near the interior near the rrect top edge will have
@@ -531,8 +533,8 @@
     // The code below is a simplified version of the above that performs maxs on the vector
     // components before computing distances and alpha values so that only one distance computation
     // need be computed to determine the min alpha.
-    fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - sk_FragCoord.xy;", rectName);
-    fragBuilder->codeAppendf("vec2 dxy1 = sk_FragCoord.xy - %s.zw;", rectName);
+    fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - %s.xy;", rectName, fragmentPos);
+    fragBuilder->codeAppendf("vec2 dxy1 = %s.xy - %s.zw;", fragmentPos, rectName);
 
     // If we're on a device with a "real" mediump then we'll do the distance computation in a space
     // that is normalized by the largest radius. The scale uniform will be scale, 1/scale. The
diff --git a/src/gpu/effects/GrTextureDomain.cpp b/src/gpu/effects/GrTextureDomain.cpp
index 58707f5..aa449d4 100644
--- a/src/gpu/effects/GrTextureDomain.cpp
+++ b/src/gpu/effects/GrTextureDomain.cpp
@@ -419,6 +419,7 @@
     fDeviceSpaceOffset.fX = deviceSpaceOffset.fX - subset.fLeft;
     fDeviceSpaceOffset.fY = deviceSpaceOffset.fY - subset.fTop;
     this->initClassID<GrDeviceSpaceTextureDecalFragmentProcessor>();
+    this->setWillReadFragmentPosition();
 }
 
 sk_sp<GrFragmentProcessor> GrDeviceSpaceTextureDecalFragmentProcessor::Make(
@@ -443,6 +444,7 @@
     fDeviceSpaceOffset.fX = deviceSpaceOffset.fX - subset.fLeft;
     fDeviceSpaceOffset.fY = deviceSpaceOffset.fY - subset.fTop;
     this->initClassID<GrDeviceSpaceTextureDecalFragmentProcessor>();
+    this->setWillReadFragmentPosition();
 }
 
 GrGLSLFragmentProcessor* GrDeviceSpaceTextureDecalFragmentProcessor::onCreateGLSLInstance() const  {
@@ -457,7 +459,8 @@
                                                                      kDefault_GrSLPrecision,
                                                                      "scaleAndTranslate",
                                                                      &scaleAndTranslateName);
-            args.fFragBuilder->codeAppendf("vec2 coords = sk_FragCoord.xy * %s.xy + %s.zw;",
+            args.fFragBuilder->codeAppendf("vec2 coords = %s.xy * %s.xy + %s.zw;",
+                                           args.fFragBuilder->fragmentPosition(),
                                            scaleAndTranslateName, scaleAndTranslateName);
             fGLDomain.sampleTexture(args.fFragBuilder,
                                     args.fUniformHandler,
diff --git a/src/gpu/gl/GrGLGpuProgramCache.cpp b/src/gpu/gl/GrGLGpuProgramCache.cpp
index 2ff5dc7..c1ca160 100644
--- a/src/gpu/gl/GrGLGpuProgramCache.cpp
+++ b/src/gpu/gl/GrGLGpuProgramCache.cpp
@@ -81,18 +81,11 @@
     desc.finalize();
     std::unique_ptr<Entry>* entry = fMap.find(desc);
     if (!entry) {
-        // Didn't find an origin-independent version, check with the specific origin
-        GrSurfaceOrigin origin = pipeline.getRenderTarget()->origin();
-        desc.setSurfaceOriginKey(GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin(origin));
-        desc.finalize();
-        entry = fMap.find(desc);
-    }
-    if (!entry) {
         // We have a cache miss
 #ifdef PROGRAM_CACHE_STATS
         ++fCacheMisses;
 #endif
-        GrGLProgram* program = GrGLProgramBuilder::CreateProgram(pipeline, primProc, &desc, fGpu);
+        GrGLProgram* program = GrGLProgramBuilder::CreateProgram(pipeline, primProc, desc, fGpu);
         if (nullptr == program) {
             return nullptr;
         }
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
index f3548e6..c3e81fb 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
@@ -30,7 +30,7 @@
 
 GrGLProgram* GrGLProgramBuilder::CreateProgram(const GrPipeline& pipeline,
                                                const GrPrimitiveProcessor& primProc,
-                                               GrProgramDesc* desc,
+                                               const GrProgramDesc& desc,
                                                GrGLGpu* gpu) {
     GrAutoLocaleSetter als("C");
 
@@ -56,7 +56,7 @@
 GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu,
                                        const GrPipeline& pipeline,
                                        const GrPrimitiveProcessor& primProc,
-                                       GrProgramDesc* desc)
+                                       const GrProgramDesc& desc)
     : INHERITED(pipeline, primProc, desc)
     , fGpu(gpu)
     , fVaryingHandler(this)
@@ -89,13 +89,6 @@
     }
 
     *shaderIds->append() = shaderId;
-    if (!outInputs->fFlipY) {
-        GrProgramDesc* d = this->desc();
-        // the program doesn't care about the surface origin, set the key to zero to indicate that
-        // it doesn't matter
-        d->setSurfaceOriginKey(0);
-        d->finalize();
-    }
 
     return true;
 }
@@ -251,7 +244,7 @@
 
 GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) {
     return new GrGLProgram(fGpu,
-                           *this->desc(),
+                           this->desc(),
                            fUniformHandles,
                            programID,
                            fUniformHandler.fUniforms,
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.h b/src/gpu/gl/builders/GrGLProgramBuilder.h
index cfbb734..84d6d91 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.h
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.h
@@ -29,14 +29,11 @@
      * The program implements what is specified in the stages given as input.
      * After successful generation, the builder result objects are available
      * to be used.
-     * This function may modify the GrProgramDesc by setting the surface origin
-     * key to 0 (unspecified) if it turns out the program does not care about
-     * the surface origin.
      * @return true if generation was successful.
      */
     static GrGLProgram* CreateProgram(const GrPipeline&,
                                       const GrPrimitiveProcessor&,
-                                      GrProgramDesc*,
+                                      const GrProgramDesc&,
                                       GrGLGpu*);
 
     const GrCaps* caps() const override;
@@ -45,7 +42,7 @@
 
 private:
     GrGLProgramBuilder(GrGLGpu*, const GrPipeline&, const GrPrimitiveProcessor&,
-                       GrProgramDesc*);
+                       const GrProgramDesc&);
 
     bool compileAndAttachShaders(GrGLSLShaderBuilder& shader,
                                  GrGLuint programId,
diff --git a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
index f583420..7ef7348 100644
--- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
@@ -130,6 +130,11 @@
     return coords2D;
 }
 
+const char* GrGLSLFragmentShaderBuilder::fragmentPosition() {
+    SkDEBUGCODE(fUsedProcessorFeatures |= GrProcessor::kFragmentPosition_RequiredFeature;)
+    return "sk_FragCoord";
+}
+
 const char* GrGLSLFragmentShaderBuilder::distanceVectorName() const {
     return "fsDistanceVector";
 }
diff --git a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
index ab806ea..f7d2323 100644
--- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
+++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
@@ -47,6 +47,11 @@
      */
     virtual SkString ensureCoords2D(const GrShaderVar&) = 0;
 
+
+    /** 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). */
+    virtual const char* fragmentPosition() = 0;
+
     // TODO: remove this method.
     void declAppendf(const char* fmt, ...);
 
@@ -162,6 +167,7 @@
     // Shared GrGLSLFragmentBuilder interface.
     bool enableFeature(GLSLFeature) override;
     virtual SkString ensureCoords2D(const GrShaderVar&) override;
+    const char* fragmentPosition() override;
     const char* distanceVectorName() const override;
 
     // GrGLSLFPFragmentBuilder interface.
diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.cpp b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
index 2b8a3a7..c805825 100644
--- a/src/gpu/glsl/GrGLSLProgramBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
@@ -20,7 +20,7 @@
 
 GrGLSLProgramBuilder::GrGLSLProgramBuilder(const GrPipeline& pipeline,
                                            const GrPrimitiveProcessor& primProc,
-                                           GrProgramDesc* desc)
+                                           const GrProgramDesc& desc)
     : fVS(this)
     , fGS(this)
     , fFS(this)
@@ -348,7 +348,7 @@
 void GrGLSLProgramBuilder::emitFSOutputSwizzle(bool hasSecondaryOutput) {
     // Swizzle the fragment shader outputs if necessary.
     GrSwizzle swizzle;
-    swizzle.setFromKey(this->desc()->header().fOutputSwizzle);
+    swizzle.setFromKey(this->desc().header().fOutputSwizzle);
     if (swizzle != GrSwizzle::RGBA()) {
         fFS.codeAppendf("%s = %s.%s;", fFS.getPrimaryColorOutputName(),
                         fFS.getPrimaryColorOutputName(),
diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.h b/src/gpu/glsl/GrGLSLProgramBuilder.h
index 3074110..2dba90f 100644
--- a/src/gpu/glsl/GrGLSLProgramBuilder.h
+++ b/src/gpu/glsl/GrGLSLProgramBuilder.h
@@ -40,8 +40,8 @@
 
     const GrPrimitiveProcessor& primitiveProcessor() const { return fPrimProc; }
     const GrPipeline& pipeline() const { return fPipeline; }
-    GrProgramDesc* desc() { return fDesc; }
-    const GrProgramDesc::KeyHeader& header() const { return fDesc->header(); }
+    const GrProgramDesc& desc() const { return fDesc; }
+    const GrProgramDesc::KeyHeader& header() const { return fDesc.header(); }
 
     void appendUniformDecls(GrShaderFlags visibility, SkString*) const;
 
@@ -99,7 +99,7 @@
 
     const GrPipeline&           fPipeline;
     const GrPrimitiveProcessor& fPrimProc;
-    GrProgramDesc*              fDesc;
+    const GrProgramDesc&        fDesc;
 
     BuiltinUniformHandles fUniformHandles;
 
@@ -110,7 +110,7 @@
 protected:
     explicit GrGLSLProgramBuilder(const GrPipeline&,
                                   const GrPrimitiveProcessor&,
-                                  GrProgramDesc*);
+                                  const GrProgramDesc&);
 
     void addFeature(GrShaderFlags shaders, uint32_t featureBit, const char* extensionName);
 
diff --git a/src/gpu/glsl/GrGLSLVertexShaderBuilder.cpp b/src/gpu/glsl/GrGLSLVertexShaderBuilder.cpp
index 2aded89..f8302b3 100644
--- a/src/gpu/glsl/GrGLSLVertexShaderBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLVertexShaderBuilder.cpp
@@ -22,7 +22,7 @@
     fProgramBuilder->addRTAdjustmentUniform(kHigh_GrSLPrecision,
                                             fProgramBuilder->rtAdjustment(),
                                             &fRtAdjustName);
-    if (this->getProgramBuilder()->desc()->header().fSnapVerticesToPixelCenters) {
+    if (this->getProgramBuilder()->desc().header().fSnapVerticesToPixelCenters) {
         if (kVec3f_GrSLType == posVar.getType()) {
             const char* p = posVar.c_str();
             this->codeAppendf("{vec2 _posTmp = vec2(%s.x/%s.z, %s.y/%s.z);", p, p, p, p);
@@ -47,7 +47,7 @@
     }
     // We could have the GrGeometryProcessor do this, but its just easier to have it performed
     // here. If we ever need to set variable pointsize, then we can reinvestigate.
-    if (this->getProgramBuilder()->desc()->header().fHasPointSize) {
+    if (this->getProgramBuilder()->desc().header().fHasPointSize) {
         this->codeAppend("gl_PointSize = 1.0;");
     }
 }
diff --git a/src/gpu/glsl/GrGLSLXferProcessor.cpp b/src/gpu/glsl/GrGLSLXferProcessor.cpp
index 4101080..e269819 100644
--- a/src/gpu/glsl/GrGLSLXferProcessor.cpp
+++ b/src/gpu/glsl/GrGLSLXferProcessor.cpp
@@ -49,10 +49,11 @@
                                                   kDefault_GrSLPrecision,
                                                   "DstTextureCoordScale",
                                                   &dstCoordScaleName);
+        const char* fragPos = fragBuilder->fragmentPosition();
 
         fragBuilder->codeAppend("// Read color from copy of the destination.\n");
-        fragBuilder->codeAppendf("vec2 _dstTexCoord = (sk_FragCoord.xy - %s) * %s;",
-                                 dstTopLeftName, dstCoordScaleName);
+        fragBuilder->codeAppendf("vec2 _dstTexCoord = (%s.xy - %s) * %s;",
+                                 fragPos, dstTopLeftName, dstCoordScaleName);
 
         if (!topDown) {
             fragBuilder->codeAppend("_dstTexCoord.y = 1.0 - _dstTexCoord.y;");
diff --git a/src/gpu/ops/GrDrawOp.h b/src/gpu/ops/GrDrawOp.h
index 447a4dd..9e949b1 100644
--- a/src/gpu/ops/GrDrawOp.h
+++ b/src/gpu/ops/GrDrawOp.h
@@ -64,6 +64,9 @@
 
     bool installPipeline(const GrPipeline::CreateArgs&);
 
+    // TODO no GrPrimitiveProcessors yet read fragment position
+    bool willReadFragmentPosition() const { return false; }
+
 protected:
     static SkString DumpPipelineInfo(const GrPipeline& pipeline) {
         SkString string;
diff --git a/src/gpu/ops/GrPLSPathRenderer.cpp b/src/gpu/ops/GrPLSPathRenderer.cpp
index 80a4cda..835ce2c 100644
--- a/src/gpu/ops/GrPLSPathRenderer.cpp
+++ b/src/gpu/ops/GrPLSPathRenderer.cpp
@@ -344,7 +344,8 @@
             // gl_FragCoord. The oriented box positioning of the subsamples is of course not
             // optimal, but it greatly simplifies the math and this simplification is necessary for
             // performance reasons.
-            fsBuilder->codeAppendf("highp vec2 firstSample = sk_FragCoord.xy - vec2(0.25);");
+            fsBuilder->codeAppendf("highp vec2 firstSample = %s.xy - vec2(0.25);",
+                                   fsBuilder->fragmentPosition());
             fsBuilder->codeAppendf("highp vec2 delta1 = %s;", delta1.fsIn());
             fsBuilder->codeAppendf("highp vec2 delta2 = %s;", delta2.fsIn());
             fsBuilder->codeAppendf("highp vec2 delta3 = %s;", delta3.fsIn());
@@ -422,6 +423,7 @@
                                             kHigh_GrSLPrecision);
         fInWindings = &this->addVertexAttrib("inWindings", kInt_GrVertexAttribType,
                                              kLow_GrSLPrecision);
+        this->setWillReadFragmentPosition();
     }
 
     const Attribute* fInPosition;
@@ -540,7 +542,8 @@
             fsBuilder->codeAppend("highp vec2 uvIncY = uvdX * 0.1 + uvdY * 0.55;");
             fsBuilder->codeAppendf("highp vec2 uv = %s.xy - uvdX * 0.35 - uvdY * 0.25;",
                                    uv.fsIn());
-            fsBuilder->codeAppendf("highp vec2 firstSample = sk_FragCoord.xy - vec2(0.25);");
+            fsBuilder->codeAppendf("highp vec2 firstSample = %s.xy - vec2(0.25);",
+                                   fsBuilder->fragmentPosition());
             fsBuilder->codeAppendf("highp float d = dot(%s, (firstSample - %s).yx) * 2.0;",
                                    delta.fsIn(), ep1.fsIn());
             fsBuilder->codeAppendf("pls.windings[0] += %s(d, uv) ? %s : 0;", inQuadName.c_str(),
@@ -601,6 +604,7 @@
                                               kHigh_GrSLPrecision);
         fInWindings  = &this->addVertexAttrib("inWindings", kInt_GrVertexAttribType,
                                               kLow_GrSLPrecision);
+        this->setWillReadFragmentPosition();
     }
 
     const Attribute* fInPosition;
diff --git a/src/gpu/vk/GrVkPipelineStateBuilder.cpp b/src/gpu/vk/GrVkPipelineStateBuilder.cpp
index f7a6173..4125938 100644
--- a/src/gpu/vk/GrVkPipelineStateBuilder.cpp
+++ b/src/gpu/vk/GrVkPipelineStateBuilder.cpp
@@ -19,7 +19,7 @@
                                                                const GrStencilSettings& stencil,
                                                                const GrPrimitiveProcessor& primProc,
                                                                GrPrimitiveType primitiveType,
-                                                               GrVkPipelineState::Desc* desc,
+                                                               const GrVkPipelineState::Desc& desc,
                                                                const GrVkRenderPass& renderPass) {
     // create a builder.  This will be handed off to effects so they can use it to add
     // uniforms, varyings, textures, etc
@@ -39,7 +39,7 @@
 GrVkPipelineStateBuilder::GrVkPipelineStateBuilder(GrVkGpu* gpu,
                                                    const GrPipeline& pipeline,
                                                    const GrPrimitiveProcessor& primProc,
-                                                   GrProgramDesc* desc)
+                                                   const GrProgramDesc& desc)
     : INHERITED(pipeline, primProc, desc)
     , fGpu(gpu)
     , fVaryingHandler(this)
@@ -62,8 +62,7 @@
                                                     const GrGLSLShaderBuilder& builder,
                                                     VkShaderModule* shaderModule,
                                                     VkPipelineShaderStageCreateInfo* stageInfo,
-                                                    const SkSL::Program::Settings& settings,
-                                                    GrVkPipelineState::Desc* desc) {
+                                                    const SkSL::Program::Settings& settings) {
     SkString shaderString;
     for (int i = 0; i < builder.fCompilerStrings.count(); ++i) {
         if (builder.fCompilerStrings[i]) {
@@ -81,19 +80,13 @@
     if (inputs.fRTHeight) {
         this->addRTHeightUniform(SKSL_RTHEIGHT_NAME);
     }
-    if (!inputs.fFlipY) {
-        // the program doesn't care about the surface origin, set the key to zero to indicate that
-        // it doesn't matter
-        desc->setSurfaceOriginKey(0);
-        desc->finalize();
-    }
     return result;
 }
 
 GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrStencilSettings& stencil,
                                                       GrPrimitiveType primitiveType,
                                                       const GrVkRenderPass& renderPass,
-                                                      GrVkPipelineState::Desc* desc) {
+                                                      const GrVkPipelineState::Desc& desc) {
     VkDescriptorSetLayout dsLayout[2];
     VkPipelineLayout pipelineLayout;
     VkShaderModule vertShaderModule;
@@ -140,8 +133,7 @@
                                               fVS,
                                               &vertShaderModule,
                                               &shaderStageInfo[0],
-                                              settings,
-                                              desc));
+                                              settings));
 
     // TODO: geometry shader support.
     SkASSERT(!this->primitiveProcessor().willUseGeoShader());
@@ -150,8 +142,7 @@
                                               fFS,
                                               &fragShaderModule,
                                               &shaderStageInfo[1],
-                                              settings,
-                                              desc));
+                                              settings));
 
     GrVkPipeline* pipeline = resourceProvider.createPipeline(fPipeline,
                                                              stencil,
@@ -174,7 +165,7 @@
     }
 
     return new GrVkPipelineState(fGpu,
-                                 *desc,
+                                 desc,
                                  pipeline,
                                  pipelineLayout,
                                  samplerDSHandle,
diff --git a/src/gpu/vk/GrVkPipelineStateBuilder.h b/src/gpu/vk/GrVkPipelineStateBuilder.h
index ae59ec4..cf4a983 100644
--- a/src/gpu/vk/GrVkPipelineStateBuilder.h
+++ b/src/gpu/vk/GrVkPipelineStateBuilder.h
@@ -28,8 +28,6 @@
     *
     * The GrVkPipelineState implements what is specified in the GrPipeline and GrPrimitiveProcessor
     * as input. After successful generation, the builder result objects are available to be used.
-    * This function may modify the program key by setting the surface origin key to 0 (unspecified)
-    * if it turns out the program does not care about the surface origin.
     * @return true if generation was successful.
     */
     static GrVkPipelineState* CreatePipelineState(GrVkGpu*,
@@ -37,7 +35,7 @@
                                                   const GrStencilSettings&,
                                                   const GrPrimitiveProcessor&,
                                                   GrPrimitiveType,
-                                                  GrVkPipelineState::Desc*,
+                                                  const GrVkPipelineState::Desc&,
                                                   const GrVkRenderPass& renderPass);
 
     const GrCaps* caps() const override;
@@ -51,19 +49,18 @@
     GrVkPipelineStateBuilder(GrVkGpu*,
                              const GrPipeline&,
                              const GrPrimitiveProcessor&,
-                             GrProgramDesc*);
+                             const GrProgramDesc&);
 
     GrVkPipelineState* finalize(const GrStencilSettings&,
                                 GrPrimitiveType primitiveType,
                                 const GrVkRenderPass& renderPass,
-                                GrVkPipelineState::Desc*);
+                                const GrVkPipelineState::Desc&);
 
     bool createVkShaderModule(VkShaderStageFlagBits stage,
                               const GrGLSLShaderBuilder& builder,
                               VkShaderModule* shaderModule,
                               VkPipelineShaderStageCreateInfo* stageInfo,
-                              const SkSL::Program::Settings& settings,
-                              GrVkPipelineState::Desc* desc);
+                              const SkSL::Program::Settings& settings);
 
     GrGLSLUniformHandler* uniformHandler() override { return &fUniformHandler; }
     const GrGLSLUniformHandler* uniformHandler() const override { return &fUniformHandler; }
diff --git a/src/gpu/vk/GrVkPipelineStateCache.cpp b/src/gpu/vk/GrVkPipelineStateCache.cpp
index f8d77a9..7b935eb 100644
--- a/src/gpu/vk/GrVkPipelineStateCache.cpp
+++ b/src/gpu/vk/GrVkPipelineStateCache.cpp
@@ -101,13 +101,6 @@
 
     std::unique_ptr<Entry>* entry = fMap.find(desc);
     if (!entry) {
-        // Didn't find an origin-independent version, check with the specific origin
-        GrSurfaceOrigin origin = pipeline.getRenderTarget()->origin();
-        desc.setSurfaceOriginKey(GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin(origin));
-        desc.finalize();
-        entry = fMap.find(desc);
-    }
-    if (!entry) {
 #ifdef GR_PIPELINE_STATE_CACHE_STATS
         ++fCacheMisses;
 #endif
@@ -117,7 +110,7 @@
                                                           stencil,
                                                           primProc,
                                                           primitiveType,
-                                                          &desc,
+                                                          desc,
                                                           renderPass));
         if (nullptr == pipelineState) {
             return nullptr;
diff --git a/src/sksl/README b/src/sksl/README
index a4117ca..d18367f 100644
--- a/src/sksl/README
+++ b/src/sksl/README
@@ -33,10 +33,8 @@
   'do_something_else();', depending on whether that cap is enabled or not.
 * no #version statement is required, and will be ignored if present
 * the output color is sk_FragColor (do not declare it)
-* the fragment coordinate is sk_FragCoord, and is always relative to the upper
-  left.
 * lowp, mediump, and highp are always permitted (but will only be respected if 
-  you run on a device which supports them)
+  you run on a GLES device)
 * you do not need to include ".0" to make a number a float (meaning that
   "vec2(x, y) * 4" is perfectly legal in SkSL, unlike GLSL where it would often
   have to be expressed "vec2(x, y) * 4.0". There is no performance penalty for 
diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp
index ebb4c52..55d9d2c 100644
--- a/src/sksl/SkSLIRGenerator.cpp
+++ b/src/sksl/SkSLIRGenerator.cpp
@@ -624,14 +624,11 @@
                                                                             f->fFunctions));
         }
         case Symbol::kVariable_Kind: {
-            const Variable* var = (const Variable*) result;
-            if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN) {
-                fInputs.fFlipY = true;
-                if (fSettings->fFlipY &&
-                    (!fSettings->fCaps ||
-                     !fSettings->fCaps->fragCoordConventionsExtensionString())) {
-                    fInputs.fRTHeight = true;
-                }
+            Variable* var = (Variable*) result;
+            if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
+                fSettings->fFlipY &&
+                (!fSettings->fCaps || !fSettings->fCaps->fragCoordConventionsExtensionString())) {
+                fInputs.fRTHeight = true;
             }
             // default to kRead_RefKind; this will be corrected later if the variable is written to
             return std::unique_ptr<VariableReference>(new VariableReference(
diff --git a/src/sksl/ir/SkSLProgram.h b/src/sksl/ir/SkSLProgram.h
index e4a975b..6a73be6 100644
--- a/src/sksl/ir/SkSLProgram.h
+++ b/src/sksl/ir/SkSLProgram.h
@@ -27,8 +27,6 @@
 struct Program {
     struct Settings {
         const GrShaderCaps* fCaps = nullptr;
-        // if false, sk_FragCoord is exactly the same as gl_FragCoord. If true, the y coordinate
-        // must be flipped.
         bool fFlipY = false;
     };
 
@@ -36,17 +34,12 @@
         // if true, this program requires the render target height uniform to be defined
         bool fRTHeight;
 
-        // if true, this program must be recompiled if the flipY setting changes. If false, the
-        // program will compile to the same code regardless of the flipY setting.
-        bool fFlipY;
-
         void reset() {
             fRTHeight = false;
-            fFlipY = false;
         }
 
         bool isEmpty() {
-            return !fRTHeight && !fFlipY;
+            return !fRTHeight;
         }
     };
 
diff --git a/tests/ImageStorageTest.cpp b/tests/ImageStorageTest.cpp
index aa34831..20c9713 100644
--- a/tests/ImageStorageTest.cpp
+++ b/tests/ImageStorageTest.cpp
@@ -31,6 +31,7 @@
                 : INHERITED(kNone_OptimizationFlags)
                 , fImageStorageAccess(std::move(texture), kRead_GrIOType, mm, restrict) {
             this->initClassID<TestFP>();
+            this->setWillReadFragmentPosition();
             this->addImageStorageAccess(&fImageStorageAccess);
         }
 
@@ -50,7 +51,8 @@
                     const TestFP& tfp = args.fFp.cast<TestFP>();
                     GrGLSLFPFragmentBuilder* fb = args.fFragBuilder;
                     SkString imageLoadStr;
-                    fb->codeAppend("highp vec2 coord = sk_FragCoord.xy;");
+                    fb->codeAppendf("highp vec2 coord = %s.xy;",
+                                    args.fFragBuilder->fragmentPosition());
                     fb->appendImageStorageLoad(&imageLoadStr, args.fImageStorages[0],
                                                "ivec2(coord)");
                     if (GrPixelConfigIsSint(tfp.fImageStorageAccess.texture()->config())) {
diff --git a/tests/SkSLErrorTest.cpp b/tests/SkSLErrorTest.cpp
index c28dbbb..a33e6f1 100644
--- a/tests/SkSLErrorTest.cpp
+++ b/tests/SkSLErrorTest.cpp
@@ -418,13 +418,4 @@
                  "error: 1: division by zero\n1 error\n");
 }
 
-DEF_TEST(SkSLUnsupportedGLSLIdentifiers, r) {
-    test_failure(r,
-                 "void main() { float x = gl_FragCoord.x; };",
-                 "error: 1: unknown identifier 'gl_FragCoord'\n1 error\n");
-    test_failure(r,
-                 "void main() { float r = gl_FragColor.r; };",
-                 "error: 1: unknown identifier 'gl_FragColor'\n1 error\n");
-}
-
 #endif