// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "GlobalShader.h" #include "Math/IntVector.h" #include "Math/UnrealMathSSE.h" #include "Misc/AssertionMacros.h" #include "RHICommandList.h" #include "RHIDefinitions.h" #include "Serialization/MemoryLayout.h" #include "Shader.h" #include "ShaderCompilerCore.h" #include "ShaderCore.h" #include "ShaderParameterUtils.h" #include "ShaderParameters.h" #include "DataDrivenShaderPlatformInfo.h" class FPointerTableBase; class FRHIComputeShader; enum class ECopyTextureResourceType { Texture2D = 0, Texture2DArray = 1, Texture3D = 2 }; enum class ECopyTextureValueType { Float, Int32, Uint32 }; namespace CopyTextureCS { template struct TThreadGroupSize { static constexpr int32 X = 8, Y = 8, Z = 1; }; template <> struct TThreadGroupSize { static constexpr int32 X = 4, Y = 4, Z = 4; }; struct DispatchContext { uint32 ThreadGroupSizeX = 0u; uint32 ThreadGroupSizeY = 0u; uint32 ThreadGroupSizeZ = 0u; ECopyTextureResourceType SrcType; ECopyTextureResourceType DstType; ECopyTextureValueType ValueType; uint32 NumChannels; }; } class FCopyTextureCS : public FGlobalShader { DECLARE_EXPORTED_TYPE_LAYOUT(FCopyTextureCS, RENDERCORE_API, NonVirtual); protected: FCopyTextureCS() {} FCopyTextureCS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) : FGlobalShader(Initializer) { DstOffsetParam.Bind(Initializer.ParameterMap, TEXT("DstOffset"), SPF_Mandatory); SrcOffsetParam.Bind(Initializer.ParameterMap, TEXT("SrcOffset"), SPF_Mandatory); DimensionsParam.Bind(Initializer.ParameterMap, TEXT("Dimensions"), SPF_Mandatory); SrcResourceParam.Bind(Initializer.ParameterMap, TEXT("SrcResource"), SPF_Mandatory); DstResourceParam.Bind(Initializer.ParameterMap, TEXT("DstResource"), SPF_Mandatory); } public: static inline void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment) { FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment); if (FDataDrivenShaderPlatformInfo::GetRequiresBindfulUtilityShaders(Parameters.Platform)) { OutEnvironment.CompilerFlags.Add(CFLAG_ForceBindful); } } inline const FShaderResourceParameter& GetSrcResourceParam() { return SrcResourceParam; } inline const FShaderResourceParameter& GetDstResourceParam() { return DstResourceParam; } void Dispatch( FRHIComputeCommandList& RHICmdList, const CopyTextureCS::DispatchContext& Context, FIntVector const& SrcOffset, FIntVector const& DstOffset, FIntVector const& Dimensions ) { check(SrcOffset.GetMin() >= 0 && DstOffset.GetMin() >= 0 && Dimensions.GetMin() >= 0); check(Context.DstType != ECopyTextureResourceType::Texture2D || Dimensions.Z <= 1); FRHIBatchedShaderParameters& BatchedParameters = RHICmdList.GetScratchShaderParameters(); SetShaderValue(BatchedParameters, SrcOffsetParam, SrcOffset); SetShaderValue(BatchedParameters, DstOffsetParam, DstOffset); SetShaderValue(BatchedParameters, DimensionsParam, Dimensions); RHICmdList.SetBatchedShaderParameters(RHICmdList.GetBoundComputeShader(), BatchedParameters); RHICmdList.DispatchComputeShader( FMath::DivideAndRoundUp(uint32(Dimensions.X), Context.ThreadGroupSizeX), FMath::DivideAndRoundUp(uint32(Dimensions.Y), Context.ThreadGroupSizeY), FMath::DivideAndRoundUp(uint32(Dimensions.Z), Context.ThreadGroupSizeZ) ); } static inline TShaderRef SelectShader(FGlobalShaderMap* GlobalShaderMap, ECopyTextureResourceType SrcType, ECopyTextureResourceType DstType, ECopyTextureValueType ValueType, CopyTextureCS::DispatchContext& OutContext); protected: template static inline TShaderRef SelectShader(FGlobalShaderMap* GlobalShaderMap, CopyTextureCS::DispatchContext& OutContext); template static inline TShaderRef SelectShader(FGlobalShaderMap* GlobalShaderMap, ECopyTextureResourceType DstType, ECopyTextureValueType ValueType, CopyTextureCS::DispatchContext& OutContext); template static inline TShaderRef SelectShader(FGlobalShaderMap* GlobalShaderMap, ECopyTextureValueType ValueType, CopyTextureCS::DispatchContext& OutContext); LAYOUT_FIELD(FShaderParameter, DstOffsetParam); LAYOUT_FIELD(FShaderParameter, SrcOffsetParam); LAYOUT_FIELD(FShaderParameter, DimensionsParam); LAYOUT_FIELD(FShaderResourceParameter, SrcResourceParam); LAYOUT_FIELD(FShaderResourceParameter, DstResourceParam); }; template class TCopyResourceCS : public FCopyTextureCS { static_assert(NumChannels >= 1 && NumChannels <= 4, "Only 1 to 4 channels are supported."); DECLARE_EXPORTED_SHADER_TYPE(TCopyResourceCS, Global, RENDERCORE_API); public: TCopyResourceCS() {} TCopyResourceCS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) : FCopyTextureCS(Initializer) {} static constexpr uint32 ThreadGroupSizeX = CopyTextureCS::TThreadGroupSize::X; static constexpr uint32 ThreadGroupSizeY = CopyTextureCS::TThreadGroupSize::Y; static constexpr uint32 ThreadGroupSizeZ = CopyTextureCS::TThreadGroupSize::Z; static const TCHAR* GetSourceFilename() { return TEXT("/Engine/Private/CopyTextureShaders.usf"); } static const TCHAR* GetFunctionName() { return TEXT("CopyTextureCS"); } static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) { return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5); } static inline void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment) { FCopyTextureCS::ModifyCompilationEnvironment(Parameters, OutEnvironment); OutEnvironment.SetDefine(TEXT("THREADGROUPSIZE_X"), ThreadGroupSizeX); OutEnvironment.SetDefine(TEXT("THREADGROUPSIZE_Y"), ThreadGroupSizeY); OutEnvironment.SetDefine(TEXT("THREADGROUPSIZE_Z"), ThreadGroupSizeZ); OutEnvironment.SetDefine(TEXT("SRC_TYPE"), uint32(SrcType)); OutEnvironment.SetDefine(TEXT("DST_TYPE"), uint32(DstType)); switch (ValueType) { case ECopyTextureValueType::Float: switch (NumChannels) { case 1: OutEnvironment.SetDefine(TEXT("VALUE_TYPE"), TEXT("float")); break; case 2: OutEnvironment.SetDefine(TEXT("VALUE_TYPE"), TEXT("float2")); break; case 3: OutEnvironment.SetDefine(TEXT("VALUE_TYPE"), TEXT("float3")); break; case 4: OutEnvironment.SetDefine(TEXT("VALUE_TYPE"), TEXT("float4")); break; } break; case ECopyTextureValueType::Int32: switch (NumChannels) { case 1: OutEnvironment.SetDefine(TEXT("VALUE_TYPE"), TEXT("int")); break; case 2: OutEnvironment.SetDefine(TEXT("VALUE_TYPE"), TEXT("int2")); break; case 3: OutEnvironment.SetDefine(TEXT("VALUE_TYPE"), TEXT("int3")); break; case 4: OutEnvironment.SetDefine(TEXT("VALUE_TYPE"), TEXT("int4")); break; } break; case ECopyTextureValueType::Uint32: switch (NumChannels) { case 1: OutEnvironment.SetDefine(TEXT("VALUE_TYPE"), TEXT("uint")); break; case 2: OutEnvironment.SetDefine(TEXT("VALUE_TYPE"), TEXT("uint2")); break; case 3: OutEnvironment.SetDefine(TEXT("VALUE_TYPE"), TEXT("uint3")); break; case 4: OutEnvironment.SetDefine(TEXT("VALUE_TYPE"), TEXT("uint4")); break; } break; } } void GetDispatchContext(CopyTextureCS::DispatchContext& OutContext) { OutContext.ThreadGroupSizeX = ThreadGroupSizeX; OutContext.ThreadGroupSizeY = ThreadGroupSizeY; OutContext.ThreadGroupSizeZ = ThreadGroupSizeZ; OutContext.SrcType = SrcType; OutContext.DstType = DstType; OutContext.ValueType = ValueType; OutContext.NumChannels = NumChannels; } }; template inline TShaderRef FCopyTextureCS::SelectShader(FGlobalShaderMap* GlobalShaderMap, CopyTextureCS::DispatchContext& OutContext) { TShaderRef Shader = GlobalShaderMap->GetShader(); Shader->GetDispatchContext(OutContext); return Shader; } template inline TShaderRef FCopyTextureCS::SelectShader(FGlobalShaderMap* GlobalShaderMap, ECopyTextureValueType ValueType, CopyTextureCS::DispatchContext& OutContext) { switch (ValueType) { default: checkNoEntry(); case ECopyTextureValueType::Float: return SelectShader>(GlobalShaderMap, OutContext); case ECopyTextureValueType::Int32: return SelectShader>(GlobalShaderMap, OutContext); case ECopyTextureValueType::Uint32: return SelectShader>(GlobalShaderMap, OutContext); } } template inline TShaderRef FCopyTextureCS::SelectShader(FGlobalShaderMap* GlobalShaderMap, ECopyTextureResourceType DstType, ECopyTextureValueType ValueType, CopyTextureCS::DispatchContext& OutContext) { switch (DstType) { default: checkNoEntry(); case ECopyTextureResourceType::Texture2D: return FCopyTextureCS::SelectShader(GlobalShaderMap, ValueType, OutContext); case ECopyTextureResourceType::Texture2DArray: return FCopyTextureCS::SelectShader(GlobalShaderMap, ValueType, OutContext); case ECopyTextureResourceType::Texture3D: return FCopyTextureCS::SelectShader(GlobalShaderMap, ValueType, OutContext); } } inline TShaderRef FCopyTextureCS::SelectShader(FGlobalShaderMap* GlobalShaderMap, ECopyTextureResourceType SrcType, ECopyTextureResourceType DstType, ECopyTextureValueType ValueType, CopyTextureCS::DispatchContext& OutContext) { switch (SrcType) { default: checkNoEntry(); case ECopyTextureResourceType::Texture2D: return FCopyTextureCS::SelectShader(GlobalShaderMap, DstType, ValueType, OutContext); case ECopyTextureResourceType::Texture2DArray: return FCopyTextureCS::SelectShader(GlobalShaderMap, DstType, ValueType, OutContext); case ECopyTextureResourceType::Texture3D: return FCopyTextureCS::SelectShader(GlobalShaderMap, DstType, ValueType, OutContext); } }