aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/buffer_cache
diff options
context:
space:
mode:
authorMaranBr <maranbr@outlook.com>2026-05-29 14:01:06 +0200
committercrueter <crueter@eden-emu.dev>2026-05-29 14:01:06 +0200
commitc84d6054261ca7535981c10859b6932c31389c63 (patch)
tree5b7cdc5046daf46f9f9a23e594a49e3983f96d72 /src/video_core/buffer_cache
parentdef03f6589007026572816baed73f762818f05bb (diff)
[buffer_cache] Fix buffer upload overwriting GPU-modified regions (#4000)
This fixes a bug in Super Mario Odyssey, in Bowser's Kingdom, where particles rapidly freeze and unfreeze in midair. It also fixes vertex explosions in Super Mario Party Jamboree. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4000 Reviewed-by: Lizzie <lizzie@eden-emu.dev> Reviewed-by: Maufeat <sahyno1996@gmail.com>
Diffstat (limited to 'src/video_core/buffer_cache')
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h40
1 files changed, 27 insertions, 13 deletions
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 0d8d37ec0c..b36dd46176 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -1619,24 +1619,38 @@ void BufferCache<P>::TouchBuffer(Buffer& buffer, BufferId buffer_id) noexcept {
template <class P>
bool BufferCache<P>::SynchronizeBuffer(Buffer& buffer, DAddr device_addr, u32 size) {
upload_copies.clear();
- u64 total_size_bytes = 0;
+ u64 staging_offset = 0;
u64 largest_copy = 0;
- const DAddr buffer_start = buffer.cpu_addr_cached;
- memory_tracker.ForEachUploadRange(device_addr, size, [&](u64 device_addr_out, u64 range_size) {
- upload_copies.push_back(BufferCopy{
- .src_offset = total_size_bytes,
- .dst_offset = device_addr_out - buffer_start,
- .size = range_size,
+ DAddr buffer_start = buffer.CpuAddr();
+ auto push = [&](u64 start, u64 end) {
+ if (start >= end) {
+ return;
+ }
+ u64 sz = end - start;
+ upload_copies.push_back({
+ .src_offset = staging_offset,
+ .dst_offset = start - buffer_start,
+ .size = sz
});
- total_size_bytes += range_size;
- largest_copy = (std::max)(largest_copy, range_size);
+ staging_offset += sz;
+ largest_copy = (std::max)(largest_copy, sz);
+ };
+ memory_tracker.ForEachUploadRange(device_addr, size, [&](u64 addr, u64 range_size) {
+ u64 start = addr;
+ u64 end = addr + range_size;
+ gpu_modified_ranges.ForEachInRange(start, range_size, [&](u64 gstart, u64 gsize) {
+ u64 gend = gstart + gsize;
+ push(start, gstart);
+ start = (std::max)(start, gend);
+ });
+ push(start, end);
+ ClearDownload(addr, range_size);
+ gpu_modified_ranges.Subtract(addr, range_size);
});
- if (total_size_bytes == 0) {
+ if (upload_copies.empty()) {
return true;
}
- const std::span<BufferCopy> copies_span(upload_copies.data(), upload_copies.size());
- UploadMemory(buffer, total_size_bytes, largest_copy, copies_span);
- any_buffer_uploaded = true;
+ UploadMemory(buffer, staging_offset, largest_copy, std::span(upload_copies));
return false;
}