mirror of
https://github.com/optiscaler/OptiScaler.git
synced 2026-09-24 22:35:57 +00:00
Add support for Vulkan AntiLag
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
};
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
Reference in New Issue
Block a user