Add support for Vulkan AntiLag

This commit is contained in:
FakeMichau
2025-06-13 00:26:46 +02:00
parent 41a2204b0b
commit 196cc83126
14 changed files with 236 additions and 14 deletions
+1 -1
View File
@@ -106,7 +106,7 @@ void AntiLag2::sleep() {
al2_sleep();
}
void AntiLag2::set_marker(MarkerParams* marker_params) {
void AntiLag2::set_marker(IUnknown* pDevice, MarkerParams* marker_params) {
switch(marker_params->marker_type) {
case MarkerType::SIMULATION_START:
if (current_call_spot == CallSpot::SimulationStart)
+1 -1
View File
@@ -32,6 +32,6 @@ public:
void get_sleep_status(SleepParams* sleep_params) override;
void set_sleep_mode(SleepMode* sleep_mode) override;
void sleep() override;
void set_marker(MarkerParams* marker_params) override;
void set_marker(IUnknown* pDevice, MarkerParams* marker_params) override;
void set_async_marker(MarkerParams* marker_params) override;
};
@@ -0,0 +1,87 @@
#include "ll_antilag_vk.h"
#include "vulkan_hooks.h"
bool AntiLagVk::init(IUnknown* pDevice) {
return VulkanHooks::o_vkAntiLagUpdateAMD != nullptr;
}
void* AntiLagVk::get_tech_context() {
return nullptr;
}
void AntiLagVk::get_sleep_status(SleepParams* sleep_params) {
sleep_params->low_latency_enabled = is_enabled();
sleep_params->fullscreen_vrr = true;
sleep_params->control_panel_vsync_override = false;
}
void AntiLagVk::set_sleep_mode(SleepMode* sleep_mode) {
// UNUSED:
// low_latency_boost
// use_markers_to_optimize
low_latency_enabled = sleep_mode->low_latency_enabled;
minimum_interval_us = sleep_mode->minimum_interval_us; // don't convert to fps due to fg fps limit fallback using intervals
}
void AntiLagVk::sleep() {
// This can be supported but prefer using markers with frame ids instead
return;
}
void AntiLagVk::set_marker(IUnknown* pDevice, MarkerParams* marker_params) {
auto mode = is_enabled() ? VK_ANTI_LAG_MODE_ON_AMD : VK_ANTI_LAG_MODE_OFF_AMD;
auto max_fps = minimum_interval_us > 0 ? (uint32_t) std::round(1000000.0f / minimum_interval_us) : 0;
if (marker_params->marker_type == MarkerType::SIMULATION_START)
{
// Before processing user input
VkAntiLagPresentationInfoAMD inputInfo = {};
inputInfo.sType = VK_STRUCTURE_TYPE_ANTI_LAG_PRESENTATION_INFO_AMD;
inputInfo.stage = VK_ANTI_LAG_STAGE_INPUT_AMD;
inputInfo.frameIndex = marker_params->frame_id;
VkAntiLagDataAMD antiLagDataInput = {};
antiLagDataInput.sType = VK_STRUCTURE_TYPE_ANTI_LAG_DATA_AMD;
antiLagDataInput.mode = mode;
antiLagDataInput.pPresentationInfo = &inputInfo;
antiLagDataInput.maxFPS = max_fps; // Or your desired FPS cap
if (VulkanHooks::o_vkAntiLagUpdateAMD)
{
spdlog::trace("AntiLag Input: {}, status: {}", marker_params->frame_id, is_enabled());
VulkanHooks::o_vkAntiLagUpdateAMD((VkDevice)pDevice, &antiLagDataInput);
}
}
if (marker_params->marker_type == MarkerType::PRESENT_START)
{
// Before calling vkQueuePresentKHR
VkAntiLagPresentationInfoAMD presentInfo = {};
presentInfo.sType = VK_STRUCTURE_TYPE_ANTI_LAG_PRESENTATION_INFO_AMD;
presentInfo.stage = VK_ANTI_LAG_STAGE_PRESENT_AMD;
presentInfo.frameIndex = marker_params->frame_id;
VkAntiLagDataAMD antiLagDataPresent = {};
antiLagDataPresent.sType = VK_STRUCTURE_TYPE_ANTI_LAG_DATA_AMD;
antiLagDataPresent.mode = mode;
antiLagDataPresent.pPresentationInfo = &presentInfo;
antiLagDataPresent.maxFPS = max_fps; // Or your desired FPS cap
if (VulkanHooks::o_vkAntiLagUpdateAMD)
{
spdlog::trace("AntiLag Present: {}, status: {}", marker_params->frame_id, is_enabled());
VulkanHooks::o_vkAntiLagUpdateAMD((VkDevice)pDevice, &antiLagDataPresent);
}
}
}
void AntiLagVk::set_async_marker(MarkerParams* marker_params) {
if (marker_params->marker_type == MarkerType::OUT_OF_BAND_PRESENT_START) {
static uint64_t previous_frame_id = marker_params->frame_id;
set_fg_type(previous_frame_id == marker_params->frame_id, marker_params->frame_id);
previous_frame_id = marker_params->frame_id;
}
}
@@ -0,0 +1,29 @@
#pragma once
#include "low_latency_tech.h"
class AntiLagVk : public virtual LowLatencyTech {
private:
uint32_t minimum_interval_us = 0;
public:
AntiLagVk(): LowLatencyTech() {}
// From LowLatencyTech
bool init(IUnknown *pDevice) override;
void deinit() override {}; // Not used by AntiLag VK
Mode get_mode() override { return Mode::AntiLagVk; };
void* get_tech_context() override;
void set_fg_type(bool interpolated, uint64_t frame_id) override {}; // Not used by AntiLag VK
void set_low_latency_override(ForceReflex low_latency_override) override { this->low_latency_override = low_latency_override; };
void set_effective_fg_state(bool effective_fg_state) override { this->effective_fg_state = effective_fg_state; };
bool is_enabled() override { return low_latency_override != ForceReflex::InGame ? low_latency_override == ForceReflex::ForceEnable : low_latency_enabled; };
void get_sleep_status(SleepParams* sleep_params) override;
void set_sleep_mode(SleepMode* sleep_mode) override;
void sleep() override;
void set_marker(IUnknown* pDevice, MarkerParams* marker_params) override;
void set_async_marker(MarkerParams* marker_params) override;
};
@@ -117,7 +117,7 @@ void LatencyFlex::sleep() {
lfx_sleep(INVALID_ID);
};
void LatencyFlex::set_marker(MarkerParams* marker_params) {
void LatencyFlex::set_marker(IUnknown* pDevice, MarkerParams* marker_params) {
switch(marker_params->marker_type) {
case MarkerType::SIMULATION_START:
if (current_call_spot == CallSpot::SimulationStart)
+1 -1
View File
@@ -39,6 +39,6 @@ public:
void get_sleep_status(SleepParams* sleep_params) override;
void set_sleep_mode(SleepMode* sleep_mode) override;
void sleep() override;
void set_marker(MarkerParams* marker_params) override;
void set_marker(IUnknown* pDevice, MarkerParams* marker_params) override;
void set_async_marker(MarkerParams* marker_params) override {}; // Not used by LFX
};
+1 -1
View File
@@ -133,7 +133,7 @@ void XeLL::set_sleep_mode(SleepMode* sleep_mode) {
auto result = o_xellSetSleepMode(ctx, &xell_sleep_params);
}
void XeLL::set_marker(MarkerParams* marker_params) {
void XeLL::set_marker(IUnknown* pDevice, MarkerParams* marker_params) {
switch (marker_params->marker_type) {
case MarkerType::SIMULATION_START:
xell_sleep(marker_params->frame_id);
+1 -1
View File
@@ -43,6 +43,6 @@ public:
void get_sleep_status(SleepParams* sleep_params) override;
void set_sleep_mode(SleepMode* sleep_mode) override;
void sleep() override {}; // Not used by XeLL due to missing frame ids
void set_marker(MarkerParams* marker_params) override;
void set_marker(IUnknown* pDevice, MarkerParams* marker_params) override;
void set_async_marker(MarkerParams* marker_params) override {}; // Not used by XeLL
};
+15 -3
View File
@@ -1,5 +1,6 @@
#include "low_latency.h"
#include "ll_antilag2.h"
#include "ll_antilag_vk.h"
#include "ll_latencyflex.h"
#include "ll_xell.h"
@@ -65,9 +66,19 @@ bool LowLatency::update_low_latency_tech(IUnknown* pDevice) {
bool LowLatency::update_low_latency_tech(HANDLE vkDevice) {
if (!currently_active_tech) {
if (!Config::get().get_force_latencyflex()) {
currently_active_tech = new AntiLagVk();
if (currently_active_tech->init(nullptr)) {
spdlog::info("LowLatency algo: AntiLag Vulkan");
return true;
}
delete currently_active_tech;
}
currently_active_tech = new LatencyFlex();
if (currently_active_tech->init(nullptr)) {
spdlog::debug("LowLatency algo: LatencyFlex");
spdlog::info("LowLatency algo: LatencyFlex");
return true;
}
}
@@ -354,7 +365,7 @@ NvAPI_Status LowLatency::SetLatencyMarker(IUnknown* pDev, NV_LATENCY_MARKER_PARA
marker_params.frame_id = pSetLatencyMarkerParams->frameID;
marker_params.marker_type = (MarkerType) pSetLatencyMarkerParams->markerType; // requires enums to match
currently_active_tech->set_marker(&marker_params);
currently_active_tech->set_marker(pDev, &marker_params);
spdlog::trace("{}: {}", marker_to_name(pSetLatencyMarkerParams->markerType), pSetLatencyMarkerParams->frameID);
@@ -376,7 +387,8 @@ NvAPI_Status LowLatency::SetLatencyMarker(HANDLE vkDevice, NV_VULKAN_LATENCY_MAR
marker_params.frame_id = pSetLatencyMarkerParams->frameID;
marker_params.marker_type = (MarkerType) pSetLatencyMarkerParams->markerType; // requires enums to match
currently_active_tech->set_marker(&marker_params);
// This cast is not ideal as it needs to be cast to VkDevice while knowing it's vulkan
currently_active_tech->set_marker((IUnknown*)vkDevice, &marker_params);
spdlog::trace("{}: {}", marker_to_name(pSetLatencyMarkerParams->markerType), pSetLatencyMarkerParams->frameID);
@@ -14,7 +14,8 @@
enum class Mode {
AntiLag2,
LatencyFlex,
XeLL
XeLL,
AntiLagVk
};
enum class CallSpot {
@@ -87,6 +88,6 @@ public:
virtual void get_sleep_status(SleepParams* sleep_params) = 0;
virtual void set_sleep_mode(SleepMode* sleep_mode) = 0;
virtual void sleep() = 0;
virtual void set_marker(MarkerParams* marker_params) = 0;
virtual void set_marker(IUnknown* pDevice, MarkerParams* marker_params) = 0;
virtual void set_async_marker(MarkerParams* marker_params) = 0;
};
+7
View File
@@ -11,6 +11,7 @@
#endif
#include "../external/nvapi/nvapi.h"
#include "fakenvapi.h"
#include "vulkan_hooks.h"
#include "../version.h"
#include "log.h"
@@ -37,6 +38,12 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
spdlog::info("Config lfx_mode: {}", (int)Config::get().get_latencyflex_mode());
spdlog::info("Config save_pcl_to_file: {}", Config::get().get_save_pcl_to_file() ? "true" : "false");
{
// TODO: won't work for late loaded vulkan-1.dll
auto vulkan_module = GetModuleHandleA("vulkan-1.dll");
VulkanHooks::hook_vulkan(vulkan_module);
}
break;
case DLL_PROCESS_DETACH:
LowLatencyCtx::get()->deinit_current_tech();
+3 -3
View File
@@ -1,9 +1,9 @@
dll = shared_library(
'nvapi'+target_suffix,
['main.cpp', 'fakenvapi.cpp', 'low_latency.cpp', 'low_latency_tech.cpp', 'll_antilag2.cpp', 'll_xell.cpp', 'll_latencyflex.cpp', 'util.cpp', 'log.cpp', fakenvapi_version],
['main.cpp', 'fakenvapi.cpp', 'low_latency.cpp', 'low_latency_tech.cpp', 'll_antilag2.cpp', 'll_antilag_vk.cpp', 'll_xell.cpp', 'll_latencyflex.cpp', 'vulkan_hooks.cpp', 'util.cpp', 'log.cpp', fakenvapi_version],
rc,
name_prefix : '',
dependencies : [ lib_dxgi ],
include_directories: [ spdlog_headers, xell_headers ],
dependencies : [ lib_dxgi, lib_detours ],
include_directories: [ spdlog_headers, xell_headers, detours_headers, vulkan_headers ],
install: true
)
@@ -0,0 +1,67 @@
#include "vulkan_hooks.h"
#include <detours.h>
#include <vulkan/vulkan_core.h>
#include <vector>
PFN_vkCreateDevice VulkanHooks::o_vkCreateDevice = nullptr;
PFN_vkGetPhysicalDeviceFeatures2 VulkanHooks::o_vkGetPhysicalDeviceFeatures2 = nullptr;
PFN_vkGetDeviceProcAddr VulkanHooks::o_vkGetDeviceProcAddr = nullptr;
PFN_vkAntiLagUpdateAMD VulkanHooks::o_vkAntiLagUpdateAMD = nullptr;
VkResult VulkanHooks::hkvkCreateDevice(VkPhysicalDevice physicalDevice, VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice) {
spdlog::debug("hkvkCreateDevice");
std::vector<const char*> extensions(pCreateInfo->ppEnabledExtensionNames, pCreateInfo->ppEnabledExtensionNames + pCreateInfo->enabledExtensionCount);
// AntiLag
bool antiLagSupported = false;
VkPhysicalDeviceFeatures2 features2 = {};
features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
VkPhysicalDeviceAntiLagFeaturesAMD antiLagFeatures = {};
antiLagFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ANTI_LAG_FEATURES_AMD;
features2.pNext = &antiLagFeatures;
if (o_vkGetPhysicalDeviceFeatures2) {
o_vkGetPhysicalDeviceFeatures2(physicalDevice, &features2);
if (antiLagFeatures.antiLag) {
antiLagSupported = true;
spdlog::info("Adding AntiLag extension");
extensions.push_back(VK_AMD_ANTI_LAG_EXTENSION_NAME);
}
}
// TODO add check for VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME as AntiLag doesn't support it
pCreateInfo->enabledExtensionCount = static_cast<uint32_t>(extensions.size());
pCreateInfo->ppEnabledExtensionNames = extensions.data();
auto result = o_vkCreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice);
// Can ask for a function from an extension after the device creation
if (antiLagSupported && o_vkGetDeviceProcAddr) {
o_vkAntiLagUpdateAMD = (PFN_vkAntiLagUpdateAMD) o_vkGetDeviceProcAddr(*pDevice, "vkAntiLagUpdateAMD");
} else {
spdlog::info("Vulkan AntiLag can't be enabled");
}
return result;
}
void VulkanHooks::hook_vulkan(HMODULE vulkanModule) {
spdlog::debug("Trying to hook Vulkan");
o_vkCreateDevice = (PFN_vkCreateDevice) GetProcAddress(vulkanModule, "vkCreateDevice");
o_vkGetPhysicalDeviceFeatures2 = (PFN_vkGetPhysicalDeviceFeatures2) GetProcAddress(vulkanModule, "vkGetPhysicalDeviceFeatures2");
o_vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr) GetProcAddress(vulkanModule, "vkGetDeviceProcAddr");
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
if (o_vkCreateDevice)
DetourAttach(&(PVOID&) o_vkCreateDevice, hkvkCreateDevice);
DetourTransactionCommit();
}
+19
View File
@@ -0,0 +1,19 @@
#pragma once
#include "log.h"
#include <detours.h>
#include <vulkan/vulkan_core.h>
#include <vector>
class VulkanHooks {
private:
static PFN_vkCreateDevice o_vkCreateDevice;
static PFN_vkGetPhysicalDeviceFeatures2 o_vkGetPhysicalDeviceFeatures2;
static PFN_vkGetDeviceProcAddr o_vkGetDeviceProcAddr;
public:
static PFN_vkAntiLagUpdateAMD o_vkAntiLagUpdateAMD;
static void hook_vulkan(HMODULE vulkanModule);
static VkResult hkvkCreateDevice(VkPhysicalDevice physicalDevice, VkDeviceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDevice *pDevice);
};