Revert "Update GrTriangulator to count curves"

This reverts commit 8e2b69440a.

Bug: chromium:1075428
Change-Id: I0be8570193783981a995265d0446db219bc73a87
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/330576
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
This commit is contained in:
Chris Dalton 2020-11-03 13:51:21 -07:00 committed by Skia Commit-Bot
parent d7b59c091d
commit 86d4cfdf8e
5 changed files with 38 additions and 40 deletions

View File

@ -818,12 +818,12 @@ void generate_cubic_points(const SkPoint& p0,
// Stage 1: convert the input path to a set of linear contours (linked list of Vertices). // Stage 1: convert the input path to a set of linear contours (linked list of Vertices).
void path_to_contours(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds, void path_to_contours(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
VertexList* contours, SkArenaAlloc& alloc, Mode mode, int* numCountedCurves) { VertexList* contours, SkArenaAlloc& alloc, Mode mode, bool *isLinear) {
SkScalar toleranceSqd = tolerance * tolerance; SkScalar toleranceSqd = tolerance * tolerance;
bool innerPolygons = (Mode::kSimpleInnerPolygons == mode); bool innerPolygons = (Mode::kSimpleInnerPolygons == mode);
SkPoint pts[4]; SkPoint pts[4];
int localCurveCount = 0; *isLinear = true;
VertexList* contour = contours; VertexList* contour = contours;
SkPath::Iter iter(path, false); SkPath::Iter iter(path, false);
if (path.isInverseFillType()) { if (path.isInverseFillType()) {
@ -839,7 +839,7 @@ void path_to_contours(const SkPath& path, SkScalar tolerance, const SkRect& clip
while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
switch (verb) { switch (verb) {
case SkPath::kConic_Verb: { case SkPath::kConic_Verb: {
++localCurveCount; *isLinear = false;
if (innerPolygons) { if (innerPolygons) {
append_point_to_contour(pts[2], contour, alloc); append_point_to_contour(pts[2], contour, alloc);
break; break;
@ -863,7 +863,7 @@ void path_to_contours(const SkPath& path, SkScalar tolerance, const SkRect& clip
break; break;
} }
case SkPath::kQuad_Verb: { case SkPath::kQuad_Verb: {
++localCurveCount; *isLinear = false;
if (innerPolygons) { if (innerPolygons) {
append_point_to_contour(pts[2], contour, alloc); append_point_to_contour(pts[2], contour, alloc);
break; break;
@ -872,7 +872,7 @@ void path_to_contours(const SkPath& path, SkScalar tolerance, const SkRect& clip
break; break;
} }
case SkPath::kCubic_Verb: { case SkPath::kCubic_Verb: {
++localCurveCount; *isLinear = false;
if (innerPolygons) { if (innerPolygons) {
append_point_to_contour(pts[3], contour, alloc); append_point_to_contour(pts[3], contour, alloc);
break; break;
@ -887,7 +887,6 @@ void path_to_contours(const SkPath& path, SkScalar tolerance, const SkRect& clip
break; break;
} }
} }
*numCountedCurves = localCurveCount;
} }
inline bool apply_fill_type(SkPathFillType fillType, int winding) { inline bool apply_fill_type(SkPathFillType fillType, int winding) {
@ -2371,7 +2370,7 @@ void* polys_to_triangles(Poly* polys, SkPathFillType fillType, Mode mode, void*
} }
Poly* path_to_polys(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds, Poly* path_to_polys(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
int contourCnt, SkArenaAlloc& alloc, Mode mode, int* numCountedCurves, int contourCnt, SkArenaAlloc& alloc, Mode mode, bool* isLinear,
VertexList* outerMesh) { VertexList* outerMesh) {
SkPathFillType fillType = path.getFillType(); SkPathFillType fillType = path.getFillType();
if (SkPathFillType_IsInverse(fillType)) { if (SkPathFillType_IsInverse(fillType)) {
@ -2379,7 +2378,7 @@ Poly* path_to_polys(const SkPath& path, SkScalar tolerance, const SkRect& clipBo
} }
std::unique_ptr<VertexList[]> contours(new VertexList[contourCnt]); std::unique_ptr<VertexList[]> contours(new VertexList[contourCnt]);
path_to_contours(path, tolerance, clipBounds, contours.get(), alloc, mode, numCountedCurves); path_to_contours(path, tolerance, clipBounds, contours.get(), alloc, mode, isLinear);
return contours_to_polys(contours.get(), contourCnt, path.getFillType(), path.getBounds(), return contours_to_polys(contours.get(), contourCnt, path.getFillType(), path.getBounds(),
mode, outerMesh, alloc); mode, outerMesh, alloc);
} }
@ -2459,16 +2458,16 @@ namespace GrTriangulator {
// Stage 6: Triangulate the monotone polygons into a vertex buffer. // Stage 6: Triangulate the monotone polygons into a vertex buffer.
int PathToTriangles(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds, int PathToTriangles(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
GrEagerVertexAllocator* vertexAllocator, Mode mode, int* numCountedCurves) { GrEagerVertexAllocator* vertexAllocator, Mode mode, bool* isLinear) {
int contourCnt = get_contour_count(path, tolerance); int contourCnt = get_contour_count(path, tolerance);
if (contourCnt <= 0) { if (contourCnt <= 0) {
*numCountedCurves = 0; *isLinear = true;
return 0; return 0;
} }
SkArenaAlloc alloc(kArenaChunkSize); SkArenaAlloc alloc(kArenaChunkSize);
VertexList outerMesh; VertexList outerMesh;
Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, mode, Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, mode,
numCountedCurves, &outerMesh); isLinear, &outerMesh);
SkPathFillType fillType = (Mode::kEdgeAntialias == mode) ? SkPathFillType fillType = (Mode::kEdgeAntialias == mode) ?
SkPathFillType::kWinding : path.getFillType(); SkPathFillType::kWinding : path.getFillType();
int64_t count64 = count_points(polys, fillType); int64_t count64 = count_points(polys, fillType);
@ -2506,9 +2505,9 @@ int PathToVertices(const SkPath& path, SkScalar tolerance, const SkRect& clipBou
return 0; return 0;
} }
SkArenaAlloc alloc(kArenaChunkSize); SkArenaAlloc alloc(kArenaChunkSize);
int numCountedCurves; bool isLinear;
Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, Mode::kNormal, Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, Mode::kNormal,
&numCountedCurves, nullptr); &isLinear, nullptr);
SkPathFillType fillType = path.getFillType(); SkPathFillType fillType = path.getFillType();
int64_t count64 = count_points(polys, fillType); int64_t count64 = count_points(polys, fillType);
if (0 == count64 || count64 > SK_MaxS32) { if (0 == count64 || count64 > SK_MaxS32) {

View File

@ -56,7 +56,7 @@ constexpr size_t GetVertexStride(Mode mode) {
} }
int PathToTriangles(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds, int PathToTriangles(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
GrEagerVertexAllocator*, Mode, int* numCountedCurves); GrEagerVertexAllocator*, Mode, bool *isLinear);
} // namespace GrTriangulator } // namespace GrTriangulator
#endif #endif

View File

@ -50,12 +50,12 @@ namespace {
// value. // value.
struct TessInfo { struct TessInfo {
int fNumVertices; int fNumVertices;
int fNumCountedCurves; bool fIsLinear;
SkScalar fTolerance; SkScalar fTolerance;
}; };
static sk_sp<SkData> create_data(int numVertices, int numCountedCurves, SkScalar tol) { static sk_sp<SkData> create_data(int numVertices, bool isLinear, SkScalar tol) {
TessInfo info { numVertices, numCountedCurves, tol }; TessInfo info { numVertices, isLinear, tol };
return SkData::MakeWithCopy(&info, sizeof(info)); return SkData::MakeWithCopy(&info, sizeof(info));
} }
@ -64,7 +64,7 @@ bool cache_match(const SkData* data, SkScalar tol) {
const TessInfo* info = static_cast<const TessInfo*>(data->data()); const TessInfo* info = static_cast<const TessInfo*>(data->data());
return info->fNumCountedCurves == 0 || info->fTolerance < 3.0f * tol; return info->fIsLinear || info->fTolerance < 3.0f * tol;
} }
// Should 'challenger' replace 'incumbent' in the cache if there is a collision? // Should 'challenger' replace 'incumbent' in the cache if there is a collision?
@ -72,7 +72,7 @@ bool is_newer_better(SkData* incumbent, SkData* challenger) {
const TessInfo* i = static_cast<const TessInfo*>(incumbent->data()); const TessInfo* i = static_cast<const TessInfo*>(incumbent->data());
const TessInfo* c = static_cast<const TessInfo*>(challenger->data()); const TessInfo* c = static_cast<const TessInfo*>(challenger->data());
if (i->fNumCountedCurves == 0 || i->fTolerance <= c->fTolerance) { if (i->fIsLinear || i->fTolerance <= c->fTolerance) {
return false; // prefer the incumbent return false; // prefer the incumbent
} }
@ -343,7 +343,7 @@ private:
const GrStyledShape& shape, const GrStyledShape& shape,
const SkIRect& devClipBounds, const SkIRect& devClipBounds,
SkScalar tol, SkScalar tol,
int* numCountedCurves) { bool* isLinear) {
SkRect clipBounds = SkRect::Make(devClipBounds); SkRect clipBounds = SkRect::Make(devClipBounds);
SkMatrix vmi; SkMatrix vmi;
@ -357,7 +357,7 @@ private:
shape.asPath(&path); shape.asPath(&path);
return GrTriangulator::PathToTriangles(path, tol, clipBounds, allocator, return GrTriangulator::PathToTriangles(path, tol, clipBounds, allocator,
GrTriangulator::Mode::kNormal, numCountedCurves); GrTriangulator::Mode::kNormal, isLinear);
} }
void createNonAAMesh(Target* target) { void createNonAAMesh(Target* target) {
@ -400,16 +400,16 @@ private:
bool canMapVB = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags(); bool canMapVB = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags();
StaticVertexAllocator allocator(rp, canMapVB); StaticVertexAllocator allocator(rp, canMapVB);
int numCountedCurves; bool isLinear;
int vertexCount = Triangulate(&allocator, fViewMatrix, fShape, fDevClipBounds, tol, int vertexCount = Triangulate(&allocator, fViewMatrix, fShape, fDevClipBounds, tol,
&numCountedCurves); &isLinear);
if (vertexCount == 0) { if (vertexCount == 0) {
return; return;
} }
fVertexData = allocator.detachVertexData(); fVertexData = allocator.detachVertexData();
key.setCustomData(create_data(vertexCount, numCountedCurves, tol)); key.setCustomData(create_data(vertexCount, isLinear, tol));
auto [tmpV, tmpD] = threadSafeCache->addVertsWithData(key, fVertexData, is_newer_better); auto [tmpV, tmpD] = threadSafeCache->addVertsWithData(key, fVertexData, is_newer_better);
if (tmpV != fVertexData) { if (tmpV != fVertexData) {
@ -439,11 +439,11 @@ private:
SkScalar tol = GrPathUtils::kDefaultTolerance; SkScalar tol = GrPathUtils::kDefaultTolerance;
sk_sp<const GrBuffer> vertexBuffer; sk_sp<const GrBuffer> vertexBuffer;
int firstVertex; int firstVertex;
int numCountedCurves; bool isLinear;
GrEagerDynamicVertexAllocator allocator(target, &vertexBuffer, &firstVertex); GrEagerDynamicVertexAllocator allocator(target, &vertexBuffer, &firstVertex);
int vertexCount = GrTriangulator::PathToTriangles(path, tol, clipBounds, &allocator, int vertexCount = GrTriangulator::PathToTriangles(path, tol, clipBounds, &allocator,
GrTriangulator::Mode::kEdgeAntialias, GrTriangulator::Mode::kEdgeAntialias,
&numCountedCurves); &isLinear);
if (vertexCount == 0) { if (vertexCount == 0) {
return; return;
} }
@ -535,16 +535,16 @@ private:
CpuVertexAllocator allocator; CpuVertexAllocator allocator;
int numCountedCurves; bool isLinear;
int vertexCount = Triangulate(&allocator, fViewMatrix, fShape, fDevClipBounds, tol, int vertexCount = Triangulate(&allocator, fViewMatrix, fShape, fDevClipBounds, tol,
&numCountedCurves); &isLinear);
if (vertexCount == 0) { if (vertexCount == 0) {
return; return;
} }
fVertexData = allocator.detachVertexData(); fVertexData = allocator.detachVertexData();
key.setCustomData(create_data(vertexCount, numCountedCurves, tol)); key.setCustomData(create_data(vertexCount, isLinear, tol));
// If some other thread created and cached its own triangulation, the 'is_newer_better' // If some other thread created and cached its own triangulation, the 'is_newer_better'
// predicate will replace the version in the cache if 'fVertexData' is a more accurate // predicate will replace the version in the cache if 'fVertexData' is a more accurate

View File

@ -102,11 +102,11 @@ void GrPathTessellateOp::prePreparePrograms(const PrePrepareArgs& args) {
float gpuFragmentWork = bounds.height() * scales[0] * bounds.width() * scales[1]; float gpuFragmentWork = bounds.height() * scales[0] * bounds.width() * scales[1];
float cpuTessellationWork = (float)numVerbs * SkNextLog2(numVerbs); // N log N. float cpuTessellationWork = (float)numVerbs * SkNextLog2(numVerbs); // N log N.
if (cpuTessellationWork * 500 + (256 * 256) < gpuFragmentWork) { // Don't try below 256x256. if (cpuTessellationWork * 500 + (256 * 256) < gpuFragmentWork) { // Don't try below 256x256.
int numCountedCubics; bool isLinear;
// This will fail if the inner triangles do not form a simple polygon (e.g., self // This will fail if the inner triangles do not form a simple polygon (e.g., self
// intersection, double winding). // intersection, double winding).
if (this->prePrepareInnerPolygonTriangulation(args, &numCountedCubics)) { if (this->prePrepareInnerPolygonTriangulation(args, &isLinear)) {
if (numCountedCubics > 0) { if (!isLinear) {
// Always use indirect draws for cubics instead of tessellation here. Our goal in // Always use indirect draws for cubics instead of tessellation here. Our goal in
// this mode is to maximize GPU performance, and the middle-out topology used by our // this mode is to maximize GPU performance, and the middle-out topology used by our
// indirect draws is easier on the rasterizer than a tessellated fan. There also // indirect draws is easier on the rasterizer than a tessellated fan. There also
@ -155,7 +155,7 @@ void GrPathTessellateOp::prePreparePrograms(const PrePrepareArgs& args) {
} }
bool GrPathTessellateOp::prePrepareInnerPolygonTriangulation(const PrePrepareArgs& args, bool GrPathTessellateOp::prePrepareInnerPolygonTriangulation(const PrePrepareArgs& args,
int* numCountedCurves) { bool* isLinear) {
SkASSERT(!fTriangleBuffer); SkASSERT(!fTriangleBuffer);
SkASSERT(fTriangleVertexCount == 0); SkASSERT(fTriangleVertexCount == 0);
SkASSERT(!fStencilTrianglesProgram); SkASSERT(!fStencilTrianglesProgram);
@ -166,7 +166,7 @@ bool GrPathTessellateOp::prePrepareInnerPolygonTriangulation(const PrePrepareArg
fTriangleVertexCount = GrTriangulator::PathToTriangles(fPath, 0, SkRect::MakeEmpty(), fTriangleVertexCount = GrTriangulator::PathToTriangles(fPath, 0, SkRect::MakeEmpty(),
args.fInnerTriangleAllocator, args.fInnerTriangleAllocator,
Mode::kSimpleInnerPolygons, Mode::kSimpleInnerPolygons,
numCountedCurves); isLinear);
if (fTriangleVertexCount == 0) { if (fTriangleVertexCount == 0) {
// Mode::kSimpleInnerPolygons causes PathToTriangles to fail if the inner polygon(s) are not // Mode::kSimpleInnerPolygons causes PathToTriangles to fail if the inner polygon(s) are not
// simple. // simple.
@ -180,7 +180,7 @@ bool GrPathTessellateOp::prePrepareInnerPolygonTriangulation(const PrePrepareArg
// stencilled. // stencilled.
this->prePrepareStencilTrianglesProgram(args); this->prePrepareStencilTrianglesProgram(args);
} }
this->prePrepareFillTrianglesProgram(args, *numCountedCurves); this->prePrepareFillTrianglesProgram(args, *isLinear);
return true; return true;
} }
@ -263,8 +263,7 @@ constexpr static GrUserStencilSettings kTestAndResetStencil(
GrUserStencilOp::kKeep, GrUserStencilOp::kKeep,
0xffff>()); 0xffff>());
void GrPathTessellateOp::prePrepareFillTrianglesProgram(const PrePrepareArgs& args, void GrPathTessellateOp::prePrepareFillTrianglesProgram(const PrePrepareArgs& args, bool isLinear) {
int numCountedCurves) {
SkASSERT(!fFillTrianglesProgram); SkASSERT(!fFillTrianglesProgram);
if (fOpFlags & OpFlags::kStencilOnly) { if (fOpFlags & OpFlags::kStencilOnly) {
@ -302,7 +301,7 @@ void GrPathTessellateOp::prePrepareFillTrianglesProgram(const PrePrepareArgs& ar
if (fStencilTrianglesProgram) { if (fStencilTrianglesProgram) {
// The path was already stencilled. Here we just need to do a cover pass. // The path was already stencilled. Here we just need to do a cover pass.
stencil = &kTestAndResetStencil; stencil = &kTestAndResetStencil;
} else if (numCountedCurves == 0) { } else if (isLinear) {
// There are no stencilled curves. We can ignore stencil and fill the path directly. // There are no stencilled curves. We can ignore stencil and fill the path directly.
stencil = &GrUserStencilSettings::kUnused; stencil = &GrUserStencilSettings::kUnused;
} else if (SkPathFillType::kWinding == fPath.getFillType()) { } else if (SkPathFillType::kWinding == fPath.getFillType()) {

View File

@ -75,13 +75,13 @@ private:
// Returns false if the inner triangles do not form a simple polygon (e.g., self intersection, // Returns false if the inner triangles do not form a simple polygon (e.g., self intersection,
// double winding). Non-simple polygons would need to split edges in order to avoid overlap, // double winding). Non-simple polygons would need to split edges in order to avoid overlap,
// and this is not an option as it would introduce T-junctions with the outer cubics. // and this is not an option as it would introduce T-junctions with the outer cubics.
bool prePrepareInnerPolygonTriangulation(const PrePrepareArgs&, int* numCountedCurves); bool prePrepareInnerPolygonTriangulation(const PrePrepareArgs&, bool* isLinear);
void prePrepareStencilTrianglesProgram(const PrePrepareArgs&); void prePrepareStencilTrianglesProgram(const PrePrepareArgs&);
template<typename ShaderType> void prePrepareStencilCubicsProgram(const PrePrepareArgs&); template<typename ShaderType> void prePrepareStencilCubicsProgram(const PrePrepareArgs&);
void prePreparePipelineForStencils(const PrePrepareArgs&); void prePreparePipelineForStencils(const PrePrepareArgs&);
void prePrepareFillTrianglesProgram(const PrePrepareArgs&, int numCountedCurves); void prePrepareFillTrianglesProgram(const PrePrepareArgs&, bool isLinear);
void prePrepareFillCubicHullsProgram(const PrePrepareArgs&); void prePrepareFillCubicHullsProgram(const PrePrepareArgs&);
void prePrepareFillBoundingBoxProgram(const PrePrepareArgs&); void prePrepareFillBoundingBoxProgram(const PrePrepareArgs&);
void prePreparePipelineForFills(const PrePrepareArgs&); void prePreparePipelineForFills(const PrePrepareArgs&);