Finish sk_VertexID workarounds for tessellated fills

At this point all tessellated fills are capable of drawing when
sk_VertexID is not supported.

Bug: chromium:1220246
Change-Id: Icb1deef1558b09d45fadcaa4092023bf0931e398
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/423156
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/src/gpu/tessellate/GrPathInnerTriangulateOp.cpp b/src/gpu/tessellate/GrPathInnerTriangulateOp.cpp
index e1cff48..376eaf2 100644
--- a/src/gpu/tessellate/GrPathInnerTriangulateOp.cpp
+++ b/src/gpu/tessellate/GrPathInnerTriangulateOp.cpp
@@ -12,6 +12,7 @@
 #include "src/gpu/GrInnerFanTriangulator.h"
 #include "src/gpu/GrOpFlushState.h"
 #include "src/gpu/GrRecordingContextPriv.h"
+#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
 #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
 #include "src/gpu/tessellate/GrPathCurveTessellator.h"
 #include "src/gpu/tessellate/GrTessellationPathRenderer.h"
@@ -25,13 +26,18 @@
 // for the "cover" pass after the curves have been fully stencilled.
 class HullShader : public GrPathTessellationShader {
 public:
-    HullShader(const SkMatrix& viewMatrix, SkPMColor4f color)
+    HullShader(const SkMatrix& viewMatrix, SkPMColor4f color, const GrShaderCaps& shaderCaps)
             : GrPathTessellationShader(kTessellate_HullShader_ClassID,
                                        GrPrimitiveType::kTriangleStrip, 0, viewMatrix, color) {
         constexpr static Attribute kPtsAttribs[] = {
                 {"input_points_0_1", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
                 {"input_points_2_3", kFloat4_GrVertexAttribType, kFloat4_GrSLType}};
         this->setInstanceAttributes(kPtsAttribs, SK_ARRAY_COUNT(kPtsAttribs));
+        if (!shaderCaps.vertexIDSupport()) {
+            constexpr static Attribute kVertexIdxAttrib("vertexidx", kFloat_GrVertexAttribType,
+                                                        kFloat_GrSLType);
+            this->setVertexAttributes(&kVertexIdxAttrib, 1);
+        }
     }
 
 private:
@@ -75,30 +81,47 @@
                     P[2] = P[3];  // swap(P2, P3)
                     P[3] = tmp;
                 }
+            })");
+
+            if (v->getProgramBuilder()->caps()->shaderCaps()->vertexIDSupport()) {
+                // If we don't have sk_VertexID support then "vertexidx" already came in as a
+                // vertex attrib.
+                v->codeAppend(R"(
+                // sk_VertexID comes in fan order. Convert to strip order.
+                int vertexidx = sk_VertexID;
+                vertexidx ^= vertexidx >> 1;)");
             }
 
-            // sk_VertexID comes in fan order. Convert to strip order.
-            int vertexidx = sk_VertexID;
-            vertexidx ^= vertexidx >> 1;
-
+            v->codeAppend(R"(
             // Find the "turn direction" of each corner and net turn direction.
             float vertexdir = 0;
             float netdir = 0;
+            float2 prev, next;
+            float dir;
+            float2 localcoord;
+            float2 nextcoord;)");
+
             for (int i = 0; i < 4; ++i) {
-                float2 prev = P[i] - P[(i + 3) & 3], next = P[(i + 1) & 3] - P[i];
-                float dir = sign(determinant(float2x2(prev, next)));
-                if (i == vertexidx) {
+                v->codeAppendf(R"(
+                prev = P[%i] - P[%i];)", i, (i + 3) % 4);
+                v->codeAppendf(R"(
+                next = P[%i] - P[%i];)", (i + 1) % 4, i);
+                v->codeAppendf(R"(
+                dir = sign(determinant(float2x2(prev, next)));
+                if (vertexidx == %i) {
                     vertexdir = dir;
+                    localcoord = P[%i];
+                    nextcoord = P[%i];
                 }
-                netdir += dir;
+                netdir += dir;)", i, i, (i + 1) % 4);
             }
 
+            v->codeAppend(R"(
             // Remove the non-convex vertex, if any.
             if (vertexdir != sign(netdir)) {
-                vertexidx = (vertexidx + 1) & 3;
+                localcoord = nextcoord;
             }
 
-            float2 localcoord = P[vertexidx];
             float2 vertexpos = AFFINE_MATRIX * localcoord + TRANSLATE;)");
             gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localcoord");
             gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos");
@@ -300,7 +323,8 @@
         // by curves. We issue a final cover pass over the curves by drawing their convex hulls.
         // This will fill in any remaining samples and reset the stencil values back to zero.
         SkASSERT(fTessellator);
-        auto* hullShader = args.fArena->make<HullShader>(fViewMatrix, fColor);
+        auto* hullShader = args.fArena->make<HullShader>(fViewMatrix, fColor,
+                                                         *args.fCaps->shaderCaps());
         fCoverHullsProgram = GrTessellationShader::MakeProgram(
                 args, hullShader, fPipelineForFills,
                 GrPathTessellationShader::TestAndResetStencilSettings());
@@ -327,6 +351,8 @@
     }
 }
 
+GR_DECLARE_STATIC_UNIQUE_KEY(gHullVertexBufferKey);
+
 void GrPathInnerTriangulateOp::onPrepare(GrOpFlushState* flushState) {
     if (!fFanTriangulator) {
         this->prePreparePrograms({flushState->allocator(), flushState->writeView(),
@@ -347,6 +373,16 @@
         // Must be called after polysToTriangles() in order for fFanBreadcrumbs to be complete.
         fTessellator->prepare(flushState, this->bounds(), fPath, &fFanBreadcrumbs);
     }
+
+    if (!flushState->caps().shaderCaps()->vertexIDSupport()) {
+        constexpr static float kStripOrderIDs[4] = {0, 1, 3, 2};
+
+        GR_DEFINE_STATIC_UNIQUE_KEY(gHullVertexBufferKey);
+
+        fHullVertexBufferIfNoIDSupport = flushState->resourceProvider()->findOrMakeStaticBuffer(
+                GrGpuBufferType::kVertex, sizeof(kStripOrderIDs), kStripOrderIDs,
+                gHullVertexBufferKey);
+    }
 }
 
 void GrPathInnerTriangulateOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
@@ -371,6 +407,6 @@
         SkASSERT(fTessellator);
         flushState->bindPipelineAndScissorClip(*fCoverHullsProgram, this->bounds());
         flushState->bindTextures(fCoverHullsProgram->geomProc(), nullptr, *fPipelineForFills);
-        fTessellator->drawHullInstances(flushState);
+        fTessellator->drawHullInstances(flushState, fHullVertexBufferIfNoIDSupport);
     }
 }