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); |
} |