diff options
author | bsalomon <bsalomon@google.com> | 2016-06-27 07:18:18 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-06-27 07:18:18 -0700 |
commit | ee43241d72148545e4e3b75aa4338c491b39cc0c (patch) | |
tree | 45db61f18014bd7c5a7a376576aa8065cf2fb65b /src/gpu/batches/GrAADistanceFieldPathRenderer.cpp | |
parent | b05df0ff261d7819da55509df03fb4525af49b40 (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.cpp | 247 |
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); } |