diff options
Diffstat (limited to 'src/video_core/buffer_cache')
| -rw-r--r-- | src/video_core/buffer_cache/buffer_cache.h | 10 | ||||
| -rw-r--r-- | src/video_core/buffer_cache/buffer_cache_base.h | 31 |
2 files changed, 39 insertions, 2 deletions
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index 42d7ba066d..e90af3214d 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -279,8 +279,10 @@ bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 am const DAddr diff = base_address - *cpu_src_address; const DAddr new_base_address = *cpu_dest_address + diff; tmp_intervals.push_back({new_base_address, size}); - if (AsyncBufferDownloads()) { + if (DownloadsAtFence(new_base_address, size)) { uncommitted_gpu_modified_ranges.Add(new_base_address, size); + } else { + ArmReadTraps(new_base_address, size); } }; gpu_modified_ranges.ForEachInRange(*cpu_src_address, amount, mirror); @@ -1603,8 +1605,10 @@ void BufferCache<P>::MarkWrittenBuffer(BufferId buffer_id, DAddr device_addr, u3 } memory_tracker.MarkRegionAsGpuModified(device_addr, size); gpu_modified_ranges.Add(device_addr, size); - if (AsyncBufferDownloads()) { + if (DownloadsAtFence(device_addr, size)) { uncommitted_gpu_modified_ranges.Add(device_addr, size); + } else { + ArmReadTraps(device_addr, size); } } @@ -2090,6 +2094,8 @@ void BufferCache<P>::DeleteBuffer(BufferId buffer_id, bool do_not_mark) { if constexpr (requires { runtime.OnBufferDeleted(slot_buffers[buffer_id]); }) { runtime.OnBufferDeleted(slot_buffers[buffer_id]); } + read_trapped_ranges.Subtract(slot_buffers[buffer_id].CpuAddr(), + slot_buffers[buffer_id].SizeBytes()); bool dirty_index{false}; boost::container::small_vector<u64, NUM_VERTEX_BUFFERS> dirty_vertex_buffers; const auto scalar_replace = [buffer_id](Binding& binding) { diff --git a/src/video_core/buffer_cache/buffer_cache_base.h b/src/video_core/buffer_cache/buffer_cache_base.h index 45a1836341..d8a61b7913 100644 --- a/src/video_core/buffer_cache/buffer_cache_base.h +++ b/src/video_core/buffer_cache/buffer_cache_base.h @@ -245,6 +245,12 @@ public: std::optional<VideoCore::RasterizerDownloadArea> GetFlushArea(DAddr device_addr, u64 size); + /// Without downloads at every fence, a guest CPU read is the only way GPU-written buffer + /// data reaches guest memory, so reads must ask the buffer cache (GetFlushArea). + bool FlushesOnCpuRead() const { + return !AsyncBufferDownloads(); + } + bool InlineMemory(DAddr dest_address, size_t copy_size, std::span<const u8> inlined_buffer); void BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, u32 size); @@ -536,6 +542,31 @@ private: } return gpu_memory == nullptr || !gpu_memory->UsesNativeTiling(); } + + /// Whether a GPU write to this range is copied back at the next fence. Ranges the guest CPU + /// has read (Preflushable, set by the first reactive flush) always are: later reads skip the + /// flush and rely on these downloads, e.g. collision meshes skinned by compute shaders. + bool DownloadsAtFence(DAddr device_addr, u64 size) noexcept { + return AsyncBufferDownloads() || memory_tracker.IsRegionPreflushable(device_addr, size); + } + + /// GPU writes that are not downloaded at fences: trap the guest CPU's next read of their + /// pages, which flushes them once and marks them Preflushable (then DownloadsAtFence). + void ArmReadTraps(DAddr device_addr, u64 size) { + const DAddr begin = Common::AlignDown(device_addr, Core::DEVICE_PAGESIZE); + const DAddr end = Common::AlignUp(device_addr + size, Core::DEVICE_PAGESIZE); + u64 armed_bytes = 0; + read_trapped_ranges.ForEachInRange(begin, end - begin, [&](DAddr lower, DAddr upper) { + armed_bytes += upper - lower; + }); + if (armed_bytes == end - begin) { + return; + } + read_trapped_ranges.Add(begin, end - begin); + device_memory.ArmReadTraps(begin, end - begin); + } + + Common::RangeSet<DAddr> read_trapped_ranges; Common::RangeSet<DAddr> gpu_modified_ranges; std::deque<Common::RangeSet<DAddr>> committed_gpu_modified_ranges; |
