2019-12-26 14:45:42 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2019-06-11 18:27:07 -04:00
# include "VirtualTextureProducer.h"
# include "VirtualTextureSystem.h"
# include "VirtualTexturePhysicalSpace.h"
2019-08-13 19:14:50 -04:00
FVirtualTextureProducer : : ~ FVirtualTextureProducer ( )
{
}
2019-06-11 18:27:07 -04:00
void FVirtualTextureProducer : : Release ( FVirtualTextureSystem * System , const FVirtualTextureProducerHandle & HandleToSelf )
{
2021-12-03 13:52:23 -05:00
TRACE_CPUPROFILER_EVENT_SCOPE ( FVirtualTextureProducer : : Release ) ;
2019-06-11 18:27:07 -04:00
if ( Description . bPersistentHighestMip )
{
System - > ForceUnlockAllTiles ( HandleToSelf , this ) ;
}
2019-09-17 20:33:19 -04:00
for ( uint32 LayerIndex = 0u ; LayerIndex < Description . NumPhysicalGroups ; + + LayerIndex )
2019-06-11 18:27:07 -04:00
{
2019-09-17 20:33:19 -04:00
FVirtualTexturePhysicalSpace * Space = PhysicalGroups [ LayerIndex ] . PhysicalSpace ;
2019-06-11 18:27:07 -04:00
Space - > GetPagePool ( ) . EvictPages ( System , HandleToSelf ) ;
2019-09-17 20:33:19 -04:00
PhysicalGroups [ LayerIndex ] . PhysicalSpace . SafeRelease ( ) ;
2019-06-11 18:27:07 -04:00
}
2019-09-17 20:33:19 -04:00
PhysicalGroups . Reset ( ) ;
2021-12-03 13:07:44 -05:00
2021-12-03 13:28:25 -05:00
FGraphEventArray ProducePageTasks ;
VirtualTexture - > GatherProducePageDataTasks ( HandleToSelf , ProducePageTasks ) ;
if ( ProducePageTasks . Num ( ) )
2021-12-03 13:07:44 -05:00
{
TRACE_CPUPROFILER_EVENT_SCOPE ( FVirtualTextureProducer : : Release_Wait ) ;
FTaskGraphInterface : : Get ( ) . WaitUntilTasksComplete ( ProducePageTasks , ENamedThreads : : GetRenderThread_Local ( ) ) ;
}
2019-06-11 18:27:07 -04:00
delete VirtualTexture ;
VirtualTexture = nullptr ;
2021-12-03 13:07:44 -05:00
2019-06-11 18:27:07 -04:00
Description = FVTProducerDescription ( ) ;
}
FVirtualTextureProducerCollection : : FVirtualTextureProducerCollection ( ) : NumPendingCallbacks ( 0u )
{
Producers . AddDefaulted ( 1 ) ;
Producers [ 0 ] . Magic = 1u ; // make sure FVirtualTextureProducerHandle(0) will not resolve to the dummy producer entry
Callbacks . AddDefaulted ( CallbackList_Count ) ;
for ( uint32 CallbackIndex = 0u ; CallbackIndex < CallbackList_Count ; + + CallbackIndex )
{
FCallbackEntry & Callback = Callbacks [ CallbackIndex ] ;
Callback . NextIndex = Callback . PrevIndex = CallbackIndex ;
}
}
FVirtualTextureProducerHandle FVirtualTextureProducerCollection : : RegisterProducer ( FVirtualTextureSystem * System , const FVTProducerDescription & InDesc , IVirtualTexture * InProducer )
{
check ( IsInRenderingThread ( ) ) ;
const uint32 ProducerWidth = InDesc . BlockWidthInTiles * InDesc . WidthInBlocks * InDesc . TileSize ;
const uint32 ProducerHeight = InDesc . BlockHeightInTiles * InDesc . HeightInBlocks * InDesc . TileSize ;
check ( ProducerWidth > 0u ) ;
check ( ProducerHeight > 0u ) ;
check ( InDesc . MaxLevel < = FMath : : CeilLogTwo ( FMath : : Max ( ProducerWidth , ProducerHeight ) ) ) ;
2019-09-17 20:33:19 -04:00
check ( InDesc . NumTextureLayers < = VIRTUALTEXTURE_SPACE_MAXLAYERS ) ;
check ( InDesc . NumPhysicalGroups < = InDesc . NumTextureLayers ) ;
2019-06-11 18:27:07 -04:00
check ( InProducer ) ;
const uint32 Index = AcquireEntry ( ) ;
FProducerEntry & Entry = Producers [ Index ] ;
Entry . Producer . Description = InDesc ;
Entry . Producer . VirtualTexture = InProducer ;
Entry . DestroyedCallbacksIndex = AcquireCallback ( ) ;
2019-09-17 20:33:19 -04:00
FVTPhysicalSpaceDescription PhysicalSpaceDesc ;
PhysicalSpaceDesc . Dimensions = InDesc . Dimensions ;
PhysicalSpaceDesc . TileSize = InDesc . TileSize + InDesc . TileBorderSize * 2u ;
PhysicalSpaceDesc . bContinuousUpdate = InDesc . bContinuousUpdate ;
Entry . Producer . PhysicalGroups . SetNum ( InDesc . NumPhysicalGroups ) ;
for ( uint32 PhysicalGroupIndex = 0u ; PhysicalGroupIndex < InDesc . NumPhysicalGroups ; + + PhysicalGroupIndex )
2019-06-11 18:27:07 -04:00
{
2019-09-17 20:33:19 -04:00
PhysicalSpaceDesc . NumLayers = 0 ;
for ( uint32 LayerIndex = 0u ; LayerIndex < InDesc . NumTextureLayers ; + + LayerIndex )
{
if ( InDesc . PhysicalGroupIndex [ LayerIndex ] = = PhysicalGroupIndex )
{
PhysicalSpaceDesc . Format [ PhysicalSpaceDesc . NumLayers ] = InDesc . LayerFormat [ LayerIndex ] ;
PhysicalSpaceDesc . NumLayers + + ;
}
}
check ( PhysicalSpaceDesc . NumLayers > 0 ) ;
Entry . Producer . PhysicalGroups [ PhysicalGroupIndex ] . PhysicalSpace = System - > AcquirePhysicalSpace ( PhysicalSpaceDesc ) ;
2019-06-11 18:27:07 -04:00
}
const FVirtualTextureProducerHandle Handle ( Index , Entry . Magic ) ;
return Handle ;
}
void FVirtualTextureProducerCollection : : ReleaseProducer ( FVirtualTextureSystem * System , const FVirtualTextureProducerHandle & Handle )
{
check ( IsInRenderingThread ( ) ) ;
if ( FProducerEntry * Entry = GetEntry ( Handle ) )
{
uint32 CallbackIndex = Callbacks [ Entry - > DestroyedCallbacksIndex ] . NextIndex ;
while ( CallbackIndex ! = Entry - > DestroyedCallbacksIndex )
{
FCallbackEntry & Callback = Callbacks [ CallbackIndex ] ;
const uint32 NextIndex = Callback . NextIndex ;
check ( Callback . OwnerHandle = = Handle ) ;
check ( ! Callback . bPending ) ;
Callback . bPending = true ;
// Move callback to pending list
RemoveCallbackFromList ( CallbackIndex ) ;
AddCallbackToList ( CallbackList_Pending , CallbackIndex ) ;
+ + NumPendingCallbacks ;
CallbackIndex = NextIndex ;
}
ReleaseCallback ( Entry - > DestroyedCallbacksIndex ) ;
Entry - > DestroyedCallbacksIndex = 0u ;
Entry - > Magic = ( Entry - > Magic + 1u ) & 1023u ;
Entry - > Producer . Release ( System , Handle ) ;
ReleaseEntry ( Handle . Index ) ;
}
}
void FVirtualTextureProducerCollection : : CallPendingCallbacks ( )
{
uint32 CallbackIndex = Callbacks [ CallbackList_Pending ] . NextIndex ;
uint32 NumCallbacksChecked = 0u ;
while ( CallbackIndex ! = CallbackList_Pending )
{
FCallbackEntry & Callback = Callbacks [ CallbackIndex ] ;
check ( Callback . bPending ) ;
// Make a copy, then release the callback entry before calling the callback function
// (The destroyed callback may try to remove this or other callbacks, so need to make sure state is valid before calling)
const FCallbackEntry CallbackCopy ( Callback ) ;
2021-06-21 12:13:58 -04:00
if ( Callback . Baton )
{
TArray < uint32 > & BatonCallbacks = CallbacksMap . FindChecked ( Callback . Baton ) ;
BatonCallbacks . Remove ( CallbackIndex ) ;
if ( BatonCallbacks . IsEmpty ( ) )
{
CallbacksMap . Remove ( Callback . Baton ) ;
}
}
2019-06-11 18:27:07 -04:00
Callback . DestroyedFunction = nullptr ;
Callback . Baton = nullptr ;
Callback . OwnerHandle = FVirtualTextureProducerHandle ( ) ;
Callback . PackedFlags = 0u ;
ReleaseCallback ( CallbackIndex ) ;
// Possible that this callback may have been removed from the list by a previous pending callback
// In this case, the function pointer will be set to nullptr
if ( CallbackCopy . DestroyedFunction )
{
check ( CallbackCopy . OwnerHandle . PackedValue ! = 0u ) ;
CallbackCopy . DestroyedFunction ( CallbackCopy . OwnerHandle , CallbackCopy . Baton ) ;
}
CallbackIndex = CallbackCopy . NextIndex ;
+ + NumCallbacksChecked ;
}
// Extra check to detect list corruption
check ( NumCallbacksChecked = = NumPendingCallbacks ) ;
NumPendingCallbacks = 0u ;
}
void FVirtualTextureProducerCollection : : AddDestroyedCallback ( const FVirtualTextureProducerHandle & Handle , FVTProducerDestroyedFunction * Function , void * Baton )
{
check ( IsInRenderingThread ( ) ) ;
check ( Function ) ;
2021-06-21 12:13:58 -04:00
check ( Baton ) ;
2019-06-11 18:27:07 -04:00
FProducerEntry * Entry = GetEntry ( Handle ) ;
if ( Entry )
{
const uint32 CallbackIndex = AcquireCallback ( ) ;
AddCallbackToList ( Entry - > DestroyedCallbacksIndex , CallbackIndex ) ;
FCallbackEntry & Callback = Callbacks [ CallbackIndex ] ;
Callback . DestroyedFunction = Function ;
Callback . Baton = Baton ;
Callback . OwnerHandle = Handle ;
Callback . PackedFlags = 0u ;
2021-06-21 12:13:58 -04:00
CallbacksMap . FindOrAdd ( Baton ) . Add ( CallbackIndex ) ;
2019-06-11 18:27:07 -04:00
}
}
uint32 FVirtualTextureProducerCollection : : RemoveAllCallbacks ( const void * Baton )
{
check ( IsInRenderingThread ( ) ) ;
check ( Baton ) ;
uint32 NumRemoved = 0u ;
2021-06-22 11:58:55 -04:00
TArray < uint32 > * CallbackIndices = CallbacksMap . Find ( Baton ) ;
if ( CallbackIndices ! = nullptr )
2019-06-11 18:27:07 -04:00
{
2021-06-22 11:58:55 -04:00
for ( int32 CallbackIndex : * CallbackIndices )
2021-06-21 12:13:58 -04:00
{
2021-06-22 11:58:55 -04:00
FCallbackEntry & Callback = Callbacks [ CallbackIndex ] ;
check ( Callback . Baton = = Baton ) ;
check ( Callback . DestroyedFunction ) ;
Callback . DestroyedFunction = nullptr ;
Callback . Baton = nullptr ;
Callback . OwnerHandle = FVirtualTextureProducerHandle ( ) ;
// If callback is already pending, we can't move it back to free list, or we risk corrupting the pending list while it's being iterated
// Setting DestroyedFunction to nullptr here will ensure callback is no longer invoked, and it will be moved to free list later when it's removed from pending list
if ( ! Callback . bPending )
{
Callback . PackedFlags = 0u ;
ReleaseCallback ( CallbackIndex ) ;
}
+ + NumRemoved ;
2019-06-11 18:27:07 -04:00
}
2021-06-22 11:58:55 -04:00
CallbacksMap . Remove ( Baton ) ;
2019-06-11 18:27:07 -04:00
}
return NumRemoved ;
}
2022-03-22 16:05:58 -04:00
void FVirtualTextureProducerCollection : : NotifyRequestsCompleted ( )
{
for ( FProducerEntry & Entry : Producers )
{
if ( Entry . Producer . Description . bNotifyCompleted )
{
Entry . Producer . GetVirtualTexture ( ) - > OnRequestsCompleted ( ) ;
}
}
}
2019-06-11 18:27:07 -04:00
FVirtualTextureProducer * FVirtualTextureProducerCollection : : FindProducer ( const FVirtualTextureProducerHandle & Handle )
{
FProducerEntry * Entry = GetEntry ( Handle ) ;
return Entry ? & Entry - > Producer : nullptr ;
}
FVirtualTextureProducer & FVirtualTextureProducerCollection : : GetProducer ( const FVirtualTextureProducerHandle & Handle )
{
const uint32 Index = Handle . Index ;
check ( Index < ( uint32 ) Producers . Num ( ) ) ;
FProducerEntry & Entry = Producers [ Index ] ;
check ( Entry . Magic = = Handle . Magic ) ;
return Entry . Producer ;
}
FVirtualTextureProducerCollection : : FProducerEntry * FVirtualTextureProducerCollection : : GetEntry ( const FVirtualTextureProducerHandle & Handle )
{
const uint32 Index = Handle . Index ;
if ( Index < ( uint32 ) Producers . Num ( ) )
{
FProducerEntry & Entry = Producers [ Index ] ;
if ( Entry . Magic = = Handle . Magic )
{
return & Entry ;
}
}
return nullptr ;
}