texture_cache.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  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/copy_params.h"
  22. #include "video_core/texture_cache/surface_base.h"
  23. #include "video_core/texture_cache/surface_params.h"
  24. #include "video_core/texture_cache/surface_view.h"
  25. namespace Core {
  26. class System;
  27. }
  28. namespace Tegra::Texture {
  29. struct FullTextureInfo;
  30. }
  31. namespace VideoCore {
  32. class RasterizerInterface;
  33. }
  34. namespace VideoCommon {
  35. using VideoCore::Surface::SurfaceTarget;
  36. using RenderTargetConfig = Tegra::Engines::Maxwell3D::Regs::RenderTargetConfig;
  37. template <typename TSurface, typename TView>
  38. class TextureCache {
  39. using IntervalMap = boost::icl::interval_map<CacheAddr, std::set<TSurface>>;
  40. using IntervalType = typename IntervalMap::interval_type;
  41. public:
  42. void InitMemoryMananger(Tegra::MemoryManager& memory_manager) {
  43. this->memory_manager = &memory_manager;
  44. }
  45. void InvalidateRegion(CacheAddr addr, std::size_t size) {
  46. for (const auto& surface : GetSurfacesInRegion(addr, size)) {
  47. Unregister(surface);
  48. }
  49. }
  50. void InvalidateRegionEx(GPUVAddr addr, std::size_t size) {
  51. for (const auto& surface : GetSurfacesInRegionInner(addr, size)) {
  52. Unregister(surface);
  53. }
  54. }
  55. TView GetTextureSurface(const Tegra::Texture::FullTextureInfo& config,
  56. const VideoCommon::Shader::Sampler& entry) {
  57. const auto gpu_addr{config.tic.Address()};
  58. if (!gpu_addr) {
  59. return {};
  60. }
  61. const auto params{SurfaceParams::CreateForTexture(system, config, entry)};
  62. return GetSurface(gpu_addr, params, true).second;
  63. }
  64. TView GetDepthBufferSurface(bool preserve_contents) {
  65. const auto& regs{system.GPU().Maxwell3D().regs};
  66. const auto gpu_addr{regs.zeta.Address()};
  67. if (!gpu_addr || !regs.zeta_enable) {
  68. return {};
  69. }
  70. const auto depth_params{SurfaceParams::CreateForDepthBuffer(
  71. system, regs.zeta_width, regs.zeta_height, regs.zeta.format,
  72. regs.zeta.memory_layout.block_width, regs.zeta.memory_layout.block_height,
  73. regs.zeta.memory_layout.block_depth, regs.zeta.memory_layout.type)};
  74. auto surface_view = GetSurface(gpu_addr, depth_params, preserve_contents);
  75. if (depth_buffer.target)
  76. depth_buffer.target->MarkAsProtected(false);
  77. if (depth_buffer.target)
  78. depth_buffer.target->MarkAsProtected(true);
  79. return surface_view.second;
  80. }
  81. TView GetColorBufferSurface(std::size_t index, bool preserve_contents) {
  82. ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets);
  83. const auto& regs{system.GPU().Maxwell3D().regs};
  84. if (index >= regs.rt_control.count || regs.rt[index].Address() == 0 ||
  85. regs.rt[index].format == Tegra::RenderTargetFormat::NONE) {
  86. SetEmptyColorBuffer(index);
  87. return {};
  88. }
  89. const auto& config{regs.rt[index]};
  90. const auto gpu_addr{config.Address()};
  91. if (!gpu_addr) {
  92. SetEmptyColorBuffer(index);
  93. return {};
  94. }
  95. auto surface_view = GetSurface(gpu_addr, SurfaceParams::CreateForFramebuffer(system, index),
  96. preserve_contents);
  97. if (render_targets[index].target)
  98. render_targets[index].target->MarkAsProtected(false);
  99. render_targets[index].target = surface_view.first;
  100. if (render_targets[index].target)
  101. render_targets[index].target->MarkAsProtected(true);
  102. return surface_view.second;
  103. }
  104. void MarkColorBufferInUse(std::size_t index) {
  105. if (render_targets[index].target)
  106. render_targets[index].target->MarkAsModified(true, Tick());
  107. }
  108. void MarkDepthBufferInUse() {
  109. if (depth_buffer.target)
  110. depth_buffer.target->MarkAsModified(true, Tick());
  111. }
  112. void SetEmptyDepthBuffer() {
  113. if (depth_buffer.target != nullptr) {
  114. depth_buffer.target->MarkAsProtected(false);
  115. depth_buffer.target = nullptr;
  116. depth_buffer.view = nullptr;
  117. }
  118. }
  119. void SetEmptyColorBuffer(std::size_t index) {
  120. if (render_targets[index].target != nullptr) {
  121. render_targets[index].target->MarkAsProtected(false);
  122. std::memset(&render_targets[index].config, sizeof(RenderTargetConfig), 0);
  123. render_targets[index].target = nullptr;
  124. render_targets[index].view = nullptr;
  125. }
  126. }
  127. TView GetFermiSurface(const Tegra::Engines::Fermi2D::Regs::Surface& config) {
  128. SurfaceParams params = SurfaceParams::CreateForFermiCopySurface(config);
  129. const GPUVAddr gpu_addr = config.Address();
  130. return GetSurface(gpu_addr, params, true).second;
  131. }
  132. TSurface TryFindFramebufferSurface(const u8* host_ptr) const {
  133. const auto it{registered_surfaces.find(ToCacheAddr(host_ptr))};
  134. return it != registered_surfaces.end() ? *it->second.begin() : nullptr;
  135. }
  136. u64 Tick() {
  137. return ++ticks;
  138. }
  139. protected:
  140. TextureCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer)
  141. : system{system}, rasterizer{rasterizer} {
  142. for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
  143. SetEmptyColorBuffer(i);
  144. }
  145. SetEmptyDepthBuffer();
  146. }
  147. ~TextureCache() = default;
  148. virtual TSurface CreateSurface(GPUVAddr gpu_addr, const SurfaceParams& params) = 0;
  149. virtual void ImageCopy(TSurface src_surface, TSurface dst_surface,
  150. const CopyParams& copy_params) = 0;
  151. void Register(TSurface surface) {
  152. const GPUVAddr gpu_addr = surface->GetGpuAddr();
  153. u8* host_ptr = memory_manager->GetPointer(gpu_addr);
  154. const std::size_t size = surface->GetSizeInBytes();
  155. const std::optional<VAddr> cpu_addr = memory_manager->GpuToCpuAddress(gpu_addr);
  156. if (!host_ptr || !cpu_addr) {
  157. LOG_CRITICAL(HW_GPU, "Failed to register surface with unmapped gpu_address 0x{:016x}",
  158. gpu_addr);
  159. return;
  160. }
  161. surface->SetHostPtr(host_ptr);
  162. surface->SetCpuAddr(*cpu_addr);
  163. registered_surfaces.add({GetInterval(host_ptr, size), {surface}});
  164. rasterizer.UpdatePagesCachedCount(*cpu_addr, size, 1);
  165. RegisterInnerCache(surface);
  166. surface->MarkAsRegistered(true);
  167. }
  168. void Unregister(TSurface surface) {
  169. if (surface->IsProtected())
  170. return;
  171. const GPUVAddr gpu_addr = surface->GetGpuAddr();
  172. const void* host_ptr = surface->GetHostPtr();
  173. const std::size_t size = surface->GetSizeInBytes();
  174. const VAddr cpu_addr = surface->GetCpuAddr();
  175. registered_surfaces.erase(GetInterval(host_ptr, size));
  176. rasterizer.UpdatePagesCachedCount(cpu_addr, size, -1);
  177. UnregisterInnerCache(surface);
  178. surface->MarkAsRegistered(false);
  179. ReserveSurface(surface->GetSurfaceParams(), surface);
  180. }
  181. TSurface GetUncachedSurface(const GPUVAddr gpu_addr, const SurfaceParams& params) {
  182. if (const auto surface = TryGetReservedSurface(params); surface) {
  183. surface->SetGpuAddr(gpu_addr);
  184. return surface;
  185. }
  186. // No reserved surface available, create a new one and reserve it
  187. auto new_surface{CreateSurface(gpu_addr, params)};
  188. return new_surface;
  189. }
  190. Core::System& system;
  191. private:
  192. enum class RecycleStrategy : u32 {
  193. Ignore = 0,
  194. Flush = 1,
  195. BufferCopy = 3,
  196. };
  197. RecycleStrategy PickStrategy(std::vector<TSurface>& overlaps, const SurfaceParams& params,
  198. const GPUVAddr gpu_addr, const bool untopological) {
  199. // Untopological decision
  200. if (untopological) {
  201. return RecycleStrategy::Ignore;
  202. }
  203. // 3D Textures decision
  204. if (params.block_depth > 1 || params.target == SurfaceTarget::Texture3D) {
  205. return RecycleStrategy::Flush;
  206. }
  207. for (auto s : overlaps) {
  208. const auto& s_params = s->GetSurfaceParams();
  209. if (s_params.block_depth > 1 || s_params.target == SurfaceTarget::Texture3D) {
  210. return RecycleStrategy::Flush;
  211. }
  212. }
  213. return RecycleStrategy::Ignore;
  214. }
  215. std::pair<TSurface, TView> RecycleSurface(std::vector<TSurface>& overlaps,
  216. const SurfaceParams& params, const GPUVAddr gpu_addr,
  217. const u8* host_ptr, const bool preserve_contents,
  218. const bool untopological) {
  219. for (auto surface : overlaps) {
  220. Unregister(surface);
  221. }
  222. RecycleStrategy strategy = !Settings::values.use_accurate_gpu_emulation
  223. ? PickStrategy(overlaps, params, gpu_addr, untopological)
  224. : RecycleStrategy::Flush;
  225. switch (strategy) {
  226. case RecycleStrategy::Ignore: {
  227. return InitializeSurface(gpu_addr, params, preserve_contents);
  228. }
  229. case RecycleStrategy::Flush: {
  230. std::sort(overlaps.begin(), overlaps.end(),
  231. [](const TSurface& a, const TSurface& b) -> bool {
  232. return a->GetModificationTick() < b->GetModificationTick();
  233. });
  234. for (auto surface : overlaps) {
  235. FlushSurface(surface);
  236. }
  237. return InitializeSurface(gpu_addr, params, preserve_contents);
  238. }
  239. default: {
  240. UNIMPLEMENTED_MSG("Unimplemented Texture Cache Recycling Strategy!");
  241. return InitializeSurface(gpu_addr, params, preserve_contents);
  242. }
  243. }
  244. }
  245. std::pair<TSurface, TView> RebuildMirage(TSurface current_surface,
  246. const SurfaceParams& params) {
  247. const auto gpu_addr = current_surface->GetGpuAddr();
  248. TSurface new_surface = GetUncachedSurface(gpu_addr, params);
  249. std::vector<CopyParams> bricks = current_surface->BreakDown();
  250. for (auto& brick : bricks) {
  251. ImageCopy(current_surface, new_surface, brick);
  252. }
  253. Unregister(current_surface);
  254. Register(new_surface);
  255. return {new_surface, new_surface->GetMainView()};
  256. }
  257. std::pair<TSurface, TView> ManageStructuralMatch(TSurface current_surface,
  258. const SurfaceParams& params) {
  259. const bool is_mirage = !current_surface->MatchFormat(params.pixel_format);
  260. if (is_mirage) {
  261. return RebuildMirage(current_surface, params);
  262. }
  263. const bool matches_target = current_surface->MatchTarget(params.target);
  264. if (matches_target) {
  265. return {current_surface, current_surface->GetMainView()};
  266. }
  267. return {current_surface, current_surface->EmplaceOverview(params)};
  268. }
  269. std::optional<std::pair<TSurface, TView>> ReconstructSurface(std::vector<TSurface>& overlaps,
  270. const SurfaceParams& params,
  271. const GPUVAddr gpu_addr,
  272. const u8* host_ptr) {
  273. if (!params.is_layered || params.target == SurfaceTarget::Texture3D) {
  274. return {};
  275. }
  276. TSurface new_surface = GetUncachedSurface(gpu_addr, params);
  277. for (auto surface : overlaps) {
  278. const SurfaceParams& src_params = surface->GetSurfaceParams();
  279. if (src_params.is_layered || src_params.num_levels > 1) {
  280. // We send this cases to recycle as they are more complex to handle
  281. return {};
  282. }
  283. const std::size_t candidate_size = src_params.GetGuestSizeInBytes();
  284. auto mipmap_layer = new_surface->GetLayerMipmap(surface->GetGpuAddr());
  285. if (!mipmap_layer) {
  286. return {};
  287. }
  288. const u32 layer = (*mipmap_layer).first;
  289. const u32 mipmap = (*mipmap_layer).second;
  290. if (new_surface->GetMipmapSize(mipmap) != candidate_size) {
  291. return {};
  292. }
  293. // Now we got all the data set up
  294. CopyParams copy_params{};
  295. const u32 dst_width = params.GetMipWidth(mipmap);
  296. const u32 dst_height = params.GetMipHeight(mipmap);
  297. copy_params.width = std::min(src_params.width, dst_width);
  298. copy_params.height = std::min(src_params.height, dst_height);
  299. copy_params.depth = 1;
  300. copy_params.source_level = 0;
  301. copy_params.dest_level = mipmap;
  302. copy_params.source_z = 0;
  303. copy_params.dest_z = layer;
  304. ImageCopy(surface, new_surface, copy_params);
  305. }
  306. for (auto surface : overlaps) {
  307. Unregister(surface);
  308. }
  309. Register(new_surface);
  310. return {{new_surface, new_surface->GetMainView()}};
  311. }
  312. std::pair<TSurface, TView> GetSurface(const GPUVAddr gpu_addr, const SurfaceParams& params,
  313. bool preserve_contents) {
  314. const auto host_ptr{memory_manager->GetPointer(gpu_addr)};
  315. const auto cache_addr{ToCacheAddr(host_ptr)};
  316. const std::size_t candidate_size = params.GetGuestSizeInBytes();
  317. auto overlaps{GetSurfacesInRegionInner(gpu_addr, candidate_size)};
  318. if (overlaps.empty()) {
  319. return InitializeSurface(gpu_addr, params, preserve_contents);
  320. }
  321. for (auto surface : overlaps) {
  322. if (!surface->MatchesTopology(params)) {
  323. return RecycleSurface(overlaps, params, gpu_addr, host_ptr, preserve_contents,
  324. true);
  325. }
  326. }
  327. if (overlaps.size() == 1) {
  328. TSurface current_surface = overlaps[0];
  329. if (current_surface->MatchesStructure(params) &&
  330. current_surface->GetGpuAddr() == gpu_addr &&
  331. (params.target != SurfaceTarget::Texture3D ||
  332. current_surface->MatchTarget(params.target))) {
  333. return ManageStructuralMatch(current_surface, params);
  334. }
  335. if (current_surface->GetSizeInBytes() <= candidate_size) {
  336. return RecycleSurface(overlaps, params, gpu_addr, host_ptr, preserve_contents,
  337. false);
  338. }
  339. std::optional<TView> view = current_surface->EmplaceView(params, gpu_addr);
  340. if (view.has_value()) {
  341. const bool is_mirage = !current_surface->MatchFormat(params.pixel_format);
  342. if (is_mirage) {
  343. LOG_CRITICAL(HW_GPU, "Mirage View Unsupported");
  344. return RecycleSurface(overlaps, params, gpu_addr, host_ptr, preserve_contents,
  345. false);
  346. }
  347. return {current_surface, *view};
  348. }
  349. return RecycleSurface(overlaps, params, gpu_addr, host_ptr, preserve_contents, false);
  350. } else {
  351. std::optional<std::pair<TSurface, TView>> view =
  352. ReconstructSurface(overlaps, params, gpu_addr, host_ptr);
  353. if (view.has_value()) {
  354. return *view;
  355. }
  356. return RecycleSurface(overlaps, params, gpu_addr, host_ptr, preserve_contents, false);
  357. }
  358. }
  359. std::pair<TSurface, TView> InitializeSurface(GPUVAddr gpu_addr, const SurfaceParams& params,
  360. bool preserve_contents) {
  361. auto new_surface{GetUncachedSurface(gpu_addr, params)};
  362. Register(new_surface);
  363. if (preserve_contents) {
  364. LoadSurface(new_surface);
  365. }
  366. return {new_surface, new_surface->GetMainView()};
  367. }
  368. void LoadSurface(const TSurface& surface) {
  369. staging_buffer.resize(surface->GetHostSizeInBytes());
  370. surface->LoadBuffer(*memory_manager, staging_buffer);
  371. surface->UploadTexture(staging_buffer);
  372. surface->MarkAsModified(false, Tick());
  373. }
  374. void FlushSurface(const TSurface& surface) {
  375. if (!surface->IsModified()) {
  376. return;
  377. }
  378. staging_buffer.resize(surface->GetHostSizeInBytes());
  379. surface->DownloadTexture(staging_buffer);
  380. surface->FlushBuffer(staging_buffer);
  381. surface->MarkAsModified(false, Tick());
  382. }
  383. std::vector<TSurface> GetSurfacesInRegion(CacheAddr cache_addr, std::size_t size) const {
  384. if (size == 0) {
  385. return {};
  386. }
  387. const IntervalType interval{cache_addr, cache_addr + size};
  388. std::vector<TSurface> surfaces;
  389. for (auto& pair : boost::make_iterator_range(registered_surfaces.equal_range(interval))) {
  390. for (auto& s : pair.second) {
  391. if (!s || !s->IsRegistered()) {
  392. continue;
  393. }
  394. surfaces.push_back(s);
  395. }
  396. }
  397. return surfaces;
  398. }
  399. void RegisterInnerCache(TSurface& surface) {
  400. GPUVAddr start = surface->GetGpuAddr() >> inner_cache_page_bits;
  401. const GPUVAddr end = (surface->GetGpuAddrEnd() - 1) >> inner_cache_page_bits;
  402. while (start <= end) {
  403. inner_cache[start].push_back(surface);
  404. start++;
  405. }
  406. }
  407. void UnregisterInnerCache(TSurface& surface) {
  408. GPUVAddr start = surface->GetGpuAddr() >> inner_cache_page_bits;
  409. const GPUVAddr end = (surface->GetGpuAddrEnd() - 1) >> inner_cache_page_bits;
  410. while (start <= end) {
  411. inner_cache[start].remove(surface);
  412. start++;
  413. }
  414. }
  415. std::vector<TSurface> GetSurfacesInRegionInner(const GPUVAddr gpu_addr, const std::size_t size) {
  416. if (size == 0) {
  417. return {};
  418. }
  419. const GPUVAddr gpu_addr_end = gpu_addr + size;
  420. GPUVAddr start = gpu_addr >> inner_cache_page_bits;
  421. const GPUVAddr end = (gpu_addr_end - 1) >> inner_cache_page_bits;
  422. std::vector<TSurface> surfaces;
  423. while (start <= end) {
  424. std::list<TSurface>& list = inner_cache[start];
  425. for (auto& s : list) {
  426. if (!s->IsPicked() && s->Overlaps(gpu_addr, gpu_addr_end)) {
  427. s->MarkAsPicked(true);
  428. surfaces.push_back(s);
  429. }
  430. }
  431. start++;
  432. }
  433. for (auto& s : surfaces) {
  434. s->MarkAsPicked(false);
  435. }
  436. return surfaces;
  437. }
  438. void ReserveSurface(const SurfaceParams& params, TSurface surface) {
  439. surface_reserve[params].push_back(std::move(surface));
  440. }
  441. TSurface TryGetReservedSurface(const SurfaceParams& params) {
  442. auto search{surface_reserve.find(params)};
  443. if (search == surface_reserve.end()) {
  444. return {};
  445. }
  446. for (auto& surface : search->second) {
  447. if (!surface->IsRegistered()) {
  448. return surface;
  449. }
  450. }
  451. return {};
  452. }
  453. IntervalType GetInterval(const void* host_ptr, const std::size_t size) const {
  454. const CacheAddr addr = ToCacheAddr(host_ptr);
  455. return IntervalType::right_open(addr, addr + size);
  456. }
  457. struct RenderInfo {
  458. RenderTargetConfig config;
  459. TSurface target;
  460. TView view;
  461. };
  462. struct DepthBufferInfo {
  463. TSurface target;
  464. TView view;
  465. };
  466. VideoCore::RasterizerInterface& rasterizer;
  467. Tegra::MemoryManager* memory_manager;
  468. u64 ticks{};
  469. IntervalMap registered_surfaces;
  470. static constexpr u64 inner_cache_page_bits{20};
  471. static constexpr u64 inner_cache_page_size{1 << inner_cache_page_bits};
  472. std::unordered_map<GPUVAddr, std::list<TSurface>> inner_cache;
  473. /// The surface reserve is a "backup" cache, this is where we put unique surfaces that have
  474. /// previously been used. This is to prevent surfaces from being constantly created and
  475. /// destroyed when used with different surface parameters.
  476. std::unordered_map<SurfaceParams, std::list<TSurface>> surface_reserve;
  477. std::array<RenderInfo, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> render_targets;
  478. DepthBufferInfo depth_buffer;
  479. std::vector<u8> staging_buffer;
  480. };
  481. } // namespace VideoCommon