Add native caching of uniquely keyed GrTextureProxies (take 2)
TBR=bsalomon@google.com Change-Id: I590dcdc85fb60706c7eb06277694791dc04c9141 Reviewed-on: https://skia-review.googlesource.com/49543 Reviewed-by: Brian Salomon <bsalomon@google.com> Commit-Queue: Robert Phillips <robertphillips@google.com>
This commit is contained in:
parent
48497462c1
commit
ae7d3f3992
@ -152,7 +152,7 @@ public:
|
||||
: SkImageGenerator(info)
|
||||
, fCtx(SkRef(ctx)) {
|
||||
|
||||
sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info, 0,
|
||||
sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kYes, info, 0,
|
||||
kTopLeft_GrSurfaceOrigin, nullptr));
|
||||
if (surface) {
|
||||
surface->getCanvas()->clear(0);
|
||||
@ -188,7 +188,7 @@ protected:
|
||||
sk_sp<GrSurfaceContext> dstContext(fCtx->contextPriv().makeDeferredSurfaceContext(
|
||||
desc,
|
||||
SkBackingFit::kExact,
|
||||
SkBudgeted::kNo));
|
||||
SkBudgeted::kYes));
|
||||
if (!dstContext) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -185,6 +185,7 @@ skia_gpu_sources = [
|
||||
"$_src/gpu/GrTessellator.h",
|
||||
"$_src/gpu/GrTextureOpList.cpp",
|
||||
"$_src/gpu/GrTextureOpList.h",
|
||||
"$_src/gpu/GrTextureProxyCacheAccess.h",
|
||||
"$_src/gpu/GrTracing.h",
|
||||
"$_src/gpu/GrTestUtils.cpp",
|
||||
"$_src/gpu/GrTestUtils.h",
|
||||
|
@ -248,6 +248,7 @@ tests_sources = [
|
||||
"$_tests/TestUtils.cpp",
|
||||
"$_tests/TextBlobCacheTest.cpp",
|
||||
"$_tests/TextBlobTest.cpp",
|
||||
"$_tests/TextureProxyTest.cpp",
|
||||
"$_tests/Time.cpp",
|
||||
"$_tests/TLSTest.cpp",
|
||||
"$_tests/TopoSortTest.cpp",
|
||||
|
@ -378,7 +378,7 @@ protected:
|
||||
|
||||
bool instantiateImpl(GrResourceProvider* resourceProvider, int sampleCnt, bool needsStencil,
|
||||
GrSurfaceFlags flags, bool isMipMapped,
|
||||
SkDestinationSurfaceColorMode mipColorMode);
|
||||
SkDestinationSurfaceColorMode mipColorMode, const GrUniqueKey*);
|
||||
|
||||
// For wrapped resources, 'fConfig', 'fWidth', 'fHeight', and 'fOrigin; will always be filled in
|
||||
// from the wrapped resource.
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "GrSurfaceProxy.h"
|
||||
|
||||
class GrCaps;
|
||||
class GrResourceCache;
|
||||
class GrResourceProvider;
|
||||
class GrTextureOpList;
|
||||
|
||||
@ -38,6 +39,31 @@ public:
|
||||
|
||||
bool isMipMapped() const { return fIsMipMapped; }
|
||||
|
||||
/**
|
||||
* Return the texture proxy's unique key. It will be invalid if the proxy doesn't have one.
|
||||
*/
|
||||
const GrUniqueKey& getUniqueKey() const {
|
||||
#ifdef SK_DEBUG
|
||||
if (fTarget && fUniqueKey.isValid()) {
|
||||
SkASSERT(fTarget->getUniqueKey().isValid());
|
||||
// It is possible for a non-keyed proxy to have a uniquely keyed resource assigned to
|
||||
// it. This just means that a future user of the resource will be filling it with unique
|
||||
// data. However, if the proxy has a unique key its attached resource should also
|
||||
// have that key.
|
||||
SkASSERT(fUniqueKey == fTarget->getUniqueKey());
|
||||
}
|
||||
#endif
|
||||
|
||||
return fUniqueKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal-only helper class used for manipulations of the resource by the cache.
|
||||
*/
|
||||
class CacheAccess;
|
||||
inline CacheAccess cacheAccess();
|
||||
inline const CacheAccess cacheAccess() const;
|
||||
|
||||
protected:
|
||||
friend class GrSurfaceProxy; // for ctors
|
||||
|
||||
@ -47,6 +73,8 @@ protected:
|
||||
// Wrapped version
|
||||
GrTextureProxy(sk_sp<GrSurface>, GrSurfaceOrigin);
|
||||
|
||||
~GrTextureProxy() override;
|
||||
|
||||
SkDestinationSurfaceColorMode mipColorMode() const { return fMipColorMode; }
|
||||
|
||||
sk_sp<GrSurface> createSurface(GrResourceProvider*) const override;
|
||||
@ -55,8 +83,15 @@ private:
|
||||
bool fIsMipMapped;
|
||||
SkDestinationSurfaceColorMode fMipColorMode;
|
||||
|
||||
GrUniqueKey fUniqueKey;
|
||||
GrResourceCache* fCache; // only set when fUniqueKey is valid
|
||||
|
||||
size_t onUninstantiatedGpuMemorySize() const override;
|
||||
|
||||
// Methods made available via GrTextureProxy::CacheAccess
|
||||
void setUniqueKey(GrResourceCache*, const GrUniqueKey&);
|
||||
void clearUniqueKey();
|
||||
|
||||
// For wrapped proxies the GrTexture pointer is stored in GrIORefProxy.
|
||||
// For deferred proxies that pointer will be filled in when we need to instantiate
|
||||
// the deferred resource
|
||||
|
@ -53,7 +53,6 @@ sk_sp<GrTextureProxy> GrBitmapTextureMaker::refOriginalTextureProxy(bool willBeM
|
||||
if (proxy && fOriginalKey.isValid()) {
|
||||
SkASSERT(proxy->origin() == kTopLeft_GrSurfaceOrigin);
|
||||
this->context()->resourceProvider()->assignUniqueKeyToProxy(fOriginalKey, proxy.get());
|
||||
// MDB TODO (caching): this has to play nice with the GrSurfaceProxy's caching
|
||||
GrInstallBitmapUniqueKeyInvalidator(fOriginalKey, fBitmap.pixelRef());
|
||||
}
|
||||
return proxy;
|
||||
|
@ -420,7 +420,6 @@ sk_sp<GrTextureProxy> GrClipStackClip::createAlphaClipMask(GrContext* context,
|
||||
|
||||
SkASSERT(result->origin() == kBottomLeft_GrSurfaceOrigin);
|
||||
resourceProvider->assignUniqueKeyToProxy(key, result.get());
|
||||
// MDB TODO (caching): this has to play nice with the GrSurfaceProxy's caching
|
||||
add_invalidate_on_pop_message(*fStack, reducedClip.elementsGenID(), key);
|
||||
|
||||
return result;
|
||||
@ -559,7 +558,6 @@ sk_sp<GrTextureProxy> GrClipStackClip::createSoftwareClipMask(
|
||||
|
||||
SkASSERT(proxy->origin() == kTopLeft_GrSurfaceOrigin);
|
||||
context->resourceProvider()->assignUniqueKeyToProxy(key, proxy.get());
|
||||
// MDB TODO (caching): this has to play nice with the GrSurfaceProxy's caching
|
||||
add_invalidate_on_pop_message(*fStack, reducedClip.elementsGenID(), key);
|
||||
return proxy;
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ bool GrRenderTargetProxy::instantiate(GrResourceProvider* resourceProvider) {
|
||||
|
||||
if (!this->instantiateImpl(resourceProvider, fSampleCnt, fNeedsStencil, kFlags,
|
||||
/* isMipped = */ false,
|
||||
SkDestinationSurfaceColorMode::kLegacy)) {
|
||||
SkDestinationSurfaceColorMode::kLegacy, nullptr)) {
|
||||
return false;
|
||||
}
|
||||
SkASSERT(fTarget->asRenderTarget());
|
||||
|
@ -10,6 +10,8 @@
|
||||
|
||||
#include "GrCaps.h"
|
||||
#include "GrGpuResourceCacheAccess.h"
|
||||
#include "GrTexture.h"
|
||||
#include "GrTextureProxyCacheAccess.h"
|
||||
#include "GrTracing.h"
|
||||
#include "SkGr.h"
|
||||
#include "SkMessageBus.h"
|
||||
@ -578,6 +580,8 @@ void GrResourceCache::purgeUnlockedResources(size_t bytesToPurge, bool preferScr
|
||||
void GrResourceCache::processInvalidUniqueKeys(
|
||||
const SkTArray<GrUniqueKeyInvalidatedMessage>& msgs) {
|
||||
for (int i = 0; i < msgs.count(); ++i) {
|
||||
this->processInvalidProxyUniqueKey(msgs[i].key());
|
||||
|
||||
GrGpuResource* resource = this->findAndRefUniqueResource(msgs[i].key());
|
||||
if (resource) {
|
||||
resource->resourcePriv().removeUniqueKey();
|
||||
@ -847,3 +851,63 @@ bool GrResourceCache::isInCache(const GrGpuResource* resource) const {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void GrResourceCache::assignUniqueKeyToProxy(const GrUniqueKey& key, GrTextureProxy* proxy) {
|
||||
SkASSERT(key.isValid());
|
||||
SkASSERT(proxy);
|
||||
|
||||
// If there is already a GrResource with this key then the caller has violated the normal
|
||||
// usage pattern of uniquely keyed resources (e.g., they have created one w/o first seeing
|
||||
// if it already existed in the cache).
|
||||
SkASSERT(!this->findAndRefUniqueResource(key));
|
||||
|
||||
// Uncached resources can never have a unique key, unless they're wrapped resources. Wrapped
|
||||
// resources are a special case: the unique keys give us a weak ref so that we can reuse the
|
||||
// same resource (rather than re-wrapping). When a wrapped resource is no longer referenced,
|
||||
// it will always be released - it is never converted to a scratch resource.
|
||||
if (SkBudgeted::kNo == proxy->isBudgeted() &&
|
||||
(!proxy->priv().isInstantiated() ||
|
||||
!proxy->priv().peekSurface()->resourcePriv().refsWrappedObjects())) {
|
||||
return;
|
||||
}
|
||||
|
||||
SkASSERT(!fUniquelyKeyedProxies.find(key)); // multiple proxies can't get the same key
|
||||
|
||||
proxy->cacheAccess().setUniqueKey(this, key);
|
||||
SkASSERT(proxy->getUniqueKey() == key);
|
||||
fUniquelyKeyedProxies.add(proxy);
|
||||
}
|
||||
|
||||
sk_sp<GrTextureProxy> GrResourceCache::findProxyByUniqueKey(const GrUniqueKey& key,
|
||||
GrSurfaceOrigin origin) {
|
||||
|
||||
sk_sp<GrTextureProxy> result = sk_ref_sp(fUniquelyKeyedProxies.find(key));
|
||||
if (result) {
|
||||
SkASSERT(result->origin() == origin);
|
||||
return result;
|
||||
}
|
||||
|
||||
GrGpuResource* resource = findAndRefUniqueResource(key);
|
||||
if (!resource) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sk_sp<GrTexture> texture(static_cast<GrSurface*>(resource)->asTexture());
|
||||
SkASSERT(texture);
|
||||
|
||||
result = GrSurfaceProxy::MakeWrapped(std::move(texture), origin);
|
||||
SkASSERT(result->getUniqueKey() == key);
|
||||
fUniquelyKeyedProxies.add(result.get());
|
||||
return result;
|
||||
}
|
||||
|
||||
void GrResourceCache::processInvalidProxyUniqueKey(const GrUniqueKey& key) {
|
||||
// Note: this method is called for the whole variety of GrGpuResources so often 'key'
|
||||
// will not be in 'fUniquelyKeyedProxies'.
|
||||
GrTextureProxy* proxy = fUniquelyKeyedProxies.find(key);
|
||||
if (proxy) {
|
||||
fUniquelyKeyedProxies.remove(key);
|
||||
proxy->cacheAccess().clearUniqueKey();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "GrGpuResourcePriv.h"
|
||||
#include "GrResourceCache.h"
|
||||
#include "GrResourceKey.h"
|
||||
#include "GrTextureProxy.h"
|
||||
#include "SkMessageBus.h"
|
||||
#include "SkRefCnt.h"
|
||||
#include "SkTArray.h"
|
||||
@ -156,6 +157,48 @@ public:
|
||||
return resource;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// TextureProxies & GrUniqueKeys
|
||||
//
|
||||
// The two GrResourceCache methods assignUniqueKeyToProxy and findProxyByUniqueKey drive
|
||||
// the behavior of uniqueKeys on proxies.
|
||||
//
|
||||
// assignUniqueKeyToProxy does the following:
|
||||
// if the proxy is wrapped, it sets the texture & proxy keys & adds the proxy to the hash
|
||||
// if the proxy is deferred, it just set the unique key on the proxy & adds it to the hash
|
||||
//
|
||||
// Note that when a deferred proxy with a unique key is instantiated, its unique key will be
|
||||
// pushed to the backing resource.
|
||||
//
|
||||
// Futher note, a proxy can only receive a unique key once. It can be removed if Ganesh
|
||||
// determines that the key will never be used again but, in that case, the proxy should
|
||||
// never receive another key.
|
||||
//
|
||||
// findProxyByUniqueKey does the following:
|
||||
// first looks in the UniqueKeyProxy hash table to see if there is already a proxy w/ the key
|
||||
// failing that it looks in the ResourceCache to see there is a texture with that key
|
||||
// if so, it will wrap the texture in a proxy, add the proxy to the hash and return it
|
||||
// failing that it will return null
|
||||
|
||||
/*
|
||||
* Associate the provided proxy with the provided unique key.
|
||||
*/
|
||||
void assignUniqueKeyToProxy(const GrUniqueKey&, GrTextureProxy*);
|
||||
|
||||
/**
|
||||
* Find a texture proxy that is associated with the provided unique key.
|
||||
*/
|
||||
sk_sp<GrTextureProxy> findProxyByUniqueKey(const GrUniqueKey&, GrSurfaceOrigin);
|
||||
|
||||
/**
|
||||
* Either the proxy attached to the unique key is being deleted (in which case we
|
||||
* don't want it cluttering up the hash table) or the client has indicated that
|
||||
* it will never refer to the unique key again. In either case, remove the key
|
||||
* from the hash table.
|
||||
* Note: this does not, by itself, alter unique key attached to the underlying GrTexture.
|
||||
*/
|
||||
void processInvalidProxyUniqueKey(const GrUniqueKey&);
|
||||
|
||||
/**
|
||||
* Query whether a unique key exists in the cache.
|
||||
*/
|
||||
@ -249,6 +292,8 @@ public:
|
||||
// Enumerates all cached resources and dumps their details to traceMemoryDump.
|
||||
void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const;
|
||||
|
||||
int numUniqueKeyProxies_TestOnly() const;
|
||||
|
||||
private:
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
/// @name Methods accessible via ResourceAccess
|
||||
@ -303,6 +348,13 @@ private:
|
||||
};
|
||||
typedef SkTDynamicHash<GrGpuResource, GrUniqueKey, UniqueHashTraits> UniqueHash;
|
||||
|
||||
struct UniquelyKeyedProxyHashTraits {
|
||||
static const GrUniqueKey& GetKey(const GrTextureProxy& p) { return p.getUniqueKey(); }
|
||||
|
||||
static uint32_t Hash(const GrUniqueKey& key) { return key.hash(); }
|
||||
};
|
||||
typedef SkTDynamicHash<GrTextureProxy, GrUniqueKey, UniquelyKeyedProxyHashTraits> UniquelyKeyedProxyHash;
|
||||
|
||||
static bool CompareTimestamp(GrGpuResource* const& a, GrGpuResource* const& b) {
|
||||
return a->cacheAccess().timestamp() < b->cacheAccess().timestamp();
|
||||
}
|
||||
@ -327,6 +379,9 @@ private:
|
||||
ScratchMap fScratchMap;
|
||||
// This holds all resources that have unique keys.
|
||||
UniqueHash fUniqueHash;
|
||||
// This holds the texture proxies that have unique keys. The resourceCache does not get a ref
|
||||
// on these proxies but they must send a message to the resourceCache when they are deleted.
|
||||
UniquelyKeyedProxyHash fUniquelyKeyedProxies;
|
||||
|
||||
// our budget, used in purgeAsNeeded()
|
||||
int fMaxCount;
|
||||
|
@ -292,7 +292,6 @@ void GrResourceProvider::assignUniqueKeyToTexture(const GrUniqueKey& key, GrText
|
||||
this->assignUniqueKeyToResource(key, texture);
|
||||
}
|
||||
|
||||
// MDB TODO (caching): this side-steps the issue of texture proxies with unique IDs
|
||||
void GrResourceProvider::assignUniqueKeyToProxy(const GrUniqueKey& key, GrTextureProxy* proxy) {
|
||||
ASSERT_SINGLE_OWNER
|
||||
SkASSERT(key.isValid());
|
||||
@ -300,25 +299,13 @@ void GrResourceProvider::assignUniqueKeyToProxy(const GrUniqueKey& key, GrTextur
|
||||
return;
|
||||
}
|
||||
|
||||
if (!proxy->instantiate(this)) {
|
||||
return;
|
||||
}
|
||||
GrTexture* texture = proxy->priv().peekTexture();
|
||||
|
||||
this->assignUniqueKeyToResource(key, texture);
|
||||
fCache->assignUniqueKeyToProxy(key, proxy);
|
||||
}
|
||||
|
||||
// MDB TODO (caching): this side-steps the issue of texture proxies with unique IDs
|
||||
sk_sp<GrTextureProxy> GrResourceProvider::findProxyByUniqueKey(const GrUniqueKey& key,
|
||||
GrSurfaceOrigin origin) {
|
||||
ASSERT_SINGLE_OWNER
|
||||
|
||||
sk_sp<GrTexture> texture(this->findAndRefTextureByUniqueKey(key));
|
||||
if (!texture) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return GrSurfaceProxy::MakeWrapped(std::move(texture), origin);
|
||||
return this->isAbandoned() ? nullptr : fCache->findProxyByUniqueKey(key, origin);
|
||||
}
|
||||
|
||||
const GrBuffer* GrResourceProvider::createPatternedIndexBuffer(const uint16_t* pattern,
|
||||
|
@ -45,18 +45,20 @@ public:
|
||||
return static_cast<T*>(this->findAndRefResourceByUniqueKey(key));
|
||||
}
|
||||
|
||||
/*
|
||||
* Assigns a unique key to a proxy. The proxy will be findable via this key using
|
||||
* findProxyByUniqueKey(). It is an error if an existing proxy already has a key.
|
||||
*/
|
||||
void assignUniqueKeyToProxy(const GrUniqueKey&, GrTextureProxy*);
|
||||
|
||||
/*
|
||||
* Finds a proxy by unique key.
|
||||
*/
|
||||
sk_sp<GrTextureProxy> findProxyByUniqueKey(const GrUniqueKey&, GrSurfaceOrigin);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Textures
|
||||
|
||||
/** Assigns a unique key to the texture. The texture will be findable via this key using
|
||||
findTextureByUniqueKey(). If an existing texture has this key, it's key will be removed. */
|
||||
void assignUniqueKeyToProxy(const GrUniqueKey& key, GrTextureProxy*);
|
||||
|
||||
/** Finds a texture by unique key. If the texture is found it is ref'ed and returned. */
|
||||
// MDB TODO (caching): If this were actually caching proxies (rather than shallowly
|
||||
// wrapping GrSurface caching) we would not need the origin parameter.
|
||||
sk_sp<GrTextureProxy> findProxyByUniqueKey(const GrUniqueKey& key, GrSurfaceOrigin);
|
||||
|
||||
/**
|
||||
* Finds a texture that approximately matches the descriptor. Will be at least as large in width
|
||||
* and height as desc specifies. If desc specifies that the texture should be a render target
|
||||
|
@ -109,8 +109,12 @@ void GrSurfaceProxy::assign(sk_sp<GrSurface> surface) {
|
||||
|
||||
bool GrSurfaceProxy::instantiateImpl(GrResourceProvider* resourceProvider, int sampleCnt,
|
||||
bool needsStencil, GrSurfaceFlags flags, bool isMipMapped,
|
||||
SkDestinationSurfaceColorMode mipColorMode) {
|
||||
SkDestinationSurfaceColorMode mipColorMode,
|
||||
const GrUniqueKey* uniqueKey) {
|
||||
if (fTarget) {
|
||||
if (uniqueKey) {
|
||||
SkASSERT(fTarget->getUniqueKey() == *uniqueKey);
|
||||
}
|
||||
return attach_stencil_if_needed(resourceProvider, fTarget, needsStencil);
|
||||
}
|
||||
|
||||
@ -120,6 +124,10 @@ bool GrSurfaceProxy::instantiateImpl(GrResourceProvider* resourceProvider, int s
|
||||
return false;
|
||||
}
|
||||
|
||||
if (uniqueKey) {
|
||||
resourceProvider->assignUniqueKeyToResource(*uniqueKey, surface.get());
|
||||
}
|
||||
|
||||
this->assign(std::move(surface));
|
||||
return true;
|
||||
}
|
||||
|
@ -7,25 +7,46 @@
|
||||
|
||||
#include "GrTextureProxy.h"
|
||||
|
||||
#include "GrContext.h"
|
||||
#include "GrResourceCache.h"
|
||||
|
||||
#include "GrTexturePriv.h"
|
||||
|
||||
GrTextureProxy::GrTextureProxy(const GrSurfaceDesc& srcDesc, SkBackingFit fit, SkBudgeted budgeted,
|
||||
const void* srcData, size_t /*rowBytes*/, uint32_t flags)
|
||||
: INHERITED(srcDesc, fit, budgeted, flags)
|
||||
, fIsMipMapped(srcDesc.fIsMipMapped)
|
||||
, fMipColorMode(SkDestinationSurfaceColorMode::kLegacy) {
|
||||
, fMipColorMode(SkDestinationSurfaceColorMode::kLegacy)
|
||||
, fCache(nullptr) {
|
||||
SkASSERT(!srcData); // currently handled in Make()
|
||||
}
|
||||
|
||||
GrTextureProxy::GrTextureProxy(sk_sp<GrSurface> surf, GrSurfaceOrigin origin)
|
||||
: INHERITED(std::move(surf), origin, SkBackingFit::kExact)
|
||||
, fIsMipMapped(fTarget->asTexture()->texturePriv().hasMipMaps())
|
||||
, fMipColorMode(fTarget->asTexture()->texturePriv().mipColorMode()) {
|
||||
, fMipColorMode(fTarget->asTexture()->texturePriv().mipColorMode())
|
||||
, fCache(nullptr) {
|
||||
if (fTarget->getUniqueKey().isValid()) {
|
||||
fUniqueKey = fTarget->getUniqueKey();
|
||||
fCache = fTarget->asTexture()->getContext()->getResourceCache();
|
||||
}
|
||||
}
|
||||
|
||||
GrTextureProxy::~GrTextureProxy() {
|
||||
// Due to the order of cleanup the GrSurface this proxy may have wrapped may have gone away
|
||||
// at this point. Zero out the pointer so the cache invalidation code doesn't try to use it.
|
||||
fTarget = nullptr;
|
||||
if (fUniqueKey.isValid()) {
|
||||
fCache->processInvalidProxyUniqueKey(fUniqueKey);
|
||||
} else {
|
||||
SkASSERT(!fCache);
|
||||
}
|
||||
}
|
||||
|
||||
bool GrTextureProxy::instantiate(GrResourceProvider* resourceProvider) {
|
||||
if (!this->instantiateImpl(resourceProvider, 0, /* needsStencil = */ false,
|
||||
kNone_GrSurfaceFlags, fIsMipMapped, fMipColorMode)) {
|
||||
kNone_GrSurfaceFlags, fIsMipMapped, fMipColorMode,
|
||||
fUniqueKey.isValid() ? &fUniqueKey : nullptr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -80,3 +101,23 @@ size_t GrTextureProxy::onUninstantiatedGpuMemorySize() const {
|
||||
return GrSurface::ComputeSize(fConfig, fWidth, fHeight, 1, kHasMipMaps,
|
||||
SkBackingFit::kApprox == fFit);
|
||||
}
|
||||
|
||||
void GrTextureProxy::setUniqueKey(GrResourceCache* cache, const GrUniqueKey& key) {
|
||||
SkASSERT(key.isValid());
|
||||
SkASSERT(!fUniqueKey.isValid()); // proxies can only ever get one uniqueKey
|
||||
|
||||
if (fTarget) {
|
||||
SkASSERT(!fTarget->getUniqueKey().isValid());
|
||||
fTarget->resourcePriv().setUniqueKey(key);
|
||||
SkASSERT(fTarget->getUniqueKey() == key);
|
||||
}
|
||||
|
||||
fUniqueKey = key;
|
||||
fCache = cache;
|
||||
}
|
||||
|
||||
void GrTextureProxy::clearUniqueKey() {
|
||||
fUniqueKey.reset();
|
||||
fCache = nullptr;
|
||||
}
|
||||
|
||||
|
46
src/gpu/GrTextureProxyCacheAccess.h
Normal file
46
src/gpu/GrTextureProxyCacheAccess.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrTextureProxyCacheAccess_DEFINED
|
||||
#define GrTextureProxyCacheAccess_DEFINED
|
||||
|
||||
#include "GrTextureProxy.h"
|
||||
|
||||
/**
|
||||
* This class allows GrResourceCache increased privileged access to GrTextureProxy objects.
|
||||
*/
|
||||
class GrTextureProxy::CacheAccess {
|
||||
private:
|
||||
void setUniqueKey(GrResourceCache* cache, const GrUniqueKey& key) {
|
||||
fTextureProxy->setUniqueKey(cache, key);
|
||||
}
|
||||
|
||||
void clearUniqueKey() {
|
||||
fTextureProxy->clearUniqueKey();
|
||||
}
|
||||
|
||||
explicit CacheAccess(GrTextureProxy* textureProxy) : fTextureProxy(textureProxy) {}
|
||||
CacheAccess(const CacheAccess&) {} // unimpl
|
||||
CacheAccess& operator=(const CacheAccess&); // unimpl
|
||||
|
||||
// No taking addresses of this type.
|
||||
const CacheAccess* operator&() const;
|
||||
CacheAccess* operator&();
|
||||
|
||||
GrTextureProxy* fTextureProxy;
|
||||
|
||||
friend class GrTextureProxy; // to construct/copy this type.
|
||||
friend class GrResourceCache; // to use this type
|
||||
};
|
||||
|
||||
inline GrTextureProxy::CacheAccess GrTextureProxy::cacheAccess() { return CacheAccess(this); }
|
||||
|
||||
inline const GrTextureProxy::CacheAccess GrTextureProxy::cacheAccess() const {
|
||||
return CacheAccess(const_cast<GrTextureProxy*>(this));
|
||||
}
|
||||
|
||||
#endif
|
@ -48,10 +48,17 @@ size_t GrTextureRenderTargetProxy::onUninstantiatedGpuMemorySize() const {
|
||||
bool GrTextureRenderTargetProxy::instantiate(GrResourceProvider* resourceProvider) {
|
||||
static constexpr GrSurfaceFlags kFlags = kRenderTarget_GrSurfaceFlag;
|
||||
|
||||
const GrUniqueKey& key = this->getUniqueKey();
|
||||
|
||||
if (!this->instantiateImpl(resourceProvider, this->numStencilSamples(), this->needsStencil(),
|
||||
kFlags, this->isMipMapped(), this->mipColorMode())) {
|
||||
kFlags, this->isMipMapped(), this->mipColorMode(),
|
||||
key.isValid() ? &key : nullptr)) {
|
||||
return false;
|
||||
}
|
||||
if (key.isValid()) {
|
||||
SkASSERT(key == this->getUniqueKey());
|
||||
}
|
||||
|
||||
SkASSERT(fTarget->asRenderTarget());
|
||||
SkASSERT(fTarget->asTexture());
|
||||
|
||||
|
@ -266,7 +266,6 @@ sk_sp<GrTextureProxy> GrMakeCachedBitmapProxy(GrResourceProvider* resourceProvid
|
||||
if (proxy && originalKey.isValid()) {
|
||||
SkASSERT(proxy->origin() == kTopLeft_GrSurfaceOrigin);
|
||||
resourceProvider->assignUniqueKeyToProxy(originalKey, proxy.get());
|
||||
// MDB TODO (caching): this has to play nice with the GrSurfaceProxy's caching
|
||||
GrInstallBitmapUniqueKeyInvalidator(originalKey, bitmap.pixelRef());
|
||||
}
|
||||
}
|
||||
|
238
tests/TextureProxyTest.cpp
Normal file
238
tests/TextureProxyTest.cpp
Normal file
@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
// This is a GPU-backend specific test.
|
||||
|
||||
#include "Test.h"
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
|
||||
#include "GrBackendSurface.h"
|
||||
#include "GrContextPriv.h"
|
||||
#include "GrResourceCache.h"
|
||||
#include "GrResourceProvider.h"
|
||||
#include "GrTest.h"
|
||||
#include "GrTexture.h"
|
||||
#include "GrTextureProxy.h"
|
||||
|
||||
#include "SkGr.h"
|
||||
#include "SkImage.h"
|
||||
|
||||
int GrResourceCache::numUniqueKeyProxies_TestOnly() const {
|
||||
return fUniquelyKeyedProxies.count();
|
||||
}
|
||||
|
||||
static GrSurfaceDesc make_desc(GrSurfaceFlags flags) {
|
||||
GrSurfaceDesc desc;
|
||||
desc.fFlags = flags;
|
||||
desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
|
||||
desc.fWidth = 64;
|
||||
desc.fHeight = 64;
|
||||
desc.fConfig = kRGBA_8888_GrPixelConfig;
|
||||
desc.fSampleCnt = 0;
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Basic test
|
||||
|
||||
static sk_sp<GrTextureProxy> deferred_tex(GrResourceProvider* provider, SkBackingFit fit) {
|
||||
GrSurfaceDesc desc = make_desc(kNone_GrSurfaceFlags);
|
||||
|
||||
// Only budgeted & wrapped external proxies get to carry uniqueKeys
|
||||
return GrSurfaceProxy::MakeDeferred(provider, desc, fit, SkBudgeted::kYes);
|
||||
}
|
||||
|
||||
static sk_sp<GrTextureProxy> deferred_texRT(GrResourceProvider* provider, SkBackingFit fit) {
|
||||
GrSurfaceDesc desc = make_desc(kRenderTarget_GrSurfaceFlag);
|
||||
|
||||
// Only budgeted & wrapped external proxies get to carry uniqueKeys
|
||||
return GrSurfaceProxy::MakeDeferred(provider, desc, fit, SkBudgeted::kYes);
|
||||
}
|
||||
|
||||
static sk_sp<GrTextureProxy> wrapped(GrResourceProvider* provider, SkBackingFit fit) {
|
||||
GrSurfaceDesc desc = make_desc(kNone_GrSurfaceFlags);
|
||||
|
||||
sk_sp<GrTexture> tex;
|
||||
if (SkBackingFit::kApprox == fit) {
|
||||
tex = sk_sp<GrTexture>(provider->createApproxTexture(desc, 0));
|
||||
} else {
|
||||
// Only budgeted & wrapped external proxies get to carry uniqueKeys
|
||||
tex = provider->createTexture(desc, SkBudgeted::kYes);
|
||||
}
|
||||
|
||||
return GrSurfaceProxy::MakeWrapped(std::move(tex), kBottomLeft_GrSurfaceOrigin);
|
||||
}
|
||||
|
||||
static sk_sp<GrTextureProxy> create_wrapped_backend(GrContext* context, SkBackingFit fit,
|
||||
sk_sp<GrTexture>* backingSurface) {
|
||||
GrResourceProvider* provider = context->resourceProvider();
|
||||
|
||||
GrSurfaceDesc desc = make_desc(kNone_GrSurfaceFlags);
|
||||
|
||||
*backingSurface = provider->createTexture(desc, SkBudgeted::kNo);
|
||||
if (!(*backingSurface)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GrBackendTexture backendTex =
|
||||
GrTest::CreateBackendTexture(context->contextPriv().getBackend(),
|
||||
64, 64,
|
||||
kRGBA_8888_GrPixelConfig,
|
||||
(*backingSurface)->getTextureHandle());
|
||||
|
||||
return GrSurfaceProxy::MakeWrappedBackend(context, backendTex, kBottomLeft_GrSurfaceOrigin);
|
||||
}
|
||||
|
||||
|
||||
// This tests the basic capabilities of the uniquely keyed texture proxies. Does assigning
|
||||
// and looking them up work, etc.
|
||||
static void basic_test(GrContext* context,
|
||||
skiatest::Reporter* reporter,
|
||||
sk_sp<GrTextureProxy> proxy, bool proxyIsCached) {
|
||||
static int id = 1;
|
||||
|
||||
GrResourceProvider* provider = context->resourceProvider();
|
||||
GrResourceCache* cache = context->getResourceCache();
|
||||
|
||||
int startCacheCount = cache->getResourceCount();
|
||||
|
||||
REPORTER_ASSERT(reporter, !proxy->getUniqueKey().isValid());
|
||||
|
||||
GrUniqueKey key;
|
||||
GrMakeKeyFromImageID(&key, id, SkIRect::MakeWH(64, 64));
|
||||
++id;
|
||||
|
||||
// Assigning the uniqueKey adds the proxy to the hash but doesn't force instantiation
|
||||
REPORTER_ASSERT(reporter, !cache->numUniqueKeyProxies_TestOnly());
|
||||
provider->assignUniqueKeyToProxy(key, proxy.get());
|
||||
REPORTER_ASSERT(reporter, 1 == cache->numUniqueKeyProxies_TestOnly());
|
||||
REPORTER_ASSERT(reporter, startCacheCount == cache->getResourceCount());
|
||||
|
||||
// setUniqueKey had better stick
|
||||
REPORTER_ASSERT(reporter, key == proxy->getUniqueKey());
|
||||
|
||||
// We just added it, surely we can find it
|
||||
REPORTER_ASSERT(reporter, provider->findProxyByUniqueKey(key, kBottomLeft_GrSurfaceOrigin));
|
||||
REPORTER_ASSERT(reporter, 1 == cache->numUniqueKeyProxies_TestOnly());
|
||||
|
||||
// Once instantiated, the backing resource should have the same key
|
||||
SkAssertResult(proxy->instantiate(provider));
|
||||
const GrUniqueKey& texKey = proxy->priv().peekSurface()->getUniqueKey();
|
||||
REPORTER_ASSERT(reporter, texKey.isValid());
|
||||
REPORTER_ASSERT(reporter, key == texKey);
|
||||
if (proxyIsCached) {
|
||||
REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
|
||||
}
|
||||
|
||||
// deleting the proxy should delete it from the hash but not the cache
|
||||
proxy = nullptr;
|
||||
REPORTER_ASSERT(reporter, 0 == cache->numUniqueKeyProxies_TestOnly());
|
||||
REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
|
||||
|
||||
// If the proxy was cached refinding it should bring it back to life
|
||||
proxy = provider->findProxyByUniqueKey(key, kBottomLeft_GrSurfaceOrigin);
|
||||
if (proxyIsCached) {
|
||||
REPORTER_ASSERT(reporter, proxy);
|
||||
REPORTER_ASSERT(reporter, 1 == cache->numUniqueKeyProxies_TestOnly());
|
||||
} else {
|
||||
REPORTER_ASSERT(reporter, !proxy);
|
||||
REPORTER_ASSERT(reporter, 0 == cache->numUniqueKeyProxies_TestOnly());
|
||||
}
|
||||
REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
|
||||
|
||||
// Mega-purging it should remove it from both the hash and the cache
|
||||
proxy = nullptr;
|
||||
cache->purgeAllUnlocked();
|
||||
if (proxyIsCached) {
|
||||
REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
|
||||
} else {
|
||||
REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
|
||||
}
|
||||
|
||||
// We can bring neither the texture nor proxy back from perma-death
|
||||
proxy = provider->findProxyByUniqueKey(key, kBottomLeft_GrSurfaceOrigin);
|
||||
REPORTER_ASSERT(reporter, !proxy);
|
||||
if (proxyIsCached) {
|
||||
REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
|
||||
} else {
|
||||
REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Invalidation test
|
||||
|
||||
// Test if invalidating unique ids operates as expected for texture proxies.
|
||||
static void invalidation_test(GrContext* context, skiatest::Reporter* reporter) {
|
||||
|
||||
GrResourceCache* cache = context->getResourceCache();
|
||||
REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
|
||||
|
||||
sk_sp<SkImage> rasterImg;
|
||||
|
||||
{
|
||||
SkImageInfo ii = SkImageInfo::Make(64, 64, kRGBA_8888_SkColorType, kOpaque_SkAlphaType);
|
||||
|
||||
SkBitmap bm;
|
||||
bm.allocPixels(ii);
|
||||
|
||||
rasterImg = SkImage::MakeFromBitmap(bm);
|
||||
REPORTER_ASSERT(reporter, 0 == cache->numUniqueKeyProxies_TestOnly());
|
||||
REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
|
||||
}
|
||||
|
||||
sk_sp<SkImage> textureImg = rasterImg->makeTextureImage(context, nullptr);
|
||||
REPORTER_ASSERT(reporter, 1 == cache->numUniqueKeyProxies_TestOnly());
|
||||
REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
|
||||
|
||||
rasterImg = nullptr; // this invalidates the uniqueKey
|
||||
|
||||
// this forces the cache to respond to the inval msg
|
||||
int maxNum;
|
||||
size_t maxBytes;
|
||||
context->getResourceCacheLimits(&maxNum, &maxBytes);
|
||||
context->setResourceCacheLimits(maxNum-1, maxBytes);
|
||||
|
||||
REPORTER_ASSERT(reporter, 0 == cache->numUniqueKeyProxies_TestOnly());
|
||||
REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
|
||||
|
||||
textureImg = nullptr;
|
||||
context->purgeAllUnlockedResources();
|
||||
|
||||
REPORTER_ASSERT(reporter, 0 == cache->numUniqueKeyProxies_TestOnly());
|
||||
REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
|
||||
}
|
||||
|
||||
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TextureProxyTest, reporter, ctxInfo) {
|
||||
GrContext* context = ctxInfo.grContext();
|
||||
GrResourceProvider* provider = context->resourceProvider();
|
||||
GrResourceCache* cache = context->getResourceCache();
|
||||
|
||||
REPORTER_ASSERT(reporter, !cache->numUniqueKeyProxies_TestOnly());
|
||||
REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
|
||||
|
||||
for (auto fit : { SkBackingFit::kExact, SkBackingFit::kApprox }) {
|
||||
for (auto create : { deferred_tex, deferred_texRT, wrapped }) {
|
||||
REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
|
||||
basic_test(context, reporter, create(provider, fit), true);
|
||||
}
|
||||
|
||||
REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
|
||||
sk_sp<GrTexture> backingTex;
|
||||
sk_sp<GrTextureProxy> proxy = create_wrapped_backend(context, fit, &backingTex);
|
||||
basic_test(context, reporter, std::move(proxy), false);
|
||||
|
||||
backingTex = nullptr;
|
||||
cache->purgeAllUnlocked();
|
||||
}
|
||||
|
||||
invalidation_test(context, reporter);
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user