GrBackendTextureImageGenerator proxy callback uses unique key to find existing GrTexture.

This removes a case where we can get the first ref on a GrGpuResource outside of
GrResourceCache.

Bug: skia:8927
Change-Id: I4068aff2f91a2e11ada059f4ef406a620140319b
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/204770
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Brian Salomon 2019-04-01 13:34:34 -04:00 committed by Skia Commit-Bot
parent acc10fa32b
commit b916b7b227
2 changed files with 43 additions and 35 deletions

View File

@ -24,8 +24,14 @@
#include "SkMessageBus.h"
#include "gl/GrGLTexture.h"
GrBackendTextureImageGenerator::RefHelper::RefHelper(GrTexture* texture, uint32_t owningContextID)
: fOriginalTexture(texture)
, fOwningContextID(owningContextID)
, fBorrowingContextReleaseProc(nullptr)
, fBorrowingContextID(SK_InvalidGenID) {}
GrBackendTextureImageGenerator::RefHelper::~RefHelper() {
SkASSERT(nullptr == fBorrowedTexture);
SkASSERT(fBorrowingContextID == SK_InvalidUniqueID);
// 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.
@ -68,12 +74,12 @@ GrBackendTextureImageGenerator::GrBackendTextureImageGenerator(const SkImageInfo
uint32_t owningContextID,
sk_sp<GrSemaphore> semaphore,
const GrBackendTexture& backendTex)
: INHERITED(info)
, fRefHelper(new RefHelper(texture, owningContextID))
, fSemaphore(std::move(semaphore))
, fBackendTexture(backendTex)
, fConfig(backendTex.config())
, fSurfaceOrigin(origin) { }
: INHERITED(info)
, fRefHelper(new RefHelper(texture, owningContextID))
, fSemaphore(std::move(semaphore))
, fBackendTexture(backendTex)
, fConfig(backendTex.config())
, fSurfaceOrigin(origin) {}
GrBackendTextureImageGenerator::~GrBackendTextureImageGenerator() {
fRefHelper->unref();
@ -85,7 +91,6 @@ void GrBackendTextureImageGenerator::ReleaseRefHelper_TextureReleaseProc(void* c
RefHelper* refHelper = static_cast<RefHelper*>(ctx);
SkASSERT(refHelper);
refHelper->fBorrowedTexture = nullptr;
refHelper->fBorrowingContextReleaseProc = nullptr;
refHelper->fBorrowingContextID = SK_InvalidGenID;
refHelper->unref();
@ -126,6 +131,11 @@ sk_sp<GrTextureProxy> GrBackendTextureImageGenerator::onGenerateTexture(
fRefHelper->fBorrowingContextReleaseProc = releaseProcHelper.get();
}
fRefHelper->fBorrowingContextID = context->priv().contextID();
if (!fRefHelper->fBorrowedTextureKey.isValid()) {
static const auto kDomain = GrUniqueKey::GenerateDomain();
GrUniqueKey::Builder builder(&fRefHelper->fBorrowedTextureKey, kDomain, 1);
builder[0] = this->uniqueID();
}
fBorrowingMutex.release();
SkASSERT(fRefHelper->fBorrowingContextID == context->priv().contextID());
@ -149,14 +159,17 @@ sk_sp<GrTextureProxy> GrBackendTextureImageGenerator::onGenerateTexture(
resourceProvider->priv().gpu()->waitSemaphore(semaphore);
}
// If a client re-draws the same image multiple times, the texture we return
// will be cached and re-used. If they draw a subset, though, we may be
// re-called. In that case, we want to re-use the borrowed texture we've
// previously created.
sk_sp<GrTexture> tex;
if (refHelper->fBorrowedTexture) {
// If a client re-draws the same image multiple times, the texture we return
// will be cached and re-used. If they draw a subset, though, we may be
// re-called. In that case, we want to re-use the borrowed texture we've
// previously created.
tex = sk_ref_sp(refHelper->fBorrowedTexture);
SkASSERT(tex);
SkASSERT(refHelper->fBorrowedTextureKey.isValid());
auto surf = resourceProvider->findByUniqueKey<GrSurface>(
refHelper->fBorrowedTextureKey);
if (surf) {
SkASSERT(surf->asTexture());
tex = sk_ref_sp(surf->asTexture());
} else {
// We just gained access to the texture. If we're on the original context, we
// could use the original texture, but we'd have no way of detecting that it's
@ -171,11 +184,12 @@ sk_sp<GrTextureProxy> GrBackendTextureImageGenerator::onGenerateTexture(
if (!tex) {
return {};
}
refHelper->fBorrowedTexture = tex.get();
tex->setRelease(releaseProcHelper);
tex->resourcePriv().setUniqueKey(refHelper->fBorrowedTextureKey);
}
return std::move(tex);
// We use keys to avoid re-wrapping the GrBackendTexture in a GrTexture. This is
// unrelated to the whatever SkImage key may be assigned to the proxy.
return {std::move(tex), GrSurfaceProxy::LazyInstantiationKeyMode::kUnsynced};
},
format, desc, fSurfaceOrigin, mipMapped, GrInternalSurfaceFlags::kReadOnly,
SkBackingFit::kExact, SkBudgeted::kNo);

View File

@ -7,9 +7,9 @@
#ifndef GrBackendTextureImageGenerator_DEFINED
#define GrBackendTextureImageGenerator_DEFINED
#include "SkImageGenerator.h"
#include "GrBackendSurface.h"
#include "GrResourceKey.h"
#include "SkImageGenerator.h"
#include "SkMutex.h"
class GrSemaphore;
@ -52,27 +52,21 @@ private:
class RefHelper : public SkNVRefCnt<RefHelper> {
public:
RefHelper(GrTexture* texture, uint32_t owningContextID)
: fOriginalTexture(texture)
, fOwningContextID(owningContextID)
, fBorrowedTexture(nullptr)
, fBorrowingContextReleaseProc(nullptr)
, fBorrowingContextID(SK_InvalidGenID) {}
RefHelper(GrTexture*, uint32_t owningContextID);
~RefHelper();
GrTexture* fOriginalTexture;
uint32_t fOwningContextID;
// There is never a 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 lets us
// avoid releasing a ref from another thread, or get into races during context shutdown.
GrTexture* fBorrowedTexture;
// For the same reason as the fBorrowedTexture, there is no ref associated with this
// pointer. The fBorrowingContextReleaseProc 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.
// 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;
// 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;
};