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.