Move GrTessellator::VertexAllocator to GrEagerVertexAllocator

Moves the interface up to Ganesh level and starts using it from other
locations.

Change-Id: I939d2b357d3ae8551976d0d71b877b72da403712
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/266063
Reviewed-by: Stephen White <senorblanco@chromium.org>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
This commit is contained in:
Chris Dalton 2020-01-23 12:09:04 -07:00 committed by Skia Commit-Bot
parent 1a496c507e
commit d081dce968
9 changed files with 205 additions and 142 deletions

View File

@ -89,6 +89,7 @@ skia_gpu_sources = [
"$_src/gpu/GrDrawOpTest.cpp",
"$_src/gpu/GrDrawOpTest.h",
"$_src/gpu/GrDriverBugWorkarounds.cpp",
"$_src/gpu/GrEagerVertexAllocator.h",
"$_src/gpu/GrFixedClip.cpp",
"$_src/gpu/GrFixedClip.h",
"$_src/gpu/GrFragmentProcessor.cpp",

View File

@ -0,0 +1,84 @@
/*
* Copyright 2020 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrEagerVertexAllocator_DEFINED
#define GrEagerVertexAllocator_DEFINED
#include "src/gpu/ops/GrMeshDrawOp.h"
// This interface is used to allocate and map GPU vertex data before the exact number of required
// vertices is known. Usage pattern:
//
// 1. Call lock(eagerCount) with an upper bound on the number of required vertices.
// 2. Compute and write vertex data to the returned pointer (if not null).
// 3. Call unlock(actualCount) and provide the actual number of vertices written during step #2.
//
// On step #3, the implementation will attempt to shrink the underlying GPU memory slot to fit the
// actual vertex count.
class GrEagerVertexAllocator {
public:
template<typename T> T* lock(int eagerCount) {
return static_cast<T*>(this->lock(sizeof(T), eagerCount));
}
virtual void* lock(size_t stride, int eagerCount) = 0;
virtual void unlock(int actualCount) = 0;
virtual ~GrEagerVertexAllocator() {}
};
// GrEagerVertexAllocator implementation that uses GrMeshDrawOp::Target::makeVertexSpace and
// GrMeshDrawOp::Target::putBackVertices.
class GrEagerDynamicVertexAllocator : public GrEagerVertexAllocator {
public:
GrEagerDynamicVertexAllocator(GrMeshDrawOp::Target* target,
sk_sp<const GrBuffer>* vertexBuffer, int* baseVertex)
: fTarget(target)
, fVertexBuffer(vertexBuffer)
, fBaseVertex(baseVertex) {
}
#ifdef SK_DEBUG
~GrEagerDynamicVertexAllocator() override {
SkASSERT(!fLockCount);
}
#endif
void* lock(size_t stride, int eagerCount) override {
SkASSERT(!fLockCount);
SkASSERT(eagerCount);
if (void* data = fTarget->makeVertexSpace(stride, eagerCount, fVertexBuffer, fBaseVertex)) {
fLockStride = stride;
fLockCount = eagerCount;
return data;
}
fVertexBuffer->reset();
*fBaseVertex = 0;
return nullptr;
}
void unlock(int actualCount) override {
SkASSERT(fLockCount);
SkASSERT(actualCount <= fLockCount);
fTarget->putBackVertices(fLockCount - actualCount, fLockStride);
if (!actualCount) {
fVertexBuffer->reset();
*fBaseVertex = 0;
}
fLockCount = 0;
}
private:
GrMeshDrawOp::Target* const fTarget;
sk_sp<const GrBuffer>* const fVertexBuffer;
int* const fBaseVertex;
size_t fLockStride;
int fLockCount = 0;
};
#endif

View File

@ -8,6 +8,7 @@
#include "src/gpu/GrTessellator.h"
#include "src/gpu/GrDefaultGeoProcFactory.h"
#include "src/gpu/GrEagerVertexAllocator.h"
#include "src/gpu/GrVertexWriter.h"
#include "src/gpu/geometry/GrPathUtils.h"
@ -2358,7 +2359,7 @@ namespace GrTessellator {
// Stage 6: Triangulate the monotone polygons into a vertex buffer.
int PathToTriangles(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
VertexAllocator* vertexAllocator, bool antialias, bool* isLinear) {
GrEagerVertexAllocator* vertexAllocator, bool antialias, bool* isLinear) {
int contourCnt = get_contour_count(path, tolerance);
if (contourCnt <= 0) {
*isLinear = true;
@ -2378,7 +2379,8 @@ int PathToTriangles(const SkPath& path, SkScalar tolerance, const SkRect& clipBo
}
int count = count64;
void* verts = vertexAllocator->lock(count);
size_t vertexStride = GetVertexStride(antialias);
void* verts = vertexAllocator->lock(vertexStride, count);
if (!verts) {
SkDebugf("Could not allocate vertices\n");
return 0;
@ -2389,7 +2391,7 @@ int PathToTriangles(const SkPath& path, SkScalar tolerance, const SkRect& clipBo
end = outer_mesh_to_triangles(outerMesh, true, end);
int actualCount = static_cast<int>((static_cast<uint8_t*>(end) - static_cast<uint8_t*>(verts))
/ vertexAllocator->stride());
/ vertexStride);
SkASSERT(actualCount <= count);
vertexAllocator->unlock(actualCount);
return actualCount;

View File

@ -12,6 +12,7 @@
#include "include/private/SkColorData.h"
#include "src/gpu/GrColor.h"
class GrEagerVertexAllocator;
class SkPath;
struct SkRect;
@ -23,17 +24,6 @@ struct SkRect;
namespace GrTessellator {
class VertexAllocator {
public:
VertexAllocator(size_t stride) : fStride(stride) {}
virtual ~VertexAllocator() {}
virtual void* lock(int vertexCount) = 0;
virtual void unlock(int actualCount) = 0;
size_t stride() const { return fStride; }
private:
size_t fStride;
};
struct WindingVertex {
SkPoint fPos;
int fWinding;
@ -46,8 +36,12 @@ struct WindingVertex {
int PathToVertices(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
WindingVertex** verts);
constexpr size_t GetVertexStride(bool antialias) {
return sizeof(SkPoint) + ((antialias) ? sizeof(float) : 0);
}
int PathToTriangles(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
VertexAllocator*, bool antialias, bool *isLinear);
GrEagerVertexAllocator*, bool antialias, bool *isLinear);
}
#endif

View File

@ -13,6 +13,7 @@
#include "src/gpu/GrClip.h"
#include "src/gpu/GrDefaultGeoProcFactory.h"
#include "src/gpu/GrDrawOpTest.h"
#include "src/gpu/GrEagerVertexAllocator.h"
#include "src/gpu/GrMesh.h"
#include "src/gpu/GrOpFlushState.h"
#include "src/gpu/GrResourceCache.h"
@ -68,16 +69,22 @@ bool cache_match(GrGpuBuffer* vertexBuffer, SkScalar tol, int* actualCount) {
return false;
}
class StaticVertexAllocator : public GrTessellator::VertexAllocator {
class StaticVertexAllocator : public GrEagerVertexAllocator {
public:
StaticVertexAllocator(size_t stride, GrResourceProvider* resourceProvider, bool canMapVB)
: VertexAllocator(stride)
, fResourceProvider(resourceProvider)
StaticVertexAllocator(GrResourceProvider* resourceProvider, bool canMapVB)
: fResourceProvider(resourceProvider)
, fCanMapVB(canMapVB)
, fVertices(nullptr) {
}
void* lock(int vertexCount) override {
size_t size = vertexCount * stride();
#ifdef SK_DEBUG
~StaticVertexAllocator() override {
SkASSERT(!fLockStride);
}
#endif
void* lock(size_t stride, int eagerCount) override {
SkASSERT(!fLockStride);
SkASSERT(stride);
size_t size = eagerCount * stride;
fVertexBuffer = fResourceProvider->createBuffer(size, GrGpuBufferType::kVertex,
kStatic_GrAccessPattern);
if (!fVertexBuffer.get()) {
@ -86,18 +93,21 @@ public:
if (fCanMapVB) {
fVertices = fVertexBuffer->map();
} else {
fVertices = sk_malloc_throw(vertexCount * stride());
fVertices = sk_malloc_throw(eagerCount * stride);
}
fLockStride = stride;
return fVertices;
}
void unlock(int actualCount) override {
SkASSERT(fLockStride);
if (fCanMapVB) {
fVertexBuffer->unmap();
} else {
fVertexBuffer->updateData(fVertices, actualCount * stride());
fVertexBuffer->updateData(fVertices, actualCount * fLockStride);
sk_free(fVertices);
}
fVertices = nullptr;
fLockStride = 0;
}
sk_sp<GrGpuBuffer> detachVertexBuffer() { return std::move(fVertexBuffer); }
@ -106,33 +116,7 @@ private:
GrResourceProvider* fResourceProvider;
bool fCanMapVB;
void* fVertices;
};
class DynamicVertexAllocator : public GrTessellator::VertexAllocator {
public:
DynamicVertexAllocator(size_t stride, GrMeshDrawOp::Target* target)
: VertexAllocator(stride)
, fTarget(target)
, fVertexBuffer(nullptr)
, fVertices(nullptr) {}
void* lock(int vertexCount) override {
fVertexCount = vertexCount;
fVertices = fTarget->makeVertexSpace(stride(), vertexCount, &fVertexBuffer, &fFirstVertex);
return fVertices;
}
void unlock(int actualCount) override {
fTarget->putBackVertices(fVertexCount - actualCount, stride());
fVertices = nullptr;
}
sk_sp<const GrBuffer> detachVertexBuffer() const { return std::move(fVertexBuffer); }
int firstVertex() const { return fFirstVertex; }
private:
GrMeshDrawOp::Target* fTarget;
sk_sp<const GrBuffer> fVertexBuffer;
int fVertexCount;
int fFirstVertex;
void* fVertices;
size_t fLockStride = 0;
};
} // namespace
@ -255,7 +239,7 @@ private:
return path;
}
void draw(Target* target, const GrGeometryProcessor* gp, size_t vertexStride) {
void draw(Target* target, const GrGeometryProcessor* gp) {
SkASSERT(!fAntiAlias);
GrResourceProvider* rp = target->resourceProvider();
bool inverseFill = fShape.inverseFilled();
@ -292,7 +276,7 @@ private:
vmi.mapRect(&clipBounds);
bool isLinear;
bool canMapVB = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags();
StaticVertexAllocator allocator(vertexStride, rp, canMapVB);
StaticVertexAllocator allocator(rp, canMapVB);
int count = GrTessellator::PathToTriangles(getPath(), tol, clipBounds, &allocator, false,
&isLinear);
if (count == 0) {
@ -309,7 +293,7 @@ private:
this->drawVertices(target, gp, std::move(vb), 0, count);
}
void drawAA(Target* target, const GrGeometryProcessor* gp, size_t vertexStride) {
void drawAA(Target* target, const GrGeometryProcessor* gp) {
SkASSERT(fAntiAlias);
SkPath path = getPath();
if (path.isEmpty()) {
@ -318,15 +302,16 @@ private:
SkRect clipBounds = SkRect::Make(fDevClipBounds);
path.transform(fViewMatrix);
SkScalar tol = GrPathUtils::kDefaultTolerance;
sk_sp<const GrBuffer> vertexBuffer;
int firstVertex;
bool isLinear;
DynamicVertexAllocator allocator(vertexStride, target);
GrEagerDynamicVertexAllocator allocator(target, &vertexBuffer, &firstVertex);
int count = GrTessellator::PathToTriangles(path, tol, clipBounds, &allocator, true,
&isLinear);
if (count == 0) {
return;
}
this->drawVertices(target, gp, allocator.detachVertexBuffer(),
allocator.firstVertex(), count);
this->drawVertices(target, gp, std::move(vertexBuffer), firstVertex, count);
}
void onPrepareDraws(Target* target) override {
@ -362,11 +347,11 @@ private:
if (!gp) {
return;
}
size_t vertexStride = gp->vertexStride();
SkASSERT(GrTessellator::GetVertexStride(fAntiAlias) == gp->vertexStride());
if (fAntiAlias) {
this->drawAA(target, gp, vertexStride);
this->drawAA(target, gp);
} else {
this->draw(target, gp, vertexStride);
this->draw(target, gp);
}
}

View File

@ -9,6 +9,7 @@
#include "include/private/SkTArray.h"
#include "src/core/SkPathPriv.h"
#include "src/gpu/GrEagerVertexAllocator.h"
static SkPoint lerp(const SkPoint& a, const SkPoint& b, float T) {
SkASSERT(1 != T); // The below does not guarantee lerp(a, b, 1) === b.
@ -76,7 +77,19 @@ private:
int fMidpointWeight;
};
int GrPathParser::EmitCenterWedgePatches(const SkPath& path, SkPoint* patchData) {
constexpr int max_wedge_vertex_count(int numPathVerbs) {
// No initial moveTo, one wedge per verb, plus an implicit close at the end.
// Each wedge has 5 vertices.
return (numPathVerbs + 1) * 5;
}
int GrPathParser::EmitCenterWedgePatches(const SkPath& path, GrEagerVertexAllocator* vertexAlloc) {
int maxVertices = max_wedge_vertex_count(path.countVerbs());
auto* vertexData = vertexAlloc->lock<SkPoint>(maxVertices);
if (!vertexData) {
return 0;
}
int vertexCount = 0;
MidpointContourParser parser(path);
while (parser.parseNextContour()) {
@ -88,7 +101,7 @@ int GrPathParser::EmitCenterWedgePatches(const SkPath& path, SkPoint* patchData)
case SkPathVerb::kDone:
if (parser.startPoint() != lastPoint) {
lastPoint = write_line_as_cubic(
patchData + vertexCount, lastPoint, parser.startPoint());
vertexData + vertexCount, lastPoint, parser.startPoint());
break;
} // fallthru
default:
@ -99,29 +112,29 @@ int GrPathParser::EmitCenterWedgePatches(const SkPath& path, SkPoint* patchData)
continue;
case SkPathVerb::kLine:
lastPoint = write_line_as_cubic(patchData + vertexCount, lastPoint,
lastPoint = write_line_as_cubic(vertexData + vertexCount, lastPoint,
parser.atPoint(ptsIdx));
++ptsIdx;
break;
case SkPathVerb::kQuad:
lastPoint = write_quadratic_as_cubic(patchData + vertexCount, lastPoint,
lastPoint = write_quadratic_as_cubic(vertexData + vertexCount, lastPoint,
parser.atPoint(ptsIdx),
parser.atPoint(ptsIdx + 1));
ptsIdx += 2;
break;
case SkPathVerb::kCubic:
lastPoint = write_cubic(patchData + vertexCount, lastPoint,
lastPoint = write_cubic(vertexData + vertexCount, lastPoint,
parser.atPoint(ptsIdx), parser.atPoint(ptsIdx + 1),
parser.atPoint(ptsIdx + 2));
ptsIdx += 3;
break;
}
patchData[vertexCount + 4] = parser.midpoint();
vertexData[vertexCount + 4] = parser.midpoint();
vertexCount += 5;
}
}
SkASSERT(vertexCount <= MaxWedgeVertices(path));
vertexAlloc->unlock(vertexCount);
return vertexCount;
}
@ -147,8 +160,9 @@ static int emit_subpolygon(const SkPoint* points, int first, int last, SkPoint*
class InnerPolygonContourParser : public SkTPathContourParser<InnerPolygonContourParser> {
public:
InnerPolygonContourParser(const SkPath& path) : SkTPathContourParser(path) {
fPolyPoints.reserve(GrPathParser::MaxInnerPolygonVertices(path));
InnerPolygonContourParser(const SkPath& path, int vertexReserveCount)
: SkTPathContourParser(path)
, fPolyPoints(vertexReserveCount) {
}
int emitInnerPolygon(SkPoint* vertexData) {
@ -197,36 +211,51 @@ private:
int fNumCurves;
};
int GrPathParser::EmitInnerPolygonTriangles(const SkPath& path, SkPoint* vertexData,
int* numCurves) {
*numCurves = 0;
int vertexCount = 0;
InnerPolygonContourParser parser(path);
while (parser.parseNextContour()) {
vertexCount += parser.emitInnerPolygon(vertexData + vertexCount);
*numCurves += parser.numCurves();
constexpr int max_inner_poly_vertex_count(int numPathVerbs) {
// No initial moveTo, plus an implicit close at the end; n-2 trianles fill an n-gon.
// Each triangle has 3 vertices.
return (numPathVerbs - 1) * 3;
}
int GrPathParser::EmitInnerPolygonTriangles(const SkPath& path,
GrEagerVertexAllocator* vertexAlloc) {
int maxVertices = max_inner_poly_vertex_count(path.countVerbs());
InnerPolygonContourParser parser(path, maxVertices);
auto* vertexData = vertexAlloc->lock<SkPoint>(maxVertices);
if (!vertexData) {
return 0;
}
SkASSERT(vertexCount <= MaxInnerPolygonVertices(path));
int vertexCount = 0;
while (parser.parseNextContour()) {
vertexCount += parser.emitInnerPolygon(vertexData + vertexCount);
}
vertexAlloc->unlock(vertexCount);
return vertexCount;
}
int GrPathParser::EmitCubicInstances(const SkPath& path, SkPoint* vertexData) {
int GrPathParser::EmitCubicInstances(const SkPath& path, GrEagerVertexAllocator* vertexAlloc) {
auto* instanceData = vertexAlloc->lock<std::array<SkPoint, 4>>(path.countVerbs());
if (!instanceData) {
return 0;
}
int instanceCount = 0;
SkPath::Iter iter(path, false);
SkPath::Verb verb;
SkPoint pts[4];
while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
if (SkPath::kQuad_Verb == verb) {
write_quadratic_as_cubic(vertexData + (instanceCount * 4), pts[0], pts[1], pts[2]);
++instanceCount;
write_quadratic_as_cubic(instanceData[instanceCount++].data(), pts[0], pts[1], pts[2]);
continue;
}
if (SkPath::kCubic_Verb == verb) {
write_cubic(vertexData + (instanceCount * 4), pts[0], pts[1], pts[2], pts[3]);
++instanceCount;
instanceData[instanceCount++] = {pts[0], pts[1], pts[2], pts[3]};
continue;
}
}
vertexAlloc->unlock(instanceCount);
return instanceCount;
}

View File

@ -10,48 +10,35 @@
#include "include/core/SkPath.h"
class GrEagerVertexAllocator;
namespace GrPathParser {
// Returns the maximum number of vertices that can be written by EmitCenterWedges() for the given
// path.
inline int MaxWedgeVertices(const SkPath& path) {
// No initial moveTo, one wedge per verb, plus an implicit close at the end.
// Each wedge has 5 vertices.
return (path.countVerbs() + 1) * 5;
}
// Writes an array of cubic "wedges" from an SkPath, converting any lines or quadratics to cubics.
// These wedges can then be fed into GrTessellateWedgeShader to stencil the path. A wedge is a
// 5-point tessellation patch consisting of 4 cubic control points, plus an anchor point fanning
// from the center of the curve's resident contour.
// These wedges can then be fed into GrStencilWedgeShader to stencil the path. A wedge is a 5-point
// tessellation patch consisting of 4 cubic control points, plus an anchor point fanning from the
// center of the curve's resident contour.
//
// TODO: Eventually we want to use rational cubic wedges in order to support conics.
//
// Returns the number of vertices written to the array.
//
// The incoming patchData array must have at least MaxWedgeVertices() elements.
int EmitCenterWedgePatches(const SkPath&, SkPoint* patchData);
int EmitCenterWedgePatches(const SkPath&, GrEagerVertexAllocator*);
// Returns the maximum number of vertices required to triangulate the given path's inner polygon(s).
inline int MaxInnerPolygonVertices(const SkPath& path) {
// No initial moveTo, plus an implicit close at the end; n-2 trianles fill an n-gon.
// Each triangle has 3 vertices.
return (path.countVerbs() - 1) * 3;
}
// Triangulates the path's inner polygon(s) and writes the result to "vertexData". The inner
// polygons connect the endpoints of each verb. (i.e., they are the path that would result from
// collapsing all curves to single lines.)
// Triangulates and writes an SkPath's inner polygon(s). The inner polygons connect the endpoints of
// each verb. (i.e., they are the path that would result from collapsing all curves to single
// lines.)
//
// This method works by recursively subdividing the path rather than emitting a linear triangle fan
// or strip. This can reduce the load on the rasterizer by a great deal on complex paths.
//
// Returns the number of vertices written to the array.
//
// The incoming vertexData array must have at least MaxInnerPolygonVertices() elements.
int EmitInnerPolygonTriangles(const SkPath&, SkPoint* vertexData, int* numCurves);
int EmitInnerPolygonTriangles(const SkPath&, GrEagerVertexAllocator*);
int EmitCubicInstances(const SkPath&, SkPoint* vertexData);
// Writes out an array of cubics from an SkPath as 4-point instances, converting any quadratics to
// cubics.
//
// Returns the number of *instances* written to the array.
int EmitCubicInstances(const SkPath&, GrEagerVertexAllocator*);
} // namespace

View File

@ -7,6 +7,7 @@
#include "src/gpu/tessellate/GrTessellatePathOp.h"
#include "src/gpu/GrEagerVertexAllocator.h"
#include "src/gpu/GrGpu.h"
#include "src/gpu/GrOpFlushState.h"
#include "src/gpu/GrOpsRenderPass.h"
@ -24,6 +25,10 @@ GrTessellatePathOp::FixedFunctionFlags GrTessellatePathOp::fixedFunctionFlags()
}
void GrTessellatePathOp::onPrepare(GrOpFlushState* state) {
GrEagerDynamicVertexAllocator pathVertexAllocator(state, &fPathVertexBuffer, &fBasePathVertex);
GrEagerDynamicVertexAllocator cubicInstanceAllocator(state, &fCubicInstanceBuffer,
&fBaseCubicInstance);
// First see if we should split up inner polygon triangles and curves, and triangulate the inner
// polygon(s) more efficiently. This causes greater CPU overhead due to the extra shaders and
// draw calls, but the better triangulation can reduce the rasterizer load by a great deal on
@ -33,39 +38,15 @@ void GrTessellatePathOp::onPrepare(GrOpFlushState* state) {
// Raster-edge work is 1-dimensional, so we sum height and width rather than multiplying them.
float rasterEdgeWork = (bounds.height() + bounds.width()) * scale * fPath.countVerbs();
if (rasterEdgeWork > 1000 * 1000) {
int numCurves = 0;
int maxVertexCount = GrPathParser::MaxInnerPolygonVertices(fPath);
if (auto* triangleData = (SkPoint*)state->makeVertexSpace(
sizeof(SkPoint), maxVertexCount, &fPathVertexBuffer, &fBasePathVertex)) {
if ((fPathVertexCount =
GrPathParser::EmitInnerPolygonTriangles(fPath, triangleData, &numCurves))) {
fPathShader = state->allocator()->make<GrStencilTriangleShader>(fViewMatrix);
} else {
fPathVertexBuffer.reset();
}
state->putBackVertices(maxVertexCount - fPathVertexCount, sizeof(SkPoint));
}
if (numCurves) {
if (auto* cubicData = (SkPoint*)state->makeVertexSpace(
sizeof(SkPoint) * 4, numCurves, &fCubicInstanceBuffer, &fBaseCubicInstance)) {
fCubicInstanceCount = GrPathParser::EmitCubicInstances(fPath, cubicData);
SkASSERT(fCubicInstanceCount == numCurves);
}
}
fPathShader = state->allocator()->make<GrStencilTriangleShader>(fViewMatrix);
fPathVertexCount = GrPathParser::EmitInnerPolygonTriangles(fPath, &pathVertexAllocator);
fCubicInstanceCount = GrPathParser::EmitCubicInstances(fPath, &cubicInstanceAllocator);
return;
}
// Fastest CPU approach: emit one cubic wedge per verb, fanning out from the center.
int maxVertexCount = GrPathParser::MaxWedgeVertices(fPath);
if (auto* patchData = (SkPoint*)state->makeVertexSpace(
sizeof(SkPoint), maxVertexCount, &fPathVertexBuffer, &fBasePathVertex)) {
if ((fPathVertexCount = GrPathParser::EmitCenterWedgePatches(fPath, patchData))) {
fPathShader = state->allocator()->make<GrStencilWedgeShader>(fViewMatrix);
} else {
fPathVertexBuffer.reset();
}
state->putBackVertices(maxVertexCount - fPathVertexCount, sizeof(SkPoint));
}
fPathShader = state->allocator()->make<GrStencilWedgeShader>(fViewMatrix);
fPathVertexCount = GrPathParser::EmitCenterWedgePatches(fPath, &pathVertexAllocator);
}
void GrTessellatePathOp::onExecute(GrOpFlushState* state, const SkRect& chainBounds) {

View File

@ -67,6 +67,9 @@ private:
SkPMColor4f fColor;
GrProcessorSet fProcessors;
// The "path shader" draws the below path geometry.
GrStencilPathShader* fPathShader;
// The "path vertex buffer" is made up of either inner polygon triangles (see
// GrPathParser::EmitInnerPolygonTriangles) or cubic wedge patches (see
// GrPathParser::EmitCenterWedgePatches).
@ -74,9 +77,6 @@ private:
int fBasePathVertex;
int fPathVertexCount;
// The "path shader" draws the above path geometry.
GrStencilPathShader* fPathShader;
// The cubic instance buffer defines standalone cubics to tessellate into the stencil buffer, in
// addition to the above path geometry.
sk_sp<const GrBuffer> fCubicInstanceBuffer;