From d074b6293c6b0c17271aa0754449601fe732ae18 Mon Sep 17 00:00:00 2001 From: Robert Phillips Date: Mon, 15 Mar 2021 08:49:24 -0400 Subject: [PATCH] Switch GrTextureFreedMessages over to using DirectContextIDs Bug: skia:11728 Change-Id: I514f917577a4166c2834f72fc8c64ab85b259938 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/382879 Reviewed-by: Brian Salomon Commit-Queue: Robert Phillips --- src/gpu/GrBackendTextureImageGenerator.cpp | 64 +++++++++++++--------- src/gpu/GrBackendTextureImageGenerator.h | 25 +++++---- src/gpu/GrDirectContext.cpp | 4 +- src/gpu/GrResourceCache.cpp | 18 +++--- src/gpu/GrResourceCache.h | 19 ++++--- src/image/SkImage_GpuBase.cpp | 7 ++- tests/ResourceCacheTest.cpp | 30 +++++----- 7 files changed, 97 insertions(+), 70 deletions(-) diff --git a/src/gpu/GrBackendTextureImageGenerator.cpp b/src/gpu/GrBackendTextureImageGenerator.cpp index 620e18c1ee..078593fe0e 100644 --- a/src/gpu/GrBackendTextureImageGenerator.cpp +++ b/src/gpu/GrBackendTextureImageGenerator.cpp @@ -23,37 +23,38 @@ #include "src/gpu/SkGr.h" #include "src/gpu/gl/GrGLTexture.h" -GrBackendTextureImageGenerator::RefHelper::RefHelper(GrTexture* texture, uint32_t owningContextID, - std::unique_ptr semaphore) +GrBackendTextureImageGenerator::RefHelper::RefHelper( + GrTexture* texture, + GrDirectContext::DirectContextID owningContextID, + std::unique_ptr semaphore) : fOriginalTexture(texture) , fOwningContextID(owningContextID) , fBorrowingContextReleaseProc(nullptr) - , fBorrowingContextID(SK_InvalidGenID) , fSemaphore(std::move(semaphore)) {} GrBackendTextureImageGenerator::RefHelper::~RefHelper() { - SkASSERT(fBorrowingContextID == SK_InvalidUniqueID); + SkASSERT(!fBorrowingContextID.isValid()); // Generator has been freed, and no one is borrowing the texture. Notify the original cache // that it can free the last ref, so it happens on the correct thread. GrTextureFreedMessage msg { fOriginalTexture, fOwningContextID }; - SkMessageBus::Post(msg); + SkMessageBus::Post(msg); } std::unique_ptr GrBackendTextureImageGenerator::Make(sk_sp texture, GrSurfaceOrigin origin, std::unique_ptr semaphore, SkColorType colorType, SkAlphaType alphaType, sk_sp colorSpace) { - GrDirectContext* context = texture->getContext(); + GrDirectContext* dContext = texture->getContext(); // Attach our texture to this context's resource cache. This ensures that deletion will happen // in the correct thread/context. This adds the only ref to the texture that will persist from // this point. That ref will be released when the generator's RefHelper is freed. - context->priv().getResourceCache()->insertDelayedTextureUnref(texture.get()); + dContext->priv().getResourceCache()->insertDelayedTextureUnref(texture.get()); GrBackendTexture backendTexture = texture->getBackendTexture(); - if (!context->priv().caps()->areColorTypeAndFormatCompatible( + if (!dContext->priv().caps()->areColorTypeAndFormatCompatible( SkColorTypeToGrColorType(colorType), backendTexture.getBackendFormat())) { return nullptr; } @@ -61,17 +62,17 @@ GrBackendTextureImageGenerator::Make(sk_sp texture, GrSurfaceOrigin o SkImageInfo info = SkImageInfo::Make(texture->width(), texture->height(), colorType, alphaType, std::move(colorSpace)); return std::unique_ptr(new GrBackendTextureImageGenerator( - info, texture.get(), origin, context->priv().contextID(), + info, texture.get(), origin, dContext->directContextID(), std::move(semaphore), backendTexture)); } GrBackendTextureImageGenerator::GrBackendTextureImageGenerator( - const SkImageInfo& info, - GrTexture* texture, - GrSurfaceOrigin origin, - uint32_t owningContextID, - std::unique_ptr semaphore, - const GrBackendTexture& backendTex) + const SkImageInfo& info, + GrTexture* texture, + GrSurfaceOrigin origin, + GrDirectContext::DirectContextID owningContextID, + std::unique_ptr semaphore, + const GrBackendTexture& backendTex) : INHERITED(info) , fRefHelper(new RefHelper(texture, owningContextID, std::move(semaphore))) , fBackendTexture(backendTex) @@ -88,33 +89,42 @@ void GrBackendTextureImageGenerator::ReleaseRefHelper_TextureReleaseProc(void* c SkASSERT(refHelper); refHelper->fBorrowingContextReleaseProc = nullptr; - refHelper->fBorrowingContextID = SK_InvalidGenID; + refHelper->fBorrowingContextID.makeInvalid(); refHelper->unref(); } GrSurfaceProxyView GrBackendTextureImageGenerator::onGenerateTexture( - GrRecordingContext* context, + GrRecordingContext* rContext, const SkImageInfo& info, const SkIPoint& origin, GrMipmapped mipMapped, GrImageTexGenPolicy texGenPolicy) { - SkASSERT(context); + SkASSERT(rContext); - if (context->backend() != fBackendTexture.backend()) { + // We currently limit GrBackendTextureImageGenerators to direct contexts since + // only Flutter uses them and doesn't use recording/DDL contexts. Ideally, the + // cross context texture functionality can be subsumed by the thread-safe cache + // working with utility contexts. + auto dContext = rContext->asDirectContext(); + if (!dContext) { + return {}; + } + + if (dContext->backend() != fBackendTexture.backend()) { return {}; } if (info.colorType() != this->getInfo().colorType()) { return {}; } - auto proxyProvider = context->priv().proxyProvider(); + auto proxyProvider = dContext->priv().proxyProvider(); fBorrowingMutex.acquire(); sk_sp releaseProcHelper; - if (SK_InvalidGenID != fRefHelper->fBorrowingContextID) { - if (fRefHelper->fBorrowingContextID != context->priv().contextID()) { + if (fRefHelper->fBorrowingContextID.isValid()) { + if (fRefHelper->fBorrowingContextID != dContext->directContextID()) { fBorrowingMutex.release(); - context->priv().printWarningMessage( + rContext->priv().printWarningMessage( "GrBackendTextureImageGenerator: Trying to use texture on two GrContexts!\n"); return {}; } else { @@ -131,7 +141,7 @@ GrSurfaceProxyView GrBackendTextureImageGenerator::onGenerateTexture( GrRefCntedCallback::Make(ReleaseRefHelper_TextureReleaseProc, fRefHelper); fRefHelper->fBorrowingContextReleaseProc = releaseProcHelper.get(); } - fRefHelper->fBorrowingContextID = context->priv().contextID(); + fRefHelper->fBorrowingContextID = dContext->directContextID(); if (!fRefHelper->fBorrowedTextureKey.isValid()) { static const auto kDomain = GrUniqueKey::GenerateDomain(); GrUniqueKey::Builder builder(&fRefHelper->fBorrowedTextureKey, kDomain, 1); @@ -139,7 +149,7 @@ GrSurfaceProxyView GrBackendTextureImageGenerator::onGenerateTexture( } fBorrowingMutex.release(); - SkASSERT(fRefHelper->fBorrowingContextID == context->priv().contextID()); + SkASSERT(fRefHelper->fBorrowingContextID == dContext->directContextID()); GrBackendFormat backendFormat = fBackendTexture.getBackendFormat(); SkASSERT(backendFormat.isValid()); @@ -154,7 +164,7 @@ GrSurfaceProxyView GrBackendTextureImageGenerator::onGenerateTexture( GrMipmapStatus mipmapStatus = fBackendTexture.hasMipmaps() ? GrMipmapStatus::kValid : GrMipmapStatus::kNotAllocated; - GrSwizzle readSwizzle = context->priv().caps()->getReadSwizzle(backendFormat, grColorType); + GrSwizzle readSwizzle = dContext->priv().caps()->getReadSwizzle(backendFormat, grColorType); // Must make copies of member variables to capture in the lambda since this image generator may // be deleted before we actually execute the lambda. @@ -219,7 +229,7 @@ GrSurfaceProxyView GrBackendTextureImageGenerator::onGenerateTexture( ? SkBudgeted::kNo : SkBudgeted::kYes; - auto copy = GrSurfaceProxy::Copy(context, + auto copy = GrSurfaceProxy::Copy(dContext, std::move(proxy), fSurfaceOrigin, mipMapped, diff --git a/src/gpu/GrBackendTextureImageGenerator.h b/src/gpu/GrBackendTextureImageGenerator.h index cea0f401d1..72bdc96ea7 100644 --- a/src/gpu/GrBackendTextureImageGenerator.h +++ b/src/gpu/GrBackendTextureImageGenerator.h @@ -9,7 +9,7 @@ #include "include/core/SkImageGenerator.h" #include "include/gpu/GrBackendSurface.h" -#include "include/gpu/GrRecordingContext.h" +#include "include/gpu/GrDirectContext.h" #include "include/private/GrResourceKey.h" #include "include/private/SkMutex.h" #include "src/gpu/GrTexture.h" @@ -48,33 +48,38 @@ protected: GrMipmapped mipMapped, GrImageTexGenPolicy) override; private: - GrBackendTextureImageGenerator(const SkImageInfo& info, GrTexture*, GrSurfaceOrigin, - uint32_t owningContextID, std::unique_ptr, + GrBackendTextureImageGenerator(const SkImageInfo& info, + GrTexture*, + GrSurfaceOrigin, + GrDirectContext::DirectContextID owningContextID, + std::unique_ptr, const GrBackendTexture&); static void ReleaseRefHelper_TextureReleaseProc(void* ctx); class RefHelper : public SkNVRefCnt { public: - RefHelper(GrTexture*, uint32_t owningContextID, std::unique_ptr); + RefHelper(GrTexture*, + GrDirectContext::DirectContextID owningContextID, + std::unique_ptr); ~RefHelper(); - GrTexture* fOriginalTexture; - uint32_t fOwningContextID; + GrTexture* fOriginalTexture; + GrDirectContext::DirectContextID fOwningContextID; // We use this key so that we don't rewrap the GrBackendTexture in a GrTexture for each // proxy created from this generator for a particular borrowing context. - GrUniqueKey fBorrowedTextureKey; + GrUniqueKey fBorrowedTextureKey; // There is no ref associated with this pointer. We rely on our atomic bookkeeping with the // context ID to know when this pointer is valid and safe to use. This is used to make sure // all uses of the wrapped texture are finished on the borrowing context before we open // this back up to other contexts. In general a ref to this release proc is owned by all // proxies and gpu uses of the backend texture. - GrRefCntedCallback* fBorrowingContextReleaseProc; - uint32_t fBorrowingContextID; + GrRefCntedCallback* fBorrowingContextReleaseProc; + GrDirectContext::DirectContextID fBorrowingContextID; - std::unique_ptr fSemaphore; + std::unique_ptr fSemaphore; }; RefHelper* fRefHelper; diff --git a/src/gpu/GrDirectContext.cpp b/src/gpu/GrDirectContext.cpp index f04c3659fc..96621c665f 100644 --- a/src/gpu/GrDirectContext.cpp +++ b/src/gpu/GrDirectContext.cpp @@ -209,7 +209,9 @@ bool GrDirectContext::init() { SkASSERT(this->threadSafeCache()); fStrikeCache = std::make_unique(); - fResourceCache = std::make_unique(this->singleOwner(), this->contextID()); + fResourceCache = std::make_unique(this->singleOwner(), + this->directContextID(), + this->contextID()); fResourceCache->setProxyProvider(this->proxyProvider()); fResourceCache->setThreadSafeCache(this->threadSafeCache()); fResourceProvider = std::make_unique(fGpu.get(), fResourceCache.get(), diff --git a/src/gpu/GrResourceCache.cpp b/src/gpu/GrResourceCache.cpp index ac2238527f..4c5cb85e4c 100644 --- a/src/gpu/GrResourceCache.cpp +++ b/src/gpu/GrResourceCache.cpp @@ -27,7 +27,7 @@ DECLARE_SKMESSAGEBUS_MESSAGE(GrUniqueKeyInvalidatedMessage, uint32_t, true); -DECLARE_SKMESSAGEBUS_MESSAGE(GrTextureFreedMessage, uint32_t, true); +DECLARE_SKMESSAGEBUS_MESSAGE(GrTextureFreedMessage, GrDirectContext::DirectContextID, true); #define ASSERT_SINGLE_OWNER GR_ASSERT_SINGLE_OWNER(fSingleOwner) @@ -108,12 +108,16 @@ inline bool GrResourceCache::TextureAwaitingUnref::finished() { return !fNumUnre ////////////////////////////////////////////////////////////////////////////// -GrResourceCache::GrResourceCache(GrSingleOwner* singleOwner, uint32_t contextUniqueID) - : fInvalidUniqueKeyInbox(contextUniqueID) - , fFreedTextureInbox(contextUniqueID) - , fContextUniqueID(contextUniqueID) +GrResourceCache::GrResourceCache(GrSingleOwner* singleOwner, + GrDirectContext::DirectContextID owningContextID, + uint32_t familyID) + : fInvalidUniqueKeyInbox(familyID) + , fFreedTextureInbox(owningContextID) + , fOwningContextID(owningContextID) + , fContextUniqueID(familyID) , fSingleOwner(singleOwner) { - SkASSERT(contextUniqueID != SK_InvalidUniqueID); + SkASSERT(owningContextID.isValid()); + SkASSERT(familyID != SK_InvalidUniqueID); } GrResourceCache::~GrResourceCache() { @@ -679,7 +683,7 @@ void GrResourceCache::processFreedGpuResources() { SkTArray msgs; fFreedTextureInbox.poll(&msgs); for (int i = 0; i < msgs.count(); ++i) { - SkASSERT(msgs[i].fOwningUniqueID == fContextUniqueID); + SkASSERT(msgs[i].fIntendedRecipient == fOwningContextID); uint32_t id = msgs[i].fTexture->uniqueID().asUInt(); TextureAwaitingUnref* info = fTexturesAwaitingUnref.find(id); // If the GrContext was released or abandoned then fTexturesAwaitingUnref should have been diff --git a/src/gpu/GrResourceCache.h b/src/gpu/GrResourceCache.h index e1706a3483..4a634ade60 100644 --- a/src/gpu/GrResourceCache.h +++ b/src/gpu/GrResourceCache.h @@ -9,6 +9,7 @@ #define GrResourceCache_DEFINED #include "include/core/SkRefCnt.h" +#include "include/gpu/GrDirectContext.h" #include "include/private/GrResourceKey.h" #include "include/private/SkTArray.h" #include "include/private/SkTHash.h" @@ -30,13 +31,12 @@ class GrThreadSafeCache; struct GrTextureFreedMessage { GrTexture* fTexture; - uint32_t fOwningUniqueID; + GrDirectContext::DirectContextID fIntendedRecipient; }; static inline bool SkShouldPostMessageToBus( - const GrTextureFreedMessage& msg, uint32_t msgBusUniqueID) { - // The inbox's ID is the unique ID of the owning GrContext. - return msgBusUniqueID == msg.fOwningUniqueID; + const GrTextureFreedMessage& msg, GrDirectContext::DirectContextID potentialRecipient) { + return potentialRecipient == msg.fIntendedRecipient; } /** @@ -58,7 +58,9 @@ static inline bool SkShouldPostMessageToBus( */ class GrResourceCache { public: - GrResourceCache(GrSingleOwner* owner, uint32_t contextUniqueID); + GrResourceCache(GrSingleOwner* owner, + GrDirectContext::DirectContextID owningContextID, + uint32_t familyID); ~GrResourceCache(); // Default maximum number of bytes of gpu memory of budgeted resources in the cache. @@ -321,8 +323,10 @@ private: return res->cacheAccess().accessCacheIndex(); } + using TextureFreedMessageBus = SkMessageBus; + typedef SkMessageBus::Inbox InvalidUniqueKeyInbox; - typedef SkMessageBus::Inbox FreedTextureInbox; typedef SkTDPQueue PurgeableQueue; typedef SkTDArray ResourceArray; @@ -362,9 +366,10 @@ private: int fNumBudgetedResourcesFlushWillMakePurgeable = 0; InvalidUniqueKeyInbox fInvalidUniqueKeyInbox; - FreedTextureInbox fFreedTextureInbox; + TextureFreedMessageBus::Inbox fFreedTextureInbox; TexturesAwaitingUnref fTexturesAwaitingUnref; + GrDirectContext::DirectContextID fOwningContextID; uint32_t fContextUniqueID = SK_InvalidUniqueID; GrSingleOwner* fSingleOwner = nullptr; diff --git a/src/image/SkImage_GpuBase.cpp b/src/image/SkImage_GpuBase.cpp index ecaabbbbe1..0b3ae30a63 100644 --- a/src/image/SkImage_GpuBase.cpp +++ b/src/image/SkImage_GpuBase.cpp @@ -259,7 +259,8 @@ sk_sp SkImage_GpuBase::MakePromiseImageLazyProxy( // In the future the GrSurface class hierarchy refactoring should eliminate this // difficulty by removing the virtual inheritance. if (fTexture) { - SkMessageBus::Post({fTexture, fTextureContextID}); + GrTextureFreedMessage msg { fTexture, fTextureContextID }; + SkMessageBus::Post(msg); } } @@ -313,7 +314,7 @@ sk_sp SkImage_GpuBase::MakePromiseImageLazyProxy( // our destructor. auto dContext = fTexture->getContext(); dContext->priv().getResourceCache()->insertDelayedTextureUnref(fTexture); - fTextureContextID = dContext->priv().contextID(); + fTextureContextID = dContext->directContextID(); return {std::move(tex), kReleaseCallbackOnInstantiation, kKeySyncMode}; } @@ -321,7 +322,7 @@ sk_sp SkImage_GpuBase::MakePromiseImageLazyProxy( PromiseImageTextureFulfillProc fFulfillProc; sk_sp fReleaseHelper; GrTexture* fTexture = nullptr; - uint32_t fTextureContextID = SK_InvalidUniqueID; + GrDirectContext::DirectContextID fTextureContextID; bool fFulfillProcFailed = false; } callback(fulfillProc, std::move(releaseHelper)); diff --git a/tests/ResourceCacheTest.cpp b/tests/ResourceCacheTest.cpp index 7e8fc84f2b..c4d2168873 100644 --- a/tests/ResourceCacheTest.cpp +++ b/tests/ResourceCacheTest.cpp @@ -1561,15 +1561,15 @@ static void test_free_texture_messages(skiatest::Reporter* reporter) { REPORTER_ASSERT(reporter, 0 == (freed[0] + freed[1] + freed[2])); // Send message to free the first resource - GrTextureFreedMessage msg1{wrapped[0], dContext->priv().contextID()}; - SkMessageBus::Post(msg1); + GrTextureFreedMessage msg1{wrapped[0], dContext->directContextID()}; + SkMessageBus::Post(msg1); cache->purgeAsNeeded(); REPORTER_ASSERT(reporter, 1 == (freed[0] + freed[1] + freed[2])); REPORTER_ASSERT(reporter, 1 == freed[0]); - GrTextureFreedMessage msg2{wrapped[2], dContext->priv().contextID()}; - SkMessageBus::Post(msg2); + GrTextureFreedMessage msg2{wrapped[2], dContext->directContextID()}; + SkMessageBus::Post(msg2); cache->purgeAsNeeded(); REPORTER_ASSERT(reporter, 2 == (freed[0] + freed[1] + freed[2])); @@ -1606,13 +1606,13 @@ DEF_GPUTEST(ResourceCacheMisc, reporter, /* options */) { // This simulates a portion of Chrome's context abandonment processing. // Please see: crbug.com/1011368 and crbug.com/1014993 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ResourceMessagesAfterAbandon, reporter, ctxInfo) { - auto context = ctxInfo.directContext(); - GrGpu* gpu = context->priv().getGpu(); - GrResourceCache* cache = context->priv().getResourceCache(); + auto dContext = ctxInfo.directContext(); + GrGpu* gpu = dContext->priv().getGpu(); + GrResourceCache* cache = dContext->priv().getResourceCache(); - GrBackendTexture backend = context->createBackendTexture(16, 16, - SkColorType::kRGBA_8888_SkColorType, - GrMipmapped::kNo, GrRenderable::kNo); + GrBackendTexture backend = dContext->createBackendTexture(16, 16, + SkColorType::kRGBA_8888_SkColorType, + GrMipmapped::kNo, GrRenderable::kNo); GrTexture* tex = gpu->wrapBackendTexture(backend, GrWrapOwnership::kBorrow_GrWrapOwnership, GrWrapCacheable::kYes, @@ -1637,18 +1637,18 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ResourceMessagesAfterAbandon, reporter, ctxIn // We must delete the backend texture before abandoning the context in vulkan. We just do it // for all the backends for consistency. - context->deleteBackendTexture(backend); - context->abandonContext(); + dContext->deleteBackendTexture(backend); + dContext->abandonContext(); REPORTER_ASSERT(reporter, 1 == freed); // In the past, creating this message could cause an exception due to // an un-safe downcast from GrTexture to GrGpuResource - GrTextureFreedMessage msg{tex, context->priv().contextID()}; - SkMessageBus::Post(msg); + GrTextureFreedMessage msg{tex, dContext->directContextID()}; + SkMessageBus::Post(msg); // This doesn't actually do anything but it does trigger us to read messages - context->purgeUnlockedResources(false); + dContext->purgeUnlockedResources(false); } ////////////////////////////////////////////////////////////////////////////////