buffer_cache.h 74 KB

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