buffer_cache.h 72 KB

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