Add a workaround for inaccurate interpolants on Adreno 3xx.

Also ensure that sk_FragCoord x and y values are at pixel centers when
workaround is used.

Change-Id: Ib748af9e496a406a50622e00e96e1346cbb5eb26
Reviewed-on: https://skia-review.googlesource.com/97064
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/ops/GrTextureOp.cpp b/src/gpu/ops/GrTextureOp.cpp
index 7c4842f..46d2630 100644
--- a/src/gpu/ops/GrTextureOp.cpp
+++ b/src/gpu/ops/GrTextureOp.cpp
@@ -168,22 +168,51 @@
                 }
                 args.fFragBuilder->codeAppend(";");
                 if (textureGP.usesCoverageEdgeAA()) {
-                    GrGLSLVarying aaDistVarying(kFloat4_GrSLType,
-                                                GrGLSLVarying::Scope::kVertToFrag);
-                    args.fVaryingHandler->addVarying("aaDists", &aaDistVarying);
-                    args.fVertBuilder->codeAppendf(
-                            R"(%s = float4(dot(aaEdge0.xy, %s.xy) + aaEdge0.z,
-                                           dot(aaEdge1.xy, %s.xy) + aaEdge1.z,
-                                           dot(aaEdge2.xy, %s.xy) + aaEdge2.z,
-                                           dot(aaEdge3.xy, %s.xy) + aaEdge3.z);)",
-                            aaDistVarying.vsOut(), textureGP.fPositions.fName,
-                            textureGP.fPositions.fName, textureGP.fPositions.fName,
-                            textureGP.fPositions.fName);
-
+                    const char* aaDistName = nullptr;
+                    // When interpolation is innacurate we perform the evaluation of the edge
+                    // equations in the fragment shader rather than interpolating values computed
+                    // in the vertex shader.
+                    if (!args.fShaderCaps->interpolantsAreInaccurate()) {
+                        GrGLSLVarying aaDistVarying(kFloat4_GrSLType,
+                                                    GrGLSLVarying::Scope::kVertToFrag);
+                        args.fVaryingHandler->addVarying("aaDists", &aaDistVarying);
+                        args.fVertBuilder->codeAppendf(
+                                R"(%s = float4(dot(aaEdge0.xy, %s.xy) + aaEdge0.z,
+                                               dot(aaEdge1.xy, %s.xy) + aaEdge1.z,
+                                               dot(aaEdge2.xy, %s.xy) + aaEdge2.z,
+                                               dot(aaEdge3.xy, %s.xy) + aaEdge3.z);)",
+                                aaDistVarying.vsOut(), textureGP.fPositions.fName,
+                                textureGP.fPositions.fName, textureGP.fPositions.fName,
+                                textureGP.fPositions.fName);
+                        aaDistName = aaDistVarying.fsIn();
+                    } else {
+                        GrGLSLVarying aaEdgeVarying[4]{
+                                {kFloat3_GrSLType, GrGLSLVarying::Scope::kVertToFrag},
+                                {kFloat3_GrSLType, GrGLSLVarying::Scope::kVertToFrag},
+                                {kFloat3_GrSLType, GrGLSLVarying::Scope::kVertToFrag},
+                                {kFloat3_GrSLType, GrGLSLVarying::Scope::kVertToFrag}
+                        };
+                        for (int i = 0; i < 4; ++i) {
+                            SkString name;
+                            name.printf("aaEdge%d", i);
+                            args.fVaryingHandler->addVarying(name.c_str(), &aaEdgeVarying[i]);
+                            args.fVertBuilder->codeAppendf(
+                                    "%s = aaEdge%d;", aaEdgeVarying[i].vsOut(), i);
+                        }
+                        args.fFragBuilder->codeAppendf(
+                                R"(float4 aaDists = float4(dot(%s.xy, sk_FragCoord.xy) + %s.z,
+                                                           dot(%s.xy, sk_FragCoord.xy) + %s.z,
+                                                           dot(%s.xy, sk_FragCoord.xy) + %s.z,
+                                                           dot(%s.xy, sk_FragCoord.xy) + %s.z);)",
+                        aaEdgeVarying[0].fsIn(), aaEdgeVarying[0].fsIn(),
+                        aaEdgeVarying[1].fsIn(), aaEdgeVarying[1].fsIn(),
+                        aaEdgeVarying[2].fsIn(), aaEdgeVarying[2].fsIn(),
+                        aaEdgeVarying[3].fsIn(), aaEdgeVarying[3].fsIn());
+                        aaDistName = "aaDists";
+                    }
                     args.fFragBuilder->codeAppendf(
                             "float mindist = min(min(%s.x, %s.y), min(%s.z, %s.w));",
-                            aaDistVarying.fsIn(), aaDistVarying.fsIn(), aaDistVarying.fsIn(),
-                            aaDistVarying.fsIn());
+                            aaDistName, aaDistName, aaDistName, aaDistName);
                     args.fFragBuilder->codeAppendf("%s = float4(clamp(mindist, 0, 1));",
                                                    args.fOutputCoverage);
                 } else {