During the late 1990s and throughout the 2000s, real-time computer graphics advanced rapidly. There was a race for performance that included the push to make the CPU and GPU run as asynchronously as possible. However, presentation remained a common choke point where the CPU and GPU had to work in unison to display rendered images on screen. For example, OpenGL®'s various SwapBuffers presentation APIs provided opaque synchronization models that prevented asynchronous operation and offered no precise control over how frames were displayed.
This lack of control was particularly problematic for interactive applications, as it prevented effective "frame pacing"—consistent timing between rendered frames. Good frame pacing means each frame is displayed for the same duration, resulting in smooth motion, while poor pacing can make a game feel choppy or janky even if the average frame rate is high.
Modern graphics APIs introduced the swapchain concept, which virtualizes the rotation of frame buffers displayed on screen while hiding the details of their management. However, swapchain design was still driven by throughput—maximizing the number of frames per second. The Vulkan® API was no exception: while the VK_KHR_swapchain extension enabled excellent pipelining of presentation, there was no API dedicated to frame pacing. In other words, it was easy to queue up many frames for presentation but nearly impossible to know when those frames would actually appear on screen. By focusing so heavily on frames per second (FPS), the new APIs still didn't give developers control over how the hardware displayed those frames.
The first attempt to address this in Vulkan was the VK_GOOGLE_display_timing extension. While a promising start, it still didn't provide enough presentation flexibility. VK_KHR_present_wait was introduced to help with frame pacing, but it did not enable the same precision as explicit time-based presentation. Thus began the long journey of VK_EXT_present_timing, which is now finally an official addition to Vulkan.
Frame Pacing Challenges
When rendering a new frame, applications typically apply a time step to their physics simulation or other animation methods, often derived from the time difference between successive frame renders or the intervals between vkAcquireNextImage's resolved fences. However, these time steps are often inconsistent, resulting in perceptible stutter even when the application fills the presentation queue fast enough to have a new frame ready for each of the display's vertical blanking periods. Using VK_KHR_present_wait to measure frame durations may help, but it lacks sufficient accuracy.
Many graphics programmers think in terms of independent CPU and GPU timelines, but often forget a third: the hardware displaying images. Ultimately, developers want users to see objects moving at exactly the rate they are simulated internally. To achieve this, the application needs to know when the next image will be displayed so it can target that time for its animation step.
Interactive applications, such as games, face an additional challenge: latency. Once again, swapchain APIs initially overlooked this in favor of throughput. The long-standing solution in the gaming community has been to disable vertical synchronization and tolerate the inevitable tearing to achieve the lowest possible latency. While Vulkan offers VK_PRESENT_MODE_MAILBOX_KHR for tear-free, low-latency display, its optional status and limited adoption has meant developers could not rely on it. Furthermore, factors beyond developer control—such as software overlays and desktop compositors—can affect frame timing.
Non-interactive applications such as media players are less sensitive to latency. However, they can struggle to maintain synchronization with other outputs such as audio, and often must resort to platform-specific APIs to achieve good results.
A true time-based presentation API would benefit both the graphics API and operating system by making them aware of the application's target frame rate, giving them the information they need to adjust compositor behavior or power management strategies accordingly. This is precisely what VK_EXT_present_timing delivers.
How Do We Fix This?
VK_EXT_present_timing is conceptually simple yet powerful. The extension combines two fundamental features, which Vulkan devices can expose independently:
- The ability to receive timing feedback about previous presentation requests
- The ability to explicitly specify a target presentation time for each request
It is the combination of these features that enables applications to achieve smooth, consistent animation.
Using timing information from previous presentations, applications can adjust their target frame rate and select a presentation time for future frames that aligns with it while still allowing rendering to complete within budget. That target presentation time can then drive the scene's animation, physics simulation, audio synchronization, rendering, and queuing of the presentation request. When everything works correctly, each frame's display duration closely matches the time step used to advance animation and simulation, resulting in smooth motion.
As always, the devil is in the details, and we will explore the technicalities of achieving these results in the upcoming Vulkan samples. For a more detailed description of the extension APIs, refer to the Vulkan Feature Descriptions (also known as "proposals"), which contains a self-contained description of the extension's features.
Drivers Available and Feedback Welcome!
VK_EXT_present_timing represents a significant development effort and a major milestone in bringing time-based frame pacing to the Vulkan ecosystem.
But there is more work to be done. The EXT prefix indicates that not all platforms yet support the extension, and some use cases—such as driving complex display topologies—are not yet possible with this extension alone. The Vulkan Working Group wants to learn from the developer community before finalizing this important piece of the Vulkan landscape.
The extension has been developed publicly, and the official specification is now posted, with drivers available or coming soon on multiple platforms:
- NVIDIA developer drivers—available now
- Mesa implementation—coming soon
- Android 17 early developer and beta releases—coming soon
Swapchains are often cited as a pain point when using Vulkan, so we warmly encourage feedback via the Vulkan Discord or GitHub issues to help guide this vital part of Vulkan's evolution to better meet real-world developer needs.