// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "MoviePipelineRenderPass.h" #include "MovieRenderPipelineDataTypes.h" #include "SceneTypes.h" #include "SceneView.h" #include "MoviePipelineSurfaceReader.h" #include "UObject/GCObject.h" #include "Async/AsyncWork.h" #include "Async/TaskGraphInterfaces.h" #include "HAL/ThreadSafeBool.h" #include "Templates/Function.h" #include "Stats/Stats.h" #include "CanvasTypes.h" #include "MovieRenderPipelineCoreModule.h" #include "OpenColorIODisplayExtension.h" #include "MoviePipelineImagePassBase.generated.h" class UTextureRenderTarget2D; struct FImageOverlappedAccumulator; class FSceneViewFamily; class FSceneView; struct FAccumulatorPool; namespace UE { namespace MoviePipeline { struct FImagePassCameraViewData { FImagePassCameraViewData() : ViewActor(nullptr) , bUseCustomProjectionMatrix(false) {} FMinimalViewInfo ViewInfo; TMap FileMetadata; AActor* ViewActor; bool bUseCustomProjectionMatrix; FMatrix CustomProjectionMatrix; }; } } class FMoviePipelineBackgroundAccumulateTask { public: FGraphEventRef LastCompletionEvent; public: FGraphEventRef Execute(TUniqueFunction InFunctor) { if (LastCompletionEvent) { LastCompletionEvent = FFunctionGraphTask::CreateAndDispatchWhenReady(MoveTemp(InFunctor), GetStatId(), LastCompletionEvent); } else { LastCompletionEvent = FFunctionGraphTask::CreateAndDispatchWhenReady(MoveTemp(InFunctor), GetStatId()); } return LastCompletionEvent; } FORCEINLINE TStatId GetStatId() const { RETURN_QUICK_DECLARE_CYCLE_STAT(FMoviePipelineBackgroundAccumulateTask, STATGROUP_ThreadPoolAsyncTasks); } }; namespace MoviePipeline { /** Describes the data required to clear the letterbox pixels outside the active pixel area */ struct FLetterboxData { /** Active pixel area of the full frame within channel plane dimensions. i.e. Region not letterboxed */ FIntRect FrameActiveArea; /** True if letterboxing is active and drawing the border was deferred */ bool bDrawLetterboxBorder; /** Left sample pixels already cleared that should therefore not be sampled */ int32 LeftSamplePixelsClearedBeforeAccumulation; /** Right sample pixels already cleared that should therefore not be sampled */ int32 RightSamplePixelsClearedBeforeAccumulation; /** Top sample pixels already cleared that should therefore not be sampled */ int32 TopSamplePixelsClearedBeforeAccumulation; /** Bottom sample pixels already cleared that should therefore not be sampled */ int32 BottomSamplePixelsClearedBeforeAccumulation; FLetterboxData() : bDrawLetterboxBorder(false) , LeftSamplePixelsClearedBeforeAccumulation(0) , RightSamplePixelsClearedBeforeAccumulation(0) , TopSamplePixelsClearedBeforeAccumulation(0) , BottomSamplePixelsClearedBeforeAccumulation(0) {}; }; struct FImageSampleAccumulationArgs { public: TWeakPtr ImageAccumulator; TWeakPtr OutputMerger; bool bAccumulateAlpha; /** Contains the data needed for clearing the letterbox area */ FLetterboxData LetterboxData; }; void MOVIERENDERPIPELINERENDERPASSES_API AccumulateSample_TaskThread(TUniquePtr&& InPixelData, const MoviePipeline::FImageSampleAccumulationArgs& InParams); } UCLASS(BlueprintType, Abstract) class MOVIERENDERPIPELINERENDERPASSES_API UMoviePipelineImagePassBase : public UMoviePipelineRenderPass { GENERATED_BODY() public: UMoviePipelineImagePassBase() : UMoviePipelineRenderPass() , bAllowCameraAspectRatio(true) { PassIdentifier = FMoviePipelinePassIdentifier("ImagePassBase"); } /* Dummy interface to allow classes with overriden functiosn to pass their own data around. */ struct IViewCalcPayload {}; protected: // UMoviePipelineRenderPass API virtual void OnFrameStartImpl() override; virtual void GatherOutputPassesImpl(TArray& ExpectedRenderPasses) override; virtual void SetupImpl(const MoviePipeline::FMoviePipelineRenderPassInitSettings& InPassInitSettings) override; virtual void RenderSample_GameThreadImpl(const FMoviePipelineRenderPassMetrics& InSampleState) override; virtual void WaitUntilTasksComplete() override; virtual void TeardownImpl() override; // ~UMovieRenderPassAPI // FGCObject Interface static void AddReferencedObjects(UObject* InThis, FReferenceCollector& Collector); // ~FGCObject Interface FVector4 CalculatePrinciplePointOffsetForTiling(const FMoviePipelineRenderPassMetrics& InSampleState) const; virtual void ModifyProjectionMatrixForTiling(const FMoviePipelineRenderPassMetrics& InSampleState, const bool bInOrthographic, FMatrix& InOutProjectionMatrix, float& OutDoFSensorScale) const; virtual FMatrix CalcCubeFaceTransform(ECubeFace Face) const final; protected: virtual void GetViewShowFlags(FEngineShowFlags& OutShowFlag, EViewModeIndex& OutViewModeIndex) const; virtual TSharedPtr CalculateViewFamily(FMoviePipelineRenderPassMetrics& InOutSampleState, IViewCalcPayload* OptPayload = nullptr); virtual void BlendPostProcessSettings(FSceneView* InView, FMoviePipelineRenderPassMetrics& InOutSampleState, IViewCalcPayload* OptPayload = nullptr); virtual void SetupViewForViewModeOverride(FSceneView* View); virtual void MoviePipelineRenderShowFlagOverride(FEngineShowFlags& OutShowFlag) {} virtual bool IsScreenPercentageSupported() const { return true; } virtual bool IsAntiAliasingSupported() const { return true; } virtual int32 GetOutputFileSortingOrder() const { return -1; } virtual FSceneViewStateInterface* GetSceneViewStateInterface(IViewCalcPayload* OptPayload = nullptr) { return ViewState.GetReference(); } virtual FSceneViewStateInterface* GetExposureSceneViewStateInterface(IViewCalcPayload* OptPayload = nullptr, int32 CubeFaceIndex = INDEX_NONE) { return nullptr; } virtual void AddViewExtensions(FSceneViewFamilyContext& InContext, FMoviePipelineRenderPassMetrics& InOutSampleState) { } virtual bool IsAutoExposureAllowed(const FMoviePipelineRenderPassMetrics& InSampleState) const { return true; } virtual FSceneView* GetSceneViewForSampleState(FSceneViewFamily* ViewFamily, FMoviePipelineRenderPassMetrics& InOutSampleState, IViewCalcPayload* OptPayload = nullptr); virtual UE::MoviePipeline::FImagePassCameraViewData GetCameraInfo(FMoviePipelineRenderPassMetrics& InOutSampleState, IViewCalcPayload* OptPayload = nullptr) const; virtual TWeakObjectPtr GetOrCreateViewRenderTarget(const FIntPoint& InSize, IViewCalcPayload* OptPayload = nullptr); virtual TSharedPtr GetOrCreateSurfaceQueue(const FIntPoint& InSize, IViewCalcPayload* OptPayload = nullptr); virtual TWeakObjectPtr CreateViewRenderTargetImpl(const FIntPoint& InSize, IViewCalcPayload* OptPayload = nullptr) const; virtual TSharedPtr CreateSurfaceQueueImpl(const FIntPoint& InSize, IViewCalcPayload* OptPayload = nullptr) const; UE_DEPRECATED(5.1, "GetViewRenderTarget is deprecated, please use GetOrCreateViewRenderTarget") virtual UTextureRenderTarget2D* GetViewRenderTarget(IViewCalcPayload* OptPayload = nullptr) const { return nullptr; } public: protected: /** A temporary render target that we render the view to. */ TMap> TileRenderTargets; /** The history for the view */ FSceneViewStateReference ViewState; /** A queue of surfaces that the render targets can be copied to. If no surface is available the game thread should hold off on submitting more samples. */ TMap> SurfaceQueues; /** Some render passes may ignore the aspect ratio of the camera. */ bool bAllowCameraAspectRatio; FMoviePipelinePassIdentifier PassIdentifier; /** Accessed by the Render Thread when starting up a new task. */ FGraphEventArray OutstandingTasks; }; struct MOVIERENDERPIPELINERENDERPASSES_API FAccumulatorPool : public TSharedFromThis { struct FAccumulatorInstance { FAccumulatorInstance(TSharedPtr InAccumulator) { Accumulator = InAccumulator; ActiveFrameNumber = INDEX_NONE; bIsActive = false; } bool IsActive() const; void SetIsActive(const bool bInIsActive); TSharedPtr Accumulator; int32 ActiveFrameNumber; FMoviePipelinePassIdentifier ActivePassIdentifier; FThreadSafeBool bIsActive; FGraphEventRef TaskPrereq; }; virtual ~FAccumulatorPool() = default; TArray> Accumulators; FCriticalSection CriticalSection; TSharedPtr BlockAndGetAccumulator_GameThread(int32 InFrameNumber, const FMoviePipelinePassIdentifier& InPassIdentifier); protected: virtual TSharedPtr CreateNewAccumulatorInstance() { return nullptr; } virtual FName GetPoolName() const { return NAME_None; } }; template struct TAccumulatorPool : FAccumulatorPool { TAccumulatorPool(int32 InNumAccumulators) : FAccumulatorPool() { for (int32 Index = 0; Index < InNumAccumulators; Index++) { // Create a new instance of the accumulator TSharedPtr Accumulator = MakeShared(); Accumulators.Add(MakeShared(Accumulator)); } } protected: virtual TSharedPtr CreateNewAccumulatorInstance() override { TSharedPtr Accumulator = MakeShared(); return MakeShared(Accumulator); } virtual FName GetPoolName() const override { return AccumulatorType::GetName(); } }; DECLARE_CYCLE_STAT(TEXT("STAT_MoviePipeline_WaitForAvailableAccumulator"), STAT_MoviePipeline_WaitForAvailableAccumulator, STATGROUP_MoviePipeline); DECLARE_CYCLE_STAT(TEXT("STAT_MoviePipeline_WaitForAvailableSurface"), STAT_MoviePipeline_WaitForAvailableSurface, STATGROUP_MoviePipeline);