texture_cache.h 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254
  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 <algorithm>
  6. #include <array>
  7. #include <list>
  8. #include <memory>
  9. #include <mutex>
  10. #include <set>
  11. #include <tuple>
  12. #include <unordered_map>
  13. #include <vector>
  14. #include <boost/icl/interval_map.hpp>
  15. #include <boost/range/iterator_range.hpp>
  16. #include "common/assert.h"
  17. #include "common/common_types.h"
  18. #include "common/math_util.h"
  19. #include "core/core.h"
  20. #include "core/memory.h"
  21. #include "core/settings.h"
  22. #include "video_core/dirty_flags.h"
  23. #include "video_core/engines/fermi_2d.h"
  24. #include "video_core/engines/maxwell_3d.h"
  25. #include "video_core/gpu.h"
  26. #include "video_core/memory_manager.h"
  27. #include "video_core/rasterizer_interface.h"
  28. #include "video_core/surface.h"
  29. #include "video_core/texture_cache/copy_params.h"
  30. #include "video_core/texture_cache/format_lookup_table.h"
  31. #include "video_core/texture_cache/surface_base.h"
  32. #include "video_core/texture_cache/surface_params.h"
  33. #include "video_core/texture_cache/surface_view.h"
  34. namespace Tegra::Texture {
  35. struct FullTextureInfo;
  36. }
  37. namespace VideoCore {
  38. class RasterizerInterface;
  39. }
  40. namespace VideoCommon {
  41. using VideoCore::Surface::PixelFormat;
  42. using VideoCore::Surface::SurfaceTarget;
  43. using RenderTargetConfig = Tegra::Engines::Maxwell3D::Regs::RenderTargetConfig;
  44. template <typename TSurface, typename TView>
  45. class TextureCache {
  46. public:
  47. void InvalidateRegion(VAddr addr, std::size_t size) {
  48. std::lock_guard lock{mutex};
  49. for (const auto& surface : GetSurfacesInRegion(addr, size)) {
  50. Unregister(surface);
  51. }
  52. }
  53. void OnCPUWrite(VAddr addr, std::size_t size) {
  54. std::lock_guard lock{mutex};
  55. for (const auto& surface : GetSurfacesInRegion(addr, size)) {
  56. if (surface->IsMemoryMarked()) {
  57. Unmark(surface);
  58. surface->SetSyncPending(true);
  59. marked_for_unregister.emplace_back(surface);
  60. }
  61. }
  62. }
  63. void SyncGuestHost() {
  64. std::lock_guard lock{mutex};
  65. for (const auto& surface : marked_for_unregister) {
  66. if (surface->IsRegistered()) {
  67. surface->SetSyncPending(false);
  68. Unregister(surface);
  69. }
  70. }
  71. marked_for_unregister.clear();
  72. }
  73. /**
  74. * Guarantees that rendertargets don't unregister themselves if the
  75. * collide. Protection is currently only done on 3D slices.
  76. */
  77. void GuardRenderTargets(bool new_guard) {
  78. guard_render_targets = new_guard;
  79. }
  80. void GuardSamplers(bool new_guard) {
  81. guard_samplers = new_guard;
  82. }
  83. void FlushRegion(VAddr addr, std::size_t size) {
  84. std::lock_guard lock{mutex};
  85. auto surfaces = GetSurfacesInRegion(addr, size);
  86. if (surfaces.empty()) {
  87. return;
  88. }
  89. std::sort(surfaces.begin(), surfaces.end(), [](const TSurface& a, const TSurface& b) {
  90. return a->GetModificationTick() < b->GetModificationTick();
  91. });
  92. for (const auto& surface : surfaces) {
  93. mutex.unlock();
  94. FlushSurface(surface);
  95. mutex.lock();
  96. }
  97. }
  98. bool MustFlushRegion(VAddr addr, std::size_t size) {
  99. std::lock_guard lock{mutex};
  100. auto surfaces = GetSurfacesInRegion(addr, size);
  101. return std::any_of(surfaces.begin(), surfaces.end(),
  102. [](const TSurface& surface) { return surface->IsModified(); });
  103. }
  104. TView GetTextureSurface(const Tegra::Texture::TICEntry& tic,
  105. const VideoCommon::Shader::Sampler& entry) {
  106. std::lock_guard lock{mutex};
  107. const auto gpu_addr{tic.Address()};
  108. if (!gpu_addr) {
  109. return GetNullSurface(SurfaceParams::ExpectedTarget(entry));
  110. }
  111. const std::optional<VAddr> cpu_addr =
  112. system.GPU().MemoryManager().GpuToCpuAddress(gpu_addr);
  113. if (!cpu_addr) {
  114. return GetNullSurface(SurfaceParams::ExpectedTarget(entry));
  115. }
  116. if (!IsTypeCompatible(tic.texture_type, entry)) {
  117. return GetNullSurface(SurfaceParams::ExpectedTarget(entry));
  118. }
  119. const auto params{SurfaceParams::CreateForTexture(format_lookup_table, tic, entry)};
  120. const auto [surface, view] = GetSurface(gpu_addr, *cpu_addr, params, false);
  121. if (guard_samplers) {
  122. sampled_textures.push_back(surface);
  123. }
  124. return view;
  125. }
  126. TView GetImageSurface(const Tegra::Texture::TICEntry& tic,
  127. const VideoCommon::Shader::Image& entry) {
  128. std::lock_guard lock{mutex};
  129. const auto gpu_addr{tic.Address()};
  130. if (!gpu_addr) {
  131. return GetNullSurface(SurfaceParams::ExpectedTarget(entry));
  132. }
  133. const std::optional<VAddr> cpu_addr =
  134. system.GPU().MemoryManager().GpuToCpuAddress(gpu_addr);
  135. if (!cpu_addr) {
  136. return GetNullSurface(SurfaceParams::ExpectedTarget(entry));
  137. }
  138. const auto params{SurfaceParams::CreateForImage(format_lookup_table, tic, entry)};
  139. const auto [surface, view] = GetSurface(gpu_addr, *cpu_addr, params, false);
  140. if (guard_samplers) {
  141. sampled_textures.push_back(surface);
  142. }
  143. return view;
  144. }
  145. bool TextureBarrier() {
  146. const bool any_rt =
  147. std::any_of(sampled_textures.begin(), sampled_textures.end(),
  148. [](const auto& surface) { return surface->IsRenderTarget(); });
  149. sampled_textures.clear();
  150. return any_rt;
  151. }
  152. TView GetDepthBufferSurface() {
  153. std::lock_guard lock{mutex};
  154. auto& maxwell3d = system.GPU().Maxwell3D();
  155. if (!maxwell3d.dirty.flags[VideoCommon::Dirty::ZetaBuffer]) {
  156. return depth_buffer.view;
  157. }
  158. maxwell3d.dirty.flags[VideoCommon::Dirty::ZetaBuffer] = false;
  159. const auto& regs{maxwell3d.regs};
  160. const auto gpu_addr{regs.zeta.Address()};
  161. if (!gpu_addr || !regs.zeta_enable) {
  162. SetEmptyDepthBuffer();
  163. return {};
  164. }
  165. const std::optional<VAddr> cpu_addr =
  166. system.GPU().MemoryManager().GpuToCpuAddress(gpu_addr);
  167. if (!cpu_addr) {
  168. SetEmptyDepthBuffer();
  169. return {};
  170. }
  171. const auto depth_params{SurfaceParams::CreateForDepthBuffer(system)};
  172. auto surface_view = GetSurface(gpu_addr, *cpu_addr, depth_params, true);
  173. if (depth_buffer.target)
  174. depth_buffer.target->MarkAsRenderTarget(false, NO_RT);
  175. depth_buffer.target = surface_view.first;
  176. depth_buffer.view = surface_view.second;
  177. if (depth_buffer.target)
  178. depth_buffer.target->MarkAsRenderTarget(true, DEPTH_RT);
  179. return surface_view.second;
  180. }
  181. TView GetColorBufferSurface(std::size_t index) {
  182. std::lock_guard lock{mutex};
  183. ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets);
  184. auto& maxwell3d = system.GPU().Maxwell3D();
  185. if (!maxwell3d.dirty.flags[VideoCommon::Dirty::ColorBuffer0 + index]) {
  186. return render_targets[index].view;
  187. }
  188. maxwell3d.dirty.flags[VideoCommon::Dirty::ColorBuffer0 + index] = false;
  189. const auto& regs{maxwell3d.regs};
  190. if (index >= regs.rt_control.count || regs.rt[index].Address() == 0 ||
  191. regs.rt[index].format == Tegra::RenderTargetFormat::NONE) {
  192. SetEmptyColorBuffer(index);
  193. return {};
  194. }
  195. const auto& config{regs.rt[index]};
  196. const auto gpu_addr{config.Address()};
  197. if (!gpu_addr) {
  198. SetEmptyColorBuffer(index);
  199. return {};
  200. }
  201. const std::optional<VAddr> cpu_addr =
  202. system.GPU().MemoryManager().GpuToCpuAddress(gpu_addr);
  203. if (!cpu_addr) {
  204. SetEmptyColorBuffer(index);
  205. return {};
  206. }
  207. auto surface_view = GetSurface(gpu_addr, *cpu_addr,
  208. SurfaceParams::CreateForFramebuffer(system, index), true);
  209. if (render_targets[index].target) {
  210. auto& surface = render_targets[index].target;
  211. surface->MarkAsRenderTarget(false, NO_RT);
  212. const auto& cr_params = surface->GetSurfaceParams();
  213. if (!cr_params.is_tiled && Settings::values.use_asynchronous_gpu_emulation) {
  214. AsyncFlushSurface(surface);
  215. }
  216. }
  217. render_targets[index].target = surface_view.first;
  218. render_targets[index].view = surface_view.second;
  219. if (render_targets[index].target)
  220. render_targets[index].target->MarkAsRenderTarget(true, static_cast<u32>(index));
  221. return surface_view.second;
  222. }
  223. void MarkColorBufferInUse(std::size_t index) {
  224. if (auto& render_target = render_targets[index].target) {
  225. render_target->MarkAsModified(true, Tick());
  226. }
  227. }
  228. void MarkDepthBufferInUse() {
  229. if (depth_buffer.target) {
  230. depth_buffer.target->MarkAsModified(true, Tick());
  231. }
  232. }
  233. void SetEmptyDepthBuffer() {
  234. if (depth_buffer.target == nullptr) {
  235. return;
  236. }
  237. depth_buffer.target->MarkAsRenderTarget(false, NO_RT);
  238. depth_buffer.target = nullptr;
  239. depth_buffer.view = nullptr;
  240. }
  241. void SetEmptyColorBuffer(std::size_t index) {
  242. if (render_targets[index].target == nullptr) {
  243. return;
  244. }
  245. render_targets[index].target->MarkAsRenderTarget(false, NO_RT);
  246. render_targets[index].target = nullptr;
  247. render_targets[index].view = nullptr;
  248. }
  249. void DoFermiCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src_config,
  250. const Tegra::Engines::Fermi2D::Regs::Surface& dst_config,
  251. const Tegra::Engines::Fermi2D::Config& copy_config) {
  252. std::lock_guard lock{mutex};
  253. SurfaceParams src_params = SurfaceParams::CreateForFermiCopySurface(src_config);
  254. SurfaceParams dst_params = SurfaceParams::CreateForFermiCopySurface(dst_config);
  255. const GPUVAddr src_gpu_addr = src_config.Address();
  256. const GPUVAddr dst_gpu_addr = dst_config.Address();
  257. DeduceBestBlit(src_params, dst_params, src_gpu_addr, dst_gpu_addr);
  258. const std::optional<VAddr> dst_cpu_addr =
  259. system.GPU().MemoryManager().GpuToCpuAddress(dst_gpu_addr);
  260. const std::optional<VAddr> src_cpu_addr =
  261. system.GPU().MemoryManager().GpuToCpuAddress(src_gpu_addr);
  262. std::pair<TSurface, TView> dst_surface =
  263. GetSurface(dst_gpu_addr, *dst_cpu_addr, dst_params, false);
  264. std::pair<TSurface, TView> src_surface =
  265. GetSurface(src_gpu_addr, *src_cpu_addr, src_params, false);
  266. ImageBlit(src_surface.second, dst_surface.second, copy_config);
  267. dst_surface.first->MarkAsModified(true, Tick());
  268. }
  269. TSurface TryFindFramebufferSurface(VAddr addr) {
  270. if (!addr) {
  271. return nullptr;
  272. }
  273. const VAddr page = addr >> registry_page_bits;
  274. std::vector<TSurface>& list = registry[page];
  275. for (auto& surface : list) {
  276. if (surface->GetCpuAddr() == addr) {
  277. return surface;
  278. }
  279. }
  280. return nullptr;
  281. }
  282. u64 Tick() {
  283. return ++ticks;
  284. }
  285. void CommitAsyncFlushes() {
  286. committed_flushes.push_back(uncommitted_flushes);
  287. uncommitted_flushes.reset();
  288. }
  289. bool HasUncommittedFlushes() const {
  290. return uncommitted_flushes != nullptr;
  291. }
  292. bool ShouldWaitAsyncFlushes() const {
  293. if (committed_flushes.empty()) {
  294. return false;
  295. }
  296. return committed_flushes.front() != nullptr;
  297. }
  298. void PopAsyncFlushes() {
  299. if (committed_flushes.empty()) {
  300. return;
  301. }
  302. auto& flush_list = committed_flushes.front();
  303. if (!flush_list) {
  304. committed_flushes.pop_front();
  305. return;
  306. }
  307. for (TSurface& surface : *flush_list) {
  308. FlushSurface(surface);
  309. }
  310. committed_flushes.pop_front();
  311. }
  312. protected:
  313. explicit TextureCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
  314. bool is_astc_supported)
  315. : system{system}, is_astc_supported{is_astc_supported}, rasterizer{rasterizer} {
  316. for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
  317. SetEmptyColorBuffer(i);
  318. }
  319. SetEmptyDepthBuffer();
  320. staging_cache.SetSize(2);
  321. const auto make_siblings = [this](PixelFormat a, PixelFormat b) {
  322. siblings_table[static_cast<std::size_t>(a)] = b;
  323. siblings_table[static_cast<std::size_t>(b)] = a;
  324. };
  325. std::fill(siblings_table.begin(), siblings_table.end(), PixelFormat::Invalid);
  326. make_siblings(PixelFormat::Z16, PixelFormat::R16U);
  327. make_siblings(PixelFormat::Z32F, PixelFormat::R32F);
  328. make_siblings(PixelFormat::Z32FS8, PixelFormat::RG32F);
  329. sampled_textures.reserve(64);
  330. }
  331. ~TextureCache() = default;
  332. virtual TSurface CreateSurface(GPUVAddr gpu_addr, const SurfaceParams& params) = 0;
  333. virtual void ImageCopy(TSurface& src_surface, TSurface& dst_surface,
  334. const CopyParams& copy_params) = 0;
  335. virtual void ImageBlit(TView& src_view, TView& dst_view,
  336. const Tegra::Engines::Fermi2D::Config& copy_config) = 0;
  337. // Depending on the backend, a buffer copy can be slow as it means deoptimizing the texture
  338. // and reading it from a separate buffer.
  339. virtual void BufferCopy(TSurface& src_surface, TSurface& dst_surface) = 0;
  340. void ManageRenderTargetUnregister(TSurface& surface) {
  341. auto& dirty = system.GPU().Maxwell3D().dirty;
  342. const u32 index = surface->GetRenderTarget();
  343. if (index == DEPTH_RT) {
  344. dirty.flags[VideoCommon::Dirty::ZetaBuffer] = true;
  345. } else {
  346. dirty.flags[VideoCommon::Dirty::ColorBuffer0 + index] = true;
  347. }
  348. dirty.flags[VideoCommon::Dirty::RenderTargets] = true;
  349. }
  350. void Register(TSurface surface) {
  351. const GPUVAddr gpu_addr = surface->GetGpuAddr();
  352. const std::size_t size = surface->GetSizeInBytes();
  353. const std::optional<VAddr> cpu_addr =
  354. system.GPU().MemoryManager().GpuToCpuAddress(gpu_addr);
  355. if (!cpu_addr) {
  356. LOG_CRITICAL(HW_GPU, "Failed to register surface with unmapped gpu_address 0x{:016x}",
  357. gpu_addr);
  358. return;
  359. }
  360. surface->SetCpuAddr(*cpu_addr);
  361. RegisterInnerCache(surface);
  362. surface->MarkAsRegistered(true);
  363. surface->SetMemoryMarked(true);
  364. rasterizer.UpdatePagesCachedCount(*cpu_addr, size, 1);
  365. }
  366. void Unmark(TSurface surface) {
  367. if (!surface->IsMemoryMarked()) {
  368. return;
  369. }
  370. const std::size_t size = surface->GetSizeInBytes();
  371. const VAddr cpu_addr = surface->GetCpuAddr();
  372. rasterizer.UpdatePagesCachedCount(cpu_addr, size, -1);
  373. surface->SetMemoryMarked(false);
  374. }
  375. void Unregister(TSurface surface) {
  376. if (guard_render_targets && surface->IsProtected()) {
  377. return;
  378. }
  379. if (!guard_render_targets && surface->IsRenderTarget()) {
  380. ManageRenderTargetUnregister(surface);
  381. }
  382. Unmark(surface);
  383. if (surface->IsSyncPending()) {
  384. marked_for_unregister.remove(surface);
  385. surface->SetSyncPending(false);
  386. }
  387. UnregisterInnerCache(surface);
  388. surface->MarkAsRegistered(false);
  389. ReserveSurface(surface->GetSurfaceParams(), surface);
  390. }
  391. TSurface GetUncachedSurface(const GPUVAddr gpu_addr, const SurfaceParams& params) {
  392. if (const auto surface = TryGetReservedSurface(params); surface) {
  393. surface->SetGpuAddr(gpu_addr);
  394. return surface;
  395. }
  396. // No reserved surface available, create a new one and reserve it
  397. auto new_surface{CreateSurface(gpu_addr, params)};
  398. return new_surface;
  399. }
  400. Core::System& system;
  401. const bool is_astc_supported;
  402. private:
  403. enum class RecycleStrategy : u32 {
  404. Ignore = 0,
  405. Flush = 1,
  406. BufferCopy = 3,
  407. };
  408. enum class DeductionType : u32 {
  409. DeductionComplete,
  410. DeductionIncomplete,
  411. DeductionFailed,
  412. };
  413. struct Deduction {
  414. DeductionType type{DeductionType::DeductionFailed};
  415. TSurface surface{};
  416. bool Failed() const {
  417. return type == DeductionType::DeductionFailed;
  418. }
  419. bool Incomplete() const {
  420. return type == DeductionType::DeductionIncomplete;
  421. }
  422. bool IsDepth() const {
  423. return surface->GetSurfaceParams().IsPixelFormatZeta();
  424. }
  425. };
  426. /**
  427. * Takes care of selecting a proper strategy to deal with a texture recycle.
  428. *
  429. * @param overlaps The overlapping surfaces registered in the cache.
  430. * @param params The parameters on the new surface.
  431. * @param gpu_addr The starting address of the new surface.
  432. * @param untopological Indicates to the recycler that the texture has no way
  433. * to match the overlaps due to topological reasons.
  434. **/
  435. RecycleStrategy PickStrategy(std::vector<TSurface>& overlaps, const SurfaceParams& params,
  436. const GPUVAddr gpu_addr, const MatchTopologyResult untopological) {
  437. if (Settings::IsGPULevelExtreme()) {
  438. return RecycleStrategy::Flush;
  439. }
  440. // 3D Textures decision
  441. if (params.block_depth > 1 || params.target == SurfaceTarget::Texture3D) {
  442. return RecycleStrategy::Flush;
  443. }
  444. for (const auto& s : overlaps) {
  445. const auto& s_params = s->GetSurfaceParams();
  446. if (s_params.block_depth > 1 || s_params.target == SurfaceTarget::Texture3D) {
  447. return RecycleStrategy::Flush;
  448. }
  449. }
  450. // Untopological decision
  451. if (untopological == MatchTopologyResult::CompressUnmatch) {
  452. return RecycleStrategy::Flush;
  453. }
  454. if (untopological == MatchTopologyResult::FullMatch && !params.is_tiled) {
  455. return RecycleStrategy::Flush;
  456. }
  457. return RecycleStrategy::Ignore;
  458. }
  459. /**
  460. * Used to decide what to do with textures we can't resolve in the cache It has 2 implemented
  461. * strategies: Ignore and Flush.
  462. *
  463. * - Ignore: Just unregisters all the overlaps and loads the new texture.
  464. * - Flush: Flushes all the overlaps into memory and loads the new surface from that data.
  465. *
  466. * @param overlaps The overlapping surfaces registered in the cache.
  467. * @param params The parameters for the new surface.
  468. * @param gpu_addr The starting address of the new surface.
  469. * @param untopological Indicates to the recycler that the texture has no way to match the
  470. * overlaps due to topological reasons.
  471. **/
  472. std::pair<TSurface, TView> RecycleSurface(std::vector<TSurface>& overlaps,
  473. const SurfaceParams& params, const GPUVAddr gpu_addr,
  474. const MatchTopologyResult untopological) {
  475. for (auto& surface : overlaps) {
  476. Unregister(surface);
  477. }
  478. switch (PickStrategy(overlaps, params, gpu_addr, untopological)) {
  479. case RecycleStrategy::Ignore: {
  480. return InitializeSurface(gpu_addr, params, Settings::IsGPULevelExtreme());
  481. }
  482. case RecycleStrategy::Flush: {
  483. std::sort(overlaps.begin(), overlaps.end(),
  484. [](const TSurface& a, const TSurface& b) -> bool {
  485. return a->GetModificationTick() < b->GetModificationTick();
  486. });
  487. for (auto& surface : overlaps) {
  488. FlushSurface(surface);
  489. }
  490. return InitializeSurface(gpu_addr, params);
  491. }
  492. case RecycleStrategy::BufferCopy: {
  493. auto new_surface = GetUncachedSurface(gpu_addr, params);
  494. BufferCopy(overlaps[0], new_surface);
  495. return {new_surface, new_surface->GetMainView()};
  496. }
  497. default: {
  498. UNIMPLEMENTED_MSG("Unimplemented Texture Cache Recycling Strategy!");
  499. return InitializeSurface(gpu_addr, params);
  500. }
  501. }
  502. }
  503. /**
  504. * Takes a single surface and recreates into another that may differ in
  505. * format, target or width alignment.
  506. *
  507. * @param current_surface The registered surface in the cache which we want to convert.
  508. * @param params The new surface params which we'll use to recreate the surface.
  509. * @param is_render Whether or not the surface is a render target.
  510. **/
  511. std::pair<TSurface, TView> RebuildSurface(TSurface current_surface, const SurfaceParams& params,
  512. bool is_render) {
  513. const auto gpu_addr = current_surface->GetGpuAddr();
  514. const auto& cr_params = current_surface->GetSurfaceParams();
  515. TSurface new_surface;
  516. if (cr_params.pixel_format != params.pixel_format && !is_render &&
  517. GetSiblingFormat(cr_params.pixel_format) == params.pixel_format) {
  518. SurfaceParams new_params = params;
  519. new_params.pixel_format = cr_params.pixel_format;
  520. new_params.type = cr_params.type;
  521. new_surface = GetUncachedSurface(gpu_addr, new_params);
  522. } else {
  523. new_surface = GetUncachedSurface(gpu_addr, params);
  524. }
  525. const auto& final_params = new_surface->GetSurfaceParams();
  526. if (cr_params.type != final_params.type) {
  527. if (Settings::IsGPULevelExtreme()) {
  528. BufferCopy(current_surface, new_surface);
  529. }
  530. } else {
  531. std::vector<CopyParams> bricks = current_surface->BreakDown(final_params);
  532. for (auto& brick : bricks) {
  533. ImageCopy(current_surface, new_surface, brick);
  534. }
  535. }
  536. Unregister(current_surface);
  537. Register(new_surface);
  538. new_surface->MarkAsModified(current_surface->IsModified(), Tick());
  539. return {new_surface, new_surface->GetMainView()};
  540. }
  541. /**
  542. * Takes a single surface and checks with the new surface's params if it's an exact
  543. * match, we return the main view of the registered surface. If its formats don't
  544. * match, we rebuild the surface. We call this last method a `Mirage`. If formats
  545. * match but the targets don't, we create an overview View of the registered surface.
  546. *
  547. * @param current_surface The registered surface in the cache which we want to convert.
  548. * @param params The new surface params which we want to check.
  549. * @param is_render Whether or not the surface is a render target.
  550. **/
  551. std::pair<TSurface, TView> ManageStructuralMatch(TSurface current_surface,
  552. const SurfaceParams& params, bool is_render) {
  553. const bool is_mirage = !current_surface->MatchFormat(params.pixel_format);
  554. const bool matches_target = current_surface->MatchTarget(params.target);
  555. const auto match_check = [&]() -> std::pair<TSurface, TView> {
  556. if (matches_target) {
  557. return {current_surface, current_surface->GetMainView()};
  558. }
  559. return {current_surface, current_surface->EmplaceOverview(params)};
  560. };
  561. if (!is_mirage) {
  562. return match_check();
  563. }
  564. if (!is_render && GetSiblingFormat(current_surface->GetFormat()) == params.pixel_format) {
  565. return match_check();
  566. }
  567. return RebuildSurface(current_surface, params, is_render);
  568. }
  569. /**
  570. * Unlike RebuildSurface where we know whether or not registered surfaces match the candidate
  571. * in some way, we have no guarantees here. We try to see if the overlaps are sublayers/mipmaps
  572. * of the new surface, if they all match we end up recreating a surface for them,
  573. * else we return nothing.
  574. *
  575. * @param overlaps The overlapping surfaces registered in the cache.
  576. * @param params The parameters on the new surface.
  577. * @param gpu_addr The starting address of the new surface.
  578. **/
  579. std::optional<std::pair<TSurface, TView>> TryReconstructSurface(std::vector<TSurface>& overlaps,
  580. const SurfaceParams& params,
  581. const GPUVAddr gpu_addr) {
  582. if (params.target == SurfaceTarget::Texture3D) {
  583. return {};
  584. }
  585. bool modified = false;
  586. TSurface new_surface = GetUncachedSurface(gpu_addr, params);
  587. u32 passed_tests = 0;
  588. for (auto& surface : overlaps) {
  589. const SurfaceParams& src_params = surface->GetSurfaceParams();
  590. if (src_params.is_layered || src_params.num_levels > 1) {
  591. // We send this cases to recycle as they are more complex to handle
  592. return {};
  593. }
  594. const std::size_t candidate_size = surface->GetSizeInBytes();
  595. auto mipmap_layer{new_surface->GetLayerMipmap(surface->GetGpuAddr())};
  596. if (!mipmap_layer) {
  597. continue;
  598. }
  599. const auto [layer, mipmap] = *mipmap_layer;
  600. if (new_surface->GetMipmapSize(mipmap) != candidate_size) {
  601. continue;
  602. }
  603. modified |= surface->IsModified();
  604. // Now we got all the data set up
  605. const u32 width = SurfaceParams::IntersectWidth(src_params, params, 0, mipmap);
  606. const u32 height = SurfaceParams::IntersectHeight(src_params, params, 0, mipmap);
  607. const CopyParams copy_params(0, 0, 0, 0, 0, layer, 0, mipmap, width, height, 1);
  608. passed_tests++;
  609. ImageCopy(surface, new_surface, copy_params);
  610. }
  611. if (passed_tests == 0) {
  612. return {};
  613. // In Accurate GPU all tests should pass, else we recycle
  614. } else if (Settings::IsGPULevelExtreme() && passed_tests != overlaps.size()) {
  615. return {};
  616. }
  617. for (const auto& surface : overlaps) {
  618. Unregister(surface);
  619. }
  620. new_surface->MarkAsModified(modified, Tick());
  621. Register(new_surface);
  622. return {{new_surface, new_surface->GetMainView()}};
  623. }
  624. /**
  625. * Takes care of managing 3D textures and its slices. Does HLE methods for reconstructing the 3D
  626. * textures within the GPU if possible. Falls back to LLE when it isn't possible to use any of
  627. * the HLE methods.
  628. *
  629. * @param overlaps The overlapping surfaces registered in the cache.
  630. * @param params The parameters on the new surface.
  631. * @param gpu_addr The starting address of the new surface.
  632. * @param cpu_addr The starting address of the new surface on physical memory.
  633. */
  634. std::optional<std::pair<TSurface, TView>> Manage3DSurfaces(std::vector<TSurface>& overlaps,
  635. const SurfaceParams& params,
  636. const GPUVAddr gpu_addr,
  637. const VAddr cpu_addr) {
  638. if (params.target == SurfaceTarget::Texture3D) {
  639. bool failed = false;
  640. if (params.num_levels > 1) {
  641. // We can't handle mipmaps in 3D textures yet, better fallback to LLE approach
  642. return std::nullopt;
  643. }
  644. TSurface new_surface = GetUncachedSurface(gpu_addr, params);
  645. bool modified = false;
  646. for (auto& surface : overlaps) {
  647. const SurfaceParams& src_params = surface->GetSurfaceParams();
  648. if (src_params.target != SurfaceTarget::Texture2D) {
  649. failed = true;
  650. break;
  651. }
  652. if (src_params.height != params.height) {
  653. failed = true;
  654. break;
  655. }
  656. if (src_params.block_depth != params.block_depth ||
  657. src_params.block_height != params.block_height) {
  658. failed = true;
  659. break;
  660. }
  661. const u32 offset = static_cast<u32>(surface->GetCpuAddr() - cpu_addr);
  662. const auto offsets = params.GetBlockOffsetXYZ(offset);
  663. const auto z = std::get<2>(offsets);
  664. modified |= surface->IsModified();
  665. const CopyParams copy_params(0, 0, 0, 0, 0, z, 0, 0, params.width, params.height,
  666. 1);
  667. ImageCopy(surface, new_surface, copy_params);
  668. }
  669. if (failed) {
  670. return std::nullopt;
  671. }
  672. for (const auto& surface : overlaps) {
  673. Unregister(surface);
  674. }
  675. new_surface->MarkAsModified(modified, Tick());
  676. Register(new_surface);
  677. auto view = new_surface->GetMainView();
  678. return {{std::move(new_surface), view}};
  679. } else {
  680. for (const auto& surface : overlaps) {
  681. if (!surface->MatchTarget(params.target)) {
  682. if (overlaps.size() == 1 && surface->GetCpuAddr() == cpu_addr) {
  683. if (Settings::IsGPULevelExtreme()) {
  684. return std::nullopt;
  685. }
  686. Unregister(surface);
  687. return InitializeSurface(gpu_addr, params);
  688. }
  689. return std::nullopt;
  690. }
  691. if (surface->GetCpuAddr() != cpu_addr) {
  692. continue;
  693. }
  694. if (surface->MatchesStructure(params) == MatchStructureResult::FullMatch) {
  695. return {{surface, surface->GetMainView()}};
  696. }
  697. }
  698. return InitializeSurface(gpu_addr, params);
  699. }
  700. }
  701. /**
  702. * Gets the starting address and parameters of a candidate surface and tries
  703. * to find a matching surface within the cache. This is done in 3 big steps:
  704. *
  705. * 1. Check the 1st Level Cache in order to find an exact match, if we fail, we move to step 2.
  706. *
  707. * 2. Check if there are any overlaps at all, if there are none, we just load the texture from
  708. * memory else we move to step 3.
  709. *
  710. * 3. Consists of figuring out the relationship between the candidate texture and the
  711. * overlaps. We divide the scenarios depending if there's 1 or many overlaps. If
  712. * there's many, we just try to reconstruct a new surface out of them based on the
  713. * candidate's parameters, if we fail, we recycle. When there's only 1 overlap then we
  714. * have to check if the candidate is a view (layer/mipmap) of the overlap or if the
  715. * registered surface is a mipmap/layer of the candidate. In this last case we reconstruct
  716. * a new surface.
  717. *
  718. * @param gpu_addr The starting address of the candidate surface.
  719. * @param params The parameters on the candidate surface.
  720. * @param is_render Whether or not the surface is a render target.
  721. **/
  722. std::pair<TSurface, TView> GetSurface(const GPUVAddr gpu_addr, const VAddr cpu_addr,
  723. const SurfaceParams& params, bool is_render) {
  724. // Step 1
  725. // Check Level 1 Cache for a fast structural match. If candidate surface
  726. // matches at certain level we are pretty much done.
  727. if (const auto iter = l1_cache.find(cpu_addr); iter != l1_cache.end()) {
  728. TSurface& current_surface = iter->second;
  729. const auto topological_result = current_surface->MatchesTopology(params);
  730. if (topological_result != MatchTopologyResult::FullMatch) {
  731. std::vector<TSurface> overlaps{current_surface};
  732. return RecycleSurface(overlaps, params, gpu_addr, topological_result);
  733. }
  734. const auto struct_result = current_surface->MatchesStructure(params);
  735. if (struct_result != MatchStructureResult::None) {
  736. const auto& old_params = current_surface->GetSurfaceParams();
  737. const bool not_3d = params.target != SurfaceTarget::Texture3D &&
  738. old_params.target != SurfaceTarget::Texture3D;
  739. if (not_3d || current_surface->MatchTarget(params.target)) {
  740. if (struct_result == MatchStructureResult::FullMatch) {
  741. return ManageStructuralMatch(current_surface, params, is_render);
  742. } else {
  743. return RebuildSurface(current_surface, params, is_render);
  744. }
  745. }
  746. }
  747. }
  748. // Step 2
  749. // Obtain all possible overlaps in the memory region
  750. const std::size_t candidate_size = params.GetGuestSizeInBytes();
  751. auto overlaps{GetSurfacesInRegion(cpu_addr, candidate_size)};
  752. // If none are found, we are done. we just load the surface and create it.
  753. if (overlaps.empty()) {
  754. return InitializeSurface(gpu_addr, params);
  755. }
  756. // Step 3
  757. // Now we need to figure the relationship between the texture and its overlaps
  758. // we do a topological test to ensure we can find some relationship. If it fails
  759. // immediately recycle the texture
  760. for (const auto& surface : overlaps) {
  761. const auto topological_result = surface->MatchesTopology(params);
  762. if (topological_result != MatchTopologyResult::FullMatch) {
  763. return RecycleSurface(overlaps, params, gpu_addr, topological_result);
  764. }
  765. }
  766. // Check if it's a 3D texture
  767. if (params.block_depth > 0) {
  768. auto surface = Manage3DSurfaces(overlaps, params, gpu_addr, cpu_addr);
  769. if (surface) {
  770. return *surface;
  771. }
  772. }
  773. // Split cases between 1 overlap or many.
  774. if (overlaps.size() == 1) {
  775. TSurface current_surface = overlaps[0];
  776. // First check if the surface is within the overlap. If not, it means
  777. // two things either the candidate surface is a supertexture of the overlap
  778. // or they don't match in any known way.
  779. if (!current_surface->IsInside(gpu_addr, gpu_addr + candidate_size)) {
  780. if (current_surface->GetGpuAddr() == gpu_addr) {
  781. std::optional<std::pair<TSurface, TView>> view =
  782. TryReconstructSurface(overlaps, params, gpu_addr);
  783. if (view) {
  784. return *view;
  785. }
  786. }
  787. return RecycleSurface(overlaps, params, gpu_addr, MatchTopologyResult::FullMatch);
  788. }
  789. // Now we check if the candidate is a mipmap/layer of the overlap
  790. std::optional<TView> view =
  791. current_surface->EmplaceView(params, gpu_addr, candidate_size);
  792. if (view) {
  793. const bool is_mirage = !current_surface->MatchFormat(params.pixel_format);
  794. if (is_mirage) {
  795. // On a mirage view, we need to recreate the surface under this new view
  796. // and then obtain a view again.
  797. SurfaceParams new_params = current_surface->GetSurfaceParams();
  798. const u32 wh = SurfaceParams::ConvertWidth(
  799. new_params.width, new_params.pixel_format, params.pixel_format);
  800. const u32 hh = SurfaceParams::ConvertHeight(
  801. new_params.height, new_params.pixel_format, params.pixel_format);
  802. new_params.width = wh;
  803. new_params.height = hh;
  804. new_params.pixel_format = params.pixel_format;
  805. std::pair<TSurface, TView> pair =
  806. RebuildSurface(current_surface, new_params, is_render);
  807. std::optional<TView> mirage_view =
  808. pair.first->EmplaceView(params, gpu_addr, candidate_size);
  809. if (mirage_view)
  810. return {pair.first, *mirage_view};
  811. return RecycleSurface(overlaps, params, gpu_addr,
  812. MatchTopologyResult::FullMatch);
  813. }
  814. return {current_surface, *view};
  815. }
  816. } else {
  817. // If there are many overlaps, odds are they are subtextures of the candidate
  818. // surface. We try to construct a new surface based on the candidate parameters,
  819. // using the overlaps. If a single overlap fails, this will fail.
  820. std::optional<std::pair<TSurface, TView>> view =
  821. TryReconstructSurface(overlaps, params, gpu_addr);
  822. if (view) {
  823. return *view;
  824. }
  825. }
  826. // We failed all the tests, recycle the overlaps into a new texture.
  827. return RecycleSurface(overlaps, params, gpu_addr, MatchTopologyResult::FullMatch);
  828. }
  829. /**
  830. * Gets the starting address and parameters of a candidate surface and tries to find a
  831. * matching surface within the cache that's similar to it. If there are many textures
  832. * or the texture found if entirely incompatible, it will fail. If no texture is found, the
  833. * blit will be unsuccessful.
  834. *
  835. * @param gpu_addr The starting address of the candidate surface.
  836. * @param params The parameters on the candidate surface.
  837. **/
  838. Deduction DeduceSurface(const GPUVAddr gpu_addr, const SurfaceParams& params) {
  839. const std::optional<VAddr> cpu_addr =
  840. system.GPU().MemoryManager().GpuToCpuAddress(gpu_addr);
  841. if (!cpu_addr) {
  842. Deduction result{};
  843. result.type = DeductionType::DeductionFailed;
  844. return result;
  845. }
  846. if (const auto iter = l1_cache.find(*cpu_addr); iter != l1_cache.end()) {
  847. TSurface& current_surface = iter->second;
  848. const auto topological_result = current_surface->MatchesTopology(params);
  849. if (topological_result != MatchTopologyResult::FullMatch) {
  850. Deduction result{};
  851. result.type = DeductionType::DeductionFailed;
  852. return result;
  853. }
  854. const auto struct_result = current_surface->MatchesStructure(params);
  855. if (struct_result != MatchStructureResult::None &&
  856. current_surface->MatchTarget(params.target)) {
  857. Deduction result{};
  858. result.type = DeductionType::DeductionComplete;
  859. result.surface = current_surface;
  860. return result;
  861. }
  862. }
  863. const std::size_t candidate_size = params.GetGuestSizeInBytes();
  864. auto overlaps{GetSurfacesInRegion(*cpu_addr, candidate_size)};
  865. if (overlaps.empty()) {
  866. Deduction result{};
  867. result.type = DeductionType::DeductionIncomplete;
  868. return result;
  869. }
  870. if (overlaps.size() > 1) {
  871. Deduction result{};
  872. result.type = DeductionType::DeductionFailed;
  873. return result;
  874. } else {
  875. Deduction result{};
  876. result.type = DeductionType::DeductionComplete;
  877. result.surface = overlaps[0];
  878. return result;
  879. }
  880. }
  881. /**
  882. * Gets a null surface based on a target texture.
  883. * @param target The target of the null surface.
  884. */
  885. TView GetNullSurface(SurfaceTarget target) {
  886. const u32 i_target = static_cast<u32>(target);
  887. if (const auto it = invalid_cache.find(i_target); it != invalid_cache.end()) {
  888. return it->second->GetMainView();
  889. }
  890. SurfaceParams params{};
  891. params.target = target;
  892. params.is_tiled = false;
  893. params.srgb_conversion = false;
  894. params.is_layered = false;
  895. params.block_width = 0;
  896. params.block_height = 0;
  897. params.block_depth = 0;
  898. params.tile_width_spacing = 1;
  899. params.width = 1;
  900. params.height = 1;
  901. params.depth = 1;
  902. if (target == SurfaceTarget::TextureCubemap || target == SurfaceTarget::TextureCubeArray) {
  903. params.depth = 6;
  904. }
  905. params.pitch = 4;
  906. params.num_levels = 1;
  907. params.emulated_levels = 1;
  908. params.pixel_format = VideoCore::Surface::PixelFormat::R8U;
  909. params.type = VideoCore::Surface::SurfaceType::ColorTexture;
  910. auto surface = CreateSurface(0ULL, params);
  911. invalid_memory.resize(surface->GetHostSizeInBytes(), 0U);
  912. surface->UploadTexture(invalid_memory);
  913. surface->MarkAsModified(false, Tick());
  914. invalid_cache.emplace(i_target, surface);
  915. return surface->GetMainView();
  916. }
  917. /**
  918. * Gets the a source and destination starting address and parameters,
  919. * and tries to deduce if they are supposed to be depth textures. If so, their
  920. * parameters are modified and fixed into so.
  921. *
  922. * @param src_params The parameters of the candidate surface.
  923. * @param dst_params The parameters of the destination surface.
  924. * @param src_gpu_addr The starting address of the candidate surface.
  925. * @param dst_gpu_addr The starting address of the destination surface.
  926. **/
  927. void DeduceBestBlit(SurfaceParams& src_params, SurfaceParams& dst_params,
  928. const GPUVAddr src_gpu_addr, const GPUVAddr dst_gpu_addr) {
  929. auto deduced_src = DeduceSurface(src_gpu_addr, src_params);
  930. auto deduced_dst = DeduceSurface(src_gpu_addr, src_params);
  931. if (deduced_src.Failed() || deduced_dst.Failed()) {
  932. return;
  933. }
  934. const bool incomplete_src = deduced_src.Incomplete();
  935. const bool incomplete_dst = deduced_dst.Incomplete();
  936. if (incomplete_src && incomplete_dst) {
  937. return;
  938. }
  939. const bool any_incomplete = incomplete_src || incomplete_dst;
  940. if (!any_incomplete) {
  941. if (!(deduced_src.IsDepth() && deduced_dst.IsDepth())) {
  942. return;
  943. }
  944. } else {
  945. if (incomplete_src && !(deduced_dst.IsDepth())) {
  946. return;
  947. }
  948. if (incomplete_dst && !(deduced_src.IsDepth())) {
  949. return;
  950. }
  951. }
  952. const auto inherit_format = [](SurfaceParams& to, TSurface from) {
  953. const SurfaceParams& params = from->GetSurfaceParams();
  954. to.pixel_format = params.pixel_format;
  955. to.type = params.type;
  956. };
  957. // Now we got the cases where one or both is Depth and the other is not known
  958. if (!incomplete_src) {
  959. inherit_format(src_params, deduced_src.surface);
  960. } else {
  961. inherit_format(src_params, deduced_dst.surface);
  962. }
  963. if (!incomplete_dst) {
  964. inherit_format(dst_params, deduced_dst.surface);
  965. } else {
  966. inherit_format(dst_params, deduced_src.surface);
  967. }
  968. }
  969. std::pair<TSurface, TView> InitializeSurface(GPUVAddr gpu_addr, const SurfaceParams& params,
  970. bool do_load = true) {
  971. auto new_surface{GetUncachedSurface(gpu_addr, params)};
  972. Register(new_surface);
  973. if (do_load) {
  974. LoadSurface(new_surface);
  975. }
  976. return {new_surface, new_surface->GetMainView()};
  977. }
  978. void LoadSurface(const TSurface& surface) {
  979. staging_cache.GetBuffer(0).resize(surface->GetHostSizeInBytes());
  980. surface->LoadBuffer(system.GPU().MemoryManager(), staging_cache);
  981. surface->UploadTexture(staging_cache.GetBuffer(0));
  982. surface->MarkAsModified(false, Tick());
  983. }
  984. void FlushSurface(const TSurface& surface) {
  985. if (!surface->IsModified()) {
  986. return;
  987. }
  988. staging_cache.GetBuffer(0).resize(surface->GetHostSizeInBytes());
  989. surface->DownloadTexture(staging_cache.GetBuffer(0));
  990. surface->FlushBuffer(system.GPU().MemoryManager(), staging_cache);
  991. surface->MarkAsModified(false, Tick());
  992. }
  993. void RegisterInnerCache(TSurface& surface) {
  994. const VAddr cpu_addr = surface->GetCpuAddr();
  995. VAddr start = cpu_addr >> registry_page_bits;
  996. const VAddr end = (surface->GetCpuAddrEnd() - 1) >> registry_page_bits;
  997. l1_cache[cpu_addr] = surface;
  998. while (start <= end) {
  999. registry[start].push_back(surface);
  1000. start++;
  1001. }
  1002. }
  1003. void UnregisterInnerCache(TSurface& surface) {
  1004. const VAddr cpu_addr = surface->GetCpuAddr();
  1005. VAddr start = cpu_addr >> registry_page_bits;
  1006. const VAddr end = (surface->GetCpuAddrEnd() - 1) >> registry_page_bits;
  1007. l1_cache.erase(cpu_addr);
  1008. while (start <= end) {
  1009. auto& reg{registry[start]};
  1010. reg.erase(std::find(reg.begin(), reg.end(), surface));
  1011. start++;
  1012. }
  1013. }
  1014. std::vector<TSurface> GetSurfacesInRegion(const VAddr cpu_addr, const std::size_t size) {
  1015. if (size == 0) {
  1016. return {};
  1017. }
  1018. const VAddr cpu_addr_end = cpu_addr + size;
  1019. VAddr start = cpu_addr >> registry_page_bits;
  1020. const VAddr end = (cpu_addr_end - 1) >> registry_page_bits;
  1021. std::vector<TSurface> surfaces;
  1022. while (start <= end) {
  1023. std::vector<TSurface>& list = registry[start];
  1024. for (auto& surface : list) {
  1025. if (!surface->IsPicked() && surface->Overlaps(cpu_addr, cpu_addr_end)) {
  1026. surface->MarkAsPicked(true);
  1027. surfaces.push_back(surface);
  1028. }
  1029. }
  1030. start++;
  1031. }
  1032. for (auto& surface : surfaces) {
  1033. surface->MarkAsPicked(false);
  1034. }
  1035. return surfaces;
  1036. }
  1037. void ReserveSurface(const SurfaceParams& params, TSurface surface) {
  1038. surface_reserve[params].push_back(std::move(surface));
  1039. }
  1040. TSurface TryGetReservedSurface(const SurfaceParams& params) {
  1041. auto search{surface_reserve.find(params)};
  1042. if (search == surface_reserve.end()) {
  1043. return {};
  1044. }
  1045. for (auto& surface : search->second) {
  1046. if (!surface->IsRegistered()) {
  1047. return surface;
  1048. }
  1049. }
  1050. return {};
  1051. }
  1052. constexpr PixelFormat GetSiblingFormat(PixelFormat format) const {
  1053. return siblings_table[static_cast<std::size_t>(format)];
  1054. }
  1055. /// Returns true the shader sampler entry is compatible with the TIC texture type.
  1056. static bool IsTypeCompatible(Tegra::Texture::TextureType tic_type,
  1057. const VideoCommon::Shader::Sampler& entry) {
  1058. const auto shader_type = entry.GetType();
  1059. switch (tic_type) {
  1060. case Tegra::Texture::TextureType::Texture1D:
  1061. case Tegra::Texture::TextureType::Texture1DArray:
  1062. return shader_type == Tegra::Shader::TextureType::Texture1D;
  1063. case Tegra::Texture::TextureType::Texture1DBuffer:
  1064. // TODO(Rodrigo): Assume as valid for now
  1065. return true;
  1066. case Tegra::Texture::TextureType::Texture2D:
  1067. case Tegra::Texture::TextureType::Texture2DNoMipmap:
  1068. return shader_type == Tegra::Shader::TextureType::Texture2D;
  1069. case Tegra::Texture::TextureType::Texture2DArray:
  1070. return shader_type == Tegra::Shader::TextureType::Texture2D ||
  1071. shader_type == Tegra::Shader::TextureType::TextureCube;
  1072. case Tegra::Texture::TextureType::Texture3D:
  1073. return shader_type == Tegra::Shader::TextureType::Texture3D;
  1074. case Tegra::Texture::TextureType::TextureCubeArray:
  1075. case Tegra::Texture::TextureType::TextureCubemap:
  1076. if (shader_type == Tegra::Shader::TextureType::TextureCube) {
  1077. return true;
  1078. }
  1079. return shader_type == Tegra::Shader::TextureType::Texture2D && entry.IsArray();
  1080. }
  1081. UNREACHABLE();
  1082. return true;
  1083. }
  1084. struct FramebufferTargetInfo {
  1085. TSurface target;
  1086. TView view;
  1087. };
  1088. void AsyncFlushSurface(TSurface& surface) {
  1089. if (!uncommitted_flushes) {
  1090. uncommitted_flushes = std::make_shared<std::list<TSurface>>();
  1091. }
  1092. uncommitted_flushes->push_back(surface);
  1093. }
  1094. VideoCore::RasterizerInterface& rasterizer;
  1095. FormatLookupTable format_lookup_table;
  1096. u64 ticks{};
  1097. // Guards the cache for protection conflicts.
  1098. bool guard_render_targets{};
  1099. bool guard_samplers{};
  1100. // The siblings table is for formats that can inter exchange with one another
  1101. // without causing issues. This is only valid when a conflict occurs on a non
  1102. // rendering use.
  1103. std::array<PixelFormat, static_cast<std::size_t>(PixelFormat::Max)> siblings_table;
  1104. // The internal Cache is different for the Texture Cache. It's based on buckets
  1105. // of 1MB. This fits better for the purpose of this cache as textures are normaly
  1106. // large in size.
  1107. static constexpr u64 registry_page_bits{20};
  1108. static constexpr u64 registry_page_size{1 << registry_page_bits};
  1109. std::unordered_map<VAddr, std::vector<TSurface>> registry;
  1110. static constexpr u32 DEPTH_RT = 8;
  1111. static constexpr u32 NO_RT = 0xFFFFFFFF;
  1112. // The L1 Cache is used for fast texture lookup before checking the overlaps
  1113. // This avoids calculating size and other stuffs.
  1114. std::unordered_map<VAddr, TSurface> l1_cache;
  1115. /// The surface reserve is a "backup" cache, this is where we put unique surfaces that have
  1116. /// previously been used. This is to prevent surfaces from being constantly created and
  1117. /// destroyed when used with different surface parameters.
  1118. std::unordered_map<SurfaceParams, std::vector<TSurface>> surface_reserve;
  1119. std::array<FramebufferTargetInfo, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets>
  1120. render_targets;
  1121. FramebufferTargetInfo depth_buffer;
  1122. std::vector<TSurface> sampled_textures;
  1123. /// This cache stores null surfaces in order to be used as a placeholder
  1124. /// for invalid texture calls.
  1125. std::unordered_map<u32, TSurface> invalid_cache;
  1126. std::vector<u8> invalid_memory;
  1127. std::list<TSurface> marked_for_unregister;
  1128. std::shared_ptr<std::list<TSurface>> uncommitted_flushes{};
  1129. std::list<std::shared_ptr<std::list<TSurface>>> committed_flushes;
  1130. StagingCache staging_cache;
  1131. std::recursive_mutex mutex;
  1132. };
  1133. } // namespace VideoCommon