mirror of
https://github.com/optiscaler/OptiScaler.git
synced 2026-09-22 21:35:51 +00:00
Turn game quirks into flags (#524)
Allows one game to have multiple quirks as well as allows for easier sharing of quirks between games
This commit is contained in:
+11
-11
@@ -7,6 +7,7 @@
|
||||
#include <deque>
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <ankerl/unordered_dense.h>
|
||||
#include <flag-set-cpp/flag_set.hpp>
|
||||
|
||||
typedef enum API
|
||||
{
|
||||
@@ -16,17 +17,15 @@ typedef enum API
|
||||
Vulkan,
|
||||
} API;
|
||||
|
||||
typedef enum GameQuirk
|
||||
enum class GameQuirk
|
||||
{
|
||||
Other,
|
||||
Cyberpunk,
|
||||
FMF2,
|
||||
RDR1,
|
||||
Banishers,
|
||||
SplitFiction,
|
||||
PoE2,
|
||||
KernelBaseHooks
|
||||
} GameQuirk;
|
||||
CyberpunkHudlessStateOverride,
|
||||
SkipFsr3Method,
|
||||
FastFeatureReset,
|
||||
LoadD3D12Manually,
|
||||
KernelBaseHooks,
|
||||
_
|
||||
};
|
||||
|
||||
typedef enum FGType : uint32_t
|
||||
{
|
||||
@@ -52,11 +51,12 @@ class State
|
||||
bool NvngxDx12Inited = false;
|
||||
bool NvngxVkInited = false;
|
||||
|
||||
flag_set<GameQuirk> gameQuirks;
|
||||
|
||||
// Reseting on creation of new feature
|
||||
std::optional<bool> AutoExposure;
|
||||
|
||||
// DLSSG
|
||||
GameQuirk gameQuirk = GameQuirk::Other;
|
||||
bool NukemsFilesAvailable = false;
|
||||
bool DLSSGDebugView = false;
|
||||
bool DLSSGInterpolatedOnly = false;
|
||||
|
||||
+10
-12
@@ -637,9 +637,9 @@ static void CheckWorkingMode()
|
||||
HooksDx::HookDx12();
|
||||
}
|
||||
|
||||
if (D3d12Proxy::Module() == nullptr && State::Instance().gameQuirk == PoE2)
|
||||
if (D3d12Proxy::Module() == nullptr && State::Instance().gameQuirks & GameQuirk::LoadD3D12Manually)
|
||||
{
|
||||
LOG_DEBUG("Loading d3d12.dll for PoE2");
|
||||
LOG_DEBUG("Loading d3d12.dll manually");
|
||||
D3d12Proxy::Init();
|
||||
}
|
||||
|
||||
@@ -865,7 +865,7 @@ static void CheckQuirks()
|
||||
|
||||
if (exePathFilename == "cyberpunk2077.exe")
|
||||
{
|
||||
State::Instance().gameQuirk = Cyberpunk;
|
||||
State::Instance().gameQuirks.set(GameQuirk::CyberpunkHudlessStateOverride);
|
||||
|
||||
// Disabled OptiFG for now
|
||||
if (Config::Instance()->FGType.value_or_default() == FGType::OptiFG)
|
||||
@@ -876,8 +876,6 @@ static void CheckQuirks()
|
||||
}
|
||||
else if (exePathFilename == "fmf2-win64-shipping.exe")
|
||||
{
|
||||
State::Instance().gameQuirk = FMF2;
|
||||
|
||||
if (!Config::Instance()->UseFsr3Inputs.has_value())
|
||||
{
|
||||
Config::Instance()->UseFsr3Inputs.set_volatile_value(false);
|
||||
@@ -892,15 +890,15 @@ static void CheckQuirks()
|
||||
}
|
||||
else if (exePathFilename == "rdr.exe" || exePathFilename == "playrdr.exe")
|
||||
{
|
||||
State::Instance().gameQuirk = RDR1;
|
||||
State::Instance().gameQuirks.set(GameQuirk::SkipFsr3Method);
|
||||
|
||||
if (Config::Instance()->FGType.value_or_default() == FGType::OptiFG)
|
||||
Config::Instance()->FGType.set_volatile_value(FGType::NoFG);
|
||||
|
||||
LOG_INFO("Enabling a quirk for RDR1 (Disable FSR-FG Swapchain)");
|
||||
}
|
||||
else if (exePathFilename == "banishers-win64-shipping.exe")
|
||||
{
|
||||
State::Instance().gameQuirk = Banishers;
|
||||
|
||||
if (!Config::Instance()->Fsr2Pattern.has_value())
|
||||
{
|
||||
Config::Instance()->Fsr2Pattern.set_volatile_value(false);
|
||||
@@ -909,23 +907,23 @@ static void CheckQuirks()
|
||||
}
|
||||
else if (exePathFilename == "splitfiction.exe")
|
||||
{
|
||||
State::Instance().gameQuirk = SplitFiction;
|
||||
State::Instance().gameQuirks.set(GameQuirk::FastFeatureReset);
|
||||
LOG_INFO("Enabling a quirk for Split Fiction (Quick upscaler reinit)");
|
||||
}
|
||||
else if (exePathFilename == "minecraft.windows.exe")
|
||||
{
|
||||
State::Instance().gameQuirk = KernelBaseHooks;
|
||||
State::Instance().gameQuirks.set(GameQuirk::KernelBaseHooks);
|
||||
LOG_INFO("Enabling a quirk for Minecraft (Enable KernelBase hooks)");
|
||||
}
|
||||
else if (exePathFilename == "nms.exe")
|
||||
{
|
||||
State::Instance().gameQuirk = KernelBaseHooks;
|
||||
State::Instance().gameQuirks.set(GameQuirk::KernelBaseHooks);
|
||||
LOG_INFO("Enabling a quirk for No Man's Sky (Enable KernelBase hooks)");
|
||||
}
|
||||
else if (exePathFilename == "pathofexile.exe" || exePathFilename == "pathofexile_x64.exe" ||
|
||||
exePathFilename == "pathofexile_x64steam.exe" || exePathFilename == "pathofexilesteam.exe")
|
||||
{
|
||||
State::Instance().gameQuirk = PoE2;
|
||||
State::Instance().gameQuirks.set(GameQuirk::LoadD3D12Manually);
|
||||
LOG_INFO("Enabling a quirk for PoE2 (Load d3d12.dll)");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1755,7 +1755,7 @@ class KernelHooks
|
||||
// These hooks cause stability regressions
|
||||
// o_KB_FreeLibrary = KernelBaseProxy::Hook_FreeLibrary(hk_KB_FreeLibrary);
|
||||
|
||||
if (State::Instance().gameQuirk == KernelBaseHooks)
|
||||
if (State::Instance().gameQuirks & GameQuirk::KernelBaseHooks)
|
||||
{
|
||||
// o_KB_LoadLibraryA = KernelBaseProxy::Hook_LoadLibraryA(hk_KB_LoadLibraryA);
|
||||
// o_KB_LoadLibraryW = KernelBaseProxy::Hook_LoadLibraryW(hk_KB_LoadLibraryW);
|
||||
|
||||
@@ -83,7 +83,7 @@ sl::Result StreamlineHooks::hkslSetTag(sl::ViewportHandle& viewport, sl::Resourc
|
||||
{
|
||||
for (uint32_t i = 0; i < numTags; i++)
|
||||
{
|
||||
if (State::Instance().gameQuirk == Cyberpunk && tags[i].type == 2 &&
|
||||
if (State::Instance().gameQuirks & GameQuirk::CyberpunkHudlessStateOverride && tags[i].type == 2 &&
|
||||
tags[i].resource->state ==
|
||||
(D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE))
|
||||
{
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
// flag_set is a type-safe class for using enums as flags in C++14 with an underlying std::bitset.
|
||||
// See https://github.com/mrts/flag-set-cpp
|
||||
// Licence: MIT, see LICENCE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <bitset>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
||||
template <typename T>
|
||||
class flag_set
|
||||
{
|
||||
public:
|
||||
flag_set() = default;
|
||||
|
||||
explicit flag_set(const T& val) { flags.set(static_cast<u_type>(val)); }
|
||||
|
||||
// Binary operations.
|
||||
|
||||
flag_set& operator&=(const T& val) noexcept
|
||||
{
|
||||
bool tmp = flags.test(static_cast<u_type>(val));
|
||||
flags.reset();
|
||||
flags.set(static_cast<u_type>(val), tmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
flag_set& operator&=(const flag_set& o) noexcept
|
||||
{
|
||||
flags &= o.flags;
|
||||
return *this;
|
||||
}
|
||||
|
||||
flag_set& operator|=(const T& val) noexcept
|
||||
{
|
||||
flags.set(static_cast<u_type>(val));
|
||||
return *this;
|
||||
}
|
||||
|
||||
flag_set& operator|=(const flag_set& o) noexcept
|
||||
{
|
||||
flags |= o.flags;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// The resulting bitset can contain at most 1 bit.
|
||||
flag_set operator&(const T& val) const
|
||||
{
|
||||
flag_set ret(*this);
|
||||
ret &= val;
|
||||
|
||||
assert(ret.flags.count() <= 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
flag_set operator&(const flag_set& val) const
|
||||
{
|
||||
flag_set ret(*this);
|
||||
ret.flags &= val.flags;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// The resulting bitset contains at least 1 bit.
|
||||
flag_set operator|(const T& val) const
|
||||
{
|
||||
flag_set ret(*this);
|
||||
ret |= val;
|
||||
|
||||
assert(ret.flags.count() >= 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
flag_set operator|(const flag_set& val) const
|
||||
{
|
||||
flag_set ret(*this);
|
||||
ret.flags |= val.flags;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
flag_set operator~() const
|
||||
{
|
||||
flag_set cp(*this);
|
||||
cp.flags.flip();
|
||||
|
||||
return cp;
|
||||
}
|
||||
|
||||
// The bitset evaluates to true if any bit is set.
|
||||
explicit operator bool() const { return flags.any(); }
|
||||
|
||||
// Methods from std::bitset.
|
||||
|
||||
bool operator==(const flag_set& o) const { return flags == o.flags; }
|
||||
|
||||
std::size_t size() const { return flags.size(); }
|
||||
|
||||
std::size_t count() const { return flags.count(); }
|
||||
|
||||
flag_set& set()
|
||||
{
|
||||
flags.set();
|
||||
return *this;
|
||||
}
|
||||
|
||||
flag_set& reset()
|
||||
{
|
||||
flags.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
flag_set& flip()
|
||||
{
|
||||
flags.flip();
|
||||
return *this;
|
||||
}
|
||||
|
||||
flag_set& set(const T& val, bool value = true)
|
||||
{
|
||||
flags.set(static_cast<u_type>(val), value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
flag_set& reset(const T& val)
|
||||
{
|
||||
flags.reset(static_cast<u_type>(val));
|
||||
return *this;
|
||||
}
|
||||
|
||||
flag_set& flip(const T& val)
|
||||
{
|
||||
flags.flip(static_cast<u_type>(val));
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr bool operator[](const T& val) const { return flags[static_cast<u_type>(val)]; }
|
||||
|
||||
std::string to_string() const { return flags.to_string(); }
|
||||
|
||||
// Operator for outputting to std::ostream.
|
||||
friend std::ostream& operator<<(std::ostream& stream, const flag_set& self)
|
||||
{
|
||||
return stream << self.flags;
|
||||
}
|
||||
|
||||
private:
|
||||
using u_type = std::underlying_type_t<T>;
|
||||
|
||||
// _ is last value sentinel and must be present in enum T.
|
||||
std::bitset<static_cast<u_type>(T::_)> flags;
|
||||
};
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct is_enum_that_contains_sentinel : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_enum_that_contains_sentinel<T, decltype(static_cast<void>(T::_))> : std::is_enum<T>
|
||||
{
|
||||
};
|
||||
|
||||
// Operator that combines two enumeration values into a flag_set only if the
|
||||
// enumeration contains the sentinel `_`.
|
||||
template <typename T>
|
||||
std::enable_if_t<is_enum_that_contains_sentinel<T>::value, flag_set<T>> operator|(const T& lhs,
|
||||
const T& rhs)
|
||||
{
|
||||
flag_set<T> fs;
|
||||
fs |= lhs;
|
||||
fs |= rhs;
|
||||
|
||||
return fs;
|
||||
}
|
||||
@@ -702,7 +702,8 @@ void HookFSR3ExeInputs()
|
||||
(PFN_ffxFsr3UpscalerContextCreate) scanner::GetAddress(exeNameV, createPattern, 0);
|
||||
|
||||
// RDR1 have duplicate methods and first found one is not used
|
||||
if (o_ffxFsr3UpscalerContextCreate_Pattern_Dx12 != nullptr && State::Instance().gameQuirk == RDR1)
|
||||
if (o_ffxFsr3UpscalerContextCreate_Pattern_Dx12 != nullptr &&
|
||||
State::Instance().gameQuirks & GameQuirk::SkipFsr3Method)
|
||||
o_ffxFsr3UpscalerContextCreate_Pattern_Dx12 = (PFN_ffxFsr3UpscalerContextCreate) scanner::GetAddress(
|
||||
exeNameV, createPattern, 0, (size_t) o_ffxFsr3UpscalerContextCreate_Pattern_Dx12 + 2);
|
||||
|
||||
@@ -716,7 +717,8 @@ void HookFSR3ExeInputs()
|
||||
"? ? ? 48 83 C1 18 48 ? ? ? ? 48 ? ? ? ? E8 ? ? ? ? 44 8B 83");
|
||||
|
||||
// RDR1 have duplicate methods and first found one is not used
|
||||
if (State::Instance().gameQuirk == RDR1 && o_ffxFsr3UpscalerContextCreate_Pattern_Dx12 != nullptr)
|
||||
if (State::Instance().gameQuirks & GameQuirk::SkipFsr3Method &&
|
||||
o_ffxFsr3UpscalerContextCreate_Pattern_Dx12 != nullptr)
|
||||
o_ffxFsr3UpscalerContextDestroy_Pattern_Dx12 = (PFN_ffxFsr3UpscalerContextDestroy) scanner::GetAddress(
|
||||
exeNameV, destroyPattern, 0, (size_t) o_ffxFsr3UpscalerContextCreate_Pattern_Dx12);
|
||||
else
|
||||
@@ -735,7 +737,8 @@ void HookFSR3ExeInputs()
|
||||
"? ? ? 77 15 48 83 B9 ? ? ? ? ? 75 06 B8 ? ? ? ? C3");
|
||||
|
||||
// RDR1 have duplicate methods and first found one is not used
|
||||
if (State::Instance().gameQuirk == RDR1 && o_ffxFsr3UpscalerContextCreate_Pattern_Dx12 != nullptr)
|
||||
if (State::Instance().gameQuirks & GameQuirk::SkipFsr3Method &&
|
||||
o_ffxFsr3UpscalerContextCreate_Pattern_Dx12 != nullptr)
|
||||
o_ffxFsr3UpscalerContextDispatch_Pattern_Dx12 = (PFN_ffxFsr3UpscalerContextDispatch) scanner::GetAddress(
|
||||
exeNameV, dispatchPattern, 0, (size_t) o_ffxFsr3UpscalerContextCreate_Pattern_Dx12);
|
||||
else
|
||||
|
||||
@@ -1299,9 +1299,9 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCom
|
||||
|
||||
dc = nullptr;
|
||||
|
||||
if (State::Instance().gameQuirk == SplitFiction)
|
||||
if (State::Instance().gameQuirks & GameQuirk::FastFeatureReset)
|
||||
{
|
||||
LOG_DEBUG("sleeping before reset of current feature for 100ms (Split Fiction)");
|
||||
LOG_DEBUG("sleeping before reset of current feature for 100ms (Fast Feature Reset)");
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
}
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user