Fix issue where GrQuadPerEdgeAA GP doesn't emit coord transforms

This happens when all the FPs are sampled with explicit coords.

The GrGLSLGeometryProcessor::emitTransforms() helper required a valid VS
var for local coords even when all FPs use explicit coords and wouldn't
use a local coords var. It now only requires the variable be valid if
there is an FP with a coord transform that is not explicitly sampled.

Change-Id: I8008e854c738a17b207c82bb791e230ef4d5364d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/272459
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/src/gpu/glsl/GrGLSLGeometryProcessor.cpp b/src/gpu/glsl/GrGLSLGeometryProcessor.cpp
index 9fae493..0eba2cd 100644
--- a/src/gpu/glsl/GrGLSLGeometryProcessor.cpp
+++ b/src/gpu/glsl/GrGLSLGeometryProcessor.cpp
@@ -62,53 +62,68 @@
                                              const GrShaderVar& localCoordsVar,
                                              const SkMatrix& localMatrix,
                                              FPCoordTransformHandler* handler) {
-    SkASSERT(GrSLTypeIsFloatType(localCoordsVar.getType()));
-    SkASSERT(2 == GrSLTypeVecLength(localCoordsVar.getType()) ||
-             3 == GrSLTypeVecLength(localCoordsVar.getType()));
+    // We only require localCoordsVar to be valid if there is a coord transform that needs
+    // it. CTs on FPs called with explicit coords do not require a local coord.
+    auto getLocalCoords = [&localCoordsVar,
+                           localCoords = SkString(),
+                           localCoordLength = int()]() mutable {
+        if (localCoords.isEmpty()) {
+            localCoordLength = GrSLTypeVecLength(localCoordsVar.getType());
+            SkASSERT(GrSLTypeIsFloatType(localCoordsVar.getType()));
+            SkASSERT(localCoordLength == 2 || localCoordLength == 3);
+            if (localCoordLength == 3) {
+                localCoords = localCoordsVar.getName();
+            } else {
+                localCoords.printf("float3(%s, 1)", localCoordsVar.c_str());
+            }
+        }
+        return std::make_tuple(localCoords, localCoordLength);
+    };
 
-    bool threeComponentLocalCoords = 3 == GrSLTypeVecLength(localCoordsVar.getType());
-    SkString localCoords;
-    if (threeComponentLocalCoords) {
-        localCoords = localCoordsVar.getName();
-    } else {
-        localCoords.printf("float3(%s, 1)", localCoordsVar.c_str());
-    }
     for (int i = 0; *handler; ++*handler, ++i) {
         auto [coordTransform, fp] = handler->get();
-        if (coordTransform.isNoOp() && fp.isSampledWithExplicitCoords()) {
-            handler->omitCoordsForCurrCoordTransform();
-            fInstalledTransforms.push_back();
-        } else {
+        // Add uniform for coord transform matrix.
+        const char* matrixName;
+        if (!fp.isSampledWithExplicitCoords() || !coordTransform.isNoOp()) {
             SkString strUniName;
             strUniName.printf("CoordTransformMatrix_%d", i);
-            const char* uniName;
             fInstalledTransforms.push_back().fHandle = uniformHandler
                                                                ->addUniform(kVertex_GrShaderFlag,
                                                                             kFloat3x3_GrSLType,
                                                                             strUniName.c_str(),
-                                                                            &uniName)
+                                                                            &matrixName)
                                                                .toIndex();
-            GrSLType varyingType = kFloat2_GrSLType;
+        } else {
+            // Install a coord transform that will be skipped.
+            fInstalledTransforms.push_back();
+            handler->omitCoordsForCurrCoordTransform();
+            continue;
+        }
+
+        // Add varying if required and register varying and matrix uniform.
+        if (!fp.isSampledWithExplicitCoords()) {
+            auto [localCoordsStr, localCoordLength] = getLocalCoords();
+            GrGLSLVarying v(kFloat2_GrSLType);
             if (localMatrix.hasPerspective() || coordTransform.matrix().hasPerspective() ||
-                threeComponentLocalCoords) {
-                varyingType = kFloat3_GrSLType;
+                localCoordLength == 3) {
+                v = GrGLSLVarying(kFloat3_GrSLType);
             }
             SkString strVaryingName;
             strVaryingName.printf("TransformedCoords_%d", i);
-            GrGLSLVarying v(varyingType);
-            if (!fp.isSampledWithExplicitCoords()) {
-                varyingHandler->addVarying(strVaryingName.c_str(), &v);
+            varyingHandler->addVarying(strVaryingName.c_str(), &v);
 
-                if (kFloat2_GrSLType == varyingType) {
-                    vb->codeAppendf("%s = (%s * %s).xy;", v.vsOut(), uniName, localCoords.c_str());
-                } else {
-                    vb->codeAppendf("%s = %s * %s;", v.vsOut(), uniName, localCoords.c_str());
-                }
+            if (v.type() == kFloat2_GrSLType) {
+                vb->codeAppendf("%s = (%s * %s).xy;", v.vsOut(), matrixName,
+                                localCoordsStr.c_str());
+            } else {
+                vb->codeAppendf("%s = %s * %s;", v.vsOut(), matrixName, localCoordsStr.c_str());
             }
-            handler->specifyCoordsForCurrCoordTransform(
-                    SkString(uniName),
-                    fInstalledTransforms.back().fHandle,
-                    GrShaderVar(SkString(v.fsIn()), varyingType));
+            GrShaderVar fsVar(SkString(v.fsIn()), v.type(), GrShaderVar::kIn_TypeModifier);
+            handler->specifyCoordsForCurrCoordTransform(SkString(matrixName),
+                                                        fInstalledTransforms.back().fHandle, fsVar);
+        } else {
+            handler->specifyCoordsForCurrCoordTransform(SkString(matrixName),
+                                                        fInstalledTransforms.back().fHandle);
         }
     }
 }
diff --git a/src/gpu/glsl/GrGLSLPrimitiveProcessor.h b/src/gpu/glsl/GrGLSLPrimitiveProcessor.h
index f4ca1f3..b4d3935 100644
--- a/src/gpu/glsl/GrGLSLPrimitiveProcessor.h
+++ b/src/gpu/glsl/GrGLSLPrimitiveProcessor.h
@@ -30,10 +30,12 @@
     struct TransformVar {
         TransformVar() = default;
 
-        TransformVar(SkString matrixCode, UniformHandle uniformMatrix, GrShaderVar varyingPoint)
-            : fMatrixCode(std::move(matrixCode))
-            , fUniformMatrix(uniformMatrix)
-            , fVaryingPoint(varyingPoint) {}
+        TransformVar(SkString matrixCode,
+                     UniformHandle uniformMatrix,
+                     GrShaderVar varyingPoint = {})
+                : fMatrixCode(std::move(matrixCode))
+                , fUniformMatrix(uniformMatrix)
+                , fVaryingPoint(varyingPoint) {}
 
         // a string of SkSL code which resolves to the transformation matrix
         SkString fMatrixCode;
diff --git a/src/gpu/ops/GrQuadPerEdgeAA.cpp b/src/gpu/ops/GrQuadPerEdgeAA.cpp
index 66b84a9..ee2a694 100644
--- a/src/gpu/ops/GrQuadPerEdgeAA.cpp
+++ b/src/gpu/ops/GrQuadPerEdgeAA.cpp
@@ -575,9 +575,7 @@
             void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& proc,
                          const CoordTransformRange& transformRange) override {
                 const auto& gp = proc.cast<QuadPerEdgeAAGeometryProcessor>();
-                if (gp.fLocalCoord.isInitialized()) {
-                    this->setTransformDataHelper(SkMatrix::I(), pdman, transformRange);
-                }
+                this->setTransformDataHelper(SkMatrix::I(), pdman, transformRange);
                 fTextureColorSpaceXformHelper.setData(pdman, gp.fTextureColorSpaceXform.get());
             }
 
@@ -610,17 +608,18 @@
                     gpArgs->fPositionVar = gp.fPosition.asShaderVar();
                 }
 
-                // Handle local coordinates if they exist
-                if (gp.fLocalCoord.isInitialized()) {
-                    // NOTE: If the only usage of local coordinates is for the inline texture fetch
-                    // before FPs, then there are no registered FPCoordTransforms and this ends up
-                    // emitting nothing, so there isn't a duplication of local coordinates
-                    this->emitTransforms(args.fVertBuilder,
-                                         args.fVaryingHandler,
-                                         args.fUniformHandler,
-                                         gp.fLocalCoord.asShaderVar(),
-                                         args.fFPCoordTransformHandler);
-                }
+                // Handle local coordinates if they exist. This is required even when the op
+                // isn't providing local coords but there are FPs called with explicit coords.
+                // It installs the uniforms that transform their coordinates in the fragment
+                // shader.
+                // NOTE: If the only usage of local coordinates is for the inline texture fetch
+                // before FPs, then there are no registered FPCoordTransforms and this ends up
+                // emitting nothing, so there isn't a duplication of local coordinates
+                this->emitTransforms(args.fVertBuilder,
+                                     args.fVaryingHandler,
+                                     args.fUniformHandler,
+                                     gp.fLocalCoord.asShaderVar(),
+                                     args.fFPCoordTransformHandler);
 
                 // Solid color before any texturing gets modulated in
                 if (gp.fColor.isInitialized()) {