diff --git a/OptiScaler/Config.cpp b/OptiScaler/Config.cpp
index eb7962b1..fd58272d 100644
--- a/OptiScaler/Config.cpp
+++ b/OptiScaler/Config.cpp
@@ -97,6 +97,8 @@ bool Config::Reload(std::filesystem::path iniPath)
FGOutput.set_from_config(FGOutput::FSRFG);
else if (lstrcmpiA(FGOutputString.value().c_str(), "nukems") == 0)
FGOutput.set_from_config(FGOutput::Nukems);
+ else if (lstrcmpiA(FGOutputString.value().c_str(), "dlssgwithnukems") == 0)
+ FGOutput.set_from_config(FGOutput::DLSSGWithNukems);
else if (lstrcmpiA(FGOutputString.value().c_str(), "xefg") == 0)
FGOutput.set_from_config(FGOutput::XeFG);
else if (lstrcmpiA(FGOutputString.value().c_str(), "dlssg") == 0)
@@ -632,6 +634,7 @@ bool Config::Reload(std::filesystem::path iniPath)
if (!SpoofHAGS.has_value())
{
SpoofHAGS.set_volatile_value(FGInput.value_or_default() == FGInput::Nukems ||
+ FGOutput.value_or_default() == FGOutput::DLSSGWithNukems ||
FGInput.value_or_default() == FGInput::DLSSG);
}
}
@@ -826,6 +829,8 @@ bool Config::SaveIni()
FGOutputString = "FSRFG";
else if (FGOutputHeld.value() == FGOutput::Nukems)
FGOutputString = "Nukems";
+ else if (FGOutputHeld.value() == FGOutput::DLSSGWithNukems)
+ FGOutputString = "DLSSGWithNukems";
else if (FGOutputHeld.value() == FGOutput::XeFG)
FGOutputString = "XeFG";
else if (FGOutputHeld.value() == FGOutput::DLSSG)
diff --git a/OptiScaler/NVNGX_Parameter.h b/OptiScaler/NVNGX_Parameter.h
index 5155db0e..4312a999 100644
--- a/OptiScaler/NVNGX_Parameter.h
+++ b/OptiScaler/NVNGX_Parameter.h
@@ -522,7 +522,8 @@ inline static void InitNGXParameters(NVSDK_NGX_Parameter* InParams)
}
// not ideal as it doesn't take different APIs into account
- if (State::Instance().activeFgInput == FGInput::Nukems || State::Instance().activeFgInput == FGInput::DLSSG)
+ if (State::Instance().activeFgInput == FGInput::Nukems || State::Instance().activeFgInput == FGInput::DLSSG ||
+ State::Instance().activeFgOutput == FGOutput::DLSSGWithNukems)
{
InParams->Set("FrameGeneration.Available", 1);
InParams->Set("FrameGeneration.NeedsUpdatedDriver", 0);
@@ -531,10 +532,8 @@ inline static void InitNGXParameters(NVSDK_NGX_Parameter* InParams)
InParams->Set(NVSDK_NGX_Parameter_FrameInterpolation_NeedsUpdatedDriver, 0);
InParams->Set(NVSDK_NGX_Parameter_FrameInterpolation_FeatureInitResult, 1);
- feature_version moreCopeVersion { 2, 11, 0 };
- auto maxCopeCount = State::Instance().streamlineVersion >= moreCopeVersion ? 5 : 3;
-
- InParams->Set("DLSSG.MultiFrameCountMax", State::Instance().NukemsMFG ? maxCopeCount : 1);
+ // Streamline handle the max interpolated frame count
+ InParams->Set("DLSSG.MultiFrameCountMax", State::Instance().NukemsMFG ? 5 : 1);
if (State::Instance().NVNGX_Engine == NVSDK_NGX_ENGINE_TYPE_UNREAL ||
State::Instance().gameQuirks & GameQuirk::ForceUnrealEngine)
diff --git a/OptiScaler/State.h b/OptiScaler/State.h
index 1e5efd69..cb27df39 100644
--- a/OptiScaler/State.h
+++ b/OptiScaler/State.h
@@ -43,7 +43,8 @@ enum class FGOutput : uint32_t
Nukems,
FSRFG,
DLSSG,
- XeFG
+ XeFG,
+ DLSSGWithNukems,
};
enum class WorkingMode : uint32_t
@@ -307,26 +308,32 @@ class State
/// Lower case dll name without `.dll` at the end. Leave blank for skipping all dll's
static void DisableChecks(UINT owner, std::string dllName = "")
{
- if (_skipOwner == 0)
- {
- _skipOwner = owner;
- _skipChecks = true;
- _skipDllName = dllName;
- }
- else
- {
- _skipDllName = ""; // Hack for multiple skip calls
- }
+ // if (_skipOwner == 0 || _skipOwner < owner)
+ //{
+ _skipOwner = owner;
+ _skipChecks = true;
+ _skipDllName[_skipOwner] = dllName;
+ //}
};
static void EnableChecks(UINT owner)
{
- if (_skipOwner == 0 || _skipOwner == owner)
+ _skipDllName.erase(_skipOwner);
+
+ // if (_skipOwner == owner)
+ //{
+ if (_skipDllName.size() > 0)
+ {
+ // loop in reverse to get the last added owner
+ _skipOwner = _skipDllName.rbegin()->first;
+ }
+ else
{
- _skipChecks = false;
- _skipDllName = "";
_skipOwner = 0;
}
+
+ _skipChecks = (_skipOwner != 0);
+ //}
};
static void DisableServeOriginal(UINT owner)
@@ -348,12 +355,15 @@ class State
};
static bool SkipDllChecks() { return _skipChecks; }
- static std::string SkipDllName() { return _skipDllName; }
+ static std::string SkipDllName()
+ {
+ return _skipOwner == 0 ? "" : (_skipDllName.contains(_skipOwner) ? _skipDllName[_skipOwner] : "");
+ }
static bool ServeOriginal() { return _serveOriginal; }
private:
inline static bool _skipChecks = false;
- inline static std::string _skipDllName = "";
+ inline static std::map _skipDllName;
inline static UINT _skipOwner = 0;
inline static UINT _lastOwner = 0;
diff --git a/OptiScaler/Util.cpp b/OptiScaler/Util.cpp
index 48b7a133..f687c1bc 100644
--- a/OptiScaler/Util.cpp
+++ b/OptiScaler/Util.cpp
@@ -381,7 +381,9 @@ std::optional Util::FindFilePath(const std::filesystem::p
{
auto normalizedPath = entry.path().lexically_normal().wstring();
to_lower_in_place(normalizedPath);
- if (State::Instance().activeFgOutput == FGOutput::DLSSG || !normalizedPath.contains(L"\\opti_dlls"))
+ if (State::Instance().activeFgOutput == FGOutput::DLSSG ||
+ State::Instance().activeFgOutput == FGOutput::DLSSGWithNukems ||
+ !normalizedPath.contains(L"\\opti_dlls"))
{
LOG_INFO(L"{} found at {}", fileName.wstring(), entry.path().parent_path().wstring());
return entry.path();
@@ -410,7 +412,9 @@ std::optional Util::FindFilePath(const std::filesystem::p
{
auto normalizedPath = entry.path().lexically_normal().wstring();
to_lower_in_place(normalizedPath);
- if (State::Instance().activeFgOutput == FGOutput::DLSSG || !normalizedPath.contains(L"\\opti_dlls"))
+ if (State::Instance().activeFgOutput == FGOutput::DLSSG ||
+ State::Instance().activeFgOutput == FGOutput::DLSSGWithNukems ||
+ !normalizedPath.contains(L"\\opti_dlls"))
{
LOG_INFO(L"{} found at {}", fileName.wstring(), entry.path().parent_path().wstring());
return entry.path();
diff --git a/OptiScaler/framegen/dlssg/DLSSG_Dx12.h b/OptiScaler/framegen/dlssg/DLSSG_Dx12.h
index d182bf29..b3da273c 100644
--- a/OptiScaler/framegen/dlssg/DLSSG_Dx12.h
+++ b/OptiScaler/framegen/dlssg/DLSSG_Dx12.h
@@ -59,6 +59,12 @@ class DLSSG_Dx12 : public virtual IFGFeature_Dx12
{
if (StreamlineProxy::Module() == nullptr)
StreamlineProxy::LoadStreamline();
+
+ if (StreamlineProxy::Module() != nullptr && !StreamlineProxy::IsD3D12Inited() &&
+ State::Instance().currentD3D12Device != nullptr)
+ {
+ StreamlineProxy::InitWithD3D12(State::Instance().currentD3D12Device);
+ }
}
~DLSSG_Dx12();
diff --git a/OptiScaler/hooks/D3D12_Hooks.cpp b/OptiScaler/hooks/D3D12_Hooks.cpp
index df5ba647..b9410173 100644
--- a/OptiScaler/hooks/D3D12_Hooks.cpp
+++ b/OptiScaler/hooks/D3D12_Hooks.cpp
@@ -1112,8 +1112,12 @@ static void HookToDevice(ID3D12Device* InDevice)
if (State::Instance().activeFgInput == FGInput::Upscaler && !Config::Instance()->FGDisableHUDFix.value_or_default())
ResTrack_Dx12::HookDevice(InDevice);
- if (State::Instance().activeFgOutput == FGOutput::DLSSG && StreamlineProxy::LoadStreamline())
+ if ((State::Instance().activeFgOutput == FGOutput::DLSSG ||
+ State::Instance().activeFgOutput == FGOutput::DLSSGWithNukems) &&
+ StreamlineProxy::LoadStreamline())
+ {
StreamlineProxy::InitWithD3D12(InDevice);
+ }
}
static void UnhookDevice()
diff --git a/OptiScaler/hooks/Dxgi_Hooks.cpp b/OptiScaler/hooks/Dxgi_Hooks.cpp
index 565dc4df..c3eb70f2 100644
--- a/OptiScaler/hooks/Dxgi_Hooks.cpp
+++ b/OptiScaler/hooks/Dxgi_Hooks.cpp
@@ -127,7 +127,8 @@ inline static HRESULT hkCreateDXGIFactory(REFIID riid, IDXGIFactory** ppFactory)
{
IDXGIFactory* real = nullptr;
- if (State::Instance().activeFgOutput != FGOutput::DLSSG &&
+ if ((State::Instance().activeFgOutput != FGOutput::DLSSG ||
+ State::Instance().activeFgOutput == FGOutput::DLSSGWithNukems) &&
Util::CheckForRealObject(__FUNCTION__, *ppFactory, (IUnknown**) &real))
{
*ppFactory = real;
@@ -185,7 +186,8 @@ inline static HRESULT hkCreateDXGIFactory1(REFIID riid, IDXGIFactory1** ppFactor
{
IDXGIFactory1* real = nullptr;
- if (State::Instance().activeFgOutput != FGOutput::DLSSG &&
+ if ((State::Instance().activeFgOutput != FGOutput::DLSSG ||
+ State::Instance().activeFgOutput == FGOutput::DLSSGWithNukems) &&
Util::CheckForRealObject(__FUNCTION__, *ppFactory, (IUnknown**) &real))
{
*ppFactory = real;
@@ -245,7 +247,8 @@ inline static HRESULT hkCreateDXGIFactory2(UINT Flags, REFIID riid, IDXGIFactory
{
IDXGIFactory2* real = nullptr;
- if (State::Instance().activeFgOutput != FGOutput::DLSSG &&
+ if ((State::Instance().activeFgOutput != FGOutput::DLSSG ||
+ State::Instance().activeFgOutput == FGOutput::DLSSGWithNukems) &&
Util::CheckForRealObject(__FUNCTION__, *ppFactory, (IUnknown**) &real))
{
*ppFactory = real;
diff --git a/OptiScaler/hooks/FG_Hooks.cpp b/OptiScaler/hooks/FG_Hooks.cpp
index 1e930d3a..e5084b78 100644
--- a/OptiScaler/hooks/FG_Hooks.cpp
+++ b/OptiScaler/hooks/FG_Hooks.cpp
@@ -58,7 +58,9 @@ static bool CheckForFGStatus()
Config::Instance()->FGOutput.set_volatile_value(FGOutput::NoFG);
State::Instance().activeFgOutput = Config::Instance()->FGOutput.value_or_default();
}
- else if (State::Instance().activeFgOutput == FGOutput::DLSSG && !StreamlineProxy::LoadStreamline())
+ else if ((State::Instance().activeFgOutput == FGOutput::DLSSG ||
+ State::Instance().activeFgOutput == FGOutput::DLSSGWithNukems) &&
+ !StreamlineProxy::LoadStreamline())
{
LOG_DEBUG("Can't init StreamlineProxy, disabling FGOutput");
Config::Instance()->FGOutput.set_volatile_value(FGOutput::NoFG);
@@ -66,7 +68,8 @@ static bool CheckForFGStatus()
}
if (State::Instance().activeFgOutput != FGOutput::FSRFG && State::Instance().activeFgOutput != FGOutput::XeFG &&
- State::Instance().activeFgOutput != FGOutput::DLSSG)
+ State::Instance().activeFgOutput != FGOutput::DLSSG &&
+ State::Instance().activeFgOutput != FGOutput::DLSSGWithNukems)
{
LOG_WARN("FGOutput is not set to FSR-FG or XeFG");
return false;
@@ -105,7 +108,8 @@ HRESULT FGHooks::CreateSwapChain(IDXGIFactory* pFactory, IUnknown* pDevice, DXGI
{
State::Instance().currentFG = new XeFG_Dx12();
}
- else if (State::Instance().activeFgOutput == FGOutput::DLSSG)
+ else if (State::Instance().activeFgOutput == FGOutput::DLSSG ||
+ State::Instance().activeFgOutput == FGOutput::DLSSGWithNukems)
{
State::Instance().currentFG = new DLSSG_Dx12();
}
@@ -232,7 +236,8 @@ HRESULT FGHooks::CreateSwapChainForHwnd(IDXGIFactory* pFactory, IUnknown* pDevic
{
State::Instance().currentFG = new XeFG_Dx12();
}
- else if (State::Instance().activeFgOutput == FGOutput::DLSSG)
+ else if (State::Instance().activeFgOutput == FGOutput::DLSSG ||
+ State::Instance().activeFgOutput == FGOutput::DLSSGWithNukems)
{
State::Instance().currentFG = new DLSSG_Dx12();
}
@@ -1063,17 +1068,21 @@ HRESULT FGHooks::FGPresent(IDXGISwapChain* This, UINT SyncInterval, UINT Flags,
sl::FrameToken* localToken = nullptr;
sl::Result tokenResult = sl::Result::eErrorReflexAPI;
- if (willPresent && State::Instance().activeFgOutput == FGOutput::DLSSG && fg->IsActive() && !fg->IsPaused())
+ if (willPresent && (State::Instance().activeFgOutput == FGOutput::DLSSG ||
+ State::Instance().activeFgOutput == FGOutput::DLSSGWithNukems))
{
((IDXGISwapChain4*) This)->GetCurrentBackBufferIndex();
- const uint32_t frameId = (uint32_t) State::Instance().currentFG->FrameCount();
- tokenResult = StreamlineProxy::GetNewFrameToken()(localToken, &frameId);
-
- if (tokenResult == sl::Result::eOk && !ReflexHooks::gameIsSendingMarkers() ||
+ if (!ReflexHooks::gameIsSendingMarkers() ||
!Config::Instance()->FGDLSSGUseGamesReflexMarkers.value_or_default())
{
- StreamlineProxy::PCLSetMarker()(sl::PCLMarker::ePresentStart, *localToken);
+ const uint32_t frameId = (uint32_t) State::Instance().currentFG->FrameCount();
+ tokenResult = StreamlineProxy::GetNewFrameToken()(localToken, &frameId);
+
+ if (tokenResult == sl::Result::eOk)
+ {
+ StreamlineProxy::PCLSetMarker()(sl::PCLMarker::ePresentStart, *localToken);
+ }
}
}
@@ -1150,7 +1159,9 @@ HRESULT FGHooks::FGPresent(IDXGISwapChain* This, UINT SyncInterval, UINT Flags,
if (tokenResult == sl::Result::eOk && localToken != nullptr &&
(!ReflexHooks::gameIsSendingMarkers() ||
!Config::Instance()->FGDLSSGUseGamesReflexMarkers.value_or_default()) &&
- willPresent && State::Instance().activeFgOutput == FGOutput::DLSSG && fg->IsActive() && !fg->IsPaused())
+ willPresent &&
+ (State::Instance().activeFgOutput == FGOutput::DLSSG ||
+ State::Instance().activeFgOutput == FGOutput::DLSSGWithNukems))
{
StreamlineProxy::PCLSetMarker()(sl::PCLMarker::ePresentEnd, *localToken);
StreamlineProxy::ReflexSleep()(*localToken);
diff --git a/OptiScaler/hooks/Reflex_Hooks.cpp b/OptiScaler/hooks/Reflex_Hooks.cpp
index fd74c794..db68ae24 100644
--- a/OptiScaler/hooks/Reflex_Hooks.cpp
+++ b/OptiScaler/hooks/Reflex_Hooks.cpp
@@ -46,7 +46,8 @@ NvAPI_Status ReflexHooks::hkNvAPI_D3D_Sleep(IUnknown* pDev)
#endif
static bool skip = false;
- if (State::Instance().activeFgOutput == FGOutput::DLSSG && StreamlineProxy::IsD3D12Inited() &&
+ if ((State::Instance().activeFgOutput == FGOutput::DLSSG ||
+ State::Instance().activeFgOutput == FGOutput::DLSSGWithNukems) &&
Config::Instance()->FGDLSSGUseGamesReflexMarkers.value_or_default() &&
State::Instance().currentFG->IsActive() && !State::Instance().currentFG->IsPaused())
{
@@ -124,8 +125,9 @@ NvAPI_Status ReflexHooks::hkNvAPI_D3D_SetLatencyMarker(IUnknown* pDev,
if (pSetLatencyMarkerParams->markerType == SIMULATION_START)
_lastMarkerFrame = State::Instance().FGLastFrame;
- if (State::Instance().activeFgOutput == FGOutput::DLSSG && StreamlineProxy::IsD3D12Inited() &&
- Config::Instance()->FGDLSSGUseGamesReflexMarkers.value_or_default() &&
+ if ((State::Instance().activeFgOutput == FGOutput::DLSSG ||
+ State::Instance().activeFgOutput == FGOutput::DLSSGWithNukems) &&
+ StreamlineProxy::IsD3D12Inited() && Config::Instance()->FGDLSSGUseGamesReflexMarkers.value_or_default() &&
State::Instance().currentFG->IsActive() && !State::Instance().currentFG->IsPaused())
{
sl::PCLMarker marker {};
diff --git a/OptiScaler/inputs/FG/DLSSG_Mod.h b/OptiScaler/inputs/FG/DLSSG_Mod.h
index 53c8ffcd..f7bdfa6b 100644
--- a/OptiScaler/inputs/FG/DLSSG_Mod.h
+++ b/OptiScaler/inputs/FG/DLSSG_Mod.h
@@ -134,8 +134,11 @@ class DLSSGMod
{
LOG_FUNC();
- if (_dx12_inited || Config::Instance()->FGInput.value_or_default() != FGInput::Nukems)
+ if (_dx12_inited || (Config::Instance()->FGInput.value_or_default() != FGInput::Nukems &&
+ Config::Instance()->FGOutput.value_or_default() != FGOutput::DLSSGWithNukems))
+ {
return;
+ }
_dll = TryInitMFG();
diff --git a/OptiScaler/inputs/NVNGX_DLSS_Dx12.cpp b/OptiScaler/inputs/NVNGX_DLSS_Dx12.cpp
index 04a824f5..5fbb2810 100644
--- a/OptiScaler/inputs/NVNGX_DLSS_Dx12.cpp
+++ b/OptiScaler/inputs/NVNGX_DLSS_Dx12.cpp
@@ -92,7 +92,8 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_Init_Ext(unsigned long long InApp
return NVSDK_NGX_Result_Success;
}
- if (State::Instance().activeFgInput == FGInput::Nukems)
+ if (State::Instance().activeFgInput == FGInput::Nukems ||
+ State::Instance().activeFgOutput == FGOutput::DLSSGWithNukems)
{
DLSSGMod::InitDLSSGMod_Dx12();
DLSSGMod::D3D12_Init_Ext(InApplicationId, InApplicationDataPath, InDevice, InSDKVersion, InFeatureInfo);
@@ -298,8 +299,11 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_Shutdown(void)
shutdown = false;
- if (State::Instance().activeFgInput == FGInput::Nukems)
+ if (State::Instance().activeFgInput == FGInput::Nukems ||
+ State::Instance().activeFgOutput == FGOutput::DLSSGWithNukems)
+ {
DLSSGMod::D3D12_Shutdown();
+ }
State::Instance().NvngxDx12Inited = false;
@@ -311,8 +315,11 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_Shutdown1(ID3D12Device* InDevice)
shutdown = true;
State::Instance().NvngxDx12Inited = false;
- if (State::Instance().activeFgInput == FGInput::Nukems)
+ if (State::Instance().activeFgInput == FGInput::Nukems ||
+ State::Instance().activeFgOutput == FGOutput::DLSSGWithNukems)
+ {
DLSSGMod::D3D12_Shutdown1(InDevice);
+ }
// Added `&& !State::Instance().isShuttingDown` hack for crash on exit
if (Config::Instance()->DLSSEnabled.value_or_default() && NVNGXProxy::IsDx12Inited() &&
@@ -454,8 +461,11 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_PopulateParameters_Impl(NVSDK_NGX
InitNGXParameters(InParameters);
- if (State::Instance().activeFgInput == FGInput::Nukems)
+ if (State::Instance().activeFgInput == FGInput::Nukems ||
+ State::Instance().activeFgOutput == FGOutput::DLSSGWithNukems)
+ {
DLSSGMod::D3D12_PopulateParameters_Impl(InParameters);
+ }
return NVSDK_NGX_Result_Success;
}
@@ -647,8 +657,8 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_CreateFeature(ID3D12GraphicsComma
const Config& cfg = *Config::Instance();
// Nukem's DLSSG mod passthrough
- if (state.activeFgInput == FGInput::Nukems && DLSSGMod::isDx12Available() &&
- InFeatureID == NVSDK_NGX_Feature_FrameGeneration)
+ if ((state.activeFgInput == FGInput::Nukems || state.activeFgOutput == FGOutput::DLSSGWithNukems) &&
+ DLSSGMod::isDx12Available() && InFeatureID == NVSDK_NGX_Feature_FrameGeneration)
{
LOG_INFO("Passthrough to Nukem's DLSSG CreateFeature for FrameGeneration");
@@ -732,7 +742,9 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_ReleaseFeature(NVSDK_NGX_Handle*
}
}
// Clean up OptiScaler feature with framegen
- else if (State::Instance().activeFgInput == FGInput::Nukems && handleId >= DLSSG_MOD_ID_OFFSET)
+ else if ((State::Instance().activeFgInput == FGInput::Nukems ||
+ State::Instance().activeFgOutput == FGOutput::DLSSGWithNukems) &&
+ handleId >= DLSSG_MOD_ID_OFFSET)
{
LOG_INFO("D3D12_ReleaseFeature modded DLSSG with HandleId: {0}", handleId);
return DLSSGMod::D3D12_ReleaseFeature(InHandle);
@@ -775,12 +787,14 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_GetFeatureRequirements(
{
LOG_DEBUG("for ({0})", (int) FeatureDiscoveryInfo->FeatureID);
- if (State::Instance().activeFgInput == FGInput::Nukems)
+ if (State::Instance().activeFgInput == FGInput::Nukems ||
+ State::Instance().activeFgOutput == FGOutput::DLSSGWithNukems)
DLSSGMod::InitDLSSGMod_Dx12();
if (FeatureDiscoveryInfo->FeatureID == NVSDK_NGX_Feature_SuperSampling ||
(FeatureDiscoveryInfo->FeatureID == NVSDK_NGX_Feature_FrameGeneration &&
- ((DLSSGMod::isDx12Available() && Config::Instance()->FGInput == FGInput::Nukems) ||
+ ((DLSSGMod::isDx12Available() && (Config::Instance()->FGInput == FGInput::Nukems ||
+ Config::Instance()->FGOutput == FGOutput::DLSSGWithNukems)) ||
Config::Instance()->FGInput == FGInput::DLSSG)))
{
if (OutSupported == nullptr)
@@ -992,7 +1006,8 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCom
}
// Nukem's DLSSG mod passthrough
- if (state.activeFgInput == FGInput::Nukems && handleId >= DLSSG_MOD_ID_OFFSET)
+ if ((state.activeFgInput == FGInput::Nukems || state.activeFgOutput == FGOutput::DLSSGWithNukems) &&
+ handleId >= DLSSG_MOD_ID_OFFSET)
{
LOG_DEBUG("Passthrough to Nukem's DLSSG EvaluateFeature for handle {}", handleId);
return DLSSGMod::D3D12_EvaluateFeature(InCmdList, InFeatureHandle, InParameters, InCallback);
@@ -1013,7 +1028,8 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_GetScratchBufferSize(NVSDK_NGX_Fe
if (OutSizeInBytes == nullptr)
return NVSDK_NGX_Result_FAIL_InvalidParameter;
- if (State::Instance().activeFgInput == FGInput::Nukems && DLSSGMod::isDx12Available() &&
+ if ((State::Instance().activeFgInput == FGInput::Nukems ||
+ State::Instance().activeFgOutput == FGOutput::DLSSGWithNukems) &&
InFeatureId == NVSDK_NGX_Feature_FrameGeneration)
{
return DLSSGMod::D3D12_GetScratchBufferSize(InFeatureId, InParameters, OutSizeInBytes);
diff --git a/OptiScaler/menu/menu_common.cpp b/OptiScaler/menu/menu_common.cpp
index a7e4b956..74903365 100644
--- a/OptiScaler/menu/menu_common.cpp
+++ b/OptiScaler/menu/menu_common.cpp
@@ -2975,7 +2975,8 @@ bool MenuCommon::RenderMenu()
{ FGOutput::Nukems, "FSR3-FG via Nukem's", "Enable DLSS-FG in-game" },
{ FGOutput::FSRFG, "FSR FG", "FSR3/4 FG" },
{ FGOutput::DLSSG, "DLSSG", "For 40xx and above" },
- { FGOutput::XeFG, "XeFG", "XeFG" }
+ { FGOutput::XeFG, "XeFG", "XeFG" },
+ { FGOutput::DLSSGWithNukems, "DLSSG with Nukem's", "DLSSG with Nukem's" }
};
// clang-format on
@@ -3005,6 +3006,15 @@ bool MenuCommon::RenderMenu()
inputOptions[nukemsInputIndex].set_disabled(nukemsUnsupportedApi, "Unsupported API");
outputOptions[nukemsOutputIndex].set_disabled(nukemsUnsupportedApi, "Unsupported API");
+ auto constexpr dlssgWithNukemsOutputIndex = (uint32_t) FGOutput::DLSSGWithNukems;
+ if (!state.NukemsFilesAvailable)
+ {
+ outputOptions[dlssgWithNukemsOutputIndex].set_disabled(
+ true, "Missing the dlssg_to_fsr3_amd_is_better.dll file");
+ }
+ outputOptions[dlssgWithNukemsOutputIndex].set_disabled(state.swapchainApi != API::DX12,
+ "Unsupported API");
+
// FSR FG output requirements
auto constexpr fsrfgOutputIndex = (uint32_t) FGOutput::FSRFG;
outputOptions[fsrfgOutputIndex].set_disabled(state.swapchainApi != API::DX12, "Unsupported API");
@@ -3131,7 +3141,8 @@ bool MenuCommon::RenderMenu()
auto fgOutput = reinterpret_cast(state.currentFG);
if (((state.activeFgOutput == FGOutput::FSRFG || state.activeFgOutput == FGOutput::XeFG ||
- state.activeFgOutput == FGOutput::DLSSG) &&
+ state.activeFgOutput == FGOutput::DLSSG ||
+ state.activeFgOutput == FGOutput::DLSSGWithNukems) &&
state.activeFgInput != FGInput::NoFG && state.activeFgInput != FGInput::Nukems) &&
fgOutput)
{
@@ -3771,8 +3782,8 @@ bool MenuCommon::RenderMenu()
}
// DLSSG controls
- if (state.activeFgOutput == FGOutput::DLSSG && state.activeFgInput != FGInput::NoFG &&
- state.currentFGSwapchain != nullptr)
+ if ((state.activeFgOutput == FGOutput::DLSSG || state.activeFgOutput == FGOutput::DLSSGWithNukems) &&
+ state.activeFgInput != FGInput::NoFG && state.currentFGSwapchain != nullptr)
{
if (StreamlineProxy::LoadStreamline() && currentFeature != nullptr && !currentFeature->IsFrozen())
{
@@ -3843,7 +3854,9 @@ bool MenuCommon::RenderMenu()
if (currentFeature != nullptr && !currentFeature->IsFrozen() &&
((state.activeFgOutput == FGOutput::FSRFG && FfxApiProxy::IsFGReady()) ||
(state.activeFgOutput == FGOutput::XeFG && XeFGProxy::Module() != nullptr) ||
- (state.activeFgOutput == FGOutput::DLSSG && StreamlineProxy::Module() != nullptr)))
+ ((state.activeFgOutput == FGOutput::DLSSG ||
+ state.activeFgOutput == FGOutput::DLSSGWithNukems) &&
+ StreamlineProxy::Module() != nullptr)))
{
if (!Config::Instance()->FGDisableHUDFix.value_or_default())
{
diff --git a/OptiScaler/proxies/Streamline_Proxy.h b/OptiScaler/proxies/Streamline_Proxy.h
index 93434ab2..2112b2ac 100644
--- a/OptiScaler/proxies/Streamline_Proxy.h
+++ b/OptiScaler/proxies/Streamline_Proxy.h
@@ -69,10 +69,15 @@ class StreamlineProxy
return true;
auto owner = State::GetOwner();
- State::DisableChecks(owner);
+ if (State::Instance().activeFgOutput != FGOutput::DLSSGWithNukems)
+ State::DisableChecks(owner);
+ else
+ State::DisableChecks(owner, "sl.");
+
std::filesystem::path slPath = Util::DllPath().parent_path() / L"opti_dlls\\streamline\\sl.interposer.dll";
LOG_INFO(L"Trying to load sl.interposer.dll from dll path: {}", slPath.wstring());
_dll = NtdllProxy::LoadLibraryExW_Ldr(slPath.c_str(), NULL, NULL);
+
State::EnableChecks(owner);
if (_dll != nullptr)
@@ -332,8 +337,14 @@ class StreamlineProxy
pref.numPathsToPlugins = (uint32_t) paths.size();
auto owner = State::GetOwner();
- State::DisableChecks(owner);
+
+ if (State::Instance().activeFgOutput != FGOutput::DLSSGWithNukems)
+ State::DisableChecks(owner);
+ else
+ State::DisableChecks(owner, "sl.");
+
auto initResult = StreamlineProxy::Init()(pref, sl::kSDKVersion);
+
State::EnableChecks(owner);
if (initResult == sl::Result::eOk)
diff --git a/OptiScaler/wrapped/wrapped_swapchain.cpp b/OptiScaler/wrapped/wrapped_swapchain.cpp
index 9ece8fc0..b9804370 100644
--- a/OptiScaler/wrapped/wrapped_swapchain.cpp
+++ b/OptiScaler/wrapped/wrapped_swapchain.cpp
@@ -500,8 +500,12 @@ HRESULT STDMETHODCALLTYPE WrappedIDXGISwapChain4::SetFullscreenState(BOOL Fullsc
#ifdef USE_LOCAL_MUTEX
// dlssg calls this from present it seems
// don't try to get a mutex when present owns it while dlssg mod is enabled
- if (!(_localMutex.getOwner() == 4 && Config::Instance()->FGInput.value_or_default() == FGInput::Nukems))
+ if (!(_localMutex.getOwner() == 4 &&
+ (Config::Instance()->FGInput.value_or_default() == FGInput::Nukems ||
+ Config::Instance()->FGOutput.value_or_default() == FGOutput::DLSSGWithNukems)))
+ {
OwnedLockGuard lock(_localMutex, 3);
+ }
#endif
if (Config::Instance()->FGUseMutexForSwapchain.value_or_default())
{
@@ -554,8 +558,12 @@ HRESULT STDMETHODCALLTYPE WrappedIDXGISwapChain4::ResizeBuffers(UINT BufferCount
#ifdef USE_LOCAL_MUTEX
// dlssg calls this from present it seems
// don't try to get a mutex when present owns it while dlssg mod is enabled
- if (!(_localMutex.getOwner() == 4 && Config::Instance()->FGInput.value_or_default() == FGInput::Nukems))
+ if (!(_localMutex.getOwner() == 4 &&
+ (Config::Instance()->FGInput.value_or_default() == FGInput::Nukems ||
+ Config::Instance()->FGOutput.value_or_default() == FGOutput::DLSSGWithNukems)))
+ {
OwnedLockGuard lock(_localMutex, 1);
+ }
#endif
if (State::Instance().currentFG != nullptr && Config::Instance()->FGUseMutexForSwapchain.value_or_default())
@@ -863,8 +871,12 @@ HRESULT STDMETHODCALLTYPE WrappedIDXGISwapChain4::ResizeBuffers1(UINT BufferCoun
#ifdef USE_LOCAL_MUTEX
// dlssg calls this from present it seems
// don't try to get a mutex when present owns it while dlssg mod is enabled
- if (!(_localMutex.getOwner() == 4 && Config::Instance()->FGInput.value_or_default() == FGInput::Nukems))
+ if (!(_localMutex.getOwner() == 4 &&
+ (Config::Instance()->FGInput.value_or_default() == FGInput::Nukems ||
+ Config::Instance()->FGOutput.value_or_default() == FGOutput::DLSSGWithNukems)))
+ {
OwnedLockGuard lock(_localMutex, 2);
+ }
#endif
if (State::Instance().activeFgOutput == FGOutput::FSRFG &&