aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp
diff options
context:
space:
mode:
authorGravatar bsalomon <bsalomon@google.com>2016-06-27 07:18:18 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-06-27 07:18:18 -0700
commitee43241d72148545e4e3b75aa4338c491b39cc0c (patch)
tree45db61f18014bd7c5a7a376576aa8065cf2fb65b /src/gpu/batches/GrAADistanceFieldPathRenderer.cpp
parentb05df0ff261d7819da55509df03fb4525af49b40 (diff)
Remove style application from GrPathRenderer subclasses
Now that GrPathRenderer is using GrShape it is possible to get a key for a path that was computed by applying style to an original path. This improves path renderer subclass selection, particularly when a post-styled path happens to work with a simpler path renderer (e.g. it is convex). Previously a more expensive path renderer may have applied the style and rendered it (e.g. the distance field PR) GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2064753003 Review-Url: https://codereview.chromium.org/2064753003
Diffstat (limited to 'src/gpu/batches/GrAADistanceFieldPathRenderer.cpp')
-rw-r--r--src/gpu/batches/GrAADistanceFieldPathRenderer.cpp247
1 files changed, 116 insertions, 131 deletions
diff --git a/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp b/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp
index 6cf3e4b82c..8aaabbc229 100644
--- a/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp
+++ b/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp
@@ -31,8 +31,8 @@
#define NUM_PLOTS_Y (ATLAS_TEXTURE_HEIGHT / PLOT_HEIGHT)
#ifdef DF_PATH_TRACKING
-static int g_NumCachedPaths = 0;
-static int g_NumFreedPaths = 0;
+static int g_NumCachedShapes = 0;
+static int g_NumFreedShapes = 0;
#endif
// mip levels
@@ -44,15 +44,15 @@ static const int kLargeMIP = 162;
void GrAADistanceFieldPathRenderer::HandleEviction(GrBatchAtlas::AtlasID id, void* pr) {
GrAADistanceFieldPathRenderer* dfpr = (GrAADistanceFieldPathRenderer*)pr;
// remove any paths that use this plot
- PathDataList::Iter iter;
- iter.init(dfpr->fPathList, PathDataList::Iter::kHead_IterStart);
- PathData* pathData;
- while ((pathData = iter.get())) {
+ ShapeDataList::Iter iter;
+ iter.init(dfpr->fShapeList, ShapeDataList::Iter::kHead_IterStart);
+ ShapeData* shapeData;
+ while ((shapeData = iter.get())) {
iter.next();
- if (id == pathData->fID) {
- dfpr->fPathCache.remove(pathData->fKey);
- dfpr->fPathList.remove(pathData);
- delete pathData;
+ if (id == shapeData->fID) {
+ dfpr->fShapeCache.remove(shapeData->fKey);
+ dfpr->fShapeList.remove(shapeData);
+ delete shapeData;
#ifdef DF_PATH_TRACKING
++g_NumFreedPaths;
#endif
@@ -64,34 +64,42 @@ void GrAADistanceFieldPathRenderer::HandleEviction(GrBatchAtlas::AtlasID id, voi
GrAADistanceFieldPathRenderer::GrAADistanceFieldPathRenderer() : fAtlas(nullptr) {}
GrAADistanceFieldPathRenderer::~GrAADistanceFieldPathRenderer() {
- PathDataList::Iter iter;
- iter.init(fPathList, PathDataList::Iter::kHead_IterStart);
- PathData* pathData;
- while ((pathData = iter.get())) {
+ ShapeDataList::Iter iter;
+ iter.init(fShapeList, ShapeDataList::Iter::kHead_IterStart);
+ ShapeData* shapeData;
+ while ((shapeData = iter.get())) {
iter.next();
- fPathList.remove(pathData);
- delete pathData;
+ delete shapeData;
}
delete fAtlas;
#ifdef DF_PATH_TRACKING
- SkDebugf("Cached paths: %d, freed paths: %d\n", g_NumCachedPaths, g_NumFreedPaths);
+ SkDebugf("Cached shapes: %d, freed shapes: %d\n", g_NumCachedShapes, g_NumFreedShapes);
#endif
}
////////////////////////////////////////////////////////////////////////////////
bool GrAADistanceFieldPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
- // We don't currently apply the dash or factor it into the DF key. (skbug.com/5082)
- if (args.fShape->style().pathEffect()) {
+ if (!args.fShaderCaps->shaderDerivativeSupport()) {
+ return false;
+ }
+ // If the shape has no key then we won't get any reuse.
+ if (!args.fShape->hasUnstyledKey()) {
+ return false;
+ }
+ // This only supports filled paths, however, the caller may apply the style to make a filled
+ // path and try again.
+ if (!args.fShape->style().isSimpleFill()) {
+ return false;
+ }
+ // This does non-inverse antialiased fills.
+ if (!args.fAntiAlias) {
return false;
}
// TODO: Support inverse fill
- if (!args.fShaderCaps->shaderDerivativeSupport() || !args.fAntiAlias ||
- args.fShape->style().isSimpleHairline() || args.fShape->mayBeInverseFilledAfterStyling() ||
- !args.fShape->hasUnstyledKey()) {
+ if (!args.fShape->inverseFilled()) {
return false;
}
-
// currently don't support perspective
if (args.fViewMatrix->hasPerspective()) {
return false;
@@ -117,34 +125,20 @@ class AADistanceFieldPathBatch : public GrVertexBatch {
public:
DEFINE_BATCH_CLASS_ID
- typedef GrAADistanceFieldPathRenderer::PathData PathData;
- typedef SkTDynamicHash<PathData, PathData::Key> PathCache;
- typedef GrAADistanceFieldPathRenderer::PathDataList PathDataList;
+ typedef GrAADistanceFieldPathRenderer::ShapeData ShapeData;
+ typedef SkTDynamicHash<ShapeData, ShapeData::Key> ShapeCache;
+ typedef GrAADistanceFieldPathRenderer::ShapeDataList ShapeDataList;
struct Geometry {
- Geometry(const SkStrokeRec& stroke) : fStroke(stroke) {
- if (!stroke.needToApply()) {
- // purify unused values to ensure binary equality
- fStroke.setStrokeParams(SkPaint::kDefault_Cap, SkPaint::kDefault_Join,
- SkIntToScalar(4));
- if (fStroke.getWidth() < 0) {
- fStroke.setStrokeStyle(-1.0f);
- }
- }
- }
- SkPath fPath;
- // The unique ID of the path involved in this draw. This may be different than the ID
- // in fPath since that path may have resulted from a SkStrokeRec::applyToPath call.
- uint32_t fGenID;
- SkStrokeRec fStroke;
+ GrShape fShape;
GrColor fColor;
bool fAntiAlias;
};
static GrDrawBatch* Create(const Geometry& geometry, const SkMatrix& viewMatrix,
- GrBatchAtlas* atlas, PathCache* pathCache, PathDataList* pathList,
- bool gammaCorrect) {
- return new AADistanceFieldPathBatch(geometry, viewMatrix, atlas, pathCache, pathList,
+ GrBatchAtlas* atlas, ShapeCache* shapeCache,
+ ShapeDataList* shapeList, bool gammaCorrect) {
+ return new AADistanceFieldPathBatch(geometry, viewMatrix, atlas, shapeCache, shapeList,
gammaCorrect);
}
@@ -229,7 +223,7 @@ private:
// get mip level
SkScalar maxScale = this->viewMatrix().getMaxScale();
- const SkRect& bounds = args.fPath.getBounds();
+ const SkRect& bounds = args.fShape.bounds();
SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height());
SkScalar size = maxScale * maxDim;
uint32_t desiredDimension;
@@ -242,24 +236,22 @@ private:
}
// check to see if path is cached
- PathData::Key key(args.fGenID, desiredDimension, args.fStroke);
- PathData* pathData = fPathCache->find(key);
- if (nullptr == pathData || !atlas->hasID(pathData->fID)) {
+ ShapeData::Key key(args.fShape, desiredDimension);
+ ShapeData* shapeData = fShapeCache->find(key);
+ if (nullptr == shapeData || !atlas->hasID(shapeData->fID)) {
// Remove the stale cache entry
- if (pathData) {
- fPathCache->remove(pathData->fKey);
- fPathList->remove(pathData);
- delete pathData;
+ if (shapeData) {
+ fShapeCache->remove(shapeData->fKey);
+ fShapeList->remove(shapeData);
+ delete shapeData;
}
SkScalar scale = desiredDimension/maxDim;
- pathData = new PathData;
+ shapeData = new ShapeData;
if (!this->addPathToAtlas(target,
&flushInfo,
atlas,
- pathData,
- args.fPath,
- args.fGenID,
- args.fStroke,
+ shapeData,
+ args.fShape,
args.fAntiAlias,
desiredDimension,
scale)) {
@@ -268,7 +260,7 @@ private:
}
}
- atlas->setLastUseToken(pathData->fID, target->nextDrawToken());
+ atlas->setLastUseToken(shapeData->fID, target->nextDrawToken());
// Now set vertices
intptr_t offset = reinterpret_cast<intptr_t>(vertices);
@@ -279,46 +271,44 @@ private:
args.fColor,
vertexStride,
this->viewMatrix(),
- args.fPath,
- pathData);
+ args.fShape,
+ shapeData);
flushInfo.fInstancesToFlush++;
}
this->flush(target, &flushInfo);
}
- SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
-
AADistanceFieldPathBatch(const Geometry& geometry,
const SkMatrix& viewMatrix,
GrBatchAtlas* atlas,
- PathCache* pathCache, PathDataList* pathList,
+ ShapeCache* shapeCache, ShapeDataList* shapeList,
bool gammaCorrect)
: INHERITED(ClassID()) {
+ SkASSERT(geometry.fShape.hasUnstyledKey());
fBatch.fViewMatrix = viewMatrix;
fGeoData.push_back(geometry);
+ SkASSERT(fGeoData[0].fShape.hasUnstyledKey());
fAtlas = atlas;
- fPathCache = pathCache;
- fPathList = pathList;
+ fShapeCache = shapeCache;
+ fShapeList = shapeList;
fGammaCorrect = gammaCorrect;
// Compute bounds
- fBounds = geometry.fPath.getBounds();
+ fBounds = geometry.fShape.bounds();
viewMatrix.mapRect(&fBounds);
}
bool addPathToAtlas(GrVertexBatch::Target* target,
FlushInfo* flushInfo,
GrBatchAtlas* atlas,
- PathData* pathData,
- const SkPath& path,
- uint32_t genID,
- const SkStrokeRec& stroke,
+ ShapeData* shapeData,
+ const GrShape& shape,
bool antiAlias,
uint32_t dimension,
SkScalar scale) const {
- const SkRect& bounds = path.getBounds();
+ const SkRect& bounds = shape.bounds();
// generate bounding rect for bitmap draw
SkRect scaledBounds = bounds;
@@ -375,6 +365,8 @@ private:
draw.fMatrix = &drawMatrix;
draw.fDst = dst;
+ SkPath path;
+ shape.asPath(&path);
draw.drawPathCoverage(path, paint);
// generate signed distance field
@@ -404,9 +396,9 @@ private:
}
// add to cache
- pathData->fKey = PathData::Key(genID, dimension, stroke);
- pathData->fScale = scale;
- pathData->fID = id;
+ shapeData->fKey.set(shape, dimension);
+ shapeData->fScale = scale;
+ shapeData->fID = id;
// change the scaled rect to match the size of the inset distance field
scaledBounds.fRight = scaledBounds.fLeft +
SkIntToScalar(devPathBounds.width() - 2*SK_DistanceFieldInset);
@@ -416,14 +408,14 @@ private:
// need to also restore the fractional translation
scaledBounds.offset(-SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPad + dx,
-SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPad + dy);
- pathData->fBounds = scaledBounds;
+ shapeData->fBounds = scaledBounds;
// origin we render from is inset from distance field edge
atlasLocation.fX += SK_DistanceFieldInset;
atlasLocation.fY += SK_DistanceFieldInset;
- pathData->fAtlasLocation = atlasLocation;
+ shapeData->fAtlasLocation = atlasLocation;
- fPathCache->add(pathData);
- fPathList->addToTail(pathData);
+ fShapeCache->add(shapeData);
+ fShapeList->addToTail(shapeData);
#ifdef DF_PATH_TRACKING
++g_NumCachedPaths;
#endif
@@ -436,16 +428,16 @@ private:
GrColor color,
size_t vertexStride,
const SkMatrix& viewMatrix,
- const SkPath& path,
- const PathData* pathData) const {
+ const GrShape& shape,
+ const ShapeData* shapeData) const {
GrTexture* texture = atlas->getTexture();
- SkScalar dx = pathData->fBounds.fLeft;
- SkScalar dy = pathData->fBounds.fTop;
- SkScalar width = pathData->fBounds.width();
- SkScalar height = pathData->fBounds.height();
+ SkScalar dx = shapeData->fBounds.fLeft;
+ SkScalar dy = shapeData->fBounds.fTop;
+ SkScalar width = shapeData->fBounds.width();
+ SkScalar height = shapeData->fBounds.height();
- SkScalar invScale = 1.0f / pathData->fScale;
+ SkScalar invScale = 1.0f / shapeData->fScale;
dx *= invScale;
dy *= invScale;
width *= invScale;
@@ -464,15 +456,15 @@ private:
*colorPtr = color;
}
- const SkScalar tx = SkIntToScalar(pathData->fAtlasLocation.fX);
- const SkScalar ty = SkIntToScalar(pathData->fAtlasLocation.fY);
+ const SkScalar tx = SkIntToScalar(shapeData->fAtlasLocation.fX);
+ const SkScalar ty = SkIntToScalar(shapeData->fAtlasLocation.fY);
// vertex texture coords
SkPoint* textureCoords = (SkPoint*)(offset + sizeof(SkPoint) + sizeof(GrColor));
textureCoords->setRectFan(tx / texture->width(),
ty / texture->height(),
- (tx + pathData->fBounds.width()) / texture->width(),
- (ty + pathData->fBounds.height()) / texture->height(),
+ (tx + shapeData->fBounds.width()) / texture->width(),
+ (ty + shapeData->fBounds.height()) / texture->height(),
vertexStride);
}
@@ -504,7 +496,7 @@ private:
return false;
}
- fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
+ fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
this->joinBounds(that->bounds());
return true;
}
@@ -517,10 +509,10 @@ private:
};
BatchTracker fBatch;
- SkSTArray<1, Geometry, true> fGeoData;
+ SkSTArray<1, Geometry> fGeoData;
GrBatchAtlas* fAtlas;
- PathCache* fPathCache;
- PathDataList* fPathList;
+ ShapeCache* fShapeCache;
+ ShapeDataList* fShapeList;
bool fGammaCorrect;
typedef GrVertexBatch INHERITED;
@@ -530,10 +522,11 @@ bool GrAADistanceFieldPathRenderer::onDrawPath(const DrawPathArgs& args) {
GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(),
"GrAADistanceFieldPathRenderer::onDrawPath");
SkASSERT(!args.fDrawContext->isUnifiedMultisampled());
+ SkASSERT(args.fShape->style().isSimpleFill());
// we've already bailed on inverse filled paths, so this is safe
SkASSERT(!args.fShape->isEmpty());
-
+ SkASSERT(args.fShape->hasUnstyledKey());
if (!fAtlas) {
fAtlas = args.fResourceProvider->createAtlas(kAlpha_8_GrPixelConfig,
ATLAS_TEXTURE_WIDTH, ATLAS_TEXTURE_HEIGHT,
@@ -545,23 +538,14 @@ bool GrAADistanceFieldPathRenderer::onDrawPath(const DrawPathArgs& args) {
}
}
- const GrStyle& style = args.fShape->style();
- // It's ok to ignore style's path effect because canDrawPath filtered out path effects.
- AADistanceFieldPathBatch::Geometry geometry(style.strokeRec());
- args.fShape->asPath(&geometry.fPath);
- // Note: this is the generation ID of the _original_ path. When a new path is
- // generated due to stroking it is important that the original path's id is used
- // for caching.
- geometry.fGenID = geometry.fPath.getGenerationID();
- if (!style.isSimpleFill()) {
- style.strokeRec().applyToPath(&geometry.fPath, geometry.fPath);
- }
+ AADistanceFieldPathBatch::Geometry geometry;
+ geometry.fShape = *args.fShape;
geometry.fColor = args.fColor;
geometry.fAntiAlias = args.fAntiAlias;
SkAutoTUnref<GrDrawBatch> batch(AADistanceFieldPathBatch::Create(geometry,
*args.fViewMatrix, fAtlas,
- &fPathCache, &fPathList,
+ &fShapeCache, &fShapeList,
args.fGammaCorrect));
GrPipelineBuilder pipelineBuilder(*args.fPaint);
@@ -577,45 +561,45 @@ bool GrAADistanceFieldPathRenderer::onDrawPath(const DrawPathArgs& args) {
#ifdef GR_TEST_UTILS
struct PathTestStruct {
- typedef GrAADistanceFieldPathRenderer::PathCache PathCache;
- typedef GrAADistanceFieldPathRenderer::PathData PathData;
- typedef GrAADistanceFieldPathRenderer::PathDataList PathDataList;
+ typedef GrAADistanceFieldPathRenderer::ShapeCache ShapeCache;
+ typedef GrAADistanceFieldPathRenderer::ShapeData ShapeData;
+ typedef GrAADistanceFieldPathRenderer::ShapeDataList ShapeDataList;
PathTestStruct() : fContextID(SK_InvalidGenID), fAtlas(nullptr) {}
~PathTestStruct() { this->reset(); }
void reset() {
- PathDataList::Iter iter;
- iter.init(fPathList, PathDataList::Iter::kHead_IterStart);
- PathData* pathData;
- while ((pathData = iter.get())) {
+ ShapeDataList::Iter iter;
+ iter.init(fShapeList, ShapeDataList::Iter::kHead_IterStart);
+ ShapeData* shapeData;
+ while ((shapeData = iter.get())) {
iter.next();
- fPathList.remove(pathData);
- delete pathData;
+ fShapeList.remove(shapeData);
+ delete shapeData;
}
delete fAtlas;
- fPathCache.reset();
+ fShapeCache.reset();
}
static void HandleEviction(GrBatchAtlas::AtlasID id, void* pr) {
PathTestStruct* dfpr = (PathTestStruct*)pr;
// remove any paths that use this plot
- PathDataList::Iter iter;
- iter.init(dfpr->fPathList, PathDataList::Iter::kHead_IterStart);
- PathData* pathData;
- while ((pathData = iter.get())) {
+ ShapeDataList::Iter iter;
+ iter.init(dfpr->fShapeList, ShapeDataList::Iter::kHead_IterStart);
+ ShapeData* shapeData;
+ while ((shapeData = iter.get())) {
iter.next();
- if (id == pathData->fID) {
- dfpr->fPathCache.remove(pathData->fKey);
- dfpr->fPathList.remove(pathData);
- delete pathData;
+ if (id == shapeData->fID) {
+ dfpr->fShapeCache.remove(shapeData->fKey);
+ dfpr->fShapeList.remove(shapeData);
+ delete shapeData;
}
}
}
uint32_t fContextID;
GrBatchAtlas* fAtlas;
- PathCache fPathCache;
- PathDataList fPathList;
+ ShapeCache fShapeCache;
+ ShapeDataList fShapeList;
};
DRAW_BATCH_TEST_DEFINE(AADistanceFieldPathBatch) {
@@ -636,16 +620,17 @@ DRAW_BATCH_TEST_DEFINE(AADistanceFieldPathBatch) {
GrColor color = GrRandomColor(random);
bool gammaCorrect = random->nextBool();
- AADistanceFieldPathBatch::Geometry geometry(GrTest::TestStrokeRec(random));
+ AADistanceFieldPathBatch::Geometry geometry;
+ // This path renderer only allows fill styles.
+ GrShape shape(GrTest::TestPath(random), GrStyle::SimpleFill());
+ geometry.fShape = shape;
geometry.fColor = color;
- geometry.fPath = GrTest::TestPath(random);
geometry.fAntiAlias = random->nextBool();
- geometry.fGenID = random->nextU();
return AADistanceFieldPathBatch::Create(geometry, viewMatrix,
gTestStruct.fAtlas,
- &gTestStruct.fPathCache,
- &gTestStruct.fPathList,
+ &gTestStruct.fShapeCache,
+ &gTestStruct.fShapeList,
gammaCorrect);
}