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