diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/device_context.cc | 13 | ||||
| -rw-r--r-- | src/device_context.hh | 4 | ||||
| -rw-r--r-- | src/layer.cc | 233 | ||||
| -rw-r--r-- | src/physical_device_context.cc | 26 | ||||
| -rw-r--r-- | src/physical_device_context.hh | 17 | ||||
| -rw-r--r-- | src/queue_context.cc | 12 | ||||
| -rw-r--r-- | src/timestamp_pool.cc | 2 |
7 files changed, 163 insertions, 144 deletions
diff --git a/src/device_context.cc b/src/device_context.cc index b149311..49b7808 100644 --- a/src/device_context.cc +++ b/src/device_context.cc @@ -11,7 +11,13 @@ DeviceContext::DeviceContext(InstanceContext& parent_instance, const VkDevice& device, VkuDeviceDispatchTable&& vtable) : instance(parent_instance), physical_device(parent_physical_device), - device(device), vtable(std::move(vtable)), clock(*this) {} + device(device), vtable(std::move(vtable)) { + + // Only create our clock if we can support creating it. + if (this->physical_device.supports_required_extensions) { + this->clock = std::make_unique<Clock>(*this); + } +} DeviceContext::~DeviceContext() { this->present_queue.reset(); @@ -102,7 +108,7 @@ void DeviceContext::sleep_in_input() { // stall until it's finished. const auto& last_frame = frames.back(); assert(std::size(last_frame.submissions)); - const auto& last_frame_submission = frames.back().submissions.back(); + const auto& last_frame_submission = last_frame.submissions.back(); last_frame_submission->end_handle->get_time_spinlock(); // From our sleep in present implementation, just spinning until @@ -123,9 +129,8 @@ void DeviceContext::notify_antilag_update(const VkAntiLagDataAMD& data) { return; } - const auto& presentation_info = *data.pPresentationInfo; // Only care about the input stage for now. - if (presentation_info.stage != VK_ANTI_LAG_STAGE_INPUT_AMD) { + if (data.pPresentationInfo->stage != VK_ANTI_LAG_STAGE_INPUT_AMD) { return; } diff --git a/src/device_context.hh b/src/device_context.hh index 37817d5..b4a337b 100644 --- a/src/device_context.hh +++ b/src/device_context.hh @@ -53,9 +53,9 @@ struct DeviceContext final : public Context { void calibrate(); time_point_t ticks_to_time(const std::uint64_t& ticks) const; }; - Clock clock; + std::unique_ptr<Clock> clock; - std::uint32_t antilag_fps = 0; + std::uint32_t antilag_fps = 0; // TODO VkAntiLagModeAMD antilag_mode = VK_ANTI_LAG_MODE_DRIVER_CONTROL_AMD; // The queue used in the last present. diff --git a/src/layer.cc b/src/layer.cc index aea2154..d2977b7 100644 --- a/src/layer.cc +++ b/src/layer.cc @@ -1,5 +1,6 @@ #include "layer.hh" +#include <ranges> #include <span> #include <string_view> #include <unordered_map> @@ -181,6 +182,24 @@ static VKAPI_ATTR VkResult VKAPI_CALL CreateDevice( VkPhysicalDevice physical_device, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice) { + // Hook logic after create device looks like this. + // !PHYS_SUPPORT && AL2_REQUESTED -> return INITIALIZATION_FAILED here. + // !PHYS_SUPPORT && !AL2_REQUESTED -> hooks are no-ops + // PHYS_SUPPORT -> hooks inject timestamps regardless + // because AL1 might be used and it + // costs virtually nothing to do. + const auto was_antilag_requested = std::ranges::any_of( + std::span{pCreateInfo->ppEnabledExtensionNames, + pCreateInfo->enabledExtensionCount}, + [](const auto& ext) { + return std::string_view{ext} == VK_AMD_ANTI_LAG_EXTENSION_NAME; + }); + + const auto context = layer_context.get_context(physical_device); + if (!context->supports_required_extensions && was_antilag_requested) { + return VK_ERROR_INITIALIZATION_FAILED; + } + const auto create_info = find_link<VkLayerDeviceCreateInfo>( pCreateInfo->pNext, VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO); if (!create_info || !create_info->u.pLayerInfo) { @@ -195,64 +214,25 @@ static VKAPI_ATTR VkResult VKAPI_CALL CreateDevice( const_cast<VkLayerDeviceCreateInfo*>(create_info)->u.pLayerInfo = create_info->u.pLayerInfo->pNext; - const auto physical_device_context = - layer_context.get_context(physical_device); - auto& instance_context = physical_device_context->instance; - - const auto next_extensions = - [&]() -> std::optional<std::vector<const char*>> { - const auto enumerate_device_extensions = - reinterpret_cast<PFN_vkEnumerateDeviceExtensionProperties>( - gipa(instance_context.instance, - "vkEnumerateDeviceExtensionProperties")); - if (!enumerate_device_extensions) { - return std::nullopt; - } - - auto count = std::uint32_t{}; - if (enumerate_device_extensions(physical_device, nullptr, &count, - nullptr) != VK_SUCCESS) { - - return std::nullopt; - } - - auto supported_extensions = std::vector<VkExtensionProperties>(count); - if (enumerate_device_extensions(physical_device, nullptr, &count, - std::data(supported_extensions)) != - VK_SUCCESS) { + // Build a next extensions vector from what they have requested. + const auto next_extensions = [&]() -> std::vector<const char*> { + auto next_extensions = std::span{pCreateInfo->ppEnabledExtensionNames, + pCreateInfo->enabledExtensionCount} | + std::ranges::to<std::vector>(); - return std::nullopt; + // Don't append anything extra if we don't support what we need. + if (!context->supports_required_extensions) { + return next_extensions; } - auto next_extensions = std::vector<const char*>{}; + const auto already_requested = + next_extensions | + std::ranges::to<std::unordered_set<std::string_view>>(); - std::ranges::copy(std::span{pCreateInfo->ppEnabledExtensionNames, - pCreateInfo->enabledExtensionCount}, - std::back_inserter(next_extensions)); - - const auto wanted_extensions = { - VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME, - VK_KHR_CALIBRATED_TIMESTAMPS_EXTENSION_NAME, - VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME}; - - for (const auto& wanted : wanted_extensions) { - - if (std::ranges::any_of( - next_extensions, [&](const auto& next_extension) { - return !std::strcmp(next_extension, wanted); - })) { - - continue; // Already included, ignore it. - } - - if (std::ranges::none_of( - supported_extensions, [&](const auto& supported_extension) { - return !std::strcmp(supported_extension.extensionName, - wanted); - })) { - - return std::nullopt; // We don't support it, the layer can't - // work. + // Only append the extra extension if it wasn't already asked for. + for (const auto& wanted : PhysicalDeviceContext::required_extensions) { + if (already_requested.contains(wanted)) { + continue; } next_extensions.push_back(wanted); @@ -261,26 +241,16 @@ static VKAPI_ATTR VkResult VKAPI_CALL CreateDevice( return next_extensions; }(); - if (!next_extensions.has_value()) { - return VK_ERROR_INITIALIZATION_FAILED; - } - - const auto create_device = instance_context.vtable.CreateDevice; - if (!create_device) { - return VK_ERROR_INITIALIZATION_FAILED; - } - const auto next_create_info = [&]() -> VkDeviceCreateInfo { auto next_pCreateInfo = *pCreateInfo; - next_pCreateInfo.ppEnabledExtensionNames = std::data(*next_extensions); - next_pCreateInfo.enabledExtensionCount = std::size(*next_extensions); + next_pCreateInfo.ppEnabledExtensionNames = std::data(next_extensions); + next_pCreateInfo.enabledExtensionCount = std::size(next_extensions); return next_pCreateInfo; }(); - if (const auto result = create_device(physical_device, &next_create_info, - pAllocator, pDevice); + if (const auto result = context->instance.vtable.CreateDevice( + physical_device, &next_create_info, pAllocator, pDevice); result != VK_SUCCESS) { - return result; } @@ -313,16 +283,13 @@ static VKAPI_ATTR VkResult VKAPI_CALL CreateDevice( DEVICE_VTABLE_LOAD(ResetQueryPoolEXT); #undef DEVICE_VTABLE_LOAD - const auto physical_context = layer_context.get_context(physical_device); - const auto key = layer_context.get_key(*pDevice); const auto lock = std::scoped_lock{layer_context.mutex}; - assert(!layer_context.contexts.contains(key)); + assert(!layer_context.contexts.contains(key)); layer_context.contexts.try_emplace( - key, - std::make_shared<DeviceContext>(instance_context, *physical_context, - *pDevice, std::move(vtable))); + key, std::make_shared<DeviceContext>(context->instance, *context, + *pDevice, std::move(vtable))); return VK_SUCCESS; } @@ -358,10 +325,10 @@ static VKAPI_ATTR void VKAPI_CALL GetDeviceQueue(VkDevice device, std::uint32_t queue_family_index, std::uint32_t queue_index, VkQueue* queue) { - const auto device_context = layer_context.get_context(device); + const auto context = layer_context.get_context(device); - device_context->vtable.GetDeviceQueue(device, queue_family_index, - queue_index, queue); + context->vtable.GetDeviceQueue(device, queue_family_index, queue_index, + queue); if (!queue || !*queue) { return; } @@ -373,7 +340,7 @@ GetDeviceQueue(VkDevice device, std::uint32_t queue_family_index, const auto lock = std::scoped_lock{layer_context.mutex}; const auto [it, inserted] = layer_context.contexts.try_emplace(key); if (inserted) { - it->second = std::make_shared<QueueContext>(*device_context, *queue, + it->second = std::make_shared<QueueContext>(*context, *queue, queue_family_index); } @@ -381,16 +348,16 @@ GetDeviceQueue(VkDevice device, std::uint32_t queue_family_index, // but this is expected. const auto ptr = std::dynamic_pointer_cast<QueueContext>(it->second); assert(ptr); - device_context->queues.emplace(*queue, ptr); + context->queues.emplace(*queue, ptr); } // Identical logic to gdq1. static VKAPI_ATTR void VKAPI_CALL GetDeviceQueue2( VkDevice device, const VkDeviceQueueInfo2* info, VkQueue* queue) { - const auto device_context = layer_context.get_context(device); + const auto context = layer_context.get_context(device); - device_context->vtable.GetDeviceQueue2(device, info, queue); + context->vtable.GetDeviceQueue2(device, info, queue); if (!queue || !*queue) { return; } @@ -399,13 +366,13 @@ static VKAPI_ATTR void VKAPI_CALL GetDeviceQueue2( const auto lock = std::scoped_lock{layer_context.mutex}; const auto [it, inserted] = layer_context.contexts.try_emplace(key); if (inserted) { - it->second = std::make_shared<QueueContext>(*device_context, *queue, + it->second = std::make_shared<QueueContext>(*context, *queue, info->queueFamilyIndex); } const auto ptr = std::dynamic_pointer_cast<QueueContext>(it->second); assert(ptr); - device_context->queues.emplace(*queue, ptr); + context->queues.emplace(*queue, ptr); } static VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImageKHR( @@ -413,6 +380,7 @@ static VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImageKHR( VkSemaphore semaphore, VkFence fence, std::uint32_t* pImageIndex) { const auto context = layer_context.get_context(device); + if (const auto result = context->vtable.AcquireNextImageKHR( device, swapchain, timeout, semaphore, fence, pImageIndex); result != VK_SUCCESS) { @@ -430,6 +398,7 @@ static VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImage2KHR( std::uint32_t* pImageIndex) { const auto context = layer_context.get_context(device); + if (const auto result = context->vtable.AcquireNextImage2KHR( device, pAcquireInfo, pImageIndex); result != VK_SUCCESS) { @@ -447,36 +416,38 @@ static VKAPI_ATTR VkResult VKAPI_CALL vkQueueSubmit(VkQueue queue, std::uint32_t submit_count, const VkSubmitInfo* submit_infos, VkFence fence) { - const auto& queue_context = layer_context.get_context(queue); - const auto& vtable = queue_context->device_context.vtable; + const auto context = layer_context.get_context(queue); + + const auto& vtable = context->device_context.vtable; - if (!submit_count || !queue_context->should_inject_timestamps()) { + if (!submit_count || !context->should_inject_timestamps()) { return vtable.QueueSubmit(queue, submit_count, submit_infos, fence); } // What's happening here? // We are making a very modest modification to all vkQueueSubmits where we // inject a start and end timestamp query command buffer that writes when - // the GPU started and finished work for each submission. It's important to - // note that we deliberately do *NOT* use or modify any semaphores - // as a mechanism to signal completion or the availability of these submits - // for multiple reasons: + // the GPU started and finished work for each submission. Note, we do *NOT* + // use or modify any semaphores as a mechanism to signal completion or the + // availability of these submits for multiple reasons: // 1. Modifying semaphores (particuarly in vkQueueSubmit1) is ANNOYING // done correctly. The pNext chain is const and difficult to modify // without traversing the entire thing and doing surgical deep copies // and patches for multiple pNext's sType's. It's easier to leave it - // alone. + // alone. If we do edit them it's either a maintenance nightmare or + // an illegal const cast timebomb that breaks valid vulkan + // applications that pass truly read only vkSubmitInfo->pNext's. // 2. Semaphores only signal at the end of their work, so we cannot use // them as a mechanism to know if work has started without doing - // another dummy submission. This adds complexity and also might - // skew our timestamps slightly as they wouldn't be a part of the - // submission which contained those command buffers. + // another dummy submission. If we did this it adds complexity and + // also might skew our timestamps slightly as they wouldn't be a part + // of the submission which contained those command buffers. // 3. Timestamps support querying if their work has started/ended // as long as we use the vkHostQueryReset extension to reset them // before we consider them queryable. This means we don't need a - // 'is it valid to query' timeline semaphore. + // 'is it valid to query my timestamps' timeline semaphore. // 4. The performance impact of using semaphores vs timestamps is - // negligable. + // negligible. using cbs_t = std::vector<VkCommandBuffer>; auto next_submits = std::vector<VkSubmitInfo>{}; @@ -496,10 +467,10 @@ vkQueueSubmit(VkQueue queue, std::uint32_t submit_count, std::ranges::transform( std::span{submit_infos, submit_count}, std::back_inserter(next_submits), [&](const auto& submit) { - const auto head_handle = queue_context->timestamp_pool->acquire(); - const auto tail_handle = queue_context->timestamp_pool->acquire(); - head_handle->setup_command_buffers(*tail_handle, *queue_context); - queue_context->notify_submit(submit, head_handle, tail_handle, now); + const auto head_handle = context->timestamp_pool->acquire(); + const auto tail_handle = context->timestamp_pool->acquire(); + head_handle->setup_command_buffers(*tail_handle, *context); + context->notify_submit(submit, head_handle, tail_handle, now); handles.emplace_back(head_handle); handles.emplace_back(tail_handle); @@ -528,10 +499,11 @@ static VKAPI_ATTR VkResult VKAPI_CALL vkQueueSubmit2(VkQueue queue, std::uint32_t submit_count, const VkSubmitInfo2* submit_infos, VkFence fence) { - const auto& queue_context = layer_context.get_context(queue); - const auto& vtable = queue_context->device_context.vtable; + const auto context = layer_context.get_context(queue); - if (!submit_count || !queue_context->should_inject_timestamps()) { + const auto& vtable = context->device_context.vtable; + + if (!submit_count || !context->should_inject_timestamps()) { return vtable.QueueSubmit2(queue, submit_count, submit_infos, fence); } @@ -545,10 +517,10 @@ vkQueueSubmit2(VkQueue queue, std::uint32_t submit_count, std::ranges::transform( std::span{submit_infos, submit_count}, std::back_inserter(next_submits), [&](const auto& submit) { - const auto head_handle = queue_context->timestamp_pool->acquire(); - const auto tail_handle = queue_context->timestamp_pool->acquire(); - head_handle->setup_command_buffers(*tail_handle, *queue_context); - queue_context->notify_submit(submit, head_handle, tail_handle, now); + const auto head_handle = context->timestamp_pool->acquire(); + const auto tail_handle = context->timestamp_pool->acquire(); + head_handle->setup_command_buffers(*tail_handle, *context); + context->notify_submit(submit, head_handle, tail_handle, now); handles.emplace_back(head_handle); handles.emplace_back(tail_handle); @@ -588,8 +560,9 @@ vkQueueSubmit2KHR(VkQueue queue, std::uint32_t submit_count, static VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { - const auto queue_context = layer_context.get_context(queue); - const auto& vtable = queue_context->device_context.vtable; + const auto context = layer_context.get_context(queue); + + const auto& vtable = context->device_context.vtable; if (const auto res = vtable.QueuePresentKHR(queue, present_info); res != VK_SUCCESS) { @@ -597,7 +570,7 @@ vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { return res; } - queue_context->notify_present(*present_info); + context->notify_present(*present_info); return VK_SUCCESS; } @@ -606,9 +579,9 @@ static VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceExtensionProperties( VkPhysicalDevice physical_device, const char* pLayerName, std::uint32_t* pPropertyCount, VkExtensionProperties* pProperties) { - const auto physical_context = layer_context.get_context(physical_device); - const auto& instance = physical_context->instance; - const auto& vtable = instance.vtable; + const auto context = layer_context.get_context(physical_device); + + const auto& vtable = context->instance.vtable; // Not asking about our layer - just forward it. if (!pLayerName || std::string_view{pLayerName} != LAYER_NAME) { @@ -623,46 +596,44 @@ static VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceExtensionProperties( return VK_SUCCESS; } - // Defensive - they gave us zero space to work with. if (!count) { - return VK_INCOMPLETE; + return VK_INCOMPLETE; // They gave us zero space to work with. } pProperties[0] = VkExtensionProperties{.extensionName = VK_AMD_ANTI_LAG_EXTENSION_NAME, .specVersion = VK_AMD_ANTI_LAG_SPEC_VERSION}; count = 1; - return VK_SUCCESS; } static VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceFeatures2( VkPhysicalDevice physical_device, VkPhysicalDeviceFeatures2* pFeatures) { - const auto physical_context = layer_context.get_context(physical_device); - const auto& vtable = physical_context->instance.vtable; + const auto context = layer_context.get_context(physical_device); + + const auto& vtable = context->instance.vtable; vtable.GetPhysicalDeviceFeatures2(physical_device, pFeatures); - if (const auto feature = find_next<VkPhysicalDeviceAntiLagFeaturesAMD>( - pFeatures->pNext, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ANTI_LAG_FEATURES_AMD); - feature) { + const auto feature = find_next<VkPhysicalDeviceAntiLagFeaturesAMD>( + pFeatures->pNext, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ANTI_LAG_FEATURES_AMD); - feature->antiLag = true; + if (feature) { + feature->antiLag = context->supports_required_extensions; } } static VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceFeatures2KHR( VkPhysicalDevice physical_device, VkPhysicalDeviceFeatures2KHR* pFeatures) { - // forward return low_latency::GetPhysicalDeviceFeatures2(physical_device, pFeatures); } static VKAPI_ATTR void VKAPI_CALL AntiLagUpdateAMD(VkDevice device, const VkAntiLagDataAMD* pData) { - const auto device_context = layer_context.get_context(device); - device_context->notify_antilag_update(*pData); + const auto context = layer_context.get_context(device); + context->notify_antilag_update(*pData); } } // namespace low_latency @@ -724,9 +695,8 @@ LowLatency_GetDeviceProcAddr(VkDevice device, const char* const pName) { return it->second; } - using namespace low_latency; - const auto& vtable = layer_context.get_context(device)->vtable; - return vtable.GetDeviceProcAddr(device, pName); + const auto context = low_latency::layer_context.get_context(device); + return context->vtable.GetDeviceProcAddr(device, pName); } VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL @@ -737,7 +707,6 @@ LowLatency_GetInstanceProcAddr(VkInstance instance, const char* const pName) { return it->second; } - using namespace low_latency; - const auto& vtable = layer_context.get_context(instance)->vtable; - return vtable.GetInstanceProcAddr(instance, pName); + const auto context = low_latency::layer_context.get_context(instance); + return context->vtable.GetInstanceProcAddr(instance, pName); } diff --git a/src/physical_device_context.cc b/src/physical_device_context.cc index 45be10e..de63b3d 100644 --- a/src/physical_device_context.cc +++ b/src/physical_device_context.cc @@ -1,6 +1,11 @@ #include "physical_device_context.hh" #include <vulkan/vulkan_core.h> +#include <ranges> +#include <string_view> +#include <unordered_set> +#include <vector> + namespace low_latency { PhysicalDeviceContext::PhysicalDeviceContext( @@ -29,6 +34,27 @@ PhysicalDeviceContext::PhysicalDeviceContext( return std::make_unique<qp_t>(std::move(result)); }(); + + this->supports_required_extensions = [&]() { + auto count = std::uint32_t{}; + vtable.EnumerateDeviceExtensionProperties(physical_device, nullptr, + &count, nullptr); + + auto supported_extensions = std::vector<VkExtensionProperties>(count); + vtable.EnumerateDeviceExtensionProperties( + physical_device, nullptr, &count, std::data(supported_extensions)); + + const auto supported_extension_names = + supported_extensions | + std::views::transform( + [](const auto& supported) { return supported.extensionName; }) | + std::ranges::to<std::unordered_set<std::string_view>>(); + + return std::ranges::all_of( + this->required_extensions, [&](const auto& required_extension) { + return supported_extension_names.contains(required_extension); + }); + }(); } PhysicalDeviceContext::~PhysicalDeviceContext() {} diff --git a/src/physical_device_context.hh b/src/physical_device_context.hh index 291946f..9624faa 100644 --- a/src/physical_device_context.hh +++ b/src/physical_device_context.hh @@ -11,15 +11,28 @@ namespace low_latency { class PhysicalDeviceContext final : public Context { public: + // The extensions we need for our layer to function. + // If the PD doesn't support this then the layer shouldn't set the anti lag + // flag in VkGetPhysicalDevices2 (check this->supports_required_extensions). + static constexpr auto required_extensions = { + VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME, + VK_KHR_CALIBRATED_TIMESTAMPS_EXTENSION_NAME, + VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME}; + + public: InstanceContext& instance; const VkPhysicalDevice physical_device; - + std::unique_ptr<const VkPhysicalDeviceProperties> properties; - + using queue_properties_t = std::vector<VkQueueFamilyProperties2>; std::unique_ptr<const queue_properties_t> queue_properties; + // Will be set to true in the constructor if the physical device supports + // everything we need to track gpu timing data. + bool supports_required_extensions = false; + public: PhysicalDeviceContext(InstanceContext& instance_context, const VkPhysicalDevice& physical_device); diff --git a/src/queue_context.cc b/src/queue_context.cc index 1f798de..2096df3 100644 --- a/src/queue_context.cc +++ b/src/queue_context.cc @@ -33,11 +33,13 @@ QueueContext::QueueContext(DeviceContext& device_context, const VkQueue& queue, return command_pool; }(); - this->timestamp_pool = std::make_unique<TimestampPool>(*this); + // Only construct a timestamp pool if we support it! + if (device_context.physical_device.supports_required_extensions) { + this->timestamp_pool = std::make_unique<TimestampPool>(*this); + } } QueueContext::~QueueContext() { - this->in_flight_frames.clear(); this->submissions.clear(); this->timestamp_pool.reset(); @@ -182,7 +184,7 @@ void QueueContext::drain_frames_to_timings() { // Only need to calibrate this device, we don't support multi device anti // lag. - this->device_context.clock.calibrate(); + this->device_context.clock->calibrate(); while (std::size(this->in_flight_frames)) { const auto& frame = this->in_flight_frames.front(); @@ -378,6 +380,10 @@ void QueueContext::sleep_in_present() { bool QueueContext::should_inject_timestamps() const { const auto& pd = this->device_context.physical_device; + if (!pd.supports_required_extensions) { + return false; + } + assert(pd.queue_properties); const auto& queue_props = *pd.queue_properties; assert(this->queue_family_index < std::size(queue_props)); diff --git a/src/timestamp_pool.cc b/src/timestamp_pool.cc index e8ef9f5..7230bb9 100644 --- a/src/timestamp_pool.cc +++ b/src/timestamp_pool.cc @@ -148,7 +148,7 @@ TimestampPool::Handle::get_time() { return std::nullopt; } - return device_ctx.clock.ticks_to_time(query_result.value); + return device_ctx.clock->ticks_to_time(query_result.value); } std::optional<DeviceContext::Clock::time_point_t> |
