From cf0bced6cd86782e9706acda1b3b6ce6b4e98481 Mon Sep 17 00:00:00 2001 From: Nicolas James Date: Sun, 5 Apr 2026 22:01:11 +1000 Subject: Implement refactored AL2, todo frame limit --- src/layer.cc | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) (limited to 'src/layer.cc') diff --git a/src/layer.cc b/src/layer.cc index 516f9d3..627fee2 100644 --- a/src/layer.cc +++ b/src/layer.cc @@ -20,6 +20,7 @@ #include "instance_context.hh" #include "layer_context.hh" #include "queue_context.hh" +#include "strategies/anti_lag/device_strategy.hh" #include "timestamp_pool.hh" namespace low_latency { @@ -307,7 +308,7 @@ GetDeviceQueue(VkDevice device, std::uint32_t queue_family_index, // insert a nullptr key, then it didn't already exist so we should // construct a new one. const auto key = layer_context.get_key(*queue); - const auto lock = std::scoped_lock{layer_context.mutex}; + const auto layer_lock = std::scoped_lock{layer_context.mutex}; const auto [it, inserted] = layer_context.contexts.try_emplace(key); if (inserted) { it->second = std::make_shared(*context, *queue, @@ -317,6 +318,7 @@ GetDeviceQueue(VkDevice device, std::uint32_t queue_family_index, // it->second should be QueueContext, also it might already be there. const auto ptr = std::dynamic_pointer_cast(it->second); assert(ptr); + const auto device_lock = std::scoped_lock{context->mutex}; context->queues.emplace(*queue, ptr); } @@ -341,6 +343,7 @@ static VKAPI_ATTR void VKAPI_CALL GetDeviceQueue2( const auto ptr = std::dynamic_pointer_cast(it->second); assert(ptr); + const auto device_lock = std::scoped_lock{context->mutex}; context->queues.emplace(*queue, ptr); } @@ -400,10 +403,16 @@ vkQueueSubmit(VkQueue queue, std::uint32_t submit_count, [&](const auto& submit) { const auto head_handle = context->timestamp_pool->acquire(); head_handle->write_command(VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT); - const auto tail_handle = context->timestamp_pool->acquire(); tail_handle->write_command(VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT); + context->strategy->notify_submit( + submit, std::make_unique(Submission{ + .start = head_handle, + .end = tail_handle, + .time = now, + })); + handles.emplace_back(head_handle); handles.emplace_back(tail_handle); next_cbs.emplace_back([&]() -> auto { @@ -445,7 +454,7 @@ vkQueueSubmit2(VkQueue queue, std::uint32_t submit_count, auto next_cbs = std::vector>{}; auto handles = std::vector>{}; - [[maybe_unused]] const auto now = DeviceClock::now(); + const auto now = DeviceClock::now(); std::ranges::transform( std::span{submit_infos, submit_count}, std::back_inserter(next_submits), @@ -455,6 +464,13 @@ vkQueueSubmit2(VkQueue queue, std::uint32_t submit_count, const auto tail_handle = context->timestamp_pool->acquire(); tail_handle->write_command(VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT); + context->strategy->notify_submit( + submit, std::make_unique(Submission{ + .start = head_handle, + .end = tail_handle, + .time = now, + })); + handles.emplace_back(head_handle); handles.emplace_back(tail_handle); next_cbs.emplace_back([&]() -> auto { @@ -786,25 +802,10 @@ AntiLagUpdateAMD(VkDevice device, const VkAntiLagDataAMD* pData) { const auto context = layer_context.get_context(device); assert(pData); - // AL2 is a synchronous while NVIDIA's low_latencty2 is asynchronous. - // It's difficult to model an asynchronous impl inside a synchronous impl, - // but it's easy to do the inverse. AMD's extension piggybacks on NVIDIA's - // more complicated implementation. - - [[maybe_unused]] const auto present_delay = - [&]() -> std::chrono::milliseconds { - using namespace std::chrono; - if (!pData->maxFPS) { - return 0ms; - } - return duration_cast(1s / pData->maxFPS); - }(); - - if (!pData->pPresentationInfo || - pData->pPresentationInfo->stage != VK_ANTI_LAG_STAGE_INPUT_AMD) { - - return; - } + const auto strategy = + dynamic_cast(context->strategy.get()); + assert(strategy); + strategy->notify_update(*pData); } VkResult LatencySleepNV(VkDevice device, -- cgit v1.2.3