UE 5.0
D:\Program Files\Epic Games\UE_5.0\Engine\Source\Runtime\RenderCore\Public\CopyTextureShader.h
클래스 선언은 다음과 같습니다.
class FCopyTextureCS : public FGlobalShader
{
DECLARE_EXPORTED_TYPE_LAYOUT(FCopyTextureCS, RENDERCORE_API, NonVirtual);
...
추가적으로 다음과 같이 되어있습니다.
```cpp
#define IMPLEMENT_COPY_RESOURCE_SHADER(SrcType,DstType,ValueType)\
typedef TCopyResourceCS<ECopyTextureResourceType::SrcType, ECopyTextureResourceType::DstType, ECopyTextureValueType::ValueType, 4> FCopyTextureCS_##SrcType##_##DstType##_##ValueType##4;\
IMPLEMENT_SHADER_TYPE4_WITH_TEMPLATE_PREFIX(template<>, RENDERCORE_API, FCopyTextureCS_##SrcType##_##DstType##_##ValueType##4, SF_Compute);
#define IMPLEMENT_COPY_RESOURCE_SHADER_ALL_TYPES(SrcType,DstType)\
IMPLEMENT_COPY_RESOURCE_SHADER(SrcType,DstType,Float)\
IMPLEMENT_COPY_RESOURCE_SHADER(SrcType,DstType,Int32)\
IMPLEMENT_COPY_RESOURCE_SHADER(SrcType,DstType,Uint32)
IMPLEMENT_COPY_RESOURCE_SHADER_ALL_TYPES(Texture2D , Texture2D );
IMPLEMENT_COPY_RESOURCE_SHADER_ALL_TYPES(Texture2D , Texture2DArray);
IMPLEMENT_COPY_RESOURCE_SHADER_ALL_TYPES(Texture2D , Texture3D );
IMPLEMENT_COPY_RESOURCE_SHADER_ALL_TYPES(Texture2DArray, Texture2D );
IMPLEMENT_COPY_RESOURCE_SHADER_ALL_TYPES(Texture2DArray, Texture2DArray);
IMPLEMENT_COPY_RESOURCE_SHADER_ALL_TYPES(Texture2DArray, Texture3D );
IMPLEMENT_COPY_RESOURCE_SHADER_ALL_TYPES(Texture3D , Texture2D );
IMPLEMENT_COPY_RESOURCE_SHADER_ALL_TYPES(Texture3D , Texture2DArray);
IMPLEMENT_COPY_RESOURCE_SHADER_ALL_TYPES(Texture3D , Texture3D );
```
- 생성자는 다음과 같습니다.
... 클래스 선언 ...
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);
}
- Initializer를 보면 Parameter를 바인드 하는 것을 알 수 있습니다.
- Parameter는 FCopyTextureCS아래에 Protected로 정의되어 있습니다.
... 클래스 선언 ...
public:
inline const FShaderResourceParameter& GetSrcResourceParam() { return SrcResourceParam; }
inline const FShaderResourceParameter& GetDstResourceParam() { return DstResourceParam; }
- Dispatch를 정의했습니다.
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);
FRHIComputeShader* ShaderRHI = RHICmdList.GetBoundComputeShader();
SetShaderValue(RHICmdList, ShaderRHI, SrcOffsetParam, SrcOffset);
SetShaderValue(RHICmdList, ShaderRHI, DstOffsetParam, DstOffset);
SetShaderValue(RHICmdList, ShaderRHI, DimensionsParam, Dimensions);
RHICmdList.DispatchComputeShader(
FMath::DivideAndRoundUp(uint32(Dimensions.X), Context.ThreadGroupSizeX),
FMath::DivideAndRoundUp(uint32(Dimensions.Y), Context.ThreadGroupSizeY),
FMath::DivideAndRoundUp(uint32(Dimensions.Z), Context.ThreadGroupSizeZ)
);
}
- SetShaderValue는 D:\Program Files\Epic Games\UE_5.0\Engine\Source\Runtime\RenderCore\Public\ShaderParameterUtils.h에 정의되어 있습니다.
- 템플릿의 세이더 유형에 대해서 매개변수의 값을 설정합니다.
- 그 외에 유용한 유틸들이 많습니다.
Code
```cpp
template<typename ShaderRHIParamRef, class ParameterType, typename TRHICmdList>
void SetShaderValue(
TRHICmdList& RHICmdList,
const ShaderRHIParamRef& Shader,
const FShaderParameter& Parameter,
const ParameterType& Value,
uint32 ElementIndex = 0
)
{
static_assert(!TIsPointer::Value, "Passing by value is not valid.");
const uint32 AlignedTypeSize = (uint32)Align(sizeof(ParameterType), SHADER_PARAMETER_ARRAY_ELEMENT_ALIGNMENT);
const int32 NumBytesToSet = FMath::Min(sizeof(ParameterType),Parameter.GetNumBytes() - ElementIndex * AlignedTypeSize);
// This will trigger if the parameter was not serialized
checkSlow(Parameter.IsInitialized());
if(NumBytesToSet > 0)
{
RHICmdList.SetShaderParameter(
Shader,
Parameter.GetBufferIndex(),
Parameter.GetBaseIndex() + ElementIndex * AlignedTypeSize,
(uint32)NumBytesToSet,
&Value
);
}
}
```
</detail>
* 어떤 쉐이더를 이용할지에 대해 템플릿으로 구현되어 있습니다.
```cpp
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 <ECopyTextureResourceType SrcType, ECopyTextureResourceType DstType>
static inline TShaderRef SelectShader(FGlobalShaderMap* GlobalShaderMap, ECopyTextureValueType ValueType, CopyTextureCS::DispatchContext& OutContext);
```
하단에 정의되어 있습니다.
```cpp
template
inline TShaderRef FCopyTextureCS::SelectShader(FGlobalShaderMap* GlobalShaderMap, CopyTextureCS::DispatchContext& OutContext)
{
TShaderRef Shader = GlobalShaderMap->GetShader();
Shader->GetDispatchContext(OutContext);
return Shader;
}
template <ECopyTextureResourceType SrcType, ECopyTextureResourceType DstType>
inline TShaderRef FCopyTextureCS::SelectShader(FGlobalShaderMap* GlobalShaderMap, ECopyTextureValueType ValueType, CopyTextureCS::DispatchContext& OutContext)
{
switch (ValueType)
{
default: checkNoEntry();
case ECopyTextureValueType::Float: return SelectShader<TCopyResourceCS<SrcType, DstType, ECopyTextureValueType::Float, 4>>(GlobalShaderMap, OutContext);
case ECopyTextureValueType::Int32: return SelectShader<TCopyResourceCS<SrcType, DstType, ECopyTextureValueType::Int32, 4>>(GlobalShaderMap, OutContext);
case ECopyTextureValueType::Uint32: return SelectShader<TCopyResourceCS<SrcType, DstType, ECopyTextureValueType::Uint32, 4>>(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<SrcType, ECopyTextureResourceType::Texture2D >(GlobalShaderMap, ValueType, OutContext);
case ECopyTextureResourceType::Texture2DArray: return FCopyTextureCS::SelectShader<SrcType, ECopyTextureResourceType::Texture2DArray>(GlobalShaderMap, ValueType, OutContext);
case ECopyTextureResourceType::Texture3D: return FCopyTextureCS::SelectShader<SrcType, ECopyTextureResourceType::Texture3D >(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<ECopyTextureResourceType::Texture2D >(GlobalShaderMap, DstType, ValueType, OutContext);
case ECopyTextureResourceType::Texture2DArray: return FCopyTextureCS::SelectShader<ECopyTextureResourceType::Texture2DArray>(GlobalShaderMap, DstType, ValueType, OutContext);
case ECopyTextureResourceType::Texture3D: return FCopyTextureCS::SelectShader<ECopyTextureResourceType::Texture3D >(GlobalShaderMap, DstType, ValueType, OutContext);
}
}
```
</detail>
* 변수로 사용할 파라메터를 정의하는 부분입니다.
```cpp
... 클래스 선언 ...
LAYOUT_FIELD(FShaderParameter, DstOffsetParam);
LAYOUT_FIELD(FShaderParameter, SrcOffsetParam);
LAYOUT_FIELD(FShaderParameter, DimensionsParam);
LAYOUT_FIELD(FShaderResourceParameter, SrcResourceParam);
LAYOUT_FIELD(FShaderResourceParameter, DstResourceParam);
};
```
* 이부분은 제대로 찾은건지 모르겠습니다. CopyTextureShader.usf입니다.
.usf파일
```cpp
// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
CopyTextureShaders.usf:
Generic shader for copying 2D, 2D Array and 3D texture resources
=============================================================================*/
#include "Common.ush"
uint3 DstOffset; // Front upper left texel in the destination texture to start writing data to
uint3 SrcOffset; // Front upper left texel in the source texture to start reading data from
uint3 Dimensions; // The total x,y,z number of texels in the copy region
#if SRC_TYPE == 0
Texture2D SrcResource;
#define SRC_ADDR(p,o) ((p).xy + (o).xy)
#elif SRC_TYPE == 1
Texture2DArray SrcResource;
#define SRC_ADDR(p,o) ((p).xyz + (o).xyz)
#elif SRC_TYPE == 2
Texture3D SrcResource;
#define SRC_ADDR(p,o) ((p).xyz + (o).xyz)
#endif
#if DST_TYPE == 0
RWTexture2D DstResource;
#define DST_ADDR(p,o) ((p).xy + (o).xy)
#elif DST_TYPE == 1
RWTexture2DArray DstResource;
#define DST_ADDR(p,o) ((p).xyz + (o).xyz)
#elif DST_TYPE == 2
RWTexture3D DstResource;
#define DST_ADDR(p,o) ((p).xyz + (o).xyz)
#endif
#define COMP(a,b) (((a).x < (b).x) && ((a).y < (b).y) && ((a).z < (b).z))
[numthreads(THREADGROUPSIZE_X, THREADGROUPSIZE_Y, THREADGROUPSIZE_Z)]
void CopyTextureCS(uint3 Position : SV_DispatchThreadID)
{
if (COMP(Position, Dimensions))
{
DstResource[DST_ADDR(Position, DstOffset)] = SrcResource[SRC_ADDR(Position, SrcOffset)];
}
}
```
</detail>