Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(390)

Unified Diff: src/gpu/batches/GrTessellatingPathRenderer.cpp

Issue 1152733009: Screenspace AA tessellated path rendering. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Make GLPrograms test generate only simple fills. Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/gpu/GrTessellator.cpp ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/gpu/batches/GrTessellatingPathRenderer.cpp
diff --git a/src/gpu/batches/GrTessellatingPathRenderer.cpp b/src/gpu/batches/GrTessellatingPathRenderer.cpp
index b2c3138aed438f9e0979826cdacd121dd8bc5da2..541254530880a96b2b8cf4248c7217309f172a43 100644
--- a/src/gpu/batches/GrTessellatingPathRenderer.cpp
+++ b/src/gpu/batches/GrTessellatingPathRenderer.cpp
@@ -12,6 +12,7 @@
#include "GrBatchTest.h"
#include "GrClip.h"
#include "GrDefaultGeoProcFactory.h"
+#include "GrDrawTarget.h"
#include "GrMesh.h"
#include "GrPathUtils.h"
#include "GrPipelineBuilder.h"
@@ -24,10 +25,12 @@
#include <stdio.h>
+#define SK_DISABLE_SCREENSPACE_TESS_AA_PATH_RENDERER
+
/*
- * This path renderer tessellates the path into triangles using GrTessellator, uploads the triangles
- * to a vertex buffer, and renders them with a single draw call. It does not currently do
- * antialiasing, so it must be used in conjunction with multisampling.
+ * This path renderer tessellates the path into triangles using GrTessellator, uploads the
+ * triangles to a vertex buffer, and renders them with a single draw call. It can do screenspace
+ * antialiasing with a one-pixel coverage ramp.
*/
namespace {
@@ -64,22 +67,23 @@ bool cache_match(GrBuffer* vertexBuffer, SkScalar tol, int* actualCount) {
class StaticVertexAllocator : public GrTessellator::VertexAllocator {
public:
- StaticVertexAllocator(GrResourceProvider* resourceProvider, bool canMapVB)
- : fResourceProvider(resourceProvider)
+ StaticVertexAllocator(size_t stride, GrResourceProvider* resourceProvider, bool canMapVB)
+ : VertexAllocator(stride)
+ , fResourceProvider(resourceProvider)
, fCanMapVB(canMapVB)
, fVertices(nullptr) {
}
- SkPoint* lock(int vertexCount) override {
- size_t size = vertexCount * sizeof(SkPoint);
+ void* lock(int vertexCount) override {
+ size_t size = vertexCount * stride();
fVertexBuffer.reset(fResourceProvider->createBuffer(
size, kVertex_GrBufferType, kStatic_GrAccessPattern, 0));
if (!fVertexBuffer.get()) {
return nullptr;
}
if (fCanMapVB) {
- fVertices = static_cast<SkPoint*>(fVertexBuffer->map());
+ fVertices = fVertexBuffer->map();
} else {
- fVertices = new SkPoint[vertexCount];
+ fVertices = sk_malloc_throw(vertexCount * stride());
}
return fVertices;
}
@@ -87,8 +91,8 @@ public:
if (fCanMapVB) {
fVertexBuffer->unmap();
} else {
- fVertexBuffer->updateData(fVertices, actualCount * sizeof(SkPoint));
- delete[] fVertices;
+ fVertexBuffer->updateData(fVertices, actualCount * stride());
+ sk_free(fVertices);
}
fVertices = nullptr;
}
@@ -97,7 +101,34 @@ private:
SkAutoTUnref<GrBuffer> fVertexBuffer;
GrResourceProvider* fResourceProvider;
bool fCanMapVB;
- SkPoint* fVertices;
+ void* fVertices;
+};
+
+class DynamicVertexAllocator : public GrTessellator::VertexAllocator {
+public:
+ DynamicVertexAllocator(size_t stride, GrVertexBatch::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;
+ }
+ const GrBuffer* vertexBuffer() const { return fVertexBuffer; }
+ int firstVertex() const { return fFirstVertex; }
+private:
+ GrVertexBatch::Target* fTarget;
+ const GrBuffer* fVertexBuffer;
+ int fVertexCount;
+ int fFirstVertex;
+ void* fVertices;
};
} // namespace
@@ -106,13 +137,30 @@ GrTessellatingPathRenderer::GrTessellatingPathRenderer() {
}
bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
- // This path renderer can draw fill styles but does not do antialiasing. It can do convex and
- // concave paths, but we'll leave the convex ones to simpler algorithms. We pass on paths that
- // have styles, though they may come back around after applying the styling information to the
- // geometry to create a filled path. We also skip paths that don't have a key since the real
- // advantage of this path renderer comes from caching the tessellated geometry.
- return !args.fShape->style().applies() && args.fShape->style().isSimpleFill() &&
- !args.fAntiAlias && args.fShape->hasUnstyledKey() && !args.fShape->knownToBeConvex();
+ // This path renderer can draw fill styles, and can do screenspace antialiasing via a
+ // one-pixel coverage ramp. It can do convex and concave paths, but we'll leave the convex
+ // ones to simpler algorithms. We pass on paths that have styles, though they may come back
+ // around after applying the styling information to the geometry to create a filled path. In
+ // the non-AA case, We skip paths thta don't have a key since the real advantage of this path
+ // renderer comes from caching the tessellated geometry. In the AA case, we do not cache, so we
+ // accept paths without keys.
+ if (!args.fShape->style().isSimpleFill() || args.fShape->knownToBeConvex()) {
+ return false;
+ }
+ if (args.fAntiAlias) {
+#ifdef SK_DISABLE_SCREENSPACE_TESS_AA_PATH_RENDERER
+ return false;
+#else
+ SkPath path;
+ args.fShape->asPath(&path);
+ if (path.countVerbs() > 10) {
+ return false;
+ }
+#endif
+ } else if (!args.fShape->hasUnstyledKey()) {
+ return false;
+ }
+ return true;
}
class TessellatingPathBatch : public GrVertexBatch {
@@ -122,8 +170,9 @@ public:
static GrDrawBatch* Create(const GrColor& color,
const GrShape& shape,
const SkMatrix& viewMatrix,
- SkRect clipBounds) {
- return new TessellatingPathBatch(color, shape, viewMatrix, clipBounds);
+ SkIRect devClipBounds,
+ bool antiAlias) {
+ return new TessellatingPathBatch(color, shape, viewMatrix, devClipBounds, antiAlias);
}
const char* name() const override { return "TessellatingPathBatch"; }
@@ -145,41 +194,53 @@ private:
fPipelineInfo = overrides;
}
- void draw(Target* target, const GrGeometryProcessor* gp) const {
- GrResourceProvider* rp = target->resourceProvider();
- SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance;
- SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, fViewMatrix,
- fShape.bounds());
-
+ SkPath getPath() const {
+ SkASSERT(!fShape.style().applies());
SkPath path;
fShape.asPath(&path);
- bool inverseFill = path.isInverseFillType();
+ return path;
+ }
+
+ void draw(Target* target, const GrGeometryProcessor* gp) const {
+ SkASSERT(!fAntiAlias);
+ GrResourceProvider* rp = target->resourceProvider();
+ bool inverseFill = fShape.inverseFilled();
// construct a cache key from the path's genID and the view matrix
static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
GrUniqueKey key;
- static constexpr int kClipBoundsCnt = sizeof(fClipBounds) / sizeof(uint32_t);
+ static constexpr int kClipBoundsCnt = sizeof(fDevClipBounds) / sizeof(uint32_t);
int shapeKeyDataCnt = fShape.unstyledKeySize();
SkASSERT(shapeKeyDataCnt >= 0);
GrUniqueKey::Builder builder(&key, kDomain, shapeKeyDataCnt + kClipBoundsCnt);
fShape.writeUnstyledKey(&builder[0]);
// For inverse fills, the tessellation is dependent on clip bounds.
if (inverseFill) {
- memcpy(&builder[shapeKeyDataCnt], &fClipBounds, sizeof(fClipBounds));
+ memcpy(&builder[shapeKeyDataCnt], &fDevClipBounds, sizeof(fDevClipBounds));
} else {
- memset(&builder[shapeKeyDataCnt], 0, sizeof(fClipBounds));
+ memset(&builder[shapeKeyDataCnt], 0, sizeof(fDevClipBounds));
}
builder.finish();
SkAutoTUnref<GrBuffer> cachedVertexBuffer(rp->findAndRefTByUniqueKey<GrBuffer>(key));
int actualCount;
+ SkScalar tol = GrPathUtils::kDefaultTolerance;
+ tol = GrPathUtils::scaleToleranceToSrc(tol, fViewMatrix, fShape.bounds());
if (cache_match(cachedVertexBuffer.get(), tol, &actualCount)) {
this->drawVertices(target, gp, cachedVertexBuffer.get(), 0, actualCount);
return;
}
+ SkRect clipBounds = SkRect::Make(fDevClipBounds);
+
+ SkMatrix vmi;
+ if (!fViewMatrix.invert(&vmi)) {
+ return;
+ }
+ vmi.mapRect(&clipBounds);
bool isLinear;
bool canMapVB = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags();
- StaticVertexAllocator allocator(rp, canMapVB);
- int count = GrTessellator::PathToTriangles(path, tol, fClipBounds, &allocator, &isLinear);
+ StaticVertexAllocator allocator(gp->getVertexStride(), rp, canMapVB);
+ int count = GrTessellator::PathToTriangles(getPath(), tol, clipBounds, &allocator,
+ false, GrColor(), false, &isLinear);
if (count == 0) {
return;
}
@@ -191,6 +252,27 @@ private:
rp->assignUniqueKeyToResource(key, allocator.vertexBuffer());
}
+ void drawAA(Target* target, const GrGeometryProcessor* gp) const {
+ SkASSERT(fAntiAlias);
+ SkPath path = getPath();
+ if (path.isEmpty()) {
+ return;
+ }
+ SkRect clipBounds = SkRect::Make(fDevClipBounds);
+ path.transform(fViewMatrix);
+ SkScalar tol = GrPathUtils::kDefaultTolerance;
+ bool isLinear;
+ DynamicVertexAllocator allocator(gp->getVertexStride(), target);
+ bool canTweakAlphaForCoverage = fPipelineInfo.canTweakAlphaForCoverage();
+ int count = GrTessellator::PathToTriangles(path, tol, clipBounds, &allocator,
+ true, fColor, canTweakAlphaForCoverage,
+ &isLinear);
+ if (count == 0) {
+ return;
+ }
+ drawVertices(target, gp, allocator.vertexBuffer(), allocator.firstVertex(), count);
+ }
+
void onPrepareDraws(Target* target) const override {
sk_sp<GrGeometryProcessor> gp;
{
@@ -201,21 +283,35 @@ private:
LocalCoords::kUsePosition_Type :
LocalCoords::kUnused_Type);
Coverage::Type coverageType;
- if (fPipelineInfo.readsCoverage()) {
+ if (fAntiAlias) {
+ color = Color(Color::kAttribute_Type);
+ if (fPipelineInfo.canTweakAlphaForCoverage()) {
+ coverageType = Coverage::kSolid_Type;
+ } else {
+ coverageType = Coverage::kAttribute_Type;
+ }
+ } else if (fPipelineInfo.readsCoverage()) {
coverageType = Coverage::kSolid_Type;
} else {
coverageType = Coverage::kNone_Type;
}
Coverage coverage(coverageType);
- gp = GrDefaultGeoProcFactory::Make(color, coverage, localCoords, fViewMatrix);
+ if (fAntiAlias) {
+ gp = GrDefaultGeoProcFactory::MakeForDeviceSpace(color, coverage, localCoords,
+ fViewMatrix);
+ } else {
+ gp = GrDefaultGeoProcFactory::Make(color, coverage, localCoords, fViewMatrix);
+ }
+ }
+ if (fAntiAlias) {
+ this->drawAA(target, gp.get());
+ } else {
+ this->draw(target, gp.get());
}
- this->draw(target, gp.get());
}
void drawVertices(Target* target, const GrGeometryProcessor* gp, const GrBuffer* vb,
int firstVertex, int count) const {
- SkASSERT(gp->getVertexStride() == sizeof(SkPoint));
-
GrPrimitiveType primitiveType = TESSELLATOR_WIREFRAME ? kLines_GrPrimitiveType
: kTriangles_GrPrimitiveType;
GrMesh mesh;
@@ -228,24 +324,29 @@ private:
TessellatingPathBatch(const GrColor& color,
const GrShape& shape,
const SkMatrix& viewMatrix,
- const SkRect& clipBounds)
+ const SkIRect& devClipBounds,
+ bool antiAlias)
: INHERITED(ClassID())
, fColor(color)
, fShape(shape)
- , fViewMatrix(viewMatrix) {
- const SkRect& pathBounds = shape.bounds();
- fClipBounds = clipBounds;
- // Because the clip bounds are used to add a contour for inverse fills, they must also
- // include the path bounds.
- fClipBounds.join(pathBounds);
- const SkRect& srcBounds = shape.inverseFilled() ? fClipBounds : pathBounds;
- this->setTransformedBounds(srcBounds, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo);
+ , fViewMatrix(viewMatrix)
+ , fDevClipBounds(devClipBounds)
+ , fAntiAlias(antiAlias) {
+ SkRect devBounds;
+ viewMatrix.mapRect(&devBounds, shape.bounds());
+ if (shape.inverseFilled()) {
+ // Because the clip bounds are used to add a contour for inverse fills, they must also
+ // include the path bounds.
+ devBounds.join(SkRect::Make(fDevClipBounds));
+ }
+ this->setBounds(devBounds, HasAABloat::kNo, IsZeroArea::kNo);
}
GrColor fColor;
GrShape fShape;
SkMatrix fViewMatrix;
- SkRect fClipBounds; // in source space
+ SkIRect fDevClipBounds;
+ bool fAntiAlias;
GrXPOverridesForBatch fPipelineInfo;
typedef GrVertexBatch INHERITED;
@@ -254,22 +355,14 @@ private:
bool GrTessellatingPathRenderer::onDrawPath(const DrawPathArgs& args) {
GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(),
"GrTessellatingPathRenderer::onDrawPath");
- SkASSERT(!args.fAntiAlias);
-
SkIRect clipBoundsI;
args.fClip->getConservativeBounds(args.fDrawContext->width(), args.fDrawContext->height(),
&clipBoundsI);
- SkRect clipBounds = SkRect::Make(clipBoundsI);
- SkMatrix vmi;
- if (!args.fViewMatrix->invert(&vmi)) {
- return false;
- }
- vmi.mapRect(&clipBounds);
- SkPath path;
- args.fShape->asPath(&path);
SkAutoTUnref<GrDrawBatch> batch(TessellatingPathBatch::Create(args.fPaint->getColor(),
*args.fShape,
- *args.fViewMatrix, clipBounds));
+ *args.fViewMatrix,
+ clipBoundsI,
+ args.fAntiAlias));
GrPipelineBuilder pipelineBuilder(*args.fPaint, args.fDrawContext->mustUseHWAA(*args.fPaint));
pipelineBuilder.setUserStencil(args.fUserStencilSettings);
@@ -287,19 +380,15 @@ DRAW_BATCH_TEST_DEFINE(TesselatingPathBatch) {
GrColor color = GrRandomColor(random);
SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
SkPath path = GrTest::TestPath(random);
- SkRect clipBounds = GrTest::TestRect(random);
- SkMatrix vmi;
- bool result = viewMatrix.invert(&vmi);
- if (!result) {
- SkFAIL("Cannot invert matrix\n");
- }
- vmi.mapRect(&clipBounds);
+ SkIRect devClipBounds = SkIRect::MakeXYWH(
+ random->nextU(), random->nextU(), random->nextU(), random->nextU());
+ bool antiAlias = random->nextBool();
GrStyle style;
do {
GrTest::TestStyle(random, &style);
- } while (style.strokeRec().isHairlineStyle());
+ } while (!style.isSimpleFill());
GrShape shape(path, style);
- return TessellatingPathBatch::Create(color, shape, viewMatrix, clipBounds);
+ return TessellatingPathBatch::Create(color, shape, viewMatrix, devClipBounds, antiAlias);
}
#endif
« no previous file with comments | « src/gpu/GrTessellator.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698