Remove texture idle proc mechanism
Bug: skia:11369
Change-Id: I0d1a74cc64dd74486acbb69df529ccc0f8b63ef3
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/375202
Reviewed-by: Greg Daniel <egdaniel@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/GrGpuResource.cpp b/src/gpu/GrGpuResource.cpp
index 9267608..716dfa8 100644
--- a/src/gpu/GrGpuResource.cpp
+++ b/src/gpu/GrGpuResource.cpp
@@ -158,11 +158,6 @@
get_resource_cache(fGpu)->resourceAccess().changeUniqueKey(this, key);
}
-void GrGpuResource::notifyRefCntWillBeZero() const {
- GrGpuResource* mutableThis = const_cast<GrGpuResource*>(this);
- mutableThis->willRemoveLastRef();
-}
-
void GrGpuResource::notifyARefCntIsZero(LastRemovedRef removedRef) const {
if (this->wasDestroyed()) {
// We've already been removed from the cache. Goodbye cruel world!
diff --git a/src/gpu/GrGpuResource.h b/src/gpu/GrGpuResource.h
index ee61bbe..015f036 100644
--- a/src/gpu/GrGpuResource.h
+++ b/src/gpu/GrGpuResource.h
@@ -83,22 +83,7 @@
private:
void notifyWillBeZero(LastRemovedRef removedRef) const {
- if (0 == this->getRefCnt() && this->hasNoCommandBufferUsages()) {
- // At this point we better be the only thread accessing this resource.
- // Trick out the notifyRefCntWillBeZero() call by adding back one more ref.
- fRefCnt.fetch_add(+1, std::memory_order_relaxed);
- static_cast<const DERIVED*>(this)->notifyRefCntWillBeZero();
- // notifyRefCntWillBeZero() could have done anything, including re-refing this and
- // passing on to another thread. Take away the ref-count we re-added above and see
- // if we're back to zero.
- // TODO: Consider making it so that refs can't be added and merge
- // notifyRefCntWillBeZero()/willRemoveLastRef() with notifyARefCntIsZero().
- if (1 == fRefCnt.fetch_add(-1, std::memory_order_acq_rel)) {
- static_cast<const DERIVED*>(this)->notifyARefCntIsZero(removedRef);
- }
- } else {
- static_cast<const DERIVED*>(this)->notifyARefCntIsZero(removedRef);
- }
+ static_cast<const DERIVED*>(this)->notifyARefCntIsZero(removedRef);
}
int32_t getRefCnt() const { return fRefCnt.load(std::memory_order_relaxed); }
@@ -294,15 +279,9 @@
virtual size_t onGpuMemorySize() const = 0;
- /**
- * Called by GrIORef when a resource is about to lose its last ref
- */
- virtual void willRemoveLastRef() {}
-
// See comments in CacheAccess and ResourcePriv.
void setUniqueKey(const GrUniqueKey&);
void removeUniqueKey();
- void notifyRefCntWillBeZero() const;
void notifyARefCntIsZero(LastRemovedRef removedRef) const;
void removeScratchKey();
void makeBudgeted();
diff --git a/src/gpu/GrManagedResource.cpp b/src/gpu/GrManagedResource.cpp
index 4620de5..c88728b 100644
--- a/src/gpu/GrManagedResource.cpp
+++ b/src/gpu/GrManagedResource.cpp
@@ -14,36 +14,3 @@
#ifdef SK_TRACE_MANAGED_RESOURCES
std::atomic<uint32_t> GrManagedResource::fKeyCounter{0};
#endif
-
-void GrTextureResource::addIdleProc(GrTexture* owningTexture,
- sk_sp<GrRefCntedCallback> idleProc) const {
- SkASSERT(!fOwningTexture || fOwningTexture == owningTexture);
- fOwningTexture = owningTexture;
- fIdleProcs.push_back(std::move(idleProc));
-}
-
-int GrTextureResource::idleProcCnt() const { return fIdleProcs.count(); }
-
-sk_sp<GrRefCntedCallback> GrTextureResource::idleProc(int i) const { return fIdleProcs[i]; }
-
-void GrTextureResource::resetIdleProcs() const { fIdleProcs.reset(); }
-
-void GrTextureResource::removeOwningTexture() const { fOwningTexture = nullptr; }
-
-void GrTextureResource::notifyQueuedForWorkOnGpu() const { ++fNumOwners; }
-
-void GrTextureResource::notifyFinishedWithWorkOnGpu() const {
- SkASSERT(fNumOwners);
- if (--fNumOwners || !fIdleProcs.count()) {
- return;
- }
- if (fOwningTexture) {
- if (fOwningTexture->resourcePriv().hasRefOrCommandBufferUsage()) {
- // Wait for the texture to become idle in the cache to call the procs.
- return;
- }
- fOwningTexture->callIdleProcsOnBehalfOfResource();
- } else {
- fIdleProcs.reset();
- }
-}
diff --git a/src/gpu/GrManagedResource.h b/src/gpu/GrManagedResource.h
index d80a7f9..fd0aa40 100644
--- a/src/gpu/GrManagedResource.h
+++ b/src/gpu/GrManagedResource.h
@@ -217,7 +217,7 @@
/** \class GrTextureResource
GrTextureResource is the base class for managed texture resources, and implements the
- basic idleProc and releaseProc functionality for them.
+ basic releaseProc functionality for them.
*/
class GrTextureResource : public GrManagedResource {
@@ -232,30 +232,8 @@
fReleaseHelper = std::move(releaseHelper);
}
- /**
- * These are used to coordinate calling the "finished" idle procs between the GrTexture
- * and the GrTextureResource. If the GrTexture becomes purgeable and if there are no command
- * buffers referring to the GrTextureResource then it calls the procs. Otherwise, the
- * GrTextureResource calls them when the last command buffer reference goes away and the
- * GrTexture is purgeable.
- */
- void addIdleProc(GrTexture*, sk_sp<GrRefCntedCallback>) const;
- int idleProcCnt() const;
- sk_sp<GrRefCntedCallback> idleProc(int) const;
- void resetIdleProcs() const;
- void removeOwningTexture() const;
-
- /**
- * We track how many outstanding references this GrTextureResource has in command buffers and
- * when the count reaches zero we call the idle proc.
- */
- void notifyQueuedForWorkOnGpu() const override;
- void notifyFinishedWithWorkOnGpu() const override;
- bool isQueuedForWorkOnGpu() const { return fNumOwners > 0; }
-
protected:
mutable sk_sp<GrRefCntedCallback> fReleaseHelper;
- mutable GrTexture* fOwningTexture = nullptr;
void invokeReleaseProc() const {
if (fReleaseHelper) {
@@ -266,9 +244,6 @@
}
private:
- mutable int fNumOwners = 0;
- mutable SkTArray<sk_sp<GrRefCntedCallback>> fIdleProcs;
-
using INHERITED = GrManagedResource;
};
diff --git a/src/gpu/GrTexture.h b/src/gpu/GrTexture.h
index 60dd828..f703b1e 100644
--- a/src/gpu/GrTexture.h
+++ b/src/gpu/GrTexture.h
@@ -40,23 +40,6 @@
GrBackendTexture*,
SkImage::BackendTextureReleaseProc*);
- /**
- * Installs a proc on this texture. It will be called when the texture becomes "idle". "Idle"
- * means, accounting only for Skia's use of the texture, it is safe to delete in the underlying
- * API. This is used to implement release procs for promise image textures because we cache
- * the GrTexture object and thus can't rely on it's destructor to trigger a normal release proc.
- */
- virtual void addIdleProc(sk_sp<GrRefCntedCallback> idleProc) {
- // This is the default implementation for the managed case where the IdleState can be
- // ignored. Unmanaged backends, e.g. Vulkan, must override this to detect when the GPU
- // is finished accessing the texture.
- fIdleProcs.push_back(std::move(idleProc));
- }
- /** Helper version of addIdleProc that creates the ref-counted wrapper. */
- void addIdleProc(GrRefCntedCallback::Callback callback, GrRefCntedCallback::Context context) {
- this->addIdleProc(GrRefCntedCallback::Make(callback, context));
- }
-
GrTextureType textureType() const { return fTextureType; }
bool hasRestrictedSampling() const {
return GrTextureTypeHasRestrictedSampling(this->textureType());
@@ -85,13 +68,6 @@
virtual bool onStealBackendTexture(GrBackendTexture*, SkImage::BackendTextureReleaseProc*) = 0;
- SkTArray<sk_sp<GrRefCntedCallback>> fIdleProcs;
-
- void willRemoveLastRef() override {
- // We're about to be idle in the resource cache. Do our part to trigger the idle callbacks.
- fIdleProcs.reset();
- }
- virtual void callIdleProcsOnBehalfOfResource() {}
void computeScratchKey(GrScratchKey*) const override;
private:
diff --git a/src/gpu/d3d/GrD3DTexture.cpp b/src/gpu/d3d/GrD3DTexture.cpp
index 230c4c9..2107343 100644
--- a/src/gpu/d3d/GrD3DTexture.cpp
+++ b/src/gpu/d3d/GrD3DTexture.cpp
@@ -109,14 +109,6 @@
}
void GrD3DTexture::onRelease() {
- // We're about to be severed from our GrManagedResource. If there are "finish" idle procs we
- // have to decide who will handle them. If the resource is still tied to a command buffer we let
- // it handle them. Otherwise, we handle them.
- SkASSERT(this->resource());
- if (this->resource()->isQueuedForWorkOnGpu()) {
- this->removeFinishIdleProcs();
- }
-
GrD3DGpu* gpu = this->getD3DGpu();
gpu->resourceProvider().recycleConstantOrShaderView(fShaderResourceView);
this->releaseResource(gpu);
@@ -125,14 +117,6 @@
}
void GrD3DTexture::onAbandon() {
- // We're about to be severed from our GrManagedResource. If there are "finish" idle procs we
- // have to decide who will handle them. If the resource is still tied to a command buffer we let
- // it handle them. Otherwise, we handle them.
- SkASSERT(this->resource());
- if (this->resource()->isQueuedForWorkOnGpu()) {
- this->removeFinishIdleProcs();
- }
-
GrD3DGpu* gpu = this->getD3DGpu();
gpu->resourceProvider().recycleConstantOrShaderView(fShaderResourceView);
this->releaseResource(gpu);
@@ -147,61 +131,3 @@
SkASSERT(!this->wasDestroyed());
return static_cast<GrD3DGpu*>(this->getGpu());
}
-
-void GrD3DTexture::addIdleProc(sk_sp<GrRefCntedCallback> idleProc) {
- INHERITED::addIdleProc(idleProc);
- this->addResourceIdleProc(this, std::move(idleProc));
-}
-
-void GrD3DTexture::callIdleProcsOnBehalfOfResource() {
- // If we got here then the resource is being removed from its last command buffer and the
- // texture is idle in the cache. Any kFlush idle procs should already have been called. So
- // the texture and resource should have the same set of procs.
- SkASSERT(this->resourceIdleProcCnt() == fIdleProcs.count());
-#ifdef SK_DEBUG
- for (int i = 0; i < fIdleProcs.count(); ++i) {
- SkASSERT(fIdleProcs[i] == this->resourceIdleProc(i));
- }
-#endif
- fIdleProcs.reset();
- this->resetResourceIdleProcs();
-}
-
-void GrD3DTexture::willRemoveLastRef() {
- if (!fIdleProcs.count()) {
- return;
- }
- // This is called when the GrTexture is purgeable. However, we need to check whether the
- // Resource is still owned by any command buffers. If it is then it will call the proc.
- if (!this->resourceIsQueuedForWorkOnGpu()) {
- // Everything must go!
- fIdleProcs.reset();
- this->resetResourceIdleProcs();
- } else {
- // The procs that should be called on flush but not finish are those that are owned
- // by the GrD3DTexture and not the Resource. We do this by copying the resource's array
- // and thereby dropping refs to procs we own but the resource does not.
- fIdleProcs.reset(this->resourceIdleProcCnt());
- for (int i = 0; i < fIdleProcs.count(); ++i) {
- fIdleProcs[i] = this->resourceIdleProc(i);
- }
- }
-}
-
-void GrD3DTexture::removeFinishIdleProcs() {
- // This should only be called by onRelease/onAbandon when we have already checked for a
- // resource.
- SkSTArray<4, sk_sp<GrRefCntedCallback>> procsToKeep;
- int resourceIdx = 0;
- // The idle procs that are common between the GrD3DTexture and its Resource should be found in
- // the same order.
- for (int i = 0; i < fIdleProcs.count(); ++i) {
- if (fIdleProcs[i] == this->resourceIdleProc(resourceIdx)) {
- ++resourceIdx;
- } else {
- procsToKeep.push_back(fIdleProcs[i]);
- }
- }
- SkASSERT(resourceIdx == this->resourceIdleProcCnt());
- fIdleProcs = procsToKeep;
-}
diff --git a/src/gpu/d3d/GrD3DTexture.h b/src/gpu/d3d/GrD3DTexture.h
index 8787e47..e57dd29 100644
--- a/src/gpu/d3d/GrD3DTexture.h
+++ b/src/gpu/d3d/GrD3DTexture.h
@@ -39,9 +39,6 @@
void textureParamsModified() override {}
- void addIdleProc(sk_sp<GrRefCntedCallback>) override;
- void callIdleProcsOnBehalfOfResource() override;
-
protected:
GrD3DTexture(GrD3DGpu*,
SkISize dimensions,
@@ -59,8 +56,6 @@
return false;
}
- void willRemoveLastRef() override;
-
private:
GrD3DTexture(GrD3DGpu*, SkBudgeted, SkISize dimensions, const GrD3DTextureResourceInfo&,
sk_sp<GrD3DResourceState>,
@@ -78,8 +73,6 @@
this->setResourceRelease(std::move(releaseHelper));
}
- void removeFinishIdleProcs();
-
struct SamplerHash {
uint32_t operator()(GrSamplerState state) const { return state.asIndex(); }
};
diff --git a/src/gpu/d3d/GrD3DTextureResource.cpp b/src/gpu/d3d/GrD3DTextureResource.cpp
index 916c359..3f3439b 100644
--- a/src/gpu/d3d/GrD3DTextureResource.cpp
+++ b/src/gpu/d3d/GrD3DTextureResource.cpp
@@ -110,7 +110,6 @@
void GrD3DTextureResource::releaseResource(GrD3DGpu* gpu) {
// TODO: do we need to migrate resource state if we change queues?
if (fResource) {
- fResource->removeOwningTexture();
fResource.reset();
}
fInfo.fResource.reset();
diff --git a/src/gpu/d3d/GrD3DTextureResource.h b/src/gpu/d3d/GrD3DTextureResource.h
index 2d0bc30..37ee930 100644
--- a/src/gpu/d3d/GrD3DTextureResource.h
+++ b/src/gpu/d3d/GrD3DTextureResource.h
@@ -77,28 +77,6 @@
protected:
void releaseResource(GrD3DGpu* gpu);
- void addResourceIdleProc(GrTexture* owningTexture, sk_sp<GrRefCntedCallback> idleProc) {
- if (fResource) {
- fResource->addIdleProc(owningTexture, std::move(idleProc));
- }
- }
- void resetResourceIdleProcs() {
- SkASSERT(fResource);
- fResource->resetIdleProcs();
- }
- bool resourceIsQueuedForWorkOnGpu() const {
- SkASSERT(fResource);
- return fResource->isQueuedForWorkOnGpu();
- }
- int resourceIdleProcCnt() const {
- SkASSERT(fResource);
- return fResource->idleProcCnt();
- }
- sk_sp<GrRefCntedCallback> resourceIdleProc(int i) const {
- SkASSERT(fResource);
- return fResource->idleProc(i);
- }
-
GrD3DTextureResourceInfo fInfo;
sk_sp<GrD3DResourceState> fState;
diff --git a/src/gpu/mock/GrMockTexture.h b/src/gpu/mock/GrMockTexture.h
index 2ebdb8f..41ad564 100644
--- a/src/gpu/mock/GrMockTexture.h
+++ b/src/gpu/mock/GrMockTexture.h
@@ -183,10 +183,6 @@
return GrMockTexture::backendFormat();
}
-protected:
- // This avoids an inherits via dominance warning on MSVC.
- void willRemoveLastRef() override { GrTexture::willRemoveLastRef(); }
-
private:
void onAbandon() override {
GrRenderTarget::onAbandon();
diff --git a/src/gpu/vk/GrVkImage.cpp b/src/gpu/vk/GrVkImage.cpp
index 52efe8a..6759481 100644
--- a/src/gpu/vk/GrVkImage.cpp
+++ b/src/gpu/vk/GrVkImage.cpp
@@ -308,7 +308,6 @@
void GrVkImage::releaseImage() {
if (fResource) {
- fResource->removeOwningTexture();
fResource->unref();
fResource = nullptr;
}
diff --git a/src/gpu/vk/GrVkTexture.cpp b/src/gpu/vk/GrVkTexture.cpp
index 9d0f400..6feb677 100644
--- a/src/gpu/vk/GrVkTexture.cpp
+++ b/src/gpu/vk/GrVkTexture.cpp
@@ -138,13 +138,6 @@
}
void GrVkTexture::onRelease() {
- // We're about to be severed from our GrManagedResource. If there are "finish" idle procs we
- // have to decide who will handle them. If the resource is still tied to a command buffer we let
- // it handle them. Otherwise, we handle them.
- if (this->hasResource() && this->resource()->isQueuedForWorkOnGpu()) {
- this->removeFinishIdleProcs();
- }
-
// we create this and don't hand it off, so we should always destroy it
if (fTextureView) {
fTextureView.reset();
@@ -171,13 +164,6 @@
};
void GrVkTexture::onAbandon() {
- // We're about to be severed from our GrManagedResource. If there are "finish" idle procs we
- // have to decide who will handle them. If the resource is still tied to a command buffer we let
- // it handle them. Otherwise, we handle them.
- if (this->hasResource() && this->resource()->isQueuedForWorkOnGpu()) {
- this->removeFinishIdleProcs();
- }
-
// we create this and don't hand it off, so we should always destroy it
if (fTextureView) {
fTextureView.reset();
@@ -202,74 +188,6 @@
return fTextureView.get();
}
-void GrVkTexture::addIdleProc(sk_sp<GrRefCntedCallback> idleProc) {
- INHERITED::addIdleProc(idleProc);
- if (auto* resource = this->resource()) {
- resource->addIdleProc(this, std::move(idleProc));
- }
-}
-
-void GrVkTexture::callIdleProcsOnBehalfOfResource() {
- // If we got here then the resource is being removed from its last command buffer and the
- // texture is idle in the cache. Any kFlush idle procs should already have been called. So
- // the texture and resource should have the same set of procs.
- SkASSERT(this->resource());
- SkASSERT(this->resource()->idleProcCnt() == fIdleProcs.count());
-#ifdef SK_DEBUG
- for (int i = 0; i < fIdleProcs.count(); ++i) {
- SkASSERT(fIdleProcs[i] == this->resource()->idleProc(i));
- }
-#endif
- fIdleProcs.reset();
- this->resource()->resetIdleProcs();
-}
-
-void GrVkTexture::willRemoveLastRef() {
- if (!fIdleProcs.count()) {
- return;
- }
- // This is called when the GrTexture is purgeable. However, we need to check whether the
- // Resource is still owned by any command buffers. If it is then it will call the proc.
- auto* resource = this->hasResource() ? this->resource() : nullptr;
- bool callFinishProcs = !resource || !resource->isQueuedForWorkOnGpu();
- if (callFinishProcs) {
- // Everything must go!
- fIdleProcs.reset();
- if (resource) {
- resource->resetIdleProcs();
- }
- } else {
- // The procs that should be called on flush but not finish are those that are owned
- // by the GrVkTexture and not the Resource. We do this by copying the resource's array
- // and thereby dropping refs to procs we own but the resource does not.
- SkASSERT(resource);
- fIdleProcs.reset(resource->idleProcCnt());
- for (int i = 0; i < fIdleProcs.count(); ++i) {
- fIdleProcs[i] = resource->idleProc(i);
- }
- }
-}
-
-void GrVkTexture::removeFinishIdleProcs() {
- // This should only be called by onRelease/onAbandon when we have already checked for a
- // resource.
- const auto* resource = this->resource();
- SkASSERT(resource);
- SkSTArray<4, sk_sp<GrRefCntedCallback>> procsToKeep;
- int resourceIdx = 0;
- // The idle procs that are common between the GrVkTexture and its Resource should be found in
- // the same order.
- for (int i = 0; i < fIdleProcs.count(); ++i) {
- if (fIdleProcs[i] == resource->idleProc(resourceIdx)) {
- ++resourceIdx;
- } else {
- procsToKeep.push_back(fIdleProcs[i]);
- }
- }
- SkASSERT(resourceIdx == resource->idleProcCnt());
- fIdleProcs = procsToKeep;
-}
-
const GrVkDescriptorSet* GrVkTexture::cachedSingleDescSet(GrSamplerState state) {
if (std::unique_ptr<DescriptorCacheEntry>* e = fDescSetCache.find(state)) {
return (*e)->fDescriptorSet;
diff --git a/src/gpu/vk/GrVkTexture.h b/src/gpu/vk/GrVkTexture.h
index 2f22f97..23950a7 100644
--- a/src/gpu/vk/GrVkTexture.h
+++ b/src/gpu/vk/GrVkTexture.h
@@ -45,9 +45,6 @@
const GrVkImageView* textureView();
- void addIdleProc(sk_sp<GrRefCntedCallback>) override;
- void callIdleProcsOnBehalfOfResource() override;
-
// For each GrVkTexture, there is a cache of GrVkDescriptorSets which only contain a single
// texture/sampler descriptor. If there is a cached descriptor set that matches the passed in
// GrSamplerState, then a pointer to it is returned. The ref count is not incremented on the
@@ -75,8 +72,6 @@
return false;
}
- void willRemoveLastRef() override;
-
private:
GrVkTexture(GrVkGpu*, SkBudgeted, SkISize, const GrVkImageInfo&,
sk_sp<GrBackendSurfaceMutableStateImpl>, sk_sp<const GrVkImageView> imageView,
@@ -92,8 +87,6 @@
this->setResourceRelease(std::move(releaseHelper));
}
- void removeFinishIdleProcs();
-
sk_sp<const GrVkImageView> fTextureView;
struct SamplerHash {
diff --git a/tests/GrSurfaceTest.cpp b/tests/GrSurfaceTest.cpp
index ac863b1..c0ee92d 100644
--- a/tests/GrSurfaceTest.cpp
+++ b/tests/GrSurfaceTest.cpp
@@ -432,395 +432,3 @@
}
}
}
-
-static const int kSurfSize = 10;
-
-static sk_sp<GrTexture> make_wrapped_texture(GrDirectContext* dContext, GrRenderable renderable) {
- auto mbet = sk_gpu_test::ManagedBackendTexture::MakeWithoutData(
- dContext, kSurfSize, kSurfSize, kRGBA_8888_SkColorType, GrMipmapped::kNo, renderable);
- SkASSERT(mbet);
- sk_sp<GrTextureProxy> proxy;
- if (renderable == GrRenderable::kYes) {
- proxy = dContext->priv().proxyProvider()->wrapRenderableBackendTexture(
- mbet->texture(), 1, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo,
- mbet->refCountedCallback());
- } else {
- proxy = dContext->priv().proxyProvider()->wrapBackendTexture(
- mbet->texture(), kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, kRW_GrIOType,
- mbet->refCountedCallback());
- }
- if (!proxy) {
- return nullptr;
- }
- return sk_ref_sp(proxy->peekTexture());
-}
-
-static sk_sp<GrTexture> make_normal_texture(GrDirectContext* dContext, GrRenderable renderable) {
- SkISize desc;
- desc.fWidth = desc.fHeight = kSurfSize;
- auto format = dContext->priv().caps()->getDefaultBackendFormat(GrColorType::kRGBA_8888,
- renderable);
- return dContext->priv().resourceProvider()->createTexture(
- desc, format, renderable, 1, GrMipmapped::kNo, SkBudgeted::kNo, GrProtected::kNo);
-}
-
-DEF_GPUTEST(TextureIdleProcTest, reporter, options) {
- // Various ways of making textures.
- auto makeWrapped = [](GrDirectContext* dContext) {
- return make_wrapped_texture(dContext, GrRenderable::kNo);
- };
- auto makeWrappedRenderable = [](GrDirectContext* dContext) {
- return make_wrapped_texture(dContext, GrRenderable::kYes);
- };
- auto makeNormal = [](GrDirectContext* dContext) {
- return make_normal_texture(dContext, GrRenderable::kNo);
- };
- auto makeRenderable = [](GrDirectContext* dContext) {
- return make_normal_texture(dContext, GrRenderable::kYes);
- };
-
- std::function<sk_sp<GrTexture>(GrDirectContext*)> makers[] = {
- makeWrapped,
- makeWrappedRenderable,
- makeNormal,
- makeRenderable
- };
-
- // Add a unique key, or not.
- auto addKey = [](GrTexture* texture) {
- static uint32_t gN = 0;
- static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
- GrUniqueKey key;
- GrUniqueKey::Builder builder(&key, kDomain, 1);
- builder[0] = gN++;
- builder.finish();
- texture->resourcePriv().setUniqueKey(key);
- };
- auto dontAddKey = [](GrTexture* texture) {};
- std::function<void(GrTexture*)> keyAdders[] = {addKey, dontAddKey};
-
- for (const auto& m : makers) {
- for (const auto& keyAdder : keyAdders) {
- for (int type = 0; type < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++type) {
- sk_gpu_test::GrContextFactory factory;
- auto contextType = static_cast<sk_gpu_test::GrContextFactory::ContextType>(type);
- auto dContext = factory.get(contextType);
- if (!dContext) {
- continue;
- }
-
- // The callback we add simply adds an integer to a set.
- std::set<int> idleIDs;
- struct Context {
- std::set<int>* fIdleIDs;
- int fNum;
- };
- auto proc = [](void* context) {
- static_cast<Context*>(context)->fIdleIDs->insert(
- static_cast<Context*>(context)->fNum);
- delete static_cast<Context*>(context);
- };
-
- // Makes a texture, possibly adds a key, and sets the callback.
- auto make = [&m, &keyAdder, &proc, &idleIDs](GrDirectContext* dContext, int num) {
- sk_sp<GrTexture> texture = m(dContext);
- texture->addIdleProc(proc, new Context{&idleIDs, num});
- keyAdder(texture.get());
- return texture;
- };
-
- auto texture = make(dContext, 1);
- REPORTER_ASSERT(reporter, idleIDs.find(1) == idleIDs.end());
- auto renderable = GrRenderable(SkToBool(texture->asRenderTarget()));
- auto backendFormat = texture->backendFormat();
- texture.reset();
- REPORTER_ASSERT(reporter, idleIDs.find(1) != idleIDs.end());
-
- texture = make(dContext, 2);
- int w = texture->width();
- int h = texture->height();
- SkImageInfo info =
- SkImageInfo::Make(w, h, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
- auto rt = SkSurface::MakeRenderTarget(dContext, SkBudgeted::kNo, info, 0, nullptr);
- auto sdc = SkCanvasPriv::TopDeviceSurfaceDrawContext(rt->getCanvas());
- auto singleUseLazyCB = [&texture](GrResourceProvider*,
- const GrSurfaceProxy::LazySurfaceDesc&) {
- auto mode = GrSurfaceProxy::LazyInstantiationKeyMode::kSynced;
- if (texture->getUniqueKey().isValid()) {
- mode = GrSurfaceProxy::LazyInstantiationKeyMode::kUnsynced;
- }
- return GrSurfaceProxy::LazyCallbackResult{std::move(texture), true, mode};
- };
- SkISize desc;
- desc.fWidth = w;
- desc.fHeight = h;
- SkBudgeted budgeted;
- if (texture->resourcePriv().budgetedType() == GrBudgetedType::kBudgeted) {
- budgeted = SkBudgeted::kYes;
- } else {
- budgeted = SkBudgeted::kNo;
- }
- sk_sp<GrSurfaceProxy> proxy;
- if (renderable == GrRenderable::kYes) {
- static const GrProxyProvider::TextureInfo kTexInfo = {GrMipMapped::kNo,
- GrTextureType::k2D};
- proxy = dContext->priv().proxyProvider()->createLazyRenderTargetProxy(
- singleUseLazyCB, backendFormat, desc, 1,
- dContext->priv().caps()->getExtraSurfaceFlagsForDeferredRT(),
- &kTexInfo,
- GrMipmapStatus::kNotAllocated,
- SkBackingFit::kExact, budgeted, GrProtected::kNo, false,
- GrSurfaceProxy::UseAllocator::kYes);
- } else {
- proxy = dContext->priv().proxyProvider()->createLazyProxy(
- singleUseLazyCB, backendFormat, desc, GrMipmapped::kNo,
- GrMipmapStatus::kNotAllocated, GrInternalSurfaceFlags ::kNone,
- SkBackingFit::kExact, budgeted, GrProtected::kNo,
- GrSurfaceProxy::UseAllocator::kYes);
- }
- GrSwizzle readSwizzle = dContext->priv().caps()->getReadSwizzle(
- backendFormat, GrColorType::kRGBA_8888);
- GrSurfaceProxyView view(std::move(proxy), kTopLeft_GrSurfaceOrigin, readSwizzle);
- sdc->drawTexture(nullptr,
- view,
- kPremul_SkAlphaType,
- GrSamplerState::Filter::kNearest,
- GrSamplerState::MipmapMode::kNone,
- SkBlendMode::kSrcOver,
- SkPMColor4f(),
- SkRect::MakeWH(w, h),
- SkRect::MakeWH(w, h),
- GrAA::kNo,
- GrQuadAAFlags::kNone,
- SkCanvas::kFast_SrcRectConstraint,
- SkMatrix::I(),
- nullptr);
- // We still have the proxy, which should remain instantiated, thereby keeping the
- // texture not purgeable.
- REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end());
- dContext->flushAndSubmit();
- REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end());
- dContext->submit(true);
- REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end());
-
- // This time we move the proxy into the draw.
- sdc->drawTexture(nullptr,
- std::move(view),
- kPremul_SkAlphaType,
- GrSamplerState::Filter::kNearest,
- GrSamplerState::MipmapMode::kNone,
- SkBlendMode::kSrcOver,
- SkPMColor4f(),
- SkRect::MakeWH(w, h),
- SkRect::MakeWH(w, h),
- GrAA::kNo,
- GrQuadAAFlags::kNone,
- SkCanvas::kFast_SrcRectConstraint,
- SkMatrix::I(),
- nullptr);
- REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end());
- dContext->flushAndSubmit(true);
- // Now that the draw is fully consumed by the GPU, the texture should be idle.
- REPORTER_ASSERT(reporter, idleIDs.find(2) != idleIDs.end());
-
- // Make sure we make the call during various shutdown scenarios where the texture
- // might persist after context is destroyed, abandoned, etc. We test three
- // variations of each scenario. One where the texture is just created. Another,
- // where the texture has been used in a draw and then the context is flushed. And
- // one where the the texture was drawn but the context is not flushed.
- // In each scenario we test holding a ref beyond the context shutdown and not.
-
- // These tests are difficult to get working with Vulkan, Direct3D, and Dawn.
- // See http://skbug.com/8705, http://skbug.com/8277, and http://skbug.com/10326
- GrBackendApi api = sk_gpu_test::GrContextFactory::ContextTypeBackend(contextType);
- if (api == GrBackendApi::kVulkan || api == GrBackendApi::kDirect3D ||
- api == GrBackendApi::kDawn) {
- continue;
- }
- int id = 3;
- enum class DrawType {
- kNoDraw,
- kDraw,
- kDrawAndFlush,
- };
- for (auto drawType :
- {DrawType::kNoDraw, DrawType::kDraw, DrawType::kDrawAndFlush}) {
- for (bool unrefFirst : {false, true}) {
- auto possiblyDrawAndFlush = [&dContext, &texture, drawType, unrefFirst, w,
- h] {
- if (drawType == DrawType::kNoDraw) {
- return;
- }
- SkImageInfo info = SkImageInfo::Make(w, h, kRGBA_8888_SkColorType,
- kPremul_SkAlphaType);
- auto rt = SkSurface::MakeRenderTarget(dContext, SkBudgeted::kNo, info, 0,
- nullptr);
- auto sdc = SkCanvasPriv::TopDeviceSurfaceDrawContext(rt->getCanvas());
- auto proxy = dContext->priv().proxyProvider()->testingOnly_createWrapped(
- texture);
- GrSwizzle swizzle = dContext->priv().caps()->getReadSwizzle(
- proxy->backendFormat(), GrColorType::kRGBA_8888);
- GrSurfaceProxyView view(std::move(proxy), kTopLeft_GrSurfaceOrigin,
- swizzle);
- sdc->drawTexture(nullptr,
- std::move(view),
- kPremul_SkAlphaType,
- GrSamplerState::Filter::kNearest,
- GrSamplerState::MipmapMode::kNone,
- SkBlendMode::kSrcOver,
- SkPMColor4f(),
- SkRect::MakeWH(w, h),
- SkRect::MakeWH(w, h),
- GrAA::kNo,
- GrQuadAAFlags::kNone,
- SkCanvas::kFast_SrcRectConstraint,
- SkMatrix::I(),
- nullptr);
- if (drawType == DrawType::kDrawAndFlush) {
- dContext->flushAndSubmit();
- }
- if (unrefFirst) {
- texture.reset();
- }
- };
- texture = make(dContext, id);
- possiblyDrawAndFlush();
- dContext->abandonContext();
- texture.reset();
- REPORTER_ASSERT(reporter, idleIDs.find(id) != idleIDs.end());
- factory.destroyContexts();
- dContext = factory.get(contextType);
- ++id;
-
- // Similar to previous, but reset the texture after the context was
- // abandoned and then destroyed.
- texture = make(dContext, id);
- possiblyDrawAndFlush();
- dContext->abandonContext();
- factory.destroyContexts();
- texture.reset();
- REPORTER_ASSERT(reporter, idleIDs.find(id) != idleIDs.end());
- dContext = factory.get(contextType);
- id++;
-
- texture = make(dContext, id);
- possiblyDrawAndFlush();
- factory.destroyContexts();
- texture.reset();
- REPORTER_ASSERT(reporter, idleIDs.find(id) != idleIDs.end());
- dContext = factory.get(contextType);
- id++;
-
- texture = make(dContext, id);
- possiblyDrawAndFlush();
- factory.releaseResourcesAndAbandonContexts();
- texture.reset();
- REPORTER_ASSERT(reporter, idleIDs.find(id) != idleIDs.end());
- dContext = factory.get(contextType);
- id++;
- }
- }
- }
- }
- }
-}
-
-// Tests an idle proc that unrefs another resource down to zero.
-DEF_GPUTEST_FOR_ALL_CONTEXTS(TextureIdleProcCacheManipulationTest, reporter, contextInfo) {
- auto context = contextInfo.directContext();
-
- // idle proc that releases another texture.
- auto idleProc = [](void* texture) { reinterpret_cast<GrTexture*>(texture)->unref(); };
-
- for (const auto& idleMaker : {make_wrapped_texture, make_normal_texture}) {
- for (const auto& otherMaker : {make_wrapped_texture, make_normal_texture}) {
- auto idleTexture = idleMaker(context, GrRenderable::kNo);
- auto otherTexture = otherMaker(context, GrRenderable::kNo);
- otherTexture->ref();
- idleTexture->addIdleProc(idleProc, otherTexture.get());
- otherTexture.reset();
- idleTexture.reset();
- }
- }
-}
-
-// Similar to above but more complicated. This flushes the context from the idle proc.
-// crbug.com/933526.
-DEF_GPUTEST_FOR_ALL_CONTEXTS(TextureIdleProcFlushTest, reporter, contextInfo) {
- auto dContext = contextInfo.directContext();
-
- // idle proc that flushes the context.
- auto idleProc = [](void* context) {
- reinterpret_cast<GrDirectContext*>(context)->flushAndSubmit();
- };
-
- for (const auto& idleMaker : {make_wrapped_texture, make_normal_texture}) {
- auto idleTexture = idleMaker(dContext, GrRenderable::kNo);
- idleTexture->addIdleProc(idleProc, dContext);
- auto info = SkImageInfo::Make(10, 10, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
- auto surf = SkSurface::MakeRenderTarget(dContext, SkBudgeted::kNo, info, 1, nullptr);
- // We'll draw two images to the canvas. One is a normal texture-backed image. The other
- // is a wrapped-texture backed image.
- surf->getCanvas()->clear(SK_ColorWHITE);
- auto img1 = surf->makeImageSnapshot();
- auto img2 = sk_gpu_test::MakeBackendTextureImage(dContext, info, SkColors::kBlack);
- REPORTER_ASSERT(reporter, img1 && img2);
- surf->getCanvas()->drawImage(std::move(img1), 0, 0);
- surf->getCanvas()->drawImage(std::move(img2), 1, 1);
- idleTexture.reset();
- }
-}
-
-DEF_GPUTEST_FOR_ALL_CONTEXTS(TextureIdleProcRerefTest, reporter, contextInfo) {
- auto context = contextInfo.directContext();
- // idle proc that refs the texture
- auto idleProc = [](void* texture) { reinterpret_cast<GrTexture*>(texture)->ref(); };
- // release proc to check whether the texture was released or not.
- auto releaseProc = [](void* isReleased) { *reinterpret_cast<bool*>(isReleased) = true; };
- bool isReleased = false;
- auto idleTexture = make_normal_texture(context, GrRenderable::kNo);
- // This test assumes the texture won't be cached (or else the release proc doesn't get
- // called).
- idleTexture->resourcePriv().removeScratchKey();
- context->flushAndSubmit();
- idleTexture->addIdleProc(idleProc, idleTexture.get());
- idleTexture->setRelease(releaseProc, &isReleased);
- auto* raw = idleTexture.get();
- idleTexture.reset();
- REPORTER_ASSERT(reporter, !isReleased);
- raw->unref();
- REPORTER_ASSERT(reporter, isReleased);
-}
-
-DEF_GPUTEST_FOR_ALL_CONTEXTS(TextureIdleStateTest, reporter, contextInfo) {
- auto context = contextInfo.directContext();
- for (const auto& idleMaker : {make_wrapped_texture, make_normal_texture}) {
- auto idleTexture = idleMaker(context, GrRenderable::kNo);
-
- bool called = false;
- auto finishProc = [](void* called) { *static_cast<bool*>(called) = true; };
- idleTexture->addIdleProc(finishProc, &called);
-
- // Insert a copy from idleTexture to another texture so that we have some queued IO on
- // idleTexture.
- SkImageInfo info = SkImageInfo::Make(kSurfSize, kSurfSize, kRGBA_8888_SkColorType,
- kPremul_SkAlphaType);
- auto rt = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 0, nullptr);
- auto sdc = SkCanvasPriv::TopDeviceSurfaceDrawContext(rt->getCanvas());
- auto proxy =
- context->priv().proxyProvider()->testingOnly_createWrapped(std::move(idleTexture));
- context->flushAndSubmit();
- SkAssertResult(sdc->testCopy(std::move(proxy)));
- REPORTER_ASSERT(reporter, !called);
-
- // After a flush we expect idleTexture to have reached the kFlushed state on all backends.
- // On "managed" backends we expect it to reach kFinished as well. On Vulkan, the only
- // current "unmanaged" backend, we *may* need a sync to reach kFinished.
- context->flushAndSubmit();
- if (contextInfo.backend() != kVulkan_GrBackend) {
- REPORTER_ASSERT(reporter, called);
- }
- context->submit(true);
- REPORTER_ASSERT(reporter, called);
- }
-}
diff --git a/tools/run-wasm-gm-tests/run-wasm-gm-tests.html b/tools/run-wasm-gm-tests/run-wasm-gm-tests.html
index 1fbda89..5a59696 100644
--- a/tools/run-wasm-gm-tests/run-wasm-gm-tests.html
+++ b/tools/run-wasm-gm-tests/run-wasm-gm-tests.html
@@ -183,7 +183,6 @@
'InitialTextureClear',
'PinnedImageTest',
'PromiseImageTextureShutdown',
- 'TextureIdleProcTest',
// These tests time out
'SkTraceMemoryDump_ownedGLRenderTarget',