UE4 Mesh Piple Line & Auto Instacing

如需转载本文,请声明作者及出处。

 

Mesh Piple Line

 

Drag a mesh into the scene

Render thead will create all mesh processor.

processor call AddMeshBatch, add draw cmd to cache buckets.

For example:

 

Compute Visibility

 

  1. FrustumCull

  2. Cal View.PrimitiveVisibilityMap , all visible objects

  3. Create FRelevancePacket with View.PrimitiveVisibilityMap

  4. FRelevancePacket.MarRelevant:take draw cmd from cache buckets

  5. FRelevancePacket.RenderThreadFinalize: add draw cmd to ViewCommands.MeshCommands

DynamicMesh

 

SetupMeshPass

 

Insert commands into View.Parallelmeshdrawcommandpasses according to different pass types Each pass takes out the draw cmd according to the pass type For example:

 

 

Auto Instancing

 

TSet<FMeshDrawCommandStateBucke, MeshDrawCommandKeyFuncs> CachedMeshDrawCommandStateBuckets.

 

FMeshDrawCommandStateBucke:

MeshDrawCommandKeyFuncs:

 

Analyze whiche drawcall can be instacing

GetDynamicInstancingHash

 

MatchesForDynamicInstancing

 

 

 

can be instacing:GetKeyHash and MatchesForDynamicInstancing return True MeshPiPleLine Finalize, get the bucket Id of the incoming mesh draw cmd and assign it to different basket and increate the count MeshPassProcessor.SubmitDraw Base on whether the numinstances of each mes draw cmd are greater than 1, it is determined whether to execute the instacing draw call

How to update uniformbuffer

GPU Scene Store the scene information, such as the world matrix, world coordinates, bounding box, lightmap data, etc. of each object in a uniformbuffer. Each object is distinguished by a primitiveid, which is used to address in GPU scene when querying parameters.

A large number of shaders must be adjusted accordingly. All the original shader parameters for each object must be obtained with primitive ID instead.

 

1.FPrimitiveSceneData

FPrimitivescenedata needs to be completely consistent with the data structure of FPrimitiveuniformshaderparameters in the CPU Layer. SceneData.ush A fprimitivescenedata structure is added to replace the original primitive for each object, and an interface getprimitivedata (uint primitiveda) is added struct FPrimitiveSceneData

struct FPrimitiveSceneData
{
    float4x4 LocalToWorld;
    float4 InvNonUniformScaleAndDeterminantSign;
    float4 ObjectWorldPositionAndRadius;
    float4x4 WorldToLocal;
    float4x4 PreviousLocalToWorld;
    float4x4 PreviousWorldToLocal;
    float3 ActorWorldPosition;
    float UseSingleSampleShadowFromStationaryLights;
    float3 ObjectBounds;
    float LpvBiasMultiplier;
    float DecalReceiverMask;
    float PerObjectGBufferData;
    float UseVolumetricLightmapShadowFromStationaryLights;
    float UseEditorDepthTest;
    float4 ObjectOrientation;
    float4 NonUniformScale;
    float3 LocalObjectBoundsMin;
    float3 LocalObjectBoundsMax;
    uint LightingChannelMask;
    uint LightmapDataIndex;
    int SingleCaptureIndex;
};
 

2.Compatibility, for devices that do not support gpuse

// Route to Primitive uniform buffer

#define GetPrimitiveData(x) Primitive

 

3.PrimitiveId Buffer

Primitiveid is added as an additional attribute of vertex,

In order to pass in the primitiveid, a property bsupport primitiveidstream is added to the vertexfactory. When initializing the vertexfactory, a vertexstream is added to store the primitiveid

void FHairStrandsVertexFactory::InitRHI()
{
   Elements.Add(AccessStreamComponent(FVertexStreamComponent(&GPrimitiveIdDummy, 0, 0, sizeof(uint32), VET_UInt, EVertexStreamUsage::Instancing), 13));
        PrimitiveIdStreamIndex = Elements.Last().StreamIndex;

}

Vertex stream usage is set to instancing, which ensures that the primitiveidvertex stream's address is per instance instead of per vertex.

 

4.BuildMeshDrawCommandPrimitiveIdBuffer Assemble the primitiveids of all meshdrawcommands into a buffer, that is, primitiveids

void BuildMeshDrawCommandPrimitiveIdBuffer
{
    //@todo - refactor into instance step rate in the RHI
    for (uint32 InstanceFactorIndex = 0; InstanceFactorIndex < InstanceFactor; InstanceFactorIndex++, PrimitiveIdIndex++)
    {
        //@todo - refactor into memcpy
        checkSlow(PrimitiveIdIndex < MaxPrimitiveId);
        PrimitiveIds[PrimitiveIdIndex] = VisibleMeshDrawCommand.DrawPrimitiveId;
    }
}

5.SubmitDraw Pass in by setting vertexbuffer stream /**

/**
 * Build mesh draw command primitive Id buffer for instancing.
 * TempVisibleMeshDrawCommands must be presized for NewPassVisibleMeshDrawCommands.
 */
void BuildMeshDrawCommandPrimitiveIdBuffer
{

    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;
        }
    }
}

GPUScene Buffer

Upload and update each frame when rendering

 

 

compute shader: transmit gpu scene buffer, which is implemented in ByteBuffer.cpp and ByteBuffer.ush

void FScatterUploadBuilder::UploadTo(FRHICommandList& RHICmdList, FRWBufferStructured& DstBuffer)
{
    RHIUnlockVertexBuffer(ScatterBuffer.Buffer);
    RHIUnlockVertexBuffer(UploadBuffer.Buffer);

    ScatterData = nullptr;
    UploadData = nullptr;

    auto ShaderMap = GetGlobalShaderMap(GMaxRHIFeatureLevel);

    TShaderMapRef<FScatterCopyCS> ComputeShader(ShaderMap);

    const FComputeShaderRHIParamRef ShaderRHI = ComputeShader->GetComputeShader();
    RHICmdList.SetComputeShader(ShaderRHI);

    SetShaderValue(RHICmdList, ShaderRHI, ComputeShader->NumScatters, NumScatters);
    SetSRVParameter(RHICmdList, ShaderRHI, ComputeShader->ScatterBuffer, ScatterBuffer.SRV);
    SetSRVParameter(RHICmdList, ShaderRHI, ComputeShader->UploadBuffer, UploadBuffer.SRV);
    SetUAVParameter(RHICmdList, ShaderRHI, ComputeShader->DstBuffer, DstBuffer.UAV);

    RHICmdList.DispatchComputeShader(FMath::DivideAndRoundUp<uint32>(NumScatters, FScatterCopyCS::ThreadGroupSize), 1, 1);

    SetUAVParameter(RHICmdList, ShaderRHI, ComputeShader->DstBuffer, FUnorderedAccessViewRHIRef());
}
// ByteBuffer.ush
 ...
uint NumScatters;
Buffer<float4> UploadBuffer;
Buffer<uint> ScatterBuffer;

[numthreads(THREADGROUP_SIZE, 1, 1)]
void ScatterCopyCS( uint3 DispatchThreadId : SV_DispatchThreadID )
{
    uint ScatterIndex = DispatchThreadId.x;

    if (ScatterIndex < NumScatters)
    {
        uint DestIndex = ScatterBuffer.Load(ScatterIndex);
        uint SrcIndex = ScatterIndex;
        DstBuffer[DestIndex] = UploadBuffer.Load(SrcIndex);
    }
}

End:

 

summary from : Mesh Auto-Instancing on Mobile

 

Auto-instancing on mobile mainly benefits projects that are heavily CPU-bound rather than GPU-bound. While it is unlikely that enabling auto-instancing will harm a GPU-bound project, you are less likely to see significant performance improvements from using it.

If a game is heavily memory-bound, it may be more beneficial to turn off r.Mobile.UseGPUSceneTexture and use the buffer instead, with the understanding that it will not work on Mali devices.

 

My thoughts: 1.work on Mali devices. huawei jj~

2.Updating buffer per frame brings consumption.

If so many many number of primitives , execute computer shader will also cause certain pressure on GPU

That is because:" While it is unlikely that enabling auto-instancing will harm a GPU-bound project, you are less likely to see significant performance improvements from using it."

3.GPU scene , If the buff is not enough, It maybe use other buffs such as texture buff, which is more expensive

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值