From c3e1bf24e818ed2165ee80014098b3846b5eeeea Mon Sep 17 00:00:00 2001 From: Ian Elliott Date: Thu, 10 May 2018 15:01:21 -0600 Subject: [PATCH 1/5] WIP: Add the VK_EXT_present_timing extension This extension allows an application that uses the VK_KHR_swapchain extension to obtain information about the presentation engine's display, to obtain timing information about each present operation, and to schedule a present to happen at a specific time. Applications can use this to minimize various visual anomalies (e.g., stuttering). --- appendices/VK_EXT_present_timing.adoc | 255 ++++++++++ appendices/glossary.adoc | 38 ++ .../PresentTimeInfo.adoc | 183 ++++++++ chapters/VK_EXT_present_timing/queries.adoc | 441 ++++++++++++++++++ .../VK_GOOGLE_display_timing/queries.adoc | 86 +--- chapters/VK_KHR_surface/wsi.adoc | 14 +- chapters/VK_KHR_swapchain/wsi.adoc | 13 + chapters/synchronization.adoc | 8 +- xml/vk.xml | 102 +++- 9 files changed, 1043 insertions(+), 97 deletions(-) create mode 100644 appendices/VK_EXT_present_timing.adoc create mode 100644 chapters/VK_EXT_present_timing/PresentTimeInfo.adoc create mode 100644 chapters/VK_EXT_present_timing/queries.adoc diff --git a/appendices/VK_EXT_present_timing.adoc b/appendices/VK_EXT_present_timing.adoc new file mode 100644 index 0000000000..ef3b9e7ea4 --- /dev/null +++ b/appendices/VK_EXT_present_timing.adoc @@ -0,0 +1,255 @@ +// Copyright (c) 2017-2022 Khronos Group. +// +// SPDX-License-Identifier: CC-BY-4.0 + +include::{generated}/meta/{refprefix}VK_EXT_present_timing.adoc[] + +*Last Modified Date*:: + 2020-07-06 +*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 + +This device extension allows an application that uses the +`<>` 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) must 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. +The special value of zero for pname:refreshDuration is used to +indicate the condition where the platform cannot yet answer the query. + +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 these 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:VkPastPresentationTimingEXT structure that is +returned by flink:vkGetPastPresentationTimingEXT will contain +pname:timeDomainChanged, which will be ename:VK_TRUE 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? + +*PROPOSED*: 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? + +*PROPOSED*: Have a query to determine the time domain. +This extension will define some return values, including some that are +platform-specific. +Other extensions can add other time domains. + + +6) What Time to use for targetPresentTime for Early Images? + +*PROPOSED*: Have no query for determining the current time in the PE’s time +domain; and do allow the special value of zero for targetPresentTime and +idealPresentTime, meaning that there is no target nor ideal time. + +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 nor idealPresentTime is requested. +Later, once the application has obtained feedback, it can specify +targetPresentTime and idealPresentTime. + + +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? + +*UNRESOLVED*: 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 long. +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. + +Is there value in having a query for the application to know how long it may +have to wait for feedback? +Can such a query be reasonably answered by the driver? + +Is there other interesting information in this space that we may wish to +capture? + + +9) Do we have a query(s) about the number of VkPastPresentationTimingEXT +structs to keep? + +*UNRESOLVED*: At the Montreal F2F, there was discussion about how much +feedback that the driver needs to keep and/or how much feedback that +the application needs to be able to query. + +The way that the LunarG cube demo (official WSI example code) used +VK_GOOGLE_display_timing, and what is proposed for the new extension is that +the application query what feedback is available during every render-present +loop. +If the application never skips querying for feedback, and always obtains +whatever feedback is available, there doesn’t seem much need for such a +query(s). +What I saw with the cube demo on a Pixel phone was that most of the time, the +application obtained feedback for 1 previous present. +Occasionally, it would get 2 VkPastPresentationTimingEXT structs on time and +then 0 the next (or vice versa). + +Perhaps, a video player application might present several images at once, and +then later get feedback for several images at the same time. +That would be the most-likely use-case that I can come up with for why a query +might be useful. +Is that compelling enough? + +What might the model for the query(s) be? +Potentially the application can tell the driver how many presents it might do +at a time, and the driver can use that to size its internal buffer. +Is there value in having a query that would influence the driver’s behavior +(beyond what’s provided for in the currently-proposed API)? + +10) How is the SWAPCHAIN_LOCAL time domain used with the calibrated +timestamps extension? + +PROPOSED: Define a struct to chain into VkCalibratedTimestampInfoEXT::pNext +that specifies a swapchain. +Is anything additional needed for +vkGetPhysicalDeviceCalibrateableTimeDomainsEXT, or are swapchain-local +timestamps always calibrateable or always not calibrateable for a given +device? + +11) Should VK_PRESENT_MODE_FIFO_LATEST_READY_EXT be part of this extension, +or split out into its own extension? + +PROPOSED: 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 diff --git a/appendices/glossary.adoc b/appendices/glossary.adoc index 47817f643a..73fa4c99f5 100644 --- a/appendices/glossary.adoc +++ b/appendices/glossary.adoc @@ -770,6 +770,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. @@ -862,6 +867,18 @@ 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). + 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. @@ -1068,6 +1085,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 @@ -1596,6 +1618,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 @@ -1618,6 +1645,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..28fcee4236 --- /dev/null +++ b/chapters/VK_EXT_present_timing/PresentTimeInfo.adoc @@ -0,0 +1,183 @@ +// Copyright (c) 2014-2022 Khronos Group. +// +// SPDX-License-Identifier: CC-BY-4.0 + +[open,refpage='VkPresentTimesInfoEXT',desc='The earliest time each image should be presented',type='structs'] +-- + +When the `<>` extension is enabled, additional +fields can: be specified that allow an application to specify the earliest +time that an image should be displayed. +This allows an application to avoid stutter that is caused by an image being +displayed earlier than planned. +Such stuttering can occur with both fixed and variable-refresh-rate +displays, because stuttering occurs when the geometry is not correctly +positioned for when the image is displayed. +An application can: instruct the presentation engine that an image should +not be displayed earlier than a specified time by including the +sname:VkPresentTimesInfoEXT structure in the pname:pNext chain of the +sname:VkPresentInfoKHR structure. + +The sname:VkPresentTimesInfoEXT structure is defined as: + +include::{generated}/api/structs/VkPresentTimesInfoEXT.adoc[] + + * pname:sType is the type of this structure. + * pname:pNext is `NULL` or a pointer to an extension-specific structure. + * pname:swapchainCount is the number of swapchains being presented to by + this command. + * pname:pTimes is `NULL` or a pointer to an array of + sname:VkPresentTimeEXT elements with pname:swapchainCount entries. + If not `NULL`, each element of pname:pTimes contains the earliest time + to present the image corresponding to the entry in the + sname:VkPresentInfoKHR::pname:pImageIndices array. + +.Valid Usage +**** + * pname:swapchainCount must: be the same value as + sname:VkPresentInfoKHR::pname:swapchainCount, where + sname:VkPresentInfoKHR is in the pname:pNext chain of this + sname:VkPresentTimesInfoEXT structure. +**** + +include::{generated}/validity/structs/VkPresentTimesInfoEXT.adoc[] +-- + +[open,refpage='VkPresentTimeEXT',desc='Specifying when an image should be presented',type='structs'] +-- + +The sname:VkPresentTimeEXT union contains either a +slink:VkAbsolutePresentTimeEXT or a slink:VkRelativePresentTimeEXT +structure, defined as: + +include::{generated}/api/structs/VkPresentTimeEXT.adoc[] + +include::{generated}/validity/structs/VkPresentTimeEXT.adoc[] +-- + +[open,refpage='VkAbsolutePresentTimeEXT',desc='Specifying the earliest time an image should be presented',type='structs'] +-- + +The sname:VkAbsolutePresentTimeEXT structure is defined as: + +include::{generated}/api/structs/VkAbsolutePresentTimeEXT.adoc[] + + * pname:presentID is an application-provided identification value. + If non-zero, flink:vkGetPastPresentationTimingEXT will return a + slink:VkPastPresentationTimingEXT struct with the timing information + associated with the present to the associated swapchain for this + call to flink:vkQueuePresentKHR, including this value being in the + pname:presentID member of the slink:VkPastPresentationTimingEXT + struct. + In order to be useful to the application, it should: be unique within + some period of time that is meaningful to the application. + * pname:targetPresentTime, if non-zero, specifies the earliest time the + application wants the image to be displayed to the user. + pname:targetPresentTime is a time in nanoseconds, according to the + time-domain being used. + A value of zero specifies that the presentation engine may: display the + image at any time. + * pname:idealPresentTime provides an indication to the presentation + engine of what the application desires its IPD to become. + An application can: set pname:idealPresentTime to the same value + as pname:targetPresentTime, indicating that the application + desires its IPD to remain steady. + A value earlier than + pname:targetPresentTime indicates that the application desires to + shorten its IPD. + A value later than pname:targetPresentTime + indicates that the application desires to lengthen its IPD. + The presentation engine will provide feedback on this value in the + data returned by flink:vkGetPastPresentationTimingEXT. + * pname:presentSlop is the period of time in nanoseconds before + pname:targetPresentTime that the presentation engine may: display + the image. + +If pname:targetPresentTime is non-zero, the presentation engine should: +not display the image to the user at a time earlier than +(pname:targetPresentTime - pname:presentSlop). + +Setting pname:targetPresentTime to zero is useful when the application +desires to provide a non-zero pname:presentID in order to get back timing +information from flink:vkGetPastPresentationTimingEXT, but does not wish +to set a pname:targetPresentTime. + +Providing a pname:presentSlop enables the application to indicate to the +presentation engine to display the image within this period if a vertical +blanking period occurs on FRR displays. + +[NOTE] +.Note +==== +The pname:presentSlop is used to avoid unintentionally missing a vertical +blanking period on FRR displays due to rounding errors or drift between +clocks. +A suggested value for pname:presentSlop is half the _Refresh Rate_. +==== + +include::{generated}/validity/structs/VkAbsolutePresentTimeEXT.adoc[] + +-- + +[open,refpage='VkRelativePresentTimeEXT',desc='Specifying the minimum duration an image should be presented',type='structs'] +-- + +The sname:VkRelativePresentTimeEXT structure is defined as: + +include::{generated}/api/structs/VkRelativePresentTimeEXT.adoc[] + + * pname:presentID is an application-provided identification value. + If non-zero, flink:vkGetPastPresentationTimingEXT will return a + slink:VkPastPresentationTimingEXT struct with the timing information + associated with the present to the associated swapchain for this + call to flink:vkQueuePresentKHR, including this value being in the + pname:presentID member of the slink:VkPastPresentationTimingEXT + struct. + In order to be useful to the application, it should: be unique within + some period of time that is meaningful to the application. + * pname:minPresentDuration, if non-zero, specifies the minimum duration + in nanoseconds the application wants the image to be displayed to the + user. + A value of zero specifies that the presentation engine may: display the + image for any duration. + * pname:idealPresentDuration provides an indication to the presentation + engine of what the application desires its IPD to become. + An application can: set pname:idealPresentDuration to the same value + as pname:minPresentDuration, indicating that the application + desires its IPD to remain steady. + A value smaller than + pname:minPresentDuration indicates that the application desires to + shorten its IPD. + A value larger than pname:minPresentDuration + indicates that the application desires to lengthen its IPD. + The presentation engine will provide feedback on this value in the + data returned by flink:vkGetPastPresentationTimingEXT. + * pname:presentSlop is the period of time in nanoseconds before + pname:minPresentDuration elapses that the presentation engine may: + display the image. + +If pname:minPresentDuration is non-zero, the presentation engine should: +display the image to the user for a minimum duration of +(pname:minPresentDuration - pname:presentSlop) nanoseconds. + +Setting pname:minPresentDuration to zero is useful when the application +desires to provide a non-zero pname:presentID in order to get back timing +information from flink:vkGetPastPresentationTimingEXT, but does not wish +to set a pname:minPresentDuration. + +Providing a pname:presentSlop enables the application to indicate to the +presentation engine to display the image within this period if a vertical +blanking period occurs on FRR displays. + +[NOTE] +.Note +==== +The pname:presentSlop is used to avoid unintentionally missing a vertical +blanking period on FRR displays due to rounding errors or drift between +clocks. +A suggested value for pname:presentSlop is half the _Refresh Rate_. +==== + +include::{generated}/validity/structs/VkRelativePresentTimeEXT.adoc[] + +-- diff --git a/chapters/VK_EXT_present_timing/queries.adoc b/chapters/VK_EXT_present_timing/queries.adoc new file mode 100644 index 0000000000..edecb5c852 --- /dev/null +++ b/chapters/VK_EXT_present_timing/queries.adoc @@ -0,0 +1,441 @@ +// Copyright (c) 2014-2022 Khronos Group. +// +// SPDX-License-Identifier: CC-BY-4.0 + +== Present/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: 1) render +and present images at a consistent rate that is 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. +Applications can: benefit from communication of timing information with the +presentation engine and its display. +For example, applications can: determine information about the refresh +rate of the display/compositor, can: specify when an image should be +presented, and can: determine when an image was actually presented. +This can allow the application's animation to look smooth to the user, with +no stuttering. +The +ifdef::VK_EXT_present_timing+VK_GOOGLE_display_timing[] +`VK_EXT_present_timing` and `VK_GOOGLE_display_timing` extensions allow +endif::VK_EXT_present_timing+VK_GOOGLE_display_timing[] +ifdef::VK_EXT_present_timing[] +`VK_EXT_present_timing` extension allows +endif::VK_EXT_present_timing[] +ifdef::VK_GOOGLE_display_timing[] +`VK_GOOGLE_display_timing` extension allows +endif::VK_GOOGLE_display_timing[] +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. + +ifdef::VK_EXT_present_timing[] +======= +[open,refpage='vkGetSwapchainTimingPropertiesEXT',desc='Obtain the display timing properties of the PE\'s display',type='protos'] +-- + +To query the presentation engine's 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 + sname:VkSwapchainTimingPropertiesEXT structure. + +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 the type of this structure. + * pname:pNext is `NULL` or a pointer to an extension-specific structure. + * pname:refreshDuration is zero; or is an indication of the duration + of a refresh cycle. + If the presentation engine is operating as an FRR display, this is the + number of nanoseconds from the start of one refresh cycle to the + start of the next refresh cycle. + If the presentation engine is operating as an VRR display + (i.e. refresh cycles may: have variable length), this is the + minimum number of nanoseconds from the start of one refresh cycle + to the start of the next refresh cycle. + * pname:variableRefresh is undefined: if pname:refreshDuration is + zero; otherwise it is ename:VK_FALSE if the presentation engine is + operating as a FRR display, or ename:VK_TRUE if the presentation + engine is operating as a VRR display. + +include::{generated}/validity/structs/VkSwapchainTimingPropertiesEXT.adoc[] + +Some platforms (e.g. Wayland) 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 same +platforms may: not provide updated results until after at least one +additional image has been presented to the pname:swapchain. + + +-- + +[NOTE] +.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, an application needs +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. +Let us say that 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. +Let us say that 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:optimalPresentTime member of the +slink:VkPastPresentationTimingEXT structure is consistently the same as the +pname:idealPresentTime member of the +slink:VkPresentTimeEXT structure over multiple images. +==== + +[open,refpage='vkGetSwapchainTimeDomainsEXT',desc='Obtain the time domain used by the PE for the swapchain',type='protos'] +-- + +To query the time domain used by the presentation engine for a given swapchain, +call: + +include::{generated}/api/protos/vkGetSwapchainTimeDomainsEXT.adoc[] + + * pname:device is the device associated with pname:swapchain. + * pname:swapchain is the swapchain to obtain timing properties for. + * pname:pSwapchainTimeDomainCount is a pointer to an integer related to the + number of time domains available or queried, as described below. + * pname:pSwapchainTimeDomains is either `NULL` or a pointer to an array of + slink:VkSwapchainTimeDomainPropertiesEXT structs, indicating the supported time + domains of the presentation engine for the swapchain. + +If pname:pSwapchainTimeDomains is `NULL`, then the number of time domains +supported for the given pname:swapchain is returned in +pname:pSwapchainTimeDomainCount (if this value is zero, pname:swapchain +does not currently support display timing). +Otherwise, pname:pSwapchainTimeDomainCount must: point to a variable set by the user +to the number of elements in the pname:pSwapchainTimeDomains array, and on return +the variable is overwritten with the number of values actually written to +pname:pSwapchainTimeDomains. +If the value of pname:pSwapchainTimeDomainCount is less than the number of +time domains supported, at most pname:pSwapchainTimeDomainCount values will be +written. +If pname:pSwapchainTimeDomainCount 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/vkGetSwapchainTimeDomainsEXT.adoc[] +-- + +[open,refpage='VkSwapchainTimeDomainPropertiesEXT',desc='An available time domain for a swapchain',type='structs'] +-- + +The sname:VkSwapchainTimeDomainPropertiesEXT structure is defined as: + +include::{generated}/api/structs/VkSwapchainTimeDomainPropertiesEXT.adoc[] + + * pname:sType is the type of this structure. + * pname:pNext is `NULL` or a pointer to an extension-specific structure. + * pname:timeDomain is a elink:VkTimeDomainEXT value representing a time + domain that is available for the swapchain. + +include::{generated}/validity/structs/VkSwapchainTimeDomainPropertiesEXT.adoc[] +-- + +[open,refpage='vkSetSwapchainTimingEXT',desc='Set timing information for a swapchain',type='protos'] +-- + +To set timing information for a swapchain, call: + +include::{generated}/api/protos/vkSetSwapchainTimingEXT.adoc[] + + * pname:device is the device associated with pname:swapchain. + * pname:swapchain is the swapchain to obtain timing properties for. + * pname:pSwapchainTimingInfo is `NULL` or a pointer to an instance of + the sname:VkSwapchainTimingInfoEXT structure. If `NULL`, + display timing is disabled for the swapchain, otherwise enables + display timing and specifies which time domain to use. + +include::{generated}/validity/protos/vkSetSwapchainTimingEXT.adoc[] +-- + +[open,refpage='VkSwapchainTimingInfoEXT',desc='Specify which of the available time domains to use for a swapchain',type='structs'] +-- + +The sname:VkSwapchainTimingInfoEXT structure is defined as: + +include::{generated}/api/structs/VkSwapchainTimingInfoEXT.adoc[] + + * pname:sType is the type of this structure. + * pname:pNext is `NULL` or a pointer to an extension-specific structure. + * pname:timeDomain is a elink:VkTimeDomainEXT value representing the time + domain that should be used with the swapchain. + +include::{generated}/validity/structs/VkSwapchainTimingInfoEXT.adoc[] + +-- + +[open,refpage='vkGetPastPresentationTimingEXT',desc='Obtain timing of a previously-presented image',type='protos'] +-- + +The implementation will maintain a limited amount of history of timing +information about previous presents. +Because of the asynchronous nature of the presentation engine, the timing +information for a given flink:vkQueuePresentKHR command will become +available some time later. +These time values can be asynchronously queried, and will be 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:swapchain is the swapchain to obtain presentation timing + information duration for. + * pname:pPresentationTimingCount is a pointer to an integer related to the + number of sname:VkPastPresentationTimingEXT structures to query, as + described below. + * pname:pPresentationTimings is either `NULL` or a pointer to an an array + of sname:VkPastPresentationTimingEXT structures. + +If pname:pPresentationTimings is `NULL`, then the number of newly-available +timing records for the given pname:swapchain is returned in +pname:pPresentationTimingCount. +Otherwise, pname:pPresentationTimingCount must: point to a variable set by +the user to 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 the value of pname:pPresentationTimingCount is less than the number of +newly-available timing records, at most pname:pPresentationTimingCount +structures will be written. +If pname:pPresentationTimingCount is smaller than the number of +newly-available timing records 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/vkGetPastPresentationTimingEXT.adoc[] +-- + +[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 the type of this structure. + * pname:pNext is `NULL` or a pointer to an extension-specific structure. + * pname:presentID is an application-provided value that was given to a + previous fname:vkQueuePresentKHR command via + slink:VkPresentTimeEXT::pname:presentID. + It can: be used to uniquely identify a previous present with the + flink:vkQueuePresentKHR command. + * pname:targetPresentTime is an application-provided value that was given + to a previous flink:vkQueuePresentKHR command via + slink:VkPresentTimeEXT::pname:targetPresentTime. + If non-zero, it was used by the application to indicate that an image + not be presented any sooner than pname:targetPresentTime. + * pname:actualPresentTime is the time when the image of the + pname:swapchain was actually displayed. + * pname:optimalPresentTime is the time when the presentation engine (PE) + would have liked the application to have set pname:targetPresentTime to. + This allows the PE to provide feedback to the application-provided + slink:VkPresentTimeEXT::pname:idealPresentTime. + The PE may: set this to pname:actualPresentTime, to + slink:VkPresentTimeEXT::pname:idealPresentTime, or to some other + time based upon how the application is performing, the system load + and/or future clock settings, etc. + * pname:timingPropertiesChanged is ename:VK_TRUE if the swapchain's + timing properties have changed since the last time those + properties were queried with + flink:vkGetSwapchainTimingPropertiesEXT, otherwise the properties + have not changed. + If ename:VK_TRUE, an application must: not compare the values of + pname:actualPresentTime and pname:optimalPresentTime with any + other values, as the pname:presentation engine may not be able to + provide accurate values. + * pname:timeDomainChanged is ename:VK_TRUE if the time domain enabled for + the swapchain is not currently available. + The application must: query what time domains are available and + enable display timing with a currently-available time domain. + If the currently-enabled time domain is the opaque domain of + ename:VK_TIME_DOMAIN_SWAPCHAIN_LOCAL_EXT, it is possible that + ename:VK_TIME_DOMAIN_SWAPCHAIN_LOCAL_EXT will be returned by + flink:vkGetSwapchainTimeDomainsEXT. + In such a case, the presentation engine may: have multiple opaque + time domains that it is switching between. + If ename:VK_TRUE, an application must: not compare the values of + pname:actualPresentTime and pname:optimalPresentTime with any + other values, as the pname:presentation engine may not be able to + provide accurate values. + +include::{generated}/validity/structs/VkPastPresentationTimingEXT.adoc[] + +The results for a given pname:swapchain and pname:presentID are only +returned once from fname:vkGetPastPresentationTimingEXT. + +The application can: use the sname:VkPastPresentationTimingEXT values to +occasionally adjust its timing. + +An example is in order. +If the system has a 60Hz FRR, and if the application’s IPD is +currently 16.67ms (i.e. 60FPS), the application will set both +slink:VkPresentTimeEXT::pname:targetPresentTime and +slink:VkPresentTimeEXT::pname:idealPresentTime to 16.67ms after the +same values that were used for the previous image. +If sname:VkPastPresentationTimingEXT::pname:actualPresentTime and +sname:VkPastPresentationTimingEXT::pname:targetPresentTime are +approximately equal to each other (e.g. less than 1ms different), +and if this is the case for many consecutive images, +the application knows that it is rendering smooth, and with no stutter. +If sname:VkPastPresentationTimingEXT::pname:actualPresentTime is +approximately 16.67 later than +sname:VkPastPresentationTimingEXT::pname:targetPresentTime, +the application knows that the image was presented late. +The application can: then change the IPD to 33.33ms (i.e. 30FPS). +It does this by setting both +slink:VkPresentTimeEXT::pname:targetPresentTime and +slink:VkPresentTimeEXT::pname:idealPresentTime to 33.33ms after the +same values that were used for the previous image. + +Later, if the application has been consistently presenting images on +time with an IPD of 33.33ms, if the application desires to try an IPD +of 16.67ms, it can: determine whether it is safe to do so. +It does this by setting slink:VkPresentTimeEXT::pname:idealPresentTime +to 16.67ms earlier than +slink:VkPresentTimeEXT::pname:targetPresentTime, which will continue +to be set to 33.33ms after the +slink:VkPresentTimeEXT::pname:targetPresentTime of the the previous +image. +In this way, the application continues to present images stutter-free, +while requesting feedback from the PE as to whether it can still be +stutter-free with an IPD of 16.67ms. +If the PE determines that it could have displayed the image at +slink:VkPresentTimeEXT::pname:idealPresentTime, it will set +pname:optimalPresentTime to +slink:VkPresentTimeEXT::pname:idealPresentTime. +If so, the application knows it is safe to change its IPD to 16.67ms. + +[NOTE] +.Note +==== +Frequent changes to an application's IPD can cause visual artifacts. +Therefore, it is wise for an application to avoid frequent changes to +its IPD. +In the above example, before an application decreases its IPD, it will +want to see several consecutive images all have +pname:optimalPresentTime equal to +slink:VkPresentTimeEXT::pname:idealPresentTime. +==== + +[NOTE] +.Note +==== +The presentation engine may change the timing properties of the +pname:swapchain for a variety of reasons. +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 60Hz 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 +pname:timingPropertiesChanged and pname:timeDomainChanged to become +ename:VK_TRUE. +It is also possible that an event can cause only +pname:timingPropertiesChanged to become ename:VK_TRUE. +==== + +-- +The full `VK_EXT_present_timing` extension semantics are only described for +swapchains created with the following present modes: + + * ename:VK_PRESENT_MODE_FIFO_KHR. + Tearing cannot be observed. + The first queued image is dequeued and presented if + both: 1) its associated wait semaphore(s) have signaled, and 2) + its target present time is less-than or equal-to the current time. + * ename:VK_PRESENT_MODE_FIFO_RELAXED_KHR. + For images that are presented in time to be displayed at the next + vertical blanking period, the semantics are identical as for + ename:VK_PRESENT_MODE_FIFO_RELAXED_KHR. + For images that are presented late, and are displayed after the start of + the vertical blanking period (i.e. with tearing), the values of + sname:VkPastPresentationTimingEXT may: be treated as if the image was + displayed at the start of the vertical blanking period, or may: be + treated the same as for ename:VK_PRESENT_MODE_IMMEDIATE_KHR. + * ename:VK_PRESENT_MODE_FIFO_LATEST_READY_EXT. + Tearing cannot be observed. + Starting in queue order, successive images are dequeued when both: + 1) its associated wait semaphore(s) have signaled, and 2) its + target present time is less-than or equal-to the current time. + The last of the successive images that are dequeued is presented. +endif::VK_EXT_present_timing[] + +ifdef::VK_GOOGLE_display_timing[] +include::../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 e124e027c3..d58bc98c58 100644 --- a/chapters/VK_KHR_surface/wsi.adoc +++ b/chapters/VK_KHR_surface/wsi.adoc @@ -1591,13 +1591,13 @@ ifdef::VK_EXT_present_mode_fifo_latest_ready[] the queue. 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 + 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. + the presentation engine dequeues the image and checks 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 image of the last dequeued request is presented. + The other dequeued requests are dropped. endif::VK_EXT_present_mode_fifo_latest_ready[] ifdef::VK_KHR_shared_presentable_image[] * ename:VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR specifies that the @@ -1944,9 +1944,9 @@ include::{generated}/validity/protos/vkGetPhysicalDevicePresentRectanglesKHR.ado -- endif::VK_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 6cda35152c..12080b65c8 100644 --- a/chapters/VK_KHR_swapchain/wsi.adoc +++ b/chapters/VK_KHR_swapchain/wsi.adoc @@ -651,6 +651,16 @@ ifdef::VK_EXT_swapchain_maintenance1[] ifdef::VK_VERSION_1_1,VK_KHR_device_group[or flink:vkAcquireNextImage2KHR] for the first time. endif::VK_EXT_swapchain_maintenance1[] +ifdef::VK_EXT_present_timing[] + * ename:VK_SWAPCHAIN_CREATE_ABSOLUTE_TIME_BIT_EXT specifies that when + images of the swapchain are presented, a + slink:VkAbsolutePresentTimeEXT can: be provided to specify the + absolute time they should: be displayed. + * ename:VK_SWAPCHAIN_CREATE_RELATIVE_TIME_BIT_EXT specifies that when + images of the swapchain are presented, an + slink:VkRelativePresentTimeEXT can: be provided to specify the + minimum duration they should: be displayed. +endif::VK_EXT_present_timing[] -- [open,refpage='VkSwapchainCreateFlagsKHR',desc='Bitmask of VkSwapchainCreateFlagBitsKHR',type='flags'] @@ -1666,6 +1676,9 @@ include::{generated}/validity/structs/VkDeviceGroupPresentInfoKHR.adoc[] -- endif::VK_VERSION_1_1,VK_KHR_device_group[] +ifdef::VK_EXT_present_timing[] +include::../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/synchronization.adoc b/chapters/synchronization.adoc index 8503a34d0b..d13640e32d 100644 --- a/chapters/synchronization.adoc +++ b/chapters/synchronization.adoc @@ -7783,7 +7783,13 @@ endif::VK_VERSION_1_3,VK_KHR_synchronization2[] and are defined to be incrementing according to the <> of the device. - * ename:VK_TIME_DOMAIN_CLOCK_MONOTONIC_KHR specifies the CLOCK_MONOTONIC +ifdef::VK_EXT_present_timing[] + * 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_EXT specifies the CLOCK_MONOTONIC time domain available on POSIX platforms. Timestamp values in this time domain are in units of nanoseconds and are comparable with platform timestamp values captured using the POSIX diff --git a/xml/vk.xml b/xml/vk.xml index 6c2246ccad..921dd07034 100644 --- a/xml/vk.xml +++ b/xml/vk.xml @@ -3252,6 +3252,54 @@ typedef void* MTLSharedEvent_id; void* pNext VkBool32 presentWaitvkWaitForPresentKHR is supported + + VkStructureType sType + const void* pNext + uint64_t refreshDurationNumber of nanoseconds from the start of one refresh cycle to the next + VkBool32 variableRefresh + + + VkStructureType sType + void* pNext + VkTimeDomainEXT timeDomainAvailable time domain to use with the swapchain + + + VkStructureType sType + const void* pNext + VkTimeDomainEXT timeDomainAvailable time domain to use with the swapchain + + + VkStructureType sType + const void* pNext + uint32_t presentIDApplication-provided identifier, previously given to vkQueuePresentKHR + uint64_t targetPresentTimeEarliest time an image should have been presented, previously given to vkQueuePresentKHR + uint64_t actualPresentTimeTime the image was actually displayed + uint64_t optimalPresentTimeTime when the PE would have liked the application to have set targetPresentTime to + VkBool32 timingPropertiesChangedVK_TRUE if swapchain's timing properties changed since last queried + VkBool32 timeDomainChangedVK_TRUE if the swapchain no longer supports the enabled time domain + + + VkStructureType sType + const void* pNext + uint32_t swapchainCountCopy of VkPresentInfoKHR::swapchainCount + const VkPresentTimeEXT* pTimesWhen to present images + + + uint32_t presentIDApplication-provided identifier + uint64_t targetPresentTimeEarliest time an image should be presented + uint64_t idealPresentTimeIndication to PE of what the application would like targetPresentTime to have been + uint64_t presentSlopPeriod of time an image may be presented before targetPresentTime + + + uint32_t presentIDApplication-provided identifier + uint64_t minPresentDurationShortest duration an image should be presented + uint64_t idealPresentDurationIndication to PE of what the application would like minPresentDuration to be + uint64_t presentSlopPeriod of time an image may be presented before minPresentDuration elapses + + + VkAbsolutePresentTimeEXT absolutePresentTime + VkRelativePresentTimeEXT relativePresentTime + Display primary in chromaticity coordinates VkStructureType sType @@ -12865,6 +12913,12 @@ typedef void* MTLSharedEvent_id; VkQueue queue const VkPresentInfoKHR* pPresentInfo + + VkResult vkSetSwapchainTimingEXT + VkDevice device + VkSwapchainKHR swapchain + const VkSwapchainTimingInfoEXT* pSwapchainTimingInfo + VkResult vkCreateViSurfaceNN VkInstance instance @@ -13547,6 +13601,13 @@ typedef void* MTLSharedEvent_id; uint32_t set const void* pData + + VkResult vkGetPastPresentationTimingEXT + VkDevice device + VkSwapchainKHR swapchain + uint32_t* pPresentationTimingCount + VkPastPresentationTimingEXT* pPresentationTimings + void vkSetHdrMetadataEXT VkDevice device @@ -15701,6 +15762,18 @@ typedef void* MTLSharedEvent_id; uint32_t stageCount const VkShaderStageFlagBits* pStages const VkShaderEXT* pShaders + + VkResult vkGetSwapchainTimingPropertiesEXT + VkDevice device + VkSwapchainKHR swapchain + VkSwapchainTimingPropertiesEXT* pSwapchainTimingProperties + + + VkResult vkGetSwapchainTimeDomainsEXT + VkDevice device + VkSwapchainKHR swapchain + uint32_t* pSwapchainTimeDomainCount + VkSwapchainTimeDomainPropertiesEXT* pSwapchainTimeDomains VkResult vkGetScreenBufferPropertiesQNX @@ -20483,10 +20556,31 @@ typedef void* MTLSharedEvent_id; - - - - + + + + + + + + + + + + + + + + + + + + + + + + + From dc267e377fa083592846c1dd3fbd5e29adfae537 Mon Sep 17 00:00:00 2001 From: Lionel Duc Date: Wed, 9 Oct 2024 22:29:27 +0200 Subject: [PATCH 2/5] Major rebase and updates to the original proposal This change rebases the original extension on main. It also brings many modifications from discussions within the Khronos SI group and this MR: - Add a proposal document - Rely on VK_KHR_present_id to identify presents - Split out VK_PRESENT_MODE_FIFO_LATEST_READY_EXT - Add physical device and surface capabilities - Define "presentation" as a set of well-defined multiple steps - Explicitly describe the internal results queue interactions - Add many per-present parameters, allowing to remove swapchain state - Refine VRR support - Cleanup appendix and update contributors - Replace present slop with a flag to round to nearest refresh cycle - Refine mechanisms for feedback about time domains and timing properties updates - Allow timing results to be returned incomplete and out of order --- appendices/VK_EXT_present_timing.adoc | 104 ++-- appendices/glossary.adoc | 3 +- .../PresentTimeInfo.adoc | 287 +++++----- chapters/VK_EXT_present_timing/queries.adoc | 463 ++++++++-------- chapters/VK_KHR_surface/wsi.adoc | 35 ++ chapters/VK_KHR_swapchain/wsi.adoc | 26 +- chapters/features.adoc | 204 +++++++ chapters/synchronization.adoc | 41 +- proposals/VK_EXT_present_timing.adoc | 510 ++++++++++++++++++ xml/vk.xml | 147 +++-- 10 files changed, 1315 insertions(+), 505 deletions(-) create mode 100644 proposals/VK_EXT_present_timing.adoc diff --git a/appendices/VK_EXT_present_timing.adoc b/appendices/VK_EXT_present_timing.adoc index ef3b9e7ea4..a56d25bf76 100644 --- a/appendices/VK_EXT_present_timing.adoc +++ b/appendices/VK_EXT_present_timing.adoc @@ -1,11 +1,13 @@ -// Copyright (c) 2017-2022 Khronos Group. +// 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*:: - 2020-07-06 + 2024-05-30 *IP Status*:: No known IP claims. *Contributors*:: @@ -21,9 +23,15 @@ include::{generated}/meta/{refprefix}VK_EXT_present_timing.adoc[] - Alon Or-Bach, Samsung - Niklas Smedberg, Unity Technologies - Tobias Hector, AMD + - Lionel Duc, NVIDIA + - Lina Versace, Google + - Sebastian Wick, Red Hat + - Jakob Bornecrantz, Collabora + +=== Description This device extension allows an application that uses the -`<>` extension to obtain information about 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. @@ -41,7 +49,6 @@ 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 @@ -61,7 +68,7 @@ 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) must be a multiple of +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 @@ -85,8 +92,6 @@ 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. -The special value of zero for pname:refreshDuration is used to -indicate the condition where the platform cannot yet answer the query. VRR displays on some platforms can also be seen as having different characteristics over time. @@ -96,11 +101,11 @@ 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 these how the timing characteristics -can change over time. +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? +2) Do we return min/max values for refresh duration for VRR? *PROPOSED*: return only the minimum value of refreshDuration for a VRR. @@ -119,8 +124,8 @@ artifacts. 3) How to deal with changes in timing properties? *RESOLVED*: The slink:VkPastPresentationTimingEXT structure that is -returned by flink:vkGetPastPresentationTimingEXT will contain -pname:timeDomainChanged, which will be ename:VK_TRUE if the time +returned by flink:vkGetPastPresentationTimingEXT contains +pname:timeDomainChanged, which is ename:VK_TRUE 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 @@ -140,24 +145,23 @@ 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? -*PROPOSED*: Have one query, as described in issue 1, that can be +*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? +5) Query to determine time domain? -*PROPOSED*: Have a query to determine the time domain. -This extension will define some return values, including some that are -platform-specific. -Other extensions can add other time domains. +*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? +6) What time to use for targetPresentTime for early images? *PROPOSED*: Have no query for determining the current time in the PE’s time -domain; and do allow the special value of zero for targetPresentTime and -idealPresentTime, meaning that there is no target nor ideal 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 @@ -165,9 +169,9 @@ 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 nor idealPresentTime is requested. +targetPresentTime is requested. Later, once the application has obtained feedback, it can specify -targetPresentTime and idealPresentTime. +targetPresentTime by using the result's actualPresentTime. 7) How long before an application’s request for new image duration is honored? @@ -188,68 +192,48 @@ 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 long. +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. -Is there value in having a query for the application to know how long it may -have to wait for feedback? -Can such a query be reasonably answered by the driver? - -Is there other interesting information in this space that we may wish to -capture? +Can such a query be reasonably answered by the driver? Is there other +interesting information in this space that we may wish to capture? 9) Do we have a query(s) about the number of VkPastPresentationTimingEXT structs to keep? -*UNRESOLVED*: At the Montreal F2F, there was discussion about how much -feedback that the driver needs to keep and/or how much feedback that -the application needs to be able to query. - -The way that the LunarG cube demo (official WSI example code) used -VK_GOOGLE_display_timing, and what is proposed for the new extension is that -the application query what feedback is available during every render-present -loop. -If the application never skips querying for feedback, and always obtains -whatever feedback is available, there doesn’t seem much need for such a -query(s). -What I saw with the cube demo on a Pixel phone was that most of the time, the -application obtained feedback for 1 previous present. -Occasionally, it would get 2 VkPastPresentationTimingEXT structs on time and -then 0 the next (or vice versa). - -Perhaps, a video player application might present several images at once, and -then later get feedback for several images at the same time. -That would be the most-likely use-case that I can come up with for why a query -might be useful. -Is that compelling enough? - -What might the model for the query(s) be? -Potentially the application can tell the driver how many presents it might do -at a time, and the driver can use that to size its internal buffer. -Is there value in having a query that would influence the driver’s behavior -(beyond what’s provided for in the currently-proposed API)? +*PROPOSED*: Let the application specify at swapchain creation how many +results the swapchain is allowed to store before querying them with +vkGetPastPresentationTimingEXT. + 10) How is the SWAPCHAIN_LOCAL time domain used with the calibrated timestamps extension? -PROPOSED: Define a struct to chain into VkCalibratedTimestampInfoEXT::pNext +*PROPOSED*: Define a struct to chain into VkCalibratedTimestampInfoEXT::pNext that specifies a swapchain. Is anything additional needed for vkGetPhysicalDeviceCalibrateableTimeDomainsEXT, or are swapchain-local timestamps always calibrateable or always not calibrateable for a given device? + 11) Should VK_PRESENT_MODE_FIFO_LATEST_READY_EXT be part of this extension, or split out into its own extension? -PROPOSED: It is only tangentially related. +*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 + ** Internal revisions. + + * Revision 2, 2022-11-30 (Lionel Duc) + ** Rebase for public discussions. + + * Revision 3, 2024-05-29 (Lionel Duc) + ** Public revisions. diff --git a/appendices/glossary.adoc b/appendices/glossary.adoc index 73fa4c99f5..932552548d 100644 --- a/appendices/glossary.adoc +++ b/appendices/glossary.adoc @@ -876,7 +876,8 @@ Image Present Duration:: Image Present Rate:: The number of newly-presented images the application intends to present each second (a.k.a. frame rate). - This value should: be a multiple of the refresh 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:: diff --git a/chapters/VK_EXT_present_timing/PresentTimeInfo.adoc b/chapters/VK_EXT_present_timing/PresentTimeInfo.adoc index 28fcee4236..48817ff30e 100644 --- a/chapters/VK_EXT_present_timing/PresentTimeInfo.adoc +++ b/chapters/VK_EXT_present_timing/PresentTimeInfo.adoc @@ -1,183 +1,184 @@ -// Copyright (c) 2014-2022 Khronos Group. +// Copyright (c) 2014-2023 Khronos Group. // // SPDX-License-Identifier: CC-BY-4.0 -[open,refpage='VkPresentTimesInfoEXT',desc='The earliest time each image should be presented',type='structs'] +[open,refpage='VkPresentTimingsInfoEXT',desc='Array of VkPresentTimingInfoEXT to chain with VkPresentInfoKHR',type='structs'] -- -When the `<>` extension is enabled, additional -fields can: be specified that allow an application to specify the earliest -time that an image should be displayed. -This allows an application to avoid stutter that is caused by an image being -displayed earlier than planned. -Such stuttering can occur with both fixed and variable-refresh-rate -displays, because stuttering occurs when the geometry is not correctly -positioned for when the image is displayed. -An application can: instruct the presentation engine that an image should -not be displayed earlier than a specified time by including the -sname:VkPresentTimesInfoEXT structure in the pname:pNext chain of the -sname:VkPresentInfoKHR structure. - -The sname:VkPresentTimesInfoEXT structure is defined as: - -include::{generated}/api/structs/VkPresentTimesInfoEXT.adoc[] - - * pname:sType is the type of this structure. - * pname:pNext is `NULL` or a pointer to an extension-specific structure. +When the <> or +<> feature is +enabled, an application can: instruct the presentation engine that an image +must: not be displayed earlier than 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:pTimes is `NULL` or a pointer to an array of - sname:VkPresentTimeEXT elements with pname:swapchainCount entries. - If not `NULL`, each element of pname:pTimes contains the earliest time - to present the image corresponding to the entry in the - sname:VkPresentInfoKHR::pname:pImageIndices array. + * 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. + +The semantics of target presentation time or duration vary depending on the presentation mode: + + * ename:VK_PRESENT_MODE_FIFO_KHR. + Tearing cannot: be observed. + The first queued image is dequeued and presented if + both: 1) its associated wait semaphore(s) have signaled, and 2) + its target present time is less-than or equal-to the current time. + * ename:VK_PRESENT_MODE_FIFO_RELAXED_KHR. + For images that are presented in time to be displayed at the next + vertical blanking period, the semantics are identical as for + ename:VK_PRESENT_MODE_FIFO_KHR. + For images that are presented late, and are displayed after the start of + the vertical blanking period (i.e. with tearing), the values of + sname:VkPastPresentationTimingEXT may: be treated as if the image was + displayed at the start of the vertical blanking period, or may: be + treated the same as for ename:VK_PRESENT_MODE_IMMEDIATE_KHR. + +Other presentation modes do not support a target presentation time or duration. .Valid Usage **** * pname:swapchainCount must: be the same value as sname:VkPresentInfoKHR::pname:swapchainCount, where sname:VkPresentInfoKHR is in the pname:pNext chain of this - sname:VkPresentTimesInfoEXT structure. + sname:VkPresentTimingsInfoEXT structure. + * For each member of sname:VkPresentInfoKHR::pname:pSwapchains, if the + associated sname:VkPresentTimeEXT is non-zero, the current present mode + must: be ename:VK_PRESENT_MODE_FIFO_KHR or + ename:VK_PRESENT_MODE_FIFO_RELAXED_KHR. **** -include::{generated}/validity/structs/VkPresentTimesInfoEXT.adoc[] +include::{generated}/validity/structs/VkPresentTimingsInfoEXT.adoc[] -- -[open,refpage='VkPresentTimeEXT',desc='Specifying when an image should be presented',type='structs'] + +[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:time is a sname:VkPresentTimeEXT specifying the target present + time or duration 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 should collect + timing information for. + * pname:targetPresentStage is zero or a tlink:VkPresentStageFlagsEXT value + specifying which present stage pname:time is targeting. + * pname:presentAtRelativeTime specifies whether pname:time is to be + interpreted as an absolute or a relative time value. + * pname:presentAtNearestRefreshCycle is a flag indicating that the + application would like the presentation engine to complete + pname:targetPresentStage at the start of the refresh cycle that is + closest to pname:time. + +If pname:targetPresentStage is not zero, the presentation engine must: not +complete the target present stage before the absolute time specified in +pname:time according to the time domain used, unless +pname:presentAtNearestRefreshCycle is ename:VK_TRUE and pname:time falls +within the first half of a refresh cycle. -The sname:VkPresentTimeEXT union contains either a -slink:VkAbsolutePresentTimeEXT or a slink:VkRelativePresentTimeEXT -structure, defined as: +[NOTE] +.Note +==== +Applications that use pname:targetPresentTime to 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 use +pname:presentAtNearestRefreshCycle to allow the implementation to compensate +for small precision errors that may cause an image to be displayed one +refresh cycle later than intended. +==== -include::{generated}/api/structs/VkPresentTimeEXT.adoc[] +.Valid Usage +**** + * If pname:presentStageTarget is not zero, it must: specify one and only + one stage. + * pname:presentStageTarget must: not be + ename:VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT + * If pname:targetPresentStage is not zero, pname:presentAtRelativeTime must: + be ename:VK_FALSE. + * If pname:presentAtRelativeTime is ename:VK_TRUE, the + <> feature + must: be enabled. +**** -include::{generated}/validity/structs/VkPresentTimeEXT.adoc[] +include::{generated}/validity/structs/VkPresentTimingInfoEXT.adoc[] -- -[open,refpage='VkAbsolutePresentTimeEXT',desc='Specifying the earliest time an image should be presented',type='structs'] + +[open,refpage='VkPresentTimeEXT',desc='Specifying when an image should be presented',type='structs'] -- -The sname:VkAbsolutePresentTimeEXT structure is defined as: - -include::{generated}/api/structs/VkAbsolutePresentTimeEXT.adoc[] - - * pname:presentID is an application-provided identification value. - If non-zero, flink:vkGetPastPresentationTimingEXT will return a - slink:VkPastPresentationTimingEXT struct with the timing information - associated with the present to the associated swapchain for this - call to flink:vkQueuePresentKHR, including this value being in the - pname:presentID member of the slink:VkPastPresentationTimingEXT - struct. - In order to be useful to the application, it should: be unique within - some period of time that is meaningful to the application. - * pname:targetPresentTime, if non-zero, specifies the earliest time the - application wants the image to be displayed to the user. - pname:targetPresentTime is a time in nanoseconds, according to the - time-domain being used. - A value of zero specifies that the presentation engine may: display the - image at any time. - * pname:idealPresentTime provides an indication to the presentation - engine of what the application desires its IPD to become. - An application can: set pname:idealPresentTime to the same value - as pname:targetPresentTime, indicating that the application - desires its IPD to remain steady. - A value earlier than - pname:targetPresentTime indicates that the application desires to - shorten its IPD. - A value later than pname:targetPresentTime - indicates that the application desires to lengthen its IPD. - The presentation engine will provide feedback on this value in the - data returned by flink:vkGetPastPresentationTimingEXT. - * pname:presentSlop is the period of time in nanoseconds before - pname:targetPresentTime that the presentation engine may: display - the image. - -If pname:targetPresentTime is non-zero, the presentation engine should: -not display the image to the user at a time earlier than -(pname:targetPresentTime - pname:presentSlop). - -Setting pname:targetPresentTime to zero is useful when the application -desires to provide a non-zero pname:presentID in order to get back timing -information from flink:vkGetPastPresentationTimingEXT, but does not wish -to set a pname:targetPresentTime. - -Providing a pname:presentSlop enables the application to indicate to the -presentation engine to display the image within this period if a vertical -blanking period occurs on FRR displays. +The sname:VkPresentTimeEXT union is defined as: -[NOTE] -.Note -==== -The pname:presentSlop is used to avoid unintentionally missing a vertical -blanking period on FRR displays due to rounding errors or drift between -clocks. -A suggested value for pname:presentSlop is half the _Refresh Rate_. -==== +include::{generated}/api/structs/VkPresentTimeEXT.adoc[] -include::{generated}/validity/structs/VkAbsolutePresentTimeEXT.adoc[] + * pname:targetPresentTime, if non-zero, specifies the earliest time in + nanoseconds the application wants the presentation engine to complete a + specified target present stage. A value of zero specifies that the + presentation engine may: display the image at any time allowed by the + current present mode. + * pname:presentDuration specifies the minimum duration in nanoseconds that + must: separate the ename:VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT + present stages of the current and the next presentation requests, if any. +include::{generated}/validity/structs/VkPresentTimeEXT.adoc[] -- -[open,refpage='VkRelativePresentTimeEXT',desc='Specifying the minimum duration an image should be presented',type='structs'] +[open,refpage='VkPresentStageFlagBitsEXT',desc='Bitmask specifying stages of the image presentation process',type='enums'] -- -The sname:VkRelativePresentTimeEXT structure is defined as: - -include::{generated}/api/structs/VkRelativePresentTimeEXT.adoc[] - - * pname:presentID is an application-provided identification value. - If non-zero, flink:vkGetPastPresentationTimingEXT will return a - slink:VkPastPresentationTimingEXT struct with the timing information - associated with the present to the associated swapchain for this - call to flink:vkQueuePresentKHR, including this value being in the - pname:presentID member of the slink:VkPastPresentationTimingEXT - struct. - In order to be useful to the application, it should: be unique within - some period of time that is meaningful to the application. - * pname:minPresentDuration, if non-zero, specifies the minimum duration - in nanoseconds the application wants the image to be displayed to the - user. - A value of zero specifies that the presentation engine may: display the - image for any duration. - * pname:idealPresentDuration provides an indication to the presentation - engine of what the application desires its IPD to become. - An application can: set pname:idealPresentDuration to the same value - as pname:minPresentDuration, indicating that the application - desires its IPD to remain steady. - A value smaller than - pname:minPresentDuration indicates that the application desires to - shorten its IPD. - A value larger than pname:minPresentDuration - indicates that the application desires to lengthen its IPD. - The presentation engine will provide feedback on this value in the - data returned by flink:vkGetPastPresentationTimingEXT. - * pname:presentSlop is the period of time in nanoseconds before - pname:minPresentDuration elapses that the presentation engine may: - display the image. - -If pname:minPresentDuration is non-zero, the presentation engine should: -display the image to the user for a minimum duration of -(pname:minPresentDuration - pname:presentSlop) nanoseconds. - -Setting pname:minPresentDuration to zero is useful when the application -desires to provide a non-zero pname:presentID in order to get back timing -information from flink:vkGetPastPresentationTimingEXT, but does not wish -to set a pname:minPresentDuration. - -Providing a pname:presentSlop enables the application to indicate to the -presentation engine to display the image within this period if a vertical -blanking period occurs on FRR displays. +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_IMAGE_LATCHED_BIT_EXT is the stage after which the + image associated with the presentation request has been latched by the + presentation engine to create the presentation of a future refresh cycle. + * 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] .Note ==== -The pname:presentSlop is used to avoid unintentionally missing a vertical -blanking period on FRR displays due to rounding errors or drift between -clocks. -A suggested value for pname:presentSlop is half the _Refresh Rate_. +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. ==== +-- -include::{generated}/validity/structs/VkRelativePresentTimeEXT.adoc[] +[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 index edecb5c852..0e426646f0 100644 --- a/chapters/VK_EXT_present_timing/queries.adoc +++ b/chapters/VK_EXT_present_timing/queries.adoc @@ -1,14 +1,15 @@ -// Copyright (c) 2014-2022 Khronos Group. +// Copyright (c) 2014-2023 Khronos Group. // // SPDX-License-Identifier: CC-BY-4.0 -== Present/Display Timing Queries +== 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. -This avoids the visual anomaly known as tearing. +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. @@ -17,54 +18,74 @@ 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: 1) render -and present images at a consistent rate that is 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. -Applications can: benefit from communication of timing information with the -presentation engine and its display. -For example, applications can: determine information about the refresh -rate of the display/compositor, can: specify when an image should be -presented, and can: determine when an image was actually presented. -This can allow the application's animation to look smooth to the user, with -no stuttering. +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+VK_GOOGLE_display_timing[] -`VK_EXT_present_timing` and `VK_GOOGLE_display_timing` extensions allow -endif::VK_EXT_present_timing+VK_GOOGLE_display_timing[] ifdef::VK_EXT_present_timing[] -`VK_EXT_present_timing` extension allows +`VK_EXT_present_timing` endif::VK_EXT_present_timing[] +ifdef::VK_EXT_present_timing+VK_GOOGLE_display_timing[or] ifdef::VK_GOOGLE_display_timing[] -`VK_GOOGLE_display_timing` extension allows +`VK_GOOGLE_display_timing` endif::VK_GOOGLE_display_timing[] -an application to satisfy these needs. +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. +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'] -- -To query the presentation engine's timing properties for a given swapchain, -call: +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 - sname:VkSwapchainTimingPropertiesEXT structure. + 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. include::{generated}/validity/protos/vkGetSwapchainTimingPropertiesEXT.adoc[] -- @@ -76,31 +97,33 @@ The sname:VkSwapchainTimingPropertiesEXT structure is defined as: include::{generated}/api/structs/VkSwapchainTimingPropertiesEXT.adoc[] - * pname:sType is the type of this structure. - * pname:pNext is `NULL` or a pointer to an extension-specific structure. - * pname:refreshDuration is zero; or is an indication of the duration + * 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. If the presentation engine is operating as an FRR display, this is the number of nanoseconds from the start of one refresh cycle to the start of the next refresh cycle. - If the presentation engine is operating as an VRR display + If the presentation engine is operating as a VRR display (i.e. refresh cycles may: have variable length), this is the minimum number of nanoseconds from the start of one refresh cycle to the start of the next refresh cycle. - * pname:variableRefresh is undefined: if pname:refreshDuration is - zero; otherwise it is ename:VK_FALSE if the presentation engine is - operating as a FRR display, or ename:VK_TRUE if the presentation - engine is operating as a VRR display. - -include::{generated}/validity/structs/VkSwapchainTimingPropertiesEXT.adoc[] + * pname:variableRefreshDelay is undefined: if pname:refreshDuration is + zero; otherwise it is a duration in nanoseconds indicating the maximum + theoretical delay for the presentation engine to start a new refresh + cycle upon processing a presentation request. -Some platforms (e.g. Wayland) 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 same -platforms may: not provide updated results until after at least one -additional image has been presented to the pname:swapchain. +If pname:variableRefreshDelay is the same as pname:refreshDuration, the +presentation engine is operating as an FRR display. +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 same platforms may: not provide +updated results until after at least one additional image has been +presented to the pname:swapchain. +include::{generated}/validity/structs/VkSwapchainTimingPropertiesEXT.adoc[] -- [NOTE] @@ -110,8 +133,8 @@ 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, an application needs -its IPD to be a multiple of pname:refreshDuration. +On FRR displays, in order to provide a smooth, stutter-free animation, an +application needs 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 @@ -121,7 +144,7 @@ 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. -Let us say that an application has an initial target IPD of 16.67ms (1X +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. @@ -142,14 +165,12 @@ 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:optimalPresentTime member of the -slink:VkPastPresentationTimingEXT structure is consistently the same as the -pname:idealPresentTime member of the -slink:VkPresentTimeEXT structure over multiple images. +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='vkGetSwapchainTimeDomainsEXT',desc='Obtain the time domain used by the PE for the swapchain',type='protos'] +[open,refpage='vkGetSwapchainTimeDomainsEXT',desc='Obtain the time domains supported by the PE for the swapchain',type='protos'] -- To query the time domain used by the presentation engine for a given swapchain, @@ -191,60 +212,39 @@ The sname:VkSwapchainTimeDomainPropertiesEXT structure is defined as: include::{generated}/api/structs/VkSwapchainTimeDomainPropertiesEXT.adoc[] - * pname:sType is the type of this structure. - * pname:pNext is `NULL` or a pointer to an extension-specific structure. + * pname:sType is a elink:VkStructureType value identifying this structure. + * pname:pNext is `NULL` or a pointer to a structure extending this + structure. * pname:timeDomain is a elink:VkTimeDomainEXT value representing a time domain that is available for the swapchain. + * pname:timeDomainId is a unique identifier for this time domain within a + swapchain's namespace. -include::{generated}/validity/structs/VkSwapchainTimeDomainPropertiesEXT.adoc[] --- - -[open,refpage='vkSetSwapchainTimingEXT',desc='Set timing information for a swapchain',type='protos'] --- - -To set timing information for a swapchain, call: - -include::{generated}/api/protos/vkSetSwapchainTimingEXT.adoc[] - - * pname:device is the device associated with pname:swapchain. - * pname:swapchain is the swapchain to obtain timing properties for. - * pname:pSwapchainTimingInfo is `NULL` or a pointer to an instance of - the sname:VkSwapchainTimingInfoEXT structure. If `NULL`, - display timing is disabled for the swapchain, otherwise enables - display timing and specifies which time domain to use. - -include::{generated}/validity/protos/vkSetSwapchainTimingEXT.adoc[] --- - -[open,refpage='VkSwapchainTimingInfoEXT',desc='Specify which of the available time domains to use for a swapchain',type='structs'] --- - -The sname:VkSwapchainTimingInfoEXT structure is defined as: - -include::{generated}/api/structs/VkSwapchainTimingInfoEXT.adoc[] - - * pname:sType is the type of this structure. - * pname:pNext is `NULL` or a pointer to an extension-specific structure. - * pname:timeDomain is a elink:VkTimeDomainEXT value representing the time - domain that should be used with the swapchain. - -include::{generated}/validity/structs/VkSwapchainTimingInfoEXT.adoc[] +[NOTE] +.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:VkTimeDomainEXT value, for example when a surface is +moved from one display hardware to another. Arbitrary identifiers, provided +in pname:timeDomainId, 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 a previously-presented image',type='protos'] +[open,refpage='vkGetPastPresentationTimingEXT',desc='Obtain timing of previously-presented images',type='protos'] -- -The implementation will maintain a limited amount of history of timing -information about previous presents. Because of the asynchronous nature of the presentation engine, the timing -information for a given flink:vkQueuePresentKHR command will become +information for a given flink:vkQueuePresentKHR command only becomes available some time later. -These time values can be asynchronously queried, and will be returned if +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 +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[] @@ -253,12 +253,18 @@ include::{generated}/api/protos/vkGetPastPresentationTimingEXT.adoc[] * pname:swapchain is the swapchain to obtain presentation timing information duration for. * pname:pPresentationTimingCount is a pointer to an integer related to the - number of sname:VkPastPresentationTimingEXT structures to query, as + number of slink:VkPastPresentationTimingEXT structures to query, as described below. - * pname:pPresentationTimings is either `NULL` or a pointer to an an array - of sname:VkPastPresentationTimingEXT structures. - -If pname:pPresentationTimings is `NULL`, then the number of newly-available + * pname:pPresentationTimings is `NULL` or a pointer to an an array + of slink:VkPastPresentationTimingEXT structures. + * 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. + * pname:pTimeDomainsChanged is `NULL` or a pointer to a boolean value + indicating if the list of supported time domains supported by the + pname:swapchain has changed since the last call to this function. + +If pname:pPresentationTimings is `NULL`, then the number of available timing records for the given pname:swapchain is returned in pname:pPresentationTimingCount. Otherwise, pname:pPresentationTimingCount must: point to a variable set by @@ -266,12 +272,44 @@ the user to 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 the value of pname:pPresentationTimingCount is less than the number of -newly-available timing records, at most pname:pPresentationTimingCount -structures will be written. -If pname:pPresentationTimingCount is smaller than the number of -newly-available timing records 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. +newly-available timing records for the given pname:swapchain, at most +pname:pPresentationTimingCount structures are written, and +ename:VK_INCOMPLETE is returned instead of ename:VK_SUCCESS to indicate that +not all the available values were returned. + +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. + +If pname:pTimeDomainsChanged is ename:VK_TRUE, applications should: query +the new list of available time domains with flink:vkGetSwapchainTimeDomainsEXT. + +Timing information may: become available out of order with regards to their +associated presentation request submission order. + +Upon return, zero or more slots of the pname:swapchain internal timing +results queue, equal to the number of entries written to +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. + +There is no requirement for any precise timing relationship between the +completion of a present stage and the availability of any associated timing +information. + +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. include::{generated}/validity/protos/vkGetPastPresentationTimingEXT.adoc[] -- @@ -283,159 +321,112 @@ The sname:VkPastPresentationTimingEXT structure is defined as: include::{generated}/api/structs/VkPastPresentationTimingEXT.adoc[] - * pname:sType is the type of this structure. - * pname:pNext is `NULL` or a pointer to an extension-specific structure. - * pname:presentID is an application-provided value that was given to a - previous fname:vkQueuePresentKHR command via - slink:VkPresentTimeEXT::pname:presentID. - It can: be used to uniquely identify a previous present with the - flink:vkQueuePresentKHR command. - * pname:targetPresentTime is an application-provided value that was given - to a previous flink:vkQueuePresentKHR command via - slink:VkPresentTimeEXT::pname:targetPresentTime. - If non-zero, it was used by the application to indicate that an image - not be presented any sooner than pname:targetPresentTime. - * pname:actualPresentTime is the time when the image of the - pname:swapchain was actually displayed. - * pname:optimalPresentTime is the time when the presentation engine (PE) - would have liked the application to have set pname:targetPresentTime to. - This allows the PE to provide feedback to the application-provided - slink:VkPresentTimeEXT::pname:idealPresentTime. - The PE may: set this to pname:actualPresentTime, to - slink:VkPresentTimeEXT::pname:idealPresentTime, or to some other - time based upon how the application is performing, the system load - and/or future clock settings, etc. - * pname:timingPropertiesChanged is ename:VK_TRUE if the swapchain's - timing properties have changed since the last time those - properties were queried with - flink:vkGetSwapchainTimingPropertiesEXT, otherwise the properties - have not changed. - If ename:VK_TRUE, an application must: not compare the values of - pname:actualPresentTime and pname:optimalPresentTime with any - other values, as the pname:presentation engine may not be able to - provide accurate values. - * pname:timeDomainChanged is ename:VK_TRUE if the time domain enabled for - the swapchain is not currently available. - The application must: query what time domains are available and - enable display timing with a currently-available time domain. - If the currently-enabled time domain is the opaque domain of - ename:VK_TIME_DOMAIN_SWAPCHAIN_LOCAL_EXT, it is possible that - ename:VK_TIME_DOMAIN_SWAPCHAIN_LOCAL_EXT will be returned by - flink:vkGetSwapchainTimeDomainsEXT. - In such a case, the presentation engine may: have multiple opaque - time domains that it is switching between. - If ename:VK_TRUE, an application must: not compare the values of - pname:actualPresentTime and pname:optimalPresentTime with any - other values, as the pname:presentation engine may not be able to - provide accurate values. + * 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 an application-provided value that was given + to a previous fname:vkQueuePresentKHR command via + slink:VkPresentIdKHR::pname:pPresentIds. + * 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:timeDomainId is the id of the time domain used by the presentation + engine to report times in pname:pPresentStages. + * pname:reportComplete is ename:VK_TRUE if the presentation engine + has reported all the requested results in pname:pPresentStages. + +If pname:presentId is not zero, pname:presentStageCount must: be set by the +application to be at least equal to the number of present stages specified +in slink:VkPresentTimingInfoEXT::pname:presentStagesQueries for the +associated flink:vkQueuePresentKHR call. Otherwise, pname:presentStageCount +must: be at least equal to the highest number of present stages queried +among all presentation requests for which there are outstanding results. + +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 at least one entity which has been affected by the presentation. + +pname:timeDomain may: be different than the time domain that was specified +in slink:VkPresentTimingInfoEXT::pname:timeDomain 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 and report results in that domain. +Applications can: continue to use this fallback time domain in future +flink:vkQueuePresentKHR calls, or they can: call +flink:vkGetSwapchainTimeDomainsEXT to choose from the currently supported +time domains. include::{generated}/validity/structs/VkPastPresentationTimingEXT.adoc[] -The results for a given pname:swapchain and pname:presentID are only -returned once from fname:vkGetPastPresentationTimingEXT. - -The application can: use the sname:VkPastPresentationTimingEXT values to -occasionally adjust its timing. - -An example is in order. -If the system has a 60Hz FRR, and if the application’s IPD is -currently 16.67ms (i.e. 60FPS), the application will set both -slink:VkPresentTimeEXT::pname:targetPresentTime and -slink:VkPresentTimeEXT::pname:idealPresentTime to 16.67ms after the -same values that were used for the previous image. -If sname:VkPastPresentationTimingEXT::pname:actualPresentTime and -sname:VkPastPresentationTimingEXT::pname:targetPresentTime are -approximately equal to each other (e.g. less than 1ms different), -and if this is the case for many consecutive images, -the application knows that it is rendering smooth, and with no stutter. -If sname:VkPastPresentationTimingEXT::pname:actualPresentTime is -approximately 16.67 later than -sname:VkPastPresentationTimingEXT::pname:targetPresentTime, -the application knows that the image was presented late. -The application can: then change the IPD to 33.33ms (i.e. 30FPS). -It does this by setting both -slink:VkPresentTimeEXT::pname:targetPresentTime and -slink:VkPresentTimeEXT::pname:idealPresentTime to 33.33ms after the -same values that were used for the previous image. - -Later, if the application has been consistently presenting images on -time with an IPD of 33.33ms, if the application desires to try an IPD -of 16.67ms, it can: determine whether it is safe to do so. -It does this by setting slink:VkPresentTimeEXT::pname:idealPresentTime -to 16.67ms earlier than -slink:VkPresentTimeEXT::pname:targetPresentTime, which will continue -to be set to 33.33ms after the -slink:VkPresentTimeEXT::pname:targetPresentTime of the the previous -image. -In this way, the application continues to present images stutter-free, -while requesting feedback from the PE as to whether it can still be -stutter-free with an IPD of 16.67ms. -If the PE determines that it could have displayed the image at -slink:VkPresentTimeEXT::pname:idealPresentTime, it will set -pname:optimalPresentTime to -slink:VkPresentTimeEXT::pname:idealPresentTime. -If so, the application knows it is safe to change its IPD to 16.67ms. - [NOTE] .Note ==== -Frequent changes to an application's IPD can cause visual artifacts. +An application can: determine its optimal IPD in FRR scenarios by using the +sname:VkPastPresentationTimingEXT values. + +For a given target present stage, if `pPresentStages[targetStageIndex].time` +is one or more refresh cycle durations later than the associated present +pname:targetPresentTime, the application knows that the image was presented +late. In order to avoid visual anomalies, it can: increase its IPD by a +multiple of the refresh cycle duration that approximately corresponds to the +difference between `pPresentStages[targetStageIndex].time` and +pname:targetPresentTime. + +If `pPresentStages[targetStageIndex].time` and pname:targetPresentTime are +consistently approximately equal to each other, the application knows that +it is rendering smoothly, without stutter. In that situation, it can: +determine if a lower IPD could be durably achieved by computing the +difference between `pPresentStages[imageLatchedStageIndex].time` and +`pPresentStages[imageHandoffStageIndex].time` over multiple frames, provided +feedback for those present stages is available. If the obtained duration is +consistently larger than the difference between the current and the desired +IPD, then the desired IPD is achievable without stutter. + +Frequent changes to an application's IPD can: cause visual artifacts. Therefore, it is wise for an application to avoid frequent changes to its IPD. -In the above example, before an application decreases its IPD, it will -want to see several consecutive images all have -pname:optimalPresentTime equal to -slink:VkPresentTimeEXT::pname:idealPresentTime. ==== [NOTE] .Note ==== -The presentation engine may change the timing properties of the +The presentation engine may: change the timing properties of the pname:swapchain for a variety of reasons. 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 60Hz FRR, and while -full-screen, the timing properties may be VRR. +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 +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 -pname:timingPropertiesChanged and pname:timeDomainChanged to become -ename:VK_TRUE. -It is also possible that an event can cause only -pname:timingPropertiesChanged to become ename:VK_TRUE. +pname:timingPropertiesChanged to become ename:VK_TRUE and and +pname:timeDomain to be different than the time domain requested in +slink:VkPresentTimingInfoEXT. ==== +-- + +[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[] -- -The full `VK_EXT_present_timing` extension semantics are only described for -swapchains created with the following present modes: - - * ename:VK_PRESENT_MODE_FIFO_KHR. - Tearing cannot be observed. - The first queued image is dequeued and presented if - both: 1) its associated wait semaphore(s) have signaled, and 2) - its target present time is less-than or equal-to the current time. - * ename:VK_PRESENT_MODE_FIFO_RELAXED_KHR. - For images that are presented in time to be displayed at the next - vertical blanking period, the semantics are identical as for - ename:VK_PRESENT_MODE_FIFO_RELAXED_KHR. - For images that are presented late, and are displayed after the start of - the vertical blanking period (i.e. with tearing), the values of - sname:VkPastPresentationTimingEXT may: be treated as if the image was - displayed at the start of the vertical blanking period, or may: be - treated the same as for ename:VK_PRESENT_MODE_IMMEDIATE_KHR. - * ename:VK_PRESENT_MODE_FIFO_LATEST_READY_EXT. - Tearing cannot be observed. - Starting in queue order, successive images are dequeued when both: - 1) its associated wait semaphore(s) have signaled, and 2) its - target present time is less-than or equal-to the current time. - The last of the successive images that are dequeued is presented. endif::VK_EXT_present_timing[] ifdef::VK_GOOGLE_display_timing[] -include::../VK_GOOGLE_display_timing/queries.adoc[] +include::{chapters}/VK_GOOGLE_display_timing/queries.adoc[] endif::VK_GOOGLE_display_timing[] diff --git a/chapters/VK_KHR_surface/wsi.adoc b/chapters/VK_KHR_surface/wsi.adoc index d58bc98c58..bbd990ebda 100644 --- a/chapters/VK_KHR_surface/wsi.adoc +++ b/chapters/VK_KHR_surface/wsi.adoc @@ -1005,6 +1005,41 @@ present barrier feature is not obtainable for this surface. include::{generated}/validity/structs/VkSurfaceCapabilitiesPresentBarrierNV.adoc[] -- endif::VK_NV_present_barrier[] + +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 the type of 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 using + slink:VkPresentTimeEXT::pname:targetPresentTime. + * pname:presentAtRelativeTimeSupported indicates whether a swapchain + created from slink:VkPhysicalDeviceSurfaceInfo2KHR::pname:surface + supports presenting images with relative times using + slink:VkPresentTimeEXT::pname:minPresentDuration. + * 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. + * pname:presentStageTargets is a bitmask of + elink:VkPresentStageFlagBitsEXT indicating which present stages a + swapchain created from slink:VkPhysicalDeviceSurfaceInfo2KHR::pname:surface + is able to provide target present times for. + +include::{generated}/validity/structs/VkPresentTimingSurfaceCapabilitiesEXT.adoc[] +-- +endif::VK_EXT_present_timing[] endif::VK_KHR_get_surface_capabilities2[] ifdef::VK_EXT_display_surface_counter[] diff --git a/chapters/VK_KHR_swapchain/wsi.adoc b/chapters/VK_KHR_swapchain/wsi.adoc index 12080b65c8..3ee4a5b2ff 100644 --- a/chapters/VK_KHR_swapchain/wsi.adoc +++ b/chapters/VK_KHR_swapchain/wsi.adoc @@ -595,6 +595,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[] @@ -652,14 +659,10 @@ ifdef::VK_VERSION_1_1,VK_KHR_device_group[or flink:vkAcquireNextImage2KHR] for the first time. endif::VK_EXT_swapchain_maintenance1[] ifdef::VK_EXT_present_timing[] - * ename:VK_SWAPCHAIN_CREATE_ABSOLUTE_TIME_BIT_EXT specifies that when - images of the swapchain are presented, a - slink:VkAbsolutePresentTimeEXT can: be provided to specify the - absolute time they should: be displayed. - * ename:VK_SWAPCHAIN_CREATE_RELATIVE_TIME_BIT_EXT specifies that when - images of the swapchain are presented, an - slink:VkRelativePresentTimeEXT can: be provided to specify the - minimum duration they should: be displayed. + * 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[] -- @@ -1357,6 +1360,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 @@ -1677,7 +1685,7 @@ include::{generated}/validity/structs/VkDeviceGroupPresentInfoKHR.adoc[] endif::VK_VERSION_1_1,VK_KHR_device_group[] ifdef::VK_EXT_present_timing[] -include::../VK_EXT_present_timing/PresentTimeInfo.adoc[] +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[] diff --git a/chapters/features.adoc b/chapters/features.adoc index b1f2a7b4f4..c8d322c1ea 100644 --- a/chapters/features.adoc +++ b/chapters/features.adoc @@ -5970,6 +5970,34 @@ include::{generated}/validity/structs/VkPhysicalDeviceHostImageCopyFeaturesEXT.a -- endif::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 the type of 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 present times with + sname:VkPresentTimeEXT::pname:targetPresentTime. + * [[features-presentAtRelativeTime]] pname:presentAtRelativeTime indicates + that the implementation supports specifying relative present times with + sname:VkPresentTimeEXT::pname:minPresentDuration. + +: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'] -- @@ -8058,6 +8086,182 @@ ifdef::VK_EXT_line_rasterization[] <>, if the `apiext:VK_EXT_line_rasterization` extension is supported. endif::VK_EXT_line_rasterization[] +ifdef::VK_KHR_16bit_storage[] + * <>, + if the `apiext:VK_KHR_16bit_storage` extension is supported. +endif::VK_KHR_16bit_storage[] +ifdef::VK_VERSION_1_1,VK_KHR_16bit_storage[] + * <>, + if <> is enabled. +endif::VK_VERSION_1_1,VK_KHR_16bit_storage[] +ifdef::VK_VERSION_1_3,VK_EXT_image_robustness[] + * <>, if +ifdef::VK_VERSION_1_3[Vulkan 1.3 or] + the `apiext:VK_EXT_image_robustness` extension is supported. +endif::VK_VERSION_1_3,VK_EXT_image_robustness[] +ifdef::VK_EXT_4444_formats[] + * <>, if the + `apiext:VK_EXT_4444_formats` extension is supported. +endif::VK_EXT_4444_formats[] +ifdef::VK_EXT_mutable_descriptor_type,VK_VALVE_mutable_descriptor_type[] + * <>, if the + `apiext:VK_EXT_mutable_descriptor_type` or + `apiext:VK_VALVE_mutable_descriptor_type` extension is supported. +endif::VK_EXT_mutable_descriptor_type,VK_VALVE_mutable_descriptor_type[] +ifdef::VK_EXT_shader_image_atomic_int64[] + * <> and + <>, if + the `apiext:VK_EXT_shader_image_atomic_int64` extension is supported. + * <>, if + the <> + feature is supported. +endif::VK_EXT_shader_image_atomic_int64[] +ifdef::VK_EXT_shader_atomic_float[] + * <>, + if the <> feature is supported. + * <>, if the + <> feature is supported. +endif::VK_EXT_shader_atomic_float[] +ifdef::VK_EXT_primitives_generated_query[] + * <>, + if the `apiext:VK_EXT_primitives_generated_query` extension is + supported. +endif::VK_EXT_primitives_generated_query[] +ifdef::VK_KHR_fragment_shading_rate[] + * <>, if the + `apiext:VK_KHR_fragment_shading_rate` extension is supported. +endif::VK_KHR_fragment_shading_rate[] +ifdef::VK_EXT_pipeline_protected_access[] + * <>, if + the `apiext:VK_EXT_pipeline_protected_access` extension is supported. +endif::VK_EXT_pipeline_protected_access[] +ifdef::VK_EXT_legacy_dithering[] + * <>, if the + `apiext:VK_EXT_legacy_dithering` extension is supported. +endif::VK_EXT_legacy_dithering[] +ifdef::VK_VERSION_1_3,VK_KHR_shader_terminate_invocation[] + * <> + if +ifdef::VK_VERSION_1_3[Vulkan 1.3 or] + the `apiext:VK_KHR_shader_terminate_invocation` extension is supported. +endif::VK_VERSION_1_3,VK_KHR_shader_terminate_invocation[] +ifdef::VK_VERSION_1_3,VK_KHR_zero_initialize_workgroup_memory[] + * <>, if +ifdef::VK_VERSION_1_3[Vulkan 1.3 or] + the `apiext:VK_KHR_zero_initialize_workgroup_memory` extension is + supported. +endif::VK_VERSION_1_3,VK_KHR_zero_initialize_workgroup_memory[] +ifdef::VK_KHR_workgroup_memory_explicit_layout[] + * <>, if the + `apiext:VK_KHR_workgroup_memory_explicit_layout` extension is supported. +endif::VK_KHR_workgroup_memory_explicit_layout[] +ifdef::VK_EXT_vertex_input_dynamic_state[] + * <>, if + the `apiext:VK_EXT_vertex_input_dynamic_state` extension is supported. +endif::VK_EXT_vertex_input_dynamic_state[] +ifdef::VK_VERSION_1_3,VK_KHR_synchronization2[] + * <> if +ifdef::VK_VERSION_1_3[Vulkan 1.3 or] + the `apiext:VK_KHR_synchronization2` extension is supported. +endif::VK_VERSION_1_3,VK_KHR_synchronization2[] +ifdef::VK_EXT_provoking_vertex[] + * <>, if the + `apiext:VK_EXT_provoking_vertex` extension is supported. +endif::VK_EXT_provoking_vertex[] +ifdef::VK_EXT_descriptor_buffer[] + * <>, if the + `<>` extension is supported. +endif::VK_EXT_descriptor_buffer[] +ifdef::VK_KHR_shader_subgroup_uniform_control_flow[] + * <>, if the + `apiext:VK_KHR_shader_subgroup_uniform_control_flow` extension is + supported. +endif::VK_KHR_shader_subgroup_uniform_control_flow[] +ifdef::VK_EXT_border_color_swizzle[] + * <> if the + `apiext:VK_EXT_border_color_swizzle` extension is supported. +endif::VK_EXT_border_color_swizzle[] +ifdef::VK_EXT_multi_draw[] + * <>, if the + `apiext:VK_EXT_multi_draw` extension is supported. +endif::VK_EXT_multi_draw[] +ifdef::VK_EXT_shader_atomic_float2[] + * <>, if the + <> feature is supported. +endif::VK_EXT_shader_atomic_float2[] +ifdef::VK_KHR_present_id[] + * <>, if the + `apiext:VK_KHR_present_id` extension is supported. +endif::VK_KHR_present_id[] +ifdef::VK_KHR_present_wait[] + * <>, if the + `apiext:VK_KHR_present_wait` extension is supported. +endif::VK_KHR_present_wait[] +ifdef::VK_EXT_host_image_copy[] + * <>, if the + `<>` extension is supported. +endif::VK_EXT_host_image_copy[] +ifdef::VK_EXT_present_timing[] + * <>, if the + `apiext:VK_EXT_present_timing` extension is supported. +endif::VK_EXT_present_timing[] +ifdef::VK_VERSION_1_3,VK_KHR_shader_integer_dot_product[] + * <> if +ifdef::VK_VERSION_1_3[Vulkan 1.3 or] + the `apiext:VK_KHR_shader_integer_dot_product` extension is supported. +endif::VK_VERSION_1_3,VK_KHR_shader_integer_dot_product[] +ifdef::VK_VERSION_1_3,VK_KHR_maintenance4[] + * <>, if +ifdef::VK_VERSION_1_3[Vulkan 1.3 or] + the `apiext:VK_KHR_maintenance4` extension is supported. +endif::VK_VERSION_1_3,VK_KHR_maintenance4[] +ifdef::VK_KHR_maintenance5[] + * <>, if the + `apiext:VK_KHR_maintenance5` extension is supported. +endif::VK_KHR_maintenance5[] +ifdef::VK_KHR_maintenance6[] + * <>, if the + `apiext:VK_KHR_maintenance6` extension is supported. +endif::VK_KHR_maintenance6[] +ifdef::VK_EXT_image_2d_view_of_3d[] + * <>, if the + `apiext:VK_EXT_image_2d_view_of_3d` extension is supported. +endif::VK_EXT_image_2d_view_of_3d[] +ifdef::VK_EXT_image_sliced_view_of_3d[] + * <>, if the + `apiext:VK_EXT_image_sliced_view_of_3d` extension is supported. +endif::VK_EXT_image_sliced_view_of_3d[] +ifdef::VK_VERSION_1_3,VK_EXT_private_data[] + * <>, if +ifdef::VK_VERSION_1_3[Vulkan 1.3 or] + the `apiext:VK_EXT_private_data` extension is supported. +endif::VK_VERSION_1_3,VK_EXT_private_data[] +ifdef::VK_EXT_extended_dynamic_state[] + * <>, if the + `apiext:VK_EXT_extended_dynamic_state` extension is supported. +endif::VK_EXT_extended_dynamic_state[] +ifdef::VK_EXT_extended_dynamic_state2[] + * <>, if the + `apiext:VK_EXT_extended_dynamic_state2` extension is supported. +endif::VK_EXT_extended_dynamic_state2[] +ifdef::VK_EXT_depth_clip_control[] + * <>, if the + `apiext:VK_EXT_depth_clip_control` extension is supported. +endif::VK_EXT_depth_clip_control[] +ifdef::VK_EXT_image_view_min_lod[] + * <>, if the + `apiext:VK_EXT_image_view_min_lod` extension is supported. +endif::VK_EXT_image_view_min_lod[] ifdef::VK_NV_external_sci_sync[] * Either <> or <>, and either diff --git a/chapters/synchronization.adoc b/chapters/synchronization.adoc index d13640e32d..fe115cc738 100644 --- a/chapters/synchronization.adoc +++ b/chapters/synchronization.adoc @@ -7757,6 +7757,11 @@ endif::VK_EXT_calibrated_timestamps[] * [[VUID-VkCalibratedTimestampInfoEXT-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[] -- @@ -7782,14 +7787,13 @@ ifdef::VK_VERSION_1_3,VK_KHR_synchronization2[] endif::VK_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_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_EXT specifies the CLOCK_MONOTONIC + * 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 comparable with platform timestamp values captured using the POSIX @@ -7844,4 +7848,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:vkGetSwapchainTimeDomainsEXT 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..a50139db40 --- /dev/null +++ b/proposals/VK_EXT_present_timing.adoc @@ -0,0 +1,510 @@ +// Copyright 2023-2024 The Khronos Group Inc. +// +// SPDX-License-Identifier: CC-BY-4.0 + += VK_EXT_present_timing +:toc: left +:refpage: https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/ +:sectnums: + +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 aren't 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` +* `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; + VkPresentStageFlagsEXT presentStageTargets; +} VkPresentTimingSurfaceCapabilitiesEXT; +---- + +In addition of the present timing and present scheduling features, surfaces also advertise which <> are available to query timing and schedule presents 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_IMAGE_LATCHED_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 all those stages is desired. See <>. + +Similarly, when using `presentAtAbsoluteTime` feature to schedule presents at specific times, a present stage must be specified as a target. + +* `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_IMAGE_LATCHED_BIT_EXT` is the step after which the image associated with the presentation request has been latched by the presentation engine to create the presentation of a future refresh cycle. For example, in a flip-model scenario, this is the time the presentation request's image has been selected for the next refresh cycle. +* `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. +* `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 `VkSurfacePresentTimingCapabilitiesEXT::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 + +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. 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. + +The `VkSwapchainTimingPropertiesEXT` structure is defined as: + +[source,c] +---- +typedef struct VkSwapchainTimingPropertiesEXT { + VkStructureType sType; + const void* pNext; + uint64_t refreshDuration; + uint64_t variableRefreshDelay; +} VkSwapchainTimingPropertiesEXT; +---- + +* `refreshDuration` is the duration in nanoseconds of the refresh cycle the presentation engine is operating at. +* `variableRefreshDelay` is a duration in nanoseconds indicating the maximum theoretical delay for the presentation engine to start a new refresh cycle upon receiving a presentation request. If this value is the same as `refreshDuration`, the presentation engine is operating in FRR mode. + +Those properties may change at any time during an application's runtime without prior notification, in order to satisfy various system constraints or user input. For example, enabling power-saving mode on a device may cause it to lower the display panel's refresh rate. Such changes are communicated back to the application when querying presentation timings via `vkGetSwapchainTimingPropertiesEXT`. + +When the presentation engine is operating in VRR mode, `refreshDuration` is the minimum refresh duration. + +`refreshDuration` may be zero, 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. + +Applications also need to query available time domains using: +[source,c] +---- +VkResult vkGetSwapchainTimeDomainsEXT( + VkDevice device, + VkSwapchainKHR swapchain, + uint32_t* pSwapchainTimeDomainCount, + VkSwapchainTimeDomainPropertiesEXT* pSwapchainTimeDomains); + +typedef struct VkSwapchainTimeDomainPropertiesEXT { + VkStructureType sType; + void* pNext; + VkTimeDomainEXT timeDomain; + uint64_t timeDomainId; +} VkSwapchainTimeDomainPropertiesEXT; +---- + +* `timeDomainId` is a unique identifier for this time domain in a swapchain-local namespace. This is used to differentiate between multiple swapchain-local time domains that have the same `VkTimeDomainEXT` scope. + +Swapchain-local time domains are added in this proposal as two new `VkTimeDomainEXT` values: +[source,c] +---- +typedef enum VkTimeDomainEXT { + // ... + VK_TIME_DOMAIN_PRESENT_STAGE_LOCAL_EXT = 1000208000, + VK_TIME_DOMAIN_SWAPCHAIN_LOCAL_EXT = 1000208001, +} VkTimeDomainEXT; +---- + +* `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. + +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. + +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; +---- + +A single present stage can be specified in `presentStage` to calibrate a `VK_TIME_DOMAIN_PRESENT_STAGE_LOCAL_EXT` timestamp from that stage. + +=== Presentation timings feedback [[statistics]] + +Applications can obtain timing information about previous presents using: + +[source,c] +---- +VkResult vkGetPastPresentationTimingEXT( + VkDevice device, + VkSwapchainKHR swapchain, + uint32_t* pPresentationTimingCount, + VkPastPresentationTimingEXT* pPresentationTimings, + uint64_t* pSwapchainTimingPropertiesCounter, + VkBool32* pTimeDomainsChanged); +---- + +If the value of `pPresentationTimingCount` is 0, the implementation sets it to the number of pending results available in the swapchain's internal queue. Otherwise, it contains the number of entries written to `pPresentationTimings` upon return. 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 internal swapchain present timing queue is released. Incomplete results for presentation requests will keep being reported by `vkGetPastPresentationTimingEXT` until complete. + +If `pSwapchainTimingPropertiesCounter` is not `NULL`, the implementation sets it to the current internal counter of the swapchain's timing properties. If its value is different than the last known counter value (from a previous call to `vkGetPastPresentationTimingEXT` or `vkGetSwapchainTimingPropertiesEXT`), applications should query those properties again using `vkGetSwapchainTimingPropertiesEXT`. + +`pTimeDomainsChanged` is `VK_TRUE` if the swapchain's list of supported time domains has changed since the last call to `vkGetPastPresentationTimingEXT`. + +`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; + uint32_t presentStageCount; + VkPresentStageTimeEXT* pPresentStages; + uint64_t timeDomainId; + VkBool32 reportComplete; +} VkPastPresentationTimingEXT; +---- + +* `presentId` is a present id provided to `vkQueuePresentKHR` by adding a `VkPresentIdKHR` to the `VkPresentInfoKHR` pNext chain. Timing results can be correlated to specific presents using this value. +* `presentStageCount` and `pPresentStages` contain the timing information for the present stages that were specified in the `VkPresentTimeTargetInfoEXT` passed to the corresponding `vkQueuePresentKHR`. +* `timeDomainId` is the id of the time domain used for `pPresentStages` result times. It may be different than the time domain specified for the associated `vkQueuePresentKHR` if that time domain was unavailable when the presentation request was processed. In this case, `timeDomainId` refers to the time domain the presentation engine used as a preferred fallback. +* `reportComplete` indicates whether results for all present stages have been reported. + +`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_MAILBOX_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 `VkSwapchainPresentTimingCreateInfoEXT::presentStageQueries`. 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] +==== +Tracking the timing of multiple present stages allows applications to deduce various useful information about the present pipeline. For example, tracking both `VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT` and `VK_PRESENT_STAGE_IMAGE_LATCHED_BIT_EXT` reveals how early a presentation request was before its image got latched by the presentation engine. Applications can use this "headroom" value to determine whether they can durably shorten their Image Present Duration (IPD). +==== + +[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 union VkPresentTimeEXT { + uint64_t targetPresentTime; + uint64_t presentDuration; +} VkPresentTimeEXT; + +typedef struct VkPresentTimingInfoEXT { + VkStructureType sType; + const void* pNext; + VkPresentTimeEXT time; + uint64_t timeDomainId; + VkPresentStageFlagsEXT presentStageQueries; + VkPresentStageFlagsEXT targetPresentStage; + VkBool32 presentAtRelativeTime; + VkBool32 presentAtNearestRefreshCycle; +} 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: +* `time` 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. +* `targetPresentStage` is a present stage which cannot be completed before the target time has elapsed. +* `presentAtRelativeTime` specifies whether `time` is to be interpreted as an absolute or a relative time value. +* `presentAtNearestRefreshCycle` specifies that the application would like to present at the refresh cycle that is nearest to the target present time. + +`VkPresentTimeEXT` is interpreted according to the `VkPresentTimingInfoEXT::presentAtRelativeTime` flag: +* `targetPresentTime` specifies the earliest time in nanoseconds the presentation engine can complete the swapchain's target present stage. +* `presentDuration` specifies the minimum duration in nanoseconds the application would like +the image to be visible. + +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 presentation engine must not complete the target present stage earlier than the specified `time`, unless `presentAtNearestRefreshCycle` is set to `VK_TRUE`. In that case, the presentation engine may complete `targetPresentStage` at an earlier time matching the beginning of a refresh cycle, if `time` is within the first half of that refresh cycle. In FRR scenarios, this can help work around clock drift or clock precision issues, which could cause the presentation engine to otherwise skip a refresh cycle for a presentation request. + +The semantics of specifying a target present time or duration only apply to FIFO present modes (`VK_PRESENT_MODE_FIFO_KHR` and `VK_PRESENT_MODE_FIFO_RELAXED_KHR`). When attempting to dequeue a presentation request from the FIFO queue, the presentation engine checks the current time against the target time. + +[NOTE] +==== +To maintain a constant IPD, applications should use timing information collected via `vkGetPastPresentationTimingEXT` to determine the target time or duration of each present. If the presentation engine is operating with a fixed refresh rate, the application's image present duration (IPD) should be a multiple of `VkSwapchainTimingPropertiesEXT::refreshDuration`. That is, the quanta for changing the IPD is `refreshDuration`. 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); + + uint32_t timeDomainCount = 0; + VkSwapchainTimeDomainPropertiesEXT *timeDomains; + + result = vkGetSwapchainTimeDomainsEXT(device, swapchain, &timeDomainCount, NULL); + timeDomains = (VkSwapchainTimeDomainPropertiesEXT *) malloc(timeDomainCount * sizeof(VkSwapchainTimeDomainPropertiesEXT)); + result = vkGetSwapchainTimeDomainsEXT(device, swapchain, &timeDomainCount, timeDomains); + + // Find the ID of the current VK_TIME_DOMAIN_SWAPCHAIN_LOCAL_EXT time domain + uint64_t currentTimeDomainId = FindTimeDomain(timeDomains, timeDomainCount, VK_TIME_DOMAIN_SWAPCHAIN_LOCAL_EXT); + + // Allocate internal queue to collect present timing results + const uint32_t maxTimingCount = GetMaxTimingCount(); // e.g. swapchainImageCount * 2 + result = vkSetSwapchainPresentTimingQueueSizeEXT(device, swapchain, maxTimingCount); + + // (Start presenting...) +---- + +=== Basic present loop + +[source, c] +---- + uint32_t maxPresentStageCount = 4; + uint64_t currentPresentId = 1; + VkPastPresentationTimingEXT *timings = NULL; + VkPresentStageFlagBitsEXT targetPresentStage = VK_PRESENT_STAGE_IMAGE_LATCHED_BIT_EXT; + + timings = (VkPastPresentationTimingEXT *) malloc(maxTimingCount * sizeof(VkPastPresentationTimingEXT)); + for (uint32_t i = 0; i < maxTimingCount; ++i) { + timings[i].pPresentStages = (VkPresentStageTimeEXT *) malloc(maxPresentStageCount * sizeof(VkPastPresentationTimingEXT)); + } + + while (!done) { + uint32_t timingCount = maxTimingCount; + uint64_t newTimingPropertiesCounter = 0; + + result = vkGetPastPresentationTimingEXT(device, swapchain, &timingCount, &timings, &newTimingPropertiesCounter); + + if (newTimingPropertiesCounter != currentTimingPropertiesCounter) { + result = vkGetSwapchainTimingPropertiesEXT(device, swapchain, &swapchainTimingProperties, ¤tTimingPropertiesCounter); + currentTimingPropertiesCounter = newTimingPropertiesCounter; + } + + for (uint32_t i = 0; i < timingCount; ++i) { + if (timings[i].reportComplete) { + if (timings[i].timeDomain == currentTimeDomain) { + // Build a presentation history + pastPresentationTimings[timings[i].presentId % maxPresentHistory] = ParseResult(timings[i]); + } else { + // Handle time domain change. A more sophisticated approach can be + // taken with calibrated timestamps to correlate both time domains. + currentTimeDomain = SelectAvailableTimeDomain(swapchain); + InvalidatePastPresentationTimings(); + } + } + } + + // Process past presentation timings to determine whether changing the IPD is necessary / desired. + uint64_t targetIPD = ProcessPastPresentationTimings(&swapchainTimingProperties); + + // Based on previous reported times and target IPD, compute the next target present time. + uint64_t targetPresentTime = pastPresentationTimings[mostRecentResultsIndex].latchTime + + (currentPresentId - pastPresentationTimings[mostRecentResultsIndex].presentId) * targetIPD. + + // Position scene geometry / camera for `targetPresentTime' + // (...) + + result = vkAcquireNextImageKHR(...); + + // Render to acquired swapchain image + // (...) + + result = vkQueueSubmit(...); + + VkPresentTimingInfoEXT targetPresentTime = { + .sType = VK_STRUCTURE_TYPE_PRESENT_TIME_TARGET_INFO_EXT, + .pNext = NULL, + .time = targetPresentTime, + .timeDomainId = currentTimeDomain, + .presentStageQueries = allStageQueries, + .targetPresentStage = VK_PRESENT_STAGE_IMAGE_LATCHED, + .presentAtNearestRefreshCycle = VK_TRUE + }; + + VkPresentTimingsInfoEXT presentTimesInfo = { + .sType = VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_EXT, + .pNext = NULL, + .swapchainCount = 1, + .pTimeInfos = &targetPresentTime + }; + + VkPresentIdKHR presentId = { + .sType = VK_STRUCTURE_TYPE_PRESENT_ID_KHR, + .pNext = &presentTimesInfo, + .swapchainCount = 1, + .pPresentIds = ¤tPresentId + } + + VkPresentInfoKHR presentInfo = { + .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + .pNext = &presentId, + // (...) + }; + + result = vkQueuePresentKHR(queue, &presentInfo); + + switch (result) { + case VK_ERROR_PRESENT_TIMING_QUEUE_FULL_EXT: + // We're presenting faster than results are coming in. We can either + // wait, reallocate the results queue, or present again without asking + // for present timing data. + targetPresentTime.presentStageQueries = 0; + result = vkQueuePresentKHR(queue, &presentInfo); + // (...) + break; + // Handle other 'result' values... + // (...) + } + + 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_id` 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, but 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. diff --git a/xml/vk.xml b/xml/vk.xml index 921dd07034..311f76f6d6 100644 --- a/xml/vk.xml +++ b/xml/vk.xml @@ -485,6 +485,7 @@ typedef void* MTLSharedEvent_id; typedef VkFlags VkPresentGravityFlagsEXT; typedef VkFlags VkShaderCreateFlagsEXT; typedef VkFlags64 VkPhysicalDeviceSchedulingControlsFlagsARM; + typedef VkFlags VkPresentStageFlagsEXT; Video Core extension typedef VkFlags VkVideoCodecOperationFlagsKHR; @@ -888,6 +889,7 @@ typedef void* MTLSharedEvent_id; + Enumerated types in the header, but not used by the API @@ -3252,53 +3254,73 @@ typedef void* MTLSharedEvent_id; void* pNext VkBool32 presentWaitvkWaitForPresentKHR 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 + VkPresentStageFlagsEXT presentStageTargetspresent stages that can be used as a present target + VkStructureType sType - const void* pNext + void* pNext uint64_t refreshDurationNumber of nanoseconds from the start of one refresh cycle to the next - VkBool32 variableRefresh + uint64_t variableRefreshDelayNumber of nanoseconds for variable refresh displays to react to IPD changes VkStructureType sType void* pNext VkTimeDomainEXT timeDomainAvailable time domain to use with the swapchain + uint64_t timeDomainIdUnique identifier for this time domain - - VkStructureType sType - const void* pNext - VkTimeDomainEXT timeDomainAvailable time domain to use with the swapchain + + VkPresentStageFlagsEXT stage + uint64_t timeTime in nanoseconds of the associated stage VkStructureType sType - const void* pNext - uint32_t presentIDApplication-provided identifier, previously given to vkQueuePresentKHR - uint64_t targetPresentTimeEarliest time an image should have been presented, previously given to vkQueuePresentKHR - uint64_t actualPresentTimeTime the image was actually displayed - uint64_t optimalPresentTimeTime when the PE would have liked the application to have set targetPresentTime to - VkBool32 timingPropertiesChangedVK_TRUE if swapchain's timing properties changed since last queried - VkBool32 timeDomainChangedVK_TRUE if the swapchain no longer supports the enabled time domain - - - VkStructureType sType + void* pNext + uint64_t presentIdApplication-provided identifier, previously given to vkQueuePresentKHR + uint32_t presentStageCountNumber of present stages results available in pPresentStages + VkPresentStageTimeEXT* pPresentStagesReported timings for each present stage + uint64_t timeDomainIdTime domain 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 VkPresentTimeEXT* pTimesWhen to present images - - - uint32_t presentIDApplication-provided identifier - uint64_t targetPresentTimeEarliest time an image should be presented - uint64_t idealPresentTimeIndication to PE of what the application would like targetPresentTime to have been - uint64_t presentSlopPeriod of time an image may be presented before targetPresentTime - - - uint32_t presentIDApplication-provided identifier - uint64_t minPresentDurationShortest duration an image should be presented - uint64_t idealPresentDurationIndication to PE of what the application would like minPresentDuration to be - uint64_t presentSlopPeriod of time an image may be presented before minPresentDuration elapses + const VkPresentTimingInfoEXT* pTimingInfosPresent timing details for each swapchain - - VkAbsolutePresentTimeEXT absolutePresentTime - VkRelativePresentTimeEXT relativePresentTime + + VkStructureType sType + const void* pNext + VkPresentTimeEXT timetarget present time or duration + uint32_t timeDomainIdTime domain to interpret the target present time and collect present stages timings with + VkPresentStageFlagsEXT presentStageQueriesPresent stages to collect timing information for + VkPresentStageFlagsEXT targetPresentStagePresent stage to target with a target present time + VkBool32 presentAtRelativeTimeWhether the specified VkPresentTimeEXT is a relative time + VkBool32 presentAtNearestRefreshCycleWhether the presentation engine is allowed to round down the target present time to the nearest refresh cycle + + + uint64_t targetPresentTime + uint64_t presentDuration + + + VkStructureType sType + const void* pNext + VkSwapchainKHR swapchain + VkPresentStageFlagsEXT presentStage + uint64_t timeDomainId Display primary in chromaticity coordinates @@ -11156,7 +11178,12 @@ typedef void* MTLSharedEvent_id; - + + + + + + @@ -12908,17 +12935,11 @@ typedef void* MTLSharedEvent_id; VkFence fence uint32_t* pImageIndex - + VkResult vkQueuePresentKHR VkQueue queue const VkPresentInfoKHR* pPresentInfo - - VkResult vkSetSwapchainTimingEXT - VkDevice device - VkSwapchainKHR swapchain - const VkSwapchainTimingInfoEXT* pSwapchainTimingInfo - VkResult vkCreateViSurfaceNN VkInstance instance @@ -13607,6 +13628,8 @@ typedef void* MTLSharedEvent_id; VkSwapchainKHR swapchain uint32_t* pPresentationTimingCount VkPastPresentationTimingEXT* pPresentationTimings + uint64_t* pSwapchainTimingPropertiesCounter + VkBool32* pTimeDomainsChanged void vkSetHdrMetadataEXT @@ -15762,11 +15785,19 @@ typedef void* MTLSharedEvent_id; uint32_t stageCount 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 vkGetSwapchainTimeDomainsEXT @@ -20556,31 +20587,39 @@ typedef void* MTLSharedEvent_id; - + - + - - - - - - - + + + + + + + + + + + + + + - - - - + + + + + + - From d270c021496468c80abd96b741a8caa626cc5aa2 Mon Sep 17 00:00:00 2001 From: Lionel Duc Date: Mon, 10 Jun 2024 11:18:55 +0200 Subject: [PATCH 3/5] Address latest review feedback - Time Domains - Rename vkGetSwapchainTimeDomainsEXT -> vkGetSwapchainTimeDomainPropertiesEXT - Add a version counter to the time domains for consistency with timing properties - Change VkSwapchainTimeDomainPropertiesEXT to hold a list of time domains - Change parameters of vkGetPastPresentationTimingEXT to use new structs --- chapters/VK_EXT_present_timing/queries.adoc | 241 +++++++++++--------- chapters/synchronization.adoc | 2 +- proposals/VK_EXT_present_timing.adoc | 172 ++++++++------ xml/vk.xml | 54 +++-- 4 files changed, 280 insertions(+), 189 deletions(-) diff --git a/chapters/VK_EXT_present_timing/queries.adoc b/chapters/VK_EXT_present_timing/queries.adoc index 0e426646f0..bf796c499b 100644 --- a/chapters/VK_EXT_present_timing/queries.adoc +++ b/chapters/VK_EXT_present_timing/queries.adoc @@ -81,11 +81,11 @@ 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. + * pname:pSwapchainTimingProperties is a pointer to an instance of the + slink:VkSwapchainTimingPropertiesEXT structure. include::{generated}/validity/protos/vkGetSwapchainTimingPropertiesEXT.adoc[] -- @@ -103,12 +103,11 @@ include::{generated}/api/structs/VkSwapchainTimingPropertiesEXT.adoc[] * pname:refreshDuration is zero or an indication of the duration of a refresh cycle. If the presentation engine is operating as an FRR display, this is the - number of nanoseconds from the start of one refresh cycle to the - start of the next refresh cycle. - If the presentation engine is operating as a VRR display - (i.e. refresh cycles may: have variable length), this is the - minimum number of nanoseconds from the start of one refresh cycle - to the start of the next refresh cycle. + number of nanoseconds from the start of one refresh cycle to the start of + the next refresh cycle. + If the presentation engine is operating as a VRR display (i.e. refresh + cycles may: have variable length), this is the minimum number of nanoseconds + from the start of one refresh cycle to the start of the next refresh cycle. * pname:variableRefreshDelay is undefined: if pname:refreshDuration is zero; otherwise it is a duration in nanoseconds indicating the maximum theoretical delay for the presentation engine to start a new refresh @@ -170,42 +169,34 @@ feedback of slink:VkPastPresentationTimingEXT values indicates that the target IPD can be durably achieved. ==== -[open,refpage='vkGetSwapchainTimeDomainsEXT',desc='Obtain the time domains supported by the PE for the swapchain',type='protos'] +[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 domain used by the presentation engine for a given swapchain, +To query the time domains supported by the presentation engine for a given swapchain, call: -include::{generated}/api/protos/vkGetSwapchainTimeDomainsEXT.adoc[] +include::{generated}/api/protos/vkGetSwapchainTimeDomainPropertiesEXT.adoc[] * pname:device is the device associated with pname:swapchain. - * pname:swapchain is the swapchain to obtain timing properties for. - * pname:pSwapchainTimeDomainCount is a pointer to an integer related to the - number of time domains available or queried, as described below. - * pname:pSwapchainTimeDomains is either `NULL` or a pointer to an array of - slink:VkSwapchainTimeDomainPropertiesEXT structs, indicating the supported time - domains of the presentation engine for the swapchain. - -If pname:pSwapchainTimeDomains is `NULL`, then the number of time domains -supported for the given pname:swapchain is returned in -pname:pSwapchainTimeDomainCount (if this value is zero, pname:swapchain -does not currently support display timing). -Otherwise, pname:pSwapchainTimeDomainCount must: point to a variable set by the user -to the number of elements in the pname:pSwapchainTimeDomains array, and on return -the variable is overwritten with the number of values actually written to -pname:pSwapchainTimeDomains. -If the value of pname:pSwapchainTimeDomainCount is less than the number of -time domains supported, at most pname:pSwapchainTimeDomainCount values will be -written. -If pname:pSwapchainTimeDomainCount 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/vkGetSwapchainTimeDomainsEXT.adoc[] + * pname:swapchain is the swapchain to obtain time domain properties for. + * 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. + * pname:pSwapchainTimeDomainProperties is a pointer to an instance of the + slink:VkSwapchainTimeDomainPropertiesEXT structure. + +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='An available time domain for a swapchain',type='structs'] +[open,refpage='VkSwapchainTimeDomainPropertiesEXT',desc='List of available time domains for a swapchain',type='structs'] -- The sname:VkSwapchainTimeDomainPropertiesEXT structure is defined as: @@ -215,20 +206,30 @@ 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:timeDomain is a elink:VkTimeDomainEXT value representing a time - domain that is available for the swapchain. - * pname:timeDomainId is a unique identifier for this time domain within a - swapchain's namespace. + * 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:VkTimeDomainEXT 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] .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:VkTimeDomainEXT value, for example when a surface is -moved from one display hardware to another. Arbitrary identifiers, provided -in pname:timeDomainId, are used by the implementation to differentiate opaque -time domains of identical scopes. +swapchains may need to expose multiple swapchain-local opaque time domains using +the same elink:VkTimeDomainEXT 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[] @@ -238,8 +239,8 @@ include::{generated}/validity/structs/VkSwapchainTimeDomainPropertiesEXT.adoc[] -- Because of the asynchronous nature of the presentation engine, the timing -information for a given flink:vkQueuePresentKHR command only becomes -available some time later. +information for a given flink:vkQueuePresentKHR command may: only becomes +available some time after the presentation has occured. 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. @@ -250,32 +251,86 @@ 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. + +Timing information may: become available out of order with regards to their +associated presentation request submission order. + +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. + +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. + +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:swapchain is the swapchain to obtain presentation timing - information duration for. - * pname:pPresentationTimingCount is a pointer to an integer related to the - number of slink:VkPastPresentationTimingEXT structures to query, as + information for. + +include::{generated}/validity/structs/VkPastPresentationTimingInfoEXT.adoc[] +-- + +[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 number + of slink:VkPastPresentationTimingEXT structures available or queried, as described below. - * pname:pPresentationTimings is `NULL` or a pointer to an an array + * pname:pPresentationTimings is `NULL` or a pointer to an array of slink:VkPastPresentationTimingEXT structures. - * 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. - * pname:pTimeDomainsChanged is `NULL` or a pointer to a boolean value - indicating if the list of supported time domains supported by the - pname:swapchain has changed since the last call to this function. - -If pname:pPresentationTimings is `NULL`, then the number of available -timing records for the given pname:swapchain is returned in -pname:pPresentationTimingCount. -Otherwise, pname:pPresentationTimingCount must: point to a variable set by -the user to 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 the value of pname:pPresentationTimingCount is less than the number of -newly-available timing records for the given pname:swapchain, at most -pname:pPresentationTimingCount structures are written, and -ename:VK_INCOMPLETE is returned instead of ename:VK_SUCCESS to indicate that -not all the available values were returned. + +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. fname:vkGetPastPresentationTimingEXT may: return incomplete results, containing only information for a subset of the requested present @@ -288,30 +343,7 @@ 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. -If pname:pTimeDomainsChanged is ename:VK_TRUE, applications should: query -the new list of available time domains with flink:vkGetSwapchainTimeDomainsEXT. - -Timing information may: become available out of order with regards to their -associated presentation request submission order. - -Upon return, zero or more slots of the pname:swapchain internal timing -results queue, equal to the number of entries written to -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. - -There is no requirement for any precise timing relationship between the -completion of a present stage and the availability of any associated timing -information. - -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. - -include::{generated}/validity/protos/vkGetPastPresentationTimingEXT.adoc[] +include::{generated}/validity/structs/VkPastPresentationTimingPropertiesEXT.adoc[] -- [open,refpage='VkPastPresentationTimingEXT',desc='Structure containing timing information about a previously-presented image',type='structs'] @@ -332,8 +364,9 @@ include::{generated}/api/structs/VkPastPresentationTimingEXT.adoc[] * pname:pPresentStages a pointer to an array of slink:VkPresentStageTimeEXT providing timing information for the presentation request associated with pname:presentId. - * pname:timeDomainId is the id of the time domain used by the presentation + * 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. @@ -351,15 +384,15 @@ For systems with multiple entities operating within the presentation engine, such as multiple displays, pname:pPresentStages will return timing results for at least one entity which has been affected by the presentation. -pname:timeDomain may: be different than the time domain that was specified -in slink:VkPresentTimingInfoEXT::pname:timeDomain 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 and report results in that domain. -Applications can: continue to use this fallback time domain in future +pname:timeDomain may: be different than the time domain that was specified in +slink:VkPresentTimingInfoEXT::pname:timeDomain 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 flink:vkQueuePresentKHR calls, or they can: call -flink:vkGetSwapchainTimeDomainsEXT to choose from the currently supported -time domains. +flink:vkGetSwapchainTimeDomainPropertiesEXT to choose from the currently +supported time domains. include::{generated}/validity/structs/VkPastPresentationTimingEXT.adoc[] @@ -408,7 +441,7 @@ 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 -pname:timingPropertiesChanged to become ename:VK_TRUE and and +pname:timingPropertiesChanged to become ename:VK_TRUE and pname:timeDomain to be different than the time domain requested in slink:VkPresentTimingInfoEXT. ==== diff --git a/chapters/synchronization.adoc b/chapters/synchronization.adoc index fe115cc738..ce64da6840 100644 --- a/chapters/synchronization.adoc +++ b/chapters/synchronization.adoc @@ -7866,7 +7866,7 @@ include::{generated}/api/structs/VkSwapchainCalibratedTimestampInfoEXT.adoc[] * pname:timeDomainId is the id for the opaque time domain being calibrated. pname:timeDomainId must: be an id previously reported by -flink:vkGetSwapchainTimeDomainsEXT for pname:swapchain. If the +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. diff --git a/proposals/VK_EXT_present_timing.adoc b/proposals/VK_EXT_present_timing.adoc index a50139db40..dbe84afde8 100644 --- a/proposals/VK_EXT_present_timing.adoc +++ b/proposals/VK_EXT_present_timing.adoc @@ -86,7 +86,7 @@ typedef enum VkPresentStageFlagBitsEXT { When queueing a presentation request for a swapchain, a set of present stages is specified to inform the implementation that timing for all those stages is desired. See <>. -Similarly, when using `presentAtAbsoluteTime` feature to schedule presents at specific times, a present stage must be specified as a target. +Similarly, when using `presentAtAbsoluteTime` feature to schedule presents at specific times, a present stage must be specified as a target. 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_IMAGE_LATCHED_BIT_EXT` is the step after which the image associated with the presentation request has been latched by the presentation engine to create the presentation of a future refresh cycle. For example, in a flip-model scenario, this is the time the presentation request's image has been selected for the next refresh cycle. @@ -115,6 +115,8 @@ Calling `vkQueuePresentKHR` with non-zero stage queries allocates a slot in that === 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] @@ -122,14 +124,12 @@ For timing to be meaningful, the application needs to be aware of various proper VkResult vkGetSwapchainTimingPropertiesEXT( VkDevice device, VkSwapchainKHR swapchain, - VkSwapchainTimingPropertiesEXT* pSwapchainTimingProperties, - uint64_t* pSwapchainTimingPropertiesCounter); + uint64_t* pSwapchainTimingPropertiesCounter, + VkSwapchainTimingPropertiesEXT* pSwapchainTimingProperties); ---- - -Swapchain timing properties may change dynamically at any time. 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. +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 communicated back to the application when querying presentation timings via `vkGetPastPresentationTimingEXT`. The `VkSwapchainTimingPropertiesEXT` structure is defined as: - [source,c] ---- typedef struct VkSwapchainTimingPropertiesEXT { @@ -139,36 +139,42 @@ typedef struct VkSwapchainTimingPropertiesEXT { uint64_t variableRefreshDelay; } VkSwapchainTimingPropertiesEXT; ---- - * `refreshDuration` is the duration in nanoseconds of the refresh cycle the presentation engine is operating at. * `variableRefreshDelay` is a duration in nanoseconds indicating the maximum theoretical delay for the presentation engine to start a new refresh cycle upon receiving a presentation request. If this value is the same as `refreshDuration`, the presentation engine is operating in FRR mode. -Those properties may change at any time during an application's runtime without prior notification, in order to satisfy various system constraints or user input. For example, enabling power-saving mode on a device may cause it to lower the display panel's refresh rate. Such changes are communicated back to the application when querying presentation timings via `vkGetSwapchainTimingPropertiesEXT`. - When the presentation engine is operating in VRR mode, `refreshDuration` is the minimum refresh duration. `refreshDuration` may be zero, 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. +==== Time Domains + Applications also need to query available time domains using: [source,c] ---- -VkResult vkGetSwapchainTimeDomainsEXT( +VkResult vkGetSwapchainTimeDomainPropertiesEXT( VkDevice device, VkSwapchainKHR swapchain, - uint32_t* pSwapchainTimeDomainCount, - VkSwapchainTimeDomainPropertiesEXT* pSwapchainTimeDomains); + uint64_t* pTimeDomainsCounter, + VkSwapchainTimeDomainPropertiesEXT* pSwapchainTimeDomainProperties); +---- +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; - VkTimeDomainEXT timeDomain; - uint64_t timeDomainId; + uint32_t timeDomainCount; + VkTimeDomainEXT *pTimeDomains; + uint64_t *pTimeDomainIds; } VkSwapchainTimeDomainPropertiesEXT; ---- +* `timeDomainCount` is an input specifying the size of the `pTimeDomains` and `pTimeDomainIds` arrays. If it is 0, 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 `VkTimeDomainEXT` currently supported by the swapchain. +* `pTimeDomainIds` is an array of unique identifiers for each supported time domain. This is used to differentiate between multiple swapchain-local time domains that have the same `VkTimeDomainEXT` scope. -* `timeDomainId` is a unique identifier for this time domain in a swapchain-local namespace. This is used to differentiate between multiple swapchain-local time domains that have the same `VkTimeDomainEXT` scope. - -Swapchain-local time domains are added in this proposal as two new `VkTimeDomainEXT` values: +Two new swapchain-local time domains are added in this proposal as `VkTimeDomainEXT` values: [source,c] ---- typedef enum VkTimeDomainEXT { @@ -177,7 +183,6 @@ typedef enum VkTimeDomainEXT { VK_TIME_DOMAIN_SWAPCHAIN_LOCAL_EXT = 1000208001, } VkTimeDomainEXT; ---- - * `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. @@ -194,8 +199,8 @@ typedef struct VkSwapchainCalibratedTimestampInfoEXT { uint64_t timeDomainId; } VkSwapchainCalibratedTimestampInfoEXT; ---- - -A single present stage can be specified in `presentStage` to calibrate a `VK_TIME_DOMAIN_PRESENT_STAGE_LOCAL_EXT` timestamp from that stage. +* `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]] @@ -204,21 +209,37 @@ Applications can obtain timing information about previous presents using: [source,c] ---- VkResult vkGetPastPresentationTimingEXT( - VkDevice device, - VkSwapchainKHR swapchain, - uint32_t* pPresentationTimingCount, - VkPastPresentationTimingEXT* pPresentationTimings, - uint64_t* pSwapchainTimingPropertiesCounter, - VkBool32* pTimeDomainsChanged); + 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; + VkSwapchainKHR swapchain; +}; ---- -If the value of `pPresentationTimingCount` is 0, the implementation sets it to the number of pending results available in the swapchain's internal queue. Otherwise, it contains the number of entries written to `pPresentationTimings` upon return. 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 internal swapchain present timing queue is released. Incomplete results for presentation requests will keep being reported by `vkGetPastPresentationTimingEXT` until complete. - -If `pSwapchainTimingPropertiesCounter` is not `NULL`, the implementation sets it to the current internal counter of the swapchain's timing properties. If its value is different than the last known counter value (from a previous call to `vkGetPastPresentationTimingEXT` or `vkGetSwapchainTimingPropertiesEXT`), applications should query those properties again using `vkGetSwapchainTimingPropertiesEXT`. +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. +* If the input value of `presentationTimingCount` is 0, the implementation sets it to the number of pending results available in the swapchain's internal queue. Otherwise, it contains the number of entries written to `pPresentationTimings` upon return. If the implementation is not able to write all the available results in the provided `pPresentationTimings` array, `VK_INCOMPLETE` is returned. -`pTimeDomainsChanged` is `VK_TRUE` if the swapchain's list of supported time domains has changed since the last call to `vkGetPastPresentationTimingEXT`. +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. `VkPastPresentationTimingEXT` is defined as: [source, c] @@ -234,14 +255,15 @@ typedef struct VkPastPresentationTimingEXT { uint64_t presentId; uint32_t presentStageCount; VkPresentStageTimeEXT* pPresentStages; + VkTimeDomainEXT timeDomain; uint64_t timeDomainId; VkBool32 reportComplete; } VkPastPresentationTimingEXT; ---- * `presentId` is a present id provided to `vkQueuePresentKHR` by adding a `VkPresentIdKHR` to the `VkPresentInfoKHR` pNext chain. Timing results can be correlated to specific presents using this value. -* `presentStageCount` and `pPresentStages` contain the timing information for the present stages that were specified in the `VkPresentTimeTargetInfoEXT` passed to the corresponding `vkQueuePresentKHR`. -* `timeDomainId` is the id of the time domain used for `pPresentStages` result times. It may be different than the time domain specified for the associated `vkQueuePresentKHR` if that time domain was unavailable when the presentation request was processed. In this case, `timeDomainId` refers to the time domain the presentation engine used as a preferred fallback. +* `presentStageCount` and `pPresentStages` contain the timing information for the present stages that were specified in the `VkPresentTimeTargetInfoEXT` 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` 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_MAILBOX_KHR`. Platform-specific events can also cause results for some present stages to be unavailable for a specific presentation request. @@ -287,8 +309,8 @@ typedef struct VkPresentTimingsInfoEXT { const VkPresentTimingInfoEXT* pTimingInfos; } VkPresentTimingsInfoEXT; ---- - For each swapchain referenced in `VkPresentInfoKHR`, a `VkPresentTimingInfoEXT` is specified: + * `time` 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. @@ -297,6 +319,7 @@ For each swapchain referenced in `VkPresentInfoKHR`, a `VkPresentTimingInfoEXT` * `presentAtNearestRefreshCycle` specifies that the application would like to present at the refresh cycle that is nearest to the target present time. `VkPresentTimeEXT` is interpreted according to the `VkPresentTimingInfoEXT::presentAtRelativeTime` flag: + * `targetPresentTime` specifies the earliest time in nanoseconds the presentation engine can complete the swapchain's target present stage. * `presentDuration` specifies the minimum duration in nanoseconds the application would like the image to be visible. @@ -352,20 +375,27 @@ To maintain a constant IPD, applications should use timing information collected }; uint64_t currentTimingPropertiesCounter = 0; - result = vkGetSwapchainTimingPropertiesEXT(device, swapchain, &swapchainTimingProperties, ¤tTimingPropertiesCounter); + result = vkGetSwapchainTimingPropertiesEXT(device, swapchain, ¤tTimingPropertiesCounter, &swapchainTimingProperties); - uint32_t timeDomainCount = 0; - VkSwapchainTimeDomainPropertiesEXT *timeDomains; + uint64_t currentTimeDomainsCounter = 0; + VkSwapchainTimeDomainPropertiesEXT timeDomains = { + .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_TIME_DOMAIN_PROPERTIES_EXT, + .pNext = NULL, + .timeDomainCount = 0, + .pTimeDomains = NULL, + .pTimeDomainIds = NULL + }; - result = vkGetSwapchainTimeDomainsEXT(device, swapchain, &timeDomainCount, NULL); - timeDomains = (VkSwapchainTimeDomainPropertiesEXT *) malloc(timeDomainCount * sizeof(VkSwapchainTimeDomainPropertiesEXT)); - result = vkGetSwapchainTimeDomainsEXT(device, swapchain, &timeDomainCount, timeDomains); + result = vkGetSwapchainTimeDomainPropertiesEXT(device, swapchain, NULL, &timeDomains); + timeDomains.pTimeDomains = (VkTimeDomainEXT *) malloc(timeDomains.timeDomainCount * sizeof(VkTimeDomainEXT)); + timeDomains.pTimeDomainIds = (uint64_t *) malloc(timeDomains.timeDomainCount * sizeof(uint64_t)); + result = vkGetSwapchainTimeDomainPropertiesEXT(device, swapchain, ¤tTimeDomainsCounter, &timeDomains); // Find the ID of the current VK_TIME_DOMAIN_SWAPCHAIN_LOCAL_EXT time domain - uint64_t currentTimeDomainId = FindTimeDomain(timeDomains, timeDomainCount, VK_TIME_DOMAIN_SWAPCHAIN_LOCAL_EXT); + uint64_t swapchainLocalTimeDomainId = FindTimeDomain(&timeDomains, VK_TIME_DOMAIN_SWAPCHAIN_LOCAL_EXT); // Allocate internal queue to collect present timing results - const uint32_t maxTimingCount = GetMaxTimingCount(); // e.g. swapchainImageCount * 2 + const uint32_t maxTimingCount = GetMaxTimingCount(); // Default to sane value, e.g. swapchainImageCount * 2 result = vkSetSwapchainPresentTimingQueueSizeEXT(device, swapchain, maxTimingCount); // (Start presenting...) @@ -377,36 +407,50 @@ To maintain a constant IPD, applications should use timing information collected ---- uint32_t maxPresentStageCount = 4; uint64_t currentPresentId = 1; - VkPastPresentationTimingEXT *timings = NULL; + VkPastPresentationTimingEXT *pTimings = (VkPastPresentationTimingEXT *) malloc(maxTimingCount * sizeof(VkPastPresentationTimingEXT)); + VkPastPresentationTimingInfoEXT pastPresentationTimingInfo = { + .sType = VK_STRUCTURE_TYPE_PAST_PRESENTATION_TIMING_INFO_EXT, + .pNext = NULL, + .swapchain = swapchain + }; + VkPastPresentationTimingPropertiesEXT pastPresentationTimingProperties = { + .sType = VK_STRUCTURE_TYPE_PAST_PRESENTATION_TIMING_PROPERTIES_EXT, + .pNext = NULL, + .pPresentationTimings = pTimings + }; VkPresentStageFlagBitsEXT targetPresentStage = VK_PRESENT_STAGE_IMAGE_LATCHED_BIT_EXT; - timings = (VkPastPresentationTimingEXT *) malloc(maxTimingCount * sizeof(VkPastPresentationTimingEXT)); for (uint32_t i = 0; i < maxTimingCount; ++i) { - timings[i].pPresentStages = (VkPresentStageTimeEXT *) malloc(maxPresentStageCount * sizeof(VkPastPresentationTimingEXT)); + pTimings[i].pPresentStages = (VkPresentStageTimeEXT *) malloc(maxPresentStageCount * sizeof(VkPresentStageTimeEXT)); } while (!done) { - uint32_t timingCount = maxTimingCount; - uint64_t newTimingPropertiesCounter = 0; + pastPresentationTimingProperties.presentationTimingCount = maxTimingCount; - result = vkGetPastPresentationTimingEXT(device, swapchain, &timingCount, &timings, &newTimingPropertiesCounter); + result = vkGetPastPresentationTimingEXT(device, &pastPresentationTimingInfo, &pastPresentationTimingProperties); - if (newTimingPropertiesCounter != currentTimingPropertiesCounter) { - result = vkGetSwapchainTimingPropertiesEXT(device, swapchain, &swapchainTimingProperties, ¤tTimingPropertiesCounter); - currentTimingPropertiesCounter = newTimingPropertiesCounter; + if (pastPresentationTimingProperties.timingPropertiesCounter != currentTimingPropertiesCounter) { + result = vkGetSwapchainTimingPropertiesEXT(device, swapchain, ¤tTimingPropertiesCounter, &swapchainTimingProperties); + currentTimingPropertiesCounter = pastPresentationTimingProperties.timingPropertiesCounter; } for (uint32_t i = 0; i < timingCount; ++i) { - if (timings[i].reportComplete) { - if (timings[i].timeDomain == currentTimeDomain) { - // Build a presentation history - pastPresentationTimings[timings[i].presentId % maxPresentHistory] = ParseResult(timings[i]); - } else { - // Handle time domain change. A more sophisticated approach can be - // taken with calibrated timestamps to correlate both time domains. - currentTimeDomain = SelectAvailableTimeDomain(swapchain); - InvalidatePastPresentationTimings(); - } + if (timings[i].reportComplete && timings[i].timeDomainId == swapchainLocalTimeDomainId) { + // Build the presentation history for reports that use the expected time domain only. + // This could be handled in a more sophisticated way by calibrating timestamps across + // different time domains if desired. + pastPresentationTimings[timings[i].presentId % maxPresentHistory] = ParseResult(timings[i]); + } + } + + // Re-query time domains if necessary. If our current time domain is not available anymore, start + // over with a new history. + if (pastPresentationTimingProperties.timeDomainsCounter != currentTimeDomainsCounter) { + currentTimeDomainsCounter = UpdateTimeDomains(swapchain, &timeDomains); + uint64_t newSwapchainLocalTimeDomainId = FindTimeDomain(&timeDomains, VK_TIME_DOMAIN_SWAPCHAIN_LOCAL_EXT); + if (newSwapchainLocalTimeDomainId != swapchainLocalTimeDomainId) { + swapchainLocalTimeDomainId = newSwapchainLocalTimeDomainId; + InvalidatePresentationTimingHistory(); } } @@ -417,7 +461,7 @@ To maintain a constant IPD, applications should use timing information collected uint64_t targetPresentTime = pastPresentationTimings[mostRecentResultsIndex].latchTime + (currentPresentId - pastPresentationTimings[mostRecentResultsIndex].presentId) * targetIPD. - // Position scene geometry / camera for `targetPresentTime' + // Position scene geometry for `targetPresentTime' // (...) result = vkAcquireNextImageKHR(...); @@ -431,7 +475,7 @@ To maintain a constant IPD, applications should use timing information collected .sType = VK_STRUCTURE_TYPE_PRESENT_TIME_TARGET_INFO_EXT, .pNext = NULL, .time = targetPresentTime, - .timeDomainId = currentTimeDomain, + .timeDomainId = swapchainLocalTimeDomainId, .presentStageQueries = allStageQueries, .targetPresentStage = VK_PRESENT_STAGE_IMAGE_LATCHED, .presentAtNearestRefreshCycle = VK_TRUE diff --git a/xml/vk.xml b/xml/vk.xml index 311f76f6d6..0f7a0a4ff3 100644 --- a/xml/vk.xml +++ b/xml/vk.xml @@ -3272,27 +3272,42 @@ typedef void* MTLSharedEvent_id; VkStructureType sType - void* pNext + void* pNext uint64_t refreshDurationNumber of nanoseconds from the start of one refresh cycle to the next uint64_t variableRefreshDelayNumber of nanoseconds for variable refresh displays to react to IPD changes VkStructureType sType - void* pNext - VkTimeDomainEXT timeDomainAvailable time domain to use with the swapchain - uint64_t timeDomainIdUnique identifier for this time domain + void* pNext + uint32_t timeDomainCount + VkTimeDomainEXT* 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 + 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 uint32_t presentStageCountNumber of present stages results available in pPresentStages VkPresentStageTimeEXT* pPresentStagesReported timings for each present stage - uint64_t timeDomainIdTime domain of the present stages + VkTimeDomainEXT 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 @@ -3315,7 +3330,7 @@ typedef void* MTLSharedEvent_id; uint64_t targetPresentTime uint64_t presentDuration - + VkStructureType sType const void* pNext VkSwapchainKHR swapchain @@ -13622,15 +13637,6 @@ typedef void* MTLSharedEvent_id; uint32_t set const void* pData - - VkResult vkGetPastPresentationTimingEXT - VkDevice device - VkSwapchainKHR swapchain - uint32_t* pPresentationTimingCount - VkPastPresentationTimingEXT* pPresentationTimings - uint64_t* pSwapchainTimingPropertiesCounter - VkBool32* pTimeDomainsChanged - void vkSetHdrMetadataEXT VkDevice device @@ -15796,15 +15802,21 @@ typedef void* MTLSharedEvent_id; VkResult vkGetSwapchainTimingPropertiesEXT VkDevice device VkSwapchainKHR swapchain - VkSwapchainTimingPropertiesEXT* pSwapchainTimingProperties uint64_t* pSwapchainTimingPropertiesCounter + VkSwapchainTimingPropertiesEXT* pSwapchainTimingProperties - VkResult vkGetSwapchainTimeDomainsEXT + VkResult vkGetSwapchainTimeDomainPropertiesEXT VkDevice device VkSwapchainKHR swapchain - uint32_t* pSwapchainTimeDomainCount - VkSwapchainTimeDomainPropertiesEXT* pSwapchainTimeDomains + uint64_t* pTimeDomainsCounter + VkSwapchainTimeDomainPropertiesEXT* pSwapchainTimeDomainProperties + + + VkResult vkGetPastPresentationTimingEXT + VkDevice device + const VkPastPresentationTimingInfoEXT* pPastPresentationTimingInfo + VkPastPresentationTimingPropertiesEXT* pPastPresentationTimingProperties VkResult vkGetScreenBufferPropertiesQNX @@ -20609,6 +20621,8 @@ typedef void* MTLSharedEvent_id; + + @@ -20618,7 +20632,7 @@ typedef void* MTLSharedEvent_id; - + From 71506d00d75f22aefe91b72a1da671ff5585ab40 Mon Sep 17 00:00:00 2001 From: Lionel Duc Date: Wed, 9 Oct 2024 18:02:40 +0200 Subject: [PATCH 4/5] Mark some issues as resolved. Also fix some boilerplate language / copyright. --- appendices/VK_EXT_present_timing.adoc | 33 +++++++++---------- .../PresentTimeInfo.adoc | 2 +- chapters/VK_EXT_present_timing/queries.adoc | 6 ++-- chapters/features.adoc | 2 +- proposals/VK_EXT_present_timing.adoc | 8 ++--- 5 files changed, 23 insertions(+), 28 deletions(-) diff --git a/appendices/VK_EXT_present_timing.adoc b/appendices/VK_EXT_present_timing.adoc index a56d25bf76..a20d51a5e1 100644 --- a/appendices/VK_EXT_present_timing.adoc +++ b/appendices/VK_EXT_present_timing.adoc @@ -7,7 +7,7 @@ include::{generated}/meta/{refprefix}VK_EXT_present_timing.adoc[] === Other Extension Metadata *Last Modified Date*:: - 2024-05-30 + 2024-10-09 *IP Status*:: No known IP claims. *Contributors*:: @@ -159,7 +159,7 @@ Other extensions can add other platform-specific time domains. 6) What time to use for targetPresentTime for early images? -*PROPOSED*: Have no query for determining the current time in the PE’s time +*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. @@ -184,7 +184,9 @@ address this issue. 8) Do we have a query for the anticipated latency from present to feedback? -*UNRESOLVED*: There is some amount of latency from when an application calls +*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. @@ -198,27 +200,22 @@ the latency was approximately 5 refresh cycles (83.33ms). For higher-frequency displays, the latency may have a larger number of refresh cycles. -Can such a query be reasonably answered by the driver? Is there other -interesting information in this space that we may wish to capture? - 9) Do we have a query(s) about the number of VkPastPresentationTimingEXT structs to keep? -*PROPOSED*: Let the application specify at swapchain creation how many -results the swapchain is allowed to store before querying them with -vkGetPastPresentationTimingEXT. +*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 time domain used with the calibrated -timestamps extension? +10) How is the SWAPCHAIN_LOCAL and STAGE_LOCAL time domain used with the +calibrated timestamps extension? -*PROPOSED*: Define a struct to chain into VkCalibratedTimestampInfoEXT::pNext -that specifies a swapchain. -Is anything additional needed for -vkGetPhysicalDeviceCalibrateableTimeDomainsEXT, or are swapchain-local -timestamps always calibrateable or always not calibrateable for a given -device? +*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, @@ -235,5 +232,5 @@ Split it out into its own extension and define the interaction here. * Revision 2, 2022-11-30 (Lionel Duc) ** Rebase for public discussions. - * Revision 3, 2024-05-29 (Lionel Duc) + * Revision 3, 2024-10-09 (Lionel Duc) ** Public revisions. diff --git a/chapters/VK_EXT_present_timing/PresentTimeInfo.adoc b/chapters/VK_EXT_present_timing/PresentTimeInfo.adoc index 48817ff30e..597d075314 100644 --- a/chapters/VK_EXT_present_timing/PresentTimeInfo.adoc +++ b/chapters/VK_EXT_present_timing/PresentTimeInfo.adoc @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2023 Khronos Group. +// Copyright (c) 2014-2024 Khronos Group. // // SPDX-License-Identifier: CC-BY-4.0 diff --git a/chapters/VK_EXT_present_timing/queries.adoc b/chapters/VK_EXT_present_timing/queries.adoc index bf796c499b..3538e5d620 100644 --- a/chapters/VK_EXT_present_timing/queries.adoc +++ b/chapters/VK_EXT_present_timing/queries.adoc @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2023 Khronos Group. +// Copyright (c) 2014-2024 Khronos Group. // // SPDX-License-Identifier: CC-BY-4.0 @@ -113,8 +113,8 @@ include::{generated}/api/structs/VkSwapchainTimingPropertiesEXT.adoc[] theoretical delay for the presentation engine to start a new refresh cycle upon processing a presentation request. -If pname:variableRefreshDelay is the same as pname:refreshDuration, the -presentation engine is operating as an FRR display. +If pname:variableRefreshDelay is code:UINT64_MAX, the presentation engine is +operating as an FRR display. Some platforms may: not provide timing properties until after at least one image has been presented to the pname:swapchain. If timing properties diff --git a/chapters/features.adoc b/chapters/features.adoc index c8d322c1ea..74e90f8b90 100644 --- a/chapters/features.adoc +++ b/chapters/features.adoc @@ -5979,7 +5979,7 @@ include::{generated}/api/structs/VkPhysicalDevicePresentTimingFeaturesEXT.adoc[] This structure describes the following feature: - * pname:sType is the type of this structure. + * 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 diff --git a/proposals/VK_EXT_present_timing.adoc b/proposals/VK_EXT_present_timing.adoc index dbe84afde8..d2af9326bf 100644 --- a/proposals/VK_EXT_present_timing.adoc +++ b/proposals/VK_EXT_present_timing.adoc @@ -127,7 +127,7 @@ VkResult vkGetSwapchainTimingPropertiesEXT( uint64_t* pSwapchainTimingPropertiesCounter, VkSwapchainTimingPropertiesEXT* pSwapchainTimingProperties); ---- -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 communicated back to the application when querying presentation timings via `vkGetPastPresentationTimingEXT`. +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`. The `VkSwapchainTimingPropertiesEXT` structure is defined as: [source,c] @@ -140,7 +140,7 @@ typedef struct VkSwapchainTimingPropertiesEXT { } VkSwapchainTimingPropertiesEXT; ---- * `refreshDuration` is the duration in nanoseconds of the refresh cycle the presentation engine is operating at. -* `variableRefreshDelay` is a duration in nanoseconds indicating the maximum theoretical delay for the presentation engine to start a new refresh cycle upon receiving a presentation request. If this value is the same as `refreshDuration`, the presentation engine is operating in FRR mode. +* `variableRefreshDelay` is a duration in nanoseconds indicating the maximum theoretical delay for the presentation engine to start a new refresh cycle upon receiving a presentation request. If this value is `UINT64_MAX`, the presentation engine is operating in FRR mode. When the presentation engine is operating in VRR mode, `refreshDuration` is the minimum refresh duration. @@ -172,7 +172,7 @@ typedef struct VkSwapchainTimeDomainPropertiesEXT { ---- * `timeDomainCount` is an input specifying the size of the `pTimeDomains` and `pTimeDomainIds` arrays. If it is 0, 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 `VkTimeDomainEXT` currently supported by the swapchain. -* `pTimeDomainIds` is an array of unique identifiers for each supported time domain. This is used to differentiate between multiple swapchain-local time domains that have the same `VkTimeDomainEXT` scope. +* `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 `VkTimeDomainEXT` values: [source,c] @@ -186,8 +186,6 @@ typedef enum VkTimeDomainEXT { * `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. -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. - 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] ---- From 1c2738ba176eaed9abd95c0648364927b664e046 Mon Sep 17 00:00:00 2001 From: Lionel Duc Date: Thu, 10 Oct 2024 02:51:40 +0200 Subject: [PATCH 5/5] Add interaction with VK_PRESENT_MODE_FIFO_LATEST_READY_EXT --- chapters/VK_EXT_present_timing/queries.adoc | 4 ++-- chapters/VK_KHR_surface/wsi.adoc | 13 +++++++++++-- xml/vk.xml | 3 +++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/chapters/VK_EXT_present_timing/queries.adoc b/chapters/VK_EXT_present_timing/queries.adoc index 3538e5d620..84028095de 100644 --- a/chapters/VK_EXT_present_timing/queries.adoc +++ b/chapters/VK_EXT_present_timing/queries.adoc @@ -26,11 +26,11 @@ 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[] -`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[] -`VK_GOOGLE_display_timing` +`apiext:VK_GOOGLE_display_timing` endif::VK_GOOGLE_display_timing[] extension allows an application to satisfy these needs. diff --git a/chapters/VK_KHR_surface/wsi.adoc b/chapters/VK_KHR_surface/wsi.adoc index bbd990ebda..0278bdba9e 100644 --- a/chapters/VK_KHR_surface/wsi.adoc +++ b/chapters/VK_KHR_surface/wsi.adoc @@ -1624,13 +1624,22 @@ ifdef::VK_EXT_present_mode_fifo_latest_ready[] 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 + 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 dequeues the image and checks the next one. -endif::VK_GOOGLE_display_timing[] +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_EXT_present_mode_fifo_latest_ready[] diff --git a/xml/vk.xml b/xml/vk.xml index 0f7a0a4ff3..8a0395393c 100644 --- a/xml/vk.xml +++ b/xml/vk.xml @@ -20634,6 +20634,9 @@ typedef void* MTLSharedEvent_id; + + +