From d4f100dad90ed5beb1b614464d8c4fcb22c0a993 Mon Sep 17 00:00:00 2001 From: Robert Phillips Date: Wed, 20 Sep 2017 15:58:44 -0400 Subject: Add native caching of uniquely keyed GrTextureProxies Change-Id: I303fe025b7856b8d681a2d35b416c015bd468e1d Reviewed-on: https://skia-review.googlesource.com/48300 Commit-Queue: Robert Phillips Reviewed-by: Brian Salomon --- src/gpu/GrBitmapTextureMaker.cpp | 1 - src/gpu/GrClipStackClip.cpp | 2 -- src/gpu/GrRenderTargetProxy.cpp | 2 +- src/gpu/GrResourceCache.cpp | 64 ++++++++++++++++++++++++++++++++++ src/gpu/GrResourceCache.h | 55 +++++++++++++++++++++++++++++ src/gpu/GrResourceProvider.cpp | 17 ++------- src/gpu/GrResourceProvider.h | 20 ++++++----- src/gpu/GrSurfaceProxy.cpp | 10 +++++- src/gpu/GrTextureProxy.cpp | 44 +++++++++++++++++++++-- src/gpu/GrTextureProxyCacheAccess.h | 46 ++++++++++++++++++++++++ src/gpu/GrTextureRenderTargetProxy.cpp | 9 ++++- src/gpu/SkGr.cpp | 1 - 12 files changed, 237 insertions(+), 34 deletions(-) create mode 100644 src/gpu/GrTextureProxyCacheAccess.h (limited to 'src') diff --git a/src/gpu/GrBitmapTextureMaker.cpp b/src/gpu/GrBitmapTextureMaker.cpp index 85e791ef90..2bf3afe4e1 100644 --- a/src/gpu/GrBitmapTextureMaker.cpp +++ b/src/gpu/GrBitmapTextureMaker.cpp @@ -53,7 +53,6 @@ sk_sp 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; diff --git a/src/gpu/GrClipStackClip.cpp b/src/gpu/GrClipStackClip.cpp index 165b442d90..69d81a08a2 100644 --- a/src/gpu/GrClipStackClip.cpp +++ b/src/gpu/GrClipStackClip.cpp @@ -420,7 +420,6 @@ sk_sp 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 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; } diff --git a/src/gpu/GrRenderTargetProxy.cpp b/src/gpu/GrRenderTargetProxy.cpp index fff3d0bcea..111ecf6625 100644 --- a/src/gpu/GrRenderTargetProxy.cpp +++ b/src/gpu/GrRenderTargetProxy.cpp @@ -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()); diff --git a/src/gpu/GrResourceCache.cpp b/src/gpu/GrResourceCache.cpp index f6170c01b6..c207b44a38 100644 --- a/src/gpu/GrResourceCache.cpp +++ b/src/gpu/GrResourceCache.cpp @@ -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& 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 GrResourceCache::findProxyByUniqueKey(const GrUniqueKey& key, + GrSurfaceOrigin origin) { + + sk_sp 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 texture(static_cast(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(); + } +} + diff --git a/src/gpu/GrResourceCache.h b/src/gpu/GrResourceCache.h index 5cdc5636ea..96323be73c 100644 --- a/src/gpu/GrResourceCache.h +++ b/src/gpu/GrResourceCache.h @@ -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 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 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 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; diff --git a/src/gpu/GrResourceProvider.cpp b/src/gpu/GrResourceProvider.cpp index 8dce5497d8..0182baa977 100644 --- a/src/gpu/GrResourceProvider.cpp +++ b/src/gpu/GrResourceProvider.cpp @@ -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 GrResourceProvider::findProxyByUniqueKey(const GrUniqueKey& key, GrSurfaceOrigin origin) { ASSERT_SINGLE_OWNER - - sk_sp 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, diff --git a/src/gpu/GrResourceProvider.h b/src/gpu/GrResourceProvider.h index 1ab1ec42fc..7be8ec1793 100644 --- a/src/gpu/GrResourceProvider.h +++ b/src/gpu/GrResourceProvider.h @@ -45,17 +45,19 @@ public: return static_cast(this->findAndRefResourceByUniqueKey(key)); } - /////////////////////////////////////////////////////////////////////////// - // Textures + /* + * 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*); - /** 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 proxy by unique key. + */ + sk_sp findProxyByUniqueKey(const GrUniqueKey&, GrSurfaceOrigin); - /** 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 findProxyByUniqueKey(const GrUniqueKey& key, GrSurfaceOrigin); + /////////////////////////////////////////////////////////////////////////// + // Textures /** * Finds a texture that approximately matches the descriptor. Will be at least as large in width diff --git a/src/gpu/GrSurfaceProxy.cpp b/src/gpu/GrSurfaceProxy.cpp index 5918830bf8..433c230881 100644 --- a/src/gpu/GrSurfaceProxy.cpp +++ b/src/gpu/GrSurfaceProxy.cpp @@ -109,8 +109,12 @@ void GrSurfaceProxy::assign(sk_sp 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; } diff --git a/src/gpu/GrTextureProxy.cpp b/src/gpu/GrTextureProxy.cpp index 3cb87b3faf..8a68e03bac 100644 --- a/src/gpu/GrTextureProxy.cpp +++ b/src/gpu/GrTextureProxy.cpp @@ -7,25 +7,43 @@ #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 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() { + 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 +98,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; +} + diff --git a/src/gpu/GrTextureProxyCacheAccess.h b/src/gpu/GrTextureProxyCacheAccess.h new file mode 100644 index 0000000000..79cf845987 --- /dev/null +++ b/src/gpu/GrTextureProxyCacheAccess.h @@ -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(this)); +} + +#endif diff --git a/src/gpu/GrTextureRenderTargetProxy.cpp b/src/gpu/GrTextureRenderTargetProxy.cpp index 4a4d79c531..7515c3df08 100644 --- a/src/gpu/GrTextureRenderTargetProxy.cpp +++ b/src/gpu/GrTextureRenderTargetProxy.cpp @@ -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()); diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp index 4943804553..b9f75e0821 100644 --- a/src/gpu/SkGr.cpp +++ b/src/gpu/SkGr.cpp @@ -266,7 +266,6 @@ sk_sp 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()); } } -- cgit v1.2.3