Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 47 additions & 32 deletions OptiScaler/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,8 @@ bool Config::Reload(std::filesystem::path iniPath)

// --- DLSS 5 Neural Rendering (OptiScaler/dlssnr) ---
DlssNrEnabled.set_from_config(readBool("DlssNr", "Enabled"));
DlssNrMode.set_from_config(readUInt("DlssNr", "Mode"));
DlssNrFeature1Pipeline.set_from_config(readUInt("DlssNr", "Feature1Pipeline"));
DlssNrToggleKey.set_from_config(readInt("DlssNr", "ToggleKey"));
DlssNrTransferStrength.set_from_config(readFloat("DlssNr", "TransferStrength"));
DlssNrColourStrength.set_from_config(readFloat("DlssNr", "ColourStrength"));
Expand All @@ -327,6 +329,14 @@ bool Config::Reload(std::filesystem::path iniPath)
DlssNrCompareZoom.set_from_config(readFloat("DlssNr", "CompareZoom"));
DlssNrCompareSwap.set_from_config(readBool("DlssNr", "CompareSwap"));
DlssNrWorkingScale.set_from_config(readFloat("DlssNr", "WorkingScale"));
DlssNrWorkAtNative.set_from_config(readBool("DlssNr", "WorkAtNative"));
DlssNrTransfer.set_from_config(readUInt("DlssNr", "Transfer"));
DlssNrHdrLift.set_from_config(readUInt("DlssNr", "HdrLift"));
if (DlssNrWorkingScale.has_value() && DlssNrWorkingScale.value() <= 0.0f)
{
DlssNrWorkAtNative = true;
DlssNrWorkingScale = 1.0f;
}
DlssNrProxyProbe.set_from_config(readBool("DlssNr", "ProxyProbe"));
DlssNrUseProxy.set_from_config(readBool("DlssNr", "UseProxy"));
DlssNrAutoCapture.set_from_config(readBool("DlssNr", "AutoCapture"));
Expand Down Expand Up @@ -1166,38 +1176,43 @@ bool Config::SaveIni()
{
ini.SetValue("DLSS", "Enabled", GetBoolValue(Instance()->DLSSEnabled.value_for_config()).c_str());

// --- DLSS 5 Neural Rendering (OptiScaler/dlssnr) ---
ini.SetValue("DlssNr", "Enabled", GetBoolValue(Instance()->DlssNrEnabled.value_for_config()).c_str());
{
auto toggle = Instance()->DlssNrToggleKey.value_for_config();
ini.SetValue("DlssNr", "ToggleKey", GetIntValue(toggle, toggle > 0).c_str());
}
ini.SetValue("DlssNr", "TransferStrength",
GetFloatValue(Instance()->DlssNrTransferStrength.value_for_config()).c_str());
ini.SetValue("DlssNr", "ColourStrength",
GetFloatValue(Instance()->DlssNrColourStrength.value_for_config()).c_str());
ini.SetValue("DlssNr", "MaxRatio", GetFloatValue(Instance()->DlssNrMaxRatio.value_for_config()).c_str());
ini.SetValue("DlssNr", "DebugView", GetIntValue(Instance()->DlssNrDebugView.value_for_config()).c_str());
ini.SetValue("DlssNr", "Compare", GetIntValue(Instance()->DlssNrCompare.value_for_config()).c_str());
ini.SetValue("DlssNr", "CompareSplit",
GetFloatValue(Instance()->DlssNrCompareSplit.value_for_config()).c_str());
ini.SetValue("DlssNr", "CompareZoom",
GetFloatValue(Instance()->DlssNrCompareZoom.value_for_config()).c_str());
ini.SetValue("DlssNr", "CompareSwap",
GetBoolValue(Instance()->DlssNrCompareSwap.value_for_config()).c_str());
ini.SetValue("DlssNr", "WorkingScale", GetFloatValue(Instance()->DlssNrWorkingScale.value_for_config()).c_str());
ini.SetValue("DlssNr", "AutoCapture", GetBoolValue(Instance()->DlssNrAutoCapture.value_for_config()).c_str());
ini.SetValue("DlssNr", "WhitePointScale",
GetFloatValue(Instance()->DlssNrWhitePointScale.value_for_config()).c_str());
ini.SetValue("DlssNr", "Preset", GetIntValue(Instance()->DlssNrPreset.value_for_config()).c_str());
ini.SetValue("DlssNr", "Intensity", GetFloatValue(Instance()->DlssNrIntensity.value_for_config()).c_str());
ini.SetValue("DlssNr", "Style", GetIntValue(Instance()->DlssNrStyle.value_for_config()).c_str());
ini.SetValue("DlssNr", "LocalStructure",
GetFloatValue(Instance()->DlssNrLocalStructure.value_for_config()).c_str());
ini.SetValue("DlssNr", "LocalTone", GetFloatValue(Instance()->DlssNrLocalTone.value_for_config()).c_str());
ini.SetValue("DlssNr", "SkinStructure",
GetFloatValue(Instance()->DlssNrSkinStructure.value_for_config()).c_str());
ini.SetValue("DlssNr", "AutoMask", GetBoolValue(Instance()->DlssNrAutoMask.value_for_config()).c_str());
// --- DLSS 5 Neural Rendering (OptiScaler/dlssnr) ---
ini.SetValue("DlssNr", "Enabled", GetBoolValue(Instance()->DlssNrEnabled.value_for_config()).c_str());
ini.SetValue("DlssNr", "Mode", GetIntValue(Instance()->DlssNrMode.value_for_config()).c_str());
ini.SetValue("DlssNr", "Feature1Pipeline",
GetIntValue(Instance()->DlssNrFeature1Pipeline.value_for_config()).c_str());
{
auto toggle = Instance()->DlssNrToggleKey.value_for_config();
ini.SetValue("DlssNr", "ToggleKey", GetIntValue(toggle, toggle > 0).c_str());
}
ini.SetValue("DlssNr", "TransferStrength",
GetFloatValue(Instance()->DlssNrTransferStrength.value_for_config()).c_str());
ini.SetValue("DlssNr", "ColourStrength",
GetFloatValue(Instance()->DlssNrColourStrength.value_for_config()).c_str());
ini.SetValue("DlssNr", "MaxRatio", GetFloatValue(Instance()->DlssNrMaxRatio.value_for_config()).c_str());
ini.SetValue("DlssNr", "DebugView", GetIntValue(Instance()->DlssNrDebugView.value_for_config()).c_str());
ini.SetValue("DlssNr", "Compare", GetIntValue(Instance()->DlssNrCompare.value_for_config()).c_str());
ini.SetValue("DlssNr", "CompareSplit",
GetFloatValue(Instance()->DlssNrCompareSplit.value_for_config()).c_str());
ini.SetValue("DlssNr", "CompareZoom", GetFloatValue(Instance()->DlssNrCompareZoom.value_for_config()).c_str());
ini.SetValue("DlssNr", "CompareSwap", GetBoolValue(Instance()->DlssNrCompareSwap.value_for_config()).c_str());
ini.SetValue("DlssNr", "WorkingScale",
GetFloatValue(Instance()->DlssNrWorkingScale.value_for_config()).c_str());
ini.SetValue("DlssNr", "WorkAtNative", GetBoolValue(Instance()->DlssNrWorkAtNative.value_for_config()).c_str());
ini.SetValue("DlssNr", "Transfer", GetIntValue(Instance()->DlssNrTransfer.value_for_config()).c_str());
ini.SetValue("DlssNr", "HdrLift", GetIntValue(Instance()->DlssNrHdrLift.value_for_config()).c_str());
ini.SetValue("DlssNr", "AutoCapture", GetBoolValue(Instance()->DlssNrAutoCapture.value_for_config()).c_str());
ini.SetValue("DlssNr", "WhitePointScale",
GetFloatValue(Instance()->DlssNrWhitePointScale.value_for_config()).c_str());
ini.SetValue("DlssNr", "Preset", GetIntValue(Instance()->DlssNrPreset.value_for_config()).c_str());
ini.SetValue("DlssNr", "Intensity", GetFloatValue(Instance()->DlssNrIntensity.value_for_config()).c_str());
ini.SetValue("DlssNr", "Style", GetIntValue(Instance()->DlssNrStyle.value_for_config()).c_str());
ini.SetValue("DlssNr", "LocalStructure",
GetFloatValue(Instance()->DlssNrLocalStructure.value_for_config()).c_str());
ini.SetValue("DlssNr", "LocalTone", GetFloatValue(Instance()->DlssNrLocalTone.value_for_config()).c_str());
ini.SetValue("DlssNr", "SkinStructure",
GetFloatValue(Instance()->DlssNrSkinStructure.value_for_config()).c_str());
ini.SetValue("DlssNr", "AutoMask", GetBoolValue(Instance()->DlssNrAutoMask.value_for_config()).c_str());
ini.SetValue("DLSS", "RenderPresetOverride",
GetBoolValue(Instance()->RenderPresetOverride.value_for_config()).c_str());
ini.SetValue("DLSS", "RenderPresetForAll",
Expand Down
31 changes: 18 additions & 13 deletions OptiScaler/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,12 @@ class Config
// DLSS Neural Rendering: a detail-synthesis pass over the upscaler's output. Off by default -- it is
// an undocumented feature driven directly through its snippet, not something NVIDIA exposes.
CustomOptional<bool> DlssNrEnabled { false };
// 0 post-process (after the upscaler), 1 multi-pass (1:1 first pass, then the model, then a
// spatial enlarge). OptiScaler's own Dx12 DLSS / Ray Reconstruction only; anything else falls
// back to post-process.
CustomOptional<uint32_t> DlssNrMode { 0 };
// Which upscaler the multi-pass first pass is: 0 Ray Reconstruction, 1 Super Resolution.
CustomOptional<uint32_t> DlssNrFeature1Pipeline { 0 };
// Toggles the pass in game. Unbound by default -- a key that does something unexpected is worse
// than one that does nothing.
CustomOptional<int> DlssNrToggleKey { UnboundKey };
Expand All @@ -276,12 +282,11 @@ class Config
CustomOptional<float> DlssNrTransferStrength { 1.0f };
CustomOptional<float> DlssNrColourStrength { 1.0f };


// The most the pass may multiply or divide a pixel by. A detail pass has no business restyling a
// light source, whatever the model returns.
CustomOptional<float> DlssNrMaxRatio { 2.0f };

// 0 off, 1 the picture the model was shown, 2 its raw answer, 3 what it changed, amplified.
// 0–5: off, proxy, model, amplified difference, full-res proxy, matched T.
CustomOptional<uint32_t> DlssNrDebugView { 0 };

// Showing the pass against itself, without having to toggle it and remember what the last frame
Expand All @@ -300,10 +305,18 @@ class Config
// Which side the edited frame sits on, in both comparison modes.
CustomOptional<bool> DlssNrCompareSwap { false };

// The fraction of the frame's resolution the model works at. The frame itself is never reduced --
// only the model's contribution is computed small and enlarged, so the picture underneath is
// untouched whatever this is set to. 1.0 is full resolution and behaves exactly as before.
// The model's working raster as a fraction of display resolution, not of the colour buffer.
// The frame itself is never reduced -- only the model's contribution is computed small and
// enlarged. 1.0 is display resolution, then clamped to the colour buffer so Multi-pass cannot
// invent pixels past Feature 1.
CustomOptional<float> DlssNrWorkingScale { 1.0f };
// Lock the model to the game's render (native) raster. The slider then shows the live R/D
// ratio and is not adjustable. WorkingScale is left alone so unchecking restores it.
CustomOptional<bool> DlssNrWorkAtNative { false };
// 0 Classic, 1 Matched residual (default). How a below-frame model is brought back.
CustomOptional<uint32_t> DlssNrTransfer { 1 };
// 0 UpgradeToneMap (H0), 1 additive headroom (H1). Used only if Transfer == 1.
CustomOptional<uint32_t> DlssNrHdrLift { 0 };

// Ask the driver's own nvngx.dll whether it will dispatch Neural Rendering, once per session.
//
Expand Down Expand Up @@ -337,18 +350,10 @@ class Config
// folder is cleared at the start of each run, so it holds one session's worth and never grows.
CustomOptional<bool> DlssNrAutoCapture { true };





// Multiplies the (auto or manual) white point before the encode: what the model considers "white".
// Higher means highlights sit lower on the curve and the model treats them as less extreme.
CustomOptional<float> DlssNrWhitePointScale { 1.0f };





// --- end DLSS 5 Neural Rendering -------------------------------------------------------------

// DLSS
Expand Down
1 change: 1 addition & 0 deletions OptiScaler/OptiScaler.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,7 @@ copy NUL "$(SolutionDir)x64\Release\a\!! EXTRACT ALL FILES TO GAME FOLDER !!" /Y
<ClCompile Include="shaders\dlssnr\DlssNr_Dx12.cpp" />
<ClCompile Include="dlssnr\DlssNr_Proxy.cpp" />
<ClCompile Include="dlssnr\DlssNr_Menu.cpp" />
<ClCompile Include="dlssnr\DlssNr_Modes.cpp" />
<ClCompile Include="inputs\NVNGX_DLSS_Dx12.cpp" />
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="inputs\NVNGX_DLSS_Vk.cpp" />
Expand Down
3 changes: 2 additions & 1 deletion OptiScaler/dlssnr/DlssNr.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
// shaders/dlssnr/DlssNr_Dx12 the composition pass, as a Shader_Dx12
//
// Call sites, for the record:
// inputs/NVNGX_DLSS_Dx12.cpp the pass after an upscale
// inputs/NVNGX_DLSS_Dx12.cpp the pass after an upscale (PostProcess)
// upscalers/IFeature_Dx12.cpp multi-pass stage (resources in, at R)
// upscalers/IFeature_Dx11wDx12.cpp the pass inside the D3D11-on-D3D12 bridge
// menu/menu_common.cpp the settings panel

Expand Down
11 changes: 6 additions & 5 deletions OptiScaler/dlssnr/DlssNrFeature_Dx12.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,22 @@ namespace DlssNr
void EvaluateAfterUpscale(ID3D12GraphicsCommandList* cmdList, NVSDK_NGX_Parameter* params,
ID3D12CommandQueue* timingQueue = nullptr);


// Resources in. Builds the composition pass on first use if it is not already
// on this device, then Dispatches. Call sites that already hold the textures
// -- the multi-pass pipeline stage -- use this rather than reading an NGX
// parameter block.
void Run(ID3D12GraphicsCommandList* cmdList, ID3D12Resource* colour, ID3D12Resource* depth, ID3D12Resource* motion,
ID3D12Resource* output, const DlssNrFrameInfo& frame, ID3D12CommandQueue* timingQueue = nullptr);

// Frame generation titles tag their UI layer through Streamline; a copy of it makes the HUD mask
// exact at the finished frame. Called at tag time.




// The settings panel, drawn inside OptiScaler's menu.
void RenderMenu(::Config* config, float menuResScale);

// Clears the session failure latch, so a failure caused by transient thrash does not cost a restart.
void RetryAfterFailure();


// Whether the model is loaded and running, for the overlay.
bool IsRunning();

Expand Down
64 changes: 64 additions & 0 deletions OptiScaler/dlssnr/DlssNr_Area.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#pragma once

#include <algorithm>
#include <cmath>

namespace DlssNr
{

inline float Overlap1D(float box0, float box1, int i)
{
const float t0 = (float) i;
const float t1 = (float) (i + 1);
const float a = box0 > t0 ? box0 : t0;
const float b = box1 < t1 ? box1 : t1;
return b > a ? (b - a) : 0.0f;
}

struct AreaSample
{
float r, g, b, a;
};

// src is row-major srcW*srcH. Matches spec §7.1 / HLSL Mode 2 Matched.
inline AreaSample AreaDownsamplePixel(const AreaSample* src, int srcW, int srcH, int dstW, int dstH, int x, int y)
{
if (dstW == srcW && dstH == srcH)
return src[y * srcW + x];

const float x0 = ((float) x * (float) srcW) / (float) dstW;
const float x1 = ((float) (x + 1) * (float) srcW) / (float) dstW;
const float y0 = ((float) y * (float) srcH) / (float) dstH;
const float y1 = ((float) (y + 1) * (float) srcH) / (float) dstH;
const float area = (x1 - x0) * (y1 - y0);

const int i0 = (int) floorf(x0);
const int i1 = (int) ceilf(x1) - 1;
const int j0 = (int) floorf(y0);
const int j1 = (int) ceilf(y1) - 1;

float ar = 0.f, ag = 0.f, ab = 0.f;
for (int j = j0; j <= j1; ++j)
{
const int jj = std::clamp(j, 0, srcH - 1);
const float wy = Overlap1D(y0, y1, j);
for (int i = i0; i <= i1; ++i)
{
const int ii = std::clamp(i, 0, srcW - 1);
const float w = Overlap1D(x0, x1, i) * wy;
const AreaSample& s = src[jj * srcW + ii];
ar += s.r * w;
ag += s.g * w;
ab += s.b * w;
}
}

const float cx = ((float) x + 0.5f) * (float) srcW / (float) dstW;
const float cy = ((float) y + 0.5f) * (float) srcH / (float) dstH;
const int acx = std::clamp((int) floorf(cx), 0, srcW - 1);
const int acy = std::clamp((int) floorf(cy), 0, srcH - 1);

return { ar / area, ag / area, ab / area, src[acy * srcW + acx].a };
}

} // namespace DlssNr
15 changes: 6 additions & 9 deletions OptiScaler/dlssnr/DlssNr_Capture.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,13 +216,11 @@ class FrameCapture
buf.SampleDesc.Count = 1;
buf.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;

return SUCCEEDED(device->CreateCommittedResource(&heap, D3D12_HEAP_FLAG_NONE, &buf,
D3D12_RESOURCE_STATE_COPY_DEST, nullptr,
IID_PPV_ARGS(&shot.readback)));
return SUCCEEDED(device->CreateCommittedResource(
&heap, D3D12_HEAP_FLAG_NONE, &buf, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&shot.readback)));
}

static void copy(ID3D12GraphicsCommandList* cmd, ID3D12Resource* src, D3D12_RESOURCE_STATES state,
Shot& shot)
static void copy(ID3D12GraphicsCommandList* cmd, ID3D12Resource* src, D3D12_RESOURCE_STATES state, Shot& shot)
{
if (shot.readback == nullptr)
return;
Expand Down Expand Up @@ -320,11 +318,10 @@ class FrameCapture
{
std::fprintf(f, "frames %u\n", captured_);
std::fprintf(f, "before width %llu height %u format %d rowPitch %u\n",
(unsigned long long) beforeDesc_.Width, beforeDesc_.Height,
(int) beforeDesc_.Format,
(unsigned long long) beforeDesc_.Width, beforeDesc_.Height, (int) beforeDesc_.Format,
beforeShots_.empty() ? 0 : beforeShots_[0].layout.Footprint.RowPitch);
std::fprintf(f, "after width %llu height %u format %d rowPitch %u\n",
(unsigned long long) afterDesc_.Width, afterDesc_.Height, (int) afterDesc_.Format,
std::fprintf(f, "after width %llu height %u format %d rowPitch %u\n", (unsigned long long) afterDesc_.Width,
afterDesc_.Height, (int) afterDesc_.Format,
afterShots_.empty() ? 0 : afterShots_[0].layout.Footprint.RowPitch);
std::fprintf(f, "\nbefore_NN.raw is the frame as the upscaler produced it.\n");
std::fprintf(f, "after_NN.raw is the same frame once the model's edit was applied.\n");
Expand Down
Loading