unreal gpuscene

(1)

TypeOffsetTable 是 Primitive Type 相同 Primitive 的结束偏移,不是开始偏移,第一个类型开始偏移是 0,第一个类型结束偏移,是第一个类型的个数

Source\Runtime\Renderer\Private\RendererScene.cpp

FTypeOffsetTableEntry& NextEntry = TypeOffsetTable[TypeIndex];

(1)

Primitives SOA 数据,不会修改这个数据结构,PersistentPrimitiveIdToIndexMap 是进行二次映射,映射到 Primitives,PersistentPrimitiveIdToIndexMap 下标索引和 Primitives 一致,PersistentPrimitiveIdToIndexMap 下标索引内容,对应 Primitives 索引

Primitives[SourceIndex]->PackedIndex 表示应该放置的数组下标

Source\Runtime\Renderer\Private\RendererScene.cpp

FPersistentPrimitiveIndex MovedPersisitentIndex = Primitives[DestIndex]->PersistentIndex;

PersistentPrimitiveIdToIndexMap[MovedPersisitentIndex.Index] = SourceIndex;

Primitives[SourceIndex]->PackedIndex = DestIndex;

(1)

需要更新 instance 条件,UpdatedInstances 和 AddedLocalPrimitiveSceneInfos

PendingAllocateInstanceIds.Reserve(UpdatedInstances.Num() + AddedLocalPrimitiveSceneInfos.Num());

(1)

primitive 更新条件 AddedPrimitiveSceneInfos 和 UpdatedTransforms 和 UpdatedInstances,不太明白为什么 UpdatedInstances 更新需要修改 primitive

const int32 SceneInfosContainerReservedSize = AddedPrimitiveSceneInfos.Num() + UpdatedTransforms.Num() + UpdatedInstances.Num();

(1)

GPUSceneInstanceSceneDataRW 是 float4 的 soa

Saved\ShaderDebugInfo\PCD3D_SM6\Global\FGPUSceneSetInstancePrimitiveIdCS\0\GPUSceneDataManagement.usf

RWStructuredBuffer<float4> GPUSceneInstanceSceneDataRW;
float4 LoadInstanceSceneDataElement(uint Index)
{
    return GPUSceneInstanceSceneDataRW[Index];
}

(1)

Source\Runtime\Engine\Public\InstanceUniformShaderParameters.h

ENGINE_API void Build

    (

        uint32 PrimitiveId,

        uint32 RelativeId,

        uint32 InstanceFlags,

        uint32 LastUpdateFrame,

        uint32 CustomDataCount,

        float RandomID,

        bool bIsVisible = true

    );

(1)

Source\Runtime\Renderer\Private\GPUScene.cpp

InstanceUploadInfo.InstanceSceneDataBuffers = PrimitiveSceneInfo->GetInstanceSceneDataBuffers();

        if (InstanceUploadInfo.InstanceSceneDataBuffers)

        {

            const FInstanceSceneDataBuffers::FReadView InstanceSceneDataBuffers = InstanceUploadInfo.InstanceSceneDataBuffers->GetReadView();

            InstanceUploadInfo.NumInstances = InstanceUploadInfo.InstanceSceneDataBuffers->GetNumInstances();

            InstanceUploadInfo.InstanceFlags = PackFlags(InstanceSceneDataBuffers.Flags);

            InstanceUploadInfo.InstanceLightShadowUVBias = InstanceSceneDataBuffers.InstanceLightShadowUVBias;

            InstanceUploadInfo.InstanceCustomData = InstanceSceneDataBuffers.InstanceCustomData;

            InstanceUploadInfo.InstanceRandomID = InstanceSceneDataBuffers.InstanceRandomIDs;

            InstanceUploadInfo.InstanceHierarchyOffset = InstanceSceneDataBuffers.InstanceHierarchyOffset;

            InstanceUploadInfo.InstancePayloadExtension = InstanceSceneDataBuffers.InstancePayloadExtension;

            InstanceUploadInfo.InstanceLocalBounds = InstanceSceneDataBuffers.InstanceLocalBounds;

#if WITH_EDITOR

            InstanceUploadInfo.InstanceEditorData = InstanceSceneDataBuffers.InstanceEditorData;

#endif

(1)

UploadDataSourceAdapter  cpu 信息获取读写封装

PrimitiveUploader gpu 数据读写封装

GetPrimitiveShaderData 获取内存 primitive 数据

Source\Runtime\Renderer\Private\GPUScene.cpp

            ParallelForTemplate(TEXT("GPUScene Upload Primitives Task"), TaskContext.NumPrimitiveDataUploads, 1, [&TaskContext, &UploadDataSourceAdapter](int32 ItemIndex)

            {

                FOptionalTaskTagScope TaskTagScope(ETaskTag::EParallelRenderingThread);

                FVector4f* DstData = static_cast<FVector4f*>(TaskContext.PrimitiveUploader->GetRef(ItemIndex));

                UploadDataSourceAdapter.GetPrimitiveShaderData(ItemIndex, DstData);

            }, bExecuteInParallel ? EParallelForFlags::None : EParallelForFlags::ForceSingleThread);

        }

(1)

Instance Data 内存数据打包流程

Source\Runtime\Engine\Public\InstanceUniformShaderParameters.h

FORCEINLINE void BuildInternal

    (

        uint32 PrimitiveId,

        uint32 RelativeId,

        uint32 InstanceFlags,

        uint32 LastUpdateFrame,

        uint32 CustomDataCount,

        float RandomID,

        const FRenderTransform& LocalToWorld,

        bool bIsVisible,

        bool bSupportsCompressedTransforms

    )

    {

        // Note: layout must match GetInstanceData in SceneData.ush and InitializeInstanceSceneData in GPUSceneWriter.ush

        const float RotDeterminant = LocalToWorld.RotDeterminant();

        if (RotDeterminant < 0.0f)

        {

            InstanceFlags |= INSTANCE_SCENE_DATA_FLAG_DETERMINANT_SIGN;

        }

        else

        {

            InstanceFlags &= ~INSTANCE_SCENE_DATA_FLAG_DETERMINANT_SIGN;

        }

        // Mark zero scaled instances as hidden.

        if (!bIsVisible || RotDeterminant == 0.0f)

        {

            InstanceFlags |= INSTANCE_SCENE_DATA_FLAG_HIDDEN;

        }

        checkSlow((PrimitiveId      & 0x000FFFFF) == PrimitiveId);

        checkSlow((InstanceFlags    & 0x00000FFF) == InstanceFlags);

        checkSlow((RelativeId       & 0x00FFFFFF) == RelativeId);

        checkSlow((CustomDataCount  & 0x000000FF) == CustomDataCount);

        const uint32 Packed0 = (InstanceFlags   << 20u) | PrimitiveId;

        const uint32 Packed1 = (CustomDataCount << 24u) | RelativeId;

        Data[0].X  = *(const float*)&Packed0;

        Data[0].Y  = *(const float*)&Packed1;

        Data[0].Z  = *(const float*)&LastUpdateFrame;

        Data[0].W  = *(const float*)&RandomID;

        if (bSupportsCompressedTransforms)

        {

            FCompressedTransform CompressedLocalToWorld(LocalToWorld);

            Data[1] = *(const FVector4f*)&CompressedLocalToWorld.Rotation[0];

            Data[2] = *(const FVector3f*)&CompressedLocalToWorld.Translation;

        }

        else

        {

            // Note: writes 3x float4s

            LocalToWorld.To3x4MatrixTranspose((float*)&Data[1]);

        }

    }

(1)

instance data 内存数据编码,上传显存数据

Source\Runtime\Renderer\Private\GPUScene.cpp

if (UploadInfo.InstanceSceneDataBuffers != nullptr)

                        {

                            InstanceSceneData.BuildInternal(

                                UploadInfo.PrimitiveID,

                                InstanceIndex,

                                UploadInfo.InstanceFlags,

                                UploadInfo.LastUpdateSceneFrameNumber,

                                UploadInfo.InstanceCustomDataCount,

                                RandomID,

                                UploadInfo.InstanceSceneDataBuffers->GetInstanceToPrimitiveRelative(InstanceIndex),

                                !UploadInfo.bIsPrimitiveForceHidden && UploadInfo.InstanceSceneDataBuffers->GetInstanceVisible(InstanceIndex),

                                bSupportsCompressedTransforms

                            );

                        }

(1)

instance data 保存在 Primitive data 中的  InstanceSceneDataBuffers 或者 PrimitiveInstances 字段, ism static mesh 或者多个 instance 使用的是 InstanceSceneDataBuffers ,dynamic mesh 使用的是 PrimitiveInstances 字段传递 instance 数据

Source\Runtime\Renderer\Private\GPUScene.cpp

FInstanceSceneShaderData InstanceSceneData;

                        if (UploadInfo.InstanceSceneDataBuffers != nullptr)

                        {

                            InstanceSceneData.BuildInternal(

                                UploadInfo.PrimitiveID,

                                InstanceIndex,

                                UploadInfo.InstanceFlags,

                                UploadInfo.LastUpdateSceneFrameNumber,

                                UploadInfo.InstanceCustomDataCount,

                                RandomID,

                                UploadInfo.InstanceSceneDataBuffers->GetInstanceToPrimitiveRelative(InstanceIndex),

                                !UploadInfo.bIsPrimitiveForceHidden && UploadInfo.InstanceSceneDataBuffers->GetInstanceVisible(InstanceIndex),

                                bSupportsCompressedTransforms

                            );

                        }

                        else if (UploadInfo.PrimitiveInstances.IsEmpty())

                        {

                            // This path should only be taken for uninstanced primitives

                            check(UploadInfo.NumInstances == 1 && InstanceIndex == 0);

                            InstanceSceneData.BuildInternal(

                                UploadInfo.PrimitiveID,

                                InstanceIndex,

                                UploadInfo.InstanceFlags,

                                UploadInfo.LastUpdateSceneFrameNumber,

                                UploadInfo.InstanceCustomDataCount,

                                RandomID,

                                UploadInfo.PrimitiveToWorld,

                                !UploadInfo.bIsPrimitiveForceHidden,

                                bSupportsCompressedTransforms

                            );

                        }

                        else

                        {

                            const FInstanceSceneData& SceneData = UploadInfo.PrimitiveInstances[InstanceIndex];

                            InstanceSceneData.Build(

                                UploadInfo.PrimitiveID,

                                InstanceIndex,

                                UploadInfo.InstanceFlags,

                                UploadInfo.LastUpdateSceneFrameNumber,

                                UploadInfo.InstanceCustomDataCount,

                                RandomID,

                                SceneData.LocalToPrimitive,

                                UploadInfo.PrimitiveToWorld,

                                !UploadInfo.bIsPrimitiveForceHidden

                            );

                        }

(1)

gpu scene 收集 dynamic instance 数据 MeshBatchData

E:\e\UE4\UnrealEngine\Engine\Source\Runtime\Renderer\Private\GPUScene.cpp

void FGPUScenePrimitiveCollector::Add(

    const FMeshBatchDynamicPrimitiveData* MeshBatchData,

    const FPrimitiveUniformShaderParameters& PrimitiveShaderParams,

    uint32 NumInstances,

    uint32& OutPrimitiveIndex,

    uint32& OutInstanceSceneDataOffset)

{

    check(GPUSceneDynamicContext != nullptr);

    check(!bCommitted);

   

    // Lazy allocation of the upload data to not waste space and processing if none was needed.

    if (UploadData == nullptr)

    {

        UploadData = AllocateUploadData();

    }

    const int32 PrimitiveIndex = UploadData->PrimitiveData.Num();

    FPrimitiveData& PrimitiveData = UploadData->PrimitiveData.AddDefaulted_GetRef();        

    if (MeshBatchData != nullptr)

    {

        // make sure the source data is appropriately structured

        MeshBatchData->Validate(NumInstances);

        PrimitiveData.SourceData = *MeshBatchData;

    }

   

    const int32 PayloadFloat4Stride = PrimitiveData.SourceData.GetPayloadFloat4Stride();

   

    PrimitiveData.ShaderParams = &PrimitiveShaderParams;

    PrimitiveData.NumInstances = NumInstances;

    PrimitiveData.LocalInstanceSceneDataOffset = UploadData->TotalInstanceCount;

    PrimitiveData.LocalPayloadDataOffset = PayloadFloat4Stride > 0 ? UploadData->InstancePayloadDataFloat4Count : INDEX_NONE;

    UploadData->TotalInstanceCount += NumInstances;

    UploadData->InstancePayloadDataFloat4Count += PayloadFloat4Stride * NumInstances;

    if (PrimitiveData.SourceData.DataWriterGPU.IsBound())

    {

        // Enqueue this primitive data to be executed (either upon upload or deferred to a later GPU write pass)

        UploadData->GPUWritePrimitives.Add(PrimitiveIndex);

    }

    // Set the output data offsets

    OutPrimitiveIndex = PrimitiveIndex;

    OutInstanceSceneDataOffset = PrimitiveData.LocalInstanceSceneDataOffset;

}

(1)

gpu 数据更新

Source\Runtime\Renderer\Private\DeferredShadingRenderer.cpp

FInitViewTaskDatas InitViewTaskDatas = OnRenderBegin(GraphBuilder);

(1)

Source\Runtime\Renderer\Private\DeferredShadingRenderer.cpp

{

        RDG_GPU_STAT_SCOPE(GraphBuilder, VisibilityCommands);

        BeginInitViews(GraphBuilder, SceneTexturesConfig, InstanceCullingManager, ExternalAccessQueue, InitViewTaskDatas);

    }

(1)

Source\Runtime\Renderer\Private\DeferredShadingRenderer.cpp

InitViewTaskDatas.VisibilityTaskData->FinishGatherDynamicMeshElements(BasePassDepthStencilAccess, InstanceCullingManager, VirtualTextureUpdater.Get());

(1)

Source\Runtime\Renderer\Private\DeferredShadingRenderer.cpp

Scene->GPUScene.UploadDynamicPrimitiveShaderDataForView(GraphBuilder, View);

(1)

Source\Runtime\Renderer\Private\DeferredShadingRenderer.cpp

InitViewTaskDatas.VisibilityTaskData->FinishGatherDynamicMeshElements(BasePassDepthStencilAccess, InstanceCullingManager, VirtualTextureUpdater.Get());

(1)

Source\Runtime\Renderer\Private\DeferredShadingRenderer.cpp

Scene->GPUScene.UploadDynamicPrimitiveShaderDataForView(GraphBuilder, View);

(1)

Source\Runtime\Renderer\Private\DeferredShadingRenderer.cpp

InstanceCullingManager.BeginDeferredCulling(GraphBuilder, Scene->GPUScene);

(1)

Source\Runtime\Engine\Private\SceneManagement.cpp

void FMeshElementCollector::Commit()

{

    TRACE_CPUPROFILER_EVENT_SCOPE(FMeshElementCollector::Commit);

    check(RHICmdList);

    for (TPair<FGPUScenePrimitiveCollector*, FMeshBatch*> Pair : MeshBatchesForGPUScene)

    {

        GetRendererModule().AddMeshBatchToGPUScene(Pair.Key, *Pair.Value);

    }

(1)

bGPUWrite 或者 InstanceDynamicData.Num()) == NumInstances 都可以

Source\Runtime\Engine\Public\MeshBatch.h

/**

 * Dynamic primitive/instance data for a mesh batch element.

 *

 * NOTES:

 * - When applied to a FMeshBatchElement, data provided to the TConstArrayView members are expected to live until the end of the frame on the render thread

 * - If `DataWriterGPU` is bound and the TConstArrayView members are left empty, the delegate is expected to write any missing data, as it will not be uploaded

 */

struct FMeshBatchDynamicPrimitiveData

{

    FORCEINLINE void Validate(uint32 NumInstances) const

    {

#if DO_CHECK

        // Ensure array views are sized exactly for all instances, or are empty and there is a GPU writer

        const bool bGPUWrite = DataWriterGPU.IsBound();

        checkf(uint32(InstanceSceneData.Num()) == NumInstances || (bGPUWrite && InstanceSceneData.Num() == 0),

            TEXT("DynamicPrimitiveData provided should have %u instances in InstanceSceneData. Found %d"),

            NumInstances, InstanceSceneData.Num());

        if (PayloadDataFlags & INSTANCE_SCENE_DATA_FLAG_HAS_DYNAMIC_DATA)

        {

            checkf(uint32(InstanceDynamicData.Num()) == NumInstances || (bGPUWrite && InstanceDynamicData.Num() == 0),

                TEXT("DynamicPrimitiveData provided should have %u elements in InstanceDynamicData. Found %d"),

                NumInstances, InstanceDynamicData.Num());

        }

        if (PayloadDataFlags & INSTANCE_SCENE_DATA_FLAG_HAS_CUSTOM_DATA)

        {

            checkf(NumInstanceCustomDataFloats > 0,

                TEXT("DynamicPrimitiveData provided has the custom data flag set, but NumInstanceCustomDataFloats == 0"));

            checkf(uint32(InstanceCustomData.Num()) == NumInstances * NumInstanceCustomDataFloats || (bGPUWrite && InstanceCustomData.Num() == 0),

                TEXT("DynamicPrimitiveData provided should have %u elements in InstanceCustomData. Found %d"),

                NumInstances * NumInstanceCustomDataFloats, InstanceCustomData.Num());

        }

#endif

    }

};

(1)

dynamic primitive instance 数据上传,取决于 DataWriterGPU

Source\Runtime\Renderer\Private\GPUScene.cpp

void FGPUScene::UploadDynamicPrimitiveShaderDataForViewInternal(FRDGBuilder& GraphBuilder, FViewInfo& View, UE::Renderer::Private::IShadowInvalidatingInstances *ShadowInvalidatingInstances)

                // Defer this write to a later GPU write pass

                FDeferredGPUWrite DeferredWrite;

                DeferredWrite.DataWriterGPU = PrimData.SourceData.DataWriterGPU;

                DeferredWrite.ViewId = View.GPUSceneViewId;

                DeferredWrite.PrimitiveId = PrimitiveIdStart + PrimitiveIndex;

                DeferredWrite.InstanceSceneDataOffset = InstanceIdStart + PrimData.LocalInstanceSceneDataOffset;

                uint32 PassIndex = uint32(PrimData.SourceData.DataWriterGPUPass);

                DeferredGPUWritePassDelegates[PassIndex].Add(DeferredWrite);

            }

(1)

2.3.1、通过CS进行Cull得到可见的InstanceId列表

https://zhuanlan.zhihu.com/p/615181692

(1)

调用 Visible 裁剪

SceneUpdateParameters.Callbacks.PostStaticMeshUpdate = [&] (const UE::Tasks::FTask& StaticMeshUpdateTask)

{

VisibilityTaskData = LaunchVisibilityTasks(GraphBuilder.RHICmdList, *this, StaticMeshUpdateTask);

}

(1)

FrustumCull 调用

FVisibilityViewPacket::FVisibilityViewPacket(FVisibilityTaskData& InTaskData, FScene& InScene, FViewInfo& InView, int32 InViewIndex)

{

        Tasks.ComputeRelevance.AddPrerequisites(Tasks.FrustumCull);        

}

(1)

FVisibilityViewPacket 数据结构

class FVisibilityViewPacket

{

    friend FVisibilityTaskData;

    friend FGPUOcclusionParallel;

    friend FGPUOcclusionParallelPacket;

public:

    FVisibilityViewPacket(FVisibilityTaskData& TaskData, FScene& InScene, FViewInfo& InView, int32 ViewIndex);

    FVisibilityTaskData& TaskData;

    FVisibilityTaskConfig& TaskConfig;

    FScene& Scene;

    FViewInfo& View;

    FSceneViewState* ViewState;

    int32 ViewIndex;

    FViewElementPDI ViewElementPDI;

private:

    void BeginInitVisibility();

    struct FOcclusionCull

    {

        FGPUOcclusionSerial*   ContextIfSerial   = nullptr;

        FGPUOcclusionParallel* ContextIfParallel = nullptr;

        TCommandPipe<FPrimitiveRange> CommandPipe{ TEXT("OcclusionCullPipe") };

    } OcclusionCull;

    struct FRelevance

    {

        FComputeAndMarkRelevance* Context = nullptr;

        TCommandPipe<FPrimitiveIndexList> CommandPipe{ TEXT("RelevancePipe") };

        TCommandPipe<FPrimitiveIndexList>* PrimaryViewCommandPipe; // When using instanced stereo, secondary views will also send their commands to the primary view's command pipe to merge data

    } Relevance;

    struct FTasks

    {

        UE::Tasks::FTaskEvent AlwaysVisible{ UE_SOURCE_LOCATION };

        UE::Tasks::FTaskEvent FrustumCull{ UE_SOURCE_LOCATION };

        UE::Tasks::FTaskEvent OcclusionCull{ UE_SOURCE_LOCATION };

        UE::Tasks::FTaskEvent ComputeRelevance{ UE_SOURCE_LOCATION };

        UE::Tasks::FTaskEvent LightVisibility{ UE_SOURCE_LOCATION };

    } Tasks;

};

(1)

Frustum Cull

Source\Runtime\Renderer\Private\SceneVisibility.cpp

// Frustum Cull

        {

            // Frustum culling tasks have to run serially if custom culling is not thread-safe.

            const UE::Tasks::EExtendedTaskPriority ExtendedTaskPriority = GetExtendedTaskPriority(bCullingIsThreadsafe);

            // Assign the number of expected commands first so the pipe can determine when the last task has completed.

            OcclusionCull.CommandPipe.AddNumCommands(TaskConfig.FrustumCull.NumTasks);

            for (uint32 TaskIndex = 0; TaskIndex < TaskConfig.FrustumCull.NumTasks; ++TaskIndex)

            {

                Tasks.FrustumCull.AddPrerequisites(

                    UE::Tasks::Launch(UE_SOURCE_LOCATION, [this, Flags, MaxDrawDistanceScale, HLODState, VisibleNodes, TaskIndex]() mutable

(1)

Source\Runtime\Renderer\Private\SceneVisibility.cpp

static int32 FrustumCull(const FScene& Scene, FViewInfo& View, FFrustumCullingFlags Flags, float MaxDrawDistanceScale, const FHLODVisibilityState* const HLODState, const FSceneBitArray* VisibleNodes, const FVisibilityTaskConfig& TaskConfig, int32 TaskIndex)

(1)

Source\Runtime\Renderer\Private\SceneVisibility.cpp

FComputeAndMarkRelevance::FComputeAndMarkRelevance(FVisibilityTaskData& InTaskData, FScene& InScene, FViewInfo& InView, uint8 InViewIndex)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值