| Index: src/gpu/batches/GrAADistanceFieldPathRenderer.cpp
|
| diff --git a/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp b/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp
|
| index 6cf3e4b82c64148efbb18525f0c54fdcd3e5f059..8aaabbc229d4ef205bc66a9071647645e93caad8 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);
|
| }
|
|
|
|
|