Reland "Reland "Use conics with w=Inf to describe triangles for the tessellator""
This is a reland offf515df5b4
Original change's description: > Reland "Use conics with w=Inf to describe triangles for the tessellator" > > This is a reland of84f70136ab
> > 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>
This commit is contained in:
parent
cad48c6868
commit
99e6f0fcfb
@ -72,16 +72,20 @@ void GrFillCubicHullShader::emitVertexCode(Impl*, GrGLSLVertexBuilder* v, const
|
||||
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.
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "include/private/SkTemplates.h"
|
||||
#include "src/core/SkMathPriv.h"
|
||||
#include "src/core/SkPathPriv.h"
|
||||
#include <limits>
|
||||
|
||||
// This class emits a polygon triangulation with a "middle-out" topology. Conceptually, middle-out
|
||||
// emits one large triangle with vertices on both endpoints and a middle point, then recurses on
|
||||
@ -40,6 +41,12 @@
|
||||
// This class is designed to not know or store all the vertices in the polygon at once. The caller
|
||||
// pushes each vertex in linear order (perhaps while parsing a path), then rather than relying on
|
||||
// recursion, we manipulate an O(log N) stack to determine the correct middle-out triangulation.
|
||||
//
|
||||
// perTriangleVertexAdvance controls how much padding to put after triangles (namely, we append
|
||||
// "perTriangleVertexAdvance - 3" vertices of padding after each triangle, including the final one).
|
||||
// Padding vertices are filled with infinity. This has the effect, when perTriangleVertexAdvance is
|
||||
// 4, of defining a conic with w=Inf for tessellation shaders, which comes out to be an exact
|
||||
// triangle.
|
||||
class GrMiddleOutPolygonTriangulator {
|
||||
public:
|
||||
GrMiddleOutPolygonTriangulator(SkPoint* vertexData, int perTriangleVertexAdvance,
|
||||
@ -166,6 +173,10 @@ private:
|
||||
fVertexData[0] = fTop[0].fPoint;
|
||||
fVertexData[1] = fTop[1].fPoint;
|
||||
fVertexData[2] = lastPt;
|
||||
for (int i = 3; i < fPerTriangleVertexAdvance; ++i) {
|
||||
fVertexData[i].set(std::numeric_limits<float>::infinity(),
|
||||
std::numeric_limits<float>::infinity());
|
||||
}
|
||||
fVertexData += fPerTriangleVertexAdvance;
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h"
|
||||
#include "src/gpu/tessellate/GrMidpointContourParser.h"
|
||||
#include "src/gpu/tessellate/GrStencilPathShader.h"
|
||||
#include <limits>
|
||||
|
||||
GrPathIndirectTessellator::GrPathIndirectTessellator(const SkMatrix& viewMatrix, const SkPath& path,
|
||||
DrawInnerFan drawInnerFan)
|
||||
@ -92,8 +93,9 @@ void GrPathIndirectTessellator::prepare(GrMeshDrawOp::Target* target, const SkMa
|
||||
}
|
||||
SkPoint* breadcrumbData = instanceData + numTrianglesAtBeginningOfData * 4;
|
||||
memcpy(breadcrumbData, p, sizeof(SkPoint) * 3);
|
||||
// Duplicate the final point since it will also be used by the convex hull shader.
|
||||
breadcrumbData[3] = p[2];
|
||||
// Mark this instance as a triangle by setting it to a conic with w=Inf.
|
||||
breadcrumbData[3].set(std::numeric_limits<float>::infinity(),
|
||||
std::numeric_limits<float>::infinity());
|
||||
++numTrianglesAtBeginningOfData;
|
||||
}
|
||||
SkASSERT(count == breadcrumbTriangleList->count());
|
||||
@ -122,29 +124,24 @@ void GrPathIndirectTessellator::prepare(GrMeshDrawOp::Target* target, const SkMa
|
||||
// location at each resolve level.
|
||||
SkPoint* instanceLocations[kMaxResolveLevel + 1];
|
||||
int runningInstanceCount = 0;
|
||||
if (numTrianglesAtBeginningOfData) {
|
||||
// The caller has already packed "triangleInstanceCount" triangles into 4-point instances
|
||||
// at the beginning of the instance buffer. Add a special-case indirect draw here that will
|
||||
// emit the triangles [P0, P1, P2] from these 4-point instances.
|
||||
SkASSERT(fIndirectDrawCount < indirectLockCnt);
|
||||
GrMiddleOutCubicShader::WriteDrawTrianglesIndirectCmd(&indirectWriter,
|
||||
numTrianglesAtBeginningOfData,
|
||||
fBaseInstance);
|
||||
++fIndirectDrawCount;
|
||||
runningInstanceCount = numTrianglesAtBeginningOfData;
|
||||
}
|
||||
SkASSERT(fResolveLevelCounts[0] == 0);
|
||||
for (int resolveLevel = 1; resolveLevel <= kMaxResolveLevel; ++resolveLevel) {
|
||||
int instanceCountAtCurrLevel = fResolveLevelCounts[resolveLevel];
|
||||
if (resolveLevel == 1) {
|
||||
instanceCountAtCurrLevel += numTrianglesAtBeginningOfData;
|
||||
}
|
||||
if (!instanceCountAtCurrLevel) {
|
||||
SkDEBUGCODE(instanceLocations[resolveLevel] = nullptr;)
|
||||
continue;
|
||||
}
|
||||
instanceLocations[resolveLevel] = instanceData + runningInstanceCount * 4;
|
||||
if (resolveLevel == 1) {
|
||||
instanceLocations[resolveLevel] += numTrianglesAtBeginningOfData * 4;
|
||||
}
|
||||
SkASSERT(fIndirectDrawCount < indirectLockCnt);
|
||||
GrMiddleOutCubicShader::WriteDrawCubicsIndirectCmd(&indirectWriter, resolveLevel,
|
||||
instanceCountAtCurrLevel,
|
||||
fBaseInstance + runningInstanceCount);
|
||||
GrMiddleOutCubicShader::WriteDrawIndirectCmd(&indirectWriter, resolveLevel,
|
||||
instanceCountAtCurrLevel,
|
||||
fBaseInstance + runningInstanceCount);
|
||||
++fIndirectDrawCount;
|
||||
runningInstanceCount += instanceCountAtCurrLevel;
|
||||
}
|
||||
|
@ -367,24 +367,25 @@ class GrMiddleOutCubicShader::Impl : public GrStencilPathShader::Impl {
|
||||
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
|
||||
const auto& shader = args.fGeomProc.cast<GrMiddleOutCubicShader>();
|
||||
args.fVaryingHandler->emitAttributes(shader);
|
||||
args.fVertBuilder->defineConstantf("int", "kMaxVertexID", "%i", 1 << kMaxResolveLevel);
|
||||
args.fVertBuilder->defineConstantf("float", "kInverseMaxVertexID",
|
||||
"(1.0 / float(kMaxVertexID))");
|
||||
args.fVertBuilder->defineConstantf("float", "kInverseMaxVertexID", "(1.0 / float(%d))",
|
||||
1 << kMaxResolveLevel);
|
||||
args.fVertBuilder->insertFunction(kUnpackRationalCubicFn);
|
||||
args.fVertBuilder->insertFunction(kEvalRationalCubicFn);
|
||||
args.fVertBuilder->codeAppend(R"(
|
||||
args.fVertBuilder->codeAppendf(R"(
|
||||
float2 pos;
|
||||
if (sk_VertexID > kMaxVertexID) {
|
||||
// This is a special index value that instructs us to emit a specific point.
|
||||
pos = ((sk_VertexID & 3) == 0) ? inputPoints_0_1.xy :
|
||||
((sk_VertexID & 2) == 0) ? inputPoints_0_1.zw : inputPoints_2_3.xy;
|
||||
if (isinf(inputPoints_2_3.z)) {
|
||||
// A conic with w=Inf is an exact triangle.
|
||||
int idx = sk_VertexID >> %d/*kMaxResolveLevel - 1*/;
|
||||
pos = (idx < 1) ? inputPoints_0_1.xy
|
||||
: (idx == 1) ? inputPoints_0_1.zw
|
||||
: inputPoints_2_3.xy;
|
||||
} else {
|
||||
// Evaluate the cubic at T = (sk_VertexID / 2^kMaxResolveLevel).
|
||||
float T = float(sk_VertexID) * kInverseMaxVertexID;
|
||||
float4x3 P = unpack_rational_cubic(inputPoints_0_1.xy, inputPoints_0_1.zw,
|
||||
inputPoints_2_3.xy, inputPoints_2_3.zw);
|
||||
pos = eval_rational_cubic(P, T);
|
||||
})");
|
||||
})", kMaxResolveLevel - 1);
|
||||
|
||||
GrShaderVar vertexPos("pos", kFloat2_GrSLType);
|
||||
if (!shader.viewMatrix().isIdentity()) {
|
||||
|
@ -152,9 +152,8 @@ public:
|
||||
|
||||
// Configures an indirect draw to render cubic instances with 2^resolveLevel evenly-spaced (in
|
||||
// the parametric sense) line segments.
|
||||
static void WriteDrawCubicsIndirectCmd(GrDrawIndexedIndirectWriter* indirectWriter,
|
||||
int resolveLevel, uint32_t instanceCount,
|
||||
uint32_t baseInstance) {
|
||||
static void WriteDrawIndirectCmd(GrDrawIndexedIndirectWriter* indirectWriter, int resolveLevel,
|
||||
uint32_t instanceCount, uint32_t baseInstance) {
|
||||
SkASSERT(resolveLevel > 0 && resolveLevel <= GrTessellationPathRenderer::kMaxResolveLevel);
|
||||
// Starting at baseIndex=3, the index buffer triangulates a cubic with 2^kMaxResolveLevel
|
||||
// line segments. Each index value corresponds to a parametric T value on the curve. Since
|
||||
@ -164,15 +163,6 @@ public:
|
||||
indirectWriter->writeIndexed(indexCount, 3, instanceCount, baseInstance, 0);
|
||||
}
|
||||
|
||||
// For performance reasons we can often express triangles as an indirect cubic draw and sneak
|
||||
// them in alongside the other indirect draws. This method configures an indirect draw to emit
|
||||
// the triangle [P0, P1, P2] from a 4-point instance.
|
||||
static void WriteDrawTrianglesIndirectCmd(GrDrawIndexedIndirectWriter* indirectWriter,
|
||||
uint32_t instanceCount, uint32_t baseInstance) {
|
||||
// Indices 0,1,2 have special index values that emit points P0, P1, and P2 respectively.
|
||||
indirectWriter->writeIndexed(3, 0, instanceCount, baseInstance, 0);
|
||||
}
|
||||
|
||||
// Returns the index buffer that should be bound when drawing with this shader.
|
||||
// (Our vertex shader uses raw index values directly, so there is no vertex buffer.)
|
||||
static sk_sp<const GrGpuBuffer> FindOrMakeMiddleOutIndexBuffer(GrResourceProvider*);
|
||||
|
Loading…
Reference in New Issue
Block a user