// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "LightSceneProxy.h" #include "RenderGraphFwd.h" #include "ShaderParameterMacros.h" class FViewFamilyInfo; class FViewInfo; class FScene; class FMaterialRenderProxy; class FRDGBuilder; class FLightSceneInfo; class FRDGTexture; struct FScreenPassTexture; struct FSortedLightSetSceneInfo; struct IPooledRenderTarget; namespace LightFunctionAtlas { // This allows to not have to store more data per GPU light representation on GPU. The light only needs an index into the array. // Using a constant buffer also workaround the fact that we would otherwise need another SRV in forward shaders. // The light atlas texture itself already use 1 extra SRV. We could an extra SRV and have LightInfoDataXXX be in a buffer that scale with amount of light in the scene. BEGIN_GLOBAL_SHADER_PARAMETER_STRUCT(FLightFunctionAtlasGlobalParameters, ) SHADER_PARAMETER_RDG_TEXTURE(Texture2D, LightFunctionAtlasTexture) SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer, LightInfoDataBuffer) SHADER_PARAMETER_SAMPLER(SamplerState, LightFunctionAtlasSampler) SHADER_PARAMETER(float, Slot_UVSize) END_GLOBAL_SHADER_PARAMETER_STRUCT() enum class ELightFunctionAtlasSystem { VolumetricFog, DeferredLighting, MegaLights, Lumen, }; struct FLightFunctionAtlas; struct FLightFunctionAtlasSceneData { void SetData(FLightFunctionAtlas* InLightFunctionAtlas, bool bInLightFunctionAtlasEnabled) { LightFunctionAtlas = InLightFunctionAtlas; bLightFunctionAtlasEnabled = bInLightFunctionAtlasEnabled; } void AddSystem(ELightFunctionAtlasSystem In) { SystemFlags |= 1u << uint32(In); } void ClearSystems() { SystemFlags = 0; } FLightFunctionAtlas* GetLightFunctionAtlas() const { return LightFunctionAtlas; } bool UsesLightFunctionAtlas(ELightFunctionAtlasSystem In) const { return (SystemFlags & (1u<GetLightFunctionAtlas() : nullptr; } bool GetLightFunctionAtlasEnabled() const { return SceneData ? SceneData->GetLightFunctionAtlasEnabled() : false; } bool UsesLightFunctionAtlas(ELightFunctionAtlasSystem In) const { return SceneData ? SceneData->UsesLightFunctionAtlas(In) : false; } uint32 GetViewIndex() const { return ViewIndex; } private: FLightFunctionAtlasSceneData* SceneData = nullptr; uint32 ViewIndex = 0; }; struct FLightFunctionSlotKey { uint32 LFMaterialUniqueID = 0; uint32 EffectiveLightFunctionSlotIndex = 0; // Not used to de-duplicate light function. It is the index of the effective lighting function for this frame in EffectiveLightFunctionSlotArray. FLightFunctionSlotKey() {}; FLightFunctionSlotKey(FLightSceneInfo* InLightSceneInfo); inline bool operator==(const FLightFunctionSlotKey& Other) const { return Other.LFMaterialUniqueID == LFMaterialUniqueID; } }; inline uint32 GetTypeHash(FLightFunctionSlotKey Key) { return ::GetTypeHash(Key.LFMaterialUniqueID); } struct FLightFunctionSlot { const FMaterialRenderProxy* LightFunctionMaterial; FIntPoint Min; FIntPoint Max; }; #define LIGHT_FUNCTION_ATLAS_MAX_LIGHT_FUNCTION_COUNT 256 struct FAtlasLightInfoData { FVector4f Parameters; FMatrix44f Transform; }; struct FLightFunctionAtlasSetup { uint32 EdgeSize = 2; uint32 SlotResolution = 32; }; // This class holds all data and resources related light function for a single scene, including multiple views. struct FLightFunctionAtlas { FLightFunctionAtlas(); virtual ~FLightFunctionAtlas(); bool IsLightFunctionAtlasEnabled() const { return bLightFunctionAtlasEnabled; } void ClearEmptySceneFrame(FViewInfo* View = nullptr, uint32 ViewIndex = 0, FLightFunctionAtlasSceneData* LightFunctionAtlasSceneData = nullptr); void BeginSceneFrame(const FViewFamilyInfo& ViewFamily, TArray& Views, FLightFunctionAtlasSceneData& LightFunctionAtlasSceneData, bool bShouldRenderVolumetricFog); void UpdateRegisterLightSceneInfo(FLightSceneInfo* LightSceneInfo); void UpdateLightFunctionAtlas(const TArray& Views); void RenderLightFunctionAtlas(FRDGBuilder& GraphBuilder, TArray& Views); FScreenPassTexture AddDebugVisualizationPasses(FRDGBuilder& GraphBuilder, const FViewInfo& View, FScreenPassTexture& ScreenPassSceneColor) const; FLightFunctionAtlasGlobalParameters* GetLightFunctionAtlasGlobalParametersStruct(FRDGBuilder& GraphBuilder, uint32 ViewIndex); TRDGUniformBufferRef GetLightFunctionAtlasGlobalParameters(FRDGBuilder& GraphBuilder, uint32 ViewIndex); static FLightFunctionAtlasGlobalParameters* GetDefaultLightFunctionAtlasGlobalParametersStruct(FRDGBuilder& GraphBuilder); TRDGUniformBufferRef GetDefaultLightFunctionAtlasGlobalParameters(FRDGBuilder& GraphBuilder); bool IsOutOfSlots(); FString GetOutOfSlotWarningMessage(); private: void AllocateAtlasSlots(const TArray& Views); void AllocateTexture2DAtlas(FRDGBuilder& GraphBuilder); void RenderAtlasSlots(FRDGBuilder& GraphBuilder, const TArray& Views); bool bLightFunctionAtlasEnabled = false; FRDGTextureRef RDGAtlasTexture2D = nullptr; FRDGBufferRef RDGLightInfoDataBuffer = nullptr; // All the lights that wants to sample light functions TArray RegisteredLights; // This set is used to de-duplicate light functions in the atlas. An alternative to set would be to use simple array with simple loops. TSet LightFunctionsSet; // The structure used to render light function and generate the associated constant buffer, containing UVs and transformation matrices. struct EffectiveLightFunctionSlot { const FMaterialRenderProxy* LightFunctionMaterial = nullptr; FIntPoint Min; FIntPoint Max; float MinU; float MinV; }; TArray EffectiveLightFunctionSlotArray; struct EffectiveLocalLightSlot { FLightSceneInfo* LightSceneInfo = nullptr; uint8 LightFunctionAtlasSlotIndex = 0; }; TArray EffectiveLocalLightSlotArray; FLightFunctionAtlasGlobalParameters* DefaultLightFunctionAtlasGlobalParameters = nullptr; TRDGUniformBufferRef DefaultLightFunctionAtlasGlobalParametersUB; TArray ViewLightFunctionAtlasGlobalParametersArray; TArray> ViewLightFunctionAtlasGlobalParametersUBArray; #if WITH_EDITOR uint32 LightCountWithLFMaterialsNotSamplingAtlas = 0; TMap NonCompatibleLightFunctionMaterials; #endif #if !UE_BUILD_SHIPPING uint32 LightCountSkippedDueToMissingAtlasSlot = 0; TSet SkippedLightFunctionsSet; #endif FLightFunctionAtlasSetup AtlasSetup; }; bool IsEnabled(const FViewInfo& InView, ELightFunctionAtlasSystem In); bool IsEnabled(const FScene& InScene, ELightFunctionAtlasSystem In); void OnRenderBegin(FLightFunctionAtlas& In, FScene& InScene, TArray& Views, const FViewFamilyInfo& ViewFamily); TRDGUniformBufferRef BindGlobalParameters(FRDGBuilder& GraphBuilder, const FViewInfo& View); FLightFunctionAtlasGlobalParameters* GetGlobalParametersStruct(FRDGBuilder& GraphBuilder, const FViewInfo& View); } // namespace LightFunctionAtlas