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