Add a GrSmallPathAtlasMgr class

This CL consolidates access to the small path renderer's atlas,
shapeCache and shapeList inside the new GrSmallPathAtlasMgr class.

It is pulled out of the omnibus CL:

https://skia-review.googlesource.com/c/skia/+/307776 (Split the small path renderer into record-time and flush-time pieces)

Change-Id: I01717948f053ee15efd27975d8b15fad75283da6
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/308680
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Robert Phillips 2020-08-07 16:17:10 -04:00 committed by Skia Commit-Bot
parent 530fc3bb4c
commit cac1764968
2 changed files with 153 additions and 169 deletions

View File

@ -32,10 +32,6 @@
#include "src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h"
#include "src/gpu/ops/GrSmallPathShapeData.h"
static constexpr size_t kMaxAtlasTextureBytes = 2048 * 2048;
static constexpr size_t kPlotWidth = 512;
static constexpr size_t kPlotHeight = 256;
#ifdef DF_PATH_TRACKING
static int g_NumCachedShapes = 0;
static int g_NumFreedShapes = 0;
@ -49,84 +45,140 @@ static constexpr SkScalar kMaxDim = 73;
static constexpr SkScalar kMinSize = SK_ScalarHalf;
static constexpr SkScalar kMaxSize = 2*kMaxMIP;
namespace GrSmallPathAtlasMgr {
class GrSmallPathAtlasMgr {
public:
~GrSmallPathAtlasMgr() {
ShapeDataList::Iter iter;
iter.init(fShapeList, ShapeDataList::Iter::kHead_IterStart);
GrSmallPathShapeData* shapeData;
while ((shapeData = iter.get())) {
iter.next();
delete shapeData;
}
static const GrSurfaceProxyView* GetViews(GrDrawOpAtlas* atlas, int* numActiveProxies) {
*numActiveProxies = atlas->numActivePages();
return atlas->getViews();
}
static void SetUseToken(GrDrawOpAtlas* atlas,
GrSmallPathShapeData* shapeData,
GrDeferredUploadToken token) {
atlas->setLastUseToken(shapeData->fAtlasLocator, token);
}
static GrSmallPathShapeData* FindOrCreate(GrDrawOpAtlas* atlas,
GrSmallPathRenderer::ShapeCache* shapeCache,
GrSmallPathRenderer::ShapeDataList* shapeList,
const GrSmallPathShapeDataKey& key) {
auto shapeData = shapeCache->find(key);
if (!shapeData) {
shapeData = new GrSmallPathShapeData(key);
shapeCache->add(shapeData);
shapeList->addToTail(shapeData);
#ifdef DF_PATH_TRACKING
++g_NumCachedPaths;
SkDebugf("Cached shapes: %d, freed shapes: %d\n", g_NumCachedShapes, g_NumFreedShapes);
#endif
} else if (!atlas->hasID(shapeData->fAtlasLocator.plotLocator())) {
shapeData->fAtlasLocator.invalidatePlotLocator();
}
return shapeData;
}
bool initAtlas(GrProxyProvider* proxyProvider, const GrCaps* caps,
GrDrawOpAtlas::GenerationCounter* generationCounter,
GrDrawOpAtlas::EvictionCallback* evictor) {
if (fAtlas) {
return true;
}
static void DeleteCacheEntry(GrSmallPathRenderer::ShapeCache* shapeCache,
GrSmallPathRenderer::ShapeDataList* shapeList,
GrSmallPathShapeData* shapeData) {
shapeCache->remove(shapeData->fKey);
shapeList->remove(shapeData);
delete shapeData;
}
static constexpr size_t kMaxAtlasTextureBytes = 2048 * 2048;
static constexpr size_t kPlotWidth = 512;
static constexpr size_t kPlotHeight = 256;
} // namespace GrSmallPathAtlasMgr
const GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kAlpha_8,
GrRenderable::kNo);
// Callback to clear out internal path cache when eviction occurs
void GrSmallPathRenderer::evict(GrDrawOpAtlas::PlotLocator plotLocator) {
// remove any paths that use this plot
ShapeDataList::Iter iter;
iter.init(fShapeList, ShapeDataList::Iter::kHead_IterStart);
GrSmallPathShapeData* shapeData;
while ((shapeData = iter.get())) {
iter.next();
if (plotLocator == shapeData->fAtlasLocator.plotLocator()) {
fShapeCache.remove(shapeData->fKey);
fShapeList.remove(shapeData);
delete shapeData;
#ifdef DF_PATH_TRACKING
++g_NumFreedPaths;
#endif
GrDrawOpAtlasConfig atlasConfig(caps->maxTextureSize(), kMaxAtlasTextureBytes);
SkISize size = atlasConfig.atlasDimensions(kA8_GrMaskFormat);
fAtlas = GrDrawOpAtlas::Make(proxyProvider, format,
GrColorType::kAlpha_8, size.width(), size.height(),
kPlotWidth, kPlotHeight, generationCounter,
GrDrawOpAtlas::AllowMultitexturing::kYes, evictor);
return SkToBool(fAtlas);
}
GrDrawOpAtlas* atlas() { return fAtlas.get(); }
const GrSurfaceProxyView* getViews(int* numActiveProxies) {
*numActiveProxies = fAtlas->numActivePages();
return fAtlas->getViews();
}
void setUseToken(GrSmallPathShapeData* shapeData, GrDeferredUploadToken token) {
fAtlas->setLastUseToken(shapeData->fAtlasLocator, token);
}
void preFlush(GrOnFlushResourceProvider* onFlushRP,
const uint32_t* /*opsTaskIDs*/, int /*numOpsTaskIDs*/) {
if (fAtlas) {
fAtlas->instantiate(onFlushRP);
}
}
}
////////////////////////////////////////////////////////////////////////////////
GrSmallPathRenderer::GrSmallPathRenderer() : fAtlas(nullptr) {}
void postFlush(GrDeferredUploadToken startTokenForNextFlush,
const uint32_t* /*opsTaskIDs*/, int /*numOpsTaskIDs*/) {
if (fAtlas) {
fAtlas->compact(startTokenForNextFlush);
}
}
GrSmallPathRenderer::~GrSmallPathRenderer() {
ShapeDataList::Iter iter;
iter.init(fShapeList, ShapeDataList::Iter::kHead_IterStart);
GrSmallPathShapeData* shapeData;
while ((shapeData = iter.get())) {
iter.next();
// Callback to clear out internal path cache when eviction occurs
void evict(GrDrawOpAtlas::PlotLocator plotLocator) {
// remove any paths that use this plot
ShapeDataList::Iter iter;
iter.init(fShapeList, ShapeDataList::Iter::kHead_IterStart);
GrSmallPathShapeData* shapeData;
while ((shapeData = iter.get())) {
iter.next();
if (plotLocator == shapeData->fAtlasLocator.plotLocator()) {
fShapeCache.remove(shapeData->fKey);
fShapeList.remove(shapeData);
delete shapeData;
#ifdef DF_PATH_TRACKING
++g_NumFreedPaths;
#endif
}
}
}
GrSmallPathShapeData* findOrCreate(const GrSmallPathShapeDataKey& key) {
auto shapeData = fShapeCache.find(key);
if (!shapeData) {
shapeData = new GrSmallPathShapeData(key);
fShapeCache.add(shapeData);
fShapeList.addToTail(shapeData);
#ifdef DF_PATH_TRACKING
++g_NumCachedPaths;
#endif
} else if (!fAtlas->hasID(shapeData->fAtlasLocator.plotLocator())) {
shapeData->fAtlasLocator.invalidatePlotLocator();
}
return shapeData;
}
void deleteCacheEntry(GrSmallPathShapeData* shapeData) {
fShapeCache.remove(shapeData->fKey);
fShapeList.remove(shapeData);
delete shapeData;
}
#ifdef DF_PATH_TRACKING
SkDebugf("Cached shapes: %d, freed shapes: %d\n", g_NumCachedShapes, g_NumFreedShapes);
#endif
private:
using ShapeCache = SkTDynamicHash<GrSmallPathShapeData, GrSmallPathShapeDataKey>;
typedef SkTInternalLList<GrSmallPathShapeData> ShapeDataList;
std::unique_ptr<GrDrawOpAtlas> fAtlas;
GrSmallPathRenderer::ShapeCache fShapeCache;
GrSmallPathRenderer::ShapeDataList fShapeList;
};
void GrSmallPathRenderer::preFlush(GrOnFlushResourceProvider* onFlushRP,
const uint32_t* opsTaskIDs, int numOpsTaskIDs) {
fAtlasMgr->preFlush(onFlushRP, opsTaskIDs, numOpsTaskIDs);
}
void GrSmallPathRenderer::postFlush(GrDeferredUploadToken startTokenForNextFlush,
const uint32_t* opsTaskIDs, int numOpsTaskIDs) {
fAtlasMgr->postFlush(startTokenForNextFlush, opsTaskIDs, numOpsTaskIDs);
}
void GrSmallPathRenderer::evict(GrDrawOpAtlas::PlotLocator plotLocator) {
fAtlasMgr->evict(plotLocator);
}
////////////////////////////////////////////////////////////////////////////////
GrSmallPathRenderer::GrSmallPathRenderer() : fAtlasMgr(new GrSmallPathAtlasMgr) {}
GrSmallPathRenderer::~GrSmallPathRenderer() { }
////////////////////////////////////////////////////////////////////////////////
GrPathRenderer::CanDrawPath GrSmallPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
if (!args.fCaps->shaderCaps()->shaderDerivativeSupport()) {
@ -188,19 +240,16 @@ public:
GrPaint&& paint,
const GrStyledShape& shape,
const SkMatrix& viewMatrix,
GrDrawOpAtlas* atlas,
ShapeCache* shapeCache,
ShapeDataList* shapeList,
GrSmallPathAtlasMgr* atlasMgr,
bool gammaCorrect,
const GrUserStencilSettings* stencilSettings) {
return Helper::FactoryHelper<SmallPathOp>(context, std::move(paint), shape, viewMatrix,
atlas, shapeCache, shapeList, gammaCorrect,
atlasMgr, gammaCorrect,
stencilSettings);
}
SmallPathOp(Helper::MakeArgs helperArgs, const SkPMColor4f& color, const GrStyledShape& shape,
const SkMatrix& viewMatrix, GrDrawOpAtlas* atlas, ShapeCache* shapeCache,
ShapeDataList* shapeList, bool gammaCorrect,
const SkMatrix& viewMatrix, GrSmallPathAtlasMgr* atlasMgr, bool gammaCorrect,
const GrUserStencilSettings* stencilSettings)
: INHERITED(ClassID())
, fHelper(helperArgs, GrAAType::kCoverage, stencilSettings) {
@ -219,9 +268,7 @@ public:
fShapes.emplace_back(Entry{color, shape, viewMatrix});
fAtlas = atlas;
fShapeCache = shapeCache;
fShapeList = shapeList;
fAtlasMgr = atlasMgr;
fGammaCorrect = gammaCorrect;
}
@ -293,7 +340,7 @@ private:
flushInfo.fPrimProcProxies = target->allocPrimProcProxyPtrs(kMaxTextures);
int numActiveProxies;
const GrSurfaceProxyView* views = GrSmallPathAtlasMgr::GetViews(fAtlas, &numActiveProxies);
const GrSurfaceProxyView* views = fAtlasMgr->getViews(&numActiveProxies);
for (int i = 0; i < numActiveProxies; ++i) {
// This op does not know its atlas proxies when it is added to a GrOpsTasks, so the
// proxies don't get added during the visitProxies call. Thus we add them here.
@ -410,41 +457,40 @@ private:
// check to see if df path is cached
GrSmallPathShapeDataKey key(args.fShape, SkScalarCeilToInt(desiredDimension));
shapeData = GrSmallPathAtlasMgr::FindOrCreate(fAtlas, fShapeCache, fShapeList, key);
shapeData = fAtlasMgr->findOrCreate(key);
if (!shapeData->fAtlasLocator.plotLocator().isValid()) {
SkScalar scale = desiredDimension / maxDim;
if (!this->addDFPathToAtlas(target,
&flushInfo,
fAtlas,
fAtlasMgr->atlas(),
shapeData,
args.fShape,
SkScalarCeilToInt(desiredDimension),
scale)) {
GrSmallPathAtlasMgr::DeleteCacheEntry(fShapeCache, fShapeList, shapeData);
fAtlasMgr->deleteCacheEntry(shapeData);
continue;
}
}
} else {
// check to see if bitmap path is cached
GrSmallPathShapeDataKey key(args.fShape, args.fViewMatrix);
shapeData = GrSmallPathAtlasMgr::FindOrCreate(fAtlas, fShapeCache, fShapeList, key);
shapeData = fAtlasMgr->findOrCreate(key);
if (!shapeData->fAtlasLocator.plotLocator().isValid()) {
if (!this->addBMPathToAtlas(target,
&flushInfo,
fAtlas,
fAtlasMgr->atlas(),
shapeData,
args.fShape,
args.fViewMatrix)) {
GrSmallPathAtlasMgr::DeleteCacheEntry(fShapeCache, fShapeList, shapeData);
fAtlasMgr->deleteCacheEntry(shapeData);
continue;
}
}
}
auto uploadTarget = target->deferredUploadTarget();
GrSmallPathAtlasMgr::SetUseToken(fAtlas, shapeData,
uploadTarget->tokenTracker()->nextDrawToken());
fAtlasMgr->setUseToken(shapeData, uploadTarget->tokenTracker()->nextDrawToken());
this->writePathVertices(vertices, GrVertexColor(args.fColor, fWideColor),
args.fViewMatrix, shapeData);
@ -674,7 +720,7 @@ private:
void flush(GrMeshDrawOp::Target* target, FlushInfo* flushInfo) const {
int numActiveProxies;
const GrSurfaceProxyView* views = GrSmallPathAtlasMgr::GetViews(fAtlas, &numActiveProxies);
const GrSurfaceProxyView* views = fAtlasMgr->getViews(&numActiveProxies);
GrGeometryProcessor* gp = flushInfo->fGeometryProcessor;
@ -770,9 +816,7 @@ private:
SkSTArray<1, Entry> fShapes;
Helper fHelper;
GrDrawOpAtlas* fAtlas;
ShapeCache* fShapeCache;
ShapeDataList* fShapeList;
GrSmallPathAtlasMgr* fAtlasMgr;
bool fGammaCorrect;
bool fWideColor;
@ -786,25 +830,14 @@ bool GrSmallPathRenderer::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) {
const GrBackendFormat format = args.fContext->priv().caps()->getDefaultBackendFormat(
GrColorType::kAlpha_8, GrRenderable::kNo);
GrDrawOpAtlasConfig atlasConfig(args.fContext->priv().caps()->maxTextureSize(),
kMaxAtlasTextureBytes);
SkISize size = atlasConfig.atlasDimensions(kA8_GrMaskFormat);
fAtlas = GrDrawOpAtlas::Make(args.fContext->priv().proxyProvider(), format,
GrColorType::kAlpha_8, size.width(), size.height(),
kPlotWidth, kPlotHeight, this,
GrDrawOpAtlas::AllowMultitexturing::kYes, this);
if (!fAtlas) {
return false;
}
if (!fAtlasMgr->initAtlas(args.fContext->priv().proxyProvider(), args.fContext->priv().caps(),
this, this)) {
return false;
}
std::unique_ptr<GrDrawOp> op = SmallPathOp::Make(
args.fContext, std::move(args.fPaint), *args.fShape, *args.fViewMatrix, fAtlas.get(),
&fShapeCache, &fShapeList, args.fGammaCorrect, args.fUserStencilSettings);
args.fContext, std::move(args.fPaint), *args.fShape, *args.fViewMatrix,
fAtlasMgr.get(), args.fGammaCorrect, args.fUserStencilSettings);
args.fRenderTargetContext->addDrawOp(args.fClip, std::move(op));
return true;
@ -816,41 +849,15 @@ bool GrSmallPathRenderer::onDrawPath(const DrawPathArgs& args) {
struct GrSmallPathRenderer::PathTestStruct : public GrDrawOpAtlas::EvictionCallback,
public GrDrawOpAtlas::GenerationCounter {
PathTestStruct() : fContextID(SK_InvalidGenID), fAtlas(nullptr) {}
~PathTestStruct() override { this->reset(); }
void reset() {
ShapeDataList::Iter iter;
iter.init(fShapeList, ShapeDataList::Iter::kHead_IterStart);
GrSmallPathShapeData* shapeData;
while ((shapeData = iter.get())) {
iter.next();
fShapeList.remove(shapeData);
delete shapeData;
}
fAtlas = nullptr;
fShapeCache.reset();
}
PathTestStruct() : fContextID(SK_InvalidGenID) {}
~PathTestStruct() override { }
void evict(GrDrawOpAtlas::PlotLocator plotLocator) override {
// remove any paths that use this plot
ShapeDataList::Iter iter;
iter.init(fShapeList, ShapeDataList::Iter::kHead_IterStart);
GrSmallPathShapeData* shapeData;
while ((shapeData = iter.get())) {
iter.next();
if (plotLocator == shapeData->fAtlasLocator.plotLocator()) {
fShapeCache.remove(shapeData->fKey);
fShapeList.remove(shapeData);
delete shapeData;
}
}
fAtlasMgr->evict(plotLocator);
}
uint32_t fContextID;
std::unique_ptr<GrDrawOpAtlas> fAtlas;
ShapeCache fShapeCache;
ShapeDataList fShapeList;
std::unique_ptr<GrSmallPathAtlasMgr> fAtlasMgr;
};
std::unique_ptr<GrDrawOp> GrSmallPathRenderer::createOp_TestingOnly(
@ -858,15 +865,12 @@ std::unique_ptr<GrDrawOp> GrSmallPathRenderer::createOp_TestingOnly(
GrPaint&& paint,
const GrStyledShape& shape,
const SkMatrix& viewMatrix,
GrDrawOpAtlas* atlas,
ShapeCache* shapeCache,
ShapeDataList* shapeList,
GrSmallPathAtlasMgr* atlasMgr,
bool gammaCorrect,
const GrUserStencilSettings* stencil) {
return GrSmallPathRenderer::SmallPathOp::Make(context, std::move(paint), shape, viewMatrix,
atlas, shapeCache, shapeList, gammaCorrect,
stencil);
atlasMgr, gammaCorrect, stencil);
}
@ -876,17 +880,10 @@ GR_DRAW_OP_TEST_DEFINE(SmallPathOp) {
if (context->priv().contextID() != gTestStruct.fContextID) {
gTestStruct.fContextID = context->priv().contextID();
gTestStruct.reset();
const GrBackendFormat format = context->priv().caps()->getDefaultBackendFormat(
GrColorType::kAlpha_8, GrRenderable::kNo);
GrDrawOpAtlasConfig atlasConfig(context->priv().caps()->maxTextureSize(),
kMaxAtlasTextureBytes);
SkISize size = atlasConfig.atlasDimensions(kA8_GrMaskFormat);
gTestStruct.fAtlas =
GrDrawOpAtlas::Make(context->priv().proxyProvider(), format, GrColorType::kAlpha_8,
size.width(), size.height(), kPlotWidth, kPlotHeight,
&gTestStruct,
GrDrawOpAtlas::AllowMultitexturing::kYes, &gTestStruct);
gTestStruct.fAtlasMgr = std::make_unique<GrSmallPathAtlasMgr>();
gTestStruct.fAtlasMgr->initAtlas(context->priv().proxyProvider(),
context->priv().caps(),
&gTestStruct, &gTestStruct);
}
SkMatrix viewMatrix = GrTest::TestMatrix(random);
@ -897,9 +894,7 @@ GR_DRAW_OP_TEST_DEFINE(SmallPathOp) {
return GrSmallPathRenderer::createOp_TestingOnly(
context,
std::move(paint), shape, viewMatrix,
gTestStruct.fAtlas.get(),
&gTestStruct.fShapeCache,
&gTestStruct.fShapeList,
gTestStruct.fAtlasMgr.get(),
gammaCorrect,
GrGetRandomStencil(random, context));
}

View File

@ -17,6 +17,7 @@
#include "src/core/SkTDynamicHash.h"
class GrRecordingContext;
class GrSmallPathAtlasMgr;
class GrSmallPathShapeData;
class GrSmallPathShapeDataKey;
@ -36,18 +37,10 @@ public:
// the list of active OnFlushBackkbackObjects in an freeGpuResources call (i.e., we accept the
// default retainOnFreeGpuResources implementation).
void preFlush(GrOnFlushResourceProvider* onFlushRP, const uint32_t*, int) override {
if (fAtlas) {
fAtlas->instantiate(onFlushRP);
}
}
void preFlush(GrOnFlushResourceProvider* onFlushRP,
const uint32_t* /*opsTaskIDs*/, int /*numOpsTaskIDs*/) override;
void postFlush(GrDeferredUploadToken startTokenForNextFlush,
const uint32_t* /*opsTaskIDs*/, int /*numOpsTaskIDs*/) override {
if (fAtlas) {
fAtlas->compact(startTokenForNextFlush);
}
}
const uint32_t* /*opsTaskIDs*/, int /*numOpsTaskIDs*/) override;
using ShapeCache = SkTDynamicHash<GrSmallPathShapeData, GrSmallPathShapeDataKey>;
typedef SkTInternalLList<GrSmallPathShapeData> ShapeDataList;
@ -56,9 +49,7 @@ public:
GrPaint&&,
const GrStyledShape&,
const SkMatrix& viewMatrix,
GrDrawOpAtlas* atlas,
ShapeCache*,
ShapeDataList*,
GrSmallPathAtlasMgr*,
bool gammaCorrect,
const GrUserStencilSettings*);
struct PathTestStruct;
@ -76,9 +67,7 @@ private:
void evict(GrDrawOpAtlas::PlotLocator) override;
std::unique_ptr<GrDrawOpAtlas> fAtlas;
ShapeCache fShapeCache;
ShapeDataList fShapeList;
std::unique_ptr<GrSmallPathAtlasMgr> fAtlasMgr;
typedef GrPathRenderer INHERITED;
};