diff --git a/appendices/VK_EXT_present_timing.adoc b/appendices/VK_EXT_present_timing.adoc new file mode 100644 index 0000000000..2973063e25 --- /dev/null +++ b/appendices/VK_EXT_present_timing.adoc @@ -0,0 +1,237 @@ +// Copyright (c) 2017-2024 Khronos Group. +// +// SPDX-License-Identifier: CC-BY-4.0 + +include::{generated}/meta/{refprefix}VK_EXT_present_timing.adoc[] + +=== Other Extension Metadata + +*Last Modified Date*:: + 2024-10-09 +*IP Status*:: + No known IP claims. +*Contributors*:: + - Ian Elliott, Google + - James Jones, NVIDIA + - Jeff Juliano, NVIDIA + - Daniel Rakos, AMD + - Daniel Stone, Collabora + - Daniel Vetter, Intel + - Aric Cyr, AMD + - Faith Ekstrand, Intel + - Nicolai Hähnle, AMD + - Alon Or-Bach, Samsung + - Niklas Smedberg, Unity Technologies + - Tobias Hector, AMD + - Lionel Duc, NVIDIA + - Lina Versace, Google + - Sebastian Wick, Red Hat + - Jakob Bornecrantz, Collabora + - David Kvasnica, NVIDIA + +=== Description + +This device extension allows an application that uses the +`apiext:VK_KHR_swapchain` extension to obtain information about the +presentation engine's display, to obtain timing information about each +present, and to schedule a present to happen no earlier than a desired time. +An application can use this to minimize various visual anomalies (e.g. +stuttering). + +Traditional game and real-time animation applications need to correctly +position their geometry for when the presentable image will be presented to +the user. +To accomplish this, applications need various timing information about the +presentation engine's display. +They need to know when presentable images were actually presented, and when +they could have been presented. +Applications also need to tell the presentation engine to display an image +no sooner than a given time. +This allows the application to avoid stuttering, so the animation looks +smooth to the user. + +include::{generated}/interfaces/VK_EXT_present_timing.adoc[] + +=== Issues + +1) How does the application determine refresh duration, quanta for change, +whether FRR vs. VRR, etc. + +*PROPOSED*: the query returns two values: 1) a refresh-cycle duration +(pname:refreshDuration), and 2) an indication whether the timing is +currently fixed (FRR) or variable (VRR). +If pname:refreshDuration is zero, the platform cannot supply these +values until after at least one flink:vkQueuePresentKHR has been done, +from this time (e.g. if flink:vkQueuePresentKHR has been previously +called for this swapchain, at least one additional call must be made). +After calling flink:vkQueuePresentKHR, the query can be repeated until +pname:refreshDuration is non-zero, at which point the FRR vs. VRR +indication will also be valid. + +If the presentation engine's pname:refreshDuration is a fixed value, +the application's image present duration (IPD) should be a multiple of +pname:refreshDuration. +That is, the quanta for changing the IPD is pname:refreshDuration. +For example, if pname:refreshDuration is 16.67ms, the IPD can be +16.67ms, 33.33ms, 50.0ms, etc. + +If the presentation engine's pname:refreshDuration is variable, +pname:refreshDuration is the minimum value of the application's IPD, and +the IPD can be larger by any quanta that is meaningful to the application. +For example, if the pname:refreshDuration is 10ms (i.e. the maximum +refresh rate is 100Hz), the application can choose an IPD of 11ms, +13.33ms, 13.5ms, or 66.0ms; any value greater than or equal to 10ms is +valid. +There may be negative consequences for choosing an IPD that is too +high, as the presentation engine may actually have a practical maximum +pname:refreshDuration, where it needs to display the previous image +again, and during this time the presentation engine might delay +displaying a newly-presented image. + +FRR displays on at least one platform (Wayland) are not necessarily +fixed; but can change over time. +For example, if a full-screen video player application is visible, the display +may operate at a 24Hz refresh cycle; and then later switch to 60Hz when +multiple windows are visible. + +VRR displays on some platforms can also be seen as having different +characteristics over time. +For example, if an application's window is full-screen-exclusive (i.e. no other +window or window system component is visible), the display can look like a VRR +display (however that is defined). +If the application's window is not full-screen-exclusive (e.g. a normal +multi-window case), the display can look like an FRR display (i.e. because the +compositor is trying to treat all windows in a consistent manner). +A different issue will deal with how the timing characteristics can change +over time. + + +2) Do we return min/max values for refresh duration for VRR? + +*PROPOSED*: return only the minimum value of refreshDuration for a VRR. + +VRR displays have a minimum and maximum refresh rate, and therefore a minimum +and maximum refreshDuration. +It has been asserted that the display effectively does not have a minimum +refresh rate. +That is because if an application does not present soon enough, the display +hardware will automatically re-display the previous image. +However, when the display does that, an application cannot present a new image +for a certain period of time. +It is unclear about whether that period is large enough to cause visual +artifacts. + + +3) How to deal with changes in timing properties? + +*RESOLVED*: The slink:VkPastPresentationTimingPropertiesEXT structure +that is returned by flink:vkGetPastPresentationTimingEXT contains +pname:timeDomainsCounter, which is incremented if the time +domain enabled for the swapchain is not currently available. + +An example of why display timing properties can change is if a surface +changes from being a window that’s a subset of the display size, to +becoming full-screen-exclusive. +While the surface was a subset of the display, a compositor might +enforce fixed timings on the surface (e.g. FRR of 60Hz), where the +presentation engine might be free to allow VRR behavior of a +full-screen-exclusive surface. + +It is possible that a full-screen-exclusive window can become +temporarily obscured (e.g. when a short-term dialog pops up). +In this case, the surface might use FRR timings while the dialog is +visible and VRR otherwise. + + +4) One Query for all Timing info vs. an initial query to determine FRR vs. VRR, +and then FRR-specific vs VRR-specific queries? + +*RESOLVED*: Have one query, as described in issue 1, that can be +called whenever the application needs to obtain the timing properties +of the surface. + + +5) Query to determine time domain? + +*RESOLVED*: Have a query to determine the time domain. +This extension defines a basic swapchain-local time domain. +Other extensions can add other platform-specific time domains. + + +6) What time to use for targetPresentTime for early images? + +*RESOLVED*: Have no query for determining the current time in the PE’s time +domain; and do allow the special value of zero for targetPresentTime, +meaning that there is no target. + +On some platforms, there is no way to determine the current time, nor +to determine surface timing properties until after at least one image +has been presented. + +In such cases, the special value of zero allows the application to +indicate that timing feedback is desired, but that no +targetPresentTime is requested. +Later, once the application has obtained feedback, it can specify +targetPresentTime by using the result's actualPresentTime. + + +7) How long before an application’s request for new image duration is honored? + +*UNRESOLVED*: Apparently, changes to some vendors' display hardware settings do +not take effect immediately. +It is not clear what settings, and therefore, it is not clear how to +address this issue. + + +8) Do we have a query for the anticipated latency from present to feedback? + +*RESOLVED*: Do not provide a query for the feedback latency. + +There is some amount of latency from when an application calls +vkQueuePresentKHR to when the image is displayed to the user, to when feedback +is available to the application on when the image was actually displayed to the +user. +The first time (from the call till the image is presented) generally doesn’t +matter, because the application will likely be providing a targetPresentTime +(i.e. the application may have some indication for how long this will be). +However, the latency between targetPresentTime until feedback is available may +be much longer. +For example, on Android on the 1st-generation Pixel phone (60Hz FRR display), +the latency was approximately 5 refresh cycles (83.33ms). +For higher-frequency displays, the latency may have a larger number of refresh +cycles. + + +9) Do we have a query(s) about the number of VkPastPresentationTimingEXT +structs to keep? + +*RESOLVED*: Do not provide a query for the number of results the swapchain +is allowed to store before querying them with +vkGetPastPresentationTimingEXT. Let the application specify that value with +a dedicated API. + + +10) How is the SWAPCHAIN_LOCAL and STAGE_LOCAL time domain used with the +calibrated timestamps extension? + +*RESOLVED*: Define a struct to chain into +VkCalibratedTimestampInfoEXT::pNext that specifies a swapchain and present +stage. + + +11) Should VK_PRESENT_MODE_FIFO_LATEST_READY_EXT be part of this extension, +or split out into its own extension? + +*RESOLVED*: It is only tangentially related. +Split it out into its own extension and define the interaction here. + +=== Version History + + * Revision 1, 2018-05-11 (Ian Elliott) + ** Internal revisions. + + * Revision 2, 2022-11-30 (Lionel Duc) + ** Rebase for public discussions. + + * Revision 3, 2024-10-09 (Lionel Duc) + ** Public revisions. diff --git a/appendices/glossary.adoc b/appendices/glossary.adoc index fc65802e9e..0e4ca5bf33 100644 --- a/appendices/glossary.adoc +++ b/appendices/glossary.adoc @@ -827,6 +827,11 @@ Framebuffer Region:: A framebuffer region is a set of sample (x, y, layer, sample) coordinates that is a subset of the entire framebuffer. +ifdef::VK_EXT_present_timing,VK_GOOGLE_display_timing[] +Frame Rate:: + A non-Vulkan term for Image Present Rate (IPR). +endif::VK_EXT_present_timing,VK_GOOGLE_display_timing[] + Front-Facing:: See Facingness. endif::VK_GRAPHICS_VERSION_1_0[] @@ -924,6 +929,19 @@ Image:: of device memory. Represented by a slink:VkImage object. +ifdef::VK_EXT_present_timing,VK_GOOGLE_display_timing[] +Image Present Duration:: + The amount of time the application intends for each + newly-presented image to be visible to the user. + This value should: be a multiple of the refresh cycle duration. + +Image Present Rate:: + The number of newly-presented images the application intends to present + each second (a.k.a. frame rate). + On fixed refresh rate displays, this value should: be a multiple of + the refresh rate. +endif::VK_EXT_present_timing,VK_GOOGLE_display_timing[] + Image Subresource:: A specific mipmap level, layer, and set of aspects of an image. @@ -1142,6 +1160,11 @@ Invocation Repack Instruction:: implementation may: change the set of invocations that are executing. endif::VK_KHR_ray_tracing_pipeline,VK_NV_ray_tracing[] +ifdef::VK_EXT_present_timing,VK_GOOGLE_display_timing[] +IPD:: + Image Present Duration. +endif::VK_EXT_present_timing,VK_GOOGLE_display_timing[] + ifdef::VK_KHR_deferred_host_operations[] Join (Deferred Host Operations):: The act of instructing a thread to participate in the execution of a @@ -1733,6 +1756,11 @@ ifdef::VK_KHR_ray_tracing_pipeline[flink:vkCmdTraceRaysKHR, and flink:vkCmdTrace . endif::VK_KHR_ray_tracing_pipeline,VK_NV_ray_tracing[] +ifdef::VK_EXT_present_timing,VK_GOOGLE_display_timing[] +RC:: + Refresh Cycle. +endif::VK_EXT_present_timing,VK_GOOGLE_display_timing[] + ifdef::VK_KHR_video_queue[] Reconstructed Picture:: A video picture resource reconstructed from a compressed bitstream using @@ -1755,6 +1783,17 @@ Reference Picture Metadata:: Opaque state associated with a DPB slot, maintained by a video session. endif::VK_KHR_video_queue[] +ifdef::VK_EXT_present_timing,VK_GOOGLE_display_timing[] +Refresh Cycle:: + The periodic process for updating the contents of the Presentation Engine's display. + +Refresh Cycle Duration:: + The amount of time from the start of one refresh cycle to the next. + +Refresh Rate:: + The number of refresh cycles per second. +endif::VK_EXT_present_timing,VK_GOOGLE_display_timing[] + Release Operation (Resource):: An operation that releases ownership of an image subresource or buffer range. diff --git a/chapters/VK_EXT_present_timing/PresentTimeInfo.adoc b/chapters/VK_EXT_present_timing/PresentTimeInfo.adoc new file mode 100644 index 0000000000..d8ce730066 --- /dev/null +++ b/chapters/VK_EXT_present_timing/PresentTimeInfo.adoc @@ -0,0 +1,200 @@ +// Copyright (c) 2014-2025 Khronos Group. +// +// SPDX-License-Identifier: CC-BY-4.0 + +[open,refpage='VkPresentTimingsInfoEXT',desc='Array of VkPresentTimingInfoEXT to chain with VkPresentInfoKHR',type='structs'] +-- + +When the <> or +<> feature is +enabled, an application can: instruct the presentation engine to attempt to +display an image at a specified time, or for a minimum duration, by +including the sname:VkPresentTimingsInfoEXT structure in the pname:pNext +chain of the slink:VkPresentInfoKHR structure. + +The sname:VkPresentTimingsInfoEXT structure is defined as: + +include::{generated}/api/structs/VkPresentTimingsInfoEXT.adoc[] + + * pname:sType is a elink:VkStructureType value identifying this structure. + * pname:pNext is `NULL` or a pointer to a structure extending this + structure. + * pname:swapchainCount is the number of swapchains being presented to by + this command. + * pname:pTimingInfos is `NULL` or a pointer to an array of + sname:VkPresentTimingInfoEXT elements with pname:swapchainCount entries. + If not `NULL`, each element of pname:pTimingInfos contains timing + information for the presentation of the image corresponding to the entry + in the sname:VkPresentInfoKHR::pname:pImageIndices array. + +.Valid Usage +**** + * pname:swapchainCount must: be equal to + slink:VkPresentInfoKHR::pname:swapchainCount. + * All swapchains in slink:VkPresentInfoKHR::pname:pSwapchains must: have + been created with the slink:VkSwapchainCreateInfoKHR::pname:flags field + containing ename:VK_SWAPCHAIN_CREATE_PRESENT_TIMING_BIT_EXT + * For each member of sname:VkPresentInfoKHR::pname:pSwapchains, if the + associated slink:VkPresentTimingInfoEXT::pname:targetTime is not zero, + the swapchain's current present mode must: be +ifdef::VK_KHR_present_mode_fifo_latest_ready[] + ename:VK_PRESENT_MODE_FIFO_LATEST_READY_KHR, +endif::VK_KHR_present_mode_fifo_latest_ready[] + ename:VK_PRESENT_MODE_FIFO_KHR or + ename:VK_PRESENT_MODE_FIFO_RELAXED_KHR. +**** + +include::{generated}/validity/structs/VkPresentTimingsInfoEXT.adoc[] +-- + +[open,refpage='VkPresentTimingInfoEXT',desc='Specifies per-present timing information',type='structs'] +-- +The sname:VkPresentTimingInfoEXT structure is defined as: + +include::{generated}/api/structs/VkPresentTimingInfoEXT.adoc[] + + * pname:sType is a elink:VkStructureType value identifying this structure. + * pname:pNext is `NULL` or a pointer to a structure extending this + structure. + * pname:flags is a bitmask of elink:VkPresentTimingInfoFlagBitsEXT + specifying options for how to interpret the timing information. + * pname:targetTime is zero or a value specifying the target present + time or duration, in nanoseconds, of the presentation request. + * pname:timeDomainId is the id of the time domain used to specify the + absolute target present time and the timing results obtained in a + subsequent flink:vkGetPastPresentationTimingEXT call for the current + presentation request. + * pname:presentStageQueries is a valid tlink:VkPresentStageFlagsEXT value + indicating which present stages the presentation engine will collect + timing information for. + * pname:targetTimeDomainPresentStage is a valid + tlink:VkPresentStageFlagsEXT specifying a single present stage used to + interpret pname:targetTime. + +If pname:targetTime is not zero, the implementation attempts to align the +ename:VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT present stage of +that presentation request with the time specified in pname:targetTime +according to the time domain used. If +ename:VK_PRESENT_TIMING_INFO_PRESENT_AT_NEAREST_REFRESH_CYCLE_BIT_EXT is not +set in pname:flags, it indicates that the application would strictly prefer +the image to not be visible before pname:targetTime has lapsed. + +If pname:targetTime is not zero and pname:timeDomainId is associated with a +ename:VK_TIME_DOMAIN_PRESENT_STAGE_LOCAL_EXT time domain, +pname:targetTimeDomainPresentStage is used to specify which present stage's +time domain pname:targetTime is specified for. Otherwise, +pname:targetTimeDomainPresentStage is ignored. + +[NOTE] +==== +Some platforms, due to hardware or system limitations, may: not be able to +accurately time pname:targetTime with the actual physical event of the image +becoming visible on the display. However, those timing capabilities may: +still be useful and result in improved animation quality. + +As such, the <> +and <> features +do not provide a strict guarantee regarding the completion of the +ename:VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT present stage +relative to the pname:targetTime, and implementations must: strive to make +it as consistent and accurate as possible. +==== + +[NOTE] +==== +Applications that specify an absolute present time should: regularly rebase +their calculations for their next target time on the feedback from +flink:vkGetPastPresentationTimingEXT to compensate for accumulated precision +errors or potential clock drift. It is recommended that when targeting the +time of a vertical blanking period, applications set +ename:VK_PRESENT_TIMING_INFO_PRESENT_AT_NEAREST_REFRESH_CYCLE_BIT_EXT +to allow the implementation to compensate for small precision errors that may +cause an image to be displayed one refresh cycle later than intended. +==== + +.Valid Usage +**** + * If pname:targetTime is not zero and pname:flags does not contain + ename:VK_PRESENT_TIMING_INFO_PRESENT_AT_RELATIVE_TIME_BIT_EXT, the + <> feature + must: be enabled. + * If pname:targetTime is not zero and pname:flags contains + ename:VK_PRESENT_TIMING_INFO_PRESENT_AT_RELATIVE_TIME_BIT_EXT, the + <> feature + must: be enabled. + * If pname:timeDomainId is associated with a + ename:VK_TIME_DOMAIN_PRESENT_STAGE_LOCAL_EXT time domain, and + pname:targetTime is not zero, pname:targetTimeDomainPresentStage must: + be a single tname:VkPresentStageFlagsEXT value. +**** + +include::{generated}/validity/structs/VkPresentTimingInfoEXT.adoc[] +-- + +[open,refpage='VkPresentTimingInfoFlagBitsEXT',desc='Bitmask specifying present timing info flags',type='enums'] +-- +Bits which can: be set in slink:VkPresentTimingInfoEXT::pname:flags, specifying options +for how to interpret timing information: + +include::{generated}/api/enums/VkPresentTimingInfoFlagBitsEXT.adoc[] + + * ename:VK_PRESENT_TIMING_INFO_PRESENT_AT_RELATIVE_TIME_BIT_EXT specifies + that sname:VkPresentTimingInfoEXT::pname:targetTime is to be interpreted + as a relative time from the previous presentation's + ename:VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT stage. If the + pname:swapchain has never been used to present an image, the provided + pname:targetTime is ignored. + * ename:VK_PRESENT_TIMING_INFO_PRESENT_AT_NEAREST_REFRESH_CYCLE_BIT_EXT + specifies that the application would prefer the image to be presented + earlier than the time specified in + sname:VkPresentTimingInfoEXT::pname:targetTime if that time falls within + the first half of a refresh cycle. In that case, the presentation engine + may: choose to display the image at the start of that refresh cycle. +-- + +[open,refpage='VkPresentTimingInfoFlagsEXT',desc='Bitmask of VkPresentTimingInfoFlagBitsEXT',type='flags'] +-- +include::{generated}/api/flags/VkPresentTimingInfoFlagsEXT.adoc[] + +tname:VkPresentTimingInfoFlagsEXT is a bitmask type for setting a mask +of zero or more elink:VkPresentTimingInfoFlagBitsEXT. +-- + +[open,refpage='VkPresentStageFlagBitsEXT',desc='Bitmask specifying stages of the image presentation process',type='enums'] +-- + +Presenting an image to the user typically involves multiple stages. Bits +which can: be set to specify present stages are: + +include::{generated}/api/enums/VkPresentStageFlagBitsEXT.adoc[] + + * ename:VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT marks the end of the + set of queue operations enqueued by flink:vkQueuePresentKHR on the provided + sname:VkQueue for a presentation request. + * ename:VK_PRESENT_STAGE_REQUEST_DEQUEUED_BIT_EXT is the stage after which + the presentation request has been dequeued from the swapchain's internal + presentation request queue, if any, as specified by the present mode + associated with that request. + * ename:VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_OUT_BIT_EXT is the stage after + which data for the first pixel of the presentation request associated with + the image has left the presentation engine for a display hardware. + * ename:VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT is the stage + after which a display hardware has made the first pixel visible for the + presentation request associated with the image to be presented. + +[NOTE] +==== +The set of queue operations delimited by +ename:VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT includes the wait for +the semaphores specified in slink:VkPresentInfoKHR::pname:pWaitSemaphores, +if any, and any work implicitly enqueued by the implementation. +==== +-- + +[open,refpage='VkPresentStageFlagsEXT',desc='Bitmask of VkPresentStageFlagBitsEXT',type='flags'] +-- +include::{generated}/api/flags/VkPresentStageFlagsEXT.adoc[] + +tname:VkPresentStageFlagsEXT is a bitmask type for setting a mask of zero or +more elink:VkPresentStageFlagBitsEXT. +-- diff --git a/chapters/VK_EXT_present_timing/queries.adoc b/chapters/VK_EXT_present_timing/queries.adoc new file mode 100644 index 0000000000..5a304f2395 --- /dev/null +++ b/chapters/VK_EXT_present_timing/queries.adoc @@ -0,0 +1,511 @@ +// Copyright (c) 2014-2025 Khronos Group. +// +// SPDX-License-Identifier: CC-BY-4.0 + +== Present Timing Queries + +Traditional game and real-time-animation applications frequently use +ename:VK_PRESENT_MODE_FIFO_KHR so that presentable images are updated during +the vertical blanking period of a given refresh cycle (RC) of the +presentation engine's display. +On fixed refresh rate displays, this avoids the visual anomaly known as +tearing. + +However, synchronizing the presentation of images with the RC does not +prevent all forms of visual anomalies. +Stuttering occurs when the geometry for each presentable image is not +accurately positioned for when that image will be displayed. +The geometry may appear to move too little some RCs, and too much for +others. +Sometimes the animation appears to freeze, when the same image is used for +more RCs than other images. + +In order to minimize stuttering, an application needs to: 1) render and +present images at a consistent rate that is, on fixed refresh rate displays, +a multiple of the presentation engine's refresh rate; 2) correctly position +its geometry for when the presentable image will be displayed to the user. +The +ifdef::VK_EXT_present_timing[] +`apiext:VK_EXT_present_timing` +endif::VK_EXT_present_timing[] +ifdef::VK_EXT_present_timing+VK_GOOGLE_display_timing[or] +ifdef::VK_GOOGLE_display_timing[] +`apiext:VK_GOOGLE_display_timing` +endif::VK_GOOGLE_display_timing[] +extension allows an application to satisfy these needs. + +The presentation engine's display typically refreshes the pixels that are +displayed to the user on a periodic basis. This period may: be fixed (Fixed +Refresh Rate, FRR) or variable (Variable Refresh Rate, VRR). + +ifdef::VK_EXT_present_timing[] +[open,refpage='vkSetSwapchainPresentTimingQueueSizeEXT',desc='Allocate memory for the swapchain-internal timing results queue',type='protos'] +-- +In order to collect timing information about presentation, a swapchain needs +an internal queue to store asynchronously updated results until applications +collect them. + +To allocate the swapchain's internal timing results queue, call: + +include::{generated}/api/protos/vkSetSwapchainPresentTimingQueueSizeEXT.adoc[] + + * pname:device is the device associated with pname:swapchain. + * pname:swapchain is the swapchain to allocate a results queue for. + * pname:size is the requested number of slots in the internal results queue. + +If this function is called multiple times, the internal queue is reallocated +to fit the new pname:size. If the new pname:size is less than the current +number of outstanding results, ename:VK_NOT_READY is returned and no allocation +is performed. + +.Valid Usage +**** + * pname:swapchain must: have been created with + sname:VkSwapchainCreateInfoKHR::pname:flags containing + ename:VK_SWAPCHAIN_CREATE_PRESENT_TIMING_BIT_EXT +**** + +include::{generated}/validity/protos/vkSetSwapchainPresentTimingQueueSizeEXT.adoc[] +-- + +[open,refpage='vkGetSwapchainTimingPropertiesEXT',desc='Obtain the display timing properties of the PE\'s display',type='protos'] +-- + +The implementation maintains an internal monotonically increasing counter +which updates when the presentation engine's timing properties are modified. + +To query the presentation engine's current timing properties for a given +swapchain, call: + +include::{generated}/api/protos/vkGetSwapchainTimingPropertiesEXT.adoc[] + + * pname:device is the device associated with pname:swapchain. + * pname:swapchain is the swapchain to obtain timing properties for. + * pname:pSwapchainTimingProperties is a pointer to an instance of the + slink:VkSwapchainTimingPropertiesEXT structure. + * pname:pSwapchainTimingPropertiesCounter is `NULL` or a pointer to a + 64-bit unsigned integer set by the implementation to the current value of + the swapchain's internal timing properties counter. + +If fname:vkGetSwapchainTimingPropertiesEXT returns ename:VK_NOT_READY, the +implementation was not able to determine the current refresh cycle +duration. Some platforms may: not provide timing properties until after at least +one image has been presented to the pname:swapchain. If timing properties change +for the pname:swapchain, these platforms may: not provide updated results until +after at least one additional image has been presented to the pname:swapchain. + +include::{generated}/validity/protos/vkGetSwapchainTimingPropertiesEXT.adoc[] +-- + +[open,refpage='VkSwapchainTimingPropertiesEXT',desc='Structure containing the RC duration of a display',type='structs'] +-- + +The sname:VkSwapchainTimingPropertiesEXT structure is defined as: + +include::{generated}/api/structs/VkSwapchainTimingPropertiesEXT.adoc[] + + * pname:sType is a elink:VkStructureType value identifying this structure. + * pname:pNext is `NULL` or a pointer to a structure extending this + structure. + * pname:refreshDuration is zero or an indication of the duration + of a refresh cycle. + * pname:refreshInterval is zero or a duration in nanoseconds indicating + the interval between refresh cycle durations. + +If pname:refreshDuration is zero, the presentation engine is not able +to determine the duration of the refresh cycle. Similarly, if +pname:refreshInterval is zero, the presentation engine is not able to +determine whether it is operating in VRR mode. + +Otherwise, if pname:refreshInterval is the same as pname:refreshDuration, +the presentation engine is operating in FRR mode. In this case, +pname:refreshDuration is the number of nanoseconds from the start of one +refresh cycle to the start of the next refresh cycle. + +If pname:refreshInterval is code:UINT64_MAX, the presentation engine is +operating in VRR mode, and pname:refreshDuration is the minimum number of +nanoseconds from the start of one refresh cycle to the start of the next +refresh cycle. + +If pname:refreshDuration and pname:refreshInterval are not zero, +pname:refreshInterval is a factor of pname:refreshDuration. + +include::{generated}/validity/structs/VkSwapchainTimingPropertiesEXT.adoc[] +-- + +[NOTE] +==== +The rate at which an application renders and presents new images is known as +the image present rate (IPR, a.k.a. frame rate). The inverse of IPR, or the +duration between each image present, is the image present duration (IPD). + +In order to provide a smooth, stutter-free animation on non-VRR displays, an +application needs its IPD to be a multiple of pname:refreshInterval that is +at least equal to pname:refreshDuration. + +For example, if a FRR display has a set 60Hz refresh rate, where +pname:refreshDuration is equal to pname:refreshInterval, +pname:refreshDuration will be a value in nanoseconds that is approximately +equal to 16.67ms. In such a case, an application will want an IPD of 16.67ms +(1X multiplier of pname:refreshInterval), or 33.33ms (2X multiplier of +pname:refreshInterval), or 50.0ms (3X multiplier of pname:refreshInterval), +etc. + +In order to determine a target IPD for a display (i.e. a multiple of +pname:refreshInterval), an application needs to determine when its images +are actually displayed. + +Consider an application that has an initial target IPD of 16.67ms (1X +multiplier of pname:refreshDuration). It will therefore position the +geometry of a new image 16.67ms later than the previous image. + +If this application is running on slower hardware, so that it actually takes +20ms to render each new image, the images will not be displayed to the user +every 16.67ms, nor every 20ms, which will create visual anomalies. +In this case, it is better for the application to adjust its target IPD to +33.33ms (i.e. a 2X multiplier of pname:refreshDuration), and tell the +presentation engine to not present images any sooner than every 33.33ms. +This will allow the geometry to be correctly positioned for each presentable +image. + +On VRR displays, where pname:refreshInterval is code:UINT64_MAX, +applications should: target an IPD that is at least equal to +pname:refreshDuration. + +Adjustments to an application's IPD may be needed because different views of +an application's geometry can take different amounts of time to render. +For example, looking at the sky may take less time to render than looking at +multiple, complex items in a room. + +In general, it is good to not frequently change IPD, as that can cause +visual anomalies. + +Adjustments to a larger IPD because of late images should happen quickly, +but adjustments to a smaller IPD should only happen if the periodic +feedback of slink:VkPastPresentationTimingEXT values indicates that the +target IPD can be durably achieved. +==== + +[open,refpage='vkGetSwapchainTimeDomainPropertiesEXT',desc='Obtain the time domains supported by the PE for the swapchain',type='protos'] +-- +The implementation maintains an internal monotonically increasing counter which +updates when the presentation engine's list of supported time domains for a +swapchain is modified. + +To query the time domains supported by the presentation engine for a given swapchain, +call: + +include::{generated}/api/protos/vkGetSwapchainTimeDomainPropertiesEXT.adoc[] + + * pname:device is the device associated with pname:swapchain. + * pname:swapchain is the swapchain to obtain time domain properties for. + * pname:pSwapchainTimeDomainProperties is a pointer to an instance of the + slink:VkSwapchainTimeDomainPropertiesEXT structure. + * pname:pTimeDomainsCounter is `NULL` or a pointer to a 64-bit unsigned + integer set by the implementation to the current value of the + swapchain's internal time domain properties counter. + +If upon return slink:VkSwapchainTimeDomainPropertiesEXT::pname:timeDomainCount +is smaller than the number of time domains supported for the given +pname:swapchain, ename:VK_INCOMPLETE will be returned instead of +ename:VK_SUCCESS to indicate that not all the available values were returned. + +include::{generated}/validity/protos/vkGetSwapchainTimeDomainPropertiesEXT.adoc[] +-- + +[open,refpage='VkSwapchainTimeDomainPropertiesEXT',desc='List of available time domains for a swapchain',type='structs'] +-- + +The sname:VkSwapchainTimeDomainPropertiesEXT structure is defined as: + +include::{generated}/api/structs/VkSwapchainTimeDomainPropertiesEXT.adoc[] + + * pname:sType is a elink:VkStructureType value identifying this structure. + * pname:pNext is `NULL` or a pointer to a structure extending this + structure. + * pname:timeDomainCount is an integer related to the number of time domains + available or queried, as described below. + * pname:pTimeDomains is a pointer to an array of elink:VkTimeDomainKHR values + representing time domains that are available for the swapchain. + * pname:pTimeDomainIds is a pointer to an array of unique identifiers for each + time domain. + +When calling flink:vkGetSwapchainTimeDomainPropertiesEXT, if pname:pTimeDomains +is `NULL` and pname:pTimeDomainIds is `NULL`, then the number of time domains +supported for the given pname:swapchain is returned in +pname:timeDomainCount. Otherwise, pname:timeDomainCount must: specify the number +of elements in the pname:pTimeDomains, pname:pTimeDomainIds, or both arrays, and +on return the variable is overwritten with the number of values actually written +to either array. + +[NOTE] +==== +Due to the dynamic nature of their underlying sname:VkSurfaceKHR properties, +swapchains may need to expose multiple swapchain-local opaque time domains using +the same elink:VkTimeDomainKHR value over time, for example when a surface is +moved from one display hardware to another. Arbitrary identifiers, provided in +pname:timeDomainIds, are used by the implementation to differentiate opaque time +domains of identical scopes. +==== + +include::{generated}/validity/structs/VkSwapchainTimeDomainPropertiesEXT.adoc[] +-- + +[open,refpage='vkGetPastPresentationTimingEXT',desc='Obtain timing of previously-presented images',type='protos'] +-- + +Because of the asynchronous nature of the presentation engine, the timing +information for a given flink:vkQueuePresentKHR command may: only becomes +available some time after the presentation has occurred. +These time values should: be asynchronously queried, and are returned if +available. +All time values are in nanoseconds, according to the time-domain being used. + +To asynchronously query the presentation engine for newly-available timing +information about one or more previous presents to a given swapchain, call: + +include::{generated}/api/protos/vkGetPastPresentationTimingEXT.adoc[] + + * pname:device is the device associated with pname:swapchain. + * pname:pPastPresentationTimingInfo is a pointer to an instance of + the slink:VkPastPresentationTimingInfoEXT structure. + * pname:pPastPresentationTimingProperties is a pointer to an instance + of the slink:VkPastPresentationTimingPropertiesEXT structure. + +If upon return the value of +sname:VkPastPresentationTimingPropertiesEXT::pname:presentationTimingCount is +less than the number of available timing records for the given +sname:VkPastPresentationTimingInfoEXT::pname:swapchain, ename:VK_INCOMPLETE is +returned instead of ename:VK_SUCCESS to indicate that not all the available +values were returned. + +Upon return, zero or more slots of the pname:swapchain internal timing results +queue, equal to the number of entries written to +sname:VkPastPresentationTimingPropertiesEXT::pname:pPresentationTimings for +which pname:reportComplete is ename:VK_TRUE, are made available for future +fname:vkQueuePresentKHR calls. Elements of pname:pPresentationTimings are +arranged in ascending order of present ids. + +Timing information may: become available out of order with regards to their +associated flink:vkQueuePresentKHR order. +ename:VK_PAST_PRESENTATION_TIMING_ALLOW_OUT_OF_ORDER_RESULTS_BIT_EXT can: be +set in sname:VkPastPresentationTimingInfoEXT::pname:flags to allow +fname:vkGetPastPresentationTimingEXT to return results in that same +order. Otherwise, results are returned in the order of their associated +flink:vkQueuePresentKHR calls. + +There is no requirement for any precise timing relationship between the +completion of a present stage and the availability of any associated timing +information. However, results must: be made available in finite time. + +As an exception to the normal rules for objects which are externally +synchronized, pname:swapchain may: be +simultaneously used by other threads in calls to functions other than +flink:vkDestroySwapchainKHR and flink:vkCreateSwapchainKHR with pname:swapchain +used as an pname:oldSwapchain. Access to the swapchain timing information must: +be atomic within the implementation. + +.Valid Usage +**** + * If ename:VK_PAST_PRESENTATION_TIMING_ALLOW_OUT_OF_ORDER_RESULTS_BIT_EXT + is set in sname:VkPastPresentationTimingInfoEXT::pname:flags, the + pname:presentStageCount value of each element of + sname:VkPastPresentationTimingPropertiesEXT::pname:pPresentationTimings + must: be at least the maximum number of present stages set in + slink:VkPresentTimingInfoEXT::pname:presentStageQueries among all + flink:vkQueuePresentKHR calls, with a non-zero + pname:presentStageQueries, for which complete results have not been + returned yet by a previous call. + * If ename:VK_PAST_PRESENTATION_TIMING_ALLOW_OUT_OF_ORDER_RESULTS_BIT_EXT + is not set in sname:VkPastPresentationTimingInfoEXT::pname:flags, the + pname:presentStageCount value of each element of + sname:VkPastPresentationTimingPropertiesEXT::pname:pPresentationTimings + must: be at least the number of present stages set in + sname:VkPresentTimingInfoEXT::pname:presentStageQueries for the earliest + call to fname:vkQueuePresentKHR, with a non-zero + pname:presentStageQueries, that corresponds to that element's index and + for which complete results have not been returned yet by a previous + call. +**** + +include::{generated}/validity/protos/vkGetPastPresentationTimingEXT.adoc[] +-- + +[open,refpage='VkPastPresentationTimingInfoEXT',desc='Structure specifying swapchain present timing query parameters',type='structs'] +-- + +The sname:VkPastPresentationTimingInfoEXT structure is defined as: + +include::{generated}/api/structs/VkPastPresentationTimingInfoEXT.adoc[] + + * pname:sType is a elink:VkStructureType value identifying this structure. + * pname:pNext is `NULL` or a pointer to a structure extending this + structure. + * pname:flags is a bitmask of elink:VkPastPresentationTimingFlagBitsEXT + specifying options for queries of past presentation timing information. + * pname:swapchain is the swapchain to obtain presentation timing + information for. + +include::{generated}/validity/structs/VkPastPresentationTimingInfoEXT.adoc[] +-- + +[open,refpage='VkPastPresentationTimingFlagsEXT',desc='Bitmask of VkPastPresentationTimingFlagBitsEXT',type='flags'] +-- +include::{generated}/api/flags/VkPastPresentationTimingFlagsEXT.adoc[] + +tname:VkPastPresentationTimingFlagsEXT is a bitmask type for setting a mask +of zero or more elink:VkPastPresentationTimingFlagBitsEXT. +-- + +[open,refpage='VkPastPresentationTimingFlagBitsEXT',desc='Bitmask specifying past presentation timing query flags',type='enums'] +-- +Bits which can: be set in slink:VkPastPresentationTimingInfoEXT::pname:flags, specifying options +for queries of past presentation timing information, are: + +include::{generated}/api/enums/VkPastPresentationTimingFlagBitsEXT.adoc[] + + * ename:VK_PAST_PRESENTATION_TIMING_ALLOW_PARTIAL_RESULTS_BIT_EXT specifies + that flink:vkGetPastPresentationTimingEXT may: return partial results for + presentation requests that have not completed all requested present stages. + * ename:VK_PAST_PRESENTATION_TIMING_ALLOW_OUT_OF_ORDER_RESULTS_BIT_EXT + specifies that flink:vkGetPastPresentationTimingEXT may: return results + out of order with respect to the presentation order. +-- + +[open,refpage='VkPastPresentationTimingPropertiesEXT',desc='Structure containing details about a swapchain past presentation activity',type='structs'] +-- + +The sname:VkPastPresentationTimingPropertiesEXT structure is defined as: + +include::{generated}/api/structs/VkPastPresentationTimingPropertiesEXT.adoc[] + + * pname:sType is a elink:VkStructureType value identifying this structure. + * pname:pNext is `NULL` or a pointer to a structure extending this + structure. + * pname:timingPropertiesCounter is a 64-bit unsigned integer set by the + implementation to the current value of the swapchain's internal timing + properties counter. + * pname:timeDomainsCounter is a 64-bit unsigned integer set by the + implementation to the current value of the swapchain's internal time + domains list counter. + * pname:presentationTimingCount is an integer related to the number of + slink:VkPastPresentationTimingEXT structures available or queried, as + described below. + * pname:pPresentationTimings is `NULL` or a pointer to an array + of slink:VkPastPresentationTimingEXT structures. + +When calling flink:vkGetPastPresentationTimingEXT, if pname:pPresentationTimings +is `NULL`, then the number of available timing records for the given +pname:swapchain is returned in pname:presentationTimingCount. Otherwise, +pname:presentationTimingCount must: specify the number of elements in the +pname:pPresentationTimings array, and on return the variable is overwritten with +the number of structures actually written to pname:pPresentationTimings. + +if ename:VK_PAST_PRESENTATION_TIMING_ALLOW_PARTIAL_RESULTS_BIT_EXT is +specified in slink:VkPastPresentationTimingInfoEXT::pname:flags, +fname:vkGetPastPresentationTimingEXT may: return incomplete results, +containing only information for a subset of the requested present +stages. Further calls to fname:vkGetPastPresentationTimingEXT will keep +providing all available results for a previously incomplete entry until it +is complete. + +The implementation must: return a slink:VkPastPresentationTimingEXT for +every flink:vkQueuePresentKHR referencing pname:swapchain where a non-zero +slink:VkPresentTimingInfoEXT::pname:presentStageQueries was specified and at +least one present stage has available results. + +include::{generated}/validity/structs/VkPastPresentationTimingPropertiesEXT.adoc[] +-- + +[NOTE] +==== +The presentation engine may: change the timing properties of the pname:swapchain +for a variety of reasons. + +This may: occur, for example, if the window system changes its mode, including +the refresh rate of the display. +Another example is if an application's surface is being composited with other +windows of a window system, and then the surface's window becomes a borderless, +full-screen window. +While composited, the timing properties may: be FRR, and while full-screen, the +timing properties may: be VRR. + +The available time domains for a swapchain may: change for similar or identical +reasons. Therefore, it is possible that the same event will cause both the +swapchain's internal timing properties counter and time domains list counter to +update. +==== + +[open,refpage='VkPastPresentationTimingEXT',desc='Structure containing timing information about a previously-presented image',type='structs'] +-- + +The sname:VkPastPresentationTimingEXT structure is defined as: + +include::{generated}/api/structs/VkPastPresentationTimingEXT.adoc[] + + * pname:sType is a elink:VkStructureType value identifying this structure. + * pname:pNext is `NULL` or a pointer to a structure extending this + structure. + * pname:presentId is zero or a value that was given to a previous + fname:vkQueuePresentKHR command via + slink:VkPresentId2KHR::pname:pPresentIds. + * pname:targetTime is the application-provided target absolute time or + duration of the associated presentation request in + slink:VkPresentTimingInfoEXT::pname:targetTime. + * pname:presentStageCount is a count of items contained in + pname:pPresentStages. + * pname:pPresentStages a pointer to an array of + slink:VkPresentStageTimeEXT providing timing information for the + presentation request associated with pname:presentId. + * pname:timeDomain is the time domain used by the presentation + engine to report times in pname:pPresentStages. + * pname:timeDomainId is the id associated with pname:timeDomain. + * pname:reportComplete is ename:VK_TRUE if the presentation engine + has reported all the requested results in pname:pPresentStages. + +When calling flink:vkGetPastPresentationTimingEXT, the implementation sets +pname:presentStageCount to the number of present stages it has written +results for. If +ename:VK_PAST_PRESENTATION_TIMING_ALLOW_PARTIAL_RESULTS_BIT_EXT was +specified in slink:VkPastPresentationTimingInfoEXT::pname:flags, the +implementation may: return an incomplete report containing fewer present +stage results than were queried by the associated presentation +request. Otherwise, results for all the present stages queried by the +presentation request are written by the implementation. + +Timing information for some present stages may: have a time value of 0, +indicating that results for that present stage are not available. + +For systems with multiple entities operating within the presentation engine, +such as multiple displays, pname:pPresentStages will return timing results for +one entity which has been affected by the presentation. + +pname:timeDomainId may: be different than the time domain that was specified in +sname:VkPresentTimingInfoEXT::pname:timeDomainId if the requirements for using +this time domain could not be met at the time the presentation engine processed +the presentation request. In such a case, the presentation engine may: pick a +time domain to fall back to, if one is available, and report results in that +domain. Applications can: continue to use this fallback time domain in future +fname:vkQueuePresentKHR calls, or they can: call +flink:vkGetSwapchainTimeDomainPropertiesEXT to choose from the currently +supported time domains. + +include::{generated}/validity/structs/VkPastPresentationTimingEXT.adoc[] +-- + +[open,refpage='VkPresentStageTimeEXT',desc='Associate a present stage with a timestamp',type='structs'] +-- +The sname:VkPresentStageTimeEXT structure is defined as: + +include::{generated}/api/structs/VkPresentStageTimeEXT.adoc[] + + * pname:stage is a tlink:VkPresentStageFlagsEXT value specifying a present stage. + * pname:time is a time in nanoseconds associated with the pname:stage. + +include::{generated}/validity/structs/VkPresentStageTimeEXT.adoc[] +-- +endif::VK_EXT_present_timing[] + +ifdef::VK_GOOGLE_display_timing[] +include::{chapters}/VK_GOOGLE_display_timing/queries.adoc[] +endif::VK_GOOGLE_display_timing[] diff --git a/chapters/VK_GOOGLE_display_timing/queries.adoc b/chapters/VK_GOOGLE_display_timing/queries.adoc index 91fee5d788..5ddd3b298c 100644 --- a/chapters/VK_GOOGLE_display_timing/queries.adoc +++ b/chapters/VK_GOOGLE_display_timing/queries.adoc @@ -2,46 +2,6 @@ // // SPDX-License-Identifier: CC-BY-4.0 -== Display Timing Queries - -Traditional game and real-time-animation applications frequently use -ename:VK_PRESENT_MODE_FIFO_KHR so that presentable images are updated during -the vertical blanking period of a given refresh cycle (RC) of the -presentation engine's display. -This avoids the visual anomaly known as tearing. - -However, synchronizing the presentation of images with the RC does not -prevent all forms of visual anomalies. -Stuttering occurs when the geometry for each presentable image is not -accurately positioned for when that image will be displayed. -The geometry may appear to move too little some RCs, and too much for -others. -Sometimes the animation appears to freeze, when the same image is used for -more than one RC. - -In order to minimize stuttering, an application needs to correctly position -their geometry for when the presentable image will be displayed to the user. -To accomplish this, applications need various timing information about the -presentation engine's display. -They need to know when presentable images were actually presented, and when -they could have been presented. -Applications also need to tell the presentation engine to display an image -no sooner than a given time. -This can allow the application's animation to look smooth to the user, with -no stuttering. -The `apiext:VK_GOOGLE_display_timing` extension allows an application to -satisfy these needs. - -The presentation engine's display typically refreshes the pixels that are -displayed to the user on a periodic basis. -The period may be fixed or variable. -In many cases, the presentation engine is associated with fixed refresh rate -(FRR) display technology, with a fixed refresh rate (RR, e.g. 60Hz). -In some cases, the presentation engine is associated with variable refresh -rate (VRR) display technology, where each refresh cycle (RC) can vary in -length. -This extension treats VRR displays as if they are FRR. - [open,refpage='vkGetRefreshCycleDurationGOOGLE',desc='Obtain the RC duration of the PE\'s display',type='protos'] -- To query the duration of a refresh cycle (RC) for the presentation engine's @@ -69,50 +29,6 @@ include::{generated}/api/structs/VkRefreshCycleDurationGOOGLE.adoc[] include::{generated}/validity/structs/VkRefreshCycleDurationGOOGLE.adoc[] -- -[NOTE] -==== -The rate at which an application renders and presents new images is known as -the image present rate (IPR, aka frame rate). -The inverse of IPR, or the duration between each image present, is the image -present duration (IPD). -In order to provide a smooth, stutter-free animation, an application will -want its IPD to be a multiple of pname:refreshDuration. -For example, if a display has a 60Hz refresh rate, pname:refreshDuration -will be a value in nanoseconds that is approximately equal to 16.67ms. -In such a case, an application will want an IPD of 16.67ms (1X multiplier of -pname:refreshDuration), or 33.33ms (2X multiplier of pname:refreshDuration), -or 50.0ms (3X multiplier of pname:refreshDuration), etc. - -In order to determine a target IPD for a display (i.e. a multiple of -pname:refreshDuration), an application needs to determine when its images -are actually displayed. -Suppose an application has an initial target IPD of 16.67ms (1X multiplier -of pname:refreshDuration). -It will therefore position the geometry of a new image 16.67ms later than -the previous image. -But suppose this application is running on slower hardware, so that it -actually takes 20ms to render each new image. -This will create visual anomalies, because the images will not be displayed -to the user every 16.67ms, nor every 20ms. -In this case, it is better for the application to adjust its target IPD to -33.33ms (i.e. a 2X multiplier of pname:refreshDuration), and tell the -presentation engine to not present images any sooner than every 33.33ms. -This will allow the geometry to be correctly positioned for each presentable -image. - -Adjustments to an application's IPD may be needed because different views of -an application's geometry can take different amounts of time to render. -For example, looking at the sky may take less time to render than looking at -multiple, complex items in a room. -In general, it is good to not frequently change IPD, as that can cause -visual anomalies. -Adjustments to a larger IPD because of late images should happen quickly, -but adjustments to a smaller IPD should only happen if the -pname:actualPresentTime and pname:earliestPresentTime members of the -slink:VkPastPresentationTimingGOOGLE structure are consistently different, -and if pname:presentMargin is consistently large, over multiple images. -==== - [open,refpage='vkGetPastPresentationTimingGOOGLE',desc='Obtain timing of a previously-presented image',type='protos'] -- The implementation will maintain a limited amount of history of timing @@ -246,7 +162,7 @@ The semantics for other present modes are as follows: far enough in the future that an image is not presented before fname:vkQueuePresentKHR is called to present another image, the first image will not be displayed to the user. - If the application continues to do that, the presentation may: not + If the application continues to do that, the presentation engine may: not display new images. * ename:VK_PRESENT_MODE_FIFO_RELAXED_KHR. For images that are presented in time to be displayed at the next diff --git a/chapters/VK_KHR_surface/wsi.adoc b/chapters/VK_KHR_surface/wsi.adoc index 407183ccd0..eb5d4d90ec 100644 --- a/chapters/VK_KHR_surface/wsi.adoc +++ b/chapters/VK_KHR_surface/wsi.adoc @@ -1686,6 +1686,34 @@ include::{generated}/validity/structs/VkSurfaceCapabilitiesPresentWait2KHR.adoc[ -- endif::VK_KHR_present_wait2[] +ifdef::VK_EXT_present_timing[] +[open,refpage='VkPresentTimingSurfaceCapabilitiesEXT',desc='Structure describing present timing capabilities of a surface',type='structs'] +-- +The sname:VkPresentTimingSurfaceCapabilitiesEXT structure is defined as: + +include::{generated}/api/structs/VkPresentTimingSurfaceCapabilitiesEXT.adoc[] + + * pname:sType is a elink:VkStructureType value identifying this structure. + * pname:pNext is `NULL` or a pointer to a structure extending this + structure. + * pname:presentTimingSupported indicates whether querying presentation + timestamps is supported for a swapchain created from + slink:VkPhysicalDeviceSurfaceInfo2KHR::pname:surface. + * pname:presentAtAbsoluteTimeSupported indicates whether a swapchain + created from slink:VkPhysicalDeviceSurfaceInfo2KHR::pname:surface + supports presenting images with absolute times. + * pname:presentAtRelativeTimeSupported indicates whether a swapchain + created from slink:VkPhysicalDeviceSurfaceInfo2KHR::pname:surface + supports presenting images with relative times. + * pname:presentStageQueries is a bitmask of + elink:VkPresentStageFlagBitsEXT indicating which present stages a + swapchain created from + slink:VkPhysicalDeviceSurfaceInfo2KHR::pname:surface is able to provide + timing information for. + +include::{generated}/validity/structs/VkPresentTimingSurfaceCapabilitiesEXT.adoc[] +-- +endif::VK_EXT_present_timing[] endif::VK_KHR_get_surface_capabilities2[] ifdef::VK_EXT_display_surface_counter[] @@ -2357,15 +2385,24 @@ ifdef::VK_KHR_present_mode_fifo_latest_ready,VK_EXT_present_mode_fifo_latest_rea At each vertical blanking period, the presentation engine dequeues all successive requests that are ready to be presented from the beginning of the queue. +ifdef::VK_EXT_present_timing,VK_GOOGLE_display_timing[] + If using ifdef::VK_GOOGLE_display_timing[] - If using `apiext:VK_GOOGLE_display_timing` to provide a target present - time, the presentation engine will check the specified time for each + the `apiext:VK_GOOGLE_display_timing` extension +endif::VK_GOOGLE_display_timing[] +ifdef::VK_EXT_present_timing+VK_GOOGLE_display_timing[or] +ifdef::VK_EXT_present_timing[] + the <> + feature +endif::VK_EXT_present_timing[] + to provide a target present + time, the presentation engine checks the specified time for each image. If the target present time is less-than or equal-to the current time, - the presentation engine will dequeue the image and check the next one. -endif::VK_GOOGLE_display_timing[] - The image of the last dequeued request will be presented. - The other dequeued requests will be dropped. + the presentation engine dequeues the image and checks the next one. +endif::VK_EXT_present_timing,VK_GOOGLE_display_timing[] + The image of the last dequeued request is presented. + The other dequeued requests are dropped. endif::VK_KHR_present_mode_fifo_latest_ready,VK_EXT_present_mode_fifo_latest_ready[] ifdef::VK_KHR_shared_presentable_image[] * ename:VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR specifies that the @@ -2712,9 +2749,9 @@ include::{generated}/validity/protos/vkGetPhysicalDevicePresentRectanglesKHR.ado -- endif::VK_BASE_VERSION_1_1,VK_KHR_device_group[] -ifdef::VK_GOOGLE_display_timing[] -include::{chapters}/VK_GOOGLE_display_timing/queries.adoc[] -endif::VK_GOOGLE_display_timing[] +ifdef::VK_EXT_present_timing,VK_GOOGLE_display_timing[] +include::{chapters}/VK_EXT_present_timing/queries.adoc[] +endif::VK_EXT_present_timing,VK_GOOGLE_display_timing[] ifdef::VK_KHR_present_wait[] include::{chapters}/VK_KHR_present_wait/present_wait.adoc[] diff --git a/chapters/VK_KHR_swapchain/wsi.adoc b/chapters/VK_KHR_swapchain/wsi.adoc index 87326aac9a..86897b31a7 100644 --- a/chapters/VK_KHR_swapchain/wsi.adoc +++ b/chapters/VK_KHR_swapchain/wsi.adoc @@ -618,6 +618,13 @@ ifndef::VK_EXT_image_compression_control_swapchain[The] pname:pNext chain must: not include an slink:VkImageCompressionControlEXT structure endif::VK_EXT_image_compression_control[] +ifdef::VK_EXT_present_timing[] + * If none of the <>, + <>, or + <> + features are enabled, pname:flags must: not contain + ename:VK_SWAPCHAIN_CREATE_PRESENT_TIMING_BIT_EXT +endif::VK_EXT_present_timing[] **** ifdef::VKSC_VERSION_1_0[] ifdef::hidden[] @@ -687,6 +694,12 @@ ifdef::VK_KHR_present_wait2[] request associated with slink:VkPresentWait2InfoKHR::pname:presentId on pname:swapchain. endif::VK_KHR_present_wait2[] +ifdef::VK_EXT_present_timing[] + * ename:VK_SWAPCHAIN_CREATE_PRESENT_TIMING_BIT_EXT specifies that features + supported by the swapchain device in + slink:VkPhysicalDevicePresentTimingFeaturesEXT can: be used to collect + timing information or schedule presentation requests at specific times. +endif::VK_EXT_present_timing[] -- [open,refpage='VkSwapchainCreateFlagsKHR',desc='Bitmask of VkSwapchainCreateFlagBitsKHR',type='flags'] @@ -1425,6 +1438,11 @@ applying the following rules in order: * If any of the presents would have a result of ename:VK_ERROR_OUT_OF_DATE_KHR if issued separately then ename:VK_ERROR_OUT_OF_DATE_KHR is returned. +ifdef::VK_EXT_present_timing[] + * If any of the presents would have a result of + ename:VK_ERROR_PRESENT_TIMING_QUEUE_FULL_EXT if issued separately + then ename:VK_ERROR_PRESENT_TIMING_QUEUE_FULL_EXT is returned. +endif::VK_EXT_present_timing[] ifdef::VK_EXT_full_screen_exclusive[] * If any of the presents would have a result of ename:VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT if issued separately @@ -1767,6 +1785,9 @@ include::{generated}/validity/structs/VkDeviceGroupPresentInfoKHR.adoc[] -- endif::VK_BASE_VERSION_1_1,VK_KHR_device_group[] +ifdef::VK_EXT_present_timing[] +include::{chapters}/VK_EXT_present_timing/PresentTimeInfo.adoc[] +endif::VK_EXT_present_timing[] ifdef::VK_GOOGLE_display_timing[] include::{chapters}/VK_GOOGLE_display_timing/PresentTimeInfo.adoc[] endif::VK_GOOGLE_display_timing[] diff --git a/chapters/features.adoc b/chapters/features.adoc index affae29871..4df09ac970 100644 --- a/chapters/features.adoc +++ b/chapters/features.adoc @@ -6457,6 +6457,32 @@ include::{generated}/validity/structs/VkPhysicalDeviceHostImageCopyFeatures.adoc -- endif::VK_BASE_VERSION_1_4,VK_EXT_host_image_copy[] +ifdef::VK_EXT_present_timing[] +[open,refpage='VkPhysicalDevicePresentTimingFeaturesEXT',desc='Structure indicating support for present timing',type='structs'] +-- +The sname:VkPhysicalDevicePresentTimingFeaturesEXT structure is defined as: + +include::{generated}/api/structs/VkPhysicalDevicePresentTimingFeaturesEXT.adoc[] + +This structure describes the following feature: + + * pname:sType is a elink:VkStructureType value identifying this structure. + * pname:pNext is `NULL` or a pointer to a structure extending this + structure. + * [[features-presentTiming]] pname:presentTiming indicates that the + implementation supports fname:vkGetPastPresentationTimingEXT. + * [[features-presentAtAbsoluteTime]] pname:presentAtAbsoluteTime indicates + that the implementation supports specifying absolute target present times. + * [[features-presentAtRelativeTime]] pname:presentAtRelativeTime indicates + that the implementation supports specifying relative target present times. + +:refpage: VkPhysicalDevicePresentTimingFeaturesEXT +include::{chapters}/features.adoc[tag=features] + +include::{generated}/validity/structs/VkPhysicalDevicePresentTimingFeaturesEXT.adoc[] +-- +endif::VK_EXT_present_timing[] + ifdef::VK_NV_present_barrier[] [open,refpage='VkPhysicalDevicePresentBarrierFeaturesNV',desc='Structure indicating support for VK_NV_present_barrier extension',type='structs'] -- diff --git a/chapters/synchronization.adoc b/chapters/synchronization.adoc index d085083b0b..de88178a63 100644 --- a/chapters/synchronization.adoc +++ b/chapters/synchronization.adoc @@ -8473,6 +8473,11 @@ endif::VK_EXT_calibrated_timestamps[] * [[VUID-VkCalibratedTimestampInfoKHR-timeDomain-02354]] pname:timeDomain must: be one of the elink:VkTimeDomainKHR values returned by flink:vkGetPhysicalDeviceCalibrateableTimeDomainsKHR +ifdef::VK_EXT_present_timing[] + * If pname:timeDomain is ename:VK_TIME_DOMAIN_SWAPCHAIN_LOCAL_EXT or + ename:VK_TIME_DOMAIN_PRESENT_STAGE_LOCAL_EXT, the pname:pNext chain + must: include a slink:VkSwapchainCalibratedTimestampInfoEXT structure. +endif::VK_EXT_present_timing[] **** include::{generated}/validity/structs/VkCalibratedTimestampInfoKHR.adoc[] -- @@ -8496,7 +8501,17 @@ ifdef::VK_BASE_VERSION_1_3,VK_KHR_synchronization2[] endif::VK_BASE_VERSION_1_3,VK_KHR_synchronization2[] and are defined to be incrementing according to the <> of the device. - +ifdef::VK_EXT_present_timing[] + * ename:VK_TIME_DOMAIN_PRESENT_STAGE_LOCAL_EXT specifies a time domain + unique to a particular swapchain and a specific present stage. + Timestamp values in this time domain are in units of nanosecond and are + comparable only with other values from the same swapchain and + present stage. + * ename:VK_TIME_DOMAIN_SWAPCHAIN_LOCAL_EXT specifies a time domain unique + to a particular swapchain. + Timestamp values in this time domain are in units of nanosecond and are + comparable only with other values from the same swapchain. +endif::VK_EXT_present_timing[] * ename:VK_TIME_DOMAIN_CLOCK_MONOTONIC_KHR specifies the CLOCK_MONOTONIC time domain available on POSIX platforms. Timestamp values in this time domain are in units of nanoseconds and are @@ -8552,4 +8567,37 @@ QueryPerformanceCounter(&counter); return counter.QuadPart; ---- -- + +ifdef::VK_EXT_present_timing[] +[open,refpage='VkSwapchainCalibratedTimestampInfoEXT',desc='Structure specifying the swapchain to calibrate a swapchain-local timestamp query',type='structs'] +-- +The sname:VkSwapchainCalibratedTimestampInfoEXT structure is defined as: + +include::{generated}/api/structs/VkSwapchainCalibratedTimestampInfoEXT.adoc[] + + * pname:sType is a elink:VkStructureType value identifying this structure. + * pname:pNext is `NULL` or a pointer to a structure extending this + structure. + * pname:swapchain is the swapchain to retrieve the swapchain-local timestamp from. + * pname:presentStage is zero or a tlink:VkPresentStageFlagsEXT value used + to identify a single present stage when calibrating a timestamp in the + ename:VK_TIME_DOMAIN_PRESENT_STAGE_LOCAL_EXT time domain. + * pname:timeDomainId is the id for the opaque time domain being calibrated. + +pname:timeDomainId must: be an id previously reported by +flink:vkGetSwapchainTimeDomainPropertiesEXT for pname:swapchain. If the +pname:timeDomainId is no longer supported by the pname:swapchain, +implementations may: report zero as the calibrated timestamp value. + +.Valid Usage +**** + * If the pname:timeDomain member of the slink:VkCalibratedTimestampInfoKHR structure + in this structure's pname:pNext chain is ename:VK_TIME_DOMAIN_PRESENT_STAGE_LOCAL_EXT, + pname:presentStage must: specify one and only one present stage. +**** + + +include::{generated}/validity/structs/VkSwapchainCalibratedTimestampInfoEXT.adoc[] +-- +endif::VK_EXT_present_timing[] endif::VK_KHR_calibrated_timestamps,VK_EXT_calibrated_timestamps[] diff --git a/proposals/VK_EXT_present_timing.adoc b/proposals/VK_EXT_present_timing.adoc new file mode 100644 index 0000000000..d1f4734c03 --- /dev/null +++ b/proposals/VK_EXT_present_timing.adoc @@ -0,0 +1,715 @@ +// Copyright 2023-2025 The Khronos Group Inc. +// +// SPDX-License-Identifier: CC-BY-4.0 + += VK_EXT_present_timing +:toc: left +:docs: https://docs.vulkan.org/spec/latest/ +:extensions: {docs}appendices/extensions.html# +:sectnums: +ifndef::images[:images: ../images] + +This extension provides facilities for applications using VK_KHR_swapchain to obtain timing information about the presentation engine's display, presentation statistics for each present operation, and to schedule present operations to happen at a specific time. + +== Problem statement + +As rendering systems have become more complex and more deeply buffered, rendering workloads have grown increasingly independent of the presentation process. Different hardware may even be involved. As a consequence, applications are left without a clear way to align the presentation process with other workloads, particularly rendering. + +This can result in visual anomalies such as stutter, or increased input latency, when the frames are not being presented to the user at the time the application was expecting it. This effect may be exacerbated in Fixed Refresh Rate (FRR) scenarios when the display refresh rate is not a factor of the application's rendered frame rate; for example, rendering 50 frames per second on a 60Hz monitor, which will result in some frames being visible for multiple refresh cycles. + +To accomplish smooth animation, applications need to predict and schedule when each frame is going to be displayed so that the application's simulation time, which places the geometry and camera within a scene, closely matches the display time. This requires various timing information about the presentation engine, such as when previous presentable images were actually displayed and when they could have been displayed, as well as the presentation engine's refresh cycle duration. + +Multimedia applications also typically require accurate frame timing in order to closely match the content's expected frame rate and synchronize presentation operations with audio output. + +== Solution Space + +Partial solutions exist to address some of the problems described above: + +* Variable Refresh Rate +* `VK_KHR_present_wait` and `VK_KHR_present_wait2` +* `VK_GOOGLE_display_timing` + +Variable Refresh Rate (VRR) technology can mitigate the effects of stutter, because the display may be able to match the variations in present duration, while FRR displays need to wait for a future refresh cycle if an image was not ready in time for its intended present time. Though this limits some of the visual anomalies, it does not address the issue of providing applications feedback and control over the presentation engine timing. + +`VK_KHR_present_wait` is a Vulkan extension which allows the host to synchronously wait for a present operation to complete. This can be used as a tool to implement efficient frame pacing, but lacks important details such as the latency of the present operation itself, and information about the display timing properties. The `VK_KHR_present_wait` specification itself also has rather loose requirements which may result in inconsistent implementations. + +`VK_GOOGLE_display_timing` is currently the only existing extension which provides a solution to this core problem of interacting with the presentation engine's timeline. However, it is not implementable by all vendors, and lacks enough details to support technologies such as VRR systems. The proposal that follows is heavily inspired by all the work and discussions surrounding `VK_GOOGLE_display_timing`, and provides a more granular approach to its features, allowing for wider vendor adoption. + +== Proposal + +=== Features + +`VK_EXT_present_timing` exposes three new physical device features: +[source,c] +---- +typedef struct VkPhysicalDevicePresentTimingFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 presentTiming; + VkBool32 presentAtAbsoluteTime; + VkBool32 presentAtRelativeTime; +} VkPhysicalDevicePresentTimingFeaturesEXT; +---- + +If `VK_EXT_present_timing` is exposed by the device, `presentTiming` is required to be supported. This feature allows applications to query details about presentation timing of a given swapchain, such as the refresh rate or supported time domains, as well as statistics about individual present operations. + +When supported, `presentAtAbsoluteTime` allows applications to specify an absolute time, in a specific time domain, with each `vkQueuePresentKHR` call. `presentAtRelativeTime` allows applications to specify a relative time instead, specifying a minimum duration before a new image can presented. See <>. + +These features are also advertised for each `VkSurfaceKHR` object with: + +[source,c] +---- +typedef struct VkPresentTimingSurfaceCapabilitiesEXT { + VkStructureType sType; + void* pNext; + VkBool32 presentTimingSupported; + VkBool32 presentAtAbsoluteTimeSupported; + VkBool32 presentAtRelativeTimeSupported; + VkPresentStageFlagsEXT presentStageQueries; +} VkPresentTimingSurfaceCapabilitiesEXT; +---- + +In addition of the present timing and present scheduling features, surfaces also advertise which <> are available to query timings for. + +=== Present stages [[present_stages]] + +It is difficult to define "presentation" while satisfying all implementations, platforms or even display technologies. Thus, this proposal introduces the concept of "present stages": a set of well-defined discrete steps within typical present pipelines. + +[source,c] +---- +typedef enum VkPresentStageFlagBitsEXT { + VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT = 0x00000001, + VK_PRESENT_STAGE_REQUEST_DEQUEUED_BIT_EXT = 0x00000002, + VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_OUT_BIT_EXT = 0x00000004, + VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT = 0x00000008, +} VkPresentStageFlagBitsEXT; +---- + +When queueing a presentation request for a swapchain, a set of present stages is specified to inform the implementation that timing for those stages is desired. See <>. + +* `VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT` marks the end of the set of queue operations enqueued by `vkQueuePresentKHR` on the provided `VkQueue`. These queue operations are implementation-specific; the usual example is a blit to a system-specific internal surface suited for presentation. +* `VK_PRESENT_STAGE_REQUEST_DEQUEUED_BIT_EXT` is the stage after which the presentation request has been dequeued from the swapchain's internal presentation request queue, as specified by the active present mode. +* `VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_OUT_BIT_EXT` is the stage after which data for the first pixel of the presentation request associated with the image has left the presentation engine for the display hardware. +* `VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT` is the stage after which a display hardware has made the first pixel visible for the presentation request associated with the image to be presented. + +Implementations are required to support at least `VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT` in `VkPresentTimingSurfaceCapabilitiesEXT::presentStageQueries` if `presentTimingSupported` is `VK_TRUE` for the surface. + +=== Enabling present timing for a swapchain + +To enable present timing for a swapchain, a new flag must be specified in `VkSwapchainCreateInfoKHR::flags`: `VK_SWAPCHAIN_CREATE_PRESENT_TIMING_BIT_EXT`. + +To provide presentation timing results, implementations need to allocate an internal queue and other resources to collect the necessary timestamps. The size of that queue must be specified by the application with a new function: + +[source,c] +---- +VkResult vkSetSwapchainPresentTimingQueueSizeEXT( + VkDevice device, + VkSwapchainKHR swapchain, + uint32_t size); +---- + +Calling this function multiple times causes the results queue to be reallocated to the new size. If the new size cannot hold all the current outstanding results, `VK_NOT_READY` is returned. + +Calling `vkQueuePresentKHR` with non-zero stage queries allocates a slot in that internal queue, while `vkGetPastPresentationTimingEXT` releases slots when complete results are returned. + +=== Swapchain Timing Information + +==== Timing Properties + +For timing to be meaningful, the application needs to be aware of various properties. Basic properties are exposed in a new structure, `VkSwapchainTimingPropertiesEXT`, which can be retrieved with: + +[source,c] +---- +VkResult vkGetSwapchainTimingPropertiesEXT( + VkDevice device, + VkSwapchainKHR swapchain, + VkSwapchainTimingPropertiesEXT* pSwapchainTimingProperties, + uint64_t* pSwapchainTimingPropertiesCounter); +---- + +Swapchain timing properties may change dynamically at any time without prior notification. For example, enabling power-saving mode on a device may cause it to lower the display panel's refresh rate. To allow applications to detect changes in those properties, a monotonically increasing counter is used by the implementation to identify the current state. This counter increases every time the swapchain properties are modified. `pSwapchainTimingPropertiesCounter` is a pointer to a `uint64_t` set by the implementation to the value of the current timing properties counter. Further updates to those properties are also communicated back to the application when querying presentation timings via `vkGetPastPresentationTimingEXT`. + +`vkGetSwapchainTimingPropertiesEXT` can return `VK_NOT_READY`, because some platforms may not provide timing properties until after at least one image has been presented to the swapchain. If timing properties of the swapchain change, updated results may again only be provided until after at least one additional image has been presented. + +The `VkSwapchainTimingPropertiesEXT` structure is defined as: +[source,c] +---- +typedef struct VkSwapchainTimingPropertiesEXT { + VkStructureType sType; + const void* pNext; + uint64_t refreshDuration; + uint64_t refreshInterval; +} VkSwapchainTimingPropertiesEXT; +---- +* `refreshDuration` is the duration in nanoseconds of the refresh cycle the presentation engine is operating at. +* `refreshInterval` is a duration in nanoseconds indicating the interval between refresh cycles. + +If `refreshDuration` is zero, the presentation engine is unable to provide the current refresh cycle duration. Similarly, if `refreshInterval` is zero, the presentation engine is unable to provide information regarding the dynamics of the refresh cycle. + +If `refreshInterval` is `UINT64_MAX`, the presentation engine is operating in VRR mode, and `refreshDuration` is the minimum duration of a refresh cycle. + +When `refreshInterval` is the same as `refreshDuration`, the presentation engine is operating in FRR mode. + +If `refreshInterval` is not zero and is not `UINT64_MAX`, `refreshDuration` is a multiple of `refreshInterval`. + +==== Time Domains + +Applications also need to query available time domains using: +[source,c] +---- +VkResult vkGetSwapchainTimeDomainPropertiesEXT( + VkDevice device, + VkSwapchainKHR swapchain, + VkSwapchainTimeDomainPropertiesEXT* pSwapchainTimeDomainProperties, + uint64_t* pTimeDomainsCounter); +---- +Similar to <>, supported time domains may change dynamically. `pTimeDomainsCounter` identifies the current list of available time domains, and further internal changes to this list are notified to the application when calling `vkGetPastPresentationTimingEXT`. + +The `VkSwapchainTimeDomainPropertiesEXT` structure is defined as: +[source,c] +---- +typedef struct VkSwapchainTimeDomainPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t timeDomainCount; + VkTimeDomainKHR *pTimeDomains; + uint64_t *pTimeDomainIds; +} VkSwapchainTimeDomainPropertiesEXT; +---- +* `timeDomainCount` is an input specifying the size of the `pTimeDomains` and `pTimeDomainIds` arrays. If `pTimeDomains` and `pTimeDomainIds` are `NULL`, it is set by the implementation upon return of `vkGetSwapchainTimeDomainPropertiesEXT` to the number of available time domains. Otherwise, it is set to the number of elements written in `pTimeDomains` and `pTimeDomainIds`. +* `pTimeDomains` is an array of `VkTimeDomainKHR` currently supported by the swapchain. +* `pTimeDomainIds` is an array of unique identifiers for each supported time domain. Time domains are assigned a unique identifier within a swapchain by the implementation. This id is used to differentiate between multiple swapchain-local time domains of the same scope. + +Two new swapchain-local time domains are added in this proposal as `VkTimeDomainKHR` values: +[source,c] +---- +typedef enum VkTimeDomainKHR { + // ... + VK_TIME_DOMAIN_PRESENT_STAGE_LOCAL_EXT = 1000208000, + VK_TIME_DOMAIN_SWAPCHAIN_LOCAL_EXT = 1000208001, +} VkTimeDomainKHR; +---- +* `VK_TIME_DOMAIN_PRESENT_STAGE_LOCAL_EXT` is a stage-local and swapchain-local time domain. It allows platforms where different presentation stages are handled by independent hardware to report timings in their own time domain. It is required to be supported. +* `VK_TIME_DOMAIN_SWAPCHAIN_LOCAL_EXT` is a swapchain-local time domain, shared by all present stages. + +To calibrate a swapchain-local or stage-local timestamp with another time domain, a new structure can be chained to `VkCalibratedTimestampInfoKHR` and passed to `vkGetCalibratedTimestampsKHR`: +[source,c] +---- +typedef struct VkSwapchainCalibratedTimestampInfoEXT { + VkStructureType sType; + const void* pNext; + VkSwapchainKHR swapchain; + VkPresentStageFlagsEXT presentStage; + uint64_t timeDomainId; +} VkSwapchainCalibratedTimestampInfoEXT; +---- +* `presentStage` is zero to calibrate a `VK_TIME_DOMAIN_SWAPCHAIN_LOCAL_EXT` time domain, or a single `VkPresentStageFlagsEXT` bit to calibrate a `VK_TIME_DOMAIN_PRESENT_STAGE_LOCAL_EXT` from that stage. +* `timeDomainId` is the identifier of the swapchain-local time domain returned by `vkGetSwapchainTimeDomainPropertiesEXT` or `vkGetPastPresentationTimingEXT`. + +=== Presentation timings feedback [[statistics]] + +Applications can obtain timing information about previous presents using: + +[source,c] +---- +VkResult vkGetPastPresentationTimingEXT( + VkDevice device, + const VkPastPresentationTimingInfoEXT* pPastPresentationTimingInfo, + VkPastPresentationTimingPropertiesEXT* pPastPresentationTimingProperties); +---- +`VkPastPresentationTimingInfoEXT` is a simple input structure referencing the `swapchain` to target, allowing for potential future extensions to hook into the `pNext` chain: +[source,c] +---- +typedef struct VkPastPresentationTimingInfoEXT { + VkStructureType sType; + const void* pNext; + VkPastPresentationTimingFlagsEXT flags; + VkSwapchainKHR swapchain; +}; +---- + +The flag bits for `VkPastPresentationTimingFlagsEXT` are defined as: +[source,c] +---- +typedef enum VkPastPresentationTimingFlagBitsEXT { + VK_PAST_PRESENTATION_TIMING_ALLOW_PARTIAL_RESULTS_BIT_EXT = 0x00000001, + VK_PAST_PRESENTATION_TIMING_ALLOW_OUT_OF_ORDER_RESULTS_BIT_EXT = 0x00000002, +} VkPastPresentationTimingFlagBitsEXT; +typedef VkFlags VkPastPresentationTimingFlagsEXT; +---- +* `VK_PAST_PRESENTATION_TIMING_ALLOW_PARTIAL_RESULTS_BIT_EXT` allows `vkGetPastPresentationTimingEXT` to return partial results for presentation requests that have not completed all requested present stages. +* `VK_PAST_PRESENTATION_TIMING_ALLOW_OUT_OF_ORDER_RESULTS_BIT_EXT` allows `vkGetPastPresentationTimingEXT` to return results out of order with respect to the presentation order. + +The `VkPastPresentationTimingPropertiesEXT` structure is defined as: +[source,c] +---- +typedef struct VkPastPresentationTimingPropertiesEXT { + VkStructureType sType; + const void* pNext; + uint64_t timingPropertiesCounter; + uint64_t timeDomainsCounter; + uint32_t presentationTimingCount; + VkPastPresentationTimingEXT* pPresentationTimings; +}; +---- +* `timingPropertiesCounter` is set to the current internal counter of the swapchain's timing properties. +* `timeDomainsCounter` is set to the current internal counter of the swapchain's supported time domain list. +* `presentationTimingCount` specifies the size of the `pPresentationTimings` array. If `pPresentationTimings` is `NULL`, the implementation sets it to the number of pending results available in the swapchain's internal queue. Otherwise, it is overwritten upon return with the number of entries written to `pPresentationTimings`. If the implementation is not able to write all the available results in the provided `pPresentationTimings` array, `VK_INCOMPLETE` is returned. + +Results for presentation requests whose entries in `pPresentationTimings` are marked as complete with `VkPastPresentationTimingEXT::reportComplete` will not be returned anymore. For each of those, a slot in the swapchain's internal results queue is released. Incomplete results for presentation requests will keep being reported in further `vkGetPastPresentationTimingEXT` calls until complete, if the `VK_PAST_PRESENTATION_TIMING_ALLOW_PARTIAL_RESULTS_BIT_EXT` flag is set in `VkPastPresentationTimingInfoEXT::flags`. + +`VkPastPresentationTimingEXT` is defined as: +[source, c] +---- +typedef struct VkPresentStageTimeEXT { + VkPresentStageFlagsEXT stage; + uint64_t time; +} VkPresentStageTimeEXT; + +typedef struct VkPastPresentationTimingEXT { + VkStructureType sType; + const void* pNext; + uint64_t presentId; + uint64_t targetTime; + uint32_t presentStageCount; + VkPresentStageTimeEXT* pPresentStages; + VkTimeDomainKHR timeDomain; + uint64_t timeDomainId; + VkBool32 reportComplete; +} VkPastPresentationTimingEXT; +---- + +* `presentId` is zero or a present id provided to `vkQueuePresentKHR` by adding a `VkPresentId2KHR` to the `VkPresentInfoKHR` pNext chain. Timing results can be correlated to specific presents using this value. +* `targetTime` is the target present time or duration in nanoseconds specified by the application for the associated presentation request in `VkPresentTimingInfoEXT::targetTime`. +* `presentStageCount` and `pPresentStages` contain the timing information for the present stages that were specified in the `VkPresentTimingInfoEXT` passed to the corresponding `vkQueuePresentKHR` call. +* `timeDomain` and `timeDomainId` define the time domain used for `pPresentStages` result times. It may be different than the time domain specified for the associated `vkQueuePresentKHR` call if that time domain was unavailable when the presentation request was processed. +* `reportComplete` indicates whether results for all present stages have been reported. + +`presentStageCount` and `pPresentStages` must be setup by the application to hold enough present stage results for the outstanding presentation requests. + +`presentStageCount` only reports the number of stages which contain definitive results. However, time values in completed `pPresentStages` can still be 0 for multiple reasons. Most notably, it is possible for a presentation request to never reach some present stages, for example if using a present mode that allows images to be replaced in the queue, such as `VK_PRESENT_MODE_FIFO_LATEST_READY_KHR`. Platform-specific events can also cause results for some present stages to be unavailable for a specific presentation request. + +To accommodate for the difference in query latency among the different present stages, timing results can be reported as incomplete when multiple present stages were specified in `VkPresentTimingInfoEXT::presentStageQueries` and the `VK_PAST_PRESENTATION_TIMING_ALLOW_PARTIAL_RESULTS_BIT_EXT` flag is set in `VkPastPresentationTimingInfoEXT::flags`. For example, in more complex topologies of the display system, such as network-based configurations, results for the `VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT` present stage can be available much earlier than for subsequent stages. + +[NOTE] +==== +One key aspect that is notably missing from this extension is the ability to collect timing information from individual "nodes" of the display topology. A typical example would be a system connected to two displays, running in "mirror" mode so that both will display the swapchain contents; in this case, this API does not provide any way to know which monitor the timings correspond to: the only requirement is that the timings are from an entity that is affected by the presentation. There are security considerations to providing such details that are best covered by system-specific extensions. +==== + +=== Scheduling presents [[scheduling]] + +A new struct `VkPresentTimingsInfoEXT` can be appended to the `VkPresentInfoKHR` pNext chain to specify present timing properties: + +[source,c] +---- +typedef struct VkPresentTimingInfoEXT { + VkStructureType sType; + const void* pNext; + VkPresentTimingInfoFlagsEXT flags; + uint64_t targetTime; + uint64_t timeDomainId; + VkPresentStageFlagsEXT presentStageQueries; + VkPresentStageFlagsEXT targetTimeDomainPresentStage; +} VkPresentTimingInfoEXT; + +typedef struct VkPresentTimingsInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t swapchainCount; + const VkPresentTimingInfoEXT* pTimingInfos; +} VkPresentTimingsInfoEXT; +---- +For each swapchain referenced in `VkPresentInfoKHR`, a `VkPresentTimingInfoEXT` is specified: + +* `targetTime` is the absolute or relative time used to schedule this presentation request. +* `timeDomainId` is the id of the time domain used to specify `time` and to query timing results. +* `presentStageQueries` is a bitmask specifying all the present stages the application would like timings for. +* `targetTimeDomainPresentStage` is used to associate a stage-local time domain with a specific present stage. + +If `presentStageQueries` is not zero, and the swapchain's internal timing queue is full, calling `vkQueuePresentKHR` yields a new error: `VK_ERROR_PRESENT_TIMING_QUEUE_FULL_EXT`. + +The semantics of specifying a target present time only apply to FIFO present modes (`VK_PRESENT_MODE_FIFO_KHR`, `VK_PRESENT_MODE_FIFO_RELAXED_KHR` and `VK_PRESENT_MODE_FIFO_LATEST_READY_KHR`). When attempting to dequeue a presentation request from the FIFO queue, the presentation engine checks the current time against the target time. + +The `VkPresentTimingInfoFlags` flags are defined as: +[source,c] +---- +typedef enum VkPresentTimingInfoFlagBitsEXT { + VK_PRESENT_TIMING_INFO_PRESENT_AT_RELATIVE_TIME_BIT_EXT = 0x00000001, + VK_PRESENT_TIMING_INFO_PRESENT_AT_NEAREST_REFRESH_CYCLE_BIT_EXT = 0x00000002 +} VkPresentTimingInfoFlagBitsEXT; +typedef VkFlags VkPresentTimingInfoFlagsEXT; +---- +`VK_PRESENT_TIMING_INFO_PRESENT_AT_RELATIVE_TIME_BIT_EXT` specifies whether `time` is to be interpreted as an absolute or a relative time value. If `time` is interpreted as an absolute time, it specifies the earliest time in nanoseconds at which the image should be visible. Otherwise, if it is interpreted as a relative time, it specifies the minimum duration in nanoseconds the previously presented image should be visible. + +If `VK_PRESENT_TIMING_INFO_PRESENT_AT_NEAREST_REFRESH_CYCLE_BIT_EXT` is set, it indicates that the application would prefer the image to be made visible during the refresh cycle that is closest to the target present time, even if that refresh cycle starts earlier than the specified `time`. + +[NOTE] +==== +More specifically, the implementation attempts to align the `VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT` present stage with the requested target present time. +==== + +[NOTE] +==== +To maintain a constant image present duration (IPD), applications should use timing information collected via `vkGetPastPresentationTimingEXT` to determine the target time of each present. If the presentation engine is operating with a fixed refresh rate, the application's IPD should be a multiple of `VkSwapchainTimingPropertiesEXT::refreshInterval`. That is, the quanta for changing the IPD is `refreshInterval`. For example, if `refreshDuration` is 16.67ms, the IPD can be 16.67ms, 33.33ms, 50.0ms, etc. +==== + +== Examples + +=== Enabling present timing for a swapchain + +[source, c] +---- + // Query device features + VkPhysicalDevicePresentTimingFeaturesEXT deviceFeaturesPresentTiming = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_TIMING_FEATURES_EXT + }; + + VkPhysicalDeviceFeatures2 features2 = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, + .pNext = &deviceFeaturesPresentTiming + }; + + vkGetPhysicalDeviceFeatures2(physicalDevice, &features2); + + // Create device + // (...) + + // Create swapchain + VkSwapchainCreateInfoKHR swapchainCreateInfo = { + .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, + .pNext = NULL, + .flags = VK_SWAPCHAIN_CREATE_PRESENT_TIMING_BIT_EXT + // (...) + }; + + result = vkCreateSwapchainKHR(device, &swapchainCreateInfo, NULL, &swapchain); + + // Query timing properties and time domains + // Note: On some systems, this may only be available after some + // presentation requests have been processed. + VkSwapchainTimingPropertiesEXT swapchainTimingProperties = { + .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_TIMING_PROPERTIES_EXT, + .pNext = NULL + }; + + uint64_t currentTimingPropertiesCounter = 0; + result = vkGetSwapchainTimingPropertiesEXT(device, swapchain, &swapchainTimingProperties, ¤tTimingPropertiesCounter); + + uint64_t currentTimeDomainsCounter = 0; + VkSwapchainTimeDomainPropertiesEXT timeDomains = { + .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_TIME_DOMAIN_PROPERTIES_EXT, + .pNext = NULL, + .timeDomainCount = 0, + .pTimeDomains = NULL, + .pTimeDomainIds = NULL + }; + + result = vkGetSwapchainTimeDomainPropertiesEXT(device, swapchain, &timeDomains, NULL); + timeDomains.pTimeDomains = (VkTimeDomainKHR *) malloc(timeDomains.timeDomainCount * sizeof(VkTimeDomainKHR)); + timeDomains.pTimeDomainIds = (uint64_t *) malloc(timeDomains.timeDomainCount * sizeof(uint64_t)); + result = vkGetSwapchainTimeDomainPropertiesEXT(device, swapchain, &timeDomains, ¤tTimeDomainsCounter); + + // Find the ID of the current VK_TIME_DOMAIN_SWAPCHAIN_LOCAL_EXT time domain + uint64_t swapchainLocalTimeDomainId = FindTimeDomain(&timeDomains, VK_TIME_DOMAIN_SWAPCHAIN_LOCAL_EXT); + + // Allocate internal queue to collect present timing results + const uint32_t maxTimingCount = GetMaxTimingCount(); // Default to sane value, e.g. swapchainImageCount * 2 + result = vkSetSwapchainPresentTimingQueueSizeEXT(device, swapchain, maxTimingCount); + + // (Start presenting...) +---- + +=== Query presentation timing results + +[source, c] +---- + // See previous examples for how to get the timing properties and time domain IDs + uint64_t currentTimingPropertiesCounter = GetCurrentTimingPropertiesCounter(...); + uint64_t currentTimeDomainsCounter = GetCurrentTimeDomainsCounter(...); + uint64_t timeDomainId = GetDesiredTimeDomain(...); + VkPresentStageFlagsEXT presentStageQueries = GetDesiredPresentStageQueries(...); + uint32_t pendingPresentResults = 0; + + VkPastPresentationTimingEXT *timings = (VkPastPresentationTimingEXT *) malloc(maxTimingCount * sizeof(VkPastPresentationTimingEXT)); + VkPresentStageTimeEXT *stageTimes = (VkPresentStageTimeEXT *) malloc(maxStageCount * maxTimingCount * sizeof(VkPresentStageTimeEXT)); + + for (uint32_t i = 0; i < maxTimingCount; ++i) { + timings[i].sType = VK_STRUCTURE_TYPE_PAST_PRESENTATION_TIMING_EXT; + timings[i].pNext = NULL; + timings[i].pPresentStages = stageTimes + i * maxStageCount; + } + + while (presenting) { + // Render & Present + // (...) + VkPresentTimingInfoEXT timingInfo = { + .sType = VK_STRUCTURE_TYPE_PRESENT_TIMING_INFO_EXT, + .pNext = NULL, + .flags = 0, + .targetTime = 0, + .timeDomainId = timeDomainId, + .presentStageQueries = presentStageQueries + }; + + VkPresentTimingsInfoEXT presentTimingsInfo = { + .sType = VK_STRUCTURE_TYPE_PRESENT_TIMINGS_INFO_EXT, + .pNext = NULL, + .swapchainCount = 1, + .pTimingInfos = &timingInfo + }; + + presentInfoTail.pNext = &presentTimingsInfo; + result = vkQueuePresentKHR(...); + + if (result == VK_ERROR_PRESENT_TIMING_QUEUE_FULL_EXT) { + // We are presenting faster than results are coming in. We can either + // wait to drain the results queue, grow the results queue, or + // present again without asking for present timing data. + // (...) + } + + if (result != VK_SUCCESS) { + // Handle vkQueuePresentKHR other non-success return values + // (...) + } + + // Track the number of pending present results, each present taking one slot in the internal queue + pendingPresentResults++; + + VkPastPresentationTimingInfoEXT pastTimingInfo = { + .sType = VK_STRUCTURE_TYPE_PAST_PRESENTATION_TIMING_INFO_EXT, + .pNext = NULL, + .flags = 0, + .swapchain = swapchain + }; + + VkPastPresentationTimingPropertiesEXT pastTimingProperties = { + .sType = VK_STRUCTURE_TYPE_PAST_PRESENTATION_TIMING_PROPERTIES_EXT, + .pNext = NULL, + .timingPropertiesCounter = 0, + .timeDomainsCounter = 0, + .presentationTimingCount = maxTimingCount, + .pPresentationTimings = timings + }; + + result = vkGetPastPresentationTimingEXT(device, &pastTimingInfo, &pastTimingProperties); + + if (result != VK_SUCCESS) { + // Handle error + // (...) + } + + if (pastTimingProperties.timingPropertiesCounter != currentTimingPropertiesCounter) { + currentTimingPropertiesCounter = pastTimingProperties.timingPropertiesCounter; + // Update swapchain timing properties + // (...) + } + + if (pastTimingProperties.timeDomainsCounter != currentTimeDomainsCounter) { + currentTimeDomainsCounter = pastTimingProperties.timeDomainsCounter; + // Update time domains + // (...) + } + + pendingPresentResults -= pastTimingProperties.presentationTimingCount; + + // Process timing results + } +---- + +=== Handling `VK_ERROR_PRESENT_TIMING_QUEUE_FULL_EXT`: waiting for results + +[source, c] +---- + VkSwapchainTimingPropertiesEXT swapchainTimingProperties = { + .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_TIMING_PROPERTIES_EXT, + .pNext = NULL + }; + + // Initialize timing properties, time domains, timing results queue, etc. + // (...) + + while (presenting) { + // Render & Present + // (...) + + result = vkQueuePresentKHR(...); + + if (result == VK_ERROR_PRESENT_TIMING_QUEUE_FULL_EXT) { + // Synchronously wait for timing results to be available. There + // is no synchronization built in the API for this, so the + // application must poll. We use the refresh cycle duration as + // our poll interval in this example. + + VkPastPresentationTimingInfoEXT pastTimingInfo = { + .sType = VK_STRUCTURE_TYPE_PAST_PRESENTATION_TIMING_INFO_EXT, + .pNext = NULL, + .flags = 0, + .swapchain = swapchain + }; + + VkPastPresentationTimingPropertiesEXT pastTimingProperties = { + .sType = VK_STRUCTURE_TYPE_PAST_PRESENTATION_TIMING_PROPERTIES_EXT, + .pNext = NULL, + .timingPropertiesCounter = 0, + .timeDomainsCounter = 0, + .presentationTimingCount = 0, + .pPresentationTimings = NULL + }; + + // Note: this loop can result in stutter if the presentation engine takes a long time to + // return results. After a couple tries, it would be reasonable to bail and present without + // requesting timing results. + uint64_t sleepDuration = swapchainTimingProperties.refreshDuration; + + do { + result = vkGetPastPresentationTimingEXT(device, &pastTimingInfo, &pastTimingProperties); + + if (result != VK_SUCCESS) { + // Handle error + // (...) + } + + if (pastTimingProperties.timingPropertiesCounter != currentTimingPropertiesCounter) { + currentTimingPropertiesCounter = pastTimingProperties.timingPropertiesCounter; + result = vkGetSwapchainTimingPropertiesEXT(device, swapchain, &swapchainTimingProperties, ¤tTimingPropertiesCounter); + + if (result != VK_SUCCESS) { + // Handle error + // (...) + } + + sleepDuration = swapchainTimingProperties.refreshDuration; + } + + // Check pastTimingProperties.timeDomainsCounter as well + // (...) + + if (pastTimingProperties.presentationTimingCount > 0) { + // We have results, break out of the loop and process them + break; + } else { + // We do not have results yet, sleep for the refresh cycle duration + SleepNS(sleepDuration); + } + + } while (pastTimingProperties.presentationTimingCount == 0); + + // Actually retrieve the timing results now that we know they are available + // (...) + } + + // (...) + } +---- + +=== Setting absolute target present times + +[source, c] +---- + // See previous examples for swapchain setup and timing results retrieval + // (...) + uint64_t currentPresentId = 1; + uint64_t lastResultPresentId = 0; + uint64_t lastResultPresentTime = 0; + uint64_t targetIPD = defaultPresentDuration; + + while (presenting) { + uint64_t targetPresentTime; + + if (lastResultDequeuedTime != 0) { + targetPresentTime = lastResultDequeuedTime + (currentPresentId - lastResultPresentId) * targetIPD; + } else { + targetPresentTime = 0; // Present ASAP until we have a baseline + } + + // Render & Present + // Note: make sure the rendering is doing a world simulation step that matches the targetIPD + // (...) + + VkPresentTimingInfoEXT presentTimingInfo = { + .sType = VK_STRUCTURE_TYPE_PRESENT_TIMING_INFO_EXT, + .pNext = NULL, + .flags = VK_PRESENT_TIMING_INFO_PRESENT_AT_NEAREST_REFRESH_CYCLE_BIT_EXT, + .targetTime = targetPresentTime, + .timeDomainId = timeDomainId, + .presentStageQueries = VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_OUT_BIT_EXT + }; + + VkPresentTimingsInfoEXT presentTimingsInfo = { + .sType = VK_STRUCTURE_TYPE_PRESENT_TIMINGS_INFO_EXT, + .pNext = NULL, + .swapchainCount = 1, + .pTimingInfos = &presentTimingInfo + }; + + presentInfoTail.pNext = &presentTimingsInfo; + + result = vkQueuePresentKHR(...); + + if (result != VK_SUCCESS) { + // Handle error + // (...) + } + + result = vkGetPastPresentationTimingEXT(device, &pastTimingInfo, &pastTimingProperties); + + if (result != VK_SUCCESS) { + // Handle error + // (...) + } + + // Analyze the timing results and adjust targetIPD if needed + // (...) + + currentPresentId++; + } +---- + + +== Issues + +=== What are the key differences to `VK_GOOGLE_display_timing`? + +The major API changes from `VK_GOOGLE_display_timing` are: + +* Introduction of present stages with `VkPresentStageFlagsEXT` +* Rely on `VK_KHR_present_id2` to specify present Ids +* Expose features in physical device and surface features +* Variable refresh rate indicator +* Progressive timings feedback +* Allow time domain selection, with new opaque domains dedicated to swapchains +* Allow for relative present times + +Compared to `VK_GOOGLE_display_timing`, stricter specification language is also used to allow for more consistent and wider adoption among implementors. + +=== RESOLVED: How does the application choose the internal queue size to pass in `vkSetSwapchainPresentTimingQueueSize`? + +Use reasonable default values, such as a multiple of the swapchain image count. + +Because presenting when the swapchain's internal timing queue is full is considered an error, the latency of the timing results effectively can end up throttling the present rate if the internal queue is small enough. The topology of the presentation engine being generally opaque to applications, there is no indication of the feedback latency before the application starts presenting. + +Applications which run into feedback latency issues can resize the internal timing queue. + +=== RESOLVED: Do we need an API to synchronously wait for present timing feedback? + +No, because some implementations cannot provide a synchronous wait on those results. However, allow applications to call vkGetPastPresentationTimingEXT without external synchronization. + +=== PROPOSED: How do we handle dynamic surface properties updates? + +`VkSurfaceKHR` objects capabilities are dynamic and can respond to a lot of different events. For example, when an application user moves a window to another monitor, it is possible for the underlying surface's capabilities to change. In the context of this extension, this means that some of the parameters set in a `VkPresentTimingInfoEXT` struct and passed to `vkQueuePresentKHR`, for example, may not be valid by the time the presentation engine processes the presentation request. +The implementation must thus be able to handle parameters that have become invalid without the application's knowledge. In those cases, the specification provides sane "fallback" behaviors, e.g. reporting timestamps in a different time domain, reporting 0 values when unavailable, etc. + +=== PROPOSED: How are dropped presentation requests handled? + +Implementations will return a time of 0 for all present stages that occur after the request is dropped. In the future, `VkPastPresentationTimingEXT` could be extended to include a flag or status bitfield to indicate the reason the request was dropped. + +=== PROPOSED: How do different variable refresh rate technologies interact with this extension? + +Expose multiple durations in `VkSwapchainTimingPropertiesEXT` to describe the variable refresh rate properties of the swapchain. One value is the minimum refresh cycle duration, while the other is the granularity at which the refresh cycle duration can be adjusted when presenting. This allows to support FRR, VRR, and, at least partially, Adaptive Refresh Rate (ARR) technologies. Note these values only reflect the current swapchain's behavior, and may be different from the actual display hardware capabilities, which need to be queried separately. + +=== PROPOSED: How does an application adjust its IPD to match the swapchain's refresh rate? + +Applications can know if they are presenting late by comparing a presentation request's timing results against their corresponding target present time. + +If images are consistently presented at their desired present time, applications can query results for the `VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT` and `VK_PRESENT_STAGE_REQUEST_DEQUEUED_BIT_EXT` stages, and subtract those values to get an estimate of how early presentation requests are. Applications can adjust their IPD or device workload in consequence. diff --git a/scripts/xml_consistency.py b/scripts/xml_consistency.py index cc85d394f2..441a33382b 100755 --- a/scripts/xml_consistency.py +++ b/scripts/xml_consistency.py @@ -145,6 +145,8 @@ 'vkCreatePipelineBinariesKHR', 'vkGetPipelineBinaryDataKHR', 'vkConvertCooperativeVectorMatrixNV', + 'vkGetPastPresentationTimingEXT', + 'vkGetSwapchainTimeDomainPropertiesEXT', )) # Exceptions to unknown structure type constants. diff --git a/xml/vk.xml b/xml/vk.xml index f3c3fa1d5b..2e585ebc21 100644 --- a/xml/vk.xml +++ b/xml/vk.xml @@ -522,6 +522,9 @@ typedef void* MTLSharedEvent_id; typedef VkFlags VkTileShadingRenderPassFlagsQCOM; typedef VkFlags64 VkPhysicalDeviceSchedulingControlsFlagsARM; typedef VkFlags VkSurfaceCreateFlagsOHOS; + typedef VkFlags VkPresentStageFlagsEXT; + typedef VkFlags VkPastPresentationTimingFlagsEXT; + typedef VkFlags VkPresentTimingInfoFlagsEXT; typedef VkFlags VkSwapchainImageUsageFlagsOHOS; typedef VkFlags VkPerformanceCounterDescriptionFlagsARM; @@ -985,6 +988,9 @@ typedef void* MTLSharedEvent_id; + + + @@ -3589,6 +3595,85 @@ typedef void* MTLSharedEvent_id; void* pNext VkBool32 presentWait2vkWaitForPresent2KHR is supported + + VkStructureType sType + void* pNext + VkBool32 presentTimingvkGetPastPresentationTimingEXT is supported + VkBool32 presentAtAbsoluteTimeAbsolute time can be used to specify present time + VkBool32 presentAtRelativeTimeRelative time can be used to specify present duration + + + VkStructureType sType + void* pNext + VkBool32 presentTimingSupportedpresentation timings of the surface can be queried using vkGetPastPresentationTimingEXT + VkBool32 presentAtAbsoluteTimeSupportedsurface can be presented using absolute times + VkBool32 presentAtRelativeTimeSupportedsurface can be presented using relative times + VkPresentStageFlagsEXT presentStageQueriespresent stages that can be queried + + + VkStructureType sType + void* pNext + uint64_t refreshDurationNumber of nanoseconds from the start of one refresh cycle to the next + uint64_t refreshIntervalInterval in nanoseconds between refresh cycles durations + + + VkStructureType sType + void* pNext + uint32_t timeDomainCount + VkTimeDomainKHR* pTimeDomainsAvailable time domains to use with the swapchain + uint64_t* pTimeDomainIdsUnique identifier for a time domain + + + VkPresentStageFlagsEXT stage + uint64_t timeTime in nanoseconds of the associated stage + + + VkStructureType sType + const void* pNext + VkPastPresentationTimingFlagsEXT flags + VkSwapchainKHR swapchain + + + VkStructureType sType + void* pNext + uint64_t timingPropertiesCounter + uint64_t timeDomainsCounter + uint32_t presentationTimingCount + VkPastPresentationTimingEXT* pPresentationTimings + + + VkStructureType sType + void* pNext + uint64_t presentIdApplication-provided identifier, previously given to vkQueuePresentKHR + uint64_t targetTimeApplication-provided present time + uint32_t presentStageCountNumber of present stages results available in pPresentStages + VkPresentStageTimeEXT* pPresentStagesReported timings for each present stage + VkTimeDomainKHR timeDomainTime domain of the present stages + uint64_t timeDomainIdTime domain id of the present stages + VkBool32 reportCompleteVK_TRUE if all the present stages have been reported + + + VkStructureType sType + const void* pNext + uint32_t swapchainCountCopy of VkPresentInfoKHR::swapchainCount + const VkPresentTimingInfoEXT* pTimingInfosPresent timing details for each swapchain + + + VkStructureType sType + const void* pNext + VkPresentTimingInfoFlagsEXT flags + uint64_t targetTime + uint64_t timeDomainIdTime domain to interpret the target present time and collect present stages timings with + VkPresentStageFlagsEXT presentStageQueriesPresent stages to collect timing information for + VkPresentStageFlagsEXT targetTimeDomainPresentStageTarget stage-local time domain's stage + + + VkStructureType sType + const void* pNext + VkSwapchainKHR swapchain + VkPresentStageFlagsEXT presentStage + uint64_t timeDomainId + Display primary in chromaticity coordinates VkStructureType sType @@ -12795,7 +12880,20 @@ typedef void* MTLSharedEvent_id; - + + + + + + + + + + + + + + @@ -14678,7 +14776,7 @@ typedef void* MTLSharedEvent_id; VkFence fence uint32_t* pImageIndex - + VkResult vkQueuePresentKHR VkQueue queue const VkPresentInfoKHR* pPresentInfo @@ -17588,6 +17686,32 @@ typedef void* MTLSharedEvent_id; const VkShaderStageFlagBits* pStages const VkShaderEXT* pShaders + + VkResult vkSetSwapchainPresentTimingQueueSizeEXT + VkDevice device + VkSwapchainKHR swapchain + uint32_t size + + + VkResult vkGetSwapchainTimingPropertiesEXT + VkDevice device + VkSwapchainKHR swapchain + VkSwapchainTimingPropertiesEXT* pSwapchainTimingProperties + uint64_t* pSwapchainTimingPropertiesCounter + + + VkResult vkGetSwapchainTimeDomainPropertiesEXT + VkDevice device + VkSwapchainKHR swapchain + VkSwapchainTimeDomainPropertiesEXT* pSwapchainTimeDomainProperties + uint64_t* pTimeDomainsCounter + + + VkResult vkGetPastPresentationTimingEXT + VkDevice device + const VkPastPresentationTimingInfoEXT* pPastPresentationTimingInfo + VkPastPresentationTimingPropertiesEXT* pPastPresentationTimingProperties + VkResult vkGetScreenBufferPropertiesQNX VkDevice device @@ -23151,11 +23275,46 @@ typedef void* MTLSharedEvent_id; - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +