From af98536df5afb1140639ec5d5b6eff593f6ecafe Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Wed, 29 Jan 2025 15:35:16 +0000 Subject: [PATCH 1/8] feat: frame limiter --- src/Hooks.cpp | 2 +- src/Streamline.cpp | 45 +++++++++++++++++++++++++++++++++++++++++++-- src/Streamline.h | 15 ++++++++++++++- 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index ec3a3f692f..2ec223c1e4 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -268,7 +268,7 @@ HRESULT WINAPI hk_D3D11CreateDeviceAndSwapChain( [[maybe_unused]] const D3D_FEATURE_LEVEL* pFeatureLevels, [[maybe_unused]] UINT FeatureLevels, UINT SDKVersion, - const DXGI_SWAP_CHAIN_DESC* pSwapChainDesc, + DXGI_SWAP_CHAIN_DESC* pSwapChainDesc, IDXGISwapChain** ppSwapChain, ID3D11Device** ppDevice, D3D_FEATURE_LEVEL* pFeatureLevel, diff --git a/src/Streamline.cpp b/src/Streamline.cpp index edce5c68a7..5dadfb1e11 100644 --- a/src/Streamline.cpp +++ b/src/Streamline.cpp @@ -1,6 +1,7 @@ #include "Streamline.h" #include +#include #include "Hooks.h" #include "Util.h" @@ -149,7 +150,7 @@ HRESULT Streamline::CreateDeviceAndSwapChain(IDXGIAdapter* pAdapter, const D3D_FEATURE_LEVEL* pFeatureLevels, UINT FeatureLevels, UINT SDKVersion, - const DXGI_SWAP_CHAIN_DESC* pSwapChainDesc, + DXGI_SWAP_CHAIN_DESC* pSwapChainDesc, IDXGISwapChain** ppSwapChain, ID3D11Device** ppDevice, D3D_FEATURE_LEVEL* pFeatureLevel, @@ -206,6 +207,8 @@ HRESULT Streamline::CreateDeviceAndSwapChain(IDXGIAdapter* pAdapter, logger::info("[Streamline] DLSSG {} available", featureDLSSG && !REL::Module::IsVR() ? "is" : "is not"); logger::info("[Streamline] Reflex {} available", featureReflex ? "is" : "is not"); + pSwapChainDesc->Flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; + HRESULT hr = S_OK; if (featureDLSSG && !REL::Module::IsVR()) { @@ -244,6 +247,8 @@ HRESULT Streamline::CreateDeviceAndSwapChain(IDXGIAdapter* pAdapter, slSetD3DDevice(*ppDevice); } + (*((IDXGISwapChain2**)ppSwapChain))->SetMaximumFrameLatency(1); + PostDevice(); return hr; @@ -577,4 +582,40 @@ void Streamline::DestroyDLSSResources() dlssOptions.mode = sl::DLSSMode::eOff; slDLSSSetOptions(viewport, dlssOptions); slFreeResources(sl::kFeatureDLSS, viewport); -} \ No newline at end of file +} + +static void TimerSleepQPC(int64_t targetQPC) +{ + LARGE_INTEGER currentQPC; + do { + QueryPerformanceCounter(¤tQPC); + } while (currentQPC.QuadPart < targetQPC); +} + +void Streamline::BeginFrame() +{ + auto manager = RE::BSGraphics::Renderer::GetSingleton(); + auto swapchain = reinterpret_cast(manager->GetRuntimeData().renderWindows->swapChain); + + auto handle = swapchain->GetFrameLatencyWaitableObject(); + WaitForSingleObjectEx(handle, 1000, true); + CloseHandle(handle); + + LARGE_INTEGER qpf; + QueryPerformanceFrequency(&qpf); + int64_t targetFrameTicks; + + if (frameGenerationMode == sl::DLSSGMode::eOff) + targetFrameTicks = int64_t(double(qpf.QuadPart) / 165.0); + else + targetFrameTicks = int64_t(double(qpf.QuadPart) / (165.0 * 0.5)); + + static LARGE_INTEGER lastFrame = {}; + LARGE_INTEGER timeNow; + QueryPerformanceCounter(&timeNow); + int64_t delta = timeNow.QuadPart - lastFrame.QuadPart; + if (delta < targetFrameTicks) { + TimerSleepQPC(lastFrame.QuadPart + targetFrameTicks); + } + QueryPerformanceCounter(&lastFrame); +} diff --git a/src/Streamline.h b/src/Streamline.h index c8ef713609..a985dce875 100644 --- a/src/Streamline.h +++ b/src/Streamline.h @@ -90,7 +90,7 @@ class Streamline const D3D_FEATURE_LEVEL* pFeatureLevels, UINT FeatureLevels, UINT SDKVersion, - const DXGI_SWAP_CHAIN_DESC* pSwapChainDesc, + DXGI_SWAP_CHAIN_DESC* pSwapChainDesc, IDXGISwapChain** ppSwapChain, ID3D11Device** ppDevice, D3D_FEATURE_LEVEL* pFeatureLevel, @@ -105,6 +105,18 @@ class Streamline void UpdateConstants(); void DestroyDLSSResources(); + + void BeginFrame(); + + struct Main_Update_Start + { + static void thunk(INT64 a_unk) + { + GetSingleton()->BeginFrame(); + func(a_unk); + } + static inline REL::Relocation func; + }; struct Main_RenderWorld { @@ -132,6 +144,7 @@ class Streamline static void InstallHooks() { + stl::write_thunk_call(REL::RelocationID(35565, 36564).address() + REL::Relocate(0x1E, 0x3E, 0x33)); stl::write_thunk_call(REL::RelocationID(35560, 36559).address() + REL::Relocate(0x831, 0x841, 0x791)); stl::write_thunk_call(REL::RelocationID(79947, 82084).address() + REL::Relocate(0x7E, 0x83, 0x97)); } From 443b2c52c76e164ba0ec3c56a65c1219cce46643 Mon Sep 17 00:00:00 2001 From: doodlum Date: Wed, 29 Jan 2025 15:36:04 +0000 Subject: [PATCH 2/8] =?UTF-8?q?style:=20=F0=9F=8E=A8=20apply=20clang-forma?= =?UTF-8?q?t=20changes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Streamline.cpp | 2 +- src/Streamline.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Streamline.cpp b/src/Streamline.cpp index 5dadfb1e11..86cd6eeaa9 100644 --- a/src/Streamline.cpp +++ b/src/Streamline.cpp @@ -596,7 +596,7 @@ void Streamline::BeginFrame() { auto manager = RE::BSGraphics::Renderer::GetSingleton(); auto swapchain = reinterpret_cast(manager->GetRuntimeData().renderWindows->swapChain); - + auto handle = swapchain->GetFrameLatencyWaitableObject(); WaitForSingleObjectEx(handle, 1000, true); CloseHandle(handle); diff --git a/src/Streamline.h b/src/Streamline.h index a985dce875..33778318d5 100644 --- a/src/Streamline.h +++ b/src/Streamline.h @@ -105,7 +105,7 @@ class Streamline void UpdateConstants(); void DestroyDLSSResources(); - + void BeginFrame(); struct Main_Update_Start From 610419607c984c6350ff4ff73e3c569dccc7e22b Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Wed, 29 Jan 2025 17:42:41 +0000 Subject: [PATCH 3/8] chore: frame limit from refresh rate --- src/Hooks.cpp | 6 ++++++ src/Streamline.cpp | 43 +++++++++++++++++++++++++++++++++---------- src/Streamline.h | 16 +++++++++++++++- 3 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index 2ec223c1e4..6ab7bc568f 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -177,6 +177,12 @@ struct IDXGISwapChain_Present State::GetSingleton()->Reset(); Menu::GetSingleton()->DrawOverlay(); Streamline::GetSingleton()->Present(); + + if (Streamline::GetSingleton()->frameGenerationMode == sl::DLSSGMode::eOn) { + SyncInterval = 0; + Flags = DXGI_PRESENT_ALLOW_TEARING; + } + auto retval = func(This, SyncInterval, Flags); TracyD3D11Collect(State::GetSingleton()->tracyCtx); return retval; diff --git a/src/Streamline.cpp b/src/Streamline.cpp index 86cd6eeaa9..2fccae2eed 100644 --- a/src/Streamline.cpp +++ b/src/Streamline.cpp @@ -110,7 +110,7 @@ void Streamline::Initialize() } } -void Streamline::PostDevice() +void Streamline::PostDevice(IDXGISwapChain* a_swapChain) { // Hook up all of the feature functions using the sl function slGetFeatureFunction @@ -131,6 +131,23 @@ void Streamline::PostDevice() slGetFeatureFunction(sl::kFeatureReflex, "slReflexSleep", (void*&)slReflexSleep); slGetFeatureFunction(sl::kFeatureReflex, "slReflexSetOptions", (void*&)slReflexSetOptions); } + + DXGI_SWAP_CHAIN_DESC swapChainDesc; + a_swapChain->GetDesc(&swapChainDesc); + + DXGI_RATIONAL refreshRateRational = swapChainDesc.BufferDesc.RefreshRate; + + MONITORINFOEX monitorInfo = {}; + monitorInfo.cbSize = sizeof(MONITORINFOEX); + + HMONITOR monitor = MonitorFromWindow(swapChainDesc.OutputWindow, MONITOR_DEFAULTTONEAREST); + GetMonitorInfo(monitor, &monitorInfo); + + DEVMODE devMode = {}; + devMode.dmSize = sizeof(DEVMODE); + + EnumDisplaySettings(monitorInfo.szDevice, ENUM_CURRENT_SETTINGS, &devMode); + refreshRate = devMode.dmDisplayFrequency; } HRESULT Streamline::CreateDXGIFactory(REFIID riid, void** ppFactory) @@ -208,6 +225,7 @@ HRESULT Streamline::CreateDeviceAndSwapChain(IDXGIAdapter* pAdapter, logger::info("[Streamline] Reflex {} available", featureReflex ? "is" : "is not"); pSwapChainDesc->Flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; + pSwapChainDesc->Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; HRESULT hr = S_OK; @@ -247,9 +265,7 @@ HRESULT Streamline::CreateDeviceAndSwapChain(IDXGIAdapter* pAdapter, slSetD3DDevice(*ppDevice); } - (*((IDXGISwapChain2**)ppSwapChain))->SetMaximumFrameLatency(1); - - PostDevice(); + PostDevice(*ppSwapChain); return hr; } @@ -597,18 +613,25 @@ void Streamline::BeginFrame() auto manager = RE::BSGraphics::Renderer::GetSingleton(); auto swapchain = reinterpret_cast(manager->GetRuntimeData().renderWindows->swapChain); - auto handle = swapchain->GetFrameLatencyWaitableObject(); - WaitForSingleObjectEx(handle, 1000, true); - CloseHandle(handle); + if (frameGenerationMode == sl::DLSSGMode::eOn) { + auto handle = swapchain->GetFrameLatencyWaitableObject(); + WaitForSingleObjectEx(handle, 1000, true); + CloseHandle(handle); + swapchain->SetMaximumFrameLatency(1); + } else { + swapchain->SetMaximumFrameLatency(0); + } LARGE_INTEGER qpf; QueryPerformanceFrequency(&qpf); int64_t targetFrameTicks; - if (frameGenerationMode == sl::DLSSGMode::eOff) - targetFrameTicks = int64_t(double(qpf.QuadPart) / 165.0); + double bestRefreshRate = refreshRate - (refreshRate * refreshRate) / 3600.0; + + if (frameGenerationMode == sl::DLSSGMode::eOn) + targetFrameTicks = int64_t(double(qpf.QuadPart) / (bestRefreshRate * 0.5)); else - targetFrameTicks = int64_t(double(qpf.QuadPart) / (165.0 * 0.5)); + targetFrameTicks = int64_t(double(qpf.QuadPart) / bestRefreshRate); static LARGE_INTEGER lastFrame = {}; LARGE_INTEGER timeNow; diff --git a/src/Streamline.h b/src/Streamline.h index 33778318d5..60aad14710 100644 --- a/src/Streamline.h +++ b/src/Streamline.h @@ -29,6 +29,8 @@ class Streamline bool featureDLSSG = false; bool featureReflex = false; + double refreshRate = 60.0; + sl::ViewportHandle viewport{ 0 }; sl::FrameToken* frameToken; @@ -79,7 +81,7 @@ class Streamline void LoadInterposer(); void Initialize(); - void PostDevice(); + void PostDevice(IDXGISwapChain* a_swapChain); HRESULT CreateDXGIFactory(REFIID riid, void** ppFactory); @@ -118,6 +120,16 @@ class Streamline static inline REL::Relocation func; }; + struct Job_PollControls + { + static void thunk() + { + GetSingleton()->BeginFrame(); + return func(); + } + static inline REL::Relocation func; + }; + struct Main_RenderWorld { static void thunk(bool a1) @@ -145,6 +157,8 @@ class Streamline static void InstallHooks() { stl::write_thunk_call(REL::RelocationID(35565, 36564).address() + REL::Relocate(0x1E, 0x3E, 0x33)); + //stl::write_thunk_call(REL::RelocationID(35575, 36564).address() + REL::Relocate(0xB, 0x3E, 0x33)); + stl::write_thunk_call(REL::RelocationID(35560, 36559).address() + REL::Relocate(0x831, 0x841, 0x791)); stl::write_thunk_call(REL::RelocationID(79947, 82084).address() + REL::Relocate(0x7E, 0x83, 0x97)); } From 9f14729de2296fa2107f177c7398203c5d59e4f0 Mon Sep 17 00:00:00 2001 From: doodlum Date: Wed, 29 Jan 2025 17:43:31 +0000 Subject: [PATCH 4/8] =?UTF-8?q?style:=20=F0=9F=8E=A8=20apply=20clang-forma?= =?UTF-8?q?t=20changes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Streamline.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Streamline.cpp b/src/Streamline.cpp index 2fccae2eed..0cab632e96 100644 --- a/src/Streamline.cpp +++ b/src/Streamline.cpp @@ -147,7 +147,7 @@ void Streamline::PostDevice(IDXGISwapChain* a_swapChain) devMode.dmSize = sizeof(DEVMODE); EnumDisplaySettings(monitorInfo.szDevice, ENUM_CURRENT_SETTINGS, &devMode); - refreshRate = devMode.dmDisplayFrequency; + refreshRate = devMode.dmDisplayFrequency; } HRESULT Streamline::CreateDXGIFactory(REFIID riid, void** ppFactory) From 40ad9b0bcc57a0aa4c9a7d44bf6e0fd86f17dd9e Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Wed, 29 Jan 2025 22:47:08 +0000 Subject: [PATCH 5/8] feat: dlssg settings --- src/Hooks.cpp | 6 ++- src/State.cpp | 18 +++++++++ src/Streamline.cpp | 99 +++++++++++++++++++++++----------------------- src/Streamline.h | 15 ++++++- 4 files changed, 85 insertions(+), 53 deletions(-) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index 6ab7bc568f..a384324f45 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -176,9 +176,11 @@ struct IDXGISwapChain_Present { State::GetSingleton()->Reset(); Menu::GetSingleton()->DrawOverlay(); - Streamline::GetSingleton()->Present(); - if (Streamline::GetSingleton()->frameGenerationMode == sl::DLSSGMode::eOn) { + auto streamline = Streamline::GetSingleton(); + streamline->Present(); + + if (streamline->settings.frameGenerationMode == sl::DLSSGMode::eOn) { SyncInterval = 0; Flags = DXGI_PRESENT_ALLOW_TEARING; } diff --git a/src/State.cpp b/src/State.cpp index 85431e88ed..882d9ae3f0 100644 --- a/src/State.cpp +++ b/src/State.cpp @@ -284,6 +284,20 @@ void State::Load(ConfigMode a_configMode, bool a_allowReload) logger::warn("Missing settings for Upscaling, using default."); } + auto streamline = Streamline::GetSingleton(); + auto& streamlineJson = settings[streamline->GetShortName()]; + if (streamlineJson.is_object()) { + logger::info("Loading Streamline settings"); + try { + streamline->LoadSettings(upscalingJson); + } catch (...) { + logger::warn("Invalid settings for Streamline, using default."); + streamline->RestoreDefaultSettings(); + } + } else { + logger::warn("Missing settings for Streamline, using default."); + } + for (auto* feature : Feature::GetFeatureList()) { try { const std::string featureName = feature->GetShortName(); @@ -364,6 +378,10 @@ void State::Save(ConfigMode a_configMode) auto& upscalingJson = settings[upscaling->GetShortName()]; upscaling->SaveSettings(upscalingJson); + auto streamline = Streamline::GetSingleton(); + auto& streamlineJson = settings[streamline->GetShortName()]; + streamline->SaveSettings(streamlineJson); + json originalShaders; for (int classIndex = 0; classIndex < RE::BSShader::Type::Total - 1; ++classIndex) { originalShaders[magic_enum::enum_name((RE::BSShader::Type)(classIndex + 1))] = enabledClasses[classIndex]; diff --git a/src/Streamline.cpp b/src/Streamline.cpp index 0cab632e96..19fcd9d5c0 100644 --- a/src/Streamline.cpp +++ b/src/Streamline.cpp @@ -8,6 +8,12 @@ #include "Upscaling.h" +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT( + Streamline::Settings, + frameLimitMode, + frameGenerationMode +); + void LoggingCallback(sl::LogType type, const char* msg) { switch (type) { @@ -31,11 +37,12 @@ void Streamline::DrawSettings() ImGui::Text("Frame Generation can only be enabled or disabled in the mod manager, it can only be temporarily toggled in-game"); if (ImGui::TreeNodeEx("NVIDIA DLSS Frame Generation", ImGuiTreeNodeFlags_DefaultOpen)) { - ImGui::Text("Requires an NVIDIA GeForce RTX 40 Series or newer"); + ImGui::Text("Requires an NVIDIA GeForce RTX 40/50 Series or newer"); if (featureDLSSG) { const char* frameGenerationModes[] = { "Off", "On" }; - ImGui::SliderInt("Frame Generation", (int*)&frameGenerationMode, 0, 1, std::format("{}", frameGenerationModes[(uint)frameGenerationMode]).c_str()); - frameGenerationMode = (sl::DLSSGMode)std::min(2u, (uint)frameGenerationMode); + ImGui::SliderInt("Frame Limit (Refresh Rate)", (int*)&settings.frameLimitMode, 0, 1, std::format("{}", frameGenerationModes[(uint)settings.frameLimitMode]).c_str()); + ImGui::SliderInt("Frame Generation", (int*)&settings.frameGenerationMode, 0, 1, std::format("{}", frameGenerationModes[(uint)settings.frameGenerationMode]).c_str()); + settings.frameGenerationMode = (sl::DLSSGMode)std::min(2u, (uint)settings.frameGenerationMode); } else { } ImGui::TreePop(); @@ -110,7 +117,7 @@ void Streamline::Initialize() } } -void Streamline::PostDevice(IDXGISwapChain* a_swapChain) +void Streamline::PostDevice(DXGI_SWAP_CHAIN_DESC* a_swapChainDesc) { // Hook up all of the feature functions using the sl function slGetFeatureFunction @@ -132,15 +139,10 @@ void Streamline::PostDevice(IDXGISwapChain* a_swapChain) slGetFeatureFunction(sl::kFeatureReflex, "slReflexSetOptions", (void*&)slReflexSetOptions); } - DXGI_SWAP_CHAIN_DESC swapChainDesc; - a_swapChain->GetDesc(&swapChainDesc); - - DXGI_RATIONAL refreshRateRational = swapChainDesc.BufferDesc.RefreshRate; - MONITORINFOEX monitorInfo = {}; monitorInfo.cbSize = sizeof(MONITORINFOEX); - HMONITOR monitor = MonitorFromWindow(swapChainDesc.OutputWindow, MONITOR_DEFAULTTONEAREST); + HMONITOR monitor = MonitorFromWindow(a_swapChainDesc->OutputWindow, MONITOR_DEFAULTTONEAREST); GetMonitorInfo(monitor, &monitorInfo); DEVMODE devMode = {}; @@ -224,13 +226,12 @@ HRESULT Streamline::CreateDeviceAndSwapChain(IDXGIAdapter* pAdapter, logger::info("[Streamline] DLSSG {} available", featureDLSSG && !REL::Module::IsVR() ? "is" : "is not"); logger::info("[Streamline] Reflex {} available", featureReflex ? "is" : "is not"); - pSwapChainDesc->Flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; - pSwapChainDesc->Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; - HRESULT hr = S_OK; if (featureDLSSG && !REL::Module::IsVR()) { logger::info("[Streamline] Proxying D3D11CreateDeviceAndSwapChain to add D3D12 swapchain"); + + pSwapChainDesc->Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; auto slD3D11CreateDeviceAndSwapChain = reinterpret_cast(GetProcAddress(interposer, "D3D11CreateDeviceAndSwapChain")); @@ -265,7 +266,7 @@ HRESULT Streamline::CreateDeviceAndSwapChain(IDXGIAdapter* pAdapter, slSetD3DDevice(*ppDevice); } - PostDevice(*ppSwapChain); + PostDevice(pSwapChainDesc); return hr; } @@ -342,7 +343,7 @@ void Streamline::SetupResources() void Streamline::CopyResourcesToSharedBuffers() { - if (!(featureDLSSG && !REL::Module::IsVR()) || frameGenerationMode == sl::DLSSGMode::eOff) + if (!(featureDLSSG && !REL::Module::IsVR()) || settings.frameGenerationMode == sl::DLSSGMode::eOff) return; auto& context = State::GetSingleton()->context; @@ -405,13 +406,13 @@ void Streamline::Present() UpdateConstants(); - static auto currentFrameGenerationMode = frameGenerationMode; + static auto currentFrameGenerationMode = settings.frameGenerationMode; - if (currentFrameGenerationMode != frameGenerationMode) { - currentFrameGenerationMode = frameGenerationMode; + if (currentFrameGenerationMode != settings.frameGenerationMode) { + currentFrameGenerationMode = settings.frameGenerationMode; sl::DLSSGOptions options{}; - options.mode = frameGenerationMode; + options.mode = settings.frameGenerationMode; options.flags = sl::DLSSGFlags::eRetainResourcesWhenOff; if (SL_FAILED(result, slDLSSGSetOptions(viewport, options))) { @@ -592,6 +593,21 @@ void Streamline::UpdateConstants() } } +void Streamline::SaveSettings(json& o_json) +{ + o_json = settings; +} + +void Streamline::LoadSettings(json& o_json) +{ + settings = o_json; +} + +void Streamline::RestoreDefaultSettings() +{ + settings = {}; +} + void Streamline::DestroyDLSSResources() { sl::DLSSOptions dlssOptions{}; @@ -610,35 +626,20 @@ static void TimerSleepQPC(int64_t targetQPC) void Streamline::BeginFrame() { - auto manager = RE::BSGraphics::Renderer::GetSingleton(); - auto swapchain = reinterpret_cast(manager->GetRuntimeData().renderWindows->swapChain); - - if (frameGenerationMode == sl::DLSSGMode::eOn) { - auto handle = swapchain->GetFrameLatencyWaitableObject(); - WaitForSingleObjectEx(handle, 1000, true); - CloseHandle(handle); - swapchain->SetMaximumFrameLatency(1); - } else { - swapchain->SetMaximumFrameLatency(0); - } - - LARGE_INTEGER qpf; - QueryPerformanceFrequency(&qpf); - int64_t targetFrameTicks; - - double bestRefreshRate = refreshRate - (refreshRate * refreshRate) / 3600.0; - - if (frameGenerationMode == sl::DLSSGMode::eOn) - targetFrameTicks = int64_t(double(qpf.QuadPart) / (bestRefreshRate * 0.5)); - else - targetFrameTicks = int64_t(double(qpf.QuadPart) / bestRefreshRate); - - static LARGE_INTEGER lastFrame = {}; - LARGE_INTEGER timeNow; - QueryPerformanceCounter(&timeNow); - int64_t delta = timeNow.QuadPart - lastFrame.QuadPart; - if (delta < targetFrameTicks) { - TimerSleepQPC(lastFrame.QuadPart + targetFrameTicks); + if (featureDLSSG && settings.frameGenerationMode == sl::DLSSGMode::eOn && settings.frameLimitMode) { + LARGE_INTEGER qpf; + QueryPerformanceFrequency(&qpf); + + double bestRefreshRate = refreshRate - (refreshRate * refreshRate) / 3600.0; + int64_t targetFrameTicks = int64_t(double(qpf.QuadPart) / (bestRefreshRate * 0.5)); + + static LARGE_INTEGER lastFrame = {}; + LARGE_INTEGER timeNow; + QueryPerformanceCounter(&timeNow); + int64_t delta = timeNow.QuadPart - lastFrame.QuadPart; + if (delta < targetFrameTicks) { + TimerSleepQPC(lastFrame.QuadPart + targetFrameTicks); + } + QueryPerformanceCounter(&lastFrame); } - QueryPerformanceCounter(&lastFrame); } diff --git a/src/Streamline.h b/src/Streamline.h index 60aad14710..fe0d799033 100644 --- a/src/Streamline.h +++ b/src/Streamline.h @@ -34,7 +34,13 @@ class Streamline sl::ViewportHandle viewport{ 0 }; sl::FrameToken* frameToken; - sl::DLSSGMode frameGenerationMode = sl::DLSSGMode::eOn; + struct Settings + { + sl::DLSSGMode frameGenerationMode = sl::DLSSGMode::eOn; + int frameLimitMode = 0; + }; + + Settings settings{}; HMODULE interposer = NULL; @@ -81,7 +87,7 @@ class Streamline void LoadInterposer(); void Initialize(); - void PostDevice(IDXGISwapChain* a_swapChain); + void PostDevice(DXGI_SWAP_CHAIN_DESC* a_swapChainDesc); HRESULT CreateDXGIFactory(REFIID riid, void** ppFactory); @@ -106,6 +112,11 @@ class Streamline void Upscale(Texture2D* a_color, Texture2D* a_alphaMask, sl::DLSSPreset a_preset); void UpdateConstants(); + void SaveSettings(json& o_json); + void LoadSettings(json& o_json); + + void RestoreDefaultSettings(); + void DestroyDLSSResources(); void BeginFrame(); From 02eca668c1159e6bc5666f2b31067a801cefa8ea Mon Sep 17 00:00:00 2001 From: doodlum Date: Wed, 29 Jan 2025 22:47:42 +0000 Subject: [PATCH 6/8] =?UTF-8?q?style:=20=F0=9F=8E=A8=20apply=20clang-forma?= =?UTF-8?q?t=20changes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Streamline.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Streamline.cpp b/src/Streamline.cpp index 19fcd9d5c0..e6acebd88a 100644 --- a/src/Streamline.cpp +++ b/src/Streamline.cpp @@ -11,8 +11,7 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT( Streamline::Settings, frameLimitMode, - frameGenerationMode -); + frameGenerationMode); void LoggingCallback(sl::LogType type, const char* msg) { @@ -230,7 +229,7 @@ HRESULT Streamline::CreateDeviceAndSwapChain(IDXGIAdapter* pAdapter, if (featureDLSSG && !REL::Module::IsVR()) { logger::info("[Streamline] Proxying D3D11CreateDeviceAndSwapChain to add D3D12 swapchain"); - + pSwapChainDesc->Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; auto slD3D11CreateDeviceAndSwapChain = reinterpret_cast(GetProcAddress(interposer, "D3D11CreateDeviceAndSwapChain")); @@ -600,7 +599,7 @@ void Streamline::SaveSettings(json& o_json) void Streamline::LoadSettings(json& o_json) { - settings = o_json; + settings = o_json; } void Streamline::RestoreDefaultSettings() From 3596590631d90aedffd8fad6e869fb4dc29a0df9 Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Wed, 29 Jan 2025 22:52:37 +0000 Subject: [PATCH 7/8] fix: loading settings --- src/State.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/State.cpp b/src/State.cpp index 882d9ae3f0..c79ff3af95 100644 --- a/src/State.cpp +++ b/src/State.cpp @@ -289,7 +289,7 @@ void State::Load(ConfigMode a_configMode, bool a_allowReload) if (streamlineJson.is_object()) { logger::info("Loading Streamline settings"); try { - streamline->LoadSettings(upscalingJson); + streamline->LoadSettings(streamlineJson); } catch (...) { logger::warn("Invalid settings for Streamline, using default."); streamline->RestoreDefaultSettings(); From ac8ffaaccb830df41bae429290cb77019a045690 Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Wed, 29 Jan 2025 23:00:23 +0000 Subject: [PATCH 8/8] chore: remove unused hook --- src/Streamline.h | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/Streamline.h b/src/Streamline.h index fe0d799033..481b42acf2 100644 --- a/src/Streamline.h +++ b/src/Streamline.h @@ -131,16 +131,6 @@ class Streamline static inline REL::Relocation func; }; - struct Job_PollControls - { - static void thunk() - { - GetSingleton()->BeginFrame(); - return func(); - } - static inline REL::Relocation func; - }; - struct Main_RenderWorld { static void thunk(bool a1) @@ -168,8 +158,6 @@ class Streamline static void InstallHooks() { stl::write_thunk_call(REL::RelocationID(35565, 36564).address() + REL::Relocate(0x1E, 0x3E, 0x33)); - //stl::write_thunk_call(REL::RelocationID(35575, 36564).address() + REL::Relocate(0xB, 0x3E, 0x33)); - stl::write_thunk_call(REL::RelocationID(35560, 36559).address() + REL::Relocate(0x831, 0x841, 0x791)); stl::write_thunk_call(REL::RelocationID(79947, 82084).address() + REL::Relocate(0x7E, 0x83, 0x97)); }