From a8c62e8db5dc914b245ac3d40331bfe7e97caf98 Mon Sep 17 00:00:00 2001 From: Lionel Duc Date: Mon, 14 Nov 2022 09:31:18 +0100 Subject: [PATCH] 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 | 58 +- chapters/VK_KHR_swapchain/wsi.adoc | 26 +- chapters/features.adoc | 32 ++ chapters/synchronization.adoc | 41 +- proposals/VK_EXT_present_timing.adoc | 510 ++++++++++++++++++ xml/vk.xml | 147 +++-- 10 files changed, 1143 insertions(+), 528 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 b8f526185c..daf34a9961 100644 --- a/appendices/glossary.adoc +++ b/appendices/glossary.adoc @@ -836,7 +836,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 222d9bf19b..35cb2d1c82 100644 --- a/chapters/VK_KHR_surface/wsi.adoc +++ b/chapters/VK_KHR_surface/wsi.adoc @@ -1020,6 +1020,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[] @@ -1575,29 +1610,6 @@ include::{generated}/api/enums/VkPresentModeKHR.adoc[] New requests are appended to the end of the queue, and one request is removed from the beginning of the queue and processed during or after each vertical blanking period in which the queue is non-empty. -ifdef::VK_EXT_present_timing[] - * ename:VK_PRESENT_MODE_FIFO_LATEST_READY_EXT specifies that the - presentation engine waits for the next vertical blanking period to - update the current image. - Tearing cannot: be observed. - An internal queue is used to hold pending presentation requests. - New requests are appended to the end of the queue. - At each vertical blanking period, the presentation engine dequeues - successive-queued images for which their associated wait semaphores have - signaled. - The last image dequeued is presented. - The other dequeued images will not be presented, and may: - immediately be returned by flink:vkAcquireNextImageKHR with a - pname:fence and/or pname:semaphore that is already in a signaled - state. - If present timing is enabled for the swapchain, the presentation - engine will also check that the target present time for an 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 image. - Once the presentation engine does not dequeue an image, it stops - checking successive images. -endif::VK_EXT_present_timing[] ifdef::VK_KHR_shared_presentable_image[] * ename:VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR specifies that the presentation engine and application have concurrent access to a single diff --git a/chapters/VK_KHR_swapchain/wsi.adoc b/chapters/VK_KHR_swapchain/wsi.adoc index 4b32a44a75..2b164a10a1 100644 --- a/chapters/VK_KHR_swapchain/wsi.adoc +++ b/chapters/VK_KHR_swapchain/wsi.adoc @@ -577,6 +577,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[] @@ -634,14 +641,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[] -- @@ -1346,6 +1349,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 @@ -1664,7 +1672,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 b4480b1db3..58120976c3 100644 --- a/chapters/features.adoc +++ b/chapters/features.adoc @@ -5887,6 +5887,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'] -- @@ -8172,6 +8200,10 @@ 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] diff --git a/chapters/synchronization.adoc b/chapters/synchronization.adoc index abead46086..713a79afa5 100644 --- a/chapters/synchronization.adoc +++ b/chapters/synchronization.adoc @@ -7691,6 +7691,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[] -- @@ -7716,14 +7721,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 @@ -7779,4 +7783,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 396a5623f1..0b891447e0 100755 --- a/xml/vk.xml +++ b/xml/vk.xml @@ -483,6 +483,7 @@ typedef void* MTLSharedEvent_id; typedef VkFlags VkPresentGravityFlagsEXT; typedef VkFlags VkShaderCreateFlagsEXT; typedef VkFlags64 VkPhysicalDeviceSchedulingControlsFlagsARM; + typedef VkFlags VkPresentStageFlagsEXT; Video Core extension typedef VkFlags VkVideoCodecOperationFlagsKHR; @@ -874,6 +875,7 @@ typedef void* MTLSharedEvent_id; + Enumerated types in the header, but not used by the API @@ -3190,53 +3192,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 @@ -10863,7 +10885,12 @@ typedef void* MTLSharedEvent_id; - + + + + + + @@ -12545,17 +12572,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 @@ -13184,6 +13205,8 @@ typedef void* MTLSharedEvent_id; VkSwapchainKHR swapchain uint32_t* pPresentationTimingCount VkPastPresentationTimingEXT* pPresentationTimings + uint64_t* pSwapchainTimingPropertiesCounter + VkBool32* pTimeDomainsChanged void vkSetHdrMetadataEXT @@ -15334,11 +15357,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 @@ -20009,31 +20040,39 @@ typedef void* MTLSharedEvent_id; - + - + - - - - - - - + + + + + + + + + + + + + + - - - - + + + + + + -