Start disentangling tessellation from pipeline creation in GrTextureOp

The idea/dream here is to be able to (optionally) tessellate in onPrePrepareDraws and then just copy the prePrepared data into the vertex buffer.

Change -Id: I899eebce36dc9516bfc4b0fce5e657458167c772

Change-Id: I899eebce36dc9516bfc4b0fce5e657458167c772
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/248804
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/ops/GrQuadPerEdgeAA.cpp b/src/gpu/ops/GrQuadPerEdgeAA.cpp
index ad060dd..27bd00e 100644
--- a/src/gpu/ops/GrQuadPerEdgeAA.cpp
+++ b/src/gpu/ops/GrQuadPerEdgeAA.cpp
@@ -477,32 +477,10 @@
     return coverage;
 }
 
-enum class CoverageMode {
-    kNone,
-    kWithPosition,
-    kWithColor
-};
-
-static CoverageMode get_mode_for_spec(const GrQuadPerEdgeAA::VertexSpec& spec) {
-    if (spec.usesCoverageAA()) {
-        if (spec.compatibleWithCoverageAsAlpha() && spec.hasVertexColors() &&
-            !spec.requiresGeometryDomain()) {
-            // Using a geometric domain acts as a second source of coverage and folding the original
-            // coverage into color makes it impossible to apply the color's alpha to the geometric
-            // domain's coverage when the original shape is clipped.
-            return CoverageMode::kWithColor;
-        } else {
-            return CoverageMode::kWithPosition;
-        }
-    } else {
-        return CoverageMode::kNone;
-    }
-}
-
 // Writes four vertices in triangle strip order, including the additional data for local
 // coordinates, geometry + texture domains, color, and coverage as needed to satisfy the vertex spec
 static void write_quad(GrVertexWriter* vb, const GrQuadPerEdgeAA::VertexSpec& spec,
-                       CoverageMode mode, const V4f& coverage, SkPMColor4f color4f,
+                       GrQuadPerEdgeAA::CoverageMode mode, const V4f& coverage, SkPMColor4f color4f,
                        const SkRect& geomDomain, const SkRect& texDomain, const Vertices& quad) {
     static constexpr auto If = GrVertexWriter::If<float>;
 
@@ -511,13 +489,14 @@
         // perspective and coverage mode.
         vb->write(quad.fX[i], quad.fY[i],
                   If(spec.deviceQuadType() == GrQuad::Type::kPerspective, quad.fW[i]),
-                  If(mode == CoverageMode::kWithPosition, coverage[i]));
+                  If(mode == GrQuadPerEdgeAA::CoverageMode::kWithPosition, coverage[i]));
 
         // save color
         if (spec.hasVertexColors()) {
             bool wide = spec.colorType() == GrQuadPerEdgeAA::ColorType::kHalf;
             vb->write(GrVertexColor(
-                    color4f * (mode == CoverageMode::kWithColor ? coverage[i] : 1.f), wide));
+                color4f * (mode == GrQuadPerEdgeAA::CoverageMode::kWithColor ? coverage[i] : 1.f),
+                wide));
         }
 
         // save local position
@@ -584,7 +563,7 @@
     SkASSERT(deviceQuad.quadType() <= spec.deviceQuadType());
     SkASSERT(!spec.hasLocalCoords() || localQuad.quadType() <= spec.localQuadType());
 
-    CoverageMode mode = get_mode_for_spec(spec);
+    GrQuadPerEdgeAA::CoverageMode mode = spec.coverageMode();
 
     // Load position data into V4fs (always x, y, and load w to avoid branching down the road)
     Vertices outer;
@@ -685,6 +664,63 @@
     return fHasLocalCoords ? (this->localQuadType() == GrQuad::Type::kPerspective ? 3 : 2) : 0;
 }
 
+CoverageMode VertexSpec::coverageMode() const {
+    if (this->usesCoverageAA()) {
+        if (this->compatibleWithCoverageAsAlpha() && this->hasVertexColors() &&
+            !this->requiresGeometryDomain()) {
+            // Using a geometric domain acts as a second source of coverage and folding
+            // the original coverage into color makes it impossible to apply the color's
+            // alpha to the geometric domain's coverage when the original shape is clipped.
+            return CoverageMode::kWithColor;
+        } else {
+            return CoverageMode::kWithPosition;
+        }
+    } else {
+        return CoverageMode::kNone;
+    }
+}
+
+// This needs to stay in sync w/ QuadPerEdgeAAGeometryProcessor::initializeAttrs
+size_t VertexSpec::vertexSize() const {
+    bool needsPerspective = (this->deviceDimensionality() == 3);
+    CoverageMode coverageMode = this->coverageMode();
+
+    size_t count = 0;
+
+    if (coverageMode == CoverageMode::kWithPosition) {
+        if (needsPerspective) {
+            count += GrVertexAttribTypeSize(kFloat4_GrVertexAttribType);
+        } else {
+            count += GrVertexAttribTypeSize(kFloat2_GrVertexAttribType) +
+                     GrVertexAttribTypeSize(kFloat_GrVertexAttribType);
+        }
+    } else {
+        if (needsPerspective) {
+            count += GrVertexAttribTypeSize(kFloat3_GrVertexAttribType);
+        } else {
+            count += GrVertexAttribTypeSize(kFloat2_GrVertexAttribType);
+        }
+    }
+
+    if (this->requiresGeometryDomain()) {
+        count += GrVertexAttribTypeSize(kFloat4_GrVertexAttribType);
+    }
+
+    count += this->localDimensionality() * GrVertexAttribTypeSize(kFloat_GrVertexAttribType);
+
+    if (ColorType::kByte == this->colorType()) {
+        count += GrVertexAttribTypeSize(kUByte4_norm_GrVertexAttribType);
+    } else if (ColorType::kHalf == this->colorType()) {
+        count += GrVertexAttribTypeSize(kHalf4_GrVertexAttribType);
+    }
+
+    if (this->hasDomain()) {
+        count += GrVertexAttribTypeSize(kFloat4_GrVertexAttribType);
+    }
+
+    return count;
+}
+
 ////////////////// Geometry Processor Implementation
 
 class QuadPerEdgeAAGeometryProcessor : public GrGeometryProcessor {
@@ -918,9 +954,10 @@
         this->setTextureSamplerCnt(1);
     }
 
+    // This needs to stay in sync w/ VertexSpec::vertexSize
     void initializeAttrs(const VertexSpec& spec) {
         fNeedsPerspective = spec.deviceDimensionality() == 3;
-        fCoverageMode = get_mode_for_spec(spec);
+        fCoverageMode = spec.coverageMode();
 
         if (fCoverageMode == CoverageMode::kWithPosition) {
             if (fNeedsPerspective) {