Skip to content

Commit 0109df9

Browse files
authored
Merge branch 'praydog:master' into master
2 parents f4bc210 + b630984 commit 0109df9

6 files changed

Lines changed: 256 additions & 39 deletions

File tree

shared/sdk/REContext.cpp

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,21 @@ namespace sdk {
2424

2525
sdk::VM* VM::get() {
2626
update_pointers();
27+
28+
if (s_global_context == nullptr) {
29+
return nullptr;
30+
}
31+
2732
return *s_global_context;
2833
}
2934

3035
REThreadContext* VM::get_thread_context(int32_t unk /*= -1*/) {
3136
update_pointers();
3237

38+
if (s_get_thread_context == nullptr) {
39+
return nullptr;
40+
}
41+
3342
return s_get_thread_context(this, unk);
3443
}
3544

@@ -86,7 +95,7 @@ namespace sdk {
8695
std::unique_lock lock{ s_mutex };
8796

8897
utility::ScopeGuard sg{ [&]() {
89-
s_fully_updated_pointers = true;
98+
s_fully_updated_pointers = s_global_context != nullptr && s_get_thread_context != nullptr;
9099
}
91100
};
92101

@@ -148,11 +157,16 @@ namespace sdk {
148157
return;
149158
}
150159

151-
s_global_context = (decltype(s_global_context))utility::calculate_absolute(*ref + context_pattern->ctx_offset);
152-
s_get_thread_context = (decltype(s_get_thread_context))utility::calculate_absolute(*ref + context_pattern->get_thread_context_offset);
160+
const auto potential_context = (decltype(s_global_context))utility::calculate_absolute(*ref + context_pattern->ctx_offset);
161+
bool found_tdb = false;
162+
163+
if (*potential_context == nullptr) {
164+
spdlog::info("[VM::update_pointers] Context is null.");
165+
return;
166+
}
153167

154168
for (auto i = 0; i < 0x20000; i += sizeof(void*)) {
155-
auto ptr = *(sdk::RETypeDB**)((uintptr_t)*s_global_context + i);
169+
auto ptr = *(sdk::RETypeDB**)((uintptr_t)*potential_context + i);
156170

157171
if (ptr == nullptr || IsBadReadPtr(ptr, sizeof(void*)) || ((uintptr_t)ptr & (sizeof(void*) - 1)) != 0) {
158172
continue;
@@ -164,6 +178,7 @@ namespace sdk {
164178
s_tdb_version = version;
165179
s_type_db_offset = i;
166180
s_static_tbl_offset = s_type_db_offset - 0x30; // hope this holds true for the older gameS!!!!!!!!!!!!!!!!!!!
181+
found_tdb = true;
167182
spdlog::info("[VM::update_pointers] s_type_db_offset: {:x}", s_type_db_offset);
168183
spdlog::info("[VM::update_pointers] s_static_tbl_offset: {:x}", s_static_tbl_offset);
169184
spdlog::info("[VM::update_pointers] TDB Version: {}", version);
@@ -172,6 +187,14 @@ namespace sdk {
172187
}
173188
}
174189

190+
if (!found_tdb) {
191+
spdlog::error("[VM::update_pointers] Unable to find TDB inside VM");
192+
return;
193+
}
194+
195+
s_global_context = potential_context;
196+
s_get_thread_context = (decltype(s_get_thread_context))utility::calculate_absolute(*ref + context_pattern->get_thread_context_offset);
197+
175198
spdlog::info("[VM::update_pointers] s_global_context: {:x}", (uintptr_t)s_global_context);
176199
spdlog::info("[VM::update_pointers] s_get_thread_context: {:x}", (uintptr_t)s_get_thread_context);
177200

@@ -181,13 +204,14 @@ namespace sdk {
181204
#if TDB_VER >= 71
182205
if (s_global_context != nullptr && *s_global_context != nullptr) {
183206
auto static_tbl = (REStaticTbl**)((uintptr_t)*s_global_context + s_static_tbl_offset);
207+
bool found_static_tbl_offset = false;
184208
if (IsBadReadPtr(*static_tbl, sizeof(void*)) || ((uintptr_t)*static_tbl & (sizeof(void*) - 1)) != 0) {
185209
spdlog::info("[VM::update_pointers] Static table offset is bad, correcting...");
186210

187211
// We are looking for the two arrays, the static field table, and the static field "initialized table"
188212
// The initialized table tells whether a specific entry in the static field table has been initialized or not
189213
// so they both should have the same size, easy to find
190-
for (auto i = sizeof(void*); i < 0x100; i+= sizeof(void*)) {
214+
for (auto i = sizeof(void*); i < 0x100; i+= sizeof(void*)) try {
191215
const auto& ptr = *(REStaticTbl**)((uintptr_t)*s_global_context + (s_type_db_offset - i));
192216

193217
if (IsBadReadPtr(ptr, sizeof(void*)) || ((uintptr_t)ptr & (sizeof(void*) - 1)) != 0) {
@@ -210,9 +234,23 @@ namespace sdk {
210234
if (previous_count == potential_count) {
211235
spdlog::info("[VM::update_pointers] Found static table at {:x} (offset {:x})", (uintptr_t)ptr, previous_offset);
212236
s_static_tbl_offset = previous_offset;
237+
found_static_tbl_offset = true;
213238
break;
214239
}
240+
} catch (...) {
241+
continue;
215242
}
243+
} else {
244+
found_static_tbl_offset = true;
245+
}
246+
247+
// Just make it return null if we can't find it
248+
// We do this so the consumer can do while(sdk::VM::get() != nullptr) { ... } to wait for everything to be valid
249+
if (!found_static_tbl_offset) {
250+
spdlog::error("[VM::update_pointers] Unable to find static table offset.");
251+
s_global_context = nullptr;
252+
s_get_thread_context = nullptr;
253+
return;
216254
}
217255
}
218256
#endif

shared/sdk/Renderer.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,17 @@ void RenderContext::copy_texture(Texture* dest, Texture* src, Fence& fence) {
710710
func(this, dest, src, fence);
711711
}
712712

713+
std::optional<uint32_t> Renderer::get_render_frame() const {
714+
static auto tdef = sdk::find_type_definition("via.render.Renderer");
715+
static auto m = tdef != nullptr ? tdef->get_method("get_RenderFrame") : nullptr;
716+
717+
if (m == nullptr) {
718+
return std::nullopt;
719+
}
720+
721+
return m->call<uint32_t>(sdk::get_thread_context(), this);
722+
}
723+
713724
ConstantBuffer* Renderer::get_constant_buffer(std::string_view name) const {
714725
static auto tdef = sdk::find_type_definition("via.render.Renderer");
715726
static auto t = tdef->get_type();

shared/sdk/Renderer.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,12 @@ class RenderContext {
413413

414414
class Renderer {
415415
public:
416+
void* get_device() const {
417+
return *(void**)((uintptr_t)this + sizeof(void*)); // simple!
418+
}
419+
420+
std::optional<uint32_t> get_render_frame() const;
421+
416422
ConstantBuffer* get_constant_buffer(std::string_view name) const;
417423

418424
ConstantBuffer* get_scene_info() const {

src/D3D12Hook.cpp

Lines changed: 67 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ void* D3D12Hook::Streamline::link_swapchain_to_cmd_queue(void* rcx, void* rdx, v
3333
return hook->get_original<decltype(link_swapchain_to_cmd_queue)>()(rcx, rdx, r8, r9);
3434
}
3535

36+
while (g_framework == nullptr) {
37+
std::this_thread::yield();
38+
}
39+
3640
std::scoped_lock _{g_framework->get_hook_monitor_mutex()};
3741

3842
spdlog::info("[Streamline] linkSwapchainToCmdQueue: {:x}", (uintptr_t)_ReturnAddress());
@@ -57,6 +61,39 @@ void* D3D12Hook::Streamline::link_swapchain_to_cmd_queue(void* rcx, void* rdx, v
5761
return result;
5862
}
5963

64+
HRESULT WINAPI D3D12Hook::create_swapchain(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) {
65+
auto create_swap_chain_fn = s_create_swapchain_hook->get_original<decltype(D3D12Hook::create_swapchain)*>();
66+
67+
if (g_inside_d3d12_hook) {
68+
spdlog::info("create_swapchain (inside D3D12 hook)");
69+
return create_swap_chain_fn(factory, device, hwnd, desc, p_fullscreen_desc, p_restrict_to_output, swap_chain);
70+
}
71+
72+
spdlog::info("create_swapchain called");
73+
74+
while (g_framework == nullptr) {
75+
std::this_thread::yield();
76+
}
77+
78+
std::scoped_lock _{g_framework->get_hook_monitor_mutex()};
79+
80+
bool hook_was_nullptr = g_d3d12_hook == nullptr;
81+
82+
if (g_d3d12_hook != nullptr && g_framework->get_d3d12_hook() != nullptr) {
83+
g_framework->on_reset(); // Needed to prevent a crash due to resources hanging around
84+
g_d3d12_hook->unhook(); // Removes all vtable hooks
85+
}
86+
87+
const auto result = create_swap_chain_fn(factory, device, hwnd, desc, p_fullscreen_desc, p_restrict_to_output, swap_chain);
88+
89+
// rather than waiting on the hook monitor to notice the hook isn't working
90+
if (!hook_was_nullptr) {
91+
g_framework->hook_d3d12();
92+
}
93+
94+
return result;
95+
}
96+
6097
void D3D12Hook::hook_streamline(HMODULE dlssg_module) try {
6198
if (D3D12Hook::s_streamline.setup) {
6299
return;
@@ -325,10 +362,13 @@ bool D3D12Hook::hook() {
325362
return false;
326363
}
327364

328-
const auto ti = utility::rtti::get_type_info(swap_chain1);
329-
330365
try {
331-
const auto swapchain_classname = ti != nullptr ? std::string_view{ti->name()} : "unknown";
366+
const auto ti = utility::rtti::get_type_info(swap_chain1);
367+
const auto swapchain_classname = ti != nullptr && ti->name() != nullptr ? std::string_view{ti->name()} : "unknown";
368+
const auto raw_name = ti != nullptr && ti->raw_name() != nullptr ? std::string_view{ti->raw_name()} : "unknown";
369+
370+
spdlog::info("Swapchain type info: {}", swapchain_classname);
371+
spdlog::info("Swapchain raw type info: {}", raw_name);
332372

333373
if (swapchain_classname.contains("interposer::DXGISwapChain")) { // DLSS3
334374
spdlog::info("Found Streamline (DLSSFG) swapchain during dummy initialization: {:x}", (uintptr_t)swap_chain1);
@@ -346,6 +386,8 @@ bool D3D12Hook::hook() {
346386

347387
spdlog::info("Finding command queue offset");
348388

389+
m_command_queue_offset = 0;
390+
349391
// Find the command queue offset in the swapchain
350392
for (auto i = 0; i < 512 * sizeof(void*); i += sizeof(void*)) {
351393
const auto base = (uintptr_t)swap_chain1 + i;
@@ -442,6 +484,12 @@ bool D3D12Hook::hook() {
442484

443485
auto& present_fn = (*(void***)target_swapchain)[8]; // Present
444486
m_present_hook = std::make_unique<PointerHook>(&present_fn, &D3D12Hook::present);
487+
488+
if (s_create_swapchain_hook == nullptr) {
489+
auto& create_swapchain_fn = (*(void***)factory)[15]; // CreateSwapChainForHwnd
490+
s_create_swapchain_hook = std::make_unique<PointerHook>(&create_swapchain_fn, &D3D12Hook::create_swapchain);
491+
}
492+
445493
m_hooked = true;
446494
} catch (const std::exception& e) {
447495
spdlog::error("Failed to initialize hooks: {}", e.what());
@@ -468,6 +516,10 @@ bool D3D12Hook::hook() {
468516
}
469517

470518
bool D3D12Hook::unhook() {
519+
while (g_framework == nullptr) {
520+
std::this_thread::yield();
521+
}
522+
471523
std::scoped_lock _{g_framework->get_hook_monitor_mutex()};
472524

473525
if (!m_hooked) {
@@ -488,6 +540,10 @@ bool D3D12Hook::unhook() {
488540
thread_local int32_t g_present_depth = 0;
489541

490542
HRESULT WINAPI D3D12Hook::present(IDXGISwapChain3* swap_chain, uint64_t sync_interval, uint64_t flags, void* r9) {
543+
while (g_framework == nullptr) {
544+
std::this_thread::yield();
545+
}
546+
491547
std::scoped_lock _{g_framework->get_hook_monitor_mutex()};
492548

493549
auto d3d12 = g_d3d12_hook;
@@ -620,6 +676,10 @@ HRESULT WINAPI D3D12Hook::present(IDXGISwapChain3* swap_chain, uint64_t sync_int
620676
thread_local int32_t g_resize_buffers_depth = 0;
621677

622678
HRESULT WINAPI D3D12Hook::resize_buffers(IDXGISwapChain3* swap_chain, UINT buffer_count, UINT width, UINT height, DXGI_FORMAT new_format, UINT swap_chain_flags) {
679+
while (g_framework == nullptr) {
680+
std::this_thread::yield();
681+
}
682+
623683
std::scoped_lock _{g_framework->get_hook_monitor_mutex()};
624684

625685
spdlog::info("D3D12 resize buffers called");
@@ -705,6 +765,10 @@ HRESULT WINAPI D3D12Hook::resize_buffers(IDXGISwapChain3* swap_chain, UINT buffe
705765
thread_local int32_t g_resize_target_depth = 0;
706766

707767
HRESULT WINAPI D3D12Hook::resize_target(IDXGISwapChain3* swap_chain, const DXGI_MODE_DESC* new_target_parameters) {
768+
while (g_framework == nullptr) {
769+
std::this_thread::yield();
770+
}
771+
708772
std::scoped_lock _{g_framework->get_hook_monitor_mutex()};
709773

710774
spdlog::info("D3D12 resize target called");
@@ -786,21 +850,3 @@ HRESULT WINAPI D3D12Hook::resize_target(IDXGISwapChain3* swap_chain, const DXGI_
786850

787851
return result;
788852
}
789-
790-
/*HRESULT WINAPI D3D12Hook::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)
791-
{
792-
spdlog::info("D3D12 create swapchain called");
793-
794-
auto d3d12 = g_d3d12_hook;
795-
796-
d3d12->m_command_queue = (ID3D12CommandQueue*)device;
797-
798-
if (d3d12->m_on_create_swap_chain) {
799-
d3d12->m_on_create_swap_chain(*d3d12);
800-
}
801-
802-
auto create_swap_chain_fn = d3d12->m_create_swap_chain_hook->get_original<decltype(D3D12Hook::create_swap_chain)>();
803-
804-
return create_swap_chain_fn(factory, device, hwnd, desc, p_fullscreen_desc, p_restrict_to_output, swap_chain);
805-
}*/
806-

src/D3D12Hook.hpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,7 @@ class D3D12Hook
122122
bool m_ignore_next_present{false};
123123

124124
std::unique_ptr<PointerHook> m_present_hook{};
125-
//std::unique_ptr<PointerHook> m_release_hook{};
126125
std::unique_ptr<VtableHook> m_swapchain_hook{};
127-
//std::unique_ptr<FunctionHook> m_create_swap_chain_hook{};
128126

129127
struct Streamline {
130128
static void* link_swapchain_to_cmd_queue(void* rcx, void* rdx, void* r8, void* r9);
@@ -135,6 +133,9 @@ class D3D12Hook
135133
};
136134

137135
static inline Streamline s_streamline{};
136+
137+
// This is static because unhooking it seems to cause a crash sometimes
138+
static inline std::unique_ptr<PointerHook> s_create_swapchain_hook{};
138139

139140
OnPresentFn m_on_present{ nullptr };
140141
OnPresentFn m_on_post_present{ nullptr };
@@ -145,6 +146,6 @@ class D3D12Hook
145146
static HRESULT WINAPI present(IDXGISwapChain3* swap_chain, uint64_t sync_interval, uint64_t flags, void* r9);
146147
static HRESULT WINAPI resize_buffers(IDXGISwapChain3* swap_chain, UINT buffer_count, UINT width, UINT height, DXGI_FORMAT new_format, UINT swap_chain_flags);
147148
static HRESULT WINAPI resize_target(IDXGISwapChain3* swap_chain, const DXGI_MODE_DESC* new_target_parameters);
148-
//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);
149+
static HRESULT WINAPI create_swapchain(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);
149150
};
150151

0 commit comments

Comments
 (0)