[PATCH] winevulkan: Implement VK_EXT_calibrated_timestamps
Liam Middlebrook
lmiddlebrook at nvidia.com
Fri Jul 17 23:49:39 CDT 2020
On 7/17/20 12:04 AM, Joshua Ashton wrote:
> Map performance counter to the appropriate monotonic clock
> used by ntdll/unix/sync.c
>
> The performance counter timestamp clock won't be available
> under Mac and platforms without clock_gettime.
>
> Signed-off-by: Joshua Ashton <joshua at froggi.es>
> ---
> dlls/winevulkan/make_vulkan | 5 +-
> dlls/winevulkan/vulkan.c | 116 ++++++++++++++++++++++++++++++++++++
> 2 files changed, 120 insertions(+), 1 deletion(-)
>
> diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan
> index 04b263e3e4..b5629b95a5 100755
> --- a/dlls/winevulkan/make_vulkan
> +++ b/dlls/winevulkan/make_vulkan
> @@ -100,7 +100,6 @@ UNSUPPORTED_EXTENSIONS = [
>
> # Device extensions
> "VK_AMD_display_native_hdr",
> - "VK_EXT_calibrated_timestamps",
> "VK_EXT_display_control", # Requires VK_EXT_display_surface_counter
> "VK_EXT_full_screen_exclusive",
> "VK_EXT_hdr_metadata", # Needs WSI work.
> @@ -222,6 +221,10 @@ FUNCTION_OVERRIDES = {
> # VK_EXT_private_data
> "vkGetPrivateDataEXT" : {"dispatch": True, "driver" : False, "thunk" : False},
> "vkSetPrivateDataEXT" : {"dispatch": True, "driver" : False, "thunk" : False},
> +
> + # VK_EXT_calibrated_timestamps
> + "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT" : {"dispatch" : True, "driver" : False, "thunk" : False},
> + "vkGetCalibratedTimestampsEXT" : {"dispatch" : True, "driver" : False, "thunk" : False},
> }
>
> STRUCT_CHAIN_CONVERSIONS = [
> diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c
> index 4642975ad0..d01e48103c 100644
> --- a/dlls/winevulkan/vulkan.c
> +++ b/dlls/winevulkan/vulkan.c
> @@ -17,6 +17,8 @@
> * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
> */
>
> +#include "config.h"
> +#include <time.h>
> #include <stdarg.h>
>
> #include "windef.h"
> @@ -1265,6 +1267,120 @@ VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevi
> return res;
> }
>
> +static VkTimeDomainEXT map_to_host_time_domain(VkTimeDomainEXT domain)
> +{
> + /* Matches dlls/ntdll/unix/sync.c's performance counter implementation. */
> +#if !defined(__APPLE__) && defined(HAVE_CLOCK_GETTIME)
> + if (domain == VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT)
> +# ifdef CLOCK_MONOTONIC_RAW
> + return VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT;
> +# else
> + return VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT;
> +# endif
> +#endif
> +
> + return domain;
> +}
> +
> +VkResult WINAPI wine_vkGetCalibratedTimestampsEXT(VkDevice device,
> + uint32_t timestamp_count, const VkCalibratedTimestampInfoEXT *timestamp_infos,
> + uint64_t *timestamps, uint64_t *max_deviation)
> +{
> + VkCalibratedTimestampInfoEXT* host_timestamp_infos;
> + unsigned int i;
> + VkResult res;
> + TRACE("%p, %u, %p, %p, %p\n", device, timestamp_count, timestamp_infos, timestamps, max_deviation);
> +
> + host_timestamp_infos = heap_alloc(sizeof(VkCalibratedTimestampInfoEXT) * timestamp_count);
> +
> + for (i = 0; i < timestamp_count; i++)
> + {
> + host_timestamp_infos[i].sType = timestamp_infos[i].sType;
> + host_timestamp_infos[i].pNext = timestamp_infos[i].pNext;
> + host_timestamp_infos[i].timeDomain = map_to_host_time_domain(timestamp_infos[i].timeDomain);
> + }
> +
> + res = device->funcs.p_vkGetCalibratedTimestampsEXT(device->device, timestamp_count, host_timestamp_infos, timestamps, max_deviation);
I think that we'll need to preform some conversion on the timestamps
after the call to vkGetCalibratedTimestampsEXT() here, at least for
non-DEVICE time domains.
Looking at the Vulkan spec, we should expect CLOCK_MONOTONIC*
implementations to return values in nanoseconds:
> Timestamp values in this time domain are in units of nanoseconds
Where-as for QUERY_PERFORMANCE_COUNTER the following is stated:
> Timestamp values in this time domain are in the same units as those provided by the Windows QueryPerformanceCounter API
Digging into dlls/ntdll/unix/sync.c:monotonic_counter we see the
following code that I'd expect is the common-path for us to hit on Linux
platforms (ie: having clock_gettime()):
> 98 #ifdef CLOCK_MONOTONIC_RAW
> 99 if (!clock_gettime( CLOCK_MONOTONIC_RAW, &ts ))
> 100 return ts.tv_sec * (ULONGLONG)TICKSPERSEC + ts.tv_nsec / 100;
> 101 #endif
> 102 if (!clock_gettime( CLOCK_MONOTONIC, &ts ))
> 103 return ts.tv_sec * (ULONGLONG)TICKSPERSEC + ts.tv_nsec / 100;
> 104 #endif
So I think to report accurate values winevulkan will need to make a
similar conversion here. Perhaps it would be good to refactor things a
bit such that this conversion lives in an area which is accessible both
by ntdll as well as winevulkan, but I'm not sure what the general
feeling is around that kind of thing in WINE since I've almost
exclusively stuck to winevulkan.
> +
> + heap_free(host_timestamp_infos);
> +
> + return res;
> +}
> +
> +VkResult WINAPI wine_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT(VkPhysicalDevice phys_dev,
> + uint32_t *time_domain_count, VkTimeDomainEXT *time_domains)
> +{
> + BOOL supports_device = FALSE, supports_monotonic = FALSE, supports_monotonic_raw = FALSE;
> + VkTimeDomainEXT *host_time_domains;
> + uint32_t host_time_domain_count;
> + VkTimeDomainEXT out_time_domains[2];
> + uint32_t out_time_domain_count;
> + unsigned int i;
> + VkResult res;
> +
> + TRACE("%p, %p, %p\n", phys_dev, time_domain_count, time_domains);
> +
> + /* Find out the time domains supported on the host */
> + res = phys_dev->instance->funcs.p_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT(phys_dev->phys_dev, &host_time_domain_count, NULL);
> + if (res != VK_SUCCESS)
> + return res;
> +
> + host_time_domains = heap_alloc(sizeof(VkTimeDomainEXT) * host_time_domain_count);
> +
> + res = phys_dev->instance->funcs.p_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT(phys_dev->phys_dev, &host_time_domain_count, host_time_domains);
> + if (res != VK_SUCCESS)
> + return res;
> +
> + for (i = 0; i < host_time_domain_count; i++)
> + {
> + if (host_time_domains[i] == VK_TIME_DOMAIN_DEVICE_EXT)
> + supports_device = TRUE;
> +
> + if (host_time_domains[i] == VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT)
> + supports_monotonic = TRUE;
> +
> + if (host_time_domains[i] == VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT)
> + supports_monotonic_raw = TRUE;
> + }
> +
> + heap_free(host_time_domains);
> +
> + out_time_domain_count = 0;
> +
> + /* Map our monotonic times -> QPC */
> + (void)(supports_monotonic);
> + (void)(supports_monotonic_raw);
> +#if !defined(__APPLE__) && defined(HAVE_CLOCK_GETTIME)
> +# ifdef CLOCK_MONOTONIC_RAW
> + if (supports_monotonic_raw)
> + out_time_domains[out_time_domain_count++] = VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT;
> +# else
> + if (supports_monotonic)
> + out_time_domains[out_time_domain_count++] = VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT;
> +# endif
Is this inner-ifdef needed? I think the ifdef for if RAW is available
should be moved up to the section which pulls in RAW from the driver.
That's just a nitpick for readability though, I don't think it matters
much either way.
> +#else
> + FIXME("VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT not supported on this platform.");
> +#endif
> +
> + /* Forward the device domain time */
> + if (supports_device)
> + out_time_domains[out_time_domain_count++] = VK_TIME_DOMAIN_DEVICE_EXT;
> +
> + /* Send back to the app */
nit: Send count back to the app
Thanks,
Liam Middlebrook
> + if (!time_domains)
> + {
> + *time_domain_count = out_time_domain_count;
> + return VK_SUCCESS;
> + }
> +
> + for (i = 0; i < min(*time_domain_count, out_time_domain_count); i++)
> + time_domains[i] = out_time_domains[i];
> +
> + res = *time_domain_count != out_time_domain_count ? VK_INCOMPLETE : VK_SUCCESS;
> + *time_domain_count = out_time_domain_count;
> + return res;
> +}
> +
> static HANDLE get_display_device_init_mutex(void)
> {
> static const WCHAR init_mutexW[] = {'d','i','s','p','l','a','y','_','d','e','v','i','c','e','_','i','n','i','t',0};
>
More information about the wine-devel
mailing list