Files
UnrealEngineUWP/Engine/Source/Runtime/Renderer/Private/MeshPassProcessor.cpp

2396 lines
94 KiB
C++
Raw Normal View History

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
MeshPassProcessor.cpp:
=============================================================================*/
#include "MeshPassProcessor.h"
#include "SceneUtils.h"
#include "SceneRendering.h"
#include "Logging/LogMacros.h"
#include "RendererModule.h"
#include "SceneCore.h"
#include "ScenePrivate.h"
#include "SceneInterface.h"
#include "MeshPassProcessor.inl"
#include "PipelineStateCache.h"
#include "RayTracing/RayTracingMaterialHitShaders.h"
#include "Hash/CityHash.h"
#include "ComponentRecreateRenderStateContext.h"
FRWLock FGraphicsMinimalPipelineStateId::PersistentIdTableLock;
FGraphicsMinimalPipelineStateId::PersistentTableType FGraphicsMinimalPipelineStateId::PersistentIdTable;
#if MESH_DRAW_COMMAND_DEBUG_DATA
std::atomic<int32> FGraphicsMinimalPipelineStateId::LocalPipelineIdTableSize(0);
std::atomic<int32> FGraphicsMinimalPipelineStateId::CurrentLocalPipelineIdTableSize(0);
#endif //MESH_DRAW_COMMAND_DEBUG_DATA
bool FGraphicsMinimalPipelineStateId::NeedsShaderInitialisation = true;
const FMeshDrawCommandSortKey FMeshDrawCommandSortKey::Default = { {0} };
int32 GEmitMeshDrawEvent = 0;
static FAutoConsoleVariableRef CVarEmitMeshDrawEvent(
TEXT("r.EmitMeshDrawEvents"),
GEmitMeshDrawEvent,
TEXT("Emits a GPU event around each drawing policy draw call. /n")
TEXT("Useful for seeing stats about each draw call, however it greatly distorts total time and time per draw call."),
ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarSafeStateLookup(
TEXT("r.SafeStateLookup"),
1,
TEXT("Forces new-style safe state lookup for easy runtime perf comparison\n"),
ECVF_Scalability | ECVF_RenderThreadSafe);
PSO Precache Base Changes (disabled by default) Add PSOPrecache file which wraps engine level PSO structs and functions - FPSOPrecacheParams used to wrap certain parameters which drive the PSO collection (mostly set from components) - IPSOCollector interface used as engine entry to the mesh pass processors in renderer project - FPSOCollectorCreateManager to wrap all statically registered IPSOCollector CreateFuncions - PSOCollectorStats structs and helper functions Add PSOPrecache support to PipelineStateCache: - functions to precache compute and graphics PSOs - functions to check current precache state - FPrecacheGraphicsPipelineCache which wraps all currently precached PSOs IMaterial entry function to PrecachePSOs with given vertex factories and params (implemented by UMaterial & UMaterialInstance) which forwards call to FMaterial and finally the FMaterialShaderMap - FMaterialShaderMap will iterate all registered IPSOCollector to collect all possible PSOs used and forward them to the PipelineStateCache for actual (async) precaching RHI Changes: - Add RHI specific functions to retrieve & compare the FRHIVertexDeclaration and FGraphicsPipelineStateInitializer hash for each RHI - Add helper functions to match RHI*State data by retrieving initializer Minimal vertex factory changes for PSO precaching as prep - actual changes in upcoming CLs MeshPassProcessor base functions to collect PSOs which can be used by all mesh pass processor implemention (actual changes in upcoming CLs) - Cache complete precache data hash of stored minimal PSO so it can be used for fast actual PSO initializer hash computation (full PSO initializer is build at runtime) - Cache if minimal PSO was successfully precache and option to skip draw when PSO is still precaching (disabled by default and doesn't work yet via GPU scene based rendering) - Add helper functions to setup the per mesh pass render target data used during PSO collection Refactor SceneTextureConfig so it can be initialized from an init struct and move all function to setup the internal members from SceneTexture to SceneTextureConfig using the data from the init struct (so it's available in Engine project) Fix GBufferInfo format for velocity target (was always floating point while it should be unorm when not android Make certain helper functions definitions to h file so they can be used everywhere (SupportsNaniteRendering, FTextureRenderTarget2DResource::GetFormat & CreateFlags) #preflight 63189a5a967ffc68fb9044a5 #jira UE-139584 #rb Mihnea.Balta [CL 21907508 by kenzo terelst in ue5-main branch]
2022-09-08 19:34:08 -04:00
int32 GSkipDrawOnPSOPrecaching = 0;
static FAutoConsoleVariableRef CVarSkipDrawOnPSOPrecaching(
TEXT("r.SkipDrawOnPSOPrecaching"),
GSkipDrawOnPSOPrecaching,
TEXT("Skips mesh draw call when the PSO is still compiling (default 0)."),
ECVF_RenderThreadSafe
);
#if WITH_EDITORONLY_DATA
int32 GNaniteIsolateInvalidCoarseMesh = 0;
static FAutoConsoleVariableRef CVarNaniteIsolateInvalidCoarseMesh(
TEXT("r.Nanite.IsolateInvalidCoarseMesh"),
GNaniteIsolateInvalidCoarseMesh,
TEXT("Debug mode to render only non-Nanite proxies that incorrectly reference coarse static mesh assets."),
FConsoleVariableDelegate::CreateLambda([](IConsoleVariable* InVariable)
{
// Needed to force a recache of all the static mesh draw commands
FGlobalComponentRecreateRenderStateContext Context;
})
);
#endif
class FReadOnlyMeshDrawSingleShaderBindings : public FMeshDrawShaderBindingsLayout
{
public:
FReadOnlyMeshDrawSingleShaderBindings(const FMeshDrawShaderBindingsLayout& InLayout, const uint8* InData) :
FMeshDrawShaderBindingsLayout(InLayout)
{
Data = InData;
}
inline FRHIUniformBuffer*const* GetUniformBufferStart() const
{
return (FRHIUniformBuffer**)(Data + GetUniformBufferOffset());
}
inline FRHISamplerState** GetSamplerStart() const
{
const uint8* SamplerDataStart = Data + GetSamplerOffset();
return (FRHISamplerState**)SamplerDataStart;
}
inline FRHIResource** GetSRVStart() const
{
const uint8* SRVDataStart = Data + GetSRVOffset();
return (FRHIResource**)SRVDataStart;
}
inline const uint8* GetSRVTypeStart() const
{
const uint8* SRVTypeDataStart = Data + GetSRVTypeOffset();
return SRVTypeDataStart;
}
inline const uint8* GetLooseDataStart() const
{
const uint8* LooseDataStart = Data + GetLooseDataOffset();
return LooseDataStart;
}
private:
const uint8* Data;
};
struct FAllShaderParameters
{
TArray<uint8> ParametersData;
TArray<FRHIShaderParameter> Parameters;
TArray<FRHIShaderParameterResource> ResourceParameters;
TArray<FRHIShaderParameterResource> BindlessParameters;
};
inline void SetTextureParameter(FAllShaderParameters& AllParameters, const FShaderResourceParameterInfo& Parameter, FRHITexture* TextureRHI)
{
#if PLATFORM_SUPPORTS_BINDLESS_RENDERING
if (Parameter.Type == EShaderParameterType::BindlessResourceIndex)
{
check(Parameter.BufferIndex == 0);
AllParameters.BindlessParameters.Emplace(TextureRHI, Parameter.BaseIndex);
}
else
#endif
{
AllParameters.ResourceParameters.Emplace(TextureRHI, Parameter.BaseIndex);
}
}
inline void SetSrvParameter(FAllShaderParameters& AllParameters, const FShaderResourceParameterInfo& Parameter, FRHIShaderResourceView* SrvRHI)
{
#if PLATFORM_SUPPORTS_BINDLESS_RENDERING
if (Parameter.Type == EShaderParameterType::BindlessResourceIndex)
{
check(Parameter.BufferIndex == 0);
AllParameters.BindlessParameters.Emplace(SrvRHI, Parameter.BaseIndex);
}
else
#endif
{
AllParameters.ResourceParameters.Emplace(SrvRHI, Parameter.BaseIndex);
}
}
inline void SetSamplerParameter(FAllShaderParameters& AllParameters, const FShaderResourceParameterInfo& Parameter, FRHISamplerState* SamplerStateRHI)
{
#if PLATFORM_SUPPORTS_BINDLESS_RENDERING
if (Parameter.Type == EShaderParameterType::BindlessSamplerIndex)
{
AllParameters.BindlessParameters.Emplace(SamplerStateRHI, Parameter.BaseIndex);
}
else
#endif
{
AllParameters.ResourceParameters.Emplace(SamplerStateRHI, Parameter.BaseIndex);
}
}
inline void SetLooseParameters(FAllShaderParameters& AllParameters, const FShaderParameterMapInfo& ParameterMapInfo, const uint8* LooseDataStart)
{
for (const FShaderLooseParameterBufferInfo& LooseParameterBuffer : ParameterMapInfo.LooseParameterBuffers)
{
for (const FShaderLooseParameterInfo& Parameter : LooseParameterBuffer.Parameters)
{
const int32 DataOffset = AllParameters.ParametersData.Num();
AllParameters.ParametersData.Append((const uint8*)LooseDataStart, Parameter.Size);
AllParameters.Parameters.Emplace(LooseParameterBuffer.BaseIndex, Parameter.BaseIndex, DataOffset, Parameter.Size);
LooseDataStart += Parameter.Size;
}
}
}
template<class RHICmdListType, class RHIShaderType>
void FMeshDrawShaderBindings::SetShaderBindings(
RHICmdListType& RHICmdList,
RHIShaderType Shader,
const FReadOnlyMeshDrawSingleShaderBindings& RESTRICT SingleShaderBindings,
FShaderBindingState& RESTRICT ShaderBindingState)
{
FRHIUniformBuffer* const* RESTRICT UniformBufferBindings = SingleShaderBindings.GetUniformBufferStart();
const FShaderUniformBufferParameterInfo* RESTRICT UniformBufferParameters = SingleShaderBindings.ParameterMapInfo.UniformBuffers.GetData();
const int32 NumUniformBuffers = SingleShaderBindings.ParameterMapInfo.UniformBuffers.Num();
FAllShaderParameters AllParameters;
for (int32 UniformBufferIndex = 0; UniformBufferIndex < NumUniformBuffers; UniformBufferIndex++)
{
FShaderUniformBufferParameterInfo Parameter = UniformBufferParameters[UniformBufferIndex];
checkSlow(Parameter.BaseIndex < UE_ARRAY_COUNT(ShaderBindingState.UniformBuffers));
FRHIUniformBuffer* UniformBuffer = UniformBufferBindings[UniformBufferIndex];
if (UniformBuffer != ShaderBindingState.UniformBuffers[Parameter.BaseIndex])
{
RHICmdList.SetShaderUniformBuffer(Shader, Parameter.BaseIndex, UniformBuffer);
ShaderBindingState.UniformBuffers[Parameter.BaseIndex] = UniformBuffer;
ShaderBindingState.MaxUniformBufferUsed = FMath::Max((int32)Parameter.BaseIndex, ShaderBindingState.MaxUniformBufferUsed);
}
}
FRHISamplerState* const* RESTRICT SamplerBindings = SingleShaderBindings.GetSamplerStart();
const FShaderResourceParameterInfo* RESTRICT TextureSamplerParameters = SingleShaderBindings.ParameterMapInfo.TextureSamplers.GetData();
const int32 NumTextureSamplers = SingleShaderBindings.ParameterMapInfo.TextureSamplers.Num();
for (int32 SamplerIndex = 0; SamplerIndex < NumTextureSamplers; SamplerIndex++)
{
FShaderResourceParameterInfo Parameter = TextureSamplerParameters[SamplerIndex];
FRHISamplerState* Sampler = (FRHISamplerState*)SamplerBindings[SamplerIndex];
SetSamplerParameter(AllParameters, Parameter, Sampler);
}
const uint8* RESTRICT SRVType = SingleShaderBindings.GetSRVTypeStart();
FRHIResource* const* RESTRICT SRVBindings = SingleShaderBindings.GetSRVStart();
const FShaderResourceParameterInfo* RESTRICT SRVParameters = SingleShaderBindings.ParameterMapInfo.SRVs.GetData();
const uint32 NumSRVs = SingleShaderBindings.ParameterMapInfo.SRVs.Num();
for (uint32 SRVIndex = 0; SRVIndex < NumSRVs; SRVIndex++)
{
FShaderResourceParameterInfo Parameter = SRVParameters[SRVIndex];
uint32 TypeByteIndex = SRVIndex / 8;
uint32 TypeBitIndex = SRVIndex % 8;
if (SRVType[TypeByteIndex] & (1 << TypeBitIndex))
{
FRHIShaderResourceView* SRV = (FRHIShaderResourceView*)SRVBindings[SRVIndex];
SetSrvParameter(AllParameters, Parameter, SRV);
}
else
{
FRHITexture* Texture = (FRHITexture*)SRVBindings[SRVIndex];
SetTextureParameter(AllParameters, Parameter, Texture);
}
}
SetLooseParameters(AllParameters, SingleShaderBindings.ParameterMapInfo, SingleShaderBindings.GetLooseDataStart());
RHICmdList.SetShaderParameters(
Shader
, AllParameters.ParametersData
, AllParameters.Parameters
, AllParameters.ResourceParameters
, AllParameters.BindlessParameters
);
}
template<class RHICmdListType, class RHIShaderType>
void FMeshDrawShaderBindings::SetShaderBindings(
RHICmdListType& RHICmdList,
RHIShaderType Shader,
const FReadOnlyMeshDrawSingleShaderBindings& RESTRICT SingleShaderBindings)
{
FRHIUniformBuffer* const* RESTRICT UniformBufferBindings = SingleShaderBindings.GetUniformBufferStart();
const FShaderUniformBufferParameterInfo* RESTRICT UniformBufferParameters = SingleShaderBindings.ParameterMapInfo.UniformBuffers.GetData();
const int32 NumUniformBuffers = SingleShaderBindings.ParameterMapInfo.UniformBuffers.Num();
FAllShaderParameters AllParameters;
for (int32 UniformBufferIndex = 0; UniformBufferIndex < NumUniformBuffers; UniformBufferIndex++)
{
FShaderUniformBufferParameterInfo Parameter = UniformBufferParameters[UniformBufferIndex];
FRHIUniformBuffer* UniformBuffer = UniformBufferBindings[UniformBufferIndex];
if (UniformBuffer)
{
RHICmdList.SetShaderUniformBuffer(Shader, Parameter.BaseIndex, UniformBuffer);
}
}
FRHISamplerState* const* RESTRICT SamplerBindings = SingleShaderBindings.GetSamplerStart();
const FShaderResourceParameterInfo* RESTRICT TextureSamplerParameters = SingleShaderBindings.ParameterMapInfo.TextureSamplers.GetData();
const int32 NumTextureSamplers = SingleShaderBindings.ParameterMapInfo.TextureSamplers.Num();
for (int32 SamplerIndex = 0; SamplerIndex < NumTextureSamplers; SamplerIndex++)
{
FShaderResourceParameterInfo Parameter = TextureSamplerParameters[SamplerIndex];
FRHISamplerState* Sampler = (FRHISamplerState*)SamplerBindings[SamplerIndex];
if (Sampler)
{
SetSamplerParameter(AllParameters, Parameter, Sampler);
}
}
const uint8* RESTRICT SRVType = SingleShaderBindings.GetSRVTypeStart();
FRHIResource* const* RESTRICT SRVBindings = SingleShaderBindings.GetSRVStart();
const FShaderResourceParameterInfo* RESTRICT SRVParameters = SingleShaderBindings.ParameterMapInfo.SRVs.GetData();
const uint32 NumSRVs = SingleShaderBindings.ParameterMapInfo.SRVs.Num();
for (uint32 SRVIndex = 0; SRVIndex < NumSRVs; SRVIndex++)
{
FShaderResourceParameterInfo Parameter = SRVParameters[SRVIndex];
uint32 TypeByteIndex = SRVIndex / 8;
uint32 TypeBitIndex = SRVIndex % 8;
if (SRVType[TypeByteIndex] & (1 << TypeBitIndex))
{
FRHIShaderResourceView* SRV = (FRHIShaderResourceView*)SRVBindings[SRVIndex];
SetSrvParameter(AllParameters, Parameter, SRV);
}
else
{
FRHITexture* Texture = (FRHITexture*)SRVBindings[SRVIndex];
SetTextureParameter(AllParameters, Parameter, Texture);
}
}
SetLooseParameters(AllParameters, SingleShaderBindings.ParameterMapInfo, SingleShaderBindings.GetLooseDataStart());
RHICmdList.SetShaderParameters(
Shader
, AllParameters.ParametersData
, AllParameters.Parameters
, AllParameters.ResourceParameters
, AllParameters.BindlessParameters
);
}
#if RHI_RAYTRACING
FRayTracingLocalShaderBindings* FMeshDrawShaderBindings::SetRayTracingShaderBindingsForHitGroup(
FRayTracingLocalShaderBindingWriter* BindingWriter,
uint32 InstanceIndex,
uint32 SegmentIndex,
uint32 HitGroupIndexInPipeline,
uint32 ShaderSlot) const
{
check(ShaderLayouts.Num() == 1);
FReadOnlyMeshDrawSingleShaderBindings SingleShaderBindings(ShaderLayouts[0], GetData());
FRHIUniformBuffer* const* RESTRICT UniformBufferBindings = SingleShaderBindings.GetUniformBufferStart();
const FShaderUniformBufferParameterInfo* RESTRICT UniformBufferParameters = SingleShaderBindings.ParameterMapInfo.UniformBuffers.GetData();
const int32 NumUniformBufferParameters = SingleShaderBindings.ParameterMapInfo.UniformBuffers.Num();
checkf(SingleShaderBindings.ParameterMapInfo.TextureSamplers.Num() == 0, TEXT("Texture sampler parameters are not supported for ray tracing. UniformBuffers must be used for all resource binding."));
checkf(SingleShaderBindings.ParameterMapInfo.SRVs.Num() == 0, TEXT("SRV parameters are not supported for ray tracing. UniformBuffers must be used for all resource binding."));
// Measure parameter memory requirements
int32 MaxUniformBufferIndex = -1;
for (int32 UniformBufferIndex = 0; UniformBufferIndex < NumUniformBufferParameters; UniformBufferIndex++)
{
FShaderUniformBufferParameterInfo Parameter = UniformBufferParameters[UniformBufferIndex];
const FRHIUniformBuffer* UniformBuffer = UniformBufferBindings[UniformBufferIndex];
MaxUniformBufferIndex = FMath::Max((int32)Parameter.BaseIndex, MaxUniformBufferIndex);
}
const uint32 NumUniformBuffersToSet = MaxUniformBufferIndex + 1;
const TMemoryImageArray<FShaderLooseParameterBufferInfo>& LooseParameterBuffers = SingleShaderBindings.ParameterMapInfo.LooseParameterBuffers;
uint32 LooseParameterDataSize = 0;
if (LooseParameterBuffers.Num())
{
check(LooseParameterBuffers.Num() <= 1);
const FShaderLooseParameterBufferInfo& LooseParameterBuffer = SingleShaderBindings.ParameterMapInfo.LooseParameterBuffers[0];
check(LooseParameterBuffer.BaseIndex == 0);
for (int32 LooseParameterIndex = 0; LooseParameterIndex < LooseParameterBuffer.Parameters.Num(); LooseParameterIndex++)
{
FShaderLooseParameterInfo LooseParameter = LooseParameterBuffer.Parameters[LooseParameterIndex];
LooseParameterDataSize = FMath::Max<uint32>(LooseParameterDataSize, LooseParameter.BaseIndex + LooseParameter.Size);
}
}
checkf(MaxUniformBufferIndex + 1 == NumUniformBufferParameters + LooseParameterBuffers.Num(),
TEXT("Highest index of a uniform buffer was %d, but there were %d uniform buffer parameters and %d loose parameters"),
MaxUniformBufferIndex,
NumUniformBufferParameters,
LooseParameterBuffers.Num());
// Allocate and fill bindings
const uint32 UserData = 0; // UserData could be used to store material ID or any other kind of per-material constant. This can be retrieved in hit shaders via GetHitGroupUserData().
FRayTracingLocalShaderBindings& Bindings = BindingWriter->AddWithInlineParameters(NumUniformBuffersToSet, LooseParameterDataSize);
Bindings.InstanceIndex = InstanceIndex;
Bindings.SegmentIndex = SegmentIndex;
Bindings.ShaderSlot = ShaderSlot;
Bindings.ShaderIndexInPipeline = HitGroupIndexInPipeline;
Bindings.UserData = UserData;
for (int32 UniformBufferIndex = 0; UniformBufferIndex < NumUniformBufferParameters; UniformBufferIndex++)
{
FShaderUniformBufferParameterInfo Parameter = UniformBufferParameters[UniformBufferIndex];
const FRHIUniformBuffer* UniformBuffer = UniformBufferBindings[UniformBufferIndex];
Bindings.UniformBuffers[Parameter.BaseIndex] = const_cast<FRHIUniformBuffer*>(UniformBuffer);
}
if (LooseParameterBuffers.Num())
{
const FShaderLooseParameterBufferInfo& LooseParameterBuffer = SingleShaderBindings.ParameterMapInfo.LooseParameterBuffers[0];
const uint8* LooseDataOffset = SingleShaderBindings.GetLooseDataStart();
for (int32 LooseParameterIndex = 0; LooseParameterIndex < LooseParameterBuffer.Parameters.Num(); LooseParameterIndex++)
{
FShaderLooseParameterInfo LooseParameter = LooseParameterBuffer.Parameters[LooseParameterIndex];
FMemory::Memcpy(Bindings.LooseParameterData + LooseParameter.BaseIndex, LooseDataOffset, LooseParameter.Size);
LooseDataOffset += LooseParameter.Size;
}
}
return &Bindings;
}
FRayTracingLocalShaderBindings* FMeshDrawShaderBindings::SetRayTracingShaderBindings(FRayTracingLocalShaderBindingWriter* BindingWriter, uint32 ShaderIndexInPipeline, uint32 ShaderSlot) const
{
check(ShaderLayouts.Num() == 1);
return SetRayTracingShaderBindingsForHitGroup(BindingWriter, 0, 0, ShaderIndexInPipeline, ShaderSlot);
}
void FMeshDrawShaderBindings::SetRayTracingShaderBindingsForMissShader(
FRHICommandList& RHICmdList,
FRHIRayTracingScene* Scene,
FRayTracingPipelineState* PipelineState,
uint32 ShaderIndexInPipeline,
uint32 ShaderSlot) const
{
check(ShaderLayouts.Num() == 1);
FReadOnlyMeshDrawSingleShaderBindings SingleShaderBindings(ShaderLayouts[0], GetData());
FShaderBindingState BindingState;
const int32 MaxUniformBuffers = UE_ARRAY_COUNT(BindingState.UniformBuffers);
FRHIUniformBuffer* const* RESTRICT UniformBufferBindings = SingleShaderBindings.GetUniformBufferStart();
const FShaderUniformBufferParameterInfo* RESTRICT UniformBufferParameters = SingleShaderBindings.ParameterMapInfo.UniformBuffers.GetData();
const int32 NumUniformBufferParameters = SingleShaderBindings.ParameterMapInfo.UniformBuffers.Num();
checkf(SingleShaderBindings.ParameterMapInfo.TextureSamplers.Num() == 0, TEXT("Texture sampler parameters are not supported for ray tracing. UniformBuffers must be used for all resource binding."));
checkf(SingleShaderBindings.ParameterMapInfo.SRVs.Num() == 0, TEXT("SRV parameters are not supported for ray tracing. UniformBuffers must be used for all resource binding."));
// Measure parameter memory requirements
int32 MaxUniformBufferUsed = -1;
for (int32 UniformBufferIndex = 0; UniformBufferIndex < NumUniformBufferParameters; UniformBufferIndex++)
{
FShaderUniformBufferParameterInfo Parameter = UniformBufferParameters[UniformBufferIndex];
checkSlow(Parameter.BaseIndex < MaxUniformBuffers);
FRHIUniformBuffer* UniformBuffer = UniformBufferBindings[UniformBufferIndex];
if (Parameter.BaseIndex < MaxUniformBuffers)
{
BindingState.UniformBuffers[Parameter.BaseIndex] = UniformBuffer;
MaxUniformBufferUsed = FMath::Max((int32)Parameter.BaseIndex, MaxUniformBufferUsed);
}
}
checkf(SingleShaderBindings.ParameterMapInfo.TextureSamplers.Num() == 0, TEXT("Texture sampler parameters are not supported for ray tracing. UniformBuffers must be used for all resource binding."));
checkf(SingleShaderBindings.ParameterMapInfo.SRVs.Num() == 0, TEXT("SRV parameters are not supported for ray tracing. UniformBuffers must be used for all resource binding."));
checkf(SingleShaderBindings.ParameterMapInfo.LooseParameterBuffers.Num() == 0, TEXT("Ray tracing miss shaders may not have loose parameters"));
uint32 NumUniformBuffersToSet = MaxUniformBufferUsed + 1;
const uint32 UserData = 0; // UserData could be used to store material ID or any other kind of per-material constant. This can be retrieved in hit shaders via GetHitGroupUserData().
RHICmdList.SetRayTracingMissShader(Scene, ShaderSlot, PipelineState, ShaderIndexInPipeline,
NumUniformBuffersToSet, BindingState.UniformBuffers,
UserData);
}
#endif // RHI_RAYTRACING
FGraphicsMinimalPipelineStateId FGraphicsMinimalPipelineStateId::GetPersistentId(const FGraphicsMinimalPipelineStateInitializer& InPipelineState)
{
Experimental::FHashElementId TableId;
auto hash = PersistentIdTable.ComputeHash(InPipelineState);
{
FRWScopeLock Lock(PersistentIdTableLock, SLT_ReadOnly);
#if UE_BUILD_DEBUG
FGraphicsMinimalPipelineStateInitializer PipelineStateDebug = FGraphicsMinimalPipelineStateInitializer(InPipelineState);
check(GetTypeHash(PipelineStateDebug) == GetTypeHash(InPipelineState));
check(PipelineStateDebug == InPipelineState);
#endif
TableId = PersistentIdTable.FindIdByHash(hash, InPipelineState);
if (!TableId.IsValid())
{
Lock.ReleaseReadOnlyLockAndAcquireWriteLock_USE_WITH_CAUTION();
TableId = PersistentIdTable.FindOrAddIdByHash(hash, InPipelineState, FRefCountedGraphicsMinimalPipelineState());
}
FRefCountedGraphicsMinimalPipelineState& Value = PersistentIdTable.GetByElementId(TableId).Value;
if (Value.RefNum == 0 && !NeedsShaderInitialisation)
{
NeedsShaderInitialisation = true;
}
Value.RefNum++;
}
checkf(TableId.GetIndex() < (MAX_uint32 >> 2), TEXT("Persistent FGraphicsMinimalPipelineStateId table overflow!"));
FGraphicsMinimalPipelineStateId Ret;
Ret.bValid = 1;
Ret.bComesFromLocalPipelineStateSet = 0;
Ret.SetElementIndex = TableId.GetIndex();
return Ret;
}
void FGraphicsMinimalPipelineStateId::InitializePersistentIds()
{
TRACE_CPUPROFILER_EVENT_SCOPE(InitializePersistentMdcIds);
FRWScopeLock WriteLock(PersistentIdTableLock, SLT_Write);
if (NeedsShaderInitialisation)
{
for (TPair<const FGraphicsMinimalPipelineStateInitializer, FRefCountedGraphicsMinimalPipelineState>& Element : PersistentIdTable)
{
Element.Key.BoundShaderState.LazilyInitShaders();
}
NeedsShaderInitialisation = false;
}
}
void FGraphicsMinimalPipelineStateId::RemovePersistentId(FGraphicsMinimalPipelineStateId Id)
{
check(!Id.bComesFromLocalPipelineStateSet && Id.bValid);
{
FRWScopeLock WriteLock(PersistentIdTableLock, SLT_Write);
FRefCountedGraphicsMinimalPipelineState& RefCountedStateInitializer = PersistentIdTable.GetByElementId(Id.SetElementIndex).Value;
check(RefCountedStateInitializer.RefNum > 0);
--RefCountedStateInitializer.RefNum;
if (RefCountedStateInitializer.RefNum == 0)
{
PersistentIdTable.RemoveByElementId(Id.SetElementIndex);
}
}
}
FGraphicsMinimalPipelineStateId FGraphicsMinimalPipelineStateId::GetPipelineStateId(const FGraphicsMinimalPipelineStateInitializer& InPipelineState, FGraphicsMinimalPipelineStateSet& InOutPassSet, bool& InNeedsShaderInitialisation)
{
FGraphicsMinimalPipelineStateId Ret;
Ret.bValid = 1;
Ret.bComesFromLocalPipelineStateSet = 1;
#if UE_BUILD_DEBUG
FGraphicsMinimalPipelineStateInitializer PipelineStateDebug = FGraphicsMinimalPipelineStateInitializer(InPipelineState);
check(GetTypeHash(PipelineStateDebug) == GetTypeHash(InPipelineState));
check(PipelineStateDebug == InPipelineState);
#endif
Experimental::FHashElementId TableIndex = InOutPassSet.FindOrAddId(InPipelineState);
#if UE_BUILD_DEBUG
check(InOutPassSet.GetByElementId(TableIndex) == InPipelineState);
#endif
InNeedsShaderInitialisation = InNeedsShaderInitialisation || InPipelineState.BoundShaderState.NeedsShaderInitialisation();
checkf(TableIndex.GetIndex() < (MAX_uint32 >> 2), TEXT("One frame FGraphicsMinimalPipelineStateId table overflow!"));
Ret.SetElementIndex = TableIndex.GetIndex();
return Ret;
}
void FGraphicsMinimalPipelineStateId::ResetLocalPipelineIdTableSize()
{
#if MESH_DRAW_COMMAND_DEBUG_DATA
int32 CapturedPipelineIdTableSize;
do
{
CapturedPipelineIdTableSize = CurrentLocalPipelineIdTableSize;
}while (!CurrentLocalPipelineIdTableSize.compare_exchange_strong(CapturedPipelineIdTableSize, 0));
LocalPipelineIdTableSize = CapturedPipelineIdTableSize;
#endif //MESH_DRAW_COMMAND_DEBUG_DATA
}
void FGraphicsMinimalPipelineStateId::AddSizeToLocalPipelineIdTableSize(SIZE_T Size)
{
#if MESH_DRAW_COMMAND_DEBUG_DATA
CurrentLocalPipelineIdTableSize += int32(Size);
#endif
}
FMeshDrawShaderBindings::~FMeshDrawShaderBindings()
{
Release();
}
void FMeshDrawShaderBindings::Initialize(FMeshProcessorShaders Shaders)
{
const int32 NumShaderFrequencies =
(Shaders.VertexShader.IsValid() ? 1 : 0) +
(Shaders.PixelShader.IsValid() ? 1 : 0) +
(Shaders.GeometryShader.IsValid() ? 1 : 0) +
(Shaders.ComputeShader.IsValid() ? 1 : 0)
#if RHI_RAYTRACING
+ (Shaders.RayTracingShader.IsValid() ? 1 : 0)
#endif
;
ShaderLayouts.Empty(NumShaderFrequencies);
int32 ShaderBindingDataSize = 0;
if (Shaders.VertexShader.IsValid())
{
ShaderLayouts.Add(FMeshDrawShaderBindingsLayout(Shaders.VertexShader));
ShaderBindingDataSize += ShaderLayouts.Last().GetDataSizeBytes();
check(ShaderFrequencyBits < (1 << SF_Vertex));
ShaderFrequencyBits |= (1 << SF_Vertex);
}
if (Shaders.PixelShader.IsValid())
{
ShaderLayouts.Add(FMeshDrawShaderBindingsLayout(Shaders.PixelShader));
ShaderBindingDataSize += ShaderLayouts.Last().GetDataSizeBytes();
check(ShaderFrequencyBits < (1 << SF_Pixel));
ShaderFrequencyBits |= (1 << SF_Pixel);
}
if (Shaders.GeometryShader.IsValid())
{
ShaderLayouts.Add(FMeshDrawShaderBindingsLayout(Shaders.GeometryShader));
ShaderBindingDataSize += ShaderLayouts.Last().GetDataSizeBytes();
check(ShaderFrequencyBits < (1 << SF_Geometry));
ShaderFrequencyBits |= (1 << SF_Geometry);
}
if (Shaders.ComputeShader.IsValid())
{
ShaderLayouts.Add(FMeshDrawShaderBindingsLayout(Shaders.ComputeShader));
ShaderBindingDataSize += ShaderLayouts.Last().GetDataSizeBytes();
check(ShaderFrequencyBits < (1 << SF_Compute));
ShaderFrequencyBits |= (1 << SF_Compute);
}
#if RHI_RAYTRACING
if (Shaders.RayTracingShader.IsValid())
{
ShaderLayouts.Add(FMeshDrawShaderBindingsLayout(Shaders.RayTracingShader));
ShaderBindingDataSize += ShaderLayouts.Last().GetDataSizeBytes();
const EShaderFrequency Frequency = Shaders.RayTracingShader->GetFrequency();
check(ShaderFrequencyBits < (1 << Frequency));
ShaderFrequencyBits |= (1 << Frequency);
}
#endif
checkSlow(ShaderLayouts.Num() == NumShaderFrequencies);
if (ShaderBindingDataSize > 0)
{
AllocateZeroed(ShaderBindingDataSize);
}
}
void FMeshDrawShaderBindings::Finalize(const FMeshProcessorShaders* ShadersForDebugging)
{
#if VALIDATE_MESH_COMMAND_BINDINGS
if (!ShadersForDebugging)
{
return;
}
const uint8* ShaderBindingDataPtr = GetData();
uint32 ShaderFrequencyBitIndex = ~0;
for (int32 ShaderBindingsIndex = 0; ShaderBindingsIndex < ShaderLayouts.Num(); ShaderBindingsIndex++)
{
EShaderFrequency Frequency = SF_NumFrequencies;
while (true)
{
ShaderFrequencyBitIndex++;
if ((ShaderFrequencyBits & (1 << ShaderFrequencyBitIndex)) != 0)
{
Frequency = EShaderFrequency(ShaderFrequencyBitIndex);
break;
}
}
check(Frequency < SF_NumFrequencies);
const FMeshDrawShaderBindingsLayout& ShaderLayout = ShaderLayouts[ShaderBindingsIndex];
TShaderRef<FShader> Shader = ShadersForDebugging->GetShader(Frequency);
check(Shader.IsValid());
const FVertexFactoryType* VFType = Shader.GetVertexFactoryType();
FReadOnlyMeshDrawSingleShaderBindings SingleShaderBindings(ShaderLayout, ShaderBindingDataPtr);
FRHIUniformBuffer* const* UniformBufferBindings = SingleShaderBindings.GetUniformBufferStart();
for (int32 BindingIndex = 0; BindingIndex < ShaderLayout.ParameterMapInfo.UniformBuffers.Num(); BindingIndex++)
{
FShaderUniformBufferParameterInfo ParameterInfo = ShaderLayout.ParameterMapInfo.UniformBuffers[BindingIndex];
FRHIUniformBuffer* UniformBufferValue = UniformBufferBindings[BindingIndex];
if (!UniformBufferValue)
{
// Search the automatically bound uniform buffers for more context if available
const FShaderParametersMetadata* AutomaticallyBoundUniformBufferStruct = Shader->FindAutomaticallyBoundUniformBufferStruct(ParameterInfo.BaseIndex);
if (AutomaticallyBoundUniformBufferStruct)
{
ensureMsgf(
UniformBufferValue || EnumHasAnyFlags(AutomaticallyBoundUniformBufferStruct->GetBindingFlags(), EUniformBufferBindingFlags::Static),
TEXT("Shader %s with vertex factory %s never set automatically bound uniform buffer at BaseIndex %i. Expected buffer of type %s. This can cause GPU hangs, depending on how the shader uses it."),
Shader.GetType()->GetName(),
VFType ? VFType->GetName() : TEXT("nullptr"),
ParameterInfo.BaseIndex,
AutomaticallyBoundUniformBufferStruct->GetStructTypeName());
}
else
{
ensureMsgf(UniformBufferValue, TEXT("Shader %s with vertex factory %s never set uniform buffer at BaseIndex %i. This can cause GPU hangs, depending on how the shader uses it."),
VFType ? VFType->GetName() : TEXT("nullptr"),
Shader.GetType()->GetName(),
ParameterInfo.BaseIndex);
}
}
}
FRHISamplerState* const* SamplerBindings = SingleShaderBindings.GetSamplerStart();
for (int32 BindingIndex = 0; BindingIndex < ShaderLayout.ParameterMapInfo.TextureSamplers.Num(); BindingIndex++)
{
FShaderResourceParameterInfo ParameterInfo = ShaderLayout.ParameterMapInfo.TextureSamplers[BindingIndex];
const FRHISamplerState* SamplerValue = SamplerBindings[BindingIndex];
ensureMsgf(SamplerValue, TEXT("Shader %s with vertex factory %s never set sampler at BaseIndex %u. This can cause GPU hangs, depending on how the shader uses it."),
Shader.GetType()->GetName(),
VFType ? VFType->GetName() : TEXT("nullptr"),
ParameterInfo.BaseIndex);
}
const uint8* RESTRICT SRVType = SingleShaderBindings.GetSRVTypeStart();
FRHIResource* const* RESTRICT SRVBindings = SingleShaderBindings.GetSRVStart();
const FShaderResourceParameterInfo* RESTRICT SRVParameters = SingleShaderBindings.ParameterMapInfo.SRVs.GetData();
const uint32 NumSRVs = SingleShaderBindings.ParameterMapInfo.SRVs.Num();
for (uint32 SRVIndex = 0; SRVIndex < NumSRVs; SRVIndex++)
{
FShaderResourceParameterInfo Parameter = SRVParameters[SRVIndex];
uint32 TypeByteIndex = SRVIndex / 8;
uint32 TypeBitIndex = SRVIndex % 8;
if (SRVType[TypeByteIndex] & (1 << TypeBitIndex))
{
FRHIShaderResourceView* SRV = (FRHIShaderResourceView*)SRVBindings[SRVIndex];
ensureMsgf(SRV, TEXT("Shader %s with vertex factory %s never set SRV at BaseIndex %u. This can cause GPU hangs, depending on how the shader uses it."),
Shader.GetType()->GetName(),
VFType ? VFType->GetName() : TEXT("nullptr"),
Parameter.BaseIndex);
}
else
{
FRHITexture* Texture = (FRHITexture*)SRVBindings[SRVIndex];
ensureMsgf(Texture, TEXT("Shader %s with vertex factory %s never set texture at BaseIndex %u. This can cause GPU hangs, depending on how the shader uses it."),
Shader.GetType()->GetName(),
VFType ? VFType->GetName() : TEXT("nullptr"),
Parameter.BaseIndex);
}
}
ShaderBindingDataPtr += ShaderLayout.GetDataSizeBytes();
}
#endif
}
void FMeshDrawShaderBindings::CopyFrom(const FMeshDrawShaderBindings& Other)
{
Release();
ShaderLayouts = Other.ShaderLayouts;
ShaderFrequencyBits = Other.ShaderFrequencyBits;
Allocate(Other.Size);
if (Other.UsesInlineStorage())
{
Data = Other.Data;
}
else
{
FPlatformMemory::Memcpy(GetData(), Other.GetData(), Size);
}
#if VALIDATE_UNIFORM_BUFFER_LIFETIME
uint8* ShaderBindingDataPtr = GetData();
for (int32 ShaderBindingsIndex = 0; ShaderBindingsIndex < ShaderLayouts.Num(); ShaderBindingsIndex++)
{
FMeshDrawSingleShaderBindings SingleShaderBindings(ShaderLayouts[ShaderBindingsIndex], ShaderBindingDataPtr);
FRHIUniformBuffer** RESTRICT UniformBufferBindings = SingleShaderBindings.GetUniformBufferStart();
const int32 NumUniformBuffers = SingleShaderBindings.ParameterMapInfo.UniformBuffers.Num();
for (int32 UniformBufferIndex = 0; UniformBufferIndex < NumUniformBuffers; UniformBufferIndex++)
{
FRHIUniformBuffer* UniformBuffer = UniformBufferBindings[UniformBufferIndex];
if (UniformBuffer)
{
UniformBuffer->NumMeshCommandReferencesForDebugging++;
}
}
ShaderBindingDataPtr += ShaderLayouts[ShaderBindingsIndex].GetDataSizeBytes();
}
#endif
}
void FMeshDrawShaderBindings::Release()
{
#if VALIDATE_UNIFORM_BUFFER_LIFETIME
uint8* ShaderBindingDataPtr = GetData();
for (int32 ShaderBindingsIndex = 0; ShaderBindingsIndex < ShaderLayouts.Num(); ShaderBindingsIndex++)
{
FMeshDrawSingleShaderBindings SingleShaderBindings(ShaderLayouts[ShaderBindingsIndex], ShaderBindingDataPtr);
FRHIUniformBuffer** RESTRICT UniformBufferBindings = SingleShaderBindings.GetUniformBufferStart();
const int32 NumUniformBuffers = SingleShaderBindings.ParameterMapInfo.UniformBuffers.Num();
for (int32 UniformBufferIndex = 0; UniformBufferIndex < NumUniformBuffers; UniformBufferIndex++)
{
FRHIUniformBuffer* UniformBuffer = UniformBufferBindings[UniformBufferIndex];
if (UniformBuffer)
{
UniformBuffer->NumMeshCommandReferencesForDebugging--;
check(UniformBuffer->NumMeshCommandReferencesForDebugging >= 0);
}
}
ShaderBindingDataPtr += ShaderLayouts[ShaderBindingsIndex].GetDataSizeBytes();
}
#endif
if (Size > sizeof(FData))
{
delete[] Data.GetHeapData();
}
Size = 0;
Data.SetHeapData(nullptr);
}
PSO Precache Base Changes (disabled by default) Add PSOPrecache file which wraps engine level PSO structs and functions - FPSOPrecacheParams used to wrap certain parameters which drive the PSO collection (mostly set from components) - IPSOCollector interface used as engine entry to the mesh pass processors in renderer project - FPSOCollectorCreateManager to wrap all statically registered IPSOCollector CreateFuncions - PSOCollectorStats structs and helper functions Add PSOPrecache support to PipelineStateCache: - functions to precache compute and graphics PSOs - functions to check current precache state - FPrecacheGraphicsPipelineCache which wraps all currently precached PSOs IMaterial entry function to PrecachePSOs with given vertex factories and params (implemented by UMaterial & UMaterialInstance) which forwards call to FMaterial and finally the FMaterialShaderMap - FMaterialShaderMap will iterate all registered IPSOCollector to collect all possible PSOs used and forward them to the PipelineStateCache for actual (async) precaching RHI Changes: - Add RHI specific functions to retrieve & compare the FRHIVertexDeclaration and FGraphicsPipelineStateInitializer hash for each RHI - Add helper functions to match RHI*State data by retrieving initializer Minimal vertex factory changes for PSO precaching as prep - actual changes in upcoming CLs MeshPassProcessor base functions to collect PSOs which can be used by all mesh pass processor implemention (actual changes in upcoming CLs) - Cache complete precache data hash of stored minimal PSO so it can be used for fast actual PSO initializer hash computation (full PSO initializer is build at runtime) - Cache if minimal PSO was successfully precache and option to skip draw when PSO is still precaching (disabled by default and doesn't work yet via GPU scene based rendering) - Add helper functions to setup the per mesh pass render target data used during PSO collection Refactor SceneTextureConfig so it can be initialized from an init struct and move all function to setup the internal members from SceneTexture to SceneTextureConfig using the data from the init struct (so it's available in Engine project) Fix GBufferInfo format for velocity target (was always floating point while it should be unorm when not android Make certain helper functions definitions to h file so they can be used everywhere (SupportsNaniteRendering, FTextureRenderTarget2DResource::GetFormat & CreateFlags) #preflight 63189a5a967ffc68fb9044a5 #jira UE-139584 #rb Mihnea.Balta [CL 21907508 by kenzo terelst in ue5-main branch]
2022-09-08 19:34:08 -04:00
void FGraphicsMinimalPipelineStateInitializer::SetupBoundShaderState(FRHIVertexDeclaration* VertexDeclaration, const FMeshProcessorShaders& Shaders)
{
PSO Precache Base Changes (disabled by default) Add PSOPrecache file which wraps engine level PSO structs and functions - FPSOPrecacheParams used to wrap certain parameters which drive the PSO collection (mostly set from components) - IPSOCollector interface used as engine entry to the mesh pass processors in renderer project - FPSOCollectorCreateManager to wrap all statically registered IPSOCollector CreateFuncions - PSOCollectorStats structs and helper functions Add PSOPrecache support to PipelineStateCache: - functions to precache compute and graphics PSOs - functions to check current precache state - FPrecacheGraphicsPipelineCache which wraps all currently precached PSOs IMaterial entry function to PrecachePSOs with given vertex factories and params (implemented by UMaterial & UMaterialInstance) which forwards call to FMaterial and finally the FMaterialShaderMap - FMaterialShaderMap will iterate all registered IPSOCollector to collect all possible PSOs used and forward them to the PipelineStateCache for actual (async) precaching RHI Changes: - Add RHI specific functions to retrieve & compare the FRHIVertexDeclaration and FGraphicsPipelineStateInitializer hash for each RHI - Add helper functions to match RHI*State data by retrieving initializer Minimal vertex factory changes for PSO precaching as prep - actual changes in upcoming CLs MeshPassProcessor base functions to collect PSOs which can be used by all mesh pass processor implemention (actual changes in upcoming CLs) - Cache complete precache data hash of stored minimal PSO so it can be used for fast actual PSO initializer hash computation (full PSO initializer is build at runtime) - Cache if minimal PSO was successfully precache and option to skip draw when PSO is still precaching (disabled by default and doesn't work yet via GPU scene based rendering) - Add helper functions to setup the per mesh pass render target data used during PSO collection Refactor SceneTextureConfig so it can be initialized from an init struct and move all function to setup the internal members from SceneTexture to SceneTextureConfig using the data from the init struct (so it's available in Engine project) Fix GBufferInfo format for velocity target (was always floating point while it should be unorm when not android Make certain helper functions definitions to h file so they can be used everywhere (SupportsNaniteRendering, FTextureRenderTarget2DResource::GetFormat & CreateFlags) #preflight 63189a5a967ffc68fb9044a5 #jira UE-139584 #rb Mihnea.Balta [CL 21907508 by kenzo terelst in ue5-main branch]
2022-09-08 19:34:08 -04:00
BoundShaderState = FMinimalBoundShaderStateInput();
BoundShaderState.VertexDeclarationRHI = VertexDeclaration;
checkf(Shaders.VertexShader.IsValid(), TEXT("Can't render without a vertex shader"));
if(Shaders.VertexShader.IsValid())
{
checkSlow(Shaders.VertexShader->GetFrequency() == SF_Vertex);
PSO Precache Base Changes (disabled by default) Add PSOPrecache file which wraps engine level PSO structs and functions - FPSOPrecacheParams used to wrap certain parameters which drive the PSO collection (mostly set from components) - IPSOCollector interface used as engine entry to the mesh pass processors in renderer project - FPSOCollectorCreateManager to wrap all statically registered IPSOCollector CreateFuncions - PSOCollectorStats structs and helper functions Add PSOPrecache support to PipelineStateCache: - functions to precache compute and graphics PSOs - functions to check current precache state - FPrecacheGraphicsPipelineCache which wraps all currently precached PSOs IMaterial entry function to PrecachePSOs with given vertex factories and params (implemented by UMaterial & UMaterialInstance) which forwards call to FMaterial and finally the FMaterialShaderMap - FMaterialShaderMap will iterate all registered IPSOCollector to collect all possible PSOs used and forward them to the PipelineStateCache for actual (async) precaching RHI Changes: - Add RHI specific functions to retrieve & compare the FRHIVertexDeclaration and FGraphicsPipelineStateInitializer hash for each RHI - Add helper functions to match RHI*State data by retrieving initializer Minimal vertex factory changes for PSO precaching as prep - actual changes in upcoming CLs MeshPassProcessor base functions to collect PSOs which can be used by all mesh pass processor implemention (actual changes in upcoming CLs) - Cache complete precache data hash of stored minimal PSO so it can be used for fast actual PSO initializer hash computation (full PSO initializer is build at runtime) - Cache if minimal PSO was successfully precache and option to skip draw when PSO is still precaching (disabled by default and doesn't work yet via GPU scene based rendering) - Add helper functions to setup the per mesh pass render target data used during PSO collection Refactor SceneTextureConfig so it can be initialized from an init struct and move all function to setup the internal members from SceneTexture to SceneTextureConfig using the data from the init struct (so it's available in Engine project) Fix GBufferInfo format for velocity target (was always floating point while it should be unorm when not android Make certain helper functions definitions to h file so they can be used everywhere (SupportsNaniteRendering, FTextureRenderTarget2DResource::GetFormat & CreateFlags) #preflight 63189a5a967ffc68fb9044a5 #jira UE-139584 #rb Mihnea.Balta [CL 21907508 by kenzo terelst in ue5-main branch]
2022-09-08 19:34:08 -04:00
BoundShaderState.VertexShaderResource = Shaders.VertexShader.GetResource();
BoundShaderState.VertexShaderIndex = Shaders.VertexShader->GetResourceIndex();
check(BoundShaderState.VertexShaderResource->IsValidShaderIndex(BoundShaderState.VertexShaderIndex));
}
if (Shaders.PixelShader.IsValid())
{
checkSlow(Shaders.PixelShader->GetFrequency() == SF_Pixel);
PSO Precache Base Changes (disabled by default) Add PSOPrecache file which wraps engine level PSO structs and functions - FPSOPrecacheParams used to wrap certain parameters which drive the PSO collection (mostly set from components) - IPSOCollector interface used as engine entry to the mesh pass processors in renderer project - FPSOCollectorCreateManager to wrap all statically registered IPSOCollector CreateFuncions - PSOCollectorStats structs and helper functions Add PSOPrecache support to PipelineStateCache: - functions to precache compute and graphics PSOs - functions to check current precache state - FPrecacheGraphicsPipelineCache which wraps all currently precached PSOs IMaterial entry function to PrecachePSOs with given vertex factories and params (implemented by UMaterial & UMaterialInstance) which forwards call to FMaterial and finally the FMaterialShaderMap - FMaterialShaderMap will iterate all registered IPSOCollector to collect all possible PSOs used and forward them to the PipelineStateCache for actual (async) precaching RHI Changes: - Add RHI specific functions to retrieve & compare the FRHIVertexDeclaration and FGraphicsPipelineStateInitializer hash for each RHI - Add helper functions to match RHI*State data by retrieving initializer Minimal vertex factory changes for PSO precaching as prep - actual changes in upcoming CLs MeshPassProcessor base functions to collect PSOs which can be used by all mesh pass processor implemention (actual changes in upcoming CLs) - Cache complete precache data hash of stored minimal PSO so it can be used for fast actual PSO initializer hash computation (full PSO initializer is build at runtime) - Cache if minimal PSO was successfully precache and option to skip draw when PSO is still precaching (disabled by default and doesn't work yet via GPU scene based rendering) - Add helper functions to setup the per mesh pass render target data used during PSO collection Refactor SceneTextureConfig so it can be initialized from an init struct and move all function to setup the internal members from SceneTexture to SceneTextureConfig using the data from the init struct (so it's available in Engine project) Fix GBufferInfo format for velocity target (was always floating point while it should be unorm when not android Make certain helper functions definitions to h file so they can be used everywhere (SupportsNaniteRendering, FTextureRenderTarget2DResource::GetFormat & CreateFlags) #preflight 63189a5a967ffc68fb9044a5 #jira UE-139584 #rb Mihnea.Balta [CL 21907508 by kenzo terelst in ue5-main branch]
2022-09-08 19:34:08 -04:00
BoundShaderState.PixelShaderResource = Shaders.PixelShader.GetResource();
BoundShaderState.PixelShaderIndex = Shaders.PixelShader->GetResourceIndex();
check(BoundShaderState.PixelShaderResource->IsValidShaderIndex(BoundShaderState.PixelShaderIndex));
}
#if PLATFORM_SUPPORTS_GEOMETRY_SHADERS
if (Shaders.GeometryShader.IsValid())
{
checkSlow(Shaders.GeometryShader->GetFrequency() == SF_Geometry);
PSO Precache Base Changes (disabled by default) Add PSOPrecache file which wraps engine level PSO structs and functions - FPSOPrecacheParams used to wrap certain parameters which drive the PSO collection (mostly set from components) - IPSOCollector interface used as engine entry to the mesh pass processors in renderer project - FPSOCollectorCreateManager to wrap all statically registered IPSOCollector CreateFuncions - PSOCollectorStats structs and helper functions Add PSOPrecache support to PipelineStateCache: - functions to precache compute and graphics PSOs - functions to check current precache state - FPrecacheGraphicsPipelineCache which wraps all currently precached PSOs IMaterial entry function to PrecachePSOs with given vertex factories and params (implemented by UMaterial & UMaterialInstance) which forwards call to FMaterial and finally the FMaterialShaderMap - FMaterialShaderMap will iterate all registered IPSOCollector to collect all possible PSOs used and forward them to the PipelineStateCache for actual (async) precaching RHI Changes: - Add RHI specific functions to retrieve & compare the FRHIVertexDeclaration and FGraphicsPipelineStateInitializer hash for each RHI - Add helper functions to match RHI*State data by retrieving initializer Minimal vertex factory changes for PSO precaching as prep - actual changes in upcoming CLs MeshPassProcessor base functions to collect PSOs which can be used by all mesh pass processor implemention (actual changes in upcoming CLs) - Cache complete precache data hash of stored minimal PSO so it can be used for fast actual PSO initializer hash computation (full PSO initializer is build at runtime) - Cache if minimal PSO was successfully precache and option to skip draw when PSO is still precaching (disabled by default and doesn't work yet via GPU scene based rendering) - Add helper functions to setup the per mesh pass render target data used during PSO collection Refactor SceneTextureConfig so it can be initialized from an init struct and move all function to setup the internal members from SceneTexture to SceneTextureConfig using the data from the init struct (so it's available in Engine project) Fix GBufferInfo format for velocity target (was always floating point while it should be unorm when not android Make certain helper functions definitions to h file so they can be used everywhere (SupportsNaniteRendering, FTextureRenderTarget2DResource::GetFormat & CreateFlags) #preflight 63189a5a967ffc68fb9044a5 #jira UE-139584 #rb Mihnea.Balta [CL 21907508 by kenzo terelst in ue5-main branch]
2022-09-08 19:34:08 -04:00
BoundShaderState.GeometryShaderResource = Shaders.GeometryShader.GetResource();
BoundShaderState.GeometryShaderIndex = Shaders.GeometryShader->GetResourceIndex();
check(BoundShaderState.GeometryShaderResource->IsValidShaderIndex(BoundShaderState.GeometryShaderIndex));
}
#endif // PLATFORM_SUPPORTS_GEOMETRY_SHADERS
PSO Precache Base Changes (disabled by default) Add PSOPrecache file which wraps engine level PSO structs and functions - FPSOPrecacheParams used to wrap certain parameters which drive the PSO collection (mostly set from components) - IPSOCollector interface used as engine entry to the mesh pass processors in renderer project - FPSOCollectorCreateManager to wrap all statically registered IPSOCollector CreateFuncions - PSOCollectorStats structs and helper functions Add PSOPrecache support to PipelineStateCache: - functions to precache compute and graphics PSOs - functions to check current precache state - FPrecacheGraphicsPipelineCache which wraps all currently precached PSOs IMaterial entry function to PrecachePSOs with given vertex factories and params (implemented by UMaterial & UMaterialInstance) which forwards call to FMaterial and finally the FMaterialShaderMap - FMaterialShaderMap will iterate all registered IPSOCollector to collect all possible PSOs used and forward them to the PipelineStateCache for actual (async) precaching RHI Changes: - Add RHI specific functions to retrieve & compare the FRHIVertexDeclaration and FGraphicsPipelineStateInitializer hash for each RHI - Add helper functions to match RHI*State data by retrieving initializer Minimal vertex factory changes for PSO precaching as prep - actual changes in upcoming CLs MeshPassProcessor base functions to collect PSOs which can be used by all mesh pass processor implemention (actual changes in upcoming CLs) - Cache complete precache data hash of stored minimal PSO so it can be used for fast actual PSO initializer hash computation (full PSO initializer is build at runtime) - Cache if minimal PSO was successfully precache and option to skip draw when PSO is still precaching (disabled by default and doesn't work yet via GPU scene based rendering) - Add helper functions to setup the per mesh pass render target data used during PSO collection Refactor SceneTextureConfig so it can be initialized from an init struct and move all function to setup the internal members from SceneTexture to SceneTextureConfig using the data from the init struct (so it's available in Engine project) Fix GBufferInfo format for velocity target (was always floating point while it should be unorm when not android Make certain helper functions definitions to h file so they can be used everywhere (SupportsNaniteRendering, FTextureRenderTarget2DResource::GetFormat & CreateFlags) #preflight 63189a5a967ffc68fb9044a5 #jira UE-139584 #rb Mihnea.Balta [CL 21907508 by kenzo terelst in ue5-main branch]
2022-09-08 19:34:08 -04:00
}
void FGraphicsMinimalPipelineStateInitializer::ComputePrecachePSOHash()
{
struct FHashKey
{
uint32 VertexDeclaration;
uint32 VertexShader;
uint32 PixelShader;
#if PLATFORM_SUPPORTS_GEOMETRY_SHADERS
uint32 GeometryShader;
#endif // PLATFORM_SUPPORTS_GEOMETRY_SHADERS
#if PLATFORM_SUPPORTS_MESH_SHADERS
uint32 MeshShader;
#endif // PLATFORM_SUPPORTS_MESH_SHADERS
PSO Precache Base Changes (disabled by default) Add PSOPrecache file which wraps engine level PSO structs and functions - FPSOPrecacheParams used to wrap certain parameters which drive the PSO collection (mostly set from components) - IPSOCollector interface used as engine entry to the mesh pass processors in renderer project - FPSOCollectorCreateManager to wrap all statically registered IPSOCollector CreateFuncions - PSOCollectorStats structs and helper functions Add PSOPrecache support to PipelineStateCache: - functions to precache compute and graphics PSOs - functions to check current precache state - FPrecacheGraphicsPipelineCache which wraps all currently precached PSOs IMaterial entry function to PrecachePSOs with given vertex factories and params (implemented by UMaterial & UMaterialInstance) which forwards call to FMaterial and finally the FMaterialShaderMap - FMaterialShaderMap will iterate all registered IPSOCollector to collect all possible PSOs used and forward them to the PipelineStateCache for actual (async) precaching RHI Changes: - Add RHI specific functions to retrieve & compare the FRHIVertexDeclaration and FGraphicsPipelineStateInitializer hash for each RHI - Add helper functions to match RHI*State data by retrieving initializer Minimal vertex factory changes for PSO precaching as prep - actual changes in upcoming CLs MeshPassProcessor base functions to collect PSOs which can be used by all mesh pass processor implemention (actual changes in upcoming CLs) - Cache complete precache data hash of stored minimal PSO so it can be used for fast actual PSO initializer hash computation (full PSO initializer is build at runtime) - Cache if minimal PSO was successfully precache and option to skip draw when PSO is still precaching (disabled by default and doesn't work yet via GPU scene based rendering) - Add helper functions to setup the per mesh pass render target data used during PSO collection Refactor SceneTextureConfig so it can be initialized from an init struct and move all function to setup the internal members from SceneTexture to SceneTextureConfig using the data from the init struct (so it's available in Engine project) Fix GBufferInfo format for velocity target (was always floating point while it should be unorm when not android Make certain helper functions definitions to h file so they can be used everywhere (SupportsNaniteRendering, FTextureRenderTarget2DResource::GetFormat & CreateFlags) #preflight 63189a5a967ffc68fb9044a5 #jira UE-139584 #rb Mihnea.Balta [CL 21907508 by kenzo terelst in ue5-main branch]
2022-09-08 19:34:08 -04:00
uint32 BlendState;
uint32 RasterizerState;
uint32 DepthStencilState;
uint32 ImmutableSamplerState;
uint32 MultiViewCount : 8;
uint32 DrawShadingRate : 8;
uint32 PrimitiveType : 8;
uint32 bDepthBounds : 1;
uint32 bHasFragmentDensityAttachment : 1;
uint32 Unused : 6;
} HashKey;
FMemory::Memzero(&HashKey, sizeof(FHashKey));
HashKey.VertexDeclaration = BoundShaderState.VertexDeclarationRHI ? BoundShaderState.VertexDeclarationRHI->GetPrecachePSOHash() : 0;
HashKey.VertexShader = HashCombine(GetTypeHash(BoundShaderState.VertexShaderIndex), GetTypeHash(BoundShaderState.VertexShaderResource));
HashKey.PixelShader = HashCombine(GetTypeHash(BoundShaderState.PixelShaderIndex), GetTypeHash(BoundShaderState.PixelShaderResource));
#if PLATFORM_SUPPORTS_GEOMETRY_SHADERS
HashKey.GeometryShader = HashCombine(GetTypeHash(BoundShaderState.GeometryShaderIndex), GetTypeHash(BoundShaderState.GeometryShaderResource));
#endif
#if PLATFORM_SUPPORTS_MESH_SHADERS
HashKey.MeshShader = HashCombine(GetTypeHash(BoundShaderState.MeshShaderIndex), GetTypeHash(BoundShaderState.MeshShaderResource));
#endif
PSO Precache Base Changes (disabled by default) Add PSOPrecache file which wraps engine level PSO structs and functions - FPSOPrecacheParams used to wrap certain parameters which drive the PSO collection (mostly set from components) - IPSOCollector interface used as engine entry to the mesh pass processors in renderer project - FPSOCollectorCreateManager to wrap all statically registered IPSOCollector CreateFuncions - PSOCollectorStats structs and helper functions Add PSOPrecache support to PipelineStateCache: - functions to precache compute and graphics PSOs - functions to check current precache state - FPrecacheGraphicsPipelineCache which wraps all currently precached PSOs IMaterial entry function to PrecachePSOs with given vertex factories and params (implemented by UMaterial & UMaterialInstance) which forwards call to FMaterial and finally the FMaterialShaderMap - FMaterialShaderMap will iterate all registered IPSOCollector to collect all possible PSOs used and forward them to the PipelineStateCache for actual (async) precaching RHI Changes: - Add RHI specific functions to retrieve & compare the FRHIVertexDeclaration and FGraphicsPipelineStateInitializer hash for each RHI - Add helper functions to match RHI*State data by retrieving initializer Minimal vertex factory changes for PSO precaching as prep - actual changes in upcoming CLs MeshPassProcessor base functions to collect PSOs which can be used by all mesh pass processor implemention (actual changes in upcoming CLs) - Cache complete precache data hash of stored minimal PSO so it can be used for fast actual PSO initializer hash computation (full PSO initializer is build at runtime) - Cache if minimal PSO was successfully precache and option to skip draw when PSO is still precaching (disabled by default and doesn't work yet via GPU scene based rendering) - Add helper functions to setup the per mesh pass render target data used during PSO collection Refactor SceneTextureConfig so it can be initialized from an init struct and move all function to setup the internal members from SceneTexture to SceneTextureConfig using the data from the init struct (so it's available in Engine project) Fix GBufferInfo format for velocity target (was always floating point while it should be unorm when not android Make certain helper functions definitions to h file so they can be used everywhere (SupportsNaniteRendering, FTextureRenderTarget2DResource::GetFormat & CreateFlags) #preflight 63189a5a967ffc68fb9044a5 #jira UE-139584 #rb Mihnea.Balta [CL 21907508 by kenzo terelst in ue5-main branch]
2022-09-08 19:34:08 -04:00
FBlendStateInitializerRHI BlendStateInitializerRHI;
if (BlendState && BlendState->GetInitializer(BlendStateInitializerRHI))
{
HashKey.BlendState = GetTypeHash(BlendStateInitializerRHI);
}
FRasterizerStateInitializerRHI RasterizerStateInitializerRHI;
if (RasterizerState && RasterizerState->GetInitializer(RasterizerStateInitializerRHI))
{
HashKey.RasterizerState = GetTypeHash(RasterizerStateInitializerRHI);
}
FDepthStencilStateInitializerRHI DepthStencilStateInitializerRHI;
if (DepthStencilState && DepthStencilState->GetInitializer(DepthStencilStateInitializerRHI))
{
HashKey.DepthStencilState = GetTypeHash(DepthStencilStateInitializerRHI);
}
// Ignore immutable samplers for now
//HashKey.ImmutableSamplerState = GetTypeHash(ImmutableSamplerState);
HashKey.MultiViewCount = MultiViewCount;
HashKey.DrawShadingRate = DrawShadingRate;
HashKey.PrimitiveType = PrimitiveType;
HashKey.bDepthBounds = bDepthBounds;
HashKey.bHasFragmentDensityAttachment = bHasFragmentDensityAttachment;
PrecachePSOHash = CityHash64((const char*)&HashKey, sizeof(FHashKey));
}
#if RHI_RAYTRACING
void FRayTracingMeshCommand::SetRayTracingShaderBindingsForHitGroup(
FRayTracingLocalShaderBindingWriter* BindingWriter,
const TUniformBufferRef<FViewUniformShaderParameters>& ViewUniformBuffer,
FRHIUniformBuffer* NaniteUniformBuffer,
uint32 InstanceIndex,
uint32 SegmentIndex,
uint32 HitGroupIndexInPipeline,
uint32 ShaderSlot) const
{
FRayTracingLocalShaderBindings* Bindings = ShaderBindings.SetRayTracingShaderBindingsForHitGroup(BindingWriter, InstanceIndex, SegmentIndex, HitGroupIndexInPipeline, ShaderSlot);
if (ViewUniformBufferParameter.IsBound())
{
check(ViewUniformBuffer);
Bindings->UniformBuffers[ViewUniformBufferParameter.GetBaseIndex()] = ViewUniformBuffer;
}
if (NaniteUniformBufferParameter.IsBound())
{
check(NaniteUniformBuffer);
Bindings->UniformBuffers[NaniteUniformBufferParameter.GetBaseIndex()] = NaniteUniformBuffer;
}
}
void FRayTracingMeshCommand::SetShaders(const FMeshProcessorShaders& Shaders)
{
check(Shaders.RayTracingShader.IsValid())
MaterialShaderIndex = Shaders.RayTracingShader.GetRayTracingHitGroupLibraryIndex();
MaterialShader = Shaders.RayTracingShader.GetRayTracingShader();
ViewUniformBufferParameter = Shaders.RayTracingShader->GetUniformBufferParameter<FViewUniformShaderParameters>();
NaniteUniformBufferParameter = Shaders.RayTracingShader->GetUniformBufferParameter<FNaniteRayTracingUniformParameters>();
ShaderBindings.Initialize(Shaders);
}
void FRayTracingShaderCommand::SetRayTracingShaderBindings(
FRayTracingLocalShaderBindingWriter* BindingWriter,
const TUniformBufferRef<FViewUniformShaderParameters>& ViewUniformBuffer,
FRHIUniformBuffer* NaniteUniformBuffer,
uint32 ShaderIndexInPipeline,
uint32 ShaderSlot) const
{
FRayTracingLocalShaderBindings* Bindings = ShaderBindings.SetRayTracingShaderBindings(BindingWriter, ShaderIndexInPipeline, ShaderSlot);
if (ViewUniformBufferParameter.IsBound())
{
check(ViewUniformBuffer);
Bindings->UniformBuffers[ViewUniformBufferParameter.GetBaseIndex()] = ViewUniformBuffer;
}
if (NaniteUniformBufferParameter.IsBound())
{
check(NaniteUniformBuffer);
Bindings->UniformBuffers[NaniteUniformBufferParameter.GetBaseIndex()] = NaniteUniformBuffer;
}
}
void FRayTracingShaderCommand::SetShader(const TShaderRef<FShader>& InShader)
{
check(InShader->GetFrequency() == SF_RayCallable || InShader->GetFrequency() == SF_RayMiss);
ShaderIndex = InShader.GetRayTracingCallableShaderLibraryIndex();
Shader = InShader.GetRayTracingShader();
ViewUniformBufferParameter = InShader->GetUniformBufferParameter<FViewUniformShaderParameters>();
NaniteUniformBufferParameter = InShader->GetUniformBufferParameter<FNaniteRayTracingUniformParameters>();
FMeshProcessorShaders Shaders;
Shaders.RayTracingShader = InShader;
ShaderBindings.Initialize(Shaders);
}
#endif // RHI_RAYTRACING
void FMeshDrawCommand::SetDrawParametersAndFinalize(
const FMeshBatch& MeshBatch,
int32 BatchElementIndex,
FGraphicsMinimalPipelineStateId PipelineId,
const FMeshProcessorShaders* ShadersForDebugging)
{
const FMeshBatchElement& BatchElement = MeshBatch.Elements[BatchElementIndex];
check(!BatchElement.IndexBuffer || (BatchElement.IndexBuffer && BatchElement.IndexBuffer->IsInitialized() && BatchElement.IndexBuffer->IndexBufferRHI));
IndexBuffer = BatchElement.IndexBuffer ? BatchElement.IndexBuffer->IndexBufferRHI.GetReference() : nullptr;
FirstIndex = BatchElement.FirstIndex;
NumPrimitives = BatchElement.NumPrimitives;
NumInstances = BatchElement.NumInstances;
// If the mesh batch has a valid dynamic index buffer, use it instead
if (BatchElement.DynamicIndexBuffer.IsValid())
{
check(!BatchElement.DynamicIndexBuffer.IndexBuffer || (BatchElement.DynamicIndexBuffer.IndexBuffer && BatchElement.DynamicIndexBuffer.IndexBuffer->IsInitialized() && BatchElement.DynamicIndexBuffer.IndexBuffer->IndexBufferRHI));
IndexBuffer = BatchElement.DynamicIndexBuffer.IndexBuffer ? BatchElement.DynamicIndexBuffer.IndexBuffer->IndexBufferRHI.GetReference() : nullptr;
FirstIndex = BatchElement.DynamicIndexBuffer.FirstIndex;
PrimitiveType = EPrimitiveType(BatchElement.DynamicIndexBuffer.PrimitiveType);
}
if (NumPrimitives > 0)
{
VertexParams.BaseVertexIndex = BatchElement.BaseVertexIndex;
VertexParams.NumVertices = BatchElement.MaxVertexIndex - BatchElement.MinVertexIndex + 1;
checkf(!BatchElement.IndirectArgsBuffer, TEXT("FMeshBatchElement::NumPrimitives must be set to 0 when a IndirectArgsBuffer is used"));
}
else
{
checkf(BatchElement.IndirectArgsBuffer, TEXT("It is only valid to set BatchElement.NumPrimitives == 0 when a IndirectArgsBuffer is used"));
IndirectArgs.Buffer = BatchElement.IndirectArgsBuffer;
IndirectArgs.Offset = BatchElement.IndirectArgsOffset;
}
Finalize(PipelineId, ShadersForDebugging);
}
void FMeshDrawShaderBindings::SetOnCommandList(FRHICommandList& RHICmdList, const FBoundShaderStateInput& Shaders, FShaderBindingState* StateCacheShaderBindings) const
{
const uint8* ShaderBindingDataPtr = GetData();
uint32 ShaderFrequencyBitIndex = ~0;
for (int32 ShaderBindingsIndex = 0; ShaderBindingsIndex < ShaderLayouts.Num(); ShaderBindingsIndex++)
{
EShaderFrequency Frequency = SF_NumFrequencies;
while (true)
{
ShaderFrequencyBitIndex++;
if ((ShaderFrequencyBits & (1 << ShaderFrequencyBitIndex)) != 0)
{
Frequency = EShaderFrequency(ShaderFrequencyBitIndex);
break;
}
}
check(Frequency < SF_NumFrequencies);
FReadOnlyMeshDrawSingleShaderBindings SingleShaderBindings(ShaderLayouts[ShaderBindingsIndex], ShaderBindingDataPtr);
FShaderBindingState& ShaderBindingState = StateCacheShaderBindings[Frequency];
if (Frequency == SF_Vertex)
{
SetShaderBindings(RHICmdList, Shaders.VertexShaderRHI, SingleShaderBindings, ShaderBindingState);
}
else if (Frequency == SF_Pixel)
{
SetShaderBindings(RHICmdList, Shaders.PixelShaderRHI, SingleShaderBindings, ShaderBindingState);
}
else if (Frequency == SF_Geometry)
{
SetShaderBindings(RHICmdList, Shaders.GetGeometryShader(), SingleShaderBindings, ShaderBindingState);
}
else
{
checkf(0, TEXT("Unknown shader frequency"));
}
ShaderBindingDataPtr += ShaderLayouts[ShaderBindingsIndex].GetDataSizeBytes();
}
}
void FMeshDrawShaderBindings::SetOnCommandList(FRHIComputeCommandList& RHICmdList, FRHIComputeShader* Shader, FShaderBindingState* StateCacheShaderBindings) const
{
check(ShaderLayouts.Num() == 1);
FReadOnlyMeshDrawSingleShaderBindings SingleShaderBindings(ShaderLayouts[0], GetData());
check(ShaderFrequencyBits & (1 << SF_Compute));
if (StateCacheShaderBindings != nullptr)
{
SetShaderBindings(RHICmdList, Shader, SingleShaderBindings, *StateCacheShaderBindings);
}
else
{
SetShaderBindings(RHICmdList, Shader, SingleShaderBindings);
}
}
bool FMeshDrawShaderBindings::MatchesForDynamicInstancing(const FMeshDrawShaderBindings& Rhs) const
{
if (ShaderFrequencyBits != Rhs.ShaderFrequencyBits)
{
return false;
}
if (ShaderLayouts.Num() != Rhs.ShaderLayouts.Num())
{
return false;
}
for (int Index = 0; Index < ShaderLayouts.Num(); Index++)
{
if (!(ShaderLayouts[Index] == Rhs.ShaderLayouts[Index]))
{
return false;
}
}
const uint8* ShaderBindingDataPtr = GetData();
const uint8* OtherShaderBindingDataPtr = Rhs.GetData();
for (int32 ShaderBindingsIndex = 0; ShaderBindingsIndex < ShaderLayouts.Num(); ShaderBindingsIndex++)
{
FReadOnlyMeshDrawSingleShaderBindings SingleShaderBindings(ShaderLayouts[ShaderBindingsIndex], ShaderBindingDataPtr);
FReadOnlyMeshDrawSingleShaderBindings OtherSingleShaderBindings(Rhs.ShaderLayouts[ShaderBindingsIndex], OtherShaderBindingDataPtr);
if (SingleShaderBindings.ParameterMapInfo.LooseParameterBuffers.Num())
{
const uint8* LooseBindings = SingleShaderBindings.GetLooseDataStart();
const uint8* OtherLooseBindings = OtherSingleShaderBindings.GetLooseDataStart();
const uint32 LooseLength = SingleShaderBindings.GetLooseDataSizeBytes();
const uint32 OtherLength = OtherSingleShaderBindings.GetLooseDataSizeBytes();
if (LooseLength != OtherLength)
{
return false;
}
if (memcmp(LooseBindings, OtherLooseBindings, LooseLength) != 0)
{
return false;
}
}
FRHISamplerState* const* SamplerBindings = SingleShaderBindings.GetSamplerStart();
FRHISamplerState* const* OtherSamplerBindings = OtherSingleShaderBindings.GetSamplerStart();
for (int32 SamplerIndex = 0; SamplerIndex < SingleShaderBindings.ParameterMapInfo.TextureSamplers.Num(); SamplerIndex++)
{
const FRHIResource* Sampler = SamplerBindings[SamplerIndex];
const FRHIResource* OtherSampler = OtherSamplerBindings[SamplerIndex];
if (Sampler != OtherSampler)
{
return false;
}
}
FRHIResource* const* SrvBindings = SingleShaderBindings.GetSRVStart();
FRHIResource* const* OtherSrvBindings = OtherSingleShaderBindings.GetSRVStart();
for (int32 SrvIndex = 0; SrvIndex < SingleShaderBindings.ParameterMapInfo.SRVs.Num(); SrvIndex++)
{
const FRHIResource* Srv = SrvBindings[SrvIndex];
const FRHIResource* OtherSrv = OtherSrvBindings[SrvIndex];
if (Srv != OtherSrv)
{
return false;
}
}
FRHIUniformBuffer* const* UniformBufferBindings = SingleShaderBindings.GetUniformBufferStart();
FRHIUniformBuffer* const* OtherUniformBufferBindings = OtherSingleShaderBindings.GetUniformBufferStart();
for (int32 UniformBufferIndex = 0; UniformBufferIndex < SingleShaderBindings.ParameterMapInfo.UniformBuffers.Num(); UniformBufferIndex++)
{
const FRHIUniformBuffer* UniformBuffer = UniformBufferBindings[UniformBufferIndex];
const FRHIUniformBuffer* OtherUniformBuffer = OtherUniformBufferBindings[UniformBufferIndex];
if (UniformBuffer != OtherUniformBuffer)
{
return false;
}
}
ShaderBindingDataPtr += ShaderLayouts[ShaderBindingsIndex].GetDataSizeBytes();
OtherShaderBindingDataPtr += Rhs.ShaderLayouts[ShaderBindingsIndex].GetDataSizeBytes();
}
return true;
}
uint32 FMeshDrawShaderBindings::GetDynamicInstancingHash() const
{
//add and initialize any leftover padding within the struct to avoid unstable keys
struct FHashKey
{
uint32 LooseParametersHash = 0;
uint32 UniformBufferHash = 0;
uint16 Size;
uint16 Frequencies;
static inline uint32 PointerHash(const void* Key)
{
#if PLATFORM_64BITS
// Ignoring the lower 4 bits since they are likely zero anyway.
// Higher bits are more significant in 64 bit builds.
return reinterpret_cast<UPTRINT>(Key) >> 4;
#else
return reinterpret_cast<UPTRINT>(Key);
#endif
};
static inline uint32 HashCombine(uint32 A, uint32 B)
{
return A ^ (B + 0x9e3779b9 + (A << 6) + (A >> 2));
}
} HashKey;
HashKey.Size = Size;
HashKey.Frequencies = ShaderFrequencyBits;
const uint8* ShaderBindingDataPtr = GetData();
for (int32 ShaderBindingsIndex = 0; ShaderBindingsIndex < ShaderLayouts.Num(); ShaderBindingsIndex++)
{
FReadOnlyMeshDrawSingleShaderBindings SingleShaderBindings(ShaderLayouts[ShaderBindingsIndex], ShaderBindingDataPtr);
if (SingleShaderBindings.ParameterMapInfo.LooseParameterBuffers.Num())
{
const uint8* LooseBindings = SingleShaderBindings.GetLooseDataStart();
uint32 Length = SingleShaderBindings.GetLooseDataSizeBytes();
HashKey.LooseParametersHash = uint32(CityHash64((const char*)LooseBindings, Length));
}
FRHISamplerState* const* SamplerBindings = SingleShaderBindings.GetSamplerStart();
for (int32 SamplerIndex = 0; SamplerIndex < SingleShaderBindings.ParameterMapInfo.TextureSamplers.Num(); SamplerIndex++)
{
const FRHIResource* Sampler = SamplerBindings[SamplerIndex];
HashKey.LooseParametersHash = FHashKey::HashCombine(FHashKey::PointerHash(Sampler), HashKey.LooseParametersHash);
}
FRHIResource* const* SrvBindings = SingleShaderBindings.GetSRVStart();
for (int32 SrvIndex = 0; SrvIndex < SingleShaderBindings.ParameterMapInfo.SRVs.Num(); SrvIndex++)
{
const FRHIResource* Srv = SrvBindings[SrvIndex];
HashKey.LooseParametersHash = FHashKey::HashCombine(FHashKey::PointerHash(Srv), HashKey.LooseParametersHash);
}
FRHIUniformBuffer* const* UniformBufferBindings = SingleShaderBindings.GetUniformBufferStart();
for (int32 UniformBufferIndex = 0; UniformBufferIndex < SingleShaderBindings.ParameterMapInfo.UniformBuffers.Num(); UniformBufferIndex++)
{
const FRHIUniformBuffer* UniformBuffer = UniformBufferBindings[UniformBufferIndex];
HashKey.UniformBufferHash = FHashKey::HashCombine(FHashKey::PointerHash(UniformBuffer), HashKey.UniformBufferHash);
}
ShaderBindingDataPtr += ShaderLayouts[ShaderBindingsIndex].GetDataSizeBytes();
}
return uint32(CityHash64((char*)&HashKey, sizeof(FHashKey)));
}
PSO Precache Base Changes (disabled by default) Add PSOPrecache file which wraps engine level PSO structs and functions - FPSOPrecacheParams used to wrap certain parameters which drive the PSO collection (mostly set from components) - IPSOCollector interface used as engine entry to the mesh pass processors in renderer project - FPSOCollectorCreateManager to wrap all statically registered IPSOCollector CreateFuncions - PSOCollectorStats structs and helper functions Add PSOPrecache support to PipelineStateCache: - functions to precache compute and graphics PSOs - functions to check current precache state - FPrecacheGraphicsPipelineCache which wraps all currently precached PSOs IMaterial entry function to PrecachePSOs with given vertex factories and params (implemented by UMaterial & UMaterialInstance) which forwards call to FMaterial and finally the FMaterialShaderMap - FMaterialShaderMap will iterate all registered IPSOCollector to collect all possible PSOs used and forward them to the PipelineStateCache for actual (async) precaching RHI Changes: - Add RHI specific functions to retrieve & compare the FRHIVertexDeclaration and FGraphicsPipelineStateInitializer hash for each RHI - Add helper functions to match RHI*State data by retrieving initializer Minimal vertex factory changes for PSO precaching as prep - actual changes in upcoming CLs MeshPassProcessor base functions to collect PSOs which can be used by all mesh pass processor implemention (actual changes in upcoming CLs) - Cache complete precache data hash of stored minimal PSO so it can be used for fast actual PSO initializer hash computation (full PSO initializer is build at runtime) - Cache if minimal PSO was successfully precache and option to skip draw when PSO is still precaching (disabled by default and doesn't work yet via GPU scene based rendering) - Add helper functions to setup the per mesh pass render target data used during PSO collection Refactor SceneTextureConfig so it can be initialized from an init struct and move all function to setup the internal members from SceneTexture to SceneTextureConfig using the data from the init struct (so it's available in Engine project) Fix GBufferInfo format for velocity target (was always floating point while it should be unorm when not android Make certain helper functions definitions to h file so they can be used everywhere (SupportsNaniteRendering, FTextureRenderTarget2DResource::GetFormat & CreateFlags) #preflight 63189a5a967ffc68fb9044a5 #jira UE-139584 #rb Mihnea.Balta [CL 21907508 by kenzo terelst in ue5-main branch]
2022-09-08 19:34:08 -04:00
bool FMeshDrawCommand::SubmitDrawBegin(
const FMeshDrawCommand& RESTRICT MeshDrawCommand,
const FGraphicsMinimalPipelineStateSet& GraphicsMinimalPipelineStateSet,
FRHIBuffer* ScenePrimitiveIdsBuffer,
int32 PrimitiveIdOffset,
uint32 InstanceFactor,
FRHICommandList& RHICmdList,
FMeshDrawCommandStateCache& RESTRICT StateCache,
bool bAllowSkipDrawCommand)
{
checkSlow(MeshDrawCommand.CachedPipelineId.IsValid());
// GPUCULL_TODO: Can't do this check as the VFs are created with GMaxRHIFeatureLevel (so may support PrimitiveIdStreamIndex even for preview platforms)
// Want to be sure that we supply GPU-scene instance data if required.
// checkSlow(MeshDrawCommand.PrimitiveIdStreamIndex == -1 || ScenePrimitiveIdsBuffer != nullptr);
const FGraphicsMinimalPipelineStateInitializer& MeshPipelineState = MeshDrawCommand.CachedPipelineId.GetPipelineState(GraphicsMinimalPipelineStateSet);
if (MeshDrawCommand.CachedPipelineId.GetId() != StateCache.PipelineId)
{
FGraphicsPipelineStateInitializer GraphicsPSOInit = MeshPipelineState.AsGraphicsPipelineStateInitializer();
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
PSO Precache Base Changes (disabled by default) Add PSOPrecache file which wraps engine level PSO structs and functions - FPSOPrecacheParams used to wrap certain parameters which drive the PSO collection (mostly set from components) - IPSOCollector interface used as engine entry to the mesh pass processors in renderer project - FPSOCollectorCreateManager to wrap all statically registered IPSOCollector CreateFuncions - PSOCollectorStats structs and helper functions Add PSOPrecache support to PipelineStateCache: - functions to precache compute and graphics PSOs - functions to check current precache state - FPrecacheGraphicsPipelineCache which wraps all currently precached PSOs IMaterial entry function to PrecachePSOs with given vertex factories and params (implemented by UMaterial & UMaterialInstance) which forwards call to FMaterial and finally the FMaterialShaderMap - FMaterialShaderMap will iterate all registered IPSOCollector to collect all possible PSOs used and forward them to the PipelineStateCache for actual (async) precaching RHI Changes: - Add RHI specific functions to retrieve & compare the FRHIVertexDeclaration and FGraphicsPipelineStateInitializer hash for each RHI - Add helper functions to match RHI*State data by retrieving initializer Minimal vertex factory changes for PSO precaching as prep - actual changes in upcoming CLs MeshPassProcessor base functions to collect PSOs which can be used by all mesh pass processor implemention (actual changes in upcoming CLs) - Cache complete precache data hash of stored minimal PSO so it can be used for fast actual PSO initializer hash computation (full PSO initializer is build at runtime) - Cache if minimal PSO was successfully precache and option to skip draw when PSO is still precaching (disabled by default and doesn't work yet via GPU scene based rendering) - Add helper functions to setup the per mesh pass render target data used during PSO collection Refactor SceneTextureConfig so it can be initialized from an init struct and move all function to setup the internal members from SceneTexture to SceneTextureConfig using the data from the init struct (so it's available in Engine project) Fix GBufferInfo format for velocity target (was always floating point while it should be unorm when not android Make certain helper functions definitions to h file so they can be used everywhere (SupportsNaniteRendering, FTextureRenderTarget2DResource::GetFormat & CreateFlags) #preflight 63189a5a967ffc68fb9044a5 #jira UE-139584 #rb Mihnea.Balta [CL 21907508 by kenzo terelst in ue5-main branch]
2022-09-08 19:34:08 -04:00
EPSOPrecacheResult PSOPrecacheResult = EPSOPrecacheResult::Unknown;
#if PSO_PRECACHING_VALIDATE
// Retrieve state from cache - can be be cached on the MeshPipelineState to not retrieve it anymore after the final state is known
#if MESH_DRAW_COMMAND_DEBUG_DATA
PSOPrecacheResult = PSOCollectorStats::CheckPipelineStateInCache(GraphicsPSOInit, MeshDrawCommand.DebugData.MeshPassType, MeshDrawCommand.DebugData.VertexFactoryType);
#else
PSOPrecacheResult = PSOCollectorStats::CheckPipelineStateInCache(GraphicsPSOInit, EMeshPass::Num, nullptr);
#endif // MESH_DRAW_COMMAND_DEBUG_DATA
#endif // PSO_PRECACHING_VALIDATE
// Check if skip draw is needed when the PSO is still precaching
if (bAllowSkipDrawCommand && GSkipDrawOnPSOPrecaching && !MeshPipelineState.bPSOPrecached)
PSO Precache Base Changes (disabled by default) Add PSOPrecache file which wraps engine level PSO structs and functions - FPSOPrecacheParams used to wrap certain parameters which drive the PSO collection (mostly set from components) - IPSOCollector interface used as engine entry to the mesh pass processors in renderer project - FPSOCollectorCreateManager to wrap all statically registered IPSOCollector CreateFuncions - PSOCollectorStats structs and helper functions Add PSOPrecache support to PipelineStateCache: - functions to precache compute and graphics PSOs - functions to check current precache state - FPrecacheGraphicsPipelineCache which wraps all currently precached PSOs IMaterial entry function to PrecachePSOs with given vertex factories and params (implemented by UMaterial & UMaterialInstance) which forwards call to FMaterial and finally the FMaterialShaderMap - FMaterialShaderMap will iterate all registered IPSOCollector to collect all possible PSOs used and forward them to the PipelineStateCache for actual (async) precaching RHI Changes: - Add RHI specific functions to retrieve & compare the FRHIVertexDeclaration and FGraphicsPipelineStateInitializer hash for each RHI - Add helper functions to match RHI*State data by retrieving initializer Minimal vertex factory changes for PSO precaching as prep - actual changes in upcoming CLs MeshPassProcessor base functions to collect PSOs which can be used by all mesh pass processor implemention (actual changes in upcoming CLs) - Cache complete precache data hash of stored minimal PSO so it can be used for fast actual PSO initializer hash computation (full PSO initializer is build at runtime) - Cache if minimal PSO was successfully precache and option to skip draw when PSO is still precaching (disabled by default and doesn't work yet via GPU scene based rendering) - Add helper functions to setup the per mesh pass render target data used during PSO collection Refactor SceneTextureConfig so it can be initialized from an init struct and move all function to setup the internal members from SceneTexture to SceneTextureConfig using the data from the init struct (so it's available in Engine project) Fix GBufferInfo format for velocity target (was always floating point while it should be unorm when not android Make certain helper functions definitions to h file so they can be used everywhere (SupportsNaniteRendering, FTextureRenderTarget2DResource::GetFormat & CreateFlags) #preflight 63189a5a967ffc68fb9044a5 #jira UE-139584 #rb Mihnea.Balta [CL 21907508 by kenzo terelst in ue5-main branch]
2022-09-08 19:34:08 -04:00
{
MeshPipelineState.bPSOPrecached = !PipelineStateCache::IsPrecaching(GraphicsPSOInit);
// Try and skip draw if not precached yet
if (!MeshPipelineState.bPSOPrecached)
{
return false;
}
}
// We can set the new StencilRef here to avoid the set below
PSO Precache Base Changes (disabled by default) Add PSOPrecache file which wraps engine level PSO structs and functions - FPSOPrecacheParams used to wrap certain parameters which drive the PSO collection (mostly set from components) - IPSOCollector interface used as engine entry to the mesh pass processors in renderer project - FPSOCollectorCreateManager to wrap all statically registered IPSOCollector CreateFuncions - PSOCollectorStats structs and helper functions Add PSOPrecache support to PipelineStateCache: - functions to precache compute and graphics PSOs - functions to check current precache state - FPrecacheGraphicsPipelineCache which wraps all currently precached PSOs IMaterial entry function to PrecachePSOs with given vertex factories and params (implemented by UMaterial & UMaterialInstance) which forwards call to FMaterial and finally the FMaterialShaderMap - FMaterialShaderMap will iterate all registered IPSOCollector to collect all possible PSOs used and forward them to the PipelineStateCache for actual (async) precaching RHI Changes: - Add RHI specific functions to retrieve & compare the FRHIVertexDeclaration and FGraphicsPipelineStateInitializer hash for each RHI - Add helper functions to match RHI*State data by retrieving initializer Minimal vertex factory changes for PSO precaching as prep - actual changes in upcoming CLs MeshPassProcessor base functions to collect PSOs which can be used by all mesh pass processor implemention (actual changes in upcoming CLs) - Cache complete precache data hash of stored minimal PSO so it can be used for fast actual PSO initializer hash computation (full PSO initializer is build at runtime) - Cache if minimal PSO was successfully precache and option to skip draw when PSO is still precaching (disabled by default and doesn't work yet via GPU scene based rendering) - Add helper functions to setup the per mesh pass render target data used during PSO collection Refactor SceneTextureConfig so it can be initialized from an init struct and move all function to setup the internal members from SceneTexture to SceneTextureConfig using the data from the init struct (so it's available in Engine project) Fix GBufferInfo format for velocity target (was always floating point while it should be unorm when not android Make certain helper functions definitions to h file so they can be used everywhere (SupportsNaniteRendering, FTextureRenderTarget2DResource::GetFormat & CreateFlags) #preflight 63189a5a967ffc68fb9044a5 #jira UE-139584 #rb Mihnea.Balta [CL 21907508 by kenzo terelst in ue5-main branch]
2022-09-08 19:34:08 -04:00
bool bApplyAdditionalState = true;
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, MeshDrawCommand.StencilRef, EApplyRendertargetOption::CheckApply, bApplyAdditionalState, PSOPrecacheResult);
StateCache.SetPipelineState(MeshDrawCommand.CachedPipelineId.GetId());
StateCache.StencilRef = MeshDrawCommand.StencilRef;
}
if (MeshDrawCommand.StencilRef != StateCache.StencilRef)
{
RHICmdList.SetStencilRef(MeshDrawCommand.StencilRef);
StateCache.StencilRef = MeshDrawCommand.StencilRef;
}
for (int32 VertexBindingIndex = 0; VertexBindingIndex < MeshDrawCommand.VertexStreams.Num(); VertexBindingIndex++)
{
const FVertexInputStream& Stream = MeshDrawCommand.VertexStreams[VertexBindingIndex];
if (MeshDrawCommand.PrimitiveIdStreamIndex != -1 && Stream.StreamIndex == MeshDrawCommand.PrimitiveIdStreamIndex)
{
RHICmdList.SetStreamSource(Stream.StreamIndex, ScenePrimitiveIdsBuffer, PrimitiveIdOffset);
StateCache.VertexStreams[Stream.StreamIndex] = Stream;
}
else if (StateCache.VertexStreams[Stream.StreamIndex] != Stream)
{
RHICmdList.SetStreamSource(Stream.StreamIndex, Stream.VertexBuffer, Stream.Offset);
StateCache.VertexStreams[Stream.StreamIndex] = Stream;
}
}
MeshDrawCommand.ShaderBindings.SetOnCommandList(RHICmdList, MeshPipelineState.BoundShaderState.AsBoundShaderState(), StateCache.ShaderBindings);
PSO Precache Base Changes (disabled by default) Add PSOPrecache file which wraps engine level PSO structs and functions - FPSOPrecacheParams used to wrap certain parameters which drive the PSO collection (mostly set from components) - IPSOCollector interface used as engine entry to the mesh pass processors in renderer project - FPSOCollectorCreateManager to wrap all statically registered IPSOCollector CreateFuncions - PSOCollectorStats structs and helper functions Add PSOPrecache support to PipelineStateCache: - functions to precache compute and graphics PSOs - functions to check current precache state - FPrecacheGraphicsPipelineCache which wraps all currently precached PSOs IMaterial entry function to PrecachePSOs with given vertex factories and params (implemented by UMaterial & UMaterialInstance) which forwards call to FMaterial and finally the FMaterialShaderMap - FMaterialShaderMap will iterate all registered IPSOCollector to collect all possible PSOs used and forward them to the PipelineStateCache for actual (async) precaching RHI Changes: - Add RHI specific functions to retrieve & compare the FRHIVertexDeclaration and FGraphicsPipelineStateInitializer hash for each RHI - Add helper functions to match RHI*State data by retrieving initializer Minimal vertex factory changes for PSO precaching as prep - actual changes in upcoming CLs MeshPassProcessor base functions to collect PSOs which can be used by all mesh pass processor implemention (actual changes in upcoming CLs) - Cache complete precache data hash of stored minimal PSO so it can be used for fast actual PSO initializer hash computation (full PSO initializer is build at runtime) - Cache if minimal PSO was successfully precache and option to skip draw when PSO is still precaching (disabled by default and doesn't work yet via GPU scene based rendering) - Add helper functions to setup the per mesh pass render target data used during PSO collection Refactor SceneTextureConfig so it can be initialized from an init struct and move all function to setup the internal members from SceneTexture to SceneTextureConfig using the data from the init struct (so it's available in Engine project) Fix GBufferInfo format for velocity target (was always floating point while it should be unorm when not android Make certain helper functions definitions to h file so they can be used everywhere (SupportsNaniteRendering, FTextureRenderTarget2DResource::GetFormat & CreateFlags) #preflight 63189a5a967ffc68fb9044a5 #jira UE-139584 #rb Mihnea.Balta [CL 21907508 by kenzo terelst in ue5-main branch]
2022-09-08 19:34:08 -04:00
return true;
}
void FMeshDrawCommand::SubmitDrawEnd(const FMeshDrawCommand& MeshDrawCommand, uint32 InstanceFactor, FRHICommandList& RHICmdList,
FRHIBuffer* IndirectArgsOverrideBuffer,
uint32 IndirectArgsOverrideByteOffset)
{
const bool bDoOverrideArgs = IndirectArgsOverrideBuffer != nullptr && MeshDrawCommand.PrimitiveIdStreamIndex >= 0;
if (MeshDrawCommand.IndexBuffer)
{
if (MeshDrawCommand.NumPrimitives > 0 && !bDoOverrideArgs)
{
RHICmdList.DrawIndexedPrimitive(
MeshDrawCommand.IndexBuffer,
MeshDrawCommand.VertexParams.BaseVertexIndex,
0,
MeshDrawCommand.VertexParams.NumVertices,
MeshDrawCommand.FirstIndex,
MeshDrawCommand.NumPrimitives,
MeshDrawCommand.NumInstances * InstanceFactor
);
}
else
{
RHICmdList.DrawIndexedPrimitiveIndirect(
MeshDrawCommand.IndexBuffer,
bDoOverrideArgs ? IndirectArgsOverrideBuffer : MeshDrawCommand.IndirectArgs.Buffer,
bDoOverrideArgs ? IndirectArgsOverrideByteOffset : MeshDrawCommand.IndirectArgs.Offset
);
}
}
else
{
if (MeshDrawCommand.NumPrimitives > 0 && !bDoOverrideArgs)
{
RHICmdList.DrawPrimitive(
MeshDrawCommand.VertexParams.BaseVertexIndex + MeshDrawCommand.FirstIndex,
MeshDrawCommand.NumPrimitives,
MeshDrawCommand.NumInstances * InstanceFactor);
}
else
{
RHICmdList.DrawPrimitiveIndirect(
bDoOverrideArgs ? IndirectArgsOverrideBuffer : MeshDrawCommand.IndirectArgs.Buffer,
bDoOverrideArgs ? IndirectArgsOverrideByteOffset : MeshDrawCommand.IndirectArgs.Offset
);
}
}
}
PSO Precache Base Changes (disabled by default) Add PSOPrecache file which wraps engine level PSO structs and functions - FPSOPrecacheParams used to wrap certain parameters which drive the PSO collection (mostly set from components) - IPSOCollector interface used as engine entry to the mesh pass processors in renderer project - FPSOCollectorCreateManager to wrap all statically registered IPSOCollector CreateFuncions - PSOCollectorStats structs and helper functions Add PSOPrecache support to PipelineStateCache: - functions to precache compute and graphics PSOs - functions to check current precache state - FPrecacheGraphicsPipelineCache which wraps all currently precached PSOs IMaterial entry function to PrecachePSOs with given vertex factories and params (implemented by UMaterial & UMaterialInstance) which forwards call to FMaterial and finally the FMaterialShaderMap - FMaterialShaderMap will iterate all registered IPSOCollector to collect all possible PSOs used and forward them to the PipelineStateCache for actual (async) precaching RHI Changes: - Add RHI specific functions to retrieve & compare the FRHIVertexDeclaration and FGraphicsPipelineStateInitializer hash for each RHI - Add helper functions to match RHI*State data by retrieving initializer Minimal vertex factory changes for PSO precaching as prep - actual changes in upcoming CLs MeshPassProcessor base functions to collect PSOs which can be used by all mesh pass processor implemention (actual changes in upcoming CLs) - Cache complete precache data hash of stored minimal PSO so it can be used for fast actual PSO initializer hash computation (full PSO initializer is build at runtime) - Cache if minimal PSO was successfully precache and option to skip draw when PSO is still precaching (disabled by default and doesn't work yet via GPU scene based rendering) - Add helper functions to setup the per mesh pass render target data used during PSO collection Refactor SceneTextureConfig so it can be initialized from an init struct and move all function to setup the internal members from SceneTexture to SceneTextureConfig using the data from the init struct (so it's available in Engine project) Fix GBufferInfo format for velocity target (was always floating point while it should be unorm when not android Make certain helper functions definitions to h file so they can be used everywhere (SupportsNaniteRendering, FTextureRenderTarget2DResource::GetFormat & CreateFlags) #preflight 63189a5a967ffc68fb9044a5 #jira UE-139584 #rb Mihnea.Balta [CL 21907508 by kenzo terelst in ue5-main branch]
2022-09-08 19:34:08 -04:00
bool FMeshDrawCommand::SubmitDrawIndirectBegin(
const FMeshDrawCommand& RESTRICT MeshDrawCommand,
const FGraphicsMinimalPipelineStateSet& GraphicsMinimalPipelineStateSet,
FRHIBuffer* ScenePrimitiveIdsBuffer,
int32 PrimitiveIdOffset,
uint32 InstanceFactor,
FRHICommandList& RHICmdList,
FMeshDrawCommandStateCache& RESTRICT StateCache,
bool bAllowSkipDrawCommand)
{
PSO Precache Base Changes (disabled by default) Add PSOPrecache file which wraps engine level PSO structs and functions - FPSOPrecacheParams used to wrap certain parameters which drive the PSO collection (mostly set from components) - IPSOCollector interface used as engine entry to the mesh pass processors in renderer project - FPSOCollectorCreateManager to wrap all statically registered IPSOCollector CreateFuncions - PSOCollectorStats structs and helper functions Add PSOPrecache support to PipelineStateCache: - functions to precache compute and graphics PSOs - functions to check current precache state - FPrecacheGraphicsPipelineCache which wraps all currently precached PSOs IMaterial entry function to PrecachePSOs with given vertex factories and params (implemented by UMaterial & UMaterialInstance) which forwards call to FMaterial and finally the FMaterialShaderMap - FMaterialShaderMap will iterate all registered IPSOCollector to collect all possible PSOs used and forward them to the PipelineStateCache for actual (async) precaching RHI Changes: - Add RHI specific functions to retrieve & compare the FRHIVertexDeclaration and FGraphicsPipelineStateInitializer hash for each RHI - Add helper functions to match RHI*State data by retrieving initializer Minimal vertex factory changes for PSO precaching as prep - actual changes in upcoming CLs MeshPassProcessor base functions to collect PSOs which can be used by all mesh pass processor implemention (actual changes in upcoming CLs) - Cache complete precache data hash of stored minimal PSO so it can be used for fast actual PSO initializer hash computation (full PSO initializer is build at runtime) - Cache if minimal PSO was successfully precache and option to skip draw when PSO is still precaching (disabled by default and doesn't work yet via GPU scene based rendering) - Add helper functions to setup the per mesh pass render target data used during PSO collection Refactor SceneTextureConfig so it can be initialized from an init struct and move all function to setup the internal members from SceneTexture to SceneTextureConfig using the data from the init struct (so it's available in Engine project) Fix GBufferInfo format for velocity target (was always floating point while it should be unorm when not android Make certain helper functions definitions to h file so they can be used everywhere (SupportsNaniteRendering, FTextureRenderTarget2DResource::GetFormat & CreateFlags) #preflight 63189a5a967ffc68fb9044a5 #jira UE-139584 #rb Mihnea.Balta [CL 21907508 by kenzo terelst in ue5-main branch]
2022-09-08 19:34:08 -04:00
return SubmitDrawBegin(
MeshDrawCommand,
GraphicsMinimalPipelineStateSet,
ScenePrimitiveIdsBuffer,
PrimitiveIdOffset,
InstanceFactor,
RHICmdList,
StateCache,
bAllowSkipDrawCommand
);
}
void FMeshDrawCommand::SubmitDrawIndirectEnd(
const FMeshDrawCommand& MeshDrawCommand,
uint32 InstanceFactor,
FRHICommandList& RHICmdList,
FRHIBuffer* IndirectArgsOverrideBuffer,
uint32 IndirectArgsOverrideByteOffset)
{
FRHIBuffer* IndirectArgsBuffer = nullptr;
uint32 IndirectArgsOffset = 0;
if (MeshDrawCommand.NumPrimitives == 0)
{
IndirectArgsBuffer = MeshDrawCommand.IndirectArgs.Buffer;
IndirectArgsOffset = MeshDrawCommand.IndirectArgs.Offset;
}
if (IndirectArgsOverrideBuffer != nullptr)
{
IndirectArgsBuffer = IndirectArgsOverrideBuffer;
IndirectArgsOffset = IndirectArgsOverrideByteOffset;
}
if (IndirectArgsBuffer != nullptr)
{
if (MeshDrawCommand.IndexBuffer)
{
RHICmdList.DrawIndexedPrimitiveIndirect(
MeshDrawCommand.IndexBuffer,
IndirectArgsBuffer,
IndirectArgsOffset
);
}
else
{
RHICmdList.DrawPrimitiveIndirect(
IndirectArgsBuffer,
IndirectArgsOffset
);
}
}
else if (MeshDrawCommand.NumPrimitives > 0)
{
if (MeshDrawCommand.IndexBuffer)
{
RHICmdList.DrawIndexedPrimitive(
MeshDrawCommand.IndexBuffer,
MeshDrawCommand.VertexParams.BaseVertexIndex,
0,
MeshDrawCommand.VertexParams.NumVertices,
MeshDrawCommand.FirstIndex,
MeshDrawCommand.NumPrimitives,
MeshDrawCommand.NumInstances * InstanceFactor
);
}
else
{
RHICmdList.DrawPrimitive(
MeshDrawCommand.VertexParams.BaseVertexIndex + MeshDrawCommand.FirstIndex,
MeshDrawCommand.NumPrimitives,
MeshDrawCommand.NumInstances * InstanceFactor
);
}
}
}
void FMeshDrawCommand::SubmitDraw(
const FMeshDrawCommand& RESTRICT MeshDrawCommand,
const FGraphicsMinimalPipelineStateSet& GraphicsMinimalPipelineStateSet,
FRHIBuffer* ScenePrimitiveIdsBuffer,
int32 PrimitiveIdOffset,
uint32 InstanceFactor,
FRHICommandList& RHICmdList,
FMeshDrawCommandStateCache& RESTRICT StateCache,
FRHIBuffer* IndirectArgsOverrideBuffer,
uint32 IndirectArgsOverrideByteOffset)
{
#if MESH_DRAW_COMMAND_DEBUG_DATA && RHI_WANT_BREADCRUMB_EVENTS
if (MeshDrawCommand.DebugData.ResourceName.IsValid())
{
TCHAR NameBuffer[FName::StringBufferSize];
const uint32 NameLen = MeshDrawCommand.DebugData.ResourceName.ToString(NameBuffer);
BREADCRUMB_EVENTF(RHICmdList, MeshDrawCommand, TEXT("%s %.*s"), *MeshDrawCommand.DebugData.MaterialName, NameLen, NameBuffer);
}
else
{
BREADCRUMB_EVENTF(RHICmdList, MeshDrawCommand, TEXT("%s"), *MeshDrawCommand.DebugData.MaterialName);
}
#endif
#if WANTS_DRAW_MESH_EVENTS
FMeshDrawEvent MeshEvent(MeshDrawCommand, InstanceFactor, RHICmdList);
#endif
bool bAllowSkipDrawCommand = true;
if (SubmitDrawBegin(MeshDrawCommand, GraphicsMinimalPipelineStateSet, ScenePrimitiveIdsBuffer, PrimitiveIdOffset, InstanceFactor, RHICmdList, StateCache, bAllowSkipDrawCommand))
PSO Precache Base Changes (disabled by default) Add PSOPrecache file which wraps engine level PSO structs and functions - FPSOPrecacheParams used to wrap certain parameters which drive the PSO collection (mostly set from components) - IPSOCollector interface used as engine entry to the mesh pass processors in renderer project - FPSOCollectorCreateManager to wrap all statically registered IPSOCollector CreateFuncions - PSOCollectorStats structs and helper functions Add PSOPrecache support to PipelineStateCache: - functions to precache compute and graphics PSOs - functions to check current precache state - FPrecacheGraphicsPipelineCache which wraps all currently precached PSOs IMaterial entry function to PrecachePSOs with given vertex factories and params (implemented by UMaterial & UMaterialInstance) which forwards call to FMaterial and finally the FMaterialShaderMap - FMaterialShaderMap will iterate all registered IPSOCollector to collect all possible PSOs used and forward them to the PipelineStateCache for actual (async) precaching RHI Changes: - Add RHI specific functions to retrieve & compare the FRHIVertexDeclaration and FGraphicsPipelineStateInitializer hash for each RHI - Add helper functions to match RHI*State data by retrieving initializer Minimal vertex factory changes for PSO precaching as prep - actual changes in upcoming CLs MeshPassProcessor base functions to collect PSOs which can be used by all mesh pass processor implemention (actual changes in upcoming CLs) - Cache complete precache data hash of stored minimal PSO so it can be used for fast actual PSO initializer hash computation (full PSO initializer is build at runtime) - Cache if minimal PSO was successfully precache and option to skip draw when PSO is still precaching (disabled by default and doesn't work yet via GPU scene based rendering) - Add helper functions to setup the per mesh pass render target data used during PSO collection Refactor SceneTextureConfig so it can be initialized from an init struct and move all function to setup the internal members from SceneTexture to SceneTextureConfig using the data from the init struct (so it's available in Engine project) Fix GBufferInfo format for velocity target (was always floating point while it should be unorm when not android Make certain helper functions definitions to h file so they can be used everywhere (SupportsNaniteRendering, FTextureRenderTarget2DResource::GetFormat & CreateFlags) #preflight 63189a5a967ffc68fb9044a5 #jira UE-139584 #rb Mihnea.Balta [CL 21907508 by kenzo terelst in ue5-main branch]
2022-09-08 19:34:08 -04:00
{
SubmitDrawEnd(MeshDrawCommand, InstanceFactor, RHICmdList, IndirectArgsOverrideBuffer, IndirectArgsOverrideByteOffset);
}
}
PSO Precache Base Changes (disabled by default) Add PSOPrecache file which wraps engine level PSO structs and functions - FPSOPrecacheParams used to wrap certain parameters which drive the PSO collection (mostly set from components) - IPSOCollector interface used as engine entry to the mesh pass processors in renderer project - FPSOCollectorCreateManager to wrap all statically registered IPSOCollector CreateFuncions - PSOCollectorStats structs and helper functions Add PSOPrecache support to PipelineStateCache: - functions to precache compute and graphics PSOs - functions to check current precache state - FPrecacheGraphicsPipelineCache which wraps all currently precached PSOs IMaterial entry function to PrecachePSOs with given vertex factories and params (implemented by UMaterial & UMaterialInstance) which forwards call to FMaterial and finally the FMaterialShaderMap - FMaterialShaderMap will iterate all registered IPSOCollector to collect all possible PSOs used and forward them to the PipelineStateCache for actual (async) precaching RHI Changes: - Add RHI specific functions to retrieve & compare the FRHIVertexDeclaration and FGraphicsPipelineStateInitializer hash for each RHI - Add helper functions to match RHI*State data by retrieving initializer Minimal vertex factory changes for PSO precaching as prep - actual changes in upcoming CLs MeshPassProcessor base functions to collect PSOs which can be used by all mesh pass processor implemention (actual changes in upcoming CLs) - Cache complete precache data hash of stored minimal PSO so it can be used for fast actual PSO initializer hash computation (full PSO initializer is build at runtime) - Cache if minimal PSO was successfully precache and option to skip draw when PSO is still precaching (disabled by default and doesn't work yet via GPU scene based rendering) - Add helper functions to setup the per mesh pass render target data used during PSO collection Refactor SceneTextureConfig so it can be initialized from an init struct and move all function to setup the internal members from SceneTexture to SceneTextureConfig using the data from the init struct (so it's available in Engine project) Fix GBufferInfo format for velocity target (was always floating point while it should be unorm when not android Make certain helper functions definitions to h file so they can be used everywhere (SupportsNaniteRendering, FTextureRenderTarget2DResource::GetFormat & CreateFlags) #preflight 63189a5a967ffc68fb9044a5 #jira UE-139584 #rb Mihnea.Balta [CL 21907508 by kenzo terelst in ue5-main branch]
2022-09-08 19:34:08 -04:00
void ApplyTargetsInfo(FGraphicsPipelineStateInitializer& GraphicsPSOInit, const FGraphicsPipelineRenderTargetsInfo& RenderTargetsInfo)
{
GraphicsPSOInit.RenderTargetsEnabled = RenderTargetsInfo.RenderTargetsEnabled;
GraphicsPSOInit.RenderTargetFormats = RenderTargetsInfo.RenderTargetFormats;
GraphicsPSOInit.RenderTargetFlags = RenderTargetsInfo.RenderTargetFlags;
GraphicsPSOInit.NumSamples = RenderTargetsInfo.NumSamples;
GraphicsPSOInit.DepthStencilTargetFormat = RenderTargetsInfo.DepthStencilTargetFormat;
GraphicsPSOInit.DepthStencilTargetFlag = RenderTargetsInfo.DepthStencilTargetFlag;
GraphicsPSOInit.DepthTargetLoadAction = RenderTargetsInfo.DepthTargetLoadAction;
GraphicsPSOInit.DepthTargetStoreAction = RenderTargetsInfo.DepthTargetStoreAction;
GraphicsPSOInit.StencilTargetLoadAction = RenderTargetsInfo.StencilTargetLoadAction;
GraphicsPSOInit.StencilTargetStoreAction = RenderTargetsInfo.StencilTargetStoreAction;
GraphicsPSOInit.DepthStencilAccess = RenderTargetsInfo.DepthStencilAccess;
GraphicsPSOInit.MultiViewCount = RenderTargetsInfo.MultiViewCount;
GraphicsPSOInit.bHasFragmentDensityAttachment = RenderTargetsInfo.bHasFragmentDensityAttachment;
}
uint64 FMeshDrawCommand::GetPipelineStateSortingKey(FRHICommandList& RHICmdList, const FGraphicsPipelineRenderTargetsInfo& RenderTargetsInfo) const
{
// Default fallback sort key
uint64 SortKey = CachedPipelineId.GetId();
if (GRHISupportsPipelineStateSortKey)
{
FGraphicsMinimalPipelineStateSet PipelineStateSet;
FGraphicsPipelineStateInitializer GraphicsPSOInit = CachedPipelineId.GetPipelineState(PipelineStateSet).AsGraphicsPipelineStateInitializer();
ApplyTargetsInfo(GraphicsPSOInit, RenderTargetsInfo);
PSO Precache Base Changes (disabled by default) Add PSOPrecache file which wraps engine level PSO structs and functions - FPSOPrecacheParams used to wrap certain parameters which drive the PSO collection (mostly set from components) - IPSOCollector interface used as engine entry to the mesh pass processors in renderer project - FPSOCollectorCreateManager to wrap all statically registered IPSOCollector CreateFuncions - PSOCollectorStats structs and helper functions Add PSOPrecache support to PipelineStateCache: - functions to precache compute and graphics PSOs - functions to check current precache state - FPrecacheGraphicsPipelineCache which wraps all currently precached PSOs IMaterial entry function to PrecachePSOs with given vertex factories and params (implemented by UMaterial & UMaterialInstance) which forwards call to FMaterial and finally the FMaterialShaderMap - FMaterialShaderMap will iterate all registered IPSOCollector to collect all possible PSOs used and forward them to the PipelineStateCache for actual (async) precaching RHI Changes: - Add RHI specific functions to retrieve & compare the FRHIVertexDeclaration and FGraphicsPipelineStateInitializer hash for each RHI - Add helper functions to match RHI*State data by retrieving initializer Minimal vertex factory changes for PSO precaching as prep - actual changes in upcoming CLs MeshPassProcessor base functions to collect PSOs which can be used by all mesh pass processor implemention (actual changes in upcoming CLs) - Cache complete precache data hash of stored minimal PSO so it can be used for fast actual PSO initializer hash computation (full PSO initializer is build at runtime) - Cache if minimal PSO was successfully precache and option to skip draw when PSO is still precaching (disabled by default and doesn't work yet via GPU scene based rendering) - Add helper functions to setup the per mesh pass render target data used during PSO collection Refactor SceneTextureConfig so it can be initialized from an init struct and move all function to setup the internal members from SceneTexture to SceneTextureConfig using the data from the init struct (so it's available in Engine project) Fix GBufferInfo format for velocity target (was always floating point while it should be unorm when not android Make certain helper functions definitions to h file so they can be used everywhere (SupportsNaniteRendering, FTextureRenderTarget2DResource::GetFormat & CreateFlags) #preflight 63189a5a967ffc68fb9044a5 #jira UE-139584 #rb Mihnea.Balta [CL 21907508 by kenzo terelst in ue5-main branch]
2022-09-08 19:34:08 -04:00
// PSO is retrieved here already. This is currently only used by Nanite::DrawLumenMeshCards - can this also used the version without command list?
const FGraphicsPipelineState* PipelineState = PipelineStateCache::GetAndOrCreateGraphicsPipelineState(RHICmdList, GraphicsPSOInit, EApplyRendertargetOption::DoNothing, EPSOPrecacheResult::Unknown);
if (PipelineState)
{
const uint64 StateSortKey = PipelineStateCache::RetrieveGraphicsPipelineStateSortKey(PipelineState);
if (StateSortKey != 0) // 0 on the first occurrence (prior to caching), so these commands will fall back on shader id for sorting.
{
SortKey = StateSortKey;
}
}
}
return SortKey;
}
uint64 FMeshDrawCommand::GetPipelineStateSortingKey(const FGraphicsPipelineRenderTargetsInfo& RenderTargetsInfo) const
{
// Default fallback sort key
uint64 SortKey = CachedPipelineId.GetId();
if (GRHISupportsPipelineStateSortKey)
{
FGraphicsMinimalPipelineStateSet PipelineStateSet;
FGraphicsPipelineStateInitializer GraphicsPSOInit = CachedPipelineId.GetPipelineState(PipelineStateSet).AsGraphicsPipelineStateInitializer();
ApplyTargetsInfo(GraphicsPSOInit, RenderTargetsInfo);
const FGraphicsPipelineState* PipelineState = PipelineStateCache::FindGraphicsPipelineState(GraphicsPSOInit);
if (PipelineState)
{
const uint64 StateSortKey = PipelineStateCache::RetrieveGraphicsPipelineStateSortKey(PipelineState);
if (StateSortKey != 0) // 0 on the first occurrence (prior to caching), so these commands will fall back on shader id for sorting.
{
SortKey = StateSortKey;
}
}
}
return SortKey;
}
#if MESH_DRAW_COMMAND_DEBUG_DATA
PSO Precache Base Changes (disabled by default) Add PSOPrecache file which wraps engine level PSO structs and functions - FPSOPrecacheParams used to wrap certain parameters which drive the PSO collection (mostly set from components) - IPSOCollector interface used as engine entry to the mesh pass processors in renderer project - FPSOCollectorCreateManager to wrap all statically registered IPSOCollector CreateFuncions - PSOCollectorStats structs and helper functions Add PSOPrecache support to PipelineStateCache: - functions to precache compute and graphics PSOs - functions to check current precache state - FPrecacheGraphicsPipelineCache which wraps all currently precached PSOs IMaterial entry function to PrecachePSOs with given vertex factories and params (implemented by UMaterial & UMaterialInstance) which forwards call to FMaterial and finally the FMaterialShaderMap - FMaterialShaderMap will iterate all registered IPSOCollector to collect all possible PSOs used and forward them to the PipelineStateCache for actual (async) precaching RHI Changes: - Add RHI specific functions to retrieve & compare the FRHIVertexDeclaration and FGraphicsPipelineStateInitializer hash for each RHI - Add helper functions to match RHI*State data by retrieving initializer Minimal vertex factory changes for PSO precaching as prep - actual changes in upcoming CLs MeshPassProcessor base functions to collect PSOs which can be used by all mesh pass processor implemention (actual changes in upcoming CLs) - Cache complete precache data hash of stored minimal PSO so it can be used for fast actual PSO initializer hash computation (full PSO initializer is build at runtime) - Cache if minimal PSO was successfully precache and option to skip draw when PSO is still precaching (disabled by default and doesn't work yet via GPU scene based rendering) - Add helper functions to setup the per mesh pass render target data used during PSO collection Refactor SceneTextureConfig so it can be initialized from an init struct and move all function to setup the internal members from SceneTexture to SceneTextureConfig using the data from the init struct (so it's available in Engine project) Fix GBufferInfo format for velocity target (was always floating point while it should be unorm when not android Make certain helper functions definitions to h file so they can be used everywhere (SupportsNaniteRendering, FTextureRenderTarget2DResource::GetFormat & CreateFlags) #preflight 63189a5a967ffc68fb9044a5 #jira UE-139584 #rb Mihnea.Balta [CL 21907508 by kenzo terelst in ue5-main branch]
2022-09-08 19:34:08 -04:00
void FMeshDrawCommand::SetDebugData(const FPrimitiveSceneProxy* PrimitiveSceneProxy, const FMaterial* Material, const FMaterialRenderProxy* MaterialRenderProxy, const FMeshProcessorShaders& UntypedShaders, const FVertexFactory* VertexFactory, uint32 MeshPassType)
{
DebugData.PrimitiveSceneProxyIfNotUsingStateBuckets = PrimitiveSceneProxy;
DebugData.MaterialRenderProxy = MaterialRenderProxy;
DebugData.VertexShader = UntypedShaders.VertexShader;
DebugData.PixelShader = UntypedShaders.PixelShader;
DebugData.VertexFactory = VertexFactory;
PSO Precache Base Changes (disabled by default) Add PSOPrecache file which wraps engine level PSO structs and functions - FPSOPrecacheParams used to wrap certain parameters which drive the PSO collection (mostly set from components) - IPSOCollector interface used as engine entry to the mesh pass processors in renderer project - FPSOCollectorCreateManager to wrap all statically registered IPSOCollector CreateFuncions - PSOCollectorStats structs and helper functions Add PSOPrecache support to PipelineStateCache: - functions to precache compute and graphics PSOs - functions to check current precache state - FPrecacheGraphicsPipelineCache which wraps all currently precached PSOs IMaterial entry function to PrecachePSOs with given vertex factories and params (implemented by UMaterial & UMaterialInstance) which forwards call to FMaterial and finally the FMaterialShaderMap - FMaterialShaderMap will iterate all registered IPSOCollector to collect all possible PSOs used and forward them to the PipelineStateCache for actual (async) precaching RHI Changes: - Add RHI specific functions to retrieve & compare the FRHIVertexDeclaration and FGraphicsPipelineStateInitializer hash for each RHI - Add helper functions to match RHI*State data by retrieving initializer Minimal vertex factory changes for PSO precaching as prep - actual changes in upcoming CLs MeshPassProcessor base functions to collect PSOs which can be used by all mesh pass processor implemention (actual changes in upcoming CLs) - Cache complete precache data hash of stored minimal PSO so it can be used for fast actual PSO initializer hash computation (full PSO initializer is build at runtime) - Cache if minimal PSO was successfully precache and option to skip draw when PSO is still precaching (disabled by default and doesn't work yet via GPU scene based rendering) - Add helper functions to setup the per mesh pass render target data used during PSO collection Refactor SceneTextureConfig so it can be initialized from an init struct and move all function to setup the internal members from SceneTexture to SceneTextureConfig using the data from the init struct (so it's available in Engine project) Fix GBufferInfo format for velocity target (was always floating point while it should be unorm when not android Make certain helper functions definitions to h file so they can be used everywhere (SupportsNaniteRendering, FTextureRenderTarget2DResource::GetFormat & CreateFlags) #preflight 63189a5a967ffc68fb9044a5 #jira UE-139584 #rb Mihnea.Balta [CL 21907508 by kenzo terelst in ue5-main branch]
2022-09-08 19:34:08 -04:00
DebugData.VertexFactoryType = VertexFactory->GetType();
DebugData.MeshPassType = MeshPassType;
DebugData.ResourceName = PrimitiveSceneProxy ? PrimitiveSceneProxy->GetResourceName() : FName();
DebugData.MaterialName = Material->GetAssetName();
}
#endif
void SubmitMeshDrawCommands(
const FMeshCommandOneFrameArray& VisibleMeshDrawCommands,
const FGraphicsMinimalPipelineStateSet& GraphicsMinimalPipelineStateSet,
FRHIBuffer* PrimitiveIdsBuffer,
uint32 PrimitiveIdBufferStride,
int32 BasePrimitiveIdsOffset,
bool bDynamicInstancing,
uint32 InstanceFactor,
FRHICommandList& RHICmdList)
{
SubmitMeshDrawCommandsRange(VisibleMeshDrawCommands, GraphicsMinimalPipelineStateSet, PrimitiveIdsBuffer, PrimitiveIdBufferStride, BasePrimitiveIdsOffset, bDynamicInstancing, 0, VisibleMeshDrawCommands.Num(), InstanceFactor, RHICmdList);
}
void SubmitMeshDrawCommandsRange(
const FMeshCommandOneFrameArray& VisibleMeshDrawCommands,
const FGraphicsMinimalPipelineStateSet& GraphicsMinimalPipelineStateSet,
FRHIBuffer* PrimitiveIdsBuffer,
uint32 PrimitiveIdBufferStride,
int32 BasePrimitiveIdsOffset,
bool bDynamicInstancing,
int32 StartIndex,
int32 NumMeshDrawCommands,
uint32 InstanceFactor,
FRHICommandList& RHICmdList)
{
// 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.
checkSlow(!bDynamicInstancing);
bDynamicInstancing = false;
FMeshDrawCommandStateCache StateCache;
INC_DWORD_STAT_BY(STAT_MeshDrawCalls, NumMeshDrawCommands);
for (int32 DrawCommandIndex = StartIndex; DrawCommandIndex < StartIndex + NumMeshDrawCommands; DrawCommandIndex++)
{
SCOPED_CONDITIONAL_DRAW_EVENTF(RHICmdList, MeshEvent, GEmitMeshDrawEvent != 0, TEXT("Mesh Draw"));
const FVisibleMeshDrawCommand& VisibleMeshDrawCommand = VisibleMeshDrawCommands[DrawCommandIndex];
const int32 PrimitiveIdBufferOffset = BasePrimitiveIdsOffset + (bDynamicInstancing ? VisibleMeshDrawCommand.PrimitiveIdBufferOffset : DrawCommandIndex) * PrimitiveIdBufferStride;
checkSlow(!bDynamicInstancing || VisibleMeshDrawCommand.PrimitiveIdBufferOffset >= 0);
FMeshDrawCommand::SubmitDraw(*VisibleMeshDrawCommand.MeshDrawCommand, GraphicsMinimalPipelineStateSet, PrimitiveIdsBuffer, PrimitiveIdBufferOffset, InstanceFactor, RHICmdList, StateCache);
}
}
void ApplyViewOverridesToMeshDrawCommands(const FSceneView& View, FMeshCommandOneFrameArray& VisibleMeshDrawCommands, FDynamicMeshDrawCommandStorage& DynamicMeshDrawCommandStorage, FGraphicsMinimalPipelineStateSet& GraphicsMinimalPipelineStateSet, bool& InNeedsShaderInitialisation)
{
if (View.bReverseCulling || View.bRenderSceneTwoSided)
{
const FMeshCommandOneFrameArray& PassVisibleMeshDrawCommands = VisibleMeshDrawCommands;
FMeshCommandOneFrameArray ViewOverriddenMeshCommands;
ViewOverriddenMeshCommands.Empty(PassVisibleMeshDrawCommands.Num());
for (int32 MeshCommandIndex = 0; MeshCommandIndex < PassVisibleMeshDrawCommands.Num(); MeshCommandIndex++)
{
DynamicMeshDrawCommandStorage.MeshDrawCommands.Add(1);
FMeshDrawCommand& NewMeshCommand = DynamicMeshDrawCommandStorage.MeshDrawCommands[DynamicMeshDrawCommandStorage.MeshDrawCommands.Num() - 1];
const FVisibleMeshDrawCommand& VisibleMeshDrawCommand = PassVisibleMeshDrawCommands[MeshCommandIndex];
const FMeshDrawCommand& MeshCommand = *VisibleMeshDrawCommand.MeshDrawCommand;
NewMeshCommand = MeshCommand;
const ERasterizerCullMode LocalCullMode = View.bRenderSceneTwoSided ? CM_None : View.bReverseCulling ? FMeshPassProcessor::InverseCullMode(VisibleMeshDrawCommand.MeshCullMode) : VisibleMeshDrawCommand.MeshCullMode;
FGraphicsMinimalPipelineStateInitializer PipelineState = MeshCommand.CachedPipelineId.GetPipelineState(GraphicsMinimalPipelineStateSet);
PipelineState.RasterizerState = GetStaticRasterizerState<true>(VisibleMeshDrawCommand.MeshFillMode, LocalCullMode);
const FGraphicsMinimalPipelineStateId PipelineId = FGraphicsMinimalPipelineStateId::GetPipelineStateId(PipelineState, GraphicsMinimalPipelineStateSet, InNeedsShaderInitialisation);
NewMeshCommand.Finalize(PipelineId, nullptr);
FVisibleMeshDrawCommand NewVisibleMeshDrawCommand;
NewVisibleMeshDrawCommand.Setup(
&NewMeshCommand,
VisibleMeshDrawCommand.PrimitiveIdInfo,
VisibleMeshDrawCommand.StateBucketId,
VisibleMeshDrawCommand.MeshFillMode,
VisibleMeshDrawCommand.MeshCullMode,
VisibleMeshDrawCommand.Flags,
VisibleMeshDrawCommand.SortKey,
VisibleMeshDrawCommand.RunArray,
VisibleMeshDrawCommand.NumRuns);
ViewOverriddenMeshCommands.Add(NewVisibleMeshDrawCommand);
}
// Replace VisibleMeshDrawCommands
FMemory::Memswap(&VisibleMeshDrawCommands, &ViewOverriddenMeshCommands, sizeof(ViewOverriddenMeshCommands));
}
}
void DrawDynamicMeshPassPrivate(
const FSceneView& View,
FRHICommandList& RHICmdList,
FMeshCommandOneFrameArray& VisibleMeshDrawCommands,
FDynamicMeshDrawCommandStorage& DynamicMeshDrawCommandStorage,
FGraphicsMinimalPipelineStateSet& GraphicsMinimalPipelineStateSet,
bool& InNeedsShaderInitialisation,
uint32 InstanceFactor)
{
if (VisibleMeshDrawCommands.Num() > 0)
{
// 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;
FRHIBuffer* PrimitiveIdVertexBuffer = nullptr;
const uint32 PrimitiveIdBufferStride = FInstanceCullingContext::GetInstanceIdBufferStride(View.GetFeatureLevel());
ApplyViewOverridesToMeshDrawCommands(View, VisibleMeshDrawCommands, DynamicMeshDrawCommandStorage, GraphicsMinimalPipelineStateSet, InNeedsShaderInitialisation);
check(View.bIsViewInfo);
const FViewInfo* ViewInfo = static_cast<const FViewInfo*>(&View);
#if DO_GUARD_SLOW
if (UseGPUScene(View.GetShaderPlatform(), View.GetFeatureLevel()))
{
bool bNeedsGPUSceneData = false;
for (const auto& VisibleMeshDrawCommand : VisibleMeshDrawCommands)
{
bNeedsGPUSceneData = bNeedsGPUSceneData || EnumHasAnyFlags(VisibleMeshDrawCommand.Flags, EFVisibleMeshDrawCommandFlags::HasPrimitiveIdStreamIndex);
}
ensure(!bNeedsGPUSceneData || ViewInfo->CachedViewUniformShaderParameters->PrimitiveSceneData != GIdentityPrimitiveBuffer.PrimitiveSceneDataBufferSRV);
ensure(!bNeedsGPUSceneData || ViewInfo->CachedViewUniformShaderParameters->InstanceSceneData != GIdentityPrimitiveBuffer.InstanceSceneDataBufferSRV);
ensure(!bNeedsGPUSceneData || ViewInfo->CachedViewUniformShaderParameters->InstancePayloadData != GIdentityPrimitiveBuffer.InstancePayloadDataBufferSRV);
}
#endif // DO_GUARD_SLOW
SortAndMergeDynamicPassMeshDrawCommands(View, RHICmdList, VisibleMeshDrawCommands, DynamicMeshDrawCommandStorage, PrimitiveIdVertexBuffer, InstanceFactor, &ViewInfo->DynamicPrimitiveCollector);
SubmitMeshDrawCommandsRange(VisibleMeshDrawCommands, GraphicsMinimalPipelineStateSet, PrimitiveIdVertexBuffer, PrimitiveIdBufferStride, 0, bDynamicInstancing, 0, VisibleMeshDrawCommands.Num(), InstanceFactor, RHICmdList);
}
}
FMeshDrawCommandSortKey CalculateMeshStaticSortKey(const FMeshMaterialShader* VertexShader, const FMeshMaterialShader* PixelShader)
{
FMeshDrawCommandSortKey SortKey;
SortKey.Generic.VertexShaderHash = VertexShader ? VertexShader->GetSortKey() : 0;
SortKey.Generic.PixelShaderHash = PixelShader ? PixelShader->GetSortKey() : 0;
return SortKey;
}
FMeshPassProcessor::FMeshPassProcessor(EMeshPass::Type InMeshPassType, const FScene* InScene, ERHIFeatureLevel::Type InFeatureLevel, const FSceneView* InViewIfDynamicMeshCommand, FMeshPassDrawListContext* InDrawListContext)
: MeshPassType(InMeshPassType)
PSO Precache Base Changes (disabled by default) Add PSOPrecache file which wraps engine level PSO structs and functions - FPSOPrecacheParams used to wrap certain parameters which drive the PSO collection (mostly set from components) - IPSOCollector interface used as engine entry to the mesh pass processors in renderer project - FPSOCollectorCreateManager to wrap all statically registered IPSOCollector CreateFuncions - PSOCollectorStats structs and helper functions Add PSOPrecache support to PipelineStateCache: - functions to precache compute and graphics PSOs - functions to check current precache state - FPrecacheGraphicsPipelineCache which wraps all currently precached PSOs IMaterial entry function to PrecachePSOs with given vertex factories and params (implemented by UMaterial & UMaterialInstance) which forwards call to FMaterial and finally the FMaterialShaderMap - FMaterialShaderMap will iterate all registered IPSOCollector to collect all possible PSOs used and forward them to the PipelineStateCache for actual (async) precaching RHI Changes: - Add RHI specific functions to retrieve & compare the FRHIVertexDeclaration and FGraphicsPipelineStateInitializer hash for each RHI - Add helper functions to match RHI*State data by retrieving initializer Minimal vertex factory changes for PSO precaching as prep - actual changes in upcoming CLs MeshPassProcessor base functions to collect PSOs which can be used by all mesh pass processor implemention (actual changes in upcoming CLs) - Cache complete precache data hash of stored minimal PSO so it can be used for fast actual PSO initializer hash computation (full PSO initializer is build at runtime) - Cache if minimal PSO was successfully precache and option to skip draw when PSO is still precaching (disabled by default and doesn't work yet via GPU scene based rendering) - Add helper functions to setup the per mesh pass render target data used during PSO collection Refactor SceneTextureConfig so it can be initialized from an init struct and move all function to setup the internal members from SceneTexture to SceneTextureConfig using the data from the init struct (so it's available in Engine project) Fix GBufferInfo format for velocity target (was always floating point while it should be unorm when not android Make certain helper functions definitions to h file so they can be used everywhere (SupportsNaniteRendering, FTextureRenderTarget2DResource::GetFormat & CreateFlags) #preflight 63189a5a967ffc68fb9044a5 #jira UE-139584 #rb Mihnea.Balta [CL 21907508 by kenzo terelst in ue5-main branch]
2022-09-08 19:34:08 -04:00
, Scene(InScene)
, FeatureLevel(InFeatureLevel)
, ViewIfDynamicMeshCommand(InViewIfDynamicMeshCommand)
, DrawListContext(InDrawListContext)
{
}
FMeshPassProcessor::FMeshDrawingPolicyOverrideSettings FMeshPassProcessor::ComputeMeshOverrideSettings(const FPSOPrecacheParams& PrecachePSOParams)
{
FMeshDrawingPolicyOverrideSettings OverrideSettings;
OverrideSettings.MeshPrimitiveType = PT_TriangleList;
OverrideSettings.MeshOverrideFlags |= PrecachePSOParams.bDisableBackFaceCulling ? EDrawingPolicyOverrideFlags::TwoSided : EDrawingPolicyOverrideFlags::None;
OverrideSettings.MeshOverrideFlags |= PrecachePSOParams.bReverseCulling ? EDrawingPolicyOverrideFlags::ReverseCullMode : EDrawingPolicyOverrideFlags::None;
return OverrideSettings;
}
FMeshPassProcessor::FMeshDrawingPolicyOverrideSettings FMeshPassProcessor::ComputeMeshOverrideSettings(const FMeshBatch& Mesh)
{
FMeshDrawingPolicyOverrideSettings OverrideSettings;
OverrideSettings.MeshPrimitiveType = (EPrimitiveType)Mesh.Type;
OverrideSettings.MeshOverrideFlags |= Mesh.bDisableBackfaceCulling ? EDrawingPolicyOverrideFlags::TwoSided : EDrawingPolicyOverrideFlags::None;
OverrideSettings.MeshOverrideFlags |= Mesh.bDitheredLODTransition ? EDrawingPolicyOverrideFlags::DitheredLODTransition : EDrawingPolicyOverrideFlags::None;
OverrideSettings.MeshOverrideFlags |= Mesh.bWireframe ? EDrawingPolicyOverrideFlags::Wireframe : EDrawingPolicyOverrideFlags::None;
OverrideSettings.MeshOverrideFlags |= Mesh.ReverseCulling ? EDrawingPolicyOverrideFlags::ReverseCullMode : EDrawingPolicyOverrideFlags::None;
return OverrideSettings;
}
ERasterizerFillMode FMeshPassProcessor::ComputeMeshFillMode(const FMaterial& InMaterialResource, const FMeshDrawingPolicyOverrideSettings& InOverrideSettings)
{
const bool bMaterialResourceIsTwoSided = InMaterialResource.IsTwoSided();
const bool bIsWireframeMaterial = InMaterialResource.IsWireframe() || !!(InOverrideSettings.MeshOverrideFlags & EDrawingPolicyOverrideFlags::Wireframe);
return bIsWireframeMaterial ? FM_Wireframe : FM_Solid;
}
ERasterizerCullMode FMeshPassProcessor::ComputeMeshCullMode(const FMaterial& InMaterialResource, const FMeshDrawingPolicyOverrideSettings& InOverrideSettings)
{
const bool bMaterialResourceIsTwoSided = InMaterialResource.IsTwoSided();
const bool bInTwoSidedOverride = !!(InOverrideSettings.MeshOverrideFlags & EDrawingPolicyOverrideFlags::TwoSided);
const bool bInReverseCullModeOverride = !!(InOverrideSettings.MeshOverrideFlags & EDrawingPolicyOverrideFlags::ReverseCullMode);
const bool bIsTwoSided = (bMaterialResourceIsTwoSided || bInTwoSidedOverride);
const bool bMeshRenderTwoSided = bIsTwoSided || bInTwoSidedOverride;
return bMeshRenderTwoSided ? CM_None : (bInReverseCullModeOverride ? CM_CCW : CM_CW);
}
FMeshDrawCommandPrimitiveIdInfo FMeshPassProcessor::GetDrawCommandPrimitiveId(
const FPrimitiveSceneInfo* RESTRICT PrimitiveSceneInfo,
const FMeshBatchElement& BatchElement) const
{
FMeshDrawCommandPrimitiveIdInfo PrimitiveIdInfo = FMeshDrawCommandPrimitiveIdInfo(0, -1);
if (UseGPUScene(GMaxRHIShaderPlatform, FeatureLevel))
{
if (BatchElement.PrimitiveIdMode == PrimID_FromPrimitiveSceneInfo)
{
ensureMsgf(BatchElement.PrimitiveUniformBufferResource == nullptr, TEXT("PrimitiveUniformBufferResource should not be setup when PrimitiveIdMode == PrimID_FromPrimitiveSceneInfo"));
check(PrimitiveSceneInfo);
PrimitiveIdInfo.DrawPrimitiveId = PrimitiveSceneInfo->GetIndex();
PrimitiveIdInfo.InstanceSceneDataOffset = PrimitiveSceneInfo->GetInstanceSceneDataOffset();
PrimitiveIdInfo.bIsDynamicPrimitive = 0U;
}
else if (BatchElement.PrimitiveIdMode == PrimID_DynamicPrimitiveShaderData && ViewIfDynamicMeshCommand != nullptr)
{
// Mark using GPrimIDDynamicFlag (top bit) as we defer this to later.
PrimitiveIdInfo.DrawPrimitiveId = BatchElement.DynamicPrimitiveIndex | GPrimIDDynamicFlag;
PrimitiveIdInfo.InstanceSceneDataOffset = BatchElement.DynamicPrimitiveInstanceSceneDataOffset;
PrimitiveIdInfo.bIsDynamicPrimitive = 1U;
}
else
{
check(BatchElement.PrimitiveIdMode == PrimID_ForceZero);
}
}
PrimitiveIdInfo.ScenePrimitiveId = PrimitiveSceneInfo ? PrimitiveSceneInfo->GetIndex() : -1;
return PrimitiveIdInfo;
}
bool FMeshPassProcessor::ShouldSkipMeshDrawCommand(const FMeshBatch& RESTRICT MeshBatch, const FPrimitiveSceneProxy* RESTRICT PrimitiveSceneProxy) const
{
bool bSkipMeshDrawCommand = false;
#if WITH_EDITORONLY_DATA
// Support debug mode to render only non-Nanite proxies that incorrectly reference coarse mesh static mesh assets.
if (GNaniteIsolateInvalidCoarseMesh != 0)
{
// Skip everything by default
bSkipMeshDrawCommand = true;
const bool bNaniteProxy = PrimitiveSceneProxy != nullptr && PrimitiveSceneProxy->IsNaniteMesh();
if (!bNaniteProxy && MeshBatch.VertexFactory != nullptr)
{
// Only skip if the referenced static mesh is not a generated Nanite coarse mesh
const bool bIsCoarseProxy = MeshBatch.VertexFactory->IsCoarseProxyMesh();
if (bIsCoarseProxy)
{
bSkipMeshDrawCommand = false;
}
}
}
#endif
return bSkipMeshDrawCommand;
}
FCachedPassMeshDrawListContext::FCachedPassMeshDrawListContext(FScene& InScene)
: Scene(InScene)
, bUseGPUScene(UseGPUScene(GMaxRHIShaderPlatform, GMaxRHIFeatureLevel))
, bUseStateBucketsAuxData(InScene.GetShadingPath() == EShadingPath::Mobile)
{
}
FMeshDrawCommand& FCachedPassMeshDrawListContext::AddCommand(FMeshDrawCommand& Initializer, uint32 NumElements)
{
checkf(CurrMeshPass < EMeshPass::Num, TEXT("BeginMeshPass() must be called before adding commands to this context"));
ensureMsgf(CommandInfo.CommandIndex == -1 && CommandInfo.StateBucketId == -1, TEXT("GetCommandInfoAndReset() wasn't called since the last command was added"));
if (NumElements == 1)
{
return Initializer;
}
else
{
MeshDrawCommandForStateBucketing = Initializer;
return MeshDrawCommandForStateBucketing;
}
}
void FCachedPassMeshDrawListContext::BeginMeshPass(EMeshPass::Type MeshPass)
{
checkf(CurrMeshPass == EMeshPass::Num, TEXT("BeginMeshPass() was called without a matching EndMeshPass()"));
check(MeshPass < EMeshPass::Num);
CurrMeshPass = MeshPass;
}
void FCachedPassMeshDrawListContext::EndMeshPass()
{
checkf(CurrMeshPass < EMeshPass::Num, TEXT("EndMeshPass() was called without matching BeginMeshPass()"));
CurrMeshPass = EMeshPass::Num;
}
FCachedMeshDrawCommandInfo FCachedPassMeshDrawListContext::GetCommandInfoAndReset()
{
FCachedMeshDrawCommandInfo Ret = CommandInfo;
CommandInfo.CommandIndex = -1;
CommandInfo.StateBucketId = -1;
return Ret;
}
void FCachedPassMeshDrawListContext::FinalizeCommandCommon(
const FMeshBatch& MeshBatch,
int32 BatchElementIndex,
ERasterizerFillMode MeshFillMode,
ERasterizerCullMode MeshCullMode,
FMeshDrawCommandSortKey SortKey,
EFVisibleMeshDrawCommandFlags Flags,
const FGraphicsMinimalPipelineStateInitializer& PipelineState,
const FMeshProcessorShaders* ShadersForDebugging,
FMeshDrawCommand& MeshDrawCommand)
{
FGraphicsMinimalPipelineStateId PipelineId = FGraphicsMinimalPipelineStateId::GetPersistentId(PipelineState);
MeshDrawCommand.SetDrawParametersAndFinalize(MeshBatch, BatchElementIndex, PipelineId, ShadersForDebugging);
CommandInfo = FCachedMeshDrawCommandInfo(CurrMeshPass);
CommandInfo.SortKey = SortKey;
CommandInfo.MeshFillMode = MeshFillMode;
CommandInfo.MeshCullMode = MeshCullMode;
CommandInfo.Flags = Flags;
#if MESH_DRAW_COMMAND_DEBUG_DATA
if (bUseGPUScene)
{
MeshDrawCommand.ClearDebugPrimitiveSceneProxy(); //When using State Buckets multiple PrimitiveSceneProxies use the same MeshDrawCommand, so The PrimitiveSceneProxy pointer can't be stored.
}
#endif
#if DO_GUARD_SLOW
if (bUseGPUScene)
{
FMeshDrawCommand MeshDrawCommandDebug = FMeshDrawCommand(MeshDrawCommand);
check(MeshDrawCommandDebug.ShaderBindings.GetDynamicInstancingHash() == MeshDrawCommand.ShaderBindings.GetDynamicInstancingHash());
check(MeshDrawCommandDebug.GetDynamicInstancingHash() == MeshDrawCommand.GetDynamicInstancingHash());
}
if (Scene.GetShadingPath() == EShadingPath::Deferred)
{
ensureMsgf(MeshDrawCommand.VertexStreams.GetAllocatedSize() == 0, TEXT("Cached Mesh Draw command overflows VertexStreams. VertexStream inline size should be tweaked."));
if (CurrMeshPass == EMeshPass::BasePass || CurrMeshPass == EMeshPass::DepthPass || CurrMeshPass == EMeshPass::CSMShadowDepth || CurrMeshPass == EMeshPass::VSMShadowDepth)
{
TArray<EShaderFrequency, TInlineAllocator<SF_NumFrequencies>> ShaderFrequencies;
MeshDrawCommand.ShaderBindings.GetShaderFrequencies(ShaderFrequencies);
int32 DataOffset = 0;
for (int32 i = 0; i < ShaderFrequencies.Num(); i++)
{
FMeshDrawSingleShaderBindings SingleShaderBindings = MeshDrawCommand.ShaderBindings.GetSingleShaderBindings(ShaderFrequencies[i], DataOffset);
if (SingleShaderBindings.GetParameterMapInfo().LooseParameterBuffers.Num() != 0)
{
bAnyLooseParameterBuffers = true;
}
ensureMsgf(SingleShaderBindings.GetParameterMapInfo().SRVs.Num() == 0, TEXT("Cached Mesh Draw command uses individual SRVs. This will break dynamic instancing in performance critical pass. Use Uniform Buffers instead."));
ensureMsgf(SingleShaderBindings.GetParameterMapInfo().TextureSamplers.Num() == 0, TEXT("Cached Mesh Draw command uses individual Texture Samplers. This will break dynamic instancing in performance critical pass. Use Uniform Buffers instead."));
}
}
}
#endif
}
void FCachedPassMeshDrawListContextImmediate::FinalizeCommand(
const FMeshBatch& MeshBatch,
int32 BatchElementIndex,
const FMeshDrawCommandPrimitiveIdInfo& IdInfo,
ERasterizerFillMode MeshFillMode,
ERasterizerCullMode MeshCullMode,
FMeshDrawCommandSortKey SortKey,
EFVisibleMeshDrawCommandFlags Flags,
const FGraphicsMinimalPipelineStateInitializer& PipelineState,
const FMeshProcessorShaders* ShadersForDebugging,
FMeshDrawCommand& MeshDrawCommand)
{
// disabling this by default as it incurs a high cost in perf captures due to sheer volume. Recommendation is to re-enable locally if you need to profile this particular code.
// QUICK_SCOPE_CYCLE_COUNTER(STAT_FinalizeCachedMeshDrawCommand);
FinalizeCommandCommon(
MeshBatch,
BatchElementIndex,
MeshFillMode,
MeshCullMode,
SortKey,
Flags,
PipelineState,
ShadersForDebugging,
MeshDrawCommand
);
if (bUseGPUScene)
{
Experimental::FHashElementId SetId;
FStateBucketMap& BucketMap = Scene.CachedMeshDrawCommandStateBuckets[CurrMeshPass];
auto hash = BucketMap.ComputeHash(MeshDrawCommand);
{
SetId = BucketMap.FindOrAddIdByHash(hash, MeshDrawCommand, FMeshDrawCommandCount());
FMeshDrawCommandCount& DrawCount = BucketMap.GetByElementId(SetId).Value;
DrawCount.Num++;
}
CommandInfo.StateBucketId = SetId.GetIndex();
if (bUseStateBucketsAuxData)
{
// grow MDC AuxData array in sync with MDC StateBuckets
Scene.CachedStateBucketsAuxData[CurrMeshPass].SetNum(BucketMap.GetMaxIndex() + 1, false);
Scene.CachedStateBucketsAuxData[CurrMeshPass][CommandInfo.StateBucketId] = FStateBucketAuxData(MeshBatch);
}
}
else
{
// Only one FMeshDrawCommand supported per FStaticMesh in a pass
// Allocate at lowest free index so that 'r.DoLazyStaticMeshUpdate' can shrink the TSparseArray more effectively
FCachedPassMeshDrawList& CachedDrawLists = Scene.CachedDrawLists[CurrMeshPass];
CommandInfo.CommandIndex = CachedDrawLists.MeshDrawCommands.EmplaceAtLowestFreeIndex(CachedDrawLists.LowestFreeIndexSearchStart, MeshDrawCommand);
}
}
void FCachedPassMeshDrawListContextDeferred::FinalizeCommand(
const FMeshBatch& MeshBatch,
int32 BatchElementIndex,
const FMeshDrawCommandPrimitiveIdInfo& IdInfo,
ERasterizerFillMode MeshFillMode,
ERasterizerCullMode MeshCullMode,
FMeshDrawCommandSortKey SortKey,
EFVisibleMeshDrawCommandFlags Flags,
const FGraphicsMinimalPipelineStateInitializer& PipelineState,
const FMeshProcessorShaders* ShadersForDebugging,
FMeshDrawCommand& MeshDrawCommand)
{
// disabling this by default as it incurs a high cost in perf captures due to sheer volume. Recommendation is to re-enable locally if you need to profile this particular code.
// QUICK_SCOPE_CYCLE_COUNTER(STAT_FinalizeCachedMeshDrawCommand);
FinalizeCommandCommon(
MeshBatch,
BatchElementIndex,
MeshFillMode,
MeshCullMode,
SortKey,
Flags,
PipelineState,
ShadersForDebugging,
MeshDrawCommand
);
const int32 Index = DeferredCommands.Add(MeshDrawCommand);
if (bUseGPUScene)
{
// Cache the hash here to make the deferred finalize less expensive
DeferredCommandHashes.Add(FStateBucketMap::ComputeHash(MeshDrawCommand));
CommandInfo.StateBucketId = Index;
if (bUseStateBucketsAuxData)
{
DeferredStateBucketsAuxData.Add(FStateBucketAuxData(MeshBatch));
}
}
else
{
CommandInfo.CommandIndex = Index;
}
}
void FCachedPassMeshDrawListContextDeferred::DeferredFinalizeMeshDrawCommands(const TArrayView<FPrimitiveSceneInfo*>& SceneInfos, int32 Start, int32 End)
{
if (bUseGPUScene)
{
for (int32 SceneInfoIndex = Start; SceneInfoIndex < End; ++SceneInfoIndex)
{
FPrimitiveSceneInfo* SceneInfo = SceneInfos[SceneInfoIndex];
for (auto& CmdInfo : SceneInfo->StaticMeshCommandInfos)
{
check(CmdInfo.MeshPass < EMeshPass::Num);
FStateBucketMap& BucketMap = Scene.CachedMeshDrawCommandStateBuckets[CmdInfo.MeshPass];
int32 DeferredIndex = CmdInfo.StateBucketId;
check(DeferredIndex >= 0 && DeferredIndex < DeferredCommands.Num());
check(CmdInfo.CommandIndex == -1);
FMeshDrawCommand& Command = DeferredCommands[DeferredIndex];
const Experimental::FHashType CommandHash = DeferredCommandHashes[DeferredIndex];
Experimental::FHashElementId SetId = BucketMap.FindOrAddIdByHash(CommandHash, MoveTemp(Command), FMeshDrawCommandCount());
FMeshDrawCommandCount& DrawCount = BucketMap.GetByElementId(SetId).Value;
DrawCount.Num++;
CmdInfo.StateBucketId = SetId.GetIndex();
if (bUseStateBucketsAuxData)
{
// grow MDC AuxData array in sync with MDC StateBuckets
Scene.CachedStateBucketsAuxData[CmdInfo.MeshPass].SetNum(BucketMap.GetMaxIndex() + 1, false);
Scene.CachedStateBucketsAuxData[CmdInfo.MeshPass][CmdInfo.StateBucketId] = DeferredStateBucketsAuxData[DeferredIndex];
}
}
}
}
else
{
for (int32 SceneInfoIndex = Start; SceneInfoIndex < End; ++SceneInfoIndex)
{
FPrimitiveSceneInfo* SceneInfo = SceneInfos[SceneInfoIndex];
for (auto& CmdInfo : SceneInfo->StaticMeshCommandInfos)
{
check(CmdInfo.MeshPass < EMeshPass::Num);
FCachedPassMeshDrawList& CachedDrawLists = Scene.CachedDrawLists[CmdInfo.MeshPass];
check(CmdInfo.CommandIndex >= 0 && CmdInfo.CommandIndex < DeferredCommands.Num());
check(CmdInfo.StateBucketId == -1);
FMeshDrawCommand& Command = DeferredCommands[CmdInfo.CommandIndex];
CmdInfo.CommandIndex = CachedDrawLists.MeshDrawCommands.EmplaceAtLowestFreeIndex(CachedDrawLists.LowestFreeIndexSearchStart, MoveTemp(Command));
}
}
}
DeferredCommands.Reset();
DeferredCommandHashes.Reset();
DeferredStateBucketsAuxData.Reset();
}
PassProcessorCreateFunction FPassProcessorManager::JumpTable[(int32)EShadingPath::Num][EMeshPass::Num] = {};
DeprecatedPassProcessorCreateFunction FPassProcessorManager::DeprecatedJumpTable[(int32)EShadingPath::Num][EMeshPass::Num] = {};
EMeshPassFlags FPassProcessorManager::Flags[(int32)EShadingPath::Num][EMeshPass::Num] = {};
PSO Precache Base Changes (disabled by default) Add PSOPrecache file which wraps engine level PSO structs and functions - FPSOPrecacheParams used to wrap certain parameters which drive the PSO collection (mostly set from components) - IPSOCollector interface used as engine entry to the mesh pass processors in renderer project - FPSOCollectorCreateManager to wrap all statically registered IPSOCollector CreateFuncions - PSOCollectorStats structs and helper functions Add PSOPrecache support to PipelineStateCache: - functions to precache compute and graphics PSOs - functions to check current precache state - FPrecacheGraphicsPipelineCache which wraps all currently precached PSOs IMaterial entry function to PrecachePSOs with given vertex factories and params (implemented by UMaterial & UMaterialInstance) which forwards call to FMaterial and finally the FMaterialShaderMap - FMaterialShaderMap will iterate all registered IPSOCollector to collect all possible PSOs used and forward them to the PipelineStateCache for actual (async) precaching RHI Changes: - Add RHI specific functions to retrieve & compare the FRHIVertexDeclaration and FGraphicsPipelineStateInitializer hash for each RHI - Add helper functions to match RHI*State data by retrieving initializer Minimal vertex factory changes for PSO precaching as prep - actual changes in upcoming CLs MeshPassProcessor base functions to collect PSOs which can be used by all mesh pass processor implemention (actual changes in upcoming CLs) - Cache complete precache data hash of stored minimal PSO so it can be used for fast actual PSO initializer hash computation (full PSO initializer is build at runtime) - Cache if minimal PSO was successfully precache and option to skip draw when PSO is still precaching (disabled by default and doesn't work yet via GPU scene based rendering) - Add helper functions to setup the per mesh pass render target data used during PSO collection Refactor SceneTextureConfig so it can be initialized from an init struct and move all function to setup the internal members from SceneTexture to SceneTextureConfig using the data from the init struct (so it's available in Engine project) Fix GBufferInfo format for velocity target (was always floating point while it should be unorm when not android Make certain helper functions definitions to h file so they can be used everywhere (SupportsNaniteRendering, FTextureRenderTarget2DResource::GetFormat & CreateFlags) #preflight 63189a5a967ffc68fb9044a5 #jira UE-139584 #rb Mihnea.Balta [CL 21907508 by kenzo terelst in ue5-main branch]
2022-09-08 19:34:08 -04:00
static_assert(EMeshPass::Num <= FPSOCollectorCreateManager::MaxPSOCollectorCount);
void FPassProcessorManager::SetPassFlags(EShadingPath ShadingPath, EMeshPass::Type PassType, EMeshPassFlags NewFlags)
{
check(IsInGameThread());
FGlobalComponentRecreateRenderStateContext Context;
if (JumpTable[(uint32)ShadingPath][PassType])
{
Flags[(uint32)ShadingPath][PassType] = NewFlags;
}
}
#if WANTS_DRAW_MESH_EVENTS
FMeshDrawCommand::FMeshDrawEvent::FMeshDrawEvent(const FMeshDrawCommand& MeshDrawCommand, const uint32 InstanceFactor, FRHICommandList& RHICmdList)
{
if (GShowMaterialDrawEvents)
{
const FString& MaterialName = MeshDrawCommand.DebugData.MaterialName;
FName ResourceName = MeshDrawCommand.DebugData.ResourceName;
FString DrawEventName = FString::Printf(
TEXT("%s %s"),
// Note: this is the parent's material name, not the material instance
*MaterialName,
ResourceName.IsValid() ? *ResourceName.ToString() : TEXT(""));
const uint32 Instances = MeshDrawCommand.NumInstances * InstanceFactor;
if (Instances > 1)
{
BEGIN_DRAW_EVENTF(
RHICmdList,
MaterialEvent,
*this,
TEXT("%s %u instances"),
*DrawEventName,
Instances);
}
else
{
BEGIN_DRAW_EVENTF(RHICmdList, MaterialEvent, *this, *DrawEventName);
}
}
}
#endif
PSO Precache Base Changes (disabled by default) Add PSOPrecache file which wraps engine level PSO structs and functions - FPSOPrecacheParams used to wrap certain parameters which drive the PSO collection (mostly set from components) - IPSOCollector interface used as engine entry to the mesh pass processors in renderer project - FPSOCollectorCreateManager to wrap all statically registered IPSOCollector CreateFuncions - PSOCollectorStats structs and helper functions Add PSOPrecache support to PipelineStateCache: - functions to precache compute and graphics PSOs - functions to check current precache state - FPrecacheGraphicsPipelineCache which wraps all currently precached PSOs IMaterial entry function to PrecachePSOs with given vertex factories and params (implemented by UMaterial & UMaterialInstance) which forwards call to FMaterial and finally the FMaterialShaderMap - FMaterialShaderMap will iterate all registered IPSOCollector to collect all possible PSOs used and forward them to the PipelineStateCache for actual (async) precaching RHI Changes: - Add RHI specific functions to retrieve & compare the FRHIVertexDeclaration and FGraphicsPipelineStateInitializer hash for each RHI - Add helper functions to match RHI*State data by retrieving initializer Minimal vertex factory changes for PSO precaching as prep - actual changes in upcoming CLs MeshPassProcessor base functions to collect PSOs which can be used by all mesh pass processor implemention (actual changes in upcoming CLs) - Cache complete precache data hash of stored minimal PSO so it can be used for fast actual PSO initializer hash computation (full PSO initializer is build at runtime) - Cache if minimal PSO was successfully precache and option to skip draw when PSO is still precaching (disabled by default and doesn't work yet via GPU scene based rendering) - Add helper functions to setup the per mesh pass render target data used during PSO collection Refactor SceneTextureConfig so it can be initialized from an init struct and move all function to setup the internal members from SceneTexture to SceneTextureConfig using the data from the init struct (so it's available in Engine project) Fix GBufferInfo format for velocity target (was always floating point while it should be unorm when not android Make certain helper functions definitions to h file so they can be used everywhere (SupportsNaniteRendering, FTextureRenderTarget2DResource::GetFormat & CreateFlags) #preflight 63189a5a967ffc68fb9044a5 #jira UE-139584 #rb Mihnea.Balta [CL 21907508 by kenzo terelst in ue5-main branch]
2022-09-08 19:34:08 -04:00
void AddRenderTargetInfo(
EPixelFormat PixelFormat,
ETextureCreateFlags CreateFlags,
FGraphicsPipelineRenderTargetsInfo& RenderTargetsInfo)
{
RenderTargetsInfo.RenderTargetFormats[RenderTargetsInfo.RenderTargetsEnabled] = PixelFormat;
RenderTargetsInfo.RenderTargetFlags[RenderTargetsInfo.RenderTargetsEnabled] = CreateFlags;
RenderTargetsInfo.RenderTargetsEnabled++;
}
void SetupDepthStencilInfo(
EPixelFormat DepthStencilFormat,
ETextureCreateFlags DepthStencilCreateFlags,
ERenderTargetLoadAction DepthTargetLoadAction,
ERenderTargetLoadAction StencilTargetLoadAction,
FExclusiveDepthStencil DepthStencilAccess,
FGraphicsPipelineRenderTargetsInfo& RenderTargetsInfo)
{
// Setup depth stencil state
RenderTargetsInfo.DepthStencilTargetFormat = DepthStencilFormat;
RenderTargetsInfo.DepthStencilTargetFlag = DepthStencilCreateFlags;
RenderTargetsInfo.DepthTargetLoadAction = DepthTargetLoadAction;
RenderTargetsInfo.StencilTargetLoadAction = StencilTargetLoadAction;
RenderTargetsInfo.DepthStencilAccess = DepthStencilAccess;
const ERenderTargetStoreAction StoreAction = EnumHasAnyFlags(RenderTargetsInfo.DepthStencilTargetFlag, TexCreate_Memoryless) ? ERenderTargetStoreAction::ENoAction : ERenderTargetStoreAction::EStore;
RenderTargetsInfo.DepthTargetStoreAction = RenderTargetsInfo.DepthStencilAccess.IsUsingDepth() ? StoreAction : ERenderTargetStoreAction::ENoAction;
RenderTargetsInfo.StencilTargetStoreAction = RenderTargetsInfo.DepthStencilAccess.IsUsingStencil() ? StoreAction : ERenderTargetStoreAction::ENoAction;
}
void SetupGBufferRenderTargetInfo(const FSceneTexturesConfig& SceneTexturesConfig, FGraphicsPipelineRenderTargetsInfo& RenderTargetsInfo, bool bSetupDepthStencil)
{
SceneTexturesConfig.GetGBufferRenderTargetsInfo(RenderTargetsInfo);
if (bSetupDepthStencil)
{
SetupDepthStencilInfo(PF_DepthStencil, SceneTexturesConfig.DepthCreateFlags, ERenderTargetLoadAction::ELoad,
ERenderTargetLoadAction::ELoad, FExclusiveDepthStencil::DepthWrite_StencilWrite, RenderTargetsInfo);
}
}
#if PSO_PRECACHING_VALIDATE
// Stats for PSO shaders only (no state, only VS/PS/GS usage)
static FCriticalSection PSOShadersPrecacheLock;
static PSOCollectorStats::FPrecacheStats PSOShadersPrecacheStats;
static Experimental::TRobinHoodHashMap<FGraphicsMinimalPipelineStateInitializer, PSOCollectorStats::FShaderStateUsage> PSOShadersPrecacheMap;
// Stats for minimal PSO initializer data during MeshDrawCommand building (doesn't contain render target info)
static FCriticalSection MinimalPSOPrecacheLock;
static PSOCollectorStats::FPrecacheStats MinimalPSOPrecacheStats;
static Experimental::TRobinHoodHashMap<uint64, PSOCollectorStats::FShaderStateUsage> MinimalPSOPrecacheMap;
PSO Precache Base Changes (disabled by default) Add PSOPrecache file which wraps engine level PSO structs and functions - FPSOPrecacheParams used to wrap certain parameters which drive the PSO collection (mostly set from components) - IPSOCollector interface used as engine entry to the mesh pass processors in renderer project - FPSOCollectorCreateManager to wrap all statically registered IPSOCollector CreateFuncions - PSOCollectorStats structs and helper functions Add PSOPrecache support to PipelineStateCache: - functions to precache compute and graphics PSOs - functions to check current precache state - FPrecacheGraphicsPipelineCache which wraps all currently precached PSOs IMaterial entry function to PrecachePSOs with given vertex factories and params (implemented by UMaterial & UMaterialInstance) which forwards call to FMaterial and finally the FMaterialShaderMap - FMaterialShaderMap will iterate all registered IPSOCollector to collect all possible PSOs used and forward them to the PipelineStateCache for actual (async) precaching RHI Changes: - Add RHI specific functions to retrieve & compare the FRHIVertexDeclaration and FGraphicsPipelineStateInitializer hash for each RHI - Add helper functions to match RHI*State data by retrieving initializer Minimal vertex factory changes for PSO precaching as prep - actual changes in upcoming CLs MeshPassProcessor base functions to collect PSOs which can be used by all mesh pass processor implemention (actual changes in upcoming CLs) - Cache complete precache data hash of stored minimal PSO so it can be used for fast actual PSO initializer hash computation (full PSO initializer is build at runtime) - Cache if minimal PSO was successfully precache and option to skip draw when PSO is still precaching (disabled by default and doesn't work yet via GPU scene based rendering) - Add helper functions to setup the per mesh pass render target data used during PSO collection Refactor SceneTextureConfig so it can be initialized from an init struct and move all function to setup the internal members from SceneTexture to SceneTextureConfig using the data from the init struct (so it's available in Engine project) Fix GBufferInfo format for velocity target (was always floating point while it should be unorm when not android Make certain helper functions definitions to h file so they can be used everywhere (SupportsNaniteRendering, FTextureRenderTarget2DResource::GetFormat & CreateFlags) #preflight 63189a5a967ffc68fb9044a5 #jira UE-139584 #rb Mihnea.Balta [CL 21907508 by kenzo terelst in ue5-main branch]
2022-09-08 19:34:08 -04:00
// Helper function to remove certain members of the PSO initializer to help track down issues with PSO precache misses
// eg Remove BlendState and check if the misses are gone for example
static FGraphicsMinimalPipelineStateInitializer PatchMinimalPipelineStateToCheck(const FGraphicsMinimalPipelineStateInitializer& MinimalPSO)
{
FGraphicsMinimalPipelineStateInitializer PSOInitializeToCheck = MinimalPSO;
//PSOInitializeToCheck.DepthStencilState = nullptr;
//PSOInitializeToCheck.RasterizerState = nullptr;
//PSOInitializeToCheck.BlendState = nullptr;
//PSOInitializeToCheck.PrimitiveType = PT_TriangleList;
//PSOInitializeToCheck.ImmutableSamplerState = FImmutableSamplerState();
//PSOInitializeToCheck.BoundShaderState.VertexDeclarationRHI = nullptr;
//PSOInitializeToCheck.UniqueEntry = false;
// Recompute the hash when disabling certain states for checks
//PSOInitializeToCheck.ComputePrecachePSOHash();
return PSOInitializeToCheck;
}
void PSOCollectorStats::AddMinimalPipelineStateToCache(const FGraphicsMinimalPipelineStateInitializer& PSOInitialize, uint32 MeshPassType, const FVertexFactoryType* VertexFactoryType)
{
if (!IsPrecachingValidationEnabled())
{
return;
}
check(VertexFactoryType == nullptr || VertexFactoryType->SupportsPSOPrecaching());
PSO Precache Base Changes (disabled by default) Add PSOPrecache file which wraps engine level PSO structs and functions - FPSOPrecacheParams used to wrap certain parameters which drive the PSO collection (mostly set from components) - IPSOCollector interface used as engine entry to the mesh pass processors in renderer project - FPSOCollectorCreateManager to wrap all statically registered IPSOCollector CreateFuncions - PSOCollectorStats structs and helper functions Add PSOPrecache support to PipelineStateCache: - functions to precache compute and graphics PSOs - functions to check current precache state - FPrecacheGraphicsPipelineCache which wraps all currently precached PSOs IMaterial entry function to PrecachePSOs with given vertex factories and params (implemented by UMaterial & UMaterialInstance) which forwards call to FMaterial and finally the FMaterialShaderMap - FMaterialShaderMap will iterate all registered IPSOCollector to collect all possible PSOs used and forward them to the PipelineStateCache for actual (async) precaching RHI Changes: - Add RHI specific functions to retrieve & compare the FRHIVertexDeclaration and FGraphicsPipelineStateInitializer hash for each RHI - Add helper functions to match RHI*State data by retrieving initializer Minimal vertex factory changes for PSO precaching as prep - actual changes in upcoming CLs MeshPassProcessor base functions to collect PSOs which can be used by all mesh pass processor implemention (actual changes in upcoming CLs) - Cache complete precache data hash of stored minimal PSO so it can be used for fast actual PSO initializer hash computation (full PSO initializer is build at runtime) - Cache if minimal PSO was successfully precache and option to skip draw when PSO is still precaching (disabled by default and doesn't work yet via GPU scene based rendering) - Add helper functions to setup the per mesh pass render target data used during PSO collection Refactor SceneTextureConfig so it can be initialized from an init struct and move all function to setup the internal members from SceneTexture to SceneTextureConfig using the data from the init struct (so it's available in Engine project) Fix GBufferInfo format for velocity target (was always floating point while it should be unorm when not android Make certain helper functions definitions to h file so they can be used everywhere (SupportsNaniteRendering, FTextureRenderTarget2DResource::GetFormat & CreateFlags) #preflight 63189a5a967ffc68fb9044a5 #jira UE-139584 #rb Mihnea.Balta [CL 21907508 by kenzo terelst in ue5-main branch]
2022-09-08 19:34:08 -04:00
static bool bFirstTime = true;
if (bFirstTime)
{
PSOShadersPrecacheStats.Empty();
MinimalPSOPrecacheStats.Empty();
bFirstTime = false;
}
// Update the Shader only stats ignoring all state
{
FScopeLock Lock(&PSOShadersPrecacheLock);
FGraphicsMinimalPipelineStateInitializer PSOInitializeToCheck;
PSOInitializeToCheck.BoundShaderState = PSOInitialize.BoundShaderState;
PSOInitializeToCheck.BoundShaderState.VertexDeclarationRHI = nullptr;
PSOInitializeToCheck.ComputePrecachePSOHash();
Experimental::FHashElementId TableId = PSOShadersPrecacheMap.FindId(PSOInitializeToCheck);
if (!TableId.IsValid())
{
TableId = PSOShadersPrecacheMap.FindOrAddId(PSOInitializeToCheck, FShaderStateUsage());
}
FShaderStateUsage& Value = PSOShadersPrecacheMap.GetByElementId(TableId).Value;
if (!Value.bPrecached)
{
check(!Value.bUsed);
PSOShadersPrecacheStats.PrecacheData.UpdateStats(MeshPassType, VertexFactoryType);
Value.bPrecached = true;
}
}
// Update the minimal PSO stats - optionally removing certain fields via PatchMinimalPipelineStateToCheck
{
FScopeLock Lock(&MinimalPSOPrecacheLock);
FGraphicsMinimalPipelineStateInitializer PSOInitializeToCheck = PatchMinimalPipelineStateToCheck(PSOInitialize);
check(PSOInitializeToCheck.PrecachePSOHash != 0);
Experimental::FHashElementId TableId = MinimalPSOPrecacheMap.FindId(PSOInitializeToCheck.PrecachePSOHash);
if (!TableId.IsValid())
{
TableId = MinimalPSOPrecacheMap.FindOrAddId(PSOInitializeToCheck.PrecachePSOHash, FShaderStateUsage());
}
FShaderStateUsage& Value = MinimalPSOPrecacheMap.GetByElementId(TableId).Value;
if (!Value.bPrecached)
{
check(!Value.bUsed);
MinimalPSOPrecacheStats.PrecacheData.UpdateStats(MeshPassType, VertexFactoryType);
Value.bPrecached = true;
}
}
}
void PSOCollectorStats::CheckMinimalPipelineStateInCache(const FGraphicsMinimalPipelineStateInitializer& PSOInitialize, uint32 MeshPassType, const FVertexFactoryType* VertexFactoryType)
{
if (!IsPrecachingValidationEnabled())
{
return;
}
const EShadingPath ShadingPath = FSceneInterface::GetShadingPath(GMaxRHIFeatureLevel);
bool bCollectPSOs = FPSOCollectorCreateManager::GetCreateFunction(ShadingPath, MeshPassType) != nullptr;
bool bTracked = bCollectPSOs && (VertexFactoryType == nullptr || VertexFactoryType->SupportsPSOPrecaching());
PSO Precache Base Changes (disabled by default) Add PSOPrecache file which wraps engine level PSO structs and functions - FPSOPrecacheParams used to wrap certain parameters which drive the PSO collection (mostly set from components) - IPSOCollector interface used as engine entry to the mesh pass processors in renderer project - FPSOCollectorCreateManager to wrap all statically registered IPSOCollector CreateFuncions - PSOCollectorStats structs and helper functions Add PSOPrecache support to PipelineStateCache: - functions to precache compute and graphics PSOs - functions to check current precache state - FPrecacheGraphicsPipelineCache which wraps all currently precached PSOs IMaterial entry function to PrecachePSOs with given vertex factories and params (implemented by UMaterial & UMaterialInstance) which forwards call to FMaterial and finally the FMaterialShaderMap - FMaterialShaderMap will iterate all registered IPSOCollector to collect all possible PSOs used and forward them to the PipelineStateCache for actual (async) precaching RHI Changes: - Add RHI specific functions to retrieve & compare the FRHIVertexDeclaration and FGraphicsPipelineStateInitializer hash for each RHI - Add helper functions to match RHI*State data by retrieving initializer Minimal vertex factory changes for PSO precaching as prep - actual changes in upcoming CLs MeshPassProcessor base functions to collect PSOs which can be used by all mesh pass processor implemention (actual changes in upcoming CLs) - Cache complete precache data hash of stored minimal PSO so it can be used for fast actual PSO initializer hash computation (full PSO initializer is build at runtime) - Cache if minimal PSO was successfully precache and option to skip draw when PSO is still precaching (disabled by default and doesn't work yet via GPU scene based rendering) - Add helper functions to setup the per mesh pass render target data used during PSO collection Refactor SceneTextureConfig so it can be initialized from an init struct and move all function to setup the internal members from SceneTexture to SceneTextureConfig using the data from the init struct (so it's available in Engine project) Fix GBufferInfo format for velocity target (was always floating point while it should be unorm when not android Make certain helper functions definitions to h file so they can be used everywhere (SupportsNaniteRendering, FTextureRenderTarget2DResource::GetFormat & CreateFlags) #preflight 63189a5a967ffc68fb9044a5 #jira UE-139584 #rb Mihnea.Balta [CL 21907508 by kenzo terelst in ue5-main branch]
2022-09-08 19:34:08 -04:00
// Enable this when we want to check the actual RHI shader resources during this function - slightly slower and don't need to be retrieved here yet
//PSOInitialize.BoundShaderState.AsBoundShaderState();
// Update the Shader only stats ignoring all state
{
FScopeLock Lock(&PSOShadersPrecacheLock);
FGraphicsMinimalPipelineStateInitializer PSOInitializeToCheck;
PSOInitializeToCheck.BoundShaderState = PSOInitialize.BoundShaderState;
PSOInitializeToCheck.BoundShaderState.VertexDeclarationRHI = nullptr;
PSOInitializeToCheck.ComputePrecachePSOHash();
Experimental::FHashElementId TableId = PSOShadersPrecacheMap.FindId(PSOInitializeToCheck);
if (!TableId.IsValid())
{
TableId = PSOShadersPrecacheMap.FindOrAddId(PSOInitializeToCheck, FShaderStateUsage());
}
FShaderStateUsage& Value = PSOShadersPrecacheMap.GetByElementId(TableId).Value;
if (!Value.bUsed)
{
PSOShadersPrecacheStats.UsageData.UpdateStats(MeshPassType, VertexFactoryType);
if (!bTracked)
{
PSOShadersPrecacheStats.UntrackedData.UpdateStats(MeshPassType, VertexFactoryType);
}
else if (!Value.bPrecached)
{
PSOShadersPrecacheStats.MissData.UpdateStats(MeshPassType, VertexFactoryType);
}
else
{
PSOShadersPrecacheStats.HitData.UpdateStats(MeshPassType, VertexFactoryType);
}
Value.bUsed = true;
}
}
// Update the minimal PSO stats - optionally removing certain fields via PatchMinimalPipelineStateToCheck
{
FScopeLock Lock(&MinimalPSOPrecacheLock);
FGraphicsMinimalPipelineStateInitializer PSOInitializeToCheck = PatchMinimalPipelineStateToCheck(PSOInitialize);
check(PSOInitializeToCheck.PrecachePSOHash != 0);
Experimental::FHashElementId TableId = MinimalPSOPrecacheMap.FindId(PSOInitializeToCheck.PrecachePSOHash);
if (!TableId.IsValid())
{
TableId = MinimalPSOPrecacheMap.FindOrAddId(PSOInitializeToCheck.PrecachePSOHash, FShaderStateUsage());
}
FShaderStateUsage& Value = MinimalPSOPrecacheMap.GetByElementId(TableId).Value;
if (!Value.bUsed)
{
MinimalPSOPrecacheStats.UsageData.UpdateStats(MeshPassType, VertexFactoryType);
if (!bTracked)
{
MinimalPSOPrecacheStats.UntrackedData.UpdateStats(MeshPassType, VertexFactoryType);
}
else if (!Value.bPrecached)
{
MinimalPSOPrecacheStats.MissData.UpdateStats(MeshPassType, VertexFactoryType);
}
else
{
MinimalPSOPrecacheStats.HitData.UpdateStats(MeshPassType, VertexFactoryType);
}
Value.bUsed = true;
}
}
}
#endif // PSO_PRECACHING_VALIDATE