From 439d7c9d8dbc7d348964195d340bf2474168ce2b Mon Sep 17 00:00:00 2001 From: Kaldaien Date: Fri, 20 Sep 2024 18:22:06 -0400 Subject: [PATCH] Fixed incorrect display topology caching caused by hashing VBlank statistics as part of SK_RenderBackend_V2::output_s's invariant data --- CHANGELOG.txt | 9 ++- include/SpecialK/DLL_VERSION.H | 4 +- include/SpecialK/render/backend.h | 42 ++++++----- .../render/d3d12/d3d12_command_queue.h | 4 +- include/SpecialK/render/d3d12/d3d12_device.h | 2 +- src/control_panel.cpp | 8 +- src/core.cpp | 3 +- src/diagnostics/compatibility.cpp | 75 ++++++++++++++----- src/imgui/backends/imgui_d3d11.cpp | 2 +- src/imgui/backends/imgui_d3d12.cpp | 2 +- src/nvapi.cpp | 14 ++-- src/osd/text.cpp | 8 +- src/render/d3d12/d3d12.cpp | 18 +++-- src/render/d3d12/d3d12_command_queue.cpp | 20 ++++- src/render/d3d12/d3d12_device.cpp | 31 ++++++-- src/render/dxgi/dxgi.cpp | 72 ++++++++++-------- src/render/dxgi/dxgi_swapchain.cpp | 11 +++ src/render/reflex/reflex.cpp | 2 +- src/render/render_backend.cpp | 23 +++--- src/widgets/hdr.cpp | 4 +- src/window.cpp | 4 +- 21 files changed, 236 insertions(+), 122 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 18947c231..3ae6e73c1 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,4 +1,11 @@ -24.9.20 +24.9.20.1 +========= + + Fixed incorrect display topology caching caused by hashing VBlank statistics + as part of SK_RenderBackend_V2::output_s's invariant data. + + Reworked Streamline initialization for games that load sl.interposer.dll + but have not loaded any plug-ins yet when SK is injected. + +24.9.20 ======= + Add hook on sl.interposer.dll slInit (...) in order to override various Streamline configuration for enhanced compatibility with third-party diff --git a/include/SpecialK/DLL_VERSION.H b/include/SpecialK/DLL_VERSION.H index f8d6945ef..dd9163445 100644 --- a/include/SpecialK/DLL_VERSION.H +++ b/include/SpecialK/DLL_VERSION.H @@ -3,8 +3,8 @@ #define SK_YEAR 24 #define SK_MONTH 9 #define SK_DATE 20 -#define SK_REV_N 0 -#define SK_REV 0 +#define SK_REV_N 1 +#define SK_REV 1 #ifndef _A2 #define _A2(a) #a diff --git a/include/SpecialK/render/backend.h b/include/SpecialK/render/backend.h index deebe4331..7db8a32ad 100644 --- a/include/SpecialK/render/backend.h +++ b/include/SpecialK/render/backend.h @@ -285,24 +285,6 @@ class SK_RenderBackend_V2 : public SK_RenderBackend_V1 monitor_caps = { }; BOOL vrr_enabled = -1; - struct vblank_history_s { - static constexpr int MaxVBlankRecords = 128; - struct record_s { - NvU64 timestamp_qpc = 0; - NvU64 vblank_count = 0; - } records [MaxVBlankRecords]; - NvU32 head = 0; - ULONG64 last_qpc_refreshed = 0; - ULONG64 last_frame_sampled = 0; - float last_average =0.0f; - float last_last_average =0.0f; - NvU32 last_polled_time = 0; - bool addRecord (NvDisplayHandle nv_disp, DXGI_FRAME_STATISTICS *pFrameStats, - NvU64 tNow) noexcept; - float getVBlankHz ( NvU64 tNow) noexcept; - void resetStats ( void) noexcept; - } vblank_counter; - static output_s* getDisplayFromId (NvU32 display_id) noexcept; static output_s* getDisplayFromHandle (NvDisplayHandle display_handle) noexcept; } nvapi; @@ -343,6 +325,30 @@ class SK_RenderBackend_V2 : public SK_RenderBackend_V1 // nits = 0.0 will read the OS preference and apply it bool setSDRWhiteLevel (float nits); + + // Data beyond this point is not static, do not hash it + // + uint8_t cache_end = 0xcd; + + struct statistics_s { + struct vblank_history_s { + static constexpr int MaxVBlankRecords = 128; + struct record_s { + NvU64 timestamp_qpc = 0; + NvU64 vblank_count = 0; + } records [MaxVBlankRecords]; + NvU32 head = 0; + ULONG64 last_qpc_refreshed = 0; + ULONG64 last_frame_sampled = 0; + float last_average =0.0f; + float last_last_average =0.0f; + NvU32 last_polled_time = 0; + bool addRecord (NvDisplayHandle nv_disp, DXGI_FRAME_STATISTICS *pFrameStats, + NvU64 tNow) noexcept; + float getVBlankHz ( NvU64 tNow) noexcept; + void resetStats ( void) noexcept; + } vblank_counter; + } statistics; } displays [_MAX_DISPLAYS]; int active_display = 0; diff --git a/include/SpecialK/render/d3d12/d3d12_command_queue.h b/include/SpecialK/render/d3d12/d3d12_command_queue.h index bd64b1451..765904951 100644 --- a/include/SpecialK/render/d3d12/d3d12_command_queue.h +++ b/include/SpecialK/render/d3d12/d3d12_command_queue.h @@ -1,4 +1,4 @@ -/** +/** * This file is part of Special K. * * Special K is free software : you can redistribute it @@ -30,4 +30,4 @@ D3D12CommandQueue_ExecuteCommandLists_pfn = void extern D3D12CommandQueue_ExecuteCommandLists_pfn D3D12CommandQueue_ExecuteCommandLists_Original; -void SK_D3D12_InstallCommandQueueHooks (ID3D12Device *pDev12); \ No newline at end of file +bool SK_D3D12_InstallCommandQueueHooks (ID3D12Device *pDev12); \ No newline at end of file diff --git a/include/SpecialK/render/d3d12/d3d12_device.h b/include/SpecialK/render/d3d12/d3d12_device.h index 6b4e5a394..958bac822 100644 --- a/include/SpecialK/render/d3d12/d3d12_device.h +++ b/include/SpecialK/render/d3d12/d3d12_device.h @@ -139,7 +139,7 @@ extern D3D12Device9_ShaderCacheControl_pfn D3D12Device9_ShaderCacheControl_Original; bool SK_D3D12_HookDeviceCreation (void); -void SK_D3D12_InstallDeviceHooks (ID3D12Device* pDev12); +bool SK_D3D12_InstallDeviceHooks (ID3D12Device* pDev12); static inline constexpr GUID SKID_D3D12IgnoredTextureCopy = { 0x3d5298cb, 0xd8f0, 0x7233, { 0xa1, 0x9d, 0xb1, 0xd5, 0x97, 0x92, 0x00, 0x70 } }; diff --git a/src/control_panel.cpp b/src/control_panel.cpp index 95afd4e3d..a4f34961a 100644 --- a/src/control_panel.cpp +++ b/src/control_panel.cpp @@ -5350,12 +5350,12 @@ SK_ImGui_ControlPanel (void) if (rb.gsync_state.active) { - auto& nvapi_display = - rb.displays [rb.active_display].nvapi; + auto& stats = + rb.displays [rb.active_display].statistics; float fVBlankHz = - nvapi_display.vblank_counter.getVBlankHz ( - SK_QueryPerf ().QuadPart ); + stats.vblank_counter.getVBlankHz ( + SK_QueryPerf ().QuadPart ); // Is it really "active" if we can't calculate the rate? if (fVBlankHz == 0.0f) diff --git a/src/core.cpp b/src/core.cpp index 7745065b6..b8380f4b9 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -1842,8 +1842,7 @@ SK_StartupCore (const wchar_t* backend, void* callback) // Not a saved INI setting; use an alternate initialization // strategy when Streamline is detected... config.compatibility.init_sync_for_streamline = - (SK_GetModuleHandleW (L"sl.interposer.dll") != 0) && - (SK_GetModuleHandleW (L"sl.dlss_g.dll") != 0); + (SK_GetModuleHandleW (L"sl.interposer.dll") != 0); try { diff --git a/src/diagnostics/compatibility.cpp b/src/diagnostics/compatibility.cpp index 20ffc83e0..fe9f80042 100644 --- a/src/diagnostics/compatibility.cpp +++ b/src/diagnostics/compatibility.cpp @@ -1150,36 +1150,77 @@ SK_COMPAT_CheckStreamlineSupport (void) // } -using PFun_slGetNativeInterface = sl::Result(void* proxyInterface, void** baseInterface); -using PFun_slUpgradeInterface = sl::Result( void** baseInterface); +// It is never necessary to call this, it can be implemented using QueryInterface +using slGetNativeInterface_pfn = sl::Result (*)(void* proxyInterface, void** baseInterface); +// This, on the other hand, requires an import from sl.interposer.dll +using slUpgradeInterface_pfn = sl::Result (*)( void** baseInterface); + +struct DECLSPEC_UUID ("ADEC44E2-61F0-45C3-AD9F-1B37379284FF") + IStreamlineBaseInterface : IUnknown { }; sl::Result SK_slGetNativeInterface (void *proxyInterface, void **baseInterface) { - // Unsafe to do this for local injection - if (SK_IsInjected ()) - { - static PFun_slGetNativeInterface * slGetNativeInterface = - (PFun_slGetNativeInterface *) SK_GetProcAddress (L"sl.interposer.dll", "slGetNativeInterface"); + if (proxyInterface == nullptr || baseInterface == nullptr) + return sl::Result::eErrorMissingInputParameter; - if ( slGetNativeInterface != nullptr) - return slGetNativeInterface (proxyInterface, baseInterface); - } + IUnknown* pUnk = + static_cast (proxyInterface); - return sl::Result::eErrorNotInitialized; + if (FAILED (pUnk->QueryInterface (__uuidof (IStreamlineBaseInterface), baseInterface))) + return sl::Result::eErrorUnsupportedInterface; + + return sl::Result::eOk; } sl::Result SK_slUpgradeInterface (void **baseInterface) { - // Unsafe to do this for local injection - if (SK_IsInjected ()) + if (baseInterface == nullptr) + return sl::Result::eErrorMissingInputParameter; + + IUnknown* pUnkInterface = *(IUnknown **)baseInterface; + void* pProxy = nullptr; + + if (SUCCEEDED (pUnkInterface->QueryInterface (__uuidof (IStreamlineBaseInterface), &pProxy))) + { + // The passed interface already has a proxy, do nothing... + static_cast (pProxy)->Release (); + + return sl::Result::eOk; + } + + // If slInit (...) has not been called yet, sl.common.dll will not be present + if (! SK_IsModuleLoaded (L"sl.common.dll")) + return sl::Result::eErrorInitNotCalled; + + auto slUpgradeInterface = + (slUpgradeInterface_pfn)SK_GetProcAddress (L"sl.interposer.dll", + "slUpgradeInterface"); + + if (slUpgradeInterface != nullptr) { - static PFun_slUpgradeInterface * slUpgradeInterface = - (PFun_slUpgradeInterface *) SK_GetProcAddress (L"sl.interposer.dll", "slUpgradeInterface"); + auto result = + slUpgradeInterface (baseInterface); + + if (result == sl::Result::eOk) + { + static HMODULE + hModPinnedInterposer = nullptr, hModPinnedCommon = nullptr; + if (hModPinnedInterposer == nullptr || hModPinnedCommon == nullptr) + { + // Once we have done this, there's no going back... + // we MUST pin the interposer DLL permanently. + const BOOL bPinnedSL = + (nullptr != hModPinnedInterposer || GetModuleHandleEx (GET_MODULE_HANDLE_EX_FLAG_PIN, L"sl.interposer.dll", &hModPinnedInterposer)) + && (nullptr != hModPinnedCommon || GetModuleHandleEx (GET_MODULE_HANDLE_EX_FLAG_PIN, L"sl.common.dll", &hModPinnedCommon )); + + if (! bPinnedSL) + SK_LOGi0 (L"Streamline Integration Has Invalid State!"); + } + } - if ( slUpgradeInterface != nullptr) - return slUpgradeInterface (baseInterface); + return result; } return sl::Result::eErrorNotInitialized; diff --git a/src/imgui/backends/imgui_d3d11.cpp b/src/imgui/backends/imgui_d3d11.cpp index 7080daed2..b4a6813d5 100644 --- a/src/imgui/backends/imgui_d3d11.cpp +++ b/src/imgui/backends/imgui_d3d11.cpp @@ -1852,7 +1852,7 @@ SK_D3D11_RenderCtx::init (IDXGISwapChain* pSwapChain, auto& rb = SK_GetCurrentRenderBackend (); - rb.displays [rb.active_display].nvapi.vblank_counter.resetStats (); + rb.displays [rb.active_display].statistics.vblank_counter.resetStats (); // Re-apply colorspace if necessary diff --git a/src/imgui/backends/imgui_d3d12.cpp b/src/imgui/backends/imgui_d3d12.cpp index 35a020941..ce3a579fc 100644 --- a/src/imgui/backends/imgui_d3d12.cpp +++ b/src/imgui/backends/imgui_d3d12.cpp @@ -1144,7 +1144,7 @@ ImGui_ImplDX12_Init ( ID3D12Device* device, auto& rb = SK_GetCurrentRenderBackend (); - rb.displays [rb.active_display].nvapi.vblank_counter.resetStats (); + rb.displays [rb.active_display].statistics.vblank_counter.resetStats (); #ifdef SK_D3D12_PERSISTENT_IMGUI_DEV_OBJECTS if (_imgui_d3d12.pDevice.p != _imgui_d3d12.pLastDevice.p) diff --git a/src/nvapi.cpp b/src/nvapi.cpp index 098c0f5ac..030b3dc15 100644 --- a/src/nvapi.cpp +++ b/src/nvapi.cpp @@ -1193,7 +1193,7 @@ NvAPI_Disp_HdrColorControl_Override ( NvU32 displayId, } bool -SK_RenderBackend_V2::output_s::nvapi_ctx_s::vblank_history_s::addRecord (NvDisplayHandle nv_disp, DXGI_FRAME_STATISTICS* pFrameStats, NvU64 tNow) noexcept +SK_RenderBackend_V2::output_s::statistics_s::vblank_history_s::addRecord (NvDisplayHandle nv_disp, DXGI_FRAME_STATISTICS* pFrameStats, NvU64 tNow) noexcept { const SK_RenderBackend& rb = SK_GetCurrentRenderBackend (); @@ -1236,23 +1236,25 @@ SK_RenderBackend_V2::output_s::nvapi_ctx_s::vblank_history_s::addRecord (NvDispl head = std::min (head, (NvU32)MaxVBlankRecords-1); - if (vblank_count > records [head].vblank_count) + // This may not be monotonic increasing if the current monitor changes + // while sampling the data, so only test for inequality. + if (vblank_count != records [head].vblank_count) { if ( head == MaxVBlankRecords-1 ) head = 0; else head++; records [head] = { tNow, vblank_count }; - } - return true; + return true; + } } return false; } void -SK_RenderBackend_V2::output_s::nvapi_ctx_s::vblank_history_s::resetStats (void) noexcept +SK_RenderBackend_V2::output_s::statistics_s::vblank_history_s::resetStats (void) noexcept { for (auto& record : records) { @@ -1266,7 +1268,7 @@ SK_RenderBackend_V2::output_s::nvapi_ctx_s::vblank_history_s::resetStats (void) } float -SK_RenderBackend_V2::output_s::nvapi_ctx_s::vblank_history_s::getVBlankHz (NvU64 tNow) noexcept +SK_RenderBackend_V2::output_s::statistics_s::vblank_history_s::getVBlankHz (NvU64 tNow) noexcept { NvU32 num_vblanks_in_period = 0; diff --git a/src/osd/text.cpp b/src/osd/text.cpp index 7983c16a2..d0e5da69b 100644 --- a/src/osd/text.cpp +++ b/src/osd/text.cpp @@ -857,12 +857,12 @@ SK_DrawOSD (void) if (gsync) { - auto& nvapi_display = - rb.displays [rb.active_display].nvapi; + auto& stats = + rb.displays [rb.active_display].statistics; fVBlankHz = - nvapi_display.vblank_counter.getVBlankHz ( - SK_QueryPerf ().QuadPart ); + stats.vblank_counter.getVBlankHz ( + SK_QueryPerf ().QuadPart ); } if (fabs (mean - INFINITY) > std::numeric_limits ::epsilon ()) diff --git a/src/render/d3d12/d3d12.cpp b/src/render/d3d12/d3d12.cpp index 07db4fde0..98c4f7513 100644 --- a/src/render/d3d12/d3d12.cpp +++ b/src/render/d3d12/d3d12.cpp @@ -99,7 +99,12 @@ HookD3D12 (LPVOID user) dll_log->Log (L"[ D3D 12 ] Hooking D3D12"); - if (SK_D3D12_Init ()) + bool hooked_create_device = SK_D3D12_Init (); + bool need_additional_hooks = + SK_D3D12_InstallDeviceHooks (nullptr) == false || + SK_D3D12_InstallCommandQueueHooks (nullptr) == false; + + if (hooked_create_device && need_additional_hooks) { SK_ComPtr pDevice; @@ -137,8 +142,6 @@ HookD3D12 (LPVOID user) { SK_D3D12_InstallDeviceHooks (pDevice.p); SK_D3D12_InstallCommandQueueHooks (pDevice.p); - - SK_ApplyQueuedHooks (); } } } @@ -164,10 +167,13 @@ SK_D3D12_HotSwapChainHook ( IDXGISwapChain3* pSwapChain, if ( pDev12 != nullptr && D3D12Device_CreateRenderTargetView_Original == nullptr ) { - SK_D3D12_InstallDeviceHooks (pDev12); - SK_D3D12_InstallCommandQueueHooks (pDev12); + bool new_hooks = false; - SK_ApplyQueuedHooks (); + new_hooks |= SK_D3D12_InstallDeviceHooks (pDev12); + new_hooks |= SK_D3D12_InstallCommandQueueHooks (pDev12); + + if (new_hooks) + SK_ApplyQueuedHooks (); init = true; } diff --git a/src/render/d3d12/d3d12_command_queue.cpp b/src/render/d3d12/d3d12_command_queue.cpp index ee1b792a2..42476f259 100644 --- a/src/render/d3d12/d3d12_command_queue.cpp +++ b/src/render/d3d12/d3d12_command_queue.cpp @@ -187,7 +187,7 @@ _InstallCommandQueueHooksImpl (ID3D12Device* pDevice12) return; const bool bHasStreamline = - SK_IsModuleLoaded (L"sl.dlss_g.dll"); + SK_IsModuleLoaded (L"sl.interposer.dll"); SK_ComPtr pDev12; @@ -212,8 +212,22 @@ _InstallCommandQueueHooksImpl (ID3D12Device* pDevice12) } } -void +bool SK_D3D12_InstallCommandQueueHooks (ID3D12Device *pDev12) { - SK_RunOnce (_InstallCommandQueueHooksImpl (pDev12)); + static bool s_Init = false; + + // Check the status of hooks + if (pDev12 == nullptr) + return s_Init; + + // Actually install hooks... once. + if (! std::exchange (s_Init, true)) + { + _InstallCommandQueueHooksImpl (pDev12); + + return true; + } + + return false; } \ No newline at end of file diff --git a/src/render/d3d12/d3d12_device.cpp b/src/render/d3d12/d3d12_device.cpp index 085e39db8..011381852 100644 --- a/src/render/d3d12/d3d12_device.cpp +++ b/src/render/d3d12/d3d12_device.cpp @@ -2308,7 +2308,7 @@ _InstallDeviceHooksImpl (ID3D12Device* pDevice12) return; const bool bHasStreamline = - SK_IsModuleLoaded (L"sl.dlss_g.dll"); + SK_IsModuleLoaded (L"sl.interposer.dll"); SK_ComPtr pDev12; @@ -2562,10 +2562,24 @@ _InstallDeviceHooksImpl (ID3D12Device* pDevice12) } } } -void +bool SK_D3D12_InstallDeviceHooks (ID3D12Device *pDev12) { - SK_RunOnce (_InstallDeviceHooksImpl (pDev12)); + static bool s_Init = false; + + // Check the status of hooks + if (pDev12 == nullptr) + return s_Init; + + // Actually install hooks... once. + if (! std::exchange (s_Init, true)) + { + _InstallDeviceHooksImpl (pDev12); + + return true; + } + + return false; } D3D12CreateDevice_pfn D3D12CreateDevice_Import = nullptr; @@ -2630,10 +2644,13 @@ D3D12CreateDevice_Detour ( ); } - SK_RunOnce ({ - SK_D3D12_InstallDeviceHooks (*(ID3D12Device **)ppDevice); - SK_D3D12_InstallCommandQueueHooks (*(ID3D12Device **)ppDevice); - }); + bool new_hooks = false; + + new_hooks |= SK_D3D12_InstallDeviceHooks (*(ID3D12Device **)ppDevice); + new_hooks |= SK_D3D12_InstallCommandQueueHooks (*(ID3D12Device **)ppDevice); + + if (new_hooks) + SK_ApplyQueuedHooks (); } return res; diff --git a/src/render/dxgi/dxgi.cpp b/src/render/dxgi/dxgi.cpp index cca3571a4..0a083a4cf 100644 --- a/src/render/dxgi/dxgi.cpp +++ b/src/render/dxgi/dxgi.cpp @@ -552,6 +552,10 @@ static volatile LONG __dxgi_ready = FALSE; void WaitForInitDXGI (void) { + // Waiting while Streamline has plugins loaded would deadlock us in local injection + if (SK_IsModuleLoaded (L"sl.common.dll")) + return; + // This is a hybrid spin; it will spin for up to 250 iterations before sleeping SK_Thread_SpinUntilFlagged (&__dxgi_ready); } @@ -8986,7 +8990,7 @@ SK_DXGI_HookSwapChain (IDXGISwapChain* pProxySwapChain) return; const bool bHasStreamline = - SK_IsModuleLoaded (L"sl.dlss_g.dll"); + SK_IsModuleLoaded (L"sl.interposer.dll"); SK_ComPtr pSwapChain; @@ -9198,7 +9202,7 @@ SK_DXGI_HookDevice1 (IDXGIDevice1* pProxyDevice) return; const bool bHasStreamline = - SK_IsModuleLoaded (L"sl.dlss_g.dll"); + SK_IsModuleLoaded (L"sl.interposer.dll"); SK_ComPtr pDevice; @@ -9351,7 +9355,7 @@ SK_DXGI_HookFactory (IDXGIFactory* pProxyFactory) return; const bool bHasStreamline = - SK_IsModuleLoaded (L"sl.dlss_g.dll"); + SK_IsModuleLoaded (L"sl.interposer.dll"); SK_ComPtr pFactory; @@ -9553,6 +9557,9 @@ SK_DXGI_SafeCreateSwapChain ( IDXGIFactory *pFactory, return E_NOTIMPL; } +#include +#include + DWORD __stdcall HookDXGI (LPVOID user) @@ -9685,7 +9692,7 @@ HookDXGI (LPVOID user) bool bHookSuccess = false; - bool bHasStreamline = SK_IsModuleLoaded (L"sl.dlss_g.dll"); + bool bHasStreamline = SK_IsModuleLoaded (L"sl.interposer.dll"); HRESULT hr = E_NOTIMPL; SK_ComPtr @@ -9713,6 +9720,9 @@ HookDXGI (LPVOID user) SK_ComPtr pFactory; CreateDXGIFactory2_Import ( factory_flags, __uuidof (IDXGIFactory), (void **)&pFactory.p); + + SK_slUpgradeInterface ((void **)&pFactory.p); + SK_ComQIPtr pFactory7 (pFactory); if (pFactory7 != nullptr) @@ -9737,8 +9747,6 @@ HookDXGI (LPVOID user) // that requires NVIDIA's DXGI/Vulkan interop layer if (bStreamlineMode || bReShadeMode) { - SK_slUpgradeInterface ((void **)&pFactory.p); - using D3D12CreateDevice_pfn = HRESULT (WINAPI *)( IUnknown *pAdapter, D3D_FEATURE_LEVEL MinimumFeatureLevel, @@ -9798,6 +9806,14 @@ HookDXGI (LPVOID user) if (SUCCEEDED (D3D12CreateDevice (pAdapter0, D3D_FEATURE_LEVEL_11_1, IID_PPV_ARGS (&pDevice12.p)))) { + if (SK_slGetNativeInterface (pDevice12.p, (void **)&pNativeDevice12.p) == sl::Result::eOk) + { _ExchangeProxyForNative (pDevice12, pNativeDevice12); + SK_LOGi0 (L"Got Native Interface for Streamline Proxy'd D3D12 Device..."); + } + + SK_D3D12_InstallDeviceHooks (pDevice12.p); + SK_D3D12_InstallCommandQueueHooks (pDevice12.p); + if (sl::Result::eOk == SK_slUpgradeInterface ((void **)&pDevice12.p)) SK_LOGi0 (L"Upgraded D3D12 Device to Streamline Proxy..."); @@ -9807,9 +9823,6 @@ HookDXGI (LPVOID user) queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; pDevice12->CreateCommandQueue (&queue_desc, IID_PPV_ARGS (&pCmdQueue.p)); - - if (sl::Result::eOk == SK_slUpgradeInterface ((void **)&pCmdQueue.p)) - SK_LOGi0 (L"Upgraded D3D12 Command Queue to Streamline Proxy..."); } } @@ -9829,26 +9842,19 @@ HookDXGI (LPVOID user) if (bHasStreamline) { - pSwapChain.p->AddRef (); - - if (SK_slGetNativeInterface (pSwapChain.p, (void **)&pNativeSwapChain.p) == sl::Result::eOk) - { _ExchangeProxyForNative (pSwapChain, pNativeSwapChain); - SK_LOGi0 (L"Got Native Interface for Streamline Proxy'd DXGI SwapChain..."); - - if (SK_slGetNativeInterface (pFactory.p, (void **)&pNativeFactory.p) == sl::Result::eOk) - { _ExchangeProxyForNative (pFactory, pNativeFactory); - SK_LOGi0 (L"Got Native Interface for Streamline Proxy'd DXGI Factory..."); - } + if (SK_slGetNativeInterface (pFactory.p, (void **)&pNativeFactory.p) == sl::Result::eOk) + { _ExchangeProxyForNative (pFactory, pNativeFactory); + SK_LOGi0 (L"Got Native Interface for Streamline Proxy'd DXGI Factory..."); + } - if (SK_slGetNativeInterface (pDevice.p, (void **)&pNativeDevice.p) == sl::Result::eOk) - { _ExchangeProxyForNative (pDevice, pNativeDevice); - SK_LOGi0 (L"Got Native Interface for Streamline Proxy'd D3D11 Device..."); - } + if (SK_slGetNativeInterface (pDevice.p, (void **)&pNativeDevice.p) == sl::Result::eOk) + { _ExchangeProxyForNative (pDevice, pNativeDevice); + SK_LOGi0 (L"Got Native Interface for Streamline Proxy'd D3D11 Device..."); + } - if (SK_slGetNativeInterface (pImmediateContext.p, (void **)&pNativeImmediateContext.p) == sl::Result::eOk) - { _ExchangeProxyForNative (pImmediateContext, pNativeImmediateContext); - SK_LOGi0 (L"Got Native Interface for Streamline Proxy'd D3D11 Immediate Context..."); - } + if (SK_slGetNativeInterface (pImmediateContext.p, (void **)&pNativeImmediateContext.p) == sl::Result::eOk) + { _ExchangeProxyForNative (pImmediateContext, pNativeImmediateContext); + SK_LOGi0 (L"Got Native Interface for Streamline Proxy'd D3D11 Immediate Context..."); } } @@ -9888,8 +9894,6 @@ HookDXGI (LPVOID user) if (SUCCEEDED (hr)) { - SK_DXGI_SafeCreateSwapChain (pFactory, pDevice.p, &desc, &pSwapChain.p); - if (SK_slGetNativeInterface (pFactory, (void **)&pNativeFactory.p) == sl::Result::eOk) _ExchangeProxyForNative (pFactory, pNativeFactory); @@ -9899,8 +9903,7 @@ HookDXGI (LPVOID user) if (SK_slGetNativeInterface (pImmediateContext.p, (void **)&pNativeImmediateContext.p) == sl::Result::eOk) _ExchangeProxyForNative (pImmediateContext, pNativeImmediateContext); - if (SK_slGetNativeInterface (pSwapChain.p, (void **)&pNativeSwapChain.p) == sl::Result::eOk) - _ExchangeProxyForNative (pSwapChain, pNativeSwapChain); + SK_DXGI_SafeCreateSwapChain (pFactory, pDevice.p, &desc, &pSwapChain.p); sk_hook_d3d11_t d3d11_hook_ctx = { &pDevice.p, &pImmediateContext.p }; @@ -9916,6 +9919,11 @@ HookDXGI (LPVOID user) { if (pSwapChain != nullptr) { + if (SK_slGetNativeInterface (pSwapChain.p, (void **)&pNativeSwapChain.p) == sl::Result::eOk) { + pSwapChain.p->AddRef (); // Leak the SwapChain to avoid crashes in Nixxes games + _ExchangeProxyForNative (pSwapChain, pNativeSwapChain); + } + SK_DXGI_HookSwapChain (pSwapChain); } @@ -10883,7 +10891,7 @@ SK_DXGI_QuickHook (void) __SK_DisableQuickHook = TRUE; } - if ( SK_IsModuleLoaded (L"sl.dlss_g.dll") ) + if ( SK_IsModuleLoaded (L"sl.interposer.dll") ) { SK_LOGi0 (L" # DXGI QuickHook disabled because an NVIDIA Streamline Interposer is present..."); diff --git a/src/render/dxgi/dxgi_swapchain.cpp b/src/render/dxgi/dxgi_swapchain.cpp index 36f3956a3..01a27f59a 100644 --- a/src/render/dxgi/dxgi_swapchain.cpp +++ b/src/render/dxgi/dxgi_swapchain.cpp @@ -124,6 +124,9 @@ IWrapDXGISwapChain::RegisterDestructionCallback (void) E_NOTIMPL; } +struct DECLSPEC_UUID ("ADEC44E2-61F0-45C3-AD9F-1B37379284FF") + IStreamlineBaseInterface : IUnknown { }; + // IDXGISwapChain HRESULT STDMETHODCALLTYPE @@ -143,6 +146,14 @@ IWrapDXGISwapChain::QueryInterface (REFIID riid, void **ppvObj) return S_OK; } + // Keep SwapChain wrapping the hell away from Streamline! + else if (riid == __uuidof (IStreamlineBaseInterface)) + { + SK_LOGi1 (L"Tried to get Streamline Base Interface for a SwapChain that SK has wrapped..."); + + return E_NOINTERFACE; + } + else if ( riid == __uuidof (IWrapDXGISwapChain) || riid == __uuidof (IUnknown) || diff --git a/src/render/reflex/reflex.cpp b/src/render/reflex/reflex.cpp index b9da4af36..3354fecd8 100644 --- a/src/render/reflex/reflex.cpp +++ b/src/render/reflex/reflex.cpp @@ -783,7 +783,7 @@ SK_NV_AdaptiveSyncControl (void) } float fEffectiveRefresh = - rb.displays [rb.active_display].nvapi.vblank_counter.getVBlankHz (SK_QueryPerf ().QuadPart); + rb.displays [rb.active_display].statistics.vblank_counter.getVBlankHz (SK_QueryPerf ().QuadPart); ImGui::Text ("Adaptive Sync Status for %hs", SK_WideCharToUTF8 (rb.display_name).c_str ()); ImGui::Separator (); diff --git a/src/render/render_backend.cpp b/src/render/render_backend.cpp index 7b972fd59..c199000b5 100644 --- a/src/render/render_backend.cpp +++ b/src/render/render_backend.cpp @@ -4145,7 +4145,7 @@ SK_RenderBackend_V2::updateOutputTopology (void) display_crc [idx] = crc32c ( 0, &display, - display_size ); + offsetof (SK_RenderBackend_V2::output_s, cache_end) - sizeof (SK_RenderBackend_V2::output_s::cache_end) ); display_changed [idx] = old_crc != display_crc [idx]; @@ -4866,8 +4866,7 @@ SK_Render_CountVBlanks () static HANDLE hVRREvent = SK_CreateEvent (nullptr, FALSE, FALSE, nullptr); - SK_RunOnce ( - { + static HANDLE hVBlankThread = SK_Thread_CreateEx ([](LPVOID) -> DWORD { DXGI_FRAME_STATISTICS @@ -4902,15 +4901,17 @@ SK_Render_CountVBlanks () auto& nvapi_display = rb.displays [rb.active_display].nvapi; + auto& stats = + rb.displays [rb.active_display].statistics; const ULONGLONG& kSyncQPC = (ULONGLONG &)frameStats.SyncQPCTime.QuadPart; - if (nvapi_display.vblank_counter.last_qpc_refreshed < kSyncQPC && - nvapi_display.vblank_counter.addRecord ( + if (stats.vblank_counter.last_qpc_refreshed < kSyncQPC && + stats.vblank_counter.addRecord ( nvapi_display.display_handle, &frameStats, kSyncQPC)) { - nvapi_display.vblank_counter.last_qpc_refreshed = + stats.vblank_counter.last_qpc_refreshed = kSyncQPC; } } @@ -4927,6 +4928,9 @@ SK_Render_CountVBlanks () auto& nvapi_display = rb.displays [rb.active_display].nvapi; + auto& stats = + rb.displays [rb.active_display].statistics; + if (nvapi_display.display_handle != nullptr) { bool got_new_reading = false; @@ -4936,11 +4940,11 @@ SK_Render_CountVBlanks () const auto current_frame = SK_GetFramesDrawn (); - if (nvapi_display.vblank_counter.last_frame_sampled < current_frame && - nvapi_display.vblank_counter.addRecord ( + if (stats.vblank_counter.last_frame_sampled < current_frame && + stats.vblank_counter.addRecord ( nvapi_display.display_handle, nullptr, SK_QueryPerf ().QuadPart)) { - nvapi_display.vblank_counter.last_frame_sampled = current_frame; + stats.vblank_counter.last_frame_sampled = current_frame; got_new_reading = true; } @@ -4960,7 +4964,6 @@ SK_Render_CountVBlanks () return 0; }, L"[SK] VBlank Counter", nullptr); - }); SetEvent (hVRREvent); } \ No newline at end of file diff --git a/src/widgets/hdr.cpp b/src/widgets/hdr.cpp index 1e835cd0c..80b2f6531 100644 --- a/src/widgets/hdr.cpp +++ b/src/widgets/hdr.cpp @@ -1251,10 +1251,10 @@ class SKWG_HDR_Control : public SK_Widget, SK_IVariableListener } } - static const bool bStreamline = + static const bool bStreamlineDLSSG = SK_IsModuleLoaded (L"sl.dlss_g.dll"); - if (bStreamline && ImGui::IsItemHovered ()) + if (bStreamlineDLSSG && ImGui::IsItemHovered ()) { ImGui::BeginTooltip ( ); { diff --git a/src/window.cpp b/src/window.cpp index f5c55c796..7c2183493 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -4946,8 +4946,8 @@ GetForegroundWindow_Detour (void) // this would be catastrophic. if (game_window.hWnd != 0 && IsWindow (game_window.hWnd)) { - if ((! rb.isTrueFullscreen ()) || SK_IsModuleLoaded (L"sl.dlss_g.dll")) - { // Frame Pacing Has Problems w/o this + if (! rb.isTrueFullscreen ()) + { if ( SK_WantBackgroundRender () || config.window.always_on_top == SmartAlwaysOnTop || config.window.treat_fg_as_active ) {