texture_cache.h 23 KB

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