Reland "Reland "Reland "Use conics with w=Inf to describe triangles for the tessellator"""
This is a reland of 99e6f0fcfb44ab9de58d927b30dd6ddd16dd861e
Original change's description:
> Reland "Reland "Use conics with w=Inf to describe triangles for the tessellator""
>
> This is a reland of ff515df5b4549673b4c7f04e41c62f2bd1d4ddc3
>
> Original change's description:
> > Reland "Use conics with w=Inf to describe triangles for the tessellator"
> >
> > This is a reland of 84f70136abfb0af3cddf2ec7e8e2405f154916b0
> >
> > Original change's description:
> > > Use conics with w=Inf to describe triangles for the tessellator
> > >
> > > Previously, only the indirect tessellator could draw triangles, and
> > > only with special index data. Using conics with w=Inf will allow us to
> > > draw triangles with the hardware tessellator as well, in addition to
> > > being able to wean the indirect tessellator off an index buffer.
> > >
> > > Bug: skia:10419
> > > Bug: chromium:1202607
> > > Change-Id: I180af9cb5410c0e0bb25a2edcfb01e17d4a2f590
> > > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/406977
> > > Commit-Queue: Chris Dalton <csmartdalton@google.com>
> > > Reviewed-by: Michael Ludwig <michaelludwig@google.com>
> >
> > Bug: skia:10419
> > Bug: chromium:1202607
> > Change-Id: Ic12b10eaa60fddd212c66757bf7100749ee58d49
> > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/408096
> > Reviewed-by: Robert Phillips <robertphillips@google.com>
> > Commit-Queue: Chris Dalton <csmartdalton@google.com>
>
> TBR=robertphillips@google.com
>
> Bug: skia:10419
> Bug: chromium:1202607
> Change-Id: Id1f8dfa133f446b9f30f2bf8493a3a7b99072e59
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/408616
> Reviewed-by: Chris Dalton <csmartdalton@google.com>
> Commit-Queue: Chris Dalton <csmartdalton@google.com>
Bug: skia:10419
Bug: chromium:1202607
Change-Id: Iadc60aae395146d5da5bfaa725b980c963e6bead
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/408817
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/bench/TessellateBench.cpp b/bench/TessellateBench.cpp
index e4a3d4a..032cd81 100644
--- a/bench/TessellateBench.cpp
+++ b/bench/TessellateBench.cpp
@@ -200,7 +200,8 @@
int baseVertex;
GrVertexWriter vertexWriter = static_cast<SkPoint*>(fTarget->makeVertexSpace(
sizeof(SkPoint), kNumCubicsInChalkboard, &buffer, &baseVertex));
- GrMiddleOutPolygonTriangulator::WritePathInnerFan(&vertexWriter, 3, fPath);
+ GrMiddleOutPolygonTriangulator::WritePathInnerFan(
+ &vertexWriter, GrMiddleOutPolygonTriangulator::OutputType::kTriangles, fPath);
}
using PathStrokeList = GrStrokeTessellator::PathStrokeList;
diff --git a/src/gpu/GrVertexWriter.h b/src/gpu/GrVertexWriter.h
index 4ca8b6b..110b351 100644
--- a/src/gpu/GrVertexWriter.h
+++ b/src/gpu/GrVertexWriter.h
@@ -23,6 +23,8 @@
* thereof.
*/
struct GrVertexWriter {
+ constexpr static uint32_t kIEEE_32_infinity = 0x7f800000;
+
void* fPtr;
GrVertexWriter() = default;
diff --git a/src/gpu/tessellate/GrFillPathShader.cpp b/src/gpu/tessellate/GrFillPathShader.cpp
index 6274845..71fd72d 100644
--- a/src/gpu/tessellate/GrFillPathShader.cpp
+++ b/src/gpu/tessellate/GrFillPathShader.cpp
@@ -72,16 +72,20 @@
GrGLSLUniformHandler* uniformHandler) const {
v->codeAppend(R"(
float4x2 P = float4x2(input_points_0_1, input_points_2_3);
- if (isinf(P[3].y)) {
- // This curve is actually a conic. Convert the control points to a trapeziodal hull
- // that circumcscribes the conic.
+ if (isinf(P[3].y)) { // Is the curve a conic?
float w = P[3].x;
- float2 p1w = P[1] * w;
- float T = .51; // Bias outward a bit to ensure we cover the outermost samples.
- float2 c1 = mix(P[0], p1w, T);
- float2 c2 = mix(P[2], p1w, T);
- float iw = 1 / mix(1, w, T);
- P = float4x2(P[0], c1 * iw, c2 * iw, P[2]);
+ if (isinf(w)) {
+ // A conic with w=Inf is an exact triangle.
+ P = float4x2(P[0], P[1], P[2], P[2]);
+ } else {
+ // Convert the control points to a trapeziodal hull that circumcscribes the conic.
+ float2 p1w = P[1] * w;
+ float T = .51; // Bias outward a bit to ensure we cover the outermost samples.
+ float2 c1 = mix(P[0], p1w, T);
+ float2 c2 = mix(P[2], p1w, T);
+ float iw = 1 / mix(1, w, T);
+ P = float4x2(P[0], c1 * iw, c2 * iw, P[2]);
+ }
}
// Translate the points to v0..3 where v0=0.
diff --git a/src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h b/src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h
index 6129dbb..79b80b3 100644
--- a/src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h
+++ b/src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h
@@ -43,10 +43,15 @@
// recursion, we manipulate an O(log N) stack to determine the correct middle-out triangulation.
class GrMiddleOutPolygonTriangulator {
public:
- GrMiddleOutPolygonTriangulator(GrVertexWriter* vertexWriter, int perTriangleVertexAdvance,
+ enum class OutputType : bool {
+ kTriangles, // Output 3-vertex triangles.
+ kConicsWithInfiniteWeight // Output 4-vertex conics with w=Inf.
+ };
+
+ GrMiddleOutPolygonTriangulator(GrVertexWriter* vertexWriter, OutputType outputType,
int maxPushVertexCalls)
: fVertexWriter(vertexWriter)
- , fPaddingLength(std::max(perTriangleVertexAdvance - 3, 0)) {
+ , fOutputType(outputType) {
// Determine the deepest our stack can ever go.
int maxStackDepth = SkNextLog2(maxPushVertexCalls) + 1;
if (maxStackDepth > kStackPreallocCount) {
@@ -118,10 +123,9 @@
SkASSERT(fTop->fVertexIdxDelta == 0); // Ensure we are in the initial stack state.
}
- static int WritePathInnerFan(GrVertexWriter* vertexWriter, int perTriangleVertexAdvance,
+ static int WritePathInnerFan(GrVertexWriter* vertexWriter, OutputType outputType,
const SkPath& path) {
- GrMiddleOutPolygonTriangulator middleOut(vertexWriter, perTriangleVertexAdvance,
- path.countVerbs());
+ GrMiddleOutPolygonTriangulator middleOut(vertexWriter, outputType, path.countVerbs());
for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
switch (verb) {
case SkPathVerb::kMove:
@@ -165,8 +169,9 @@
SkASSERT(fTop > fVertexStack); // We should never pop the starting point.
--fTop;
fVertexWriter->write(fTop[0].fPoint, fTop[1].fPoint, lastPt);
- if (fPaddingLength) {
- fVertexWriter->fill(SkPoint{0,0}, fPaddingLength);
+ if (fOutputType == OutputType::kConicsWithInfiniteWeight) {
+ // Output a 4-point conic with w=Inf.
+ fVertexWriter->fill(GrVertexWriter::kIEEE_32_infinity, 2);
}
}
@@ -175,8 +180,8 @@
SkDEBUGCODE(int fStackAllocCount;)
StackVertex* fTop;
GrVertexWriter* fVertexWriter;
- int fPaddingLength;
int fTotalClosedTriangleCount = 0;
+ OutputType fOutputType;
};
#endif
diff --git a/src/gpu/tessellate/GrPathShader.h b/src/gpu/tessellate/GrPathShader.h
index 345cf54..2784112 100644
--- a/src/gpu/tessellate/GrPathShader.h
+++ b/src/gpu/tessellate/GrPathShader.h
@@ -15,7 +15,6 @@
#include "src/gpu/GrProgramInfo.h"
#include "src/gpu/GrVertexWriter.h"
#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
-#include <limits>
// This is a common base class for shaders in the GPU tessellator.
class GrPathShader : public GrGeometryProcessor {
@@ -58,7 +57,7 @@
// Write out the 3 conic points to patch[0..2], the weight to patch[3].x, and then set
// patch[3].y as NaN to flag this patch as a conic.
writer->writeArray(pts, 3);
- writer->write(w, std::numeric_limits<float>::infinity());
+ writer->write(w, GrVertexWriter::kIEEE_32_infinity);
}
static void WriteConicPatch(const SkPoint pts[3], float w, SkPoint patch[4]) {
GrVertexWriter writer(patch);
diff --git a/src/gpu/tessellate/GrPathStencilFillOp.cpp b/src/gpu/tessellate/GrPathStencilFillOp.cpp
index 77b6c07..1e3d7cd 100644
--- a/src/gpu/tessellate/GrPathStencilFillOp.cpp
+++ b/src/gpu/tessellate/GrPathStencilFillOp.cpp
@@ -145,7 +145,8 @@
int maxFanTriangles = fPath.countVerbs() - 2; // n - 2 triangles make an n-gon.
GrVertexWriter triangleVertexWriter = vertexAlloc.lock<SkPoint>(maxFanTriangles * 3);
fFanVertexCount = GrMiddleOutPolygonTriangulator::WritePathInnerFan(
- &triangleVertexWriter, 3/*perTriangleVertexAdvance*/, fPath) * 3;
+ &triangleVertexWriter, GrMiddleOutPolygonTriangulator::OutputType::kTriangles,
+ fPath) * 3;
SkASSERT(fFanVertexCount <= maxFanTriangles * 3);
vertexAlloc.unlock(fFanVertexCount);
}
diff --git a/src/gpu/tessellate/GrPathTessellator.cpp b/src/gpu/tessellate/GrPathTessellator.cpp
index 586eb42..722cd41 100644
--- a/src/gpu/tessellate/GrPathTessellator.cpp
+++ b/src/gpu/tessellate/GrPathTessellator.cpp
@@ -73,11 +73,13 @@
return;
}
- // Write out any triangles at the beginning of the cubic data.
+ // Write out any triangles at the beginning of the cubic data. Since this shader draws curves,
+ // output the triangles as conics with w=infinity (which is equivalent to a triangle).
int numTrianglesAtBeginningOfData = 0;
if (fDrawInnerFan) {
numTrianglesAtBeginningOfData = GrMiddleOutPolygonTriangulator::WritePathInnerFan(
- &instanceWriter, 4/*stride*/, path);
+ &instanceWriter,
+ GrMiddleOutPolygonTriangulator::OutputType::kConicsWithInfiniteWeight, path);
}
if (breadcrumbTriangleList) {
SkDEBUGCODE(int count = 0;)
@@ -91,8 +93,8 @@
continue;
}
instanceWriter.writeArray(p, 3);
- // Duplicate the final point since it will also be used by the convex hull shader.
- instanceWriter.write(p[2]);
+ // Mark this instance as a triangle by setting it to a conic with w=Inf.
+ instanceWriter.fill(GrVertexWriter::kIEEE_32_infinity, 2);
++numTrianglesAtBeginningOfData;
}
SkASSERT(count == breadcrumbTriangleList->count());
diff --git a/src/gpu/tessellate/GrStencilPathShader.cpp b/src/gpu/tessellate/GrStencilPathShader.cpp
index 85b1f42..2959886 100644
--- a/src/gpu/tessellate/GrStencilPathShader.cpp
+++ b/src/gpu/tessellate/GrStencilPathShader.cpp
@@ -374,8 +374,8 @@
args.fVertBuilder->insertFunction(kEvalRationalCubicFn);
args.fVertBuilder->codeAppend(R"(
float2 pos;
- if (sk_VertexID > kMaxVertexID) {
- // This is a special index value that instructs us to emit a specific point.
+ if (isinf(inputPoints_2_3.z)) {
+ // A conic with w=Inf is an exact triangle.
pos = ((sk_VertexID & 3) == 0) ? inputPoints_0_1.xy :
((sk_VertexID & 2) == 0) ? inputPoints_0_1.zw : inputPoints_2_3.xy;
} else {