Game thread update code flow

For UPrimitiveComponent:

PostLoad()

  • BeginInitResources(): Create static render resources (e.g. index/vertex buffer)

Component Register

  • FScene::AddPrimitive()

  • Calls PrimitiveSceneProxy::CreateSceneProxy()

  • GT Enqueues PrimitiveSceneProxy::SetTransform(): Updates render side xforms, local bounds, & actor position,

    • Calls UpdateUniformBufferMaybeLazy(): Lazily updates uniform buffer

    • Calls virtual OnTransformChanged(): StaticMesh just caches TotalScale3D but isn't used

  • RT Enqueue AddPrimitiveSceneInfo_RenderThread(): Only

  • Allocates new entries into FScene arrays (Bounds, VisiblityIds,OcclusionBounds,ComponentIds)

  • Sets up attachment group, Parent LOD, DistanceFieldSceneData

  • PrimitiveSceneInfo::AddToScene()

    • Mark Precomputed Lighting Buffer Dirty

    • PrimtiiveSceneInfo::AddStaticMeshes(): Add this primtive to StaticMeshDrawlist

    • Proxy::DrawStaticElements(): Collects Static Mesh BatchElements from ScenePrimtiveProxy

      • StaticMeshSceneProxy adds 2 batch elements per mesh element. One for optimized shadows and one for normal rendering
    • AddToDrawLists(): Called on all the FStaticMesh elements added from DrawStaticElements(). Goes through and adds each them to respective StaticMeshDrawList

      • Each DrawPolicyFactory::AddStaticMesh() creates a Drawing Policy for the specific mesh and TStaticMeshDrawlist::AddMesh() it to the corresponding list. Drawing Policies define specific parameters on how to draw this mesh in this specific pass, e.g. DepthDrawingPolicy. They're sorted based on state to minimize state changes

      • FBasePassOpaqueDrawingPolicyFactory::AddStaticMesh() is the main responsible BasePass factory. TBasePassDrawingPolicy is the main draw policy

    • Update PrimitiveOctree

    • Compute Bounds, Visibility Id index, OcclusionFlags, Occlusion Bounds, ComponentIds

    • Loop through Light Octree and create LightPrimitiveInteractions for each Light affecting this Primitive

    • PrimitiveSceneProxy::GetLightRelevance() based on FlightInteraction for primitive (retrieved through PrimitiveSceneProxy::GetInteraction())

Component Transform Update

  • MarkRenderTransformDirty(): Calls MarkForNeededEndOfFrameUpdate() so component can send transform updates at end of frame

  • UWorld::MarkActorComponentForNeededEndOfFrameUpdate() stores this component in its list to do deferred marshalling of sending updates to render thread

  • UActorComponent::DoDeferredRenderUpdates_Concurrent(): Is parallel called to actually send updates to render thread

  • SendRenderTransform_Concurrent() calls FScene::UpdatePrimitiveTransform()

    • For some objects (PrimitiveSceneProxy::ShouldRecreateProxyOnUpdateTransform()), this recreates the render state so it's expensive

    • GT Enqueues UpdatePrimitiveTransform_RenderThread()

    • PrimitiveSceneInfo::RemoveFromScene(): Remove primitive from scene at old location, octree, LightInteractions, & PrecomputedLightingBuffer, and

    • PrimitiveSceneProxy::SetTransform(): Updates render side xforms, local bounds, & actor position,

      • Calls UpdateUniformBufferMaybeLazy(): Lazily updates uniform buffer

      • Calls virtual OnTransformChanged(): StaticMesh just caches TotalScale3D but isn't used

    • PrimitiveSceneInfo::AddToScene(): Cross reference list above

  • Same things happens when render state is marked dirty (gets recreated with remove/add) or render dynamic data gets marked as dirty (SendRenderDynamicData_Concurrent()

For other render components not deriving from UPrimitiveComponent (e.g. Lights/Decals),

Component::CreateRenderState_Concurrent(): - Create dynamic render resources

  • FScene::AddLight/AddDecal()

  • Calls respective CreateSceneProxy()