From 69b2d629382cdc475b0cc316cb866c1ff7422a35 Mon Sep 17 00:00:00 2001 From: cdozdil Date: Sun, 10 Nov 2024 00:34:44 +0300 Subject: [PATCH] stash --- OptiScaler/OptiScaler.vcxproj | 14 +- OptiScaler/apis/NVNGX_DLSS_Dx11.cpp | 50 +- OptiScaler/apis/NVNGX_DLSS_Vk.cpp | 21 +- OptiScaler/apis/XeSS_Dx12.cpp | 1 - OptiScaler/dllmain.cpp | 118 +- OptiScaler/exports/Dxgi.cpp | 107 +- OptiScaler/exports/Dxgi.h | 15 +- OptiScaler/hooks/Dxgi.cpp | 532 +++++++ OptiScaler/hooks/Dxgi.h | 10 + OptiScaler/hooks/Hooks.cpp | 6 - OptiScaler/hooks/Hooks.h | 8 - OptiScaler/hooks/LoadLibrary.cpp | 168 +-- OptiScaler/menu/MenuDx11.cpp | 1322 +++++++++++++++++ OptiScaler/menu/MenuDx11.h | 25 + OptiScaler/menu/{MenuDx.cpp => MenuDx12.cpp} | 309 +--- OptiScaler/menu/{MenuDx.h => MenuDx12.h} | 0 OptiScaler/menu/MenuVulkan.cpp | 33 +- OptiScaler/menu/MenuVulkan.h | 3 + .../WrappedSwapChain.cpp} | 28 +- .../WrappedSwapChain.h} | 8 +- OptiScaler/proxies/FfxApi_Proxy.h | 16 +- OptiScaler/proxies/NVNGX_Proxy.h | 162 +- 22 files changed, 2179 insertions(+), 777 deletions(-) create mode 100644 OptiScaler/hooks/Dxgi.cpp create mode 100644 OptiScaler/hooks/Dxgi.h delete mode 100644 OptiScaler/hooks/Hooks.cpp delete mode 100644 OptiScaler/hooks/Hooks.h create mode 100644 OptiScaler/menu/MenuDx11.cpp create mode 100644 OptiScaler/menu/MenuDx11.h rename OptiScaler/menu/{MenuDx.cpp => MenuDx12.cpp} (80%) rename OptiScaler/menu/{MenuDx.h => MenuDx12.h} (100%) rename OptiScaler/{menu/wrapped_swapchain.cpp => objects/WrappedSwapChain.cpp} (79%) rename OptiScaler/{menu/wrapped_swapchain.h => objects/WrappedSwapChain.h} (96%) diff --git a/OptiScaler/OptiScaler.vcxproj b/OptiScaler/OptiScaler.vcxproj index 25bcf297..d61eef78 100644 --- a/OptiScaler/OptiScaler.vcxproj +++ b/OptiScaler/OptiScaler.vcxproj @@ -191,9 +191,11 @@ copy $(SolutionDir)nvngx.ini $(SolutionDir)x64\Release\a\ - + + + @@ -260,9 +262,8 @@ copy $(SolutionDir)nvngx.ini $(SolutionDir)x64\Release\a\ - - + @@ -279,9 +280,11 @@ copy $(SolutionDir)nvngx.ini $(SolutionDir)x64\Release\a\ - + + + @@ -327,9 +330,8 @@ copy $(SolutionDir)nvngx.ini $(SolutionDir)x64\Release\a\ - - + diff --git a/OptiScaler/apis/NVNGX_DLSS_Dx11.cpp b/OptiScaler/apis/NVNGX_DLSS_Dx11.cpp index c9497a4f..9713d5d5 100644 --- a/OptiScaler/apis/NVNGX_DLSS_Dx11.cpp +++ b/OptiScaler/apis/NVNGX_DLSS_Dx11.cpp @@ -1,18 +1,18 @@ -#include "pch.h" +#include -#include "Util.h" -#include "Config.h" +#include +#include +#include #include "NVNGX_Parameter.h" -#include "proxies/NVNGX_Proxy.h" -#include "menu/imgui_overlay_dx.h" -#include "upscalers/dlss/DLSSFeature_Dx11.h" -#include "upscalers/dlssd/DLSSDFeature_Dx11.h" -#include "upscalers/fsr2/FSR2Feature_Dx11.h" -#include "upscalers/fsr2/FSR2Feature_Dx11On12.h" -#include "upscalers/fsr2_212/FSR2Feature_Dx11On12_212.h" -#include "upscalers/fsr31/FSR31Feature_Dx11.h" -#include "upscalers/fsr31/FSR31Feature_Dx11On12.h" -#include "upscalers/xess/XeSSFeature_Dx11.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include #include @@ -90,11 +90,11 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D11_Init_Ext(unsigned long long InApp D3D11_QUERY_DESC timestampQueryDesc = {}; timestampQueryDesc.Query = D3D11_QUERY_TIMESTAMP; - for (int i = 0; i < ImGuiOverlayDx::QUERY_BUFFER_COUNT; i++) + for (int i = 0; i < MenuDx::QUERY_BUFFER_COUNT; i++) { - InDevice->CreateQuery(&disjointQueryDesc, &ImGuiOverlayDx::disjointQueries[i]); - InDevice->CreateQuery(×tampQueryDesc, &ImGuiOverlayDx::startQueries[i]); - InDevice->CreateQuery(×tampQueryDesc, &ImGuiOverlayDx::endQueries[i]); + InDevice->CreateQuery(&disjointQueryDesc, &MenuDx::disjointQueries[i]); + InDevice->CreateQuery(×tampQueryDesc, &MenuDx::startQueries[i]); + InDevice->CreateQuery(×tampQueryDesc, &MenuDx::endQueries[i]); } return NVSDK_NGX_Result_Success; @@ -208,7 +208,7 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D11_Shutdown() // Unhooking and cleaning stuff causing issues during shutdown. // Disabled for now to check if it cause any issues - //ImGuiOverlayDx::UnHookDx(); + //MenuDx::UnHookDx(); shutdown = false; @@ -831,12 +831,12 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D11_EvaluateFeature(ID3D11DeviceConte } // In the render loop: - ImGuiOverlayDx::previousFrameIndex = (ImGuiOverlayDx::currentFrameIndex + ImGuiOverlayDx::QUERY_BUFFER_COUNT - 2) % ImGuiOverlayDx::QUERY_BUFFER_COUNT; - int nextFrameIndex = ImGuiOverlayDx::currentFrameIndex; + MenuDx::previousFrameIndex = (MenuDx::currentFrameIndex + MenuDx::QUERY_BUFFER_COUNT - 2) % MenuDx::QUERY_BUFFER_COUNT; + int nextFrameIndex = MenuDx::currentFrameIndex; // Record the queries in the current frame - InDevCtx->Begin(ImGuiOverlayDx::disjointQueries[nextFrameIndex]); - InDevCtx->End(ImGuiOverlayDx::startQueries[nextFrameIndex]); + InDevCtx->Begin(MenuDx::disjointQueries[nextFrameIndex]); + InDevCtx->End(MenuDx::startQueries[nextFrameIndex]); if (!deviceContext->Evaluate(InDevCtx, InParameters) && !deviceContext->IsInited() && (deviceContext->Name() == "XeSS" || deviceContext->Name() == "DLSS" || deviceContext->Name() == "FSR3 w/Dx12")) { @@ -844,10 +844,10 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D11_EvaluateFeature(ID3D11DeviceConte Config::Instance()->changeBackend = true; } - InDevCtx->End(ImGuiOverlayDx::endQueries[nextFrameIndex]); - InDevCtx->End(ImGuiOverlayDx::disjointQueries[nextFrameIndex]); + InDevCtx->End(MenuDx::endQueries[nextFrameIndex]); + InDevCtx->End(MenuDx::disjointQueries[nextFrameIndex]); - ImGuiOverlayDx::dx11UpscaleTrig[nextFrameIndex] = true; + MenuDx::dx11UpscaleTrig[nextFrameIndex] = true; return NVSDK_NGX_Result_Success; } diff --git a/OptiScaler/apis/NVNGX_DLSS_Vk.cpp b/OptiScaler/apis/NVNGX_DLSS_Vk.cpp index 16afb85b..5d116825 100644 --- a/OptiScaler/apis/NVNGX_DLSS_Vk.cpp +++ b/OptiScaler/apis/NVNGX_DLSS_Vk.cpp @@ -50,6 +50,8 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_VULKAN_Init_Ext(unsigned long long InAp } } + MenuVulkan::PrepareTimeObjects(InInstance, InPD, InDevice); + return NVSDK_NGX_VULKAN_Init_Ext2(InApplicationId, InApplicationDataPath, InInstance, InPD, InDevice, vkGetInstanceProcAddr, vkGetDeviceProcAddr, InSDKVersion, InFeatureInfo); } @@ -156,16 +158,6 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_VULKAN_Init_Ext2(unsigned long long InA Config::Instance()->Api = NVNGX_VULKAN; - VkQueryPoolCreateInfo queryPoolInfo = {}; - queryPoolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; - queryPoolInfo.queryType = VK_QUERY_TYPE_TIMESTAMP; - queryPoolInfo.queryCount = 2; // Start and End timestamps - - vkCreateQueryPool(InDevice, &queryPoolInfo, nullptr, &ImGuiOverlayVk::queryPool); - - VkPhysicalDeviceProperties deviceProperties; - vkGetPhysicalDeviceProperties(InPD, &deviceProperties); - ImGuiOverlayVk::timeStampPeriod = deviceProperties.limits.timestampPeriod; return NVSDK_NGX_Result_Success; } @@ -957,14 +949,9 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_VULKAN_EvaluateFeature(VkCommandBuffer Config::Instance()->RenderMenu = true; - // Record the first timestamp (before FSR2) - vkCmdWriteTimestamp(InCmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, ImGuiOverlayVk::queryPool, 0); - + MenuVulkan::BeforeUpscale(InCmdBuffer); auto upscaleResult = deviceContext->Evaluate(InCmdBuffer, InParameters); - - // Record the second timestamp (after FSR2) - vkCmdWriteTimestamp(InCmdBuffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, ImGuiOverlayVk::queryPool, 1); - ImGuiOverlayVk::vkUpscaleTrig = true; + MenuVulkan::AfterUpscale(InCmdBuffer); return upscaleResult ? NVSDK_NGX_Result_Success : NVSDK_NGX_Result_Fail; } diff --git a/OptiScaler/apis/XeSS_Dx12.cpp b/OptiScaler/apis/XeSS_Dx12.cpp index aef376b0..3b595350 100644 --- a/OptiScaler/apis/XeSS_Dx12.cpp +++ b/OptiScaler/apis/XeSS_Dx12.cpp @@ -6,7 +6,6 @@ #include "NVNGX_Parameter.h" #include "xess_d3d12_debug.h" #include "proxies/XeSS_Proxy.h" -#include "menu/imgui_overlay_dx.h" typedef struct MotionScale { diff --git a/OptiScaler/dllmain.cpp b/OptiScaler/dllmain.cpp index 4c8a5979..60ed4b34 100644 --- a/OptiScaler/dllmain.cpp +++ b/OptiScaler/dllmain.cpp @@ -4,107 +4,27 @@ #include "Logger.h" #include "resource.h" #include "WorkingMode.h" +#include "hooks/LoadLibrary.h" #include "proxies/NVNGX_Proxy.h" #include "proxies/FfxApi_Proxy.h" #include "proxies/XeSS_Proxy.h" -void AttachHooks(); -void DetachHooks(); -HMODULE LoadNvApi(); -HMODULE LoadNvgxDlss(std::wstring originalPath); - -static HMODULE LoadNvApi() -{ - HMODULE nvapi = nullptr; - - if (Config::Instance()->NvapiDllPath.has_value()) - { - nvapi = o_LoadLibraryW(Config::Instance()->NvapiDllPath->c_str()); - - if (nvapi != nullptr) - { - LOG_INFO("nvapi64.dll loaded from {0}", wstring_to_string(Config::Instance()->NvapiDllPath.value())); - return nvapi; - } - } - - if (nvapi == nullptr) - { - auto localPath = Util::DllPath().parent_path() / L"nvapi64.dll"; - nvapi = o_LoadLibraryW(localPath.wstring().c_str()); - - if (nvapi != nullptr) - { - LOG_INFO("nvapi64.dll loaded from {0}", wstring_to_string(localPath.wstring())); - return nvapi; - } - } - - if (nvapi == nullptr) - { - nvapi = o_LoadLibraryW(L"nvapi64.dll"); - - if (nvapi != nullptr) - { - LOG_WARN("nvapi64.dll loaded from system!"); - return nvapi; - } - } - - return nullptr; -} - -static HMODULE LoadNvgxDlss(std::wstring originalPath) -{ - HMODULE nvngxDlss = nullptr; - - if (Config::Instance()->NVNGX_DLSS_Library.has_value()) - { - nvngxDlss = o_LoadLibraryW(Config::Instance()->NVNGX_DLSS_Library.value().c_str()); - - if (nvngxDlss != nullptr) - { - LOG_INFO("nvngx_dlss.dll loaded from {0}", wstring_to_string(Config::Instance()->NVNGX_DLSS_Library.value())); - return nvngxDlss; - } - else - { - LOG_WARN("nvngx_dlss.dll can't found at {0}", wstring_to_string(Config::Instance()->NVNGX_DLSS_Library.value())); - } - } - - if (nvngxDlss == nullptr) - { - nvngxDlss = o_LoadLibraryW(originalPath.c_str()); - - if (nvngxDlss != nullptr) - { - LOG_INFO("nvngx_dlss.dll loaded from {0}", wstring_to_string(originalPath)); - return nvngxDlss; - } - } - - return nullptr; -} - BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: - if (loadCount > 1) + if (LoadLibraryHooks::LoadCount() > 1) { - LOG_INFO("DLL_PROCESS_ATTACH from module: {0:X}, count: {1}", (UINT64)hModule, loadCount); + LOG_INFO("DLL_PROCESS_ATTACH from module: {0:X}, count: {1}", (UINT64)hModule, LoadLibraryHooks::LoadCount()); return TRUE; } - dllModule = hModule; processId = GetCurrentProcessId(); - DisableThreadLibraryCalls(hModule); - loadCount++; + LoadLibraryHooks::AddLoad(); #ifdef VER_PRE_RELEASE // Enable file logging for pre builds @@ -128,34 +48,8 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv // Check if real DLSS available if (Config::Instance()->DLSSEnabled.value_or(true)) - { - spdlog::info(""); NVNGXProxy::InitNVNGX(); - if (NVNGXProxy::NVNGXModule() == nullptr) - { - spdlog::info("Can't load nvngx.dll, disabling DLSS"); - Config::Instance()->DLSSEnabled = false; - } - else - { - spdlog::info("nvngx.dll loaded, setting DLSS as default upscaler and disabling spoofing options set to auto"); - - Config::Instance()->DLSSEnabled = true; - - if (!Config::Instance()->DxgiSpoofing.has_value()) - Config::Instance()->DxgiSpoofing = false; - - if (!Config::Instance()->VulkanSpoofing.has_value()) - Config::Instance()->VulkanSpoofing = false; - - if (!Config::Instance()->VulkanExtensionSpoofing.has_value()) - Config::Instance()->VulkanExtensionSpoofing = false; - - isNvngxAvailable = true; - } - } - // Init XeSS proxy if (!XeSSProxy::InitXeSS()) spdlog::warn("Can't init XeSS!"); @@ -172,7 +66,7 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv spdlog::info(""); if (WorkingMode::Check()) - AttachHooks(); + LoadLibraryHooks::Hook(); spdlog::info(""); @@ -187,7 +81,7 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv case DLL_PROCESS_DETACH: // Unhooking and cleaning stuff causing issues during shutdown. // Disabled for now to check if it cause any issues - //DetachHooks(); + //LoadLibraryHooks::Unhook(); if (skHandle != nullptr) FreeLibrary(skHandle); diff --git a/OptiScaler/exports/Dxgi.cpp b/OptiScaler/exports/Dxgi.cpp index 96da128e..95ac5790 100644 --- a/OptiScaler/exports/Dxgi.cpp +++ b/OptiScaler/exports/Dxgi.cpp @@ -7,16 +7,15 @@ #include #include +typedef HRESULT(*PFN_GetDesc)(IDXGIAdapter* This, DXGI_ADAPTER_DESC* pDesc); +typedef HRESULT(*PFN_GetDesc1)(IDXGIAdapter1* This, DXGI_ADAPTER_DESC1* pDesc); +typedef HRESULT(*PFN_GetDesc2)(IDXGIAdapter2* This, DXGI_ADAPTER_DESC2* pDesc); +typedef HRESULT(*PFN_GetDesc3)(IDXGIAdapter4* This, DXGI_ADAPTER_DESC3* pDesc); -typedef HRESULT(WINAPI* PFN_GetDesc)(IDXGIAdapter* This, DXGI_ADAPTER_DESC* pDesc); -typedef HRESULT(WINAPI* PFN_GetDesc1)(IDXGIAdapter1* This, DXGI_ADAPTER_DESC1* pDesc); -typedef HRESULT(WINAPI* PFN_GetDesc2)(IDXGIAdapter2* This, DXGI_ADAPTER_DESC2* pDesc); -typedef HRESULT(WINAPI* PFN_GetDesc3)(IDXGIAdapter4* This, DXGI_ADAPTER_DESC3* pDesc); - -typedef HRESULT(WINAPI* PFN_EnumAdapterByGpuPreference)(IDXGIFactory6* This, UINT Adapter, DXGI_GPU_PREFERENCE GpuPreference, REFIID riid, void** ppvAdapter); -typedef HRESULT(WINAPI* PFN_EnumAdapterByLuid)(IDXGIFactory4* This, LUID AdapterLuid, REFIID riid, void** ppvAdapter); -typedef HRESULT(WINAPI* PFN_EnumAdapters1)(IDXGIFactory1* This, UINT Adapter, IDXGIAdapter1** ppAdapter); -typedef HRESULT(WINAPI* PFN_EnumAdapters)(IDXGIFactory* This, UINT Adapter, IDXGIAdapter** ppAdapter); +typedef HRESULT(*PFN_EnumAdapterByGpuPreference)(IDXGIFactory6* This, UINT Adapter, DXGI_GPU_PREFERENCE GpuPreference, REFIID riid, IDXGIAdapter** ppvAdapter); +typedef HRESULT(*PFN_EnumAdapterByLuid)(IDXGIFactory4* This, LUID AdapterLuid, REFIID riid, IDXGIAdapter** ppvAdapter); +typedef HRESULT(*PFN_EnumAdapters1)(IDXGIFactory1* This, UINT Adapter, IDXGIAdapter1** ppAdapter); +typedef HRESULT(*PFN_EnumAdapters)(IDXGIFactory* This, UINT Adapter, IDXGIAdapter** ppAdapter); static PFN_GetDesc o_GetDesc = nullptr; static PFN_GetDesc1 o_GetDesc1 = nullptr; @@ -33,9 +32,35 @@ void AttachToFactory(IUnknown* unkFactory); #pragma region DXGI Adapter methods +static void CheckAdapter(IUnknown* unkAdapter) +{ + if (Config::Instance()->IsRunningOnDXVK) + return; + + //DXVK VkInterface GUID + const GUID guid = { 0x907bf281,0xea3c,0x43b4,{0xa8,0xe4,0x9f,0x23,0x11,0x07,0xb4,0xff} }; + + IDXGIAdapter* adapter = nullptr; + bool adapterOk = unkAdapter->QueryInterface(IID_PPV_ARGS(&adapter)) == S_OK; + + void* dxvkAdapter = nullptr; + if (adapterOk && adapter->QueryInterface(guid, &dxvkAdapter) == S_OK) + { + + Config::Instance()->IsRunningOnDXVK = dxvkAdapter != nullptr; + ((IDXGIAdapter*)dxvkAdapter)->Release(); + } + + if (adapterOk) + adapter->Release(); + + if (Config::Instance()->IsRunningOnDXVK) + LOG_INFO("DXVK adapter detected"); +} + bool SkipSpoofing() { - auto skip = !Config::Instance()->DxgiSpoofing.value_or(true) || Config::Instance()->dxgiSkipSpoofing || Config::Instance()->IsRunningOnLinux; + auto skip = !Config::Instance()->DxgiSpoofing.value_or(true) || Config::Instance()->dxgiSkipSpoofing; if (skip) LOG_TRACE("DxgiSpoofing: {}, dxgiSkipSpoofing: {}, skipping spoofing", @@ -202,33 +227,31 @@ static HRESULT hkGetDesc(IDXGIAdapter* This, DXGI_ADAPTER_DESC* pDesc) #pragma region DXGI Factory methods -static HRESULT WINAPI hkEnumAdapterByGpuPreference(IDXGIFactory6* This, UINT Adapter, DXGI_GPU_PREFERENCE GpuPreference, REFIID riid, void** ppvAdapter) +static HRESULT WINAPI hkEnumAdapterByGpuPreference(IDXGIFactory6* This, UINT Adapter, DXGI_GPU_PREFERENCE GpuPreference, REFIID riid, IDXGIAdapter** ppvAdapter) { AttachToFactory(This); - IDXGIAdapter* adapter = nullptr; - auto result = o_EnumAdapterByGpuPreference(This, Adapter, GpuPreference, riid, (void**)&adapter); + auto result = o_EnumAdapterByGpuPreference(This, Adapter, GpuPreference, riid, ppvAdapter); if (result == S_OK) { - AttachToAdapter(adapter); - *ppvAdapter = adapter; + CheckAdapter(*ppvAdapter); + AttachToAdapter(*ppvAdapter); } return result; } -static HRESULT WINAPI hkEnumAdapterByLuid(IDXGIFactory4* This, LUID AdapterLuid, REFIID riid, void** ppvAdapter) +static HRESULT WINAPI hkEnumAdapterByLuid(IDXGIFactory4* This, LUID AdapterLuid, REFIID riid, IDXGIAdapter** ppvAdapter) { AttachToFactory(This); - IDXGIAdapter* adapter = nullptr; - auto result = o_EnumAdapterByLuid(This, AdapterLuid, riid, (void**)&adapter); + auto result = o_EnumAdapterByLuid(This, AdapterLuid, riid, ppvAdapter); if (result == S_OK) { - AttachToAdapter(adapter); - *ppvAdapter = adapter; + CheckAdapter(*ppvAdapter); + AttachToAdapter(*ppvAdapter); } return result; @@ -238,13 +261,12 @@ static HRESULT WINAPI hkEnumAdapters1(IDXGIFactory1* This, UINT Adapter, IDXGIAd { AttachToFactory(This); - IDXGIAdapter1* adapter = nullptr; - auto result = o_EnumAdapters1(This, Adapter, &adapter); + auto result = o_EnumAdapters1(This, Adapter, ppAdapter); if (result == S_OK) { - AttachToAdapter(adapter); - *ppAdapter = adapter; + CheckAdapter(*ppAdapter); + AttachToAdapter(*ppAdapter); } return result; @@ -254,13 +276,12 @@ static HRESULT WINAPI hkEnumAdapters(IDXGIFactory* This, UINT Adapter, IDXGIAdap { AttachToFactory(This); - IDXGIAdapter* adapter = nullptr; - auto result = o_EnumAdapters(This, Adapter, &adapter); + auto result = o_EnumAdapters(This, Adapter, ppAdapter); if (result == S_OK) { - AttachToAdapter(adapter); - *ppAdapter = adapter; + CheckAdapter(*ppAdapter); + AttachToAdapter(*ppAdapter); } return result; @@ -358,7 +379,7 @@ static void AttachToFactory(IUnknown* unkFactory) DetourTransactionCommit(); } - + factory->Release(); IDXGIFactory1* factory1; @@ -411,41 +432,32 @@ static void AttachToFactory(IUnknown* unkFactory) #pragma region DXGI methods -HRESULT _CreateDXGIFactory(REFIID riid, _COM_Outptr_ void** ppFactory) +HRESULT _CreateDXGIFactory(REFIID riid, _COM_Outptr_ IDXGIFactory** ppFactory) { - IDXGIFactory* factory; - HRESULT result = dxgi.CreateDxgiFactory(riid, (void**)&factory); + HRESULT result = dxgi.CreateDxgiFactory(riid, ppFactory); if (result == S_OK) - AttachToFactory(factory); - - *ppFactory = factory; + AttachToFactory(*ppFactory); return result; } -HRESULT _CreateDXGIFactory1(REFIID riid, _COM_Outptr_ void** ppFactory) +HRESULT _CreateDXGIFactory1(REFIID riid, _COM_Outptr_ IDXGIFactory1** ppFactory) { - IDXGIFactory1* factory1; - HRESULT result = dxgi.CreateDxgiFactory1(riid, (void**)&factory1); + HRESULT result = dxgi.CreateDxgiFactory1(riid, ppFactory); if (result == S_OK) - AttachToFactory(factory1); - - *ppFactory = factory1; + AttachToFactory(*ppFactory); return result; } -HRESULT _CreateDXGIFactory2(UINT Flags, REFIID riid, _COM_Outptr_ void** ppFactory) +HRESULT _CreateDXGIFactory2(UINT Flags, REFIID riid, _COM_Outptr_ IDXGIFactory2** ppFactory) { - IDXGIFactory* factory; - HRESULT result = dxgi.CreateDxgiFactory2(Flags, riid, (void**)&factory); + HRESULT result = dxgi.CreateDxgiFactory2(Flags, riid, ppFactory); if (result == S_OK) - AttachToFactory(factory); - - *ppFactory = factory; + AttachToFactory(*ppFactory); return result; } @@ -552,6 +564,5 @@ void _UpdateHMDEmulationStatus() dxgi.UpdateHMDEmulationStatus(); } -#pragma endregion diff --git a/OptiScaler/exports/Dxgi.h b/OptiScaler/exports/Dxgi.h index 9b0b732f..2f02c426 100644 --- a/OptiScaler/exports/Dxgi.h +++ b/OptiScaler/exports/Dxgi.h @@ -4,15 +4,16 @@ #include -typedef HRESULT(WINAPI* PFN_CREATE_DXGI_FACTORY)(REFIID riid, _COM_Outptr_ void** ppFactory); -typedef HRESULT(WINAPI* PFN_CREATE_DXGI_FACTORY_2)(UINT Flags, REFIID riid, _COM_Outptr_ void** ppFactory); +typedef HRESULT(*PFN_CREATE_DXGI_FACTORY)(REFIID riid, IDXGIFactory** ppFactory); +typedef HRESULT(*PFN_CREATE_DXGI_FACTORY_1)(REFIID riid, IDXGIFactory1** ppFactory); +typedef HRESULT(*PFN_CREATE_DXGI_FACTORY_2)(UINT Flags, REFIID riid, IDXGIFactory2** ppFactory); inline struct dxgi_dll { HMODULE dll = nullptr; PFN_CREATE_DXGI_FACTORY CreateDxgiFactory; - PFN_CREATE_DXGI_FACTORY CreateDxgiFactory1; + PFN_CREATE_DXGI_FACTORY_1 CreateDxgiFactory1; PFN_CREATE_DXGI_FACTORY_2 CreateDxgiFactory2; FARPROC DeclareAdapterRemovalSupport; @@ -38,7 +39,7 @@ inline struct dxgi_dll dll = module; CreateDxgiFactory = (PFN_CREATE_DXGI_FACTORY)GetProcAddress(module, "CreateDXGIFactory"); - CreateDxgiFactory1 = (PFN_CREATE_DXGI_FACTORY)GetProcAddress(module, "CreateDXGIFactory1"); + CreateDxgiFactory1 = (PFN_CREATE_DXGI_FACTORY_1)GetProcAddress(module, "CreateDXGIFactory1"); CreateDxgiFactory2 = (PFN_CREATE_DXGI_FACTORY_2)GetProcAddress(module, "CreateDXGIFactory2"); DeclareAdapterRemovalSupport = GetProcAddress(module, "DXGIDeclareAdapterRemovalSupport"); @@ -61,9 +62,9 @@ inline struct dxgi_dll } } dxgi; -HRESULT _CreateDXGIFactory(REFIID riid, _COM_Outptr_ void** ppFactory); -HRESULT _CreateDXGIFactory1(REFIID riid, _COM_Outptr_ void** ppFactory); -HRESULT _CreateDXGIFactory2(UINT Flags, REFIID riid, _COM_Outptr_ void** ppFactory); +HRESULT _CreateDXGIFactory(REFIID riid, IDXGIFactory** ppFactory); +HRESULT _CreateDXGIFactory1(REFIID riid, IDXGIFactory1** ppFactory); +HRESULT _CreateDXGIFactory2(UINT Flags, REFIID riid, IDXGIFactory2** ppFactory); void _DXGIDeclareAdapterRemovalSupport(); void _DXGIGetDebugInterface1(); diff --git a/OptiScaler/hooks/Dxgi.cpp b/OptiScaler/hooks/Dxgi.cpp new file mode 100644 index 00000000..aa89d290 --- /dev/null +++ b/OptiScaler/hooks/Dxgi.cpp @@ -0,0 +1,532 @@ +#include "Dxgi.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +typedef HRESULT(*PFN_CreateSwapChain)(IDXGIFactory*, IUnknown*, DXGI_SWAP_CHAIN_DESC*, IDXGISwapChain**); +typedef HRESULT(*PFN_CreateSwapChainForHwnd)(IDXGIFactory*, IUnknown*, HWND, const DXGI_SWAP_CHAIN_DESC1*, const DXGI_SWAP_CHAIN_FULLSCREEN_DESC*, IDXGIOutput*, IDXGISwapChain1**); + +static PFN_CreateSwapChain o_CreateSwapChain = nullptr; +static PFN_CreateSwapChainForHwnd o_CreateSwapChainForHwnd = nullptr; + +static bool dx11Device = false; +static bool dx12Device = false; + +static void CleanupRenderTarget(bool clearQueue, HWND hWnd) +{ + LOG_FUNC(); + + if (clearQueue) + currentSCCommandQueue = nullptr; + + if (dx11Device) + CleanupRenderTargetDx11(false); + else + CleanupRenderTargetDx12(clearQueue); + + // Releasing RTSS D3D11on12 device + if (clearQueue && GetModuleHandle(L"RTSSHooks64.dll") != nullptr) + { + LOG_DEBUG("Releasing D3d11on12 device"); + d3d11on12Device = nullptr; + } +} + +static HRESULT Present(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags, const DXGI_PRESENT_PARAMETERS* pPresentParameters, IUnknown* pDevice, HWND hWnd) +{ + LOG_FUNC(); + + HRESULT presentResult; + + if (hWnd != Util::GetProcessWindow()) + { + if (pPresentParameters == nullptr) + presentResult = pSwapChain->Present(SyncInterval, Flags); + else + presentResult = ((IDXGISwapChain1*)pSwapChain)->Present1(SyncInterval, Flags, pPresentParameters); + + LOG_FUNC_RESULT(presentResult); + return presentResult; + } + + ID3D12CommandQueue* cq = nullptr; + ID3D11Device* device = nullptr; + ID3D12Device* device12 = nullptr; + + // try to obtain directx objects and find the path + if (pDevice->QueryInterface(IID_PPV_ARGS(&device)) == S_OK) + { + if (!dx11Device) + LOG_DEBUG("D3D11Device captured"); + + dx11Device = true; + } + else if (pDevice->QueryInterface(IID_PPV_ARGS(&cq)) == S_OK) + { + if (!dx12Device) + LOG_DEBUG("D3D12CommandQueue captured"); + + currentSCCommandQueue = pDevice; + MenuDx::GameCommandQueue = (ID3D12CommandQueue*)pDevice; + + if (cq->GetDevice(IID_PPV_ARGS(&device12)) == S_OK) + { + if (!dx12Device) + LOG_DEBUG("D3D12Device captured"); + + dx12Device = true; + } + } + + // Upscaler GPU time computation + if (MenuDx::dx12UpscaleTrig && MenuDx::readbackBuffer != nullptr && MenuDx::queryHeap != nullptr && cq != nullptr) + { + if (MenuBase::IsInited() && MenuBase::IsVisible()) + { + UINT64* timestampData; + MenuDx::readbackBuffer->Map(0, nullptr, reinterpret_cast(×tampData)); + + // Get the GPU timestamp frequency (ticks per second) + UINT64 gpuFrequency; + cq->GetTimestampFrequency(&gpuFrequency); + + // Calculate elapsed time in milliseconds + UINT64 startTime = timestampData[0]; + UINT64 endTime = timestampData[1]; + double elapsedTimeMs = (endTime - startTime) / static_cast(gpuFrequency) * 1000.0; + + Config::Instance()->upscaleTimes.push_back(elapsedTimeMs); + Config::Instance()->upscaleTimes.pop_front(); + + // Unmap the buffer + MenuDx::readbackBuffer->Unmap(0, nullptr); + } + + MenuDx::dx12UpscaleTrig = false; + } + else if (MenuDx::dx11UpscaleTrig[MenuDx::currentFrameIndex] && device != nullptr && MenuDx::disjointQueries[0] != nullptr && + MenuDx::startQueries[0] != nullptr && MenuDx::endQueries[0] != nullptr) + { + if (g_pd3dDeviceContext == nullptr) + device->GetImmediateContext(&g_pd3dDeviceContext); + + if (MenuBase::IsInited() && MenuBase::IsVisible()) + { + // Retrieve the results from the previous frame + D3D11_QUERY_DATA_TIMESTAMP_DISJOINT disjointData; + if (g_pd3dDeviceContext->GetData(MenuDx::disjointQueries[MenuDx::previousFrameIndex], &disjointData, sizeof(disjointData), 0) == S_OK) + { + if (!disjointData.Disjoint && disjointData.Frequency > 0) + { + UINT64 startTime = 0, endTime = 0; + if (g_pd3dDeviceContext->GetData(MenuDx::startQueries[MenuDx::previousFrameIndex], &startTime, sizeof(UINT64), 0) == S_OK && + g_pd3dDeviceContext->GetData(MenuDx::endQueries[MenuDx::previousFrameIndex], &endTime, sizeof(UINT64), 0) == S_OK) + { + double elapsedTimeMs = (endTime - startTime) / static_cast(disjointData.Frequency) * 1000.0; + Config::Instance()->upscaleTimes.push_back(elapsedTimeMs); + Config::Instance()->upscaleTimes.pop_front(); + } + } + } + } + + + MenuDx::dx11UpscaleTrig[MenuDx::currentFrameIndex] = false; + MenuDx::currentFrameIndex = (MenuDx::currentFrameIndex + 1) % MenuDx::QUERY_BUFFER_COUNT; + } + + // DXVK check, it's here because of upscaler time calculations + if (Config::Instance()->IsRunningOnDXVK) + { + if (cq != nullptr) + cq->Release(); + + if (device != nullptr) + device->Release(); + + if (device12 != nullptr) + device12->Release(); + + if (pPresentParameters == nullptr) + presentResult = pSwapChain->Present(SyncInterval, Flags); + else + presentResult = ((IDXGISwapChain1*)pSwapChain)->Present1(SyncInterval, Flags, pPresentParameters); + + LOG_FUNC_RESULT(presentResult); + return presentResult; + } + + // Process window handle changed, update base + if (MenuBase::Handle() != hWnd) + { + LOG_DEBUG("Handle changed"); + + if (MenuBase::IsInited()) + MenuBase::Shutdown(); + + MenuBase::Init(hWnd); + + _isInited = false; + } + + // Init + if (!_isInited) + { + if (dx11Device) + { + CleanupRenderTargetDx11(false); + + g_pd3dDevice = device; + g_pd3dDevice->AddRef(); + + CreateRenderTargetDx11(pSwapChain); + MenuBase::Dx11Ready(); + _isInited = true; + } + else if (dx12Device && (g_pd3dDeviceParam != nullptr || device12 != nullptr)) + { + if (g_pd3dDeviceParam != nullptr && device12 == nullptr) + device12 = g_pd3dDeviceParam; + + CleanupRenderTargetDx12(true); + + g_pd3dCommandQueue = cq; + g_pd3dDeviceParam = device12; + + g_pd3dCommandQueue->AddRef(); + g_pd3dDeviceParam->AddRef(); + + MenuBase::Dx12Ready(); + _isInited = true; + } + } + + // dx11 multi thread safety + ID3D11Multithread* dx11MultiThread = nullptr; + ID3D11DeviceContext* dx11Context = nullptr; + bool mtState = false; + + if (dx11Device) + { + ID3D11Device* dx11Device = g_pd3dDevice; + if (dx11Device == nullptr) + dx11Device = d3d11Device; + + if (dx11Device == nullptr) + dx11Device = d3d11on12Device; + + if (dx11Device != nullptr) + { + dx11Device->GetImmediateContext(&dx11Context); + + if (dx11Context != nullptr && dx11Context->QueryInterface(IID_PPV_ARGS(&dx11MultiThread)) == S_OK && dx11MultiThread != nullptr) + { + mtState = dx11MultiThread->GetMultithreadProtected(); + dx11MultiThread->SetMultithreadProtected(TRUE); + dx11MultiThread->Enter(); + } + } + } + + // Render menu + if (dx11Device) + RenderImGui_DX11(pSwapChain); + else if (dx12Device) + RenderImGui_DX12(pSwapChain); + + // swapchain present + if (pPresentParameters == nullptr) + presentResult = pSwapChain->Present(SyncInterval, Flags); + else + presentResult = ((IDXGISwapChain1*)pSwapChain)->Present1(SyncInterval, Flags, pPresentParameters); + + // dx11 multi thread safety + if (dx11Device && dx11MultiThread != nullptr) + { + dx11MultiThread->Leave(); + dx11MultiThread->SetMultithreadProtected(mtState); + + dx11MultiThread->Release(); + dx11Context->Release(); + } + + // release used objects + if (cq != nullptr) + cq->Release(); + + if (device != nullptr) + device->Release(); + + if (device12 != nullptr) + device12->Release(); + + return presentResult; +} + +static HRESULT hkCreateSwapChain(IDXGIFactory* pFactory, IUnknown* pDevice, DXGI_SWAP_CHAIN_DESC* pDesc, IDXGISwapChain** ppSwapChain) +{ + LOG_FUNC(); + + *ppSwapChain = nullptr; + + if (Config::Instance()->VulkanCreatingSC) + { + LOG_WARN("Vulkan is creating swapchain!"); + + if (pDesc != nullptr) + LOG_DEBUG("Width: {0}, Height: {1}, Format: {2:X}, Count: {3}, Windowed: {4}", pDesc->BufferDesc.Width, pDesc->BufferDesc.Height, (UINT)pDesc->BufferDesc.Format, pDesc->BufferCount, pDesc->Windowed); + + return o_CreateSwapChain(pFactory, pDevice, pDesc, ppSwapChain); + } + + if (pDevice == nullptr) + { + LOG_WARN("pDevice is nullptr!"); + return o_CreateSwapChain(pFactory, pDevice, pDesc, ppSwapChain); + } + + auto result = o_CreateSwapChain(pFactory, pDevice, pDesc, ppSwapChain); + + if (result == S_OK) + { + LOG_DEBUG("Width: {0}, Height: {1}, Format: {2:X}, Count: {3}, Windowed: {4}", pDesc->BufferDesc.Width, pDesc->BufferDesc.Height, (UINT)pDesc->BufferDesc.Format, pDesc->BufferCount, pDesc->Windowed); + + if (Util::GetProcessWindow() == pDesc->OutputWindow) + { + Config::Instance()->ScreenWidth = pDesc->BufferDesc.Width; + Config::Instance()->ScreenHeight = pDesc->BufferDesc.Height; + } + + if (Config::Instance()->OverlayMenu.value_or(true)) + { + LOG_DEBUG("created new swapchain: {0:X}, hWnd: {1:X}", (UINT64)*ppSwapChain, (UINT64)pDesc->OutputWindow); + *ppSwapChain = new WrappedSwapChain(*ppSwapChain, pDevice, pDesc->OutputWindow, Present, CleanupRenderTarget); + LOG_DEBUG("created new WrappedSwapChain: {0:X}, pDevice: {1:X}", (UINT64)*ppSwapChain, (UINT64)pDevice); + } + } + + return result; +} + +static HRESULT hkCreateSwapChainForHwnd(IDXGIFactory* pCommandQueue, IUnknown* pDevice, HWND hWnd, const DXGI_SWAP_CHAIN_DESC1* pDesc, + const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc, IDXGIOutput* pRestrictToOutput, IDXGISwapChain1** ppSwapChain) +{ + LOG_FUNC(); + + *ppSwapChain = nullptr; + + if (Config::Instance()->VulkanCreatingSC) + { + LOG_WARN("Vulkan is creating swapchain!"); + + if (pDesc != nullptr) + LOG_DEBUG("Width: {0}, Height: {1}, Format: {2:X}, Count: {3}, Flags: {4:X}", pDesc->Width, pDesc->Height, (UINT)pDesc->Format, pDesc->BufferCount, pDesc->Flags); + + return o_CreateSwapChainForHwnd(pCommandQueue, pDevice, hWnd, pDesc, pFullscreenDesc, pRestrictToOutput, ppSwapChain); + } + + if (pDevice == nullptr) + { + LOG_WARN("pDevice is nullptr!"); + return o_CreateSwapChainForHwnd(pCommandQueue, pDevice, hWnd, pDesc, pFullscreenDesc, pRestrictToOutput, ppSwapChain); + } + + auto result = o_CreateSwapChainForHwnd(pCommandQueue, pDevice, hWnd, pDesc, pFullscreenDesc, pRestrictToOutput, ppSwapChain); + + if (result == S_OK) + { + LOG_DEBUG("Width: {0}, Height: {1}, Format: {2:X}, Count: {3}, Flags: {4:X}", pDesc->Width, pDesc->Height, (UINT)pDesc->Format, pDesc->BufferCount, pDesc->Flags); + + if (Util::GetProcessWindow() == hWnd) + { + Config::Instance()->ScreenWidth = pDesc->Width; + Config::Instance()->ScreenHeight = pDesc->Height; + } + + if (Config::Instance()->OverlayMenu.value_or(true)) + { + LOG_DEBUG("created new swapchain: {0:X}, hWnd: {1:X}", (UINT64)*ppSwapChain, (UINT64)hWnd); + *ppSwapChain = new WrappedSwapChain(*ppSwapChain, pDevice, hWnd, Present, CleanupRenderTarget); + LOG_DEBUG("created new WrappedSwapChain: {0:X}, pDevice: {1:X}", (UINT64)*ppSwapChain, (UINT64)pDevice); + } + } + + return result; +} + +static HRESULT hkCreateDXGIFactory(REFIID riid, IDXGIFactory** ppFactory) +{ + HRESULT result; + + if (Config::Instance()->DxgiSpoofing.value_or(true)) + result = _CreateDXGIFactory(riid, ppFactory); + else + result = dxgi.CreateDxgiFactory(riid, ppFactory); + + if (result == S_OK && o_CreateSwapChain == nullptr) + { + void** pFactoryVTable = *reinterpret_cast(*ppFactory); + + o_CreateSwapChain = (PFN_CreateSwapChain)pFactoryVTable[10]; + + if (o_CreateSwapChain != nullptr) + { + LOG_INFO("Hooking native DXGIFactory"); + + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + DetourAttach(&(PVOID&)o_CreateSwapChain, hkCreateSwapChain); + + DetourTransactionCommit(); + } + } + + return result; +} + +static HRESULT hkCreateDXGIFactory1(REFIID riid, IDXGIFactory1** ppFactory) +{ + HRESULT result; + + if (Config::Instance()->DxgiSpoofing.value_or(true)) + result = _CreateDXGIFactory1(riid, ppFactory); + else + result = dxgi.CreateDxgiFactory1(riid, ppFactory); + + if (result == S_OK && o_CreateSwapChainForHwnd == nullptr) + { + IDXGIFactory2* factory2 = nullptr; + + if ((*ppFactory)->QueryInterface(IID_PPV_ARGS(&factory2)) == S_OK && factory2 != nullptr) + { + void** pFactoryVTable = *reinterpret_cast(factory2); + + bool skip = false; + + if (o_CreateSwapChain == nullptr) + o_CreateSwapChain = (PFN_CreateSwapChain)pFactoryVTable[10]; + else + skip = true; + + o_CreateSwapChainForHwnd = (PFN_CreateSwapChainForHwnd)pFactoryVTable[15]; + + if (o_CreateSwapChainForHwnd != nullptr) + { + LOG_INFO("Hooking native DXGIFactory"); + + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + if (!skip) + DetourAttach(&(PVOID&)o_CreateSwapChain, hkCreateSwapChain); + + DetourAttach(&(PVOID&)o_CreateSwapChainForHwnd, hkCreateSwapChainForHwnd); + + DetourTransactionCommit(); + } + + factory2->Release(); + factory2 = nullptr; + } + } + + return result; +} + +static HRESULT hkCreateDXGIFactory2(UINT Flags, REFIID riid, IDXGIFactory2** ppFactory) +{ + HRESULT result; + + if (Config::Instance()->DxgiSpoofing.value_or(true)) + result = _CreateDXGIFactory2(Flags, riid, ppFactory); + else + result = dxgi.CreateDxgiFactory2(Flags, riid, ppFactory); + + if (result == S_OK && o_CreateSwapChainForHwnd == nullptr) + { + IDXGIFactory2* factory2 = nullptr; + + if ((*ppFactory)->QueryInterface(IID_PPV_ARGS(&factory2)) == S_OK && factory2 != nullptr) + { + void** pFactoryVTable = *reinterpret_cast(factory2); + + bool skip = false; + + if (o_CreateSwapChain == nullptr) + o_CreateSwapChain = (PFN_CreateSwapChain)pFactoryVTable[10]; + else + skip = true; + + o_CreateSwapChainForHwnd = (PFN_CreateSwapChainForHwnd)pFactoryVTable[15]; + + if (o_CreateSwapChainForHwnd != nullptr) + { + LOG_INFO("Hooking native DXGIFactory"); + + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + if (!skip) + DetourAttach(&(PVOID&)o_CreateSwapChain, hkCreateSwapChain); + + DetourAttach(&(PVOID&)o_CreateSwapChainForHwnd, hkCreateSwapChainForHwnd); + + DetourTransactionCommit(); + } + + factory2->Release(); + factory2 = nullptr; + } + } + + return result; +} + +inline static void HookForDxgiSpoofing() +{ + // hook dxgi when not working as dxgi.dll + if (dxgi.CreateDxgiFactory == nullptr && !WorkingMode::IsWorkingWithEnabler() && !Config::Instance()->IsDxgiMode) + { + LOG_INFO("DxgiSpoofing is enabled loading dxgi.dll"); + + dxgi.CreateDxgiFactory = (PFN_CREATE_DXGI_FACTORY)DetourFindFunction("dxgi.dll", "CreateDXGIFactory"); + dxgi.CreateDxgiFactory1 = (PFN_CREATE_DXGI_FACTORY_1)DetourFindFunction("dxgi.dll", "CreateDXGIFactory1"); + dxgi.CreateDxgiFactory2 = (PFN_CREATE_DXGI_FACTORY_2)DetourFindFunction("dxgi.dll", "CreateDXGIFactory2"); + + if (dxgi.CreateDxgiFactory != nullptr || dxgi.CreateDxgiFactory1 != nullptr || dxgi.CreateDxgiFactory2 != nullptr) + { + LOG_INFO("dxgi.dll found, hooking CreateDxgiFactory methods"); + + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + if (dxgi.CreateDxgiFactory != nullptr) + DetourAttach(&(PVOID&)dxgi.CreateDxgiFactory, hkCreateDXGIFactory); + + if (dxgi.CreateDxgiFactory1 != nullptr) + DetourAttach(&(PVOID&)dxgi.CreateDxgiFactory1, hkCreateDXGIFactory1); + + if (dxgi.CreateDxgiFactory2 != nullptr) + DetourAttach(&(PVOID&)dxgi.CreateDxgiFactory2, hkCreateDXGIFactory2); + + DetourTransactionCommit(); + } + } +} + +void DxgiHooks::Hook() +{ + HookForDxgiSpoofing(); +} + +void DxgiHooks::Unhook() +{ +} diff --git a/OptiScaler/hooks/Dxgi.h b/OptiScaler/hooks/Dxgi.h new file mode 100644 index 00000000..aaf52a0c --- /dev/null +++ b/OptiScaler/hooks/Dxgi.h @@ -0,0 +1,10 @@ +#pragma once +#include + +class DxgiHooks +{ +private: +public: + static void Hook(); + static void Unhook(); +}; \ No newline at end of file diff --git a/OptiScaler/hooks/Hooks.cpp b/OptiScaler/hooks/Hooks.cpp deleted file mode 100644 index fa8704b5..00000000 --- a/OptiScaler/hooks/Hooks.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "Hooks.h" - -void Hooks::Attach() -{ - -} diff --git a/OptiScaler/hooks/Hooks.h b/OptiScaler/hooks/Hooks.h deleted file mode 100644 index beeef7f3..00000000 --- a/OptiScaler/hooks/Hooks.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include - -class Hooks -{ -public: - void Attach(); -}; \ No newline at end of file diff --git a/OptiScaler/hooks/LoadLibrary.cpp b/OptiScaler/hooks/LoadLibrary.cpp index 5066a7df..ecc938e4 100644 --- a/OptiScaler/hooks/LoadLibrary.cpp +++ b/OptiScaler/hooks/LoadLibrary.cpp @@ -1,5 +1,6 @@ #include "LoadLibrary.h" +#include "Dxgi.h" #include #include #include "Vulkan.h" @@ -41,6 +42,80 @@ static bool dontCount = false; static bool skipLoadChecks = false; static UINT loadCount = 0; +static HMODULE LoadNvApi() +{ + HMODULE nvapi = nullptr; + + if (Config::Instance()->NvapiDllPath.has_value()) + { + nvapi = o_LoadLibraryW(Config::Instance()->NvapiDllPath->c_str()); + + if (nvapi != nullptr) + { + LOG_INFO("nvapi64.dll loaded from {0}", wstring_to_string(Config::Instance()->NvapiDllPath.value())); + return nvapi; + } + } + + if (nvapi == nullptr) + { + auto localPath = Util::DllPath().parent_path() / L"nvapi64.dll"; + nvapi = o_LoadLibraryW(localPath.wstring().c_str()); + + if (nvapi != nullptr) + { + LOG_INFO("nvapi64.dll loaded from {0}", wstring_to_string(localPath.wstring())); + return nvapi; + } + } + + if (nvapi == nullptr) + { + nvapi = o_LoadLibraryW(L"nvapi64.dll"); + + if (nvapi != nullptr) + { + LOG_WARN("nvapi64.dll loaded from system!"); + return nvapi; + } + } + + return nullptr; +} + +static HMODULE LoadNvgxDlss(std::wstring originalPath) +{ + HMODULE nvngxDlss = nullptr; + + if (Config::Instance()->NVNGX_DLSS_Library.has_value()) + { + nvngxDlss = o_LoadLibraryW(Config::Instance()->NVNGX_DLSS_Library.value().c_str()); + + if (nvngxDlss != nullptr) + { + LOG_INFO("nvngx_dlss.dll loaded from {0}", wstring_to_string(Config::Instance()->NVNGX_DLSS_Library.value())); + return nvngxDlss; + } + else + { + LOG_WARN("nvngx_dlss.dll can't found at {0}", wstring_to_string(Config::Instance()->NVNGX_DLSS_Library.value())); + } + } + + if (nvngxDlss == nullptr) + { + nvngxDlss = o_LoadLibraryW(originalPath.c_str()); + + if (nvngxDlss != nullptr) + { + LOG_INFO("nvngx_dlss.dll loaded from {0}", wstring_to_string(originalPath)); + return nvngxDlss; + } + } + + return nullptr; +} + inline static bool CheckDllName(std::string* dllName, std::vector* namesList) { for (size_t i = 0; i < namesList->size(); i++) @@ -145,12 +220,7 @@ inline static HMODULE LoadLibraryCheck(std::string lcaseLibName) HooksDx::HookDx12(); if (CheckDllName(&lcaseLibName, &dxgiNames)) - { - HookForDxgiSpoofing(); - - if (Config::Instance()->OverlayMenu.value_or(true)) - HooksDx::HookDxgi(); - } + DxgiHooks::Hook(); if (CheckDllName(&lcaseLibName, &vkNames)) { @@ -250,12 +320,7 @@ inline static HMODULE LoadLibraryCheckW(std::wstring lcaseLibName) HooksDx::HookDx12(); if (CheckDllNameW(&lcaseLibName, &dxgiNamesW)) - { - HookForDxgiSpoofing(); - - if (Config::Instance()->OverlayMenu.value_or(true)) - HooksDx::HookDxgi(); - } + DxgiHooks::Hook(); if (CheckDllNameW(&lcaseLibName, &vkNamesW)) { @@ -279,80 +344,6 @@ inline static HMODULE LoadLibraryCheckW(std::wstring lcaseLibName) return nullptr; } -static HMODULE LoadNvApi() -{ - HMODULE nvapi = nullptr; - - if (Config::Instance()->NvapiDllPath.has_value()) - { - nvapi = o_LoadLibraryW(Config::Instance()->NvapiDllPath->c_str()); - - if (nvapi != nullptr) - { - LOG_INFO("nvapi64.dll loaded from {0}", wstring_to_string(Config::Instance()->NvapiDllPath.value())); - return nvapi; - } - } - - if (nvapi == nullptr) - { - auto localPath = Util::DllPath().parent_path() / L"nvapi64.dll"; - nvapi = o_LoadLibraryW(localPath.wstring().c_str()); - - if (nvapi != nullptr) - { - LOG_INFO("nvapi64.dll loaded from {0}", wstring_to_string(localPath.wstring())); - return nvapi; - } - } - - if (nvapi == nullptr) - { - nvapi = o_LoadLibraryW(L"nvapi64.dll"); - - if (nvapi != nullptr) - { - LOG_WARN("nvapi64.dll loaded from system!"); - return nvapi; - } - } - - return nullptr; -} - -static HMODULE LoadNvgxDlss(std::wstring originalPath) -{ - HMODULE nvngxDlss = nullptr; - - if (Config::Instance()->NVNGX_DLSS_Library.has_value()) - { - nvngxDlss = o_LoadLibraryW(Config::Instance()->NVNGX_DLSS_Library.value().c_str()); - - if (nvngxDlss != nullptr) - { - LOG_INFO("nvngx_dlss.dll loaded from {0}", wstring_to_string(Config::Instance()->NVNGX_DLSS_Library.value())); - return nvngxDlss; - } - else - { - LOG_WARN("nvngx_dlss.dll can't found at {0}", wstring_to_string(Config::Instance()->NVNGX_DLSS_Library.value())); - } - } - - if (nvngxDlss == nullptr) - { - nvngxDlss = o_LoadLibraryW(originalPath.c_str()); - - if (nvngxDlss != nullptr) - { - LOG_INFO("nvngx_dlss.dll loaded from {0}", wstring_to_string(originalPath)); - return nvngxDlss; - } - } - - return nullptr; -} - static FARPROC hkGetProcAddress(HMODULE hModule, LPCSTR lpProcName) { if (hModule == dllModule) @@ -557,7 +548,7 @@ void LoadLibraryHooks::Hook() if (dxgiModule != nullptr) { LOG_DEBUG("dxgi.dll already in memory"); - HookForDxgiSpoofing(); + DxgiHooks::Hook(); } HMODULE vulkanModule = nullptr; @@ -593,9 +584,6 @@ void LoadLibraryHooks::Hook() LOG_DEBUG("d3d12.dll already in memory"); HooksDx::HookDx12(); } - - if (Config::Instance()->OverlayMenu.value() && dxgiModule != nullptr) - HooksDx::HookDxgi(); } void LoadLibraryHooks::Unhook() diff --git a/OptiScaler/menu/MenuDx11.cpp b/OptiScaler/menu/MenuDx11.cpp new file mode 100644 index 00000000..e5bad9cd --- /dev/null +++ b/OptiScaler/menu/MenuDx11.cpp @@ -0,0 +1,1322 @@ +#include "MenuDx11.h" + +#include +#include +#include +#include "MenuBase.h" + +#include +#include +#include +#include +#include +#include + +// DirectX +typedef void(*PFN_CreateSampler)(ID3D12Device* device, const D3D12_SAMPLER_DESC* pDesc, D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor); +typedef HRESULT(*PFN_CreateSamplerState)(ID3D11Device* This, const D3D11_SAMPLER_DESC* pSamplerDesc, ID3D11SamplerState** ppSamplerState); + +// MipMap hooks +static PFN_D3D12_CREATE_DEVICE o_D3D12CreateDevice = nullptr; +static PFN_CreateSampler o_CreateSampler = nullptr; + +static PFN_D3D11_CREATE_DEVICE o_D3D11CreateDevice = nullptr; +static PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN o_D3D11CreateDeviceAndSwapChain = nullptr; +static PFN_CreateSamplerState o_CreateSamplerState = nullptr; +static PFN_D3D11ON12_CREATE_DEVICE o_D3D11On12CreateDevice = nullptr; +static ID3D11Device* d3d11Device = nullptr; +static ID3D11Device* d3d11on12Device = nullptr; + +// current command queue for dx12 swapchain +static IUnknown* currentSCCommandQueue = nullptr; + +// menu +static int const NUM_BACK_BUFFERS = 8; +static bool _dx11Device = false; +static bool _dx12Device = false; + +// for dx11 +static ID3D11Device* g_pd3dDevice = nullptr; +static ID3D11DeviceContext* g_pd3dDeviceContext = nullptr; +static ID3D11RenderTargetView* g_pd3dRenderTarget = nullptr; + +// for dx12 +static ID3D12Device* g_pd3dDeviceParam = nullptr; +static ID3D12DescriptorHeap* g_pd3dRtvDescHeap = nullptr; +static ID3D12DescriptorHeap* g_pd3dSrvDescHeap = nullptr; +static ID3D12CommandQueue* g_pd3dCommandQueue = nullptr; +static ID3D12GraphicsCommandList* g_pd3dCommandList = nullptr; +static ID3D12CommandAllocator* g_commandAllocators[NUM_BACK_BUFFERS] = { }; +static ID3D12Resource* g_mainRenderTargetResource[NUM_BACK_BUFFERS] = { }; +static D3D12_CPU_DESCRIPTOR_HANDLE g_mainRenderTargetDescriptor[NUM_BACK_BUFFERS] = { }; + +// status +static bool _isInited = false; + +// for showing +static bool _showRenderImGuiDebugOnce = true; + +// mutexes +static std::mutex _dx11CleanMutex; +static std::mutex _dx12CleanMutex; + +static void RenderImGui_DX11(IDXGISwapChain* pSwapChain); +static void RenderImGui_DX12(IDXGISwapChain* pSwapChain); +static void DeatachAllHooks(); +static void hkCreateSampler(ID3D12Device* device, const D3D12_SAMPLER_DESC* pDesc, D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor); +static HRESULT hkCreateSamplerState(ID3D11Device* This, const D3D11_SAMPLER_DESC* pSamplerDesc, ID3D11SamplerState** ppSamplerState); +static HRESULT hkEnumAdapters(IDXGIFactory* This, UINT Adapter, IUnknown** ppAdapter); +static HRESULT hkEnumAdapters1(IDXGIFactory1* This, UINT Adapter, IUnknown** ppAdapter); +static HRESULT hkEnumAdapterByLuid(IDXGIFactory4* This, LUID AdapterLuid, REFIID riid, IUnknown** ppvAdapter); +static HRESULT hkEnumAdapterByGpuPreference(IDXGIFactory6* This, UINT Adapter, DXGI_GPU_PREFERENCE GpuPreference, REFIID riid, IUnknown** ppvAdapter); + +static int GetCorrectDXGIFormat(int eCurrentFormat) +{ + switch (eCurrentFormat) + { + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + return DXGI_FORMAT_R8G8B8A8_UNORM; + } + + return eCurrentFormat; +} + +static void CreateRenderTargetDx12(ID3D12Device* device, IDXGISwapChain* pSwapChain) +{ + LOG_FUNC(); + + DXGI_SWAP_CHAIN_DESC desc; + HRESULT hr = pSwapChain->GetDesc(&desc); + + if (hr != S_OK) + { + LOG_ERROR("pSwapChain->GetDesc: {0:X}", (unsigned long)hr); + return; + } + + for (UINT i = 0; i < desc.BufferCount; ++i) + { + ID3D12Resource* pBackBuffer = NULL; + + auto result = pSwapChain->GetBuffer(i, IID_PPV_ARGS(&pBackBuffer)); + + if (result != S_OK) + { + LOG_ERROR("pSwapChain->GetBuffer: {0:X}", (unsigned long)result); + return; + } + + if (pBackBuffer) + { + DXGI_SWAP_CHAIN_DESC sd; + pSwapChain->GetDesc(&sd); + + D3D12_RENDER_TARGET_VIEW_DESC desc = { }; + desc.Format = static_cast(GetCorrectDXGIFormat(sd.BufferDesc.Format)); + desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; + + device->CreateRenderTargetView(pBackBuffer, &desc, g_mainRenderTargetDescriptor[i]); + g_mainRenderTargetResource[i] = pBackBuffer; + } + } + + LOG_INFO("done!"); +} + +static void CleanupRenderTargetDx12(bool clearQueue) +{ + if (!_isInited || !_dx12Device) + return; + + LOG_FUNC(); + + for (UINT i = 0; i < NUM_BACK_BUFFERS; ++i) + { + if (g_mainRenderTargetResource[i]) + { + g_mainRenderTargetResource[i]->Release(); + g_mainRenderTargetResource[i] = NULL; + } + } + + if (clearQueue) + { + if (MenuBase::IsInited() && g_pd3dDeviceParam != nullptr && g_pd3dSrvDescHeap != nullptr && ImGui::GetIO().BackendRendererUserData) + { + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + ImGui_ImplDX12_Shutdown(); + } + + if (g_pd3dRtvDescHeap != nullptr) + { + g_pd3dRtvDescHeap->Release(); + g_pd3dRtvDescHeap = nullptr; + + } + + if (g_pd3dSrvDescHeap != nullptr) + { + g_pd3dSrvDescHeap->Release(); + g_pd3dSrvDescHeap = nullptr; + + } + + for (UINT i = 0; i < NUM_BACK_BUFFERS; ++i) + { + if (g_commandAllocators[i] != nullptr) + { + g_commandAllocators[i]->Release(); + g_commandAllocators[i] = nullptr; + } + } + + if (g_pd3dCommandList != nullptr) + { + g_pd3dCommandList->Release(); + g_pd3dCommandList = nullptr; + } + + if (g_pd3dCommandQueue != nullptr) + { + g_pd3dCommandQueue->Release(); + g_pd3dCommandQueue = nullptr; + } + + if (g_pd3dDeviceParam != nullptr) + { + g_pd3dDeviceParam->Release(); + g_pd3dDeviceParam = nullptr; + } + + _dx12Device = false; + _isInited = false; + } +} + +static void CreateRenderTargetDx11(IDXGISwapChain* pSwapChain) +{ + ID3D11Texture2D* pBackBuffer = NULL; + pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer)); + + if (pBackBuffer) + { + DXGI_SWAP_CHAIN_DESC sd; + pSwapChain->GetDesc(&sd); + + D3D11_RENDER_TARGET_VIEW_DESC desc = { }; + desc.Format = static_cast(GetCorrectDXGIFormat(sd.BufferDesc.Format)); + desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + + g_pd3dDevice->CreateRenderTargetView(pBackBuffer, &desc, &g_pd3dRenderTarget); + pBackBuffer->Release(); + } +} + +static void CleanupRenderTargetDx11(bool shutDown) +{ + if (!_isInited || !_dx11Device) + return; + + if (!shutDown) + LOG_FUNC(); + + if (g_pd3dRenderTarget != nullptr) + { + g_pd3dRenderTarget->Release(); + g_pd3dRenderTarget = nullptr; + } + + if (g_pd3dDevice != nullptr) + { + g_pd3dDevice->Release(); + g_pd3dDevice = nullptr; + } + + _dx11Device = false; + _isInited = false; +} + +#pragma region Callbacks for wrapped swapchain + +static void CleanupRenderTarget(bool clearQueue, HWND hWnd) +{ + LOG_FUNC(); + + if (clearQueue) + currentSCCommandQueue = nullptr; + + if (_dx11Device) + CleanupRenderTargetDx11(false); + else + CleanupRenderTargetDx12(clearQueue); + + // Releasing RTSS D3D11on12 device + if (clearQueue && d3d11on12Device != nullptr && GetModuleHandle(L"RTSSHooks64.dll") != nullptr) + { + LOG_DEBUG("Releasing D3d11on12 device"); + d3d11on12Device = nullptr; + } +} + +static HRESULT Present(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags, const DXGI_PRESENT_PARAMETERS* pPresentParameters, IUnknown* pDevice, HWND hWnd) +{ + LOG_FUNC(); + + HRESULT presentResult; + + if (hWnd != Util::GetProcessWindow()) + { + if (pPresentParameters == nullptr) + presentResult = pSwapChain->Present(SyncInterval, Flags); + else + presentResult = ((IDXGISwapChain1*)pSwapChain)->Present1(SyncInterval, Flags, pPresentParameters); + + LOG_FUNC_RESULT(presentResult); + return presentResult; + } + + ID3D12CommandQueue* cq = nullptr; + ID3D11Device* device = nullptr; + ID3D12Device* device12 = nullptr; + + // try to obtain directx objects and find the path + if (pDevice->QueryInterface(IID_PPV_ARGS(&device)) == S_OK) + { + if (!_dx11Device) + LOG_DEBUG("D3D11Device captured"); + + _dx11Device = true; + } + else if (pDevice->QueryInterface(IID_PPV_ARGS(&cq)) == S_OK) + { + if (!_dx12Device) + LOG_DEBUG("D3D12CommandQueue captured"); + + currentSCCommandQueue = pDevice; + MenuDx11::GameCommandQueue = (ID3D12CommandQueue*)pDevice; + + if (cq->GetDevice(IID_PPV_ARGS(&device12)) == S_OK) + { + if (!_dx12Device) + LOG_DEBUG("D3D12Device captured"); + + _dx12Device = true; + } + } + + // DXVK check, it's here because of upscaler time calculations + if (Config::Instance()->IsRunningOnDXVK) + { + if (cq != nullptr) + cq->Release(); + + if (device != nullptr) + device->Release(); + + if (device12 != nullptr) + device12->Release(); + + if (pPresentParameters == nullptr) + presentResult = pSwapChain->Present(SyncInterval, Flags); + else + presentResult = ((IDXGISwapChain1*)pSwapChain)->Present1(SyncInterval, Flags, pPresentParameters); + + LOG_FUNC_RESULT(presentResult); + return presentResult; + } + + // Upscaler GPU time computation + if (MenuDx11::dx12UpscaleTrig && MenuDx11::readbackBuffer != nullptr && MenuDx11::queryHeap != nullptr && cq != nullptr) + { + if (MenuBase::IsInited() && MenuBase::IsVisible()) + { + UINT64* timestampData; + MenuDx11::readbackBuffer->Map(0, nullptr, reinterpret_cast(×tampData)); + + // Get the GPU timestamp frequency (ticks per second) + UINT64 gpuFrequency; + cq->GetTimestampFrequency(&gpuFrequency); + + // Calculate elapsed time in milliseconds + UINT64 startTime = timestampData[0]; + UINT64 endTime = timestampData[1]; + double elapsedTimeMs = (endTime - startTime) / static_cast(gpuFrequency) * 1000.0; + + Config::Instance()->upscaleTimes.push_back(elapsedTimeMs); + Config::Instance()->upscaleTimes.pop_front(); + + // Unmap the buffer + MenuDx11::readbackBuffer->Unmap(0, nullptr); + } + + MenuDx11::dx12UpscaleTrig = false; + } + else if (MenuDx11::dx11UpscaleTrig[MenuDx11::currentFrameIndex] && device != nullptr && MenuDx11::disjointQueries[0] != nullptr && + MenuDx11::startQueries[0] != nullptr && MenuDx11::endQueries[0] != nullptr) + { + if (g_pd3dDeviceContext == nullptr) + device->GetImmediateContext(&g_pd3dDeviceContext); + + if (MenuBase::IsInited() && MenuBase::IsVisible()) + { + // Retrieve the results from the previous frame + D3D11_QUERY_DATA_TIMESTAMP_DISJOINT disjointData; + if (g_pd3dDeviceContext->GetData(MenuDx11::disjointQueries[MenuDx11::previousFrameIndex], &disjointData, sizeof(disjointData), 0) == S_OK) + { + if (!disjointData.Disjoint && disjointData.Frequency > 0) + { + UINT64 startTime = 0, endTime = 0; + if (g_pd3dDeviceContext->GetData(MenuDx11::startQueries[MenuDx11::previousFrameIndex], &startTime, sizeof(UINT64), 0) == S_OK && + g_pd3dDeviceContext->GetData(MenuDx11::endQueries[MenuDx11::previousFrameIndex], &endTime, sizeof(UINT64), 0) == S_OK) + { + double elapsedTimeMs = (endTime - startTime) / static_cast(disjointData.Frequency) * 1000.0; + Config::Instance()->upscaleTimes.push_back(elapsedTimeMs); + Config::Instance()->upscaleTimes.pop_front(); + } + } + } + } + + + MenuDx11::dx11UpscaleTrig[MenuDx11::currentFrameIndex] = false; + MenuDx11::currentFrameIndex = (MenuDx11::currentFrameIndex + 1) % MenuDx11::QUERY_BUFFER_COUNT; + } + + // Process window handle changed, update base + if (MenuBase::Handle() != hWnd) + { + LOG_DEBUG("Handle changed"); + + if (MenuBase::IsInited()) + MenuBase::Shutdown(); + + MenuBase::Init(hWnd); + + _isInited = false; + } + + // Init + if (!_isInited) + { + if (_dx11Device) + { + CleanupRenderTargetDx11(false); + + g_pd3dDevice = device; + g_pd3dDevice->AddRef(); + + CreateRenderTargetDx11(pSwapChain); + MenuBase::Dx11Ready(); + _isInited = true; + } + else if (_dx12Device && (g_pd3dDeviceParam != nullptr || device12 != nullptr)) + { + if (g_pd3dDeviceParam != nullptr && device12 == nullptr) + device12 = g_pd3dDeviceParam; + + CleanupRenderTargetDx12(true); + + g_pd3dCommandQueue = cq; + g_pd3dDeviceParam = device12; + + g_pd3dCommandQueue->AddRef(); + g_pd3dDeviceParam->AddRef(); + + MenuBase::Dx12Ready(); + _isInited = true; + } + } + + // dx11 multi thread safety + ID3D11Multithread* dx11MultiThread = nullptr; + ID3D11DeviceContext* dx11Context = nullptr; + bool mtState = false; + + if (_dx11Device) + { + ID3D11Device* dx11Device = g_pd3dDevice; + if (dx11Device == nullptr) + dx11Device = d3d11Device; + + if (dx11Device == nullptr) + dx11Device = d3d11on12Device; + + if (dx11Device != nullptr) + { + dx11Device->GetImmediateContext(&dx11Context); + + if (dx11Context != nullptr && dx11Context->QueryInterface(IID_PPV_ARGS(&dx11MultiThread)) == S_OK && dx11MultiThread != nullptr) + { + mtState = dx11MultiThread->GetMultithreadProtected(); + dx11MultiThread->SetMultithreadProtected(TRUE); + dx11MultiThread->Enter(); + } + } + } + + // Render menu + if (_dx11Device) + RenderImGui_DX11(pSwapChain); + else if (_dx12Device) + RenderImGui_DX12(pSwapChain); + + // swapchain present + if (pPresentParameters == nullptr) + presentResult = pSwapChain->Present(SyncInterval, Flags); + else + presentResult = ((IDXGISwapChain1*)pSwapChain)->Present1(SyncInterval, Flags, pPresentParameters); + + // dx11 multi thread safety + if (_dx11Device && dx11MultiThread != nullptr) + { + dx11MultiThread->Leave(); + dx11MultiThread->SetMultithreadProtected(mtState); + + dx11MultiThread->Release(); + dx11Context->Release(); + } + + // release used objects + if (cq != nullptr) + cq->Release(); + + if (device != nullptr) + device->Release(); + + if (device12 != nullptr) + device12->Release(); + + return presentResult; +} + +#pragma endregion + +#pragma region DXGI hooks + +static void CheckAdapter(IUnknown* unkAdapter) +{ + if (Config::Instance()->IsRunningOnDXVK) + return; + + //DXVK VkInterface GUID + const GUID guid = { 0x907bf281,0xea3c,0x43b4,{0xa8,0xe4,0x9f,0x23,0x11,0x07,0xb4,0xff} }; + + IDXGIAdapter* adapter = nullptr; + bool adapterOk = unkAdapter->QueryInterface(IID_PPV_ARGS(&adapter)) == S_OK; + + void* dxvkAdapter = nullptr; + if (adapterOk && adapter->QueryInterface(guid, &dxvkAdapter) == S_OK) + { + + Config::Instance()->IsRunningOnDXVK = dxvkAdapter != nullptr; + ((IDXGIAdapter*)dxvkAdapter)->Release(); + } + + if (adapterOk) + adapter->Release(); +} + +static void AttachToFactory(IUnknown* unkFactory) +{ + PVOID* pVTable = *(PVOID**)unkFactory; + + IDXGIFactory* factory; + if (ptrEnumAdapters == nullptr && unkFactory->QueryInterface(IID_PPV_ARGS(&factory)) == S_OK) + { + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + ptrEnumAdapters = (PFN_EnumAdapters2)pVTable[7]; + + DetourAttach(&(PVOID&)ptrEnumAdapters, hkEnumAdapters); + + DetourTransactionCommit(); + + factory->Release(); + } + + IDXGIFactory1* factory1; + if (ptrEnumAdapters1 == nullptr && unkFactory->QueryInterface(IID_PPV_ARGS(&factory1)) == S_OK) + { + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + ptrEnumAdapters1 = (PFN_EnumAdapters12)pVTable[12]; + + DetourAttach(&(PVOID&)ptrEnumAdapters1, hkEnumAdapters1); + + DetourTransactionCommit(); + + factory1->Release(); + } + + IDXGIFactory4* factory4; + if (ptrEnumAdapterByLuid == nullptr && unkFactory->QueryInterface(IID_PPV_ARGS(&factory4)) == S_OK) + { + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + ptrEnumAdapterByLuid = (PFN_EnumAdapterByLuid2)pVTable[26]; + + DetourAttach(&(PVOID&)ptrEnumAdapterByLuid, hkEnumAdapterByLuid); + + DetourTransactionCommit(); + + factory4->Release(); + } + + IDXGIFactory6* factory6; + if (ptrEnumAdapterByGpuPreference == nullptr && unkFactory->QueryInterface(IID_PPV_ARGS(&factory6)) == S_OK) + { + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + ptrEnumAdapterByGpuPreference = (PFN_EnumAdapterByGpuPreference2)pVTable[29]; + + DetourAttach(&(PVOID&)ptrEnumAdapterByGpuPreference, hkEnumAdapterByGpuPreference); + + DetourTransactionCommit(); + + factory6->Release(); + } +} + + + +#pragma endregion + +#pragma region DirectX hooks + +static void HookToDevice(ID3D12Device* InDevice) +{ + if (o_CreateSampler != nullptr || InDevice == nullptr) + return; + + LOG_FUNC(); + + // Get the vtable pointer + PVOID* pVTable = *(PVOID**)InDevice; + + o_CreateSampler = (PFN_CreateSampler)pVTable[22]; + + // Apply the detour + if (o_CreateSampler != nullptr) + { + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + DetourAttach(&(PVOID&)o_CreateSampler, hkCreateSampler); + + DetourTransactionCommit(); + } +} + +static void HookToDevice(ID3D11Device* InDevice) +{ + if (o_CreateSamplerState != nullptr || InDevice == nullptr) + return; + + LOG_FUNC(); + + // Get the vtable pointer + PVOID* pVTable = *(PVOID**)InDevice; + + o_CreateSamplerState = (PFN_CreateSamplerState)pVTable[23]; + + // Apply the detour + if (o_CreateSamplerState != nullptr) + { + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + DetourAttach(&(PVOID&)o_CreateSamplerState, hkCreateSamplerState); + + DetourTransactionCommit(); + } +} + +static HRESULT hkD3D11On12CreateDevice(IUnknown* pDevice, UINT Flags, D3D_FEATURE_LEVEL* pFeatureLevels, UINT FeatureLevels, IUnknown** ppCommandQueues, + UINT NumQueues, UINT NodeMask, ID3D11Device** ppDevice, ID3D11DeviceContext** ppImmediateContext, D3D_FEATURE_LEVEL* pChosenFeatureLevel) +{ + LOG_FUNC(); + + // Assuming RTSS is creating a D3D11on12 device, not sure why but sometimes RTSS tries to create + // it's D3D11on12 device with old CommandQueue which results crash + // I am changing it's CommandQueue with current swapchain's command queue + if (currentSCCommandQueue != nullptr && *ppCommandQueues != currentSCCommandQueue && GetModuleHandle(L"RTSSHooks64.dll") != nullptr) + { + LOG_INFO("Replaced RTSS CommandQueue with correct one {0:X} -> {1:X}", (UINT64)*ppCommandQueues, (UINT64)currentSCCommandQueue); + *ppCommandQueues = currentSCCommandQueue; + } + + auto result = o_D3D11On12CreateDevice(pDevice, Flags, pFeatureLevels, FeatureLevels, ppCommandQueues, NumQueues, NodeMask, ppDevice, ppImmediateContext, pChosenFeatureLevel); + + if (result == S_OK && *ppDevice != nullptr) + { + LOG_INFO("Device captured, CommandQueue: {0:X}", (UINT64)*ppCommandQueues); + d3d11on12Device = *ppDevice; + HookToDevice(d3d11on12Device); + } + + LOG_FUNC_RESULT(result); + + return result; +} + +static HRESULT hkD3D11CreateDevice(IDXGIAdapter* pAdapter, D3D_DRIVER_TYPE DriverType, HMODULE Software, UINT Flags, CONST D3D_FEATURE_LEVEL* pFeatureLevels, + UINT FeatureLevels, UINT SDKVersion, ID3D11Device** ppDevice, D3D_FEATURE_LEVEL* pFeatureLevel, ID3D11DeviceContext** ppImmediateContext) +{ + LOG_FUNC(); + + static const D3D_FEATURE_LEVEL levels[] = { + D3D_FEATURE_LEVEL_11_1, + }; + + D3D_FEATURE_LEVEL maxLevel = D3D_FEATURE_LEVEL_1_0_CORE; + + for (UINT i = 0; i < FeatureLevels; ++i) + { + maxLevel = std::max(maxLevel, pFeatureLevels[i]); + } + + if (maxLevel == D3D_FEATURE_LEVEL_11_0) + { + LOG_INFO("Overriding D3D_FEATURE_LEVEL, Game requested D3D_FEATURE_LEVEL_11_0, we need D3D_FEATURE_LEVEL_11_1!"); + pFeatureLevels = levels; + FeatureLevels = ARRAYSIZE(levels); + } + + auto result = o_D3D11CreateDevice(pAdapter, DriverType, Software, Flags, pFeatureLevels, FeatureLevels, SDKVersion, ppDevice, pFeatureLevel, ppImmediateContext); + + if (result == S_OK && *ppDevice != nullptr) + { + LOG_INFO("Device captured"); + d3d11Device = *ppDevice; + + HookToDevice(d3d11Device); + } + + LOG_FUNC_RESULT(result); + + return result; +} + +static HRESULT hkD3D11CreateDeviceAndSwapChain(IDXGIAdapter* pAdapter, D3D_DRIVER_TYPE DriverType, HMODULE Software, UINT Flags, CONST D3D_FEATURE_LEVEL* pFeatureLevels, + UINT FeatureLevels, UINT SDKVersion, DXGI_SWAP_CHAIN_DESC* pSwapChainDesc, IDXGISwapChain** ppSwapChain, ID3D11Device** ppDevice, D3D_FEATURE_LEVEL* pFeatureLevel, ID3D11DeviceContext** ppImmediateContext) +{ + LOG_FUNC(); + + static const D3D_FEATURE_LEVEL levels[] = { + D3D_FEATURE_LEVEL_11_1, + }; + + D3D_FEATURE_LEVEL maxLevel = D3D_FEATURE_LEVEL_1_0_CORE; + + for (UINT i = 0; i < FeatureLevels; ++i) + { + maxLevel = std::max(maxLevel, pFeatureLevels[i]); + } + + if (maxLevel == D3D_FEATURE_LEVEL_11_0) + { + LOG_INFO("Overriding D3D_FEATURE_LEVEL, Game requested D3D_FEATURE_LEVEL_11_0, we need D3D_FEATURE_LEVEL_11_1!"); + pFeatureLevels = levels; + FeatureLevels = ARRAYSIZE(levels); + } + + IDXGISwapChain* buffer = nullptr; + auto result = o_D3D11CreateDeviceAndSwapChain(pAdapter, DriverType, Software, Flags, pFeatureLevels, FeatureLevels, SDKVersion, pSwapChainDesc, &buffer, ppDevice, pFeatureLevel, ppImmediateContext); + + if (result == S_OK && *ppDevice != nullptr) + { + LOG_INFO("Device captured"); + d3d11Device = *ppDevice; + + HookToDevice(d3d11Device); + + WrappedSwapChain* buf = nullptr; + if (buffer != nullptr && buffer->QueryInterface(IID_PPV_ARGS(&buf)) != S_OK) + { + // check for SL proxy + IID riid; + IDXGISwapChain* real = nullptr; + auto iidResult = IIDFromString(L"{ADEC44E2-61F0-45C3-AD9F-1B37379284FF}", &riid); + + if (iidResult == S_OK) + { + auto qResult = buffer->QueryInterface(riid, (void**)&real); + + if (qResult == S_OK && real != nullptr) + { + LOG_INFO("Streamline proxy found"); + real->Release(); + } + else + { + LOG_DEBUG("Streamline proxy not found"); + } + } + + if (pSwapChainDesc != nullptr) + { + LOG_DEBUG("Width: {0}, Height: {1}, Format: {2:X}, Count: {3}, Windowed: {4}", pSwapChainDesc->BufferDesc.Width, pSwapChainDesc->BufferDesc.Height, (UINT)pSwapChainDesc->BufferDesc.Format, pSwapChainDesc->BufferCount, pSwapChainDesc->Windowed); + + if (Util::GetProcessWindow() == pSwapChainDesc->OutputWindow) + { + Config::Instance()->ScreenWidth = pSwapChainDesc->BufferDesc.Width; + Config::Instance()->ScreenHeight = pSwapChainDesc->BufferDesc.Height; + } + + LOG_DEBUG("created new swapchain: {0:X}, hWnd: {1:X}", (UINT64)buffer, (UINT64)pSwapChainDesc->OutputWindow); + *ppSwapChain = new WrappedSwapChain(real == nullptr ? buffer : real, d3d11Device, pSwapChainDesc->OutputWindow, Present, CleanupRenderTarget); + LOG_DEBUG("created new WrappedSwapChain: {0:X}, pDevice: {1:X}", (UINT64)buffer, (UINT64)d3d11Device); + } + } + + if (buf != nullptr) + buf->Release(); + } + + if (buffer != nullptr) + buffer->Release(); + + LOG_FUNC_RESULT(result); + + return result; +} + +static HRESULT hkD3D12CreateDevice(IUnknown* pAdapter, D3D_FEATURE_LEVEL MinimumFeatureLevel, REFIID riid, void** ppDevice) +{ + LOG_FUNC(); + + auto result = o_D3D12CreateDevice(pAdapter, MinimumFeatureLevel, riid, ppDevice); + + if (result == S_OK) + { + LOG_INFO("Device captured"); + g_pd3dDeviceParam = (ID3D12Device*)*ppDevice; + HookToDevice(g_pd3dDeviceParam); + } + + LOG_FUNC_RESULT(result); + + return result; +} + +static void hkCreateSampler(ID3D12Device* device, const D3D12_SAMPLER_DESC* pDesc, D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor) +{ + if (pDesc == nullptr || device == nullptr) + return; + + D3D12_SAMPLER_DESC newDesc{}; + + newDesc.AddressU = pDesc->AddressU; + newDesc.AddressV = pDesc->AddressV; + newDesc.AddressW = pDesc->AddressW; + newDesc.BorderColor[0] = pDesc->BorderColor[0]; + newDesc.BorderColor[1] = pDesc->BorderColor[1]; + newDesc.BorderColor[2] = pDesc->BorderColor[2]; + newDesc.BorderColor[3] = pDesc->BorderColor[3]; + newDesc.ComparisonFunc = pDesc->ComparisonFunc; + + if (Config::Instance()->AnisotropyOverride.has_value() && + (pDesc->Filter == D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT || + pDesc->Filter == D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT || + pDesc->Filter == D3D12_FILTER_MIN_MAG_MIP_LINEAR || + pDesc->Filter == D3D12_FILTER_ANISOTROPIC)) + { + LOG_INFO("Overriding Anisotrpic ({2}) filtering {0} -> {1}", pDesc->MaxAnisotropy, Config::Instance()->AnisotropyOverride.value(), (UINT)pDesc->Filter); + newDesc.Filter = D3D12_FILTER_ANISOTROPIC; + newDesc.MaxAnisotropy = Config::Instance()->AnisotropyOverride.value(); + } + else + { + newDesc.Filter = pDesc->Filter; + newDesc.MaxAnisotropy = pDesc->MaxAnisotropy; + } + + newDesc.MaxLOD = pDesc->MaxLOD; + newDesc.MinLOD = pDesc->MinLOD; + newDesc.MipLODBias = pDesc->MipLODBias; + + if (newDesc.MipLODBias < 0.0f) + { + if (Config::Instance()->MipmapBiasOverride.has_value()) + { + LOG_INFO("Overriding mipmap bias {0} -> {1}", pDesc->MipLODBias, Config::Instance()->MipmapBiasOverride.value()); + newDesc.MipLODBias = Config::Instance()->MipmapBiasOverride.value(); + } + + Config::Instance()->lastMipBias = newDesc.MipLODBias; + } + + return o_CreateSampler(device, &newDesc, DestDescriptor); +} + +static HRESULT hkCreateSamplerState(ID3D11Device* This, const D3D11_SAMPLER_DESC* pSamplerDesc, ID3D11SamplerState** ppSamplerState) +{ + if (pSamplerDesc == nullptr || This == nullptr) + return E_INVALIDARG; + + LOG_FUNC(); + + D3D11_SAMPLER_DESC newDesc{}; + + newDesc.AddressU = pSamplerDesc->AddressU; + newDesc.AddressV = pSamplerDesc->AddressV; + newDesc.AddressW = pSamplerDesc->AddressW; + newDesc.ComparisonFunc = pSamplerDesc->ComparisonFunc; + newDesc.BorderColor[0] = pSamplerDesc->BorderColor[0]; + newDesc.BorderColor[1] = pSamplerDesc->BorderColor[1]; + newDesc.BorderColor[2] = pSamplerDesc->BorderColor[2]; + newDesc.BorderColor[3] = pSamplerDesc->BorderColor[3]; + newDesc.MinLOD = pSamplerDesc->MinLOD; + newDesc.MaxLOD = pSamplerDesc->MaxLOD; + + if (Config::Instance()->AnisotropyOverride.has_value() && + (pSamplerDesc->Filter == D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT || + pSamplerDesc->Filter == D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT || + pSamplerDesc->Filter == D3D11_FILTER_MIN_MAG_MIP_LINEAR || + pSamplerDesc->Filter == D3D11_FILTER_ANISOTROPIC)) + { + LOG_INFO("Overriding Anisotrpic ({2}) filtering {0} -> {1}", pSamplerDesc->MaxAnisotropy, Config::Instance()->AnisotropyOverride.value(), (UINT)pSamplerDesc->Filter); + newDesc.Filter = D3D11_FILTER_ANISOTROPIC; + newDesc.MaxAnisotropy = Config::Instance()->AnisotropyOverride.value(); + } + else + { + newDesc.Filter = pSamplerDesc->Filter; + newDesc.MaxAnisotropy = pSamplerDesc->MaxAnisotropy; + } + + newDesc.MipLODBias = pSamplerDesc->MipLODBias; + + if (newDesc.MipLODBias < 0.0f) + { + if (Config::Instance()->MipmapBiasOverride.has_value()) + { + LOG_INFO("Overriding mipmap bias {0} -> {1}", pSamplerDesc->MipLODBias, Config::Instance()->MipmapBiasOverride.value()); + newDesc.MipLODBias = Config::Instance()->MipmapBiasOverride.value(); + } + + Config::Instance()->lastMipBias = newDesc.MipLODBias; + } + + return o_CreateSamplerState(This, &newDesc, ppSamplerState); +} + +#pragma endregion + +static void RenderImGui_DX11(IDXGISwapChain* pSwapChain) +{ + bool drawMenu = false; + + do + { + if (!MenuBase::IsInited()) + break; + + // Draw only when menu activated + if (!MenuBase::IsVisible()) + break; + + if (!_dx11Device || g_pd3dDevice == nullptr) + break; + + drawMenu = true; + + } while (false); + + if (!drawMenu) + { + MenuBase::HideMenu(); + return; + } + + LOG_FUNC(); + + if (ImGui::GetIO().BackendRendererUserData == nullptr) + { + if (pSwapChain->GetDevice(IID_PPV_ARGS(&g_pd3dDevice)) == S_OK) + { + g_pd3dDevice->GetImmediateContext(&g_pd3dDeviceContext); + ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); + } + } + + if (_isInited) + { + if (!g_pd3dRenderTarget) + CreateRenderTargetDx11(pSwapChain); + + if (ImGui::GetCurrentContext() && g_pd3dRenderTarget) + { + ImGui_ImplDX11_NewFrame(); + ImGui_ImplWin32_NewFrame(); + + MenuBase::RenderMenu(); + + ImGui::Render(); + + g_pd3dDeviceContext->OMSetRenderTargets(1, &g_pd3dRenderTarget, NULL); + ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); + } + } +} + +static void RenderImGui_DX12(IDXGISwapChain* pSwapChainPlain) +{ + bool drawMenu = false; + IDXGISwapChain3* pSwapChain = nullptr; + + do + { + if (pSwapChainPlain->QueryInterface(IID_PPV_ARGS(&pSwapChain)) != S_OK || pSwapChain == nullptr) + return; + + if (!MenuBase::IsInited()) + break; + + // Draw only when menu activated + if (!MenuBase::IsVisible()) + break; + + if (!_dx12Device || g_pd3dCommandQueue == nullptr || g_pd3dDeviceParam == nullptr) + break; + + drawMenu = true; + + } while (false); + + if (!drawMenu) + { + MenuBase::HideMenu(); + auto releaseResult = pSwapChain->Release(); + return; + } + + LOG_FUNC(); + + // Get device from swapchain + ID3D12Device* device = g_pd3dDeviceParam; + + // Generate ImGui resources + if (!ImGui::GetIO().BackendRendererUserData && g_pd3dCommandQueue != nullptr) + { + LOG_DEBUG("ImGui::GetIO().BackendRendererUserData == nullptr"); + + HRESULT result; + + { + D3D12_DESCRIPTOR_HEAP_DESC desc = { }; + desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; + desc.NumDescriptors = NUM_BACK_BUFFERS; + desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; + desc.NodeMask = 1; + + result = device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&g_pd3dRtvDescHeap)); + if (result != S_OK) + { + LOG_ERROR("CreateDescriptorHeap(g_pd3dRtvDescHeap): {0:X}", (unsigned long)result); + MenuBase::HideMenu(); + CleanupRenderTargetDx12(true); + pSwapChain->Release(); + return; + } + + SIZE_T rtvDescriptorSize = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); + D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = g_pd3dRtvDescHeap->GetCPUDescriptorHandleForHeapStart(); + + for (UINT i = 0; i < NUM_BACK_BUFFERS; ++i) + { + g_mainRenderTargetDescriptor[i] = rtvHandle; + rtvHandle.ptr += rtvDescriptorSize; + } + } + + { + D3D12_DESCRIPTOR_HEAP_DESC desc = { }; + desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; + desc.NumDescriptors = 1; + desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + + result = device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&g_pd3dSrvDescHeap)); + if (result != S_OK) + { + LOG_ERROR("CreateDescriptorHeap(g_pd3dSrvDescHeap): {0:X}", (unsigned long)result); + MenuBase::HideMenu(); + CleanupRenderTargetDx12(true); + pSwapChain->Release(); + return; + } + } + + for (UINT i = 0; i < NUM_BACK_BUFFERS; ++i) + { + result = device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&g_commandAllocators[i])); + + if (result != S_OK) + { + LOG_ERROR("CreateCommandAllocator[{0}]: {1:X}", i, (unsigned long)result); + MenuBase::HideMenu(); + CleanupRenderTargetDx12(true); + pSwapChain->Release(); + return; + } + } + + result = device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, g_commandAllocators[0], NULL, IID_PPV_ARGS(&g_pd3dCommandList)); + if (result != S_OK) + { + LOG_ERROR("CreateCommandList: {0:X}", (unsigned long)result); + MenuBase::HideMenu(); + CleanupRenderTargetDx12(true); + pSwapChain->Release(); + return; + } + + result = g_pd3dCommandList->Close(); + if (result != S_OK) + { + LOG_ERROR("g_pd3dCommandList->Close: {0:X}", (unsigned long)result); + MenuBase::HideMenu(); + CleanupRenderTargetDx12(false); + pSwapChain->Release(); + return; + } + + ImGui_ImplDX12_Init(device, NUM_BACK_BUFFERS, DXGI_FORMAT_R8G8B8A8_UNORM, g_pd3dSrvDescHeap, + g_pd3dSrvDescHeap->GetCPUDescriptorHandleForHeapStart(), g_pd3dSrvDescHeap->GetGPUDescriptorHandleForHeapStart()); + + pSwapChain->Release(); + return; + } + + if (_isInited) + { + // Generate render targets + if (!g_mainRenderTargetResource[0]) + { + CreateRenderTargetDx12(device, pSwapChain); + pSwapChain->Release(); + return; + } + + // If everything is ready render the frame + if (ImGui::GetCurrentContext() && g_mainRenderTargetResource[0]) + { + _showRenderImGuiDebugOnce = true; + + ImGui_ImplDX12_NewFrame(); + ImGui_ImplWin32_NewFrame(); + + MenuBase::RenderMenu(); + + ImGui::Render(); + + + UINT backBufferIdx = pSwapChain->GetCurrentBackBufferIndex(); + ID3D12CommandAllocator* commandAllocator = g_commandAllocators[backBufferIdx]; + + auto result = commandAllocator->Reset(); + if (result != S_OK) + { + LOG_ERROR("commandAllocator->Reset: {0:X}", (unsigned long)result); + CleanupRenderTargetDx12(false); + pSwapChain->Release(); + return; + } + + D3D12_RESOURCE_BARRIER barrier = { }; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + barrier.Transition.pResource = g_mainRenderTargetResource[backBufferIdx]; + barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; + + result = g_pd3dCommandList->Reset(commandAllocator, nullptr); + if (result != S_OK) + { + LOG_ERROR("g_pd3dCommandList->Reset: {0:X}", (unsigned long)result); + pSwapChain->Release(); + return; + } + + g_pd3dCommandList->ResourceBarrier(1, &barrier); + g_pd3dCommandList->OMSetRenderTargets(1, &g_mainRenderTargetDescriptor[backBufferIdx], FALSE, NULL); + g_pd3dCommandList->SetDescriptorHeaps(1, &g_pd3dSrvDescHeap); + + ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), g_pd3dCommandList); + + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; + g_pd3dCommandList->ResourceBarrier(1, &barrier); + + result = g_pd3dCommandList->Close(); + if (result != S_OK) + { + LOG_ERROR("g_pd3dCommandList->Close: {0:X}", (unsigned long)result); + CleanupRenderTargetDx12(true); + pSwapChain->Release(); + return; + } + + ID3D12CommandList* ppCommandLists[] = { g_pd3dCommandList }; + g_pd3dCommandQueue->ExecuteCommandLists(1, ppCommandLists); + + } + else + { + if (_showRenderImGuiDebugOnce) + LOG_INFO("!(ImGui::GetCurrentContext() && g_pd3dCommandQueue && g_mainRenderTargetResource[0])"); + + MenuBase::HideMenu(); + _showRenderImGuiDebugOnce = false; + } + } + + pSwapChain->Release(); +} + +void DeatachAllHooks() +{ + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + if (o_D3D11CreateDevice != nullptr) + { + DetourDetach(&(PVOID&)o_D3D11CreateDevice, hkD3D11CreateDevice); + o_D3D11CreateDevice = nullptr; + } + + if (o_D3D11On12CreateDevice != nullptr) + { + DetourDetach(&(PVOID&)o_D3D11On12CreateDevice, hkD3D11On12CreateDevice); + o_D3D11On12CreateDevice = nullptr; + } + + if (o_D3D12CreateDevice != nullptr) + { + DetourDetach(&(PVOID&)o_D3D12CreateDevice, hkD3D12CreateDevice); + o_D3D12CreateDevice = nullptr; + } + + if (o_CreateDXGIFactory1 != nullptr) + { + DetourDetach(&(PVOID&)o_CreateDXGIFactory1, hkCreateDXGIFactory1); + o_CreateDXGIFactory1 = nullptr; + } + + if (o_CreateDXGIFactory2 != nullptr) + { + DetourDetach(&(PVOID&)o_CreateDXGIFactory2, hkCreateDXGIFactory2); + o_CreateDXGIFactory2 = nullptr; + } + + if (oCreateSwapChain != nullptr) + { + DetourDetach(&(PVOID&)oCreateSwapChain, hkCreateSwapChain); + oCreateSwapChain = nullptr; + } + + if (oCreateSwapChainForHwnd != nullptr) + { + DetourDetach(&(PVOID&)oCreateSwapChainForHwnd, hkCreateSwapChainForHwnd); + oCreateSwapChainForHwnd = nullptr; + } + + if (o_CreateSampler != nullptr) + { + DetourDetach(&(PVOID&)o_CreateSampler, hkCreateSampler); + o_CreateSampler = nullptr; + } + + DetourTransactionCommit(); +} + +void MenuDx11::HookDx() +{ + if (_isInited) + return; + + o_D3D12CreateDevice = (PFN_D3D12_CREATE_DEVICE)DetourFindFunction("d3d12.dll", "D3D12CreateDevice"); + if (o_D3D12CreateDevice != nullptr) + { + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + DetourAttach(&(PVOID&)o_D3D12CreateDevice, hkD3D12CreateDevice); + + DetourTransactionCommit(); + } + + o_D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)DetourFindFunction("d3d11.dll", "D3D11CreateDevice"); + o_D3D11CreateDeviceAndSwapChain = (PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN)DetourFindFunction("d3d11.dll", "D3D11CreateDeviceAndSwapChain"); + o_D3D11On12CreateDevice = (PFN_D3D11ON12_CREATE_DEVICE)DetourFindFunction("d3d11.dll", "D3D11On12CreateDevice"); + if (o_D3D11CreateDevice != nullptr || o_D3D11On12CreateDevice != nullptr || o_D3D11CreateDeviceAndSwapChain != nullptr) + { + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + if (o_D3D11CreateDevice != nullptr) + DetourAttach(&(PVOID&)o_D3D11CreateDevice, hkD3D11CreateDevice); + + if (o_D3D11On12CreateDevice != nullptr) + DetourAttach(&(PVOID&)o_D3D11On12CreateDevice, hkD3D11On12CreateDevice); + + if (o_D3D11CreateDeviceAndSwapChain != nullptr) + DetourAttach(&(PVOID&)o_D3D11CreateDeviceAndSwapChain, hkD3D11CreateDeviceAndSwapChain); + + DetourTransactionCommit(); + } + + o_CreateDXGIFactory = (PFN_CreateDXGIFactory)DetourFindFunction("dxgi.dll", "CreateDXGIFactory"); + o_CreateDXGIFactory1 = (PFN_CreateDXGIFactory1)DetourFindFunction("dxgi.dll", "CreateDXGIFactory1"); + o_CreateDXGIFactory2 = (PFN_CreateDXGIFactory2)DetourFindFunction("dxgi.dll", "CreateDXGIFactory2"); + + if (o_CreateDXGIFactory1 != nullptr) + { + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + if (o_CreateDXGIFactory != nullptr) + DetourAttach(&(PVOID&)o_CreateDXGIFactory, hkCreateDXGIFactory); + + if (o_CreateDXGIFactory1 != nullptr) + DetourAttach(&(PVOID&)o_CreateDXGIFactory1, hkCreateDXGIFactory1); + + if (o_CreateDXGIFactory2 != nullptr) + DetourAttach(&(PVOID&)o_CreateDXGIFactory2, hkCreateDXGIFactory2); + + DetourTransactionCommit(); + } +} + +void MenuDx11::UnHookDx() +{ + if (!Config::Instance()->IsRunningOnDXVK) + { + if (_isInited && MenuBase::IsInited() && ImGui::GetIO().BackendRendererUserData) + { + if (_dx11Device) + ImGui_ImplDX11_Shutdown(); + else + ImGui_ImplDX12_Shutdown(); + } + + MenuBase::Shutdown(); + + if (_isInited) + { + if (_dx11Device) + CleanupRenderTargetDx11(true); + else + CleanupRenderTargetDx12(true); + } + } + + DeatachAllHooks(); + + _isInited = false; +} diff --git a/OptiScaler/menu/MenuDx11.h b/OptiScaler/menu/MenuDx11.h new file mode 100644 index 00000000..52cb000c --- /dev/null +++ b/OptiScaler/menu/MenuDx11.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +#include +#include + +class MenuDx11 +{ +private: + inline static const int QUERY_BUFFER_COUNT = 3; + inline static ID3D11Query* disjointQueries[QUERY_BUFFER_COUNT] = { nullptr, nullptr, nullptr }; + inline static ID3D11Query* startQueries[QUERY_BUFFER_COUNT] = { nullptr, nullptr, nullptr }; + inline static ID3D11Query* endQueries[QUERY_BUFFER_COUNT] = { nullptr, nullptr, nullptr }; + inline static bool dx11UpscaleTrig[QUERY_BUFFER_COUNT] = { false, false, false }; + + inline static int currentFrameIndex = 0; + inline static int previousFrameIndex = 0; + +public: + + static void PrepareTimeObjects(VkInstance InInstance, VkPhysicalDevice InPD, VkDevice InDevice); + static void BeforeUpscale(VkCommandBuffer InCmdBuffer); + static void AfterUpscale(VkCommandBuffer InCmdBuffer); +}; diff --git a/OptiScaler/menu/MenuDx.cpp b/OptiScaler/menu/MenuDx12.cpp similarity index 80% rename from OptiScaler/menu/MenuDx.cpp rename to OptiScaler/menu/MenuDx12.cpp index cdd298d1..98abb32a 100644 --- a/OptiScaler/menu/MenuDx.cpp +++ b/OptiScaler/menu/MenuDx12.cpp @@ -3,7 +3,6 @@ #include #include #include -#include "wrapped_swapchain.h" #include "MenuBase.h" #include @@ -16,12 +15,12 @@ // dxgi stuff typedef HRESULT(*PFN_CreateDXGIFactory)(REFIID riid, IDXGIFactory** ppFactory); typedef HRESULT(*PFN_CreateDXGIFactory1)(REFIID riid, IDXGIFactory1** ppFactory); -typedef HRESULT(*PFN_CreateDXGIFactory2)(UINT Flags, REFIID riid, _COM_Outptr_ IDXGIFactory2** ppFactory); +typedef HRESULT(*PFN_CreateDXGIFactory2)(UINT Flags, REFIID riid, IDXGIFactory2** ppFactory); -typedef HRESULT(WINAPI* PFN_EnumAdapterByGpuPreference2)(IDXGIFactory6* This, UINT Adapter, DXGI_GPU_PREFERENCE GpuPreference, REFIID riid, IUnknown** ppvAdapter); -typedef HRESULT(WINAPI* PFN_EnumAdapterByLuid2)(IDXGIFactory4* This, LUID AdapterLuid, REFIID riid, IUnknown** ppvAdapter); -typedef HRESULT(WINAPI* PFN_EnumAdapters12)(IDXGIFactory1* This, UINT Adapter, IUnknown** ppAdapter); -typedef HRESULT(WINAPI* PFN_EnumAdapters2)(IDXGIFactory* This, UINT Adapter, IUnknown** ppAdapter); +typedef HRESULT(*PFN_EnumAdapterByGpuPreference2)(IDXGIFactory6* This, UINT Adapter, DXGI_GPU_PREFERENCE GpuPreference, REFIID riid, IUnknown** ppvAdapter); +typedef HRESULT(*PFN_EnumAdapterByLuid2)(IDXGIFactory4* This, LUID AdapterLuid, REFIID riid, IUnknown** ppvAdapter); +typedef HRESULT(*PFN_EnumAdapters12)(IDXGIFactory1* This, UINT Adapter, IUnknown** ppAdapter); +typedef HRESULT(*PFN_EnumAdapters2)(IDXGIFactory* This, UINT Adapter, IUnknown** ppAdapter); static PFN_CreateDXGIFactory o_CreateDXGIFactory = nullptr; static PFN_CreateDXGIFactory1 o_CreateDXGIFactory1 = nullptr; @@ -31,18 +30,16 @@ inline static PFN_EnumAdapters2 ptrEnumAdapters = nullptr; inline static PFN_EnumAdapters12 ptrEnumAdapters1 = nullptr; inline static PFN_EnumAdapterByLuid2 ptrEnumAdapterByLuid = nullptr; inline static PFN_EnumAdapterByGpuPreference2 ptrEnumAdapterByGpuPreference = nullptr; -inline static PFN_Present o_Present = nullptr; -inline static PFN_Present1 o_Present1 = nullptr; static PFN_CreateSwapChain oCreateSwapChain = nullptr; static PFN_CreateSwapChainForHwnd oCreateSwapChainForHwnd = nullptr; -// MipMap hooks // DirectX typedef void(*PFN_CreateSampler)(ID3D12Device* device, const D3D12_SAMPLER_DESC* pDesc, D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor); typedef HRESULT(*PFN_CreateSamplerState)(ID3D11Device* This, const D3D11_SAMPLER_DESC* pSamplerDesc, ID3D11SamplerState** ppSamplerState); +// MipMap hooks static PFN_D3D12_CREATE_DEVICE o_D3D12CreateDevice = nullptr; static PFN_CreateSampler o_CreateSampler = nullptr; @@ -86,7 +83,6 @@ static bool _showRenderImGuiDebugOnce = true; static std::mutex _dx11CleanMutex; static std::mutex _dx12CleanMutex; - static void RenderImGui_DX11(IDXGISwapChain* pSwapChain); static void RenderImGui_DX12(IDXGISwapChain* pSwapChain); static void DeatachAllHooks(); @@ -608,294 +604,7 @@ static void AttachToFactory(IUnknown* unkFactory) } } -static HRESULT hkCreateSwapChain(IDXGIFactory* pFactory, IUnknown* pDevice, DXGI_SWAP_CHAIN_DESC* pDesc, IDXGISwapChain** ppSwapChain) -{ - LOG_FUNC(); - *ppSwapChain = nullptr; - - if (Config::Instance()->VulkanCreatingSC) - { - LOG_WARN("Vulkan is creating swapchain!"); - - if(pDesc != nullptr) - LOG_DEBUG("Width: {0}, Height: {1}, Format: {2:X}, Count: {3}, Windowed: {4}", pDesc->BufferDesc.Width, pDesc->BufferDesc.Height, (UINT)pDesc->BufferDesc.Format, pDesc->BufferCount, pDesc->Windowed); - - return oCreateSwapChain(pFactory, pDevice, pDesc, ppSwapChain); - } - - if (pDevice == nullptr) - { - LOG_WARN("pDevice is nullptr!"); - return oCreateSwapChain(pFactory, pDevice, pDesc, ppSwapChain); - } - - auto result = oCreateSwapChain(pFactory, pDevice, pDesc, ppSwapChain); - - if (result == S_OK) - { - // check for SL proxy - IID riid; - IDXGISwapChain* real = nullptr; - auto iidResult = IIDFromString(L"{ADEC44E2-61F0-45C3-AD9F-1B37379284FF}", &riid); - - if (iidResult == S_OK) - { - auto qResult = (*ppSwapChain)->QueryInterface(riid, (void**)&real); - - if (qResult == S_OK && real != nullptr) - { - LOG_INFO("Streamline proxy found"); - real->Release(); - } - else - { - LOG_DEBUG("Streamline proxy not found"); - } - } - - LOG_DEBUG("Width: {0}, Height: {1}, Format: {2:X}, Count: {3}, Windowed: {4}", pDesc->BufferDesc.Width, pDesc->BufferDesc.Height, (UINT)pDesc->BufferDesc.Format, pDesc->BufferCount, pDesc->Windowed); - - if (Util::GetProcessWindow() == pDesc->OutputWindow) - { - Config::Instance()->ScreenWidth = pDesc->BufferDesc.Width; - Config::Instance()->ScreenHeight = pDesc->BufferDesc.Height; - } - - LOG_DEBUG("created new swapchain: {0:X}, hWnd: {1:X}", (UINT64)*ppSwapChain, (UINT64)pDesc->OutputWindow); - *ppSwapChain = new WrappedIDXGISwapChain4(real == nullptr ? *ppSwapChain : real, pDevice, pDesc->OutputWindow, Present, CleanupRenderTarget); - LOG_DEBUG("created new WrappedIDXGISwapChain4: {0:X}, pDevice: {1:X}", (UINT64)*ppSwapChain, (UINT64)pDevice); - } - - return result; -} - -static HRESULT hkCreateSwapChainForHwnd(IDXGIFactory* pCommandQueue, IUnknown* pDevice, HWND hWnd, const DXGI_SWAP_CHAIN_DESC1* pDesc, - const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc, IDXGIOutput* pRestrictToOutput, IDXGISwapChain1** ppSwapChain) -{ - LOG_FUNC(); - - *ppSwapChain = nullptr; - - if (Config::Instance()->VulkanCreatingSC) - { - LOG_WARN("Vulkan is creating swapchain!"); - - if (pDesc != nullptr) - LOG_DEBUG("Width: {0}, Height: {1}, Format: {2:X}, Count: {3}, Flags: {4:X}", pDesc->Width, pDesc->Height, (UINT)pDesc->Format, pDesc->BufferCount, pDesc->Flags); - - return oCreateSwapChainForHwnd(pCommandQueue, pDevice, hWnd, pDesc, pFullscreenDesc, pRestrictToOutput, ppSwapChain); - } - - if (pDevice == nullptr) - { - LOG_WARN("pDevice is nullptr!"); - return oCreateSwapChainForHwnd(pCommandQueue, pDevice, hWnd, pDesc, pFullscreenDesc, pRestrictToOutput, ppSwapChain); - } - - auto result = oCreateSwapChainForHwnd(pCommandQueue, pDevice, hWnd, pDesc, pFullscreenDesc, pRestrictToOutput, ppSwapChain); - - if (result == S_OK) - { - // check for SL proxy - IID riid; - IDXGISwapChain1* real = nullptr; - auto iidResult = IIDFromString(L"{ADEC44E2-61F0-45C3-AD9F-1B37379284FF}", &riid); - - if (iidResult == S_OK) - { - IUnknown* real = nullptr; - auto qResult = (*ppSwapChain)->QueryInterface(riid, (void**)&real); - - if (qResult == S_OK && real != nullptr) - { - LOG_INFO("Streamline proxy found"); - real->Release(); - } - else - { - LOG_DEBUG("Streamline proxy not found"); - } - } - - LOG_DEBUG("Width: {0}, Height: {1}, Format: {2:X}, Count: {3}, Flags: {4:X}", pDesc->Width, pDesc->Height, (UINT)pDesc->Format, pDesc->BufferCount, pDesc->Flags); - - if (Util::GetProcessWindow() == hWnd) - { - Config::Instance()->ScreenWidth = pDesc->Width; - Config::Instance()->ScreenHeight = pDesc->Height; - } - - LOG_DEBUG("created new swapchain: {0:X}, hWnd: {1:X}", (UINT64)*ppSwapChain, (UINT64)hWnd); - *ppSwapChain = new WrappedIDXGISwapChain4(real == nullptr ? *ppSwapChain : real, pDevice, hWnd, Present, CleanupRenderTarget); - LOG_DEBUG("created new WrappedIDXGISwapChain4: {0:X}, pDevice: {1:X}", (UINT64)*ppSwapChain, (UINT64)pDevice); - } - - return result; -} - -static HRESULT hkCreateDXGIFactory(REFIID riid, IDXGIFactory** ppFactory) -{ - auto result = o_CreateDXGIFactory(riid, ppFactory); - - if (result == S_OK) - AttachToFactory(*ppFactory); - - if (result == S_OK && oCreateSwapChain == nullptr) - { - void** pFactoryVTable = *reinterpret_cast(*ppFactory); - - oCreateSwapChain = (PFN_CreateSwapChain)pFactoryVTable[10]; - - if (oCreateSwapChain != nullptr) - { - LOG_INFO("Hooking native DXGIFactory"); - - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - - DetourAttach(&(PVOID&)oCreateSwapChain, hkCreateSwapChain); - - DetourTransactionCommit(); - } - } - - return result; -} - -static HRESULT hkCreateDXGIFactory1(REFIID riid, IDXGIFactory1** ppFactory) -{ - auto result = o_CreateDXGIFactory1(riid, ppFactory); - - if (result == S_OK) - AttachToFactory(*ppFactory); - - if (result == S_OK && oCreateSwapChainForHwnd == nullptr) - { - IDXGIFactory2* factory2 = nullptr; - - if ((*ppFactory)->QueryInterface(IID_PPV_ARGS(&factory2)) == S_OK && factory2 != nullptr) - { - void** pFactoryVTable = *reinterpret_cast(factory2); - - bool skip = false; - - if (oCreateSwapChain == nullptr) - oCreateSwapChain = (PFN_CreateSwapChain)pFactoryVTable[10]; - else - skip = true; - - oCreateSwapChainForHwnd = (PFN_CreateSwapChainForHwnd)pFactoryVTable[15]; - - if (oCreateSwapChainForHwnd != nullptr) - { - LOG_INFO("Hooking native DXGIFactory"); - - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - - if (!skip) - DetourAttach(&(PVOID&)oCreateSwapChain, hkCreateSwapChain); - - DetourAttach(&(PVOID&)oCreateSwapChainForHwnd, hkCreateSwapChainForHwnd); - - DetourTransactionCommit(); - } - - factory2->Release(); - factory2 = nullptr; - } - } - - return result; -} - -static HRESULT hkCreateDXGIFactory2(UINT Flags, REFIID riid, IDXGIFactory2** ppFactory) -{ - auto result = o_CreateDXGIFactory2(Flags, riid, ppFactory); - - if (result == S_OK) - AttachToFactory(*ppFactory); - - if (result == S_OK && oCreateSwapChainForHwnd == nullptr) - { - IDXGIFactory2* factory2 = nullptr; - - if ((*ppFactory)->QueryInterface(IID_PPV_ARGS(&factory2)) == S_OK && factory2 != nullptr) - { - void** pFactoryVTable = *reinterpret_cast(factory2); - - bool skip = false; - - if (oCreateSwapChain == nullptr) - oCreateSwapChain = (PFN_CreateSwapChain)pFactoryVTable[10]; - else - skip = true; - - oCreateSwapChainForHwnd = (PFN_CreateSwapChainForHwnd)pFactoryVTable[15]; - - if (oCreateSwapChainForHwnd != nullptr) - { - LOG_INFO("Hooking native DXGIFactory"); - - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - - if (!skip) - DetourAttach(&(PVOID&)oCreateSwapChain, hkCreateSwapChain); - - DetourAttach(&(PVOID&)oCreateSwapChainForHwnd, hkCreateSwapChainForHwnd); - - DetourTransactionCommit(); - } - - factory2->Release(); - factory2 = nullptr; - } - } - - return result; -} - -static HRESULT hkEnumAdapterByGpuPreference(IDXGIFactory6* This, UINT Adapter, DXGI_GPU_PREFERENCE GpuPreference, REFIID riid, IUnknown** ppvAdapter) -{ - auto result = ptrEnumAdapterByGpuPreference(This, Adapter, GpuPreference, riid, ppvAdapter); - - if (result == S_OK) - CheckAdapter(*ppvAdapter); - - return result; -} - -static HRESULT hkEnumAdapterByLuid(IDXGIFactory4* This, LUID AdapterLuid, REFIID riid, IUnknown** ppvAdapter) -{ - auto result = ptrEnumAdapterByLuid(This, AdapterLuid, riid, ppvAdapter); - - if (result == S_OK) - CheckAdapter(*ppvAdapter); - - return result; -} - -static HRESULT hkEnumAdapters1(IDXGIFactory1* This, UINT Adapter, IUnknown** ppAdapter) -{ - auto result = ptrEnumAdapters1(This, Adapter, ppAdapter); - - if (result == S_OK) - CheckAdapter(*ppAdapter); - - return result; -} - -static HRESULT hkEnumAdapters(IDXGIFactory* This, UINT Adapter, IUnknown** ppAdapter) -{ - auto result = ptrEnumAdapters(This, Adapter, ppAdapter); - - if (result == S_OK) - CheckAdapter(*ppAdapter); - - return result; -} #pragma endregion @@ -1048,7 +757,7 @@ static HRESULT hkD3D11CreateDeviceAndSwapChain(IDXGIAdapter* pAdapter, D3D_DRIVE HookToDevice(d3d11Device); - WrappedIDXGISwapChain4* buf = nullptr; + WrappedSwapChain* buf = nullptr; if (buffer != nullptr && buffer->QueryInterface(IID_PPV_ARGS(&buf)) != S_OK) { // check for SL proxy @@ -1082,8 +791,8 @@ static HRESULT hkD3D11CreateDeviceAndSwapChain(IDXGIAdapter* pAdapter, D3D_DRIVE } LOG_DEBUG("created new swapchain: {0:X}, hWnd: {1:X}", (UINT64)buffer, (UINT64)pSwapChainDesc->OutputWindow); - *ppSwapChain = new WrappedIDXGISwapChain4(real == nullptr ? buffer : real, d3d11Device, pSwapChainDesc->OutputWindow, Present, CleanupRenderTarget); - LOG_DEBUG("created new WrappedIDXGISwapChain4: {0:X}, pDevice: {1:X}", (UINT64)buffer, (UINT64)d3d11Device); + *ppSwapChain = new WrappedSwapChain(real == nullptr ? buffer : real, d3d11Device, pSwapChainDesc->OutputWindow, Present, CleanupRenderTarget); + LOG_DEBUG("created new WrappedSwapChain: {0:X}, pDevice: {1:X}", (UINT64)buffer, (UINT64)d3d11Device); } } diff --git a/OptiScaler/menu/MenuDx.h b/OptiScaler/menu/MenuDx12.h similarity index 100% rename from OptiScaler/menu/MenuDx.h rename to OptiScaler/menu/MenuDx12.h diff --git a/OptiScaler/menu/MenuVulkan.cpp b/OptiScaler/menu/MenuVulkan.cpp index 7b8d9877..9f3481e9 100644 --- a/OptiScaler/menu/MenuVulkan.cpp +++ b/OptiScaler/menu/MenuVulkan.cpp @@ -499,14 +499,14 @@ VkResult MenuVulkan::QueuePresent(VkQueue queue, VkPresentInfoKHR* pPresentInfo) _vkPresentMutex.lock(); - if (MenuVulkan::vkUpscaleTrig && MenuVulkan::queryPool != VK_NULL_HANDLE) + if (vkUpscaleTrig && queryPool != VK_NULL_HANDLE) { // Retrieve timestamps uint64_t timestamps[2]; - vkGetQueryPoolResults(_device, MenuVulkan::queryPool, 0, 2, sizeof(timestamps), timestamps, sizeof(uint64_t), VK_QUERY_RESULT_64_BIT); + vkGetQueryPoolResults(_device, queryPool, 0, 2, sizeof(timestamps), timestamps, sizeof(uint64_t), VK_QUERY_RESULT_64_BIT); // Calculate elapsed time in milliseconds - double elapsedTimeMs = (timestamps[1] - timestamps[0]) * MenuVulkan::timeStampPeriod / 1e6; + double elapsedTimeMs = (timestamps[1] - timestamps[0]) * timeStampPeriod / 1e6; if (elapsedTimeMs > 0.0 && elapsedTimeMs < 5000.0) { @@ -514,7 +514,7 @@ VkResult MenuVulkan::QueuePresent(VkQueue queue, VkPresentInfoKHR* pPresentInfo) Config::Instance()->upscaleTimes.pop_front(); } - MenuVulkan::vkUpscaleTrig = false; + vkUpscaleTrig = false; } LOG_DEBUG("rendering menu, swapchain count: {0}", pPresentInfo->swapchainCount); @@ -648,3 +648,28 @@ void MenuVulkan::CreateSwapchain(VkDevice device, const VkSwapchainCreateInfoKHR MenuBase::VulkanReady(); } } + +void MenuVulkan::PrepareTimeObjects(VkInstance InInstance, VkPhysicalDevice InPD, VkDevice InDevice) +{ + VkQueryPoolCreateInfo queryPoolInfo = {}; + queryPoolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; + queryPoolInfo.queryType = VK_QUERY_TYPE_TIMESTAMP; + queryPoolInfo.queryCount = 2; // Start and End timestamps + + vkCreateQueryPool(InDevice, &queryPoolInfo, nullptr, &queryPool); + + VkPhysicalDeviceProperties deviceProperties; + vkGetPhysicalDeviceProperties(InPD, &deviceProperties); + timeStampPeriod = deviceProperties.limits.timestampPeriod; +} + +void MenuVulkan::BeforeUpscale(VkCommandBuffer InCmdBuffer) +{ + vkCmdWriteTimestamp(InCmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, queryPool, 0); +} + +void MenuVulkan::AfterUpscale(VkCommandBuffer InCmdBuffer) +{ + vkCmdWriteTimestamp(InCmdBuffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool, 1); + vkUpscaleTrig = true; +} diff --git a/OptiScaler/menu/MenuVulkan.h b/OptiScaler/menu/MenuVulkan.h index 2fbc7564..fe6820a0 100644 --- a/OptiScaler/menu/MenuVulkan.h +++ b/OptiScaler/menu/MenuVulkan.h @@ -17,4 +17,7 @@ public: static void CreateDevice(VkPhysicalDevice physicalDevice, VkDevice* pDevice); static VkResult QueuePresent(VkQueue queue, VkPresentInfoKHR* pPresentInfo); static void CreateSwapchain(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, VkSwapchainKHR* pSwapchain); + static void PrepareTimeObjects(VkInstance InInstance, VkPhysicalDevice InPD, VkDevice InDevice); + static void BeforeUpscale(VkCommandBuffer InCmdBuffer); + static void AfterUpscale(VkCommandBuffer InCmdBuffer); }; diff --git a/OptiScaler/menu/wrapped_swapchain.cpp b/OptiScaler/objects/WrappedSwapChain.cpp similarity index 79% rename from OptiScaler/menu/wrapped_swapchain.cpp rename to OptiScaler/objects/WrappedSwapChain.cpp index e78742d0..9a1ee704 100644 --- a/OptiScaler/menu/wrapped_swapchain.cpp +++ b/OptiScaler/objects/WrappedSwapChain.cpp @@ -1,4 +1,4 @@ -#include "wrapped_swapchain.h" +#include "WrappedSwapChain.h" #include #include @@ -8,7 +8,7 @@ static int scCount = 0; -WrappedIDXGISwapChain4::WrappedIDXGISwapChain4(IDXGISwapChain* real, IUnknown* pDevice, HWND hWnd, PFN_SC_Present renderTrig, PFN_SC_Clean clearTrig) +WrappedSwapChain::WrappedSwapChain(IDXGISwapChain* real, IUnknown* pDevice, HWND hWnd, PFN_SC_Present renderTrig, PFN_SC_Clean clearTrig) : m_pReal(real), Device(pDevice), Handle(hWnd), RenderTrig(renderTrig), ClearTrig(clearTrig), m_iRefcount(1) { id = ++scCount; @@ -19,12 +19,12 @@ WrappedIDXGISwapChain4::WrappedIDXGISwapChain4(IDXGISwapChain* real, IUnknown* p m_pReal->QueryInterface(IID_PPV_ARGS(&m_pReal4)); } -WrappedIDXGISwapChain4::~WrappedIDXGISwapChain4() +WrappedSwapChain::~WrappedSwapChain() { } -HRESULT STDMETHODCALLTYPE WrappedIDXGISwapChain4::QueryInterface(REFIID riid, void** ppvObject) +HRESULT STDMETHODCALLTYPE WrappedSwapChain::QueryInterface(REFIID riid, void** ppvObject) { if (riid == __uuidof(IDXGISwapChain)) { @@ -112,7 +112,7 @@ HRESULT STDMETHODCALLTYPE WrappedIDXGISwapChain4::QueryInterface(REFIID riid, vo return E_NOINTERFACE; } -HRESULT WrappedIDXGISwapChain4::ResizeBuffers(UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags) +HRESULT WrappedSwapChain::ResizeBuffers(UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags) { LOG_FUNC(); @@ -136,12 +136,12 @@ HRESULT WrappedIDXGISwapChain4::ResizeBuffers(UINT BufferCount, UINT Width, UINT return result; } -HRESULT STDMETHODCALLTYPE WrappedIDXGISwapChain4::GetContainingOutput(IDXGIOutput** ppOutput) +HRESULT STDMETHODCALLTYPE WrappedSwapChain::GetContainingOutput(IDXGIOutput** ppOutput) { return m_pReal->GetContainingOutput(ppOutput); } -HRESULT WrappedIDXGISwapChain4::ResizeBuffers1(UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT Format, UINT SwapChainFlags, +HRESULT WrappedSwapChain::ResizeBuffers1(UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT Format, UINT SwapChainFlags, const UINT* pCreationNodeMask, IUnknown* const* ppPresentQueue) { LOG_FUNC(); @@ -166,27 +166,27 @@ HRESULT WrappedIDXGISwapChain4::ResizeBuffers1(UINT BufferCount, UINT Width, UIN return result; } -HRESULT WrappedIDXGISwapChain4::SetFullscreenState(BOOL Fullscreen, IDXGIOutput* pTarget) +HRESULT WrappedSwapChain::SetFullscreenState(BOOL Fullscreen, IDXGIOutput* pTarget) { return m_pReal->SetFullscreenState(Fullscreen, pTarget); } -HRESULT WrappedIDXGISwapChain4::GetFullscreenState(BOOL* pFullscreen, IDXGIOutput** ppTarget) +HRESULT WrappedSwapChain::GetFullscreenState(BOOL* pFullscreen, IDXGIOutput** ppTarget) { return m_pReal->GetFullscreenState(pFullscreen, ppTarget); } -HRESULT WrappedIDXGISwapChain4::GetBuffer(UINT Buffer, REFIID riid, void** ppSurface) +HRESULT WrappedSwapChain::GetBuffer(UINT Buffer, REFIID riid, void** ppSurface) { return m_pReal->GetBuffer(Buffer, riid, ppSurface); } -HRESULT WrappedIDXGISwapChain4::GetDevice(REFIID riid, void** ppDevice) +HRESULT WrappedSwapChain::GetDevice(REFIID riid, void** ppDevice) { return m_pReal->GetDevice(riid, ppDevice); } -HRESULT WrappedIDXGISwapChain4::Present(UINT SyncInterval, UINT Flags) +HRESULT WrappedSwapChain::Present(UINT SyncInterval, UINT Flags) { if (m_pReal == nullptr) return DXGI_ERROR_DEVICE_REMOVED; @@ -201,7 +201,7 @@ HRESULT WrappedIDXGISwapChain4::Present(UINT SyncInterval, UINT Flags) return result; } -HRESULT WrappedIDXGISwapChain4::Present1(UINT SyncInterval, UINT Flags, const DXGI_PRESENT_PARAMETERS* pPresentParameters) +HRESULT WrappedSwapChain::Present1(UINT SyncInterval, UINT Flags, const DXGI_PRESENT_PARAMETERS* pPresentParameters) { if (m_pReal1 == nullptr) return DXGI_ERROR_DEVICE_REMOVED; @@ -216,7 +216,7 @@ HRESULT WrappedIDXGISwapChain4::Present1(UINT SyncInterval, UINT Flags, const DX return result; } -HRESULT STDMETHODCALLTYPE WrappedIDXGISwapChain4::GetRestrictToOutput(IDXGIOutput** ppRestrictToOutput) +HRESULT STDMETHODCALLTYPE WrappedSwapChain::GetRestrictToOutput(IDXGIOutput** ppRestrictToOutput) { return m_pReal1->GetRestrictToOutput(ppRestrictToOutput); } \ No newline at end of file diff --git a/OptiScaler/menu/wrapped_swapchain.h b/OptiScaler/objects/WrappedSwapChain.h similarity index 96% rename from OptiScaler/menu/wrapped_swapchain.h rename to OptiScaler/objects/WrappedSwapChain.h index 7eab6dcd..b9205470 100644 --- a/OptiScaler/menu/wrapped_swapchain.h +++ b/OptiScaler/objects/WrappedSwapChain.h @@ -2,18 +2,16 @@ #include -#include "MenuBase.h" - #include typedef HRESULT(*PFN_SC_Present)(IDXGISwapChain*, UINT, UINT, const DXGI_PRESENT_PARAMETERS*, IUnknown*, HWND); typedef void(*PFN_SC_Clean)(bool, HWND); -struct DECLSPEC_UUID("3af622a3-82d0-49cd-994f-cce05122c222") WrappedIDXGISwapChain4 : public IDXGISwapChain4 +struct DECLSPEC_UUID("3af622a3-82d0-49cd-994f-cce05122c222") WrappedSwapChain : public IDXGISwapChain4 { - WrappedIDXGISwapChain4(IDXGISwapChain* real, IUnknown* pDevice, HWND hWnd, PFN_SC_Present renderTrig, PFN_SC_Clean clearTrig); + WrappedSwapChain(IDXGISwapChain* real, IUnknown* pDevice, HWND hWnd, PFN_SC_Present renderTrig, PFN_SC_Clean clearTrig); - virtual ~WrappedIDXGISwapChain4(); + virtual ~WrappedSwapChain(); virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject); diff --git a/OptiScaler/proxies/FfxApi_Proxy.h b/OptiScaler/proxies/FfxApi_Proxy.h index 460948c2..7a53a6e3 100644 --- a/OptiScaler/proxies/FfxApi_Proxy.h +++ b/OptiScaler/proxies/FfxApi_Proxy.h @@ -1,20 +1,14 @@ #pragma once -#include "pch.h" +#include -#include "Util.h" -#include "Config.h" -#include "Logger.h" +#include +#include +#include #include "ffx_api.h" -#include -typedef struct _feature_version -{ - unsigned int major; - unsigned int minor; - unsigned int patch; -} feature_version; +#include class FfxApiProxy { diff --git a/OptiScaler/proxies/NVNGX_Proxy.h b/OptiScaler/proxies/NVNGX_Proxy.h index 11e12759..2965e4be 100644 --- a/OptiScaler/proxies/NVNGX_Proxy.h +++ b/OptiScaler/proxies/NVNGX_Proxy.h @@ -17,81 +17,14 @@ constexpr unsigned long long app_id_override = 0x24480451; #pragma region spoofing hooks for 16xx -// NvAPI_GPU_GetArchInfo hooking based on Nukem's spoofing code here -// https://github.com/Nukem9/dlssg-to-fsr3/blob/89ddc8c1cce4593fb420e633a06605c3c4b9c3cf/source/wrapper_generic/nvapi.cpp#L50 - -enum class NV_INTERFACE : uint32_t -{ - GPU_GetArchInfo = 0xD8265D24, - D3D12_SetRawScgPriority = 0x5DB3048A, -}; - -typedef void* (__stdcall* PFN_NvApi_QueryInterface)(NV_INTERFACE InterfaceId); typedef NVSDK_NGX_Result(*PFN_NVSDK_NGX_D3D1X_GetFeatureRequirements)(IDXGIAdapter* Adapter, const NVSDK_NGX_FeatureDiscoveryInfo* FeatureDiscoveryInfo, NVSDK_NGX_FeatureRequirement* OutSupported); typedef NVSDK_NGX_Result(*PFN_NVSDK_NGX_VULKAN_GetFeatureRequirements)(const VkInstance Instance, const VkPhysicalDevice PhysicalDevice, const NVSDK_NGX_FeatureDiscoveryInfo* FeatureDiscoveryInfo, NVSDK_NGX_FeatureRequirement* OutSupported); -using PfnNvAPI_GPU_GetArchInfo = uint32_t(__stdcall*)(void* GPUHandle, NV_GPU_ARCH_INFO* ArchInfo); - -inline static PFN_NvApi_QueryInterface OriginalNvAPI_QueryInterface = nullptr; -inline static PfnNvAPI_GPU_GetArchInfo OriginalNvAPI_GPU_GetArchInfo = nullptr; inline static PFN_NVSDK_NGX_D3D1X_GetFeatureRequirements Original_D3D11_GetFeatureRequirements = nullptr; inline static PFN_NVSDK_NGX_D3D1X_GetFeatureRequirements Original_D3D12_GetFeatureRequirements = nullptr; inline static PFN_NVSDK_NGX_VULKAN_GetFeatureRequirements Original_Vulkan_GetFeatureRequirements = nullptr; -inline static uint32_t __stdcall HookedNvAPI_GPU_GetArchInfo(void* GPUHandle, NV_GPU_ARCH_INFO* ArchInfo) -{ - if (OriginalNvAPI_GPU_GetArchInfo) - { - const auto status = OriginalNvAPI_GPU_GetArchInfo(GPUHandle, ArchInfo); - - if (status == 0 && ArchInfo) - { - LOG_DEBUG("From api arch: {0:X} impl: {1:X} rev: {2:X}!", ArchInfo->architecture, ArchInfo->implementation, ArchInfo->revision); - - // for 16xx cards - if (ArchInfo->architecture == NV_GPU_ARCHITECTURE_TU100 && ArchInfo->implementation > NV_GPU_ARCH_IMPLEMENTATION_TU106) - { - ArchInfo->implementation = NV_GPU_ARCH_IMPLEMENTATION_TU106; - ArchInfo->implementation_id = NV_GPU_ARCH_IMPLEMENTATION_TU106; - - LOG_INFO("Spoofed arch: {0:X} impl: {1:X} rev: {2:X}!", ArchInfo->architecture, ArchInfo->implementation, ArchInfo->revision); - } - //else if (ArchInfo->architecture < NV_GPU_ARCHITECTURE_TU100 && ArchInfo->architecture >= NV_GPU_ARCHITECTURE_GP100) - //{ - // LOG_INFO("Spoofing below 16xx arch: {0:X} impl: {1:X} rev: {2:X}!", ArchInfo->architecture, ArchInfo->implementation, ArchInfo->revision); - - // ArchInfo->architecture = NV_GPU_ARCHITECTURE_TU100; - // ArchInfo->architecture_id = NV_GPU_ARCHITECTURE_TU100; - // ArchInfo->implementation = NV_GPU_ARCH_IMPLEMENTATION_TU106; - // ArchInfo->implementation_id = NV_GPU_ARCH_IMPLEMENTATION_TU106; - - // LOG_INFO("Spoofed arch: {0:X} impl: {1:X} rev: {2:X}!", ArchInfo->architecture, ArchInfo->implementation, ArchInfo->revision); - //} - } - - return status; - } - - return 0xFFFFFFFF; -} - -inline static void* __stdcall HookedNvAPI_QueryInterface(NV_INTERFACE InterfaceId) -{ - const auto result = OriginalNvAPI_QueryInterface(InterfaceId); - - if (result) - { - if (InterfaceId == NV_INTERFACE::GPU_GetArchInfo) - { - OriginalNvAPI_GPU_GetArchInfo = static_cast(result); - return &HookedNvAPI_GPU_GetArchInfo; - } - } - - return result; -} - inline static NVSDK_NGX_Result __stdcall Hooked_Dx12_GetFeatureRequirements(IDXGIAdapter* Adapter, const NVSDK_NGX_FeatureDiscoveryInfo* FeatureDiscoveryInfo, NVSDK_NGX_FeatureRequirement* OutSupported) { LOG_FUNC(); @@ -144,29 +77,6 @@ inline static NVSDK_NGX_Result __stdcall Hooked_Vulkan_GetFeatureRequirements(co return result; } -inline static void HookNvApi() -{ - if (OriginalNvAPI_QueryInterface != nullptr) - return; - - LOG_DEBUG("Trying to hook NvApi"); - OriginalNvAPI_QueryInterface = (PFN_NvApi_QueryInterface)DetourFindFunction("nvapi64.dll", "nvapi_QueryInterface"); - LOG_DEBUG("OriginalNvAPI_QueryInterface = {0:X}", (unsigned long long)OriginalNvAPI_QueryInterface); - - if (OriginalNvAPI_QueryInterface != nullptr) - { - LOG_INFO("NvAPI_QueryInterface found, hooking!"); - - if (!Config::Instance()->DE_Available) - { - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - DetourAttach(&(PVOID&)OriginalNvAPI_QueryInterface, HookedNvAPI_QueryInterface); - DetourTransactionCommit(); - } - } -} - inline static void HookNgxApi(HMODULE nvngx) { if (Original_D3D11_GetFeatureRequirements != nullptr || Original_D3D12_GetFeatureRequirements != nullptr) @@ -200,42 +110,32 @@ inline static void HookNgxApi(HMODULE nvngx) inline static void UnhookApis() { - if (OriginalNvAPI_QueryInterface != nullptr || Original_D3D11_GetFeatureRequirements != nullptr || Original_D3D12_GetFeatureRequirements != nullptr) + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + if (Original_D3D11_GetFeatureRequirements != nullptr) { - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - - if (OriginalNvAPI_QueryInterface != nullptr) - { - DetourDetach(&(PVOID&)OriginalNvAPI_QueryInterface, HookedNvAPI_QueryInterface); - OriginalNvAPI_QueryInterface = nullptr; - } - - if (Original_D3D11_GetFeatureRequirements != nullptr) - { - DetourDetach(&(PVOID&)Original_D3D11_GetFeatureRequirements, Hooked_Dx11_GetFeatureRequirements); - Original_D3D11_GetFeatureRequirements = nullptr; - } - - if (Original_D3D12_GetFeatureRequirements != nullptr) - { - DetourDetach(&(PVOID&)Original_D3D12_GetFeatureRequirements, Hooked_Dx12_GetFeatureRequirements); - Original_D3D12_GetFeatureRequirements = nullptr; - } - - if (Original_Vulkan_GetFeatureRequirements != nullptr) - { - DetourDetach(&(PVOID&)Original_Vulkan_GetFeatureRequirements, Hooked_Vulkan_GetFeatureRequirements); - Original_Vulkan_GetFeatureRequirements = nullptr; - } - - DetourTransactionCommit(); + DetourDetach(&(PVOID&)Original_D3D11_GetFeatureRequirements, Hooked_Dx11_GetFeatureRequirements); + Original_D3D11_GetFeatureRequirements = nullptr; } + + if (Original_D3D12_GetFeatureRequirements != nullptr) + { + DetourDetach(&(PVOID&)Original_D3D12_GetFeatureRequirements, Hooked_Dx12_GetFeatureRequirements); + Original_D3D12_GetFeatureRequirements = nullptr; + } + + if (Original_Vulkan_GetFeatureRequirements != nullptr) + { + DetourDetach(&(PVOID&)Original_Vulkan_GetFeatureRequirements, Hooked_Vulkan_GetFeatureRequirements); + Original_Vulkan_GetFeatureRequirements = nullptr; + } + + DetourTransactionCommit(); } #pragma endregion - typedef NVSDK_NGX_Result(*PFN_CUDA_Init)(unsigned long long InApplicationId, const wchar_t* InApplicationDataPath, const NVSDK_NGX_FeatureCommonInfo* InFeatureInfo, NVSDK_NGX_Version InSDKVersion); typedef NVSDK_NGX_Result(*PFN_CUDA_Init_ProjectID)(const char* InProjectId, NVSDK_NGX_EngineType InEngineType, const char* InEngineVersion, const wchar_t* InApplicationDataPath, NVSDK_NGX_Version InSDKVersion, const NVSDK_NGX_FeatureCommonInfo* InFeatureInfo); typedef NVSDK_NGX_Result(*PFN_CUDA_Shutdown)(void); @@ -382,7 +282,7 @@ public: if (_dll != nullptr) return; - LOG_FUNC(); + spdlog::info(""); Config::Instance()->upscalerDisableHook = true; @@ -492,11 +392,22 @@ public: if (_dll != nullptr) { - HookNvApi(); - if (!Config::Instance()->DE_Available) HookNgxApi(_dll); + LOG_INFO("nvngx.dll loaded, setting DLSS as default upscaler and disabling spoofing options set to auto"); + + Config::Instance()->DLSSEnabled = true; + + if (!Config::Instance()->DxgiSpoofing.has_value()) + Config::Instance()->DxgiSpoofing = false; + + if (!Config::Instance()->VulkanSpoofing.has_value()) + Config::Instance()->VulkanSpoofing = false; + + if (!Config::Instance()->VulkanExtensionSpoofing.has_value()) + Config::Instance()->VulkanExtensionSpoofing = false; + LOG_INFO("getting nvngx method addresses"); _D3D11_Init = (PFN_D3D11_Init)GetProcAddress(_dll, "NVSDK_NGX_D3D11_Init"); @@ -552,6 +463,11 @@ public: _UpdateFeature = (PFN_UpdateFeature)GetProcAddress(_dll, "NVSDK_NGX_UpdateFeature"); } + else + { + LOG_INFO("Can't load nvngx.dll, disabling DLSS"); + Config::Instance()->DLSSEnabled = false; + } Config::Instance()->upscalerDisableHook = false; }