diff --git a/features/Terrain Blending/Shaders/TerrainBlending/DepthBlend.hlsl b/features/Terrain Blending/Shaders/TerrainBlending/DepthBlend.hlsl index 3248d8def1..c4e5a1a7cf 100644 --- a/features/Terrain Blending/Shaders/TerrainBlending/DepthBlend.hlsl +++ b/features/Terrain Blending/Shaders/TerrainBlending/DepthBlend.hlsl @@ -1,11 +1,14 @@ RWTexture2D BlendedDepthTexture : register(u0); RWTexture2D BlendedDepthTexture16 : register(u1); +RWTexture2D MainDepthCopy : register(u2); // R32_FLOAT snapshot replaces CopyResource(terrainDepth <- mainDepth) Texture2D MainDepthTexture : register(t0); Texture2D TerrainDepthTexture : register(t1); [numthreads(8, 8, 1)] void main(uint3 DTid : SV_DispatchThreadID) { - float mixedDepth = min(MainDepthTexture[DTid.xy], TerrainDepthTexture[DTid.xy]); + float mainDepth = MainDepthTexture[DTid.xy]; + float mixedDepth = min(mainDepth, TerrainDepthTexture[DTid.xy]); BlendedDepthTexture[DTid.xy] = mixedDepth; BlendedDepthTexture16[DTid.xy] = mixedDepth; + MainDepthCopy[DTid.xy] = mainDepth; } diff --git a/src/Features/TerrainBlending.cpp b/src/Features/TerrainBlending.cpp index 7248d920f4..0d6cf97c08 100644 --- a/src/Features/TerrainBlending.cpp +++ b/src/Features/TerrainBlending.cpp @@ -693,6 +693,16 @@ void TerrainBlending::SetupResources() blendedDepthTexture16->CreateSRV(srvDesc); blendedDepthTexture16->CreateUAV(uavDesc); + // R32_FLOAT snapshot of main depth written by DepthBlend CS; replaces the per-frame + // CopyResource(terrainDepth <- mainDepth) that was needed for terrain shader slot 55. + texDesc.Format = DXGI_FORMAT_R32_FLOAT; + srvDesc.Format = texDesc.Format; + uavDesc.Format = texDesc.Format; + + mainDepthCopy = new Texture2D(texDesc); + mainDepthCopy->CreateSRV(srvDesc); + mainDepthCopy->CreateUAV(uavDesc); + auto& mainDepth = renderer->GetDepthStencilData().depthStencils[RE::RENDER_TARGETS_DEPTHSTENCIL::kMAIN]; depthSRVBackup = mainDepth.depthSRV; @@ -781,10 +791,13 @@ void TerrainBlending::BlendPrepassDepths() auto dispatchCount = Util::GetScreenDispatchCount(); { + TracyD3D11Zone(globals::state->tracyCtx, "Terrain Blending - Depth Blend CS"); + ID3D11ShaderResourceView* views[2] = { depthSRVBackup, terrainDepth.depthSRV }; context->CSSetShaderResources(0, ARRAYSIZE(views), views); - ID3D11UnorderedAccessView* uavs[2] = { blendedDepthTexture->uav.get(), blendedDepthTexture16->uav.get() }; + // u0=blendedDepth(R32), u1=blendedDepth16(R16), u2=mainDepthCopy(R32) written inline + ID3D11UnorderedAccessView* uavs[3] = { blendedDepthTexture->uav.get(), blendedDepthTexture16->uav.get(), mainDepthCopy->uav.get() }; context->CSSetUnorderedAccessViews(0, ARRAYSIZE(uavs), uavs, nullptr); context->CSSetShader(GetDepthBlendShader(), nullptr, 0); @@ -795,7 +808,7 @@ void TerrainBlending::BlendPrepassDepths() ID3D11ShaderResourceView* views[2] = { nullptr, nullptr }; context->CSSetShaderResources(0, ARRAYSIZE(views), views); - ID3D11UnorderedAccessView* uavs[2] = { nullptr, nullptr }; + ID3D11UnorderedAccessView* uavs[3] = { nullptr, nullptr, nullptr }; context->CSSetUnorderedAccessViews(0, ARRAYSIZE(uavs), uavs, nullptr); ID3D11ComputeShader* shader = nullptr; @@ -803,11 +816,8 @@ void TerrainBlending::BlendPrepassDepths() auto stateUpdateFlags = globals::game::stateUpdateFlags; stateUpdateFlags->set(RE::BSGraphics::ShaderFlags::DIRTY_RENDERTARGET); - - auto renderer = globals::game::renderer; - auto& mainDepth = renderer->GetDepthStencilData().depthStencils[RE::RENDER_TARGETS_DEPTHSTENCIL::kMAIN]; - - context->CopyResource(terrainDepth.texture, mainDepth.texture); + // CopyResource(terrainDepth <- mainDepth) eliminated: main depth is now written + // directly into mainDepthCopy (u2) by the CS above, saving a full-stereo D24S8 copy. if (globals::state->frameAnnotations) globals::state->EndPerfEvent(); @@ -992,8 +1002,11 @@ void TerrainBlending::RenderTerrainBlendingPasses() auto shadowState = globals::game::shadowState; auto stateUpdateFlags = globals::game::stateUpdateFlags; - // Used to get the distance of the surface to the lowest depth - context->PSSetShaderResources(55, 1, &terrainDepth.depthSRV); + // Slot 55: main depth snapshot used to measure surface-to-lowest-depth distance. + // R32_FLOAT copy written inline by DepthBlend CS; safe to read here because + // mainDepthCopy is not written during the main rendering pass. + auto mainDepthSRV = mainDepthCopy->srv.get(); + context->PSSetShaderResources(55, 1, &mainDepthSRV); const uint64_t terrainPassCount = static_cast(terrainRenderPasses.size()); const uint64_t noBlendPassCount = static_cast(renderPasses.size()); diff --git a/src/Features/TerrainBlending.h b/src/Features/TerrainBlending.h index 4d552b61c8..4981b03d85 100644 --- a/src/Features/TerrainBlending.h +++ b/src/Features/TerrainBlending.h @@ -72,6 +72,7 @@ struct TerrainBlending : Feature Texture2D* blendedDepthTexture = nullptr; Texture2D* blendedDepthTexture16 = nullptr; + Texture2D* mainDepthCopy = nullptr; // R32_FLOAT snapshot written inline by DepthBlend CS, replaces CopyResource ID3D11ShaderResourceView* GetBlendedDepthSRV() const { diff --git a/src/Features/Upscaling.cpp b/src/Features/Upscaling.cpp index 76f72a0bd2..036c9f24ea 100644 --- a/src/Features/Upscaling.cpp +++ b/src/Features/Upscaling.cpp @@ -1912,9 +1912,16 @@ void Upscaling::UpscaleDepth() }; { - // Sometimes this is not already copied e.g. map menu. - // Skip alias copies to reduce unnecessary copy churn. - copyIfNonAliased(depthCopy.texture, depth.texture); + // Engine copies kMAIN→kMAIN_COPY during 3D scene rendering. + // In non-3D contexts (map, main menu, loading, pause) the engine skips its copy. + auto* ui = globals::game::ui; + const bool inMenuContext = globals::state->isMapMenuOpen || + globals::state->isMainMenuOpen || + globals::state->isLoadingMenuOpen || + (ui && ui->GameIsPaused()); + if (inMenuContext) { + copyIfNonAliased(depthCopy.texture, depth.texture); + } // Clear stencil to be 0xFF if (globals::game::isVR) { @@ -1989,18 +1996,13 @@ void Upscaling::ApplySharpening() auto renderer = globals::game::renderer; auto& main = renderer->GetRuntimeData().renderTargets[RE::RENDER_TARGETS::kMAIN]; - ID3D11Resource* mainResource = nullptr; - main.SRV->GetResource(&mainResource); - - if (!mainResource) + if (!main.UAV) return; context->OMSetRenderTargets(0, nullptr, nullptr); - rcas.ApplySharpen(main.SRV, sharpenerTexture->uav.get(), currentSharpness); - context->CopyResource(mainResource, sharpenerTexture->resource.get()); - - mainResource->Release(); + // Zero-copy path: DLSS has already written to sharpenerTexture; sharpen directly into kMAIN.UAV. + rcas.ApplySharpen(sharpenerTexture->srv.get(), main.UAV, currentSharpness); globals::game::stateUpdateFlags->set(RE::BSGraphics::ShaderFlags::DIRTY_RENDERTARGET); } diff --git a/src/Features/Upscaling/Streamline.cpp b/src/Features/Upscaling/Streamline.cpp index f5b5ca4599..f5e3c58284 100644 --- a/src/Features/Upscaling/Streamline.cpp +++ b/src/Features/Upscaling/Streamline.cpp @@ -612,11 +612,16 @@ void Streamline::Upscale(ID3D11Resource* a_upscalingTexture, ID3D11Resource* a_r auto screenSize = state->screenSize; auto renderSize = Util::ConvertToDynamic(screenSize); + // When RCAS sharpening is active, direct DLSS output to sharpenerTexture so RCAS can + // sharpen directly into kMAIN.UAV without a CopyResource round-trip. + auto& upscaling = globals::features::upscaling; + ID3D11Resource* colorOut = + (upscaling.settings.sharpnessDLSS > 0.0f && upscaling.sharpenerTexture) ? upscaling.sharpenerTexture->resource.get() : a_upscalingTexture; + // VR: Combined-buffer mode with extent offsets causes temporal ghosting on the right eye // because DLSS's internal history buffers use extent offsets as indices. // Per-eye isolation with extents at {0,0} is required. if (globals::game::isVR) { - auto& upscaling = globals::features::upscaling; uint32_t eyeWidthOut = (uint32_t)(screenSize.x / 2); uint32_t eyeHeightOut = (uint32_t)screenSize.y; uint32_t eyeWidthIn = (uint32_t)(renderSize.x / 2); @@ -636,14 +641,14 @@ void Streamline::Upscale(ID3D11Resource* a_upscalingTexture, ID3D11Resource* a_r extentIn, extentOut, eyeWidthOut); } - upscaling.FinalizePerEyeOutputs(a_upscalingTexture); + upscaling.FinalizePerEyeOutputs(colorOut); } else { - // Non-VR: Simple full-texture upscale + // Non-VR: Simple full-texture upscale. sl::Extent extentIn{ 0, 0, (uint)renderSize.x, (uint)renderSize.y }; sl::Extent extentOut{ 0, 0, (uint)screenSize.x, (uint)screenSize.y }; EvaluateDLSS(viewport, 0, - a_upscalingTexture, a_upscalingTexture, + a_upscalingTexture, colorOut, depthTexture.texture, a_motionVectors, a_reactiveMask, a_transparencyCompositionMask, extentIn, extentOut, (uint)screenSize.x); }