diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index 906943710..f34df0da3 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -578,6 +578,13 @@ impl super::Device { let images = unsafe { functor.get_swapchain_images(raw) }.map_err(super::map_host_device_oom_err)?; + let fence = unsafe { + self.shared + .raw + .create_fence(&vk::FenceCreateInfo::default(), None) + .map_err(super::map_host_device_oom_err)? + }; + // NOTE: It's important that we define the same number of acquire/present semaphores // as we will need to index into them with the image index. let acquire_semaphores = (0..=images.len()) @@ -597,6 +604,7 @@ impl super::Device { functor, device: Arc::clone(&self.shared), images, + fence, config: config.clone(), acquire_semaphores, next_acquire_index: 0, diff --git a/wgpu-hal/src/vulkan/instance.rs b/wgpu-hal/src/vulkan/instance.rs index 572ffcd3f..6cb8515dc 100644 --- a/wgpu-hal/src/vulkan/instance.rs +++ b/wgpu-hal/src/vulkan/instance.rs @@ -187,6 +187,8 @@ impl super::Swapchain { }; }; + unsafe { device.destroy_fence(self.fence, None) } + // We cannot take this by value, as the function returns `self`. for semaphore in self.acquire_semaphores.drain(..) { let arc_removed = Arc::into_inner(semaphore).expect( @@ -1115,7 +1117,7 @@ impl crate::Surface for super::Surface { swapchain.raw, timeout_ns, acquire_semaphore_guard.acquire, - vk::Fence::null(), + swapchain.fence, ) } { // We treat `VK_SUBOPTIMAL_KHR` as `VK_SUCCESS` on Android. @@ -1138,6 +1140,30 @@ impl crate::Surface for super::Surface { } }; + // Wait for the image was acquired to be fully ready to be rendered too. + // + // This wait is very important on Windows to avoid bad frame pacing on + // Windows where the Vulkan driver is using a DXGI swapchain. See + // https://github.com/gfx-rs/wgpu/issues/8310 and + // https://github.com/gfx-rs/wgpu/issues/8354 for more details. + // + // On other platforms, this wait may serve to slightly decrease frame + // latency, depending on how the platform implements waiting within + // acquire. + unsafe { + swapchain + .device + .raw + .wait_for_fences(&[swapchain.fence], false, timeout_ns) + .map_err(super::map_host_device_oom_and_lost_err)?; + + swapchain + .device + .raw + .reset_fences(&[swapchain.fence]) + .map_err(super::map_host_device_oom_and_lost_err)?; + } + drop(acquire_semaphore_guard); // We only advance the surface semaphores if we successfully acquired an image, otherwise // we should try to re-acquire using the same semaphores. diff --git a/wgpu-hal/src/vulkan/mod.rs b/wgpu-hal/src/vulkan/mod.rs index d807411e6..1cd12ea39 100644 --- a/wgpu-hal/src/vulkan/mod.rs +++ b/wgpu-hal/src/vulkan/mod.rs @@ -390,6 +390,8 @@ struct Swapchain { functor: khr::swapchain::Device, device: Arc, images: Vec, + /// Fence used to wait on the acquired image. + fence: vk::Fence, config: crate::SurfaceConfiguration, /// Semaphores used between image acquisition and the first submission