texture_cache.h 52 KB

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