Skip to content

Commit 251e996

Browse files
committed
DLSSPresets: add hook to override presets forced by DLSS with users ones
OverrideAppId should no longer be required to change these, so maybe can help DLSS keep using any game-specific things it might want to apply, and probably allow any telemetry to be more accurate too. @NVIDIA, please consider adding a parameter to tell DLSS to ignore the NV / DRS provided ones instead (or a parameter which lets it always use the game provided NVSDK_NGX_Parameter_DLSS_Hint_Render_Preset_XXX param) Don't really enjoy needing to inline hook your code for this, but it's necessary atm...
1 parent 515b6be commit 251e996

File tree

2 files changed

+117
-11
lines changed

2 files changed

+117
-11
lines changed

dlsstweaks.ini

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -93,21 +93,14 @@ Quality = 0.66666667
9393
;UltraQuality = 0.77
9494

9595
[DLSSPresets]
96-
; OverrideAppId: for some games DLSS might enforce certain DLSS3.1 presets, even when game requests them to be changed
97-
; Preventing any of the DLSSPresets tweaks below from being applied
98-
; To get around that you can enable OverrideAppId to make DLSS think that this is a generic title instead
99-
; Titles that are known to require this for DLSSPresets to work:
100-
; - Dying Light 2
101-
; - Shadow of the Tomb Raider
102-
; - Death Stranding
103-
; - Cyberpunk 2077
104-
OverrideAppId = false
105-
10696
; DLSS preset overrides for each quality level: set to Default to leave the preset set to whatever game/DLSS decided for it
10797
; Or set to A / B / C / D / F to try forcing that preset instead.
10898
; Presets were added in DLSS 3.1, these are essentially the different kinds of DLSS 2.x DLL versions, all merged into 3.1 as these presets
10999
; (so eg. instead of picking the best quality DLSS DLL for your game, you'd just find the right preset for it instead)
110100
; For descriptions of each preset see https://www.reddit.com/r/nvidia/comments/10z2ra9/nvidia_publishes_dlss_super_resolution_sdk_31/j81f9te/
101+
; (OverrideAppId should no longer be needed to use this section, any overrides should just work without needing anything else enabled)
102+
; (in case the presets here aren't being applied for you the OverrideAppId tweak can still be enabled in Compatibility section below)
103+
111104
DLAA = Default
112105
Quality = Default
113106
Balanced = Default
@@ -132,3 +125,10 @@ ResolutionOffset = 0
132125
; INI monitoring should have almost no cost to performance, but may possibly cause issues with certain games depending how they're installed
133126
; In case game fails to launch with DLSSTweaks in place, you can try disabling the INI update code here
134127
DisableIniMonitoring = false
128+
129+
; OverrideAppId: previously this was required to be set in order to override DLSS3.1 presets on certain games
130+
; However in newer DLSSTweaks a different solution has been found, which can now let presets be overridden without needing any app ID changes
131+
; That method could stop working on future titles/DLSS versions though
132+
; So in case game doesn't seem to apply DLSSPresets section for you at all, you can try seeing if OverrideAppId can still help
133+
; (in majority of cases this likely won't be needed however)
134+
OverrideAppId = false

src/HooksNvngxDlss.cpp

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,119 @@ uint32_t __fastcall DLSS_GetIndicatorValue(void* thisptr, uint32_t* OutValue)
4343
return ret;
4444
}
4545

46+
// Hooks that allow us to override the NV-provided DLSS3.1 presets, without needing us to override the whole AppID for the game
47+
// I'd imagine leaving games AppID might help DLSS keep using certain game-specific things, and also probably let any DLSS telemetry be more accurate too
48+
// @NVIDIA, please consider adding a parameter to tell DLSS to ignore the NV / DRS provided ones instead
49+
// (or a parameter which lets it always use the game provided NVSDK_NGX_Parameter_DLSS_Hint_Render_Preset_XXX param)
50+
// Don't really enjoy needing to inline hook your code for this, but it's necessary atm...
51+
52+
// override func present in later builds (3.1.11+?):
53+
SafetyHookInline DlssPresetOverrideFunc_LaterVersion_Hook;
54+
void DlssPresetOverrideFunc_LaterVersion(void* a1, int* OutPreset, int InPresetParamValue, int InDLSSAppOverrideValue, int a5, void* a6)
55+
{
56+
// If user has set a custom preset then zero the app override value that DLSS would force
57+
// This way the value set by user should get used, without needing to override the whole app ID
58+
//
59+
// TODO: it'd be nice if we could only zero presets that user has actually set, instead of zeroing them all if user set any
60+
// Doesn't seem like any kind of index/ID/etc for the preset is even passed to this func tho...
61+
62+
if(settings.presetDLAA || settings.presetQuality || settings.presetBalanced || settings.presetPerformance || settings.presetUltraPerformance)
63+
InDLSSAppOverrideValue = 0;
64+
65+
DlssPresetOverrideFunc_LaterVersion_Hook.unsafe_call(a1, OutPreset, InPresetParamValue, InDLSSAppOverrideValue, a5, a6);
66+
}
67+
68+
struct DlssNvidiaPresetOverrides
69+
{
70+
uint32_t overrideDLAA;
71+
uint32_t overrideQuality;
72+
uint32_t overrideBalanced;
73+
uint32_t overridePerformance;
74+
uint32_t overrideUltraPerformance;
75+
};
76+
77+
// Seems earlier DLSS 3.1 builds (3.1.2 and older?) don't use the func above, but some kind of inlined version
78+
// So instead we'll hook the code that would call into it instead
79+
// This has the benefit of letting us access the struct that holds each presets value, named as DlssNvidiaPresetOverrides above
80+
// so we can selectively disable them based on which ones user has overridden
81+
// (hopefully can find a way to do that for newer versions soon...)
82+
SafetyHookMid DlssPresetOverrideFunc_EarlyVersion_Hook;
83+
void DlssPresetOverrideFunc_EarlyVersion(SafetyHookContext& ctx)
84+
{
85+
// Code that we overwrote
86+
*(uint32_t*)(ctx.rbx + 0x1C) = uint32_t(ctx.rcx);
87+
ctx.rax = *(uint64_t*)ctx.rdi;
88+
89+
// Zero out NV-provided override if user has set their own override for that level
90+
// (@NVIDIA, please consider adding a parameter that can override these
91+
auto* nv_settings = (DlssNvidiaPresetOverrides*)ctx.rax;
92+
if (settings.presetDLAA)
93+
nv_settings->overrideDLAA = 0;
94+
if (settings.presetQuality)
95+
nv_settings->overrideQuality = 0;
96+
if (settings.presetBalanced)
97+
nv_settings->overrideBalanced = 0;
98+
if (settings.presetPerformance)
99+
nv_settings->overridePerformance = 0;
100+
if (settings.presetUltraPerformance)
101+
nv_settings->overrideUltraPerformance = 0;
102+
}
103+
46104
SafetyHookMid dlssIndicatorHudHook{};
47105
bool hook(HMODULE ngx_module)
48106
{
107+
// Search for & hook the function that overrides the DLSS presets with ones set by NV
108+
// So that users can set custom DLSS presets without needing to override the whole app ID
109+
// (if OverrideAppId is set there shouldn't be any need for this)
110+
if (!settings.overrideAppId)
111+
{
112+
auto pattern = hook::pattern((void*)ngx_module, "41 0F BA F0 1F 48 8B DA");
113+
uint8_t* match = nullptr;
114+
115+
if (pattern.size())
116+
{
117+
// search for start of the function...
118+
uint8_t* patternAddr = pattern.count(1).get_first<uint8_t>(0);
119+
for (int i = 0; i < 0x20; i++)
120+
{
121+
uint8_t* p = patternAddr - i;
122+
if (p[0] == 0x48 && p[1] == 0x89 && p[2] == 0x5C && p[3] == 0x24)
123+
{
124+
match = p;
125+
break;
126+
}
127+
}
128+
}
129+
130+
if (match)
131+
{
132+
{
133+
DlssPresetOverrideFunc_LaterVersion_Hook = safetyhook::create_inline(match, DlssPresetOverrideFunc_LaterVersion);
134+
}
135+
spdlog::info("nvngx_dlss: applied DLSS preset override hook v2");
136+
}
137+
else
138+
{
139+
// Couldn't find the preset override func, seems it might be inlined inside non-dev DLL...
140+
// Search for & hook the inlined code instead
141+
pattern = hook::pattern((void*)ngx_module, "89 4B 1C 48 8B 07 39 30 75");
142+
if (!pattern.size())
143+
spdlog::warn("nvngx_dlss: failed to apply DLSS preset override hooks, recommend enabling OverrideAppId instead");
144+
else
145+
{
146+
uint8_t* midhookAddress = pattern.count(1).get_first<uint8_t>(0);
147+
{
148+
DlssPresetOverrideFunc_EarlyVersion_Hook = safetyhook::create_mid(midhookAddress, DlssPresetOverrideFunc_EarlyVersion);
149+
}
150+
spdlog::info("nvngx_dlss: applied DLSS preset override hook v1");
151+
}
152+
}
153+
}
154+
155+
// OverrideDlssHud hooks
49156
// This pattern finds 2 matches in latest DLSS, but only 1 in older ones
50157
// The one we're trying to find seems to always be first match
51158
// TODO: scan for RegQueryValue call and grab the offset from that, use offset instead of wildcards below
52-
53159
auto indicatorValueCheck = hook::pattern((void*)ngx_module, "8B 81 ? ? ? ? 89 02 33 C0 C3");
54160
if ((!settings.disableIniMonitoring || settings.overrideDlssHud == 2) && indicatorValueCheck.size())
55161
{

0 commit comments

Comments
 (0)