From 188428a7a9a089cb817bec3917e5d8ac8216b8fa Mon Sep 17 00:00:00 2001 From: Wojciech Figat Date: Wed, 14 Dec 2022 14:03:59 +0100 Subject: [PATCH] Add `RenderSetup` and allow customizing it by gameplay and postfx --- Source/Engine/Graphics/PostProcessEffect.h | 7 +++ Source/Engine/Graphics/RenderTask.h | 5 ++ Source/Engine/Graphics/RenderView.cpp | 2 +- Source/Engine/Renderer/AntiAliasing/TAA.cpp | 5 -- Source/Engine/Renderer/AntiAliasing/TAA.h | 8 --- .../GI/DynamicDiffuseGlobalIllumination.cpp | 2 +- Source/Engine/Renderer/MotionBlurPass.cpp | 2 +- Source/Engine/Renderer/RenderList.h | 6 +++ Source/Engine/Renderer/RenderSetup.h | 15 ++++++ Source/Engine/Renderer/Renderer.cpp | 51 ++++++++++++------- Source/Engine/Renderer/Renderer.h | 7 --- .../Renderer/ScreenSpaceReflectionsPass.cpp | 6 --- .../Renderer/ScreenSpaceReflectionsPass.h | 7 --- 13 files changed, 68 insertions(+), 55 deletions(-) create mode 100644 Source/Engine/Renderer/RenderSetup.h diff --git a/Source/Engine/Graphics/PostProcessEffect.h b/Source/Engine/Graphics/PostProcessEffect.h index c02e428f6..7e5ce96d2 100644 --- a/Source/Engine/Graphics/PostProcessEffect.h +++ b/Source/Engine/Graphics/PostProcessEffect.h @@ -44,6 +44,13 @@ public: return GetEnabled(); } + /// + /// Pre-rendering event called before scene rendering begin. Can be used to perform custom rendering or customize render view/setup. + /// + virtual void PreRender(GPUContext* context, RenderContext& renderContext) + { + } + /// /// Performs custom postFx rendering. /// diff --git a/Source/Engine/Graphics/RenderTask.h b/Source/Engine/Graphics/RenderTask.h index 4df61c9d0..3596f9f7e 100644 --- a/Source/Engine/Graphics/RenderTask.h +++ b/Source/Engine/Graphics/RenderTask.h @@ -371,6 +371,11 @@ public: /// The rendering context. virtual void OnPostRender(GPUContext* context, RenderContext& renderContext); + /// + /// The action called before any rendering to override/customize setup RenderSetup inside RenderList. Can be used to enable eg. Motion Vectors rendering. + /// + Delegate SetupRender; + public: /// /// Gets the rendering render task viewport (before upsampling). diff --git a/Source/Engine/Graphics/RenderView.cpp b/Source/Engine/Graphics/RenderView.cpp index 777b7595d..9776608ed 100644 --- a/Source/Engine/Graphics/RenderView.cpp +++ b/Source/Engine/Graphics/RenderView.cpp @@ -18,7 +18,7 @@ void RenderView::Prepare(RenderContext& renderContext) // Check if use TAA (need to modify the projection matrix) Float2 taaJitter; NonJitteredProjection = Projection; - if (renderContext.List->Settings.AntiAliasing.Mode == AntialiasingMode::TemporalAntialiasing) + if (renderContext.List->Setup.UseTemporalAAJitter) { // Move to the next frame const int MaxSampleCount = 8; diff --git a/Source/Engine/Renderer/AntiAliasing/TAA.cpp b/Source/Engine/Renderer/AntiAliasing/TAA.cpp index 63038ae27..c8730220a 100644 --- a/Source/Engine/Renderer/AntiAliasing/TAA.cpp +++ b/Source/Engine/Renderer/AntiAliasing/TAA.cpp @@ -63,11 +63,6 @@ void TAA::Dispose() _shader = nullptr; } -bool TAA::NeedMotionVectors(const RenderContext& renderContext) -{ - return renderContext.List->Settings.AntiAliasing.Mode == AntialiasingMode::TemporalAntialiasing; -} - void TAA::Render(const RenderContext& renderContext, GPUTexture* input, GPUTextureView* output) { auto context = GPUDevice::Instance->GetMainContext(); diff --git a/Source/Engine/Renderer/AntiAliasing/TAA.h b/Source/Engine/Renderer/AntiAliasing/TAA.h index 06951a638..e6bfe9f44 100644 --- a/Source/Engine/Renderer/AntiAliasing/TAA.h +++ b/Source/Engine/Renderer/AntiAliasing/TAA.h @@ -16,14 +16,6 @@ private: GPUPipelineState* _psTAA; public: - - /// - /// Determinates whenever this pass requires motion vectors rendering. - /// - /// The rendering context. - /// True if need to render motion vectors, otherwise false. - static bool NeedMotionVectors(const RenderContext& renderContext); - /// /// Performs AA pass rendering for the input task. /// diff --git a/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.cpp b/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.cpp index 25c98678d..2414ddeca 100644 --- a/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.cpp +++ b/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.cpp @@ -480,7 +480,7 @@ bool DynamicDiffuseGlobalIlluminationPass::RenderInner(RenderContext& renderCont auto& cascade = ddgiData.Cascades[cascadeIndex]; data.ProbeScrollClears[cascadeIndex] = Int4(cascade.ProbeScrollClears, 0); } - if (renderContext.List->Settings.AntiAliasing.Mode == AntialiasingMode::TemporalAntialiasing) + if (renderContext.List->Setup.UseTemporalAAJitter) { // Use temporal offset in the dithering factor (gets cleaned out by TAA) const float time = Time::Draw.UnscaledTime.GetTotalSeconds(); diff --git a/Source/Engine/Renderer/MotionBlurPass.cpp b/Source/Engine/Renderer/MotionBlurPass.cpp index f47132794..ba7b20569 100644 --- a/Source/Engine/Renderer/MotionBlurPass.cpp +++ b/Source/Engine/Renderer/MotionBlurPass.cpp @@ -162,7 +162,7 @@ void MotionBlurPass::RenderMotionVectors(RenderContext& renderContext) const int32 motionVectorsHeight = screenHeight / static_cast(settings.MotionVectorsResolution); // Ensure to have valid data - if (!Renderer::NeedMotionVectors(renderContext) || checkIfSkipPass()) + if (!renderContext.List->Setup.UseMotionVectors || checkIfSkipPass()) { // Skip pass (just clear motion vectors if texture is allocated) if (motionVectors->IsAllocated()) diff --git a/Source/Engine/Renderer/RenderList.h b/Source/Engine/Renderer/RenderList.h index 421f17dea..592d0d5ce 100644 --- a/Source/Engine/Renderer/RenderList.h +++ b/Source/Engine/Renderer/RenderList.h @@ -10,6 +10,7 @@ #include "DrawCall.h" #include "RenderListBuffer.h" #include "RendererAllocation.h" +#include "RenderSetup.h" enum class StaticFlags; class RenderBuffers; @@ -363,6 +364,11 @@ public: /// Array PostFx; + /// + /// The renderer setup for the frame drawing. + /// + RenderSetup Setup; + /// /// The post process settings. /// diff --git a/Source/Engine/Renderer/RenderSetup.h b/Source/Engine/Renderer/RenderSetup.h new file mode 100644 index 000000000..343f9dee0 --- /dev/null +++ b/Source/Engine/Renderer/RenderSetup.h @@ -0,0 +1,15 @@ +// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. + +#pragma once + +#include "Engine/Graphics/RenderTask.h" + +/// +/// The utility container for rendering setup configuration. Allows to properly decide about using certain render features (eg. motion vectors, TAA jitter) before rendering happens. +/// +struct FLAXENGINE_API RenderSetup +{ + RenderingUpscaleLocation UpscaleLocation = RenderingUpscaleLocation::AfterAntiAliasingPass; + bool UseMotionVectors = false; + bool UseTemporalAAJitter = false; +}; diff --git a/Source/Engine/Renderer/Renderer.cpp b/Source/Engine/Renderer/Renderer.cpp index 9396069f7..0ab25f6e5 100644 --- a/Source/Engine/Renderer/Renderer.cpp +++ b/Source/Engine/Renderer/Renderer.cpp @@ -5,6 +5,7 @@ #include "Engine/Graphics/RenderTargetPool.h" #include "Engine/Graphics/RenderBuffers.h" #include "Engine/Graphics/RenderTask.h" +#include "Engine/Graphics/PostProcessEffect.h" #include "Engine/Engine/EngineService.h" #include "GBufferPass.h" #include "ForwardPass.h" @@ -224,19 +225,6 @@ void Renderer::Render(SceneRenderTask* task) RenderList::ReturnToPool(e.List); } -bool Renderer::NeedMotionVectors(const RenderContext& renderContext) -{ - const int32 screenWidth = renderContext.Buffers->GetWidth(); - const int32 screenHeight = renderContext.Buffers->GetHeight(); - if (screenWidth < 16 || screenHeight < 16 || renderContext.Task->IsCameraCut) - return false; - MotionBlurSettings& motionBlurSettings = renderContext.List->Settings.MotionBlur; - return ((renderContext.View.Flags & ViewFlags::MotionBlur) != 0 && motionBlurSettings.Enabled && motionBlurSettings.Scale > ZeroTolerance) || - renderContext.View.Mode == ViewMode::MotionVectors || - ScreenSpaceReflectionsPass::NeedMotionVectors(renderContext) || - TAA::NeedMotionVectors(renderContext); -} - void Renderer::DrawSceneDepth(GPUContext* context, SceneRenderTask* task, GPUTexture* output, const Array& customActors) { CHECK(context && task && output && output->IsDepthStencil()); @@ -314,20 +302,45 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext, RenderCont aaMode = AntialiasingMode::None; // TODO: support TAA in ortho projection (see RenderView::Prepare to jitter projection matrix better) renderContext.List->Settings.AntiAliasing.Mode = aaMode; + // Initialize setup + RenderSetup& setup = renderContext.List->Setup; + { + PROFILE_CPU_NAMED("Setup"); + if (renderContext.View.Origin != renderContext.View.PrevOrigin) + renderContext.Task->CameraCut(); // Cut any temporal effects on rendering origin change + const int32 screenWidth = renderContext.Buffers->GetWidth(); + const int32 screenHeight = renderContext.Buffers->GetHeight(); + setup.UpscaleLocation = renderContext.Task->UpscaleLocation; + if (screenWidth < 16 || screenHeight < 16 || renderContext.Task->IsCameraCut) + setup.UseMotionVectors = false; + else + { + const MotionBlurSettings& motionBlurSettings = renderContext.List->Settings.MotionBlur; + const ScreenSpaceReflectionsSettings ssrSettings = renderContext.List->Settings.ScreenSpaceReflections; + setup.UseMotionVectors = ((renderContext.View.Flags & ViewFlags::MotionBlur) != 0 && motionBlurSettings.Enabled && motionBlurSettings.Scale > ZeroTolerance) || + renderContext.View.Mode == ViewMode::MotionVectors || + (ssrSettings.TemporalEffect && renderContext.View.Flags & ViewFlags::SSR) || + renderContext.List->Settings.AntiAliasing.Mode == AntialiasingMode::TemporalAntialiasing; + } + setup.UseTemporalAAJitter = aaMode == AntialiasingMode::TemporalAntialiasing; + + // Customize setup (by postfx or custom gameplay effects) + renderContext.Task->SetupRender(renderContext); + for (PostProcessEffect* e : renderContext.List->PostFx) + e->PreRender(context, renderContext); + } + // Prepare renderContext.View.Prepare(renderContext); - if (renderContext.View.Origin != renderContext.View.PrevOrigin) - renderContext.Task->CameraCut(); // Cut any temporal effects on rendering origin change renderContext.Buffers->Prepare(); // Build batch of render contexts (main view and shadow projections) const bool isGBufferDebug = GBufferPass::IsDebugView(renderContext.View.Mode); - const bool needMotionVectors = Renderer::NeedMotionVectors(renderContext); { PROFILE_CPU_NAMED("Collect Draw Calls"); view.Pass = DrawPass::GBuffer | DrawPass::Forward | DrawPass::Distortion; - if (needMotionVectors) + if (setup.UseMotionVectors) view.Pass |= DrawPass::MotionVectors; renderContextBatch.GetMainContext() = renderContext; // Sync render context in batch with the current value @@ -372,7 +385,7 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext, RenderCont renderContext.List->SortDrawCalls(renderContext, false, DrawCallsListType::GBufferNoDecals); renderContext.List->SortDrawCalls(renderContext, true, DrawCallsListType::Forward); renderContext.List->SortDrawCalls(renderContext, false, DrawCallsListType::Distortion); - if (needMotionVectors) + if (setup.UseMotionVectors) renderContext.List->SortDrawCalls(renderContext, false, DrawCallsListType::MotionVectors); for (int32 i = 1; i < renderContextBatch.Contexts.Count(); i++) { @@ -555,7 +568,7 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext, RenderCont // Upscaling after scene rendering but before post processing bool useUpscaling = task->RenderingPercentage < 1.0f; const Viewport outputViewport = task->GetOutputViewport(); - if (useUpscaling && task->UpscaleLocation == RenderingUpscaleLocation::BeforePostProcessingPass) + if (useUpscaling && setup.UpscaleLocation == RenderingUpscaleLocation::BeforePostProcessingPass) { useUpscaling = false; RenderTargetPool::Release(tempBuffer); diff --git a/Source/Engine/Renderer/Renderer.h b/Source/Engine/Renderer/Renderer.h index 8f98f5335..7f470407e 100644 --- a/Source/Engine/Renderer/Renderer.h +++ b/Source/Engine/Renderer/Renderer.h @@ -33,13 +33,6 @@ public: /// The scene rendering task. static void Render(SceneRenderTask* task); - /// - /// Determinates whenever any pass requires motion vectors rendering. - /// - /// The rendering context. - /// True if need to render motion vectors, otherwise false. - static bool NeedMotionVectors(const RenderContext& renderContext); - public: /// diff --git a/Source/Engine/Renderer/ScreenSpaceReflectionsPass.cpp b/Source/Engine/Renderer/ScreenSpaceReflectionsPass.cpp index ce7e6e3f3..2614d9f63 100644 --- a/Source/Engine/Renderer/ScreenSpaceReflectionsPass.cpp +++ b/Source/Engine/Renderer/ScreenSpaceReflectionsPass.cpp @@ -55,12 +55,6 @@ PACK_STRUCT(struct Data GlobalSurfaceAtlasPass::ConstantsData GlobalSurfaceAtlas; }); -bool ScreenSpaceReflectionsPass::NeedMotionVectors(const RenderContext& renderContext) -{ - auto& settings = renderContext.List->Settings.ScreenSpaceReflections; - return settings.TemporalEffect && renderContext.View.Flags & ViewFlags::SSR; -} - String ScreenSpaceReflectionsPass::ToString() const { return TEXT("ScreenSpaceReflectionsPass"); diff --git a/Source/Engine/Renderer/ScreenSpaceReflectionsPass.h b/Source/Engine/Renderer/ScreenSpaceReflectionsPass.h index 8d38fd40d..84bdc8f42 100644 --- a/Source/Engine/Renderer/ScreenSpaceReflectionsPass.h +++ b/Source/Engine/Renderer/ScreenSpaceReflectionsPass.h @@ -36,13 +36,6 @@ private: AssetReference _preIntegratedGF; public: - /// - /// Determinates whenever this pass requires motion vectors rendering. - /// - /// The rendering context. - /// True if need to render motion vectors, otherwise false. - static bool NeedMotionVectors(const RenderContext& renderContext); - /// /// Perform SSR rendering for the input task (blends reflections to given texture using alpha blending). ///