diff --git a/runtime/vk_sync.c b/runtime/vk_sync.c index 9e7ee07a..cc4a6bb4 100644 --- a/runtime/vk_sync.c +++ b/runtime/vk_sync.c @@ -703,7 +703,11 @@ static int fence_wait_impl(uint64_t value, uint64_t timeout_ns) { // CPU side effects of its fence may still be to come. 1 when reached. int vk_sync_exec_wait(uint64_t value, uint64_t timeout_ns) { vk_sync_start(); - if (!vk_sync_wb_split()) return vk_sync_fence_wait(value, timeout_ns); + // With shadow storage (vk_mem_shadow_storage) what the GPU wrote reaches guest memory in the completion thread's + // fence callback, after the executed timeline: a wait that returned there let the game rewrite a pool that an + // older write-back then overwrote (Kokiri Forest: a sky coefficient the game had reset came back, and the world + // flickered washed out). So the wait covers the write-backs there, as without the split. + if (vk_mem_shadow_storage() || !vk_sync_wb_split()) return vk_sync_fence_wait(value, timeout_ns); if (__atomic_load_n(&done, __ATOMIC_ACQUIRE) >= value) return 1; uint64_t p0 = perf_begin(); hold_release(value, 0, 0); // a held submission the waiter needs goes to the queue now