1 // Copyright 2010 Dolphin Emulator Project 2 // Licensed under GPLv2+ 3 // Refer to the license.txt file included. 4 5 #pragma once 6 7 #include <array> 8 #include <bitset> 9 #include <map> 10 #include <memory> 11 #include <optional> 12 #include <string> 13 #include <tuple> 14 #include <unordered_map> 15 #include <unordered_set> 16 #include <vector> 17 18 #include "Common/CommonTypes.h" 19 #include "Common/MathUtil.h" 20 #include "VideoCommon/AbstractTexture.h" 21 #include "VideoCommon/BPMemory.h" 22 #include "VideoCommon/TextureConfig.h" 23 #include "VideoCommon/TextureDecoder.h" 24 25 class AbstractFramebuffer; 26 class AbstractStagingTexture; 27 class PointerWrap; 28 struct VideoConfig; 29 30 struct TextureAndTLUTFormat 31 { 32 TextureAndTLUTFormat(TextureFormat texfmt_ = TextureFormat::I4, 33 TLUTFormat tlutfmt_ = TLUTFormat::IA8) texfmtTextureAndTLUTFormat34 : texfmt(texfmt_), tlutfmt(tlutfmt_) 35 { 36 } 37 38 bool operator==(const TextureAndTLUTFormat& other) const 39 { 40 if (IsColorIndexed(texfmt)) 41 return texfmt == other.texfmt && tlutfmt == other.tlutfmt; 42 43 return texfmt == other.texfmt; 44 } 45 46 bool operator!=(const TextureAndTLUTFormat& other) const { return !operator==(other); } 47 TextureFormat texfmt; 48 TLUTFormat tlutfmt; 49 }; 50 51 struct EFBCopyParams 52 { EFBCopyParamsEFBCopyParams53 EFBCopyParams(PEControl::PixelFormat efb_format_, EFBCopyFormat copy_format_, bool depth_, 54 bool yuv_, bool copy_filter_) 55 : efb_format(efb_format_), copy_format(copy_format_), depth(depth_), yuv(yuv_), 56 copy_filter(copy_filter_) 57 { 58 } 59 60 bool operator<(const EFBCopyParams& rhs) const 61 { 62 return std::tie(efb_format, copy_format, depth, yuv, copy_filter) < 63 std::tie(rhs.efb_format, rhs.copy_format, rhs.depth, rhs.yuv, rhs.copy_filter); 64 } 65 66 PEControl::PixelFormat efb_format; 67 EFBCopyFormat copy_format; 68 bool depth; 69 bool yuv; 70 bool copy_filter; 71 }; 72 73 // Reduced version of the full coefficient array, with a single value for each row. 74 struct EFBCopyFilterCoefficients 75 { 76 float upper; 77 float middle; 78 float lower; 79 }; 80 81 class TextureCacheBase 82 { 83 private: 84 static const int FRAMECOUNT_INVALID = 0; 85 86 public: 87 struct TCacheEntry 88 { 89 // common members 90 std::unique_ptr<AbstractTexture> texture; 91 std::unique_ptr<AbstractFramebuffer> framebuffer; 92 u32 addr; 93 u32 size_in_bytes; 94 u64 base_hash; 95 u64 hash; // for paletted textures, hash = base_hash ^ palette_hash 96 TextureAndTLUTFormat format; 97 u32 memory_stride; 98 bool is_efb_copy; 99 bool is_custom_tex; 100 bool may_have_overlapping_textures = true; 101 bool tmem_only = false; // indicates that this texture only exists in the tmem cache 102 bool has_arbitrary_mips = false; // indicates that the mips in this texture are arbitrary 103 // content, aren't just downscaled 104 bool should_force_safe_hashing = false; // for XFB 105 bool is_xfb_copy = false; 106 bool is_xfb_container = false; 107 u64 id; 108 109 bool reference_changed = false; // used by xfb to determine when a reference xfb changed 110 111 unsigned int native_width, 112 native_height; // Texture dimensions from the GameCube's point of view 113 unsigned int native_levels; 114 115 // used to delete textures which haven't been used for TEXTURE_KILL_THRESHOLD frames 116 int frameCount = FRAMECOUNT_INVALID; 117 118 // Keep an iterator to the entry in textures_by_hash, so it does not need to be searched when 119 // removing the cache entry 120 std::multimap<u64, TCacheEntry*>::iterator textures_by_hash_iter; 121 122 // This is used to keep track of both: 123 // * efb copies used by this partially updated texture 124 // * partially updated textures which refer to this efb copy 125 std::unordered_set<TCacheEntry*> references; 126 127 // Pending EFB copy 128 std::unique_ptr<AbstractStagingTexture> pending_efb_copy; 129 u32 pending_efb_copy_width = 0; 130 u32 pending_efb_copy_height = 0; 131 bool pending_efb_copy_invalidated = false; 132 133 explicit TCacheEntry(std::unique_ptr<AbstractTexture> tex, 134 std::unique_ptr<AbstractFramebuffer> fb); 135 136 ~TCacheEntry(); 137 SetGeneralParametersTCacheEntry138 void SetGeneralParameters(u32 _addr, u32 _size, TextureAndTLUTFormat _format, 139 bool force_safe_hashing) 140 { 141 addr = _addr; 142 size_in_bytes = _size; 143 format = _format; 144 should_force_safe_hashing = force_safe_hashing; 145 } 146 SetDimensionsTCacheEntry147 void SetDimensions(unsigned int _native_width, unsigned int _native_height, 148 unsigned int _native_levels) 149 { 150 native_width = _native_width; 151 native_height = _native_height; 152 native_levels = _native_levels; 153 memory_stride = _native_width; 154 } 155 SetHashesTCacheEntry156 void SetHashes(u64 _base_hash, u64 _hash) 157 { 158 base_hash = _base_hash; 159 hash = _hash; 160 } 161 162 // This texture entry is used by the other entry as a sub-texture CreateReferenceTCacheEntry163 void CreateReference(TCacheEntry* other_entry) 164 { 165 // References are two-way, so they can easily be destroyed later 166 this->references.emplace(other_entry); 167 other_entry->references.emplace(this); 168 } 169 170 void SetXfbCopy(u32 stride); 171 void SetEfbCopy(u32 stride); 172 void SetNotCopy(); 173 174 bool OverlapsMemoryRange(u32 range_address, u32 range_size) const; 175 IsEfbCopyTCacheEntry176 bool IsEfbCopy() const { return is_efb_copy; } IsCopyTCacheEntry177 bool IsCopy() const { return is_xfb_copy || is_efb_copy; } 178 u32 NumBlocksY() const; 179 u32 BytesPerRow() const; 180 181 u64 CalculateHash() const; 182 183 int HashSampleSize() const; GetWidthTCacheEntry184 u32 GetWidth() const { return texture->GetConfig().width; } GetHeightTCacheEntry185 u32 GetHeight() const { return texture->GetConfig().height; } GetNumLevelsTCacheEntry186 u32 GetNumLevels() const { return texture->GetConfig().levels; } GetNumLayersTCacheEntry187 u32 GetNumLayers() const { return texture->GetConfig().layers; } GetFormatTCacheEntry188 AbstractTextureFormat GetFormat() const { return texture->GetConfig().format; } 189 void DoState(PointerWrap& p); 190 }; 191 192 // Minimal version of TCacheEntry just for TexPool 193 struct TexPoolEntry 194 { 195 std::unique_ptr<AbstractTexture> texture; 196 std::unique_ptr<AbstractFramebuffer> framebuffer; 197 int frameCount = FRAMECOUNT_INVALID; 198 199 TexPoolEntry(std::unique_ptr<AbstractTexture> tex, std::unique_ptr<AbstractFramebuffer> fb); 200 }; 201 202 TextureCacheBase(); 203 virtual ~TextureCacheBase(); 204 205 bool Initialize(); 206 207 void OnConfigChanged(const VideoConfig& config); 208 209 // Removes textures which aren't used for more than TEXTURE_KILL_THRESHOLD frames, 210 // frameCount is the current frame number. 211 void Cleanup(int _frameCount); 212 213 void Invalidate(); 214 215 TCacheEntry* Load(const u32 stage); InvalidateAllBindPoints()216 static void InvalidateAllBindPoints() { valid_bind_points.reset(); } IsValidBindPoint(u32 i)217 static bool IsValidBindPoint(u32 i) { return valid_bind_points.test(i); } 218 TCacheEntry* GetTexture(u32 address, u32 width, u32 height, const TextureFormat texformat, 219 const int textureCacheSafetyColorSampleSize, u32 tlutaddr = 0, 220 TLUTFormat tlutfmt = TLUTFormat::IA8, bool use_mipmaps = false, 221 u32 tex_levels = 1, bool from_tmem = false, u32 tmem_address_even = 0, 222 u32 tmem_address_odd = 0); 223 TCacheEntry* GetXFBTexture(u32 address, u32 width, u32 height, u32 stride, 224 MathUtil::Rectangle<int>* display_rect); 225 226 virtual void BindTextures(); 227 void CopyRenderTargetToTexture(u32 dstAddr, EFBCopyFormat dstFormat, u32 width, u32 height, 228 u32 dstStride, bool is_depth_copy, 229 const MathUtil::Rectangle<int>& srcRect, bool isIntensity, 230 bool scaleByHalf, float y_scale, float gamma, bool clamp_top, 231 bool clamp_bottom, 232 const CopyFilterCoefficients::Values& filter_coefficients); 233 234 void ScaleTextureCacheEntryTo(TCacheEntry* entry, u32 new_width, u32 new_height); 235 236 // Flushes all pending EFB copies to emulated RAM. 237 void FlushEFBCopies(); 238 239 // Texture Serialization 240 void SerializeTexture(AbstractTexture* tex, const TextureConfig& config, PointerWrap& p); 241 std::optional<TexPoolEntry> DeserializeTexture(PointerWrap& p); 242 243 // Save States 244 void DoState(PointerWrap& p); 245 246 // Returns false if the top/bottom row coefficients are zero. 247 static bool NeedsCopyFilterInShader(const EFBCopyFilterCoefficients& coefficients); 248 249 protected: 250 // Decodes the specified data to the GPU texture specified by entry. 251 // Returns false if the configuration is not supported. 252 // width, height are the size of the image in pixels. 253 // aligned_width, aligned_height are the size of the image in pixels, aligned to the block size. 254 // row_stride is the number of bytes for a row of blocks, not pixels. 255 bool DecodeTextureOnGPU(TCacheEntry* entry, u32 dst_level, const u8* data, u32 data_size, 256 TextureFormat format, u32 width, u32 height, u32 aligned_width, 257 u32 aligned_height, u32 row_stride, const u8* palette, 258 TLUTFormat palette_format); 259 260 virtual void CopyEFB(AbstractStagingTexture* dst, const EFBCopyParams& params, u32 native_width, 261 u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, 262 const MathUtil::Rectangle<int>& src_rect, bool scale_by_half, 263 bool linear_filter, float y_scale, float gamma, bool clamp_top, 264 bool clamp_bottom, const EFBCopyFilterCoefficients& filter_coefficients); 265 virtual void CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy, 266 const MathUtil::Rectangle<int>& src_rect, bool scale_by_half, 267 bool linear_filter, EFBCopyFormat dst_format, bool is_intensity, 268 float gamma, bool clamp_top, bool clamp_bottom, 269 const EFBCopyFilterCoefficients& filter_coefficients); 270 271 alignas(16) u8* temp = nullptr; 272 size_t temp_size = 0; 273 274 std::array<TCacheEntry*, 8> bound_textures{}; 275 static std::bitset<8> valid_bind_points; 276 277 private: 278 using TexAddrCache = std::multimap<u32, TCacheEntry*>; 279 using TexHashCache = std::multimap<u64, TCacheEntry*>; 280 using TexPool = std::unordered_multimap<TextureConfig, TexPoolEntry>; 281 282 bool CreateUtilityTextures(); 283 284 void SetBackupConfig(const VideoConfig& config); 285 286 TCacheEntry* GetXFBFromCache(u32 address, u32 width, u32 height, u32 stride, u64 hash); 287 288 TCacheEntry* ApplyPaletteToEntry(TCacheEntry* entry, u8* palette, TLUTFormat tlutfmt); 289 290 TCacheEntry* ReinterpretEntry(const TCacheEntry* existing_entry, TextureFormat new_format); 291 292 TCacheEntry* DoPartialTextureUpdates(TCacheEntry* entry_to_update, u8* palette, 293 TLUTFormat tlutfmt); 294 void StitchXFBCopy(TCacheEntry* entry_to_update); 295 296 void DumpTexture(TCacheEntry* entry, std::string basename, unsigned int level, bool is_arbitrary); 297 void CheckTempSize(size_t required_size); 298 299 TCacheEntry* AllocateCacheEntry(const TextureConfig& config); 300 std::optional<TexPoolEntry> AllocateTexture(const TextureConfig& config); 301 TexPool::iterator FindMatchingTextureFromPool(const TextureConfig& config); 302 TexAddrCache::iterator GetTexCacheIter(TCacheEntry* entry); 303 304 // Return all possible overlapping textures. As addr+size of the textures is not 305 // indexed, this may return false positives. 306 std::pair<TexAddrCache::iterator, TexAddrCache::iterator> 307 FindOverlappingTextures(u32 addr, u32 size_in_bytes); 308 309 // Removes and unlinks texture from texture cache and returns it to the pool 310 TexAddrCache::iterator InvalidateTexture(TexAddrCache::iterator t_iter, 311 bool discard_pending_efb_copy = false); 312 313 void UninitializeXFBMemory(u8* dst, u32 stride, u32 bytes_per_row, u32 num_blocks_y); 314 315 // Precomputing the coefficients for the previous, current, and next lines for the copy filter. 316 static EFBCopyFilterCoefficients 317 GetRAMCopyFilterCoefficients(const CopyFilterCoefficients::Values& coefficients); 318 static EFBCopyFilterCoefficients 319 GetVRAMCopyFilterCoefficients(const CopyFilterCoefficients::Values& coefficients); 320 321 // Flushes a pending EFB copy to RAM from the host to the guest RAM. 322 void WriteEFBCopyToRAM(u8* dst_ptr, u32 width, u32 height, u32 stride, 323 std::unique_ptr<AbstractStagingTexture> staging_texture); 324 void FlushEFBCopy(TCacheEntry* entry); 325 326 // Returns a staging texture of the maximum EFB copy size. 327 std::unique_ptr<AbstractStagingTexture> GetEFBCopyStagingTexture(); 328 329 // Returns an EFB copy staging texture to the pool, so it can be re-used. 330 void ReleaseEFBCopyStagingTexture(std::unique_ptr<AbstractStagingTexture> tex); 331 332 bool CheckReadbackTexture(u32 width, u32 height, AbstractTextureFormat format); 333 void DoSaveState(PointerWrap& p); 334 void DoLoadState(PointerWrap& p); 335 336 TexAddrCache textures_by_address; 337 TexHashCache textures_by_hash; 338 TexPool texture_pool; 339 u64 last_entry_id = 0; 340 341 // Backup configuration values 342 struct BackupConfig 343 { 344 int color_samples; 345 bool texfmt_overlay; 346 bool texfmt_overlay_center; 347 bool hires_textures; 348 bool cache_hires_textures; 349 bool copy_cache_enable; 350 bool stereo_3d; 351 bool efb_mono_depth; 352 bool gpu_texture_decoding; 353 bool disable_vram_copies; 354 bool arbitrary_mipmap_detection; 355 }; 356 BackupConfig backup_config = {}; 357 358 // Encoding texture used for EFB copies to RAM. 359 std::unique_ptr<AbstractTexture> m_efb_encoding_texture; 360 std::unique_ptr<AbstractFramebuffer> m_efb_encoding_framebuffer; 361 362 // Decoding texture used for GPU texture decoding. 363 std::unique_ptr<AbstractTexture> m_decoding_texture; 364 365 // Pool of readback textures used for deferred EFB copies. 366 std::vector<std::unique_ptr<AbstractStagingTexture>> m_efb_copy_staging_texture_pool; 367 368 // List of pending EFB copies. It is important that the order is preserved for these, 369 // so that overlapping textures are written to guest RAM in the order they are issued. 370 std::vector<TCacheEntry*> m_pending_efb_copies; 371 372 // Staging texture used for readbacks. 373 // We store this in the class so that the same staging texture can be used for multiple 374 // readbacks, saving the overhead of allocating a new buffer every time. 375 std::unique_ptr<AbstractStagingTexture> m_readback_texture; 376 }; 377 378 extern std::unique_ptr<TextureCacheBase> g_texture_cache; 379