2019-12-26 14:45:42 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2019-01-15 10:24:32 -05:00
/*=============================================================================
MeshDrawCommandSetup . cpp : Mesh draw command setup .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
# include "MeshDrawCommands.h"
# include "RendererModule.h"
# include "ScenePrivate.h"
# include "TranslucentRendering.h"
2021-01-14 05:23:34 -04:00
# include "InstanceCulling/InstanceCullingManager.h"
2019-01-15 10:24:32 -05:00
2019-01-18 15:03:15 -05:00
TGlobalResource < FPrimitiveIdVertexBufferPool > GPrimitiveIdVertexBufferPool ;
2019-01-17 11:09:36 -05:00
2019-01-15 10:24:32 -05:00
static TAutoConsoleVariable < int32 > CVarMeshDrawCommandsParallelPassSetup (
TEXT ( " r.MeshDrawCommands.ParallelPassSetup " ) ,
1 ,
TEXT ( " Whether to setup mesh draw command pass in parallel. " ) ,
ECVF_RenderThreadSafe ) ;
2019-02-13 03:55:43 -05:00
static TAutoConsoleVariable < int32 > CVarMobileMeshSortingMethod (
TEXT ( " r.Mobile.MeshSortingMethod " ) ,
0 ,
TEXT ( " How to sort mesh commands on mobile: \n " )
TEXT ( " \t 0: Sort by state, roughly front to back (Default). \n " )
TEXT ( " \t 1: Strict front to back sorting. \n " ) ,
ECVF_RenderThreadSafe ) ;
2020-09-24 00:43:27 -04:00
static int32 GAllowOnDemandShaderCreation = 1 ;
static FAutoConsoleVariableRef CVarAllowOnDemandShaderCreation (
TEXT ( " r.MeshDrawCommands.AllowOnDemandShaderCreation " ) ,
GAllowOnDemandShaderCreation ,
TEXT ( " How to create RHI shaders: \n " )
TEXT ( " \t 0: Always create them on a Rendering Thread, before executing other MDC tasks. \n " )
TEXT ( " \t 1: If RHI supports multi-threaded shader creation, create them on demand on tasks threads, at the time of submitting the draws. \n " ) ,
ECVF_RenderThreadSafe ) ;
2019-01-17 11:09:36 -05:00
FPrimitiveIdVertexBufferPool : : FPrimitiveIdVertexBufferPool ( )
: DiscardId ( 0 )
{
}
FPrimitiveIdVertexBufferPool : : ~ FPrimitiveIdVertexBufferPool ( )
{
2019-01-18 15:03:15 -05:00
check ( ! Entries . Num ( ) ) ;
2019-01-17 11:09:36 -05:00
}
2020-02-12 15:27:05 -05:00
FPrimitiveIdVertexBufferPoolEntry FPrimitiveIdVertexBufferPool : : Allocate ( int32 BufferSize )
2019-01-17 11:09:36 -05:00
{
2020-02-12 15:27:05 -05:00
check ( IsInRenderingThread ( ) ) ;
FScopeLock Lock ( & AllocationCS ) ;
2019-01-22 10:08:47 -05:00
BufferSize = Align ( BufferSize , 1024 ) ;
// First look for a smallest unused one.
int32 BestFitBufferIndex = - 1 ;
2019-01-17 11:09:36 -05:00
for ( int32 Index = 0 ; Index < Entries . Num ( ) ; + + Index )
{
2019-01-22 10:08:47 -05:00
// Unused and fits?
if ( Entries [ Index ] . LastDiscardId ! = DiscardId & & Entries [ Index ] . BufferSize > = BufferSize )
2019-01-17 11:09:36 -05:00
{
2019-01-22 10:08:47 -05:00
// Is it a bet fit than current BestFitBufferIndex?
if ( BestFitBufferIndex = = - 1 | | Entries [ Index ] . BufferSize < Entries [ BestFitBufferIndex ] . BufferSize )
{
BestFitBufferIndex = Index ;
if ( Entries [ BestFitBufferIndex ] . BufferSize = = BufferSize )
{
break ;
}
}
2019-01-17 11:09:36 -05:00
}
}
2019-01-22 10:08:47 -05:00
2020-02-12 15:27:05 -05:00
if ( BestFitBufferIndex > = 0 )
2019-01-22 10:08:47 -05:00
{
// Reuse existing buffer.
2020-02-12 15:27:05 -05:00
FPrimitiveIdVertexBufferPoolEntry ReusedEntry = MoveTemp ( Entries [ BestFitBufferIndex ] ) ;
ReusedEntry . LastDiscardId = DiscardId ;
Entries . RemoveAt ( BestFitBufferIndex ) ;
return ReusedEntry ;
2019-01-22 10:08:47 -05:00
}
else
{
// Allocate new one.
FPrimitiveIdVertexBufferPoolEntry NewEntry ;
NewEntry . LastDiscardId = DiscardId ;
NewEntry . BufferSize = BufferSize ;
2020-07-06 18:58:26 -04:00
FRHIResourceCreateInfo CreateInfo ( TEXT ( " FPrimitiveIdVertexBufferPool " ) ) ;
2019-01-22 10:08:47 -05:00
NewEntry . BufferRHI = RHICreateVertexBuffer ( NewEntry . BufferSize , BUF_Volatile , CreateInfo ) ;
2019-01-17 11:09:36 -05:00
2020-02-12 15:27:05 -05:00
return NewEntry ;
2019-01-22 10:08:47 -05:00
}
2019-01-17 11:09:36 -05:00
}
2020-02-12 15:27:05 -05:00
void FPrimitiveIdVertexBufferPool : : ReturnToFreeList ( FPrimitiveIdVertexBufferPoolEntry Entry )
{
// Entries can be returned from RHIT or RT, depending on if FParallelMeshDrawCommandPass::DispatchDraw() takes the parallel path
FScopeLock Lock ( & AllocationCS ) ;
Entries . Add ( MoveTemp ( Entry ) ) ;
}
2019-01-17 11:09:36 -05:00
void FPrimitiveIdVertexBufferPool : : DiscardAll ( )
{
2020-02-12 15:27:05 -05:00
FScopeLock Lock ( & AllocationCS ) ;
2019-01-17 11:09:36 -05:00
+ + DiscardId ;
// Remove old unused pool entries.
for ( int32 Index = 0 ; Index < Entries . Num ( ) ; )
{
if ( DiscardId - Entries [ Index ] . LastDiscardId > 1000u )
{
Entries . RemoveAtSwap ( Index ) ;
}
else
{
+ + Index ;
}
}
}
2019-01-18 15:03:15 -05:00
void FPrimitiveIdVertexBufferPool : : ReleaseDynamicRHI ( )
{
Entries . Empty ( ) ;
}
2019-01-15 10:24:32 -05:00
uint32 BitInvertIfNegativeFloat ( uint32 f )
{
unsigned mask = - int32 ( f > > 31 ) | 0x80000000 ;
return f ^ mask ;
}
/**
* Update mesh sort keys with view dependent data .
*/
void UpdateTranslucentMeshSortKeys (
ETranslucentSortPolicy : : Type TranslucentSortPolicy ,
const FVector & TranslucentSortAxis ,
const FVector & ViewOrigin ,
const FMatrix & ViewMatrix ,
const TArray < struct FPrimitiveBounds > & PrimitiveBounds ,
ETranslucencyPass : : Type TranslucencyPass ,
2022-03-22 15:06:48 -04:00
bool bInverseSorting ,
2019-01-15 10:24:32 -05:00
FMeshCommandOneFrameArray & VisibleMeshCommands
)
{
QUICK_SCOPE_CYCLE_COUNTER ( STAT_UpdateTranslucentMeshSortKeys ) ;
for ( int32 CommandIndex = 0 ; CommandIndex < VisibleMeshCommands . Num ( ) ; + + CommandIndex )
{
FVisibleMeshDrawCommand & VisibleCommand = VisibleMeshCommands [ CommandIndex ] ;
2021-06-21 12:27:09 -04:00
const int32 PrimitiveIndex = VisibleCommand . PrimitiveIdInfo . ScenePrimitiveId ;
2019-06-11 18:27:07 -04:00
const FVector BoundsOrigin = PrimitiveIndex > = 0 ? PrimitiveBounds [ PrimitiveIndex ] . BoxSphereBounds . Origin : FVector : : ZeroVector ;
2019-01-15 10:24:32 -05:00
float Distance = 0.0f ;
if ( TranslucentSortPolicy = = ETranslucentSortPolicy : : SortByDistance )
{
//sort based on distance to the view position, view rotation is not a factor
Distance = ( BoundsOrigin - ViewOrigin ) . Size ( ) ;
}
else if ( TranslucentSortPolicy = = ETranslucentSortPolicy : : SortAlongAxis )
{
// Sort based on enforced orthogonal distance
const FVector CameraToObject = BoundsOrigin - ViewOrigin ;
Distance = FVector : : DotProduct ( CameraToObject , TranslucentSortAxis ) ;
}
else
{
// Sort based on projected Z distance
check ( TranslucentSortPolicy = = ETranslucentSortPolicy : : SortByProjectedZ ) ;
Distance = ViewMatrix . TransformPosition ( BoundsOrigin ) . Z ;
}
2020-11-24 18:42:39 -04:00
// Apply distance offset from the primitive
const uint32 PackedOffset = VisibleCommand . SortKey . Translucent . Distance ;
const float DistanceOffset = * ( ( float * ) & PackedOffset ) ;
Distance + = DistanceOffset ;
2022-03-22 15:06:48 -04:00
// Sort front-to-back instead of back-to-front
if ( bInverseSorting )
{
const float MaxSortingDistance = 1000000.f ; // 100km, arbitrary
Distance = MaxSortingDistance - Distance ;
}
2019-01-15 10:24:32 -05:00
// Patch distance inside translucent mesh sort key.
2019-01-21 09:54:32 -05:00
FMeshDrawCommandSortKey SortKey ;
SortKey . PackedData = VisibleCommand . SortKey . PackedData ;
SortKey . Translucent . Distance = ( uint32 ) ~ BitInvertIfNegativeFloat ( * ( ( uint32 * ) & Distance ) ) ;
VisibleCommand . SortKey . PackedData = SortKey . PackedData ;
2019-01-15 10:24:32 -05:00
}
}
/**
* Merge mobile BasePass with BasePassCSM based on CSM visibility in order to select appropriate shader for given command .
*/
void MergeMobileBasePassMeshDrawCommands (
const FMobileCSMVisibilityInfo & MobileCSMVisibilityInfo ,
int32 ScenePrimitiveNum ,
FMeshCommandOneFrameArray & MeshCommands ,
FMeshCommandOneFrameArray & MeshCommandsCSM
)
{
if ( MobileCSMVisibilityInfo . bMobileDynamicCSMInUse )
{
// determine per view CSM visibility
2021-09-27 19:54:25 -04:00
if ( MobileCSMVisibilityInfo . bAlwaysUseCSM )
2019-01-15 10:24:32 -05:00
{
2021-09-27 19:54:25 -04:00
# if DO_CHECK
check ( ! MeshCommandsCSM . Num ( ) | | MeshCommands . Num ( ) = = MeshCommandsCSM . Num ( ) ) ;
for ( int32 Index = 0 ; Index < MeshCommandsCSM . Num ( ) ; + + Index )
2019-01-15 10:24:32 -05:00
{
2021-09-27 19:54:25 -04:00
check ( MeshCommands [ Index ] . PrimitiveIdInfo . ScenePrimitiveId = = MeshCommandsCSM [ Index ] . PrimitiveIdInfo . ScenePrimitiveId ) ;
}
# endif
if ( MeshCommandsCSM . Num ( ) > 0 )
{
MeshCommands = MoveTemp ( MeshCommandsCSM ) ;
2019-01-15 10:24:32 -05:00
}
}
2021-09-27 19:54:25 -04:00
else
{
checkf ( MeshCommands . Num ( ) = = MeshCommandsCSM . Num ( ) , TEXT ( " VisibleMeshDrawCommands of BasePass and MobileBasePassCSM are expected to match. " ) ) ;
for ( int32 i = MeshCommands . Num ( ) - 1 ; i > = 0 ; - - i )
{
FVisibleMeshDrawCommand & MeshCommand = MeshCommands [ i ] ;
FVisibleMeshDrawCommand & MeshCommandCSM = MeshCommandsCSM [ i ] ;
if ( MeshCommand . PrimitiveIdInfo . ScenePrimitiveId < ScenePrimitiveNum & & MobileCSMVisibilityInfo . MobilePrimitiveCSMReceiverVisibilityMap [ MeshCommand . PrimitiveIdInfo . ScenePrimitiveId ] )
{
checkf ( MeshCommand . PrimitiveIdInfo . ScenePrimitiveId = = MeshCommandCSM . PrimitiveIdInfo . ScenePrimitiveId , TEXT ( " VisibleMeshDrawCommands of BasePass and MobileBasePassCSM are expected to match. " ) ) ;
// Use CSM's VisibleMeshDrawCommand.
MeshCommand = MeshCommandCSM ;
}
}
MeshCommandsCSM . Reset ( ) ;
}
2019-01-15 10:24:32 -05:00
}
}
2022-03-31 04:42:34 -04:00
static uint64 GetMobileBasePassSortKey_FrontToBack ( bool bMasked , bool bBackground , uint32 PipelineId , int32 StateBucketId , float PrimitiveDistance )
{
union
{
uint64 PackedInt ;
struct
{
uint64 StateBucketId : 25 ; // Order by state bucket
uint64 PipelineId : 22 ; // Order by PSO
uint64 DepthBits : 15 ; // Order by primitive depth
uint64 Background : 1 ; // Non-background meshes first
uint64 Masked : 1 ; // Non-masked first
} Fields ;
} Key ;
union FFloatToInt { float F ; uint32 I ; } ;
FFloatToInt F2I ;
Key . Fields . Masked = bMasked ;
Key . Fields . Background = bBackground ;
F2I . F = PrimitiveDistance ;
Key . Fields . DepthBits = ( ( - int32 ( F2I . I > > 31 ) | 0x80000000 ) ^ F2I . I ) > > 17 ;
Key . Fields . PipelineId = PipelineId ;
Key . Fields . StateBucketId = StateBucketId ;
return Key . PackedInt ;
}
static uint32 DepthBuckets_4 ( float Distance )
{
union FFloatToInt { float F ; uint32 I ; } ;
FFloatToInt F2I ;
F2I . F = Distance ;
// discard distance shorter than 64
int32 Exp = ( ( F2I . I > > 23u ) & 0xff ) - ( 127 + 6 ) ;
// 16 buckets, ranging from 64 to 2km
return ( uint32 ) FMath : : Clamp < int32 > ( Exp , 0 , 15 ) ;
}
static uint64 GetMobileBasePassSortKey_ByState ( bool bMasked , bool bBackground , uint32 PipelineId , uint32 StateBucketId , float PipelineDistance , float StateBucketDistance , float PrimitiveDistance )
{
// maximum primitive distance for bucketing, aprox 10.5km
constexpr float PrimitiveMaxDepth = ( 1 < < 20 ) ;
constexpr float PrimitiveDepthQuantization = ( ( 1 < < 12 ) - 1 ) ;
union
{
uint64 PackedInt ;
struct
{
uint64 DepthBits : 12 ; // Order by primitive depth
uint64 StateBucketId : 20 ; // Order by state bucket
uint64 StateBucketDepthBits : 4 ; // Order state buckets front to back
uint64 PipelineId : 22 ; // Order by PSO
uint64 PipelineDepthBits : 4 ; // Order PSOs front to back
uint64 Background : 1 ; // Non-background meshes first
uint64 Masked : 1 ; // Non-masked first
} Fields ;
} Key ;
Key . PackedInt = 0 ;
Key . Fields . Masked = bMasked ;
Key . Fields . Background = bBackground ;
Key . Fields . PipelineDepthBits = DepthBuckets_4 ( PipelineDistance ) ;
Key . Fields . PipelineId = PipelineId ;
Key . Fields . StateBucketDepthBits = DepthBuckets_4 ( StateBucketDistance ) ;
Key . Fields . StateBucketId = StateBucketId ;
Key . Fields . DepthBits = uint32 ( ( FMath : : Min < float > ( PrimitiveDistance , PrimitiveMaxDepth ) / PrimitiveMaxDepth ) * PrimitiveDepthQuantization ) ;
return Key . PackedInt ;
}
2019-01-15 10:24:32 -05:00
/**
* Compute mesh sort keys for the mobile base pass
*/
void UpdateMobileBasePassMeshSortKeys (
const FVector & ViewOrigin ,
const TArray < struct FPrimitiveBounds > & ScenePrimitiveBounds ,
FMeshCommandOneFrameArray & VisibleMeshCommands
)
{
QUICK_SCOPE_CYCLE_COUNTER ( STAT_UpdateMobileBasePassMeshSortKeys ) ;
2022-03-31 04:42:34 -04:00
// Object radius past which we treat object as part of 'background'
constexpr float MIN_BACKGROUND_OBJECT_RADIUS = 500000 ;
2019-01-15 10:24:32 -05:00
int32 NumCmds = VisibleMeshCommands . Num ( ) ;
2019-02-13 03:55:43 -05:00
int32 MeshSortingMethod = CVarMobileMeshSortingMethod . GetValueOnAnyThread ( ) ;
if ( MeshSortingMethod = = 1 ) //strict front to back sorting
2019-01-15 10:24:32 -05:00
{
2019-02-13 03:55:43 -05:00
// compute sort key for each mesh command
for ( int32 CmdIdx = 0 ; CmdIdx < NumCmds ; + + CmdIdx )
2019-01-15 10:24:32 -05:00
{
2019-02-13 03:55:43 -05:00
FVisibleMeshDrawCommand & Cmd = VisibleMeshCommands [ CmdIdx ] ;
// Set in MobileBasePass.cpp - GetBasePassStaticSortKey;
2022-03-31 04:42:34 -04:00
bool bMasked = Cmd . SortKey . PackedData & 0x1 ? true : false ;
2019-02-13 03:55:43 -05:00
bool bBackground = Cmd . SortKey . PackedData & 0x2 ? true : false ;
float PrimitiveDistance = 0 ;
2021-06-21 12:27:09 -04:00
if ( Cmd . PrimitiveIdInfo . ScenePrimitiveId < ScenePrimitiveBounds . Num ( ) )
2019-02-13 03:55:43 -05:00
{
2021-06-21 12:27:09 -04:00
const FPrimitiveBounds & PrimitiveBounds = ScenePrimitiveBounds [ Cmd . PrimitiveIdInfo . ScenePrimitiveId ] ;
2019-02-13 03:55:43 -05:00
PrimitiveDistance = ( PrimitiveBounds . BoxSphereBounds . Origin - ViewOrigin ) . Size ( ) ;
2022-03-31 04:42:34 -04:00
bBackground | = ( PrimitiveBounds . BoxSphereBounds . SphereRadius > MIN_BACKGROUND_OBJECT_RADIUS ) ;
2019-02-13 03:55:43 -05:00
}
2019-01-15 10:24:32 -05:00
2019-02-18 13:18:45 -05:00
uint32 PipelineId = Cmd . MeshDrawCommand - > CachedPipelineId . GetId ( ) ;
2019-05-23 00:36:32 -04:00
// use state bucket if dynamic instancing is enabled, otherwise identify same meshes by index buffer resource
2022-03-31 04:42:34 -04:00
uint32 StateBucketId = Cmd . StateBucketId > = 0 ? Cmd . StateBucketId : PointerHash ( Cmd . MeshDrawCommand - > IndexBuffer ) ;
2019-02-13 03:55:43 -05:00
Cmd . SortKey . PackedData = GetMobileBasePassSortKey_FrontToBack ( bMasked , bBackground , PipelineId , StateBucketId , PrimitiveDistance ) ;
}
2019-01-15 10:24:32 -05:00
}
2022-03-31 04:42:34 -04:00
else
2019-01-15 10:24:32 -05:00
{
2022-03-31 04:42:34 -04:00
struct FPipelineDistance
{
double DistanceSum = 0.0 ;
int32 Num = 0 ;
} ;
TMap < uint32 , FPipelineDistance > PipelineDistances ;
2019-02-13 03:55:43 -05:00
PipelineDistances . Reserve ( 256 ) ;
2022-03-31 04:42:34 -04:00
TMap < uint64 , float > StateBucketDistances ;
StateBucketDistances . Reserve ( 512 ) ;
// pre-compute a distance to a group of meshes that share same PSO and state
2019-02-13 03:55:43 -05:00
for ( int32 CmdIdx = 0 ; CmdIdx < NumCmds ; + + CmdIdx )
2019-01-15 10:24:32 -05:00
{
2021-06-21 12:27:09 -04:00
const FVisibleMeshDrawCommand & Cmd = VisibleMeshCommands [ CmdIdx ] ;
2022-03-31 04:42:34 -04:00
float PrimitiveDistance = 0.f ;
2021-06-21 12:27:09 -04:00
if ( Cmd . PrimitiveIdInfo . ScenePrimitiveId < ScenePrimitiveBounds . Num ( ) )
2019-02-13 03:55:43 -05:00
{
2021-06-21 12:27:09 -04:00
const FPrimitiveBounds & PrimitiveBounds = ScenePrimitiveBounds [ Cmd . PrimitiveIdInfo . ScenePrimitiveId ] ;
2019-02-13 03:55:43 -05:00
PrimitiveDistance = ( PrimitiveBounds . BoxSphereBounds . Origin - ViewOrigin ) . Size ( ) ;
}
2022-03-31 04:42:34 -04:00
// group meshes by PSO and find distance to each group
uint32 PipelineId = Cmd . MeshDrawCommand - > CachedPipelineId . GetId ( ) ;
FPipelineDistance & PipelineDistance = PipelineDistances . FindOrAdd ( PipelineId ) ;
PipelineDistance . DistanceSum + = PrimitiveDistance ;
PipelineDistance . Num + = 1 ;
// group meshes by StateBucketId or index buffer resource and find minimum distance to each group
uint32 StateBucketId = Cmd . StateBucketId > = 0 ? Cmd . StateBucketId : PointerHash ( Cmd . MeshDrawCommand - > IndexBuffer ) ;
uint64 PipelineAndStateBucketId = ( ( uint64 ) PipelineId < < 32u ) | StateBucketId ;
float & StateBucketDistance = StateBucketDistances . FindOrAdd ( PipelineAndStateBucketId , BIG_NUMBER ) ;
StateBucketDistance = FMath : : Min ( StateBucketDistance , PrimitiveDistance ) ;
2019-01-15 10:24:32 -05:00
}
2019-02-13 03:55:43 -05:00
// compute sort key for each mesh command
for ( int32 CmdIdx = 0 ; CmdIdx < NumCmds ; + + CmdIdx )
{
FVisibleMeshDrawCommand & Cmd = VisibleMeshCommands [ CmdIdx ] ;
// Set in MobileBasePass.cpp - GetBasePassStaticSortKey;
2022-03-31 04:42:34 -04:00
bool bMasked = Cmd . SortKey . PackedData & 0x1 ? true : false ;
2019-02-13 03:55:43 -05:00
bool bBackground = Cmd . SortKey . PackedData & 0x2 ? true : false ;
float PrimitiveDistance = 0 ;
2021-06-21 12:27:09 -04:00
if ( Cmd . PrimitiveIdInfo . ScenePrimitiveId < ScenePrimitiveBounds . Num ( ) )
2019-02-13 03:55:43 -05:00
{
2021-06-21 12:27:09 -04:00
const FPrimitiveBounds & PrimitiveBounds = ScenePrimitiveBounds [ Cmd . PrimitiveIdInfo . ScenePrimitiveId ] ;
2019-02-13 03:55:43 -05:00
PrimitiveDistance = ( PrimitiveBounds . BoxSphereBounds . Origin - ViewOrigin ) . Size ( ) ;
2022-03-31 04:42:34 -04:00
bBackground | = ( PrimitiveBounds . BoxSphereBounds . SphereRadius > MIN_BACKGROUND_OBJECT_RADIUS ) ;
2019-02-13 03:55:43 -05:00
}
2022-03-31 04:42:34 -04:00
uint32 PipelineId = Cmd . MeshDrawCommand - > CachedPipelineId . GetId ( ) ;
FPipelineDistance PipelineDistance = PipelineDistances . FindRef ( PipelineId ) ;
float MeanPipelineDistance = PipelineDistance . DistanceSum / PipelineDistance . Num ;
uint32 StateBucketId = Cmd . StateBucketId > = 0 ? Cmd . StateBucketId : PointerHash ( Cmd . MeshDrawCommand - > IndexBuffer ) ;
uint64 PipelineAndStateBucketId = ( ( uint64 ) PipelineId < < 32u ) | StateBucketId ;
float StateBucketDistance = StateBucketDistances . FindRef ( PipelineAndStateBucketId ) ;
Cmd . SortKey . PackedData = GetMobileBasePassSortKey_ByState ( bMasked , bBackground , PipelineId , StateBucketId , MeanPipelineDistance , StateBucketDistance , PrimitiveDistance ) ;
2019-02-13 03:55:43 -05:00
}
2019-01-15 10:24:32 -05:00
}
}
2021-02-17 15:31:33 -04:00
FORCEINLINE int32 TranslatePrimitiveId ( int32 DrawPrimitiveIdIn , int32 DynamicPrimitiveIdOffset , int32 DynamicPrimitiveIdMax )
{
2021-09-08 20:06:34 -04:00
// INDEX_NONE means we defer the translation to later
if ( DynamicPrimitiveIdOffset = = INDEX_NONE )
2021-02-17 15:31:33 -04:00
{
return DrawPrimitiveIdIn ;
}
2021-09-08 20:06:34 -04:00
2021-02-17 15:31:33 -04:00
int32 DrawPrimitiveId = DrawPrimitiveIdIn ;
if ( ( DrawPrimitiveIdIn & GPrimIDDynamicFlag ) ! = 0 )
{
int32 DynamicPrimitiveIndex = DrawPrimitiveIdIn & ( ~ GPrimIDDynamicFlag ) ;
DrawPrimitiveId = DynamicPrimitiveIdOffset + DynamicPrimitiveIndex ;
checkSlow ( DrawPrimitiveId < DynamicPrimitiveIdMax ) ;
}
2021-09-08 20:06:34 -04:00
// Append flag to mark this as a non-instance data index.
// This value is treated as a primitive ID in the SceneData.ush loading.
const uint32 VF_TREAT_INSTANCE_ID_OFFSET_AS_PRIMITIVE_ID_FLAG = 1U < < 31U ;
return DrawPrimitiveId | = VF_TREAT_INSTANCE_ID_OFFSET_AS_PRIMITIVE_ID_FLAG ;
2021-02-17 15:31:33 -04:00
}
2019-01-15 10:24:32 -05:00
/**
* Build mesh draw command primitive Id buffer for instancing .
* TempVisibleMeshDrawCommands must be presized for NewPassVisibleMeshDrawCommands .
*/
2021-02-17 15:31:33 -04:00
static void BuildMeshDrawCommandPrimitiveIdBuffer (
2019-01-29 11:23:59 -05:00
bool bDynamicInstancing ,
2019-01-15 10:24:32 -05:00
FMeshCommandOneFrameArray & VisibleMeshDrawCommands ,
FDynamicMeshDrawCommandStorage & MeshDrawCommandStorage ,
FMeshCommandOneFrameArray & TempVisibleMeshDrawCommands ,
int32 & MaxInstances ,
int32 & VisibleMeshDrawCommandsNum ,
2019-01-17 05:02:52 -05:00
int32 & NewPassVisibleMeshDrawCommandsNum ,
2019-10-22 11:07:33 -04:00
EShaderPlatform ShaderPlatform ,
2021-02-17 15:31:33 -04:00
uint32 InstanceFactor ,
2021-08-07 07:20:52 -04:00
TFunctionRef < void ( int32 , int32 ) > WritePrimitiveDataFn )
2019-01-15 10:24:32 -05:00
{
QUICK_SCOPE_CYCLE_COUNTER ( STAT_BuildMeshDrawCommandPrimitiveIdBuffer ) ;
const FVisibleMeshDrawCommand * RESTRICT PassVisibleMeshDrawCommands = VisibleMeshDrawCommands . GetData ( ) ;
const int32 NumDrawCommands = VisibleMeshDrawCommands . Num ( ) ;
2019-01-17 05:02:52 -05:00
uint32 PrimitiveIdIndex = 0 ;
2019-01-15 10:24:32 -05:00
2019-01-29 11:23:59 -05:00
if ( bDynamicInstancing )
2019-01-15 10:24:32 -05:00
{
QUICK_SCOPE_CYCLE_COUNTER ( STAT_DynamicInstancingOfVisibleMeshDrawCommands ) ;
2019-01-18 23:03:56 -05:00
check ( VisibleMeshDrawCommands . Num ( ) < = TempVisibleMeshDrawCommands . Max ( ) & & TempVisibleMeshDrawCommands . Num ( ) = = 0 ) ;
2019-01-15 10:24:32 -05:00
int32 CurrentStateBucketId = - 1 ;
uint32 * RESTRICT CurrentDynamicallyInstancedMeshCommandNumInstances = nullptr ;
MaxInstances = 1 ;
for ( int32 DrawCommandIndex = 0 ; DrawCommandIndex < NumDrawCommands ; DrawCommandIndex + + )
{
const FVisibleMeshDrawCommand & RESTRICT VisibleMeshDrawCommand = PassVisibleMeshDrawCommands [ DrawCommandIndex ] ;
if ( VisibleMeshDrawCommand . StateBucketId = = CurrentStateBucketId & & VisibleMeshDrawCommand . StateBucketId ! = - 1 )
{
if ( CurrentDynamicallyInstancedMeshCommandNumInstances )
{
const int32 CurrentNumInstances = * CurrentDynamicallyInstancedMeshCommandNumInstances ;
* CurrentDynamicallyInstancedMeshCommandNumInstances = CurrentNumInstances + 1 ;
MaxInstances = FMath : : Max ( MaxInstances , CurrentNumInstances + 1 ) ;
}
else
{
FVisibleMeshDrawCommand NewVisibleMeshDrawCommand = VisibleMeshDrawCommand ;
2019-01-17 05:02:52 -05:00
NewVisibleMeshDrawCommand . PrimitiveIdBufferOffset = PrimitiveIdIndex ;
2019-01-15 10:24:32 -05:00
TempVisibleMeshDrawCommands . Emplace ( MoveTemp ( NewVisibleMeshDrawCommand ) ) ;
}
}
else
{
// First time state bucket setup
CurrentStateBucketId = VisibleMeshDrawCommand . StateBucketId ;
2020-09-24 00:43:27 -04:00
if ( VisibleMeshDrawCommand . StateBucketId ! = INDEX_NONE
& & VisibleMeshDrawCommand . MeshDrawCommand - > PrimitiveIdStreamIndex > = 0
2019-01-15 10:24:32 -05:00
& & VisibleMeshDrawCommand . MeshDrawCommand - > NumInstances = = 1
// Don't create a new FMeshDrawCommand for the last command and make it safe for us to look at the next command
& & DrawCommandIndex + 1 < NumDrawCommands
// Only create a new FMeshDrawCommand if more than one draw in the state bucket
& & CurrentStateBucketId = = PassVisibleMeshDrawCommands [ DrawCommandIndex + 1 ] . StateBucketId )
{
const int32 Index = MeshDrawCommandStorage . MeshDrawCommands . AddElement ( * VisibleMeshDrawCommand . MeshDrawCommand ) ;
FMeshDrawCommand & NewCommand = MeshDrawCommandStorage . MeshDrawCommands [ Index ] ;
FVisibleMeshDrawCommand NewVisibleMeshDrawCommand ;
NewVisibleMeshDrawCommand . Setup (
& NewCommand ,
2021-06-21 12:27:09 -04:00
VisibleMeshDrawCommand . PrimitiveIdInfo ,
2019-01-15 10:24:32 -05:00
VisibleMeshDrawCommand . StateBucketId ,
VisibleMeshDrawCommand . MeshFillMode ,
VisibleMeshDrawCommand . MeshCullMode ,
2021-02-17 15:32:52 -04:00
VisibleMeshDrawCommand . Flags ,
2021-01-19 08:25:03 -04:00
VisibleMeshDrawCommand . SortKey ,
VisibleMeshDrawCommand . RunArray ,
VisibleMeshDrawCommand . NumRuns ) ;
2019-01-15 10:24:32 -05:00
2019-01-17 05:02:52 -05:00
NewVisibleMeshDrawCommand . PrimitiveIdBufferOffset = PrimitiveIdIndex ;
2019-01-15 10:24:32 -05:00
TempVisibleMeshDrawCommands . Emplace ( MoveTemp ( NewVisibleMeshDrawCommand ) ) ;
CurrentDynamicallyInstancedMeshCommandNumInstances = & NewCommand . NumInstances ;
}
else
{
CurrentDynamicallyInstancedMeshCommandNumInstances = nullptr ;
FVisibleMeshDrawCommand NewVisibleMeshDrawCommand = VisibleMeshDrawCommand ;
2019-01-17 05:02:52 -05:00
NewVisibleMeshDrawCommand . PrimitiveIdBufferOffset = PrimitiveIdIndex ;
2019-01-15 10:24:32 -05:00
TempVisibleMeshDrawCommands . Emplace ( MoveTemp ( NewVisibleMeshDrawCommand ) ) ;
}
}
2019-01-17 05:02:52 -05:00
//@todo - refactor into instance step rate in the RHI
for ( uint32 InstanceFactorIndex = 0 ; InstanceFactorIndex < InstanceFactor ; InstanceFactorIndex + + , PrimitiveIdIndex + + )
{
2021-08-07 07:20:52 -04:00
WritePrimitiveDataFn ( PrimitiveIdIndex , VisibleMeshDrawCommand . PrimitiveIdInfo . DrawPrimitiveId ) ;
2019-01-17 05:02:52 -05:00
}
2019-01-15 10:24:32 -05:00
}
// Setup instancing stats for logging.
VisibleMeshDrawCommandsNum = VisibleMeshDrawCommands . Num ( ) ;
NewPassVisibleMeshDrawCommandsNum = TempVisibleMeshDrawCommands . Num ( ) ;
// Replace VisibleMeshDrawCommands
FMemory : : Memswap ( & VisibleMeshDrawCommands , & TempVisibleMeshDrawCommands , sizeof ( TempVisibleMeshDrawCommands ) ) ;
TempVisibleMeshDrawCommands . Reset ( ) ;
}
else
{
QUICK_SCOPE_CYCLE_COUNTER ( STAT_BuildVisibleMeshDrawCommandPrimitiveIdBuffers ) ;
for ( int32 DrawCommandIndex = 0 ; DrawCommandIndex < NumDrawCommands ; DrawCommandIndex + + )
{
const FVisibleMeshDrawCommand & VisibleMeshDrawCommand = VisibleMeshDrawCommands [ DrawCommandIndex ] ;
2019-01-17 05:02:52 -05:00
for ( uint32 InstanceFactorIndex = 0 ; InstanceFactorIndex < InstanceFactor ; InstanceFactorIndex + + , PrimitiveIdIndex + + )
{
2021-08-07 07:20:52 -04:00
WritePrimitiveDataFn ( PrimitiveIdIndex , VisibleMeshDrawCommand . PrimitiveIdInfo . DrawPrimitiveId ) ;
2019-01-17 05:02:52 -05:00
}
2019-01-15 10:24:32 -05:00
}
}
}
/**
* Converts each FMeshBatch into a set of FMeshDrawCommands for a specific mesh pass type .
*/
void GenerateDynamicMeshDrawCommands (
const FViewInfo & View ,
EShadingPath ShadingPath ,
EMeshPass : : Type PassType ,
FMeshPassProcessor * PassMeshProcessor ,
const TArray < FMeshBatchAndRelevance , SceneRenderingAllocator > & DynamicMeshElements ,
2019-01-28 17:06:11 -05:00
const TArray < FMeshPassMask , SceneRenderingAllocator > * DynamicMeshElementsPassRelevance ,
2019-01-16 11:28:46 -05:00
int32 MaxNumDynamicMeshElements ,
2019-01-16 15:48:19 -05:00
const TArray < const FStaticMeshBatch * , SceneRenderingAllocator > & DynamicMeshCommandBuildRequests ,
2019-01-16 11:28:46 -05:00
int32 MaxNumBuildRequestElements ,
2019-01-15 10:24:32 -05:00
FMeshCommandOneFrameArray & VisibleCommands ,
2019-05-16 16:08:59 -04:00
FDynamicMeshDrawCommandStorage & MeshDrawCommandStorage ,
2020-02-06 13:13:41 -05:00
FGraphicsMinimalPipelineStateSet & MinimalPipelineStatePassSet ,
bool & NeedsShaderInitialisation
2019-01-15 10:24:32 -05:00
)
{
QUICK_SCOPE_CYCLE_COUNTER ( STAT_GenerateDynamicMeshDrawCommands ) ;
check ( PassMeshProcessor ) ;
2019-01-28 17:06:11 -05:00
check ( ( PassType = = EMeshPass : : Num ) = = ( DynamicMeshElementsPassRelevance = = nullptr ) ) ;
2019-01-15 10:24:32 -05:00
FDynamicPassMeshDrawListContext DynamicPassMeshDrawListContext (
MeshDrawCommandStorage ,
2019-05-16 16:08:59 -04:00
VisibleCommands ,
2020-02-06 13:13:41 -05:00
MinimalPipelineStatePassSet ,
NeedsShaderInitialisation
2019-01-15 10:24:32 -05:00
) ;
PassMeshProcessor - > SetDrawListContext ( & DynamicPassMeshDrawListContext ) ;
{
2019-01-16 11:28:46 -05:00
const int32 NumCommandsBefore = VisibleCommands . Num ( ) ;
const int32 NumDynamicMeshBatches = DynamicMeshElements . Num ( ) ;
2019-01-15 10:24:32 -05:00
2019-01-16 11:28:46 -05:00
for ( int32 MeshIndex = 0 ; MeshIndex < NumDynamicMeshBatches ; MeshIndex + + )
{
2019-01-28 17:06:11 -05:00
if ( ! DynamicMeshElementsPassRelevance | | ( * DynamicMeshElementsPassRelevance ) [ MeshIndex ] . Get ( PassType ) )
{
const FMeshBatchAndRelevance & MeshAndRelevance = DynamicMeshElements [ MeshIndex ] ;
const uint64 BatchElementMask = ~ 0ull ;
2019-01-16 11:28:46 -05:00
2019-01-28 17:06:11 -05:00
PassMeshProcessor - > AddMeshBatch ( * MeshAndRelevance . Mesh , BatchElementMask , MeshAndRelevance . PrimitiveSceneProxy ) ;
}
2019-01-16 11:28:46 -05:00
}
const int32 NumCommandsGenerated = VisibleCommands . Num ( ) - NumCommandsBefore ;
checkf ( NumCommandsGenerated < = MaxNumDynamicMeshElements ,
TEXT ( " Generated %d mesh draw commands for DynamicMeshElements, while preallocating resources only for %d of them. " ) , NumCommandsGenerated , MaxNumDynamicMeshElements ) ;
2019-01-15 10:24:32 -05:00
}
{
2019-01-16 11:28:46 -05:00
const int32 NumCommandsBefore = VisibleCommands . Num ( ) ;
const int32 NumStaticMeshBatches = DynamicMeshCommandBuildRequests . Num ( ) ;
2019-01-15 10:24:32 -05:00
2019-01-16 11:28:46 -05:00
for ( int32 MeshIndex = 0 ; MeshIndex < NumStaticMeshBatches ; MeshIndex + + )
{
2019-01-16 15:48:19 -05:00
const FStaticMeshBatch * StaticMeshBatch = DynamicMeshCommandBuildRequests [ MeshIndex ] ;
2020-06-23 18:40:00 -04:00
const uint64 DefaultBatchElementMask = ~ 0ul ;
PassMeshProcessor - > AddMeshBatch ( * StaticMeshBatch , DefaultBatchElementMask , StaticMeshBatch - > PrimitiveSceneInfo - > Proxy , StaticMeshBatch - > Id ) ;
2019-01-16 11:28:46 -05:00
}
const int32 NumCommandsGenerated = VisibleCommands . Num ( ) - NumCommandsBefore ;
checkf ( NumCommandsGenerated < = MaxNumBuildRequestElements ,
TEXT ( " Generated %d mesh draw commands for DynamicMeshCommandBuildRequests, while preallocating resources only for %d of them. " ) , NumCommandsGenerated , MaxNumBuildRequestElements ) ;
2019-01-15 10:24:32 -05:00
}
}
/**
* Special version of GenerateDynamicMeshDrawCommands for the mobile base pass .
* Based on CSM visibility it will generate mesh draw commands using either normal base pass processor or CSM base pass processor .
*/
void GenerateMobileBasePassDynamicMeshDrawCommands (
const FViewInfo & View ,
EShadingPath ShadingPath ,
EMeshPass : : Type PassType ,
FMeshPassProcessor * PassMeshProcessor ,
FMeshPassProcessor * MobilePassCSMPassMeshProcessor ,
const TArray < FMeshBatchAndRelevance , SceneRenderingAllocator > & DynamicMeshElements ,
2019-01-28 17:06:11 -05:00
const TArray < FMeshPassMask , SceneRenderingAllocator > * DynamicMeshElementsPassRelevance ,
2019-01-16 11:28:46 -05:00
int32 MaxNumDynamicMeshElements ,
2019-01-16 15:48:19 -05:00
const TArray < const FStaticMeshBatch * , SceneRenderingAllocator > & DynamicMeshCommandBuildRequests ,
2019-01-16 11:28:46 -05:00
int32 MaxNumBuildRequestElements ,
2019-01-15 10:24:32 -05:00
FMeshCommandOneFrameArray & VisibleCommands ,
2019-05-16 16:08:59 -04:00
FDynamicMeshDrawCommandStorage & MeshDrawCommandStorage ,
2020-02-06 13:13:41 -05:00
FGraphicsMinimalPipelineStateSet & GraphicsMinimalPipelineStateSet ,
bool & NeedsShaderInitialisation
2019-01-15 10:24:32 -05:00
)
{
QUICK_SCOPE_CYCLE_COUNTER ( STAT_GenerateMobileBasePassDynamicMeshDrawCommands ) ;
check ( PassMeshProcessor & & MobilePassCSMPassMeshProcessor ) ;
2019-01-28 17:06:11 -05:00
check ( ( PassType = = EMeshPass : : Num ) = = ( DynamicMeshElementsPassRelevance = = nullptr ) ) ;
2019-01-15 10:24:32 -05:00
FDynamicPassMeshDrawListContext DynamicPassMeshDrawListContext (
MeshDrawCommandStorage ,
2019-05-16 16:08:59 -04:00
VisibleCommands ,
2020-02-06 13:13:41 -05:00
GraphicsMinimalPipelineStateSet ,
NeedsShaderInitialisation
2019-01-15 10:24:32 -05:00
) ;
PassMeshProcessor - > SetDrawListContext ( & DynamicPassMeshDrawListContext ) ;
MobilePassCSMPassMeshProcessor - > SetDrawListContext ( & DynamicPassMeshDrawListContext ) ;
const FMobileCSMVisibilityInfo & MobileCSMVisibilityInfo = View . MobileCSMVisibilityInfo ;
{
2019-01-16 11:28:46 -05:00
const int32 NumCommandsBefore = VisibleCommands . Num ( ) ;
const int32 NumDynamicMeshBatches = DynamicMeshElements . Num ( ) ;
2019-01-15 10:24:32 -05:00
2019-01-16 11:28:46 -05:00
for ( int32 MeshIndex = 0 ; MeshIndex < NumDynamicMeshBatches ; MeshIndex + + )
2019-01-15 10:24:32 -05:00
{
2019-01-28 17:06:11 -05:00
if ( ! DynamicMeshElementsPassRelevance | | ( * DynamicMeshElementsPassRelevance ) [ MeshIndex ] . Get ( PassType ) )
{
const FMeshBatchAndRelevance & MeshAndRelevance = DynamicMeshElements [ MeshIndex ] ;
const uint64 BatchElementMask = ~ 0ull ;
2019-01-16 11:28:46 -05:00
2019-01-28 17:06:11 -05:00
const int32 PrimitiveIndex = MeshAndRelevance . PrimitiveSceneProxy - > GetPrimitiveSceneInfo ( ) - > GetIndex ( ) ;
if ( MobileCSMVisibilityInfo . bMobileDynamicCSMInUse
& & ( MobileCSMVisibilityInfo . bAlwaysUseCSM | | MobileCSMVisibilityInfo . MobilePrimitiveCSMReceiverVisibilityMap [ PrimitiveIndex ] ) )
{
MobilePassCSMPassMeshProcessor - > AddMeshBatch ( * MeshAndRelevance . Mesh , BatchElementMask , MeshAndRelevance . PrimitiveSceneProxy ) ;
}
else
{
PassMeshProcessor - > AddMeshBatch ( * MeshAndRelevance . Mesh , BatchElementMask , MeshAndRelevance . PrimitiveSceneProxy ) ;
}
2019-01-16 11:28:46 -05:00
}
2019-01-15 10:24:32 -05:00
}
2019-01-16 11:28:46 -05:00
const int32 NumCommandsGenerated = VisibleCommands . Num ( ) - NumCommandsBefore ;
checkf ( NumCommandsGenerated < = MaxNumDynamicMeshElements ,
TEXT ( " Generated %d mesh draw commands for DynamicMeshElements, while preallocating resources only for %d of them. " ) , NumCommandsGenerated , MaxNumDynamicMeshElements ) ;
2019-01-15 10:24:32 -05:00
}
{
2019-01-16 11:28:46 -05:00
const int32 NumCommandsBefore = VisibleCommands . Num ( ) ;
const int32 NumStaticMeshBatches = DynamicMeshCommandBuildRequests . Num ( ) ;
2019-01-15 10:24:32 -05:00
2019-01-16 11:28:46 -05:00
for ( int32 MeshIndex = 0 ; MeshIndex < NumStaticMeshBatches ; MeshIndex + + )
2019-01-15 10:24:32 -05:00
{
2019-01-16 15:48:19 -05:00
const FStaticMeshBatch * StaticMeshBatch = DynamicMeshCommandBuildRequests [ MeshIndex ] ;
2019-01-16 11:28:46 -05:00
const int32 PrimitiveIndex = StaticMeshBatch - > PrimitiveSceneInfo - > Proxy - > GetPrimitiveSceneInfo ( ) - > GetIndex ( ) ;
if ( MobileCSMVisibilityInfo . bMobileDynamicCSMInUse
& & ( MobileCSMVisibilityInfo . bAlwaysUseCSM | | MobileCSMVisibilityInfo . MobilePrimitiveCSMReceiverVisibilityMap [ PrimitiveIndex ] ) )
{
2020-06-23 18:40:00 -04:00
const uint64 DefaultBatchElementMask = ~ 0ul ;
MobilePassCSMPassMeshProcessor - > AddMeshBatch ( * StaticMeshBatch , DefaultBatchElementMask , StaticMeshBatch - > PrimitiveSceneInfo - > Proxy , StaticMeshBatch - > Id ) ;
2019-01-16 11:28:46 -05:00
}
else
{
2020-06-23 18:40:00 -04:00
const uint64 DefaultBatchElementMask = ~ 0ul ;
PassMeshProcessor - > AddMeshBatch ( * StaticMeshBatch , DefaultBatchElementMask , StaticMeshBatch - > PrimitiveSceneInfo - > Proxy , StaticMeshBatch - > Id ) ;
2019-01-16 11:28:46 -05:00
}
2019-01-15 10:24:32 -05:00
}
2019-01-16 11:28:46 -05:00
const int32 NumCommandsGenerated = VisibleCommands . Num ( ) - NumCommandsBefore ;
checkf ( NumCommandsGenerated < = MaxNumBuildRequestElements ,
TEXT ( " Generated %d mesh draw commands for DynamicMeshCommandBuildRequests, while preallocating resources only for %d of them. " ) , NumCommandsGenerated , MaxNumBuildRequestElements ) ;
2019-01-15 10:24:32 -05:00
}
}
/**
* Apply view overrides to existing mesh draw commands ( e . g . reverse culling mode for rendering planar reflections ) .
* TempVisibleMeshDrawCommands must be presized for NewPassVisibleMeshDrawCommands .
*/
void ApplyViewOverridesToMeshDrawCommands (
EShadingPath ShadingPath ,
EMeshPass : : Type PassType ,
bool bReverseCulling ,
bool bRenderSceneTwoSided ,
FExclusiveDepthStencil : : Type BasePassDepthStencilAccess ,
2019-03-12 10:09:45 -04:00
FExclusiveDepthStencil : : Type DefaultBasePassDepthStencilAccess ,
2019-01-15 10:24:32 -05:00
FMeshCommandOneFrameArray & VisibleMeshDrawCommands ,
FDynamicMeshDrawCommandStorage & MeshDrawCommandStorage ,
2019-05-16 16:08:59 -04:00
FGraphicsMinimalPipelineStateSet & MinimalPipelineStatePassSet ,
2020-02-06 13:13:41 -05:00
bool & NeedsShaderInitialisation ,
2019-01-15 10:24:32 -05:00
FMeshCommandOneFrameArray & TempVisibleMeshDrawCommands
)
{
QUICK_SCOPE_CYCLE_COUNTER ( STAT_ApplyViewOverridesToMeshDrawCommands ) ;
check ( VisibleMeshDrawCommands . Num ( ) < = TempVisibleMeshDrawCommands . Max ( ) & & TempVisibleMeshDrawCommands . Num ( ) = = 0 & & PassType ! = EMeshPass : : Num ) ;
if ( ( FPassProcessorManager : : GetPassFlags ( ShadingPath , PassType ) & EMeshPassFlags : : MainView ) ! = EMeshPassFlags : : None )
{
if ( bReverseCulling | | bRenderSceneTwoSided | | ( BasePassDepthStencilAccess ! = DefaultBasePassDepthStencilAccess & & PassType = = EMeshPass : : BasePass ) )
{
for ( int32 MeshCommandIndex = 0 ; MeshCommandIndex < VisibleMeshDrawCommands . Num ( ) ; MeshCommandIndex + + )
{
MeshDrawCommandStorage . MeshDrawCommands . Add ( 1 ) ;
FMeshDrawCommand & NewMeshCommand = MeshDrawCommandStorage . MeshDrawCommands [ MeshDrawCommandStorage . MeshDrawCommands . Num ( ) - 1 ] ;
const FVisibleMeshDrawCommand & VisibleMeshDrawCommand = VisibleMeshDrawCommands [ MeshCommandIndex ] ;
const FMeshDrawCommand & MeshCommand = * VisibleMeshDrawCommand . MeshDrawCommand ;
NewMeshCommand = MeshCommand ;
2019-01-16 14:28:24 -05:00
const ERasterizerCullMode LocalCullMode = bRenderSceneTwoSided ? CM_None : bReverseCulling ? FMeshPassProcessor : : InverseCullMode ( VisibleMeshDrawCommand . MeshCullMode ) : VisibleMeshDrawCommand . MeshCullMode ;
2019-04-08 18:20:01 -04:00
2019-05-16 16:08:59 -04:00
FGraphicsMinimalPipelineStateInitializer PipelineState = MeshCommand . CachedPipelineId . GetPipelineState ( MinimalPipelineStatePassSet ) ;
2019-02-14 08:36:29 -05:00
PipelineState . RasterizerState = GetStaticRasterizerState < true > ( VisibleMeshDrawCommand . MeshFillMode , LocalCullMode ) ;
2019-01-15 10:24:32 -05:00
if ( BasePassDepthStencilAccess ! = DefaultBasePassDepthStencilAccess & & PassType = = EMeshPass : : BasePass )
{
2019-01-16 16:09:39 -05:00
FMeshPassProcessorRenderState PassDrawRenderState ;
2019-01-15 10:24:32 -05:00
SetupBasePassState ( BasePassDepthStencilAccess , false , PassDrawRenderState ) ;
2019-02-14 08:36:29 -05:00
PipelineState . DepthStencilState = PassDrawRenderState . GetDepthStencilState ( ) ;
2019-01-15 10:24:32 -05:00
}
2020-02-06 13:13:41 -05:00
const FGraphicsMinimalPipelineStateId PipelineId = FGraphicsMinimalPipelineStateId : : GetPipelineStateId ( PipelineState , MinimalPipelineStatePassSet , NeedsShaderInitialisation ) ;
2019-02-18 13:18:45 -05:00
NewMeshCommand . Finalize ( PipelineId , nullptr ) ;
2019-01-15 10:24:32 -05:00
FVisibleMeshDrawCommand NewVisibleMeshDrawCommand ;
NewVisibleMeshDrawCommand . Setup (
& NewMeshCommand ,
2021-06-21 12:27:09 -04:00
VisibleMeshDrawCommand . PrimitiveIdInfo ,
2019-01-15 10:24:32 -05:00
VisibleMeshDrawCommand . StateBucketId ,
VisibleMeshDrawCommand . MeshFillMode ,
VisibleMeshDrawCommand . MeshCullMode ,
2021-02-17 15:32:52 -04:00
VisibleMeshDrawCommand . Flags ,
2021-01-19 08:25:03 -04:00
VisibleMeshDrawCommand . SortKey ,
VisibleMeshDrawCommand . RunArray ,
VisibleMeshDrawCommand . NumRuns ) ;
2019-01-15 10:24:32 -05:00
TempVisibleMeshDrawCommands . Add ( NewVisibleMeshDrawCommand ) ;
}
// Replace VisibleMeshDrawCommands
FMemory : : Memswap ( & VisibleMeshDrawCommands , & TempVisibleMeshDrawCommands , sizeof ( TempVisibleMeshDrawCommands ) ) ;
TempVisibleMeshDrawCommands . Reset ( ) ;
}
}
}
FAutoConsoleTaskPriority CPrio_FMeshDrawCommandPassSetupTask (
TEXT ( " TaskGraph.TaskPriorities.FMeshDrawCommandPassSetupTask " ) ,
TEXT ( " Task and thread priority for FMeshDrawCommandPassSetupTask. " ) ,
2019-02-07 15:44:07 -05:00
ENamedThreads : : NormalThreadPriority ,
ENamedThreads : : HighTaskPriority
2019-01-15 10:24:32 -05:00
) ;
/**
* Task for a parallel setup of mesh draw commands . Includes generation of dynamic mesh draw commands , sorting , merging etc .
*/
class FMeshDrawCommandPassSetupTask
{
public :
FMeshDrawCommandPassSetupTask ( FMeshDrawCommandPassSetupTaskContext & InContext )
: Context ( InContext )
{
}
FORCEINLINE TStatId GetStatId ( ) const
{
RETURN_QUICK_DECLARE_CYCLE_STAT ( FMeshDrawCommandPassSetupTask , STATGROUP_TaskGraphTasks ) ;
}
ENamedThreads : : Type GetDesiredThread ( )
{
return CPrio_FMeshDrawCommandPassSetupTask . Get ( ) ;
}
static ESubsequentsMode : : Type GetSubsequentsMode ( )
{
return ESubsequentsMode : : TrackSubsequents ;
}
void AnyThreadTask ( )
{
2020-07-02 13:21:15 -04:00
FOptionalTaskTagScope Scope ( ETaskTag : : EParallelRenderingThread ) ;
2021-08-04 23:10:26 -04:00
SCOPED_NAMED_EVENT ( MeshDrawCommandPassSetupTask , FColor : : Magenta ) ;
2019-01-15 10:24:32 -05:00
// Mobile base pass is a special case, as final lists is created from two mesh passes based on CSM visibility.
2020-03-02 11:00:17 -05:00
const bool bMobileShadingBasePass = Context . ShadingPath = = EShadingPath : : Mobile & & Context . PassType = = EMeshPass : : BasePass ;
// On SM5 Mobile platform, still want the same sorting
const bool bMobileVulkanSM5BasePass = IsVulkanMobileSM5Platform ( Context . ShaderPlatform ) & & Context . PassType = = EMeshPass : : BasePass ;
2019-01-15 10:24:32 -05:00
2020-03-02 11:00:17 -05:00
if ( bMobileShadingBasePass )
2019-01-15 10:24:32 -05:00
{
MergeMobileBasePassMeshDrawCommands (
Context . View - > MobileCSMVisibilityInfo ,
Context . PrimitiveBounds - > Num ( ) ,
Context . MeshDrawCommands ,
Context . MobileBasePassCSMMeshDrawCommands
) ;
GenerateMobileBasePassDynamicMeshDrawCommands (
* Context . View ,
Context . ShadingPath ,
Context . PassType ,
Context . MeshPassProcessor ,
Context . MobileBasePassCSMMeshPassProcessor ,
* Context . DynamicMeshElements ,
2019-01-28 17:06:11 -05:00
Context . DynamicMeshElementsPassRelevance ,
2019-01-15 10:24:32 -05:00
Context . NumDynamicMeshElements ,
Context . DynamicMeshCommandBuildRequests ,
Context . NumDynamicMeshCommandBuildRequestElements ,
Context . MeshDrawCommands ,
2019-05-16 16:08:59 -04:00
Context . MeshDrawCommandStorage ,
2020-02-06 13:13:41 -05:00
Context . MinimalPipelineStatePassSet ,
Context . NeedsShaderInitialisation
2019-01-15 10:24:32 -05:00
) ;
}
else
{
GenerateDynamicMeshDrawCommands (
* Context . View ,
Context . ShadingPath ,
Context . PassType ,
Context . MeshPassProcessor ,
* Context . DynamicMeshElements ,
2019-01-28 17:06:11 -05:00
Context . DynamicMeshElementsPassRelevance ,
2019-01-15 10:24:32 -05:00
Context . NumDynamicMeshElements ,
Context . DynamicMeshCommandBuildRequests ,
Context . NumDynamicMeshCommandBuildRequestElements ,
Context . MeshDrawCommands ,
2019-05-16 16:08:59 -04:00
Context . MeshDrawCommandStorage ,
2020-02-06 13:13:41 -05:00
Context . MinimalPipelineStatePassSet ,
Context . NeedsShaderInitialisation
2019-01-15 10:24:32 -05:00
) ;
}
if ( Context . MeshDrawCommands . Num ( ) > 0 )
{
if ( Context . PassType ! = EMeshPass : : Num )
{
ApplyViewOverridesToMeshDrawCommands (
Context . ShadingPath ,
Context . PassType ,
Context . bReverseCulling ,
Context . bRenderSceneTwoSided ,
Context . BasePassDepthStencilAccess ,
2019-03-12 10:09:45 -04:00
Context . DefaultBasePassDepthStencilAccess ,
2019-01-15 10:24:32 -05:00
Context . MeshDrawCommands ,
Context . MeshDrawCommandStorage ,
2019-05-16 16:08:59 -04:00
Context . MinimalPipelineStatePassSet ,
2020-02-06 13:13:41 -05:00
Context . NeedsShaderInitialisation ,
2019-01-15 10:24:32 -05:00
Context . TempVisibleMeshDrawCommands
) ;
}
// Update sort keys.
2020-03-02 11:00:17 -05:00
if ( bMobileShadingBasePass | | bMobileVulkanSM5BasePass )
2019-01-15 10:24:32 -05:00
{
UpdateMobileBasePassMeshSortKeys (
Context . ViewOrigin ,
* Context . PrimitiveBounds ,
Context . MeshDrawCommands
) ;
}
else if ( Context . TranslucencyPass ! = ETranslucencyPass : : TPT_MAX )
{
2022-03-22 15:06:48 -04:00
// When per-pixel OIT is enabled, sort primitive from front to back ensure avoid
// constantly resorting front-to-back samples list.
const bool bInverseSorting = OIT : : IsEnabled ( EOITSortingType : : SortedPixels , Context . ShaderPlatform ) & & Context . View - > AntiAliasingMethod ! = EAntiAliasingMethod : : AAM_MSAA ;
2019-01-15 10:24:32 -05:00
UpdateTranslucentMeshSortKeys (
Context . TranslucentSortPolicy ,
Context . TranslucentSortAxis ,
Context . ViewOrigin ,
Context . ViewMatrix ,
* Context . PrimitiveBounds ,
Context . TranslucencyPass ,
2022-03-22 15:06:48 -04:00
bInverseSorting ,
2019-01-15 10:24:32 -05:00
Context . MeshDrawCommands
) ;
}
{
QUICK_SCOPE_CYCLE_COUNTER ( STAT_SortVisibleMeshDrawCommands ) ;
Context . MeshDrawCommands . Sort ( FCompareFMeshDrawCommands ( ) ) ;
}
if ( Context . bUseGPUScene )
{
2021-06-08 10:54:17 -04:00
Context . InstanceCullingContext . SetupDrawCommands ( Context . MeshDrawCommands , true , Context . MaxInstances , Context . VisibleMeshDrawCommandsNum , Context . NewPassVisibleMeshDrawCommandsNum ) ;
2019-01-15 10:24:32 -05:00
}
}
}
void DoTask ( ENamedThreads : : Type CurrentThread , const FGraphEventRef & MyCompletionGraphEvent )
{
AnyThreadTask ( ) ;
}
2020-02-06 13:13:41 -05:00
private :
FMeshDrawCommandPassSetupTaskContext & Context ;
} ;
/**
* Task for shader initialization . This will run on the RenderThread after Commands have been generated .
*/
class FMeshDrawCommandInitResourcesTask
{
public :
FMeshDrawCommandInitResourcesTask ( FMeshDrawCommandPassSetupTaskContext & InContext )
: Context ( InContext )
{
}
FORCEINLINE TStatId GetStatId ( ) const
{
RETURN_QUICK_DECLARE_CYCLE_STAT ( FMeshDrawCommandInitResourcesTask , STATGROUP_TaskGraphTasks ) ;
}
ENamedThreads : : Type GetDesiredThread ( )
{
return ENamedThreads : : GetRenderThread_Local ( ) ;
}
static ESubsequentsMode : : Type GetSubsequentsMode ( )
{
return ESubsequentsMode : : TrackSubsequents ;
}
void AnyThreadTask ( )
{
TRACE_CPUPROFILER_EVENT_SCOPE ( MeshDrawCommandInitResourcesTask ) ;
if ( Context . NeedsShaderInitialisation )
{
for ( const FGraphicsMinimalPipelineStateInitializer & Initializer : Context . MinimalPipelineStatePassSet )
{
Initializer . BoundShaderState . LazilyInitShaders ( ) ;
}
}
}
void DoTask ( ENamedThreads : : Type CurrentThread , const FGraphEventRef & MyCompletionGraphEvent )
{
AnyThreadTask ( ) ;
}
2019-01-15 10:24:32 -05:00
private :
FMeshDrawCommandPassSetupTaskContext & Context ;
} ;
2019-01-17 12:25:59 -05:00
/*
* Used by various dynamic passes to sort / merge mesh draw commands immediately on a rendering thread .
*/
void SortAndMergeDynamicPassMeshDrawCommands (
2021-08-07 07:20:52 -04:00
const FSceneView & SceneView ,
2019-01-15 10:24:32 -05:00
FMeshCommandOneFrameArray & VisibleMeshDrawCommands ,
FDynamicMeshDrawCommandStorage & MeshDrawCommandStorage ,
2021-01-20 06:49:41 -04:00
FRHIBuffer * & OutPrimitiveIdVertexBuffer ,
2021-02-17 15:31:33 -04:00
uint32 InstanceFactor ,
2021-08-07 07:20:52 -04:00
const FGPUScenePrimitiveCollector * DynamicPrimitiveCollector )
2019-01-15 10:24:32 -05:00
{
2021-08-07 07:20:52 -04:00
const ERHIFeatureLevel : : Type FeatureLevel = SceneView . GetFeatureLevel ( ) ;
2019-01-15 10:24:32 -05:00
const bool bUseGPUScene = UseGPUScene ( GMaxRHIShaderPlatform , FeatureLevel ) ;
const int32 NumDrawCommands = VisibleMeshDrawCommands . Num ( ) ;
if ( NumDrawCommands > 0 )
{
FMeshCommandOneFrameArray NewPassVisibleMeshDrawCommands ;
int32 MaxInstances = 1 ;
int32 VisibleMeshDrawCommandsNum = 0 ;
int32 NewPassVisibleMeshDrawCommandsNum = 0 ;
VisibleMeshDrawCommands . Sort ( FCompareFMeshDrawCommands ( ) ) ;
if ( bUseGPUScene )
{
2021-01-20 19:57:54 -04:00
// GPUCULL_TODO: workaround for the fact that DrawDynamicMeshPassPrivate et al. don't work with GPU-Scene instancing
// we don't support dynamic instancing for this path since we require one primitive per draw command
// This is because the stride on the instance data buffer is set to 0 so only the first will ever be fetched.
const bool bDynamicInstancing = false ;
2021-05-25 08:15:14 -04:00
2019-01-29 11:23:59 -05:00
if ( bDynamicInstancing )
2019-01-17 11:09:36 -05:00
{
NewPassVisibleMeshDrawCommands . Empty ( NumDrawCommands ) ;
}
2021-09-08 20:06:34 -04:00
// INDEX_NONE used in TranslatePrimitiveId to defer id translation
int32 DynamicPrimitiveIdOffset = INDEX_NONE ;
int32 DynamicPrimitiveIdMax = 0 ;
if ( DynamicPrimitiveCollector )
{
const TRange < int32 > DynamicPrimitiveIdRange = DynamicPrimitiveCollector - > GetPrimitiveIdRange ( ) ;
DynamicPrimitiveIdOffset = DynamicPrimitiveIdRange . GetLowerBoundValue ( ) ;
DynamicPrimitiveIdMax = DynamicPrimitiveIdRange . GetUpperBoundValue ( ) ;
}
2021-08-07 07:20:52 -04:00
const uint32 PrimitiveIdBufferStride = FInstanceCullingContext : : GetInstanceIdBufferStride ( FeatureLevel ) ;
const int32 MaxNumPrimitives = InstanceFactor * NumDrawCommands ;
const int32 PrimitiveIdBufferDataSize = MaxNumPrimitives * PrimitiveIdBufferStride ;
2020-02-12 15:27:05 -05:00
FPrimitiveIdVertexBufferPoolEntry Entry = GPrimitiveIdVertexBufferPool . Allocate ( PrimitiveIdBufferDataSize ) ;
OutPrimitiveIdVertexBuffer = Entry . BufferRHI ;
2020-12-10 11:51:32 -04:00
void * PrimitiveIdBufferData = RHILockBuffer ( OutPrimitiveIdVertexBuffer , 0 , PrimitiveIdBufferDataSize , RLM_WriteOnly ) ;
2019-01-17 11:09:36 -05:00
2021-08-07 07:20:52 -04:00
if ( FeatureLevel = = ERHIFeatureLevel : : ES3_1 )
{
2021-10-06 02:20:54 -04:00
check ( sizeof ( FGPUSceneCompactInstanceData ) = = PrimitiveIdBufferStride ) ;
2021-08-07 07:20:52 -04:00
auto WritePrimitiveDataFn = [ & ] ( int32 PrimitiveIndex , int32 PrimitiveId )
{
checkSlow ( PrimitiveIndex < MaxNumPrimitives ) ;
2021-10-06 02:20:54 -04:00
2021-08-07 07:20:52 -04:00
FGPUSceneCompactInstanceData * PrimitiveData = reinterpret_cast < FGPUSceneCompactInstanceData * > ( PrimitiveIdBufferData ) + PrimitiveIndex ;
if ( ( PrimitiveId & GPrimIDDynamicFlag ) ! = 0 )
{
PrimitiveId = PrimitiveId & ( ~ GPrimIDDynamicFlag ) ;
PrimitiveData - > Init ( DynamicPrimitiveCollector , PrimitiveId ) ;
}
else
{
const FScene * Scene = SceneView . Family - > Scene - > GetRenderScene ( ) ;
PrimitiveData - > Init ( Scene , PrimitiveId ) ;
}
} ;
BuildMeshDrawCommandPrimitiveIdBuffer (
bDynamicInstancing ,
VisibleMeshDrawCommands ,
MeshDrawCommandStorage ,
NewPassVisibleMeshDrawCommands ,
MaxInstances ,
VisibleMeshDrawCommandsNum ,
NewPassVisibleMeshDrawCommandsNum ,
GShaderPlatformForFeatureLevel [ FeatureLevel ] ,
InstanceFactor ,
WritePrimitiveDataFn ) ;
}
else
{
int32 * RESTRICT PrimitiveIds = reinterpret_cast < int32 * > ( PrimitiveIdBufferData ) ;
auto WritePrimitiveDataFn = [ & ] ( int32 PrimitiveIndex , int32 DrawPrimitiveId )
{
checkSlow ( PrimitiveIndex < MaxNumPrimitives ) ;
PrimitiveIds [ PrimitiveIndex ] = TranslatePrimitiveId ( DrawPrimitiveId , DynamicPrimitiveIdOffset , DynamicPrimitiveIdMax ) ;
} ;
BuildMeshDrawCommandPrimitiveIdBuffer (
bDynamicInstancing ,
VisibleMeshDrawCommands ,
MeshDrawCommandStorage ,
NewPassVisibleMeshDrawCommands ,
MaxInstances ,
VisibleMeshDrawCommandsNum ,
NewPassVisibleMeshDrawCommandsNum ,
GShaderPlatformForFeatureLevel [ FeatureLevel ] ,
InstanceFactor ,
WritePrimitiveDataFn ) ;
}
2019-01-17 11:09:36 -05:00
2020-12-10 11:51:32 -04:00
RHIUnlockBuffer ( OutPrimitiveIdVertexBuffer ) ;
2020-02-12 15:27:05 -05:00
GPrimitiveIdVertexBufferPool . ReturnToFreeList ( Entry ) ;
2019-01-15 10:24:32 -05:00
}
}
}
2021-01-14 23:37:17 -04:00
2019-01-15 10:24:32 -05:00
void FParallelMeshDrawCommandPass : : DispatchPassSetup (
FScene * Scene ,
const FViewInfo & View ,
2021-02-04 10:44:19 -04:00
FInstanceCullingContext & & InstanceCullingContext ,
2019-01-15 10:24:32 -05:00
EMeshPass : : Type PassType ,
FExclusiveDepthStencil : : Type BasePassDepthStencilAccess ,
FMeshPassProcessor * MeshPassProcessor ,
const TArray < FMeshBatchAndRelevance , SceneRenderingAllocator > & DynamicMeshElements ,
2019-01-28 17:06:11 -05:00
const TArray < FMeshPassMask , SceneRenderingAllocator > * DynamicMeshElementsPassRelevance ,
2019-01-15 10:24:32 -05:00
int32 NumDynamicMeshElements ,
2019-01-16 15:48:19 -05:00
TArray < const FStaticMeshBatch * , SceneRenderingAllocator > & InOutDynamicMeshCommandBuildRequests ,
2019-01-15 10:24:32 -05:00
int32 NumDynamicMeshCommandBuildRequestElements ,
FMeshCommandOneFrameArray & InOutMeshDrawCommands ,
FMeshPassProcessor * MobileBasePassCSMMeshPassProcessor ,
FMeshCommandOneFrameArray * InOutMobileBasePassCSMMeshDrawCommands
)
{
2020-02-06 13:13:41 -05:00
TRACE_CPUPROFILER_EVENT_SCOPE ( ParallelMdcDispatchPassSetup ) ;
2019-01-23 16:20:07 -05:00
check ( ! TaskEventRef . IsValid ( ) & & MeshPassProcessor ! = nullptr & & TaskContext . PrimitiveIdBufferData = = nullptr ) ;
2019-01-28 17:06:11 -05:00
check ( ( PassType = = EMeshPass : : Num ) = = ( DynamicMeshElementsPassRelevance = = nullptr ) ) ;
2019-01-15 10:24:32 -05:00
MaxNumDraws = InOutMeshDrawCommands . Num ( ) + NumDynamicMeshElements + NumDynamicMeshCommandBuildRequestElements ;
TaskContext . MeshPassProcessor = MeshPassProcessor ;
TaskContext . MobileBasePassCSMMeshPassProcessor = MobileBasePassCSMMeshPassProcessor ;
TaskContext . DynamicMeshElements = & DynamicMeshElements ;
2019-01-28 17:06:11 -05:00
TaskContext . DynamicMeshElementsPassRelevance = DynamicMeshElementsPassRelevance ;
2019-01-15 10:24:32 -05:00
TaskContext . View = & View ;
2021-01-14 05:23:34 -04:00
TaskContext . Scene = Scene ;
2019-01-15 10:24:32 -05:00
TaskContext . ShadingPath = Scene - > GetShadingPath ( ) ;
2019-10-22 11:07:33 -04:00
TaskContext . ShaderPlatform = Scene - > GetShaderPlatform ( ) ;
2019-01-15 10:24:32 -05:00
TaskContext . PassType = PassType ;
TaskContext . bUseGPUScene = UseGPUScene ( GMaxRHIShaderPlatform , View . GetFeatureLevel ( ) ) ;
2019-01-29 11:23:59 -05:00
TaskContext . bDynamicInstancing = IsDynamicInstancingEnabled ( View . GetFeatureLevel ( ) ) ;
2019-01-15 10:24:32 -05:00
TaskContext . bReverseCulling = View . bReverseCulling ;
TaskContext . bRenderSceneTwoSided = View . bRenderSceneTwoSided ;
TaskContext . BasePassDepthStencilAccess = BasePassDepthStencilAccess ;
2019-03-12 10:09:45 -04:00
TaskContext . DefaultBasePassDepthStencilAccess = Scene - > DefaultBasePassDepthStencilAccess ;
2019-01-15 10:24:32 -05:00
TaskContext . NumDynamicMeshElements = NumDynamicMeshElements ;
TaskContext . NumDynamicMeshCommandBuildRequestElements = NumDynamicMeshCommandBuildRequestElements ;
2019-02-01 16:42:04 -05:00
// Only apply instancing for ISR to main view passes
2021-01-19 08:25:03 -04:00
2019-04-12 10:46:56 -04:00
const bool bIsMainViewPass = PassType ! = EMeshPass : : Num & & ( FPassProcessorManager : : GetPassFlags ( TaskContext . ShadingPath , TaskContext . PassType ) & EMeshPassFlags : : MainView ) ! = EMeshPassFlags : : None ;
2021-03-18 13:39:09 -04:00
// GPUCULL_TODO: Note the InstanceFactor is ignored by the GPU-Scene supported instances, but is used for legacy primitives.
2019-02-01 16:42:04 -05:00
TaskContext . InstanceFactor = ( bIsMainViewPass & & View . IsInstancedStereoPass ( ) ) ? 2 : 1 ;
2021-02-04 10:44:19 -04:00
TaskContext . InstanceCullingContext = MoveTemp ( InstanceCullingContext ) ;
2021-01-14 05:23:34 -04:00
2019-01-15 10:24:32 -05:00
// Setup translucency sort key update pass based on view.
TaskContext . TranslucencyPass = ETranslucencyPass : : TPT_MAX ;
TaskContext . TranslucentSortPolicy = View . TranslucentSortPolicy ;
TaskContext . TranslucentSortAxis = View . TranslucentSortAxis ;
TaskContext . ViewOrigin = View . ViewMatrices . GetViewOrigin ( ) ;
TaskContext . ViewMatrix = View . ViewMatrices . GetViewMatrix ( ) ;
TaskContext . PrimitiveBounds = & Scene - > PrimitiveBounds ;
switch ( PassType )
{
case EMeshPass : : TranslucencyStandard : TaskContext . TranslucencyPass = ETranslucencyPass : : TPT_StandardTranslucency ; break ;
case EMeshPass : : TranslucencyAfterDOF : TaskContext . TranslucencyPass = ETranslucencyPass : : TPT_TranslucencyAfterDOF ; break ;
2020-02-12 13:27:19 -05:00
case EMeshPass : : TranslucencyAfterDOFModulate : TaskContext . TranslucencyPass = ETranslucencyPass : : TPT_TranslucencyAfterDOFModulate ; break ;
2021-05-19 02:09:02 -04:00
case EMeshPass : : TranslucencyAfterMotionBlur : TaskContext . TranslucencyPass = ETranslucencyPass : : TPT_TranslucencyAfterMotionBlur ; break ;
2019-01-15 10:24:32 -05:00
case EMeshPass : : TranslucencyAll : TaskContext . TranslucencyPass = ETranslucencyPass : : TPT_AllTranslucency ; break ;
}
FMemory : : Memswap ( & TaskContext . MeshDrawCommands , & InOutMeshDrawCommands , sizeof ( InOutMeshDrawCommands ) ) ;
FMemory : : Memswap ( & TaskContext . DynamicMeshCommandBuildRequests , & InOutDynamicMeshCommandBuildRequests , sizeof ( InOutDynamicMeshCommandBuildRequests ) ) ;
if ( TaskContext . ShadingPath = = EShadingPath : : Mobile & & TaskContext . PassType = = EMeshPass : : BasePass )
{
FMemory : : Memswap ( & TaskContext . MobileBasePassCSMMeshDrawCommands , InOutMobileBasePassCSMMeshDrawCommands , sizeof ( * InOutMobileBasePassCSMMeshDrawCommands ) ) ;
}
else
{
check ( MobileBasePassCSMMeshPassProcessor = = nullptr & & InOutMobileBasePassCSMMeshDrawCommands = = nullptr ) ;
}
2019-02-14 14:23:27 -05:00
if ( MaxNumDraws > 0 )
2019-01-15 10:24:32 -05:00
{
2019-02-14 14:23:27 -05:00
// Preallocate resources on rendering thread based on MaxNumDraws.
TaskContext . PrimitiveIdBufferDataSize = TaskContext . InstanceFactor * MaxNumDraws * sizeof ( int32 ) ;
TaskContext . PrimitiveIdBufferData = FMemory : : Malloc ( TaskContext . PrimitiveIdBufferDataSize ) ;
2021-02-17 15:31:33 -04:00
# if DO_GUARD_SLOW
FMemory : : Memzero ( TaskContext . PrimitiveIdBufferData , TaskContext . PrimitiveIdBufferDataSize ) ;
# endif // DO_GUARD_SLOW
2020-02-12 15:27:05 -05:00
PrimitiveIdVertexBufferPoolEntry = GPrimitiveIdVertexBufferPool . Allocate ( TaskContext . PrimitiveIdBufferDataSize ) ;
2019-02-14 14:23:27 -05:00
TaskContext . MeshDrawCommands . Reserve ( MaxNumDraws ) ;
TaskContext . TempVisibleMeshDrawCommands . Reserve ( MaxNumDraws ) ;
const bool bExecuteInParallel = FApp : : ShouldUseThreadingForPerformance ( )
& & CVarMeshDrawCommandsParallelPassSetup . GetValueOnRenderThread ( ) > 0
2020-09-24 00:43:27 -04:00
& & GIsThreadedRendering ; // Rendering thread is required to safely use rendering resources in parallel.
2019-02-14 14:23:27 -05:00
if ( bExecuteInParallel )
{
2020-09-24 00:43:27 -04:00
if ( IsOnDemandShaderCreationEnabled ( ) )
2020-08-11 01:36:57 -04:00
{
TaskEventRef = TGraphTask < FMeshDrawCommandPassSetupTask > : : CreateTask ( nullptr , ENamedThreads : : GetRenderThread ( ) ) . ConstructAndDispatchWhenReady ( TaskContext ) ;
}
else
{
FGraphEventArray DependentGraphEvents ;
DependentGraphEvents . Add ( TGraphTask < FMeshDrawCommandPassSetupTask > : : CreateTask ( nullptr , ENamedThreads : : GetRenderThread ( ) ) . ConstructAndDispatchWhenReady ( TaskContext ) ) ;
TaskEventRef = TGraphTask < FMeshDrawCommandInitResourcesTask > : : CreateTask ( & DependentGraphEvents , ENamedThreads : : GetRenderThread ( ) ) . ConstructAndDispatchWhenReady ( TaskContext ) ;
}
2019-02-14 14:23:27 -05:00
}
else
{
2019-02-19 13:48:59 -05:00
QUICK_SCOPE_CYCLE_COUNTER ( STAT_MeshPassSetupImmediate ) ;
2019-02-14 14:23:27 -05:00
FMeshDrawCommandPassSetupTask Task ( TaskContext ) ;
Task . AnyThreadTask ( ) ;
2020-09-24 00:43:27 -04:00
if ( ! IsOnDemandShaderCreationEnabled ( ) )
2020-08-11 01:36:57 -04:00
{
FMeshDrawCommandInitResourcesTask DependentTask ( TaskContext ) ;
DependentTask . AnyThreadTask ( ) ;
}
2019-02-14 14:23:27 -05:00
}
2019-01-15 10:24:32 -05:00
}
}
2020-09-24 00:43:27 -04:00
bool FParallelMeshDrawCommandPass : : IsOnDemandShaderCreationEnabled ( )
{
2020-10-22 19:19:16 -04:00
// GL rhi does not support multithreaded shader creation, however the engine can be configured to not run mesh drawing tasks in threads other than the RT
// (see FRHICommandListExecutor::UseParallelAlgorithms()): if this condition is true, on demand shader creation can be enabled.
const bool bIsMobileRenderer = FSceneInterface : : GetShadingPath ( GMaxRHIFeatureLevel ) = = EShadingPath : : Mobile ;
2021-09-21 15:10:29 -04:00
return GAllowOnDemandShaderCreation & &
( GRHISupportsMultithreadedShaderCreation | | ( bIsMobileRenderer & & ( ! GSupportsParallelRenderingTasksWithSeparateRHIThread & & IsRunningRHIInSeparateThread ( ) ) ) ) ;
2020-09-24 00:43:27 -04:00
}
2021-05-21 11:30:17 -04:00
void FParallelMeshDrawCommandPass : : WaitForMeshPassSetupTask ( EWaitThread WaitThread ) const
2019-01-15 10:24:32 -05:00
{
2021-08-04 23:10:26 -04:00
if ( TaskEventRef . IsValid ( ) & & WaitThread ! = EWaitThread : : TaskAlreadyWaited )
2019-01-15 10:24:32 -05:00
{
// Need to wait on GetRenderThread_Local, as mesh pass setup task can wait on rendering thread inside InitResourceFromPossiblyParallelRendering().
2019-02-19 13:48:59 -05:00
QUICK_SCOPE_CYCLE_COUNTER ( STAT_WaitForMeshPassSetupTask ) ;
2021-05-21 11:30:17 -04:00
FTaskGraphInterface : : Get ( ) . WaitUntilTaskCompletes ( TaskEventRef , WaitThread = = EWaitThread : : Render ? ENamedThreads : : GetRenderThread_Local ( ) : ENamedThreads : : AnyThread ) ;
2019-01-15 10:24:32 -05:00
}
}
2021-05-21 11:30:17 -04:00
void FParallelMeshDrawCommandPass : : WaitForTasksAndEmpty ( EWaitThread WaitThread )
2019-01-15 10:24:32 -05:00
{
// Need to wait in case if someone dispatched sort and draw merge task, but didn't draw it.
2021-05-21 11:30:17 -04:00
WaitForMeshPassSetupTask ( WaitThread ) ;
2019-01-23 16:20:07 -05:00
TaskEventRef = nullptr ;
2019-01-15 10:24:32 -05:00
DumpInstancingStats ( ) ;
2019-02-14 14:23:27 -05:00
if ( TaskContext . MeshPassProcessor )
{
TaskContext . MeshPassProcessor - > ~ FMeshPassProcessor ( ) ;
TaskContext . MeshPassProcessor = nullptr ;
}
if ( TaskContext . MobileBasePassCSMMeshPassProcessor )
{
TaskContext . MobileBasePassCSMMeshPassProcessor - > ~ FMeshPassProcessor ( ) ;
TaskContext . MobileBasePassCSMMeshPassProcessor = nullptr ;
}
2020-02-12 15:27:05 -05:00
if ( MaxNumDraws > 0 )
{
2021-07-29 15:48:43 -04:00
GPrimitiveIdVertexBufferPool . ReturnToFreeList ( PrimitiveIdVertexBufferPoolEntry ) ;
2020-02-12 15:27:05 -05:00
}
2021-07-29 15:48:43 -04:00
FMemory : : Free ( TaskContext . PrimitiveIdBufferData ) ;
2019-01-15 10:24:32 -05:00
MaxNumDraws = 0 ;
2019-01-23 12:30:00 -05:00
PassNameForStats . Empty ( ) ;
2019-01-15 10:24:32 -05:00
TaskContext . DynamicMeshElements = nullptr ;
2019-01-28 17:06:11 -05:00
TaskContext . DynamicMeshElementsPassRelevance = nullptr ;
2019-01-15 10:24:32 -05:00
TaskContext . MeshDrawCommands . Empty ( ) ;
2019-02-26 16:17:52 -05:00
TaskContext . MeshDrawCommandStorage . MeshDrawCommands . Empty ( ) ;
2019-05-16 16:08:59 -04:00
FGraphicsMinimalPipelineStateId : : AddSizeToLocalPipelineIdTableSize ( TaskContext . MinimalPipelineStatePassSet . GetAllocatedSize ( ) ) ;
TaskContext . MinimalPipelineStatePassSet . Empty ( ) ;
2019-01-15 10:24:32 -05:00
TaskContext . MobileBasePassCSMMeshDrawCommands . Empty ( ) ;
TaskContext . DynamicMeshCommandBuildRequests . Empty ( ) ;
TaskContext . TempVisibleMeshDrawCommands . Empty ( ) ;
2019-01-17 11:09:36 -05:00
TaskContext . PrimitiveIdBufferData = nullptr ;
TaskContext . PrimitiveIdBufferDataSize = 0 ;
2019-01-15 10:24:32 -05:00
}
FParallelMeshDrawCommandPass : : ~ FParallelMeshDrawCommandPass ( )
{
2019-02-26 16:17:22 -05:00
check ( TaskEventRef = = nullptr ) ;
2019-01-15 10:24:32 -05:00
}
class FDrawVisibleMeshCommandsAnyThreadTask : public FRenderTask
{
FRHICommandList & RHICmdList ;
2021-08-03 09:31:28 -04:00
const FInstanceCullingContext & InstanceCullingContext ;
2019-01-15 10:24:32 -05:00
const FMeshCommandOneFrameArray & VisibleMeshDrawCommands ;
2019-05-16 16:08:59 -04:00
const FGraphicsMinimalPipelineStateSet & GraphicsMinimalPipelineStateSet ;
2021-08-03 09:31:28 -04:00
const FMeshDrawCommandOverrideArgs OverrideArgs ;
2021-03-18 13:39:09 -04:00
uint32 InstanceFactor ;
2019-01-15 10:24:32 -05:00
int32 TaskIndex ;
int32 TaskNum ;
public :
FDrawVisibleMeshCommandsAnyThreadTask (
FRHICommandList & InRHICmdList ,
2021-08-03 09:31:28 -04:00
const FInstanceCullingContext & InInstanceCullingContext ,
2019-01-15 10:24:32 -05:00
const FMeshCommandOneFrameArray & InVisibleMeshDrawCommands ,
2019-05-16 16:08:59 -04:00
const FGraphicsMinimalPipelineStateSet & InGraphicsMinimalPipelineStateSet ,
2021-08-03 09:31:28 -04:00
const FMeshDrawCommandOverrideArgs & InOverrideArgs ,
2021-03-18 13:39:09 -04:00
uint32 InInstanceFactor ,
2019-01-15 10:24:32 -05:00
int32 InTaskIndex ,
int32 InTaskNum
)
: RHICmdList ( InRHICmdList )
2021-08-03 09:31:28 -04:00
, InstanceCullingContext ( InInstanceCullingContext )
2019-01-15 10:24:32 -05:00
, VisibleMeshDrawCommands ( InVisibleMeshDrawCommands )
2019-05-16 16:08:59 -04:00
, GraphicsMinimalPipelineStateSet ( InGraphicsMinimalPipelineStateSet )
2021-08-03 09:31:28 -04:00
, OverrideArgs ( InOverrideArgs )
2021-03-18 13:39:09 -04:00
, InstanceFactor ( InInstanceFactor )
2019-01-15 10:24:32 -05:00
, TaskIndex ( InTaskIndex )
, TaskNum ( InTaskNum )
2021-08-03 09:31:28 -04:00
{
}
2019-01-15 10:24:32 -05:00
FORCEINLINE TStatId GetStatId ( ) const
{
RETURN_QUICK_DECLARE_CYCLE_STAT ( FDrawVisibleMeshCommandsAnyThreadTask , STATGROUP_TaskGraphTasks ) ;
}
static ESubsequentsMode : : Type GetSubsequentsMode ( ) { return ESubsequentsMode : : TrackSubsequents ; }
void DoTask ( ENamedThreads : : Type CurrentThread , const FGraphEventRef & MyCompletionGraphEvent )
{
2020-07-02 13:21:15 -04:00
FOptionalTaskTagScope Scope ( ETaskTag : : EParallelRenderingThread ) ;
2021-08-04 23:10:26 -04:00
SCOPED_NAMED_EVENT_TEXT ( " DrawVisibleMeshCommandsAnyThreadTask " , FColor : : Magenta ) ;
2019-01-15 10:24:32 -05:00
checkSlow ( RHICmdList . IsInsideRenderPass ( ) ) ;
2021-09-21 15:10:29 -04:00
// check for the multithreaded shader creation has been moved to FShaderCodeArchive::CreateShader()
2020-10-22 19:19:16 -04:00
2019-01-15 10:24:32 -05:00
// Recompute draw range.
const int32 DrawNum = VisibleMeshDrawCommands . Num ( ) ;
2020-01-24 18:07:01 -05:00
const int32 NumDrawsPerTask = TaskIndex < DrawNum ? FMath : : DivideAndRoundUp ( DrawNum , TaskNum ) : 0 ;
2019-01-15 10:24:32 -05:00
const int32 StartIndex = TaskIndex * NumDrawsPerTask ;
const int32 NumDraws = FMath : : Min ( NumDrawsPerTask , DrawNum - StartIndex ) ;
2021-08-03 09:31:28 -04:00
InstanceCullingContext . SubmitDrawCommands (
2021-01-19 08:25:03 -04:00
VisibleMeshDrawCommands ,
GraphicsMinimalPipelineStateSet ,
2021-08-03 09:31:28 -04:00
OverrideArgs ,
2021-01-19 08:25:03 -04:00
StartIndex ,
NumDraws ,
2021-03-18 13:39:09 -04:00
InstanceFactor ,
2021-01-19 08:25:03 -04:00
RHICmdList ) ;
2019-01-15 10:24:32 -05:00
RHICmdList . EndRenderPass ( ) ;
RHICmdList . HandleRTThreadTaskCompletion ( MyCompletionGraphEvent ) ;
}
} ;
2021-06-07 12:19:06 -04:00
void FParallelMeshDrawCommandPass : : BuildRenderingCommands (
FRDGBuilder & GraphBuilder ,
2021-07-22 13:51:03 -04:00
const FGPUScene & GPUScene ,
2021-06-07 12:19:06 -04:00
FInstanceCullingDrawParams & OutInstanceCullingDrawParams )
2021-01-14 15:46:32 -04:00
{
2021-02-04 10:44:19 -04:00
if ( TaskContext . InstanceCullingContext . IsEnabled ( ) )
2021-01-14 15:46:32 -04:00
{
2021-06-07 12:19:06 -04:00
check ( ! bHasInstanceCullingDrawParameters ) ;
2021-01-25 16:30:37 -04:00
WaitForMeshPassSetupTask ( ) ;
2021-12-06 13:18:17 -05:00
# if DO_CHECK
for ( const FVisibleMeshDrawCommand & VisibleMeshDrawCommand : TaskContext . MeshDrawCommands )
{
if ( VisibleMeshDrawCommand . PrimitiveIdInfo . bIsDynamicPrimitive )
{
uint32 PrimitiveIndex = VisibleMeshDrawCommand . PrimitiveIdInfo . DrawPrimitiveId & ~ GPrimIDDynamicFlag ;
checkf ( TaskContext . View - > DynamicPrimitiveCollector . IsPrimitiveProcessed ( PrimitiveIndex , GPUScene ) ,
TEXT ( " Dynamic Primitive index %u has not been fully processed. It may be an invalid index for the collector or it has a pending GPU write. " ) ,
PrimitiveIndex ) ;
}
}
# endif
2021-06-07 12:19:06 -04:00
// 2. Run or queue finalize culling commands pass
2021-06-21 16:52:03 -04:00
TaskContext . InstanceCullingContext . BuildRenderingCommands ( GraphBuilder , GPUScene , TaskContext . View - > DynamicPrimitiveCollector . GetInstanceSceneDataOffset ( ) , TaskContext . View - > DynamicPrimitiveCollector . NumInstances ( ) , TaskContext . InstanceCullingResult , & OutInstanceCullingDrawParams ) ;
2021-06-03 02:19:28 -04:00
TaskContext . InstanceCullingResult . GetDrawParameters ( OutInstanceCullingDrawParams ) ;
2021-06-07 12:19:06 -04:00
bHasInstanceCullingDrawParameters = true ;
check ( ! TaskContext . InstanceCullingContext . HasCullingCommands ( ) | | OutInstanceCullingDrawParams . DrawIndirectArgsBuffer & & OutInstanceCullingDrawParams . InstanceIdOffsetBuffer ) ;
2021-06-03 02:19:28 -04:00
return ;
2021-01-14 15:46:32 -04:00
}
2021-01-25 16:30:37 -04:00
OutInstanceCullingDrawParams . DrawIndirectArgsBuffer = nullptr ;
OutInstanceCullingDrawParams . InstanceIdOffsetBuffer = nullptr ;
2021-08-03 09:31:28 -04:00
OutInstanceCullingDrawParams . InstanceDataByteOffset = 0U ;
OutInstanceCullingDrawParams . IndirectArgsByteOffset = 0U ;
2021-05-14 04:16:02 -04:00
}
2021-06-21 16:52:03 -04:00
void FParallelMeshDrawCommandPass : : WaitForSetupTask ( )
2021-01-14 15:46:32 -04:00
{
2021-06-21 16:52:03 -04:00
WaitForMeshPassSetupTask ( ) ;
2021-01-14 15:46:32 -04:00
}
2021-01-14 05:23:34 -04:00
void FParallelMeshDrawCommandPass : : DispatchDraw ( FParallelCommandListSet * ParallelCommandListSet , FRHICommandList & RHICmdList , const FInstanceCullingDrawParams * InstanceCullingDrawParams ) const
2019-01-15 10:24:32 -05:00
{
2020-02-06 13:13:41 -05:00
TRACE_CPUPROFILER_EVENT_SCOPE ( ParallelMdcDispatchDraw ) ;
2019-01-15 10:24:32 -05:00
if ( MaxNumDraws < = 0 )
{
return ;
}
2021-08-03 09:31:28 -04:00
FMeshDrawCommandOverrideArgs OverrideArgs ;
if ( InstanceCullingDrawParams )
2021-01-19 08:25:03 -04:00
{
2021-08-03 09:31:28 -04:00
OverrideArgs = GetMeshDrawCommandOverrideArgs ( * InstanceCullingDrawParams ) ;
2021-01-19 08:25:03 -04:00
}
2021-01-25 16:30:37 -04:00
2019-01-15 10:24:32 -05:00
if ( ParallelCommandListSet )
{
const ENamedThreads : : Type RenderThread = ENamedThreads : : GetRenderThread ( ) ;
2019-01-23 16:20:07 -05:00
FGraphEventArray Prereqs ;
2019-01-15 10:24:32 -05:00
if ( ParallelCommandListSet - > GetPrereqs ( ) )
{
Prereqs . Append ( * ParallelCommandListSet - > GetPrereqs ( ) ) ;
}
2019-01-23 16:20:07 -05:00
if ( TaskEventRef . IsValid ( ) )
{
Prereqs . Add ( TaskEventRef ) ;
}
2019-01-15 10:24:32 -05:00
// Distribute work evenly to the available task graph workers based on NumEstimatedDraws.
// Every task will then adjust it's working range based on FVisibleMeshDrawCommandProcessTask results.
const int32 NumThreads = FMath : : Min < int32 > ( FTaskGraphInterface : : Get ( ) . GetNumWorkerThreads ( ) , ParallelCommandListSet - > Width ) ;
const int32 NumTasks = FMath : : Min < int32 > ( NumThreads , FMath : : DivideAndRoundUp ( MaxNumDraws , ParallelCommandListSet - > MinDrawsPerCommandList ) ) ;
const int32 NumDrawsPerTask = FMath : : DivideAndRoundUp ( MaxNumDraws , NumTasks ) ;
for ( int32 TaskIndex = 0 ; TaskIndex < NumTasks ; TaskIndex + + )
{
const int32 StartIndex = TaskIndex * NumDrawsPerTask ;
const int32 NumDraws = FMath : : Min ( NumDrawsPerTask , MaxNumDraws - StartIndex ) ;
checkSlow ( NumDraws > 0 ) ;
FRHICommandList * CmdList = ParallelCommandListSet - > NewParallelCommandList ( ) ;
FGraphEventRef AnyThreadCompletionEvent = TGraphTask < FDrawVisibleMeshCommandsAnyThreadTask > : : CreateTask ( & Prereqs , RenderThread )
2021-08-03 09:31:28 -04:00
. ConstructAndDispatchWhenReady ( * CmdList , TaskContext . InstanceCullingContext , TaskContext . MeshDrawCommands , TaskContext . MinimalPipelineStatePassSet ,
OverrideArgs ,
2021-03-18 13:39:09 -04:00
TaskContext . InstanceFactor ,
2021-01-19 08:25:03 -04:00
TaskIndex , NumTasks ) ;
2021-05-25 08:15:14 -04:00
2019-01-15 10:24:32 -05:00
ParallelCommandListSet - > AddParallelCommandList ( CmdList , AnyThreadCompletionEvent , NumDraws ) ;
}
}
else
{
2019-02-19 13:48:59 -05:00
QUICK_SCOPE_CYCLE_COUNTER ( STAT_MeshPassDrawImmediate ) ;
2021-07-15 20:00:42 -04:00
WaitForMeshPassSetupTask ( IsInActualRenderingThread ( ) ? EWaitThread : : Render : EWaitThread : : Task ) ;
2019-01-17 11:09:36 -05:00
2021-01-19 08:25:03 -04:00
if ( TaskContext . bUseGPUScene )
{
if ( TaskContext . MeshDrawCommands . Num ( ) > 0 )
{
2021-08-03 09:31:28 -04:00
TaskContext . InstanceCullingContext . SubmitDrawCommands (
2021-01-19 08:25:03 -04:00
TaskContext . MeshDrawCommands ,
TaskContext . MinimalPipelineStatePassSet ,
2021-08-03 09:31:28 -04:00
OverrideArgs ,
2021-01-19 08:25:03 -04:00
0 ,
TaskContext . MeshDrawCommands . Num ( ) ,
2021-03-18 13:39:09 -04:00
TaskContext . InstanceFactor ,
2021-01-19 08:25:03 -04:00
RHICmdList ) ;
}
}
else
{
2021-08-07 07:20:52 -04:00
SubmitMeshDrawCommandsRange ( TaskContext . MeshDrawCommands , TaskContext . MinimalPipelineStatePassSet , nullptr , 0 , 0 , TaskContext . bDynamicInstancing , 0 , TaskContext . MeshDrawCommands . Num ( ) , TaskContext . InstanceFactor , RHICmdList ) ;
2021-01-19 08:25:03 -04:00
}
2019-01-15 10:24:32 -05:00
}
}
2021-01-14 23:37:17 -04:00
2019-01-15 10:24:32 -05:00
void FParallelMeshDrawCommandPass : : DumpInstancingStats ( ) const
{
2019-01-21 09:13:36 -05:00
if ( ! PassNameForStats . IsEmpty ( ) & & TaskContext . VisibleMeshDrawCommandsNum > 0 )
2019-01-15 10:24:32 -05:00
{
UE_LOG ( LogRenderer , Log , TEXT ( " Instancing stats for %s " ) , * PassNameForStats ) ;
UE_LOG ( LogRenderer , Log , TEXT ( " %i Mesh Draw Commands in %i instancing state buckets " ) , TaskContext . VisibleMeshDrawCommandsNum , TaskContext . NewPassVisibleMeshDrawCommandsNum ) ;
UE_LOG ( LogRenderer , Log , TEXT ( " Largest %i " ) , TaskContext . MaxInstances ) ;
UE_LOG ( LogRenderer , Log , TEXT ( " %.1f Dynamic Instancing draw call reduction factor " ) , TaskContext . VisibleMeshDrawCommandsNum / ( float ) TaskContext . NewPassVisibleMeshDrawCommandsNum ) ;
}
}
void FParallelMeshDrawCommandPass : : SetDumpInstancingStats ( const FString & InPassNameForStats )
{
PassNameForStats = InPassNameForStats ;
2021-01-14 23:37:17 -04:00
}