Add a robust "isinf" workaround for tessellation

When isinf is not supported, we simply add another instanced attrib that
tells the shader exactly what type of curve it's dealing with.

Bug: chromium:1220246
Change-Id: I3496de674ce8c7df205e3c40559ae89dc29488e1
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/429676
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/src/gpu/tessellate/GrPathInnerTriangulateOp.cpp b/src/gpu/tessellate/GrPathInnerTriangulateOp.cpp
index 0a69e0a..be9875a 100644
--- a/src/gpu/tessellate/GrPathInnerTriangulateOp.cpp
+++ b/src/gpu/tessellate/GrPathInnerTriangulateOp.cpp
@@ -29,10 +29,17 @@
     HullShader(const SkMatrix& viewMatrix, SkPMColor4f color, const GrShaderCaps& shaderCaps)
             : GrPathTessellationShader(kTessellate_HullShader_ClassID,
                                        GrPrimitiveType::kTriangleStrip, 0, viewMatrix, color) {
-        constexpr static Attribute kPtsAttribs[] = {
-                {"p01", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
-                {"p23", kFloat4_GrVertexAttribType, kFloat4_GrSLType}};
-        this->setInstanceAttributes(kPtsAttribs, SK_ARRAY_COUNT(kPtsAttribs));
+        fInstanceAttribs.emplace_back("p01", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
+        fInstanceAttribs.emplace_back("p23", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
+        if (!shaderCaps.infinitySupport()) {
+            // A conic curve is written out with p3=[w,Infinity], but GPUs that don't support
+            // infinity can't detect this. On these platforms we also write out an extra float with
+            // each patch that explicitly tells the shader what type of curve it is.
+            fInstanceAttribs.emplace_back("curveType", kFloat_GrVertexAttribType, kFloat_GrSLType);
+        }
+        this->setInstanceAttributes(fInstanceAttribs.data(), fInstanceAttribs.count());
+        SkASSERT(fInstanceAttribs.count() <= kMaxInstanceAttribCount);
+
         if (!shaderCaps.vertexIDSupport()) {
             constexpr static Attribute kVertexIdxAttrib("vertexidx", kFloat_GrVertexAttribType,
                                                         kFloat_GrSLType);
@@ -44,20 +51,39 @@
     const char* name() const final { return "tessellate_HullShader"; }
     void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const final {}
     GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const final;
+
+    constexpr static int kMaxInstanceAttribCount = 3;
+    SkSTArray<kMaxInstanceAttribCount, Attribute> fInstanceAttribs;
 };
 
 GrGLSLGeometryProcessor* HullShader::createGLSLInstance(const GrShaderCaps&) const {
     class Impl : public GrPathTessellationShader::Impl {
         void emitVertexCode(const GrShaderCaps& shaderCaps, const GrPathTessellationShader&,
                             GrGLSLVertexBuilder* v, GrGPArgs* gpArgs) override {
+            if (shaderCaps.infinitySupport()) {
+                v->insertFunction(R"(
+                bool is_conic_curve() { return isinf(p23.w); }
+                bool is_non_triangular_conic_curve() {
+                    // We consider a conic non-triangular as long as its weight isn't infinity.
+                    // NOTE: "isinf == false" works on Mac Radeon GLSL; "!isinf" can get the wrong
+                    // answer.
+                    return isinf(p23.z) == false;
+                })");
+            } else {
+                v->insertFunction(SkStringPrintf(R"(
+                bool is_conic_curve() { return curveType != %g; })", kCubicCurveType).c_str());
+                v->insertFunction(SkStringPrintf(R"(
+                bool is_non_triangular_conic_curve() {
+                    return curveType == %g;
+                })", kConicCurveType).c_str());
+            }
             v->codeAppend(R"(
             float2 p0=p01.xy, p1=p01.zw, p2=p23.xy, p3=p23.zw;
-            if (isinf(p3.y)) {  // Is the curve a conic?
+            if (is_conic_curve()) {
+                // Conics are 3 points, with the weight in p3.
                 float w = p3.x;
-                p3 = p2;
-                // A conic with w=Inf is an exact triangle.
-                // NOTE: "isinf == false" works on Mac Radeon GLSL. "!isinf" gets the wrong answer.
-                if (isinf(w) == false) {
+                p3 = p2;  // Duplicate the endpoint for shared code that also runs on cubics.
+                if (is_non_triangular_conic_curve()) {
                     // Convert the points to a trapeziodal hull that circumcscribes the conic.
                     float2 p1w = p1 * w;
                     float T = .51;  // Bias outward a bit to ensure we cover the outermost samples.