From 05ebbe744851f3296a2b83aa832352d17fc3744c Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 13 Aug 2026 11:26:27 +0200 Subject: [PATCH] Add new temporal upsampling option (TAAU) when using location `DuringAntiAliasing` Refactor `RenderingUpscaleLocation` enum item names. --- Content/Shaders/TAA.flax | 4 +- .../Editor/Windows/GraphicsQualityWindow.cs | 2 +- Source/Engine/Graphics/RenderTask.h | 11 ++++-- Source/Engine/Renderer/AntiAliasing/TAA.cpp | 23 ++++++------ Source/Engine/Renderer/AntiAliasing/TAA.h | 2 +- Source/Engine/Renderer/RenderSetup.h | 2 +- Source/Engine/Renderer/Renderer.cpp | 37 ++++++++++++++----- Source/Shaders/TAA.shader | 22 +++++------ 8 files changed, 64 insertions(+), 39 deletions(-) diff --git a/Content/Shaders/TAA.flax b/Content/Shaders/TAA.flax index 6b435c407..03b4f101d 100644 --- a/Content/Shaders/TAA.flax +++ b/Content/Shaders/TAA.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:02bd5d36064ed0f6855b302dfcf9745cbafac1992c1a012b3c4c1d003a32b434 -size 9238 +oid sha256:90444dccb05f8ae91098dfec2b8827939d34e221a110e2e8b16ab029ab94d901 +size 9315 diff --git a/Source/Editor/Windows/GraphicsQualityWindow.cs b/Source/Editor/Windows/GraphicsQualityWindow.cs index 02e2da9bf..6bf9e9d28 100644 --- a/Source/Editor/Windows/GraphicsQualityWindow.cs +++ b/Source/Editor/Windows/GraphicsQualityWindow.cs @@ -104,7 +104,7 @@ namespace FlaxEditor.Windows set => MainRenderTask.Instance.RenderScale = value; } - [NoSerialize, DefaultValue(RenderingUpscaleLocation.AfterAntiAliasingPass), VisibleIf(nameof(UpscaleLocation_Visible))] + [NoSerialize, DefaultValue(RenderingUpscaleLocation.DuringAntiAliasing), VisibleIf(nameof(UpscaleLocation_Visible))] [EditorOrder(1401), EditorDisplay("Quality")] [Tooltip("The image resolution upscale location within rendering pipeline.")] public RenderingUpscaleLocation UpscaleLocation diff --git a/Source/Engine/Graphics/RenderTask.h b/Source/Engine/Graphics/RenderTask.h index 770d59a2e..bf912f7c8 100644 --- a/Source/Engine/Graphics/RenderTask.h +++ b/Source/Engine/Graphics/RenderTask.h @@ -206,12 +206,17 @@ API_ENUM() enum class RenderingUpscaleLocation /// /// The up-scaling happens directly to the output buffer (backbuffer) after post processing and anti-aliasing. /// - AfterAntiAliasingPass = 0, + AfterAntiAliasing = 0, /// /// The up-scaling happens before the post processing after scene rendering (after geometry, lighting, volumetrics, transparency and SSR/SSAO). /// - BeforePostProcessingPass = 1, + BeforePostProcessing = 1, + + /// + /// The up-scaling happens during anti-aliasing. For example, when using Temporal Anti-Aliasing (TAA) it work as Temporal Anti-Aliasing Upsampling (TAAU) to both remove aliasing and upscale the image. + /// + DuringAntiAliasing = 2, }; /// @@ -285,7 +290,7 @@ public: /// /// The image resolution upscale location within rendering pipeline. Unused if RenderingPercentage is 1. /// - API_FIELD() RenderingUpscaleLocation UpscaleLocation = RenderingUpscaleLocation::AfterAntiAliasingPass; + API_FIELD() RenderingUpscaleLocation UpscaleLocation = RenderingUpscaleLocation::DuringAntiAliasing; public: /// diff --git a/Source/Engine/Renderer/AntiAliasing/TAA.cpp b/Source/Engine/Renderer/AntiAliasing/TAA.cpp index f904f98cd..d404a6ea0 100644 --- a/Source/Engine/Renderer/AntiAliasing/TAA.cpp +++ b/Source/Engine/Renderer/AntiAliasing/TAA.cpp @@ -58,24 +58,26 @@ void TAA::Dispose() _shader = nullptr; } -void TAA::Render(const RenderContext& renderContext, GPUTexture* input, GPUTextureView* output) +void TAA::Render(const RenderContext& renderContext, GPUTexture* input, GPUTexture* output) { + auto viewport = Viewport(0, 0, (float)output->Width(), (float)output->Height()); + auto inputSize = Float2((float)input->Width(), (float)input->Height()); auto context = GPUDevice::Instance->GetMainContext(); if (checkIfSkipPass()) { // Resources are missing. Do not perform rendering, just copy source frame. - context->SetRenderTarget(output); + context->SetViewportAndScissors(viewport); + context->SetRenderTarget(output->View()); context->Draw(input); return; } const auto& settings = renderContext.List->Settings.AntiAliasing; - PROFILE_GPU_CPU("Temporal Antialiasing"); // Get history buffers bool resetHistory = renderContext.Task->IsCameraCut; renderContext.Buffers->LastFrameTemporalAA = Engine::FrameCount; - const auto tempDesc = GPUTextureDescription::New2D(input->Width(), input->Height(), input->Format()); + const auto tempDesc = GPUTextureDescription::New2D(output->Width(), output->Height(), output->Format()); if (renderContext.Buffers->TemporalAA == nullptr) { // Missing temporal buffer @@ -99,13 +101,11 @@ void TAA::Render(const RenderContext& renderContext, GPUTexture* input, GPUTextu float blendStrength = 1.0f; if (resetHistory) { -#if 0 - context->CopyTexture(inputHistory, 0, 0, 0, 0, input, 0); -#else + context->SetViewportAndScissors(viewport); context->SetRenderTarget(inputHistory->View()); + // TODO: when using upscalimg, copu history via MultiScaler to reduce aliasing context->Draw(input); context->ResetRenderTarget(); -#endif blendStrength = 0.0f; } @@ -113,8 +113,8 @@ void TAA::Render(const RenderContext& renderContext, GPUTexture* input, GPUTextu Data data; data.ScreenSizeInv.X = renderContext.View.ScreenSize.Z; data.ScreenSizeInv.Y = renderContext.View.ScreenSize.W; - data.JitterInv.X = renderContext.View.TemporalAAJitter.X / (float)tempDesc.Width; - data.JitterInv.Y = renderContext.View.TemporalAAJitter.Y / (float)tempDesc.Height; + data.JitterInv.X = renderContext.View.TemporalAAJitter.X / inputSize.X; + data.JitterInv.Y = renderContext.View.TemporalAAJitter.Y / inputSize.Y; data.Sharpness = settings.TAA_Sharpness * 3; // Hardcoded scale data.StationaryBlending = settings.TAA_StationaryBlending * blendStrength; data.MotionBlending = settings.TAA_MotionBlending * blendStrength; @@ -130,7 +130,8 @@ void TAA::Render(const RenderContext& renderContext, GPUTexture* input, GPUTextu context->BindSR(3, renderContext.Buffers->DepthBuffer); // Render - context->SetRenderTarget(output); + context->SetViewportAndScissors(viewport); + context->SetRenderTarget(output->View()); int qualityLevel; switch (Graphics::AAQuality) { diff --git a/Source/Engine/Renderer/AntiAliasing/TAA.h b/Source/Engine/Renderer/AntiAliasing/TAA.h index 52826feaa..9d029cc33 100644 --- a/Source/Engine/Renderer/AntiAliasing/TAA.h +++ b/Source/Engine/Renderer/AntiAliasing/TAA.h @@ -21,7 +21,7 @@ public: /// The rendering context. /// The input render target. /// The output render target. - void Render(const RenderContext& renderContext, GPUTexture* input, GPUTextureView* output); + void Render(const RenderContext& renderContext, GPUTexture* input, GPUTexture* output); private: #if COMPILE_WITH_DEV_ENV diff --git a/Source/Engine/Renderer/RenderSetup.h b/Source/Engine/Renderer/RenderSetup.h index b5a04b51f..1838f5bbd 100644 --- a/Source/Engine/Renderer/RenderSetup.h +++ b/Source/Engine/Renderer/RenderSetup.h @@ -9,7 +9,7 @@ /// struct FLAXENGINE_API RenderSetup { - RenderingUpscaleLocation UpscaleLocation = RenderingUpscaleLocation::AfterAntiAliasingPass; + RenderingUpscaleLocation UpscaleLocation = RenderingUpscaleLocation::DuringAntiAliasing; bool UseShadows = false; bool UseMotionVectors = false; bool UseTemporalAAJitter = false; diff --git a/Source/Engine/Renderer/Renderer.cpp b/Source/Engine/Renderer/Renderer.cpp index 614bdc342..983a07fd8 100644 --- a/Source/Engine/Renderer/Renderer.cpp +++ b/Source/Engine/Renderer/Renderer.cpp @@ -192,7 +192,7 @@ void RenderLightBuffer(const SceneRenderTask* task, GPUContext* context, RenderC context->ResetRenderTarget(); if (renderContext.List->Settings.AntiAliasing.Mode == AntialiasingMode::TemporalAntialiasing) { - TAA::Instance()->Render(renderContext, tempBuffer, lightBuffer->View()); + TAA::Instance()->Render(renderContext, tempBuffer, lightBuffer); Swap(lightBuffer, tempBuffer); } RenderTargetPool::Release(lightBuffer); @@ -387,6 +387,8 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext, RenderCont const int32 screenWidth = renderContext.Buffers->GetWidth(); const int32 screenHeight = renderContext.Buffers->GetHeight(); setup.UpscaleLocation = renderContext.Task->UpscaleLocation; + if (setup.UpscaleLocation == RenderingUpscaleLocation::DuringAntiAliasing && renderContext.List->Settings.AntiAliasing.Mode != AntialiasingMode::TemporalAntialiasing) + setup.UpscaleLocation = RenderingUpscaleLocation::AfterAntiAliasing; // Fall-back when AA doesn't support uplscaling setup.UseShadows = !isGBufferDebug && EnumHasAnyFlags(view.Flags, ViewFlags::Shadows) && ShadowsPass::Instance()->IsReady(); switch (renderContext.View.Mode) { @@ -750,18 +752,35 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext, RenderCont renderContext.List->RunCustomPostFxPass(context, renderContext, PostProcessEffectLocation::BeforePostProcessingPass, frameBuffer, tempBuffer); // Temporal Anti-Aliasing (goes before post processing) - if (renderContext.List->Settings.AntiAliasing.Mode == AntialiasingMode::TemporalAntialiasing) - { - TAA::Instance()->Render(renderContext, frameBuffer, tempBuffer->View()); - Swap(frameBuffer, tempBuffer); - } - - // Upscaling after scene rendering but before post-processing PRAGMA_DISABLE_DEPRECATION_WARNINGS bool useUpscaling = task->RenderingPercentage * task->RenderScale < 1.0f; PRAGMA_ENABLE_DEPRECATION_WARNINGS const Viewport outputViewport = task->GetOutputViewport(); - if (useUpscaling && setup.UpscaleLocation == RenderingUpscaleLocation::BeforePostProcessingPass) + if (renderContext.List->Settings.AntiAliasing.Mode == AntialiasingMode::TemporalAntialiasing) + { + if (useUpscaling && setup.UpscaleLocation == RenderingUpscaleLocation::DuringAntiAliasing) + { + // TAAU + useUpscaling = false; + RenderTargetPool::Release(tempBuffer); + tempDesc.Width = (int32)outputViewport.Width; + tempDesc.Height = (int32)outputViewport.Height; + tempBuffer = RenderTargetPool::Get(tempDesc); + context->ResetSR(); + TAA::Instance()->Render(renderContext, frameBuffer, tempBuffer); + RenderTargetPool::Release(frameBuffer); + frameBuffer = RenderTargetPool::Get(tempDesc); + } + else + { + // TAA + TAA::Instance()->Render(renderContext, frameBuffer, tempBuffer); + } + Swap(frameBuffer, tempBuffer); + } + + // Upscaling after scene rendering but before post-processing + if (useUpscaling && setup.UpscaleLocation == RenderingUpscaleLocation::BeforePostProcessing) { useUpscaling = false; RenderTargetPool::Release(tempBuffer); diff --git a/Source/Shaders/TAA.shader b/Source/Shaders/TAA.shader index d4e08bcf5..f41613d0b 100644 --- a/Source/Shaders/TAA.shader +++ b/Source/Shaders/TAA.shader @@ -160,9 +160,9 @@ float4 PS(Quad_VS2PS input) : SV_Target0 // Sample image and history #if UNJITTER_INPUT - float4 current = SAMPLE_RT(Input, input.TexCoord - JitterInv.xy); + float4 current = SAMPLE_RT_LINEAR(Input, input.TexCoord - JitterInv.xy); #else - float4 current = SAMPLE_RT(Input, input.TexCoord); + float4 current = SAMPLE_RT_LINEAR(Input, input.TexCoord); #endif float4 history = SAMPLE_RT_LINEAR(InputHistory, input.TexCoord - velocityDepth.xy); @@ -176,15 +176,15 @@ float4 PS(Quad_VS2PS input) : SV_Target0 float2 du = float2(ScreenSizeInv.x, 0.0); float2 dv = float2(0.0, ScreenSizeInv.y); - float4 ctl = SAMPLE_RT(Input, uv - dv - du); - float4 ctc = SAMPLE_RT(Input, uv - dv); - float4 ctr = SAMPLE_RT(Input, uv - dv + du); - float4 cml = SAMPLE_RT(Input, uv - du); - float4 cmc = SAMPLE_RT(Input, uv); - float4 cmr = SAMPLE_RT(Input, uv + du); - float4 cbl = SAMPLE_RT(Input, uv + dv - du); - float4 cbc = SAMPLE_RT(Input, uv + dv); - float4 cbr = SAMPLE_RT(Input, uv + dv + du); + float4 ctl = SAMPLE_RT_LINEAR(Input, uv - dv - du); + float4 ctc = SAMPLE_RT_LINEAR(Input, uv - dv); + float4 ctr = SAMPLE_RT_LINEAR(Input, uv - dv + du); + float4 cml = SAMPLE_RT_LINEAR(Input, uv - du); + float4 cmc = SAMPLE_RT_LINEAR(Input, uv); + float4 cmr = SAMPLE_RT_LINEAR(Input, uv + du); + float4 cbl = SAMPLE_RT_LINEAR(Input, uv + dv - du); + float4 cbc = SAMPLE_RT_LINEAR(Input, uv + dv); + float4 cbr = SAMPLE_RT_LINEAR(Input, uv + dv + du); float4 cMin = min(ctl, min(ctc, min(ctr, min(cml, min(cmc, min(cmr, min(cbl, min(cbc, cbr)))))))); float4 cMax = max(ctl, max(ctc, max(ctr, max(cml, max(cmc, max(cmr, max(cbl, max(cbc, cbr))))))));