| /* |
| * Copyright 2024 Google LLC |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "src/gpu/graphite/ScratchResourceManager.h" |
| |
| #include "src/gpu/graphite/Resource.h" |
| #include "src/gpu/graphite/ResourceProvider.h" |
| #include "src/gpu/graphite/Texture.h" |
| #include "src/gpu/graphite/TextureProxy.h" |
| |
| namespace skgpu::graphite { |
| |
| #if defined(SK_DEBUG) |
| bool ProxyReadCountMap::hasPendingReads() const { |
| bool hasPendingReads = false; |
| fCounts.foreach([&hasPendingReads](const TextureProxy*, int proxyReadCount) { |
| hasPendingReads |= (proxyReadCount > 0); |
| }); |
| return hasPendingReads; |
| } |
| #endif |
| |
| ScratchResourceManager::ScratchResourceManager(ResourceProvider* resourceProvider, |
| std::unique_ptr<ProxyReadCountMap> proxyCounts) |
| : fResourceProvider(resourceProvider) |
| , fProxyReadCounts(std::move(proxyCounts)) { |
| SkASSERT(resourceProvider); |
| SkASSERT(fProxyReadCounts); |
| } |
| |
| ScratchResourceManager::~ScratchResourceManager() { |
| SkASSERT(fUnavailable.empty()); |
| SkASSERT(!fProxyReadCounts->hasPendingReads()); |
| } |
| |
| sk_sp<Texture> ScratchResourceManager::getScratchTexture(SkISize dimensions, |
| const TextureInfo& info, |
| std::string_view label) { |
| sk_sp<Texture> scratchTexture = fResourceProvider->findOrCreateScratchTexture( |
| dimensions, info, label, fUnavailable); |
| // Store the returned scratch texture into fUnavailable so that it is filtered from the |
| // ResourceCache when going through *this* ScratchResourceManager. But the scratch texture will |
| // remain visible to other Recorders. |
| SkASSERT(!fUnavailable.contains(scratchTexture.get())); |
| fUnavailable.add(scratchTexture.get()); |
| return scratchTexture; |
| } |
| |
| void ScratchResourceManager::returnTexture(sk_sp<Texture> texture) { |
| // Fails if trying to return a resource that didn't come from getScratchTexture() |
| SkASSERT(fUnavailable.contains(texture.get())); |
| fUnavailable.remove(texture.get()); |
| } |
| |
| void ScratchResourceManager::pushScope() { |
| // Push a null pointer to mark the beginning of the list of listeners in the next depth |
| fListenerStack.push_back(nullptr); |
| } |
| |
| void ScratchResourceManager::popScope() { |
| // Must have at least the null element to start the scope being popped |
| SkASSERT(!fListenerStack.empty()); |
| |
| // TODO: Assert that the current sublist is empty (i.e. the back element is a null pointer) but |
| // for now skip over them and leave them un-invoked to keep the unconsumed scratch resources |
| // out of the pool so they remain valid in later recordings. |
| int n = 0; |
| while (fListenerStack.fromBack(n)) { |
| n++; |
| } |
| SkASSERT(n < fListenerStack.size() && fListenerStack.fromBack(n) == nullptr); |
| // Remove all non-null listeners after the most recent null entry AND the null entry |
| fListenerStack.pop_back_n(n + 1); |
| } |
| |
| void ScratchResourceManager::notifyResourcesConsumed() { |
| // Should only be called inside a scope |
| SkASSERT(!fListenerStack.empty()); |
| |
| int n = 0; |
| while (PendingUseListener* listener = fListenerStack.fromBack(n)) { |
| listener->onUseCompleted(this); |
| n++; |
| } |
| SkASSERT(n < fListenerStack.size() && fListenerStack.fromBack(n) == nullptr); |
| // Remove all non-null listeners that were just invoked, but do not remove the null entry that |
| // marks the start of this scope boundary. |
| if (n > 0) { |
| fListenerStack.pop_back_n(n); |
| } |
| } |
| |
| void ScratchResourceManager::markResourceInUse(PendingUseListener* listener) { |
| // Should only be called inside a scope |
| SkASSERT(!fListenerStack.empty()); |
| fListenerStack.push_back(listener); |
| } |
| |
| } // namespace skgpu::graphite |