Skip to content

Commit

Permalink
D3D12: Fix DLSSFG swapchains causing flickering/lag issues
Browse files Browse the repository at this point in the history
  • Loading branch information
praydog committed Jul 18, 2024
1 parent 0f75215 commit 11b0815
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 3 deletions.
48 changes: 45 additions & 3 deletions src/hooks/D3D12Hook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <spdlog/spdlog.h>
#include <utility/Thread.hpp>
#include <utility/Module.hpp>
#include <utility/RTTI.hpp>

#include <safetyhook/thread_freezer.hpp>

Expand Down Expand Up @@ -225,8 +226,33 @@ bool D3D12Hook::hook() {
return false;
}

try {
const auto ti = utility::rtti::get_type_info(swap_chain1);
const auto swapchain_classname = ti != nullptr && ti->name() != nullptr ? std::string_view{ti->name()} : "unknown";
const auto raw_name = ti != nullptr && ti->raw_name() != nullptr ? std::string_view{ti->raw_name()} : "unknown";

spdlog::info("Swapchain type info: {}", swapchain_classname);
spdlog::info("Swapchain raw type info: {}", raw_name);

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;
}
// Need to test this one to see if it actually has the same issues - disabling it for now
/*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");

m_command_queue_offset = 0;

// Find the command queue offset in the swapchain
for (auto i = 0; i < 512 * sizeof(void*); i += sizeof(void*)) {
const auto base = (uintptr_t)swap_chain1 + i;
Expand All @@ -245,9 +271,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;

Expand All @@ -272,17 +302,29 @@ 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);
break;
}
}

if (m_using_proton_swapchain) {
if (m_using_proton_swapchain || should_break) {
break;
}
}
Expand All @@ -301,7 +343,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<PointerHook>(&present_fn, (void*)&D3D12Hook::present);
m_hooked = true;
});
Expand Down
5 changes: 5 additions & 0 deletions src/hooks/D3D12Hook.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -114,6 +118,7 @@ class D3D12Hook
std::optional<uint32_t> m_next_present_interval{};

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};
Expand Down

0 comments on commit 11b0815

Please sign in to comment.