Skip to content
Merged
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
70 changes: 54 additions & 16 deletions src/Features/Upscaling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1819,15 +1819,29 @@ void Upscaling::UpscaleDepth()
// 3) Resource copies are skipped for aliased src/dst to reduce copy churn.

// (1) Early validation exits
if (!IsUpscalingActive()) {
const bool depthUpscaleActive = IsUpscalingActive();
const auto upscaleMethod = GetUpscaleMethod();
const bool isVR = globals::game::isVR;
const bool vendorUpscaler = upscaleMethod == UpscaleMethod::kDLSS || upscaleMethod == UpscaleMethod::kFSR;
const bool fullResolutionMaskPath =
upscaleMethod == UpscaleMethod::kNONE ||
upscaleMethod == UpscaleMethod::kTAA ||
(vendorUpscaler && settings.qualityMode == 0);
const bool repairVRFullResolutionMask =
isVR &&
fullResolutionMaskPath &&
!depthUpscaleActive;

if (!depthUpscaleActive && !repairVRFullResolutionMask) {
return;
}

auto state = globals::state;
auto renderer = globals::game::renderer;
auto context = globals::d3d::context;
auto deferred = globals::deferred;
if (!state || !renderer || !context || !deferred || !deferred->linearSampler || !jitterCB || !upscaleRasterizerState || !upscaleBlendState || !upscaleDepthStencilState) {
if (!state || !renderer || !context || !deferred || !deferred->linearSampler || !jitterCB || !upscaleRasterizerState || !upscaleBlendState ||
(depthUpscaleActive && !upscaleDepthStencilState)) {
return;
}

Expand All @@ -1842,24 +1856,39 @@ void Upscaling::UpscaleDepth()
auto& saoCameraZ = renderer->GetRuntimeData().renderTargets[RE::RENDER_TARGET::kSAO_CAMERAZ];
auto& underwaterMask = renderer->GetRuntimeData().renderTargets[RE::RENDER_TARGET::kUNDERWATER_MASK];

if (!depth.texture || !depth.views[0] || !depthCopy.texture || !depthCopy.depthSRV ||
!refractionNormals.texture || !refractionNormals.textureCopy || !refractionNormals.SRVCopy || !refractionNormals.RTV || !saoCameraZ.RTV ||
if (!depth.texture || !depthCopy.texture || !depthCopy.depthSRV ||
!underwaterMask.texture || !underwaterMask.textureCopy || !underwaterMask.SRVCopy || !underwaterMask.RTV) {
return;
}
if (globals::game::isVR && (!depthCopy.views[0] || !depthCopy.stencilSRV)) {
if (depthUpscaleActive &&
(!depth.views[0] || !refractionNormals.texture || !refractionNormals.textureCopy || !refractionNormals.SRVCopy || !refractionNormals.RTV || !saoCameraZ.RTV)) {
return;
}
// stencilSRV + views[0] are both upscale-path-only: the depth-upscale
// draw binds depthCopy as a stencil SRV input and depth.views[0] as DSV.
// The full-resolution mask repair never touches either, so don't disable
// the VR fix on setups where stencil SRV creation is unavailable.
if (depthUpscaleActive && isVR && (!depthCopy.stencilSRV || !depthCopy.views[0])) {
return;
}

auto* fullscreenVS = GetUpscaleVS();
auto* depthUpscalePS = GetDepthRefractionUpscalePS();
auto* depthUpscalePS = depthUpscaleActive ? GetDepthRefractionUpscalePS() : nullptr;
auto* underwaterMaskPS = GetUnderwaterMaskUpscalePS();
if (!fullscreenVS || !depthUpscalePS || !underwaterMaskPS) {
if (!fullscreenVS || !underwaterMaskPS || (depthUpscaleActive && !depthUpscalePS)) {
return;
}

state->BeginPerfEvent("Render Target Upscaling");

// Unbind any prior render targets before issuing CopyResource on depth/
// depthCopy. Upscale() does this for the standard upscale path, but
// UpscaleDepth() can now be invoked standalone from Main_PostProcessing
// (kNONE/kTAA VR path) without going through Upscale() first — match the
// same precondition here to avoid a debug-layer hazard when depth happens
// to still be bound as a DSV from a prior pass.
context->OMSetRenderTargets(0, nullptr, nullptr);

// Set up Input Assembler for fullscreen triangle (no vertex/index buffers needed)
context->IASetInputLayout(nullptr);
context->IASetVertexBuffers(0, 0, nullptr, nullptr, nullptr);
Expand Down Expand Up @@ -1887,10 +1916,10 @@ void Upscaling::UpscaleDepth()
context->PSSetSamplers(0, ARRAYSIZE(samplers), samplers);

// Set up jitter/depth-kernel constant buffer for upscaling
JitterCB jitterData;
JitterCB jitterData{};
jitterData.jitter = jitter;
// (2) Wide-kernel hysteresis
{
if (depthUpscaleActive) {
constexpr float kEnterWideKernelRatio = 1.55f;
constexpr float kExitWideKernelRatio = 1.45f;
const float minScale = std::max(std::min(resolutionScale.x, resolutionScale.y), FLT_EPSILON);
Expand All @@ -1907,7 +1936,6 @@ void Upscaling::UpscaleDepth()
}

jitterData.useWideKernel = depthUpscaleUseWideKernel ? 1.0f : 0.0f;
jitterData.pad0 = 0.0f;
}

jitterCB->Update(jitterData);
Expand All @@ -1921,15 +1949,15 @@ void Upscaling::UpscaleDepth()
}
};

{
if (depthUpscaleActive) {
TracyD3D11Zone(globals::state->tracyCtx, "Upscaling - Depth Upscale");

// Sometimes this is not already copied e.g. map menu.
// Skip alias copies to reduce unnecessary copy churn.
copyIfNonAliased(depthCopy.texture, depth.texture);

// Clear stencil to be 0xFF
if (globals::game::isVR) {
if (isVR) {
context->ClearDepthStencilView(depthCopy.views[0], D3D11_CLEAR_STENCIL, 1.0f, 0xFF);
}

Expand All @@ -1944,11 +1972,16 @@ void Upscaling::UpscaleDepth()
// kSAO_CAMERAZ is at quarter-stereo resolution in VR; the full-stereo viewport would
// corrupt only the top-left quarter. The engine's ISSAOCameraZ pass populates it correctly.
ID3D11RenderTargetView* rtvs[] = { refractionNormals.RTV,
globals::game::isVR ? nullptr : saoCameraZ.RTV };
isVR ? nullptr : saoCameraZ.RTV };
context->OMSetRenderTargets(2, rtvs, depth.views[0]);

context->PSSetShader(depthUpscalePS, nullptr, 0);
context->Draw(3, 0);
} else {
TracyD3D11Zone(globals::state->tracyCtx, "Upscaling - Full Resolution Underwater Mask Depth Copy");

// Full-resolution paths only need to refresh the underwater mask depth source.
copyIfNonAliased(depthCopy.texture, depth.texture);
Comment thread
alandtse marked this conversation as resolved.
}

{
Expand All @@ -1974,8 +2007,10 @@ void Upscaling::UpscaleDepth()
context->Draw(3, 0);
}

// Now propagate the upscaled depth to kMAIN_COPY so downstream VR passes see it.
if (globals::game::isVR) {
// Propagate the upscaled depth to kMAIN_COPY so downstream VR passes see
// it. Skipped on the full-resolution path because the else branch above
// already refreshed depthCopy from depth and nothing has touched it since.
if (isVR && depthUpscaleActive) {
TracyD3D11Zone(globals::state->tracyCtx, "Upscaling - Depth VR Propagate");
copyIfNonAliased(depthCopy.texture, depth.texture);
}
Expand Down Expand Up @@ -2045,8 +2080,11 @@ void Upscaling::Main_PostProcessing::thunk(RE::ImageSpaceManager* a_this, uint32
if (upscaling.ShouldUseFrameGenerationThisFrame())
upscaling.CopySharedD3D12Resources();

if (upscaleMethod != UpscaleMethod::kNONE && upscaleMethod != UpscaleMethod::kTAA)
if (upscaleMethod != UpscaleMethod::kNONE && upscaleMethod != UpscaleMethod::kTAA) {
upscaling.PerformUpscaling();
} else if (globals::game::isVR) {
Comment thread
alandtse marked this conversation as resolved.
upscaling.UpscaleDepth();
}

if (upscaleMethod == UpscaleMethod::kDLSS)
upscaling.ApplySharpening();
Expand Down
Loading