From a01d5283ec1dc6a4dc50e4b8da48e6de1c6ac1dd Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Wed, 27 Jul 2022 19:35:51 +1200 Subject: [PATCH] TextureCache: Add content locking Texture cache occasionally mutates textures for efficiency. Which is awkward if we want to borrow those textures from texture cache to do something else, such as a graphics debugger, or async presentation on another thread. Content locking provides a way to signal that the contents of a texture cache entry should not change. Texture cache will be forced to use alternative strategies. --- Source/Core/VideoCommon/TextureCacheBase.cpp | 42 +++++++++++++------- Source/Core/VideoCommon/TextureCacheBase.h | 14 +++++-- 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index 84208c8094..6102767e70 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -700,7 +700,8 @@ void TextureCacheBase::DoLoadState(PointerWrap& p) // Even if the texture isn't valid, we still need to create the cache entry object // to update the point in the state state. We'll just throw it away if it's invalid. auto tex = DeserializeTexture(p); - auto entry = Common::make_rc(std::move(tex->texture), std::move(tex->framebuffer)); + auto entry = + std::make_shared(std::move(tex->texture), std::move(tex->framebuffer)); entry->textures_by_hash_iter = textures_by_hash.end(); entry->DoState(p); if (entry->texture && commit_state) @@ -809,6 +810,13 @@ RcTcacheEntry TextureCacheBase::DoPartialTextureUpdates(RcTcacheEntry& entry_to_ if (entry_to_update->IsCopy()) return entry_to_update; + if (entry_to_update->IsLocked()) + { + // TODO: Shouldn't be too hard, just need to clone the texture entry + texture contents. + PanicAlertFmt("TextureCache: PartialTextureUpdates of locked textures is not implemented"); + return {}; + } + u32 block_width = TexDecoder_GetBlockWidthInTexels(entry_to_update->format.texfmt); u32 block_height = TexDecoder_GetBlockHeightInTexels(entry_to_update->format.texfmt); u32 block_size = block_width * block_height * @@ -1474,8 +1482,11 @@ RcTcacheEntry TextureCacheBase::GetTexture(const int textureCacheSafetyColorSamp { entry = DoPartialTextureUpdates(iter->second, texture_info.GetTlutAddress(), texture_info.GetTlutFormat()); - entry->texture->FinishedRendering(); - return entry; + if (entry) + { + entry->texture->FinishedRendering(); + return entry; + } } } @@ -1511,9 +1522,8 @@ RcTcacheEntry TextureCacheBase::GetTexture(const int textureCacheSafetyColorSamp if (unconverted_copy != textures_by_address.end()) { - auto decoded_entry = - ApplyPaletteToEntry(unconverted_copy->second, texture_info.GetTlutAddress(), - texture_info.GetTlutFormat()); + auto decoded_entry = ApplyPaletteToEntry( + unconverted_copy->second, texture_info.GetTlutAddress(), texture_info.GetTlutFormat()); if (decoded_entry) { @@ -1543,8 +1553,11 @@ RcTcacheEntry TextureCacheBase::GetTexture(const int textureCacheSafetyColorSamp { entry = DoPartialTextureUpdates(hash_iter->second, texture_info.GetTlutAddress(), texture_info.GetTlutFormat()); - entry->texture->FinishedRendering(); - return entry; + if (entry) + { + entry->texture->FinishedRendering(); + return entry; + } } ++hash_iter; } @@ -1771,9 +1784,9 @@ RcTcacheEntry TextureCacheBase::GetXFBTexture(u32 address, u32 width, u32 height return {}; } - // Do we currently have a version of this XFB copy in VRAM? + // Do we currently have a mutable version of this XFB copy in VRAM? RcTcacheEntry entry = GetXFBFromCache(address, width, height, stride); - if (entry) + if (entry && !entry->IsLocked()) { if (entry->is_xfb_container) { @@ -2265,8 +2278,8 @@ void TextureCacheBase::CopyRenderTargetToTexture( entry->may_have_overlapping_textures = false; entry->is_custom_tex = false; - CopyEFBToCacheEntry(entry, is_depth_copy, srcRect, scaleByHalf, linear_filter, - dstFormat, isIntensity, gamma, clamp_top, clamp_bottom, + CopyEFBToCacheEntry(entry, is_depth_copy, srcRect, scaleByHalf, linear_filter, dstFormat, + isIntensity, gamma, clamp_top, clamp_bottom, GetVRAMCopyFilterCoefficients(filter_coefficients)); if (is_xfb_copy && (g_ActiveConfig.bDumpXFBTarget || g_ActiveConfig.bGraphicMods)) @@ -2584,7 +2597,7 @@ RcTcacheEntry TextureCacheBase::AllocateCacheEntry(const TextureConfig& config) return {}; auto cacheEntry = - Common::make_rc(std::move(alloc->texture), std::move(alloc->framebuffer)); + std::make_shared(std::move(alloc->texture), std::move(alloc->framebuffer)); cacheEntry->textures_by_hash_iter = textures_by_hash.end(); cacheEntry->id = last_entry_id++; return cacheEntry; @@ -2710,7 +2723,8 @@ TextureCacheBase::InvalidateTexture(TexAddrCache::iterator iter, bool discard_pe { // The texture data has already been copied into the staging texture, so it's valid to // optimistically release the texture data. Will slightly lower VRAM usage. - ReleaseToPool(entry.get()); + if (!entry->IsLocked()) + ReleaseToPool(entry.get()); } } entry->invalidated = true; diff --git a/Source/Core/VideoCommon/TextureCacheBase.h b/Source/Core/VideoCommon/TextureCacheBase.h index c0540cd0df..8b9010a50e 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.h +++ b/Source/Core/VideoCommon/TextureCacheBase.h @@ -19,7 +19,6 @@ #include "Common/BitSet.h" #include "Common/CommonTypes.h" #include "Common/MathUtil.h" -#include "Common/RcPtr.h" #include "VideoCommon/AbstractTexture.h" #include "VideoCommon/BPMemory.h" #include "VideoCommon/TextureConfig.h" @@ -127,6 +126,7 @@ struct TCacheEntry bool is_xfb_copy = false; bool is_xfb_container = false; u64 id = 0; + u32 content_semaphore = 0; // Counts up // Indicates that this TCacheEntry has been invalided from textures_by_address bool invalidated = false; @@ -143,7 +143,7 @@ struct TCacheEntry // Keep an iterator to the entry in textures_by_hash, so it does not need to be searched when // removing the cache entry - std::multimap>::iterator textures_by_hash_iter; + std::multimap>::iterator textures_by_hash_iter; // This is used to keep track of both: // * efb copies used by this partially updated texture @@ -194,6 +194,14 @@ struct TCacheEntry other_entry->references.emplace(this); } + // Acquiring a content lock will lock the current contents and prevent texture cache from + // reusing the same entry for a newer version of the texture. + void AcquireContentLock() { content_semaphore++; } + void ReleaseContentLock() { content_semaphore--; } + + // Can this be mutated? + bool IsLocked() const { return content_semaphore > 0; } + void SetXfbCopy(u32 stride); void SetEfbCopy(u32 stride); void SetNotCopy(); @@ -217,7 +225,7 @@ struct TCacheEntry void DoState(PointerWrap& p); }; -using RcTcacheEntry = Common::rc_ptr; +using RcTcacheEntry = std::shared_ptr; class TextureCacheBase {