372 lines
17 KiB
C++
372 lines
17 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "Containers/UnrealString.h"
|
|
#include "CoreMinimal.h"
|
|
#include "UObject/NameTypes.h"
|
|
#include "AssetRegistry/AssetData.h"
|
|
#include "LandscapeTextureHash.h"
|
|
#include "Materials/Material.h"
|
|
#include "RenderGraphDefinitions.h"
|
|
#include "RenderGraphEvent.h"
|
|
#include "RenderGraphBuilder.h"
|
|
|
|
enum EShaderPlatform : uint16;
|
|
class AActor;
|
|
class FRDGBuilder;
|
|
class FRDGEventName;
|
|
class ULandscapeComponent;
|
|
class ULandscapeLayerInfoObject;
|
|
class ULandscapeMaterialInstanceConstant;
|
|
class ULevel;
|
|
class UTexture;
|
|
class UTexture2D;
|
|
class UWorld;
|
|
class FTextureResource;
|
|
class FMaterialUpdateContext;
|
|
enum class ELandscapeToolTargetType : uint8;
|
|
enum class ELandscapeToolTargetTypeFlags : uint8;
|
|
|
|
namespace UE::Landscape
|
|
{
|
|
enum class EBuildFlags : uint8;
|
|
|
|
/**
|
|
* Returns true if edit layers (GPU landscape tools) are enabled on this platform :
|
|
* Note: this is intended for the editor but is in runtime code since global shaders need to exist in runtime modules
|
|
*/
|
|
LANDSCAPE_API bool DoesPlatformSupportEditLayers(EShaderPlatform InShaderPlatform);
|
|
|
|
LANDSCAPE_API ELandscapeToolTargetTypeFlags GetLandscapeToolTargetTypeAsFlags(ELandscapeToolTargetType InTargetType);
|
|
LANDSCAPE_API ELandscapeToolTargetType GetLandscapeToolTargetTypeSingleFlagAsType(ELandscapeToolTargetTypeFlags InSingleFlag);
|
|
LANDSCAPE_API FString GetLandscapeToolTargetTypeFlagsAsString(ELandscapeToolTargetTypeFlags InTargetTypeFlags);
|
|
|
|
|
|
// ----------------------------------------------------------------------------------
|
|
|
|
/** This struct is usually meant to be allocated on the game thread (where there's no FRDGBuilder, which is Render Thread-only) and allows to queue successive operations (lambdas) onto a single render command,
|
|
* sharing the same FRDGBuilder. This allows to sequence a list of RDG passes from the game thread and makes it possible to interleave render thread operations (in a single render command) with game thread-initiated
|
|
* render commands.
|
|
* Here's an extensive use case :
|
|
*
|
|
* FRDGBuilderRecorder Recorder;
|
|
*
|
|
* // Start recording commands to a single graph builder :
|
|
* Recorder.StartRecording();
|
|
*
|
|
* Recorder.EnqueueRDGCommand([](FRDGBuilder* GraphBuilder) { GraphBuilder->AddPass(); }); // Append a Pass_A
|
|
* ENQUEUE_RENDER_COMMAND(...) // Push Render_Command_A (immediately)
|
|
* Recorder.EnqueueRDGCommand([](FRDGBuilder* GraphBuilder) { GraphBuilder->AddPass(); }, { { SomeTexture, ERHIAccess::RTV } }); // Append a Pass_B and inform of the final state of a given texture to prevent the RDG from auto-transitioning to SRVMask at the end
|
|
* Recorder.EnqueueRenderCommand([](FRHICommandListImmediate& InRHICmdList) mutable { [...]; }); // Append a Render_Command_B to the graph builder
|
|
* Recorder.EnqueueRDGCommand([](FRDGBuilder* GraphBuilder) { GraphBuilder->AddPass(); }, { { }SomeTexture, ERHIAccess::CopySrc } }); // Append a Pass_C and inform of the final state of a given texture to prevent the RDG from auto-transitioning to SRVMask at the end
|
|
*
|
|
* // Stop recording and issue a render command with all that's been recorded so far
|
|
* Recorder.StopRecordingAndFlush(RDG_EVENT_NAME("Pass ABC"));
|
|
*
|
|
* // Enqueue some game-thread render commands (e.g. BP render) either directly or via the recorder in immediate mode :
|
|
* ENQUEUE_RENDER_COMMAND(...) // Render_Command_C
|
|
* Recorder.EnqueueRDGCommand([](FRDGBuilder* GraphBuilder) { GraphBuilder->AddPass(); }, { { SomeTexture, ERHIAccess::CopyDst } }); // Append a Pass_D and inform of the final state of a given texture to prevent the RDG from auto-transitioning to SRVMask at the end
|
|
* Recorder.EnqueueRenderCommand([RHIOperation](FRHICommandListImmediate& InRHICmdList) mutable { [...]; }); // Append a Render_Command_D
|
|
*
|
|
* // Start recording commands again to a new single graph builder :
|
|
* Recorder.StartRecording();
|
|
* Recorder.EnqueueRDGCommand([](FRDGBuilder* GraphBuilder) { GraphBuilder->AddPass(); }); // Append a Pass_E
|
|
*
|
|
* // Stop recording and issue a render command with all that's been recorded so far
|
|
* Recorder.StopRecordingAndFlush(RDG_EVENT_NAME("Pass E"));
|
|
*
|
|
* --> Will yield the following sequence on the render thread:
|
|
* + Render_Command_A
|
|
* + Render Command "Pass ABC"
|
|
* +- (RDGBuilder_0)
|
|
* +- RDGBuilder_0.Pass_A
|
|
* +- RDGBuilder_0.Pass_B
|
|
* +- RDGBuilder_0.LambdaPass (Render_Command_B)
|
|
* +- RDGBuilder_0.Pass_C
|
|
* +- RDGBuilder_0.SetTextureAccessFinal(OutputTexture, ERHIAccess::CopySrc); // Only the final state recorded for a given texture is set
|
|
* +- RDGBuilder_0.Execute
|
|
* + Render_Command_C
|
|
* + Render Command
|
|
* +- (RDGBuilder_1)
|
|
* +- RDGBuilder_1.Pass_D
|
|
* +- RDGBuilder_1.SetTextureAccessFinal(OutputTexture, ERHIAccess::CopyDst);
|
|
* +- RDGBuilder_1.Execute
|
|
* + Render_Command_D
|
|
* + Render Command "Pass E"
|
|
* +- (RDGBuilder_2)
|
|
* +- RDGBuilder_2.Pass_E
|
|
* +- RDGBuilder_2.Execute
|
|
*/
|
|
class FRDGBuilderRecorder final
|
|
{
|
|
public:
|
|
using FRDGRecorderRDGCommand = TFunction<void(FRDGBuilder& /*GraphBuilder*/)>;
|
|
using FRDGRecorderRenderCommand = TFunction<void(FRHICommandListImmediate& /*InRHICmdList*/)>;
|
|
struct FRDGExternalTextureAccessFinal
|
|
{
|
|
FTextureResource* TextureResource = nullptr;
|
|
ERHIAccess Access = ERHIAccess::None;
|
|
};
|
|
|
|
FRDGBuilderRecorder() = default;
|
|
LANDSCAPE_API ~FRDGBuilderRecorder();
|
|
|
|
enum class EState
|
|
{
|
|
Immediate, // In immediate mode, any command that is enqueued will be pushed to the render thread immediately (effectively acting like a ENQUEUE_RENDER_COMMAND)
|
|
Recording, // In recording mode, any command that is enqueued will be deferred to the render thread (effectively acting like a ENQUEUE_RENDER_COMMAND)
|
|
};
|
|
|
|
inline EState GetState() const { return State; }
|
|
inline bool IsRecording() const { return State == EState::Recording; }
|
|
|
|
/**
|
|
* Starts recording commands
|
|
*/
|
|
LANDSCAPE_API void StartRecording();
|
|
|
|
/**
|
|
* Stops recording commands. A call to Flush is needed to ensure any pending command is flushed to the render thread (use StopRecordingAndFlush to do both)
|
|
*/
|
|
LANDSCAPE_API void StopRecording();
|
|
|
|
/**
|
|
* Stops recording commands and flushes them to the render thread. Expects the recorder to be in Recording mode and changes it to Immediate mode.
|
|
* @param EventName RDG event name to use on the render command's FRDGBuilder
|
|
*/
|
|
LANDSCAPE_API void StopRecordingAndFlush(FRDGEventName&& EventName);
|
|
|
|
/**
|
|
* Flushes any pending command to the render thread
|
|
* @param EventName RDG event name to use on the render command's FRDGBuilder
|
|
*/
|
|
LANDSCAPE_API void Flush(FRDGEventName&& EventName);
|
|
|
|
/**
|
|
* Records a FRDGRecorderRDGCommand to execute when registering passes to the single FRDGBuilder when in Recording mode or pushes it immediately to the render thread when in Immediate mode
|
|
*
|
|
* @param InRDGCommand Lambda to execute on the render thread
|
|
* @param InRDGTextureAccessFinalList (optional) : list of external texture with the RHIAccess they should have when executing the FRDGBuilder. This is to prevent the RDG from auto-transitioning to SRVMask at the end
|
|
*/
|
|
LANDSCAPE_API void EnqueueRDGCommand(FRDGRecorderRDGCommand InRDGCommand, TConstArrayView<FRDGExternalTextureAccessFinal> InRDGExternalTextureAccessFinalList = {});
|
|
|
|
/**
|
|
* Records a FRDGRecorderRenderCommand to execute when registering passes to the single FRDGBuilder when in Recording mode or pushes it immediately to the render thread when in Immediate mode
|
|
*
|
|
* @param InRenderCommand Lambda to execute on the render thread
|
|
*/
|
|
LANDSCAPE_API void EnqueueRenderCommand(FRDGRecorderRenderCommand InRenderCommand);
|
|
|
|
/**
|
|
* @return true if there's no command currently recorded
|
|
*/
|
|
LANDSCAPE_API bool IsEmpty() const;
|
|
|
|
/**
|
|
* Cancels all recorder operations. This must be used if the FRDGEventRenderRecorder is "cancelled" (i.e. its sequence of operations is not flushed to a render command).
|
|
* Otherwise, there will be an assert in ~FRDGBuilderRecorder().
|
|
*/
|
|
LANDSCAPE_API void Clear();
|
|
|
|
private:
|
|
EState State = EState::Immediate;
|
|
|
|
// List of callbacks to call on the render thread after the render command was initiated
|
|
TArray<FRDGRecorderRDGCommand> RDGCommands;
|
|
|
|
// Map of textures and the RHI access they should have when leaving the FRDGBuilder :
|
|
TMap<FTextureResource*, ERHIAccess> RDGExternalTextureAccessFinal;
|
|
|
|
#if RDG_EVENTS
|
|
public:
|
|
/**
|
|
* Scope object meant to insert a RDG event in the RDG operations, as if it was inserted on the render thread on a FRDGBuilder.
|
|
* Use RDG_RENDER_COMMAND_RECORDER_BREADCRUMB_EVENT to create one.
|
|
*/
|
|
class FScopedBreadcrumbEvent final
|
|
{
|
|
public:
|
|
FScopedBreadcrumbEvent(FRDGBuilderRecorder& InRecorder, TCHAR const* StaticName, FRDGEventName&& EventName)
|
|
: Recorder(&InRecorder)
|
|
, RDGEvent(MakeShared<TOptional<TRDGEventScopeGuard<FRDGScope_RHI>>>())
|
|
{
|
|
// We use a shared ptr to create a TOptional<TRDGEventScopeGuard> immediately, then capture this shared ptr in these additional operations' lambdas (so that the object
|
|
// continues to live until the closing tag operation)
|
|
Recorder->EnqueueRDGCommand(
|
|
[
|
|
RDGEvent = RDGEvent,
|
|
StaticName = StaticName,
|
|
EventName = MoveTemp(EventName)
|
|
](FRDGBuilder& GraphBuilder) mutable
|
|
{
|
|
// Allocate the TOptional<TRDGEventScopeGuard> now in order to insert the tag :
|
|
RDG_EVENT_SCOPE_CONSTRUCT(*RDGEvent, GraphBuilder, true, ERDGScopeFlags::None, RHI_GPU_STAT_ARGS_NONE, StaticName, MoveTemp(EventName));
|
|
});
|
|
}
|
|
|
|
~FScopedBreadcrumbEvent()
|
|
{
|
|
Recorder->EnqueueRDGCommand([RDGEvent = RDGEvent](FRDGBuilder& GraphBuilder)
|
|
{
|
|
// Reset the TOptional in order to delete the TRDGEventScopeGuard, which will remove the tag :
|
|
RDGEvent->Reset();
|
|
});
|
|
}
|
|
|
|
private:
|
|
FRDGBuilderRecorder* Recorder = nullptr;
|
|
TSharedPtr<TOptional<TRDGEventScopeGuard<FRDGScope_RHI>>> RDGEvent;
|
|
};
|
|
#endif // RDG_EVENTS
|
|
};
|
|
|
|
#if RDG_EVENTS
|
|
#define RDG_RENDER_COMMAND_RECORDER_BREADCRUMB_EVENT(Recorder, Format, ...) FRDGBuilderRecorder::FScopedBreadcrumbEvent ANONYMOUS_VARIABLE(BreadcrumbEvent)(Recorder, TEXT(Format), RDG_EVENT_NAME(Format, ##__VA_ARGS__))
|
|
#else // RDG_EVENTS
|
|
#define RDG_RENDER_COMMAND_RECORDER_BREADCRUMB_EVENT(Recorder, Format, ...) do { } while(0)
|
|
#endif // !RDG_EVENTS
|
|
|
|
|
|
#if WITH_EDITOR
|
|
|
|
// ----------------------------------------------------------------------------------
|
|
|
|
struct FTextureCopyRequest
|
|
{
|
|
UTexture2D* Source = nullptr;
|
|
UTexture* Destination = nullptr;
|
|
int8 DestinationSlice = 0;
|
|
ELandscapeTextureUsage TextureUsage = ELandscapeTextureUsage::Unknown;
|
|
ELandscapeTextureType TextureType = ELandscapeTextureType::Unknown;
|
|
};
|
|
|
|
uint32 GetTypeHash(const FTextureCopyRequest& InKey);
|
|
bool operator==(const FTextureCopyRequest& InEntryA, const FTextureCopyRequest& InEntryB);
|
|
|
|
/** Represents the DestinationChannel->SourceChannel binding.DestinationChannel is used as index.
|
|
* For example if the source channel is 1 and the destination channel is 2, then Mappings[2] == 1.
|
|
*/
|
|
struct FTextureCopyChannelMapping
|
|
{
|
|
FTextureCopyChannelMapping()
|
|
: Mappings{ INDEX_NONE, INDEX_NONE, INDEX_NONE, INDEX_NONE }
|
|
{}
|
|
|
|
int8& operator[](int32 Index) { return Mappings[Index]; }
|
|
const int8 operator[](int32 Index) const { return Mappings[Index]; }
|
|
|
|
int8 Mappings[4];
|
|
};
|
|
|
|
class FBatchTextureCopy
|
|
{
|
|
public:
|
|
/**
|
|
* Uses the provided arguments to add proper source/destination entries to internal copy requests.
|
|
* @param InDestination The texture used as a destination for the copy.
|
|
* @param InDestinationSlice The Texture array slice to write to (use 0 for a Texture2D)
|
|
* @param InDestinationChannel The channel used as a destination for the copy.
|
|
* @param InComponent The component containing the wanted source weightmap.
|
|
* @param InLayerInfo The layer info used to retrieve the proper source weightmap and channel.
|
|
* @return True if the copy has been successfully added.
|
|
*/
|
|
LANDSCAPE_API bool AddWeightmapCopy(UTexture* InDestination, int8 InDestinationSlice, int8 InDestinationChannel, const ULandscapeComponent* InComponent, ULandscapeLayerInfoObject* InLayerInfo);
|
|
|
|
/** Process pending internal copy requests. */
|
|
LANDSCAPE_API bool ProcessTextureCopies();
|
|
|
|
private:
|
|
using FTextureCopyChannelMappingMap = TMap<FTextureCopyRequest, FTextureCopyChannelMapping>;
|
|
|
|
FTextureCopyChannelMappingMap CopyRequests;
|
|
};
|
|
|
|
/**
|
|
* Returns a generated path used for Landscape Shared Assets
|
|
* @param InPath Path used as a basis to generate shared assets path. If /Temp/, it will be replaced by the last valid path used for level.
|
|
* @return Path used for Landscape Shared Assets
|
|
*/
|
|
LANDSCAPE_API FString GetSharedAssetsPath(const FString& InPath);
|
|
|
|
/**
|
|
* Returns a generated path used for Landscape Shared Assets
|
|
* @param InLevel Level's Path will be used as a basis to generate shared assets path. If /Temp/, it will be replaced by the last valid path used for level.
|
|
* @return Path used for Landscape Shared Assets
|
|
*/
|
|
LANDSCAPE_API FString GetSharedAssetsPath(const ULevel* InLevel);
|
|
|
|
/**
|
|
* Returns a generated package name for a Layer Info Object
|
|
* @param InLayerName The LayerName of the Layer Info Object
|
|
* @param InPackagePath Base package path that will be used, should be Current Level SharedAssetPath or the LandscapeEditorObject->TargetLayerAssetFilePath
|
|
* @param OutLayerObjectName The generated object name for Layer Info Object
|
|
*/
|
|
LANDSCAPE_API FString GetLayerInfoObjectPackageName(const FName& InLayerName, const FString& InPackagePath, FName& OutLayerObjectName);
|
|
|
|
/**
|
|
* Returns a generated package name for a Layer Info Object
|
|
* @param InLevel Level's Path will be used as a basis to generate package's path. If /Temp/, it will be replaced by the last valid path used for level.
|
|
* @param InLayerName The LayerName of the Layer Info Object
|
|
* @param OutLayerObjectName The generated object name for Layer Info Object
|
|
* @return
|
|
*/
|
|
UE_DEPRECATED(5.6, "This Get function is deprecated. Please use new GetLayerInfo and pass in a full asset package path.")
|
|
LANDSCAPE_API FString GetLayerInfoObjectPackageName(const ULevel* InLevel, const FName& InLayerName, FName& OutLayerObjectName);
|
|
|
|
/**
|
|
* Creates a new layer info object, using the default template if available, or a new empty one. Sets asset file name as LayerName_LayerInfo_%d
|
|
* @param InLayerName The layer name of the created asset info
|
|
* @param InFilePath New asset file path, typically is CurrentLevel/SharedAssetPath or the LandscapeEditorObject->TargetLayerAssetFilePath->DirectoryPath
|
|
* @return a new LandscapeLayerInfoObject.
|
|
*/
|
|
LANDSCAPE_API ULandscapeLayerInfoObject* CreateTargetLayerInfo(const FName& InLayerName, const FString& InFilePath);
|
|
|
|
/**
|
|
* Creates a new layer info object, using the default template if available, or a new empty one at the path: InFilePath/InFilename
|
|
* @param InLayerName The layer name of the created asset info
|
|
* @param InFilePath New asset file path, typically is CurrentLevel/SharedAssetPath or the LandscapeEditorObject->TargetLayerAssetFilePath->DirectoryPath
|
|
* @param InFileName The unique file name of the created asset
|
|
* @return a new LandscapeLayerInfoObject.
|
|
*/
|
|
LANDSCAPE_API ULandscapeLayerInfoObject* CreateTargetLayerInfo(const FName& InLayerName, const FString& InFilePath, const FString& InFileName);
|
|
|
|
/** Returns true if the provided layer info object is the current visibility layer. */
|
|
LANDSCAPE_API bool IsVisibilityLayer(const ULandscapeLayerInfoObject* InLayerInfoObject);
|
|
|
|
struct UE_DEPRECATED(5.6, "This helper struct is deprecated. Please use utility methods in LandscapeEditorUtils.") FLayerInfoFinder
|
|
{
|
|
LANDSCAPE_API FLayerInfoFinder();
|
|
LANDSCAPE_API ~FLayerInfoFinder() = default;
|
|
LANDSCAPE_API ULandscapeLayerInfoObject* Find(const FName& LayerName) const;
|
|
TArray<FAssetData> LayerInfoAssets;
|
|
};
|
|
|
|
/**
|
|
* Returns a pointer to a newly created ULandscapeMaterialInstanceConstant
|
|
* @param BaseMaterial The base material appended to the debug name and set as parent of MaterialInstance
|
|
* @return Pointer to ULandscapeMaterialInstanceConstant
|
|
*/
|
|
LANDSCAPE_API UMaterialInstance* CreateToolLandscapeMaterialInstanceConstant(UMaterialInterface* BaseMaterial);
|
|
|
|
|
|
/** Create a thumbnail material for a given layer. Can return nullptr if the option to disable landscape thumbnails has been turned on */
|
|
LANDSCAPE_API ULandscapeMaterialInstanceConstant* CreateLandscapeLayerThumbnailMIC(FMaterialUpdateContext& MaterialUpdateContext, UMaterialInterface* LandscapeMaterial, FName LayerName);
|
|
|
|
/** Concatenates the target layer names in parameter into a string */
|
|
LANDSCAPE_API FString ConvertTargetLayerNamesToString(const TArrayView<const FName>& InTargetLayerNames);
|
|
|
|
/**
|
|
* Helper to delete one or multiple actors.
|
|
* @param InActorsToDelete the list of actors to delete. Cannot contain null entries and all actors should be part of the world passed in InWorld
|
|
* @param InWorld world to which all actors to be deleted belong
|
|
* @param bInAllowUI allows the standard delete actors UX to be displayed, allowing the user to remove lingering reference to these actors, etc.
|
|
*
|
|
* @return true if all actors could be properly deleted
|
|
*/
|
|
LANDSCAPE_API bool DeleteActors(const TArray<AActor*>& InActorsToDelete, UWorld* InWorld, bool bInAllowUI);
|
|
|
|
#endif // WITH_EDITOR
|
|
|
|
} // end namespace UE::Landscape
|