aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Robert Phillips <robertphillips@google.com>2017-09-20 15:58:44 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-09-20 20:21:50 +0000
commitd4f100dad90ed5beb1b614464d8c4fcb22c0a993 (patch)
tree4194bbcbe1884a5454143a7579f656113cf8f00f /src
parent8d4a5c75f07a70f71320a426f392783dbcf180ba (diff)
Add native caching of uniquely keyed GrTextureProxies
Change-Id: I303fe025b7856b8d681a2d35b416c015bd468e1d Reviewed-on: https://skia-review.googlesource.com/48300 Commit-Queue: Robert Phillips <robertphillips@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com>
Diffstat (limited to 'src')
-rw-r--r--src/gpu/GrBitmapTextureMaker.cpp1
-rw-r--r--src/gpu/GrClipStackClip.cpp2
-rw-r--r--src/gpu/GrRenderTargetProxy.cpp2
-rw-r--r--src/gpu/GrResourceCache.cpp64
-rw-r--r--src/gpu/GrResourceCache.h55
-rw-r--r--src/gpu/GrResourceProvider.cpp17
-rw-r--r--src/gpu/GrResourceProvider.h20
-rw-r--r--src/gpu/GrSurfaceProxy.cpp10
-rw-r--r--src/gpu/GrTextureProxy.cpp44
-rw-r--r--src/gpu/GrTextureProxyCacheAccess.h46
-rw-r--r--src/gpu/GrTextureRenderTargetProxy.cpp9
-rw-r--r--src/gpu/SkGr.cpp1
12 files changed, 237 insertions, 34 deletions
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<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;
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<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;
}
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<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();
+ }
+}
+
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<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;
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<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,
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<T*>(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<GrTextureProxy> 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<GrTextureProxy> 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<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;
}
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<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() {
+ 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<GrTextureProxy*>(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<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());
}
}