// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. #pragma once #include "Engine/Core/Delegate.h" #include "Engine/Core/Math/Viewport.h" #include "Engine/Core/Collections/Array.h" #include "Engine/Platform/CriticalSection.h" #include "Engine/Scripting/ScriptingObjectReference.h" #include "Engine/Scripting/ScriptingType.h" #include "Engine/Renderer/RendererAllocation.h" #include "RenderView.h" class GPUDevice; class GPUContext; class GPUTexture; class GPUTextureView; class GPUSwapChain; class RenderBuffers; class PostProcessEffect; struct RenderContext; class Camera; class Actor; class Scene; /// /// Allows to perform custom rendering using graphics pipeline. /// API_CLASS() class FLAXENGINE_API RenderTask : public ScriptingObject { DECLARE_SCRIPTING_TYPE(RenderTask); /// /// List with all registered tasks /// static Array Tasks; /// /// Static locker for render tasks list /// static CriticalSection TasksLocker; /// /// Amount of tasks rendered during last frame /// static int32 TasksDoneLastFrame; /// /// Draws all tasks. Called only during rendering by the graphics device. /// static void DrawAll(); private: RenderTask* _prevTask = nullptr; public: /// /// Finalizes an instance of the class. /// virtual ~RenderTask(); public: /// /// Gets or sets a value indicating whether task is enabled. /// API_FIELD() bool Enabled = true; /// /// The order of the task. Used for tasks rendering order. Lower first, higher later. /// API_FIELD() int32 Order = 0; /// /// The amount of frames rendered by this task. It is auto incremented on task drawing. /// API_FIELD(ReadOnly) int32 FrameCount = 0; /// /// The output window swap chain. Optional, used only when rendering to native window backbuffer. /// GPUSwapChain* SwapChain = nullptr; /// /// The index of the frame when this task was last time rendered. /// API_FIELD(ReadOnly) uint64 LastUsedFrame = 0; /// /// Action fired on task rendering. /// API_EVENT() Delegate Render; /// /// Action fired on task rendering begin. /// API_EVENT() Delegate Begin; /// /// Action fired on task rendering end. /// API_EVENT() Delegate End; /// /// Action fired just after frame present. /// API_EVENT() Delegate Present; /// /// Determines whether this task can be rendered. /// /// true if this task can be rendered; otherwise, false. API_PROPERTY() virtual bool CanDraw() const; /// /// Called by graphics device to draw this task. Can be used to invoke task rendering nested inside another task - use on own risk! /// API_FUNCTION() virtual void OnDraw(); /// /// Called on task rendering begin. /// /// The GPU context. virtual void OnBegin(GPUContext* context); /// /// Called on task rendering. /// /// The GPU context. virtual void OnRender(GPUContext* context); /// /// Called on task rendering end. /// /// The GPU context. virtual void OnEnd(GPUContext* context); /// /// Presents frame to the output. /// /// True if use vertical synchronization to lock frame rate. virtual void OnPresent(bool vsync); /// /// Changes the buffers and output size. Does nothing if size won't change. Called by window or user to resize rendering buffers. /// /// The width. /// The height. /// True if cannot resize the buffers. API_FUNCTION() virtual bool Resize(int32 width, int32 height); public: bool operator<(const RenderTask& other) const { return Order < other.Order; } }; /// /// Defines actors to draw sources. /// API_ENUM(Attributes="Flags") enum class ActorsSources { /// /// The actors won't be rendered. /// None = 0, /// /// The actors from the loaded scenes. /// Scenes = 1, /// /// The actors from the custom collection. /// CustomActors = 2, /// /// The scenes from the custom collection. /// CustomScenes = 4, /// /// The actors from the loaded scenes and custom collection. /// ScenesAndCustomActors = Scenes | CustomActors, }; DECLARE_ENUM_OPERATORS(ActorsSources); /// /// The Post Process effect rendering location within the rendering pipeline. /// API_ENUM() enum class RenderingUpscaleLocation { /// /// The up-scaling happens directly to the output buffer (backbuffer) after post processing and anti-aliasing. /// AfterAntiAliasingPass = 0, /// /// The up-scaling happens before the post processing after scene rendering (after geometry, lighting, volumetrics, transparency and SSR/SSAO). /// BeforePostProcessingPass = 1, }; /// /// Render task which draws scene actors into the output buffer. /// /// API_CLASS() class FLAXENGINE_API SceneRenderTask : public RenderTask { DECLARE_SCRIPTING_TYPE(SceneRenderTask); protected: class SceneRendering* _customActorsScene = nullptr; public: /// /// Finalizes an instance of the class. /// ~SceneRenderTask(); public: /// /// True if the current frame is after the camera cut. Used to clear the temporal effects history and prevent visual artifacts blended from the previous frames. /// bool IsCameraCut = true; /// /// True if the task is used for custom scene rendering and default scene drawing into output should be skipped. Enable it if you use Render event and draw scene manually. /// API_FIELD() bool IsCustomRendering = false; /// /// Marks the next rendered frame as camera cut. Used to clear the temporal effects history and prevent visual artifacts blended from the previous frames. /// API_FUNCTION() void CameraCut(); /// /// The output texture (can be null if using rendering to window swap chain). Can be used to redirect the default scene rendering output to a texture. /// API_FIELD() GPUTexture* Output = nullptr; /// /// The scene rendering buffers. Created and managed by the task. /// API_FIELD(ReadOnly) RenderBuffers* Buffers = nullptr; /// /// The scene rendering camera. Can be used to override the rendering view properties based on the current camera setup. /// API_FIELD() ScriptingObjectReference Camera; /// /// The render view description. /// API_FIELD() RenderView View; /// /// The actors source to use (configures what objects to render). /// API_FIELD() ActorsSources ActorsSource = ActorsSources::Scenes; /// /// The scale of the rendering resolution relative to the output dimensions. If lower than 1 the scene and postprocessing will be rendered at a lower resolution and upscaled to the output backbuffer. /// API_FIELD() float RenderingPercentage = 1.0f; /// /// The image resolution upscale location within rendering pipeline. Unused if RenderingPercentage is 1. /// API_FIELD() RenderingUpscaleLocation UpscaleLocation = RenderingUpscaleLocation::AfterAntiAliasingPass; public: /// /// The custom set of actors to render. Used when ActorsSources::CustomActors flag is active. /// API_FIELD() Array CustomActors; /// /// The custom set of scenes to render. Used when ActorsSources::CustomScenes flag is active. /// API_FIELD() Array CustomScenes; /// /// Adds the custom actor to the rendering. /// /// The actor. API_FUNCTION() void AddCustomActor(Actor* actor); /// /// Removes the custom actor from the rendering. /// /// The actor. API_FUNCTION() void RemoveCustomActor(Actor* actor); /// /// Removes all the custom actors from the rendering. /// API_FUNCTION() void ClearCustomActors(); public: /// /// The custom set of postfx to render. /// Array CustomPostFx; /// /// Adds the custom postfx to the rendering. /// /// The postfx script. API_FUNCTION() void AddCustomPostFx(PostProcessEffect* fx); /// /// Removes the custom postfx from the rendering. /// /// The postfx script. API_FUNCTION() void RemoveCustomPostFx(PostProcessEffect* fx); /// /// True if allow using global custom PostFx when rendering this task. /// API_FIELD() bool AllowGlobalCustomPostFx = true; /// /// The custom set of global postfx to render for all (applied to tasks that have turned on). /// static Array GlobalCustomPostFx; /// /// Adds the custom global postfx to the rendering. /// /// The postfx script. API_FUNCTION() static void AddGlobalCustomPostFx(PostProcessEffect* fx); /// /// Removes the custom global postfx from the rendering. /// /// The postfx script. API_FUNCTION() static void RemoveGlobalCustomPostFx(PostProcessEffect* fx); public: /// /// The action called on view rendering to collect draw calls. It allows to extend rendering pipeline and draw custom geometry non-existing in the scene or custom actors set. /// API_EVENT() Delegate CollectDrawCalls; /// /// Calls collecting postFx volumes for rendering. /// /// The rendering context. virtual void CollectPostFxVolumes(RenderContext& renderContext); /// /// Calls drawing scene objects. /// /// The rendering context batch. /// The actors category to draw (see SceneRendering::DrawCategory). virtual void OnCollectDrawCalls(RenderContextBatch& renderContextBatch, byte category = 0); /// /// The action called after scene rendering. Can be used to perform custom pre-rendering or to modify the render view. /// API_EVENT() Delegate PreRender; /// /// Called before scene rendering. Can be used to perform custom pre-rendering or to modify the render view. /// /// The GPU commands context. /// The rendering context. virtual void OnPreRender(GPUContext* context, RenderContext& renderContext); /// /// The action called after scene rendering. Can be used to render additional visual elements to the output. /// API_EVENT() Delegate PostRender; /// /// Called after scene rendering. Can be used to render additional visual elements to the output. /// /// The GPU commands context. /// 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). /// API_PROPERTY() Viewport GetViewport() const; /// /// Gets the rendering output viewport (after upsampling). /// API_PROPERTY() Viewport GetOutputViewport() const; /// /// Gets the rendering output view. /// API_PROPERTY() GPUTextureView* GetOutputView() const; public: // [RenderTask] bool Resize(int32 width, int32 height) override; bool CanDraw() const override; void OnBegin(GPUContext* context) override; void OnRender(GPUContext* context) override; void OnEnd(GPUContext* context) override; }; /// /// The main game rendering task used by the engine. /// /// /// For Main Render Task its may be null because game can be rendered directly to the native window backbuffer. /// This allows to increase game rendering performance (reduced memory usage and data transfer). /// User should use post effects pipeline to modify the final frame. /// /// API_CLASS() class FLAXENGINE_API MainRenderTask : public SceneRenderTask { DECLARE_SCRIPTING_TYPE(MainRenderTask); /// /// Finalizes an instance of the class. /// ~MainRenderTask(); public: /// /// Gets the main game rendering task. Use it to plug custom rendering logic for your game. /// API_FIELD(ReadOnly) static MainRenderTask* Instance; public: // [SceneRenderTask] void OnBegin(GPUContext* context) override; }; /// /// The high-level renderer context. Used to collect the draw calls for the scene rendering. Can be used to perform a custom rendering. /// API_STRUCT(NoDefault) struct RenderContext { DECLARE_SCRIPTING_TYPE_MINIMAL(RenderContext); /// /// The render buffers. /// API_FIELD() RenderBuffers* Buffers = nullptr; /// /// The render list. /// API_FIELD() RenderList* List = nullptr; /// /// The scene rendering task that is a source of renderable objects (optional). /// API_FIELD() SceneRenderTask* Task = nullptr; /// /// The proxy render view used to synchronize objects level of detail during rendering (eg. during shadow maps rendering passes). It's optional. /// API_FIELD() RenderView* LodProxyView = nullptr; /// /// The render view. /// API_FIELD() RenderView View; /// /// The GPU access locking critical section to protect data access when performing multi-threaded rendering. /// static CriticalSection GPULocker; RenderContext() = default; RenderContext(SceneRenderTask* task) noexcept; }; /// /// The high-level renderer context batch that encapsulates multiple rendering requests within a single task (eg. optimize main view scene rendering and shadow projections at once). /// API_STRUCT(NoDefault) struct RenderContextBatch { DECLARE_SCRIPTING_TYPE_MINIMAL(RenderContextBatch); /// /// The render buffers. /// API_FIELD() RenderBuffers* Buffers = nullptr; /// /// The scene rendering task that is a source of renderable objects (optional). /// API_FIELD() SceneRenderTask* Task = nullptr; /// /// The all render views collection for the current rendering (main view, shadow projections, etc.). /// API_FIELD() Array Contexts; /// /// The Job System labels to wait on, after draw calls collecting. /// API_FIELD() Array> WaitLabels; /// /// Enables using async tasks via Job System when performing drawing. /// API_FIELD() bool EnableAsync = true; RenderContextBatch() = default; RenderContextBatch(SceneRenderTask* task); RenderContextBatch(const RenderContext& context); FORCE_INLINE RenderContext& GetMainContext() { return Contexts.Get()[0]; } FORCE_INLINE const RenderContext& GetMainContext() const { return Contexts.Get()[0]; } };