/ src / video_core / rasterizer_cache / rasterizer_cache_base.h
rasterizer_cache_base.h
  1  // Copyright 2023 Citra Emulator Project
  2  // Licensed under GPLv2 or any later version
  3  // Refer to the license.txt file included.
  4  
  5  #pragma once
  6  
  7  #include <functional>
  8  #include <list>
  9  #include <optional>
 10  #include <span>
 11  #include <unordered_map>
 12  #include <vector>
 13  #include <boost/icl/interval_map.hpp>
 14  #include <tsl/robin_map.h>
 15  
 16  #include "video_core/rasterizer_cache/framebuffer_base.h"
 17  #include "video_core/rasterizer_cache/sampler_params.h"
 18  #include "video_core/rasterizer_cache/surface_params.h"
 19  #include "video_core/rasterizer_cache/texture_cube.h"
 20  
 21  namespace Memory {
 22  class MemorySystem;
 23  }
 24  
 25  namespace Pica {
 26  struct RegsInternal;
 27  struct DisplayTransferConfig;
 28  struct MemoryFillConfig;
 29  } // namespace Pica
 30  
 31  namespace Pica::Texture {
 32  struct TextureInfo;
 33  }
 34  
 35  namespace Settings {
 36  enum class TextureFilter : u32;
 37  }
 38  
 39  namespace VideoCore {
 40  
 41  enum class ScaleMatch {
 42      Exact,   ///< Only accept same res scale
 43      Upscale, ///< Only allow higher scale than params
 44      Ignore   ///< Accept every scaled res
 45  };
 46  
 47  enum class MatchFlags {
 48      Exact = 1 << 0,       ///< Surface perfectly matches params
 49      SubRect = 1 << 1,     ///< Surface encompasses params
 50      Copy = 1 << 2,        ///< Surface that can be used as a copy source
 51      TexCopy = 1 << 3,     ///< Surface that will match a display transfer "texture copy" parameters
 52      Reinterpret = 1 << 4, ///< Surface might have different pixel format.
 53  };
 54  
 55  DECLARE_ENUM_FLAG_OPERATORS(MatchFlags);
 56  
 57  class CustomTexManager;
 58  class RendererBase;
 59  
 60  template <class T>
 61  class RasterizerCache {
 62      /// Address shift for caching surfaces into a hash table
 63      static constexpr u64 CITRA_PAGEBITS = 18;
 64  
 65      using Runtime = typename T::Runtime;
 66      using Sampler = typename T::Sampler;
 67      using Surface = typename T::Surface;
 68      using Framebuffer = typename T::Framebuffer;
 69      using DebugScope = typename T::DebugScope;
 70  
 71      using SurfaceMap = boost::icl::interval_map<PAddr, SurfaceId, boost::icl::partial_absorber,
 72                                                  std::less, boost::icl::inplace_plus,
 73                                                  boost::icl::inter_section, SurfaceInterval>;
 74  
 75      using SurfaceRect_Tuple = std::pair<SurfaceId, Common::Rectangle<u32>>;
 76      using PageMap = boost::icl::interval_map<u32, int>;
 77  
 78  public:
 79      explicit RasterizerCache(Memory::MemorySystem& memory, CustomTexManager& custom_tex_manager,
 80                               Runtime& runtime, Pica::RegsInternal& regs, RendererBase& renderer);
 81      ~RasterizerCache();
 82  
 83      /// Notify the cache that a new frame has been queued
 84      void TickFrame();
 85  
 86      /// Perform hardware accelerated texture copy according to the provided configuration
 87      bool AccelerateTextureCopy(const Pica::DisplayTransferConfig& config);
 88  
 89      /// Perform hardware accelerated display transfer according to the provided configuration
 90      bool AccelerateDisplayTransfer(const Pica::DisplayTransferConfig& config);
 91  
 92      /// Perform hardware accelerated memory fill according to the provided configuration
 93      bool AccelerateFill(const Pica::MemoryFillConfig& config);
 94  
 95      /// Returns a reference to the surface object assigned to surface_id
 96      Surface& GetSurface(SurfaceId surface_id);
 97  
 98      /// Returns a reference to the sampler object matching the provided configuration
 99      Sampler& GetSampler(const Pica::TexturingRegs::TextureConfig& config);
100      Sampler& GetSampler(SamplerId sampler_id);
101  
102      /// Copy one surface's region to another
103      void CopySurface(Surface& src_surface, Surface& dst_surface, SurfaceInterval copy_interval);
104  
105      /// Load a texture from 3DS memory to OpenGL and cache it (if not already cached)
106      SurfaceId GetSurface(const SurfaceParams& params, ScaleMatch match_res_scale,
107                           bool load_if_create);
108  
109      /// Attempt to find a subrect (resolution scaled) of a surface, otherwise loads a texture from
110      /// 3DS memory to OpenGL and caches it (if not already cached)
111      SurfaceRect_Tuple GetSurfaceSubRect(const SurfaceParams& params, ScaleMatch match_res_scale,
112                                          bool load_if_create);
113  
114      /// Get a surface based on the texture configuration
115      Surface& GetTextureSurface(const Pica::TexturingRegs::FullTextureConfig& config);
116      SurfaceId GetTextureSurface(const Pica::Texture::TextureInfo& info, u32 max_level = 0);
117  
118      /// Get a texture cube based on the texture configuration
119      Surface& GetTextureCube(const TextureCubeConfig& config);
120  
121      /// Get the color and depth surfaces based on the framebuffer configuration
122      FramebufferHelper<T> GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb);
123  
124      /// Get a surface that matches a "texture copy" display transfer config
125      SurfaceRect_Tuple GetTexCopySurface(const SurfaceParams& params);
126  
127      /// Write any cached resources overlapping the region back to memory (if dirty)
128      void FlushRegion(PAddr addr, u32 size, SurfaceId flush_surface = {});
129  
130      /// Mark region as being invalidated by region_owner (nullptr if 3DS memory)
131      void InvalidateRegion(PAddr addr, u32 size, SurfaceId region_owner = {});
132  
133      /// Flush all cached resources tracked by this cache manager
134      void FlushAll();
135  
136      /// Clear all cached resources tracked by this cache manager
137      void ClearAll(bool flush);
138  
139  private:
140      /// Iterate over all page indices in a range
141      template <typename Func>
142      void ForEachPage(PAddr addr, std::size_t size, Func&& func) {
143          static constexpr bool RETURNS_BOOL = std::is_same_v<std::invoke_result<Func, u64>, bool>;
144          const u64 page_end = (addr + size - 1) >> CITRA_PAGEBITS;
145          for (u64 page = addr >> CITRA_PAGEBITS; page <= page_end; ++page) {
146              if constexpr (RETURNS_BOOL) {
147                  if (func(page)) {
148                      break;
149                  }
150              } else {
151                  func(page);
152              }
153          }
154      }
155  
156      /// Iterates over all the surfaces in a region calling func
157      template <typename Func>
158      void ForEachSurfaceInRegion(PAddr addr, std::size_t size, Func&& func);
159  
160      /// Get the best surface match (and its match type) for the given flags
161      template <MatchFlags find_flags>
162      SurfaceId FindMatch(const SurfaceParams& params, ScaleMatch match_scale_type,
163                          std::optional<SurfaceInterval> validate_interval = std::nullopt);
164  
165      /// Unregisters sentenced surfaces that have surpassed the destruction threshold.
166      void RunGarbageCollector();
167  
168      /// Removes any framebuffers that reference the provided surface_id.
169      void RemoveFramebuffers(SurfaceId surface_id);
170  
171      /// Removes any references of the provided surface id from cached texture cubes.
172      void RemoveTextureCubeFace(SurfaceId surface_id);
173  
174      /// Computes the hash of the provided texture data.
175      u64 ComputeHash(const SurfaceParams& load_info, std::span<u8> upload_data);
176  
177      /// Update surface's texture for given region when necessary
178      void ValidateSurface(SurfaceId surface, PAddr addr, u32 size);
179  
180      /// Copies pixel data in interval from the guest VRAM to the host GPU surface
181      void UploadSurface(Surface& surface, SurfaceInterval interval);
182  
183      /// Uploads a custom texture identified with hash to the target surface
184      bool UploadCustomSurface(SurfaceId surface_id, SurfaceInterval interval);
185  
186      /// Copies pixel data in interval from the host GPU surface to the guest VRAM
187      void DownloadSurface(Surface& surface, SurfaceInterval interval);
188  
189      /// Downloads a fill surface to guest VRAM
190      void DownloadFillSurface(Surface& surface, SurfaceInterval interval);
191  
192      /// Attempt to find a reinterpretable surface in the cache and use it to copy for validation
193      bool ValidateByReinterpretation(Surface& surface, SurfaceParams params,
194                                      const SurfaceInterval& interval);
195  
196      /// Return true if a surface with an invalid pixel format exists at the interval
197      bool IntervalHasInvalidPixelFormat(const SurfaceParams& params, SurfaceInterval interval);
198  
199      /// Create a new surface
200      SurfaceId CreateSurface(const SurfaceParams& params);
201  
202      /// Register surface into the cache
203      void RegisterSurface(SurfaceId surface);
204  
205      /// Remove surface from the cache
206      void UnregisterSurface(SurfaceId surface);
207  
208      /// Unregisters all surfaces from the cache
209      void UnregisterAll();
210  
211      /// Increase/decrease the number of surface in pages touching the specified region
212      void UpdatePagesCachedCount(PAddr addr, u32 size, int delta);
213  
214  private:
215      Memory::MemorySystem& memory;
216      CustomTexManager& custom_tex_manager;
217      Runtime& runtime;
218      Pica::RegsInternal& regs;
219      RendererBase& renderer;
220      std::unordered_map<TextureCubeConfig, TextureCube> texture_cube_cache;
221      tsl::robin_pg_map<u64, std::vector<SurfaceId>, Common::IdentityHash<u64>> page_table;
222      std::unordered_map<FramebufferParams, FramebufferId> framebuffers;
223      std::unordered_map<SamplerParams, SamplerId> samplers;
224      std::list<std::pair<SurfaceId, u64>> sentenced;
225      Common::SlotVector<Surface> slot_surfaces;
226      Common::SlotVector<Sampler> slot_samplers;
227      Common::SlotVector<Framebuffer> slot_framebuffers;
228      SurfaceMap dirty_regions;
229      PageMap cached_pages;
230      u32 resolution_scale_factor;
231      u64 frame_tick{};
232      FramebufferParams fb_params;
233      Settings::TextureFilter filter;
234      bool dump_textures;
235      bool use_custom_textures;
236  };
237  
238  } // namespace VideoCore