Skip to content

Commit f4bc210

Browse files
authored
Merge branch 'praydog:master' into master
2 parents ae70e36 + 5dc5998 commit f4bc210

4 files changed

Lines changed: 162 additions & 28 deletions

File tree

src/D3D12Hook.cpp

Lines changed: 138 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22
#include <future>
33
#include <unordered_set>
44
#include <stacktrace>
5+
#include <wrl/client.h>
56

67
#include <spdlog/spdlog.h>
78
#include <utility/Thread.hpp>
89
#include <utility/Module.hpp>
910
#include <utility/String.hpp>
1011
#include <utility/RTTI.hpp>
12+
#include <utility/Scan.hpp>
13+
#include <utility/ScopeGuard.hpp>
1114

1215
#include "REFramework.hpp"
1316

@@ -16,16 +19,111 @@
1619
#include "D3D12Hook.hpp"
1720

1821
static D3D12Hook* g_d3d12_hook = nullptr;
22+
thread_local bool g_inside_d3d12_hook = false;
1923

2024
D3D12Hook::~D3D12Hook() {
2125
unhook();
2226
}
2327

28+
void* D3D12Hook::Streamline::link_swapchain_to_cmd_queue(void* rcx, void* rdx, void* r8, void* r9) {
29+
if (g_inside_d3d12_hook) {
30+
spdlog::info("[Streamline] linkSwapchainToCmdQueue: {:x} (inside D3D12 hook)", (uintptr_t)_ReturnAddress());
31+
32+
auto& hook = D3D12Hook::s_streamline.link_swapchain_to_cmd_queue_hook;
33+
return hook->get_original<decltype(link_swapchain_to_cmd_queue)>()(rcx, rdx, r8, r9);
34+
}
35+
36+
std::scoped_lock _{g_framework->get_hook_monitor_mutex()};
37+
38+
spdlog::info("[Streamline] linkSwapchainToCmdQueue: {:x}", (uintptr_t)_ReturnAddress());
39+
40+
bool hook_was_nullptr = g_d3d12_hook == nullptr;
41+
42+
if (g_d3d12_hook != nullptr) {
43+
g_framework->on_reset(); // Needed to prevent a crash due to resources hanging around
44+
g_d3d12_hook->unhook(); // Removes all vtable hooks
45+
}
46+
47+
auto& hook = D3D12Hook::s_streamline.link_swapchain_to_cmd_queue_hook;
48+
const auto result = hook->get_original<decltype(link_swapchain_to_cmd_queue)>()(rcx, rdx, r8, r9);
49+
50+
// Re-hooks present after the above function creates the swapchain
51+
// This allows the hook to immediately still function
52+
// rather than waiting on the hook monitor to notice the hook isn't working
53+
if (!hook_was_nullptr) {
54+
g_framework->hook_d3d12();
55+
}
56+
57+
return result;
58+
}
59+
60+
void D3D12Hook::hook_streamline(HMODULE dlssg_module) try {
61+
if (D3D12Hook::s_streamline.setup) {
62+
return;
63+
}
64+
65+
std::scoped_lock _{D3D12Hook::s_streamline.hook_mutex};
66+
67+
if (D3D12Hook::s_streamline.setup) {
68+
return;
69+
}
70+
71+
spdlog::info("[Streamline] Hooking Streamline");
72+
73+
if (dlssg_module == nullptr) {
74+
dlssg_module = GetModuleHandleW(L"sl.dlss_g.dll");
75+
}
76+
77+
if (dlssg_module == nullptr) {
78+
spdlog::error("[Streamline] Failed to get sl.dlss_g.dll module handle");
79+
return;
80+
}
81+
82+
const auto str = utility::scan_string(dlssg_module, "linkSwapchainToCmdQueue");
83+
84+
if (!str) {
85+
spdlog::error("[Streamline] Failed to find linkSwapchainToCmdQueue");
86+
return;
87+
}
88+
89+
const auto str_ref = utility::scan_displacement_reference(dlssg_module, *str);
90+
91+
if (!str_ref) {
92+
spdlog::error("[Streamline] Failed to find linkSwapchainToCmdQueue reference");
93+
return;
94+
}
95+
96+
const auto fn = utility::find_function_start_with_call(*str_ref);
97+
98+
if (!fn) {
99+
spdlog::error("[Streamline] Failed to find linkSwapchainToCmdQueue function");
100+
return;
101+
}
102+
103+
D3D12Hook::s_streamline.link_swapchain_to_cmd_queue_hook = std::make_unique<FunctionHook>(*fn, (uintptr_t)&Streamline::link_swapchain_to_cmd_queue);
104+
105+
if (D3D12Hook::s_streamline.link_swapchain_to_cmd_queue_hook->create()) {
106+
spdlog::info("[Streamline] Hooked linkSwapchainToCmdQueue");
107+
} else {
108+
spdlog::error("[Streamline] Failed to hook linkSwapchainToCmdQueue");
109+
}
110+
111+
D3D12Hook::s_streamline.setup = true;
112+
} catch(...) {
113+
spdlog::error("[Streamline] Failed to hook Streamline");
114+
}
115+
24116
bool D3D12Hook::hook() {
25117
spdlog::info("Hooking D3D12");
26118

27119
g_d3d12_hook = this;
28120

121+
g_inside_d3d12_hook = true;
122+
123+
utility::ScopeGuard guard{[]() {
124+
g_inside_d3d12_hook = false;
125+
}};
126+
29127
IDXGISwapChain1* swap_chain1{ nullptr };
30128
IDXGISwapChain3* swap_chain{ nullptr };
31129
ID3D12Device* device{ nullptr };
@@ -330,7 +428,9 @@ bool D3D12Hook::hook() {
330428
return false;
331429
}
332430

333-
utility::ThreadSuspender suspender{};
431+
hook_streamline();
432+
433+
//utility::ThreadSuspender suspender{};
334434

335435
try {
336436
spdlog::info("Initializing hooks");
@@ -341,20 +441,20 @@ bool D3D12Hook::hook() {
341441
m_is_phase_1 = true;
342442

343443
auto& present_fn = (*(void***)target_swapchain)[8]; // Present
344-
m_present_hook = std::make_unique<PointerHook>(&present_fn, (void*)&D3D12Hook::present);
444+
m_present_hook = std::make_unique<PointerHook>(&present_fn, &D3D12Hook::present);
345445
m_hooked = true;
346446
} catch (const std::exception& e) {
347447
spdlog::error("Failed to initialize hooks: {}", e.what());
348448
m_hooked = false;
349449
}
350450

351-
suspender.resume();
451+
//suspender.resume();
352452

353-
device->Release();
354453
command_queue->Release();
355-
factory->Release();
356454
swap_chain1->Release();
357455
swap_chain->Release();
456+
device->Release();
457+
factory->Release();
358458

359459
if (hwnd) {
360460
::DestroyWindow(hwnd);
@@ -368,6 +468,8 @@ bool D3D12Hook::hook() {
368468
}
369469

370470
bool D3D12Hook::unhook() {
471+
std::scoped_lock _{g_framework->get_hook_monitor_mutex()};
472+
371473
if (!m_hooked) {
372474
return true;
373475
}
@@ -385,57 +487,67 @@ bool D3D12Hook::unhook() {
385487

386488
thread_local int32_t g_present_depth = 0;
387489

388-
HRESULT WINAPI D3D12Hook::present(IDXGISwapChain3* swap_chain, UINT sync_interval, UINT flags) {
490+
HRESULT WINAPI D3D12Hook::present(IDXGISwapChain3* swap_chain, uint64_t sync_interval, uint64_t flags, void* r9) {
389491
std::scoped_lock _{g_framework->get_hook_monitor_mutex()};
390492

391493
auto d3d12 = g_d3d12_hook;
392494

393-
HWND swapchain_wnd{nullptr};
394-
swap_chain->GetHwnd(&swapchain_wnd);
395-
396495
decltype(D3D12Hook::present)* present_fn{nullptr};
397496

398-
//if (d3d12->m_is_phase_1) {
497+
if (d3d12->m_is_phase_1) {
399498
present_fn = d3d12->m_present_hook->get_original<decltype(D3D12Hook::present)*>();
400-
/*} else {
499+
} else {
401500
present_fn = d3d12->m_swapchain_hook->get_method<decltype(D3D12Hook::present)*>(8);
402-
}*/
501+
}
502+
503+
HWND swapchain_wnd{nullptr};
504+
swap_chain->GetHwnd(&swapchain_wnd);
403505

404506
if (d3d12->m_is_phase_1 && WindowFilter::get().is_filtered(swapchain_wnd)) {
405507
//present_fn = d3d12->m_present_hook->get_original<decltype(D3D12Hook::present)*>();
406-
return present_fn(swap_chain, sync_interval, flags);
508+
return present_fn(swap_chain, sync_interval, flags, r9);
407509
}
408510

409511
if (!d3d12->m_is_phase_1 && swap_chain != d3d12->m_swapchain_hook->get_instance()) {
410-
return present_fn(swap_chain, sync_interval, flags);
512+
return present_fn(swap_chain, sync_interval, flags, r9);
411513
}
412514

413515
if (d3d12->m_is_phase_1) {
414-
//d3d12->m_present_hook.reset();
516+
// Remove the present hook, we will just rely on the vtable hook below
517+
// because we don't want to cause any conflicts with other hooks
518+
// vtable hooks are the least intrusive
519+
// And doing a global pointer replacement seems to have
520+
// conflicts with Streamline's hooks, causing unexplainable crashes
521+
d3d12->m_present_hook.reset();
415522

416523
// vtable hook the swapchain instead of global hooking
417524
// this seems safer for whatever reason
418525
// if we globally hook the vtable pointers, it causes all sorts of weird conflicts with other hooks
419526
// dont hook present though via this hook so other hooks dont get confused
420527
d3d12->m_swapchain_hook = std::make_unique<VtableHook>(swap_chain);
421-
//d3d12->m_swapchain_hook->hook_method(8, (uintptr_t)&D3D12Hook::present);
528+
//d3d12->m_swapchain_hook->hook_method(2, (uintptr_t)&D3D12Hook::release);
529+
d3d12->m_swapchain_hook->hook_method(8, (uintptr_t)&D3D12Hook::present);
422530
d3d12->m_swapchain_hook->hook_method(13, (uintptr_t)&D3D12Hook::resize_buffers);
423531
d3d12->m_swapchain_hook->hook_method(14, (uintptr_t)&D3D12Hook::resize_target);
424532
d3d12->m_is_phase_1 = false;
533+
534+
present_fn = d3d12->m_swapchain_hook->get_method<decltype(D3D12Hook::present)*>(8);
425535
}
426536

427537
d3d12->m_inside_present = true;
428538
d3d12->m_swap_chain = swap_chain;
429539

430-
swap_chain->GetDevice(IID_PPV_ARGS(&d3d12->m_device));
540+
{
541+
Microsoft::WRL::ComPtr<ID3D12Device4> temp_device{};
542+
swap_chain->GetDevice(IID_PPV_ARGS(&temp_device));
543+
d3d12->m_device = temp_device.Get();
544+
}
431545

432-
if (d3d12->m_device != nullptr) {
433-
if (d3d12->m_using_proton_swapchain) {
434-
const auto real_swapchain = *(uintptr_t*)((uintptr_t)swap_chain + d3d12->m_proton_swapchain_offset);
435-
d3d12->m_command_queue = *(ID3D12CommandQueue**)(real_swapchain + d3d12->m_command_queue_offset);
436-
} else {
437-
d3d12->m_command_queue = *(ID3D12CommandQueue**)((uintptr_t)swap_chain + d3d12->m_command_queue_offset);
438-
}
546+
if (d3d12->m_using_proton_swapchain) {
547+
const auto real_swapchain = *(uintptr_t*)((uintptr_t)swap_chain + d3d12->m_proton_swapchain_offset);
548+
d3d12->m_command_queue = *(ID3D12CommandQueue**)(real_swapchain + d3d12->m_command_queue_offset);
549+
} else {
550+
d3d12->m_command_queue = *(ID3D12CommandQueue**)((uintptr_t)swap_chain + d3d12->m_command_queue_offset);
439551
}
440552

441553
if (d3d12->m_swapchain_0 == nullptr) {
@@ -462,7 +574,7 @@ HRESULT WINAPI D3D12Hook::present(IDXGISwapChain3* swap_chain, UINT sync_interva
462574
spdlog::info("Attempting to call real present function");
463575

464576
++g_present_depth;
465-
const auto result = present_fn(swap_chain, sync_interval, flags);
577+
const auto result = present_fn(swap_chain, sync_interval, flags, r9);
466578
--g_present_depth;
467579

468580
if (result != S_OK) {
@@ -485,7 +597,7 @@ HRESULT WINAPI D3D12Hook::present(IDXGISwapChain3* swap_chain, UINT sync_interva
485597
auto result = S_OK;
486598

487599
if (!d3d12->m_ignore_next_present) {
488-
result = present_fn(swap_chain, sync_interval, flags);
600+
result = present_fn(swap_chain, sync_interval, flags, r9);
489601

490602
if (result != S_OK) {
491603
spdlog::error("Present failed: {:x}", result);

src/D3D12Hook.hpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <dxgi1_4.h>
1111

1212
#include "utility/PointerHook.hpp"
13+
#include "utility/FunctionHook.hpp"
1314
#include "utility/VtableHook.hpp"
1415

1516
class D3D12Hook
@@ -88,7 +89,7 @@ class D3D12Hook
8889
bool is_proton_swapchain() const {
8990
return m_using_proton_swapchain;
9091
}
91-
92+
9293
bool is_framegen_swapchain() const {
9394
return m_using_frame_generation_swapchain;
9495
}
@@ -97,6 +98,8 @@ class D3D12Hook
9798
m_ignore_next_present = true;
9899
}
99100

101+
static void hook_streamline(HMODULE dlssg_module = nullptr);
102+
100103
protected:
101104
ID3D12Device4* m_device{ nullptr };
102105
IDXGISwapChain3* m_swap_chain{ nullptr };
@@ -119,16 +122,27 @@ class D3D12Hook
119122
bool m_ignore_next_present{false};
120123

121124
std::unique_ptr<PointerHook> m_present_hook{};
125+
//std::unique_ptr<PointerHook> m_release_hook{};
122126
std::unique_ptr<VtableHook> m_swapchain_hook{};
123127
//std::unique_ptr<FunctionHook> m_create_swap_chain_hook{};
124128

129+
struct Streamline {
130+
static void* link_swapchain_to_cmd_queue(void* rcx, void* rdx, void* r8, void* r9);
131+
132+
std::unique_ptr<FunctionHook> link_swapchain_to_cmd_queue_hook{};
133+
std::mutex hook_mutex{};
134+
bool setup{ false };
135+
};
136+
137+
static inline Streamline s_streamline{};
138+
125139
OnPresentFn m_on_present{ nullptr };
126140
OnPresentFn m_on_post_present{ nullptr };
127141
OnResizeBuffersFn m_on_resize_buffers{ nullptr };
128142
OnResizeTargetFn m_on_resize_target{ nullptr };
129143
//OnCreateSwapChainFn m_on_create_swap_chain{ nullptr };
130144

131-
static HRESULT WINAPI present(IDXGISwapChain3* swap_chain, UINT sync_interval, UINT flags);
145+
static HRESULT WINAPI present(IDXGISwapChain3* swap_chain, uint64_t sync_interval, uint64_t flags, void* r9);
132146
static HRESULT WINAPI resize_buffers(IDXGISwapChain3* swap_chain, UINT buffer_count, UINT width, UINT height, DXGI_FORMAT new_format, UINT swap_chain_flags);
133147
static HRESULT WINAPI resize_target(IDXGISwapChain3* swap_chain, const DXGI_MODE_DESC* new_target_parameters);
134148
//static HRESULT WINAPI create_swap_chain(IDXGIFactory4* factory, IUnknown* device, HWND hwnd, const DXGI_SWAP_CHAIN_DESC* desc, const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* p_fullscreen_desc, IDXGIOutput* p_restrict_to_output, IDXGISwapChain** swap_chain);

src/REFramework.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,12 @@ try {
199199
if (NotificationData->Loaded.BaseDllName != nullptr && NotificationData->Loaded.BaseDllName->Buffer != nullptr) {
200200
std::wstring base_dll_name = NotificationData->Loaded.BaseDllName->Buffer;
201201
spdlog::info("LdrRegisterDllNotification: Loaded: {}", utility::narrow(base_dll_name));
202+
203+
if (base_dll_name.find(L"sl.dlss_g.dll") != std::wstring::npos) {
204+
spdlog::info("LdrRegisterDllNotification: Detected DLSS DLL loaded");
205+
206+
D3D12Hook::hook_streamline((HMODULE)NotificationData->Loaded.DllBase);
207+
}
202208
}
203209

204210
if (g_current_game_path && NotificationData->Loaded.FullDllName != nullptr && NotificationData->Loaded.FullDllName->Buffer != nullptr) {

src/REFramework.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,11 @@ class REFramework {
144144
void draw_ui();
145145
void draw_about();
146146

147+
public:
147148
bool hook_d3d11();
148149
bool hook_d3d12();
149150

151+
private:
150152
bool initialize();
151153
bool initialize_game_data();
152154
bool initialize_windows_message_hook();

0 commit comments

Comments
 (0)