Skip to content
Open
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
8 changes: 8 additions & 0 deletions OptiScaler/dlssnr/DlssNrFeature_Dx12.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,5 +178,13 @@ std::optional<double> LastGpuTime();
void RequestCapture(unsigned int frames);
bool CaptureInProgress();

// Session-only D3D12 inspection. Pending takes a matched snapshot on the next successful resolve;
// Held runs only that resolve with live Compare/Debug controls, never NGX with stale guides.
// Capture takes priority and resumes live rendering. Resume invalidates every model history.
enum class InspectionHoldState { Unavailable, Live, Pending, Held };
InspectionHoldState GetInspectionHoldState();
void RequestInspectionHold();
void ReleaseInspectionHold();

void Shutdown();
} // namespace DlssNr
2 changes: 1 addition & 1 deletion OptiScaler/dlssnr/DlssNrFeature_Vk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,7 @@ bool EvaluateAtSeamVk(VkCommandBuffer cmdBuffer, NVSDK_NGX_Parameter* params, Vk

// The model's working size. The slider is a fraction of the frame; at 1 it is the frame, and the
// reduced path below never runs, so the default is byte-for-byte what it was.
const float workScale = std::clamp(cfg.DlssNrWorkingScale.value_or_default(), 0.25f, 1.0f);
const float workScale = std::clamp(cfg.DlssNrWorkingScale.value_or_default(), 0.25f, 2.0f);
const uint32_t workWidth = (uint32_t) (width * workScale + 0.5f);
const uint32_t workHeight = (uint32_t) (height * workScale + 0.5f);
const bool reduced = workWidth != width || workHeight != height;
Expand Down
44 changes: 32 additions & 12 deletions OptiScaler/dlssnr/DlssNr_Menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -376,24 +376,22 @@ void RenderMenu(Config* config, float menuResScale)
? pendingScale
: (int) lroundf(config->DlssNrWorkingScale.value_or_default() * 100.0f);

if (ImGui::SliderInt("Model resolution", &scalePercent, 25, 100, "%d%%"))
if (ImGui::SliderInt("Model resolution", &scalePercent, 25, 200, "%d%%"))
pendingScale = scalePercent;

if (ImGui::IsItemDeactivatedAfterEdit() && pendingScale >= 0)
{
config->DlssNrWorkingScale = std::clamp(pendingScale, 25, 100) / 100.0f;
config->DlssNrWorkingScale = std::clamp(pendingScale, 25, 200) / 100.0f;
pendingScale = -1;
}

HelpMarker("What fraction of the frame the model works at. Cost falls with the square of"
"\nthis, so half resolution is roughly a quarter of the time."
"\n\nThe frame is never reduced. Only the model's contribution is computed small"
"\nand enlarged, so the picture underneath is untouched whatever this says."
"\n\nWhat it trades: the shading the model adds is broad and survives enlargement;"
"\nthe fine structure it synthesises does not, and softens. Worth having when the"
"\npass costs more than you want to pay for the detail it returns."
"\n\nThe frame itself stays at full detail whatever this says -- only the"
"\nmodel's own work is done small.");
HelpMarker("The model's raster as a percentage of the frame, from 25% to 200%."
"\nThe original frame stays at full detail; only the model's work is resampled."
"\n\nBelow 100%, the model works on a smaller picture and its answer is enlarged."
"\nHalf resolution is a quarter of the model pixels, but fine detail softens."
"\n\nAbove 100%, the model works on a larger raster and its answer returns to"
"\nframe size. 200% is twice each axis, four times the model pixels and higher"
"\nVRAM cost; it does not add game geometry samples.");

{
bool dual = config->DlssNrDualFeature.value_or_default();
Expand Down Expand Up @@ -1152,7 +1150,29 @@ void RenderMenu(Config* config, float menuResScale)
// while the exaggeration slider was still at 32x and deserves a clean re-run.


if (DlssNr::CaptureInProgress())
const auto hold = DlssNr::GetInspectionHoldState();
const bool holding = hold == DlssNr::InspectionHoldState::Held;
const bool holdPending = hold == DlssNr::InspectionHoldState::Pending;
const bool capturing = DlssNr::CaptureInProgress();
ImGui::BeginDisabled(!holding && !holdPending &&
(vulkan || capturing || hold == DlssNr::InspectionHoldState::Unavailable));
if (ImGui::Button(holding ? "Resume" : holdPending ? "Cancel hold" : "Hold frame"))
{
if (holding || holdPending)
DlssNr::ReleaseInspectionHold();
else
DlssNr::RequestInspectionHold();
}
ImGui::EndDisabled();
HelpMarker("D3D12 inspection only: keeps the next successful frame's proxy, model answer"
"\nand original together. Compare and Debug remain interactive; the model does"
"\nnot run again until Resume. This does not pause the game."
"\n\nModel and colour tuning apply after Resume. A resize releases the hold."
"\nCapture resumes live rendering first; Hold waits until capture has finished."
"\nUnavailable on native Vulkan or the experimental proxy path.");
ImGui::SameLine();

if (capturing)
{
ImGui::TextDisabled("Capturing...");
}
Expand Down
33 changes: 19 additions & 14 deletions OptiScaler/menu/menu_common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3480,17 +3480,26 @@ void MenuCommon::RenderFrameGenerationSelection(RenderMenuContext& ctx)

ImGui::EndDisabled();

if (state.dlssgGameDMFGSupported && !dlssgInputOrOutput)
if (!dlssgInputOrOutput)
{
ImGui::SameLine(0.0f, 16.0f);

if (bool dynamicMFG = config->FGDLSSGOverrideForceDMFG.value_or_default();
ImGui::Checkbox("Force Dynamic MFG", &dynamicMFG))
if (state.dlssgGameDMFGSupported)
{
config->FGDLSSGOverrideForceDMFG = dynamicMFG;
StreamlineHooks::updateDlssgOptions();
ImGui::SameLine(0.0f, 16.0f);

if (bool dynamicMFG = config->FGDLSSGOverrideForceDMFG.value_or_default();
ImGui::Checkbox("Force Dynamic MFG", &dynamicMFG))
{
config->FGDLSSGOverrideForceDMFG = dynamicMFG;
StreamlineHooks::updateDlssgOptions();
}
}

SeparatorWithHelpMarker("MFG Unlock (RTX 40)",
"Raises the generated frame maximum in nvngx_dlssg.dll and in the count "
"Streamline reports, so the ratio above offers up to 6X on pre-Blackwell "
"cards. Patched in memory; the file on disk is not touched. Takes effect "
"on the next game start. Undocumented and unsupported by NVIDIA.");

bool adaUnlock = config->FGDLSSGAdaMfgUnlock.value_or_default();

if (ImGui::Checkbox("Unlock MFG on RTX 40", &adaUnlock))
Expand Down Expand Up @@ -3539,14 +3548,10 @@ void MenuCommon::RenderFrameGenerationSelection(RenderMenuContext& ctx)
ImGui::TextColored(good, "%u kernel containers run the Blackwell image.", mfg.KernelsRewritten);
}
}
}

ShowHelpMarker("Raises the generated frame maximum in nvngx_dlssg.dll and in the count Streamline "
"reports, so the ratio above offers up to 6X on pre-Blackwell cards. Patched in "
"memory; the file on disk is not touched. Takes effect on the next game start.\n\n"
"Pacing above 2X is uneven -- the module expects Blackwell's flip metering hardware. "
"Try DisableFlipMetering under [NvApi] alongside it.\n\n"
"Undocumented and unsupported by NVIDIA.");

if (!dlssgInputOrOutput && state.dlssgGameDMFGSupported)
{
ImGui::BeginDisabled(state.dlssgLastSetMode != sl::DLSSGMode::eDynamic);
static float fpsTarget = config->FGDLSSGFramerateTargetDMFG.value_or_default();
ImGui::SliderFloat("DMFG FPS Target", &fpsTarget, 0, 200, "%.0f");
Expand Down
Loading