Control access to adding ref to a GrGpuResource when it's ref count is zero.

We want GrResourceCache to be able to track which resources are held by
refs (as opposed to pending IOs) so that it can track the affect of
flushing on resource purgeability. Therefore, all cases that can add the
first ref to a GrGpuResource must funnel through GrResourceCache. This
lays the groundwork by restricting initial refs.

No-Presubmit: true
No-Tree-Checks: true
No-Try: true

Bug: skia:8927
Change-Id: I1213c3db258d2412df6666e3222419211ceaa192
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/205482
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Brian Salomon 2019-04-02 11:49:54 -04:00 committed by Skia Commit-Bot
parent c1c686b4d4
commit 01ceae9352
7 changed files with 90 additions and 17 deletions

View File

@ -53,6 +53,8 @@ public:
// refs (e.g. pending reads). We also don't require thread safety as GrCacheable objects are
// not intended to cross thread boundaries.
void ref() const {
// Only the cache should be able to add the first ref to a resource.
SkASSERT(fRefCnt > 0);
this->validate();
++fRefCnt;
}
@ -100,6 +102,12 @@ protected:
bool internalHasRef() const { return SkToBool(fRefCnt); }
bool internalHasUniqueRef() const { return fRefCnt == 1; }
// Privileged method that allows going from ref count = 0 to ref count = 1.
void addInitialRef() const {
this->validate();
++fRefCnt;
}
private:
// This is for a unit test.
template <typename T>
@ -226,6 +234,12 @@ public:
inline CacheAccess cacheAccess();
inline const CacheAccess cacheAccess() const;
/**
* Internal-only helper class used for manipulations of the resource by GrSurfaceProxy.
*/
class ProxyAccess;
inline ProxyAccess proxyAccess();
/**
* Internal-only helper class used for manipulations of the resource by internal code.
*/
@ -361,4 +375,24 @@ private:
friend class GrIORef<GrGpuResource>; // to access notifyAllCntsAreZero and notifyRefCntIsZero.
};
class GrGpuResource::ProxyAccess {
private:
ProxyAccess(GrGpuResource* resource) : fResource(resource) {}
/** Proxies are allowed to take a resource from no refs to one ref. */
void ref() { fResource->addInitialRef(); }
// No taking addresses of this type.
const CacheAccess* operator&() const = delete;
CacheAccess* operator&() = delete;
GrGpuResource* fResource;
friend class GrGpuResource;
friend class GrSurfaceProxy;
friend class GrIORefProxy;
};
inline GrGpuResource::ProxyAccess GrGpuResource::proxyAccess() { return ProxyAccess(this); }
#endif

View File

@ -18,7 +18,6 @@
class GrCaps;
class GrContext_Base;
class GrOpList;
class GrProxyProvider;
class GrRecordingContext;
class GrRenderTargetOpList;
class GrRenderTargetProxy;
@ -152,6 +151,15 @@ protected:
// have forwarded on the unref call that got us here.
}
// Privileged method that allows going from ref count = 0 to ref count = 1.
void addInitialRef() const {
this->validate();
++fRefCnt;
if (fTarget) {
fTarget->proxyAccess().ref();
}
}
// This GrIORefProxy was deferred before but has just been instantiated. To
// make all the reffing & unreffing work out we now need to transfer any deferred
// refs & unrefs to the new GrSurface
@ -458,6 +466,13 @@ public:
inline GrSurfaceProxyPriv priv();
inline const GrSurfaceProxyPriv priv() const;
/**
* Provides privileged access to select callers to be able to add a ref to a GrSurfaceProxy
* with zero refs.
*/
class FirstRefAccess;
inline FirstRefAccess firstRefAccess();
GrInternalSurfaceFlags testingOnly_getFlags() const;
protected:
@ -568,4 +583,25 @@ private:
typedef GrIORefProxy INHERITED;
};
class GrSurfaceProxy::FirstRefAccess {
private:
void ref() { fProxy->addInitialRef(); }
FirstRefAccess(GrSurfaceProxy* proxy) : fProxy(proxy) {}
// No taking addresses of this type.
const FirstRefAccess* operator&() const = delete;
FirstRefAccess* operator&() = delete;
GrSurfaceProxy* fProxy;
friend class GrSurfaceProxy;
friend class GrProxyProvider;
friend class GrDeinstantiateProxyTracker;
};
inline GrSurfaceProxy::FirstRefAccess GrSurfaceProxy::firstRefAccess() {
return FirstRefAccess(this);
}
#endif

View File

@ -18,7 +18,8 @@ void GrDeinstantiateProxyTracker::addProxy(GrSurfaceProxy* proxy) {
SkASSERT(proxy != fProxies[i].get());
}
#endif
fProxies.push_back(sk_ref_sp(proxy));
proxy->firstRefAccess().ref();
fProxies.push_back(sk_sp<GrSurfaceProxy>(proxy));
}
void GrDeinstantiateProxyTracker::deinstantiateAllProxies() {

View File

@ -20,6 +20,9 @@ namespace skiatest {
*/
class GrGpuResource::CacheAccess {
private:
/** The cache is allowed to go from no refs to 1 ref. */
void ref() { fResource->addInitialRef(); }
/**
* Is the resource currently cached as scratch? This means it is cached, has a valid scratch
* key, and does not have a unique key.
@ -78,8 +81,8 @@ private:
CacheAccess& operator=(const CacheAccess&); // unimpl
// No taking addresses of this type.
const CacheAccess* operator&() const;
CacheAccess* operator&();
const CacheAccess* operator&() const = delete;
CacheAccess* operator&() = delete;
GrGpuResource* fResource;

View File

@ -102,8 +102,11 @@ sk_sp<GrTextureProxy> GrProxyProvider::findProxyByUniqueKey(const GrUniqueKey& k
return nullptr;
}
sk_sp<GrTextureProxy> result = sk_ref_sp(fUniquelyKeyedProxies.find(key));
if (result) {
GrTextureProxy* proxy = fUniquelyKeyedProxies.find(key);
sk_sp<GrTextureProxy> result;
if (proxy) {
proxy->firstRefAccess().ref();
result.reset(proxy);
SkASSERT(result->origin() == origin);
}
return result;
@ -790,15 +793,10 @@ void GrProxyProvider::processInvalidUniqueKey(const GrUniqueKey& key, GrTextureP
// proxy's unique key. We must do it in this order because 'key' may alias the proxy's key.
sk_sp<GrGpuResource> invalidGpuResource;
if (InvalidateGPUResource::kYes == invalidateGPUResource) {
if (proxy && proxy->isInstantiated()) {
invalidGpuResource = sk_ref_sp(proxy->peekSurface());
}
if (!invalidGpuResource) {
GrContext* direct = fImageContext->priv().asDirectContext();
if (direct) {
GrResourceProvider* resourceProvider = direct->priv().resourceProvider();
invalidGpuResource = resourceProvider->findByUniqueKey<GrGpuResource>(key);
}
GrContext* direct = fImageContext->priv().asDirectContext();
if (direct) {
GrResourceProvider* resourceProvider = direct->priv().resourceProvider();
invalidGpuResource = resourceProvider->findByUniqueKey<GrGpuResource>(key);
}
SkASSERT(!invalidGpuResource || invalidGpuResource->getUniqueKey() == key);
}

View File

@ -410,7 +410,7 @@ void GrResourceCache::refAndMakeResourceMRU(GrGpuResource* resource) {
fPurgeableQueue.remove(resource);
this->addToNonpurgeableArray(resource);
}
resource->ref();
resource->cacheAccess().ref();
resource->cacheAccess().setTimestamp(this->getNextTimestamp());
this->validate();

View File

@ -337,7 +337,8 @@ private:
*testExecuteValue = 1;
return {};
}
return rp->createTexture(desc, SkBudgeted::kNo);
return {rp->createTexture(desc, SkBudgeted::kNo),
GrSurfaceProxy::LazyInstantiationKeyMode::kUnsynced};
},
format, desc, kTopLeft_GrSurfaceOrigin, GrMipMapped::kNo, SkBackingFit::kExact,
SkBudgeted::kNo);