From df2794c7989c10e7e36400e3d01fd94472c99240 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 25 Jun 2026 23:04:23 +0200 Subject: [PATCH] Optimize rendering when using TAA to draw PostFX directly to backbuffer --- .../Renderer/GI/GlobalSurfaceAtlasPass.cpp | 4 ++-- Source/Engine/Renderer/PostProcessingPass.cpp | 17 ++++++++--------- Source/Engine/Renderer/PostProcessingPass.h | 4 +++- Source/Engine/Renderer/Renderer.cpp | 18 ++++++++++++++++-- 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp index 3a7589212..ffb0a3c11 100644 --- a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp +++ b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp @@ -1000,7 +1000,7 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co return true; memUsage += surfaceAtlasData.ChunksBuffer->GetMemoryUsage(); } - surfaceAtlasData.MemoryUsage = memUsage; + surfaceAtlasData.MemoryUsage = (uint32)memUsage; LOG(Info, "Global Surface Atlas resolution: {0}, memory usage: {1} MB", resolution, memUsage / (1024 * 1024)); context->Clear(surfaceAtlasData.AtlasLighting->View(), Color::Transparent); @@ -1786,7 +1786,7 @@ void GlobalSurfaceAtlasPass::RenderDebug(RenderContext& renderContext, GPUContex context->ResetRenderTarget(); auto colorGradingLUT = ColorGradingPass::Instance()->RenderLUT(renderContext); EyeAdaptationPass::Instance()->Render(renderContext, tempBuffer); - PostProcessingPass::Instance()->Render(renderContext, tempBuffer, output, colorGradingLUT); + PostProcessingPass::Instance()->Render(renderContext, tempBuffer, output->View(), Viewport(output->Size()), colorGradingLUT); RenderTargetPool::Release(tempBuffer); context->ResetRenderTarget(); diff --git a/Source/Engine/Renderer/PostProcessingPass.cpp b/Source/Engine/Renderer/PostProcessingPass.cpp index d3913e648..d6f8a0ebc 100644 --- a/Source/Engine/Renderer/PostProcessingPass.cpp +++ b/Source/Engine/Renderer/PostProcessingPass.cpp @@ -249,7 +249,7 @@ int32 CalculateBloomMipCount(int32 width, int32 height) return mipCount; } -void PostProcessingPass::Render(RenderContext& renderContext, GPUTexture* input, GPUTexture* output, GPUTexture* colorGradingLUT) +void PostProcessingPass::Render(RenderContext& renderContext, GPUTexture* input, GPUTextureView* output, const Viewport& outputViewport, GPUTexture* colorGradingLUT) { PROFILE_GPU_CPU("Post Processing"); auto device = GPUDevice::Instance; @@ -279,8 +279,8 @@ void PostProcessingPass::Render(RenderContext& renderContext, GPUTexture* input, if (!(useBloom || useToneMapping || useCameraArtifacts || colorGradingLUT) || checkIfSkipPass() || w8 <= 1 || h8 <= 1) { // Resources are missing. Do not perform rendering. Just copy raw frame - context->SetViewportAndScissors((float)output->Width(), (float)output->Height()); - context->SetRenderTarget(*output); + context->SetViewportAndScissors(outputViewport); + context->SetRenderTarget(output); context->Draw(input); return; } @@ -304,7 +304,7 @@ void PostProcessingPass::Render(RenderContext& renderContext, GPUTexture* input, data.GrainAmount = settings.CameraArtifacts.GrainAmount; data.GrainParticleSize = Math::Max(0.0001f, settings.CameraArtifacts.GrainParticleSize); data.GrainTime = time * 0.5f * settings.CameraArtifacts.GrainSpeed; - data.ChromaticDistortion = Math::Saturate(settings.CameraArtifacts.ChromaticDistortion * (float)output->Width() / 1080.0f); // Rescale based on reference 1080p resolution + data.ChromaticDistortion = Math::Saturate(settings.CameraArtifacts.ChromaticDistortion * outputViewport.Width / 1080.0f); // Rescale based on reference 1080p resolution data.ScreenFadeColor = settings.CameraArtifacts.ScreenFadeColor; } else @@ -363,7 +363,7 @@ void PostProcessingPass::Render(RenderContext& renderContext, GPUTexture* input, data.LensFlareIntensity = 0; data.LensDirtIntensity = 0; } - data.QuantizationError = RenderTools::GetColorQuantizationError(output->Format()); + data.QuantizationError = RenderTools::GetColorQuantizationError(output->GetFormat()); data.PostExposure = Math::Exp2(settings.EyeAdaptation.PostExposure); data.InputSize = Float2(static_cast(w1), static_cast(h1)); data.InvInputSize = Float2(1.0f / static_cast(w1), 1.0f / static_cast(h1)); @@ -384,7 +384,7 @@ void PostProcessingPass::Render(RenderContext& renderContext, GPUTexture* input, //////////////////////////////////////////////////////////////////////////////////// // Bloom - auto tempDesc = GPUTextureDescription::New2D(w2, h2, bloomMipCount, output->Format(), GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget | GPUTextureFlags::PerMipViews); + auto tempDesc = GPUTextureDescription::New2D(w2, h2, bloomMipCount, output->GetFormat(), GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget | GPUTextureFlags::PerMipViews); GPUTexture* bloomBuffer1 = nullptr, *bloomBuffer2 = nullptr; if (useBloom || useLensFlares) { @@ -566,10 +566,9 @@ void PostProcessingPass::Render(RenderContext& renderContext, GPUTexture* input, // Composite final frame during single pass (done in full resolution) { - auto rt = output->View(); auto rtAction = GPUDrawPassAction::Store; - GPUDrawPass drawPass(context, ToSpan(&rt, 1), ToSpan(&rtAction, 1)); - context->SetViewportAndScissors((float)output->Width(), (float)output->Height()); + GPUDrawPass drawPass(context, ToSpan(&output, 1), ToSpan(&rtAction, 1)); + context->SetViewportAndScissors(outputViewport); context->SetState(_psComposite.Get(compositePermutationIndex)); context->DrawFullscreenTriangle(); } diff --git a/Source/Engine/Renderer/PostProcessingPass.h b/Source/Engine/Renderer/PostProcessingPass.h index e450bf5ee..811ff145c 100644 --- a/Source/Engine/Renderer/PostProcessingPass.h +++ b/Source/Engine/Renderer/PostProcessingPass.h @@ -3,6 +3,7 @@ #pragma once #include "RendererPass.h" +#include "Engine/Core/Math/Viewport.h" #include "Engine/Graphics/GPUPipelineStatePermutations.h" /// @@ -30,8 +31,9 @@ public: /// The rendering context. /// Target with rendered HDR frame to post process /// Output frame + /// Output viewport /// The prebaked LUT for color grading and tonemapping. - void Render(RenderContext& renderContext, GPUTexture* input, GPUTexture* output, GPUTexture* colorGradingLUT); + void Render(RenderContext& renderContext, GPUTexture* input, GPUTextureView* output, const Viewport& outputViewport, GPUTexture* colorGradingLUT); private: #if COMPILE_WITH_DEV_ENV diff --git a/Source/Engine/Renderer/Renderer.cpp b/Source/Engine/Renderer/Renderer.cpp index 26897f054..5742f008c 100644 --- a/Source/Engine/Renderer/Renderer.cpp +++ b/Source/Engine/Renderer/Renderer.cpp @@ -188,7 +188,7 @@ void RenderLightBuffer(const SceneRenderTask* task, GPUContext* context, RenderC auto tempBuffer = RenderTargetPool::Get(tempDesc); RENDER_TARGET_POOL_SET_NAME(tempBuffer, "TempBuffer"); EyeAdaptationPass::Instance()->Render(renderContext, lightBuffer); - PostProcessingPass::Instance()->Render(renderContext, lightBuffer, tempBuffer, colorGradingLUT); + PostProcessingPass::Instance()->Render(renderContext, lightBuffer, tempBuffer->View(), Viewport(tempBuffer->Size()), colorGradingLUT); context->ResetRenderTarget(); if (renderContext.List->Settings.AntiAliasing.Mode == AntialiasingMode::TemporalAntialiasing) { @@ -790,7 +790,21 @@ PRAGMA_ENABLE_DEPRECATION_WARNINGS // Post-processing EyeAdaptationPass::Instance()->Render(renderContext, frameBuffer); - PostProcessingPass::Instance()->Render(renderContext, frameBuffer, tempBuffer, colorGradingLUT); + if (!useUpscaling && + !renderContext.List->HasAnyPostFx(renderContext, PostProcessEffectLocation::AfterAntiAliasingPass, MaterialPostFxLocation::AfterAntiAliasingPass) && + !renderContext.List->HasAnyPostFx(renderContext, PostProcessEffectLocation::Default, MaterialPostFxLocation::AfterPostProcessingPass) && + !renderContext.List->HasAnyPostFx(renderContext, MaterialPostFxLocation::AfterCustomPostEffects) && + renderContext.View.Mode != ViewMode::MotionVectors + ) + { + // PostFx -> Back Buffer + GPUTextureView* outputView = task->GetOutputView(); + PostProcessingPass::Instance()->Render(renderContext, frameBuffer, outputView, outputViewport, colorGradingLUT); + RenderTargetPool::Release(tempBuffer); + RenderTargetPool::Release(frameBuffer); + return; + } + PostProcessingPass::Instance()->Render(renderContext, frameBuffer, tempBuffer->View(), Viewport(tempBuffer->Size()), colorGradingLUT); Swap(frameBuffer, tempBuffer); // Cleanup