mirror of
https://github.com/optiscaler/OptiScaler.git
synced 2026-08-28 17:16:46 +00:00
Fix slDLSSGSetOptions hooks when using steam overlay; force DLSSG Auto to always mean On; marker fix for Roadcraft
This commit is contained in:
@@ -147,6 +147,7 @@ DEFINE_NAME_VECTORS(slInterposer, "sl.interposer");
|
||||
DEFINE_NAME_VECTORS(slDlss, "sl.dlss");
|
||||
DEFINE_NAME_VECTORS(slDlssg, "sl.dlss_g");
|
||||
DEFINE_NAME_VECTORS(slReflex, "sl.reflex");
|
||||
DEFINE_NAME_VECTORS(slPcl, "sl.pcl");
|
||||
DEFINE_NAME_VECTORS(slCommon, "sl.common");
|
||||
|
||||
DEFINE_NAME_VECTORS(xess, "libxess");
|
||||
|
||||
@@ -259,7 +259,7 @@ copy "$(SolutionDir)external\directx_agility_sdk\LICENSE.txt" $(SolutionDir)x64\
|
||||
copy NUL "$(SolutionDir)x64\Release\a\!! EXTRACT ALL FILES TO GAME FOLDER !!" /Y</Command>
|
||||
</PostBuildEvent>
|
||||
<PreBuildEvent>
|
||||
<Command>powershell -Command "$date = Get-Date -Format 'yyyyMMdd_HHmmss'; Set-Content -Path '$(ProjectDir)resource_build_date.h' -Value ('#define VER_BUILD_DATE ""' + $date + '"""')</Command>
|
||||
<Command>powershell -Command "Start-Sleep -Seconds 2; $date = Get-Date -Format 'yyyyMMdd_HHmmss'; Set-Content -Path '$(ProjectDir)resource_build_date.h' -Value ('#define VER_BUILD_DATE ""' + $date + '"""')</Command>
|
||||
</PreBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDebug|x64'">
|
||||
@@ -289,7 +289,7 @@ copy NUL "$(SolutionDir)x64\Release\a\!! EXTRACT ALL FILES TO GAME FOLDER !!" /Y
|
||||
<Command>powershell -Command "$timestamp = Get-Date -Format 'yyyyMMdd_HHmmss'; $fileName = '$(OutDir)OptiScaler_' + $timestamp + '.7z'; $backupFileName = '$(OutDir)OptiScaler_' + $timestamp + '_Backup.7z'; & '7z.exe' a -t7z $fileName '$(TargetPath)'; & '7z.exe' a -t7z $backupFileName '$(OutDir)$(TargetName).*'"</Command>
|
||||
</PostBuildEvent>
|
||||
<PreBuildEvent>
|
||||
<Command>powershell -Command "$date = Get-Date -Format 'yyyyMMdd_HHmmss'; Set-Content -Path '$(ProjectDir)resource_build_date.h' -Value ('#define VER_BUILD_DATE ""' + $date + '"""')</Command>
|
||||
<Command>powershell -Command "Start-Sleep -Seconds 2; $date = Get-Date -Format 'yyyyMMdd_HHmmss'; Set-Content -Path '$(ProjectDir)resource_build_date.h' -Value ('#define VER_BUILD_DATE ""' + $date + '"""')</Command>
|
||||
</PreBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
|
||||
+12
-3
@@ -18,15 +18,14 @@ typedef BOOL (*PFN_VerQueryValueW)(LPCVOID pBlock, LPCWSTR lpSubBlock, LPVOID* l
|
||||
/// <returns>Caller module filename</returns>
|
||||
std::string Util::WhoIsTheCaller(void* returnAddress)
|
||||
{
|
||||
HMODULE hModule = NULL;
|
||||
|
||||
char callerPath[MAX_PATH] = { 0 };
|
||||
|
||||
// Get the return address from the current function call.
|
||||
// void* returnAddress = _ReturnAddress();
|
||||
|
||||
// Get the base address of the module containing the return address.
|
||||
if (GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
||||
(LPCSTR) returnAddress, &hModule))
|
||||
if (HMODULE hModule = GetCallerModule(returnAddress); hModule != nullptr)
|
||||
{
|
||||
// Get the full path of the calling module.
|
||||
GetModuleFileNameA(hModule, callerPath, sizeof(callerPath));
|
||||
@@ -38,6 +37,16 @@ std::string Util::WhoIsTheCaller(void* returnAddress)
|
||||
return "";
|
||||
}
|
||||
|
||||
HMODULE Util::GetCallerModule(void* returnAddress)
|
||||
{
|
||||
HMODULE hModule = NULL;
|
||||
|
||||
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
||||
(LPCSTR) returnAddress, &hModule);
|
||||
|
||||
return hModule;
|
||||
}
|
||||
|
||||
std::wstring Util::GetWindowTitle(HWND hwnd)
|
||||
{
|
||||
const int maxLength = 512;
|
||||
|
||||
@@ -43,6 +43,7 @@ std::wstring GetWindowTitle(HWND hwnd);
|
||||
std::optional<std::filesystem::path> FindFilePath(const std::filesystem::path& startDir,
|
||||
const std::filesystem::path fileName);
|
||||
std::string WhoIsTheCaller(void* returnAddress);
|
||||
HMODULE GetCallerModule(void* returnAddress);
|
||||
MonitorInfo GetMonitorInfoForWindow(HWND hwnd);
|
||||
MonitorInfo GetMonitorInfoForOutput(IDXGIOutput* pOutput);
|
||||
|
||||
|
||||
@@ -818,6 +818,14 @@ static void CheckWorkingMode()
|
||||
StreamlineHooks::hookReflex(slReflex);
|
||||
}
|
||||
|
||||
HMODULE slPcl = nullptr;
|
||||
slPcl = GetDllNameWModule(&slPclNamesW);
|
||||
if (slPcl != nullptr)
|
||||
{
|
||||
LOG_DEBUG("sl.pcl.dll already in memory");
|
||||
StreamlineHooks::hookPcl(slPcl);
|
||||
}
|
||||
|
||||
HMODULE slCommon = nullptr;
|
||||
slCommon = GetDllNameWModule(&slCommonNamesW);
|
||||
if (slCommon != nullptr)
|
||||
|
||||
@@ -210,6 +210,23 @@ class KernelHooks
|
||||
return reflexModule;
|
||||
}
|
||||
|
||||
// sl.pcl.dll
|
||||
if (CheckDllName(&lcaseLibName, &slPclNames))
|
||||
{
|
||||
auto pclModule = KernelBaseProxy::LoadLibraryExA_()(lpLibFullPath, NULL, 0);
|
||||
|
||||
if (pclModule != nullptr)
|
||||
{
|
||||
StreamlineHooks::hookPcl(pclModule);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("Trying to load dll: {}", lcaseLibName);
|
||||
}
|
||||
|
||||
return pclModule;
|
||||
}
|
||||
|
||||
// sl.common.dll
|
||||
if (CheckDllName(&lcaseLibName, &slCommonNames))
|
||||
{
|
||||
@@ -683,6 +700,24 @@ class KernelHooks
|
||||
return reflexModule;
|
||||
}
|
||||
|
||||
// sl.pcl.dll
|
||||
if (CheckDllNameW(&lcaseLibName, &slPclNamesW) ||
|
||||
(lcaseLibName.contains(L"/versions/") && lcaseLibName.contains(L"/sl_pcl_")))
|
||||
{
|
||||
auto pclModule = KernelBaseProxy::LoadLibraryExW_()(lpLibFullPath, NULL, 0);
|
||||
|
||||
if (pclModule != nullptr)
|
||||
{
|
||||
StreamlineHooks::hookPcl(pclModule);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("Trying to load dll as sl.pcl: {}", lcaseLibNameA);
|
||||
}
|
||||
|
||||
return pclModule;
|
||||
}
|
||||
|
||||
// sl.common.dll
|
||||
if (CheckDllNameW(&lcaseLibName, &slCommonNamesW) ||
|
||||
(lcaseLibName.contains(L"/versions/") && lcaseLibName.contains(L"/sl_common_")))
|
||||
|
||||
@@ -24,6 +24,7 @@ decltype(&slAllocateResources) StreamlineHooks::o_slAllocateResources = nullptr;
|
||||
decltype(&slSetConstants) StreamlineHooks::o_slSetConstants = nullptr;
|
||||
decltype(&slGetNativeInterface) StreamlineHooks::o_slGetNativeInterface = nullptr;
|
||||
decltype(&slSetD3DDevice) StreamlineHooks::o_slSetD3DDevice = nullptr;
|
||||
decltype(&slGetNewFrameToken) StreamlineHooks::o_slGetNewFrameToken = nullptr;
|
||||
|
||||
decltype(&sl1::slInit) StreamlineHooks::o_slInit_sl1 = nullptr;
|
||||
|
||||
@@ -46,6 +47,10 @@ StreamlineHooks::PFN_slOnPluginLoad StreamlineHooks::o_reflex_slOnPluginLoad = n
|
||||
decltype(&slReflexSetOptions) StreamlineHooks::o_slReflexSetOptions = nullptr;
|
||||
sl::ReflexMode StreamlineHooks::reflexGamesLastMode = sl::ReflexMode::eOff;
|
||||
|
||||
// PCL
|
||||
StreamlineHooks::PFN_slGetPluginFunction StreamlineHooks::o_pcl_slGetPluginFunction = nullptr;
|
||||
decltype(&slPCLSetMarker) StreamlineHooks::o_slPCLSetMarker = nullptr;
|
||||
|
||||
// Common
|
||||
StreamlineHooks::PFN_slGetPluginFunction StreamlineHooks::o_common_slGetPluginFunction = nullptr;
|
||||
StreamlineHooks::PFN_slOnPluginLoad StreamlineHooks::o_common_slOnPluginLoad = nullptr;
|
||||
@@ -460,27 +465,27 @@ bool StreamlineHooks::hkcommon_slOnPluginLoad(void* params, const char* loaderJS
|
||||
|
||||
sl::Result StreamlineHooks::hkslDLSSGSetOptions(const sl::ViewportHandle& viewport, const sl::DLSSGOptions& options)
|
||||
{
|
||||
if (State::Instance().api != API::Vulkan)
|
||||
return o_slDLSSGSetOptions(viewport, options);
|
||||
// Make DLSSG auto always mean On
|
||||
sl::DLSSGOptions newOptions = options;
|
||||
newOptions.mode = newOptions.mode == sl::DLSSGMode::eOff ? sl::DLSSGMode::eOff : sl::DLSSGMode::eOn;
|
||||
|
||||
// Only matters for Vulkan, DX doesn't use this delay
|
||||
if (options.mode != sl::DLSSGMode::eOff && !MenuOverlayBase::IsVisible())
|
||||
State::Instance().delayMenuRenderBy = 10;
|
||||
|
||||
if (MenuOverlayBase::IsVisible())
|
||||
if (State::Instance().api == API::Vulkan)
|
||||
{
|
||||
sl::DLSSGOptions newOptions = options;
|
||||
newOptions.mode = sl::DLSSGMode::eOff;
|
||||
newOptions.flags |= sl::DLSSGFlags::eRetainResourcesWhenOff;
|
||||
// Only matters for Vulkan, DX doesn't use this delay
|
||||
if (options.mode != sl::DLSSGMode::eOff && !MenuOverlayBase::IsVisible())
|
||||
State::Instance().delayMenuRenderBy = 10;
|
||||
|
||||
LOG_TRACE("DLSSG Modified Mode: {}", (uint32_t) newOptions.mode);
|
||||
ReflexHooks::setDlssgDetectedState(false);
|
||||
return o_slDLSSGSetOptions(viewport, newOptions);
|
||||
if (MenuOverlayBase::IsVisible())
|
||||
{
|
||||
newOptions.mode = sl::DLSSGMode::eOff;
|
||||
newOptions.flags |= sl::DLSSGFlags::eRetainResourcesWhenOff;
|
||||
ReflexHooks::setDlssgDetectedState(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Can't tell if eAuto means enabled or disabled
|
||||
ReflexHooks::setDlssgDetectedState(options.mode == sl::DLSSGMode::eOn);
|
||||
return o_slDLSSGSetOptions(viewport, options);
|
||||
LOG_TRACE("DLSSG Modified Mode: {}", magic_enum::enum_name(newOptions.mode));
|
||||
|
||||
return o_slDLSSGSetOptions(viewport, newOptions);
|
||||
}
|
||||
|
||||
bool StreamlineHooks::hkreflex_slOnPluginLoad(void* params, const char* loaderJSON, const char** pluginJSON)
|
||||
@@ -528,8 +533,18 @@ void* StreamlineHooks::hkdlssg_slGetPluginFunction(const char* functionName)
|
||||
return &hkdlssg_slOnPluginLoad;
|
||||
}
|
||||
|
||||
if (strcmp(functionName, "slDLSSGSetOptions") == 0 && State::Instance().api == API::Vulkan)
|
||||
if (strcmp(functionName, "slDLSSGSetOptions") == 0)
|
||||
{
|
||||
// Give steam overlay the original as it seems to be hooking it
|
||||
auto steamOverlay = KernelBaseProxy::GetModuleHandleA_()("gameoverlayrenderer64.dll");
|
||||
if (steamOverlay != nullptr)
|
||||
{
|
||||
if (HMODULE callerModule = Util::GetCallerModule(_ReturnAddress()); callerModule == steamOverlay)
|
||||
{
|
||||
return o_dlssg_slGetPluginFunction(functionName);
|
||||
}
|
||||
}
|
||||
|
||||
o_slDLSSGSetOptions = (decltype(&slDLSSGSetOptions)) o_dlssg_slGetPluginFunction(functionName);
|
||||
return &hkslDLSSGSetOptions;
|
||||
}
|
||||
@@ -582,6 +597,45 @@ void* StreamlineHooks::hkreflex_slGetPluginFunction(const char* functionName)
|
||||
return o_reflex_slGetPluginFunction(functionName);
|
||||
}
|
||||
|
||||
sl::Result StreamlineHooks::hkslPCLSetMarker(sl::PCLMarker marker, const sl::FrameToken& frame)
|
||||
{
|
||||
// HACK for broken games
|
||||
static uint64_t last_simulation_end_id = 0;
|
||||
if (marker == sl::PCLMarker::eSimulationEnd)
|
||||
{
|
||||
last_simulation_end_id = frame;
|
||||
}
|
||||
|
||||
if (marker == sl::PCLMarker::eSimulationStart && last_simulation_end_id >= frame && o_slGetNewFrameToken)
|
||||
{
|
||||
const uint64_t correction_offset = last_simulation_end_id - frame + 1;
|
||||
uint32_t newFrameId = frame + correction_offset;
|
||||
|
||||
sl::FrameToken* newFramePointer {};
|
||||
auto result = o_slGetNewFrameToken(newFramePointer, &newFrameId);
|
||||
|
||||
LOG_WARN("Simulation start marker sent after end marker, offset: {}", correction_offset);
|
||||
|
||||
result = o_slPCLSetMarker(marker, *newFramePointer);
|
||||
return result;
|
||||
}
|
||||
|
||||
return o_slPCLSetMarker(marker, frame);
|
||||
}
|
||||
|
||||
void* StreamlineHooks::hkpcl_slGetPluginFunction(const char* functionName)
|
||||
{
|
||||
LOG_DEBUG("{}", functionName);
|
||||
|
||||
if (strcmp(functionName, "slPCLSetMarker") == 0)
|
||||
{
|
||||
o_slPCLSetMarker = (decltype(&slPCLSetMarker)) o_pcl_slGetPluginFunction(functionName);
|
||||
return &hkslPCLSetMarker;
|
||||
}
|
||||
|
||||
return o_pcl_slGetPluginFunction(functionName);
|
||||
}
|
||||
|
||||
bool StreamlineHooks::hk_setVoid(void* self, const char* key, void** value)
|
||||
{
|
||||
// LOG_DEBUG("{}", key);
|
||||
@@ -762,6 +816,8 @@ void StreamlineHooks::hookInterposer(HMODULE slInterposer)
|
||||
KernelBaseProxy::GetProcAddress_()(slInterposer, "slGetNativeInterface"));
|
||||
o_slSetD3DDevice = reinterpret_cast<decltype(&slSetD3DDevice)>(
|
||||
KernelBaseProxy::GetProcAddress_()(slInterposer, "slSetD3DDevice"));
|
||||
o_slGetNewFrameToken = reinterpret_cast<decltype(&slGetNewFrameToken)>(
|
||||
KernelBaseProxy::GetProcAddress_()(slInterposer, "slGetNewFrameToken")); // Not hooked
|
||||
|
||||
if (o_slInit != nullptr)
|
||||
{
|
||||
@@ -960,6 +1016,55 @@ void StreamlineHooks::hookReflex(HMODULE slReflex)
|
||||
}
|
||||
}
|
||||
|
||||
// SL PCL
|
||||
|
||||
void StreamlineHooks::unhookPcl()
|
||||
{
|
||||
LOG_FUNC();
|
||||
|
||||
DetourTransactionBegin();
|
||||
DetourUpdateThread(GetCurrentThread());
|
||||
|
||||
if (o_pcl_slGetPluginFunction)
|
||||
{
|
||||
DetourDetach(&(PVOID&) o_pcl_slGetPluginFunction, hkpcl_slGetPluginFunction);
|
||||
o_pcl_slGetPluginFunction = nullptr;
|
||||
}
|
||||
|
||||
DetourTransactionCommit();
|
||||
}
|
||||
|
||||
void StreamlineHooks::hookPcl(HMODULE slPcl)
|
||||
{
|
||||
LOG_FUNC();
|
||||
|
||||
if (!slPcl)
|
||||
{
|
||||
LOG_WARN("Pcl module in NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(State::Instance().gameQuirks & GameQuirk::FixSlSimulationMarkers))
|
||||
return;
|
||||
|
||||
if (o_pcl_slGetPluginFunction)
|
||||
unhookPcl();
|
||||
|
||||
o_pcl_slGetPluginFunction =
|
||||
reinterpret_cast<PFN_slGetPluginFunction>(KernelBaseProxy::GetProcAddress_()(slPcl, "slGetPluginFunction"));
|
||||
|
||||
if (o_pcl_slGetPluginFunction != nullptr)
|
||||
{
|
||||
LOG_TRACE("Hooking slGetPluginFunction in sl.pcl");
|
||||
DetourTransactionBegin();
|
||||
DetourUpdateThread(GetCurrentThread());
|
||||
|
||||
DetourAttach(&(PVOID&) o_pcl_slGetPluginFunction, hkpcl_slGetPluginFunction);
|
||||
|
||||
DetourTransactionCommit();
|
||||
}
|
||||
}
|
||||
|
||||
// SL COMMON
|
||||
|
||||
void StreamlineHooks::unhookCommon()
|
||||
|
||||
@@ -33,6 +33,9 @@ class StreamlineHooks
|
||||
static void unhookReflex();
|
||||
static void hookReflex(HMODULE slReflex);
|
||||
|
||||
static void unhookPcl();
|
||||
static void hookPcl(HMODULE slPcl);
|
||||
|
||||
static void unhookCommon();
|
||||
static void hookCommon(HMODULE slCommon);
|
||||
|
||||
@@ -49,6 +52,7 @@ class StreamlineHooks
|
||||
static decltype(&slSetConstants) o_slSetConstants;
|
||||
static decltype(&slGetNativeInterface) o_slGetNativeInterface;
|
||||
static decltype(&slSetD3DDevice) o_slSetD3DDevice;
|
||||
static decltype(&slGetNewFrameToken) o_slGetNewFrameToken;
|
||||
|
||||
static decltype(&sl1::slInit) o_slInit_sl1;
|
||||
|
||||
@@ -86,6 +90,7 @@ class StreamlineHooks
|
||||
static PFN_slGetPluginFunction o_dlssg_slGetPluginFunction;
|
||||
static PFN_slOnPluginLoad o_dlssg_slOnPluginLoad;
|
||||
static decltype(&slDLSSGSetOptions) o_slDLSSGSetOptions;
|
||||
static decltype(&slDLSSGGetState) o_slDLSSGGetState;
|
||||
|
||||
static bool hkdlssg_slOnPluginLoad(void* params, const char* loaderJSON, const char** pluginJSON);
|
||||
static sl::Result hkslSetConstants(const sl::Constants& values, const sl::FrameToken& frame,
|
||||
@@ -105,6 +110,13 @@ class StreamlineHooks
|
||||
static bool hkreflex_slSetConstants_sl1(const void* data, uint32_t frameIndex, uint32_t id);
|
||||
static void* hkreflex_slGetPluginFunction(const char* functionName);
|
||||
|
||||
// PCL
|
||||
static PFN_slGetPluginFunction o_pcl_slGetPluginFunction;
|
||||
static decltype(&slPCLSetMarker) o_slPCLSetMarker;
|
||||
|
||||
static void* hkpcl_slGetPluginFunction(const char* functionName);
|
||||
static sl::Result hkslPCLSetMarker(sl::PCLMarker marker, const sl::FrameToken& frame);
|
||||
|
||||
// Common
|
||||
static PFN_slGetPluginFunction o_common_slGetPluginFunction;
|
||||
static PFN_slOnPluginLoad o_common_slOnPluginLoad;
|
||||
|
||||
@@ -32,6 +32,7 @@ enum class GameQuirk : uint64_t
|
||||
VulkanDLSSBarrierFixup,
|
||||
ForceUnrealEngine,
|
||||
NoFSRFGFirstSwapchain,
|
||||
FixSlSimulationMarkers,
|
||||
// Don't forget to add the new entry to printQuirks
|
||||
_
|
||||
};
|
||||
@@ -199,6 +200,7 @@ static const QuirkEntry quirkTable[] = {
|
||||
QUIRK_ENTRY("minecraft.windows.exe", GameQuirk::KernelBaseHooks),
|
||||
QUIRK_ENTRY("prey.exe", GameQuirk::DontUseNTShared, GameQuirk::DisableOptiXessPipelineCreation,
|
||||
GameQuirk::DisableDxgiSpoofing),
|
||||
QUIRK_ENTRY("roadcraft - retail.exe", GameQuirk::FixSlSimulationMarkers),
|
||||
|
||||
// VULKAN
|
||||
// ------
|
||||
@@ -275,6 +277,8 @@ static void printQuirks(flag_set<GameQuirk>& quirks)
|
||||
spdlog::info("Quirk: Skipping upscaling for first 10 frames");
|
||||
if (quirks & GameQuirk::NoFSRFGFirstSwapchain)
|
||||
spdlog::info("Quirk: Skip turning the first swapchain created into an FSR swapchain");
|
||||
if (quirks & GameQuirk::FixSlSimulationMarkers)
|
||||
spdlog::info("Quirk: Correct simulation start marker's frame id");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user