void FIndirectLightingCache::UpdateCachePrimitivesInternal(FScene* Scene, FSceneRenderer& Renderer, bool bAllowUnbuiltPreview, TMap<FIntVector, FBlockUpdateInfo>& OutBlocksToUpdate, TArray<FIndirectLightingCacheAllocation*>& OutTransitionsOverTimeToUpdate) { SCOPE_CYCLE_COUNTER(STAT_UpdateIndirectLightingCachePrims); const TMap<FPrimitiveComponentId, FAttachmentGroupSceneInfo>& AttachmentGroups = Scene->AttachmentGroups; if (IndirectLightingAllowed(Scene, Renderer)) { if (bUpdateAllCacheEntries) { const uint32 PrimitiveCount = Scene->Primitives.Num(); for (uint32 PrimitiveIndex = 0; PrimitiveIndex < PrimitiveCount; ++PrimitiveIndex) { FPrimitiveSceneInfo* PrimitiveSceneInfo = Scene->Primitives[PrimitiveIndex]; const bool bPrecomputedLightingBufferWasDirty = PrimitiveSceneInfo->NeedsPrecomputedLightingBufferUpdate(); UpdateCachePrimitive(AttachmentGroups, PrimitiveSceneInfo, false, true, OutBlocksToUpdate, OutTransitionsOverTimeToUpdate); // If it was already dirty, then the primitive is already in one of the view dirty primitive list at this point. // This also ensures that a primitive does not get added twice to the list, which could create an array reallocation. if (!bPrecomputedLightingBufferWasDirty) { PrimitiveSceneInfo->MarkPrecomputedLightingBufferDirty(); // Check if it is visible otherwise, it will be updated next time it is visible. for (int32 ViewIndex = 0; ViewIndex < Renderer.Views.Num(); ViewIndex++) { FViewInfo& View = Renderer.Views[ViewIndex]; if (View.PrimitiveVisibilityMap[PrimitiveIndex]) { // Since the update can be executed on a threaded job (see GILCUpdatePrimTaskEnabled), no reallocation must happen here. checkSlow(View.DirtyPrecomputedLightingBufferPrimitives.Num() < View.DirtyPrecomputedLightingBufferPrimitives.Max()); View.DirtyPrecomputedLightingBufferPrimitives.Push(PrimitiveSceneInfo); break; // We only need to add it in one of the view list. } } } } } else { TArray<uint32> SetBitIndices[4]; { QUICK_SCOPE_CYCLE_COUNTER(STAT_UpdateCachePreWalk); for (int32 ViewIndex = 0; ViewIndex < Renderer.Views.Num(); ViewIndex++) { FViewInfo& View = Renderer.Views[ViewIndex]; SetBitIndices[ViewIndex].Reserve(View.PrimitiveVisibilityMap.Num()); for (FSceneSetBitIterator BitIt(View.PrimitiveVisibilityMap); BitIt; ++BitIt) { uint32 PrimitiveIndex = BitIt.GetIndex(); SetBitIndices[ViewIndex].Add(PrimitiveIndex); } // Any visible primitives with an indirect shadow need their ILC updated, since that determines the indirect shadow direction for (int32 IndirectPrimitiveIndex = 0; IndirectPrimitiveIndex < View.IndirectShadowPrimitives.Num(); IndirectPrimitiveIndex++) { int32 PrimitiveIndex = View.IndirectShadowPrimitives[IndirectPrimitiveIndex]->GetIndex(); SetBitIndices[ViewIndex].AddUnique(PrimitiveIndex); } } } // Go over the views and operate on any relevant visible primitives for (int32 ViewIndex = 0; ViewIndex < Renderer.Views.Num(); ViewIndex++) { FViewInfo& View = Renderer.Views[ViewIndex]; const TArray<uint32>& SetBits = SetBitIndices[ViewIndex]; for (int32 i = 0; i < SetBits.Num(); ++i) { uint32 PrimitiveIndex = SetBits[i]; FPrimitiveSceneInfo* PrimitiveSceneInfo = Scene->Primitives[PrimitiveIndex]; const bool bPrecomputedLightingBufferWasDirty = PrimitiveSceneInfo->NeedsPrecomputedLightingBufferUpdate(); const FPrimitiveViewRelevance& PrimitiveRelevance = View.PrimitiveViewRelevanceMap[PrimitiveIndex]; UpdateCachePrimitive(AttachmentGroups, PrimitiveSceneInfo, bAllowUnbuiltPreview, PrimitiveRelevance.bOpaqueRelevance, OutBlocksToUpdate, OutTransitionsOverTimeToUpdate); // If it was already dirty, then the primitive is already in one of the view dirty primitive list at this point. // This also ensures that a primitive does not get added twice to the list, which could create an array reallocation. if (!bPrecomputedLightingBufferWasDirty && PrimitiveSceneInfo->NeedsPrecomputedLightingBufferUpdate()) { // Since the update can be executed on a threaded job (see GILCUpdatePrimTaskEnabled), no reallocation must happen here. checkSlow(View.DirtyPrecomputedLightingBufferPrimitives.Num() < View.DirtyPrecomputedLightingBufferPrimitives.Max()); View.DirtyPrecomputedLightingBufferPrimitives.Push(PrimitiveSceneInfo); } } } } bUpdateAllCacheEntries = false; } }
void FIndirectLightingCache::UpdateCache(FScene* Scene, FSceneRenderer& Renderer, bool bAllowUnbuiltPreview) { if (IsIndirectLightingCacheAllowed()) { bool bAnyViewAllowsIndirectLightingCache = false; for (int32 ViewIndex = 0; ViewIndex < Renderer.Views.Num(); ViewIndex++) { bAnyViewAllowsIndirectLightingCache |= Renderer.Views[ViewIndex].Family->EngineShowFlags.IndirectLightingCache; } if (bAnyViewAllowsIndirectLightingCache) { SCOPE_CYCLE_COUNTER(STAT_UpdateIndirectLightingCache); TMap<FIntVector, FBlockUpdateInfo> BlocksToUpdate; TArray<FIndirectLightingCacheAllocation*> TransitionsOverTimeToUpdate; if (bUpdateAllCacheEntries) { const uint32 PrimitiveCount = Scene->Primitives.Num(); for (uint32 PrimitiveIndex = 0; PrimitiveIndex < PrimitiveCount; ++PrimitiveIndex) { FPrimitiveSceneInfo* PrimitiveSceneInfo = Scene->Primitives[PrimitiveIndex]; UpdateCachePrimitive(Scene, PrimitiveSceneInfo, false, true, BlocksToUpdate, TransitionsOverTimeToUpdate); } } // Go over the views and operate on any relevant visible primitives for (int32 ViewIndex = 0; ViewIndex < Renderer.Views.Num(); ViewIndex++) { FViewInfo& View = Renderer.Views[ViewIndex]; if (!bUpdateAllCacheEntries) { for (FSceneSetBitIterator BitIt(View.PrimitiveVisibilityMap); BitIt; ++BitIt) { uint32 PrimitiveIndex = BitIt.GetIndex(); FPrimitiveSceneInfo* PrimitiveSceneInfo = Scene->Primitives[PrimitiveIndex]; const FPrimitiveViewRelevance& PrimitiveRelevance = View.PrimitiveViewRelevanceMap[PrimitiveIndex]; UpdateCachePrimitive(Scene, PrimitiveSceneInfo, bAllowUnbuiltPreview, PrimitiveRelevance.bOpaqueRelevance, BlocksToUpdate, TransitionsOverTimeToUpdate); } } UpdateTranslucentVolumeCache(View, BlocksToUpdate, TransitionsOverTimeToUpdate); } UpdateBlocks(Scene, Renderer.Views.GetTypedData(), BlocksToUpdate); UpdateTransitionsOverTime(TransitionsOverTimeToUpdate, Renderer.ViewFamily.DeltaWorldTime); if (GCacheDrawLightingSamples || Renderer.ViewFamily.EngineShowFlags.VolumeLightingSamples || GCacheDrawDirectionalShadowing) { FViewElementPDI DebugPDI(Renderer.Views.GetTypedData(), NULL); for (int32 VolumeIndex = 0; VolumeIndex < Scene->PrecomputedLightVolumes.Num(); VolumeIndex++) { const FPrecomputedLightVolume* PrecomputedLightVolume = Scene->PrecomputedLightVolumes[VolumeIndex]; PrecomputedLightVolume->DebugDrawSamples(&DebugPDI, GCacheDrawDirectionalShadowing != 0); } } } bUpdateAllCacheEntries = false; } }