2020-01-24 23:36:12 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2020-01-24 18:07:01 -05:00
# include "UnifiedBuffer.h"
2023-01-27 14:54:10 -05:00
# include "Containers/ResourceArray.h"
2020-01-24 18:07:01 -05:00
# include "RHI.h"
# include "ShaderParameters.h"
# include "ShaderParameterStruct.h"
# include "Shader.h"
# include "GlobalShader.h"
# include "RenderGraphUtils.h"
2024-06-03 22:54:22 -04:00
# include "RHIResourceUtils.h"
2022-12-08 15:35:35 -05:00
# include "DataDrivenShaderPlatformInfo.h"
2020-01-24 18:07:01 -05:00
2023-03-27 23:25:48 -04:00
// Uploads use a storage buffers which are at least 128m elements
static uint64 GetMaxUploadBufferElements ( )
{
return ( 1 < < 27 ) ;
}
2021-08-03 07:56:47 -04:00
enum class EByteBufferResourceType
{
2021-09-01 19:20:47 -04:00
Float4_Buffer ,
2023-04-19 04:53:37 -04:00
StructuredBuffer ,
2021-08-03 07:56:47 -04:00
Uint_Buffer ,
Uint4Aligned_Buffer ,
Float4_Texture ,
Count
} ;
2023-04-19 04:53:37 -04:00
enum class EByteBufferStructuredSize
{
Uint1 ,
Uint2 ,
Uint4 ,
Uint8 ,
Count
} ;
// placeholder struct, not really used (on the host side)
struct FUint8
{
uint32 Values [ 8 ] ;
} ;
2020-01-24 18:07:01 -05:00
class FByteBufferShader : public FGlobalShader
{
2021-08-03 07:56:47 -04:00
DECLARE_INLINE_TYPE_LAYOUT ( FByteBufferShader , NonVirtual ) ;
2020-01-24 18:07:01 -05:00
FByteBufferShader ( ) { }
2021-08-03 07:56:47 -04:00
FByteBufferShader ( const ShaderMetaType : : CompiledShaderInitializerType & Initializer )
: FGlobalShader ( Initializer )
2020-01-24 18:07:01 -05:00
{ }
2021-08-03 07:56:47 -04:00
class ResourceTypeDim : SHADER_PERMUTATION_INT ( " RESOURCE_TYPE " , ( int ) EByteBufferResourceType : : Count ) ;
2023-04-19 04:53:37 -04:00
class StructuredElementSizeDim : SHADER_PERMUTATION_INT ( " STRUCTURED_ELEMENT_SIZE " , ( int ) EByteBufferStructuredSize : : Count ) ;
2020-01-24 18:07:01 -05:00
2023-04-19 04:53:37 -04:00
using FPermutationDomain = TShaderPermutationDomain < ResourceTypeDim , StructuredElementSizeDim > ;
2020-01-24 18:07:01 -05:00
static bool ShouldCompilePermutation ( const FGlobalShaderPermutationParameters & Parameters )
{
FPermutationDomain PermutationVector ( Parameters . PermutationId ) ;
2021-08-03 07:56:47 -04:00
EByteBufferResourceType ResourceType = ( EByteBufferResourceType ) PermutationVector . Get < ResourceTypeDim > ( ) ;
if ( ResourceType = = EByteBufferResourceType : : Uint_Buffer | | ResourceType = = EByteBufferResourceType : : Uint4Aligned_Buffer )
2020-01-24 18:07:01 -05:00
{
2021-11-18 14:37:34 -05:00
return FDataDrivenShaderPlatformInfo : : GetSupportsByteBufferComputeShaders ( Parameters . Platform ) ;
2020-01-24 18:07:01 -05:00
}
2023-11-06 11:33:49 -05:00
// Don't compile structured buffer size variations unless we need them
else if ( ResourceType ! = EByteBufferResourceType : : StructuredBuffer & & static_cast < EByteBufferStructuredSize > ( PermutationVector . Get < StructuredElementSizeDim > ( ) ) ! = EByteBufferStructuredSize : : Uint4 )
{
return false ;
}
2021-08-03 07:56:47 -04:00
else
{
2022-09-07 10:18:52 -04:00
return true ;
2021-08-03 07:56:47 -04:00
}
2023-04-19 04:53:37 -04:00
2020-02-12 13:27:19 -05:00
}
2020-01-24 18:07:01 -05:00
BEGIN_SHADER_PARAMETER_STRUCT ( FParameters , )
2020-02-12 13:27:19 -05:00
SHADER_PARAMETER ( uint32 , Value )
SHADER_PARAMETER ( uint32 , Size )
SHADER_PARAMETER ( uint32 , SrcOffset )
SHADER_PARAMETER ( uint32 , DstOffset )
SHADER_PARAMETER ( uint32 , Float4sPerLine )
2021-09-01 19:20:47 -04:00
SHADER_PARAMETER_UAV ( RWBuffer < float4 > , DstBuffer )
2023-04-19 04:53:37 -04:00
SHADER_PARAMETER_UAV ( RWStructuredBuffer < float4 > , DstStructuredBuffer4x )
2020-02-12 13:27:19 -05:00
SHADER_PARAMETER_UAV ( RWByteAddressBuffer , DstByteAddressBuffer )
SHADER_PARAMETER_UAV ( RWTexture2D < float4 > , DstTexture )
2020-01-24 18:07:01 -05:00
END_SHADER_PARAMETER_STRUCT ( )
} ;
class FMemsetBufferCS : public FByteBufferShader
{
DECLARE_GLOBAL_SHADER ( FMemsetBufferCS ) ;
SHADER_USE_PARAMETER_STRUCT ( FMemsetBufferCS , FByteBufferShader ) ;
2023-04-19 04:53:37 -04:00
static bool ShouldCompilePermutation ( const FGlobalShaderPermutationParameters & Parameters )
{
FPermutationDomain PermutationVector ( Parameters . PermutationId ) ;
// Don't compile structured buffer size variations
if ( static_cast < EByteBufferStructuredSize > ( PermutationVector . Get < StructuredElementSizeDim > ( ) ) ! = EByteBufferStructuredSize : : Uint4 )
{
return false ;
}
return FByteBufferShader : : ShouldCompilePermutation ( Parameters ) ;
}
2020-01-24 18:07:01 -05:00
} ;
IMPLEMENT_GLOBAL_SHADER ( FMemsetBufferCS , " /Engine/Private/ByteBuffer.usf " , " MemsetBufferCS " , SF_Compute ) ;
2021-08-03 07:56:47 -04:00
class FMemcpyCS : public FByteBufferShader
2020-01-24 18:07:01 -05:00
{
2021-08-03 07:56:47 -04:00
DECLARE_GLOBAL_SHADER ( FMemcpyCS ) ;
SHADER_USE_PARAMETER_STRUCT ( FMemcpyCS , FByteBufferShader ) ;
2023-04-19 04:53:37 -04:00
static bool ShouldCompilePermutation ( const FGlobalShaderPermutationParameters & Parameters )
{
FPermutationDomain PermutationVector ( Parameters . PermutationId ) ;
// Don't compile structured buffer size variations
if ( static_cast < EByteBufferStructuredSize > ( PermutationVector . Get < StructuredElementSizeDim > ( ) ) ! = EByteBufferStructuredSize : : Uint4 )
{
return false ;
}
return FByteBufferShader : : ShouldCompilePermutation ( Parameters ) ;
}
2020-02-12 13:27:19 -05:00
BEGIN_SHADER_PARAMETER_STRUCT ( FParameters , )
SHADER_PARAMETER_STRUCT_INCLUDE ( FByteBufferShader : : FParameters , Common )
2021-09-01 19:20:47 -04:00
SHADER_PARAMETER_SRV ( Buffer < float4 > , SrcBuffer )
2023-04-19 04:53:37 -04:00
SHADER_PARAMETER_SRV ( StructuredBuffer < float4 > , SrcStructuredBuffer4x )
2021-08-03 07:56:47 -04:00
SHADER_PARAMETER_SRV ( ByteAddressBuffer , SrcByteAddressBuffer )
2020-02-12 13:27:19 -05:00
SHADER_PARAMETER_SRV ( Texture2D < float4 > , SrcTexture )
END_SHADER_PARAMETER_STRUCT ( )
2020-01-24 18:07:01 -05:00
} ;
2021-08-03 07:56:47 -04:00
IMPLEMENT_GLOBAL_SHADER ( FMemcpyCS , " /Engine/Private/ByteBuffer.usf " , " MemcpyCS " , SF_Compute ) ;
2020-01-24 18:07:01 -05:00
class FScatterCopyCS : public FByteBufferShader
{
DECLARE_GLOBAL_SHADER ( FScatterCopyCS ) ;
SHADER_USE_PARAMETER_STRUCT ( FScatterCopyCS , FByteBufferShader ) ;
2023-04-19 04:53:37 -04:00
static bool ShouldCompilePermutation ( const FGlobalShaderPermutationParameters & Parameters )
{
FPermutationDomain PermutationVector ( Parameters . PermutationId ) ;
// Don't compile structured buffer size variations
if ( static_cast < EByteBufferStructuredSize > ( PermutationVector . Get < StructuredElementSizeDim > ( ) ) ! = EByteBufferStructuredSize : : Uint4 )
{
return false ;
}
return FByteBufferShader : : ShouldCompilePermutation ( Parameters ) ;
}
2020-02-12 13:27:19 -05:00
BEGIN_SHADER_PARAMETER_STRUCT ( FParameters , )
SHADER_PARAMETER_STRUCT_INCLUDE ( FByteBufferShader : : FParameters , Common )
SHADER_PARAMETER ( uint32 , NumScatters )
SHADER_PARAMETER_SRV ( ByteAddressBuffer , UploadByteAddressBuffer )
2023-04-19 04:53:37 -04:00
SHADER_PARAMETER_SRV ( StructuredBuffer < float4 > , UploadStructuredBuffer4x )
2020-02-12 13:27:19 -05:00
SHADER_PARAMETER_SRV ( ByteAddressBuffer , ScatterByteAddressBuffer )
SHADER_PARAMETER_SRV ( StructuredBuffer < uint > , ScatterStructuredBuffer )
2020-01-24 18:07:01 -05:00
END_SHADER_PARAMETER_STRUCT ( )
} ;
IMPLEMENT_GLOBAL_SHADER ( FScatterCopyCS , " /Engine/Private/ByteBuffer.usf " , " ScatterCopyCS " , SF_Compute ) ;
2020-02-12 13:27:19 -05:00
enum class EResourceType
2020-01-24 18:07:01 -05:00
{
2021-09-01 19:20:47 -04:00
BUFFER ,
2021-08-03 07:56:47 -04:00
STRUCTURED_BUFFER ,
2020-02-12 13:27:19 -05:00
BYTEBUFFER ,
2023-05-01 12:39:32 -04:00
TEXTURE // NOTE: Deprecated
2020-02-12 13:27:19 -05:00
} ;
2020-01-24 18:07:01 -05:00
2020-02-12 13:27:19 -05:00
template < typename ResourceType >
struct ResourceTypeTraits ;
2020-01-24 18:07:01 -05:00
2021-09-01 19:20:47 -04:00
template < >
struct ResourceTypeTraits < FRWBuffer >
{
static const EResourceType Type = EResourceType : : BUFFER ;
} ;
2020-02-12 13:27:19 -05:00
template < >
struct ResourceTypeTraits < FRWBufferStructured >
2020-01-24 18:07:01 -05:00
{
2021-08-03 07:56:47 -04:00
static const EResourceType Type = EResourceType : : STRUCTURED_BUFFER ;
2020-02-12 13:27:19 -05:00
} ;
2020-01-24 18:07:01 -05:00
2023-05-01 12:39:32 -04:00
// NOTE: Deprecated
2020-02-12 13:27:19 -05:00
template < >
2022-03-30 13:36:17 -04:00
struct ResourceTypeTraits < FTextureRWBuffer >
2020-01-24 18:07:01 -05:00
{
2020-02-12 13:27:19 -05:00
static const EResourceType Type = EResourceType : : TEXTURE ;
} ;
2020-01-24 18:07:01 -05:00
2020-02-12 13:27:19 -05:00
template < >
struct ResourceTypeTraits < FRWByteAddressBuffer >
{
static const EResourceType Type = EResourceType : : BYTEBUFFER ;
} ;
2021-08-03 07:56:47 -04:00
static uint32 CalculateFloat4sPerLine ( )
{
2023-05-01 12:39:32 -04:00
// This is a remnant from when primitive scene data used textures to scatter upload, and should be removed once
// texture uploads have been fully deprecated
PRAGMA_DISABLE_DEPRECATION_WARNINGS
2022-01-07 10:39:08 -05:00
uint16 PrimitivesPerTextureLine = ( uint16 ) FMath : : Min ( ( int32 ) MAX_uint16 , ( int32 ) GMaxTextureDimensions ) / FScatterUploadBuffer : : PrimitiveDataStrideInFloat4s ;
2021-08-03 07:56:47 -04:00
return PrimitivesPerTextureLine * FScatterUploadBuffer : : PrimitiveDataStrideInFloat4s ;
2023-05-01 12:39:32 -04:00
PRAGMA_ENABLE_DEPRECATION_WARNINGS
2021-08-03 07:56:47 -04:00
}
2022-04-25 12:25:24 -04:00
///////////////////////////////////////////////////////////////////////////////////////////////////
class FRDGByteBufferShader : public FGlobalShader
{
DECLARE_INLINE_TYPE_LAYOUT ( FRDGByteBufferShader , NonVirtual ) ;
FRDGByteBufferShader ( ) { }
FRDGByteBufferShader ( const ShaderMetaType : : CompiledShaderInitializerType & Initializer )
: FGlobalShader ( Initializer )
{ }
2023-04-19 04:53:37 -04:00
using ResourceTypeDim = FByteBufferShader : : ResourceTypeDim ;
using StructuredElementSizeDim = FByteBufferShader : : StructuredElementSizeDim ;
using FPermutationDomain = FByteBufferShader : : FPermutationDomain ;
2022-04-25 12:25:24 -04:00
static bool ShouldCompilePermutation ( const FGlobalShaderPermutationParameters & Parameters )
{
return FByteBufferShader : : ShouldCompilePermutation ( Parameters ) ;
}
BEGIN_SHADER_PARAMETER_STRUCT ( FParameters , )
SHADER_PARAMETER ( uint32 , Value )
SHADER_PARAMETER ( uint32 , Size )
SHADER_PARAMETER ( uint32 , SrcOffset )
SHADER_PARAMETER ( uint32 , DstOffset )
SHADER_PARAMETER ( uint32 , Float4sPerLine )
SHADER_PARAMETER_RDG_BUFFER_UAV ( RWBuffer < float4 > , DstBuffer )
2023-04-19 04:53:37 -04:00
SHADER_PARAMETER_RDG_BUFFER_UAV ( RWStructuredBuffer < FUint8 > , DstStructuredBuffer8x )
SHADER_PARAMETER_RDG_BUFFER_UAV ( RWStructuredBuffer < uint4 > , DstStructuredBuffer4x )
SHADER_PARAMETER_RDG_BUFFER_UAV ( RWStructuredBuffer < uint2 > , DstStructuredBuffer2x )
SHADER_PARAMETER_RDG_BUFFER_UAV ( RWStructuredBuffer < uint > , DstStructuredBuffer1x )
2022-04-25 12:25:24 -04:00
SHADER_PARAMETER_RDG_BUFFER_UAV ( RWByteAddressBuffer , DstByteAddressBuffer )
SHADER_PARAMETER_RDG_TEXTURE_UAV ( RWTexture2D < float4 > , DstTexture )
END_SHADER_PARAMETER_STRUCT ( )
} ;
class FRDGMemsetBufferCS : public FRDGByteBufferShader
{
DECLARE_GLOBAL_SHADER ( FRDGMemsetBufferCS ) ;
SHADER_USE_PARAMETER_STRUCT ( FRDGMemsetBufferCS , FRDGByteBufferShader ) ;
} ;
IMPLEMENT_GLOBAL_SHADER ( FRDGMemsetBufferCS , " /Engine/Private/ByteBuffer.usf " , " MemsetBufferCS " , SF_Compute ) ;
class FRDGMemcpyCS : public FRDGByteBufferShader
{
DECLARE_GLOBAL_SHADER ( FRDGMemcpyCS ) ;
SHADER_USE_PARAMETER_STRUCT ( FRDGMemcpyCS , FRDGByteBufferShader ) ;
BEGIN_SHADER_PARAMETER_STRUCT ( FParameters , )
SHADER_PARAMETER_STRUCT_INCLUDE ( FRDGByteBufferShader : : FParameters , Common )
SHADER_PARAMETER_RDG_BUFFER_SRV ( Buffer < float4 > , SrcBuffer )
2023-04-19 04:53:37 -04:00
SHADER_PARAMETER_RDG_BUFFER_SRV ( StructuredBuffer < FUint8 > , SrcStructuredBuffer8x )
SHADER_PARAMETER_RDG_BUFFER_SRV ( StructuredBuffer < uint4 > , SrcStructuredBuffer4x )
SHADER_PARAMETER_RDG_BUFFER_SRV ( StructuredBuffer < uint2 > , SrcStructuredBuffer2x )
SHADER_PARAMETER_RDG_BUFFER_SRV ( StructuredBuffer < uint > , SrcStructuredBuffer1x )
2022-04-25 12:25:24 -04:00
SHADER_PARAMETER_RDG_BUFFER_SRV ( ByteAddressBuffer , SrcByteAddressBuffer )
SHADER_PARAMETER_RDG_TEXTURE_SRV ( Texture2D < float4 > , SrcTexture )
END_SHADER_PARAMETER_STRUCT ( )
} ;
IMPLEMENT_GLOBAL_SHADER ( FRDGMemcpyCS , " /Engine/Private/ByteBuffer.usf " , " MemcpyCS " , SF_Compute ) ;
class FRDGScatterCopyCS : public FRDGByteBufferShader
{
DECLARE_GLOBAL_SHADER ( FRDGScatterCopyCS ) ;
SHADER_USE_PARAMETER_STRUCT ( FRDGScatterCopyCS , FRDGByteBufferShader ) ;
BEGIN_SHADER_PARAMETER_STRUCT ( FParameters , )
SHADER_PARAMETER_STRUCT_INCLUDE ( FRDGByteBufferShader : : FParameters , Common )
SHADER_PARAMETER ( uint32 , NumScatters )
SHADER_PARAMETER_RDG_BUFFER_SRV ( ByteAddressBuffer , UploadByteAddressBuffer )
2023-04-19 04:53:37 -04:00
SHADER_PARAMETER_RDG_BUFFER_SRV ( StructuredBuffer < FUint8 > , UploadStructuredBuffer8x )
SHADER_PARAMETER_RDG_BUFFER_SRV ( StructuredBuffer < uint4 > , UploadStructuredBuffer4x )
SHADER_PARAMETER_RDG_BUFFER_SRV ( StructuredBuffer < uint2 > , UploadStructuredBuffer2x )
SHADER_PARAMETER_RDG_BUFFER_SRV ( StructuredBuffer < uint > , UploadStructuredBuffer1x )
2022-04-25 12:25:24 -04:00
SHADER_PARAMETER_RDG_BUFFER_SRV ( ByteAddressBuffer , ScatterByteAddressBuffer )
SHADER_PARAMETER_RDG_BUFFER_SRV ( StructuredBuffer < uint > , ScatterStructuredBuffer )
END_SHADER_PARAMETER_STRUCT ( )
} ;
IMPLEMENT_GLOBAL_SHADER ( FRDGScatterCopyCS , " /Engine/Private/ByteBuffer.usf " , " ScatterCopyCS " , SF_Compute ) ;
EResourceType GetBufferType ( FRDGBuffer * Buffer )
{
const FRDGBufferDesc & Desc = Buffer - > Desc ;
2022-05-06 15:44:23 -04:00
if ( EnumHasAnyFlags ( Desc . Usage , EBufferUsageFlags : : ByteAddressBuffer ) )
2022-04-25 12:25:24 -04:00
{
2022-05-06 15:44:23 -04:00
return EResourceType : : BYTEBUFFER ;
}
else if ( EnumHasAnyFlags ( Desc . Usage , EBufferUsageFlags : : StructuredBuffer ) )
{
return EResourceType : : STRUCTURED_BUFFER ;
2022-04-25 12:25:24 -04:00
}
else
{
return EResourceType : : BUFFER ;
}
}
EResourceType GetResourceType ( FRDGViewableResource * Resource )
{
check ( Resource ) ;
switch ( Resource - > Type )
{
case ERDGViewableResourceType : : Texture :
return EResourceType : : TEXTURE ;
case ERDGViewableResourceType : : Buffer :
return GetBufferType ( GetAsBuffer ( Resource ) ) ;
}
checkNoEntry ( ) ;
return EResourceType : : BUFFER ;
}
2022-05-02 19:28:19 -04:00
void MemsetResource ( FRDGBuilder & GraphBuilder , FRDGBuffer * DstResource , const FMemsetResourceParams & Params )
2022-04-25 12:25:24 -04:00
{
2022-05-02 19:28:19 -04:00
MemsetResource ( GraphBuilder , GraphBuilder . CreateUAV ( DstResource , ERDGUnorderedAccessViewFlags : : SkipBarrier ) , Params ) ;
}
void MemcpyResource ( FRDGBuilder & GraphBuilder , FRDGBuffer * DstResource , FRDGBuffer * SrcResource , const FMemcpyResourceParams & Params )
{
MemcpyResource ( GraphBuilder , GraphBuilder . CreateUAV ( DstResource , ERDGUnorderedAccessViewFlags : : SkipBarrier ) , GraphBuilder . CreateSRV ( SrcResource ) , Params ) ;
}
2023-04-19 04:53:37 -04:00
static EByteBufferStructuredSize GetStructuredBufferElementSize ( FRDGBufferUAV * RDGBufferUAV )
{
int32 BytesPerElement = RDGBufferUAV - > Desc . Buffer - > Desc . BytesPerElement ;
uint32 Log2NumElements = FMath : : FloorLog2 ( BytesPerElement / 4 ) ;
checkf ( ( BytesPerElement % 4 ) = = 0 & & FMath : : IsPowerOfTwo ( BytesPerElement / 4 ) & & Log2NumElements < uint32 ( EByteBufferStructuredSize : : Count ) , TEXT ( " Unsupported structured buffer BytesPerElement size (%d) for buffer '%s' (supported sizes are 4,8,16,32). " ) , BytesPerElement , RDGBufferUAV - > Name ) ;
return static_cast < EByteBufferStructuredSize > ( Log2NumElements ) ;
}
2022-05-02 19:28:19 -04:00
void MemsetResource ( FRDGBuilder & GraphBuilder , FRDGUnorderedAccessView * UAV , const FMemsetResourceParams & Params )
{
check ( UAV ) ;
FRDGViewableResource * Resource = UAV - > GetParent ( ) ;
2022-04-25 12:25:24 -04:00
EByteBufferResourceType ResourceTypeEnum = EByteBufferResourceType : : Count ;
2023-04-19 04:53:37 -04:00
// This is only used for structured buffers, since that is where we must match the format specified when it is created / used or whatever the platform happens to care about.
EByteBufferStructuredSize ByteBufferStructuredSize = EByteBufferStructuredSize : : Uint4 ;
2022-04-25 12:25:24 -04:00
auto * PassParameters = GraphBuilder . AllocParameters < FRDGMemsetBufferCS : : FParameters > ( ) ;
PassParameters - > Value = Params . Value ;
PassParameters - > Size = Params . Count ;
PassParameters - > DstOffset = Params . DstOffset ;
// each thread will set 4 floats / uints
uint32 Divisor = 1 ;
switch ( GetResourceType ( Resource ) )
{
case EResourceType : : BYTEBUFFER :
ResourceTypeEnum = EByteBufferResourceType : : Uint_Buffer ;
2022-05-02 19:28:19 -04:00
PassParameters - > DstByteAddressBuffer = GetAs < FRDGBufferUAV > ( UAV ) ;
2022-04-25 12:25:24 -04:00
Divisor = 4 ;
break ;
case EResourceType : : BUFFER :
ResourceTypeEnum = EByteBufferResourceType : : Float4_Buffer ;
2022-05-02 19:28:19 -04:00
PassParameters - > DstBuffer = GetAs < FRDGBufferUAV > ( UAV ) ;
2022-04-25 12:25:24 -04:00
break ;
case EResourceType : : STRUCTURED_BUFFER :
2023-04-19 04:53:37 -04:00
{
ResourceTypeEnum = EByteBufferResourceType : : StructuredBuffer ;
FRDGBufferUAV * RDGBufferUAV = GetAs < FRDGBufferUAV > ( UAV ) ;
ByteBufferStructuredSize = GetStructuredBufferElementSize ( RDGBufferUAV ) ;
switch ( ByteBufferStructuredSize )
{
case EByteBufferStructuredSize : : Uint1 :
PassParameters - > DstStructuredBuffer1x = RDGBufferUAV ;
break ;
case EByteBufferStructuredSize : : Uint2 :
PassParameters - > DstStructuredBuffer2x = RDGBufferUAV ;
break ;
case EByteBufferStructuredSize : : Uint4 :
PassParameters - > DstStructuredBuffer4x = RDGBufferUAV ;
break ;
case EByteBufferStructuredSize : : Uint8 :
PassParameters - > DstStructuredBuffer8x = RDGBufferUAV ;
break ;
default :
break ;
} ;
2022-04-25 12:25:24 -04:00
break ;
2023-04-19 04:53:37 -04:00
}
2022-04-25 12:25:24 -04:00
case EResourceType : : TEXTURE :
ResourceTypeEnum = EByteBufferResourceType : : Float4_Texture ;
2022-05-02 19:28:19 -04:00
PassParameters - > DstTexture = GetAs < FRDGTextureUAV > ( UAV ) ;
2022-04-25 12:25:24 -04:00
PassParameters - > Float4sPerLine = CalculateFloat4sPerLine ( ) ;
break ;
default :
checkNoEntry ( ) ;
}
FRDGMemsetBufferCS : : FPermutationDomain PermutationVector ;
PermutationVector . Set < FRDGMemsetBufferCS : : ResourceTypeDim > ( ( int ) ResourceTypeEnum ) ;
2023-04-19 04:53:37 -04:00
PermutationVector . Set < FRDGMemsetBufferCS : : StructuredElementSizeDim > ( ( int ) ByteBufferStructuredSize ) ;
2022-04-25 12:25:24 -04:00
TShaderMapRef < FRDGMemsetBufferCS > ComputeShader ( GetGlobalShaderMap ( GMaxRHIFeatureLevel ) , PermutationVector ) ;
FComputeShaderUtils : : AddPass (
GraphBuilder ,
RDG_EVENT_NAME ( " MemsetResource (%s) " , Resource - > Name ) ,
ComputeShader ,
PassParameters ,
2024-08-22 05:51:11 -04:00
FComputeShaderUtils : : GetGroupCountWrapped ( Params . Count / Divisor , 64 ) ) ;
2022-04-25 12:25:24 -04:00
}
2023-05-01 12:39:32 -04:00
void MemsetResource ( FRDGBuilder & GraphBuilder , FRDGBufferUAV * UAV , const FMemsetResourceParams & Params )
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS
MemsetResource ( GraphBuilder , static_cast < FRDGUnorderedAccessView * > ( UAV ) , Params ) ;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
void MemsetResource ( FRDGBuilder & GraphBuilder , FRDGTextureUAV * UAV , const FMemsetResourceParams & Params )
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS
MemsetResource ( GraphBuilder , static_cast < FRDGUnorderedAccessView * > ( UAV ) , Params ) ;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
2022-05-02 19:28:19 -04:00
void MemcpyResource ( FRDGBuilder & GraphBuilder , FRDGUnorderedAccessView * UAV , FRDGShaderResourceView * SRV , const FMemcpyResourceParams & Params )
2022-04-25 12:25:24 -04:00
{
2022-05-02 19:28:19 -04:00
check ( UAV & & SRV ) ;
FRDGViewableResource * DstResource = UAV - > GetParent ( ) ;
FRDGViewableResource * SrcResource = SRV - > GetParent ( ) ;
2022-04-25 12:25:24 -04:00
const EResourceType ResourceType = GetResourceType ( DstResource ) ;
checkf ( ResourceType = = GetResourceType ( SrcResource ) , TEXT ( " Unable to MemcpyResource because the source and destination view types don't match. " ) ) ;
RDG_EVENT_SCOPE ( GraphBuilder , " Memcpy %s -> %s " , DstResource - > Name , SrcResource - > Name ) ;
// each thread will copy 4 floats / uints
const uint32 Divisor = ResourceType = = EResourceType : : BYTEBUFFER ? 4 : 1 ;
uint32 NumElementsProcessed = 0 ;
while ( NumElementsProcessed < Params . Count )
{
const uint32 NumWaves = FMath : : Max ( FMath : : Min < uint32 > ( GRHIMaxDispatchThreadGroupsPerDimension . X , FMath : : DivideAndRoundUp ( Params . Count / Divisor , 64u ) ) , 1u ) ;
const uint32 NumElementsPerDispatch = FMath : : Min ( FMath : : Max ( NumWaves , 1u ) * Divisor * 64 , Params . Count - NumElementsProcessed ) ;
EByteBufferResourceType ResourceTypeEnum = EByteBufferResourceType : : Count ;
2023-04-19 04:53:37 -04:00
EByteBufferStructuredSize ByteBufferStructuredSize = EByteBufferStructuredSize : : Uint4 ;
2022-04-25 12:25:24 -04:00
auto * PassParameters = GraphBuilder . AllocParameters < FRDGMemcpyCS : : FParameters > ( ) ;
PassParameters - > Common . Size = NumElementsPerDispatch ;
PassParameters - > Common . SrcOffset = ( Params . SrcOffset + NumElementsProcessed ) ;
PassParameters - > Common . DstOffset = ( Params . DstOffset + NumElementsProcessed ) ;
switch ( ResourceType )
{
case EResourceType : : BYTEBUFFER :
ResourceTypeEnum = EByteBufferResourceType : : Uint_Buffer ;
2022-05-02 19:28:19 -04:00
PassParameters - > SrcByteAddressBuffer = GetAs < FRDGBufferSRV > ( SRV ) ;
PassParameters - > Common . DstByteAddressBuffer = GetAs < FRDGBufferUAV > ( UAV ) ;
2022-04-25 12:25:24 -04:00
break ;
case EResourceType : : STRUCTURED_BUFFER :
2023-04-19 04:53:37 -04:00
{
ResourceTypeEnum = EByteBufferResourceType : : StructuredBuffer ;
FRDGBufferUAV * RDGBufferUAV = GetAs < FRDGBufferUAV > ( UAV ) ;
ByteBufferStructuredSize = GetStructuredBufferElementSize ( RDGBufferUAV ) ;
switch ( ByteBufferStructuredSize )
{
case EByteBufferStructuredSize : : Uint1 :
PassParameters - > SrcStructuredBuffer1x = GetAs < FRDGBufferSRV > ( SRV ) ;
PassParameters - > Common . DstStructuredBuffer1x = RDGBufferUAV ;
break ;
case EByteBufferStructuredSize : : Uint2 :
PassParameters - > SrcStructuredBuffer2x = GetAs < FRDGBufferSRV > ( SRV ) ;
PassParameters - > Common . DstStructuredBuffer2x = RDGBufferUAV ;
break ;
case EByteBufferStructuredSize : : Uint4 :
PassParameters - > SrcStructuredBuffer4x = GetAs < FRDGBufferSRV > ( SRV ) ;
PassParameters - > Common . DstStructuredBuffer4x = RDGBufferUAV ;
break ;
case EByteBufferStructuredSize : : Uint8 :
PassParameters - > SrcStructuredBuffer8x = GetAs < FRDGBufferSRV > ( SRV ) ;
PassParameters - > Common . DstStructuredBuffer8x = RDGBufferUAV ;
break ;
default :
break ;
} ;
2022-04-25 12:25:24 -04:00
break ;
2023-04-19 04:53:37 -04:00
}
2022-04-25 12:25:24 -04:00
case EResourceType : : BUFFER :
ResourceTypeEnum = EByteBufferResourceType : : Float4_Buffer ;
2022-05-02 19:28:19 -04:00
PassParameters - > SrcBuffer = GetAs < FRDGBufferSRV > ( SRV ) ;
PassParameters - > Common . DstBuffer = GetAs < FRDGBufferUAV > ( UAV ) ;
2022-04-25 12:25:24 -04:00
break ;
case EResourceType : : TEXTURE :
ResourceTypeEnum = EByteBufferResourceType : : Float4_Texture ;
2022-05-02 19:28:19 -04:00
PassParameters - > SrcTexture = GetAs < FRDGTextureSRV > ( SRV ) ;
PassParameters - > Common . DstTexture = GetAs < FRDGTextureUAV > ( UAV ) ;
2022-04-25 12:25:24 -04:00
PassParameters - > Common . Float4sPerLine = CalculateFloat4sPerLine ( ) ;
break ;
default :
checkNoEntry ( ) ;
}
FRDGMemcpyCS : : FPermutationDomain PermutationVector ;
PermutationVector . Set < FRDGMemcpyCS : : ResourceTypeDim > ( ( int ) ResourceTypeEnum ) ;
2023-04-19 04:53:37 -04:00
PermutationVector . Set < FRDGMemcpyCS : : StructuredElementSizeDim > ( ( int ) ByteBufferStructuredSize ) ;
2022-04-25 12:25:24 -04:00
TShaderMapRef < FRDGMemcpyCS > ComputeShader ( GetGlobalShaderMap ( GMaxRHIFeatureLevel ) , PermutationVector ) ;
FComputeShaderUtils : : AddPass (
GraphBuilder ,
RDG_EVENT_NAME ( " Offset[%d] Count[%d] " , NumElementsProcessed , NumElementsPerDispatch ) ,
ComputeShader ,
PassParameters ,
FIntVector ( NumWaves , 1 , 1 ) ) ;
NumElementsProcessed + = NumElementsPerDispatch ;
}
}
2023-05-01 12:39:32 -04:00
void MemcpyResource ( FRDGBuilder & GraphBuilder , FRDGBufferUAV * UAV , FRDGBufferSRV * SRV , const FMemcpyResourceParams & Params )
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS
MemcpyResource ( GraphBuilder , static_cast < FRDGUnorderedAccessView * > ( UAV ) , static_cast < FRDGShaderResourceView * > ( SRV ) , Params ) ;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
void MemcpyResource ( FRDGBuilder & GraphBuilder , FRDGTextureUAV * UAV , FRDGTextureSRV * SRV , const FMemcpyResourceParams & Params )
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS
MemcpyResource ( GraphBuilder , static_cast < FRDGUnorderedAccessView * > ( UAV ) , static_cast < FRDGShaderResourceView * > ( SRV ) , Params ) ;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
2022-04-25 12:25:24 -04:00
FRDGBuffer * ResizeBufferIfNeeded ( FRDGBuilder & GraphBuilder , TRefCountPtr < FRDGPooledBuffer > & ExternalBuffer , const FRDGBufferDesc & BufferDesc , const TCHAR * Name )
{
FRDGBuffer * InternalBufferNew = nullptr ;
if ( ! ExternalBuffer )
{
InternalBufferNew = GraphBuilder . CreateBuffer ( BufferDesc , Name ) ;
ExternalBuffer = GraphBuilder . ConvertToExternalBuffer ( InternalBufferNew ) ;
return InternalBufferNew ;
}
2023-11-09 21:34:39 -05:00
const uint32 BufferSizeNew = BufferDesc . GetSize ( ) ;
const uint32 BufferSizeOld = ExternalBuffer - > GetCommittedSize ( ) ;
2022-04-25 12:25:24 -04:00
FRDGBuffer * InternalBufferOld = GraphBuilder . RegisterExternalBuffer ( ExternalBuffer ) ;
2023-11-09 21:34:39 -05:00
if ( BufferSizeNew = = BufferSizeOld )
{
return InternalBufferOld ;
}
2022-04-25 12:25:24 -04:00
2023-11-09 21:34:39 -05:00
if ( EnumHasAllFlags ( ExternalBuffer - > Desc . Usage , EBufferUsageFlags : : ReservedResource )
& & ensureMsgf ( ExternalBuffer - > GetSize ( ) > = BufferSizeNew , TEXT ( " Reserved buffers can't grow beyond the size specified at creation " ) ) )
{
GraphBuilder . QueueCommitReservedBuffer ( InternalBufferOld , BufferSizeNew ) ;
return InternalBufferOld ;
}
else
2022-04-25 12:25:24 -04:00
{
InternalBufferNew = GraphBuilder . CreateBuffer ( BufferDesc , Name ) ;
ExternalBuffer = GraphBuilder . ConvertToExternalBuffer ( InternalBufferNew ) ;
// Copy data to new buffer
FMemcpyResourceParams Params ;
2023-11-09 21:34:39 -05:00
Params . Count = FMath : : Min ( BufferSizeNew , BufferSizeOld ) / BufferDesc . BytesPerElement ;
2022-04-25 12:25:24 -04:00
Params . SrcOffset = 0 ;
Params . DstOffset = 0 ;
MemcpyResource ( GraphBuilder , InternalBufferNew , InternalBufferOld , Params ) ;
return InternalBufferNew ;
}
}
FRDGBuffer * ResizeBufferIfNeeded ( FRDGBuilder & GraphBuilder , TRefCountPtr < FRDGPooledBuffer > & ExternalBuffer , EPixelFormat Format , uint32 NumElements , const TCHAR * Name )
{
const uint32 BytesPerElement = GPixelFormats [ Format ] . BlockBytes ;
return ResizeBufferIfNeeded ( GraphBuilder , ExternalBuffer , FRDGBufferDesc : : CreateBufferDesc ( BytesPerElement , NumElements ) , Name ) ;
}
FRDGBuffer * ResizeStructuredBufferIfNeeded ( FRDGBuilder & GraphBuilder , TRefCountPtr < FRDGPooledBuffer > & ExternalBuffer , uint32 NumBytes , const TCHAR * Name )
{
const uint32 BytesPerElement = 16 ;
check ( ( NumBytes & ( BytesPerElement - 1 ) ) = = 0 ) ;
const uint32 NumElements = NumBytes / BytesPerElement ;
return ResizeBufferIfNeeded ( GraphBuilder , ExternalBuffer , FRDGBufferDesc : : CreateStructuredDesc ( BytesPerElement , NumElements ) , Name ) ;
}
2022-05-02 19:28:19 -04:00
FRDGBuffer * ResizeStructuredBufferSOAIfNeeded ( FRDGBuilder & GraphBuilder , TRefCountPtr < FRDGPooledBuffer > & ExternalBuffer , const FResizeResourceSOAParams & Params , const TCHAR * Name )
{
const uint32 BytesPerElement = 16 ;
const uint32 ExternalBufferSize = TryGetSize ( ExternalBuffer ) ;
2023-04-18 07:14:47 -04:00
checkf ( Params . NumBytes % BytesPerElement = = 0 , TEXT ( " NumBytes (%u) must be a multiple of BytesPerElement (%u) " ) , Params . NumBytes , BytesPerElement ) ;
checkf ( ExternalBufferSize % BytesPerElement = = 0 , TEXT ( " NumBytes (%u) must be a multiple of BytesPerElement (%u) " ) , ExternalBufferSize , BytesPerElement ) ;
2022-05-02 19:28:19 -04:00
uint32 NumElements = Params . NumBytes / BytesPerElement ;
uint32 NumElementsOld = ExternalBufferSize / BytesPerElement ;
2023-04-18 07:14:47 -04:00
checkf ( NumElements % Params . NumArrays = = 0 , TEXT ( " NumElements (%u) must be a multiple of NumArrays (%u) " ) , NumElements , Params . NumArrays ) ;
checkf ( NumElementsOld % Params . NumArrays = = 0 , TEXT ( " NumElements (%u) must be a multiple of NumArrays (%u) " ) , NumElementsOld , Params . NumArrays ) ;
2022-05-02 19:28:19 -04:00
const FRDGBufferDesc BufferDesc = FRDGBufferDesc : : CreateStructuredDesc ( BytesPerElement , NumElements ) ;
FRDGBuffer * InternalBufferNew = nullptr ;
if ( ! ExternalBuffer )
{
InternalBufferNew = GraphBuilder . CreateBuffer ( BufferDesc , Name ) ;
ExternalBuffer = GraphBuilder . ConvertToExternalBuffer ( InternalBufferNew ) ;
return InternalBufferNew ;
}
FRDGBuffer * InternalBufferOld = GraphBuilder . RegisterExternalBuffer ( ExternalBuffer ) ;
const uint32 BufferSize = BufferDesc . GetSize ( ) ;
const uint32 BufferSizeOld = InternalBufferOld - > GetSize ( ) ;
if ( BufferSize ! = BufferSizeOld )
{
InternalBufferNew = GraphBuilder . CreateBuffer ( BufferDesc , Name ) ;
ExternalBuffer = GraphBuilder . ConvertToExternalBuffer ( InternalBufferNew ) ;
FRDGBufferUAV * NewBufferUAV = GraphBuilder . CreateUAV ( InternalBufferNew , ERDGUnorderedAccessViewFlags : : SkipBarrier ) ;
FRDGBufferSRV * OldBufferSRV = GraphBuilder . CreateSRV ( InternalBufferOld ) ;
// Copy data to new buffer
uint32 OldArraySize = NumElementsOld / Params . NumArrays ;
uint32 NewArraySize = NumElements / Params . NumArrays ;
FMemcpyResourceParams MemcpyParams ;
MemcpyParams . Count = FMath : : Min ( NewArraySize , OldArraySize ) ;
for ( uint32 Index = 0 ; Index < Params . NumArrays ; Index + + )
{
MemcpyParams . SrcOffset = Index * OldArraySize ;
MemcpyParams . DstOffset = Index * NewArraySize ;
MemcpyResource ( GraphBuilder , NewBufferUAV , OldBufferSRV , MemcpyParams ) ;
}
return InternalBufferNew ;
}
return InternalBufferOld ;
}
2022-04-25 12:25:24 -04:00
FRDGBuffer * ResizeByteAddressBufferIfNeeded ( FRDGBuilder & GraphBuilder , TRefCountPtr < FRDGPooledBuffer > & ExternalBuffer , uint32 NumBytes , const TCHAR * Name )
{
// Needs to be aligned to 16 bytes to MemcpyResource to work correctly (otherwise it skips last unaligned elements of the buffer during resize)
check ( ( NumBytes & 15 ) = = 0 ) ;
return ResizeBufferIfNeeded ( GraphBuilder , ExternalBuffer , FRDGBufferDesc : : CreateByteAddressDesc ( NumBytes ) , Name ) ;
}
2022-05-02 19:28:19 -04:00
void FRDGScatterUploadBuffer : : Release ( )
{
check ( ! ScatterData ) ;
ScatterBuffer = nullptr ;
UploadBuffer = nullptr ;
}
uint32 FRDGScatterUploadBuffer : : GetNumBytes ( ) const
{
return TryGetSize ( ScatterBuffer ) + TryGetSize ( UploadBuffer ) ;
}
void FRDGScatterUploadBuffer : : Init ( FRDGBuilder & GraphBuilder , TArrayView < const uint32 > ElementScatterOffsets , uint32 InNumBytesPerElement , bool bInFloat4Buffer , const TCHAR * DebugName )
{
Init ( GraphBuilder , ElementScatterOffsets . Num ( ) , InNumBytesPerElement , bInFloat4Buffer , DebugName ) ;
FMemory : : ParallelMemcpy ( ScatterData , ElementScatterOffsets . GetData ( ) , ElementScatterOffsets . Num ( ) * ElementScatterOffsets . GetTypeSize ( ) , EMemcpyCachePolicy : : StoreUncached ) ;
NumScatters = ElementScatterOffsets . Num ( ) ;
}
void FRDGScatterUploadBuffer : : InitPreSized ( FRDGBuilder & GraphBuilder , uint32 NumElements , uint32 InNumBytesPerElement , bool bInFloat4Buffer , const TCHAR * DebugName )
{
Init ( GraphBuilder , NumElements , InNumBytesPerElement , bInFloat4Buffer , DebugName ) ;
NumScatters = NumElements ;
}
2022-09-13 21:47:56 -04:00
struct FScatterUploadComputeConfig
{
uint32 ThreadGroupSize ;
uint32 NumBytesPerThread ;
uint32 NumThreadsPerScatter ;
uint32 NumThreads ;
uint32 NumDispatches ;
uint32 NumLoops ;
} ;
2023-04-19 04:53:37 -04:00
FScatterUploadComputeConfig GetScatterUploadComputeConfig ( uint32 NumScatters , uint32 NumBytesPerElement , int32 NumElementsPerScatter = - 1 )
2022-09-13 21:47:56 -04:00
{
constexpr uint32 ThreadGroupSize = 64u ;
FScatterUploadComputeConfig Config ;
Config . ThreadGroupSize = ThreadGroupSize ;
2023-04-19 04:53:37 -04:00
if ( NumElementsPerScatter ! = INDEX_NONE )
{
Config . NumBytesPerThread = NumBytesPerElement ;
Config . NumThreadsPerScatter = NumElementsPerScatter ;
}
else
{
Config . NumBytesPerThread = ( NumBytesPerElement & 15 ) = = 0 ? 16 : 4 ;
Config . NumThreadsPerScatter = NumBytesPerElement / Config . NumBytesPerThread ;
}
2022-09-13 21:47:56 -04:00
Config . NumThreads = NumScatters * Config . NumThreadsPerScatter ;
Config . NumDispatches = FMath : : DivideAndRoundUp ( Config . NumThreads , Config . ThreadGroupSize ) ;
Config . NumLoops = FMath : : DivideAndRoundUp ( Config . NumDispatches , ( uint32 ) GMaxComputeDispatchDimension ) ;
return Config ;
}
2023-04-19 04:53:37 -04:00
void ScatterCopyResource ( FRDGBuilder & GraphBuilder , FRDGViewableResource * DstResource , FRDGBufferSRV * ScatterBufferSRV , FRDGBufferSRV * UploadBufferSRV , const FScatterCopyParams & Params )
{
const FScatterUploadComputeConfig ComputeConfig = GetScatterUploadComputeConfig ( Params . NumScatters , Params . NumBytesPerElement , Params . NumElementsPerScatter ) ;
const EResourceType DstResourceType = GetResourceType ( DstResource ) ;
EByteBufferResourceType ResourceTypeEnum = EByteBufferResourceType : : Count ;
EByteBufferStructuredSize ByteBufferStructuredSize = EByteBufferStructuredSize : : Uint4 ;
FRDGScatterCopyCS : : FParameters Parameters ;
Parameters . Common . Size = ComputeConfig . NumThreadsPerScatter ;
Parameters . NumScatters = Params . NumScatters ;
if ( DstResourceType = = EResourceType : : BYTEBUFFER )
{
if ( ComputeConfig . NumBytesPerThread = = 16 )
{
ResourceTypeEnum = EByteBufferResourceType : : Uint4Aligned_Buffer ;
}
else
{
ResourceTypeEnum = EByteBufferResourceType : : Uint_Buffer ;
}
Parameters . UploadByteAddressBuffer = UploadBufferSRV ;
Parameters . ScatterByteAddressBuffer = ScatterBufferSRV ;
Parameters . Common . DstByteAddressBuffer = GraphBuilder . CreateUAV ( GetAsBuffer ( DstResource ) , ERDGUnorderedAccessViewFlags : : SkipBarrier ) ;
}
else if ( DstResourceType = = EResourceType : : STRUCTURED_BUFFER )
{
ResourceTypeEnum = EByteBufferResourceType : : StructuredBuffer ;
FRDGBufferUAV * RDGBufferUAV = GraphBuilder . CreateUAV ( GetAsBuffer ( DstResource ) , ERDGUnorderedAccessViewFlags : : SkipBarrier ) ;
ByteBufferStructuredSize = GetStructuredBufferElementSize ( RDGBufferUAV ) ;
switch ( ByteBufferStructuredSize )
{
case EByteBufferStructuredSize : : Uint1 :
Parameters . UploadStructuredBuffer1x = UploadBufferSRV ;
Parameters . Common . DstStructuredBuffer1x = RDGBufferUAV ;
break ;
case EByteBufferStructuredSize : : Uint2 :
Parameters . UploadStructuredBuffer2x = UploadBufferSRV ;
Parameters . Common . DstStructuredBuffer2x = RDGBufferUAV ;
break ;
case EByteBufferStructuredSize : : Uint4 :
Parameters . UploadStructuredBuffer4x = UploadBufferSRV ;
Parameters . Common . DstStructuredBuffer4x = RDGBufferUAV ;
break ;
case EByteBufferStructuredSize : : Uint8 :
Parameters . UploadStructuredBuffer8x = UploadBufferSRV ;
Parameters . Common . DstStructuredBuffer8x = RDGBufferUAV ;
break ;
default :
break ;
} ;
Parameters . ScatterStructuredBuffer = ScatterBufferSRV ;
}
else if ( DstResourceType = = EResourceType : : BUFFER )
{
ResourceTypeEnum = EByteBufferResourceType : : Float4_Buffer ;
Parameters . UploadStructuredBuffer4x = UploadBufferSRV ;
Parameters . ScatterStructuredBuffer = ScatterBufferSRV ;
Parameters . Common . DstBuffer = GraphBuilder . CreateUAV ( GetAsBuffer ( DstResource ) , ERDGUnorderedAccessViewFlags : : SkipBarrier ) ;
}
else if ( DstResourceType = = EResourceType : : TEXTURE )
{
ResourceTypeEnum = EByteBufferResourceType : : Float4_Texture ;
Parameters . UploadStructuredBuffer4x = UploadBufferSRV ;
Parameters . ScatterStructuredBuffer = ScatterBufferSRV ;
Parameters . Common . DstTexture = GraphBuilder . CreateUAV ( GetAsTexture ( DstResource ) , ERDGUnorderedAccessViewFlags : : SkipBarrier ) ;
Parameters . Common . Float4sPerLine = CalculateFloat4sPerLine ( ) ;
}
FRDGScatterCopyCS : : FPermutationDomain PermutationVector ;
PermutationVector . Set < FRDGScatterCopyCS : : ResourceTypeDim > ( ( int ) ResourceTypeEnum ) ;
PermutationVector . Set < FRDGScatterCopyCS : : StructuredElementSizeDim > ( ( int ) ByteBufferStructuredSize ) ;
TShaderMapRef < FRDGScatterCopyCS > ComputeShader ( GetGlobalShaderMap ( GMaxRHIFeatureLevel ) , PermutationVector ) ;
for ( uint32 LoopIdx = 0 ; LoopIdx < ComputeConfig . NumLoops ; + + LoopIdx )
{
Parameters . Common . SrcOffset = LoopIdx * ( uint32 ) GMaxComputeDispatchDimension * ComputeConfig . ThreadGroupSize ;
uint32 LoopNumDispatch = FMath : : Min ( ComputeConfig . NumDispatches - LoopIdx * ( uint32 ) GMaxComputeDispatchDimension , ( uint32 ) GMaxComputeDispatchDimension ) ;
FComputeShaderUtils : : AddPass (
GraphBuilder ,
RDG_EVENT_NAME ( " ScatterUpload[%d] (Resource: %s, Offset: %u, GroupSize: %u) " , LoopIdx , DstResource - > Name , Parameters . Common . SrcOffset , LoopNumDispatch ) ,
ComputeShader ,
GraphBuilder . AllocParameters ( & Parameters ) ,
FIntVector ( LoopNumDispatch , 1 , 1 ) ) ;
}
}
2023-05-01 12:39:32 -04:00
void ScatterCopyResource ( FRDGBuilder & GraphBuilder , FRDGBuffer * DstResource , FRDGBufferSRV * ScatterBufferSRV , FRDGBufferSRV * UploadBufferSRV , const FScatterCopyParams & Params )
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS
ScatterCopyResource ( GraphBuilder , static_cast < FRDGViewableResource * > ( DstResource ) , ScatterBufferSRV , UploadBufferSRV , Params ) ;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
void ScatterCopyResource ( FRDGBuilder & GraphBuilder , FRDGTexture * DstResource , FRDGBufferSRV * ScatterBufferSRV , FRDGBufferSRV * UploadBufferSRV , const FScatterCopyParams & Params )
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS
ScatterCopyResource ( GraphBuilder , static_cast < FRDGViewableResource * > ( DstResource ) , ScatterBufferSRV , UploadBufferSRV , Params ) ;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
2023-04-19 04:53:37 -04:00
2022-04-25 12:25:24 -04:00
void FRDGScatterUploadBuffer : : Init ( FRDGBuilder & GraphBuilder , uint32 NumElements , uint32 InNumBytesPerElement , bool bInFloat4Buffer , const TCHAR * Name )
{
TRACE_CPUPROFILER_EVENT_SCOPE ( FRDGScatterUploadBuffer : : Init ) ;
NumScatters = 0 ;
MaxScatters = NumElements ;
NumBytesPerElement = InNumBytesPerElement ;
bFloat4Buffer = bInFloat4Buffer ;
2023-06-22 11:08:27 -04:00
FRHICommandListBase & RHICmdList = GraphBuilder . RHICmdList ;
2022-04-25 12:25:24 -04:00
const EBufferUsageFlags Usage = bInFloat4Buffer ? BUF_None : BUF_ByteAddressBuffer ;
const uint32 TypeSize = bInFloat4Buffer ? 16 : 4 ;
const uint32 ScatterNumBytesPerElement = sizeof ( uint32 ) ;
const uint32 ScatterBytes = NumElements * ScatterNumBytesPerElement ;
2023-05-25 10:57:33 -04:00
const uint32 ScatterBufferSize = ( uint32 ) FMath : : Min ( FMath : : RoundUpToPowerOfTwo64 ( ( uint64 ) ScatterBytes ) , GetMaxUploadBufferElements ( ) * sizeof ( uint32 ) ) ;
2022-04-25 12:25:24 -04:00
check ( ScatterBufferSize > = ScatterBytes ) ;
const uint32 UploadNumBytesPerElement = TypeSize ;
const uint32 UploadBytes = NumElements * NumBytesPerElement ;
2023-05-25 10:57:33 -04:00
const uint32 UploadBufferSize = ( uint32 ) FMath : : Min ( FMath : : RoundUpToPowerOfTwo64 ( ( uint64 ) UploadBytes ) , GetMaxUploadBufferElements ( ) * TypeSize ) ;
2022-04-25 12:25:24 -04:00
check ( UploadBufferSize > = UploadBytes ) ;
// Recreate buffers is they are already queued into RDG from a previous call.
if ( IsRegistered ( GraphBuilder , ScatterBuffer ) )
{
ScatterBuffer = nullptr ;
UploadBuffer = nullptr ;
}
if ( ! ScatterBuffer | | ScatterBytes > ScatterBuffer - > GetSize ( ) | | ScatterBufferSize < ScatterBuffer - > GetSize ( ) / 2 )
{
FRDGBufferDesc Desc = FRDGBufferDesc : : CreateStructuredUploadDesc ( ScatterNumBytesPerElement , ScatterBufferSize / ScatterNumBytesPerElement ) ;
Desc . Usage | = Usage ;
AllocatePooledBuffer ( Desc , ScatterBuffer , Name , ERDGPooledBufferAlignment : : None ) ;
}
if ( ! UploadBuffer | | UploadBytes > UploadBuffer - > GetSize ( ) | | UploadBufferSize < UploadBuffer - > GetSize ( ) / 2 )
{
FRDGBufferDesc Desc = FRDGBufferDesc : : CreateStructuredUploadDesc ( TypeSize , UploadBufferSize / UploadNumBytesPerElement ) ;
Desc . Usage | = Usage ;
AllocatePooledBuffer ( Desc , UploadBuffer , Name , ERDGPooledBufferAlignment : : None ) ;
}
2023-06-22 11:08:27 -04:00
ScatterData = ( uint32 * ) RHICmdList . LockBuffer ( ScatterBuffer - > GetRHI ( ) , 0 , ScatterBytes , RLM_WriteOnly ) ;
UploadData = ( uint8 * ) RHICmdList . LockBuffer ( UploadBuffer - > GetRHI ( ) , 0 , UploadBytes , RLM_WriteOnly ) ;
2022-04-25 12:25:24 -04:00
}
2023-05-01 12:39:32 -04:00
void FRDGScatterUploadBuffer : : ResourceUploadToInternal ( FRDGBuilder & GraphBuilder , FRDGViewableResource * DstResource )
2022-04-25 12:25:24 -04:00
{
TRACE_CPUPROFILER_EVENT_SCOPE ( FRDGScatterUploadBuffer : : ResourceUploadTo ) ;
2023-06-22 11:08:27 -04:00
FRHICommandListBase & RHICmdList = GraphBuilder . RHICmdList ;
2022-04-25 12:25:24 -04:00
2023-06-22 11:08:27 -04:00
RHICmdList . UnlockBuffer ( ScatterBuffer - > GetRHI ( ) ) ;
RHICmdList . UnlockBuffer ( UploadBuffer - > GetRHI ( ) ) ;
2022-04-25 12:25:24 -04:00
ScatterData = nullptr ;
UploadData = nullptr ;
if ( NumScatters = = 0 )
{
return ;
}
const EResourceType DstResourceType = GetResourceType ( DstResource ) ;
check ( bFloat4Buffer ! = ( DstResourceType = = EResourceType : : BYTEBUFFER ) ) ;
FRDGBufferSRV * ScatterBufferSRV = GraphBuilder . CreateSRV ( GraphBuilder . RegisterExternalBuffer ( ScatterBuffer ) ) ;
FRDGBufferSRV * UploadBufferSRV = GraphBuilder . CreateSRV ( GraphBuilder . RegisterExternalBuffer ( UploadBuffer ) ) ;
2023-05-01 12:39:32 -04:00
PRAGMA_DISABLE_DEPRECATION_WARNINGS
2023-04-19 04:53:37 -04:00
ScatterCopyResource ( GraphBuilder , DstResource , ScatterBufferSRV , UploadBufferSRV , FScatterCopyParams { NumScatters , NumBytesPerElement , INDEX_NONE } ) ;
2023-05-01 12:39:32 -04:00
PRAGMA_ENABLE_DEPRECATION_WARNINGS
2022-04-25 12:25:24 -04:00
Reset ( ) ;
}
void FRDGScatterUploadBuffer : : Reset ( )
{
NumScatters = 0 ;
MaxScatters = 0 ;
NumBytesPerElement = 0 ;
}
2022-09-13 21:47:56 -04:00
void FRDGScatterUploader : : Lock ( FRHICommandListBase & RHICmdList )
{
check ( State = = EState : : Empty ) ;
State = EState : : Locked ;
ScatterData = ( uint32 * ) RHICmdList . LockBuffer ( ScatterBuffer , 0 , ScatterBytes , RLM_WriteOnly ) ;
UploadData = ( uint8 * ) RHICmdList . LockBuffer ( UploadBuffer , 0 , UploadBytes , RLM_WriteOnly ) ;
}
void FRDGScatterUploader : : Unlock ( FRHICommandListBase & RHICmdList )
{
check ( State = = EState : : Locked ) ;
State = EState : : Unlocked ;
RHICmdList . UnlockBuffer ( ScatterBuffer ) ;
RHICmdList . UnlockBuffer ( UploadBuffer ) ;
}
FRDGScatterUploader * FRDGAsyncScatterUploadBuffer : : Begin ( FRDGBuilder & GraphBuilder , FRDGViewableResource * DstResource , uint32 NumElements , uint32 NumBytesPerElement , const TCHAR * Name )
{
TRACE_CPUPROFILER_EVENT_SCOPE ( FRDGAsyncScatterUploadBuffer : : Upload ) ;
const EResourceType DstResourceType = GetResourceType ( DstResource ) ;
const EBufferUsageFlags Usage = DstResourceType = = EResourceType : : BYTEBUFFER ? BUF_ByteAddressBuffer : BUF_None ;
const uint32 TypeSize = DstResourceType = = EResourceType : : BYTEBUFFER ? 4 : 16 ;
const uint32 ScatterNumBytesPerElement = sizeof ( uint32 ) ;
const uint32 ScatterBytes = NumElements * ScatterNumBytesPerElement ;
2023-03-27 23:25:48 -04:00
const uint32 ScatterBufferSize = ( uint32 ) FMath : : Min ( ( uint64 ) FMath : : RoundUpToPowerOfTwo ( ScatterBytes ) , GetMaxUploadBufferElements ( ) * sizeof ( uint32 ) ) ;
2022-09-13 21:47:56 -04:00
check ( ScatterBufferSize > = ScatterBytes ) ;
const uint32 UploadNumBytesPerElement = TypeSize ;
const uint32 UploadBytes = NumElements * NumBytesPerElement ;
2023-03-27 23:25:48 -04:00
const uint32 UploadBufferSize = ( uint32 ) FMath : : Min ( ( uint64 ) FMath : : RoundUpToPowerOfTwo ( UploadBytes ) , GetMaxUploadBufferElements ( ) * TypeSize ) ;
2022-09-13 21:47:56 -04:00
check ( UploadBufferSize > = UploadBytes ) ;
// Recreate buffers is they are already queued into RDG from a previous call.
if ( IsRegistered ( GraphBuilder , ScatterBuffer ) )
{
ScatterBuffer = nullptr ;
UploadBuffer = nullptr ;
}
if ( ! ScatterBuffer | | ScatterBytes > ScatterBuffer - > GetSize ( ) | | ScatterBufferSize < ScatterBuffer - > GetSize ( ) / 2 )
{
FRDGBufferDesc Desc = FRDGBufferDesc : : CreateStructuredUploadDesc ( ScatterNumBytesPerElement , ScatterBufferSize / ScatterNumBytesPerElement ) ;
Desc . Usage | = Usage ;
AllocatePooledBuffer ( Desc , ScatterBuffer , Name , ERDGPooledBufferAlignment : : None ) ;
}
if ( ! UploadBuffer | | UploadBytes > UploadBuffer - > GetSize ( ) | | UploadBufferSize < UploadBuffer - > GetSize ( ) / 2 )
{
FRDGBufferDesc Desc = FRDGBufferDesc : : CreateStructuredUploadDesc ( TypeSize , UploadBufferSize / UploadNumBytesPerElement ) ;
Desc . Usage | = Usage ;
AllocatePooledBuffer ( Desc , UploadBuffer , Name , ERDGPooledBufferAlignment : : None ) ;
}
FRDGScatterUploader * Uploader = GraphBuilder . AllocObject < FRDGScatterUploader > ( ) ;
Uploader - > MaxScatters = NumElements ;
Uploader - > NumBytesPerElement = NumBytesPerElement ;
Uploader - > DstResource = DstResource ;
Uploader - > ScatterBuffer = ScatterBuffer - > GetRHI ( ) ;
Uploader - > UploadBuffer = UploadBuffer - > GetRHI ( ) ;
Uploader - > ScatterBytes = ScatterBytes ;
Uploader - > UploadBytes = UploadBytes ;
return Uploader ;
}
FRDGScatterUploader * FRDGAsyncScatterUploadBuffer : : BeginPreSized ( FRDGBuilder & GraphBuilder , FRDGViewableResource * DstResource , uint32 NumElements , uint32 NumBytesPerElement , const TCHAR * Name )
{
FRDGScatterUploader * Uploader = Begin ( GraphBuilder , DstResource , NumElements , NumBytesPerElement , Name ) ;
Uploader - > NumScatters = NumElements ;
Uploader - > bNumScattersPreSized = true ;
return Uploader ;
}
void FRDGAsyncScatterUploadBuffer : : End ( FRDGBuilder & GraphBuilder , FRDGScatterUploader * Uploader )
{
check ( Uploader ) ;
checkf ( ! FRDGBuilder : : IsImmediateMode ( ) | | Uploader - > State = = FRDGScatterUploader : : EState : : Unlocked , TEXT ( " In immediate mode, you must fill the uploader prior to calling End. " ) ) ;
const uint32 NumScatters = Uploader - > bNumScattersPreSized ? Uploader - > NumScatters : Uploader - > MaxScatters ;
const FScatterUploadComputeConfig ComputeConfig = GetScatterUploadComputeConfig ( NumScatters , Uploader - > NumBytesPerElement ) ;
FRDGScatterCopyCS : : FParameters Parameters ;
Parameters . Common . Size = ComputeConfig . NumThreadsPerScatter ;
Parameters . NumScatters = NumScatters ;
FRDGBufferSRV * ScatterBufferSRV = GraphBuilder . CreateSRV ( GraphBuilder . RegisterExternalBuffer ( ScatterBuffer ) ) ;
FRDGBufferSRV * UploadBufferSRV = GraphBuilder . CreateSRV ( GraphBuilder . RegisterExternalBuffer ( UploadBuffer ) ) ;
FRDGViewableResource * DstResource = Uploader - > DstResource ;
const EResourceType DstResourceType = GetResourceType ( DstResource ) ;
EByteBufferResourceType ResourceTypeEnum = EByteBufferResourceType : : Count ;
2023-04-19 04:53:37 -04:00
EByteBufferStructuredSize ByteBufferStructuredSize = EByteBufferStructuredSize : : Uint4 ;
2022-09-13 21:47:56 -04:00
if ( DstResourceType = = EResourceType : : BYTEBUFFER )
{
if ( ComputeConfig . NumBytesPerThread = = 16 )
{
ResourceTypeEnum = EByteBufferResourceType : : Uint4Aligned_Buffer ;
}
else
{
ResourceTypeEnum = EByteBufferResourceType : : Uint_Buffer ;
}
Parameters . UploadByteAddressBuffer = UploadBufferSRV ;
Parameters . ScatterByteAddressBuffer = ScatterBufferSRV ;
Parameters . Common . DstByteAddressBuffer = GraphBuilder . CreateUAV ( GetAsBuffer ( DstResource ) , ERDGUnorderedAccessViewFlags : : SkipBarrier ) ;
}
else if ( DstResourceType = = EResourceType : : STRUCTURED_BUFFER )
{
2023-04-19 04:53:37 -04:00
ResourceTypeEnum = EByteBufferResourceType : : StructuredBuffer ;
2022-09-13 21:47:56 -04:00
2023-04-19 04:53:37 -04:00
FRDGBufferUAV * RDGBufferUAV = GraphBuilder . CreateUAV ( GetAsBuffer ( DstResource ) , ERDGUnorderedAccessViewFlags : : SkipBarrier ) ;
ByteBufferStructuredSize = GetStructuredBufferElementSize ( RDGBufferUAV ) ;
switch ( ByteBufferStructuredSize )
{
case EByteBufferStructuredSize : : Uint1 :
Parameters . UploadStructuredBuffer1x = UploadBufferSRV ;
Parameters . Common . DstStructuredBuffer1x = RDGBufferUAV ;
break ;
case EByteBufferStructuredSize : : Uint2 :
Parameters . UploadStructuredBuffer2x = UploadBufferSRV ;
Parameters . Common . DstStructuredBuffer2x = RDGBufferUAV ;
break ;
case EByteBufferStructuredSize : : Uint4 :
Parameters . UploadStructuredBuffer4x = UploadBufferSRV ;
Parameters . Common . DstStructuredBuffer4x = RDGBufferUAV ;
break ;
case EByteBufferStructuredSize : : Uint8 :
Parameters . UploadStructuredBuffer8x = UploadBufferSRV ;
Parameters . Common . DstStructuredBuffer8x = RDGBufferUAV ;
break ;
default :
break ;
} ;
2022-09-13 21:47:56 -04:00
Parameters . ScatterStructuredBuffer = ScatterBufferSRV ;
}
else if ( DstResourceType = = EResourceType : : BUFFER )
{
ResourceTypeEnum = EByteBufferResourceType : : Float4_Buffer ;
2023-04-19 04:53:37 -04:00
Parameters . UploadStructuredBuffer4x = UploadBufferSRV ;
2022-09-13 21:47:56 -04:00
Parameters . ScatterStructuredBuffer = ScatterBufferSRV ;
Parameters . Common . DstBuffer = GraphBuilder . CreateUAV ( GetAsBuffer ( DstResource ) , ERDGUnorderedAccessViewFlags : : SkipBarrier ) ;
}
else if ( DstResourceType = = EResourceType : : TEXTURE )
{
ResourceTypeEnum = EByteBufferResourceType : : Float4_Texture ;
2023-04-19 04:53:37 -04:00
Parameters . UploadStructuredBuffer4x = UploadBufferSRV ;
2022-09-13 21:47:56 -04:00
Parameters . ScatterStructuredBuffer = ScatterBufferSRV ;
Parameters . Common . DstTexture = GraphBuilder . CreateUAV ( GetAsTexture ( DstResource ) , ERDGUnorderedAccessViewFlags : : SkipBarrier ) ;
Parameters . Common . Float4sPerLine = CalculateFloat4sPerLine ( ) ;
}
2023-04-19 04:53:37 -04:00
FRDGScatterCopyCS : : FPermutationDomain PermutationVector ;
PermutationVector . Set < FRDGScatterCopyCS : : ResourceTypeDim > ( ( int ) ResourceTypeEnum ) ;
PermutationVector . Set < FRDGScatterCopyCS : : StructuredElementSizeDim > ( static_cast < int32 > ( ByteBufferStructuredSize ) ) ;
2022-09-13 21:47:56 -04:00
TShaderMapRef < FRDGScatterCopyCS > ComputeShader ( GetGlobalShaderMap ( GMaxRHIFeatureLevel ) , PermutationVector ) ;
for ( uint32 LoopIdx = 0 ; LoopIdx < ComputeConfig . NumLoops ; + + LoopIdx )
{
Parameters . Common . SrcOffset = LoopIdx * ( uint32 ) GMaxComputeDispatchDimension * ComputeConfig . ThreadGroupSize ;
FRDGScatterCopyCS : : FParameters * PassParameters = GraphBuilder . AllocParameters ( & Parameters ) ;
if ( Uploader - > bNumScattersPreSized )
{
const uint32 LoopNumDispatch = FMath : : Min ( ComputeConfig . NumDispatches - LoopIdx * ( uint32 ) GMaxComputeDispatchDimension , ( uint32 ) GMaxComputeDispatchDimension ) ;
FComputeShaderUtils : : AddPass (
GraphBuilder ,
RDG_EVENT_NAME ( " ScatterUpload[%d] (Resource: %s, Offset: %u, GroupSize: %u) " , LoopIdx , DstResource - > Name , Parameters . Common . SrcOffset , LoopNumDispatch ) ,
ComputeShader ,
PassParameters ,
FIntVector ( LoopNumDispatch , 1 , 1 ) ) ;
}
else
{
FComputeShaderUtils : : AddPass (
GraphBuilder ,
RDG_EVENT_NAME ( " ScatterUpload[%d] (Resource: %s, Offset: %u) " , LoopIdx , DstResource - > Name , Parameters . Common . SrcOffset ) ,
ComputeShader ,
PassParameters ,
[ PassParameters , LoopIdx , NumBytesPerElement = Uploader - > NumBytesPerElement , Uploader ]
{
const uint32 NumScatters = Uploader - > GetFinalNumScatters ( ) ;
const FScatterUploadComputeConfig ComputeConfig = GetScatterUploadComputeConfig ( NumScatters , NumBytesPerElement ) ;
if ( LoopIdx < ComputeConfig . NumLoops )
{
PassParameters - > NumScatters = NumScatters ;
return FIntVector ( FMath : : Min ( ComputeConfig . NumDispatches - LoopIdx * ( uint32 ) GMaxComputeDispatchDimension , ( uint32 ) GMaxComputeDispatchDimension ) , 1 , 1 ) ;
}
else
{
return FIntVector : : ZeroValue ;
}
} ) ;
}
}
}
void FRDGAsyncScatterUploadBuffer : : Release ( )
{
ScatterBuffer = nullptr ;
UploadBuffer = nullptr ;
}
uint32 FRDGAsyncScatterUploadBuffer : : GetNumBytes ( ) const
{
return TryGetSize ( ScatterBuffer ) + TryGetSize ( UploadBuffer ) ;
}
2020-02-12 13:27:19 -05:00
template < typename ResourceType >
2021-09-01 19:20:47 -04:00
void MemsetResource ( FRHICommandList & RHICmdList , const ResourceType & DstBuffer , const FMemsetResourceParams & Params )
2020-02-12 13:27:19 -05:00
{
2021-08-03 07:56:47 -04:00
EByteBufferResourceType ResourceTypeEnum ;
FMemsetBufferCS : : FParameters Parameters ;
2021-09-01 19:20:47 -04:00
Parameters . Value = Params . Value ;
Parameters . Size = Params . Count ;
Parameters . DstOffset = Params . DstOffset ;
2021-08-03 07:56:47 -04:00
2020-02-12 13:27:19 -05:00
if ( ResourceTypeTraits < ResourceType > : : Type = = EResourceType : : BYTEBUFFER )
{
2021-08-03 07:56:47 -04:00
ResourceTypeEnum = EByteBufferResourceType : : Uint_Buffer ;
2020-02-12 13:27:19 -05:00
Parameters . DstByteAddressBuffer = DstBuffer . UAV ;
}
2021-09-01 19:20:47 -04:00
else if ( ResourceTypeTraits < ResourceType > : : Type = = EResourceType : : BUFFER )
{
ResourceTypeEnum = EByteBufferResourceType : : Float4_Buffer ;
Parameters . DstBuffer = DstBuffer . UAV ;
}
2021-08-03 07:56:47 -04:00
else if ( ResourceTypeTraits < ResourceType > : : Type = = EResourceType : : STRUCTURED_BUFFER )
2020-02-12 13:27:19 -05:00
{
2023-04-19 04:53:37 -04:00
ResourceTypeEnum = EByteBufferResourceType : : StructuredBuffer ;
2021-08-03 07:56:47 -04:00
2023-04-19 04:53:37 -04:00
Parameters . DstStructuredBuffer4x = DstBuffer . UAV ;
2020-02-12 13:27:19 -05:00
}
2021-08-03 07:56:47 -04:00
else if ( ResourceTypeTraits < ResourceType > : : Type = = EResourceType : : TEXTURE )
{
ResourceTypeEnum = EByteBufferResourceType : : Float4_Texture ;
2020-02-12 13:27:19 -05:00
2021-08-03 07:56:47 -04:00
Parameters . DstTexture = DstBuffer . UAV ;
Parameters . Float4sPerLine = CalculateFloat4sPerLine ( ) ;
2020-02-12 13:27:19 -05:00
}
2021-08-03 07:56:47 -04:00
FMemcpyCS : : FPermutationDomain PermutationVector ;
PermutationVector . Set < FMemcpyCS : : ResourceTypeDim > ( ( int ) ResourceTypeEnum ) ;
2023-04-19 04:53:37 -04:00
PermutationVector . Set < FMemcpyCS : : StructuredElementSizeDim > ( ( int32 ) EByteBufferStructuredSize : : Uint4 ) ;
2021-08-03 07:56:47 -04:00
2020-02-12 13:27:19 -05:00
auto ShaderMap = GetGlobalShaderMap ( GMaxRHIFeatureLevel ) ;
2021-08-03 07:56:47 -04:00
auto ComputeShader = GetGlobalShaderMap ( GMaxRHIFeatureLevel ) - > GetShader < FMemsetBufferCS > ( PermutationVector ) ;
2020-02-12 13:27:19 -05:00
2021-09-01 19:20:47 -04:00
// each thread will set 4 floats / uints
const uint32 Divisor = ResourceTypeTraits < ResourceType > : : Type = = EResourceType : : BYTEBUFFER ? 4 : 1 ;
FComputeShaderUtils : : Dispatch ( RHICmdList , ComputeShader , Parameters , FIntVector ( FMath : : DivideAndRoundUp ( Params . Count / Divisor , 64u ) , 1 , 1 ) ) ;
2020-01-24 18:07:01 -05:00
}
2020-02-12 13:27:19 -05:00
template < typename ResourceType >
2021-09-01 19:20:47 -04:00
void MemcpyResource ( FRHICommandList & RHICmdList , const ResourceType & DstBuffer , const ResourceType & SrcBuffer , const FMemcpyResourceParams & Params , bool bAlreadyInUAVOverlap )
2020-01-24 18:07:01 -05:00
{
2021-09-01 19:20:47 -04:00
// each thread will copy 4 floats / uints
const uint32 Divisor = ResourceTypeTraits < ResourceType > : : Type = = EResourceType : : BYTEBUFFER ? 4 : 1 ;
2020-01-24 18:07:01 -05:00
2021-06-03 10:26:59 -04:00
if ( ! bAlreadyInUAVOverlap ) // TODO: Get rid of this check once BeginUAVOverlap/EndUAVOverlap supports nesting.
2021-09-01 19:20:47 -04:00
RHICmdList . BeginUAVOverlap ( DstBuffer . UAV ) ;
2021-06-03 10:26:59 -04:00
2021-09-01 19:20:47 -04:00
uint32 NumElementsProcessed = 0 ;
while ( NumElementsProcessed < Params . Count )
2020-02-12 13:27:19 -05:00
{
2021-09-01 19:20:47 -04:00
const uint32 NumWaves = FMath : : Max ( FMath : : Min < uint32 > ( GRHIMaxDispatchThreadGroupsPerDimension . X , FMath : : DivideAndRoundUp ( Params . Count / Divisor , 64u ) ) , 1u ) ;
const uint32 NumElementsPerDispatch = FMath : : Min ( FMath : : Max ( NumWaves , 1u ) * Divisor * 64 , Params . Count - NumElementsProcessed ) ;
2020-01-24 18:07:01 -05:00
2021-08-03 07:56:47 -04:00
EByteBufferResourceType ResourceTypeEnum ;
FMemcpyCS : : FParameters Parameters ;
2021-09-01 19:20:47 -04:00
Parameters . Common . Size = NumElementsPerDispatch ;
Parameters . Common . SrcOffset = ( Params . SrcOffset + NumElementsProcessed ) ;
Parameters . Common . DstOffset = ( Params . DstOffset + NumElementsProcessed ) ;
2021-08-03 07:56:47 -04:00
2020-07-06 18:58:26 -04:00
if ( ResourceTypeTraits < ResourceType > : : Type = = EResourceType : : BYTEBUFFER )
{
2021-08-03 07:56:47 -04:00
ResourceTypeEnum = EByteBufferResourceType : : Uint_Buffer ;
2020-07-06 18:58:26 -04:00
Parameters . SrcByteAddressBuffer = SrcBuffer . SRV ;
Parameters . Common . DstByteAddressBuffer = DstBuffer . UAV ;
}
2021-08-03 07:56:47 -04:00
else if ( ResourceTypeTraits < ResourceType > : : Type = = EResourceType : : STRUCTURED_BUFFER )
2020-07-06 18:58:26 -04:00
{
2023-04-19 04:53:37 -04:00
ResourceTypeEnum = EByteBufferResourceType : : StructuredBuffer ;
2021-08-03 07:56:47 -04:00
2023-04-19 04:53:37 -04:00
Parameters . SrcStructuredBuffer4x = SrcBuffer . SRV ;
Parameters . Common . DstStructuredBuffer4x = DstBuffer . UAV ;
2020-07-06 18:58:26 -04:00
}
2021-09-01 19:20:47 -04:00
else if ( ResourceTypeTraits < ResourceType > : : Type = = EResourceType : : BUFFER )
{
ResourceTypeEnum = EByteBufferResourceType : : Float4_Buffer ;
Parameters . SrcBuffer = SrcBuffer . SRV ;
Parameters . Common . DstBuffer = DstBuffer . UAV ;
}
2020-07-06 18:58:26 -04:00
else if ( ResourceTypeTraits < ResourceType > : : Type = = EResourceType : : TEXTURE )
{
2021-08-03 07:56:47 -04:00
ResourceTypeEnum = EByteBufferResourceType : : Float4_Texture ;
2020-07-06 18:58:26 -04:00
Parameters . SrcTexture = SrcBuffer . SRV ;
Parameters . Common . DstTexture = DstBuffer . UAV ;
2021-08-03 07:56:47 -04:00
Parameters . Common . Float4sPerLine = CalculateFloat4sPerLine ( ) ;
2020-07-06 18:58:26 -04:00
}
else
{
2021-08-03 07:56:47 -04:00
check ( false ) ;
2020-07-06 18:58:26 -04:00
}
2021-08-03 07:56:47 -04:00
FMemcpyCS : : FPermutationDomain PermutationVector ;
PermutationVector . Set < FMemcpyCS : : ResourceTypeDim > ( ( int ) ResourceTypeEnum ) ;
2023-04-19 04:53:37 -04:00
PermutationVector . Set < FMemcpyCS : : StructuredElementSizeDim > ( ( int32 ) EByteBufferStructuredSize : : Uint4 ) ;
2021-08-03 07:56:47 -04:00
auto ComputeShader = GetGlobalShaderMap ( GMaxRHIFeatureLevel ) - > GetShader < FMemcpyCS > ( PermutationVector ) ;
2020-07-06 18:58:26 -04:00
FComputeShaderUtils : : Dispatch ( RHICmdList , ComputeShader , Parameters , FIntVector ( NumWaves , 1 , 1 ) ) ;
2021-09-01 19:20:47 -04:00
NumElementsProcessed + = NumElementsPerDispatch ;
2020-07-06 18:58:26 -04:00
}
2021-06-03 10:26:59 -04:00
if ( ! bAlreadyInUAVOverlap )
RHICmdList . EndUAVOverlap ( DstBuffer . UAV ) ;
2020-01-24 18:07:01 -05:00
}
2023-05-01 12:39:32 -04:00
// NOTE: Deprecated
RENDERCORE_API bool ResizeResourceIfNeeded ( FRHICommandList & RHICmdList , FTextureRWBuffer & Texture , uint32 NumBytes , const TCHAR * DebugName )
2020-01-24 18:07:01 -05:00
{
2020-02-12 13:27:19 -05:00
check ( ( NumBytes & 15 ) = = 0 ) ;
2021-08-03 07:56:47 -04:00
uint32 Float4sPerLine = CalculateFloat4sPerLine ( ) ;
2020-02-12 13:27:19 -05:00
uint32 BytesPerLine = Float4sPerLine * 16 ;
2020-01-24 18:07:01 -05:00
EPixelFormat BufferFormat = PF_A32B32G32R32F ;
uint32 BytesPerElement = GPixelFormats [ BufferFormat ] . BlockBytes ;
uint32 NumLines = ( NumBytes + BytesPerLine - 1 ) / BytesPerLine ;
if ( Texture . NumBytes = = 0 )
{
2022-03-30 13:36:17 -04:00
Texture . Initialize2D ( DebugName , BytesPerElement , Float4sPerLine , NumLines , PF_A32B32G32R32F , TexCreate_RenderTargetable | TexCreate_UAV ) ;
2020-11-11 11:06:59 -04:00
return true ;
2020-01-24 18:07:01 -05:00
}
else if ( ( NumLines * Float4sPerLine * BytesPerElement ) ! = Texture . NumBytes )
{
2022-03-30 13:36:17 -04:00
FTextureRWBuffer NewTexture ;
NewTexture . Initialize2D ( DebugName , BytesPerElement , Float4sPerLine , NumLines , PF_A32B32G32R32F , TexCreate_RenderTargetable | TexCreate_UAV ) ;
2021-09-01 19:20:47 -04:00
FMemcpyResourceParams Params ;
Params . Count = NumBytes / BytesPerElement ;
Params . SrcOffset = 0 ;
Params . DstOffset = 0 ;
2023-05-01 12:39:32 -04:00
PRAGMA_DISABLE_DEPRECATION_WARNINGS
2021-09-01 19:20:47 -04:00
MemcpyResource ( RHICmdList , NewTexture , Texture , Params ) ;
2023-05-01 12:39:32 -04:00
PRAGMA_ENABLE_DEPRECATION_WARNINGS
2020-01-24 18:07:01 -05:00
Texture = NewTexture ;
return true ;
}
return false ;
}
2020-02-12 13:27:19 -05:00
template < >
RENDERCORE_API bool ResizeResourceIfNeeded < FRWBufferStructured > ( FRHICommandList & RHICmdList , FRWBufferStructured & Buffer , uint32 NumBytes , const TCHAR * DebugName )
{
2021-09-01 19:20:47 -04:00
const uint32 BytesPerElement = 16 ;
check ( ( NumBytes & ( BytesPerElement - 1 ) ) = = 0 ) ;
uint32 NumElements = NumBytes / BytesPerElement ;
2020-02-12 13:27:19 -05:00
if ( Buffer . NumBytes = = 0 )
{
2023-06-22 11:08:27 -04:00
Buffer . Initialize ( RHICmdList , DebugName , BytesPerElement , NumElements ) ;
2020-11-11 11:06:59 -04:00
return true ;
2020-02-12 13:27:19 -05:00
}
else if ( NumBytes ! = Buffer . NumBytes )
{
FRWBufferStructured NewBuffer ;
2023-06-22 11:08:27 -04:00
NewBuffer . Initialize ( RHICmdList , DebugName , BytesPerElement , NumElements ) ;
2020-02-12 13:27:19 -05:00
2021-03-16 05:14:05 -04:00
RHICmdList . Transition ( FRHITransitionInfo ( Buffer . UAV , ERHIAccess : : Unknown , ERHIAccess : : SRVCompute ) ) ;
RHICmdList . Transition ( FRHITransitionInfo ( NewBuffer . UAV , ERHIAccess : : Unknown , ERHIAccess : : UAVCompute ) ) ;
2020-02-12 13:27:19 -05:00
// Copy data to new buffer
2021-09-01 19:20:47 -04:00
FMemcpyResourceParams Params ;
Params . Count = FMath : : Min ( NumBytes , Buffer . NumBytes ) / BytesPerElement ;
Params . SrcOffset = 0 ;
Params . DstOffset = 0 ;
MemcpyResource ( RHICmdList , NewBuffer , Buffer , Params ) ;
2020-02-12 13:27:19 -05:00
Buffer = NewBuffer ;
return true ;
}
return false ;
}
template < >
RENDERCORE_API bool ResizeResourceIfNeeded < FRWByteAddressBuffer > ( FRHICommandList & RHICmdList , FRWByteAddressBuffer & Buffer , uint32 NumBytes , const TCHAR * DebugName )
{
2021-09-01 19:20:47 -04:00
const uint32 BytesPerElement = 4 ;
2020-07-06 18:58:26 -04:00
// Needs to be aligned to 16 bytes to MemcpyResource to work correctly (otherwise it skips last unaligned elements of the buffer during resize)
check ( ( NumBytes & 15 ) = = 0 ) ;
2020-02-12 13:27:19 -05:00
if ( Buffer . NumBytes = = 0 )
{
2023-06-22 11:08:27 -04:00
Buffer . Initialize ( RHICmdList , DebugName , NumBytes ) ;
2020-11-11 11:06:59 -04:00
return true ;
2020-02-12 13:27:19 -05:00
}
else if ( NumBytes ! = Buffer . NumBytes )
{
FRWByteAddressBuffer NewBuffer ;
2023-06-22 11:08:27 -04:00
NewBuffer . Initialize ( RHICmdList , DebugName , NumBytes ) ;
2020-02-12 13:27:19 -05:00
2021-04-06 13:59:36 -04:00
RHICmdList . Transition ( {
FRHITransitionInfo ( Buffer . UAV , ERHIAccess : : Unknown , ERHIAccess : : SRVCompute ) ,
FRHITransitionInfo ( NewBuffer . UAV , ERHIAccess : : Unknown , ERHIAccess : : UAVCompute )
} ) ;
2020-02-12 13:27:19 -05:00
// Copy data to new buffer
2021-09-01 19:20:47 -04:00
FMemcpyResourceParams Params ;
Params . Count = FMath : : Min ( NumBytes , Buffer . NumBytes ) / BytesPerElement ;
Params . SrcOffset = 0 ;
Params . DstOffset = 0 ;
MemcpyResource ( RHICmdList , NewBuffer , Buffer , Params ) ;
Buffer = NewBuffer ;
return true ;
}
return false ;
}
RENDERCORE_API bool ResizeResourceIfNeeded ( FRHICommandList & RHICmdList , FRWBuffer & Buffer , EPixelFormat Format , uint32 NumElements , const TCHAR * DebugName )
{
const uint32 BytesPerElement = GPixelFormats [ Format ] . BlockBytes ;
const uint32 NumBytes = BytesPerElement * NumElements ;
if ( Buffer . NumBytes = = 0 )
{
2023-06-22 11:08:27 -04:00
Buffer . Initialize ( RHICmdList , DebugName , BytesPerElement , NumElements , Format ) ;
2021-09-01 19:20:47 -04:00
return true ;
}
else if ( NumBytes ! = Buffer . NumBytes )
{
FRWBuffer NewBuffer ;
2023-06-22 11:08:27 -04:00
NewBuffer . Initialize ( RHICmdList , DebugName , BytesPerElement , NumElements , Format ) ;
2021-09-01 19:20:47 -04:00
RHICmdList . Transition ( FRHITransitionInfo ( Buffer . UAV , ERHIAccess : : Unknown , ERHIAccess : : SRVCompute ) ) ;
RHICmdList . Transition ( FRHITransitionInfo ( NewBuffer . UAV , ERHIAccess : : Unknown , ERHIAccess : : UAVCompute ) ) ;
// Copy data to new buffer
FMemcpyResourceParams MemcpyParams ;
MemcpyParams . Count = FMath : : Min ( NumBytes , Buffer . NumBytes ) / BytesPerElement ;
MemcpyParams . SrcOffset = 0 ;
MemcpyParams . DstOffset = 0 ;
MemcpyResource ( RHICmdList , NewBuffer , Buffer , MemcpyParams ) ;
2020-02-12 13:27:19 -05:00
Buffer = NewBuffer ;
return true ;
}
return false ;
}
2020-07-06 18:58:26 -04:00
template < >
2021-09-01 19:20:47 -04:00
RENDERCORE_API bool ResizeResourceSOAIfNeeded < FRWBufferStructured > ( FRHICommandList & RHICmdList , FRWBufferStructured & Buffer , const FResizeResourceSOAParams & Params , const TCHAR * DebugName )
2020-07-06 18:58:26 -04:00
{
2021-09-01 19:20:47 -04:00
const uint32 BytesPerElement = 16 ;
2023-08-31 08:56:30 -04:00
checkf ( Params . NumBytes % BytesPerElement = = 0 , TEXT ( " NumBytes (%u) must be a multiple of BytesPerElement (%u) " ) , Params . NumBytes , BytesPerElement ) ;
checkf ( Buffer . NumBytes % BytesPerElement = = 0 , TEXT ( " NumBytes (%u) must be a multiple of BytesPerElement (%u) " ) , Buffer . NumBytes , BytesPerElement ) ;
2021-09-01 19:20:47 -04:00
uint32 NumElements = Params . NumBytes / BytesPerElement ;
uint32 NumElementsOld = Buffer . NumBytes / BytesPerElement ;
2023-08-31 08:56:30 -04:00
checkf ( NumElements % Params . NumArrays = = 0 , TEXT ( " NumElements (%u) must be a multiple of NumArrays (%u) " ) , NumElements , Params . NumArrays ) ;
checkf ( NumElementsOld % Params . NumArrays = = 0 , TEXT ( " NumElements (%u) must be a multiple of NumArrays (%u) " ) , NumElementsOld , Params . NumArrays ) ;
2020-07-06 18:58:26 -04:00
if ( Buffer . NumBytes = = 0 )
{
2023-06-22 11:08:27 -04:00
Buffer . Initialize ( RHICmdList , DebugName , BytesPerElement , NumElements ) ;
2020-11-11 11:06:59 -04:00
return true ;
2020-07-06 18:58:26 -04:00
}
2021-09-01 19:20:47 -04:00
else if ( Params . NumBytes ! = Buffer . NumBytes )
2020-07-06 18:58:26 -04:00
{
FRWBufferStructured NewBuffer ;
2023-06-22 11:08:27 -04:00
NewBuffer . Initialize ( RHICmdList , DebugName , BytesPerElement , NumElements ) ;
2020-07-06 18:58:26 -04:00
2021-04-06 13:59:36 -04:00
RHICmdList . Transition ( {
FRHITransitionInfo ( Buffer . UAV , ERHIAccess : : Unknown , ERHIAccess : : SRVCompute ) ,
FRHITransitionInfo ( NewBuffer . UAV , ERHIAccess : : Unknown , ERHIAccess : : UAVCompute )
} ) ;
2021-03-16 05:14:05 -04:00
2020-07-06 18:58:26 -04:00
// Copy data to new buffer
2021-09-01 19:20:47 -04:00
uint32 OldArraySize = NumElementsOld / Params . NumArrays ;
uint32 NewArraySize = NumElements / Params . NumArrays ;
2021-03-16 05:14:05 -04:00
RHICmdList . BeginUAVOverlap ( NewBuffer . UAV ) ;
2021-09-01 19:20:47 -04:00
FMemcpyResourceParams MemcpyParams ;
MemcpyParams . Count = FMath : : Min ( NewArraySize , OldArraySize ) ;
for ( uint32 i = 0 ; i < Params . NumArrays ; i + + )
2020-07-06 18:58:26 -04:00
{
2021-09-01 19:20:47 -04:00
MemcpyParams . SrcOffset = i * OldArraySize ;
MemcpyParams . DstOffset = i * NewArraySize ;
MemcpyResource ( RHICmdList , NewBuffer , Buffer , MemcpyParams , true ) ;
2020-07-06 18:58:26 -04:00
}
2021-09-01 19:20:47 -04:00
2021-03-16 05:14:05 -04:00
RHICmdList . EndUAVOverlap ( NewBuffer . UAV ) ;
2020-07-06 18:58:26 -04:00
Buffer = NewBuffer ;
return true ;
}
return false ;
}
2021-09-01 19:20:47 -04:00
RENDERCORE_API bool ResizeResourceSOAIfNeeded ( FRDGBuilder & GraphBuilder , FRWBufferStructured & Buffer , const FResizeResourceSOAParams & Params , const TCHAR * DebugName )
2021-04-06 13:59:36 -04:00
{
2021-09-01 19:20:47 -04:00
const uint32 BytesPerElement = 16 ;
2023-08-31 08:56:30 -04:00
checkf ( Params . NumBytes % BytesPerElement = = 0 , TEXT ( " NumBytes (%u) must be a multiple of BytesPerElement (%u) " ) , Params . NumBytes , BytesPerElement ) ;
checkf ( Buffer . NumBytes % BytesPerElement = = 0 , TEXT ( " NumBytes (%u) must be a multiple of BytesPerElement (%u) " ) , Buffer . NumBytes , BytesPerElement ) ;
2021-09-01 19:20:47 -04:00
uint32 NumElements = Params . NumBytes / BytesPerElement ;
uint32 NumElementsOld = Buffer . NumBytes / BytesPerElement ;
2023-08-31 08:56:30 -04:00
checkf ( NumElements % Params . NumArrays = = 0 , TEXT ( " NumElements (%u) must be a multiple of NumArrays (%u) " ) , NumElements , Params . NumArrays ) ;
checkf ( NumElementsOld % Params . NumArrays = = 0 , TEXT ( " NumElements (%u) must be a multiple of NumArrays (%u) " ) , NumElementsOld , Params . NumArrays ) ;
2021-04-06 13:59:36 -04:00
if ( Buffer . NumBytes = = 0 )
{
2023-06-22 11:08:27 -04:00
Buffer . Initialize ( GraphBuilder . RHICmdList , DebugName , BytesPerElement , NumElements ) ;
2021-04-06 13:59:36 -04:00
return true ;
}
2021-09-01 19:20:47 -04:00
else if ( Params . NumBytes ! = Buffer . NumBytes )
2021-04-06 13:59:36 -04:00
{
FRWBufferStructured NewBuffer ;
FRWBufferStructured OldBuffer = Buffer ;
2023-06-22 11:08:27 -04:00
NewBuffer . Initialize ( GraphBuilder . RHICmdList , DebugName , BytesPerElement , NumElements ) ;
2021-09-01 19:20:47 -04:00
2021-04-06 13:59:36 -04:00
AddPass ( GraphBuilder , RDG_EVENT_NAME ( " ResizeResourceSOAIfNeeded " ) ,
2024-09-05 11:12:23 -04:00
[ OldBuffer , NewBuffer , NumElements , NumElementsOld , Params ] ( FRDGAsyncTask , FRHICommandList & RHICmdList )
2021-04-06 13:59:36 -04:00
{
RHICmdList . Transition ( {
FRHITransitionInfo ( OldBuffer . UAV , ERHIAccess : : Unknown , ERHIAccess : : SRVCompute ) ,
FRHITransitionInfo ( NewBuffer . UAV , ERHIAccess : : Unknown , ERHIAccess : : UAVCompute )
} ) ;
// Copy data to new buffer
2021-09-01 19:20:47 -04:00
uint32 OldArraySize = NumElementsOld / Params . NumArrays ;
uint32 NewArraySize = NumElements / Params . NumArrays ;
2021-04-06 13:59:36 -04:00
RHICmdList . BeginUAVOverlap ( NewBuffer . UAV ) ;
2021-09-01 19:20:47 -04:00
FMemcpyResourceParams MemcpyParams ;
MemcpyParams . Count = FMath : : Min ( NewArraySize , OldArraySize ) ;
for ( uint32 i = 0 ; i < Params . NumArrays ; i + + )
2021-04-06 13:59:36 -04:00
{
2021-09-01 19:20:47 -04:00
MemcpyParams . SrcOffset = i * OldArraySize ;
MemcpyParams . DstOffset = i * NewArraySize ;
MemcpyResource ( RHICmdList , NewBuffer , OldBuffer , MemcpyParams , true ) ;
2021-04-06 13:59:36 -04:00
}
RHICmdList . EndUAVOverlap ( NewBuffer . UAV ) ;
} ) ;
Buffer = NewBuffer ;
return true ;
}
return false ;
}
template < typename FBufferType >
2021-09-01 19:20:47 -04:00
void AddCopyBufferPass ( FRDGBuilder & GraphBuilder , const FBufferType & NewBuffer , const FBufferType & OldBuffer , uint32 ElementSize )
2021-04-06 13:59:36 -04:00
{
AddPass ( GraphBuilder , RDG_EVENT_NAME ( " ResizeResourceIfNeeded-Copy " ) ,
2024-09-05 11:12:23 -04:00
[ OldBuffer , NewBuffer , ElementSize ] ( FRDGAsyncTask , FRHICommandList & RHICmdList )
2021-04-06 13:59:36 -04:00
{
RHICmdList . Transition ( {
FRHITransitionInfo ( OldBuffer . UAV , ERHIAccess : : Unknown , ERHIAccess : : SRVCompute ) ,
FRHITransitionInfo ( NewBuffer . UAV , ERHIAccess : : Unknown , ERHIAccess : : UAVCompute )
} ) ;
// Copy data to new buffer
2021-09-01 19:20:47 -04:00
FMemcpyResourceParams MemcpyParams ;
MemcpyParams . Count = FMath : : Min ( NewBuffer . NumBytes , OldBuffer . NumBytes ) / ElementSize ;
MemcpyParams . SrcOffset = 0 ;
MemcpyParams . DstOffset = 0 ;
MemcpyResource ( RHICmdList , NewBuffer , OldBuffer , MemcpyParams ) ;
2021-04-06 13:59:36 -04:00
} ) ;
}
RENDERCORE_API bool ResizeResourceIfNeeded ( FRDGBuilder & GraphBuilder , FRWBufferStructured & Buffer , uint32 NumBytes , const TCHAR * DebugName )
{
2021-09-01 19:20:47 -04:00
const uint32 BytesPerElement = 16 ;
2023-08-31 08:56:30 -04:00
checkf ( ( NumBytes % BytesPerElement ) = = 0 , TEXT ( " NumBytes (%u) must be a multiple of BytesPerElement (%u) " ) , NumBytes , BytesPerElement ) ;
2021-09-01 19:20:47 -04:00
uint32 NumElements = NumBytes / BytesPerElement ;
2021-04-06 13:59:36 -04:00
if ( Buffer . NumBytes = = 0 )
{
2023-06-22 11:08:27 -04:00
Buffer . Initialize ( GraphBuilder . RHICmdList , DebugName , BytesPerElement , NumElements ) ;
2021-04-06 13:59:36 -04:00
return true ;
}
else if ( NumBytes ! = Buffer . NumBytes )
{
FRWBufferStructured NewBuffer ;
2023-06-22 11:08:27 -04:00
NewBuffer . Initialize ( GraphBuilder . RHICmdList , DebugName , BytesPerElement , NumElements ) ;
2021-04-06 13:59:36 -04:00
2021-09-01 19:20:47 -04:00
AddCopyBufferPass ( GraphBuilder , NewBuffer , Buffer , BytesPerElement ) ;
2021-04-06 13:59:36 -04:00
Buffer = NewBuffer ;
return true ;
}
return false ;
}
RENDERCORE_API bool ResizeResourceIfNeeded ( FRDGBuilder & GraphBuilder , FRWByteAddressBuffer & Buffer , uint32 NumBytes , const TCHAR * DebugName )
{
// Needs to be aligned to 16 bytes to MemcpyResource to work correctly (otherwise it skips last unaligned elements of the buffer during resize)
check ( ( NumBytes & 15 ) = = 0 ) ;
if ( Buffer . NumBytes = = 0 )
{
2023-06-22 11:08:27 -04:00
Buffer . Initialize ( GraphBuilder . RHICmdList , DebugName , NumBytes ) ;
2021-04-06 13:59:36 -04:00
return true ;
}
else if ( NumBytes ! = Buffer . NumBytes )
{
FRWByteAddressBuffer NewBuffer ;
2023-06-22 11:08:27 -04:00
NewBuffer . Initialize ( GraphBuilder . RHICmdList , DebugName , NumBytes ) ;
2021-04-06 13:59:36 -04:00
2021-09-01 19:20:47 -04:00
AddCopyBufferPass ( GraphBuilder , NewBuffer , Buffer , 4 ) ;
Buffer = NewBuffer ;
return true ;
}
return false ;
}
RENDERCORE_API bool ResizeResourceIfNeeded ( FRDGBuilder & GraphBuilder , FRWBuffer & Buffer , EPixelFormat Format , uint32 NumElements , const TCHAR * DebugName )
{
const uint32 BytesPerElement = GPixelFormats [ Format ] . BlockBytes ;
const uint32 NumBytes = BytesPerElement * NumElements ;
if ( Buffer . NumBytes = = 0 )
{
2023-06-22 11:08:27 -04:00
Buffer . Initialize ( GraphBuilder . RHICmdList , DebugName , BytesPerElement , NumElements , Format ) ;
2021-09-01 19:20:47 -04:00
return true ;
}
else if ( NumBytes ! = Buffer . NumBytes )
{
FRWBuffer NewBuffer ;
2023-06-22 11:08:27 -04:00
NewBuffer . Initialize ( GraphBuilder . RHICmdList , DebugName , BytesPerElement , NumElements , Format ) ;
2021-09-01 19:20:47 -04:00
AddCopyBufferPass ( GraphBuilder , NewBuffer , Buffer , BytesPerElement ) ;
2021-04-06 13:59:36 -04:00
Buffer = NewBuffer ;
return true ;
}
return false ;
}
2020-01-24 18:07:01 -05:00
void FScatterUploadBuffer : : Init ( uint32 NumElements , uint32 InNumBytesPerElement , bool bInFloat4Buffer , const TCHAR * DebugName )
{
2023-06-22 11:08:27 -04:00
FRHICommandListBase & RHICmdList = FRHICommandListImmediate : : Get ( ) ;
2020-01-24 18:07:01 -05:00
NumScatters = 0 ;
MaxScatters = NumElements ;
NumBytesPerElement = InNumBytesPerElement ;
bFloat4Buffer = bInFloat4Buffer ;
2021-07-28 17:19:36 -04:00
const EBufferUsageFlags Usage = bInFloat4Buffer ? BUF_None : BUF_ByteAddressBuffer ;
2020-01-24 18:07:01 -05:00
const uint32 TypeSize = bInFloat4Buffer ? 16 : 4 ;
uint32 ScatterBytes = NumElements * sizeof ( uint32 ) ;
2022-04-21 06:46:12 -04:00
uint32 ScatterBufferSize = FMath : : RoundUpToPowerOfTwo ( ScatterBytes ) ;
2020-01-24 18:07:01 -05:00
uint32 UploadBytes = NumElements * NumBytesPerElement ;
2022-04-21 06:46:12 -04:00
uint32 UploadBufferSize = FMath : : RoundUpToPowerOfTwo ( UploadBytes ) ;
2021-03-24 16:27:13 -04:00
2021-11-23 14:18:14 -05:00
if ( bUploadViaCreate )
2020-01-24 18:07:01 -05:00
{
2021-11-23 14:18:14 -05:00
if ( ScatterBytes > ScatterDataSize | | ScatterBufferSize < ScatterDataSize / 2 )
{
FMemory : : Free ( ScatterData ) ;
ScatterData = ( uint32 * ) FMemory : : Malloc ( ScatterBufferSize ) ;
ScatterDataSize = ScatterBufferSize ;
}
2020-01-24 18:07:01 -05:00
2021-11-23 14:18:14 -05:00
if ( UploadBytes > UploadDataSize | | UploadBufferSize < UploadDataSize / 2 )
{
FMemory : : Free ( UploadData ) ;
UploadData = ( uint8 * ) FMemory : : Malloc ( UploadBufferSize ) ;
UploadDataSize = UploadBufferSize ;
}
}
else
{
check ( ScatterData = = nullptr ) ;
check ( UploadData = = nullptr ) ;
if ( ScatterBytes > ScatterBuffer . NumBytes | | ScatterBufferSize < ScatterBuffer . NumBytes / 2 )
{
// Resize Scatter Buffer
ScatterBuffer . Release ( ) ;
ScatterBuffer . NumBytes = ScatterBufferSize ;
FRHIResourceCreateInfo CreateInfo ( DebugName ) ;
2023-06-22 11:08:27 -04:00
ScatterBuffer . Buffer = RHICmdList . CreateStructuredBuffer ( sizeof ( uint32 ) , ScatterBuffer . NumBytes , BUF_ShaderResource | BUF_Volatile | Usage , CreateInfo ) ;
ScatterBuffer . SRV = RHICmdList . CreateShaderResourceView ( ScatterBuffer . Buffer ) ;
2021-11-23 14:18:14 -05:00
}
if ( UploadBytes > UploadBuffer . NumBytes | | UploadBufferSize < UploadBuffer . NumBytes / 2 )
{
// Resize Upload Buffer
UploadBuffer . Release ( ) ;
UploadBuffer . NumBytes = UploadBufferSize ;
FRHIResourceCreateInfo CreateInfo ( DebugName ) ;
2023-06-22 11:08:27 -04:00
UploadBuffer . Buffer = RHICmdList . CreateStructuredBuffer ( TypeSize , UploadBuffer . NumBytes , BUF_ShaderResource | BUF_Volatile | Usage , CreateInfo ) ;
UploadBuffer . SRV = RHICmdList . CreateShaderResourceView ( UploadBuffer . Buffer ) ;
2021-11-23 14:18:14 -05:00
}
2023-06-22 11:08:27 -04:00
ScatterData = ( uint32 * ) RHICmdList . LockBuffer ( ScatterBuffer . Buffer , 0 , ScatterBytes , RLM_WriteOnly ) ;
UploadData = ( uint8 * ) RHICmdList . LockBuffer ( UploadBuffer . Buffer , 0 , UploadBytes , RLM_WriteOnly ) ;
2021-11-23 14:18:14 -05:00
}
}
2021-12-03 10:44:54 -05:00
void FScatterUploadBuffer : : Init ( TArrayView < const uint32 > ElementScatterOffsets , uint32 InNumBytesPerElement , bool bInFloat4Buffer , const TCHAR * DebugName )
{
Init ( ElementScatterOffsets . Num ( ) , InNumBytesPerElement , bInFloat4Buffer , DebugName ) ;
FMemory : : ParallelMemcpy ( ScatterData , ElementScatterOffsets . GetData ( ) , ElementScatterOffsets . Num ( ) * ElementScatterOffsets . GetTypeSize ( ) , EMemcpyCachePolicy : : StoreUncached ) ;
NumScatters = ElementScatterOffsets . Num ( ) ;
}
void FScatterUploadBuffer : : InitPreSized ( uint32 NumElements , uint32 InNumBytesPerElement , bool bInFloat4Buffer , const TCHAR * DebugName )
{
Init ( NumElements , InNumBytesPerElement , bInFloat4Buffer , DebugName ) ;
NumScatters = NumElements ;
}
2020-02-12 13:27:19 -05:00
template < typename ResourceType >
2021-04-06 13:59:36 -04:00
void FScatterUploadBuffer : : ResourceUploadTo ( FRHICommandList & RHICmdList , const ResourceType & DstBuffer , bool bFlush )
2020-01-24 18:07:01 -05:00
{
2020-09-24 00:43:27 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( FScatterUploadBuffer : : ResourceUploadTo ) ;
2020-01-24 18:07:01 -05:00
2021-11-23 14:18:14 -05:00
if ( bUploadViaCreate )
{
ScatterBuffer . Release ( ) ;
UploadBuffer . Release ( ) ;
ScatterBuffer . NumBytes = ScatterDataSize ;
UploadBuffer . NumBytes = UploadDataSize ;
const uint32 TypeSize = bFloat4Buffer ? 16 : 4 ;
2024-08-02 17:45:40 -04:00
const EBufferUsageFlags Usage = EBufferUsageFlags : : StructuredBuffer | EBufferUsageFlags : : ShaderResource | EBufferUsageFlags : : Volatile | ( bFloat4Buffer ? EBufferUsageFlags : : None : EBufferUsageFlags : : ByteAddressBuffer ) ;
2021-11-23 14:18:14 -05:00
{
2024-08-02 17:45:40 -04:00
ScatterBuffer . Buffer = UE : : RHIResourceUtils : : CreateBufferFromArray ( RHICmdList , TEXT ( " ScatterResourceArray " ) , Usage , sizeof ( uint32 ) , ScatterData , ScatterDataSize ) ;
2023-06-22 11:08:27 -04:00
ScatterBuffer . SRV = RHICmdList . CreateShaderResourceView ( ScatterBuffer . Buffer ) ;
2021-11-23 14:18:14 -05:00
}
{
2024-08-02 17:45:40 -04:00
UploadBuffer . Buffer = UE : : RHIResourceUtils : : CreateBufferFromArray ( RHICmdList , TEXT ( " ScatterUploadBuffer " ) , Usage , TypeSize , UploadData , UploadDataSize ) ;
2023-06-22 11:08:27 -04:00
UploadBuffer . SRV = RHICmdList . CreateShaderResourceView ( UploadBuffer . Buffer ) ;
2021-11-23 14:18:14 -05:00
}
}
else
{
2023-06-22 11:08:27 -04:00
RHICmdList . UnlockBuffer ( ScatterBuffer . Buffer ) ;
RHICmdList . UnlockBuffer ( UploadBuffer . Buffer ) ;
2021-11-23 14:18:14 -05:00
ScatterData = nullptr ;
UploadData = nullptr ;
}
2020-01-24 18:07:01 -05:00
2020-02-12 13:27:19 -05:00
if ( NumScatters = = 0 )
2023-04-19 04:53:37 -04:00
{
2020-02-12 13:27:19 -05:00
return ;
2023-04-19 04:53:37 -04:00
}
2020-02-12 13:27:19 -05:00
constexpr uint32 ThreadGroupSize = 64u ;
uint32 NumBytesPerThread = ( NumBytesPerElement & 15 ) = = 0 ? 16 : 4 ;
uint32 NumThreadsPerScatter = NumBytesPerElement / NumBytesPerThread ;
2020-01-24 18:07:01 -05:00
uint32 NumThreads = NumScatters * NumThreadsPerScatter ;
2020-02-12 13:27:19 -05:00
uint32 NumDispatches = FMath : : DivideAndRoundUp ( NumThreads , ThreadGroupSize ) ;
uint32 NumLoops = FMath : : DivideAndRoundUp ( NumDispatches , ( uint32 ) GMaxComputeDispatchDimension ) ;
2020-01-24 18:07:01 -05:00
2021-08-03 07:56:47 -04:00
EByteBufferResourceType ResourceTypeEnum ;
2020-02-12 13:27:19 -05:00
2021-08-03 07:56:47 -04:00
FScatterCopyCS : : FParameters Parameters ;
2020-02-12 13:27:19 -05:00
Parameters . Common . Size = NumThreadsPerScatter ;
Parameters . NumScatters = NumScatters ;
2021-08-03 07:56:47 -04:00
check ( bFloat4Buffer | | ResourceTypeTraits < ResourceType > : : Type = = EResourceType : : BYTEBUFFER ) ;
2020-02-12 13:27:19 -05:00
if ( ResourceTypeTraits < ResourceType > : : Type = = EResourceType : : BYTEBUFFER )
{
2021-08-03 07:56:47 -04:00
if ( NumBytesPerThread = = 16 )
{
ResourceTypeEnum = EByteBufferResourceType : : Uint4Aligned_Buffer ;
}
else
{
ResourceTypeEnum = EByteBufferResourceType : : Uint_Buffer ;
}
2020-02-12 13:27:19 -05:00
Parameters . UploadByteAddressBuffer = UploadBuffer . SRV ;
Parameters . ScatterByteAddressBuffer = ScatterBuffer . SRV ;
Parameters . Common . DstByteAddressBuffer = DstBuffer . UAV ;
}
2021-08-03 07:56:47 -04:00
else if ( ResourceTypeTraits < ResourceType > : : Type = = EResourceType : : STRUCTURED_BUFFER )
2020-02-12 13:27:19 -05:00
{
2023-04-19 04:53:37 -04:00
ResourceTypeEnum = EByteBufferResourceType : : StructuredBuffer ;
2021-08-03 07:56:47 -04:00
2023-04-19 04:53:37 -04:00
Parameters . UploadStructuredBuffer4x = UploadBuffer . SRV ;
2020-02-12 13:27:19 -05:00
Parameters . ScatterStructuredBuffer = ScatterBuffer . SRV ;
2023-04-19 04:53:37 -04:00
Parameters . Common . DstStructuredBuffer4x = DstBuffer . UAV ;
2020-02-12 13:27:19 -05:00
}
2021-09-01 19:20:47 -04:00
else if ( ResourceTypeTraits < ResourceType > : : Type = = EResourceType : : BUFFER )
{
ResourceTypeEnum = EByteBufferResourceType : : Float4_Buffer ;
2023-04-19 04:53:37 -04:00
Parameters . UploadStructuredBuffer4x = UploadBuffer . SRV ;
2021-09-01 19:20:47 -04:00
Parameters . ScatterStructuredBuffer = ScatterBuffer . SRV ;
Parameters . Common . DstBuffer = DstBuffer . UAV ;
}
2020-02-12 13:27:19 -05:00
else if ( ResourceTypeTraits < ResourceType > : : Type = = EResourceType : : TEXTURE )
{
2021-08-03 07:56:47 -04:00
ResourceTypeEnum = EByteBufferResourceType : : Float4_Texture ;
2023-04-19 04:53:37 -04:00
Parameters . UploadStructuredBuffer4x = UploadBuffer . SRV ;
2020-02-12 13:27:19 -05:00
Parameters . ScatterStructuredBuffer = ScatterBuffer . SRV ;
Parameters . Common . DstTexture = DstBuffer . UAV ;
2021-08-03 07:56:47 -04:00
Parameters . Common . Float4sPerLine = CalculateFloat4sPerLine ( ) ;
2020-02-12 13:27:19 -05:00
}
2021-08-03 07:56:47 -04:00
FByteBufferShader : : FPermutationDomain PermutationVector ;
PermutationVector . Set < FByteBufferShader : : ResourceTypeDim > ( ( int ) ResourceTypeEnum ) ;
2023-04-19 04:53:37 -04:00
PermutationVector . Set < FMemcpyCS : : StructuredElementSizeDim > ( ( int32 ) EByteBufferStructuredSize : : Uint4 ) ;
2020-02-12 13:27:19 -05:00
2021-08-03 07:56:47 -04:00
auto ComputeShader = GetGlobalShaderMap ( GMaxRHIFeatureLevel ) - > GetShader < FScatterCopyCS > ( PermutationVector ) ;
2020-10-14 14:20:26 -04:00
RHICmdList . BeginUAVOverlap ( DstBuffer . UAV ) ;
2020-02-12 13:27:19 -05:00
for ( uint32 LoopIdx = 0 ; LoopIdx < NumLoops ; + + LoopIdx )
{
Parameters . Common . SrcOffset = LoopIdx * ( uint32 ) GMaxComputeDispatchDimension * ThreadGroupSize ;
uint32 LoopNumDispatch = FMath : : Min ( NumDispatches - LoopIdx * ( uint32 ) GMaxComputeDispatchDimension , ( uint32 ) GMaxComputeDispatchDimension ) ;
FComputeShaderUtils : : Dispatch ( RHICmdList , ComputeShader , Parameters , FIntVector ( LoopNumDispatch , 1 , 1 ) ) ;
}
2020-10-14 14:20:26 -04:00
RHICmdList . EndUAVOverlap ( DstBuffer . UAV ) ;
2022-03-10 21:53:39 -05:00
// We need to unbind shader SRVs in this case, because scatter upload buffers are sometimes used more than once in a
// frame, and this can cause rendering bugs on D3D12, where the driver fails to update the bound SRV with new data.
UnsetShaderSRVs ( RHICmdList , ComputeShader , ComputeShader . GetComputeShader ( ) ) ;
2020-10-14 14:20:26 -04:00
2020-02-12 13:27:19 -05:00
if ( bFlush )
{
FRHICommandListExecutor : : GetImmediateCommandList ( ) . ImmediateFlush ( EImmediateFlushType : : DispatchToRHIThread ) ;
2020-01-24 18:07:01 -05:00
}
}
2020-02-12 13:27:19 -05:00
2021-09-01 19:20:47 -04:00
template RENDERCORE_API void MemsetResource < FRWBufferStructured > ( FRHICommandList & RHICmdList , const FRWBufferStructured & DstBuffer , const FMemsetResourceParams & Params ) ;
template RENDERCORE_API void MemsetResource < FRWByteAddressBuffer > ( FRHICommandList & RHICmdList , const FRWByteAddressBuffer & DstBuffer , const FMemsetResourceParams & Params ) ;
2021-08-03 07:56:47 -04:00
2022-03-30 13:36:17 -04:00
template RENDERCORE_API void MemcpyResource < FTextureRWBuffer > ( FRHICommandList & RHICmdList , const FTextureRWBuffer & DstBuffer , const FTextureRWBuffer & SrcBuffer , const FMemcpyResourceParams & Params , bool bAlreadyInUAVOverlap ) ;
2021-09-01 19:20:47 -04:00
template RENDERCORE_API void MemcpyResource < FRWBuffer > ( FRHICommandList & RHICmdList , const FRWBuffer & DstBuffer , const FRWBuffer & SrcBuffer , const FMemcpyResourceParams & Params , bool bAlreadyInUAVOverlap ) ;
template RENDERCORE_API void MemcpyResource < FRWBufferStructured > ( FRHICommandList & RHICmdList , const FRWBufferStructured & DstBuffer , const FRWBufferStructured & SrcBuffer , const FMemcpyResourceParams & Params , bool bAlreadyInUAVOverlap ) ;
template RENDERCORE_API void MemcpyResource < FRWByteAddressBuffer > ( FRHICommandList & RHICmdList , const FRWByteAddressBuffer & DstBuffer , const FRWByteAddressBuffer & SrcBuffer , const FMemcpyResourceParams & Params , bool bAlreadyInUAVOverlap ) ;
2021-08-03 07:56:47 -04:00
2021-09-01 19:20:47 -04:00
template RENDERCORE_API void FScatterUploadBuffer : : ResourceUploadTo < FRWBuffer > ( FRHICommandList & RHICmdList , const FRWBuffer & DstBuffer , bool bFlush ) ;
2021-04-06 13:59:36 -04:00
template RENDERCORE_API void FScatterUploadBuffer : : ResourceUploadTo < FRWBufferStructured > ( FRHICommandList & RHICmdList , const FRWBufferStructured & DstBuffer , bool bFlush ) ;
2023-01-27 14:54:10 -05:00
template RENDERCORE_API void FScatterUploadBuffer : : ResourceUploadTo < FRWByteAddressBuffer > ( FRHICommandList & RHICmdList , const FRWByteAddressBuffer & DstBuffer , bool bFlush ) ;
2023-05-01 12:39:32 -04:00
// NOTE: Deprecated
template RENDERCORE_API void FScatterUploadBuffer : : ResourceUploadTo < FTextureRWBuffer > ( FRHICommandList & RHICmdList , const FTextureRWBuffer & DstBuffer , bool bFlush ) ;