diff --git a/appendices/VK_EXT_present_timing.adoc b/appendices/VK_EXT_present_timing.adoc new file mode 100644 index 000000000..a20d51a5e --- /dev/null +++ b/appendices/VK_EXT_present_timing.adoc @@ -0,0 +1,236 @@ +// Copyright (c) 2017-2024 Khronos Group. +// +// SPDX-License-Identifier: CC-BY-4.0 + +include::{generated}/meta/{refprefix}VK_EXT_present_timing.adoc[] + +=== Other Extension Metadata + +*Last Modified Date*:: + 2024-10-09 +*IP Status*:: + No known IP claims. +*Contributors*:: + - Ian Elliott, Google + - James Jones, NVIDIA + - Jeff Juliano, NVIDIA + - Daniel Rakos, AMD + - Daniel Stone, Collabora + - Daniel Vetter, Intel + - Aric Cyr, AMD + - Faith Ekstrand, Intel + - Nicolai Hähnle, AMD + - Alon Or-Bach, Samsung + - Niklas Smedberg, Unity Technologies + - Tobias Hector, AMD + - Lionel Duc, NVIDIA + - Lina Versace, Google + - Sebastian Wick, Red Hat + - Jakob Bornecrantz, Collabora + +=== Description + +This device extension allows an application that uses the +`apiext:VK_KHR_swapchain` extension to obtain information about the +presentation engine's display, to obtain timing information about each +present, and to schedule a present to happen no earlier than a desired time. +An application can use this to minimize various visual anomalies (e.g. +stuttering). + +Traditional game and real-time animation applications need to correctly +position their geometry for when the presentable image will be presented to +the user. +To accomplish this, applications need various timing information about the +presentation engine's display. +They need to know when presentable images were actually presented, and when +they could have been presented. +Applications also need to tell the presentation engine to display an image +no sooner than a given time. +This allows the application to avoid stuttering, so the animation looks +smooth to the user. + +include::{generated}/interfaces/VK_EXT_present_timing.adoc[] + +=== Issues + +1) How does the application determine refresh duration, quanta for change, +whether FRR vs. VRR, etc. + +*PROPOSED*: the query returns two values: 1) a refresh-cycle duration +(pname:refreshDuration), and 2) an indication whether the timing is +currently fixed (FRR) or variable (VRR). +If pname:refreshDuration is zero, the platform cannot supply these +values until after at least one flink:vkQueuePresentKHR has been done, +from this time (e.g. if flink:vkQueuePresentKHR has been previously +called for this swapchain, at least one additional call must be made). +After calling flink:vkQueuePresentKHR, the query can be repeated until +pname:refreshDuration is non-zero, at which point the FRR vs. VRR +indication will also be valid. + +If the presentation engine's pname:refreshDuration is a fixed value, +the application's image present duration (IPD) should be a multiple of +pname:refreshDuration. +That is, the quanta for changing the IPD is pname:refreshDuration. +For example, if pname:refreshDuration is 16.67ms, the IPD can be +16.67ms, 33.33ms, 50.0ms, etc. + +If the presentation engine's pname:refreshDuration is variable, +pname:refreshDuration is the minimum value of the application's IPD, and +the IPD can be larger by any quanta that is meaningful to the application. +For example, if the pname:refreshDuration is 10ms (i.e. the maximum +refresh rate is 100Hz), the application can choose an IPD of 11ms, +13.33ms, 13.5ms, or 66.0ms; any value greater than or equal to 10ms is +valid. +There may be negative consequences for choosing an IPD that is too +high, as the presentation engine may actually have a practical maximum +pname:refreshDuration, where it needs to display the previous image +again, and during this time the presentation engine might delay +displaying a newly-presented image. + +FRR displays on at least one platform (Wayland) are not necessarily +fixed; but can change over time. +For example, if a full-screen video player application is visible, the display +may operate at a 24Hz refresh cycle; and then later switch to 60Hz when +multiple windows are visible. + +VRR displays on some platforms can also be seen as having different +characteristics over time. +For example, if an application's window is full-screen-exclusive (i.e. no other +window or window system component is visible), the display can look like a VRR +display (however that is defined). +If the application's window is not full-screen-exclusive (e.g. a normal +multi-window case), the display can look like an FRR display (i.e. because the +compositor is trying to treat all windows in a consistent manner). +A different issue will deal with how the timing characteristics can change +over time. + + +2) Do we return min/max values for refresh duration for VRR? + +*PROPOSED*: return only the minimum value of refreshDuration for a VRR. + +VRR displays have a minimum and maximum refresh rate, and therefore a minimum +and maximum refreshDuration. +It has been asserted that the display effectively does not have a minimum +refresh rate. +That is because if an application does not present soon enough, the display +hardware will automatically re-display the previous image. +However, when the display does that, an application cannot present a new image +for a certain period of time. +It is unclear about whether that period is large enough to cause visual +artifacts. + + +3) How to deal with changes in timing properties? + +*RESOLVED*: The slink:VkPastPresentationTimingEXT structure that is +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 +changes from being a window that’s a subset of the display size, to +becoming full-screen-exclusive. +While the surface was a subset of the display, a compositor might +enforce fixed timings on the surface (e.g. FRR of 60Hz), where the +presentation engine might be free to allow VRR behavior of a +full-screen-exclusive surface. + +It is possible that a full-screen-exclusive window can become +temporarily obscured (e.g. when a short-term dialog pops up). +In this case, the surface might use FRR timings while the dialog is +visible and VRR otherwise. + + +4) One Query for all Timing info vs. an initial query to determine FRR vs. VRR, +and then FRR-specific vs VRR-specific queries? + +*RESOLVED*: Have one query, as described in issue 1, that can be +called whenever the application needs to obtain the timing properties +of the surface. + + +5) Query to determine time domain? + +*RESOLVED*: Have a query to determine the time domain. +This extension defines a basic swapchain-local time domain. +Other extensions can add other platform-specific time domains. + + +6) What time to use for targetPresentTime for early images? + +*RESOLVED*: Have no query for determining the current time in the PE’s time +domain; and do allow the special value of zero for targetPresentTime, +meaning that there is no target. + +On some platforms, there is no way to determine the current time, nor +to determine surface timing properties until after at least one image +has been presented. + +In such cases, the special value of zero allows the application to +indicate that timing feedback is desired, but that no +targetPresentTime is requested. +Later, once the application has obtained feedback, it can specify +targetPresentTime by using the result's actualPresentTime. + + +7) How long before an application’s request for new image duration is honored? + +*UNRESOLVED*: Apparently, changes to some vendors' display hardware settings do +not take effect immediately. +It is not clear what settings, and therefore, it is not clear how to +address this issue. + + +8) Do we have a query for the anticipated latency from present to feedback? + +*RESOLVED*: Do not provide a query for the feedback latency. + +There is some amount of latency from when an application calls +vkQueuePresentKHR to when the image is displayed to the user, to when feedback +is available to the application on when the image was actually displayed to the +user. +The first time (from the call till the image is presented) generally doesn’t +matter, because the application will likely be providing a targetPresentTime +(i.e. the application may have some indication for how long this will be). +However, the latency between targetPresentTime until feedback is available may +be much longer. +For example, on Android on the 1st-generation Pixel phone (60Hz FRR display), +the latency was approximately 5 refresh cycles (83.33ms). +For higher-frequency displays, the latency may have a larger number of refresh +cycles. + + +9) Do we have a query(s) about the number of VkPastPresentationTimingEXT +structs to keep? + +*RESOLVED*: Do not provide a query for the number of results the swapchain +is allowed to store before querying them with +vkGetPastPresentationTimingEXT. Let the application specify that value with +a dedicated API. + + +10) How is the SWAPCHAIN_LOCAL and STAGE_LOCAL time domain used with the +calibrated timestamps extension? + +*RESOLVED*: Define a struct to chain into +VkCalibratedTimestampInfoEXT::pNext that specifies a swapchain and present +stage. + + +11) Should VK_PRESENT_MODE_FIFO_LATEST_READY_EXT be part of this extension, +or split out into its own extension? + +*RESOLVED*: It is only tangentially related. +Split it out into its own extension and define the interaction here. + +=== Version History + + * Revision 1, 2018-05-11 (Ian Elliott) + ** Internal revisions. + + * Revision 2, 2022-11-30 (Lionel Duc) + ** Rebase for public discussions. + + * Revision 3, 2024-10-09 (Lionel Duc) + ** Public revisions. diff --git a/appendices/glossary.adoc b/appendices/glossary.adoc index 47817f643..932552548 100644 --- a/appendices/glossary.adoc +++ b/appendices/glossary.adoc @@ -770,6 +770,11 @@ Framebuffer Region:: A framebuffer region is a set of sample (x, y, layer, sample) coordinates that is a subset of the entire framebuffer. +ifdef::VK_EXT_present_timing,VK_GOOGLE_display_timing[] +Frame Rate:: + A non-Vulkan term for Image Present Rate (IPR). +endif::VK_EXT_present_timing,VK_GOOGLE_display_timing[] + Front-Facing:: See Facingness. @@ -862,6 +867,19 @@ Image:: of device memory. Represented by a slink:VkImage object. +ifdef::VK_EXT_present_timing,VK_GOOGLE_display_timing[] +Image Present Duration:: + The amount of time the application intends for each + newly-presented image to be visible to the user. + This value should: be a multiple of the refresh cycle duration. + +Image Present Rate:: + The number of newly-presented images the application intends to present + each second (a.k.a. frame rate). + On fixed refresh rate displays, this value should: be a multiple of + the refresh rate. +endif::VK_EXT_present_timing,VK_GOOGLE_display_timing[] + Image Subresource:: A specific mipmap level, layer, and set of aspects of an image. @@ -1068,6 +1086,11 @@ Invocation Repack Instruction:: implementation may: change the set of invocations that are executing. endif::VK_KHR_ray_tracing_pipeline,VK_NV_ray_tracing[] +ifdef::VK_EXT_present_timing,VK_GOOGLE_display_timing[] +IPD:: + Image Present Duration. +endif::VK_EXT_present_timing,VK_GOOGLE_display_timing[] + ifdef::VK_KHR_deferred_host_operations[] Join (Deferred Host Operations):: The act of instructing a thread to participate in the execution of a @@ -1596,6 +1619,11 @@ ifdef::VK_KHR_ray_tracing_pipeline[flink:vkCmdTraceRaysKHR, and flink:vkCmdTrace . endif::VK_KHR_ray_tracing_pipeline,VK_NV_ray_tracing[] +ifdef::VK_EXT_present_timing,VK_GOOGLE_display_timing[] +RC:: + Refresh Cycle. +endif::VK_EXT_present_timing,VK_GOOGLE_display_timing[] + ifdef::VK_KHR_video_queue[] Reconstructed Picture:: A video picture resource reconstructed from a compressed bitstream using @@ -1618,6 +1646,17 @@ Reference Picture Metadata:: Opaque state associated with a DPB slot, maintained by a video session. endif::VK_KHR_video_queue[] +ifdef::VK_EXT_present_timing,VK_GOOGLE_display_timing[] +Refresh Cycle:: + The periodic process for updating the contents of the Presentation Engine's display. + +Refresh Cycle Duration:: + The amount of time from the start of one refresh cycle to the next. + +Refresh Rate:: + The number of refresh cycles per second. +endif::VK_EXT_present_timing,VK_GOOGLE_display_timing[] + Release Operation (Resource):: An operation that releases ownership of an image subresource or buffer range. diff --git a/chapters/VK_EXT_present_timing/PresentTimeInfo.adoc b/chapters/VK_EXT_present_timing/PresentTimeInfo.adoc new file mode 100644 index 000000000..597d07531 --- /dev/null +++ b/chapters/VK_EXT_present_timing/PresentTimeInfo.adoc @@ -0,0 +1,184 @@ +// Copyright (c) 2014-2024 Khronos Group. +// +// SPDX-License-Identifier: CC-BY-4.0 + +[open,refpage='VkPresentTimingsInfoEXT',desc='Array of VkPresentTimingInfoEXT to chain with VkPresentInfoKHR',type='structs'] +-- + +When the <> or +<> feature is +enabled, an application can: instruct the presentation engine 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: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: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/VkPresentTimingsInfoEXT.adoc[] +-- + + +[open,refpage='VkPresentTimingInfoEXT',desc='Specifies per-present timing information',type='structs'] +-- +The sname:VkPresentTimingInfoEXT structure is defined as: + +include::{generated}/api/structs/VkPresentTimingInfoEXT.adoc[] + + * pname:sType is a elink:VkStructureType value identifying this structure. + * pname:pNext is `NULL` or a pointer to a structure extending this + structure. + * pname: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. + +[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. +==== + +.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/VkPresentTimingInfoEXT.adoc[] +-- + + +[open,refpage='VkPresentTimeEXT',desc='Specifying when an image should be presented',type='structs'] +-- + +The sname:VkPresentTimeEXT union is defined as: + +include::{generated}/api/structs/VkPresentTimeEXT.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='VkPresentStageFlagBitsEXT',desc='Bitmask specifying stages of the image presentation process',type='enums'] +-- + +Presenting an image to the user typically involves multiple stages. Bits +which can: be set to specify present stages are: + +include::{generated}/api/enums/VkPresentStageFlagBitsEXT.adoc[] + + * ename:VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT marks the end of the + set of queue operations enqueued by flink:vkQueuePresentKHR on the provided + sname:VkQueue for a presentation request. + * ename:VK_PRESENT_STAGE_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 set of queue operations delimited by +ename:VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT includes the wait for +the semaphores specified in slink:VkPresentInfoKHR::pname:pWaitSemaphores, +if any, and any work implicitly enqueued by the implementation. +==== +-- + +[open,refpage='VkPresentStageFlagsEXT',desc='Bitmask of VkPresentStageFlagBitsEXT',type='flags'] +-- +include::{generated}/api/flags/VkPresentStageFlagsEXT.adoc[] + +tname:VkPresentStageFlagsEXT is a bitmask type for setting a mask of zero or +more elink:VkPresentStageFlagBitsEXT. +-- diff --git a/chapters/VK_EXT_present_timing/queries.adoc b/chapters/VK_EXT_present_timing/queries.adoc new file mode 100644 index 000000000..84028095d --- /dev/null +++ b/chapters/VK_EXT_present_timing/queries.adoc @@ -0,0 +1,465 @@ +// Copyright (c) 2014-2024 Khronos Group. +// +// SPDX-License-Identifier: CC-BY-4.0 + +== Present Timing Queries + +Traditional game and real-time-animation applications frequently use +ename:VK_PRESENT_MODE_FIFO_KHR so that presentable images are updated during +the vertical blanking period of a given refresh cycle (RC) of the +presentation engine's display. +On fixed refresh rate displays, this avoids the visual anomaly known as +tearing. + +However, synchronizing the presentation of images with the RC does not +prevent all forms of visual anomalies. +Stuttering occurs when the geometry for each presentable image is not +accurately positioned for when that image will be displayed. +The geometry may appear to move too little some RCs, and too much for +others. +Sometimes the animation appears to freeze, when the same image is used for +more RCs than other images. + +In order to minimize stuttering, an application needs to: 1) render and +present images at a consistent rate that is, on fixed refresh rate displays, +a multiple of the presentation engine's refresh rate; 2) correctly position +its geometry for when the presentable image will be displayed to the user. +The +ifdef::VK_EXT_present_timing[] +`apiext:VK_EXT_present_timing` +endif::VK_EXT_present_timing[] +ifdef::VK_EXT_present_timing+VK_GOOGLE_display_timing[or] +ifdef::VK_GOOGLE_display_timing[] +`apiext:VK_GOOGLE_display_timing` +endif::VK_GOOGLE_display_timing[] +extension allows an application to satisfy these needs. + +The presentation engine's display typically refreshes the pixels that are +displayed to the user on a periodic basis. This period may: be fixed (Fixed +Refresh Rate, FRR) or variable (Variable Refresh Rate, VRR). + +ifdef::VK_EXT_present_timing[] +[open,refpage='vkSetSwapchainPresentTimingQueueSizeEXT',desc='Allocate memory for the swapchain-internal timing results queue',type='protos'] +-- +In order to collect timing information about presentation, a swapchain needs +an internal queue to store asynchronously updated results until applications +collect them. + +To allocate the swapchain's internal timing results queue, call: + +include::{generated}/api/protos/vkSetSwapchainPresentTimingQueueSizeEXT.adoc[] + + * pname:device is the device associated with pname:swapchain. + * pname:swapchain is the swapchain to allocate a results queue for. + * pname:size is the requested number of slots in the internal results queue. + +If this function is called multiple times, the internal queue is reallocated +to fit the new pname:size. If the new pname:size is less than the current +number of outstanding results, ename:VK_NOT_READY is returned and no allocation +is performed. + +.Valid Usage +**** + * pname:swapchain must: have been created with + sname:VkSwapchainCreateInfoKHR::pname:flags containing + ename:VK_SWAPCHAIN_CREATE_PRESENT_TIMING_BIT_EXT +**** + +include::{generated}/validity/protos/vkSetSwapchainPresentTimingQueueSizeEXT.adoc[] +-- + +[open,refpage='vkGetSwapchainTimingPropertiesEXT',desc='Obtain the display timing properties of the PE\'s display',type='protos'] +-- + +The implementation maintains an internal monotonically increasing counter +which updates when the presentation engine's timing properties are modified. + +To query the presentation engine's current timing properties for a given +swapchain, call: + +include::{generated}/api/protos/vkGetSwapchainTimingPropertiesEXT.adoc[] + + * pname:device is the device associated with pname:swapchain. + * pname:swapchain is the swapchain to obtain timing properties for. + * pname:pSwapchainTimingPropertiesCounter is `NULL` or a pointer to a + 64-bit unsigned integer set by the implementation to the current value of + the swapchain's internal timing properties counter. + * pname:pSwapchainTimingProperties is a pointer to an instance of the + slink:VkSwapchainTimingPropertiesEXT structure. + +include::{generated}/validity/protos/vkGetSwapchainTimingPropertiesEXT.adoc[] +-- + +[open,refpage='VkSwapchainTimingPropertiesEXT',desc='Structure containing the RC duration of a display',type='structs'] +-- + +The sname:VkSwapchainTimingPropertiesEXT structure is defined as: + +include::{generated}/api/structs/VkSwapchainTimingPropertiesEXT.adoc[] + + * pname:sType is a elink:VkStructureType value identifying this structure. + * pname:pNext is `NULL` or a pointer to a structure extending this + structure. + * pname:refreshDuration is zero or an indication of the duration + of a refresh cycle. + If the presentation engine is operating as an FRR display, this is the + number of nanoseconds from the start of one refresh cycle to the start of + the next refresh cycle. + If the presentation engine is operating as a VRR display (i.e. refresh + cycles may: have variable length), this is the minimum number of nanoseconds + from the start of one refresh cycle to the start of the next refresh cycle. + * 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. + +If pname:variableRefreshDelay is code:UINT64_MAX, the presentation engine is +operating as an FRR display. + +Some platforms may: not provide timing properties until after at least one +image has been presented to the pname:swapchain. If timing properties +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] +.Note +==== +The rate at which an application renders and presents new images is known as +the image present rate (IPR, a.k.a. frame rate). +The inverse of IPR, or the duration between each image present, is the image +present duration (IPD). +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 +pname:refreshDuration), or 33.33ms (2X multiplier of pname:refreshDuration), +or 50.0ms (3X multiplier of pname:refreshDuration), etc. + +In order to determine a target IPD for a display (i.e. a multiple of +pname:refreshDuration), an application needs to determine when its images +are actually displayed. +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. +Let us say that this application is running on slower hardware, so that it +actually takes 20ms to render each new image. +This will create visual anomalies, because the images will not be displayed +to the user every 16.67ms, nor every 20ms. +In this case, it is better for the application to adjust its target IPD to +33.33ms (i.e. a 2X multiplier of pname:refreshDuration), and tell the +presentation engine to not present images any sooner than every 33.33ms. +This will allow the geometry to be correctly positioned for each presentable +image. + +Adjustments to an application's IPD may be needed because different views of +an application's geometry can take different amounts of time to render. +For example, looking at the sky may take less time to render than looking at +multiple, complex items in a room. +In general, it is good to not frequently change IPD, as that can cause +visual anomalies. +Adjustments to a larger IPD because of late images should happen quickly, +but adjustments to a smaller IPD should only happen if the periodic +feedback of slink:VkPastPresentationTimingEXT values indicates that the +target IPD can be durably achieved. +==== + +[open,refpage='vkGetSwapchainTimeDomainPropertiesEXT',desc='Obtain the time domains supported by the PE for the swapchain',type='protos'] +-- +The implementation maintains an internal monotonically increasing counter which +updates when the presentation engine's list of supported time domains for a +swapchain is modified. + +To query the time domains supported by the presentation engine for a given swapchain, +call: + +include::{generated}/api/protos/vkGetSwapchainTimeDomainPropertiesEXT.adoc[] + + * pname:device is the device associated with pname:swapchain. + * pname:swapchain is the swapchain to obtain time domain properties for. + * pname:pTimeDomainsCounter is `NULL` or a pointer to a 64-bit unsigned + integer set by the implementation to the current value of the + swapchain's internal time domain properties counter. + * pname:pSwapchainTimeDomainProperties is a pointer to an instance of the + slink:VkSwapchainTimeDomainPropertiesEXT structure. + +If upon return slink:VkSwapchainTimeDomainPropertiesEXT::pname:timeDomainCount +is smaller than the number of time domains supported for the given +pname:swapchain, ename:VK_INCOMPLETE will be returned instead of +ename:VK_SUCCESS to indicate that not all the available values were returned. + +include::{generated}/validity/protos/vkGetSwapchainTimeDomainPropertiesEXT.adoc[] +-- + +[open,refpage='VkSwapchainTimeDomainPropertiesEXT',desc='List of available time domains for a swapchain',type='structs'] +-- + +The sname:VkSwapchainTimeDomainPropertiesEXT structure is defined as: + +include::{generated}/api/structs/VkSwapchainTimeDomainPropertiesEXT.adoc[] + + * pname:sType is a elink:VkStructureType value identifying this structure. + * pname:pNext is `NULL` or a pointer to a structure extending this + structure. + * pname:timeDomainCount is an integer related to the number of time domains + available or queried, as described below. + * pname:pTimeDomains is a pointer to an array of elink:VkTimeDomainEXT values + representing time domains that are available for the swapchain. + * pname:pTimeDomainIds is a pointer to an array of unique identifiers for each + time domain. + +When calling flink:vkGetSwapchainTimeDomainPropertiesEXT, if pname:pTimeDomains +is `NULL` and pname:pTimeDomainIds is `NULL`, then the number of time domains +supported for the given pname:swapchain is returned in +pname:timeDomainCount. Otherwise, pname:timeDomainCount must: specify the number +of elements in the pname:pTimeDomains, pname:pTimeDomainIds, or both arrays, and +on return the variable is overwritten with the number of values actually written +to either array. + +[NOTE] +.Note +==== +Due to the dynamic nature of their underlying sname:VkSurfaceKHR properties, +swapchains may need to expose multiple swapchain-local opaque time domains using +the same elink:VkTimeDomainEXT value over time, for example when a surface is +moved from one display hardware to another. Arbitrary identifiers, provided in +pname:timeDomainIds, are used by the implementation to differentiate opaque time +domains of identical scopes. +==== + +include::{generated}/validity/structs/VkSwapchainTimeDomainPropertiesEXT.adoc[] +-- + +[open,refpage='vkGetPastPresentationTimingEXT',desc='Obtain timing of previously-presented images',type='protos'] +-- + +Because of the asynchronous nature of the presentation engine, the timing +information for a given flink:vkQueuePresentKHR command may: only becomes +available some time after the presentation has occured. +These time values should: be asynchronously queried, and are returned if +available. +All time values are in nanoseconds, according to the time-domain being used. + +To asynchronously query the presentation engine for newly-available timing +information about one or more previous presents to a given swapchain, call: + +include::{generated}/api/protos/vkGetPastPresentationTimingEXT.adoc[] + + * pname:device is the device associated with pname:swapchain. + * pname:pPastPresentationTimingInfo is a pointer to an instance of + the slink:VkPastPresentationTimingInfoEXT structure. + * pname:pPastPresentationTimingProperties is a pointer to an instance + of the slink:VkPastPresentationTimingPropertiesEXT structure. + +If upon return the value of +sname:VkPastPresentationTimingPropertiesEXT::pname:presentationTimingCount is +less than the number of available timing records for the given +sname:VkPastPresentationTimingInfoEXT::pname:swapchain, ename:VK_INCOMPLETE is +returned instead of ename:VK_SUCCESS to indicate that not all the available +values were returned. + +Timing information may: become available out of order with regards to their +associated presentation request submission order. + +Upon return, zero or more slots of the pname:swapchain internal timing results +queue, equal to the number of entries written to +sname:VkPastPresentationTimingPropertiesEXT::pname:pPresentationTimings for +which pname:reportComplete is ename:VK_TRUE, are made available for future +fname:vkQueuePresentKHR calls. Elements of pname:pPresentationTimings are +arranged in ascending order of present ids. + +There is no requirement for any precise timing relationship between the +completion of a present stage and the availability of any associated timing +information. However, results must: be made available in finite time. + +As an exception to the normal rules for objects which are externally +synchronized, pname:swapchain may: be +simultaneously used by other threads in calls to functions other than +flink:vkDestroySwapchainKHR and flink:vkCreateSwapchainKHR with pname:swapchain +used as an pname:oldSwapchain. Access to the swapchain timing information must: +be atomic within the implementation. + +include::{generated}/validity/protos/vkGetPastPresentationTimingEXT.adoc[] +-- + +[open,refpage='VkPastPresentationTimingInfoEXT',desc='Structure specifying swapchain present timing query parameters',type='structs'] +-- + +The sname:VkPastPresentationTimingInfoEXT structure is defined as: + +include::{generated}/api/structs/VkPastPresentationTimingInfoEXT.adoc[] + + * pname:sType is a elink:VkStructureType value identifying this structure. + * pname:pNext is `NULL` or a pointer to a structure extending this + structure. + * pname:swapchain is the swapchain to obtain presentation timing + information for. + +include::{generated}/validity/structs/VkPastPresentationTimingInfoEXT.adoc[] +-- + +[open,refpage='VkPastPresentationTimingPropertiesEXT',desc='Structure containing details about a swapchain past presentation activity',type='structs'] +-- + +The sname:VkPastPresentationTimingPropertiesEXT structure is defined as: + +include::{generated}/api/structs/VkPastPresentationTimingPropertiesEXT.adoc[] + + * pname:sType is a elink:VkStructureType value identifying this structure. + * pname:pNext is `NULL` or a pointer to a structure extending this + structure. + * pname:timingPropertiesCounter is a 64-bit unsigned integer set by the + implementation to the current value of the swapchain's internal timing + properties counter. + * pname:timeDomainsCounter is a 64-bit unsigned integer set by the + implementation to the current value of the swapchain's internal time + domains list counter. + * pname:presentationTimingCount is an integer related to the number of number + of slink:VkPastPresentationTimingEXT structures available or queried, as + described below. + * pname:pPresentationTimings is `NULL` or a pointer to an array + of slink:VkPastPresentationTimingEXT structures. + +When calling flink:vkGetPastPresentationTimingEXT, if pname:pPresentationTimings +is `NULL`, then the number of available timing records for the given +pname:swapchain is returned in pname:presentationTimingCount. Otherwise, +pname:presentationTimingCount must: specify the number of elements in the +pname:pPresentationTimings array, and on return the variable is overwritten with +the number of structures actually written to pname:pPresentationTimings. + +fname:vkGetPastPresentationTimingEXT may: return incomplete results, +containing only information for a subset of the requested present +stages. Further calls to fname:vkGetPastPresentationTimingEXT will keep +providing all available results for a previously incomplete entry until it +is complete. + +The implementation must: return a slink:VkPastPresentationTimingEXT for +every flink:vkQueuePresentKHR referencing pname:swapchain where a non-zero +slink:VkPresentTimingInfoEXT::pname:presentStageQueries was specified and at +least one present stage has available results. + +include::{generated}/validity/structs/VkPastPresentationTimingPropertiesEXT.adoc[] +-- + +[open,refpage='VkPastPresentationTimingEXT',desc='Structure containing timing information about a previously-presented image',type='structs'] +-- + +The sname:VkPastPresentationTimingEXT structure is defined as: + +include::{generated}/api/structs/VkPastPresentationTimingEXT.adoc[] + + * pname:sType is a elink:VkStructureType value identifying this structure. + * pname:pNext is `NULL` or a pointer to a structure extending this + structure. + * pname:presentId is zero or 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:timeDomain is the time domain used by the presentation + engine to report times in pname:pPresentStages. + * pname:timeDomainId is the id associated with pname:timeDomain. + * pname:reportComplete is ename:VK_TRUE if the presentation engine + has reported all the requested results in pname:pPresentStages. + +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, if one is available, and report results in that +domain. Applications can: continue to use this fallback time domain in future +flink:vkQueuePresentKHR calls, or they can: call +flink:vkGetSwapchainTimeDomainPropertiesEXT to choose from the currently +supported time domains. + +include::{generated}/validity/structs/VkPastPresentationTimingEXT.adoc[] + +[NOTE] +.Note +==== +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. +==== + +[NOTE] +.Note +==== +The presentation engine may: change the timing properties of the +pname:swapchain for a variety of reasons. +For example, if the window system changes its mode, including the +refresh rate of the display. +Another example is if an application's surface is being composited +with other windows of a window system, and then the surface's window +becomes a borderless, full-screen window. +While composited, the timing properties may: be FRR, and while +full-screen, the timing properties may: be VRR. + +The available time domains for a swapchain may: change for similar or +identical reasons. +Therefore, it is possible that the same event will cause both +pname:timingPropertiesChanged to become ename:VK_TRUE 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[] +-- +endif::VK_EXT_present_timing[] + +ifdef::VK_GOOGLE_display_timing[] +include::{chapters}/VK_GOOGLE_display_timing/queries.adoc[] +endif::VK_GOOGLE_display_timing[] diff --git a/chapters/VK_GOOGLE_display_timing/queries.adoc b/chapters/VK_GOOGLE_display_timing/queries.adoc index 91fee5d78..5ddd3b298 100644 --- a/chapters/VK_GOOGLE_display_timing/queries.adoc +++ b/chapters/VK_GOOGLE_display_timing/queries.adoc @@ -2,46 +2,6 @@ // // SPDX-License-Identifier: CC-BY-4.0 -== Display Timing Queries - -Traditional game and real-time-animation applications frequently use -ename:VK_PRESENT_MODE_FIFO_KHR so that presentable images are updated during -the vertical blanking period of a given refresh cycle (RC) of the -presentation engine's display. -This avoids the visual anomaly known as tearing. - -However, synchronizing the presentation of images with the RC does not -prevent all forms of visual anomalies. -Stuttering occurs when the geometry for each presentable image is not -accurately positioned for when that image will be displayed. -The geometry may appear to move too little some RCs, and too much for -others. -Sometimes the animation appears to freeze, when the same image is used for -more than one RC. - -In order to minimize stuttering, an application needs to correctly position -their geometry for when the presentable image will be displayed to the user. -To accomplish this, applications need various timing information about the -presentation engine's display. -They need to know when presentable images were actually presented, and when -they could have been presented. -Applications also need to tell the presentation engine to display an image -no sooner than a given time. -This can allow the application's animation to look smooth to the user, with -no stuttering. -The `apiext:VK_GOOGLE_display_timing` extension allows an application to -satisfy these needs. - -The presentation engine's display typically refreshes the pixels that are -displayed to the user on a periodic basis. -The period may be fixed or variable. -In many cases, the presentation engine is associated with fixed refresh rate -(FRR) display technology, with a fixed refresh rate (RR, e.g. 60Hz). -In some cases, the presentation engine is associated with variable refresh -rate (VRR) display technology, where each refresh cycle (RC) can vary in -length. -This extension treats VRR displays as if they are FRR. - [open,refpage='vkGetRefreshCycleDurationGOOGLE',desc='Obtain the RC duration of the PE\'s display',type='protos'] -- To query the duration of a refresh cycle (RC) for the presentation engine's @@ -69,50 +29,6 @@ include::{generated}/api/structs/VkRefreshCycleDurationGOOGLE.adoc[] include::{generated}/validity/structs/VkRefreshCycleDurationGOOGLE.adoc[] -- -[NOTE] -==== -The rate at which an application renders and presents new images is known as -the image present rate (IPR, aka frame rate). -The inverse of IPR, or the duration between each image present, is the image -present duration (IPD). -In order to provide a smooth, stutter-free animation, an application will -want its IPD to be a multiple of pname:refreshDuration. -For example, if a display has a 60Hz refresh rate, pname:refreshDuration -will be a value in nanoseconds that is approximately equal to 16.67ms. -In such a case, an application will want an IPD of 16.67ms (1X multiplier of -pname:refreshDuration), or 33.33ms (2X multiplier of pname:refreshDuration), -or 50.0ms (3X multiplier of pname:refreshDuration), etc. - -In order to determine a target IPD for a display (i.e. a multiple of -pname:refreshDuration), an application needs to determine when its images -are actually displayed. -Suppose an application has an initial target IPD of 16.67ms (1X multiplier -of pname:refreshDuration). -It will therefore position the geometry of a new image 16.67ms later than -the previous image. -But suppose this application is running on slower hardware, so that it -actually takes 20ms to render each new image. -This will create visual anomalies, because the images will not be displayed -to the user every 16.67ms, nor every 20ms. -In this case, it is better for the application to adjust its target IPD to -33.33ms (i.e. a 2X multiplier of pname:refreshDuration), and tell the -presentation engine to not present images any sooner than every 33.33ms. -This will allow the geometry to be correctly positioned for each presentable -image. - -Adjustments to an application's IPD may be needed because different views of -an application's geometry can take different amounts of time to render. -For example, looking at the sky may take less time to render than looking at -multiple, complex items in a room. -In general, it is good to not frequently change IPD, as that can cause -visual anomalies. -Adjustments to a larger IPD because of late images should happen quickly, -but adjustments to a smaller IPD should only happen if the -pname:actualPresentTime and pname:earliestPresentTime members of the -slink:VkPastPresentationTimingGOOGLE structure are consistently different, -and if pname:presentMargin is consistently large, over multiple images. -==== - [open,refpage='vkGetPastPresentationTimingGOOGLE',desc='Obtain timing of a previously-presented image',type='protos'] -- The implementation will maintain a limited amount of history of timing @@ -246,7 +162,7 @@ The semantics for other present modes are as follows: far enough in the future that an image is not presented before fname:vkQueuePresentKHR is called to present another image, the first image will not be displayed to the user. - If the application continues to do that, the presentation may: not + If the application continues to do that, the presentation engine may: not display new images. * ename:VK_PRESENT_MODE_FIFO_RELAXED_KHR. For images that are presented in time to be displayed at the next diff --git a/chapters/VK_KHR_surface/wsi.adoc b/chapters/VK_KHR_surface/wsi.adoc index e124e027c..0278bdba9 100644 --- a/chapters/VK_KHR_surface/wsi.adoc +++ b/chapters/VK_KHR_surface/wsi.adoc @@ -1005,6 +1005,41 @@ present barrier feature is not obtainable for this surface. include::{generated}/validity/structs/VkSurfaceCapabilitiesPresentBarrierNV.adoc[] -- endif::VK_NV_present_barrier[] + +ifdef::VK_EXT_present_timing[] +[open,refpage='VkPresentTimingSurfaceCapabilitiesEXT',desc='Structure describing present timing capabilities of a surface',type='structs'] +-- +The sname:VkPresentTimingSurfaceCapabilitiesEXT structure is defined as: + +include::{generated}/api/structs/VkPresentTimingSurfaceCapabilitiesEXT.adoc[] + + * pname:sType is the type of this structure. + * pname:pNext is `NULL` or a pointer to a structure extending this + structure. + * pname:presentTimingSupported indicates whether querying presentation + timestamps is supported for a swapchain created from + slink:VkPhysicalDeviceSurfaceInfo2KHR::pname:surface. + * pname:presentAtAbsoluteTimeSupported indicates whether a swapchain + created from slink:VkPhysicalDeviceSurfaceInfo2KHR::pname:surface + supports presenting images with absolute times using + slink:VkPresentTimeEXT::pname:targetPresentTime. + * pname:presentAtRelativeTimeSupported indicates whether a swapchain + created from slink:VkPhysicalDeviceSurfaceInfo2KHR::pname:surface + supports presenting images with relative times using + slink:VkPresentTimeEXT::pname:minPresentDuration. + * pname:presentStageQueries is a bitmask of + elink:VkPresentStageFlagBitsEXT indicating which present stages a + swapchain created from + slink:VkPhysicalDeviceSurfaceInfo2KHR::pname:surface is able to provide + timing information for. + * pname:presentStageTargets is a bitmask of + elink:VkPresentStageFlagBitsEXT indicating which present stages a + swapchain created from slink:VkPhysicalDeviceSurfaceInfo2KHR::pname:surface + is able to provide target present times for. + +include::{generated}/validity/structs/VkPresentTimingSurfaceCapabilitiesEXT.adoc[] +-- +endif::VK_EXT_present_timing[] endif::VK_KHR_get_surface_capabilities2[] ifdef::VK_EXT_display_surface_counter[] @@ -1589,15 +1624,24 @@ ifdef::VK_EXT_present_mode_fifo_latest_ready[] At each vertical blanking period, the presentation engine dequeues all successive requests that are ready to be presented from the beginning of the queue. +ifdef::VK_EXT_present_timing,VK_GOOGLE_display_timing[] + If using ifdef::VK_GOOGLE_display_timing[] - If using `apiext:VK_GOOGLE_display_timing` to provide a target present - time, the presentation engine will check the specified time for each + the `apiext:VK_GOOGLE_display_timing` extension +endif::VK_GOOGLE_display_timing[] +ifdef::VK_EXT_present_timing+VK_GOOGLE_display_timing[or] +ifdef::VK_EXT_present_timing[] + the <> + feature +endif::VK_EXT_present_timing[] + to provide a target present + time, the presentation engine checks the specified time for each image. If the target present time is less-than or equal-to the current time, - the presentation engine will dequeue the image and check the next one. -endif::VK_GOOGLE_display_timing[] - The image of the last dequeued request will be presented. - The other dequeued requests will be dropped. + the presentation engine dequeues the image and checks the next one. +endif::VK_EXT_present_timing,VK_GOOGLE_display_timing[] + The image of the last dequeued request is presented. + The other dequeued requests are dropped. endif::VK_EXT_present_mode_fifo_latest_ready[] ifdef::VK_KHR_shared_presentable_image[] * ename:VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR specifies that the @@ -1944,9 +1988,9 @@ include::{generated}/validity/protos/vkGetPhysicalDevicePresentRectanglesKHR.ado -- endif::VK_VERSION_1_1,VK_KHR_device_group[] -ifdef::VK_GOOGLE_display_timing[] -include::{chapters}/VK_GOOGLE_display_timing/queries.adoc[] -endif::VK_GOOGLE_display_timing[] +ifdef::VK_EXT_present_timing,VK_GOOGLE_display_timing[] +include::{chapters}/VK_EXT_present_timing/queries.adoc[] +endif::VK_EXT_present_timing,VK_GOOGLE_display_timing[] ifdef::VK_KHR_present_wait[] include::{chapters}/VK_KHR_present_wait/present_wait.adoc[] diff --git a/chapters/VK_KHR_swapchain/wsi.adoc b/chapters/VK_KHR_swapchain/wsi.adoc index 6cda35152..3ee4a5b2f 100644 --- a/chapters/VK_KHR_swapchain/wsi.adoc +++ b/chapters/VK_KHR_swapchain/wsi.adoc @@ -595,6 +595,13 @@ ifndef::VK_EXT_image_compression_control_swapchain[The] pname:pNext chain must: not include an slink:VkImageCompressionControlEXT structure endif::VK_EXT_image_compression_control[] +ifdef::VK_EXT_present_timing[] + * If none of the <>, + <>, or + <> + features are enabled, pname:flags must: not contain + ename:VK_SWAPCHAIN_CREATE_PRESENT_TIMING_BIT_EXT +endif::VK_EXT_present_timing[] **** ifdef::VKSC_VERSION_1_0[] ifdef::hidden[] @@ -651,6 +658,12 @@ ifdef::VK_EXT_swapchain_maintenance1[] ifdef::VK_VERSION_1_1,VK_KHR_device_group[or flink:vkAcquireNextImage2KHR] for the first time. endif::VK_EXT_swapchain_maintenance1[] +ifdef::VK_EXT_present_timing[] + * ename:VK_SWAPCHAIN_CREATE_PRESENT_TIMING_BIT_EXT specifies that features + supported by the swapchain device in + slink:VkPhysicalDevicePresentTimingFeaturesEXT can: be used to collect + timing information or schedule presentation requests at specific times. +endif::VK_EXT_present_timing[] -- [open,refpage='VkSwapchainCreateFlagsKHR',desc='Bitmask of VkSwapchainCreateFlagBitsKHR',type='flags'] @@ -1347,6 +1360,11 @@ applying the following rules in order: * If any of the presents would have a result of ename:VK_ERROR_OUT_OF_DATE_KHR if issued separately then ename:VK_ERROR_OUT_OF_DATE_KHR is returned. +ifdef::VK_EXT_present_timing[] + * If any of the presents would have a result of + ename:VK_ERROR_PRESENT_TIMING_QUEUE_FULL_EXT if issued separately + then ename:VK_ERROR_PRESENT_TIMING_QUEUE_FULL_EXT is returned. +endif::VK_EXT_present_timing[] ifdef::VK_EXT_full_screen_exclusive[] * If any of the presents would have a result of ename:VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT if issued separately @@ -1666,6 +1684,9 @@ include::{generated}/validity/structs/VkDeviceGroupPresentInfoKHR.adoc[] -- endif::VK_VERSION_1_1,VK_KHR_device_group[] +ifdef::VK_EXT_present_timing[] +include::{chapters}/VK_EXT_present_timing/PresentTimeInfo.adoc[] +endif::VK_EXT_present_timing[] ifdef::VK_GOOGLE_display_timing[] include::{chapters}/VK_GOOGLE_display_timing/PresentTimeInfo.adoc[] endif::VK_GOOGLE_display_timing[] diff --git a/chapters/features.adoc b/chapters/features.adoc index b1f2a7b4f..74e90f8b9 100644 --- a/chapters/features.adoc +++ b/chapters/features.adoc @@ -5970,6 +5970,34 @@ include::{generated}/validity/structs/VkPhysicalDeviceHostImageCopyFeaturesEXT.a -- endif::VK_EXT_host_image_copy[] +ifdef::VK_EXT_present_timing[] +[open,refpage='VkPhysicalDevicePresentTimingFeaturesEXT',desc='Structure indicating support for present timing',type='structs'] +-- +The sname:VkPhysicalDevicePresentTimingFeaturesEXT structure is defined as: + +include::{generated}/api/structs/VkPhysicalDevicePresentTimingFeaturesEXT.adoc[] + +This structure describes the following feature: + + * pname:sType is a elink:VkStructureType value identifying this structure. + * pname:pNext is `NULL` or a pointer to a structure extending this + structure. + * [[features-presentTiming]] pname:presentTiming indicates that the + implementation supports fname:vkGetPastPresentationTimingEXT. + * [[features-presentAtAbsoluteTime]] pname:presentAtAbsoluteTime indicates + that the implementation supports specifying present times with + sname:VkPresentTimeEXT::pname:targetPresentTime. + * [[features-presentAtRelativeTime]] pname:presentAtRelativeTime indicates + that the implementation supports specifying relative present times with + sname:VkPresentTimeEXT::pname:minPresentDuration. + +:refpage: VkPhysicalDevicePresentTimingFeaturesEXT +include::{chapters}/features.adoc[tag=features] + +include::{generated}/validity/structs/VkPhysicalDevicePresentTimingFeaturesEXT.adoc[] +-- +endif::VK_EXT_present_timing[] + ifdef::VK_NV_present_barrier[] [open,refpage='VkPhysicalDevicePresentBarrierFeaturesNV',desc='Structure indicating support for VK_NV_present_barrier extension',type='structs'] -- @@ -8058,6 +8086,182 @@ ifdef::VK_EXT_line_rasterization[] <>, if the `apiext:VK_EXT_line_rasterization` extension is supported. endif::VK_EXT_line_rasterization[] +ifdef::VK_KHR_16bit_storage[] + * <>, + if the `apiext:VK_KHR_16bit_storage` extension is supported. +endif::VK_KHR_16bit_storage[] +ifdef::VK_VERSION_1_1,VK_KHR_16bit_storage[] + * <>, + if <> is enabled. +endif::VK_VERSION_1_1,VK_KHR_16bit_storage[] +ifdef::VK_VERSION_1_3,VK_EXT_image_robustness[] + * <>, if +ifdef::VK_VERSION_1_3[Vulkan 1.3 or] + the `apiext:VK_EXT_image_robustness` extension is supported. +endif::VK_VERSION_1_3,VK_EXT_image_robustness[] +ifdef::VK_EXT_4444_formats[] + * <>, if the + `apiext:VK_EXT_4444_formats` extension is supported. +endif::VK_EXT_4444_formats[] +ifdef::VK_EXT_mutable_descriptor_type,VK_VALVE_mutable_descriptor_type[] + * <>, if the + `apiext:VK_EXT_mutable_descriptor_type` or + `apiext:VK_VALVE_mutable_descriptor_type` extension is supported. +endif::VK_EXT_mutable_descriptor_type,VK_VALVE_mutable_descriptor_type[] +ifdef::VK_EXT_shader_image_atomic_int64[] + * <> and + <>, if + the `apiext:VK_EXT_shader_image_atomic_int64` extension is supported. + * <>, if + the <> + feature is supported. +endif::VK_EXT_shader_image_atomic_int64[] +ifdef::VK_EXT_shader_atomic_float[] + * <>, + if the <> feature is supported. + * <>, if the + <> feature is supported. +endif::VK_EXT_shader_atomic_float[] +ifdef::VK_EXT_primitives_generated_query[] + * <>, + if the `apiext:VK_EXT_primitives_generated_query` extension is + supported. +endif::VK_EXT_primitives_generated_query[] +ifdef::VK_KHR_fragment_shading_rate[] + * <>, if the + `apiext:VK_KHR_fragment_shading_rate` extension is supported. +endif::VK_KHR_fragment_shading_rate[] +ifdef::VK_EXT_pipeline_protected_access[] + * <>, if + the `apiext:VK_EXT_pipeline_protected_access` extension is supported. +endif::VK_EXT_pipeline_protected_access[] +ifdef::VK_EXT_legacy_dithering[] + * <>, if the + `apiext:VK_EXT_legacy_dithering` extension is supported. +endif::VK_EXT_legacy_dithering[] +ifdef::VK_VERSION_1_3,VK_KHR_shader_terminate_invocation[] + * <> + if +ifdef::VK_VERSION_1_3[Vulkan 1.3 or] + the `apiext:VK_KHR_shader_terminate_invocation` extension is supported. +endif::VK_VERSION_1_3,VK_KHR_shader_terminate_invocation[] +ifdef::VK_VERSION_1_3,VK_KHR_zero_initialize_workgroup_memory[] + * <>, if +ifdef::VK_VERSION_1_3[Vulkan 1.3 or] + the `apiext:VK_KHR_zero_initialize_workgroup_memory` extension is + supported. +endif::VK_VERSION_1_3,VK_KHR_zero_initialize_workgroup_memory[] +ifdef::VK_KHR_workgroup_memory_explicit_layout[] + * <>, if the + `apiext:VK_KHR_workgroup_memory_explicit_layout` extension is supported. +endif::VK_KHR_workgroup_memory_explicit_layout[] +ifdef::VK_EXT_vertex_input_dynamic_state[] + * <>, if + the `apiext:VK_EXT_vertex_input_dynamic_state` extension is supported. +endif::VK_EXT_vertex_input_dynamic_state[] +ifdef::VK_VERSION_1_3,VK_KHR_synchronization2[] + * <> if +ifdef::VK_VERSION_1_3[Vulkan 1.3 or] + the `apiext:VK_KHR_synchronization2` extension is supported. +endif::VK_VERSION_1_3,VK_KHR_synchronization2[] +ifdef::VK_EXT_provoking_vertex[] + * <>, if the + `apiext:VK_EXT_provoking_vertex` extension is supported. +endif::VK_EXT_provoking_vertex[] +ifdef::VK_EXT_descriptor_buffer[] + * <>, if the + `<>` extension is supported. +endif::VK_EXT_descriptor_buffer[] +ifdef::VK_KHR_shader_subgroup_uniform_control_flow[] + * <>, if the + `apiext:VK_KHR_shader_subgroup_uniform_control_flow` extension is + supported. +endif::VK_KHR_shader_subgroup_uniform_control_flow[] +ifdef::VK_EXT_border_color_swizzle[] + * <> if the + `apiext:VK_EXT_border_color_swizzle` extension is supported. +endif::VK_EXT_border_color_swizzle[] +ifdef::VK_EXT_multi_draw[] + * <>, if the + `apiext:VK_EXT_multi_draw` extension is supported. +endif::VK_EXT_multi_draw[] +ifdef::VK_EXT_shader_atomic_float2[] + * <>, if the + <> feature is supported. +endif::VK_EXT_shader_atomic_float2[] +ifdef::VK_KHR_present_id[] + * <>, if the + `apiext:VK_KHR_present_id` extension is supported. +endif::VK_KHR_present_id[] +ifdef::VK_KHR_present_wait[] + * <>, if the + `apiext:VK_KHR_present_wait` extension is supported. +endif::VK_KHR_present_wait[] +ifdef::VK_EXT_host_image_copy[] + * <>, if the + `<>` extension is supported. +endif::VK_EXT_host_image_copy[] +ifdef::VK_EXT_present_timing[] + * <>, if the + `apiext:VK_EXT_present_timing` extension is supported. +endif::VK_EXT_present_timing[] +ifdef::VK_VERSION_1_3,VK_KHR_shader_integer_dot_product[] + * <> if +ifdef::VK_VERSION_1_3[Vulkan 1.3 or] + the `apiext:VK_KHR_shader_integer_dot_product` extension is supported. +endif::VK_VERSION_1_3,VK_KHR_shader_integer_dot_product[] +ifdef::VK_VERSION_1_3,VK_KHR_maintenance4[] + * <>, if +ifdef::VK_VERSION_1_3[Vulkan 1.3 or] + the `apiext:VK_KHR_maintenance4` extension is supported. +endif::VK_VERSION_1_3,VK_KHR_maintenance4[] +ifdef::VK_KHR_maintenance5[] + * <>, if the + `apiext:VK_KHR_maintenance5` extension is supported. +endif::VK_KHR_maintenance5[] +ifdef::VK_KHR_maintenance6[] + * <>, if the + `apiext:VK_KHR_maintenance6` extension is supported. +endif::VK_KHR_maintenance6[] +ifdef::VK_EXT_image_2d_view_of_3d[] + * <>, if the + `apiext:VK_EXT_image_2d_view_of_3d` extension is supported. +endif::VK_EXT_image_2d_view_of_3d[] +ifdef::VK_EXT_image_sliced_view_of_3d[] + * <>, if the + `apiext:VK_EXT_image_sliced_view_of_3d` extension is supported. +endif::VK_EXT_image_sliced_view_of_3d[] +ifdef::VK_VERSION_1_3,VK_EXT_private_data[] + * <>, if +ifdef::VK_VERSION_1_3[Vulkan 1.3 or] + the `apiext:VK_EXT_private_data` extension is supported. +endif::VK_VERSION_1_3,VK_EXT_private_data[] +ifdef::VK_EXT_extended_dynamic_state[] + * <>, if the + `apiext:VK_EXT_extended_dynamic_state` extension is supported. +endif::VK_EXT_extended_dynamic_state[] +ifdef::VK_EXT_extended_dynamic_state2[] + * <>, if the + `apiext:VK_EXT_extended_dynamic_state2` extension is supported. +endif::VK_EXT_extended_dynamic_state2[] +ifdef::VK_EXT_depth_clip_control[] + * <>, if the + `apiext:VK_EXT_depth_clip_control` extension is supported. +endif::VK_EXT_depth_clip_control[] +ifdef::VK_EXT_image_view_min_lod[] + * <>, if the + `apiext:VK_EXT_image_view_min_lod` extension is supported. +endif::VK_EXT_image_view_min_lod[] ifdef::VK_NV_external_sci_sync[] * Either <> or <>, and either diff --git a/chapters/synchronization.adoc b/chapters/synchronization.adoc index 8503a34d0..ce64da684 100644 --- a/chapters/synchronization.adoc +++ b/chapters/synchronization.adoc @@ -7757,6 +7757,11 @@ endif::VK_EXT_calibrated_timestamps[] * [[VUID-VkCalibratedTimestampInfoEXT-timeDomain-02354]] pname:timeDomain must: be one of the elink:VkTimeDomainKHR values returned by flink:vkGetPhysicalDeviceCalibrateableTimeDomainsKHR +ifdef::VK_EXT_present_timing[] + * If pname:timeDomain is ename:VK_TIME_DOMAIN_SWAPCHAIN_LOCAL_EXT or + ename:VK_TIME_DOMAIN_PRESENT_STAGE_LOCAL_EXT, the pname:pNext chain + must: include a slink:VkSwapchainCalibratedTimestampInfoEXT structure. +endif::VK_EXT_present_timing[] **** include::{generated}/validity/structs/VkCalibratedTimestampInfoKHR.adoc[] -- @@ -7782,7 +7787,12 @@ 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_KHR specifies the CLOCK_MONOTONIC time domain available on POSIX platforms. Timestamp values in this time domain are in units of nanoseconds and are @@ -7838,4 +7848,37 @@ QueryPerformanceCounter(&counter); return counter.QuadPart; ---- -- + +ifdef::VK_EXT_present_timing[] +[open,refpage='VkSwapchainCalibratedTimestampInfoEXT',desc='Structure specifying the swapchain to calibrate a swapchain-local timestamp query',type='structs'] +-- +The sname:VkSwapchainCalibratedTimestampInfoEXT structure is defined as: + +include::{generated}/api/structs/VkSwapchainCalibratedTimestampInfoEXT.adoc[] + + * pname:sType is a elink:VkStructureType value identifying this structure. + * pname:pNext is `NULL` or a pointer to a structure extending this + structure. + * pname:swapchain is the swapchain to retrieve the swapchain-local timestamp from. + * pname:presentStage is zero or a tlink:VkPresentStageFlagsEXT value used + to identify a single present stage when calibrating a timestamp in the + ename:VK_TIME_DOMAIN_PRESENT_STAGE_LOCAL_EXT time domain. + * pname:timeDomainId is the id for the opaque time domain being calibrated. + +pname:timeDomainId must: be an id previously reported by +flink:vkGetSwapchainTimeDomainPropertiesEXT for pname:swapchain. If the +pname:timeDomainId is no longer supported by the pname:swapchain, +implementations may: report zero as the calibrated timestamp value. + +.Valid Usage +**** + * If the pname:timeDomain member of the slink:VkCalibratedTimestampInfoKHR structure + in this structure's pname:pNext chain is ename:VK_TIME_DOMAIN_PRESENT_STAGE_LOCAL_EXT, + pname:presentStage must: specify one and only one present stage. +**** + + +include::{generated}/validity/structs/VkSwapchainCalibratedTimestampInfoEXT.adoc[] +-- +endif::VK_EXT_present_timing[] endif::VK_KHR_calibrated_timestamps,VK_EXT_calibrated_timestamps[] diff --git a/proposals/VK_EXT_present_timing.adoc b/proposals/VK_EXT_present_timing.adoc new file mode 100644 index 000000000..d2af9326b --- /dev/null +++ b/proposals/VK_EXT_present_timing.adoc @@ -0,0 +1,552 @@ +// 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. See <>. + +* `VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT` marks the end of the set of queue operations enqueued by `vkQueuePresentKHR` on the provided `VkQueue`. These queue operations are implementation-specific; the usual example is a blit to a system-specific internal surface suited for presentation. +* `VK_PRESENT_STAGE_IMAGE_LATCHED_BIT_EXT` is the step after which the image associated with the presentation request has been latched by the presentation engine to create the presentation of a future refresh cycle. For example, in a flip-model scenario, this is the time the presentation request's image has been selected for the next refresh cycle. +* `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 + +==== Timing Properties + +For timing to be meaningful, the application needs to be aware of various properties. Basic properties are exposed in a new structure, `VkSwapchainTimingPropertiesEXT`, which can be retrieved with: + +[source,c] +---- +VkResult vkGetSwapchainTimingPropertiesEXT( + VkDevice device, + VkSwapchainKHR swapchain, + uint64_t* pSwapchainTimingPropertiesCounter, + VkSwapchainTimingPropertiesEXT* pSwapchainTimingProperties); +---- +Swapchain timing properties may change dynamically at any time without prior notification. For example, enabling power-saving mode on a device may cause it to lower the display panel's refresh rate. To allow applications to detect changes in those properties, a monotonically increasing counter is used by the implementation to identify the current state. This counter increases every time the swapchain properties are modified. `pSwapchainTimingPropertiesCounter` is a pointer to a `uint64_t` set by the implementation to the value of the current timing properties counter. Further updates to those properties are also communicated back to the application when querying presentation timings via `vkGetPastPresentationTimingEXT`. + +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 `UINT64_MAX`, the presentation engine is operating in FRR mode. + +When the presentation engine is operating in VRR mode, `refreshDuration` is the minimum refresh duration. + +`refreshDuration` may be zero, because some platforms may not provide timing properties until after at least one image has been presented to the swapchain. If timing properties of the swapchain change, updated results may again only be provided until after at least one additional image has been presented. + +==== Time Domains + +Applications also need to query available time domains using: +[source,c] +---- +VkResult vkGetSwapchainTimeDomainPropertiesEXT( + VkDevice device, + VkSwapchainKHR swapchain, + uint64_t* pTimeDomainsCounter, + VkSwapchainTimeDomainPropertiesEXT* pSwapchainTimeDomainProperties); +---- +Similar to <>, supported time domains may change dynamically. `pTimeDomainsCounter` identifies the current list of available time domains, and further internal changes to this list are notified to the application when calling `vkGetPastPresentationTimingEXT`. + +The `VkSwapchainTimeDomainPropertiesEXT` structure is defined as: +[source,c] +---- +typedef struct VkSwapchainTimeDomainPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t timeDomainCount; + VkTimeDomainEXT *pTimeDomains; + uint64_t *pTimeDomainIds; +} VkSwapchainTimeDomainPropertiesEXT; +---- +* `timeDomainCount` is an input specifying the size of the `pTimeDomains` and `pTimeDomainIds` arrays. If it is 0, it is set by the implementation upon return of `vkGetSwapchainTimeDomainPropertiesEXT` to the number of available time domains. Otherwise, it is set to the number of elements written in `pTimeDomains` and `pTimeDomainIds`. +* `pTimeDomains` is an array of `VkTimeDomainEXT` currently supported by the swapchain. +* `pTimeDomainIds` is an array of unique identifiers for each supported time domain. Time domains are assigned a unique identifier within a swapchain by the implementation. This id is used to differentiate between multiple swapchain-local time domains of the same scope. + +Two new swapchain-local time domains are added in this proposal as `VkTimeDomainEXT` values: +[source,c] +---- +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. + +To calibrate a swapchain-local or stage-local timestamp with another time domain, a new structure can be chained to `VkCalibratedTimestampInfoKHR` and passed to `vkGetCalibratedTimestampsKHR`: +[source,c] +---- +typedef struct VkSwapchainCalibratedTimestampInfoEXT { + VkStructureType sType; + const void* pNext; + VkSwapchainKHR swapchain; + VkPresentStageFlagsEXT presentStage; + uint64_t timeDomainId; +} VkSwapchainCalibratedTimestampInfoEXT; +---- +* `presentStage` is zero to calibrate a `VK_TIME_DOMAIN_SWAPCHAIN_LOCAL_EXT` time domain, or a single `VkPresentStageFlagsEXT` bit to calibrate a `VK_TIME_DOMAIN_PRESENT_STAGE_LOCAL_EXT` from that stage. +* `timeDomainId` is the identifier of the swapchain-local time domain returned by `vkGetSwapchainTimeDomainPropertiesEXT` or `vkGetPastPresentationTimingEXT`. + +=== Presentation timings feedback [[statistics]] + +Applications can obtain timing information about previous presents using: + +[source,c] +---- +VkResult vkGetPastPresentationTimingEXT( + VkDevice device, + const VkPastPresentationTimingInfoEXT* pPastPresentationTimingInfo, + VkPastPresentationTimingPropertiesEXT* pPastPresentationTimingProperties); +---- +`VkPastPresentationTimingInfoEXT` is a simple input structure referencing the `swapchain` to target, allowing for potential future extensions to hook into the `pNext` chain: +[source,c] +---- +typedef struct VkPastPresentationTimingInfoEXT { + VkStructureType sType; + const void* pNext; + VkSwapchainKHR swapchain; +}; +---- + +The `VkPastPresentationTimingPropertiesEXT` structure is defined as: +[source,c] +---- +typedef struct VkPastPresentationTimingPropertiesEXT { + VkStructureType sType; + const void* pNext; + uint64_t timingPropertiesCounter; + uint64_t timeDomainsCounter; + uint32_t presentationTimingCount; + VkPastPresentationTimingEXT* pPresentationTimings; +}; +---- +* `timingPropertiesCounter` is set to the current internal counter of the swapchain's timing properties. +* `timeDomainsCounter` is set to the current internal counter of the swapchain's supported time domain list. +* If the input value of `presentationTimingCount` is 0, the implementation sets it to the number of pending results available in the swapchain's internal queue. Otherwise, it contains the number of entries written to `pPresentationTimings` upon return. If the implementation is not able to write all the available results in the provided `pPresentationTimings` array, `VK_INCOMPLETE` is returned. + +Results for presentation requests whose entries in `pPresentationTimings` are marked as complete with `VkPastPresentationTimingEXT::reportComplete` will not be returned anymore. For each of those, a slot in the swapchain's internal results queue is released. Incomplete results for presentation requests will keep being reported in further `vkGetPastPresentationTimingEXT` calls until complete. + +`VkPastPresentationTimingEXT` is defined as: +[source, c] +---- +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; + VkTimeDomainEXT timeDomain; + uint64_t timeDomainId; + VkBool32 reportComplete; +} VkPastPresentationTimingEXT; +---- + +* `presentId` is a present id provided to `vkQueuePresentKHR` by adding a `VkPresentIdKHR` to the `VkPresentInfoKHR` pNext chain. Timing results can be correlated to specific presents using this value. +* `presentStageCount` and `pPresentStages` contain the timing information for the present stages that were specified in the `VkPresentTimeTargetInfoEXT` passed to the corresponding `vkQueuePresentKHR` call. +* `timeDomain` and `timeDomainId` define the time domain used for `pPresentStages` result times. It may be different than the time domain specified for the associated `vkQueuePresentKHR` call if that time domain was unavailable when the presentation request was processed. +* `reportComplete` indicates whether results for all present stages have been reported. + +`presentStageCount` only reports the number of stages which contain definitive results. However, time values in completed `pPresentStages` can still be 0 for multiple reasons. Most notably, it is possible for a presentation request to never reach some present stages, for example if using a present mode that allows images to be replaced in the queue, such as `VK_PRESENT_MODE_MAILBOX_KHR`. Platform-specific events can also cause results for some present stages to be unavailable for a specific presentation request. + +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, ¤tTimingPropertiesCounter, &swapchainTimingProperties); + + uint64_t currentTimeDomainsCounter = 0; + VkSwapchainTimeDomainPropertiesEXT timeDomains = { + .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_TIME_DOMAIN_PROPERTIES_EXT, + .pNext = NULL, + .timeDomainCount = 0, + .pTimeDomains = NULL, + .pTimeDomainIds = NULL + }; + + result = vkGetSwapchainTimeDomainPropertiesEXT(device, swapchain, NULL, &timeDomains); + timeDomains.pTimeDomains = (VkTimeDomainEXT *) malloc(timeDomains.timeDomainCount * sizeof(VkTimeDomainEXT)); + timeDomains.pTimeDomainIds = (uint64_t *) malloc(timeDomains.timeDomainCount * sizeof(uint64_t)); + result = vkGetSwapchainTimeDomainPropertiesEXT(device, swapchain, ¤tTimeDomainsCounter, &timeDomains); + + // Find the ID of the current VK_TIME_DOMAIN_SWAPCHAIN_LOCAL_EXT time domain + uint64_t swapchainLocalTimeDomainId = FindTimeDomain(&timeDomains, VK_TIME_DOMAIN_SWAPCHAIN_LOCAL_EXT); + + // Allocate internal queue to collect present timing results + const uint32_t maxTimingCount = GetMaxTimingCount(); // Default to sane value, e.g. swapchainImageCount * 2 + result = vkSetSwapchainPresentTimingQueueSizeEXT(device, swapchain, maxTimingCount); + + // (Start presenting...) +---- + +=== Basic present loop + +[source, c] +---- + uint32_t maxPresentStageCount = 4; + uint64_t currentPresentId = 1; + VkPastPresentationTimingEXT *pTimings = (VkPastPresentationTimingEXT *) malloc(maxTimingCount * sizeof(VkPastPresentationTimingEXT)); + VkPastPresentationTimingInfoEXT pastPresentationTimingInfo = { + .sType = VK_STRUCTURE_TYPE_PAST_PRESENTATION_TIMING_INFO_EXT, + .pNext = NULL, + .swapchain = swapchain + }; + VkPastPresentationTimingPropertiesEXT pastPresentationTimingProperties = { + .sType = VK_STRUCTURE_TYPE_PAST_PRESENTATION_TIMING_PROPERTIES_EXT, + .pNext = NULL, + .pPresentationTimings = pTimings + }; + VkPresentStageFlagBitsEXT targetPresentStage = VK_PRESENT_STAGE_IMAGE_LATCHED_BIT_EXT; + + for (uint32_t i = 0; i < maxTimingCount; ++i) { + pTimings[i].pPresentStages = (VkPresentStageTimeEXT *) malloc(maxPresentStageCount * sizeof(VkPresentStageTimeEXT)); + } + + while (!done) { + pastPresentationTimingProperties.presentationTimingCount = maxTimingCount; + + result = vkGetPastPresentationTimingEXT(device, &pastPresentationTimingInfo, &pastPresentationTimingProperties); + + if (pastPresentationTimingProperties.timingPropertiesCounter != currentTimingPropertiesCounter) { + result = vkGetSwapchainTimingPropertiesEXT(device, swapchain, ¤tTimingPropertiesCounter, &swapchainTimingProperties); + currentTimingPropertiesCounter = pastPresentationTimingProperties.timingPropertiesCounter; + } + + for (uint32_t i = 0; i < timingCount; ++i) { + if (timings[i].reportComplete && timings[i].timeDomainId == swapchainLocalTimeDomainId) { + // Build the presentation history for reports that use the expected time domain only. + // This could be handled in a more sophisticated way by calibrating timestamps across + // different time domains if desired. + pastPresentationTimings[timings[i].presentId % maxPresentHistory] = ParseResult(timings[i]); + } + } + + // Re-query time domains if necessary. If our current time domain is not available anymore, start + // over with a new history. + if (pastPresentationTimingProperties.timeDomainsCounter != currentTimeDomainsCounter) { + currentTimeDomainsCounter = UpdateTimeDomains(swapchain, &timeDomains); + uint64_t newSwapchainLocalTimeDomainId = FindTimeDomain(&timeDomains, VK_TIME_DOMAIN_SWAPCHAIN_LOCAL_EXT); + if (newSwapchainLocalTimeDomainId != swapchainLocalTimeDomainId) { + swapchainLocalTimeDomainId = newSwapchainLocalTimeDomainId; + InvalidatePresentationTimingHistory(); + } + } + + // 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 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 = swapchainLocalTimeDomainId, + .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 6c2246cca..8a0395393 100644 --- a/xml/vk.xml +++ b/xml/vk.xml @@ -485,6 +485,7 @@ typedef void* MTLSharedEvent_id; typedef VkFlags VkPresentGravityFlagsEXT; typedef VkFlags VkShaderCreateFlagsEXT; typedef VkFlags64 VkPhysicalDeviceSchedulingControlsFlagsARM; + typedef VkFlags VkPresentStageFlagsEXT; Video Core extension typedef VkFlags VkVideoCodecOperationFlagsKHR; @@ -888,6 +889,7 @@ typedef void* MTLSharedEvent_id; + Enumerated types in the header, but not used by the API @@ -3252,6 +3254,89 @@ 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 + void* pNext + uint64_t refreshDurationNumber of nanoseconds from the start of one refresh cycle to the next + uint64_t variableRefreshDelayNumber of nanoseconds for variable refresh displays to react to IPD changes + + + VkStructureType sType + void* pNext + uint32_t timeDomainCount + VkTimeDomainEXT* pTimeDomainsAvailable time domains to use with the swapchain + uint64_t* pTimeDomainIdsUnique identifier for a time domain + + + VkPresentStageFlagsEXT stage + uint64_t timeTime in nanoseconds of the associated stage + + + VkStructureType sType + const void* pNext + VkSwapchainKHR swapchain + + + VkStructureType sType + void* pNext + uint64_t timingPropertiesCounter + uint64_t timeDomainsCounter + uint32_t presentationTimingCount + VkPastPresentationTimingEXT* pPresentationTimings + + + VkStructureType sType + void* pNext + uint64_t presentIdApplication-provided identifier, previously given to vkQueuePresentKHR + uint32_t presentStageCountNumber of present stages results available in pPresentStages + VkPresentStageTimeEXT* pPresentStagesReported timings for each present stage + VkTimeDomainEXT timeDomainTime domain of the present stages + uint64_t timeDomainIdTime domain id of the present stages + VkBool32 reportCompleteVK_TRUE if all the present stages have been reported + + + VkStructureType sType + const void* pNext + uint32_t swapchainCountCopy of VkPresentInfoKHR::swapchainCount + const VkPresentTimingInfoEXT* pTimingInfosPresent timing details for each swapchain + + + 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 VkStructureType sType @@ -11108,7 +11193,12 @@ typedef void* MTLSharedEvent_id; - + + + + + + @@ -12860,7 +12950,7 @@ typedef void* MTLSharedEvent_id; VkFence fence uint32_t* pImageIndex - + VkResult vkQueuePresentKHR VkQueue queue const VkPresentInfoKHR* pPresentInfo @@ -15702,6 +15792,32 @@ typedef void* MTLSharedEvent_id; const VkShaderStageFlagBits* pStages const VkShaderEXT* pShaders + + VkResult vkSetSwapchainPresentTimingQueueSizeEXT + VkDevice device + VkSwapchainKHR swapchain + uint32_t size + + + VkResult vkGetSwapchainTimingPropertiesEXT + VkDevice device + VkSwapchainKHR swapchain + uint64_t* pSwapchainTimingPropertiesCounter + VkSwapchainTimingPropertiesEXT* pSwapchainTimingProperties + + + VkResult vkGetSwapchainTimeDomainPropertiesEXT + VkDevice device + VkSwapchainKHR swapchain + uint64_t* pTimeDomainsCounter + VkSwapchainTimeDomainPropertiesEXT* pSwapchainTimeDomainProperties + + + VkResult vkGetPastPresentationTimingEXT + VkDevice device + const VkPastPresentationTimingInfoEXT* pPastPresentationTimingInfo + VkPastPresentationTimingPropertiesEXT* pPastPresentationTimingProperties + VkResult vkGetScreenBufferPropertiesQNX VkDevice device @@ -20483,10 +20599,44 @@ typedef void* MTLSharedEvent_id; - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +