diff options
| author | Scott Mansell <phiren@gmail.com> | 2023-02-09 19:59:16 +1300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-02-09 19:59:16 +1300 |
| commit | ccf92a3e56764d6378c436a8040519a5bffc3372 (patch) | |
| tree | e2b330b225044e1901e77a6ed147cf21b9d7ac0e /Source/Core/VideoCommon/TextureCacheBase.h | |
| parent | 72b22ef0a54f841b1c52d49cf0e00d3b12c29ac7 (diff) | |
| parent | 5c1b3ac61d7e660a9d1c206dbd0e615d637d3272 (diff) | |
Merge pull request #11522 from phire/KillRendererWithFire
Kill Renderer (with phire)
Diffstat (limited to 'Source/Core/VideoCommon/TextureCacheBase.h')
| -rw-r--r-- | Source/Core/VideoCommon/TextureCacheBase.h | 301 |
1 files changed, 170 insertions, 131 deletions
diff --git a/Source/Core/VideoCommon/TextureCacheBase.h b/Source/Core/VideoCommon/TextureCacheBase.h index 4fe11a64f4..958d7704fe 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.h +++ b/Source/Core/VideoCommon/TextureCacheBase.h @@ -18,12 +18,15 @@ #include "Common/BitSet.h" #include "Common/CommonTypes.h" +#include "Common/Flag.h" #include "Common/MathUtil.h" + #include "VideoCommon/AbstractTexture.h" #include "VideoCommon/BPMemory.h" #include "VideoCommon/TextureConfig.h" #include "VideoCommon/TextureDecoder.h" #include "VideoCommon/TextureInfo.h" +#include "VideoCommon/VideoEvents.h" class AbstractFramebuffer; class AbstractStagingTexture; @@ -33,6 +36,8 @@ struct VideoConfig; constexpr std::string_view EFB_DUMP_PREFIX = "efb1"; constexpr std::string_view XFB_DUMP_PREFIX = "xfb1"; +static constexpr int FRAMECOUNT_INVALID = 0; + struct TextureAndTLUTFormat { TextureAndTLUTFormat(TextureFormat texfmt_ = TextureFormat::I4, @@ -86,6 +91,7 @@ struct EFBCopyParams template <> struct fmt::formatter<EFBCopyParams> { + std::shared_ptr<int> state; constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } template <typename FormatContext> auto format(const EFBCopyParams& uid, FormatContext& ctx) const @@ -103,121 +109,130 @@ struct fmt::formatter<EFBCopyParams> } }; -class TextureCacheBase +struct TCacheEntry { -private: - static const int FRAMECOUNT_INVALID = 0; + // common members + std::unique_ptr<AbstractTexture> texture; + std::unique_ptr<AbstractFramebuffer> framebuffer; + u32 addr = 0; + u32 size_in_bytes = 0; + u64 base_hash = 0; + u64 hash = 0; // for paletted textures, hash = base_hash ^ palette_hash + TextureAndTLUTFormat format; + u32 memory_stride = 0; + bool is_efb_copy = false; + bool is_custom_tex = false; + bool may_have_overlapping_textures = true; + // indicates that the mips in this texture are arbitrary content, aren't just downscaled + bool has_arbitrary_mips = false; + bool should_force_safe_hashing = false; // for XFB + 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; + + bool reference_changed = false; // used by xfb to determine when a reference xfb changed + + // Texture dimensions from the GameCube's point of view + u32 native_width = 0; + u32 native_height = 0; + u32 native_levels = 0; + + // used to delete textures which haven't been used for TEXTURE_KILL_THRESHOLD frames + int frameCount = FRAMECOUNT_INVALID; + + // 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<u64, std::shared_ptr<TCacheEntry>>::iterator textures_by_hash_iter; + + // This is used to keep track of both: + // * efb copies used by this partially updated texture + // * partially updated textures which refer to this efb copy + std::unordered_set<TCacheEntry*> references; + + // Pending EFB copy + std::unique_ptr<AbstractStagingTexture> pending_efb_copy; + u32 pending_efb_copy_width = 0; + u32 pending_efb_copy_height = 0; + + std::string texture_info_name = ""; + + explicit TCacheEntry(std::unique_ptr<AbstractTexture> tex, + std::unique_ptr<AbstractFramebuffer> fb); + + ~TCacheEntry(); + + void SetGeneralParameters(u32 _addr, u32 _size, TextureAndTLUTFormat _format, + bool force_safe_hashing) + { + addr = _addr; + size_in_bytes = _size; + format = _format; + should_force_safe_hashing = force_safe_hashing; + } -public: - struct TCacheEntry + void SetDimensions(unsigned int _native_width, unsigned int _native_height, + unsigned int _native_levels) { - // common members - std::unique_ptr<AbstractTexture> texture; - std::unique_ptr<AbstractFramebuffer> framebuffer; - u32 addr = 0; - u32 size_in_bytes = 0; - u64 base_hash = 0; - u64 hash = 0; // for paletted textures, hash = base_hash ^ palette_hash - TextureAndTLUTFormat format; - u32 memory_stride = 0; - bool is_efb_copy = false; - bool is_custom_tex = false; - bool may_have_overlapping_textures = true; - bool tmem_only = false; // indicates that this texture only exists in the tmem cache - bool has_arbitrary_mips = false; // indicates that the mips in this texture are arbitrary - // content, aren't just downscaled - bool should_force_safe_hashing = false; // for XFB - bool is_xfb_copy = false; - bool is_xfb_container = false; - u64 id = 0; - - bool reference_changed = false; // used by xfb to determine when a reference xfb changed - - // Texture dimensions from the GameCube's point of view - u32 native_width = 0; - u32 native_height = 0; - u32 native_levels = 0; - - // used to delete textures which haven't been used for TEXTURE_KILL_THRESHOLD frames - int frameCount = FRAMECOUNT_INVALID; + native_width = _native_width; + native_height = _native_height; + native_levels = _native_levels; + memory_stride = _native_width; + } - // 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<u64, TCacheEntry*>::iterator textures_by_hash_iter; - - // This is used to keep track of both: - // * efb copies used by this partially updated texture - // * partially updated textures which refer to this efb copy - std::unordered_set<TCacheEntry*> references; - - // Pending EFB copy - std::unique_ptr<AbstractStagingTexture> pending_efb_copy; - u32 pending_efb_copy_width = 0; - u32 pending_efb_copy_height = 0; - bool pending_efb_copy_invalidated = false; - - std::string texture_info_name = ""; - - explicit TCacheEntry(std::unique_ptr<AbstractTexture> tex, - std::unique_ptr<AbstractFramebuffer> fb); - - ~TCacheEntry(); - - void SetGeneralParameters(u32 _addr, u32 _size, TextureAndTLUTFormat _format, - bool force_safe_hashing) - { - addr = _addr; - size_in_bytes = _size; - format = _format; - should_force_safe_hashing = force_safe_hashing; - } - - void SetDimensions(unsigned int _native_width, unsigned int _native_height, - unsigned int _native_levels) - { - native_width = _native_width; - native_height = _native_height; - native_levels = _native_levels; - memory_stride = _native_width; - } - - void SetHashes(u64 _base_hash, u64 _hash) - { - base_hash = _base_hash; - hash = _hash; - } - - // This texture entry is used by the other entry as a sub-texture - void CreateReference(TCacheEntry* other_entry) - { - // References are two-way, so they can easily be destroyed later - this->references.emplace(other_entry); - other_entry->references.emplace(this); - } - - void SetXfbCopy(u32 stride); - void SetEfbCopy(u32 stride); - void SetNotCopy(); - - bool OverlapsMemoryRange(u32 range_address, u32 range_size) const; - - bool IsEfbCopy() const { return is_efb_copy; } - bool IsCopy() const { return is_xfb_copy || is_efb_copy; } - u32 NumBlocksX() const; - u32 NumBlocksY() const; - u32 BytesPerRow() const; - - u64 CalculateHash() const; - - int HashSampleSize() const; - u32 GetWidth() const { return texture->GetConfig().width; } - u32 GetHeight() const { return texture->GetConfig().height; } - u32 GetNumLevels() const { return texture->GetConfig().levels; } - u32 GetNumLayers() const { return texture->GetConfig().layers; } - AbstractTextureFormat GetFormat() const { return texture->GetConfig().format; } - void DoState(PointerWrap& p); - }; + void SetHashes(u64 _base_hash, u64 _hash) + { + base_hash = _base_hash; + hash = _hash; + } + + // This texture entry is used by the other entry as a sub-texture + void CreateReference(TCacheEntry* other_entry) + { + // References are two-way, so they can easily be destroyed later + this->references.emplace(other_entry); + 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(); + bool OverlapsMemoryRange(u32 range_address, u32 range_size) const; + + bool IsEfbCopy() const { return is_efb_copy; } + bool IsCopy() const { return is_xfb_copy || is_efb_copy; } + u32 NumBlocksX() const; + u32 NumBlocksY() const; + u32 BytesPerRow() const; + + u64 CalculateHash() const; + + int HashSampleSize() const; + u32 GetWidth() const { return texture->GetConfig().width; } + u32 GetHeight() const { return texture->GetConfig().height; } + u32 GetNumLevels() const { return texture->GetConfig().levels; } + u32 GetNumLayers() const { return texture->GetConfig().layers; } + AbstractTextureFormat GetFormat() const { return texture->GetConfig().format; } + void DoState(PointerWrap& p); +}; + +using RcTcacheEntry = std::shared_ptr<TCacheEntry>; + +class TextureCacheBase +{ +public: // Minimal version of TCacheEntry just for TexPool struct TexPoolEntry { @@ -232,6 +247,7 @@ public: virtual ~TextureCacheBase(); bool Initialize(); + void Shutdown(); void OnConfigChanged(const VideoConfig& config); void ForceReload(); @@ -241,12 +257,13 @@ public: void Cleanup(int _frameCount); void Invalidate(); + void ReleaseToPool(TCacheEntry* entry); TCacheEntry* Load(const TextureInfo& texture_info); - TCacheEntry* GetTexture(const int textureCacheSafetyColorSampleSize, - const TextureInfo& texture_info); - TCacheEntry* GetXFBTexture(u32 address, u32 width, u32 height, u32 stride, - MathUtil::Rectangle<int>* display_rect); + RcTcacheEntry GetTexture(const int textureCacheSafetyColorSampleSize, + const TextureInfo& texture_info); + RcTcacheEntry GetXFBTexture(u32 address, u32 width, u32 height, u32 stride, + MathUtil::Rectangle<int>* display_rect); virtual void BindTextures(BitSet32 used_textures); void CopyRenderTargetToTexture(u32 dstAddr, EFBCopyFormat dstFormat, u32 width, u32 height, @@ -256,11 +273,14 @@ public: bool clamp_bottom, const CopyFilterCoefficients::Values& filter_coefficients); - void ScaleTextureCacheEntryTo(TCacheEntry* entry, u32 new_width, u32 new_height); + void ScaleTextureCacheEntryTo(RcTcacheEntry& entry, u32 new_width, u32 new_height); // Flushes all pending EFB copies to emulated RAM. void FlushEFBCopies(); + // Flush any Bound textures that can't be reused + void FlushStaleBinds(); + // Texture Serialization void SerializeTexture(AbstractTexture* tex, const TextureConfig& config, PointerWrap& p); std::optional<TexPoolEntry> DeserializeTexture(PointerWrap& p); @@ -271,13 +291,16 @@ public: static bool AllCopyFilterCoefsNeeded(const std::array<u32, 3>& coefficients); static bool CopyFilterCanOverflow(const std::array<u32, 3>& coefficients); + // Will forcibly reload all textures when the frame next ends + void ForceReloadTextures() { m_force_reload_textures.Set(); } + protected: // Decodes the specified data to the GPU texture specified by entry. // Returns false if the configuration is not supported. // width, height are the size of the image in pixels. // aligned_width, aligned_height are the size of the image in pixels, aligned to the block size. // row_stride is the number of bytes for a row of blocks, not pixels. - bool DecodeTextureOnGPU(TCacheEntry* entry, u32 dst_level, const u8* data, u32 data_size, + bool DecodeTextureOnGPU(RcTcacheEntry& entry, u32 dst_level, const u8* data, u32 data_size, TextureFormat format, u32 width, u32 height, u32 aligned_width, u32 aligned_height, u32 row_stride, const u8* palette, TLUTFormat palette_format); @@ -287,7 +310,7 @@ protected: const MathUtil::Rectangle<int>& src_rect, bool scale_by_half, bool linear_filter, float y_scale, float gamma, bool clamp_top, bool clamp_bottom, const std::array<u32, 3>& filter_coefficients); - virtual void CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy, + virtual void CopyEFBToCacheEntry(RcTcacheEntry& entry, bool is_depth_copy, const MathUtil::Rectangle<int>& src_rect, bool scale_by_half, bool linear_filter, EFBCopyFormat dst_format, bool is_intensity, float gamma, bool clamp_top, bool clamp_bottom, @@ -296,32 +319,31 @@ protected: alignas(16) u8* temp = nullptr; size_t temp_size = 0; - std::array<TCacheEntry*, 8> bound_textures{}; - static std::bitset<8> valid_bind_points; - private: - using TexAddrCache = std::multimap<u32, TCacheEntry*>; - using TexHashCache = std::multimap<u64, TCacheEntry*>; + using TexAddrCache = std::multimap<u32, RcTcacheEntry>; + using TexHashCache = std::multimap<u64, RcTcacheEntry>; + using TexPool = std::unordered_multimap<TextureConfig, TexPoolEntry>; bool CreateUtilityTextures(); void SetBackupConfig(const VideoConfig& config); - TCacheEntry* GetXFBFromCache(u32 address, u32 width, u32 height, u32 stride); + RcTcacheEntry GetXFBFromCache(u32 address, u32 width, u32 height, u32 stride); - TCacheEntry* ApplyPaletteToEntry(TCacheEntry* entry, const u8* palette, TLUTFormat tlutfmt); + RcTcacheEntry ApplyPaletteToEntry(RcTcacheEntry& entry, const u8* palette, TLUTFormat tlutfmt); - TCacheEntry* ReinterpretEntry(const TCacheEntry* existing_entry, TextureFormat new_format); + RcTcacheEntry ReinterpretEntry(const RcTcacheEntry& existing_entry, TextureFormat new_format); - TCacheEntry* DoPartialTextureUpdates(TCacheEntry* entry_to_update, const u8* palette, - TLUTFormat tlutfmt); - void StitchXFBCopy(TCacheEntry* entry_to_update); + RcTcacheEntry DoPartialTextureUpdates(RcTcacheEntry& entry_to_update, const u8* palette, + TLUTFormat tlutfmt); + void StitchXFBCopy(RcTcacheEntry& entry_to_update); - void DumpTexture(TCacheEntry* entry, std::string basename, unsigned int level, bool is_arbitrary); + void DumpTexture(RcTcacheEntry& entry, std::string basename, unsigned int level, + bool is_arbitrary); void CheckTempSize(size_t required_size); - TCacheEntry* AllocateCacheEntry(const TextureConfig& config); + RcTcacheEntry AllocateCacheEntry(const TextureConfig& config); std::optional<TexPoolEntry> AllocateTexture(const TextureConfig& config); TexPool::iterator FindMatchingTextureFromPool(const TextureConfig& config); TexAddrCache::iterator GetTexCacheIter(TCacheEntry* entry); @@ -359,8 +381,18 @@ private: void DoSaveState(PointerWrap& p); void DoLoadState(PointerWrap& p); + // textures_by_address is the authoritive version of what's actually "in" the texture cache + // but it's possible for invalidated TCache entries to live on elsewhere TexAddrCache textures_by_address; + + // textures_by_hash is an alternative view of the texture cache + // All textures in here will also be in textures_by_address TexHashCache textures_by_hash; + + // bound_textures are actually active in the current draw + // It's valid for textures to be in here after they've been invalidated + std::array<RcTcacheEntry, 8> bound_textures{}; + TexPool texture_pool; u64 last_entry_id = 0; @@ -395,12 +427,19 @@ private: // List of pending EFB copies. It is important that the order is preserved for these, // so that overlapping textures are written to guest RAM in the order they are issued. - std::vector<TCacheEntry*> m_pending_efb_copies; + // It's valid for textures to live be in here after they've been invalidated + std::vector<RcTcacheEntry> m_pending_efb_copies; // Staging texture used for readbacks. // We store this in the class so that the same staging texture can be used for multiple // readbacks, saving the overhead of allocating a new buffer every time. std::unique_ptr<AbstractStagingTexture> m_readback_texture; + + void OnFrameEnd(); + + Common::Flag m_force_reload_textures; + Common::EventHook m_frame_event = + AfterFrameEvent::Register([this] { OnFrameEnd(); }, "TextureCache"); }; extern std::unique_ptr<TextureCacheBase> g_texture_cache; |
