buffer_cache.h 73 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845
  1. // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-3.0-or-later
  3. #pragma once
  4. #include <algorithm>
  5. #include <memory>
  6. #include <numeric>
  7. #include "video_core/buffer_cache/buffer_cache_base.h"
  8. namespace VideoCommon {
  9. using Core::Memory::YUZU_PAGESIZE;
  10. template <class P>
  11. BufferCache<P>::BufferCache(VideoCore::RasterizerInterface& rasterizer_,
  12. Core::Memory::Memory& cpu_memory_, Runtime& runtime_)
  13. : runtime{runtime_}, rasterizer{rasterizer_}, cpu_memory{cpu_memory_}, memory_tracker{
  14. rasterizer} {
  15. // Ensure the first slot is used for the null buffer
  16. void(slot_buffers.insert(runtime, NullBufferParams{}));
  17. common_ranges.clear();
  18. inline_buffer_id = NULL_BUFFER_ID;
  19. if (!runtime.CanReportMemoryUsage()) {
  20. minimum_memory = DEFAULT_EXPECTED_MEMORY;
  21. critical_memory = DEFAULT_CRITICAL_MEMORY;
  22. return;
  23. }
  24. const s64 device_memory = static_cast<s64>(runtime.GetDeviceLocalMemory());
  25. const s64 min_spacing_expected = device_memory - 1_GiB;
  26. const s64 min_spacing_critical = device_memory - 512_MiB;
  27. const s64 mem_threshold = std::min(device_memory, TARGET_THRESHOLD);
  28. const s64 min_vacancy_expected = (6 * mem_threshold) / 10;
  29. const s64 min_vacancy_critical = (3 * mem_threshold) / 10;
  30. minimum_memory = static_cast<u64>(
  31. std::max(std::min(device_memory - min_vacancy_expected, min_spacing_expected),
  32. DEFAULT_EXPECTED_MEMORY));
  33. critical_memory = static_cast<u64>(
  34. std::max(std::min(device_memory - min_vacancy_critical, min_spacing_critical),
  35. DEFAULT_CRITICAL_MEMORY));
  36. }
  37. template <class P>
  38. void BufferCache<P>::RunGarbageCollector() {
  39. const bool aggressive_gc = total_used_memory >= critical_memory;
  40. const u64 ticks_to_destroy = aggressive_gc ? 60 : 120;
  41. int num_iterations = aggressive_gc ? 64 : 32;
  42. const auto clean_up = [this, &num_iterations](BufferId buffer_id) {
  43. if (num_iterations == 0) {
  44. return true;
  45. }
  46. --num_iterations;
  47. auto& buffer = slot_buffers[buffer_id];
  48. DownloadBufferMemory(buffer);
  49. DeleteBuffer(buffer_id);
  50. return false;
  51. };
  52. lru_cache.ForEachItemBelow(frame_tick - ticks_to_destroy, clean_up);
  53. }
  54. template <class P>
  55. void BufferCache<P>::TickFrame() {
  56. // Homebrew console apps don't create or bind any channels, so this will be nullptr.
  57. if (!channel_state) {
  58. return;
  59. }
  60. // Calculate hits and shots and move hit bits to the right
  61. const u32 hits = std::reduce(channel_state->uniform_cache_hits.begin(),
  62. channel_state->uniform_cache_hits.end());
  63. const u32 shots = std::reduce(channel_state->uniform_cache_shots.begin(),
  64. channel_state->uniform_cache_shots.end());
  65. std::copy_n(channel_state->uniform_cache_hits.begin(),
  66. channel_state->uniform_cache_hits.size() - 1,
  67. channel_state->uniform_cache_hits.begin() + 1);
  68. std::copy_n(channel_state->uniform_cache_shots.begin(),
  69. channel_state->uniform_cache_shots.size() - 1,
  70. channel_state->uniform_cache_shots.begin() + 1);
  71. channel_state->uniform_cache_hits[0] = 0;
  72. channel_state->uniform_cache_shots[0] = 0;
  73. const bool skip_preferred = hits * 256 < shots * 251;
  74. channel_state->uniform_buffer_skip_cache_size = skip_preferred ? DEFAULT_SKIP_CACHE_SIZE : 0;
  75. // If we can obtain the memory info, use it instead of the estimate.
  76. if (runtime.CanReportMemoryUsage()) {
  77. total_used_memory = runtime.GetDeviceMemoryUsage();
  78. }
  79. if (total_used_memory >= minimum_memory) {
  80. RunGarbageCollector();
  81. }
  82. ++frame_tick;
  83. delayed_destruction_ring.Tick();
  84. if constexpr (IMPLEMENTS_ASYNC_DOWNLOADS) {
  85. for (auto& buffer : async_buffers_death_ring) {
  86. runtime.FreeDeferredStagingBuffer(buffer);
  87. }
  88. async_buffers_death_ring.clear();
  89. }
  90. }
  91. template <class P>
  92. void BufferCache<P>::WriteMemory(VAddr cpu_addr, u64 size) {
  93. if (memory_tracker.IsRegionGpuModified(cpu_addr, size)) {
  94. const IntervalType subtract_interval{cpu_addr, cpu_addr + size};
  95. ClearDownload(subtract_interval);
  96. common_ranges.subtract(subtract_interval);
  97. }
  98. memory_tracker.MarkRegionAsCpuModified(cpu_addr, size);
  99. }
  100. template <class P>
  101. void BufferCache<P>::CachedWriteMemory(VAddr cpu_addr, u64 size) {
  102. const bool is_dirty = IsRegionRegistered(cpu_addr, size);
  103. if (!is_dirty) {
  104. return;
  105. }
  106. VAddr aligned_start = Common::AlignDown(cpu_addr, YUZU_PAGESIZE);
  107. VAddr aligned_end = Common::AlignUp(cpu_addr + size, YUZU_PAGESIZE);
  108. if (!IsRegionGpuModified(aligned_start, aligned_end - aligned_start)) {
  109. WriteMemory(cpu_addr, size);
  110. return;
  111. }
  112. tmp_buffer.resize_destructive(size);
  113. cpu_memory.ReadBlockUnsafe(cpu_addr, tmp_buffer.data(), size);
  114. InlineMemoryImplementation(cpu_addr, size, tmp_buffer);
  115. }
  116. template <class P>
  117. bool BufferCache<P>::OnCPUWrite(VAddr cpu_addr, u64 size) {
  118. const bool is_dirty = IsRegionRegistered(cpu_addr, size);
  119. if (!is_dirty) {
  120. return false;
  121. }
  122. if (memory_tracker.IsRegionGpuModified(cpu_addr, size)) {
  123. return true;
  124. }
  125. WriteMemory(cpu_addr, size);
  126. return false;
  127. }
  128. template <class P>
  129. std::optional<VideoCore::RasterizerDownloadArea> BufferCache<P>::GetFlushArea(VAddr cpu_addr,
  130. u64 size) {
  131. std::optional<VideoCore::RasterizerDownloadArea> area{};
  132. area.emplace();
  133. VAddr cpu_addr_start_aligned = Common::AlignDown(cpu_addr, Core::Memory::YUZU_PAGESIZE);
  134. VAddr cpu_addr_end_aligned = Common::AlignUp(cpu_addr + size, Core::Memory::YUZU_PAGESIZE);
  135. area->start_address = cpu_addr_start_aligned;
  136. area->end_address = cpu_addr_end_aligned;
  137. if (memory_tracker.IsRegionPreflushable(cpu_addr, size)) {
  138. area->preemtive = true;
  139. return area;
  140. };
  141. area->preemtive =
  142. !IsRegionGpuModified(cpu_addr_start_aligned, cpu_addr_end_aligned - cpu_addr_start_aligned);
  143. memory_tracker.MarkRegionAsPreflushable(cpu_addr_start_aligned,
  144. cpu_addr_end_aligned - cpu_addr_start_aligned);
  145. return area;
  146. }
  147. template <class P>
  148. void BufferCache<P>::DownloadMemory(VAddr cpu_addr, u64 size) {
  149. ForEachBufferInRange(cpu_addr, size, [&](BufferId, Buffer& buffer) {
  150. DownloadBufferMemory(buffer, cpu_addr, size);
  151. });
  152. }
  153. template <class P>
  154. void BufferCache<P>::ClearDownload(IntervalType subtract_interval) {
  155. RemoveEachInOverlapCounter(async_downloads, subtract_interval, -1024);
  156. uncommitted_ranges.subtract(subtract_interval);
  157. for (auto& interval_set : committed_ranges) {
  158. interval_set.subtract(subtract_interval);
  159. }
  160. }
  161. template <class P>
  162. bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) {
  163. const std::optional<VAddr> cpu_src_address = gpu_memory->GpuToCpuAddress(src_address);
  164. const std::optional<VAddr> cpu_dest_address = gpu_memory->GpuToCpuAddress(dest_address);
  165. if (!cpu_src_address || !cpu_dest_address) {
  166. return false;
  167. }
  168. const bool source_dirty = IsRegionRegistered(*cpu_src_address, amount);
  169. const bool dest_dirty = IsRegionRegistered(*cpu_dest_address, amount);
  170. if (!source_dirty && !dest_dirty) {
  171. return false;
  172. }
  173. const IntervalType subtract_interval{*cpu_dest_address, *cpu_dest_address + amount};
  174. ClearDownload(subtract_interval);
  175. BufferId buffer_a;
  176. BufferId buffer_b;
  177. do {
  178. channel_state->has_deleted_buffers = false;
  179. buffer_a = FindBuffer(*cpu_src_address, static_cast<u32>(amount));
  180. buffer_b = FindBuffer(*cpu_dest_address, static_cast<u32>(amount));
  181. } while (channel_state->has_deleted_buffers);
  182. auto& src_buffer = slot_buffers[buffer_a];
  183. auto& dest_buffer = slot_buffers[buffer_b];
  184. SynchronizeBuffer(src_buffer, *cpu_src_address, static_cast<u32>(amount));
  185. SynchronizeBuffer(dest_buffer, *cpu_dest_address, static_cast<u32>(amount));
  186. std::array copies{BufferCopy{
  187. .src_offset = src_buffer.Offset(*cpu_src_address),
  188. .dst_offset = dest_buffer.Offset(*cpu_dest_address),
  189. .size = amount,
  190. }};
  191. boost::container::small_vector<IntervalType, 4> tmp_intervals;
  192. auto mirror = [&](VAddr base_address, VAddr base_address_end) {
  193. const u64 size = base_address_end - base_address;
  194. const VAddr diff = base_address - *cpu_src_address;
  195. const VAddr new_base_address = *cpu_dest_address + diff;
  196. const IntervalType add_interval{new_base_address, new_base_address + size};
  197. tmp_intervals.push_back(add_interval);
  198. uncommitted_ranges.add(add_interval);
  199. };
  200. ForEachInRangeSet(common_ranges, *cpu_src_address, amount, mirror);
  201. // This subtraction in this order is important for overlapping copies.
  202. common_ranges.subtract(subtract_interval);
  203. const bool has_new_downloads = tmp_intervals.size() != 0;
  204. for (const IntervalType& add_interval : tmp_intervals) {
  205. common_ranges.add(add_interval);
  206. }
  207. runtime.CopyBuffer(dest_buffer, src_buffer, copies);
  208. if (has_new_downloads) {
  209. memory_tracker.MarkRegionAsGpuModified(*cpu_dest_address, amount);
  210. }
  211. Core::Memory::CpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::UnsafeReadWrite> tmp(
  212. cpu_memory, *cpu_src_address, amount, &tmp_buffer);
  213. tmp.SetAddressAndSize(*cpu_dest_address, amount);
  214. return true;
  215. }
  216. template <class P>
  217. bool BufferCache<P>::DMAClear(GPUVAddr dst_address, u64 amount, u32 value) {
  218. const std::optional<VAddr> cpu_dst_address = gpu_memory->GpuToCpuAddress(dst_address);
  219. if (!cpu_dst_address) {
  220. return false;
  221. }
  222. const bool dest_dirty = IsRegionRegistered(*cpu_dst_address, amount);
  223. if (!dest_dirty) {
  224. return false;
  225. }
  226. const size_t size = amount * sizeof(u32);
  227. const IntervalType subtract_interval{*cpu_dst_address, *cpu_dst_address + size};
  228. ClearDownload(subtract_interval);
  229. common_ranges.subtract(subtract_interval);
  230. const BufferId buffer = FindBuffer(*cpu_dst_address, static_cast<u32>(size));
  231. auto& dest_buffer = slot_buffers[buffer];
  232. const u32 offset = dest_buffer.Offset(*cpu_dst_address);
  233. runtime.ClearBuffer(dest_buffer, offset, size, value);
  234. return true;
  235. }
  236. template <class P>
  237. std::pair<typename P::Buffer*, u32> BufferCache<P>::ObtainBuffer(GPUVAddr gpu_addr, u32 size,
  238. ObtainBufferSynchronize sync_info,
  239. ObtainBufferOperation post_op) {
  240. const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr);
  241. if (!cpu_addr) {
  242. return {&slot_buffers[NULL_BUFFER_ID], 0};
  243. }
  244. const BufferId buffer_id = FindBuffer(*cpu_addr, size);
  245. Buffer& buffer = slot_buffers[buffer_id];
  246. // synchronize op
  247. switch (sync_info) {
  248. case ObtainBufferSynchronize::FullSynchronize:
  249. SynchronizeBuffer(buffer, *cpu_addr, size);
  250. break;
  251. default:
  252. break;
  253. }
  254. switch (post_op) {
  255. case ObtainBufferOperation::MarkAsWritten:
  256. MarkWrittenBuffer(buffer_id, *cpu_addr, size);
  257. break;
  258. case ObtainBufferOperation::DiscardWrite: {
  259. IntervalType interval{*cpu_addr, size};
  260. ClearDownload(interval);
  261. break;
  262. }
  263. default:
  264. break;
  265. }
  266. return {&buffer, buffer.Offset(*cpu_addr)};
  267. }
  268. template <class P>
  269. void BufferCache<P>::BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr,
  270. u32 size) {
  271. const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr);
  272. const Binding binding{
  273. .cpu_addr = *cpu_addr,
  274. .size = size,
  275. .buffer_id = BufferId{},
  276. };
  277. channel_state->uniform_buffers[stage][index] = binding;
  278. }
  279. template <class P>
  280. void BufferCache<P>::DisableGraphicsUniformBuffer(size_t stage, u32 index) {
  281. channel_state->uniform_buffers[stage][index] = NULL_BINDING;
  282. }
  283. template <class P>
  284. void BufferCache<P>::UpdateGraphicsBuffers(bool is_indexed) {
  285. MICROPROFILE_SCOPE(GPU_PrepareBuffers);
  286. do {
  287. channel_state->has_deleted_buffers = false;
  288. DoUpdateGraphicsBuffers(is_indexed);
  289. } while (channel_state->has_deleted_buffers);
  290. }
  291. template <class P>
  292. void BufferCache<P>::UpdateComputeBuffers() {
  293. MICROPROFILE_SCOPE(GPU_PrepareBuffers);
  294. do {
  295. channel_state->has_deleted_buffers = false;
  296. DoUpdateComputeBuffers();
  297. } while (channel_state->has_deleted_buffers);
  298. }
  299. template <class P>
  300. void BufferCache<P>::BindHostGeometryBuffers(bool is_indexed) {
  301. MICROPROFILE_SCOPE(GPU_BindUploadBuffers);
  302. if (is_indexed) {
  303. BindHostIndexBuffer();
  304. } else if constexpr (!HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) {
  305. const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
  306. if (draw_state.topology == Maxwell::PrimitiveTopology::Quads ||
  307. draw_state.topology == Maxwell::PrimitiveTopology::QuadStrip) {
  308. runtime.BindQuadIndexBuffer(draw_state.topology, draw_state.vertex_buffer.first,
  309. draw_state.vertex_buffer.count);
  310. }
  311. }
  312. BindHostVertexBuffers();
  313. BindHostTransformFeedbackBuffers();
  314. if (current_draw_indirect) {
  315. BindHostDrawIndirectBuffers();
  316. }
  317. }
  318. template <class P>
  319. void BufferCache<P>::BindHostStageBuffers(size_t stage) {
  320. MICROPROFILE_SCOPE(GPU_BindUploadBuffers);
  321. BindHostGraphicsUniformBuffers(stage);
  322. BindHostGraphicsStorageBuffers(stage);
  323. BindHostGraphicsTextureBuffers(stage);
  324. }
  325. template <class P>
  326. void BufferCache<P>::BindHostComputeBuffers() {
  327. MICROPROFILE_SCOPE(GPU_BindUploadBuffers);
  328. BindHostComputeUniformBuffers();
  329. BindHostComputeStorageBuffers();
  330. BindHostComputeTextureBuffers();
  331. }
  332. template <class P>
  333. void BufferCache<P>::SetUniformBuffersState(const std::array<u32, NUM_STAGES>& mask,
  334. const UniformBufferSizes* sizes) {
  335. if constexpr (HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS) {
  336. if (channel_state->enabled_uniform_buffer_masks != mask) {
  337. if constexpr (IS_OPENGL) {
  338. channel_state->fast_bound_uniform_buffers.fill(0);
  339. }
  340. channel_state->dirty_uniform_buffers.fill(~u32{0});
  341. channel_state->uniform_buffer_binding_sizes.fill({});
  342. }
  343. }
  344. channel_state->enabled_uniform_buffer_masks = mask;
  345. channel_state->uniform_buffer_sizes = sizes;
  346. }
  347. template <class P>
  348. void BufferCache<P>::SetComputeUniformBufferState(u32 mask,
  349. const ComputeUniformBufferSizes* sizes) {
  350. channel_state->enabled_compute_uniform_buffer_mask = mask;
  351. channel_state->compute_uniform_buffer_sizes = sizes;
  352. }
  353. template <class P>
  354. void BufferCache<P>::UnbindGraphicsStorageBuffers(size_t stage) {
  355. channel_state->enabled_storage_buffers[stage] = 0;
  356. channel_state->written_storage_buffers[stage] = 0;
  357. }
  358. template <class P>
  359. void BufferCache<P>::BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index, u32 cbuf_index,
  360. u32 cbuf_offset, bool is_written) {
  361. channel_state->enabled_storage_buffers[stage] |= 1U << ssbo_index;
  362. channel_state->written_storage_buffers[stage] |= (is_written ? 1U : 0U) << ssbo_index;
  363. const auto& cbufs = maxwell3d->state.shader_stages[stage];
  364. const GPUVAddr ssbo_addr = cbufs.const_buffers[cbuf_index].address + cbuf_offset;
  365. channel_state->storage_buffers[stage][ssbo_index] =
  366. StorageBufferBinding(ssbo_addr, cbuf_index, is_written);
  367. }
  368. template <class P>
  369. void BufferCache<P>::UnbindGraphicsTextureBuffers(size_t stage) {
  370. channel_state->enabled_texture_buffers[stage] = 0;
  371. channel_state->written_texture_buffers[stage] = 0;
  372. channel_state->image_texture_buffers[stage] = 0;
  373. }
  374. template <class P>
  375. void BufferCache<P>::BindGraphicsTextureBuffer(size_t stage, size_t tbo_index, GPUVAddr gpu_addr,
  376. u32 size, PixelFormat format, bool is_written,
  377. bool is_image) {
  378. channel_state->enabled_texture_buffers[stage] |= 1U << tbo_index;
  379. channel_state->written_texture_buffers[stage] |= (is_written ? 1U : 0U) << tbo_index;
  380. if constexpr (SEPARATE_IMAGE_BUFFERS_BINDINGS) {
  381. channel_state->image_texture_buffers[stage] |= (is_image ? 1U : 0U) << tbo_index;
  382. }
  383. channel_state->texture_buffers[stage][tbo_index] =
  384. GetTextureBufferBinding(gpu_addr, size, format);
  385. }
  386. template <class P>
  387. void BufferCache<P>::UnbindComputeStorageBuffers() {
  388. channel_state->enabled_compute_storage_buffers = 0;
  389. channel_state->written_compute_storage_buffers = 0;
  390. channel_state->image_compute_texture_buffers = 0;
  391. }
  392. template <class P>
  393. void BufferCache<P>::BindComputeStorageBuffer(size_t ssbo_index, u32 cbuf_index, u32 cbuf_offset,
  394. bool is_written) {
  395. if (ssbo_index >= channel_state->compute_storage_buffers.size()) [[unlikely]] {
  396. LOG_ERROR(HW_GPU, "Storage buffer index {} exceeds maximum storage buffer count",
  397. ssbo_index);
  398. return;
  399. }
  400. channel_state->enabled_compute_storage_buffers |= 1U << ssbo_index;
  401. channel_state->written_compute_storage_buffers |= (is_written ? 1U : 0U) << ssbo_index;
  402. const auto& launch_desc = kepler_compute->launch_description;
  403. ASSERT(((launch_desc.const_buffer_enable_mask >> cbuf_index) & 1) != 0);
  404. const auto& cbufs = launch_desc.const_buffer_config;
  405. const GPUVAddr ssbo_addr = cbufs[cbuf_index].Address() + cbuf_offset;
  406. channel_state->compute_storage_buffers[ssbo_index] =
  407. StorageBufferBinding(ssbo_addr, cbuf_index, is_written);
  408. }
  409. template <class P>
  410. void BufferCache<P>::UnbindComputeTextureBuffers() {
  411. channel_state->enabled_compute_texture_buffers = 0;
  412. channel_state->written_compute_texture_buffers = 0;
  413. channel_state->image_compute_texture_buffers = 0;
  414. }
  415. template <class P>
  416. void BufferCache<P>::BindComputeTextureBuffer(size_t tbo_index, GPUVAddr gpu_addr, u32 size,
  417. PixelFormat format, bool is_written, bool is_image) {
  418. if (tbo_index >= channel_state->compute_texture_buffers.size()) [[unlikely]] {
  419. LOG_ERROR(HW_GPU, "Texture buffer index {} exceeds maximum texture buffer count",
  420. tbo_index);
  421. return;
  422. }
  423. channel_state->enabled_compute_texture_buffers |= 1U << tbo_index;
  424. channel_state->written_compute_texture_buffers |= (is_written ? 1U : 0U) << tbo_index;
  425. if constexpr (SEPARATE_IMAGE_BUFFERS_BINDINGS) {
  426. channel_state->image_compute_texture_buffers |= (is_image ? 1U : 0U) << tbo_index;
  427. }
  428. channel_state->compute_texture_buffers[tbo_index] =
  429. GetTextureBufferBinding(gpu_addr, size, format);
  430. }
  431. template <class P>
  432. void BufferCache<P>::FlushCachedWrites() {
  433. memory_tracker.FlushCachedWrites();
  434. }
  435. template <class P>
  436. bool BufferCache<P>::HasUncommittedFlushes() const noexcept {
  437. return !uncommitted_ranges.empty() || !committed_ranges.empty();
  438. }
  439. template <class P>
  440. void BufferCache<P>::AccumulateFlushes() {
  441. if (uncommitted_ranges.empty()) {
  442. return;
  443. }
  444. committed_ranges.emplace_back(std::move(uncommitted_ranges));
  445. }
  446. template <class P>
  447. bool BufferCache<P>::ShouldWaitAsyncFlushes() const noexcept {
  448. if constexpr (IMPLEMENTS_ASYNC_DOWNLOADS) {
  449. return (!async_buffers.empty() && async_buffers.front().has_value());
  450. } else {
  451. return false;
  452. }
  453. }
  454. template <class P>
  455. void BufferCache<P>::CommitAsyncFlushesHigh() {
  456. AccumulateFlushes();
  457. if (committed_ranges.empty()) {
  458. if constexpr (IMPLEMENTS_ASYNC_DOWNLOADS) {
  459. async_buffers.emplace_back(std::optional<Async_Buffer>{});
  460. }
  461. return;
  462. }
  463. MICROPROFILE_SCOPE(GPU_DownloadMemory);
  464. auto it = committed_ranges.begin();
  465. while (it != committed_ranges.end()) {
  466. auto& current_intervals = *it;
  467. auto next_it = std::next(it);
  468. while (next_it != committed_ranges.end()) {
  469. for (auto& interval : *next_it) {
  470. current_intervals.subtract(interval);
  471. }
  472. next_it++;
  473. }
  474. it++;
  475. }
  476. boost::container::small_vector<std::pair<BufferCopy, BufferId>, 1> downloads;
  477. u64 total_size_bytes = 0;
  478. u64 largest_copy = 0;
  479. for (const IntervalSet& intervals : committed_ranges) {
  480. for (auto& interval : intervals) {
  481. const std::size_t size = interval.upper() - interval.lower();
  482. const VAddr cpu_addr = interval.lower();
  483. ForEachBufferInRange(cpu_addr, size, [&](BufferId buffer_id, Buffer& buffer) {
  484. const VAddr buffer_start = buffer.CpuAddr();
  485. const VAddr buffer_end = buffer_start + buffer.SizeBytes();
  486. const VAddr new_start = std::max(buffer_start, cpu_addr);
  487. const VAddr new_end = std::min(buffer_end, cpu_addr + size);
  488. memory_tracker.ForEachDownloadRange(
  489. new_start, new_end - new_start, false, [&](u64 cpu_addr_out, u64 range_size) {
  490. const VAddr buffer_addr = buffer.CpuAddr();
  491. const auto add_download = [&](VAddr start, VAddr end) {
  492. const u64 new_offset = start - buffer_addr;
  493. const u64 new_size = end - start;
  494. downloads.push_back({
  495. BufferCopy{
  496. .src_offset = new_offset,
  497. .dst_offset = total_size_bytes,
  498. .size = new_size,
  499. },
  500. buffer_id,
  501. });
  502. // Align up to avoid cache conflicts
  503. constexpr u64 align = 64ULL;
  504. constexpr u64 mask = ~(align - 1ULL);
  505. total_size_bytes += (new_size + align - 1) & mask;
  506. largest_copy = std::max(largest_copy, new_size);
  507. };
  508. ForEachInRangeSet(common_ranges, cpu_addr_out, range_size, add_download);
  509. });
  510. });
  511. }
  512. }
  513. committed_ranges.clear();
  514. if (downloads.empty()) {
  515. if constexpr (IMPLEMENTS_ASYNC_DOWNLOADS) {
  516. async_buffers.emplace_back(std::optional<Async_Buffer>{});
  517. }
  518. return;
  519. }
  520. if constexpr (IMPLEMENTS_ASYNC_DOWNLOADS) {
  521. auto download_staging = runtime.DownloadStagingBuffer(total_size_bytes, true);
  522. boost::container::small_vector<BufferCopy, 4> normalized_copies;
  523. IntervalSet new_async_range{};
  524. runtime.PreCopyBarrier();
  525. for (auto& [copy, buffer_id] : downloads) {
  526. copy.dst_offset += download_staging.offset;
  527. const std::array copies{copy};
  528. BufferCopy second_copy{copy};
  529. Buffer& buffer = slot_buffers[buffer_id];
  530. second_copy.src_offset = static_cast<size_t>(buffer.CpuAddr()) + copy.src_offset;
  531. VAddr orig_cpu_addr = static_cast<VAddr>(second_copy.src_offset);
  532. const IntervalType base_interval{orig_cpu_addr, orig_cpu_addr + copy.size};
  533. async_downloads += std::make_pair(base_interval, 1);
  534. runtime.CopyBuffer(download_staging.buffer, buffer, copies, false);
  535. normalized_copies.push_back(second_copy);
  536. }
  537. runtime.PostCopyBarrier();
  538. pending_downloads.emplace_back(std::move(normalized_copies));
  539. async_buffers.emplace_back(download_staging);
  540. } else {
  541. if (!Settings::IsGPULevelHigh()) {
  542. committed_ranges.clear();
  543. uncommitted_ranges.clear();
  544. } else {
  545. if constexpr (USE_MEMORY_MAPS) {
  546. auto download_staging = runtime.DownloadStagingBuffer(total_size_bytes);
  547. runtime.PreCopyBarrier();
  548. for (auto& [copy, buffer_id] : downloads) {
  549. // Have in mind the staging buffer offset for the copy
  550. copy.dst_offset += download_staging.offset;
  551. const std::array copies{copy};
  552. runtime.CopyBuffer(download_staging.buffer, slot_buffers[buffer_id], copies,
  553. false);
  554. }
  555. runtime.PostCopyBarrier();
  556. runtime.Finish();
  557. for (const auto& [copy, buffer_id] : downloads) {
  558. const Buffer& buffer = slot_buffers[buffer_id];
  559. const VAddr cpu_addr = buffer.CpuAddr() + copy.src_offset;
  560. // Undo the modified offset
  561. const u64 dst_offset = copy.dst_offset - download_staging.offset;
  562. const u8* read_mapped_memory = download_staging.mapped_span.data() + dst_offset;
  563. cpu_memory.WriteBlockUnsafe(cpu_addr, read_mapped_memory, copy.size);
  564. }
  565. } else {
  566. const std::span<u8> immediate_buffer = ImmediateBuffer(largest_copy);
  567. for (const auto& [copy, buffer_id] : downloads) {
  568. Buffer& buffer = slot_buffers[buffer_id];
  569. buffer.ImmediateDownload(copy.src_offset,
  570. immediate_buffer.subspan(0, copy.size));
  571. const VAddr cpu_addr = buffer.CpuAddr() + copy.src_offset;
  572. cpu_memory.WriteBlockUnsafe(cpu_addr, immediate_buffer.data(), copy.size);
  573. }
  574. }
  575. }
  576. }
  577. }
  578. template <class P>
  579. void BufferCache<P>::CommitAsyncFlushes() {
  580. CommitAsyncFlushesHigh();
  581. }
  582. template <class P>
  583. void BufferCache<P>::PopAsyncFlushes() {
  584. MICROPROFILE_SCOPE(GPU_DownloadMemory);
  585. PopAsyncBuffers();
  586. }
  587. template <class P>
  588. void BufferCache<P>::PopAsyncBuffers() {
  589. if (async_buffers.empty()) {
  590. return;
  591. }
  592. if (!async_buffers.front().has_value()) {
  593. async_buffers.pop_front();
  594. return;
  595. }
  596. if constexpr (IMPLEMENTS_ASYNC_DOWNLOADS) {
  597. auto& downloads = pending_downloads.front();
  598. auto& async_buffer = async_buffers.front();
  599. u8* base = async_buffer->mapped_span.data();
  600. const size_t base_offset = async_buffer->offset;
  601. for (const auto& copy : downloads) {
  602. const VAddr cpu_addr = static_cast<VAddr>(copy.src_offset);
  603. const u64 dst_offset = copy.dst_offset - base_offset;
  604. const u8* read_mapped_memory = base + dst_offset;
  605. ForEachInOverlapCounter(
  606. async_downloads, cpu_addr, copy.size, [&](VAddr start, VAddr end, int count) {
  607. cpu_memory.WriteBlockUnsafe(start, &read_mapped_memory[start - cpu_addr],
  608. end - start);
  609. if (count == 1) {
  610. const IntervalType base_interval{start, end};
  611. common_ranges.subtract(base_interval);
  612. }
  613. });
  614. const IntervalType subtract_interval{cpu_addr, cpu_addr + copy.size};
  615. RemoveEachInOverlapCounter(async_downloads, subtract_interval, -1);
  616. }
  617. async_buffers_death_ring.emplace_back(*async_buffer);
  618. async_buffers.pop_front();
  619. pending_downloads.pop_front();
  620. }
  621. }
  622. template <class P>
  623. bool BufferCache<P>::IsRegionGpuModified(VAddr addr, size_t size) {
  624. bool is_dirty = false;
  625. ForEachInRangeSet(common_ranges, addr, size, [&](VAddr, VAddr) { is_dirty = true; });
  626. return is_dirty;
  627. }
  628. template <class P>
  629. bool BufferCache<P>::IsRegionRegistered(VAddr addr, size_t size) {
  630. const VAddr end_addr = addr + size;
  631. const u64 page_end = Common::DivCeil(end_addr, CACHING_PAGESIZE);
  632. for (u64 page = addr >> CACHING_PAGEBITS; page < page_end;) {
  633. const BufferId buffer_id = page_table[page];
  634. if (!buffer_id) {
  635. ++page;
  636. continue;
  637. }
  638. Buffer& buffer = slot_buffers[buffer_id];
  639. const VAddr buf_start_addr = buffer.CpuAddr();
  640. const VAddr buf_end_addr = buf_start_addr + buffer.SizeBytes();
  641. if (buf_start_addr < end_addr && addr < buf_end_addr) {
  642. return true;
  643. }
  644. page = Common::DivCeil(end_addr, CACHING_PAGESIZE);
  645. }
  646. return false;
  647. }
  648. template <class P>
  649. bool BufferCache<P>::IsRegionCpuModified(VAddr addr, size_t size) {
  650. return memory_tracker.IsRegionCpuModified(addr, size);
  651. }
  652. template <class P>
  653. void BufferCache<P>::BindHostIndexBuffer() {
  654. Buffer& buffer = slot_buffers[channel_state->index_buffer.buffer_id];
  655. TouchBuffer(buffer, channel_state->index_buffer.buffer_id);
  656. const u32 offset = buffer.Offset(channel_state->index_buffer.cpu_addr);
  657. const u32 size = channel_state->index_buffer.size;
  658. const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
  659. if (!draw_state.inline_index_draw_indexes.empty()) [[unlikely]] {
  660. if constexpr (USE_MEMORY_MAPS_FOR_UPLOADS) {
  661. auto upload_staging = runtime.UploadStagingBuffer(size);
  662. std::array<BufferCopy, 1> copies{
  663. {BufferCopy{.src_offset = upload_staging.offset, .dst_offset = 0, .size = size}}};
  664. std::memcpy(upload_staging.mapped_span.data(),
  665. draw_state.inline_index_draw_indexes.data(), size);
  666. runtime.CopyBuffer(buffer, upload_staging.buffer, copies);
  667. } else {
  668. buffer.ImmediateUpload(0, draw_state.inline_index_draw_indexes);
  669. }
  670. } else {
  671. SynchronizeBuffer(buffer, channel_state->index_buffer.cpu_addr, size);
  672. }
  673. if constexpr (HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) {
  674. const u32 new_offset =
  675. offset + draw_state.index_buffer.first * draw_state.index_buffer.FormatSizeInBytes();
  676. runtime.BindIndexBuffer(buffer, new_offset, size);
  677. } else {
  678. runtime.BindIndexBuffer(draw_state.topology, draw_state.index_buffer.format,
  679. draw_state.index_buffer.first, draw_state.index_buffer.count,
  680. buffer, offset, size);
  681. }
  682. }
  683. template <class P>
  684. void BufferCache<P>::BindHostVertexBuffers() {
  685. HostBindings<typename P::Buffer> host_bindings;
  686. bool any_valid{false};
  687. auto& flags = maxwell3d->dirty.flags;
  688. for (u32 index = 0; index < NUM_VERTEX_BUFFERS; ++index) {
  689. const Binding& binding = channel_state->vertex_buffers[index];
  690. Buffer& buffer = slot_buffers[binding.buffer_id];
  691. TouchBuffer(buffer, binding.buffer_id);
  692. SynchronizeBuffer(buffer, binding.cpu_addr, binding.size);
  693. if (!flags[Dirty::VertexBuffer0 + index]) {
  694. continue;
  695. }
  696. flags[Dirty::VertexBuffer0 + index] = false;
  697. host_bindings.min_index = std::min(host_bindings.min_index, index);
  698. host_bindings.max_index = std::max(host_bindings.max_index, index);
  699. any_valid = true;
  700. }
  701. if (any_valid) {
  702. host_bindings.max_index++;
  703. for (u32 index = host_bindings.min_index; index < host_bindings.max_index; index++) {
  704. flags[Dirty::VertexBuffer0 + index] = false;
  705. const Binding& binding = channel_state->vertex_buffers[index];
  706. Buffer& buffer = slot_buffers[binding.buffer_id];
  707. const u32 stride = maxwell3d->regs.vertex_streams[index].stride;
  708. const u32 offset = buffer.Offset(binding.cpu_addr);
  709. host_bindings.buffers.push_back(&buffer);
  710. host_bindings.offsets.push_back(offset);
  711. host_bindings.sizes.push_back(binding.size);
  712. host_bindings.strides.push_back(stride);
  713. }
  714. runtime.BindVertexBuffers(host_bindings);
  715. }
  716. }
  717. template <class P>
  718. void BufferCache<P>::BindHostDrawIndirectBuffers() {
  719. const auto bind_buffer = [this](const Binding& binding) {
  720. Buffer& buffer = slot_buffers[binding.buffer_id];
  721. TouchBuffer(buffer, binding.buffer_id);
  722. SynchronizeBuffer(buffer, binding.cpu_addr, binding.size);
  723. };
  724. if (current_draw_indirect->include_count) {
  725. bind_buffer(channel_state->count_buffer_binding);
  726. }
  727. bind_buffer(channel_state->indirect_buffer_binding);
  728. }
  729. template <class P>
  730. void BufferCache<P>::BindHostGraphicsUniformBuffers(size_t stage) {
  731. u32 dirty = ~0U;
  732. if constexpr (HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS) {
  733. dirty = std::exchange(channel_state->dirty_uniform_buffers[stage], 0);
  734. }
  735. u32 binding_index = 0;
  736. ForEachEnabledBit(channel_state->enabled_uniform_buffer_masks[stage], [&](u32 index) {
  737. const bool needs_bind = ((dirty >> index) & 1) != 0;
  738. BindHostGraphicsUniformBuffer(stage, index, binding_index, needs_bind);
  739. if constexpr (NEEDS_BIND_UNIFORM_INDEX) {
  740. ++binding_index;
  741. }
  742. });
  743. }
  744. template <class P>
  745. void BufferCache<P>::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32 binding_index,
  746. bool needs_bind) {
  747. const Binding& binding = channel_state->uniform_buffers[stage][index];
  748. const VAddr cpu_addr = binding.cpu_addr;
  749. const u32 size = std::min(binding.size, (*channel_state->uniform_buffer_sizes)[stage][index]);
  750. Buffer& buffer = slot_buffers[binding.buffer_id];
  751. TouchBuffer(buffer, binding.buffer_id);
  752. const bool use_fast_buffer = binding.buffer_id != NULL_BUFFER_ID &&
  753. size <= channel_state->uniform_buffer_skip_cache_size &&
  754. !memory_tracker.IsRegionGpuModified(cpu_addr, size);
  755. if (use_fast_buffer) {
  756. if constexpr (IS_OPENGL) {
  757. if (runtime.HasFastBufferSubData()) {
  758. // Fast path for Nvidia
  759. const bool should_fast_bind =
  760. !HasFastUniformBufferBound(stage, binding_index) ||
  761. channel_state->uniform_buffer_binding_sizes[stage][binding_index] != size;
  762. if (should_fast_bind) {
  763. // We only have to bind when the currently bound buffer is not the fast version
  764. channel_state->fast_bound_uniform_buffers[stage] |= 1U << binding_index;
  765. channel_state->uniform_buffer_binding_sizes[stage][binding_index] = size;
  766. runtime.BindFastUniformBuffer(stage, binding_index, size);
  767. }
  768. const auto span = ImmediateBufferWithData(cpu_addr, size);
  769. runtime.PushFastUniformBuffer(stage, binding_index, span);
  770. return;
  771. }
  772. }
  773. if constexpr (IS_OPENGL) {
  774. channel_state->fast_bound_uniform_buffers[stage] |= 1U << binding_index;
  775. channel_state->uniform_buffer_binding_sizes[stage][binding_index] = size;
  776. }
  777. // Stream buffer path to avoid stalling on non-Nvidia drivers or Vulkan
  778. const std::span<u8> span = runtime.BindMappedUniformBuffer(stage, binding_index, size);
  779. cpu_memory.ReadBlockUnsafe(cpu_addr, span.data(), size);
  780. return;
  781. }
  782. // Classic cached path
  783. const bool sync_cached = SynchronizeBuffer(buffer, cpu_addr, size);
  784. if (sync_cached) {
  785. ++channel_state->uniform_cache_hits[0];
  786. }
  787. ++channel_state->uniform_cache_shots[0];
  788. // Skip binding if it's not needed and if the bound buffer is not the fast version
  789. // This exists to avoid instances where the fast buffer is bound and a GPU write happens
  790. needs_bind |= HasFastUniformBufferBound(stage, binding_index);
  791. if constexpr (HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS) {
  792. needs_bind |= channel_state->uniform_buffer_binding_sizes[stage][binding_index] != size;
  793. }
  794. if (!needs_bind) {
  795. return;
  796. }
  797. const u32 offset = buffer.Offset(cpu_addr);
  798. if constexpr (IS_OPENGL) {
  799. // Fast buffer will be unbound
  800. channel_state->fast_bound_uniform_buffers[stage] &= ~(1U << binding_index);
  801. // Mark the index as dirty if offset doesn't match
  802. const bool is_copy_bind = offset != 0 && !runtime.SupportsNonZeroUniformOffset();
  803. channel_state->dirty_uniform_buffers[stage] |= (is_copy_bind ? 1U : 0U) << index;
  804. }
  805. if constexpr (HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS) {
  806. channel_state->uniform_buffer_binding_sizes[stage][binding_index] = size;
  807. }
  808. if constexpr (NEEDS_BIND_UNIFORM_INDEX) {
  809. runtime.BindUniformBuffer(stage, binding_index, buffer, offset, size);
  810. } else {
  811. runtime.BindUniformBuffer(buffer, offset, size);
  812. }
  813. }
  814. template <class P>
  815. void BufferCache<P>::BindHostGraphicsStorageBuffers(size_t stage) {
  816. u32 binding_index = 0;
  817. ForEachEnabledBit(channel_state->enabled_storage_buffers[stage], [&](u32 index) {
  818. const Binding& binding = channel_state->storage_buffers[stage][index];
  819. Buffer& buffer = slot_buffers[binding.buffer_id];
  820. TouchBuffer(buffer, binding.buffer_id);
  821. const u32 size = binding.size;
  822. SynchronizeBuffer(buffer, binding.cpu_addr, size);
  823. const u32 offset = buffer.Offset(binding.cpu_addr);
  824. const bool is_written = ((channel_state->written_storage_buffers[stage] >> index) & 1) != 0;
  825. if constexpr (NEEDS_BIND_STORAGE_INDEX) {
  826. runtime.BindStorageBuffer(stage, binding_index, buffer, offset, size, is_written);
  827. ++binding_index;
  828. } else {
  829. runtime.BindStorageBuffer(buffer, offset, size, is_written);
  830. }
  831. });
  832. }
  833. template <class P>
  834. void BufferCache<P>::BindHostGraphicsTextureBuffers(size_t stage) {
  835. ForEachEnabledBit(channel_state->enabled_texture_buffers[stage], [&](u32 index) {
  836. const TextureBufferBinding& binding = channel_state->texture_buffers[stage][index];
  837. Buffer& buffer = slot_buffers[binding.buffer_id];
  838. const u32 size = binding.size;
  839. SynchronizeBuffer(buffer, binding.cpu_addr, size);
  840. const u32 offset = buffer.Offset(binding.cpu_addr);
  841. const PixelFormat format = binding.format;
  842. if constexpr (SEPARATE_IMAGE_BUFFERS_BINDINGS) {
  843. if (((channel_state->image_texture_buffers[stage] >> index) & 1) != 0) {
  844. runtime.BindImageBuffer(buffer, offset, size, format);
  845. } else {
  846. runtime.BindTextureBuffer(buffer, offset, size, format);
  847. }
  848. } else {
  849. runtime.BindTextureBuffer(buffer, offset, size, format);
  850. }
  851. });
  852. }
  853. template <class P>
  854. void BufferCache<P>::BindHostTransformFeedbackBuffers() {
  855. if (maxwell3d->regs.transform_feedback_enabled == 0) {
  856. return;
  857. }
  858. HostBindings<typename P::Buffer> host_bindings;
  859. for (u32 index = 0; index < NUM_TRANSFORM_FEEDBACK_BUFFERS; ++index) {
  860. const Binding& binding = channel_state->transform_feedback_buffers[index];
  861. if (maxwell3d->regs.transform_feedback.controls[index].varying_count == 0 &&
  862. maxwell3d->regs.transform_feedback.controls[index].stride == 0) {
  863. break;
  864. }
  865. Buffer& buffer = slot_buffers[binding.buffer_id];
  866. TouchBuffer(buffer, binding.buffer_id);
  867. const u32 size = binding.size;
  868. SynchronizeBuffer(buffer, binding.cpu_addr, size);
  869. const u32 offset = buffer.Offset(binding.cpu_addr);
  870. host_bindings.buffers.push_back(&buffer);
  871. host_bindings.offsets.push_back(offset);
  872. host_bindings.sizes.push_back(binding.size);
  873. }
  874. if (host_bindings.buffers.size() > 0) {
  875. runtime.BindTransformFeedbackBuffers(host_bindings);
  876. }
  877. }
  878. template <class P>
  879. void BufferCache<P>::BindHostComputeUniformBuffers() {
  880. if constexpr (HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS) {
  881. // Mark all uniform buffers as dirty
  882. channel_state->dirty_uniform_buffers.fill(~u32{0});
  883. channel_state->fast_bound_uniform_buffers.fill(0);
  884. }
  885. u32 binding_index = 0;
  886. ForEachEnabledBit(channel_state->enabled_compute_uniform_buffer_mask, [&](u32 index) {
  887. const Binding& binding = channel_state->compute_uniform_buffers[index];
  888. Buffer& buffer = slot_buffers[binding.buffer_id];
  889. TouchBuffer(buffer, binding.buffer_id);
  890. const u32 size =
  891. std::min(binding.size, (*channel_state->compute_uniform_buffer_sizes)[index]);
  892. SynchronizeBuffer(buffer, binding.cpu_addr, size);
  893. const u32 offset = buffer.Offset(binding.cpu_addr);
  894. if constexpr (NEEDS_BIND_UNIFORM_INDEX) {
  895. runtime.BindComputeUniformBuffer(binding_index, buffer, offset, size);
  896. ++binding_index;
  897. } else {
  898. runtime.BindUniformBuffer(buffer, offset, size);
  899. }
  900. });
  901. }
  902. template <class P>
  903. void BufferCache<P>::BindHostComputeStorageBuffers() {
  904. u32 binding_index = 0;
  905. ForEachEnabledBit(channel_state->enabled_compute_storage_buffers, [&](u32 index) {
  906. const Binding& binding = channel_state->compute_storage_buffers[index];
  907. Buffer& buffer = slot_buffers[binding.buffer_id];
  908. TouchBuffer(buffer, binding.buffer_id);
  909. const u32 size = binding.size;
  910. SynchronizeBuffer(buffer, binding.cpu_addr, size);
  911. const u32 offset = buffer.Offset(binding.cpu_addr);
  912. const bool is_written =
  913. ((channel_state->written_compute_storage_buffers >> index) & 1) != 0;
  914. if constexpr (NEEDS_BIND_STORAGE_INDEX) {
  915. runtime.BindComputeStorageBuffer(binding_index, buffer, offset, size, is_written);
  916. ++binding_index;
  917. } else {
  918. runtime.BindStorageBuffer(buffer, offset, size, is_written);
  919. }
  920. });
  921. }
  922. template <class P>
  923. void BufferCache<P>::BindHostComputeTextureBuffers() {
  924. ForEachEnabledBit(channel_state->enabled_compute_texture_buffers, [&](u32 index) {
  925. const TextureBufferBinding& binding = channel_state->compute_texture_buffers[index];
  926. Buffer& buffer = slot_buffers[binding.buffer_id];
  927. const u32 size = binding.size;
  928. SynchronizeBuffer(buffer, binding.cpu_addr, size);
  929. const u32 offset = buffer.Offset(binding.cpu_addr);
  930. const PixelFormat format = binding.format;
  931. if constexpr (SEPARATE_IMAGE_BUFFERS_BINDINGS) {
  932. if (((channel_state->image_compute_texture_buffers >> index) & 1) != 0) {
  933. runtime.BindImageBuffer(buffer, offset, size, format);
  934. } else {
  935. runtime.BindTextureBuffer(buffer, offset, size, format);
  936. }
  937. } else {
  938. runtime.BindTextureBuffer(buffer, offset, size, format);
  939. }
  940. });
  941. }
  942. template <class P>
  943. void BufferCache<P>::DoUpdateGraphicsBuffers(bool is_indexed) {
  944. do {
  945. channel_state->has_deleted_buffers = false;
  946. if (is_indexed) {
  947. UpdateIndexBuffer();
  948. }
  949. UpdateVertexBuffers();
  950. UpdateTransformFeedbackBuffers();
  951. for (size_t stage = 0; stage < NUM_STAGES; ++stage) {
  952. UpdateUniformBuffers(stage);
  953. UpdateStorageBuffers(stage);
  954. UpdateTextureBuffers(stage);
  955. }
  956. if (current_draw_indirect) {
  957. UpdateDrawIndirect();
  958. }
  959. } while (channel_state->has_deleted_buffers);
  960. }
  961. template <class P>
  962. void BufferCache<P>::DoUpdateComputeBuffers() {
  963. UpdateComputeUniformBuffers();
  964. UpdateComputeStorageBuffers();
  965. UpdateComputeTextureBuffers();
  966. }
  967. template <class P>
  968. void BufferCache<P>::UpdateIndexBuffer() {
  969. // We have to check for the dirty flags and index count
  970. // The index count is currently changed without updating the dirty flags
  971. const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
  972. const auto& index_buffer_ref = draw_state.index_buffer;
  973. auto& flags = maxwell3d->dirty.flags;
  974. if (!flags[Dirty::IndexBuffer]) {
  975. return;
  976. }
  977. flags[Dirty::IndexBuffer] = false;
  978. if (!draw_state.inline_index_draw_indexes.empty()) [[unlikely]] {
  979. auto inline_index_size = static_cast<u32>(draw_state.inline_index_draw_indexes.size());
  980. u32 buffer_size = Common::AlignUp(inline_index_size, CACHING_PAGESIZE);
  981. if (inline_buffer_id == NULL_BUFFER_ID) [[unlikely]] {
  982. inline_buffer_id = CreateBuffer(0, buffer_size);
  983. }
  984. if (slot_buffers[inline_buffer_id].SizeBytes() < buffer_size) [[unlikely]] {
  985. slot_buffers.erase(inline_buffer_id);
  986. inline_buffer_id = CreateBuffer(0, buffer_size);
  987. }
  988. channel_state->index_buffer = Binding{
  989. .cpu_addr = 0,
  990. .size = inline_index_size,
  991. .buffer_id = inline_buffer_id,
  992. };
  993. return;
  994. }
  995. const GPUVAddr gpu_addr_begin = index_buffer_ref.StartAddress();
  996. const GPUVAddr gpu_addr_end = index_buffer_ref.EndAddress();
  997. const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr_begin);
  998. const u32 address_size = static_cast<u32>(gpu_addr_end - gpu_addr_begin);
  999. const u32 draw_size =
  1000. (index_buffer_ref.count + index_buffer_ref.first) * index_buffer_ref.FormatSizeInBytes();
  1001. const u32 size = std::min(address_size, draw_size);
  1002. if (size == 0 || !cpu_addr) {
  1003. channel_state->index_buffer = NULL_BINDING;
  1004. return;
  1005. }
  1006. channel_state->index_buffer = Binding{
  1007. .cpu_addr = *cpu_addr,
  1008. .size = size,
  1009. .buffer_id = FindBuffer(*cpu_addr, size),
  1010. };
  1011. }
  1012. template <class P>
  1013. void BufferCache<P>::UpdateVertexBuffers() {
  1014. auto& flags = maxwell3d->dirty.flags;
  1015. if (!maxwell3d->dirty.flags[Dirty::VertexBuffers]) {
  1016. return;
  1017. }
  1018. flags[Dirty::VertexBuffers] = false;
  1019. for (u32 index = 0; index < NUM_VERTEX_BUFFERS; ++index) {
  1020. UpdateVertexBuffer(index);
  1021. }
  1022. }
  1023. template <class P>
  1024. void BufferCache<P>::UpdateVertexBuffer(u32 index) {
  1025. if (!maxwell3d->dirty.flags[Dirty::VertexBuffer0 + index]) {
  1026. return;
  1027. }
  1028. const auto& array = maxwell3d->regs.vertex_streams[index];
  1029. const auto& limit = maxwell3d->regs.vertex_stream_limits[index];
  1030. const GPUVAddr gpu_addr_begin = array.Address();
  1031. const GPUVAddr gpu_addr_end = limit.Address() + 1;
  1032. const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr_begin);
  1033. const u32 address_size = static_cast<u32>(gpu_addr_end - gpu_addr_begin);
  1034. u32 size = address_size; // TODO: Analyze stride and number of vertices
  1035. if (array.enable == 0 || size == 0 || !cpu_addr) {
  1036. channel_state->vertex_buffers[index] = NULL_BINDING;
  1037. return;
  1038. }
  1039. if (!gpu_memory->IsWithinGPUAddressRange(gpu_addr_end)) {
  1040. size = static_cast<u32>(gpu_memory->MaxContinuousRange(gpu_addr_begin, size));
  1041. }
  1042. channel_state->vertex_buffers[index] = Binding{
  1043. .cpu_addr = *cpu_addr,
  1044. .size = size,
  1045. .buffer_id = FindBuffer(*cpu_addr, size),
  1046. };
  1047. }
  1048. template <class P>
  1049. void BufferCache<P>::UpdateDrawIndirect() {
  1050. const auto update = [this](GPUVAddr gpu_addr, size_t size, Binding& binding) {
  1051. const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr);
  1052. if (!cpu_addr) {
  1053. binding = NULL_BINDING;
  1054. return;
  1055. }
  1056. binding = Binding{
  1057. .cpu_addr = *cpu_addr,
  1058. .size = static_cast<u32>(size),
  1059. .buffer_id = FindBuffer(*cpu_addr, static_cast<u32>(size)),
  1060. };
  1061. };
  1062. if (current_draw_indirect->include_count) {
  1063. update(current_draw_indirect->count_start_address, sizeof(u32),
  1064. channel_state->count_buffer_binding);
  1065. }
  1066. update(current_draw_indirect->indirect_start_address, current_draw_indirect->buffer_size,
  1067. channel_state->indirect_buffer_binding);
  1068. }
  1069. template <class P>
  1070. void BufferCache<P>::UpdateUniformBuffers(size_t stage) {
  1071. ForEachEnabledBit(channel_state->enabled_uniform_buffer_masks[stage], [&](u32 index) {
  1072. Binding& binding = channel_state->uniform_buffers[stage][index];
  1073. if (binding.buffer_id) {
  1074. // Already updated
  1075. return;
  1076. }
  1077. // Mark as dirty
  1078. if constexpr (HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS) {
  1079. channel_state->dirty_uniform_buffers[stage] |= 1U << index;
  1080. }
  1081. // Resolve buffer
  1082. binding.buffer_id = FindBuffer(binding.cpu_addr, binding.size);
  1083. });
  1084. }
  1085. template <class P>
  1086. void BufferCache<P>::UpdateStorageBuffers(size_t stage) {
  1087. const u32 written_mask = channel_state->written_storage_buffers[stage];
  1088. ForEachEnabledBit(channel_state->enabled_storage_buffers[stage], [&](u32 index) {
  1089. // Resolve buffer
  1090. Binding& binding = channel_state->storage_buffers[stage][index];
  1091. const BufferId buffer_id = FindBuffer(binding.cpu_addr, binding.size);
  1092. binding.buffer_id = buffer_id;
  1093. // Mark buffer as written if needed
  1094. if (((written_mask >> index) & 1) != 0) {
  1095. MarkWrittenBuffer(buffer_id, binding.cpu_addr, binding.size);
  1096. }
  1097. });
  1098. }
  1099. template <class P>
  1100. void BufferCache<P>::UpdateTextureBuffers(size_t stage) {
  1101. ForEachEnabledBit(channel_state->enabled_texture_buffers[stage], [&](u32 index) {
  1102. Binding& binding = channel_state->texture_buffers[stage][index];
  1103. binding.buffer_id = FindBuffer(binding.cpu_addr, binding.size);
  1104. // Mark buffer as written if needed
  1105. if (((channel_state->written_texture_buffers[stage] >> index) & 1) != 0) {
  1106. MarkWrittenBuffer(binding.buffer_id, binding.cpu_addr, binding.size);
  1107. }
  1108. });
  1109. }
  1110. template <class P>
  1111. void BufferCache<P>::UpdateTransformFeedbackBuffers() {
  1112. if (maxwell3d->regs.transform_feedback_enabled == 0) {
  1113. return;
  1114. }
  1115. for (u32 index = 0; index < NUM_TRANSFORM_FEEDBACK_BUFFERS; ++index) {
  1116. UpdateTransformFeedbackBuffer(index);
  1117. }
  1118. }
  1119. template <class P>
  1120. void BufferCache<P>::UpdateTransformFeedbackBuffer(u32 index) {
  1121. const auto& binding = maxwell3d->regs.transform_feedback.buffers[index];
  1122. const GPUVAddr gpu_addr = binding.Address() + binding.start_offset;
  1123. const u32 size = binding.size;
  1124. const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr);
  1125. if (binding.enable == 0 || size == 0 || !cpu_addr) {
  1126. channel_state->transform_feedback_buffers[index] = NULL_BINDING;
  1127. return;
  1128. }
  1129. const BufferId buffer_id = FindBuffer(*cpu_addr, size);
  1130. channel_state->transform_feedback_buffers[index] = Binding{
  1131. .cpu_addr = *cpu_addr,
  1132. .size = size,
  1133. .buffer_id = buffer_id,
  1134. };
  1135. MarkWrittenBuffer(buffer_id, *cpu_addr, size);
  1136. }
  1137. template <class P>
  1138. void BufferCache<P>::UpdateComputeUniformBuffers() {
  1139. ForEachEnabledBit(channel_state->enabled_compute_uniform_buffer_mask, [&](u32 index) {
  1140. Binding& binding = channel_state->compute_uniform_buffers[index];
  1141. binding = NULL_BINDING;
  1142. const auto& launch_desc = kepler_compute->launch_description;
  1143. if (((launch_desc.const_buffer_enable_mask >> index) & 1) != 0) {
  1144. const auto& cbuf = launch_desc.const_buffer_config[index];
  1145. const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(cbuf.Address());
  1146. if (cpu_addr) {
  1147. binding.cpu_addr = *cpu_addr;
  1148. binding.size = cbuf.size;
  1149. }
  1150. }
  1151. binding.buffer_id = FindBuffer(binding.cpu_addr, binding.size);
  1152. });
  1153. }
  1154. template <class P>
  1155. void BufferCache<P>::UpdateComputeStorageBuffers() {
  1156. ForEachEnabledBit(channel_state->enabled_compute_storage_buffers, [&](u32 index) {
  1157. // Resolve buffer
  1158. Binding& binding = channel_state->compute_storage_buffers[index];
  1159. binding.buffer_id = FindBuffer(binding.cpu_addr, binding.size);
  1160. // Mark as written if needed
  1161. if (((channel_state->written_compute_storage_buffers >> index) & 1) != 0) {
  1162. MarkWrittenBuffer(binding.buffer_id, binding.cpu_addr, binding.size);
  1163. }
  1164. });
  1165. }
  1166. template <class P>
  1167. void BufferCache<P>::UpdateComputeTextureBuffers() {
  1168. ForEachEnabledBit(channel_state->enabled_compute_texture_buffers, [&](u32 index) {
  1169. Binding& binding = channel_state->compute_texture_buffers[index];
  1170. binding.buffer_id = FindBuffer(binding.cpu_addr, binding.size);
  1171. // Mark as written if needed
  1172. if (((channel_state->written_compute_texture_buffers >> index) & 1) != 0) {
  1173. MarkWrittenBuffer(binding.buffer_id, binding.cpu_addr, binding.size);
  1174. }
  1175. });
  1176. }
  1177. template <class P>
  1178. void BufferCache<P>::MarkWrittenBuffer(BufferId buffer_id, VAddr cpu_addr, u32 size) {
  1179. if (memory_tracker.IsRegionCpuModified(cpu_addr, size)) {
  1180. SynchronizeBuffer(slot_buffers[buffer_id], cpu_addr, size);
  1181. }
  1182. memory_tracker.MarkRegionAsGpuModified(cpu_addr, size);
  1183. const IntervalType base_interval{cpu_addr, cpu_addr + size};
  1184. common_ranges.add(base_interval);
  1185. uncommitted_ranges.add(base_interval);
  1186. }
  1187. template <class P>
  1188. BufferId BufferCache<P>::FindBuffer(VAddr cpu_addr, u32 size) {
  1189. if (cpu_addr == 0) {
  1190. return NULL_BUFFER_ID;
  1191. }
  1192. const u64 page = cpu_addr >> CACHING_PAGEBITS;
  1193. const BufferId buffer_id = page_table[page];
  1194. if (!buffer_id) {
  1195. return CreateBuffer(cpu_addr, size);
  1196. }
  1197. const Buffer& buffer = slot_buffers[buffer_id];
  1198. if (buffer.IsInBounds(cpu_addr, size)) {
  1199. return buffer_id;
  1200. }
  1201. return CreateBuffer(cpu_addr, size);
  1202. }
  1203. template <class P>
  1204. typename BufferCache<P>::OverlapResult BufferCache<P>::ResolveOverlaps(VAddr cpu_addr,
  1205. u32 wanted_size) {
  1206. static constexpr int STREAM_LEAP_THRESHOLD = 16;
  1207. boost::container::small_vector<BufferId, 16> overlap_ids;
  1208. VAddr begin = cpu_addr;
  1209. VAddr end = cpu_addr + wanted_size;
  1210. int stream_score = 0;
  1211. bool has_stream_leap = false;
  1212. if (begin == 0) {
  1213. return OverlapResult{
  1214. .ids = std::move(overlap_ids),
  1215. .begin = begin,
  1216. .end = end,
  1217. .has_stream_leap = has_stream_leap,
  1218. };
  1219. }
  1220. for (; cpu_addr >> CACHING_PAGEBITS < Common::DivCeil(end, CACHING_PAGESIZE);
  1221. cpu_addr += CACHING_PAGESIZE) {
  1222. const BufferId overlap_id = page_table[cpu_addr >> CACHING_PAGEBITS];
  1223. if (!overlap_id) {
  1224. continue;
  1225. }
  1226. Buffer& overlap = slot_buffers[overlap_id];
  1227. if (overlap.IsPicked()) {
  1228. continue;
  1229. }
  1230. overlap_ids.push_back(overlap_id);
  1231. overlap.Pick();
  1232. const VAddr overlap_cpu_addr = overlap.CpuAddr();
  1233. const bool expands_left = overlap_cpu_addr < begin;
  1234. if (expands_left) {
  1235. begin = overlap_cpu_addr;
  1236. }
  1237. const VAddr overlap_end = overlap_cpu_addr + overlap.SizeBytes();
  1238. const bool expands_right = overlap_end > end;
  1239. if (overlap_end > end) {
  1240. end = overlap_end;
  1241. }
  1242. stream_score += overlap.StreamScore();
  1243. if (stream_score > STREAM_LEAP_THRESHOLD && !has_stream_leap) {
  1244. // When this memory region has been joined a bunch of times, we assume it's being used
  1245. // as a stream buffer. Increase the size to skip constantly recreating buffers.
  1246. has_stream_leap = true;
  1247. if (expands_right) {
  1248. begin -= CACHING_PAGESIZE * 256;
  1249. cpu_addr = begin - CACHING_PAGESIZE;
  1250. }
  1251. if (expands_left) {
  1252. end += CACHING_PAGESIZE * 256;
  1253. }
  1254. }
  1255. }
  1256. return OverlapResult{
  1257. .ids = std::move(overlap_ids),
  1258. .begin = begin,
  1259. .end = end,
  1260. .has_stream_leap = has_stream_leap,
  1261. };
  1262. }
  1263. template <class P>
  1264. void BufferCache<P>::JoinOverlap(BufferId new_buffer_id, BufferId overlap_id,
  1265. bool accumulate_stream_score) {
  1266. Buffer& new_buffer = slot_buffers[new_buffer_id];
  1267. Buffer& overlap = slot_buffers[overlap_id];
  1268. if (accumulate_stream_score) {
  1269. new_buffer.IncreaseStreamScore(overlap.StreamScore() + 1);
  1270. }
  1271. boost::container::small_vector<BufferCopy, 10> copies;
  1272. const size_t dst_base_offset = overlap.CpuAddr() - new_buffer.CpuAddr();
  1273. copies.push_back(BufferCopy{
  1274. .src_offset = 0,
  1275. .dst_offset = dst_base_offset,
  1276. .size = overlap.SizeBytes(),
  1277. });
  1278. runtime.CopyBuffer(new_buffer, overlap, copies);
  1279. DeleteBuffer(overlap_id, true);
  1280. }
  1281. template <class P>
  1282. BufferId BufferCache<P>::CreateBuffer(VAddr cpu_addr, u32 wanted_size) {
  1283. VAddr cpu_addr_end = Common::AlignUp(cpu_addr + wanted_size, CACHING_PAGESIZE);
  1284. cpu_addr = Common::AlignDown(cpu_addr, CACHING_PAGESIZE);
  1285. wanted_size = static_cast<u32>(cpu_addr_end - cpu_addr);
  1286. const OverlapResult overlap = ResolveOverlaps(cpu_addr, wanted_size);
  1287. const u32 size = static_cast<u32>(overlap.end - overlap.begin);
  1288. const BufferId new_buffer_id = slot_buffers.insert(runtime, rasterizer, overlap.begin, size);
  1289. auto& new_buffer = slot_buffers[new_buffer_id];
  1290. runtime.ClearBuffer(new_buffer, 0, new_buffer.SizeBytes(), 0);
  1291. for (const BufferId overlap_id : overlap.ids) {
  1292. JoinOverlap(new_buffer_id, overlap_id, !overlap.has_stream_leap);
  1293. }
  1294. Register(new_buffer_id);
  1295. TouchBuffer(new_buffer, new_buffer_id);
  1296. return new_buffer_id;
  1297. }
  1298. template <class P>
  1299. void BufferCache<P>::Register(BufferId buffer_id) {
  1300. ChangeRegister<true>(buffer_id);
  1301. }
  1302. template <class P>
  1303. void BufferCache<P>::Unregister(BufferId buffer_id) {
  1304. ChangeRegister<false>(buffer_id);
  1305. }
  1306. template <class P>
  1307. template <bool insert>
  1308. void BufferCache<P>::ChangeRegister(BufferId buffer_id) {
  1309. Buffer& buffer = slot_buffers[buffer_id];
  1310. const auto size = buffer.SizeBytes();
  1311. if (insert) {
  1312. total_used_memory += Common::AlignUp(size, 1024);
  1313. buffer.setLRUID(lru_cache.Insert(buffer_id, frame_tick));
  1314. } else {
  1315. total_used_memory -= Common::AlignUp(size, 1024);
  1316. lru_cache.Free(buffer.getLRUID());
  1317. }
  1318. const VAddr cpu_addr_begin = buffer.CpuAddr();
  1319. const VAddr cpu_addr_end = cpu_addr_begin + size;
  1320. const u64 page_begin = cpu_addr_begin / CACHING_PAGESIZE;
  1321. const u64 page_end = Common::DivCeil(cpu_addr_end, CACHING_PAGESIZE);
  1322. for (u64 page = page_begin; page != page_end; ++page) {
  1323. if constexpr (insert) {
  1324. page_table[page] = buffer_id;
  1325. } else {
  1326. page_table[page] = BufferId{};
  1327. }
  1328. }
  1329. }
  1330. template <class P>
  1331. void BufferCache<P>::TouchBuffer(Buffer& buffer, BufferId buffer_id) noexcept {
  1332. if (buffer_id != NULL_BUFFER_ID) {
  1333. lru_cache.Touch(buffer.getLRUID(), frame_tick);
  1334. }
  1335. }
  1336. template <class P>
  1337. bool BufferCache<P>::SynchronizeBuffer(Buffer& buffer, VAddr cpu_addr, u32 size) {
  1338. return SynchronizeBufferImpl(buffer, cpu_addr, size);
  1339. }
  1340. template <class P>
  1341. bool BufferCache<P>::SynchronizeBufferImpl(Buffer& buffer, VAddr cpu_addr, u32 size) {
  1342. boost::container::small_vector<BufferCopy, 4> copies;
  1343. u64 total_size_bytes = 0;
  1344. u64 largest_copy = 0;
  1345. VAddr buffer_start = buffer.CpuAddr();
  1346. memory_tracker.ForEachUploadRange(cpu_addr, size, [&](u64 cpu_addr_out, u64 range_size) {
  1347. copies.push_back(BufferCopy{
  1348. .src_offset = total_size_bytes,
  1349. .dst_offset = cpu_addr_out - buffer_start,
  1350. .size = range_size,
  1351. });
  1352. total_size_bytes += range_size;
  1353. largest_copy = std::max(largest_copy, range_size);
  1354. });
  1355. if (total_size_bytes == 0) {
  1356. return true;
  1357. }
  1358. const std::span<BufferCopy> copies_span(copies.data(), copies.size());
  1359. UploadMemory(buffer, total_size_bytes, largest_copy, copies_span);
  1360. return false;
  1361. }
  1362. template <class P>
  1363. bool BufferCache<P>::SynchronizeBufferNoModified(Buffer& buffer, VAddr cpu_addr, u32 size) {
  1364. boost::container::small_vector<BufferCopy, 4> copies;
  1365. u64 total_size_bytes = 0;
  1366. u64 largest_copy = 0;
  1367. IntervalSet found_sets{};
  1368. auto make_copies = [&] {
  1369. for (auto& interval : found_sets) {
  1370. const std::size_t sub_size = interval.upper() - interval.lower();
  1371. const VAddr cpu_addr_ = interval.lower();
  1372. copies.push_back(BufferCopy{
  1373. .src_offset = total_size_bytes,
  1374. .dst_offset = cpu_addr_ - buffer.CpuAddr(),
  1375. .size = sub_size,
  1376. });
  1377. total_size_bytes += sub_size;
  1378. largest_copy = std::max<u64>(largest_copy, sub_size);
  1379. }
  1380. const std::span<BufferCopy> copies_span(copies.data(), copies.size());
  1381. UploadMemory(buffer, total_size_bytes, largest_copy, copies_span);
  1382. };
  1383. memory_tracker.ForEachUploadRange(cpu_addr, size, [&](u64 cpu_addr_out, u64 range_size) {
  1384. const VAddr base_adr = cpu_addr_out;
  1385. const VAddr end_adr = base_adr + range_size;
  1386. const IntervalType add_interval{base_adr, end_adr};
  1387. found_sets.add(add_interval);
  1388. });
  1389. if (found_sets.empty()) {
  1390. return true;
  1391. }
  1392. const IntervalType search_interval{cpu_addr, cpu_addr + size};
  1393. auto it = common_ranges.lower_bound(search_interval);
  1394. auto it_end = common_ranges.upper_bound(search_interval);
  1395. if (it == common_ranges.end()) {
  1396. make_copies();
  1397. return false;
  1398. }
  1399. while (it != it_end) {
  1400. found_sets.subtract(*it);
  1401. it++;
  1402. }
  1403. make_copies();
  1404. return false;
  1405. }
  1406. template <class P>
  1407. void BufferCache<P>::UploadMemory(Buffer& buffer, u64 total_size_bytes, u64 largest_copy,
  1408. std::span<BufferCopy> copies) {
  1409. if constexpr (USE_MEMORY_MAPS_FOR_UPLOADS) {
  1410. MappedUploadMemory(buffer, total_size_bytes, copies);
  1411. } else {
  1412. ImmediateUploadMemory(buffer, largest_copy, copies);
  1413. }
  1414. }
  1415. template <class P>
  1416. void BufferCache<P>::ImmediateUploadMemory([[maybe_unused]] Buffer& buffer,
  1417. [[maybe_unused]] u64 largest_copy,
  1418. [[maybe_unused]] std::span<const BufferCopy> copies) {
  1419. if constexpr (!USE_MEMORY_MAPS_FOR_UPLOADS) {
  1420. std::span<u8> immediate_buffer;
  1421. for (const BufferCopy& copy : copies) {
  1422. std::span<const u8> upload_span;
  1423. const VAddr cpu_addr = buffer.CpuAddr() + copy.dst_offset;
  1424. if (IsRangeGranular(cpu_addr, copy.size)) {
  1425. upload_span = std::span(cpu_memory.GetPointer(cpu_addr), copy.size);
  1426. } else {
  1427. if (immediate_buffer.empty()) {
  1428. immediate_buffer = ImmediateBuffer(largest_copy);
  1429. }
  1430. cpu_memory.ReadBlockUnsafe(cpu_addr, immediate_buffer.data(), copy.size);
  1431. upload_span = immediate_buffer.subspan(0, copy.size);
  1432. }
  1433. buffer.ImmediateUpload(copy.dst_offset, upload_span);
  1434. }
  1435. }
  1436. }
  1437. template <class P>
  1438. void BufferCache<P>::MappedUploadMemory([[maybe_unused]] Buffer& buffer,
  1439. [[maybe_unused]] u64 total_size_bytes,
  1440. [[maybe_unused]] std::span<BufferCopy> copies) {
  1441. if constexpr (USE_MEMORY_MAPS) {
  1442. auto upload_staging = runtime.UploadStagingBuffer(total_size_bytes);
  1443. const std::span<u8> staging_pointer = upload_staging.mapped_span;
  1444. for (BufferCopy& copy : copies) {
  1445. u8* const src_pointer = staging_pointer.data() + copy.src_offset;
  1446. const VAddr cpu_addr = buffer.CpuAddr() + copy.dst_offset;
  1447. cpu_memory.ReadBlockUnsafe(cpu_addr, src_pointer, copy.size);
  1448. // Apply the staging offset
  1449. copy.src_offset += upload_staging.offset;
  1450. }
  1451. runtime.CopyBuffer(buffer, upload_staging.buffer, copies);
  1452. }
  1453. }
  1454. template <class P>
  1455. bool BufferCache<P>::InlineMemory(VAddr dest_address, size_t copy_size,
  1456. std::span<const u8> inlined_buffer) {
  1457. const bool is_dirty = IsRegionRegistered(dest_address, copy_size);
  1458. if (!is_dirty) {
  1459. return false;
  1460. }
  1461. VAddr aligned_start = Common::AlignDown(dest_address, YUZU_PAGESIZE);
  1462. VAddr aligned_end = Common::AlignUp(dest_address + copy_size, YUZU_PAGESIZE);
  1463. if (!IsRegionGpuModified(aligned_start, aligned_end - aligned_start)) {
  1464. return false;
  1465. }
  1466. InlineMemoryImplementation(dest_address, copy_size, inlined_buffer);
  1467. return true;
  1468. }
  1469. template <class P>
  1470. void BufferCache<P>::InlineMemoryImplementation(VAddr dest_address, size_t copy_size,
  1471. std::span<const u8> inlined_buffer) {
  1472. const IntervalType subtract_interval{dest_address, dest_address + copy_size};
  1473. ClearDownload(subtract_interval);
  1474. common_ranges.subtract(subtract_interval);
  1475. BufferId buffer_id = FindBuffer(dest_address, static_cast<u32>(copy_size));
  1476. auto& buffer = slot_buffers[buffer_id];
  1477. SynchronizeBuffer(buffer, dest_address, static_cast<u32>(copy_size));
  1478. if constexpr (USE_MEMORY_MAPS_FOR_UPLOADS) {
  1479. auto upload_staging = runtime.UploadStagingBuffer(copy_size);
  1480. std::array copies{BufferCopy{
  1481. .src_offset = upload_staging.offset,
  1482. .dst_offset = buffer.Offset(dest_address),
  1483. .size = copy_size,
  1484. }};
  1485. u8* const src_pointer = upload_staging.mapped_span.data();
  1486. std::memcpy(src_pointer, inlined_buffer.data(), copy_size);
  1487. runtime.CopyBuffer(buffer, upload_staging.buffer, copies);
  1488. } else {
  1489. buffer.ImmediateUpload(buffer.Offset(dest_address), inlined_buffer.first(copy_size));
  1490. }
  1491. }
  1492. template <class P>
  1493. void BufferCache<P>::DownloadBufferMemory(Buffer& buffer) {
  1494. DownloadBufferMemory(buffer, buffer.CpuAddr(), buffer.SizeBytes());
  1495. }
  1496. template <class P>
  1497. void BufferCache<P>::DownloadBufferMemory(Buffer& buffer, VAddr cpu_addr, u64 size) {
  1498. boost::container::small_vector<BufferCopy, 1> copies;
  1499. u64 total_size_bytes = 0;
  1500. u64 largest_copy = 0;
  1501. memory_tracker.ForEachDownloadRangeAndClear(
  1502. cpu_addr, size, [&](u64 cpu_addr_out, u64 range_size) {
  1503. const VAddr buffer_addr = buffer.CpuAddr();
  1504. const auto add_download = [&](VAddr start, VAddr end) {
  1505. const u64 new_offset = start - buffer_addr;
  1506. const u64 new_size = end - start;
  1507. copies.push_back(BufferCopy{
  1508. .src_offset = new_offset,
  1509. .dst_offset = total_size_bytes,
  1510. .size = new_size,
  1511. });
  1512. // Align up to avoid cache conflicts
  1513. constexpr u64 align = 64ULL;
  1514. constexpr u64 mask = ~(align - 1ULL);
  1515. total_size_bytes += (new_size + align - 1) & mask;
  1516. largest_copy = std::max(largest_copy, new_size);
  1517. };
  1518. const VAddr start_address = cpu_addr_out;
  1519. const VAddr end_address = start_address + range_size;
  1520. ForEachInRangeSet(common_ranges, start_address, range_size, add_download);
  1521. const IntervalType subtract_interval{start_address, end_address};
  1522. ClearDownload(subtract_interval);
  1523. common_ranges.subtract(subtract_interval);
  1524. });
  1525. if (total_size_bytes == 0) {
  1526. return;
  1527. }
  1528. MICROPROFILE_SCOPE(GPU_DownloadMemory);
  1529. if constexpr (USE_MEMORY_MAPS) {
  1530. auto download_staging = runtime.DownloadStagingBuffer(total_size_bytes);
  1531. const u8* const mapped_memory = download_staging.mapped_span.data();
  1532. const std::span<BufferCopy> copies_span(copies.data(), copies.data() + copies.size());
  1533. for (BufferCopy& copy : copies) {
  1534. // Modify copies to have the staging offset in mind
  1535. copy.dst_offset += download_staging.offset;
  1536. }
  1537. runtime.CopyBuffer(download_staging.buffer, buffer, copies_span);
  1538. runtime.Finish();
  1539. for (const BufferCopy& copy : copies) {
  1540. const VAddr copy_cpu_addr = buffer.CpuAddr() + copy.src_offset;
  1541. // Undo the modified offset
  1542. const u64 dst_offset = copy.dst_offset - download_staging.offset;
  1543. const u8* copy_mapped_memory = mapped_memory + dst_offset;
  1544. cpu_memory.WriteBlockUnsafe(copy_cpu_addr, copy_mapped_memory, copy.size);
  1545. }
  1546. } else {
  1547. const std::span<u8> immediate_buffer = ImmediateBuffer(largest_copy);
  1548. for (const BufferCopy& copy : copies) {
  1549. buffer.ImmediateDownload(copy.src_offset, immediate_buffer.subspan(0, copy.size));
  1550. const VAddr copy_cpu_addr = buffer.CpuAddr() + copy.src_offset;
  1551. cpu_memory.WriteBlockUnsafe(copy_cpu_addr, immediate_buffer.data(), copy.size);
  1552. }
  1553. }
  1554. }
  1555. template <class P>
  1556. void BufferCache<P>::DeleteBuffer(BufferId buffer_id, bool do_not_mark) {
  1557. bool dirty_index{false};
  1558. boost::container::small_vector<u64, NUM_VERTEX_BUFFERS> dirty_vertex_buffers;
  1559. const auto scalar_replace = [buffer_id](Binding& binding) {
  1560. if (binding.buffer_id == buffer_id) {
  1561. binding.buffer_id = BufferId{};
  1562. }
  1563. };
  1564. const auto replace = [scalar_replace](std::span<Binding> bindings) {
  1565. std::ranges::for_each(bindings, scalar_replace);
  1566. };
  1567. if (channel_state->index_buffer.buffer_id == buffer_id) {
  1568. channel_state->index_buffer.buffer_id = BufferId{};
  1569. dirty_index = true;
  1570. }
  1571. for (u32 index = 0; index < channel_state->vertex_buffers.size(); index++) {
  1572. auto& binding = channel_state->vertex_buffers[index];
  1573. if (binding.buffer_id == buffer_id) {
  1574. binding.buffer_id = BufferId{};
  1575. dirty_vertex_buffers.push_back(index);
  1576. }
  1577. }
  1578. std::ranges::for_each(channel_state->uniform_buffers, replace);
  1579. std::ranges::for_each(channel_state->storage_buffers, replace);
  1580. replace(channel_state->transform_feedback_buffers);
  1581. replace(channel_state->compute_uniform_buffers);
  1582. replace(channel_state->compute_storage_buffers);
  1583. // Mark the whole buffer as CPU written to stop tracking CPU writes
  1584. if (!do_not_mark) {
  1585. Buffer& buffer = slot_buffers[buffer_id];
  1586. memory_tracker.MarkRegionAsCpuModified(buffer.CpuAddr(), buffer.SizeBytes());
  1587. }
  1588. Unregister(buffer_id);
  1589. delayed_destruction_ring.Push(std::move(slot_buffers[buffer_id]));
  1590. slot_buffers.erase(buffer_id);
  1591. if constexpr (HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS) {
  1592. channel_state->dirty_uniform_buffers.fill(~u32{0});
  1593. channel_state->uniform_buffer_binding_sizes.fill({});
  1594. }
  1595. auto& flags = maxwell3d->dirty.flags;
  1596. if (dirty_index) {
  1597. flags[Dirty::IndexBuffer] = true;
  1598. }
  1599. if (dirty_vertex_buffers.size() > 0) {
  1600. flags[Dirty::VertexBuffers] = true;
  1601. for (auto index : dirty_vertex_buffers) {
  1602. flags[Dirty::VertexBuffer0 + index] = true;
  1603. }
  1604. }
  1605. channel_state->has_deleted_buffers = true;
  1606. }
  1607. template <class P>
  1608. Binding BufferCache<P>::StorageBufferBinding(GPUVAddr ssbo_addr, u32 cbuf_index,
  1609. bool is_written) const {
  1610. const GPUVAddr gpu_addr = gpu_memory->Read<u64>(ssbo_addr);
  1611. const auto size = [&]() {
  1612. const bool is_nvn_cbuf = cbuf_index == 0;
  1613. // The NVN driver buffer (index 0) is known to pack the SSBO address followed by its size.
  1614. if (is_nvn_cbuf) {
  1615. const u32 ssbo_size = gpu_memory->Read<u32>(ssbo_addr + 8);
  1616. if (ssbo_size != 0) {
  1617. return ssbo_size;
  1618. }
  1619. }
  1620. // Other titles (notably Doom Eternal) may use STG/LDG on buffer addresses in custom defined
  1621. // cbufs, which do not store the sizes adjacent to the addresses, so use the fully
  1622. // mapped buffer size for now.
  1623. const u32 memory_layout_size = static_cast<u32>(gpu_memory->GetMemoryLayoutSize(gpu_addr));
  1624. return std::min(memory_layout_size, static_cast<u32>(8_MiB));
  1625. }();
  1626. const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr);
  1627. if (!cpu_addr || size == 0) {
  1628. LOG_WARNING(HW_GPU, "Failed to find storage buffer for cbuf index {}", cbuf_index);
  1629. return NULL_BINDING;
  1630. }
  1631. const VAddr cpu_end = Common::AlignUp(*cpu_addr + size, YUZU_PAGESIZE);
  1632. const Binding binding{
  1633. .cpu_addr = *cpu_addr,
  1634. .size = is_written ? size : static_cast<u32>(cpu_end - *cpu_addr),
  1635. .buffer_id = BufferId{},
  1636. };
  1637. return binding;
  1638. }
  1639. template <class P>
  1640. TextureBufferBinding BufferCache<P>::GetTextureBufferBinding(GPUVAddr gpu_addr, u32 size,
  1641. PixelFormat format) {
  1642. const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr);
  1643. TextureBufferBinding binding;
  1644. if (!cpu_addr || size == 0) {
  1645. binding.cpu_addr = 0;
  1646. binding.size = 0;
  1647. binding.buffer_id = NULL_BUFFER_ID;
  1648. binding.format = PixelFormat::Invalid;
  1649. } else {
  1650. binding.cpu_addr = *cpu_addr;
  1651. binding.size = size;
  1652. binding.buffer_id = BufferId{};
  1653. binding.format = format;
  1654. }
  1655. return binding;
  1656. }
  1657. template <class P>
  1658. std::span<const u8> BufferCache<P>::ImmediateBufferWithData(VAddr cpu_addr, size_t size) {
  1659. u8* const base_pointer = cpu_memory.GetPointer(cpu_addr);
  1660. if (IsRangeGranular(cpu_addr, size) ||
  1661. base_pointer + size == cpu_memory.GetPointer(cpu_addr + size)) {
  1662. return std::span(base_pointer, size);
  1663. } else {
  1664. const std::span<u8> span = ImmediateBuffer(size);
  1665. cpu_memory.ReadBlockUnsafe(cpu_addr, span.data(), size);
  1666. return span;
  1667. }
  1668. }
  1669. template <class P>
  1670. std::span<u8> BufferCache<P>::ImmediateBuffer(size_t wanted_capacity) {
  1671. immediate_buffer_alloc.resize_destructive(wanted_capacity);
  1672. return std::span<u8>(immediate_buffer_alloc.data(), wanted_capacity);
  1673. }
  1674. template <class P>
  1675. bool BufferCache<P>::HasFastUniformBufferBound(size_t stage, u32 binding_index) const noexcept {
  1676. if constexpr (IS_OPENGL) {
  1677. return ((channel_state->fast_bound_uniform_buffers[stage] >> binding_index) & 1) != 0;
  1678. } else {
  1679. // Only OpenGL has fast uniform buffers
  1680. return false;
  1681. }
  1682. }
  1683. template <class P>
  1684. std::pair<typename BufferCache<P>::Buffer*, u32> BufferCache<P>::GetDrawIndirectCount() {
  1685. auto& buffer = slot_buffers[channel_state->count_buffer_binding.buffer_id];
  1686. return std::make_pair(&buffer, buffer.Offset(channel_state->count_buffer_binding.cpu_addr));
  1687. }
  1688. template <class P>
  1689. std::pair<typename BufferCache<P>::Buffer*, u32> BufferCache<P>::GetDrawIndirectBuffer() {
  1690. auto& buffer = slot_buffers[channel_state->indirect_buffer_binding.buffer_id];
  1691. return std::make_pair(&buffer, buffer.Offset(channel_state->indirect_buffer_binding.cpu_addr));
  1692. }
  1693. } // namespace VideoCommon