texture_cache.h 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750
  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 <type_traits>
  10. #include <unordered_map>
  11. #include <boost/icl/interval_map.hpp>
  12. #include <boost/range/iterator_range.hpp>
  13. #include "common/assert.h"
  14. #include "common/common_types.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. namespace Core {
  23. class System;
  24. }
  25. namespace Tegra::Texture {
  26. struct FullTextureInfo;
  27. }
  28. namespace VideoCore {
  29. class RasterizerInterface;
  30. }
  31. namespace VideoCommon {
  32. class HasheableSurfaceParams {
  33. public:
  34. std::size_t Hash() const;
  35. bool operator==(const HasheableSurfaceParams& rhs) const;
  36. bool operator!=(const HasheableSurfaceParams& rhs) const {
  37. return !operator==(rhs);
  38. }
  39. protected:
  40. // Avoid creation outside of a managed environment.
  41. HasheableSurfaceParams() = default;
  42. bool is_tiled;
  43. bool srgb_conversion;
  44. u32 block_width;
  45. u32 block_height;
  46. u32 block_depth;
  47. u32 tile_width_spacing;
  48. u32 width;
  49. u32 height;
  50. u32 depth;
  51. u32 pitch;
  52. u32 unaligned_height;
  53. u32 num_levels;
  54. VideoCore::Surface::PixelFormat pixel_format;
  55. VideoCore::Surface::ComponentType component_type;
  56. VideoCore::Surface::SurfaceType type;
  57. VideoCore::Surface::SurfaceTarget target;
  58. };
  59. class SurfaceParams final : public HasheableSurfaceParams {
  60. public:
  61. /// Creates SurfaceCachedParams from a texture configuration.
  62. static SurfaceParams CreateForTexture(Core::System& system,
  63. const Tegra::Texture::FullTextureInfo& config);
  64. /// Creates SurfaceCachedParams for a depth buffer configuration.
  65. static SurfaceParams CreateForDepthBuffer(
  66. Core::System& system, u32 zeta_width, u32 zeta_height, Tegra::DepthFormat format,
  67. u32 block_width, u32 block_height, u32 block_depth,
  68. Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout type);
  69. /// Creates SurfaceCachedParams from a framebuffer configuration.
  70. static SurfaceParams CreateForFramebuffer(Core::System& system, std::size_t index);
  71. /// Creates SurfaceCachedParams from a Fermi2D surface configuration.
  72. static SurfaceParams CreateForFermiCopySurface(
  73. const Tegra::Engines::Fermi2D::Regs::Surface& config);
  74. bool IsTiled() const {
  75. return is_tiled;
  76. }
  77. bool GetSrgbConversion() const {
  78. return srgb_conversion;
  79. }
  80. u32 GetBlockWidth() const {
  81. return block_width;
  82. }
  83. u32 GetTileWidthSpacing() const {
  84. return tile_width_spacing;
  85. }
  86. u32 GetWidth() const {
  87. return width;
  88. }
  89. u32 GetHeight() const {
  90. return height;
  91. }
  92. u32 GetDepth() const {
  93. return depth;
  94. }
  95. u32 GetPitch() const {
  96. return pitch;
  97. }
  98. u32 GetNumLevels() const {
  99. return num_levels;
  100. }
  101. VideoCore::Surface::PixelFormat GetPixelFormat() const {
  102. return pixel_format;
  103. }
  104. VideoCore::Surface::ComponentType GetComponentType() const {
  105. return component_type;
  106. }
  107. VideoCore::Surface::SurfaceTarget GetTarget() const {
  108. return target;
  109. }
  110. VideoCore::Surface::SurfaceType GetType() const {
  111. return type;
  112. }
  113. std::size_t GetGuestSizeInBytes() const {
  114. return guest_size_in_bytes;
  115. }
  116. std::size_t GetHostSizeInBytes() const {
  117. return host_size_in_bytes;
  118. }
  119. u32 GetNumLayers() const {
  120. return num_layers;
  121. }
  122. /// Returns the width of a given mipmap level.
  123. u32 GetMipWidth(u32 level) const;
  124. /// Returns the height of a given mipmap level.
  125. u32 GetMipHeight(u32 level) const;
  126. /// Returns the depth of a given mipmap level.
  127. u32 GetMipDepth(u32 level) const;
  128. /// Returns true if these parameters are from a layered surface.
  129. bool IsLayered() const;
  130. /// Returns the block height of a given mipmap level.
  131. u32 GetMipBlockHeight(u32 level) const;
  132. /// Returns the block depth of a given mipmap level.
  133. u32 GetMipBlockDepth(u32 level) const;
  134. /// Returns the offset in bytes in guest memory of a given mipmap level.
  135. std::size_t GetGuestMipmapLevelOffset(u32 level) const;
  136. /// Returns the offset in bytes in host memory (linear) of a given mipmap level.
  137. std::size_t GetHostMipmapLevelOffset(u32 level) const;
  138. /// Returns the size in bytes in host memory (linear) of a given mipmap level.
  139. std::size_t GetHostMipmapSize(u32 level) const;
  140. /// Returns the size of a layer in bytes in guest memory.
  141. std::size_t GetGuestLayerSize() const;
  142. /// Returns the size of a layer in bytes in host memory for a given mipmap level.
  143. std::size_t GetHostLayerSize(u32 level) const;
  144. /// Returns the default block width.
  145. u32 GetDefaultBlockWidth() const;
  146. /// Returns the default block height.
  147. u32 GetDefaultBlockHeight() const;
  148. /// Returns the bits per pixel.
  149. u32 GetBitsPerPixel() const;
  150. /// Returns the bytes per pixel.
  151. u32 GetBytesPerPixel() const;
  152. /// Returns true if another surface can be familiar with this. This is a loosely defined term
  153. /// that reflects the possibility of these two surface parameters potentially being part of a
  154. /// bigger superset.
  155. bool IsFamiliar(const SurfaceParams& view_params) const;
  156. /// Returns true if the pixel format is a depth and/or stencil format.
  157. bool IsPixelFormatZeta() const;
  158. /// Creates a map that redirects an address difference to a layer and mipmap level.
  159. std::map<u64, std::pair<u32, u32>> CreateViewOffsetMap() const;
  160. /// Returns true if the passed surface view parameters is equal or a valid subset of this.
  161. bool IsViewValid(const SurfaceParams& view_params, u32 layer, u32 level) const;
  162. private:
  163. /// Calculates values that can be deduced from HasheableSurfaceParams.
  164. void CalculateCachedValues();
  165. /// Returns the size of a given mipmap level inside a layer.
  166. std::size_t GetInnerMipmapMemorySize(u32 level, bool as_host_size, bool uncompressed) const;
  167. /// Returns the size of all mipmap levels and aligns as needed.
  168. std::size_t GetInnerMemorySize(bool as_host_size, bool layer_only, bool uncompressed) const;
  169. /// Returns the size of a layer
  170. std::size_t GetLayerSize(bool as_host_size, bool uncompressed) const;
  171. /// Returns true if the passed view width and height match the size of this params in a given
  172. /// mipmap level.
  173. bool IsDimensionValid(const SurfaceParams& view_params, u32 level) const;
  174. /// Returns true if the passed view depth match the size of this params in a given mipmap level.
  175. bool IsDepthValid(const SurfaceParams& view_params, u32 level) const;
  176. /// Returns true if the passed view layers and mipmap levels are in bounds.
  177. bool IsInBounds(const SurfaceParams& view_params, u32 layer, u32 level) const;
  178. std::size_t guest_size_in_bytes;
  179. std::size_t host_size_in_bytes;
  180. u32 num_layers;
  181. };
  182. struct ViewKey {
  183. std::size_t Hash() const;
  184. bool operator==(const ViewKey& rhs) const;
  185. u32 base_layer{};
  186. u32 num_layers{};
  187. u32 base_level{};
  188. u32 num_levels{};
  189. };
  190. } // namespace VideoCommon
  191. namespace std {
  192. template <>
  193. struct hash<VideoCommon::SurfaceParams> {
  194. std::size_t operator()(const VideoCommon::SurfaceParams& k) const noexcept {
  195. return k.Hash();
  196. }
  197. };
  198. template <>
  199. struct hash<VideoCommon::ViewKey> {
  200. std::size_t operator()(const VideoCommon::ViewKey& k) const noexcept {
  201. return k.Hash();
  202. }
  203. };
  204. } // namespace std
  205. namespace VideoCommon {
  206. class SurfaceBaseImpl {
  207. public:
  208. void LoadBuffer();
  209. void FlushBuffer();
  210. GPUVAddr GetGpuAddr() const {
  211. ASSERT(is_registered);
  212. return gpu_addr;
  213. }
  214. VAddr GetCpuAddr() const {
  215. ASSERT(is_registered);
  216. return cpu_addr;
  217. }
  218. u8* GetHostPtr() const {
  219. ASSERT(is_registered);
  220. return host_ptr;
  221. }
  222. CacheAddr GetCacheAddr() const {
  223. ASSERT(is_registered);
  224. return cache_addr;
  225. }
  226. const SurfaceParams& GetSurfaceParams() const {
  227. return params;
  228. }
  229. void Register(GPUVAddr gpu_addr_, VAddr cpu_addr_, u8* host_ptr_) {
  230. ASSERT(!is_registered);
  231. is_registered = true;
  232. gpu_addr = gpu_addr_;
  233. cpu_addr = cpu_addr_;
  234. host_ptr = host_ptr_;
  235. cache_addr = ToCacheAddr(host_ptr_);
  236. DecorateSurfaceName();
  237. }
  238. void Unregister() {
  239. ASSERT(is_registered);
  240. is_registered = false;
  241. }
  242. bool IsRegistered() const {
  243. return is_registered;
  244. }
  245. std::size_t GetSizeInBytes() const {
  246. return params.GetGuestSizeInBytes();
  247. }
  248. u8* GetStagingBufferLevelData(u32 level) {
  249. return staging_buffer.data() + params.GetHostMipmapLevelOffset(level);
  250. }
  251. protected:
  252. explicit SurfaceBaseImpl(const SurfaceParams& params);
  253. ~SurfaceBaseImpl(); // non-virtual is intended
  254. virtual void DecorateSurfaceName() = 0;
  255. const SurfaceParams params;
  256. private:
  257. GPUVAddr gpu_addr{};
  258. VAddr cpu_addr{};
  259. u8* host_ptr{};
  260. CacheAddr cache_addr{};
  261. bool is_registered{};
  262. std::vector<u8> staging_buffer;
  263. };
  264. template <typename TTextureCache, typename TView, typename TExecutionContext>
  265. class SurfaceBase : public SurfaceBaseImpl {
  266. static_assert(std::is_trivially_copyable_v<TExecutionContext>);
  267. public:
  268. virtual TExecutionContext UploadTexture(TExecutionContext exctx) = 0;
  269. virtual TExecutionContext DownloadTexture(TExecutionContext exctx) = 0;
  270. TView* TryGetView(GPUVAddr view_addr, const SurfaceParams& view_params) {
  271. if (view_addr < GetGpuAddr() || !params.IsFamiliar(view_params)) {
  272. // It can't be a view if it's in a prior address.
  273. return {};
  274. }
  275. const auto relative_offset{static_cast<u64>(view_addr - GetGpuAddr())};
  276. const auto it{view_offset_map.find(relative_offset)};
  277. if (it == view_offset_map.end()) {
  278. // Couldn't find an aligned view.
  279. return {};
  280. }
  281. const auto [layer, level] = it->second;
  282. if (!params.IsViewValid(view_params, layer, level)) {
  283. return {};
  284. }
  285. return GetView(layer, view_params.GetNumLayers(), level, view_params.GetNumLevels());
  286. }
  287. void MarkAsModified(bool is_modified_) {
  288. is_modified = is_modified_;
  289. if (is_modified_) {
  290. modification_tick = texture_cache.Tick();
  291. }
  292. }
  293. TView* GetView(GPUVAddr view_addr, const SurfaceParams& view_params) {
  294. TView* view{TryGetView(view_addr, view_params)};
  295. ASSERT(view != nullptr);
  296. return view;
  297. }
  298. bool IsModified() const {
  299. return is_modified;
  300. }
  301. u64 GetModificationTick() const {
  302. return modification_tick;
  303. }
  304. protected:
  305. explicit SurfaceBase(TTextureCache& texture_cache, const SurfaceParams& params)
  306. : SurfaceBaseImpl{params}, texture_cache{texture_cache},
  307. view_offset_map{params.CreateViewOffsetMap()} {}
  308. ~SurfaceBase() = default;
  309. virtual std::unique_ptr<TView> CreateView(const ViewKey& view_key) = 0;
  310. private:
  311. TView* GetView(u32 base_layer, u32 num_layers, u32 base_level, u32 num_levels) {
  312. const ViewKey key{base_layer, num_layers, base_level, num_levels};
  313. const auto [entry, is_cache_miss] = views.try_emplace(key);
  314. auto& view{entry->second};
  315. if (is_cache_miss) {
  316. view = CreateView(key);
  317. }
  318. return view.get();
  319. }
  320. TTextureCache& texture_cache;
  321. const std::map<u64, std::pair<u32, u32>> view_offset_map;
  322. bool is_modified{};
  323. u64 modification_tick{};
  324. std::unordered_map<ViewKey, std::unique_ptr<TView>> views;
  325. };
  326. template <typename TSurface, typename TView, typename TExecutionContext>
  327. class TextureCache {
  328. static_assert(std::is_trivially_copyable_v<TExecutionContext>);
  329. using ResultType = std::tuple<TView*, TExecutionContext>;
  330. using IntervalMap = boost::icl::interval_map<CacheAddr, std::set<std::shared_ptr<TSurface>>>;
  331. using IntervalType = typename IntervalMap::interval_type;
  332. public:
  333. void InvalidateRegion(CacheAddr addr, std::size_t size) {
  334. for (const auto& surface : GetSurfacesInRegion(addr, size)) {
  335. if (!surface->IsRegistered()) {
  336. // Skip duplicates
  337. continue;
  338. }
  339. Unregister(surface);
  340. }
  341. }
  342. ResultType GetTextureSurface(TExecutionContext exctx,
  343. const Tegra::Texture::FullTextureInfo& config) {
  344. const auto gpu_addr{config.tic.Address()};
  345. if (!gpu_addr) {
  346. return {{}, exctx};
  347. }
  348. const auto params{SurfaceParams::CreateForTexture(system, config)};
  349. return GetSurfaceView(exctx, gpu_addr, params, true);
  350. }
  351. ResultType GetDepthBufferSurface(TExecutionContext exctx, bool preserve_contents) {
  352. const auto& regs{system.GPU().Maxwell3D().regs};
  353. const auto gpu_addr{regs.zeta.Address()};
  354. if (!gpu_addr || !regs.zeta_enable) {
  355. return {{}, exctx};
  356. }
  357. const auto depth_params{SurfaceParams::CreateForDepthBuffer(
  358. system, regs.zeta_width, regs.zeta_height, regs.zeta.format,
  359. regs.zeta.memory_layout.block_width, regs.zeta.memory_layout.block_height,
  360. regs.zeta.memory_layout.block_depth, regs.zeta.memory_layout.type)};
  361. return GetSurfaceView(exctx, gpu_addr, depth_params, preserve_contents);
  362. }
  363. ResultType GetColorBufferSurface(TExecutionContext exctx, std::size_t index,
  364. bool preserve_contents) {
  365. ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets);
  366. const auto& regs{system.GPU().Maxwell3D().regs};
  367. if (index >= regs.rt_control.count || regs.rt[index].Address() == 0 ||
  368. regs.rt[index].format == Tegra::RenderTargetFormat::NONE) {
  369. return {{}, exctx};
  370. }
  371. auto& memory_manager{system.GPU().MemoryManager()};
  372. const auto& config{system.GPU().Maxwell3D().regs.rt[index]};
  373. const auto gpu_addr{config.Address() +
  374. config.base_layer * config.layer_stride * sizeof(u32)};
  375. if (!gpu_addr) {
  376. return {{}, exctx};
  377. }
  378. return GetSurfaceView(exctx, gpu_addr, SurfaceParams::CreateForFramebuffer(system, index),
  379. preserve_contents);
  380. }
  381. ResultType GetFermiSurface(TExecutionContext exctx,
  382. const Tegra::Engines::Fermi2D::Regs::Surface& config) {
  383. return GetSurfaceView(exctx, config.Address(),
  384. SurfaceParams::CreateForFermiCopySurface(config), true);
  385. }
  386. std::shared_ptr<TSurface> TryFindFramebufferSurface(const u8* host_ptr) const {
  387. const auto it{registered_surfaces.find(ToCacheAddr(host_ptr))};
  388. return it != registered_surfaces.end() ? *it->second.begin() : nullptr;
  389. }
  390. u64 Tick() {
  391. return ++ticks;
  392. }
  393. protected:
  394. TextureCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer)
  395. : system{system}, rasterizer{rasterizer} {}
  396. ~TextureCache() = default;
  397. virtual ResultType TryFastGetSurfaceView(
  398. TExecutionContext exctx, GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr,
  399. const SurfaceParams& params, bool preserve_contents,
  400. const std::vector<std::shared_ptr<TSurface>>& overlaps) = 0;
  401. virtual std::shared_ptr<TSurface> CreateSurface(const SurfaceParams& params) = 0;
  402. void Register(std::shared_ptr<TSurface> surface, GPUVAddr gpu_addr, VAddr cpu_addr,
  403. u8* host_ptr) {
  404. surface->Register(gpu_addr, cpu_addr, host_ptr);
  405. registered_surfaces.add({GetSurfaceInterval(surface), {surface}});
  406. rasterizer.UpdatePagesCachedCount(surface->GetCpuAddr(), surface->GetSizeInBytes(), 1);
  407. }
  408. void Unregister(std::shared_ptr<TSurface> surface) {
  409. registered_surfaces.subtract({GetSurfaceInterval(surface), {surface}});
  410. rasterizer.UpdatePagesCachedCount(surface->GetCpuAddr(), surface->GetSizeInBytes(), -1);
  411. surface->Unregister();
  412. }
  413. std::shared_ptr<TSurface> GetUncachedSurface(const SurfaceParams& params) {
  414. if (const auto surface = TryGetReservedSurface(params); surface)
  415. return surface;
  416. // No reserved surface available, create a new one and reserve it
  417. auto new_surface{CreateSurface(params)};
  418. ReserveSurface(params, new_surface);
  419. return new_surface;
  420. }
  421. Core::System& system;
  422. private:
  423. ResultType GetSurfaceView(TExecutionContext exctx, GPUVAddr gpu_addr,
  424. const SurfaceParams& params, bool preserve_contents) {
  425. auto& memory_manager{system.GPU().MemoryManager()};
  426. const auto cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr)};
  427. DEBUG_ASSERT(cpu_addr);
  428. const auto host_ptr{memory_manager.GetPointer(gpu_addr)};
  429. const auto cache_addr{ToCacheAddr(host_ptr)};
  430. auto overlaps{GetSurfacesInRegion(cache_addr, params.GetGuestSizeInBytes())};
  431. if (overlaps.empty()) {
  432. return LoadSurfaceView(exctx, gpu_addr, *cpu_addr, host_ptr, params, preserve_contents);
  433. }
  434. if (overlaps.size() == 1) {
  435. if (TView* view = overlaps[0]->TryGetView(gpu_addr, params); view) {
  436. return {view, exctx};
  437. }
  438. }
  439. TView* fast_view;
  440. std::tie(fast_view, exctx) = TryFastGetSurfaceView(exctx, gpu_addr, *cpu_addr, host_ptr,
  441. params, preserve_contents, overlaps);
  442. if (!fast_view) {
  443. std::sort(overlaps.begin(), overlaps.end(), [](const auto& lhs, const auto& rhs) {
  444. return lhs->GetModificationTick() < rhs->GetModificationTick();
  445. });
  446. }
  447. for (const auto& surface : overlaps) {
  448. if (!fast_view) {
  449. // Flush even when we don't care about the contents, to preserve memory not
  450. // written by the new surface.
  451. exctx = FlushSurface(exctx, surface);
  452. }
  453. Unregister(surface);
  454. }
  455. if (fast_view) {
  456. return {fast_view, exctx};
  457. }
  458. return LoadSurfaceView(exctx, gpu_addr, *cpu_addr, host_ptr, params, preserve_contents);
  459. }
  460. ResultType LoadSurfaceView(TExecutionContext exctx, GPUVAddr gpu_addr, VAddr cpu_addr,
  461. u8* host_ptr, const SurfaceParams& params, bool preserve_contents) {
  462. const auto new_surface{GetUncachedSurface(params)};
  463. Register(new_surface, gpu_addr, cpu_addr, host_ptr);
  464. if (preserve_contents) {
  465. exctx = LoadSurface(exctx, new_surface);
  466. }
  467. return {new_surface->GetView(gpu_addr, params), exctx};
  468. }
  469. TExecutionContext LoadSurface(TExecutionContext exctx,
  470. const std::shared_ptr<TSurface>& surface) {
  471. surface->LoadBuffer();
  472. exctx = surface->UploadTexture(exctx);
  473. surface->MarkAsModified(false);
  474. return exctx;
  475. }
  476. TExecutionContext FlushSurface(TExecutionContext exctx,
  477. const std::shared_ptr<TSurface>& surface) {
  478. if (!surface->IsModified()) {
  479. return exctx;
  480. }
  481. exctx = surface->DownloadTexture(exctx);
  482. surface->FlushBuffer();
  483. return exctx;
  484. }
  485. std::vector<std::shared_ptr<TSurface>> GetSurfacesInRegion(CacheAddr cache_addr,
  486. std::size_t size) const {
  487. if (size == 0) {
  488. return {};
  489. }
  490. const IntervalType interval{cache_addr, cache_addr + size};
  491. std::vector<std::shared_ptr<TSurface>> surfaces;
  492. for (auto& pair : boost::make_iterator_range(registered_surfaces.equal_range(interval))) {
  493. surfaces.push_back(*pair.second.begin());
  494. }
  495. return surfaces;
  496. }
  497. void ReserveSurface(const SurfaceParams& params, std::shared_ptr<TSurface> surface) {
  498. surface_reserve[params].push_back(std::move(surface));
  499. }
  500. std::shared_ptr<TSurface> TryGetReservedSurface(const SurfaceParams& params) {
  501. auto search{surface_reserve.find(params)};
  502. if (search == surface_reserve.end()) {
  503. return {};
  504. }
  505. for (auto& surface : search->second) {
  506. if (!surface->IsRegistered()) {
  507. return surface;
  508. }
  509. }
  510. return {};
  511. }
  512. IntervalType GetSurfaceInterval(std::shared_ptr<TSurface> surface) const {
  513. return IntervalType::right_open(surface->GetCacheAddr(),
  514. surface->GetCacheAddr() + surface->GetSizeInBytes());
  515. }
  516. VideoCore::RasterizerInterface& rasterizer;
  517. u64 ticks{};
  518. IntervalMap registered_surfaces;
  519. /// The surface reserve is a "backup" cache, this is where we put unique surfaces that have
  520. /// previously been used. This is to prevent surfaces from being constantly created and
  521. /// destroyed when used with different surface parameters.
  522. std::unordered_map<SurfaceParams, std::list<std::shared_ptr<TSurface>>> surface_reserve;
  523. };
  524. struct DummyExecutionContext {};
  525. template <typename TSurface, typename TView>
  526. class TextureCacheContextless : protected TextureCache<TSurface, TView, DummyExecutionContext> {
  527. using Base = TextureCache<TSurface, TView, DummyExecutionContext>;
  528. public:
  529. void InvalidateRegion(CacheAddr addr, std::size_t size) {
  530. Base::InvalidateRegion(addr, size);
  531. }
  532. TView* GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) {
  533. return RemoveContext(Base::GetTextureSurface({}, config));
  534. }
  535. TView* GetDepthBufferSurface(bool preserve_contents) {
  536. return RemoveContext(Base::GetDepthBufferSurface({}, preserve_contents));
  537. }
  538. TView* GetColorBufferSurface(std::size_t index, bool preserve_contents) {
  539. return RemoveContext(Base::GetColorBufferSurface({}, index, preserve_contents));
  540. }
  541. TView* GetFermiSurface(const Tegra::Engines::Fermi2D::Regs::Surface& config) {
  542. return RemoveContext(Base::GetFermiSurface({}, config));
  543. }
  544. std::shared_ptr<TSurface> TryFindFramebufferSurface(const u8* host_ptr) const {
  545. return Base::TryFindFramebufferSurface(host_ptr);
  546. }
  547. u64 Tick() {
  548. return Base::Tick();
  549. }
  550. protected:
  551. explicit TextureCacheContextless(Core::System& system,
  552. VideoCore::RasterizerInterface& rasterizer)
  553. : TextureCache<TSurface, TView, DummyExecutionContext>{system, rasterizer} {}
  554. virtual TView* TryFastGetSurfaceView(
  555. GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr, const SurfaceParams& params,
  556. bool preserve_contents, const std::vector<std::shared_ptr<TSurface>>& overlaps) = 0;
  557. private:
  558. std::tuple<TView*, DummyExecutionContext> TryFastGetSurfaceView(
  559. DummyExecutionContext, GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr,
  560. const SurfaceParams& params, bool preserve_contents,
  561. const std::vector<std::shared_ptr<TSurface>>& overlaps) {
  562. return {TryFastGetSurfaceView(gpu_addr, cpu_addr, host_ptr, params, preserve_contents,
  563. overlaps),
  564. {}};
  565. }
  566. TView* RemoveContext(std::tuple<TView*, DummyExecutionContext> return_value) {
  567. const auto [view, exctx] = return_value;
  568. return view;
  569. }
  570. };
  571. template <typename TTextureCache, typename TView>
  572. class SurfaceBaseContextless : public SurfaceBase<TTextureCache, TView, DummyExecutionContext> {
  573. public:
  574. DummyExecutionContext DownloadTexture(DummyExecutionContext) {
  575. DownloadTextureImpl();
  576. return {};
  577. }
  578. DummyExecutionContext UploadTexture(DummyExecutionContext) {
  579. UploadTextureImpl();
  580. return {};
  581. }
  582. protected:
  583. explicit SurfaceBaseContextless(TTextureCache& texture_cache, const SurfaceParams& params)
  584. : SurfaceBase<TTextureCache, TView, DummyExecutionContext>{texture_cache, params} {}
  585. virtual void DownloadTextureImpl() = 0;
  586. virtual void UploadTextureImpl() = 0;
  587. };
  588. } // namespace VideoCommon