Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com --- libs/vkd3d/command.c | 60 ++++++++++++++++++++++++++++++++++++-- libs/vkd3d/device.c | 53 +++++++++++++++++++++++++++++++++ libs/vkd3d/vkd3d_private.h | 2 ++ libs/vkd3d/vulkan_procs.h | 6 ++++ tests/d3d12.c | 4 --- 5 files changed, 119 insertions(+), 6 deletions(-)
diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index 3e252aee..919b0584 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c @@ -6238,13 +6238,69 @@ static HRESULT STDMETHODCALLTYPE d3d12_command_queue_GetTimestampFrequency(ID3D1 return S_OK; }
+#define TICKSPERSEC 10000000 + static HRESULT STDMETHODCALLTYPE d3d12_command_queue_GetClockCalibration(ID3D12CommandQueue *iface, UINT64 *gpu_timestamp, UINT64 *cpu_timestamp) { - FIXME("iface %p, gpu_timestamp %p, cpu_timestamp %p stub!\n", + struct d3d12_command_queue *command_queue = impl_from_ID3D12CommandQueue(iface); + struct d3d12_device *device = command_queue->device; + const struct vkd3d_vk_device_procs *vk_procs; + VkCalibratedTimestampInfoEXT infos[2]; + uint64_t timestamps[2]; + uint64_t deviations[2]; + VkResult vr; + + TRACE("iface %p, gpu_timestamp %p, cpu_timestamp %p.\n", iface, gpu_timestamp, cpu_timestamp);
- return E_NOTIMPL; + if (!command_queue->vkd3d_queue->timestamp_bits) + { + WARN("Timestamp queries not supported.\n"); + return E_FAIL; + } + + if (!gpu_timestamp || !cpu_timestamp) + return E_INVALIDARG; + + if (!device->vk_info.EXT_calibrated_timestamps || device->vk_host_time_domain == VK_TIME_DOMAIN_MAX_ENUM_EXT) + { + WARN(!device->vk_info.EXT_calibrated_timestamps + ? "VK_EXT_calibrated_timestamps was not found. Setting timestamps to zero.\n" + : "Device and/or host time domain is not available. Setting timestamps to zero.\n"); + *gpu_timestamp = 0; + *cpu_timestamp = 0; + return S_OK; + } + + vk_procs = &device->vk_procs; + + infos[0].sType = VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT; + infos[0].pNext = NULL; + infos[0].timeDomain = VK_TIME_DOMAIN_DEVICE_EXT; + infos[1].sType = VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT; + infos[1].pNext = NULL; + infos[1].timeDomain = device->vk_host_time_domain; + + memset(timestamps, 0, sizeof(timestamps)); + if ((vr = VK_CALL(vkGetCalibratedTimestampsEXT(command_queue->device->vk_device, + ARRAY_SIZE(infos), infos, timestamps, deviations))) < 0) + { + WARN("Failed to get calibrated timestamps, vr %d.\n", vr); + return E_FAIL; + } + + if (infos[1].timeDomain == VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT + || infos[1].timeDomain == VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT) + { + /* Convert monotonic clock to match Wine's RtlQueryPerformanceFrequency(). */ + timestamps[1] /= 1000000000 / TICKSPERSEC; + } + + *gpu_timestamp = timestamps[0]; + *cpu_timestamp = timestamps[1]; + + return S_OK; }
static D3D12_COMMAND_QUEUE_DESC * STDMETHODCALLTYPE d3d12_command_queue_GetDesc(ID3D12CommandQueue *iface, diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c index 661ca1d9..a37f8c52 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c @@ -130,6 +130,7 @@ static const struct vkd3d_optional_extension_info optional_device_extensions[] = VK_EXTENSION(KHR_PUSH_DESCRIPTOR, KHR_push_descriptor), VK_EXTENSION(KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE, KHR_sampler_mirror_clamp_to_edge), /* EXT extensions */ + VK_EXTENSION(EXT_CALIBRATED_TIMESTAMPS, EXT_calibrated_timestamps), VK_EXTENSION(EXT_CONDITIONAL_RENDERING, EXT_conditional_rendering), VK_EXTENSION(EXT_DEBUG_MARKER, EXT_debug_marker), VK_EXTENSION(EXT_DEPTH_CLIP_ENABLE, EXT_depth_clip_enable), @@ -2349,6 +2350,57 @@ static void vkd3d_gpu_descriptor_allocator_cleanup(struct vkd3d_gpu_descriptor_a pthread_mutex_destroy(&allocator->mutex); }
+static bool have_vk_time_domain(VkTimeDomainEXT *domains, unsigned int count, VkTimeDomainEXT domain) +{ + unsigned int i; + + for (i = 0; i < count; ++i) + if (domains[i] == domain) + return true; + + return false; +} + +static void vkd3d_time_domains_init(struct d3d12_device *device) +{ + const struct vkd3d_vk_instance_procs *vk_procs = &device->vkd3d_instance->vk_procs; + VkTimeDomainEXT domains[8]; + uint32_t count; + VkResult vr; + + device->vk_host_time_domain = VK_TIME_DOMAIN_MAX_ENUM_EXT; + + if (!device->vk_info.EXT_calibrated_timestamps) + return; + + count = ARRAY_SIZE(domains); + if ((vr = VK_CALL(vkGetPhysicalDeviceCalibrateableTimeDomainsEXT(device->vk_physical_device, + &count, domains))) == VK_SUCCESS || vr == VK_INCOMPLETE) + { + if (vr == VK_INCOMPLETE) + FIXME("Calibrated time domain list is incomplete.\n"); + + if (!have_vk_time_domain(domains, count, VK_TIME_DOMAIN_DEVICE_EXT)) + { + WARN("Device time domain not found. Calibrated timestamps will not be available.\n"); + return; + } + + if (have_vk_time_domain(domains, count, VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT)) + device->vk_host_time_domain = VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT; + else if (have_vk_time_domain(domains, count, VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT)) + device->vk_host_time_domain = VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT; + else if (have_vk_time_domain(domains, count, VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT)) + device->vk_host_time_domain = VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT; + else + WARN("Found no acceptable host time domain. Calibrated timestamps will not be available.\n"); + } + else + { + WARN("Failed to get calibrated time domains, vr %d.\n", vr); + } +} + /* ID3D12Device */ static inline struct d3d12_device *impl_from_ID3D12Device(ID3D12Device *iface) { @@ -3910,6 +3962,7 @@ static HRESULT d3d12_device_init(struct d3d12_device *device, vkd3d_render_pass_cache_init(&device->render_pass_cache); vkd3d_gpu_descriptor_allocator_init(&device->gpu_descriptor_allocator); vkd3d_gpu_va_allocator_init(&device->gpu_va_allocator); + vkd3d_time_domains_init(device);
for (i = 0; i < ARRAY_SIZE(device->desc_mutex); ++i) pthread_mutex_init(&device->desc_mutex[i], NULL); diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index 047f4a29..6441ba1a 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -108,6 +108,7 @@ struct vkd3d_vulkan_info bool KHR_push_descriptor; bool KHR_sampler_mirror_clamp_to_edge; /* EXT device extensions */ + bool EXT_calibrated_timestamps; bool EXT_conditional_rendering; bool EXT_debug_marker; bool EXT_depth_clip_enable; @@ -1195,6 +1196,7 @@ struct d3d12_device struct vkd3d_queue *copy_queue; uint32_t queue_family_indices[VKD3D_MAX_QUEUE_FAMILY_COUNT]; unsigned int queue_family_count; + VkTimeDomainEXT vk_host_time_domain;
struct vkd3d_instance *vkd3d_instance;
diff --git a/libs/vkd3d/vulkan_procs.h b/libs/vkd3d/vulkan_procs.h index ec29eb45..60556735 100644 --- a/libs/vkd3d/vulkan_procs.h +++ b/libs/vkd3d/vulkan_procs.h @@ -55,6 +55,9 @@ VK_INSTANCE_EXT_PFN(vkGetPhysicalDeviceProperties2KHR) VK_INSTANCE_EXT_PFN(vkCreateDebugReportCallbackEXT) VK_INSTANCE_EXT_PFN(vkDestroyDebugReportCallbackEXT)
+/* VK_EXT_calibrated_timestamps */ +VK_INSTANCE_EXT_PFN(vkGetPhysicalDeviceCalibrateableTimeDomainsEXT) + /* Device functions (obtained by vkGetDeviceProcAddr). */ VK_DEVICE_PFN(vkDestroyDevice) /* Load vkDestroyDevice() first. */ VK_DEVICE_PFN(vkAllocateCommandBuffers) @@ -192,6 +195,9 @@ VK_DEVICE_EXT_PFN(vkGetDescriptorSetLayoutSupportKHR) /* VK_KHR_push_descriptor */ VK_DEVICE_EXT_PFN(vkCmdPushDescriptorSetKHR)
+/* VK_EXT_calibrated_timestamps */ +VK_DEVICE_EXT_PFN(vkGetCalibratedTimestampsEXT) + /* VK_EXT_conditional_rendering */ VK_DEVICE_EXT_PFN(vkCmdBeginConditionalRenderingEXT) VK_DEVICE_EXT_PFN(vkCmdEndConditionalRenderingEXT) diff --git a/tests/d3d12.c b/tests/d3d12.c index cb9fe5fb..5b61e498 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -36019,19 +36019,15 @@ static void test_clock_calibration(void) return;
hr = ID3D12CommandQueue_GetClockCalibration(context.queue, &gpu_times[0], &cpu_times[0]); - todo ok(hr == S_OK, "Failed to retrieve calibrated timestamps, hr %#x.\n", hr);
vkd3d_sleep(100);
hr = ID3D12CommandQueue_GetClockCalibration(context.queue, &gpu_times[1], &cpu_times[1]); - todo ok(hr == S_OK, "Failed to retrieve calibrated timestamps, hr %#x.\n", hr);
- todo ok(gpu_times[1] > gpu_times[0], "Inconsistent GPU timestamps %"PRIu64" and %"PRIu64".\n", gpu_times[0], gpu_times[1]); - todo ok(cpu_times[1] > cpu_times[0], "Inconsistent CPU timestamps %"PRIu64" and %"PRIu64".\n", cpu_times[0], cpu_times[1]);