void BufferCache::MarkWrittenBuffer(BufferId buffer_id, DAddr device_addr, u32 size) {
+ if constexpr (!IS_OPENGL) {
+ Buffer& buffer = slot_buffers[buffer_id];
+ buffer.setWriteTick(runtime.CurrentTick());
+ }
memory_tracker.MarkRegionAsGpuModified(device_addr, size);
gpu_modified_ranges.Add(device_addr, size);
uncommitted_gpu_modified_ranges.Add(device_addr, size);
@@ -1442,16 +1446,32 @@ BufferId BufferCache
::FindBuffer(DAddr device_addr, u32 size) {
}
const u64 page = device_addr >> CACHING_PAGEBITS;
const BufferId buffer_id = page_table[page];
- if (!buffer_id) {
- return CreateBuffer(device_addr, size);
- }
- const Buffer& buffer = slot_buffers[buffer_id];
- if (buffer.IsInBounds(device_addr, size)) {
- return buffer_id;
+ if (buffer_id) {
+ Buffer& buffer = slot_buffers[buffer_id];
+ WaitForGpuFenceIfNeeded(buffer);
+ if (buffer.IsInBounds(device_addr, size)) {
+ return buffer_id;
+ }
}
return CreateBuffer(device_addr, size);
}
+template
+void BufferCache::WaitForGpuFenceIfNeeded(Buffer& buffer) {
+ if constexpr (!IS_OPENGL) {
+ const bool gpu_fence_accurate = Settings::IsGPUFenceBehaviorAccurate();
+ const bool gpu_fence_strict = Settings::IsGPUFenceBehaviorStrict();
+ if (gpu_fence_accurate || gpu_fence_strict) {
+ const u64 gpu_tick_delay = gpu_fence_strict ? 0 : 3;
+ const u64 buffer_tick = buffer.getWriteTick();
+ const u64 gpu_tick = runtime.KnownGpuTick();
+ if (buffer_tick > gpu_tick + gpu_tick_delay) {
+ runtime.Wait(buffer_tick);
+ }
+ }
+ }
+}
+
template
typename BufferCache::OverlapResult BufferCache
::ResolveOverlaps(DAddr device_addr,
u32 wanted_size) {
@@ -1634,17 +1654,6 @@ bool BufferCache
::SynchronizeBuffer(Buffer& buffer, DAddr device_addr, u32 si
if (total_size_bytes == 0) {
return true;
}
- if (Settings::values.enable_gpu_buffer_readback.GetValue()) {
- u64 min_offset = (std::numeric_limits::max)();
- u64 max_offset = 0;
- for (const auto& copy : upload_copies) {
- min_offset = (std::min)(min_offset, copy.dst_offset);
- max_offset = (std::max)(max_offset, copy.dst_offset + copy.size);
- }
- const DAddr sync_addr = buffer.CpuAddr() + min_offset;
- const u64 sync_size = max_offset - min_offset;
- DownloadBufferMemory(buffer, sync_addr, sync_size);
- }
const std::span copies_span(upload_copies.data(), upload_copies.size());
UploadMemory(buffer, total_size_bytes, largest_copy, copies_span);
any_buffer_uploaded = true;
@@ -1679,6 +1688,9 @@ void BufferCache::ImmediateUploadMemory([[maybe_unused]] Buffer& buffer,
if (immediate_buffer.empty()) {
immediate_buffer = ImmediateBuffer(largest_copy);
}
+ if (Settings::values.enable_gpu_buffer_readback.GetValue()) {
+ DownloadBufferMemory(buffer, device_addr, copy.size);
+ }
device_memory.ReadBlockUnsafe(device_addr, immediate_buffer.data(), copy.size);
upload_span = immediate_buffer.subspan(0, copy.size);
}
@@ -1697,6 +1709,9 @@ void BufferCache
::MappedUploadMemory([[maybe_unused]] Buffer& buffer,
for (BufferCopy& copy : copies) {
u8* const src_pointer = staging_pointer.data() + copy.src_offset;
const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset;
+ if (Settings::values.enable_gpu_buffer_readback.GetValue()) {
+ DownloadBufferMemory(buffer, device_addr, copy.size);
+ }
device_memory.ReadBlockUnsafe(device_addr, src_pointer, copy.size);
// Apply the staging offset
copy.src_offset += upload_staging.offset;
diff --git a/src/video_core/buffer_cache/buffer_cache_base.h b/src/video_core/buffer_cache/buffer_cache_base.h
index 473cc6842e..14ab3e6ebc 100644
--- a/src/video_core/buffer_cache/buffer_cache_base.h
+++ b/src/video_core/buffer_cache/buffer_cache_base.h
@@ -416,6 +416,8 @@ private:
[[nodiscard]] BufferId FindBuffer(DAddr device_addr, u32 size);
+ void WaitForGpuFenceIfNeeded(Buffer& buffer);
+
[[nodiscard]] OverlapResult ResolveOverlaps(DAddr device_addr, u32 wanted_size);
void JoinOverlap(BufferId new_buffer_id, BufferId overlap_id, bool accumulate_stream_score);
diff --git a/src/video_core/dma_pusher.cpp b/src/video_core/dma_pusher.cpp
index 41bb43f0c1..2417659f09 100644
--- a/src/video_core/dma_pusher.cpp
+++ b/src/video_core/dma_pusher.cpp
@@ -78,7 +78,8 @@ bool DmaPusher::Step() {
}
if (header.size > 0) {
- if (Settings::IsDMALevelDefault() ? (Settings::IsGPULevelMedium() || Settings::IsGPULevelHigh()) : Settings::IsDMALevelSafe()) {
+ const bool use_safe = Settings::IsDMALevelDefault() ? Settings::IsGPULevelHigh() : Settings::IsDMALevelSafe();
+ if (use_safe) {
Tegra::Memory::GpuGuestMemoryheaders(memory_manager, dma_state.dma_get, header.size, &command_headers);
ProcessCommands(headers);
} else {
diff --git a/src/video_core/fence_manager.h b/src/video_core/fence_manager.h
index 1b11ff52d2..16f19bf009 100644
--- a/src/video_core/fence_manager.h
+++ b/src/video_core/fence_manager.h
@@ -72,16 +72,13 @@ public:
}
void SignalFence(std::function&& func) {
+ const bool delay_fence = Settings::IsGPUFenceBehaviorDefault() ? Settings::IsGPULevelHigh() : Settings::IsGPUFenceBehaviorBalanced() || Settings::IsGPUFenceBehaviorAccurate() || Settings::IsGPUFenceBehaviorStrict();
+ const bool should_flush = ShouldFlush();
if constexpr (!can_async_check) {
TryReleasePendingFences();
}
- const bool should_flush = ShouldFlush();
- const bool antiflicker_toggled = Settings::values.antiflicker.GetValue();
- const bool delay_fence = Settings::IsGPULevelHigh() ||
- (Settings::IsGPULevelMedium() && should_flush) ||
- antiflicker_toggled;
CommitAsyncFlushes();
- TFence new_fence = CreateFence(!should_flush && !antiflicker_toggled);
+ TFence new_fence = CreateFence(!should_flush);
if constexpr (can_async_check) {
guard.lock();
}
diff --git a/src/video_core/query_cache/query_cache.h b/src/video_core/query_cache/query_cache.h
index 6bed91a53e..50b662e0ad 100644
--- a/src/video_core/query_cache/query_cache.h
+++ b/src/video_core/query_cache/query_cache.h
@@ -260,7 +260,7 @@ void QueryCacheBase::CounterReport(GPUVAddr addr, QueryType counter_type
};
u8* pointer = impl->device_memory.template GetPointer(cpu_addr);
u8* pointer_timestamp = impl->device_memory.template GetPointer(cpu_addr + 8);
- bool is_synced = !Settings::IsGPULevelHigh() && is_fence;
+ bool is_synced = (Settings::IsGPUFenceBehaviorDefault() ? !Settings::IsGPULevelHigh() : !Settings::IsGPUFenceBehaviorBalanced() && !Settings::IsGPUFenceBehaviorAccurate() && !Settings::IsGPUFenceBehaviorStrict()) && is_fence;
std::function operation([this, is_synced, streamer, query_base = query, query_location,
pointer, pointer_timestamp] {
if (True(query_base->flags & QueryFlagBits::IsInvalidated)) {
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index 00f4f81f29..4402550af9 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -396,6 +396,18 @@ void BufferCacheRuntime::TickFrame(Common::SlotVector& slot_buffers) noe
}
}
+u64 BufferCacheRuntime::CurrentTick() {
+ return scheduler.GetMasterSemaphore().CurrentTick();
+}
+
+u64 BufferCacheRuntime::KnownGpuTick() {
+ return scheduler.GetMasterSemaphore().KnownGpuTick();
+}
+
+void BufferCacheRuntime::Wait(u64 buffer_tick) {
+ scheduler.Wait(buffer_tick);
+}
+
void BufferCacheRuntime::Finish() {
scheduler.Finish();
}
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h
index 764263717d..d4ad156073 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.h
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h
@@ -92,6 +92,12 @@ public:
void TickFrame(Common::SlotVector& slot_buffers) noexcept;
+ u64 CurrentTick();
+
+ u64 KnownGpuTick();
+
+ void Wait(u64 buffer_tick);
+
void Finish();
u64 GetDeviceLocalMemory() const;
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp
index 3bf7a9ac78..334d82efff 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.cpp
+++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp
@@ -27,8 +27,6 @@
namespace Vulkan {
-constexpr u64 MAX_PENDING_FLUSHES = 5;
-
void Scheduler::CommandChunk::ExecuteAll(vk::CommandBuffer cmdbuf,
vk::CommandBuffer upload_cmdbuf) {
auto command = first;
@@ -49,15 +47,6 @@ Scheduler::Scheduler(const Device& device_, StateTracker& state_tracker_)
master_semaphore{std::make_unique(device)},
command_pool{std::make_unique(*master_semaphore, device)} {
- /*// PRE-OPTIMIZATION: Warm up the pool to prevent mid-frame spikes
- {
- std::scoped_lock rl{reserve_mutex};
- chunk_reserve.reserve(2048); // Prevent vector resizing
- for (int i = 0; i < 1024; ++i) {
- chunk_reserve.push_back(std::make_unique());
- }
- }*/
-
AcquireNewChunk();
AllocateWorkerCommandBuffer();
worker_thread = std::jthread([this](std::stop_token token) { WorkerThread(token); });
@@ -66,18 +55,7 @@ Scheduler::Scheduler(const Device& device_, StateTracker& state_tracker_)
Scheduler::~Scheduler() = default;
u64 Scheduler::Flush(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) {
- // Prevent the CPU from getting too far ahead of the GPU by limiting pending flushes.
- const bool should_throttle = Settings::IsGPULevelHigh();
- if (should_throttle) {
- const u64 current_tick = master_semaphore->CurrentTick();
- const u64 gap = current_tick > last_submitted_tick ? current_tick - last_submitted_tick : 0;
- const u64 step = (std::min)(MAX_PENDING_FLUSHES, gap);
- const u64 new_tick = last_submitted_tick + step;
- if (new_tick < current_tick) {
- last_submitted_tick = new_tick;
- master_semaphore->Wait(last_submitted_tick);
- }
- }
+ // When flushing, we only send data to the worker thread; no waiting is necessary.
const u64 signal_value = SubmitExecution(signal_semaphore, wait_semaphore);
AllocateNewContext();
return signal_value;
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h
index 51ccd102f8..0709c3a370 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.h
+++ b/src/video_core/renderer_vulkan/vk_scheduler.h
@@ -298,8 +298,6 @@ private:
double last_target_fps{};
u64 max_frame_count{};
u64 frame_counter{};
-
- u64 last_submitted_tick = 0;
};
} // namespace Vulkan
diff --git a/src/yuzu/main_window.cpp b/src/yuzu/main_window.cpp
index 2801fbd321..88de185c6a 100644
--- a/src/yuzu/main_window.cpp
+++ b/src/yuzu/main_window.cpp
@@ -3585,9 +3585,6 @@ void MainWindow::OnToggleDockedMode() {
void MainWindow::OnToggleGpuAccuracy() {
switch (Settings::values.gpu_accuracy.GetValue()) {
case Settings::GpuAccuracy::Low:
- Settings::values.gpu_accuracy.SetValue(Settings::GpuAccuracy::Medium);
- break;
- case Settings::GpuAccuracy::Medium:
Settings::values.gpu_accuracy.SetValue(Settings::GpuAccuracy::High);
break;
case Settings::GpuAccuracy::High: