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 <bsalomon@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Robert Phillips 2021-03-15 08:49:24 -04:00 committed by Skia Commit-Bot
parent e895ab2fc8
commit d074b6293c
7 changed files with 97 additions and 70 deletions

View File

@ -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<GrSemaphore> semaphore)
GrBackendTextureImageGenerator::RefHelper::RefHelper(
GrTexture* texture,
GrDirectContext::DirectContextID owningContextID,
std::unique_ptr<GrSemaphore> 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<GrTextureFreedMessage, uint32_t>::Post(msg);
SkMessageBus<GrTextureFreedMessage, GrDirectContext::DirectContextID>::Post(msg);
}
std::unique_ptr<SkImageGenerator>
GrBackendTextureImageGenerator::Make(sk_sp<GrTexture> texture, GrSurfaceOrigin origin,
std::unique_ptr<GrSemaphore> semaphore, SkColorType colorType,
SkAlphaType alphaType, sk_sp<SkColorSpace> 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<GrTexture> texture, GrSurfaceOrigin o
SkImageInfo info = SkImageInfo::Make(texture->width(), texture->height(), colorType, alphaType,
std::move(colorSpace));
return std::unique_ptr<SkImageGenerator>(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<GrSemaphore> semaphore,
const GrBackendTexture& backendTex)
const SkImageInfo& info,
GrTexture* texture,
GrSurfaceOrigin origin,
GrDirectContext::DirectContextID owningContextID,
std::unique_ptr<GrSemaphore> 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<GrRefCntedCallback> 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,

View File

@ -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<GrSemaphore>,
GrBackendTextureImageGenerator(const SkImageInfo& info,
GrTexture*,
GrSurfaceOrigin,
GrDirectContext::DirectContextID owningContextID,
std::unique_ptr<GrSemaphore>,
const GrBackendTexture&);
static void ReleaseRefHelper_TextureReleaseProc(void* ctx);
class RefHelper : public SkNVRefCnt<RefHelper> {
public:
RefHelper(GrTexture*, uint32_t owningContextID, std::unique_ptr<GrSemaphore>);
RefHelper(GrTexture*,
GrDirectContext::DirectContextID owningContextID,
std::unique_ptr<GrSemaphore>);
~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<GrSemaphore> fSemaphore;
std::unique_ptr<GrSemaphore> fSemaphore;
};
RefHelper* fRefHelper;

View File

@ -209,7 +209,9 @@ bool GrDirectContext::init() {
SkASSERT(this->threadSafeCache());
fStrikeCache = std::make_unique<GrStrikeCache>();
fResourceCache = std::make_unique<GrResourceCache>(this->singleOwner(), this->contextID());
fResourceCache = std::make_unique<GrResourceCache>(this->singleOwner(),
this->directContextID(),
this->contextID());
fResourceCache->setProxyProvider(this->proxyProvider());
fResourceCache->setThreadSafeCache(this->threadSafeCache());
fResourceProvider = std::make_unique<GrResourceProvider>(fGpu.get(), fResourceCache.get(),

View File

@ -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<GrTextureFreedMessage> 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

View File

@ -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<GrTextureFreedMessage,
GrDirectContext::DirectContextID>;
typedef SkMessageBus<GrUniqueKeyInvalidatedMessage, uint32_t>::Inbox InvalidUniqueKeyInbox;
typedef SkMessageBus<GrTextureFreedMessage, uint32_t>::Inbox FreedTextureInbox;
typedef SkTDPQueue<GrGpuResource*, CompareTimestamp, AccessResourceIndex> PurgeableQueue;
typedef SkTDArray<GrGpuResource*> 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;

View File

@ -259,7 +259,8 @@ sk_sp<GrTextureProxy> SkImage_GpuBase::MakePromiseImageLazyProxy(
// In the future the GrSurface class hierarchy refactoring should eliminate this
// difficulty by removing the virtual inheritance.
if (fTexture) {
SkMessageBus<GrTextureFreedMessage, uint32_t>::Post({fTexture, fTextureContextID});
GrTextureFreedMessage msg { fTexture, fTextureContextID };
SkMessageBus<GrTextureFreedMessage, GrDirectContext::DirectContextID>::Post(msg);
}
}
@ -313,7 +314,7 @@ sk_sp<GrTextureProxy> 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<GrTextureProxy> SkImage_GpuBase::MakePromiseImageLazyProxy(
PromiseImageTextureFulfillProc fFulfillProc;
sk_sp<GrRefCntedCallback> fReleaseHelper;
GrTexture* fTexture = nullptr;
uint32_t fTextureContextID = SK_InvalidUniqueID;
GrDirectContext::DirectContextID fTextureContextID;
bool fFulfillProcFailed = false;
} callback(fulfillProc, std::move(releaseHelper));

View File

@ -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<GrTextureFreedMessage, uint32_t>::Post(msg1);
GrTextureFreedMessage msg1{wrapped[0], dContext->directContextID()};
SkMessageBus<GrTextureFreedMessage, GrDirectContext::DirectContextID>::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<GrTextureFreedMessage, uint32_t>::Post(msg2);
GrTextureFreedMessage msg2{wrapped[2], dContext->directContextID()};
SkMessageBus<GrTextureFreedMessage, GrDirectContext::DirectContextID>::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<GrTextureFreedMessage, uint32_t>::Post(msg);
GrTextureFreedMessage msg{tex, dContext->directContextID()};
SkMessageBus<GrTextureFreedMessage, GrDirectContext::DirectContextID>::Post(msg);
// This doesn't actually do anything but it does trigger us to read messages
context->purgeUnlockedResources(false);
dContext->purgeUnlockedResources(false);
}
////////////////////////////////////////////////////////////////////////////////