From 9c1d957e8479bc599ab88a17b43b3e98ef17d798 Mon Sep 17 00:00:00 2001 From: praydog Date: Wed, 13 Mar 2024 09:54:45 -0700 Subject: [PATCH 1/8] D3D12: Possible fix for menu rendering issues --- src/REFramework.cpp | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/REFramework.cpp b/src/REFramework.cpp index 181dc2a1a..5fb85ddf2 100644 --- a/src/REFramework.cpp +++ b/src/REFramework.cpp @@ -662,6 +662,19 @@ void REFramework::on_frame_d3d12() { return; } + auto swapchain = m_d3d12_hook->get_swap_chain(); + const auto bb_index = swapchain->GetCurrentBackBufferIndex(); + + // Test if our RT for this index is valid. + if (m_d3d12.get_rt((D3D12::RTV)bb_index) == nullptr) { + spdlog::error("RTV for index {} is null, reinitializing...", bb_index); + deinit_d3d12(); + m_has_frame = false; + m_first_initialize = false; + m_initialized = false; + return; + } + cmd_ctx->wait(INFINITE); { std::scoped_lock _{ cmd_ctx->mtx }; @@ -692,8 +705,6 @@ void REFramework::on_frame_d3d12() { cmd_ctx->cmd_list->ResourceBarrier(1, &barrier); // Draw to the back buffer. - auto swapchain = m_d3d12_hook->get_swap_chain(); - auto bb_index = swapchain->GetCurrentBackBufferIndex(); barrier.Transition.pResource = m_d3d12.rts[bb_index].Get(); barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; @@ -1845,12 +1856,20 @@ bool REFramework::init_d3d12() { if (SUCCEEDED(swapchain->GetBuffer(i, IID_PPV_ARGS(&m_d3d12.rts[i])))) { device->CreateRenderTargetView(m_d3d12.rts[i].Get(), nullptr, m_d3d12.get_cpu_rtv(device, (D3D12::RTV)i)); } else { - spdlog::error("[D3D12] Failed to get back buffer for rtv."); + spdlog::error("[D3D12] Failed to get back buffer for rtv {}", i); + m_d3d12.rts[i].Reset(); // just in case } } // Create our imgui and blank rts. auto& backbuffer = m_d3d12.get_rt(D3D12::RTV::BACKBUFFER_0); + + if (backbuffer == nullptr) { + spdlog::error("[D3D12] Failed to get first back buffer RTV."); + deinit_d3d12(); + return false; + } + auto desc = backbuffer->GetDesc(); spdlog::info("[D3D12] Back buffer format is {}", desc.Format); From 0c271d07318d7fbfbc01a0473368a3e890afeb4d Mon Sep 17 00:00:00 2001 From: praydog Date: Wed, 13 Mar 2024 11:07:43 -0700 Subject: [PATCH 2/8] Pin kananlib to commit hash --- CMakeLists.txt | 4 ++-- cmake.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a16542832..b423f91e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,13 +123,13 @@ FetchContent_Declare( ) FetchContent_MakeAvailable(bddisasm) -message(STATUS "Fetching kananlib (main)...") +message(STATUS "Fetching kananlib (b0323a0b005fc9e3944e0ea36dcc98eda4b84eea)...") FetchContent_Declare( kananlib GIT_REPOSITORY https://github.com/cursey/kananlib GIT_TAG - main + b0323a0b005fc9e3944e0ea36dcc98eda4b84eea ) FetchContent_MakeAvailable(kananlib) diff --git a/cmake.toml b/cmake.toml index 06fd0407c..c6d34a4af 100644 --- a/cmake.toml +++ b/cmake.toml @@ -171,7 +171,7 @@ tag = "v1.34.10" [fetch-content.kananlib] git = "https://github.com/cursey/kananlib" -tag = "main" +tag = "b0323a0b005fc9e3944e0ea36dcc98eda4b84eea" [target.utility] type = "static" From 0acce8d838d36c0685732d81194d71dc212acdfe Mon Sep 17 00:00:00 2001 From: praydog Date: Wed, 13 Mar 2024 11:07:51 -0700 Subject: [PATCH 3/8] Troubleshooting: Log loaded modules and encountered windows --- src/REFramework.cpp | 15 +++++++++++++++ src/WindowFilter.cpp | 7 +++++++ 2 files changed, 22 insertions(+) diff --git a/src/REFramework.cpp b/src/REFramework.cpp index 5fb85ddf2..b6f4049e4 100644 --- a/src/REFramework.cpp +++ b/src/REFramework.cpp @@ -1683,6 +1683,21 @@ bool REFramework::first_frame_initialize() { m_mods_fully_initialized = true; } + // Troubleshooting by logging loaded modules + // helps us figure out if someone has conflicting software running + try { + spdlog::info("Logging loaded modules..."); + + const auto loaded_modules = utility::get_loaded_module_names(); + + for (const auto& name : loaded_modules) { + spdlog::info("Loaded module: {}", utility::narrow(name)); + } + } catch(...) { + spdlog::error("Failed to get loaded modules."); + } + + return true; } diff --git a/src/WindowFilter.cpp b/src/WindowFilter.cpp index d32d3a8bc..38c4af6fb 100644 --- a/src/WindowFilter.cpp +++ b/src/WindowFilter.cpp @@ -1,3 +1,5 @@ +#include + #include "WindowFilter.hpp" // To prevent usage of statics (TLS breaks the present thread...?) @@ -27,6 +29,11 @@ WindowFilter::WindowFilter() { std::scoped_lock _{m_mutex}; for (const auto hwnd : m_window_jobs) { + char window_name[256]{}; + if (GetWindowTextA(hwnd, window_name, sizeof(window_name)) != 0) { + spdlog::info("[WindowFilter] Encountered new window: {}", window_name); + } + if (is_filtered_nocache(hwnd)) { filter_window(hwnd); } From 8bbe3eb526968ab55f71401a193f88978cd0c4c1 Mon Sep 17 00:00:00 2001 From: praydog Date: Wed, 13 Mar 2024 11:30:22 -0700 Subject: [PATCH 4/8] Troubleshooting: Log callstack of ResizeBuffers/Target --- src/D3D12Hook.cpp | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/D3D12Hook.cpp b/src/D3D12Hook.cpp index 0dc6d0f10..753473c26 100644 --- a/src/D3D12Hook.cpp +++ b/src/D3D12Hook.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -475,6 +476,21 @@ HRESULT WINAPI D3D12Hook::resize_buffers(IDXGISwapChain3* swap_chain, UINT buffe spdlog::info("D3D12 resize buffers called"); spdlog::info(" Parameters: buffer_count {} width {} height {} new_format {} swap_chain_flags {}", buffer_count, width, height, new_format, swap_chain_flags); + // Walk the callstack and print out module names + try { + std::string callstack_str{}; + for (const auto& entry : std::stacktrace::current()) { + //spdlog::info(" {}", entry.description()); + callstack_str += entry.description() + "\n"; + } + + spdlog::info("callstack: \n{}", callstack_str); // because this can be running on a different thread and get garbled in the middle of the log + } catch (const std::exception& e) { + spdlog::error("Failed to print callstack: {}", e.what()); + } catch(...) { + spdlog::error("Failed to print callstack: unknown exception"); + } + auto d3d12 = g_d3d12_hook; //auto& hook = d3d12->m_resize_buffers_hook; //auto resize_buffers_fn = hook->get_original(); @@ -545,6 +561,21 @@ HRESULT WINAPI D3D12Hook::resize_target(IDXGISwapChain3* swap_chain, const DXGI_ spdlog::info("D3D12 resize target called"); spdlog::info(" Parameters: new_target_parameters {:x}", (uintptr_t)new_target_parameters); + // Walk the callstack and print out module names + try { + std::string callstack_str{}; + for (const auto& entry : std::stacktrace::current()) { + //spdlog::info(" {}", entry.description()); + callstack_str += entry.description() + "\n"; + } + + spdlog::info("callstack: \n{}", callstack_str); // because this can be running on a different thread and get garbled in the middle of the log + } catch (const std::exception& e) { + spdlog::error("Failed to print callstack: {}", e.what()); + } catch(...) { + spdlog::error("Failed to print callstack: unknown exception"); + } + auto d3d12 = g_d3d12_hook; //auto resize_target_fn = d3d12->m_resize_target_hook->get_original(); From e206942355177d0c7a6ca0f294acd55c8e26169e Mon Sep 17 00:00:00 2001 From: praydog Date: Fri, 15 Mar 2024 11:58:04 -0700 Subject: [PATCH 5/8] D3D12Hook: Add hook support for Streamline(DLSS3)/FSR3 based swapchains --- src/D3D12Hook.cpp | 43 ++++++++++++++++++++++++++++++++++++++++--- src/D3D12Hook.hpp | 5 +++++ 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/D3D12Hook.cpp b/src/D3D12Hook.cpp index 753473c26..baea8a8ac 100644 --- a/src/D3D12Hook.cpp +++ b/src/D3D12Hook.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include "REFramework.hpp" @@ -225,6 +227,25 @@ bool D3D12Hook::hook() { return false; } + const auto ti = utility::rtti::get_type_info(swap_chain1); + + try { + const auto swapchain_classname = ti != nullptr ? std::string_view{ti->name()} : "unknown"; + + if (swapchain_classname.contains("interposer::DXGISwapChain")) { // DLSS3 + spdlog::info("Found Streamline (DLSSFG) swapchain during dummy initialization: {:x}", (uintptr_t)swap_chain1); + m_using_frame_generation_swapchain = true; + } else if (swapchain_classname.contains("FrameInterpolationSwapChain")) { // FSR3 + spdlog::info("Found FSR3 swapchain during dummy initialization: {:x}", (uintptr_t)swap_chain1); + m_using_frame_generation_swapchain = true; + } + } catch (const std::exception& e) { + spdlog::error("Failed to get type info: {}", e.what()); + } catch (...) { + spdlog::error("Failed to get type info: unknown exception"); + } + + spdlog::info("Finding command queue offset"); // Find the command queue offset in the swapchain @@ -245,9 +266,13 @@ bool D3D12Hook::hook() { } } + auto target_swapchain = swap_chain; + // Scan throughout the swapchain for a valid pointer to scan through // this is usually only necessary for Proton if (m_command_queue_offset == 0) { + bool should_break = false; + for (auto base = 0; base < 512 * sizeof(void*); base += sizeof(void*)) { const auto pre_scan_base = (uintptr_t)swap_chain1 + base; @@ -272,9 +297,21 @@ bool D3D12Hook::hook() { auto data = *(ID3D12CommandQueue**)pre_data; if (data == command_queue) { - m_using_proton_swapchain = true; + // If we hook Streamline's Swapchain, the menu fails to render correctly/flickers + // So we switch out the swapchain with the internal one owned by Streamline + // Side note: Even though we are scanning for Proton here, + // this doubles as an offset scanner for the real swapchain inside Streamline (or FSR3) + if (m_using_frame_generation_swapchain) { + target_swapchain = (IDXGISwapChain3*)scan_base; + } + + if (!m_using_frame_generation_swapchain) { + m_using_proton_swapchain = true; + } + m_command_queue_offset = i; m_proton_swapchain_offset = base; + should_break = true; spdlog::info("Proton potentially detected"); spdlog::info("Found command queue offset: {:x}", i); @@ -282,7 +319,7 @@ bool D3D12Hook::hook() { } } - if (m_using_proton_swapchain) { + if (m_using_proton_swapchain || should_break) { break; } } @@ -303,7 +340,7 @@ bool D3D12Hook::hook() { m_is_phase_1 = true; - auto& present_fn = (*(void***)swap_chain)[8]; // Present + auto& present_fn = (*(void***)target_swapchain)[8]; // Present m_present_hook = std::make_unique(&present_fn, (void*)&D3D12Hook::present); m_hooked = true; } catch (const std::exception& e) { diff --git a/src/D3D12Hook.hpp b/src/D3D12Hook.hpp index f4da0782b..1a3315ac8 100644 --- a/src/D3D12Hook.hpp +++ b/src/D3D12Hook.hpp @@ -89,6 +89,10 @@ class D3D12Hook return m_using_proton_swapchain; } + bool is_framegen_swapchain() const { + return m_using_frame_generation_swapchain; + } + void ignore_next_present() { m_ignore_next_present = true; } @@ -108,6 +112,7 @@ class D3D12Hook uint32_t m_proton_swapchain_offset{}; bool m_using_proton_swapchain{ false }; + bool m_using_frame_generation_swapchain{ false }; bool m_hooked{ false }; bool m_is_phase_1{ true }; bool m_inside_present{false}; From 2185ad8615a2edb0ff255a318b339604f44b6370 Mon Sep 17 00:00:00 2001 From: praydog Date: Thu, 21 Mar 2024 15:07:03 -0700 Subject: [PATCH 6/8] SDK: Fix a bunch of race conditions in type APIs --- shared/sdk/RETypeDB.cpp | 1 + shared/sdk/RETypeDefinition.cpp | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/shared/sdk/RETypeDB.cpp b/shared/sdk/RETypeDB.cpp index 04922f21a..ea697e03c 100644 --- a/shared/sdk/RETypeDB.cpp +++ b/shared/sdk/RETypeDB.cpp @@ -53,6 +53,7 @@ sdk::RETypeDefinition* RETypeDB::find_type(std::string_view name) const { } } + std::unique_lock _{ g_tdb_type_mtx }; return g_tdb_type_map[name.data()]; } diff --git a/shared/sdk/RETypeDefinition.cpp b/shared/sdk/RETypeDefinition.cpp index fdb4e669e..3103dd6b3 100644 --- a/shared/sdk/RETypeDefinition.cpp +++ b/shared/sdk/RETypeDefinition.cpp @@ -380,6 +380,7 @@ sdk::RETypeDefinition* RETypeDefinition::get_underlying_type() const { } } + std::unique_lock _{ g_underlying_mtx }; return g_underlying_types[this]; #else const auto value_field = this->get_field("value__"); @@ -391,6 +392,7 @@ sdk::RETypeDefinition* RETypeDefinition::get_underlying_type() const { const auto underlying_type = value_field->get_type(); + std::unique_lock _{ g_underlying_mtx }; g_underlying_types[this] = underlying_type; return g_underlying_types[this]; #endif @@ -438,6 +440,7 @@ sdk::REField* RETypeDefinition::get_field(std::string_view name) const { } } + std::unique_lock _{ g_field_mtx }; return g_field_map[full_name]; } @@ -499,6 +502,7 @@ sdk::REMethodDefinition* RETypeDefinition::get_method(std::string_view name) con } } + std::unique_lock _{g_method_mtx}; return g_method_map[full_name]; } @@ -943,10 +947,11 @@ ::REManagedObject* RETypeDefinition::get_runtime_type() const { const auto& vm_type = vm->types[this->get_index()]; + std::unique_lock _{g_runtime_type_mtx}; g_runtime_type_map[this] = (::REManagedObject*)vm_type.runtime_type; return g_runtime_type_map[this]; #endif - + std::unique_lock _{g_runtime_type_mtx}; return g_runtime_type_map[this]; } From 2f5c89b3cf3cad8e8b26bc6d23773f51fc6e0a6f Mon Sep 17 00:00:00 2001 From: praydog Date: Thu, 21 Mar 2024 15:19:25 -0700 Subject: [PATCH 7/8] Fix RE7_TDB49 compile failing because of last commit --- shared/sdk/RETypeDefinition.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/shared/sdk/RETypeDefinition.cpp b/shared/sdk/RETypeDefinition.cpp index 3103dd6b3..63884fc39 100644 --- a/shared/sdk/RETypeDefinition.cpp +++ b/shared/sdk/RETypeDefinition.cpp @@ -938,6 +938,9 @@ ::REManagedObject* RETypeDefinition::get_runtime_type() const { } } } + + std::unique_lock _{g_runtime_type_mtx}; + return g_runtime_type_map[this]; #else auto vm = sdk::VM::get(); @@ -951,8 +954,6 @@ ::REManagedObject* RETypeDefinition::get_runtime_type() const { g_runtime_type_map[this] = (::REManagedObject*)vm_type.runtime_type; return g_runtime_type_map[this]; #endif - std::unique_lock _{g_runtime_type_mtx}; - return g_runtime_type_map[this]; } void* RETypeDefinition::get_instance() const { From b1484706baf94f6105eb32ba1c132adf3cabbde7 Mon Sep 17 00:00:00 2001 From: praydog Date: Thu, 21 Mar 2024 18:05:21 -0700 Subject: [PATCH 8/8] Dragons Dogma 2: Fix crashes in retail build --- src/REFramework.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/REFramework.cpp b/src/REFramework.cpp index b6f4049e4..f794e5faa 100644 --- a/src/REFramework.cpp +++ b/src/REFramework.cpp @@ -301,7 +301,7 @@ REFramework::REFramework(HMODULE reframework_module) IntegrityCheckBypass::immediate_patch_re8(); #endif -#if defined(RE4) || defined(SF6) +#if defined(RE4) || defined(SF6) || TDB_VER >= 73 // Fixes new code added in RE4 only. IntegrityCheckBypass::immediate_patch_re4(); #endif