Chromium Code Reviews| Index: src/gpu/batches/GrAADistanceFieldPathRenderer.cpp |
| diff --git a/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp b/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp |
| index 6cf3e4b82c64148efbb18525f0c54fdcd3e5f059..c6c47059bcbae9dc38bd025f23a573363b7d2246 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,31 +64,37 @@ 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; |
| + fShapeList.remove(shapeData); |
| + 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; |
| + } |
| + if (args.fShape->style().applies()) { |
| + // This may come back around after the style has been applied. |
| + return false; |
| + } |
| + // This does non-inverse antialiased fills. |
| // TODO: Support inverse fill |
| - if (!args.fShaderCaps->shaderDerivativeSupport() || !args.fAntiAlias || |
| - args.fShape->style().isSimpleHairline() || args.fShape->mayBeInverseFilledAfterStyling() || |
| - !args.fShape->hasUnstyledKey()) { |
| + if (!args.fAntiAlias || !args.fShape->style().isSimpleFill() ||args.fShape->inverseFilled()) { |
|
egdaniel
2016/06/27 13:16:58
space after ||
bsalomon
2016/06/27 13:37:52
Done.
|
| return false; |
| } |
| @@ -117,34 +123,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 +221,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 +234,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 +258,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 +269,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 +363,8 @@ private: |
| draw.fMatrix = &drawMatrix; |
| draw.fDst = dst; |
| + SkPath path; |
| + shape.asPath(&path); |
| draw.drawPathCoverage(path, paint); |
| // generate signed distance field |
| @@ -404,9 +394,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 +406,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 +426,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 +454,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 +494,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 +507,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; |
| @@ -533,7 +523,7 @@ bool GrAADistanceFieldPathRenderer::onDrawPath(const DrawPathArgs& args) { |
| // 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 +535,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 +558,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 +617,17 @@ DRAW_BATCH_TEST_DEFINE(AADistanceFieldPathBatch) { |
| GrColor color = GrRandomColor(random); |
| bool gammaCorrect = random->nextBool(); |
| - AADistanceFieldPathBatch::Geometry geometry(GrTest::TestStrokeRec(random)); |
| + AADistanceFieldPathBatch::Geometry geometry; |
| + SkStrokeRec strokeRec = GrTest::TestStrokeRec(random); |
| + GrShape shape(GrTest::TestPath(random), GrStyle(strokeRec, nullptr)); |
| + 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); |
| } |