From 41a3b87846553e9d77e0e113bfaf4ec74a068e96 Mon Sep 17 00:00:00 2001 From: Robert Phillips Date: Fri, 9 Mar 2018 12:00:34 -0500 Subject: [PATCH] Make GrTextureStripAtlas DDL friendly Change-Id: If8fdd7a1c027bc2b2791cfe1af13f99c2561d93d Reviewed-on: https://skia-review.googlesource.com/113268 Reviewed-by: Brian Salomon Commit-Queue: Robert Phillips --- include/gpu/GrContext.h | 27 +----- src/effects/SkTableColorFilter.cpp | 8 +- src/gpu/GrContext.cpp | 10 ++- src/gpu/GrContextPriv.h | 4 + src/gpu/GrTextureStripAtlas.h | 98 ++++++++++++---------- src/gpu/effects/GrTextureStripAtlas.cpp | 87 +++++++++---------- src/shaders/gradients/SkGradientShader.cpp | 6 +- 7 files changed, 112 insertions(+), 128 deletions(-) diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h index 98d278acdb..eccad0465a 100644 --- a/include/gpu/GrContext.h +++ b/include/gpu/GrContext.h @@ -42,6 +42,7 @@ class GrSwizzle; class GrTextBlobCache; class GrTextContext; class GrTextureProxy; +class GrTextureStripAtlasManager; class GrVertexBuffer; struct GrVkBackendContext; @@ -98,24 +99,6 @@ public: */ void resetContext(uint32_t state = kAll_GrBackendState); - /** - * Callback function to allow classes to cleanup on GrContext destruction. - * The 'info' field is filled in with the 'info' passed to addCleanUp. - */ - typedef void (*PFCleanUpFunc)(const GrContext* context, void* info); - - /** - * Add a function to be called from within GrContext's destructor. - * This gives classes a chance to free resources held on a per context basis. - * The 'info' parameter will be stored and passed to the callback function. - */ - void addCleanUp(PFCleanUpFunc cleanUp, void* info) { - CleanUpData* entry = fCleanUpData.push(); - - entry->fFunc = cleanUp; - entry->fInfo = info; - } - /** * Abandons all GPU resources and assumes the underlying backend 3D API context is no longer * usable. Call this if you have lost the associated GPU context, and thus internal texture, @@ -293,6 +276,7 @@ private: GrResourceCache* fResourceCache; GrResourceProvider* fResourceProvider; GrProxyProvider* fProxyProvider; + std::unique_ptr fTextureStripAtlasManager; GrGlyphCache* fGlyphCache; @@ -311,13 +295,6 @@ private: std::unique_ptr fTaskGroup; - struct CleanUpData { - PFCleanUpFunc fFunc; - void* fInfo; - }; - - SkTDArray fCleanUpData; - const uint32_t fUniqueID; std::unique_ptr fDrawingManager; diff --git a/src/effects/SkTableColorFilter.cpp b/src/effects/SkTableColorFilter.cpp index 46bfba99ca..3896acda59 100644 --- a/src/effects/SkTableColorFilter.cpp +++ b/src/effects/SkTableColorFilter.cpp @@ -444,16 +444,16 @@ std::unique_ptr ColorTableEffect::Make(GrContext* context, desc.fWidth = bitmap.width(); desc.fHeight = 128; desc.fRowHeight = bitmap.height(); - // TODO: this seems a bit heavy handed (passing a GrContext as part of the desc) - desc.fContext = context; desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info(), *context->caps()); if (kUnknown_GrPixelConfig == desc.fConfig) { return nullptr; } - GrTextureStripAtlas* atlas = GrTextureStripAtlas::GetAtlas(desc); - int row = atlas->lockRow(bitmap); + auto atlasManager = context->contextPriv().textureStripAtlasManager(); + + GrTextureStripAtlas* atlas = atlasManager->getAtlas(desc); + int row = atlas->lockRow(context, bitmap); sk_sp proxy; if (-1 == row) { atlas = nullptr; diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index f88da28970..4b624ee820 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -24,6 +24,7 @@ #include "GrSurfaceProxyPriv.h" #include "GrTexture.h" #include "GrTextureContext.h" +#include "GrTextureStripAtlas.h" #include "GrTracing.h" #include "SkConvertPixels.h" #include "SkDeferredDisplayList.h" @@ -90,6 +91,8 @@ bool GrContext::initCommon(const GrContextOptions& options) { fResourceCache->setProxyProvider(fProxyProvider); } + fTextureStripAtlasManager.reset(new GrTextureStripAtlasManager); + fDisableGpuYUVConversion = options.fDisableGpuYUVConversion; fSharpenMipmappedTextures = options.fSharpenMipmappedTextures; fDidTestPMConversions = false; @@ -146,10 +149,7 @@ GrContext::~GrContext() { fDrawingManager->cleanup(); } - for (int i = 0; i < fCleanUpData.count(); ++i) { - (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo); - } - + fTextureStripAtlasManager = nullptr; delete fResourceProvider; delete fResourceCache; delete fProxyProvider; @@ -199,6 +199,7 @@ SkSurfaceCharacterization GrContextThreadSafeProxy::createCharacterization( void GrContext::abandonContext() { ASSERT_SINGLE_OWNER + fTextureStripAtlasManager->abandon(); fProxyProvider->abandon(); fResourceProvider->abandon(); @@ -219,6 +220,7 @@ void GrContext::abandonContext() { void GrContext::releaseResourcesAndAbandonContext() { ASSERT_SINGLE_OWNER + fTextureStripAtlasManager->abandon(); fProxyProvider->abandon(); fResourceProvider->abandon(); diff --git a/src/gpu/GrContextPriv.h b/src/gpu/GrContextPriv.h index 35dc4a9ff4..745397658c 100644 --- a/src/gpu/GrContextPriv.h +++ b/src/gpu/GrContextPriv.h @@ -186,6 +186,10 @@ public: GrResourceCache* getResourceCache() { return fContext->fResourceCache; } + GrTextureStripAtlasManager* textureStripAtlasManager() { + return fContext->fTextureStripAtlasManager.get(); + } + GrGpu* getGpu() { return fContext->fGpu.get(); } const GrGpu* getGpu() const { return fContext->fGpu.get(); } diff --git a/src/gpu/GrTextureStripAtlas.h b/src/gpu/GrTextureStripAtlas.h index a67438bbe7..7a777b53ba 100644 --- a/src/gpu/GrTextureStripAtlas.h +++ b/src/gpu/GrTextureStripAtlas.h @@ -26,10 +26,9 @@ class GrTextureStripAtlas { public: /** * Descriptor struct which we'll use as a hash table key - **/ + */ struct Desc { Desc() { sk_bzero(this, sizeof(*this)); } - GrContext* fContext; GrPixelConfig fConfig; uint16_t fWidth, fHeight, fRowHeight; uint16_t fUnusedPadding; @@ -38,11 +37,6 @@ public: } }; - /** - * Try to find an atlas with the required parameters, creates a new one if necessary - */ - static GrTextureStripAtlas* GetAtlas(const Desc& desc); - ~GrTextureStripAtlas(); /** @@ -51,7 +45,8 @@ public: * @return The row index we inserted into, or -1 if we failed to find an open row. The caller * is responsible for calling unlockRow() with this row index when it's done with it. */ - int lockRow(const SkBitmap& data); + int lockRow(GrContext*, const SkBitmap&); + /** * This is intended to be used when cloning a processor that already holds a lock. It is * assumed that the row already has at least one lock. @@ -78,11 +73,12 @@ public: SkScalar getYOffset(int row) const { return SkIntToScalar(row) / fNumRows; } SkScalar getNormalizedTexelHeight() const { return fNormalizedYHeight; } - GrContext* getContext() const { return fDesc.fContext; } - sk_sp asTextureProxyRef() const; private: + friend class GrTextureStripAtlasManager; // for ctor + + static uint32_t CreateUniqueID(); // Key to indicate an atlas row without any meaningful data stored in it const static uint32_t kEmptyAtlasRowKey = 0xffffffff; @@ -103,11 +99,11 @@ private: }; /** - * We'll only allow construction via the static GrTextureStripAtlas::GetAtlas + * Only the GrTextureStripAtlasManager is allowed to create GrTextureStripAtlases */ - GrTextureStripAtlas(Desc desc); + GrTextureStripAtlas(const Desc& desc); - void lockTexture(); + void lockTexture(GrContext*); void unlockTexture(); /** @@ -116,7 +112,8 @@ private: void initLRU(); /** - * Grabs the least recently used free row out of the LRU list, returns nullptr if no rows are free. + * Grabs the least recently used free row out of the LRU list, returns nullptr if no rows + * are free. */ AtlasRow* getLRU(); @@ -140,37 +137,9 @@ private: void validate(); #endif - /** - * Clean up callback registered with GrContext. Allows this class to - * free up any allocated AtlasEntry and GrTextureStripAtlas objects - */ - static void CleanUp(const GrContext* context, void* info); - - // Hash table entry for atlases - class AtlasEntry : public ::SkNoncopyable { - public: - // for SkTDynamicHash - static const Desc& GetKey(const AtlasEntry& entry) { return entry.fDesc; } - static uint32_t Hash(const Desc& desc) { return SkOpts::hash(&desc, sizeof(Desc)); } - - // AtlasEntry proper - AtlasEntry() : fAtlas(nullptr) {} - ~AtlasEntry() { delete fAtlas; } - Desc fDesc; - GrTextureStripAtlas* fAtlas; - }; - - class Hash; - static Hash* gAtlasCache; - - static Hash* GetCache(); - - // We increment gCacheCount for each atlas - static int32_t gCacheCount; - - // A unique ID for this texture (formed with: gCacheCount++), so we can be sure that if we + // A unique ID for this atlas, so we can be sure that if we // get a texture back from the texture cache, that it's the same one we last used. - const int32_t fCacheKey; + const uint32_t fCacheKey; // Total locks on all rows (when this reaches zero, we can unlock our texture) int32_t fLockedRows; @@ -195,4 +164,45 @@ private: SkTDArray fKeyTable; }; +class GrTextureStripAtlasManager { +public: + GrTextureStripAtlasManager() {} + ~GrTextureStripAtlasManager(); + + void abandon(); + + /** + * Try to find an atlas with the required parameters, creates a new one if necessary + */ + GrTextureStripAtlas* getAtlas(const GrTextureStripAtlas::Desc&); + +private: + void deleteAllAtlases(); + + // Hash table entry for atlases + class AtlasEntry : public ::SkNoncopyable { + public: + AtlasEntry(const GrTextureStripAtlas::Desc& desc, GrTextureStripAtlas* atlas) + : fDesc(desc) + , fAtlas(atlas) { + } + ~AtlasEntry() { delete fAtlas; } + + // for SkTDynamicHash + static const GrTextureStripAtlas::Desc& GetKey(const AtlasEntry& entry) { + return entry.fDesc; + } + static uint32_t Hash(const GrTextureStripAtlas::Desc& desc) { + return SkOpts::hash(&desc, sizeof(GrTextureStripAtlas::Desc)); + } + + const GrTextureStripAtlas::Desc fDesc; + GrTextureStripAtlas* fAtlas; + }; + + typedef SkTDynamicHash AtlasHash; + + AtlasHash fAtlasCache; +}; + #endif diff --git a/src/gpu/effects/GrTextureStripAtlas.cpp b/src/gpu/effects/GrTextureStripAtlas.cpp index 59a35bcc6b..4159d392b1 100644 --- a/src/gpu/effects/GrTextureStripAtlas.cpp +++ b/src/gpu/effects/GrTextureStripAtlas.cpp @@ -20,59 +20,50 @@ #define VALIDATE #endif -class GrTextureStripAtlas::Hash : public SkTDynamicHash {}; - -int32_t GrTextureStripAtlas::gCacheCount = 0; - -// DDL TODO: The texture strip atlas can't have this global! -GrTextureStripAtlas::Hash* GrTextureStripAtlas::gAtlasCache = nullptr; - -GrTextureStripAtlas::Hash* GrTextureStripAtlas::GetCache() { - - if (nullptr == gAtlasCache) { - gAtlasCache = new Hash; - } - - return gAtlasCache; +//////////////////////////////////////////////////////////////////////////////// +GrTextureStripAtlasManager::~GrTextureStripAtlasManager() { + this->deleteAllAtlases(); } -// Remove the specified atlas from the cache -void GrTextureStripAtlas::CleanUp(const GrContext*, void* info) { - SkASSERT(info); - - AtlasEntry* entry = static_cast(info); - - // remove the cache entry - GetCache()->remove(entry->fDesc); - - // remove the actual entry - delete entry; - - if (0 == GetCache()->count()) { - delete gAtlasCache; - gAtlasCache = nullptr; +void GrTextureStripAtlasManager::deleteAllAtlases() { + AtlasHash::Iter iter(&fAtlasCache); + while (!iter.done()) { + AtlasEntry* tmp = &(*iter); + ++iter; + delete tmp; } + fAtlasCache.reset(); } -GrTextureStripAtlas* GrTextureStripAtlas::GetAtlas(const GrTextureStripAtlas::Desc& desc) { - AtlasEntry* entry = GetCache()->find(desc); - if (nullptr == entry) { - entry = new AtlasEntry; +void GrTextureStripAtlasManager::abandon() { + this->deleteAllAtlases(); +} - entry->fAtlas = new GrTextureStripAtlas(desc); - entry->fDesc = desc; +GrTextureStripAtlas* GrTextureStripAtlasManager::getAtlas(const GrTextureStripAtlas::Desc& desc) { + AtlasEntry* entry = fAtlasCache.find(desc); + if (!entry) { + // TODO: Does the AtlasEntry need a copy of the Desc if the GrTextureStripAtlas has one? + entry = new AtlasEntry(desc, new GrTextureStripAtlas(desc)); - desc.fContext->addCleanUp(CleanUp, entry); - - GetCache()->add(entry); + fAtlasCache.add(entry); } return entry->fAtlas; } -GrTextureStripAtlas::GrTextureStripAtlas(GrTextureStripAtlas::Desc desc) - : fCacheKey(sk_atomic_inc(&gCacheCount)) +//////////////////////////////////////////////////////////////////////////////// +uint32_t GrTextureStripAtlas::CreateUniqueID() { + static int32_t gUniqueID = SK_InvalidUniqueID; + uint32_t id; + // Loop in case our global wraps around, as we never want to return a 0. + do { + id = static_cast(sk_atomic_inc(&gUniqueID) + 1); + } while (id == SK_InvalidUniqueID); + return id; +} + +GrTextureStripAtlas::GrTextureStripAtlas(const Desc& desc) + : fCacheKey(CreateUniqueID()) , fLockedRows(0) , fDesc(desc) , fNumRows(desc.fHeight / desc.fRowHeight) @@ -94,10 +85,10 @@ void GrTextureStripAtlas::lockRow(int row) { ++fLockedRows; } -int GrTextureStripAtlas::lockRow(const SkBitmap& bitmap) { +int GrTextureStripAtlas::lockRow(GrContext* context, const SkBitmap& bitmap) { VALIDATE; - if (!this->getContext()->contextPriv().resourceProvider()) { + if (!context->contextPriv().resourceProvider()) { // DDL TODO: For DDL we need to schedule inline & ASAP uploads. However these systems // currently use the flushState which we can't use for the opList-based DDL phase. // For the opList-based solution every texture strip will get its own texture proxy. @@ -106,7 +97,7 @@ int GrTextureStripAtlas::lockRow(const SkBitmap& bitmap) { } if (0 == fLockedRows) { - this->lockTexture(); + this->lockTexture(context); if (!fTexContext) { return -1; } @@ -139,7 +130,7 @@ int GrTextureStripAtlas::lockRow(const SkBitmap& bitmap) { if (nullptr == row) { // force a flush, which should unlock all the rows; then try again - fDesc.fContext->contextPriv().flush(nullptr); // tighten this up? + context->contextPriv().flush(nullptr); // tighten this up? row = this->getLRU(); if (nullptr == row) { --fLockedRows; @@ -209,7 +200,7 @@ GrTextureStripAtlas::AtlasRow* GrTextureStripAtlas::getLRU() { return row; } -void GrTextureStripAtlas::lockTexture() { +void GrTextureStripAtlas::lockTexture(GrContext* context) { static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); GrUniqueKey key; @@ -217,7 +208,7 @@ void GrTextureStripAtlas::lockTexture() { builder[0] = static_cast(fCacheKey); builder.finish(); - GrProxyProvider* proxyProvider = fDesc.fContext->contextPriv().proxyProvider(); + GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); sk_sp proxy = proxyProvider->findOrCreateProxyByUniqueKey( key, kTopLeft_GrSurfaceOrigin); @@ -240,7 +231,7 @@ void GrTextureStripAtlas::lockTexture() { fKeyTable.rewind(); } SkASSERT(proxy); - fTexContext = fDesc.fContext->contextPriv().makeWrappedSurfaceContext(std::move(proxy)); + fTexContext = context->contextPriv().makeWrappedSurfaceContext(std::move(proxy)); } void GrTextureStripAtlas::unlockTexture() { diff --git a/src/shaders/gradients/SkGradientShader.cpp b/src/shaders/gradients/SkGradientShader.cpp index 8f0c5c836e..e5f0c7f33c 100644 --- a/src/shaders/gradients/SkGradientShader.cpp +++ b/src/shaders/gradients/SkGradientShader.cpp @@ -1291,21 +1291,21 @@ GrGradientEffect::GrGradientEffect(ClassID classID, const CreateArgs& args, bool shader.getGradientTableBitmap(&bitmap, bitmapType); SkASSERT(1 == bitmap.height() && SkIsPow2(bitmap.width())); + auto atlasManager = args.fContext->contextPriv().textureStripAtlasManager(); GrTextureStripAtlas::Desc desc; desc.fWidth = bitmap.width(); desc.fHeight = 32; desc.fRowHeight = bitmap.height(); // always 1 here - desc.fContext = args.fContext; desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info(), *args.fContext->caps()); - fAtlas = GrTextureStripAtlas::GetAtlas(desc); + fAtlas = atlasManager->getAtlas(desc); SkASSERT(fAtlas); // We always filter the gradient table. Each table is one row of a texture, always // y-clamp. GrSamplerState samplerState(args.fWrapMode, GrSamplerState::Filter::kBilerp); - fRow = fAtlas->lockRow(bitmap); + fRow = fAtlas->lockRow(args.fContext, bitmap); if (-1 != fRow) { fYCoord = fAtlas->getYOffset(fRow)+SK_ScalarHalf*fAtlas->getNormalizedTexelHeight(); // This is 1/2 places where auto-normalization is disabled