texture_cache.h 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. // Copyright 2019 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <list>
  6. #include <memory>
  7. #include <set>
  8. #include <tuple>
  9. #include <unordered_map>
  10. #include <boost/icl/interval_map.hpp>
  11. #include <boost/range/iterator_range.hpp>
  12. #include "common/assert.h"
  13. #include "common/common_types.h"
  14. #include "core/memory.h"
  15. #include "video_core/engines/fermi_2d.h"
  16. #include "video_core/engines/maxwell_3d.h"
  17. #include "video_core/gpu.h"
  18. #include "video_core/memory_manager.h"
  19. #include "video_core/rasterizer_interface.h"
  20. #include "video_core/surface.h"
  21. #include "video_core/texture_cache/surface_base.h"
  22. #include "video_core/texture_cache/surface_params.h"
  23. #include "video_core/texture_cache/surface_view.h"
  24. namespace Core {
  25. class System;
  26. }
  27. namespace Tegra::Texture {
  28. struct FullTextureInfo;
  29. }
  30. namespace VideoCore {
  31. class RasterizerInterface;
  32. }
  33. namespace VideoCommon {
  34. template <typename TSurface, typename TView>
  35. class TextureCache {
  36. using IntervalMap = boost::icl::interval_map<CacheAddr, std::set<std::shared_ptr<TSurface>>>;
  37. using IntervalType = typename IntervalMap::interval_type;
  38. public:
  39. void InvalidateRegion(CacheAddr addr, std::size_t size) {
  40. for (const auto& surface : GetSurfacesInRegion(addr, size)) {
  41. if (!surface->IsRegistered()) {
  42. // Skip duplicates
  43. continue;
  44. }
  45. Unregister(surface);
  46. }
  47. }
  48. TView* GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) {
  49. const auto gpu_addr{config.tic.Address()};
  50. if (!gpu_addr) {
  51. return {};
  52. }
  53. const auto params{SurfaceParams::CreateForTexture(system, config)};
  54. return GetSurfaceView(gpu_addr, params, true);
  55. }
  56. TView* GetDepthBufferSurface(bool preserve_contents) {
  57. const auto& regs{system.GPU().Maxwell3D().regs};
  58. const auto gpu_addr{regs.zeta.Address()};
  59. if (!gpu_addr || !regs.zeta_enable) {
  60. return {};
  61. }
  62. const auto depth_params{SurfaceParams::CreateForDepthBuffer(
  63. system, regs.zeta_width, regs.zeta_height, regs.zeta.format,
  64. regs.zeta.memory_layout.block_width, regs.zeta.memory_layout.block_height,
  65. regs.zeta.memory_layout.block_depth, regs.zeta.memory_layout.type)};
  66. return GetSurfaceView(gpu_addr, depth_params, preserve_contents);
  67. }
  68. TView* GetColorBufferSurface(std::size_t index, bool preserve_contents) {
  69. ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets);
  70. const auto& regs{system.GPU().Maxwell3D().regs};
  71. if (index >= regs.rt_control.count || regs.rt[index].Address() == 0 ||
  72. regs.rt[index].format == Tegra::RenderTargetFormat::NONE) {
  73. return {};
  74. }
  75. auto& memory_manager{system.GPU().MemoryManager()};
  76. const auto& config{system.GPU().Maxwell3D().regs.rt[index]};
  77. const auto gpu_addr{config.Address() +
  78. config.base_layer * config.layer_stride * sizeof(u32)};
  79. if (!gpu_addr) {
  80. return {};
  81. }
  82. return GetSurfaceView(gpu_addr, SurfaceParams::CreateForFramebuffer(system, index),
  83. preserve_contents);
  84. }
  85. TView* GetFermiSurface(const Tegra::Engines::Fermi2D::Regs::Surface& config) {
  86. return GetSurfaceView(config.Address(), SurfaceParams::CreateForFermiCopySurface(config),
  87. true);
  88. }
  89. std::shared_ptr<TSurface> TryFindFramebufferSurface(const u8* host_ptr) const {
  90. const auto it{registered_surfaces.find(ToCacheAddr(host_ptr))};
  91. return it != registered_surfaces.end() ? *it->second.begin() : nullptr;
  92. }
  93. u64 Tick() {
  94. return ++ticks;
  95. }
  96. protected:
  97. TextureCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer)
  98. : system{system}, rasterizer{rasterizer} {}
  99. ~TextureCache() = default;
  100. virtual TView* TryFastGetSurfaceView(
  101. GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr, const SurfaceParams& params,
  102. bool preserve_contents, const std::vector<std::shared_ptr<TSurface>>& overlaps) = 0;
  103. virtual std::shared_ptr<TSurface> CreateSurface(const SurfaceParams& params) = 0;
  104. void Register(std::shared_ptr<TSurface> surface, GPUVAddr gpu_addr, VAddr cpu_addr,
  105. u8* host_ptr) {
  106. surface->Register(gpu_addr, cpu_addr, host_ptr);
  107. registered_surfaces.add({GetSurfaceInterval(surface), {surface}});
  108. rasterizer.UpdatePagesCachedCount(surface->GetCpuAddr(), surface->GetSizeInBytes(), 1);
  109. }
  110. void Unregister(std::shared_ptr<TSurface> surface) {
  111. registered_surfaces.subtract({GetSurfaceInterval(surface), {surface}});
  112. rasterizer.UpdatePagesCachedCount(surface->GetCpuAddr(), surface->GetSizeInBytes(), -1);
  113. surface->Unregister();
  114. }
  115. std::shared_ptr<TSurface> GetUncachedSurface(const SurfaceParams& params) {
  116. if (const auto surface = TryGetReservedSurface(params); surface)
  117. return surface;
  118. // No reserved surface available, create a new one and reserve it
  119. auto new_surface{CreateSurface(params)};
  120. ReserveSurface(params, new_surface);
  121. return new_surface;
  122. }
  123. Core::System& system;
  124. private:
  125. TView* GetSurfaceView(GPUVAddr gpu_addr, const SurfaceParams& params, bool preserve_contents) {
  126. auto& memory_manager{system.GPU().MemoryManager()};
  127. const auto cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr)};
  128. DEBUG_ASSERT(cpu_addr);
  129. const auto host_ptr{memory_manager.GetPointer(gpu_addr)};
  130. const auto cache_addr{ToCacheAddr(host_ptr)};
  131. auto overlaps{GetSurfacesInRegion(cache_addr, params.GetGuestSizeInBytes())};
  132. if (overlaps.empty()) {
  133. return LoadSurfaceView(gpu_addr, *cpu_addr, host_ptr, params, preserve_contents);
  134. }
  135. if (overlaps.size() == 1) {
  136. if (TView* view = overlaps[0]->TryGetView(gpu_addr, params); view) {
  137. return view;
  138. }
  139. }
  140. const auto fast_view{TryFastGetSurfaceView(gpu_addr, *cpu_addr, host_ptr, params,
  141. preserve_contents, overlaps)};
  142. if (!fast_view) {
  143. std::sort(overlaps.begin(), overlaps.end(), [](const auto& lhs, const auto& rhs) {
  144. return lhs->GetModificationTick() < rhs->GetModificationTick();
  145. });
  146. }
  147. for (const auto& surface : overlaps) {
  148. if (!fast_view) {
  149. // Flush even when we don't care about the contents, to preserve memory not
  150. // written by the new surface.
  151. FlushSurface(surface);
  152. }
  153. Unregister(surface);
  154. }
  155. if (fast_view) {
  156. return fast_view;
  157. }
  158. return LoadSurfaceView(gpu_addr, *cpu_addr, host_ptr, params, preserve_contents);
  159. }
  160. TView* LoadSurfaceView(GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr,
  161. const SurfaceParams& params, bool preserve_contents) {
  162. const auto new_surface{GetUncachedSurface(params)};
  163. Register(new_surface, gpu_addr, cpu_addr, host_ptr);
  164. if (preserve_contents) {
  165. LoadSurface(new_surface);
  166. }
  167. return new_surface->GetView(gpu_addr, params);
  168. }
  169. void LoadSurface(const std::shared_ptr<TSurface>& surface) {
  170. surface->LoadBuffer();
  171. surface->UploadTexture();
  172. surface->MarkAsModified(false);
  173. }
  174. void FlushSurface(const std::shared_ptr<TSurface>& surface) {
  175. if (!surface->IsModified()) {
  176. return;
  177. }
  178. surface->DownloadTexture();
  179. surface->FlushBuffer();
  180. }
  181. std::vector<std::shared_ptr<TSurface>> GetSurfacesInRegion(CacheAddr cache_addr,
  182. std::size_t size) const {
  183. if (size == 0) {
  184. return {};
  185. }
  186. const IntervalType interval{cache_addr, cache_addr + size};
  187. std::vector<std::shared_ptr<TSurface>> surfaces;
  188. for (auto& pair : boost::make_iterator_range(registered_surfaces.equal_range(interval))) {
  189. surfaces.push_back(*pair.second.begin());
  190. }
  191. return surfaces;
  192. }
  193. void ReserveSurface(const SurfaceParams& params, std::shared_ptr<TSurface> surface) {
  194. surface_reserve[params].push_back(std::move(surface));
  195. }
  196. std::shared_ptr<TSurface> TryGetReservedSurface(const SurfaceParams& params) {
  197. auto search{surface_reserve.find(params)};
  198. if (search == surface_reserve.end()) {
  199. return {};
  200. }
  201. for (auto& surface : search->second) {
  202. if (!surface->IsRegistered()) {
  203. return surface;
  204. }
  205. }
  206. return {};
  207. }
  208. IntervalType GetSurfaceInterval(std::shared_ptr<TSurface> surface) const {
  209. return IntervalType::right_open(surface->GetCacheAddr(),
  210. surface->GetCacheAddr() + surface->GetSizeInBytes());
  211. }
  212. VideoCore::RasterizerInterface& rasterizer;
  213. u64 ticks{};
  214. IntervalMap registered_surfaces;
  215. /// The surface reserve is a "backup" cache, this is where we put unique surfaces that have
  216. /// previously been used. This is to prevent surfaces from being constantly created and
  217. /// destroyed when used with different surface parameters.
  218. std::unordered_map<SurfaceParams, std::list<std::shared_ptr<TSurface>>> surface_reserve;
  219. };
  220. } // namespace VideoCommon