2022-09-26 15:12:13 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
2022-10-01 02:04:57 -04:00
# include "MuCO/CustomizableObjectSystem.h"
2022-09-26 15:12:13 -04:00
2022-10-02 10:56:02 -04:00
# include "Animation/Skeleton.h"
# include "AssetRegistry/ARFilter.h"
# include "AssetRegistry/AssetRegistryModule.h"
# include "Engine/SkeletalMesh.h"
2023-01-12 01:48:34 -05:00
# include "Engine/SkinnedAsset.h"
# include "Engine/SkinnedAssetCommon.h"
2023-09-13 06:59:56 -04:00
# include "Engine/SkeletalMeshLODSettings.h"
2022-10-02 10:56:02 -04:00
# include "GameFramework/PlayerController.h"
# include "Interfaces/ITargetPlatform.h"
# include "MuCO/CustomizableInstanceLODManagement.h"
2022-10-01 02:04:57 -04:00
# include "MuCO/CustomizableInstancePrivateData.h"
2022-10-02 10:56:02 -04:00
# include "MuCO/CustomizableObjectPrivate.h"
2022-11-04 09:18:44 -04:00
# include "MuCO/DefaultImageProvider.h"
2023-10-24 08:17:10 -04:00
# include "MuCO/CustomizableObjectInstanceUsage.h"
2022-10-02 10:56:02 -04:00
# include "MuCO/ICustomizableObjectModule.h"
# include "MuCO/LogBenchmarkUtil.h"
# include "MuCO/LogInformationUtil.h"
2023-04-05 11:20:44 -04:00
# include "MuCO/UnrealExtensionDataStreamer.h"
2022-10-01 02:06:09 -04:00
# include "MuCO/UnrealMutableImageProvider.h"
2022-10-01 02:04:57 -04:00
# include "MuCO/UnrealMutableModelDiskStreamer.h"
2023-04-04 06:06:06 -04:00
# include "MuCO/UnrealPortabilityHelpers.h"
2023-01-12 01:48:34 -05:00
# include "MuR/Model.h"
2022-10-02 10:56:02 -04:00
# include "MuR/Settings.h"
# include "UObject/UObjectIterator.h"
# include "Widgets/Notifications/SNotificationList.h"
2023-03-15 07:39:39 -04:00
# include "ContentStreaming.h"
2023-09-07 06:34:12 -04:00
# include "MuCO/EditorImageProvider.h"
2023-10-24 08:17:10 -04:00
# include "Components/SkeletalMeshComponent.h"
2023-11-30 09:17:22 -05:00
# include "CustomizableObjectSystemPrivate.h"
2022-09-26 15:12:13 -04:00
# if WITH_EDITOR
# include "Editor.h"
2022-10-02 10:56:02 -04:00
# include "Logging/MessageLog.h"
2022-09-26 15:12:13 -04:00
# include "Misc/ConfigCacheIni.h"
# include "Misc/MessageDialog.h"
2023-09-14 05:31:42 -04:00
# include "Engine/World.h"
2023-01-12 02:59:45 -05:00
# else
# include "Engine/Engine.h"
2022-09-26 15:12:13 -04:00
# endif
2022-10-02 10:56:02 -04:00
# include UE_INLINE_GENERATED_CPP_BY_NAME(CustomizableObjectSystem)
class AActor ;
class UAnimInstance ;
2022-09-26 15:12:13 -04:00
2023-10-17 03:57:37 -04:00
void CacheTexturesParameters ( const TArray < FName > & TextureParameters ) ;
void UnCacheTexturesParameters ( const TArray < FName > & TextureParameters ) ;
2022-09-26 15:12:13 -04:00
DECLARE_CYCLE_STAT ( TEXT ( " MutablePendingRelease Time " ) , STAT_MutablePendingRelease , STATGROUP_Game ) ;
DECLARE_CYCLE_STAT ( TEXT ( " MutableTask " ) , STAT_MutableTask , STATGROUP_Game ) ;
2023-10-16 12:05:17 -04:00
# define UE_MUTABLE_UPDATE_REGION TEXT("Mutable Update")
2022-09-26 15:12:13 -04:00
UCustomizableObjectSystem * FCustomizableObjectSystemPrivate : : SSystem = nullptr ;
2023-05-24 02:50:03 -04:00
static TAutoConsoleVariable < int32 > CVarWorkingMemory (
TEXT ( " mutable.WorkingMemory " ) ,
2023-03-14 07:59:06 -04:00
# if !PLATFORM_DESKTOP
2023-05-24 02:50:03 -04:00
( 10 * 1024 ) ,
2023-03-14 07:59:06 -04:00
# else
2023-05-24 02:50:03 -04:00
( 50 * 1024 ) ,
2023-03-14 07:59:06 -04:00
# endif
2023-05-24 02:50:03 -04:00
TEXT ( " Limit the amount of memory (in KB) to use as working memory when building characters. More memory reduces the object construction time. 0 means no restriction. Defaults: Desktop = 50,000 KB, Others = 10,000 KB " ) ,
2022-09-26 15:12:13 -04:00
ECVF_Scalability ) ;
2023-05-24 02:50:03 -04:00
TAutoConsoleVariable < bool > CVarClearWorkingMemoryOnUpdateEnd (
2023-06-01 04:30:20 -04:00
TEXT ( " mutable.ClearWorkingMemoryOnUpdateEnd " ) ,
2023-03-07 12:43:38 -05:00
false ,
2023-05-26 15:05:33 -04:00
TEXT ( " Clear the working memory and cache after every Mutable operation. " ) ,
2023-03-07 12:43:38 -05:00
ECVF_Scalability ) ;
2023-06-27 06:04:11 -04:00
TAutoConsoleVariable < bool > CVarReuseImagesBetweenInstances (
TEXT ( " mutable.ReuseImagesBetweenInstances " ) ,
2023-09-20 06:20:12 -04:00
true ,
2023-06-27 06:04:11 -04:00
TEXT ( " Enables or disables the reuse of images between instances. " ) ,
2023-03-17 06:24:34 -04:00
ECVF_Scalability ) ;
2023-06-26 02:16:47 -04:00
static TAutoConsoleVariable < int32 > CVarGeneratedResourcesCacheSize (
TEXT ( " mutable.GeneratedResourcesCacheSize " ) ,
512 ,
TEXT ( " Limit the number of resources (images and meshes) that will be tracked for reusal. Each tracked resource uses a small amout of memory for its key. " ) ,
ECVF_Scalability ) ;
2023-11-03 09:34:38 -04:00
TAutoConsoleVariable < bool > CVarPreserveUserLODsOnFirstGeneration (
TEXT ( " mutable.PreserveUserLODsOnFirstGeneration " ) ,
true ,
TEXT ( " If false, force disable UCustomizableObject::bPreserveUserLODsOnFirstGeneration. " ) ,
ECVF_Scalability ) ;
2023-11-03 14:21:25 -04:00
TAutoConsoleVariable < bool > CVarEnableMeshCache (
TEXT ( " mutable.EnableMeshCache " ) ,
true ,
TEXT ( " Enables or disables the reuse of meshes. " ) ,
ECVF_Scalability ) ;
2023-08-22 08:38:33 -04:00
int32 FCustomizableObjectSystemPrivate : : SkeletalMeshMinLodQualityLevel = - 1 ;
2023-11-03 09:34:38 -04:00
2023-08-22 08:38:33 -04:00
static void CVarMutableSinkFunction ( )
{
if ( UCustomizableObjectSystem : : IsCreated ( ) )
{
FCustomizableObjectSystemPrivate * PrivateSystem = UCustomizableObjectSystem : : GetInstance ( ) - > GetPrivate ( ) ;
static const IConsoleVariable * CVarSkeletalMeshMinLodQualityLevelCVarName = IConsoleManager : : Get ( ) . FindConsoleVariable ( TEXT ( " r.SkeletalMesh.MinLodQualityLevel " ) ) ;
PrivateSystem - > SkeletalMeshMinLodQualityLevel = CVarSkeletalMeshMinLodQualityLevelCVarName ? CVarSkeletalMeshMinLodQualityLevelCVarName - > GetInt ( ) : INDEX_NONE ;
}
}
2023-09-07 04:23:11 -04:00
2023-08-22 08:38:33 -04:00
static FAutoConsoleVariableSink CVarMutableSink ( FConsoleCommandDelegate : : CreateStatic ( & CVarMutableSinkFunction ) ) ;
2023-03-17 06:24:34 -04:00
2023-10-17 03:57:37 -04:00
FUpdateContextPrivate : : FUpdateContextPrivate ( UCustomizableObjectInstance & InInstance )
{
check ( InInstance . GetPrivate ( ) ) ;
check ( InInstance . GetCustomizableObject ( ) ) ;
Instance = & InInstance ;
InstanceDescriptorRuntimeHash = FDescriptorRuntimeHash ( Instance - > GetDescriptor ( ) ) ;
InInstance . GetPrivate ( ) - > UpdateDescriptorRuntimeHash = InstanceDescriptorRuntimeHash ; // TODO GMTFuture Remove on MTBL-1409
State = InInstance . GetState ( ) ;
bBuildParameterRelevancy = InInstance . GetBuildParameterRelevancy ( ) ;
Parameters = InInstance . GetDescriptor ( ) . GetParameters ( ) ;
TextureParameters = InInstance . GetPrivate ( ) - > UpdateTextureParameters ;
2023-11-08 08:42:39 -05:00
NumComponents = InInstance . GetCustomizableObject ( ) - > GetComponentCount ( ) ;
2023-11-03 09:34:38 -04:00
CurrentMinLOD = InInstance . GetCurrentMinLOD ( ) ;
2023-11-08 08:42:39 -05:00
CurrentMaxLOD = InInstance . GetCurrentMaxLOD ( ) ;
2023-11-03 09:34:38 -04:00
RequestedLODs = InInstance . GetRequestedLODsPerComponent ( ) ;
2023-10-17 03:57:37 -04:00
InInstance . GetCustomizableObject ( ) - > ApplyStateForcedValuesToParameters ( State , Parameters . get ( ) ) ;
CacheTexturesParameters ( TextureParameters ) ;
}
FUpdateContextPrivate : : ~ FUpdateContextPrivate ( )
{
UnCacheTexturesParameters ( TextureParameters ) ;
}
2023-11-03 14:21:25 -04:00
FString FUpdateContextPrivate : : GetReferencerName ( ) const
{
return TEXT ( " FUpdateContextPrivate " ) ;
}
void FUpdateContextPrivate : : AddReferencedObjects ( FReferenceCollector & Collector )
{
Collector . AddReferencedObjects ( Objects ) ;
}
2023-10-17 03:57:37 -04:00
FMutablePendingInstanceUpdate : : FMutablePendingInstanceUpdate ( const TSharedRef < FUpdateContextPrivate > & InContext ) :
Context ( InContext )
{
}
bool FMutablePendingInstanceUpdate : : operator = = ( const FMutablePendingInstanceUpdate & Other ) const
{
return Context - > Instance . HasSameIndexAndSerialNumber ( Other . Context - > Instance ) ;
}
bool FMutablePendingInstanceUpdate : : operator < ( const FMutablePendingInstanceUpdate & Other ) const
{
if ( Context - > PriorityType < Other . Context - > PriorityType )
{
return true ;
}
else if ( Context - > PriorityType > Other . Context - > PriorityType )
{
return false ;
}
else
{
2023-11-21 10:47:27 -05:00
return Context - > StartQueueTime < Other . Context - > StartQueueTime ;
2023-10-17 03:57:37 -04:00
}
}
uint32 GetTypeHash ( const FMutablePendingInstanceUpdate & Update )
{
return GetTypeHash ( Update . Context - > Instance . GetWeakPtrTypeHash ( ) ) ;
}
TWeakObjectPtr < const UCustomizableObjectInstance > FPendingInstanceUpdateKeyFuncs : : GetSetKey ( const FMutablePendingInstanceUpdate & PendingUpdate )
{
return PendingUpdate . Context - > Instance ;
}
bool FPendingInstanceUpdateKeyFuncs : : Matches ( const TWeakObjectPtr < const UCustomizableObjectInstance > & A , const TWeakObjectPtr < const UCustomizableObjectInstance > & B )
{
return A . HasSameIndexAndSerialNumber ( B ) ;
}
uint32 FPendingInstanceUpdateKeyFuncs : : GetKeyHash ( const TWeakObjectPtr < const UCustomizableObjectInstance > & Identifier )
{
return GetTypeHash ( Identifier . GetWeakPtrTypeHash ( ) ) ;
}
2023-06-22 06:24:44 -04:00
int32 FMutablePendingInstanceWork : : Num ( ) const
2022-09-26 15:12:13 -04:00
{
2023-06-22 06:24:44 -04:00
return PendingInstanceUpdates . Num ( ) + PendingInstanceDiscards . Num ( ) + PendingIDsToRelease . Num ( ) + NumLODUpdatesLastTick ;
2022-09-26 15:12:13 -04:00
}
2023-06-22 06:24:44 -04:00
void FMutablePendingInstanceWork : : SetLODUpdatesLastTick ( int32 NumLODUpdates )
2022-09-26 15:12:13 -04:00
{
2023-06-22 06:24:44 -04:00
NumLODUpdatesLastTick = NumLODUpdates ;
}
void FMutablePendingInstanceWork : : AddUpdate ( const FMutablePendingInstanceUpdate & UpdateToAdd )
{
2023-11-21 10:47:27 -05:00
UpdateToAdd . Context - > StartQueueTime = FPlatformTime : : Seconds ( ) ;
2023-10-17 03:57:37 -04:00
if ( const FMutablePendingInstanceUpdate * ExistingUpdate = PendingInstanceUpdates . Find ( UpdateToAdd . Context - > Instance ) )
2022-09-26 15:12:13 -04:00
{
2023-10-17 03:57:37 -04:00
ExistingUpdate - > Context - > UpdateResult = EUpdateResult : : ErrorReplaced ;
FinishUpdateGlobal ( ExistingUpdate - > Context ) ;
2023-11-21 10:47:27 -05:00
const FMutablePendingInstanceUpdate TaskToEnqueue = UpdateToAdd ;
2023-10-17 03:57:37 -04:00
TaskToEnqueue . Context - > PriorityType = FMath : : Min ( ExistingUpdate - > Context - > PriorityType , UpdateToAdd . Context - > PriorityType ) ;
2023-11-21 10:47:27 -05:00
TaskToEnqueue . Context - > StartQueueTime = FMath : : Min ( ExistingUpdate - > Context - > StartQueueTime , UpdateToAdd . Context - > StartQueueTime ) ;
2023-04-06 16:56:51 -04:00
2023-11-21 10:47:27 -05:00
RemoveUpdate ( ExistingUpdate - > Context - > Instance ) ;
2023-06-22 06:24:44 -04:00
PendingInstanceUpdates . Add ( TaskToEnqueue ) ;
2022-09-26 15:12:13 -04:00
}
2023-06-22 06:24:44 -04:00
else
2022-09-26 15:12:13 -04:00
{
2023-06-22 06:24:44 -04:00
PendingInstanceUpdates . Add ( UpdateToAdd ) ;
2022-09-26 15:12:13 -04:00
}
2023-10-17 03:57:37 -04:00
if ( const FMutablePendingInstanceDiscard * ExistingDiscard = PendingInstanceDiscards . Find ( UpdateToAdd . Context - > Instance ) )
2022-09-26 15:12:13 -04:00
{
2023-10-17 03:57:37 -04:00
UpdateToAdd . Context - > UpdateResult = EUpdateResult : : ErrorReplaced ;
FinishUpdateGlobal ( UpdateToAdd . Context ) ;
2023-06-22 06:24:44 -04:00
PendingInstanceDiscards . Remove ( ExistingDiscard - > CustomizableObjectInstance ) ;
2022-09-26 15:12:13 -04:00
}
}
2023-06-22 06:24:44 -04:00
void FMutablePendingInstanceWork : : RemoveUpdate ( const TWeakObjectPtr < UCustomizableObjectInstance > & Instance )
2022-09-26 15:12:13 -04:00
{
2023-11-21 10:47:27 -05:00
if ( const FMutablePendingInstanceUpdate * Update = PendingInstanceUpdates . Find ( Instance ) )
{
Update - > Context - > QueueTime = FPlatformTime : : Seconds ( ) - Update - > Context - > StartQueueTime ;
PendingInstanceUpdates . Remove ( Instance ) ;
}
2023-06-22 06:24:44 -04:00
}
2023-10-02 05:40:58 -04:00
const FMutablePendingInstanceUpdate * FMutablePendingInstanceWork : : GetUpdate ( const TWeakObjectPtr < const UCustomizableObjectInstance > & Instance ) const
2023-06-22 06:24:44 -04:00
{
return PendingInstanceUpdates . Find ( Instance ) ;
}
void FMutablePendingInstanceWork : : AddDiscard ( const FMutablePendingInstanceDiscard & TaskToEnqueue )
{
2023-09-07 04:23:11 -04:00
if ( const FMutablePendingInstanceUpdate * ExistingUpdate = PendingInstanceUpdates . Find ( TaskToEnqueue . CustomizableObjectInstance . Get ( ) ) )
2022-09-26 15:12:13 -04:00
{
2023-10-17 03:57:37 -04:00
ExistingUpdate - > Context - > UpdateResult = EUpdateResult : : ErrorReplaced ;
FinishUpdateGlobal ( ExistingUpdate - > Context ) ;
2023-11-21 10:47:27 -05:00
RemoveUpdate ( ExistingUpdate - > Context - > Instance ) ;
2022-09-26 15:12:13 -04:00
}
2023-06-22 06:24:44 -04:00
PendingInstanceDiscards . Add ( TaskToEnqueue ) ;
2022-09-26 15:12:13 -04:00
}
2023-06-22 06:24:44 -04:00
void FMutablePendingInstanceWork : : AddIDRelease ( mu : : Instance : : ID IDToRelease )
2022-09-26 15:12:13 -04:00
{
2023-06-22 06:24:44 -04:00
PendingIDsToRelease . Add ( IDToRelease ) ;
}
2022-09-26 15:12:13 -04:00
UCustomizableObjectSystem * UCustomizableObjectSystem : : GetInstance ( )
{
if ( ! FCustomizableObjectSystemPrivate : : SSystem )
{
2023-04-27 05:10:23 -04:00
UE_LOG ( LogMutable , Log , TEXT ( " Creating Mutable Customizable Object System. " ) ) ;
2022-09-26 15:12:13 -04:00
check ( IsInGameThread ( ) ) ;
FCustomizableObjectSystemPrivate : : SSystem = NewObject < UCustomizableObjectSystem > ( UCustomizableObjectSystem : : StaticClass ( ) ) ;
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
check ( FCustomizableObjectSystemPrivate : : SSystem ! = nullptr ) ;
2022-09-26 15:12:13 -04:00
checkf ( ! GUObjectArray . IsDisregardForGC ( FCustomizableObjectSystemPrivate : : SSystem ) , TEXT ( " Mutable was initialized too early in the UE4 init process, for instance, in the constructor of a default UObject. " ) ) ;
FCustomizableObjectSystemPrivate : : SSystem - > AddToRoot ( ) ;
checkf ( ! GUObjectArray . IsDisregardForGC ( FCustomizableObjectSystemPrivate : : SSystem ) , TEXT ( " Mutable was initialized too early in the UE4 init process, for instance, in the constructor of a default UObject. " ) ) ;
FCustomizableObjectSystemPrivate : : SSystem - > InitSystem ( ) ;
//FCoreUObjectDelegates::PurgePendingReleaseSkeletalMesh.AddUObject(FCustomizableObjectSystemPrivate::SSystem, &UCustomizableObjectSystem::PurgePendingReleaseSkeletalMesh);
}
return FCustomizableObjectSystemPrivate : : SSystem ;
}
2023-09-07 04:23:11 -04:00
UCustomizableObjectSystem * UCustomizableObjectSystem : : GetInstanceChecked ( )
{
UCustomizableObjectSystem * System = GetInstance ( ) ;
check ( System ) ;
return System ;
}
UCustomizableInstanceLODManagementBase * UCustomizableObjectSystem : : GetInstanceLODManagement ( ) const
{
return CurrentInstanceLODManagement . Get ( ) ;
}
void UCustomizableObjectSystem : : SetInstanceLODManagement ( UCustomizableInstanceLODManagementBase * NewInstanceLODManagement )
{
CurrentInstanceLODManagement = NewInstanceLODManagement ? NewInstanceLODManagement : ToRawPtr ( DefaultInstanceLODManagement ) ;
}
2022-09-26 15:12:13 -04:00
FString UCustomizableObjectSystem : : GetPluginVersion ( ) const
{
// Bridge the call from the module. This implementation is available from blueprint.
return ICustomizableObjectModule : : Get ( ) . GetPluginVersion ( ) ;
}
void UCustomizableObjectSystem : : LogShowData ( bool bFullInfo , bool ShowMaterialInfo ) const
{
LogInformationUtil : : ResetCounters ( ) ;
TArray < UCustomizableObjectInstance * > ArrayData ;
2023-10-24 08:17:10 -04:00
for ( TObjectIterator < UCustomizableObjectInstanceUsage > It ; It ; + + It )
2022-09-26 15:12:13 -04:00
{
2023-10-24 08:17:10 -04:00
const UCustomizableObjectInstanceUsage * CustomizableObjectInstanceUsage = * It ;
2022-09-26 15:12:13 -04:00
2023-09-22 04:26:19 -04:00
# if WITH_EDITOR
2023-11-09 06:25:16 -05:00
if ( IsValid ( CustomizableObjectInstanceUsage ) & & CustomizableObjectInstanceUsage - > IsNetMode ( NM_DedicatedServer ) )
2023-09-22 04:26:19 -04:00
{
continue ;
}
# endif
2023-11-09 06:25:16 -05:00
if ( IsValid ( CustomizableObjectInstanceUsage ) & & CustomizableObjectInstanceUsage - > GetCustomizableObjectInstance ( )
2023-10-24 08:17:10 -04:00
& & CustomizableObjectInstanceUsage - > GetAttachParent ( ) )
2022-09-26 15:12:13 -04:00
{
2023-10-24 08:17:10 -04:00
const AActor * ParentActor = CustomizableObjectInstanceUsage - > GetAttachParent ( ) - > GetAttachmentRootActor ( ) ;
2022-09-26 15:12:13 -04:00
if ( ParentActor ! = nullptr )
{
2023-10-24 08:17:10 -04:00
ArrayData . AddUnique ( CustomizableObjectInstanceUsage - > GetCustomizableObjectInstance ( ) ) ;
2022-09-26 15:12:13 -04:00
}
}
}
ArrayData . Sort ( [ ] ( UCustomizableObjectInstance & A , UCustomizableObjectInstance & B )
{
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
check ( A . GetPrivate ( ) ! = nullptr ) ;
check ( B . GetPrivate ( ) ! = nullptr ) ;
2022-09-26 15:12:13 -04:00
return ( A . GetPrivate ( ) - > LastMinSquareDistFromComponentToPlayer < B . GetPrivate ( ) - > LastMinSquareDistFromComponentToPlayer ) ;
} ) ;
2023-09-07 04:23:11 -04:00
int32 i ;
const int32 Max = ArrayData . Num ( ) ;
2022-09-26 15:12:13 -04:00
if ( bFullInfo )
{
for ( i = 0 ; i < Max ; + + i )
{
LogInformationUtil : : LogShowInstanceDataFull ( ArrayData [ i ] , ShowMaterialInfo ) ;
}
}
else
{
FString LogData = " \n \n " ;
for ( i = 0 ; i < Max ; + + i )
{
LogInformationUtil : : LogShowInstanceData ( ArrayData [ i ] , LogData ) ;
}
2023-04-27 05:10:23 -04:00
UE_LOG ( LogMutable , Log , TEXT ( " %s " ) , * LogData ) ;
2022-09-26 15:12:13 -04:00
UWorld * World = GWorld ;
if ( World )
{
APlayerController * PlayerController = World - > GetFirstPlayerController ( ) ;
if ( PlayerController )
{
PlayerController - > ClientMessage ( LogData ) ;
}
}
}
}
2023-05-24 10:22:36 -04:00
FCustomizableObjectSystemPrivate * UCustomizableObjectSystem : : GetPrivate ( )
{
return Private . Get ( ) ;
}
const FCustomizableObjectSystemPrivate * UCustomizableObjectSystem : : GetPrivate ( ) const
{
return Private . Get ( ) ;
}
FCustomizableObjectSystemPrivate * UCustomizableObjectSystem : : GetPrivateChecked ( )
{
check ( Private )
return Private . Get ( ) ;
}
const FCustomizableObjectSystemPrivate * UCustomizableObjectSystem : : GetPrivateChecked ( ) const
{
check ( Private )
return Private . Get ( ) ;
}
2023-09-07 04:23:11 -04:00
FStreamableManager & UCustomizableObjectSystem : : GetStreamableManager ( )
{
return StreamableManager ;
}
2022-09-26 15:12:13 -04:00
bool UCustomizableObjectSystem : : IsCreated ( )
{
return FCustomizableObjectSystemPrivate : : SSystem ! = 0 ;
}
void UCustomizableObjectSystem : : InitSystem ( )
{
// Everything initialized in Init() instead of constructor to prevent the default UCustomizableObjectSystem from registering a tick function
Private = MakeShareable ( new FCustomizableObjectSystemPrivate ( ) ) ;
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
check ( Private ! = nullptr ) ;
2022-09-26 15:12:13 -04:00
Private - > NewCompilerFunc = nullptr ;
Private - > bReplaceDiscardedWithReferenceMesh = false ;
const IConsoleVariable * CVarSupport16BitBoneIndex = IConsoleManager : : Get ( ) . FindConsoleVariable ( TEXT ( " r.GPUSkin.Support16BitBoneIndex " ) ) ;
Private - > bSupport16BitBoneIndex = CVarSupport16BitBoneIndex ? CVarSupport16BitBoneIndex - > GetBool ( ) : false ;
2023-08-22 08:38:33 -04:00
CVarMutableSinkFunction ( ) ;
2022-09-26 15:12:13 -04:00
Private - > CurrentMutableOperation = nullptr ;
Private - > CurrentInstanceBeingUpdated = nullptr ;
# if !UE_SERVER
Private - > TickDelegate = FTickerDelegate : : CreateUObject ( this , & UCustomizableObjectSystem : : Tick ) ;
Private - > TickDelegateHandle = FTSTicker : : GetCoreTicker ( ) . AddTicker ( Private - > TickDelegate , 0.f ) ;
# endif // !UE_SERVER
2023-05-24 02:50:03 -04:00
Private - > LastWorkingMemoryBytes = CVarWorkingMemory . GetValueOnGameThread ( ) * 1024 ;
2023-06-26 02:16:47 -04:00
Private - > LastGeneratedResourceCacheSize = CVarGeneratedResourcesCacheSize . GetValueOnGameThread ( ) ;
2023-03-14 07:59:06 -04:00
2023-09-07 04:23:11 -04:00
const mu : : Ptr < mu : : Settings > pSettings = new mu : : Settings ;
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
check ( pSettings ) ;
2022-09-26 15:12:13 -04:00
pSettings - > SetProfile ( false ) ;
2023-05-24 02:50:03 -04:00
pSettings - > SetWorkingMemoryBytes ( Private - > LastWorkingMemoryBytes ) ;
Private - > ExtensionDataStreamer = MakeShared < FUnrealExtensionDataStreamer > ( Private . ToSharedRef ( ) ) ;
2023-04-05 11:20:44 -04:00
Private - > MutableSystem = new mu : : System ( pSettings , Private - > ExtensionDataStreamer ) ;
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
check ( Private - > MutableSystem ) ;
2022-09-26 15:12:13 -04:00
2023-06-26 02:16:47 -04:00
Private - > Streamer = MakeShared < FUnrealMutableModelBulkReader > ( ) ;
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
check ( Private - > Streamer ! = nullptr ) ;
2022-09-26 15:12:13 -04:00
Private - > MutableSystem - > SetStreamingInterface ( Private - > Streamer ) ;
// Set up the external image provider, for image parameters.
2023-05-24 02:50:03 -04:00
TSharedPtr < FUnrealMutableImageProvider > Provider = MakeShared < FUnrealMutableImageProvider > ( ) ;
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
check ( Provider ! = nullptr ) ;
2022-09-26 15:12:13 -04:00
Private - > ImageProvider = Provider ;
Private - > MutableSystem - > SetImageParameterGenerator ( Provider ) ;
2023-09-07 06:34:12 -04:00
# if WITH_EDITORONLY_DATA
Private - > EditorImageProvider = NewObject < UEditorImageProvider > ( ) ;
check ( Private - > EditorImageProvider ) ;
RegisterImageProvider ( Private - > EditorImageProvider ) ;
# endif
2022-09-26 15:12:13 -04:00
# if WITH_EDITOR
if ( ! IsRunningGame ( ) )
{
FEditorDelegates : : PreBeginPIE . AddUObject ( this , & UCustomizableObjectSystem : : OnPreBeginPIE ) ;
}
# endif
DefaultInstanceLODManagement = NewObject < UCustomizableInstanceLODManagement > ( ) ;
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
check ( DefaultInstanceLODManagement ! = nullptr ) ;
2022-09-26 15:12:13 -04:00
CurrentInstanceLODManagement = DefaultInstanceLODManagement ;
}
void UCustomizableObjectSystem : : BeginDestroy ( )
{
# if WITH_EDITOR
if ( RecompileCustomizableObjectsCompiler )
{
RecompileCustomizableObjectsCompiler - > ForceFinishCompilation ( ) ;
delete RecompileCustomizableObjectsCompiler ;
}
if ( ! IsRunningGame ( ) )
{
FEditorDelegates : : PreBeginPIE . RemoveAll ( this ) ;
}
# endif
// It could be null, for the default object.
if ( Private . IsValid ( ) )
{
# if !UE_SERVER
FTSTicker : : GetCoreTicker ( ) . RemoveTicker ( Private - > TickDelegateHandle ) ;
# endif // !UE_SERVER
// Discard pending game thread tasks
Private - > PendingTasks . Empty ( ) ;
// Complete pending taskgraph tasks
2023-05-15 05:50:59 -04:00
Private - > MutableTaskGraph . WaitForMutableTasks ( ) ;
2022-09-26 15:12:13 -04:00
// Clear the ongoing operation
Private - > CurrentMutableOperation = nullptr ;
// Deallocate streaming
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
check ( Private - > Streamer ! = nullptr ) ;
2022-09-26 15:12:13 -04:00
Private - > Streamer - > EndStreaming ( ) ;
Private - > CurrentInstanceBeingUpdated = nullptr ;
FCustomizableObjectSystemPrivate : : SSystem = nullptr ;
Private = nullptr ;
}
Super : : BeginDestroy ( ) ;
}
FString UCustomizableObjectSystem : : GetDesc ( )
{
return TEXT ( " Customizable Object System Singleton " ) ;
}
FCustomizableObjectCompilerBase * ( * FCustomizableObjectSystemPrivate : : NewCompilerFunc ) ( ) = nullptr ;
FCustomizableObjectCompilerBase * UCustomizableObjectSystem : : GetNewCompiler ( )
{
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
check ( Private ! = nullptr ) ;
if ( Private - > NewCompilerFunc ! = nullptr )
2022-09-26 15:12:13 -04:00
{
return Private - > NewCompilerFunc ( ) ;
}
else
{
return nullptr ;
}
}
void UCustomizableObjectSystem : : SetNewCompilerFunc ( FCustomizableObjectCompilerBase * ( * InNewCompilerFunc ) ( ) )
{
2023-09-07 04:23:11 -04:00
GetPrivateChecked ( ) - > NewCompilerFunc = InNewCompilerFunc ;
2022-09-26 15:12:13 -04:00
}
2022-11-22 04:57:22 -05:00
int32 FCustomizableObjectSystemPrivate : : EnableMutableAnimInfoDebugging = 0 ;
2022-09-26 15:12:13 -04:00
static FAutoConsoleVariableRef CVarEnableMutableAnimInfoDebugging (
2022-11-22 04:57:22 -05:00
TEXT ( " mutable.EnableMutableAnimInfoDebugging " ) , FCustomizableObjectSystemPrivate : : EnableMutableAnimInfoDebugging ,
TEXT ( " If set to 1 or greater print on screen the animation info of the pawn's Customizable Object Instance. Anim BPs, slots and tags will be displayed. "
" If the root Customizable Object is recompiled after this command is run, the used skeletal meshes will also be displayed. " ) ,
2022-09-26 15:12:13 -04:00
ECVF_Default ) ;
2023-09-07 04:23:11 -04:00
void FCustomizableObjectSystemPrivate : : AddGameThreadTask ( const FMutableTask & Task )
{
PendingTasks . Enqueue ( Task ) ;
}
2022-09-26 15:12:13 -04:00
void FCustomizableObjectSystemPrivate : : AddReferencedObjects ( FReferenceCollector & Collector )
{
if ( CurrentInstanceBeingUpdated )
{
Collector . AddReferencedObject ( CurrentInstanceBeingUpdated ) ;
}
2023-09-07 06:34:12 -04:00
# if WITH_EDITORONLY_DATA
Collector . AddReferencedObject ( EditorImageProvider ) ;
# endif
2022-09-26 15:12:13 -04:00
}
2023-09-07 04:23:11 -04:00
FString FCustomizableObjectSystemPrivate : : GetReferencerName ( ) const
{
return TEXT ( " FCustomizableObjectSystemPrivate " ) ;
}
2023-08-17 07:38:09 -04:00
TAutoConsoleVariable < bool > CVarCleanupTextureCache (
TEXT ( " mutable.EnableCleanupCache " ) ,
true ,
TEXT ( " If enabled stale textures and meshes in mutable's cache will be removed. " ) ,
ECVF_Scalability ) ;
void FCustomizableObjectSystemPrivate : : CleanupCache ( )
{
check ( IsInGameThread ( ) ) ;
2023-09-07 04:23:11 -04:00
const bool bCleanupEnabled = CVarCleanupTextureCache . GetValueOnGameThread ( ) ;
2023-08-17 07:38:09 -04:00
for ( int32 ModelIndex = 0 ; ModelIndex < ModelResourcesCache . Num ( ) ; )
{
if ( ! ModelResourcesCache [ ModelIndex ] . Object . IsValid ( false , true ) )
{
// The whole object has been destroyed. Remove everything.
ModelResourcesCache . RemoveAtSwap ( ModelIndex ) ;
}
else
{
if ( bCleanupEnabled )
{
// Remove stale textures
for ( auto Iterator = ModelResourcesCache [ ModelIndex ] . Images . CreateIterator ( ) ; Iterator ; + + Iterator )
{
if ( Iterator - > Value . IsStale ( ) )
{
Iterator . RemoveCurrent ( ) ;
}
}
// Remove stale meshes
for ( auto Iterator = ModelResourcesCache [ ModelIndex ] . Meshes . CreateIterator ( ) ; Iterator ; + + Iterator )
{
if ( Iterator - > Value . IsStale ( ) )
{
Iterator . RemoveCurrent ( ) ;
}
}
}
+ + ModelIndex ;
}
}
}
2023-09-07 04:23:11 -04:00
FMutableResourceCache & FCustomizableObjectSystemPrivate : : GetObjectCache ( const UCustomizableObject * Object )
{
check ( IsInGameThread ( ) ) ;
// Not mandatory, but a good place for a cleanup
CleanupCache ( ) ;
for ( int ModelIndex = 0 ; ModelIndex < ModelResourcesCache . Num ( ) ; + + ModelIndex )
{
if ( ModelResourcesCache [ ModelIndex ] . Object = = Object )
{
return ModelResourcesCache [ ModelIndex ] ;
}
}
// Not found, create and add it.
ModelResourcesCache . Push ( FMutableResourceCache ( ) ) ;
ModelResourcesCache . Last ( ) . Object = Object ;
return ModelResourcesCache . Last ( ) ;
}
2022-11-11 14:11:45 -05:00
int32 FCustomizableObjectSystemPrivate : : EnableMutableProgressiveMipStreaming = 1 ;
2022-09-26 15:12:13 -04:00
// Warning! If this is enabled, do not get references to the textures generated by Mutable! They are owned by Mutable and could become invalid at any moment
static FAutoConsoleVariableRef CVarEnableMutableProgressiveMipStreaming (
TEXT ( " mutable.EnableMutableProgressiveMipStreaming " ) , FCustomizableObjectSystemPrivate : : EnableMutableProgressiveMipStreaming ,
TEXT ( " If set to 1 or greater use progressive Mutable Mip streaming for Mutable textures. If disabled, all mips will always be generated and spending memory. In that case, on Desktop platforms they will be stored in CPU memory, on other platforms textures will be non-streaming. " ) ,
ECVF_Default ) ;
2023-01-11 14:44:41 -05:00
int32 FCustomizableObjectSystemPrivate : : EnableMutableLiveUpdate = 1 ;
static FAutoConsoleVariableRef CVarEnableMutableLiveUpdate (
TEXT ( " mutable.EnableMutableLiveUpdate " ) , FCustomizableObjectSystemPrivate : : EnableMutableLiveUpdate ,
TEXT ( " If set to 1 or greater Mutable can use the live update mode if set in the current Mutable state. If disabled, it will never use live update mode even if set in the current Mutable state. " ) ,
ECVF_Default ) ;
2023-02-02 08:45:44 -05:00
int32 FCustomizableObjectSystemPrivate : : EnableReuseInstanceTextures = 1 ;
2023-01-19 10:44:15 -05:00
static FAutoConsoleVariableRef CVarEnableMutableReuseInstanceTextures (
TEXT ( " mutable.EnableReuseInstanceTextures " ) , FCustomizableObjectSystemPrivate : : EnableReuseInstanceTextures ,
TEXT ( " If set to 1 or greater and set in the corresponding setting in the current Mutable state, Mutable can reuse instance UTextures (only uncompressed and not streaming, so set the options in the state) and their resources between updates when they are modified. If geometry or state is changed they cannot be reused. " ) ,
ECVF_Default ) ;
2023-01-27 14:45:45 -05:00
int32 FCustomizableObjectSystemPrivate : : EnableOnlyGenerateRequestedLODs = 1 ;
2023-01-24 08:45:18 -05:00
static FAutoConsoleVariableRef CVarEnableOnlyGenerateRequestedLODs (
2023-01-27 14:45:45 -05:00
TEXT ( " mutable.EnableOnlyGenerateRequestedLODs " ) , FCustomizableObjectSystemPrivate : : EnableOnlyGenerateRequestedLODs ,
TEXT ( " If 1 or greater, Only the RequestedLODLevels will be generated. If 0, all LODs will be build. " ) ,
2023-01-24 08:45:18 -05:00
ECVF_Default ) ;
2023-02-02 02:41:54 -05:00
int32 FCustomizableObjectSystemPrivate : : EnableSkipGenerateResidentMips = 1 ;
static FAutoConsoleVariableRef CVarSkipGenerateResidentMips (
TEXT ( " mutable.EnableSkipGenerateResidentMips " ) , FCustomizableObjectSystemPrivate : : EnableSkipGenerateResidentMips ,
TEXT ( " If 1 or greater, resident mip generation will be optional. If 0, resident mips will be always generated " ) ,
ECVF_Default ) ;
2023-03-01 12:33:52 -05:00
int32 FCustomizableObjectSystemPrivate : : MaxTextureSizeToGenerate = 0 ;
FAutoConsoleVariableRef CVarMaxTextureSizeToGenerate (
TEXT ( " Mutable.MaxTextureSizeToGenerate " ) ,
FCustomizableObjectSystemPrivate : : MaxTextureSizeToGenerate ,
TEXT ( " Max texture size on Mutable textures. Mip 0 will be the first mip with max size equal or less than MaxTextureSizeToGenerate. "
" If a texture doesn't have small enough mips, mip 0 will be the last mip available. " ) ) ;
2023-08-31 15:22:46 -04:00
static bool bApplyFixPrepareSkeletons = true ;
static FAutoConsoleVariableRef CVarApplyFixPrepareSkeletons (
TEXT ( " mutable.ApplyFixPrepareSkeletons " ) , bApplyFixPrepareSkeletons ,
TEXT ( " If true, Fix missing SkeletonsData when FirstLODToGenerate is greater than 0. If false, There may be a crash when generating meshes on platform that skip LODs. " ) ,
ECVF_Default ) ;
2023-01-24 08:45:18 -05:00
2023-10-18 04:56:12 -04:00
static FAutoConsoleVariable CVarDescriptorDebugPrint (
TEXT ( " mutable.DescriptorDebugPrint " ) ,
false ,
TEXT ( " If true, each time an update is enqueued, print its captured parameters. " ) ,
ECVF_Default ) ;
2023-10-17 03:57:37 -04:00
void FinishUpdateGlobal ( const TSharedRef < FUpdateContextPrivate > & Context )
2022-10-10 07:09:51 -04:00
{
2023-05-15 05:50:59 -04:00
check ( IsInGameThread ( ) )
2023-10-02 05:40:58 -04:00
2023-10-17 03:57:37 -04:00
UCustomizableObjectInstance * Instance = Context - > Instance . Get ( ) ;
2023-10-25 06:41:33 -04:00
UCustomizableObjectSystem * System = UCustomizableObjectSystem : : GetInstance ( ) ;
FCustomizableObjectSystemPrivate * SystemPrivate = System ? System - > GetPrivate ( ) : nullptr ;
2023-04-06 16:56:51 -04:00
if ( Instance )
2022-10-10 07:09:51 -04:00
{
2023-10-02 05:40:58 -04:00
UCustomizableInstancePrivateData * PrivateInstance = Instance - > GetPrivate ( ) ;
2023-10-17 03:57:37 -04:00
switch ( Context - > UpdateResult )
2023-10-02 05:40:58 -04:00
{
case EUpdateResult : : Success :
PrivateInstance - > SetSkeletalMeshStatus ( ESkeletalMeshStatus : : Success ) ;
2023-10-17 03:57:37 -04:00
PrivateInstance - > DescriptorRuntimeHash = Context - > InstanceDescriptorRuntimeHash ;
2023-10-02 05:40:58 -04:00
// Delegates must be called only after updating the Instance flags.
Instance - > UpdatedDelegate . Broadcast ( Instance ) ;
Instance - > UpdatedNativeDelegate . Broadcast ( Instance ) ;
break ;
case EUpdateResult : : ErrorOptimized :
break ; // Skeletal Mesh not changed.
case EUpdateResult : : ErrorDiscarded :
break ; // Status will be updated once the discard is performed.
case EUpdateResult : : Error :
case EUpdateResult : : Error16BitBoneIndex :
PrivateInstance - > SetSkeletalMeshStatus ( ESkeletalMeshStatus : : Error ) ;
break ;
case EUpdateResult : : ErrorReplaced :
break ; // Skeletal Mesh not changed.
default :
unimplemented ( ) ;
}
2023-04-06 16:56:51 -04:00
}
2022-10-10 07:09:51 -04:00
2023-10-17 03:57:37 -04:00
if ( Context - > UpdateResult = = EUpdateResult : : Success )
2023-04-06 16:56:51 -04:00
{
2023-10-24 08:17:10 -04:00
// Call CustomizableObjectInstanceUsages updated callbacks.
for ( TObjectIterator < UCustomizableObjectInstanceUsage > It ; It ; + + It ) // Since iterating objects is expensive, for now CustomizableObjectInstanceUsage does not have a FinishUpdate function.
2022-10-10 07:09:51 -04:00
{
2023-09-22 04:26:19 -04:00
# if WITH_EDITOR
2023-11-09 06:25:16 -05:00
if ( IsValid ( * It ) & & It - > IsNetMode ( NM_DedicatedServer ) )
2023-09-22 04:26:19 -04:00
{
continue ;
}
# endif
2023-10-24 08:17:10 -04:00
if ( const UCustomizableObjectInstanceUsage * CustomizableObjectInstanceUsage = * It ;
2023-11-09 06:25:16 -05:00
IsValid ( CustomizableObjectInstanceUsage ) & &
2023-10-24 08:17:10 -04:00
CustomizableObjectInstanceUsage - > GetCustomizableObjectInstance ( ) = = Instance )
2022-10-10 07:09:51 -04:00
{
2023-10-24 08:17:10 -04:00
CustomizableObjectInstanceUsage - > Callbacks ( ) ;
2022-10-10 07:09:51 -04:00
}
}
2023-04-06 16:56:51 -04:00
}
2022-10-10 07:09:51 -04:00
2023-10-17 03:57:37 -04:00
FUpdateContext ContextPublic ;
ContextPublic . UpdateResult = Context - > UpdateResult ;
2023-04-06 16:56:51 -04:00
2023-10-17 03:57:37 -04:00
Context - > UpdateCallback . ExecuteIfBound ( ContextPublic ) ;
2023-05-15 05:50:59 -04:00
2023-10-25 06:41:33 -04:00
if ( SystemPrivate )
{
SystemPrivate - > MutableTaskGraph . AllowLaunchingMutableTaskLowPriority ( true , false ) ;
}
2023-11-21 10:47:27 -05:00
if ( Context - > StartUpdateTime ! = 0.0 ) // Update started.
2023-10-25 06:41:33 -04:00
{
2023-11-21 10:47:27 -05:00
Context - > UpdateTime = FPlatformTime : : Seconds ( ) - Context - > StartUpdateTime ;
}
const uint32 InstanceId = Instance ? Instance - > GetUniqueID ( ) : 0 ;
UE_LOG ( LogMutable , Log , TEXT ( " Finished UpdateSkeletalMesh Async. Instance=%d, Frame=%d, QueueTime=%f, UpdateTime=%f " ) , InstanceId , GFrameNumber , Context - > QueueTime , Context - > UpdateTime ) ;
if ( SystemPrivate & &
CVarEnableBenchmark . GetValueOnAnyThread ( ) )
{
FFunctionGraphTask : : CreateAndDispatchWhenReady ( // Calling Benchmark in a task so we make sure we exited all scopes.
[ Context ] ( )
{
UCustomizableObjectSystem * System = UCustomizableObjectSystem : : GetInstance ( ) ;
if ( ! System )
{
return ;
}
System - > GetPrivateChecked ( ) - > LogBenchmarkUtil . FinishUpdateMesh ( Context ) ;
} ,
TStatId { } ,
nullptr ,
ENamedThreads : : GameThread ) ;
2023-10-25 06:41:33 -04:00
}
if ( Context - > UpdateStarted )
{
TRACE_END_REGION ( UE_MUTABLE_UPDATE_REGION ) ;
}
2022-10-10 07:09:51 -04:00
}
2023-11-30 10:15:51 -05:00
/** Update the given Instance Skeletal Meshes */
2023-10-17 03:57:37 -04:00
void UpdateSkeletalMesh ( const TSharedRef < FUpdateContextPrivate > & Context )
2023-04-06 16:56:51 -04:00
{
MUTABLE_CPUPROFILER_SCOPE ( UpdateSkeletalMesh ) ;
2023-07-18 09:36:44 -04:00
check ( IsInGameThread ( ) ) ;
2023-10-17 03:57:37 -04:00
UCustomizableObjectInstance * CustomizableObjectInstance = Context - > Instance . Get ( ) ;
check ( CustomizableObjectInstance ) ;
for ( int32 ComponentIndex = 0 ; ComponentIndex < CustomizableObjectInstance - > SkeletalMeshes . Num ( ) ; + + ComponentIndex )
2023-04-06 16:56:51 -04:00
{
2023-10-17 03:57:37 -04:00
if ( TObjectPtr < USkeletalMesh > SkeletalMesh = CustomizableObjectInstance - > SkeletalMeshes [ ComponentIndex ] )
2023-04-06 16:56:51 -04:00
{
# if WITH_EDITOR
2023-09-13 06:59:56 -04:00
UCustomizableInstancePrivateData : : RegenerateImportedModel ( SkeletalMesh ) ;
2023-04-06 16:56:51 -04:00
# else
SkeletalMesh - > RebuildSocketMap ( ) ;
# endif
}
}
2023-10-17 03:57:37 -04:00
UCustomizableInstancePrivateData * CustomizableObjectInstancePrivateData = CustomizableObjectInstance - > GetPrivate ( ) ;
2023-04-06 16:56:51 -04:00
check ( CustomizableObjectInstancePrivateData ! = nullptr ) ;
2023-10-24 08:17:10 -04:00
for ( TObjectIterator < UCustomizableObjectInstanceUsage > It ; It ; + + It )
2023-04-06 16:56:51 -04:00
{
2023-10-24 08:17:10 -04:00
UCustomizableObjectInstanceUsage * CustomizableObjectInstanceUsage = * It ;
2023-04-06 16:56:51 -04:00
2023-09-22 04:26:19 -04:00
# if WITH_EDITOR
2023-11-09 06:25:16 -05:00
if ( IsValid ( CustomizableObjectInstanceUsage ) & & CustomizableObjectInstanceUsage - > IsNetMode ( NM_DedicatedServer ) )
2023-09-22 04:26:19 -04:00
{
continue ;
}
# endif
2023-11-09 06:25:16 -05:00
if ( IsValid ( CustomizableObjectInstanceUsage ) & &
2023-10-24 08:17:10 -04:00
( CustomizableObjectInstanceUsage - > GetCustomizableObjectInstance ( ) = = CustomizableObjectInstance ) & &
CustomizableObjectInstance - > SkeletalMeshes . IsValidIndex ( CustomizableObjectInstanceUsage - > GetComponentIndex ( ) )
2023-04-06 16:56:51 -04:00
)
{
MUTABLE_CPUPROFILER_SCOPE ( UpdateSkeletalMesh_SetSkeletalMesh ) ;
const bool bIsCreatingSkeletalMesh = CustomizableObjectInstancePrivateData - > HasCOInstanceFlags ( CreatingSkeletalMesh ) ; //TODO MTBL-391: Review
2023-10-24 08:17:10 -04:00
CustomizableObjectInstanceUsage - > SetSkeletalMesh ( CustomizableObjectInstance - > SkeletalMeshes [ CustomizableObjectInstanceUsage - > GetComponentIndex ( ) ] , false , bIsCreatingSkeletalMesh ) ;
2023-04-06 16:56:51 -04:00
if ( CustomizableObjectInstancePrivateData - > HasCOInstanceFlags ( ReplacePhysicsAssets ) )
{
2023-10-24 08:17:10 -04:00
CustomizableObjectInstanceUsage - > SetPhysicsAsset (
CustomizableObjectInstance - > SkeletalMeshes [ CustomizableObjectInstanceUsage - > GetComponentIndex ( ) ] ?
CustomizableObjectInstance - > SkeletalMeshes [ CustomizableObjectInstanceUsage - > GetComponentIndex ( ) ] - > GetPhysicsAsset ( ) : nullptr ) ;
2023-04-06 16:56:51 -04:00
}
}
}
CustomizableObjectInstancePrivateData - > SetCOInstanceFlags ( Generated ) ;
CustomizableObjectInstancePrivateData - > ClearCOInstanceFlags ( CreatingSkeletalMesh ) ;
2023-10-17 03:57:37 -04:00
CustomizableObjectInstance - > bEditorPropertyChanged = false ;
2023-04-06 16:56:51 -04:00
}
2023-06-22 06:24:44 -04:00
void FCustomizableObjectSystemPrivate : : GetMipStreamingConfig ( const UCustomizableObjectInstance & Instance , bool & bOutNeverStream , int32 & OutMipsToSkip ) const
2022-09-26 15:12:13 -04:00
{
2023-11-03 09:03:29 -04:00
bOutNeverStream = false ;
// From user-controlled per-state flag?
2022-11-03 14:23:46 -04:00
const FString CurrentState = Instance . GetCurrentState ( ) ;
2023-11-03 09:03:29 -04:00
const FParameterUIData * State = Instance . GetCustomizableObject ( ) - > StateUIDataMap . Find ( CurrentState ) ;
if ( State )
{
bOutNeverStream = State - > bDisableTextureStreaming ;
// Was streaming disabled at object-compilation time?
if ( State - > bDisableTextureStreamingOverride )
{
bOutNeverStream = true ;
}
}
2023-03-08 04:37:54 -05:00
2023-06-22 06:24:44 -04:00
bool bUseMipmapStreaming = ! bOutNeverStream ;
2023-11-03 09:03:29 -04:00
OutMipsToSkip = 0 ; // 0 means generate all mips
2022-09-26 15:12:13 -04:00
2023-11-03 09:03:29 -04:00
// Streaming disabled from platform settings?
2023-03-15 07:39:39 -04:00
# if PLATFORM_SUPPORTS_TEXTURE_STREAMING
if ( ! IStreamingManager : : Get ( ) . IsTextureStreamingEnabled ( ) )
{
bUseMipmapStreaming = false ;
}
# else
bUseMipmapStreaming = false ;
# endif
2023-11-03 09:03:29 -04:00
// Streaming disabled from platform CustomizableObjectSystem properties?
2022-11-03 14:23:46 -04:00
if ( bUseMipmapStreaming & & EnableMutableProgressiveMipStreaming )
2022-09-26 15:12:13 -04:00
{
2023-06-22 06:24:44 -04:00
OutMipsToSkip = 255 ; // This means skip all possible mips until only UTexture::GetStaticMinTextureResidentMipCount() are left
2022-09-26 15:12:13 -04:00
}
2023-06-22 06:24:44 -04:00
}
2023-09-07 04:23:11 -04:00
bool FCustomizableObjectSystemPrivate : : IsReplaceDiscardedWithReferenceMeshEnabled ( ) const
{
return bReplaceDiscardedWithReferenceMesh ;
}
void FCustomizableObjectSystemPrivate : : SetReplaceDiscardedWithReferenceMeshEnabled ( bool bIsEnabled )
{
bReplaceDiscardedWithReferenceMesh = bIsEnabled ;
}
2023-10-25 06:41:33 -04:00
int32 FCustomizableObjectSystemPrivate : : GetNumSkeletalMeshes ( ) const
2023-09-07 04:23:11 -04:00
{
2023-10-25 06:41:33 -04:00
return NumSkeletalMeshes ;
2023-09-07 04:23:11 -04:00
}
void FCustomizableObjectSystemPrivate : : AddTextureReference ( const FMutableImageCacheKey & TextureId )
{
uint32 & CountRef = TextureReferenceCount . FindOrAdd ( TextureId ) ;
CountRef + + ;
}
bool FCustomizableObjectSystemPrivate : : RemoveTextureReference ( const FMutableImageCacheKey & TextureId )
{
uint32 * CountPtr = TextureReferenceCount . Find ( TextureId ) ;
if ( CountPtr & & * CountPtr > 0 )
{
( * CountPtr ) - - ;
if ( * CountPtr = = 0 )
{
TextureReferenceCount . Remove ( TextureId ) ;
return true ;
}
}
else
{
ensure ( false ) ; // Mutable texture reference count is incorrect
TextureReferenceCount . Remove ( TextureId ) ;
}
return false ;
}
bool FCustomizableObjectSystemPrivate : : TextureHasReferences ( const FMutableImageCacheKey & TextureId ) const
{
const uint32 * CountPtr = TextureReferenceCount . Find ( TextureId ) ;
if ( CountPtr & & * CountPtr > 0 )
{
return true ;
}
return false ;
}
2023-09-25 04:49:55 -04:00
EUpdateRequired FCustomizableObjectSystemPrivate : : IsUpdateRequired ( const UCustomizableObjectInstance & Instance , bool bOnlyUpdateIfNotGenerated , bool bIgnoreCloseDist ) const
2023-06-22 06:24:44 -04:00
{
2023-09-25 04:49:55 -04:00
UCustomizableObjectSystem * System = UCustomizableObjectSystem : : GetInstance ( ) ;
const UCustomizableInstancePrivateData * const Private = Instance . GetPrivate ( ) ;
2022-09-26 15:12:13 -04:00
2023-09-25 04:49:55 -04:00
const UCustomizableObject * CustomizableObject = Instance . GetCustomizableObject ( ) ;
2023-11-08 08:42:39 -05:00
if ( ! Instance . CanUpdateInstance ( ) )
2022-09-26 15:12:13 -04:00
{
2023-09-25 04:49:55 -04:00
return EUpdateRequired : : NoUpdate ;
}
const bool bIsGenerated = Private - > HasCOInstanceFlags ( Generated ) ;
const int32 NumGeneratedInstancesLimit = System - > GetInstanceLODManagement ( ) - > GetNumGeneratedInstancesLimitFullLODs ( ) ;
const int32 NumGeneratedInstancesLimitLOD1 = System - > GetInstanceLODManagement ( ) - > GetNumGeneratedInstancesLimitLOD1 ( ) ;
const int32 NumGeneratedInstancesLimitLOD2 = System - > GetInstanceLODManagement ( ) - > GetNumGeneratedInstancesLimitLOD2 ( ) ;
if ( ! bIsGenerated & & // Prevent generating more instances than the limit, but let updates to existing instances run normally
NumGeneratedInstancesLimit > 0 & &
2023-10-25 06:41:33 -04:00
System - > GetPrivate ( ) - > GetNumSkeletalMeshes ( ) > NumGeneratedInstancesLimit + NumGeneratedInstancesLimitLOD1 + NumGeneratedInstancesLimitLOD2 )
2023-09-25 04:49:55 -04:00
{
return EUpdateRequired : : NoUpdate ;
}
const bool bShouldUpdateLODs = Private - > HasCOInstanceFlags ( PendingLODsUpdate ) ;
const bool bDiscardByDistance = Private - > LastMinSquareDistFromComponentToPlayer > FMath : : Square ( System - > GetInstanceLODManagement ( ) - > GetOnlyUpdateCloseCustomizableObjectsDist ( ) ) ;
const bool bLODManagementDiscard = System - > GetInstanceLODManagement ( ) - > IsOnlyUpdateCloseCustomizableObjectsEnabled ( ) & &
bDiscardByDistance & &
! bIgnoreCloseDist ;
if ( Private - > HasCOInstanceFlags ( DiscardedByNumInstancesLimit ) | |
bLODManagementDiscard )
{
2023-10-02 05:40:58 -04:00
if ( bIsGenerated )
2023-09-25 04:49:55 -04:00
{
return EUpdateRequired : : Discard ;
}
else
{
return EUpdateRequired : : NoUpdate ;
}
}
if ( bIsGenerated & &
! bShouldUpdateLODs & &
bOnlyUpdateIfNotGenerated )
{
return EUpdateRequired : : NoUpdate ;
}
return EUpdateRequired : : Update ;
}
EQueuePriorityType FCustomizableObjectSystemPrivate : : GetUpdatePriority ( const UCustomizableObjectInstance & Instance , bool bForceHighPriority ) const
{
const UCustomizableInstancePrivateData * InstancePrivate = Instance . GetPrivate ( ) ;
const bool bIsGenerated = InstancePrivate - > HasCOInstanceFlags ( Generated ) ;
const bool bShouldUpdateLODs = InstancePrivate - > HasCOInstanceFlags ( PendingLODsUpdate ) ;
const bool bIsDowngradeLODUpdate = InstancePrivate - > HasCOInstanceFlags ( PendingLODsDowngrade ) ;
const bool bIsPlayerOrNearIt = InstancePrivate - > HasCOInstanceFlags ( UsedByPlayerOrNearIt ) ;
EQueuePriorityType Priority = EQueuePriorityType : : Low ;
if ( bForceHighPriority )
{
Priority = EQueuePriorityType : : High ;
}
else if ( ! bIsGenerated | | ! Instance . HasAnySkeletalMesh ( ) )
{
Priority = EQueuePriorityType : : Med ;
}
else if ( bShouldUpdateLODs & & bIsDowngradeLODUpdate )
{
Priority = EQueuePriorityType : : Med_Low ;
}
else if ( bIsPlayerOrNearIt & & bShouldUpdateLODs & & ! bIsDowngradeLODUpdate )
{
Priority = EQueuePriorityType : : High ;
}
else if ( bShouldUpdateLODs & & ! bIsDowngradeLODUpdate )
{
Priority = EQueuePriorityType : : Med ;
}
else if ( bIsPlayerOrNearIt )
{
Priority = EQueuePriorityType : : High ;
}
return Priority ;
}
2023-10-17 03:57:37 -04:00
void FCustomizableObjectSystemPrivate : : EnqueueUpdateSkeletalMesh ( const TSharedRef < FUpdateContextPrivate > & Context )
2023-09-25 04:49:55 -04:00
{
MUTABLE_CPUPROFILER_SCOPE ( FCustomizableObjectSystemPrivate : : EnqueueUpdateSkeletalMesh ) ;
check ( IsInGameThread ( ) ) ;
2023-10-17 03:57:37 -04:00
UCustomizableObjectInstance * Instance = Context - > Instance . Get ( ) ;
check ( Instance ) ;
2023-10-02 05:40:58 -04:00
2023-10-17 03:57:37 -04:00
UCustomizableInstancePrivateData * InstancePrivate = Instance - > GetPrivate ( ) ;
2023-11-21 10:47:27 -05:00
const EQueuePriorityType Priority = GetUpdatePriority ( * Instance , Context - > bForceHighPriority ) ;
const uint32 InstanceId = Instance - > GetUniqueID ( ) ;
const float Distance = FMath : : Sqrt ( InstancePrivate - > LastMinSquareDistFromComponentToPlayer ) ;
const bool bIsPlayerOrNearIt = InstancePrivate - > HasCOInstanceFlags ( UsedByPlayerOrNearIt ) ;
UE_LOG ( LogMutable , Log , TEXT ( " Enqueue UpdateSkeletalMesh Async. Instance=%d, Frame=%d, Priority=%d, dist=%f, bIsPlayerOrNearIt=%d " ) , InstanceId , GFrameNumber , static_cast < int32 > ( Priority ) , Distance , bIsPlayerOrNearIt ) ;
2023-10-17 03:57:37 -04:00
if ( ! Instance - > CanUpdateInstance ( ) )
2023-09-25 04:49:55 -04:00
{
2023-10-17 03:57:37 -04:00
Context - > UpdateResult = EUpdateResult : : Error ;
FinishUpdateGlobal ( Context ) ;
2023-09-25 04:49:55 -04:00
return ;
}
UCustomizableObjectSystem * System = UCustomizableObjectSystem : : GetInstance ( ) ;
2023-10-17 03:57:37 -04:00
const EUpdateRequired UpdateRequired = IsUpdateRequired ( * Instance , Context - > bOnlyUpdateIfNotGenerated , Context - > bIgnoreCloseDist ) ;
2023-09-25 04:49:55 -04:00
switch ( UpdateRequired )
{
case EUpdateRequired : : NoUpdate :
{
2023-10-17 03:57:37 -04:00
Context - > UpdateResult = EUpdateResult : : Error ;
FinishUpdateGlobal ( Context ) ;
2023-09-25 04:49:55 -04:00
break ;
}
case EUpdateRequired : : Update :
{
if ( InstancePrivate - > HasCOInstanceFlags ( PendingLODsUpdate ) )
{
2023-10-17 03:57:37 -04:00
UE_LOG ( LogMutable , Verbose , TEXT ( " LOD change: %d, %d -> %d, %d " ) , Instance - > GetCurrentMinLOD ( ) , Instance - > GetCurrentMaxLOD ( ) , Instance - > GetMinLODToLoad ( ) , Instance - > GetMaxLODToLoad ( ) ) ;
2023-09-25 04:49:55 -04:00
}
2023-10-17 03:57:37 -04:00
if ( const FMutablePendingInstanceUpdate * QueueElem = MutablePendingInstanceWork . GetUpdate ( Instance ) )
2023-09-25 04:49:55 -04:00
{
2023-10-17 03:57:37 -04:00
if ( InstancePrivate - > UpdateDescriptorRuntimeHash . IsSubset ( FDescriptorRuntimeHash ( QueueElem - > Context - > InstanceDescriptorRuntimeHash ) ) )
2023-09-25 04:49:55 -04:00
{
2023-10-17 03:57:37 -04:00
Context - > UpdateResult = EUpdateResult : : ErrorOptimized ;
FinishUpdateGlobal ( Context ) ;
2023-09-25 04:49:55 -04:00
return ; // The the requested update is equal to the last enqueued update.
}
}
if ( CurrentMutableOperation & &
2023-10-17 03:57:37 -04:00
Instance = = CurrentMutableOperation - > Instance & &
2023-09-25 04:49:55 -04:00
InstancePrivate - > UpdateDescriptorRuntimeHash . IsSubset ( CurrentMutableOperation - > InstanceDescriptorRuntimeHash ) )
2022-09-26 15:12:13 -04:00
{
2023-10-17 03:57:37 -04:00
Context - > UpdateResult = EUpdateResult : : ErrorOptimized ;
FinishUpdateGlobal ( Context ) ;
2023-09-25 04:49:55 -04:00
return ; // The requested update is equal to the running update.
2022-09-26 15:12:13 -04:00
}
2022-11-04 09:18:44 -04:00
2023-09-25 04:49:55 -04:00
if ( InstancePrivate - > UpdateDescriptorRuntimeHash . IsSubset ( InstancePrivate - > DescriptorRuntimeHash ) & &
! ( CurrentMutableOperation & &
2023-10-17 03:57:37 -04:00
Instance = = CurrentMutableOperation - > Instance ) ) // This condition is necessary because even if the descriptor is a subset, it will be replaced by the CurrentMutableOperation
2023-09-25 04:49:55 -04:00
{
2023-10-17 03:57:37 -04:00
Context - > UpdateResult = EUpdateResult : : Success ;
UpdateSkeletalMesh ( Context ) ;
2023-10-25 06:41:33 -04:00
FinishUpdateGlobal ( Context ) ;
2023-09-25 04:49:55 -04:00
}
else
{
// Cache Texture Parameters being used during the update:
check ( ImageProvider ) ;
// Cache new Texture Parameters
2023-10-17 03:57:37 -04:00
for ( const FCustomizableObjectTextureParameterValue & TextureParameters : Instance - > GetDescriptor ( ) . GetTextureParameters ( ) )
2023-09-25 04:49:55 -04:00
{
ImageProvider - > CacheImage ( TextureParameters . ParameterValue , false ) ;
for ( const FName & TextureParameter : TextureParameters . ParameterRangeValues )
{
ImageProvider - > CacheImage ( TextureParameter , false ) ;
}
}
// Uncache old Texture Parameters
for ( const FName & TextureParameter : InstancePrivate - > UpdateTextureParameters )
{
ImageProvider - > UnCacheImage ( TextureParameter , false ) ;
}
// Update which ones are currently are being used
InstancePrivate - > UpdateTextureParameters . Reset ( ) ;
2023-10-17 03:57:37 -04:00
for ( const FCustomizableObjectTextureParameterValue & TextureParameters : Instance - > GetDescriptor ( ) . GetTextureParameters ( ) )
2023-09-25 04:49:55 -04:00
{
InstancePrivate - > UpdateTextureParameters . Add ( TextureParameters . ParameterValue ) ;
for ( const FName & TextureParameter : TextureParameters . ParameterRangeValues )
{
InstancePrivate - > UpdateTextureParameters . Add ( TextureParameter ) ;
}
}
2023-10-18 04:56:12 -04:00
if ( CVarDescriptorDebugPrint - > GetBool ( ) )
{
FString String = TEXT ( " DESCRIPTOR DEBUG PRINT \n " ) ;
String + = " ================================ \n " ;
String + = FString : : Printf ( TEXT ( " === DESCRIPTOR HASH === \n %s \n " ) , * InstancePrivate - > UpdateDescriptorRuntimeHash . ToString ( ) ) ;
String + = FString : : Printf ( TEXT ( " === DESCRIPTOR === \n %s " ) , * Instance - > GetDescriptor ( ) . ToString ( ) ) ;
String + = " ================================ " ;
UE_LOG ( LogMutable , Log , TEXT ( " %s " ) , * String ) ;
}
2023-10-17 03:57:37 -04:00
const FMutablePendingInstanceUpdate InstanceUpdate ( Context ) ;
2023-09-25 04:49:55 -04:00
MutablePendingInstanceWork . AddUpdate ( InstanceUpdate ) ;
}
break ;
2022-09-26 15:12:13 -04:00
}
2023-09-25 04:49:55 -04:00
case EUpdateRequired : : Discard :
2023-07-28 06:06:02 -04:00
{
2023-10-17 03:57:37 -04:00
System - > GetPrivate ( ) - > InitDiscardResourcesSkeletalMesh ( Instance ) ;
Context - > UpdateResult = EUpdateResult : : ErrorDiscarded ;
FinishUpdateGlobal ( Context ) ;
2023-09-25 04:49:55 -04:00
break ;
}
2023-07-28 06:06:02 -04:00
2023-09-25 04:49:55 -04:00
default :
unimplemented ( ) ;
2022-10-10 07:09:51 -04:00
}
2022-09-26 15:12:13 -04:00
}
void FCustomizableObjectSystemPrivate : : InitDiscardResourcesSkeletalMesh ( UCustomizableObjectInstance * InCustomizableObjectInstance )
{
check ( IsInGameThread ( ) ) ;
if ( InCustomizableObjectInstance & & InCustomizableObjectInstance - > IsValidLowLevel ( ) )
{
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
check ( InCustomizableObjectInstance - > GetPrivate ( ) ! = nullptr ) ;
2023-06-22 06:24:44 -04:00
MutablePendingInstanceWork . AddDiscard ( FMutablePendingInstanceDiscard ( InCustomizableObjectInstance ) ) ;
2022-09-26 15:12:13 -04:00
}
}
2023-01-10 15:48:59 -05:00
void FCustomizableObjectSystemPrivate : : InitInstanceIDRelease ( mu : : Instance : : ID IDToRelease )
{
check ( IsInGameThread ( ) ) ;
2023-06-22 06:24:44 -04:00
MutablePendingInstanceWork . AddIDRelease ( IDToRelease ) ;
2023-01-10 15:48:59 -05:00
}
2022-09-26 15:12:13 -04:00
bool UCustomizableObjectSystem : : IsReplaceDiscardedWithReferenceMeshEnabled ( ) const
{
if ( Private . IsValid ( ) )
{
return Private - > IsReplaceDiscardedWithReferenceMeshEnabled ( ) ;
}
return false ;
}
void UCustomizableObjectSystem : : SetReplaceDiscardedWithReferenceMeshEnabled ( bool bIsEnabled )
{
if ( Private . IsValid ( ) )
{
Private - > SetReplaceDiscardedWithReferenceMeshEnabled ( bIsEnabled ) ;
}
}
void UCustomizableObjectSystem : : ClearResourceCacheProtected ( )
{
check ( IsInGameThread ( ) ) ;
ProtectedCachedTextures . Reset ( 0 ) ;
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
check ( GetPrivate ( ) ! = nullptr ) ;
2022-09-26 15:12:13 -04:00
GetPrivate ( ) - > ProtectedObjectCachedImages . Reset ( 0 ) ;
}
# if WITH_EDITOR
bool UCustomizableObjectSystem : : LockObject ( const class UCustomizableObject * InObject )
{
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
check ( InObject ! = nullptr ) ;
2023-11-04 01:30:32 -04:00
check ( InObject - > GetPrivate ( ) ) ;
2022-09-26 15:12:13 -04:00
check ( ! InObject - > GetPrivate ( ) - > bLocked ) ;
2022-11-24 10:07:28 -05:00
check ( IsInGameThread ( ) & & ! IsInParallelGameThread ( ) ) ;
2022-09-26 15:12:13 -04:00
2023-11-04 01:30:32 -04:00
if ( Private )
2022-09-26 15:12:13 -04:00
{
2023-06-12 11:06:50 -04:00
// If the current instance is for this object, make the lock fail by returning false
if ( Private - > CurrentInstanceBeingUpdated & &
Private - > CurrentInstanceBeingUpdated - > GetCustomizableObject ( ) = = InObject )
{
UE_LOG ( LogMutable , Warning , TEXT ( " ---- failed to lock object %s " ) , * InObject - > GetName ( ) ) ;
return false ;
}
FString Message = FString : : Printf ( TEXT ( " Customizable Object %s has pending texture streaming operations. Please wait a few seconds and try again. " ) ,
* InObject - > GetName ( ) ) ;
// Pre-check pending operations before locking. This check is redundant and incomplete because it's checked again after locking
// and some operations may start between here and the actual lock. But in the CO Editor preview it will prevent some
// textures getting stuck at low resolution when they try to update mips and are cancelled when the user presses
// the compile button but the compilation quits anyway because there are pending operations
if ( CheckIfDiskOrMipUpdateOperationsPending ( * InObject ) )
{
UE_LOG ( LogMutable , Warning , TEXT ( " %s " ) , * Message ) ;
return false ;
}
// Lock the object, no new file or mip streaming operations should start from this point
InObject - > GetPrivate ( ) - > bLocked = true ;
// But some could have started between the first CheckIfDiskOrMipUpdateOperationsPending and the lock a few lines back, so check again
if ( CheckIfDiskOrMipUpdateOperationsPending ( * InObject ) )
{
UE_LOG ( LogMutable , Warning , TEXT ( " %s " ) , * Message ) ;
// Unlock and return because the pending operations cannot be easily stopped now, the compilation hasn't started and the CO
// hasn't changed state yet. It's simpler to quit the compilation, unlock and let the user try to compile again
InObject - > GetPrivate ( ) - > bLocked = false ;
return false ;
}
// Ensure that we don't try to handle any further streaming operations for this object
check ( GetPrivate ( ) ! = nullptr ) ;
if ( GetPrivate ( ) - > Streamer )
{
GetPrivate ( ) - > Streamer - > CancelStreamingForObject ( InObject ) ;
}
// Clear the cache for the instance, since we will remake it
FMutableResourceCache & Cache = GetPrivate ( ) - > GetObjectCache ( InObject ) ;
Cache . Clear ( ) ;
check ( InObject - > GetPrivate ( ) - > bLocked ) ;
return true ;
}
else
{
FString ObjectName = InObject ? InObject - > GetName ( ) : FString ( " null " ) ;
UE_LOG ( LogMutable , Warning , TEXT ( " Failed to lock the object [%s] because it was null or the system was null or partially destroyed. " ) , * ObjectName ) ;
2022-11-24 10:07:28 -05:00
return false ;
}
2022-09-26 15:12:13 -04:00
}
void UCustomizableObjectSystem : : UnlockObject ( const class UCustomizableObject * Obj )
{
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
check ( Obj ! = nullptr ) ;
2023-11-04 01:30:32 -04:00
check ( Obj - > GetPrivate ( ) ) ;
2022-09-26 15:12:13 -04:00
check ( Obj - > GetPrivate ( ) - > bLocked ) ;
2022-11-24 10:07:28 -05:00
check ( IsInGameThread ( ) & & ! IsInParallelGameThread ( ) ) ;
2023-06-12 11:06:50 -04:00
2023-11-04 01:30:32 -04:00
Obj - > GetPrivate ( ) - > bLocked = false ;
2022-09-26 15:12:13 -04:00
}
2022-11-24 10:07:28 -05:00
bool UCustomizableObjectSystem : : CheckIfDiskOrMipUpdateOperationsPending ( const UCustomizableObject & Object ) const
{
for ( TObjectIterator < UCustomizableObjectInstance > CustomizableObjectInstance ; CustomizableObjectInstance ; + + CustomizableObjectInstance )
{
2023-11-09 06:25:16 -05:00
if ( IsValid ( * CustomizableObjectInstance ) & & CustomizableObjectInstance - > GetCustomizableObject ( ) = = & Object )
2022-11-24 10:07:28 -05:00
{
for ( const FGeneratedTexture & GeneratedTexture : CustomizableObjectInstance - > GetPrivate ( ) - > GeneratedTextures )
{
if ( GeneratedTexture . Texture - > HasPendingInitOrStreaming ( ) )
{
return true ;
}
}
}
}
// Ensure that we don't try to handle any further streaming operations for this object
check ( GetPrivate ( ) ) ;
2023-06-26 02:16:47 -04:00
if ( const FUnrealMutableModelBulkReader * Streamer = GetPrivate ( ) - > Streamer . Get ( ) )
2022-11-24 10:07:28 -05:00
{
if ( Streamer - > AreTherePendingStreamingOperationsForObject ( & Object ) )
{
return true ;
}
}
return false ;
}
2022-09-26 15:12:13 -04:00
void UCustomizableObjectSystem : : EditorSettingsChanged ( const FEditorCompileSettings & InEditorSettings )
{
EditorSettings = InEditorSettings ;
}
bool UCustomizableObjectSystem : : IsCompilationDisabled ( ) const
{
return EditorSettings . bDisableCompilation ;
}
bool UCustomizableObjectSystem : : IsAutoCompileEnabled ( ) const
{
return EditorSettings . bEnableAutomaticCompilation ;
}
bool UCustomizableObjectSystem : : IsAutoCompilationSync ( ) const
{
return EditorSettings . bCompileObjectsSynchronously ;
}
# endif
void UCustomizableObjectSystem : : PurgePendingReleaseSkeletalMesh ( )
{
MUTABLE_CPUPROFILER_SCOPE ( UCustomizableObjectSystem : : PurgePendingReleaseSkeletalMesh ) ;
2023-09-07 04:23:11 -04:00
const double CurTime = FPlatformTime : : Seconds ( ) ;
2022-09-26 15:12:13 -04:00
static double TimeToDelete = 1.0 ;
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
for ( int32 InfoIndex = PendingReleaseSkeletalMesh . Num ( ) - 1 ; InfoIndex > = 0 ; - - InfoIndex )
2022-09-26 15:12:13 -04:00
{
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
FPendingReleaseSkeletalMeshInfo & Info = PendingReleaseSkeletalMesh [ InfoIndex ] ;
2022-09-26 15:12:13 -04:00
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
if ( Info . SkeletalMesh ! = nullptr )
2022-09-26 15:12:13 -04:00
{
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
if ( ( CurTime - Info . TimeStamp ) > = TimeToDelete )
2022-09-26 15:12:13 -04:00
{
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
if ( Info . SkeletalMesh - > GetSkeleton ( ) )
2022-09-26 15:12:13 -04:00
{
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
Info . SkeletalMesh - > GetSkeleton ( ) - > ClearCacheData ( ) ;
2022-09-26 15:12:13 -04:00
}
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
Info . SkeletalMesh - > GetRefSkeleton ( ) . Empty ( ) ;
Info . SkeletalMesh - > GetMaterials ( ) . Empty ( ) ;
Info . SkeletalMesh - > GetRefBasesInvMatrix ( ) . Empty ( ) ;
Info . SkeletalMesh - > ReleaseResources ( ) ;
Info . SkeletalMesh - > ReleaseResourcesFence . Wait ( ) ;
2022-09-26 15:12:13 -04:00
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
PendingReleaseSkeletalMesh . RemoveAt ( InfoIndex ) ;
2022-09-26 15:12:13 -04:00
}
}
}
}
2023-08-31 13:21:05 -04:00
static int32 TicksUntilMaterialRelease = 4 ;
static FAutoConsoleVariableRef CVarTicksUntilMaterialRelease (
TEXT ( " mutable.TicksUntilMaterialRelease " ) , TicksUntilMaterialRelease ,
TEXT ( " If higher than zero, the number of ticks to keep discarded materials guarded from being GCed. " ) ,
ECVF_Default ) ;
void UCustomizableObjectSystem : : AddPendingReleaseMaterials ( TArray < TObjectPtr < UMaterialInterface > > & InMaterials )
{
if ( TicksUntilMaterialRelease > 0 )
{
FPendingReleaseMaterialsInfo & PendingMaterials = PendingReleaseMaterials . AddDefaulted_GetRef ( ) ;
PendingMaterials . Materials = InMaterials ;
PendingMaterials . TicksUntilRelease = TicksUntilMaterialRelease ;
}
}
void UCustomizableObjectSystem : : TickPendingReleaseMaterials ( )
{
2023-09-07 04:23:11 -04:00
for ( TArray < FPendingReleaseMaterialsInfo > : : TIterator PendingRelease = PendingReleaseMaterials . CreateIterator ( ) ; PendingRelease ; + + PendingRelease )
2023-08-31 13:21:05 -04:00
{
if ( - - PendingRelease - > TicksUntilRelease < = 0 )
{
PendingRelease . RemoveCurrent ( ) ;
}
}
}
2023-08-10 14:14:20 -04:00
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
void UCustomizableObjectSystem : : AddPendingReleaseSkeletalMesh ( USkeletalMesh * SkeletalMesh )
2022-09-26 15:12:13 -04:00
{
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
check ( SkeletalMesh ! = nullptr ) ;
2022-09-26 15:12:13 -04:00
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
FPendingReleaseSkeletalMeshInfo Info ;
Info . SkeletalMesh = SkeletalMesh ;
Info . TimeStamp = FPlatformTime : : Seconds ( ) ;
2022-09-26 15:12:13 -04:00
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
PendingReleaseSkeletalMesh . Add ( Info ) ;
2022-09-26 15:12:13 -04:00
}
void UCustomizableObjectSystem : : ClearCurrentMutableOperation ( )
{
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
check ( Private ! = nullptr ) ;
2022-09-26 15:12:13 -04:00
Private - > CurrentInstanceBeingUpdated = nullptr ;
Private - > CurrentMutableOperation = nullptr ;
ClearResourceCacheProtected ( ) ;
}
2023-05-24 02:50:03 -04:00
void FCustomizableObjectSystemPrivate : : UpdateMemoryLimit ( )
2022-09-26 15:12:13 -04:00
{
// This must run on game thread, and when the mutable thread is not running
check ( IsInGameThread ( ) ) ;
2023-05-24 02:50:03 -04:00
const uint64 MemoryBytes = CVarWorkingMemory . GetValueOnGameThread ( ) * 1024 ;
if ( MemoryBytes ! = LastWorkingMemoryBytes )
2022-09-26 15:12:13 -04:00
{
2023-05-24 02:50:03 -04:00
LastWorkingMemoryBytes = MemoryBytes ;
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
check ( MutableSystem ) ;
2023-05-24 02:50:03 -04:00
MutableSystem - > SetWorkingMemoryBytes ( MemoryBytes ) ;
2022-09-26 15:12:13 -04:00
}
2023-06-26 02:16:47 -04:00
const uint32 GeneratedResourceCacheSize = CVarGeneratedResourcesCacheSize . GetValueOnGameThread ( ) ;
if ( GeneratedResourceCacheSize ! = LastGeneratedResourceCacheSize )
{
LastGeneratedResourceCacheSize = GeneratedResourceCacheSize ;
check ( MutableSystem ) ;
MutableSystem - > SetGeneratedCacheSize ( GeneratedResourceCacheSize ) ;
}
2022-09-26 15:12:13 -04:00
}
// Asynchronous tasks performed during the creation or update of a mutable instance.
// Check the documentation before modifying and keep it up to date.
// https://docs.google.com/drawings/d/109NlsdKVxP59K5TuthJkleVG3AROkLJr6N03U4bNp4s
// When it says "mutable thread" it means any task pool thread, but with the guarantee that no other thread is using the mutable runtime.
// Naming: Task_<thread>_<description>
namespace impl
{
2023-10-17 03:57:37 -04:00
void Subtask_Mutable_UpdateParameterRelevancy ( const TSharedRef < FUpdateContextPrivate > & OperationData )
2022-09-26 15:12:13 -04:00
{
2023-04-25 06:07:49 -04:00
MUTABLE_CPUPROFILER_SCOPE ( Subtask_Mutable_UpdateParameterRelevancy )
2022-09-26 15:12:13 -04:00
2023-10-17 03:57:37 -04:00
check ( OperationData - > Parameters ) ;
2023-04-25 06:07:49 -04:00
check ( OperationData - > InstanceID ! = 0 ) ;
2022-09-26 15:12:13 -04:00
2023-09-07 04:23:11 -04:00
OperationData - > RelevantParametersInProgress . Empty ( ) ;
2022-09-26 15:12:13 -04:00
// This must run in the mutable thread.
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
check ( UCustomizableObjectSystem : : GetInstance ( ) ! = nullptr ) ;
check ( UCustomizableObjectSystem : : GetInstance ( ) - > GetPrivate ( ) ! = nullptr ) ;
2023-09-07 04:23:11 -04:00
const mu : : Ptr < mu : : System > MutableSystem = UCustomizableObjectSystem : : GetInstance ( ) - > GetPrivate ( ) - > MutableSystem ;
2022-09-26 15:12:13 -04:00
// Update the parameter relevancy.
{
MUTABLE_CPUPROFILER_SCOPE ( ParameterRelevancy )
2023-10-17 03:57:37 -04:00
const int32 NumParameters = OperationData - > Parameters - > GetCount ( ) ;
2023-09-07 04:23:11 -04:00
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
TArray < bool > Relevant ;
Relevant . SetNumZeroed ( NumParameters ) ;
2023-10-17 03:57:37 -04:00
MutableSystem - > GetParameterRelevancy ( OperationData - > InstanceID , OperationData - > Parameters , Relevant . GetData ( ) ) ;
2022-09-26 15:12:13 -04:00
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
for ( int32 ParamIndex = 0 ; ParamIndex < NumParameters ; + + ParamIndex )
2022-09-26 15:12:13 -04:00
{
2023-04-25 06:07:49 -04:00
if ( Relevant [ ParamIndex ] )
2022-09-26 15:12:13 -04:00
{
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
OperationData - > RelevantParametersInProgress . Add ( ParamIndex ) ;
2022-09-26 15:12:13 -04:00
}
}
}
}
2023-11-03 14:21:25 -04:00
void CreateMutableInstance ( const TSharedRef < FUpdateContextPrivate > & Operation )
{
UCustomizableObjectSystem * System = UCustomizableObjectSystem : : GetInstanceChecked ( ) ; // Save since UCustomizableObjectSystem::BeginDestroy always waits for all tasks to finish
const FCustomizableObjectSystemPrivate * SystemPrivate = System - > GetPrivateChecked ( ) ;
const mu : : Ptr < mu : : System > MutableSystem = SystemPrivate - > MutableSystem ;
const TSharedPtr < mu : : Model > Model = Operation - > Instance - > GetCustomizableObject ( ) - > GetPrivate ( ) - > GetModel ( ) ;
if ( Operation - > bLiveUpdateMode )
{
if ( Operation - > InstanceID = = 0 )
{
// It's the first update since the instance was put in LiveUpdate Mode, this ID will be reused from now on
Operation - > InstanceID = MutableSystem - > NewInstance ( Model ) ;
UE_LOG ( LogMutable , Verbose , TEXT ( " Creating Mutable instance with id [%d] for reuse " ) , Operation - > InstanceID ) ;
}
else
{
// The instance was already in LiveUpdate Mode, the ID is reused
check ( Operation - > InstanceID ) ;
UE_LOG ( LogMutable , Verbose , TEXT ( " Reusing Mutable instance with id [%d] " ) , Operation - > InstanceID ) ;
}
}
else
{
// In non-LiveUpdate mode, we are forcing the recreation of mutable-side instances with every update.
check ( Operation - > InstanceID = = 0 ) ;
Operation - > InstanceID = MutableSystem - > NewInstance ( Model ) ;
UE_LOG ( LogMutable , Verbose , TEXT ( " Creating Mutable instance with id [%d] " ) , Operation - > InstanceID ) ;
}
2023-12-01 10:03:28 -05:00
Operation - > MutableInstance = MutableSystem - > BeginUpdate ( Operation - > InstanceID , Operation - > Parameters , Operation - > State , mu : : System : : AllLODs ) ;
2023-11-03 14:21:25 -04:00
}
void FixLODs ( const TSharedRef < FUpdateContextPrivate > & Operation )
{
Operation - > NumLODsAvailable = Operation - > MutableInstance - > GetLODCount ( ) ;
if ( Operation - > CurrentMinLOD > = Operation - > NumLODsAvailable )
{
Operation - > CurrentMinLOD = Operation - > NumLODsAvailable - 1 ;
Operation - > CurrentMaxLOD = Operation - > CurrentMinLOD ;
}
else if ( Operation - > CurrentMaxLOD > = Operation - > NumLODsAvailable )
{
Operation - > CurrentMaxLOD = Operation - > NumLODsAvailable - 1 ;
}
2023-11-08 08:42:39 -05:00
// Initialize RequestedLODs to zero if not set
Operation - > RequestedLODs . SetNumZeroed ( Operation - > NumComponents ) ;
for ( int32 ComponentIndex = 0 ; ComponentIndex < Operation - > NumComponents ; + + ComponentIndex )
{
// Ensure we're generating at least one LOD
for ( int32 LODIndex = Operation - > CurrentMaxLOD ; LODIndex < MAX_MESH_LOD_COUNT ; + + LODIndex )
{
Operation - > RequestedLODs [ ComponentIndex ] | = ( 1 < < LODIndex ) ;
}
}
Operation - > InstanceDescriptorRuntimeHash . UpdateRequestedLODs ( Operation - > RequestedLODs ) ;
2023-11-03 14:21:25 -04:00
}
2023-03-23 08:20:51 -04:00
// This runs in the mutable thread.
2023-10-17 03:57:37 -04:00
void Subtask_Mutable_BeginUpdate_GetMesh ( const TSharedRef < FUpdateContextPrivate > & OperationData , TSharedPtr < mu : : Model > Model )
2022-09-26 15:12:13 -04:00
{
2023-03-23 08:20:51 -04:00
MUTABLE_CPUPROFILER_SCOPE ( Subtask_Mutable_BeginUpdate_GetMesh )
2022-09-26 15:12:13 -04:00
2023-10-17 03:57:37 -04:00
check ( OperationData - > Parameters ) ;
2022-09-26 15:12:13 -04:00
OperationData - > InstanceUpdateData . Clear ( ) ;
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
check ( UCustomizableObjectSystem : : GetInstance ( ) ! = nullptr ) ;
check ( UCustomizableObjectSystem : : GetInstance ( ) - > GetPrivate ( ) ! = nullptr ) ;
2022-09-26 15:12:13 -04:00
mu : : System * System = UCustomizableObjectSystem : : GetInstance ( ) - > GetPrivate ( ) - > MutableSystem . get ( ) ;
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
check ( System ! = nullptr ) ;
2022-09-26 15:12:13 -04:00
2023-09-27 07:44:07 -04:00
const UCustomizableObject * CustomizableObject = OperationData - > Instance - > GetCustomizableObject ( ) ;
UCustomizableInstancePrivateData * CustomizableObjectInstancePrivateData = OperationData - > Instance - > GetPrivate ( ) ;
CustomizableObjectInstancePrivateData - > PassThroughTexturesToLoad . Empty ( ) ;
2023-09-13 06:59:56 -04:00
if ( OperationData - > PixelFormatOverride )
{
System - > SetImagePixelConversionOverride ( OperationData - > PixelFormatOverride ) ;
}
2023-11-03 14:21:25 -04:00
if ( ! OperationData - > bUseMeshCache )
{
CreateMutableInstance ( OperationData ) ;
FixLODs ( OperationData ) ;
}
2022-09-26 15:12:13 -04:00
// Main instance generation step
2023-09-07 04:23:11 -04:00
// LOD mask, set to all ones to build all LODs
2023-11-03 14:21:25 -04:00
const mu : : Instance * Instance = OperationData - > MutableInstance ; // TODO GMTFuture remove
2023-09-07 04:23:11 -04:00
if ( ! Instance )
2022-09-26 15:12:13 -04:00
{
2023-09-07 04:23:11 -04:00
UE_LOG ( LogMutable , Warning , TEXT ( " An Instace update has failed. " ) ) ;
return ;
2022-09-26 15:12:13 -04:00
}
2023-05-10 08:29:50 -04:00
// Map SharedSurfaceId to surface index
TArray < int32 > SurfacesSharedId ;
2022-09-26 15:12:13 -04:00
// Generate the mesh and gather all the required resource Ids
OperationData - > InstanceUpdateData . LODs . SetNum ( Instance - > GetLODCount ( ) ) ;
for ( int32 MutableLODIndex = 0 ; MutableLODIndex < Instance - > GetLODCount ( ) ; + + MutableLODIndex )
{
2023-09-07 04:23:11 -04:00
// Skip LODs outside the range we want to generate
2022-09-26 15:12:13 -04:00
if ( MutableLODIndex < OperationData - > CurrentMinLOD | | MutableLODIndex > OperationData - > CurrentMaxLOD )
{
continue ;
}
FInstanceUpdateData : : FLOD & LOD = OperationData - > InstanceUpdateData . LODs [ MutableLODIndex ] ;
LOD . FirstComponent = OperationData - > InstanceUpdateData . Components . Num ( ) ;
LOD . ComponentCount = Instance - > GetComponentCount ( MutableLODIndex ) ;
for ( int32 ComponentIndex = 0 ; ComponentIndex < LOD . ComponentCount ; + + ComponentIndex )
{
OperationData - > InstanceUpdateData . Components . Push ( FInstanceUpdateData : : FComponent ( ) ) ;
FInstanceUpdateData : : FComponent & Component = OperationData - > InstanceUpdateData . Components . Last ( ) ;
Component . Id = Instance - > GetComponentId ( MutableLODIndex , ComponentIndex ) ;
Component . FirstSurface = OperationData - > InstanceUpdateData . Surfaces . Num ( ) ;
Component . SurfaceCount = 0 ;
2023-01-24 08:45:18 -05:00
const bool bGenerateLOD = OperationData - > RequestedLODs . IsValidIndex ( Component . Id ) ? ( OperationData - > RequestedLODs [ Component . Id ] & ( 1 < < MutableLODIndex ) ) ! = 0 : true ;
2022-09-26 15:12:13 -04:00
// Mesh
if ( Instance - > GetMeshCount ( MutableLODIndex , ComponentIndex ) > 0 )
{
MUTABLE_CPUPROFILER_SCOPE ( GetMesh ) ;
2023-01-24 08:45:18 -05:00
Component . MeshID = Instance - > GetMeshId ( MutableLODIndex , ComponentIndex , 0 ) ;
2022-09-26 15:12:13 -04:00
2023-10-05 09:01:56 -04:00
if ( bGenerateLOD )
2023-01-24 08:45:18 -05:00
{
Component . Mesh = System - > GetMesh ( OperationData - > InstanceID , Component . MeshID ) ;
}
2022-09-26 15:12:13 -04:00
}
2023-10-05 09:01:56 -04:00
if ( ! Component . Mesh )
2022-09-26 15:12:13 -04:00
{
continue ;
}
2023-01-24 08:45:18 -05:00
Component . bGenerated = true ;
2022-09-26 15:12:13 -04:00
// Materials and images
2023-10-05 09:01:56 -04:00
const int32 SurfaceCount = Component . Mesh - > GetSurfaceCount ( ) ;
2023-01-24 08:45:18 -05:00
for ( int32 MeshSurfaceIndex = 0 ; MeshSurfaceIndex < SurfaceCount ; + + MeshSurfaceIndex )
2022-09-26 15:12:13 -04:00
{
2023-10-05 09:01:56 -04:00
const uint32 SurfaceId = Component . Mesh - > GetSurfaceId ( MeshSurfaceIndex ) ;
2023-09-07 04:23:11 -04:00
const int32 InstanceSurfaceIndex = Instance - > FindSurfaceById ( MutableLODIndex , ComponentIndex , SurfaceId ) ;
2023-10-05 09:01:56 -04:00
check ( Component . Mesh - > GetVertexCount ( ) > 0 | | InstanceSurfaceIndex > = 0 ) ;
2022-09-26 15:12:13 -04:00
2023-05-10 08:29:50 -04:00
int32 BaseSurfaceIndex = InstanceSurfaceIndex ;
int32 BaseLODIndex = MutableLODIndex ;
2022-09-26 15:12:13 -04:00
if ( InstanceSurfaceIndex > = 0 )
{
OperationData - > InstanceUpdateData . Surfaces . Push ( { } ) ;
FInstanceUpdateData : : FSurface & Surface = OperationData - > InstanceUpdateData . Surfaces . Last ( ) ;
+ + Component . SurfaceCount ;
2023-07-28 02:20:23 -04:00
// Now Surface.MaterialIndex is decoded from a parameter at the end of this if()
2022-10-04 07:53:49 -04:00
Surface . SurfaceId = SurfaceId ;
2022-09-26 15:12:13 -04:00
2023-05-10 08:29:50 -04:00
const int32 SharedSurfaceId = Instance - > GetSharedSurfaceId ( MutableLODIndex , ComponentIndex , InstanceSurfaceIndex ) ;
const int32 SharedSurfaceIndex = SurfacesSharedId . Find ( SharedSurfaceId ) ;
SurfacesSharedId . Add ( SharedSurfaceId ) ;
if ( SharedSurfaceId ! = INDEX_NONE )
{
if ( SharedSurfaceIndex > = 0 )
{
Surface = OperationData - > InstanceUpdateData . Surfaces [ SharedSurfaceIndex ] ;
continue ;
}
// Find the first LOD where this surface can be found
Instance - > FindBaseSurfaceBySharedId ( ComponentIndex , SharedSurfaceId , BaseSurfaceIndex , BaseLODIndex ) ;
Surface . SurfaceId = Instance - > GetSurfaceId ( BaseLODIndex , ComponentIndex , BaseSurfaceIndex ) ;
}
2022-09-26 15:12:13 -04:00
// Images
Surface . FirstImage = OperationData - > InstanceUpdateData . Images . Num ( ) ;
2023-07-20 07:38:13 -04:00
Surface . ImageCount = Instance - > GetImageCount ( BaseLODIndex , ComponentIndex , InstanceSurfaceIndex ) ;
2022-09-26 15:12:13 -04:00
for ( int32 ImageIndex = 0 ; ImageIndex < Surface . ImageCount ; + + ImageIndex )
{
MUTABLE_CPUPROFILER_SCOPE ( GetImageId ) ;
OperationData - > InstanceUpdateData . Images . Push ( { } ) ;
FInstanceUpdateData : : FImage & Image = OperationData - > InstanceUpdateData . Images . Last ( ) ;
2023-07-20 07:38:13 -04:00
Image . Name = Instance - > GetImageName ( BaseLODIndex , ComponentIndex , InstanceSurfaceIndex , ImageIndex ) ;
2023-05-10 08:29:50 -04:00
Image . ImageID = Instance - > GetImageId ( BaseLODIndex , ComponentIndex , BaseSurfaceIndex , ImageIndex ) ;
2022-09-26 15:12:13 -04:00
Image . FullImageSizeX = 0 ;
Image . FullImageSizeY = 0 ;
2023-05-10 08:29:50 -04:00
Image . BaseLOD = BaseLODIndex ;
2023-08-25 05:16:17 -04:00
Image . BaseMip = 0 ;
2023-09-27 07:44:07 -04:00
FString KeyName = Image . Name . ToString ( ) ;
int32 ImageKey = FCString : : Atoi ( * KeyName ) ;
if ( ImageKey > = 0 & & ImageKey < CustomizableObject - > ImageProperties . Num ( ) )
{
const FMutableModelImageProperties & Props = CustomizableObject - > ImageProperties [ ImageKey ] ;
if ( Props . IsPassThrough )
{
2023-11-03 09:03:29 -04:00
// Since it's known it's a pass-through texture there is no need to cache or convert it so we can generate it here already.
2023-09-27 07:44:07 -04:00
Image . Image = System - > GetImage ( OperationData - > InstanceID , Image . ImageID , 0 , 0 ) ;
check ( Image . Image - > IsReference ( ) ) ;
uint32 ReferenceID = Image . Image - > GetReferencedTexture ( ) ;
if ( CustomizableObject - > ReferencedPassThroughTextures . IsValidIndex ( ReferenceID ) )
{
TSoftObjectPtr < UTexture > Ref = CustomizableObject - > ReferencedPassThroughTextures [ ReferenceID ] ;
CustomizableObjectInstancePrivateData - > PassThroughTexturesToLoad . Add ( Ref ) ;
Image . bIsPassThrough = true ;
}
else
{
// internal error.
UE_LOG ( LogMutable , Error , TEXT ( " Referenced image [%d] was not stored in the resource array. " ) , ReferenceID ) ;
}
}
}
else
{
// This means the compiled model (maybe coming from derived data) has images that the asset doesn't know about.
UE_LOG ( LogMutable , Error , TEXT ( " CustomizableObject derived data out of sync with asset for [%s]. Try recompiling it. " ) , * CustomizableObject - > GetName ( ) ) ;
}
2022-09-26 15:12:13 -04:00
}
// Vectors
Surface . FirstVector = OperationData - > InstanceUpdateData . Vectors . Num ( ) ;
2023-07-20 07:38:13 -04:00
Surface . VectorCount = Instance - > GetVectorCount ( BaseLODIndex , ComponentIndex , InstanceSurfaceIndex ) ;
2022-09-26 15:12:13 -04:00
for ( int32 VectorIndex = 0 ; VectorIndex < Surface . VectorCount ; + + VectorIndex )
{
MUTABLE_CPUPROFILER_SCOPE ( GetVector ) ;
OperationData - > InstanceUpdateData . Vectors . Push ( { } ) ;
FInstanceUpdateData : : FVector & Vector = OperationData - > InstanceUpdateData . Vectors . Last ( ) ;
2023-07-20 07:38:13 -04:00
Vector . Name = Instance - > GetVectorName ( BaseLODIndex , ComponentIndex , InstanceSurfaceIndex , VectorIndex ) ;
Vector . Vector = Instance - > GetVector ( BaseLODIndex , ComponentIndex , InstanceSurfaceIndex , VectorIndex ) ;
2022-09-26 15:12:13 -04:00
}
// Scalars
Surface . FirstScalar = OperationData - > InstanceUpdateData . Scalars . Num ( ) ;
2023-07-20 07:38:13 -04:00
Surface . ScalarCount = Instance - > GetScalarCount ( BaseLODIndex , ComponentIndex , InstanceSurfaceIndex ) ;
2022-09-26 15:12:13 -04:00
for ( int32 ScalarIndex = 0 ; ScalarIndex < Surface . ScalarCount ; + + ScalarIndex )
{
2023-07-28 02:20:23 -04:00
MUTABLE_CPUPROFILER_SCOPE ( GetScalar )
2023-09-26 04:43:37 -04:00
const FName ScalarName = Instance - > GetScalarName ( BaseLODIndex , ComponentIndex , InstanceSurfaceIndex , ScalarIndex ) ;
2023-09-07 04:23:11 -04:00
const float ScalarValue = Instance - > GetScalar ( BaseLODIndex , ComponentIndex , InstanceSurfaceIndex , ScalarIndex ) ;
2023-07-28 02:20:23 -04:00
FString EncodingMaterialIdString = " __MutableMaterialId " ;
// Decoding Material Switch from Mutable parameter name
2023-09-26 04:43:37 -04:00
if ( ScalarName . ToString ( ) . Equals ( EncodingMaterialIdString ) )
2023-07-28 02:20:23 -04:00
{
2023-09-07 04:23:11 -04:00
Surface . MaterialIndex = static_cast < uint32 > ( ScalarValue ) ;
2023-07-28 02:20:23 -04:00
// This parameter is not needed in the final material instance
Surface . ScalarCount - = 1 ;
}
else
{
OperationData - > InstanceUpdateData . Scalars . Push ( { ScalarName , ScalarValue } ) ;
}
2022-09-26 15:12:13 -04:00
}
}
}
}
}
2023-04-05 11:20:44 -04:00
// Copy ExtensionData Object node input from the Instance to the InstanceUpdateData
for ( int32 ExtensionDataIndex = 0 ; ExtensionDataIndex < Instance - > GetExtensionDataCount ( ) ; ExtensionDataIndex + + )
{
2023-09-26 04:43:37 -04:00
mu : : Ptr < const mu : : ExtensionData > ExtensionData ;
FName Name ;
Instance - > GetExtensionData ( ExtensionDataIndex , ExtensionData , Name ) ;
2023-04-05 11:20:44 -04:00
check ( ExtensionData ) ;
FInstanceUpdateData : : FNamedExtensionData & NewEntry = OperationData - > InstanceUpdateData . ExtendedInputPins . AddDefaulted_GetRef ( ) ;
NewEntry . Data = ExtensionData ;
2023-09-26 04:43:37 -04:00
NewEntry . Name = Name ;
2023-04-05 11:20:44 -04:00
check ( NewEntry . Name ! = NAME_None ) ;
}
2022-09-26 15:12:13 -04:00
}
2023-03-23 08:20:51 -04:00
// This runs in the mutable thread.
2023-10-17 03:57:37 -04:00
void Subtask_Mutable_GetImages ( const TSharedRef < FUpdateContextPrivate > & OperationData )
2022-09-26 15:12:13 -04:00
{
2023-03-23 08:20:51 -04:00
MUTABLE_CPUPROFILER_SCOPE ( Subtask_Mutable_GetImages )
2022-09-26 15:12:13 -04:00
2023-09-07 04:23:11 -04:00
const FCustomizableObjectSystemPrivate * CustomizableObjectSystemPrivateData = UCustomizableObjectSystem : : GetInstanceChecked ( ) - > GetPrivateChecked ( ) ;
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
mu : : System * System = CustomizableObjectSystemPrivateData - > MutableSystem . get ( ) ;
check ( System ! = nullptr ) ;
2022-09-26 15:12:13 -04:00
// Generate all the required resources, that are not cached
2023-06-26 02:16:47 -04:00
TArray < mu : : FResourceID > ImagesInThisInstance ;
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
for ( FInstanceUpdateData : : FImage & Image : OperationData - > InstanceUpdateData . Images )
2022-09-26 15:12:13 -04:00
{
MUTABLE_CPUPROFILER_SCOPE ( GetImage ) ;
2023-09-27 07:44:07 -04:00
// If the image is a reference to an engine texture, we are done.
if ( Image . bIsPassThrough )
{
continue ;
}
2023-02-02 02:41:54 -05:00
mu : : FImageDesc ImageDesc ;
2022-09-26 15:12:13 -04:00
// This should only be done when using progressive images, since GetImageDesc does some actual processing.
{
System - > GetImageDesc ( OperationData - > InstanceID , Image . ImageID , ImageDesc ) ;
2023-03-01 12:33:52 -05:00
2023-09-07 04:23:11 -04:00
const uint16 MaxTextureSizeToGenerate = static_cast < uint16 > ( CustomizableObjectSystemPrivateData - > MaxTextureSizeToGenerate ) ;
const uint16 MaxSize = FMath : : Max ( ImageDesc . m_size [ 0 ] , ImageDesc . m_size [ 1 ] ) ;
2023-03-01 12:33:52 -05:00
uint16 Reduction = 1 ;
if ( MaxTextureSizeToGenerate > 0 & & MaxSize > MaxTextureSizeToGenerate )
{
2023-08-25 05:16:17 -04:00
// Find the reduction factor, and the BaseMip of the texture.
const uint32 NextPowerOfTwo = FMath : : RoundUpToPowerOfTwo ( FMath : : DivideAndRoundUp ( MaxSize , MaxTextureSizeToGenerate ) ) ;
Reduction = FMath : : Max ( NextPowerOfTwo , 2U ) ; // At least divide the texture by a factor of two
Image . BaseMip = FMath : : FloorLog2 ( Reduction ) ;
2023-03-01 12:33:52 -05:00
}
Image . FullImageSizeX = ImageDesc . m_size [ 0 ] / Reduction ;
Image . FullImageSizeY = ImageDesc . m_size [ 1 ] / Reduction ;
2022-09-26 15:12:13 -04:00
}
2023-06-27 06:04:11 -04:00
const bool bCached = ImagesInThisInstance . Contains ( Image . ImageID ) | | // See if it is cached from this same instance (can happen with LODs)
( CVarReuseImagesBetweenInstances . GetValueOnAnyThread ( ) & & CustomizableObjectSystemPrivateData - > ProtectedObjectCachedImages . Contains ( Image . ImageID ) ) ; // See if it is cached from another instance
2022-09-26 15:12:13 -04:00
if ( bCached )
{
2023-09-07 04:23:11 -04:00
UE_LOG ( LogMutable , VeryVerbose , TEXT ( " Texture resource with id [%llu] is cached. " ) , Image . ImageID ) ;
2022-09-26 15:12:13 -04:00
}
else
{
2023-09-07 04:23:11 -04:00
const int32 MaxSize = FMath : : Max ( Image . FullImageSizeX , Image . FullImageSizeY ) ;
const int32 FullLODCount = FMath : : CeilLogTwo ( MaxSize ) + 1 ;
const int32 MinMipsInImage = FMath : : Min ( FullLODCount , UTexture : : GetStaticMinTextureResidentMipCount ( ) ) ;
const int32 MaxMipsToSkip = FullLODCount - MinMipsInImage ;
2022-09-26 15:12:13 -04:00
int32 MipsToSkip = FMath : : Min ( MaxMipsToSkip , OperationData - > MipsToSkip ) ;
2023-02-02 02:41:54 -05:00
2023-03-16 13:03:00 -04:00
if ( ! FMath : : IsPowerOfTwo ( Image . FullImageSizeX ) | | ! FMath : : IsPowerOfTwo ( Image . FullImageSizeY ) )
{
// It doesn't make sense to skip mips as non-power-of-two size textures cannot be streamed anyway
MipsToSkip = 0 ;
}
2023-05-26 15:05:33 -04:00
const int32 MipSizeX = FMath : : Max ( Image . FullImageSizeX > > MipsToSkip , 1 ) ;
const int32 MipSizeY = FMath : : Max ( Image . FullImageSizeY > > MipsToSkip , 1 ) ;
2023-09-26 04:43:37 -04:00
if ( MipsToSkip > 0 & & CustomizableObjectSystemPrivateData - > EnableSkipGenerateResidentMips ! = 0 & & OperationData - > LowPriorityTextures . Find ( Image . Name . ToString ( ) ) ! = INDEX_NONE )
2023-02-02 02:41:54 -05:00
{
2023-06-23 02:01:13 -04:00
Image . Image = new mu : : Image ( MipSizeX , MipSizeY , FullLODCount - MipsToSkip , ImageDesc . m_format , mu : : EInitializationType : : Black ) ;
2023-02-02 02:41:54 -05:00
}
else
{
2023-08-25 05:16:17 -04:00
Image . Image = System - > GetImage ( OperationData - > InstanceID , Image . ImageID , Image . BaseMip + MipsToSkip , Image . BaseLOD ) ;
2023-02-02 02:41:54 -05:00
}
2022-09-26 15:12:13 -04:00
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
check ( Image . Image ) ;
2023-04-28 15:57:31 -04:00
2023-09-07 04:23:11 -04:00
// We should have generated exactly this size.
const bool bSizeMissmatch = Image . Image - > GetSizeX ( ) ! = MipSizeX | | Image . Image - > GetSizeY ( ) ! = MipSizeY ;
2023-05-26 15:05:33 -04:00
if ( bSizeMissmatch )
{
// Generate a correctly-sized but empty image instead, to avoid crashes.
2023-09-07 04:23:11 -04:00
UE_LOG ( LogMutable , Warning , TEXT ( " Mutable generated a wrongly-sized image %llu. " ) , Image . ImageID ) ;
2023-06-23 02:01:13 -04:00
Image . Image = new mu : : Image ( MipSizeX , MipSizeY , FullLODCount - MipsToSkip , Image . Image - > GetFormat ( ) , mu : : EInitializationType : : Black ) ;
2023-05-26 15:05:33 -04:00
}
2023-04-28 15:57:31 -04:00
// We need one mip or the complete chain. Otherwise there was a bug.
2023-09-07 04:23:11 -04:00
const int32 FullMipCount = Image . Image - > GetMipmapCount ( Image . Image - > GetSizeX ( ) , Image . Image - > GetSizeY ( ) ) ;
const int32 RealMipCount = Image . Image - > GetLODCount ( ) ;
2023-05-26 15:05:33 -04:00
bool bForceMipchain =
// Did we fail to generate the entire mipchain (if we have mips at all)?
( RealMipCount ! = 1 ) & & ( RealMipCount ! = FullMipCount ) ;
if ( bForceMipchain )
2022-09-26 15:12:13 -04:00
{
MUTABLE_CPUPROFILER_SCOPE ( GetImage_MipFix ) ;
2023-09-07 04:23:11 -04:00
UE_LOG ( LogMutable , Warning , TEXT ( " Mutable generated an incomplete mip chain for image %llu. " ) , Image . ImageID ) ;
2022-09-26 15:12:13 -04:00
// Force the right number of mips. The missing data will be black.
2023-09-07 04:23:11 -04:00
const mu : : Ptr < mu : : Image > NewImage = new mu : : Image ( Image . Image - > GetSizeX ( ) , Image . Image - > GetSizeY ( ) , FullMipCount , Image . Image - > GetFormat ( ) , mu : : EInitializationType : : Black ) ;
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
check ( NewImage ) ;
2022-09-26 15:12:13 -04:00
if ( NewImage - > GetDataSize ( ) > = Image . Image - > GetDataSize ( ) )
{
FMemory : : Memcpy ( NewImage - > GetData ( ) , Image . Image - > GetData ( ) , Image . Image - > GetDataSize ( ) ) ;
}
Image . Image = NewImage ;
}
ImagesInThisInstance . Add ( Image . ImageID ) ;
}
}
}
2023-03-16 13:03:00 -04:00
2022-09-26 15:12:13 -04:00
2023-03-23 08:20:51 -04:00
// This runs in a worker thread
2023-10-17 03:57:37 -04:00
void Subtask_Mutable_PrepareTextures ( const TSharedRef < FUpdateContextPrivate > & OperationData )
2022-09-26 15:12:13 -04:00
{
2023-03-23 08:20:51 -04:00
MUTABLE_CPUPROFILER_SCOPE ( Subtask_Mutable_PrepareTextures )
2022-09-26 15:12:13 -04:00
for ( const FInstanceUpdateData : : FSurface & Surface : OperationData - > InstanceUpdateData . Surfaces )
{
for ( int32 ImageIndex = 0 ; ImageIndex < Surface . ImageCount ; + + ImageIndex )
{
const FInstanceUpdateData : : FImage & Image = OperationData - > InstanceUpdateData . Images [ Surface . FirstImage + ImageIndex ] ;
2023-09-26 04:43:37 -04:00
const FName KeyName = Image . Name ;
2022-09-26 15:12:13 -04:00
mu : : ImagePtrConst MutableImage = Image . Image ;
// If the image is null, it must be in the cache (or repeated in this instance), and we don't need to do anything here.
if ( MutableImage )
{
2023-09-07 04:23:11 -04:00
// Image references are just references to texture assets and require no work at all
2023-05-24 09:51:14 -04:00
if ( ! MutableImage - > IsReference ( ) )
{
2023-09-07 12:42:16 -04:00
if ( ! OperationData - > ImageToPlatformDataMap . Contains ( Image . ImageID ) )
{
2023-11-30 09:17:22 -05:00
FTexturePlatformData * PlatformData = MutableCreateImagePlatformData ( MutableImage , - 1 , Image . FullImageSizeX , Image . FullImageSizeY ) ;
2023-09-07 12:42:16 -04:00
OperationData - > ImageToPlatformDataMap . Add ( Image . ImageID , PlatformData ) ;
}
else
{
// The ImageID already exists in the ImageToPlatformDataMap, that means the equivalent surface in a lower
// LOD already created the PlatformData for that ImageID and added it to the ImageToPlatformDataMap.
}
2023-05-24 09:51:14 -04:00
}
2022-09-26 15:12:13 -04:00
}
}
}
}
2023-03-01 12:33:52 -05:00
2022-09-26 15:12:13 -04:00
2023-03-23 08:20:51 -04:00
// This runs in a worker thread
2023-10-17 03:57:37 -04:00
void Subtask_Mutable_PrepareSkeletonData ( const TSharedRef < FUpdateContextPrivate > & OperationData )
2022-09-26 15:12:13 -04:00
{
2023-03-23 08:20:51 -04:00
MUTABLE_CPUPROFILER_SCOPE ( Subtask_Mutable_PrepareSkeletonData )
2022-09-26 15:12:13 -04:00
2023-08-31 15:22:46 -04:00
if ( bApplyFixPrepareSkeletons )
{
for ( FInstanceUpdateData : : FComponent & Component : OperationData - > InstanceUpdateData . Components )
{
if ( ! OperationData - > InstanceUpdateData . Skeletons . IsValidIndex ( Component . Id ) )
{
OperationData - > InstanceUpdateData . Skeletons . SetNum ( Component . Id + 1 ) ;
}
FInstanceUpdateData : : FSkeletonData & SkeletonData = OperationData - > InstanceUpdateData . Skeletons [ Component . Id ] ;
SkeletonData . ComponentIndex = Component . Id ;
mu : : MeshPtrConst Mesh = Component . Mesh ;
if ( ! Mesh )
{
continue ;
}
// Add SkeletonIds
const int32 SkeletonIDsCount = Mesh - > GetSkeletonIDsCount ( ) ;
for ( int32 SkeletonIndex = 0 ; SkeletonIndex < SkeletonIDsCount ; + + SkeletonIndex )
{
SkeletonData . SkeletonIds . AddUnique ( Mesh - > GetSkeletonID ( SkeletonIndex ) ) ;
}
// Append BoneMap to the array of BoneMaps
const TArray < uint16 > & BoneMap = Mesh - > GetBoneMap ( ) ;
Component . FirstBoneMap = OperationData - > InstanceUpdateData . BoneMaps . Num ( ) ;
Component . BoneMapCount = BoneMap . Num ( ) ;
OperationData - > InstanceUpdateData . BoneMaps . Append ( BoneMap ) ;
// Add active bone indices and poses
const int32 MaxBoneIndex = Mesh - > GetBonePoseCount ( ) ;
Component . ActiveBones . Reserve ( MaxBoneIndex ) ;
for ( int32 BonePoseIndex = 0 ; BonePoseIndex < MaxBoneIndex ; + + BonePoseIndex )
{
const uint16 BoneId = Mesh - > GetBonePoseBoneId ( BonePoseIndex ) ;
Component . ActiveBones . Add ( BoneId ) ;
if ( SkeletonData . BoneIds . Find ( BoneId ) = = INDEX_NONE )
{
SkeletonData . BoneIds . Add ( BoneId ) ;
FTransform3f Transform ;
Mesh - > GetBoneTransform ( BonePoseIndex , Transform ) ;
SkeletonData . BoneMatricesWithScale . Emplace ( Transform . Inverse ( ) . ToMatrixWithScale ( ) ) ;
}
}
}
return ;
}
2022-09-26 15:12:13 -04:00
const int32 LODCount = OperationData - > InstanceUpdateData . LODs . Num ( ) ;
const FInstanceUpdateData : : FLOD & MinLOD = OperationData - > InstanceUpdateData . LODs [ OperationData - > CurrentMinLOD ] ;
const int32 ComponentCount = MinLOD . ComponentCount ;
// Add SkeletonData for each component
OperationData - > InstanceUpdateData . Skeletons . AddDefaulted ( ComponentCount ) ;
for ( int32 ComponentIndex = 0 ; ComponentIndex < ComponentCount ; + + ComponentIndex )
{
2023-01-04 15:46:42 -05:00
FInstanceUpdateData : : FComponent & MinLODComponent = OperationData - > InstanceUpdateData . Components [ MinLOD . FirstComponent + ComponentIndex ] ;
2022-09-26 15:12:13 -04:00
// Set the ComponentIndex
OperationData - > InstanceUpdateData . Skeletons [ ComponentIndex ] . ComponentIndex = MinLODComponent . Id ;
// Fill the data used to generate the RefSkeletalMesh
2023-05-29 10:25:59 -04:00
TArray < uint16 > & SkeletonIds = OperationData - > InstanceUpdateData . Skeletons [ ComponentIndex ] . SkeletonIds ;
2023-06-28 07:02:00 -04:00
TArray < uint16 > & BoneIds = OperationData - > InstanceUpdateData . Skeletons [ ComponentIndex ] . BoneIds ;
TArray < FMatrix44f > & BoneMatricesWithScale = OperationData - > InstanceUpdateData . Skeletons [ ComponentIndex ] . BoneMatricesWithScale ;
2023-01-04 15:46:42 -05:00
2022-09-26 15:12:13 -04:00
// Use first valid LOD bone count as a potential total number of bones, used for pre-allocating data arrays
if ( MinLODComponent . Mesh & & MinLODComponent . Mesh - > GetSkeleton ( ) )
{
const int32 TotalPossibleBones = MinLODComponent . Mesh - > GetSkeleton ( ) - > GetBoneCount ( ) ;
// Out Data
2023-06-28 07:02:00 -04:00
BoneIds . Reserve ( TotalPossibleBones ) ;
2022-09-26 15:12:13 -04:00
BoneMatricesWithScale . Reserve ( TotalPossibleBones ) ;
}
for ( int32 LODIndex = OperationData - > CurrentMinLOD ; LODIndex < = OperationData - > CurrentMaxLOD & & LODIndex < LODCount ; + + LODIndex )
{
MUTABLE_CPUPROFILER_SCOPE ( PrepareSkeletonData_LODs ) ;
const FInstanceUpdateData : : FLOD & CurrentLOD = OperationData - > InstanceUpdateData . LODs [ LODIndex ] ;
FInstanceUpdateData : : FComponent & CurrentLODComponent = OperationData - > InstanceUpdateData . Components [ CurrentLOD . FirstComponent + ComponentIndex ] ;
mu : : MeshPtrConst Mesh = CurrentLODComponent . Mesh ;
2023-06-28 07:02:00 -04:00
if ( ! Mesh )
2022-09-26 15:12:13 -04:00
{
continue ;
}
2022-11-07 04:57:31 -05:00
// Add SkeletonIds
const int32 SkeletonIDsCount = Mesh - > GetSkeletonIDsCount ( ) ;
for ( int32 SkeletonIndex = 0 ; SkeletonIndex < SkeletonIDsCount ; + + SkeletonIndex )
{
SkeletonIds . AddUnique ( Mesh - > GetSkeletonID ( SkeletonIndex ) ) ;
}
2023-06-28 07:02:00 -04:00
// Append BoneMap to the array of BoneMaps
2023-05-10 07:27:16 -04:00
const TArray < uint16 > & BoneMap = Mesh - > GetBoneMap ( ) ;
CurrentLODComponent . FirstBoneMap = OperationData - > InstanceUpdateData . BoneMaps . Num ( ) ;
CurrentLODComponent . BoneMapCount = BoneMap . Num ( ) ;
2023-06-28 07:02:00 -04:00
OperationData - > InstanceUpdateData . BoneMaps . Append ( BoneMap ) ;
2022-09-26 15:12:13 -04:00
2023-05-10 07:27:16 -04:00
// Add active bone indices and poses
2023-01-04 15:46:42 -05:00
const int32 MaxBoneIndex = Mesh - > GetBonePoseCount ( ) ;
CurrentLODComponent . ActiveBones . Reserve ( MaxBoneIndex ) ;
for ( int32 BonePoseIndex = 0 ; BonePoseIndex < MaxBoneIndex ; + + BonePoseIndex )
2022-09-26 15:12:13 -04:00
{
2023-06-28 07:02:00 -04:00
const uint16 BoneId = Mesh - > GetBonePoseBoneId ( BonePoseIndex ) ;
2022-09-26 15:12:13 -04:00
2023-06-28 07:02:00 -04:00
CurrentLODComponent . ActiveBones . Add ( BoneId ) ;
2023-01-04 15:46:42 -05:00
2023-06-28 07:02:00 -04:00
if ( BoneIds . Find ( BoneId ) = = INDEX_NONE )
2023-05-10 07:27:16 -04:00
{
2023-06-28 07:02:00 -04:00
BoneIds . Add ( BoneId ) ;
2023-01-04 15:46:42 -05:00
FTransform3f Transform ;
Mesh - > GetBoneTransform ( BonePoseIndex , Transform ) ;
2023-06-28 07:02:00 -04:00
BoneMatricesWithScale . Emplace ( Transform . Inverse ( ) . ToMatrixWithScale ( ) ) ;
2022-09-26 15:12:13 -04:00
}
}
}
}
}
2023-03-23 08:20:51 -04:00
// This runs in a worker thread.
2023-10-17 03:57:37 -04:00
void Task_Mutable_Update_GetMesh ( const TSharedRef < FUpdateContextPrivate > & OperationData , const TSharedPtr < mu : : Model > & Model )
2022-09-26 15:12:13 -04:00
{
2023-03-23 08:20:51 -04:00
MUTABLE_CPUPROFILER_SCOPE ( Task_Mutable_Update_GetMesh )
2023-10-25 07:05:08 -04:00
FMutableScopeTimer Timer ( OperationData - > TaskGetMeshTime ) ;
2022-09-26 15:12:13 -04:00
# if WITH_EDITOR
2023-09-07 04:23:11 -04:00
const uint32 StartCycles = FPlatformTime : : Cycles ( ) ;
2022-09-26 15:12:13 -04:00
# endif
2023-09-14 05:31:42 -04:00
Subtask_Mutable_BeginUpdate_GetMesh ( OperationData , Model ) ;
2022-09-26 15:12:13 -04:00
// TODO: Not strictly mutable: move to another worker thread task to free mutable access?
Subtask_Mutable_PrepareSkeletonData ( OperationData ) ;
2023-09-07 04:23:11 -04:00
if ( OperationData - > bBuildParameterRelevancy )
2023-04-25 06:07:49 -04:00
{
2023-09-07 04:23:11 -04:00
Subtask_Mutable_UpdateParameterRelevancy ( OperationData ) ;
2023-04-25 06:07:49 -04:00
}
else
{
OperationData - > RelevantParametersInProgress . Reset ( ) ;
}
2022-09-26 15:12:13 -04:00
# if WITH_EDITOR
2023-09-07 04:23:11 -04:00
const uint32 EndCycles = FPlatformTime : : Cycles ( ) ;
2022-09-26 15:12:13 -04:00
OperationData - > MutableRuntimeCycles = EndCycles - StartCycles ;
# endif
}
2023-09-07 04:23:11 -04:00
// This runs in a worker thread.
2023-10-17 03:57:37 -04:00
void Task_Mutable_Update_GetImages ( const TSharedRef < FUpdateContextPrivate > & OperationData )
2022-09-26 15:12:13 -04:00
{
MUTABLE_CPUPROFILER_SCOPE ( Task_Mutable_GetImages )
2023-10-25 07:05:08 -04:00
FMutableScopeTimer Timer ( OperationData - > TaskGetImagesTime ) ;
2022-09-26 15:12:13 -04:00
# if WITH_EDITOR
uint32 StartCycles = FPlatformTime : : Cycles ( ) ;
# endif
2023-09-07 04:23:11 -04:00
Subtask_Mutable_GetImages ( OperationData ) ;
2022-09-26 15:12:13 -04:00
// TODO: Not strictly mutable: move to another worker thread task to free mutable access?
Subtask_Mutable_PrepareTextures ( OperationData ) ;
# if WITH_EDITOR
2023-09-07 04:23:11 -04:00
const uint32 EndCycles = FPlatformTime : : Cycles ( ) ;
2022-09-26 15:12:13 -04:00
OperationData - > MutableRuntimeCycles + = EndCycles - StartCycles ;
# endif
}
2023-03-23 08:20:51 -04:00
// This runs in a worker thread.
2023-10-17 03:57:37 -04:00
void Task_Mutable_ReleaseInstance ( const TSharedRef < FUpdateContextPrivate > & OperationData , mu : : Ptr < mu : : System > MutableSystem )
2022-09-26 15:12:13 -04:00
{
MUTABLE_CPUPROFILER_SCOPE ( Task_Mutable_ReleaseInstance )
2023-09-13 06:59:56 -04:00
check ( MutableSystem ) ;
2022-09-26 15:12:13 -04:00
if ( OperationData - > InstanceID > 0 )
{
MUTABLE_CPUPROFILER_SCOPE ( EndUpdate ) ;
MutableSystem - > EndUpdate ( OperationData - > InstanceID ) ;
OperationData - > InstanceUpdateData . Clear ( ) ;
2023-01-10 15:48:59 -05:00
if ( ! OperationData - > bLiveUpdateMode )
{
MutableSystem - > ReleaseInstance ( OperationData - > InstanceID ) ;
OperationData - > InstanceID = 0 ;
2023-11-03 14:21:25 -04:00
OperationData - > MutableInstance = nullptr ;
2023-01-10 15:48:59 -05:00
}
}
2023-03-07 12:43:38 -05:00
2023-09-13 06:59:56 -04:00
MutableSystem - > SetImagePixelConversionOverride ( nullptr ) ;
2023-05-24 02:50:03 -04:00
if ( CVarClearWorkingMemoryOnUpdateEnd . GetValueOnAnyThread ( ) )
2023-03-07 12:43:38 -05:00
{
2023-05-24 02:50:03 -04:00
MutableSystem - > ClearWorkingMemory ( ) ;
2023-03-07 12:43:38 -05:00
}
2023-07-26 06:46:59 -04:00
UCustomizableObjectSystem : : GetInstance ( ) - > GetPrivate ( ) - > MutableTaskGraph . AllowLaunchingMutableTaskLowPriority ( true , true ) ;
2023-01-10 15:48:59 -05:00
}
2023-09-07 04:23:11 -04:00
// This runs in a worker thread.
2023-10-17 03:57:37 -04:00
void Task_Mutable_ReleaseInstanceID ( const mu : : Instance : : ID InstanceID , const mu : : Ptr < mu : : System > & MutableSystem )
2023-01-10 15:48:59 -05:00
{
MUTABLE_CPUPROFILER_SCOPE ( Task_Mutable_ReleaseInstanceID )
2023-10-17 03:57:37 -04:00
if ( InstanceID > 0 )
2023-01-10 15:48:59 -05:00
{
2023-10-17 03:57:37 -04:00
MutableSystem - > ReleaseInstance ( InstanceID ) ;
2022-09-26 15:12:13 -04:00
}
2023-03-07 12:43:38 -05:00
2023-05-24 02:50:03 -04:00
if ( CVarClearWorkingMemoryOnUpdateEnd . GetValueOnAnyThread ( ) )
2023-03-07 12:43:38 -05:00
{
2023-05-24 02:50:03 -04:00
MutableSystem - > ClearWorkingMemory ( ) ;
2023-03-07 12:43:38 -05:00
}
2022-09-26 15:12:13 -04:00
}
2023-09-07 04:23:11 -04:00
void Task_Game_ReleasePlatformData ( const TSharedPtr < FMutableReleasePlatformOperationData > & OperationData )
2022-09-26 15:12:13 -04:00
{
MUTABLE_CPUPROFILER_SCOPE ( Task_Game_ReleasePlatformData )
2023-09-07 04:23:11 -04:00
check ( OperationData ) ;
2022-09-26 15:12:13 -04:00
TMap < uint32 , FTexturePlatformData * > & ImageToPlatformDataMap = OperationData - > ImageToPlatformDataMap ;
2023-09-07 04:23:11 -04:00
for ( const TPair < uint32 , FTexturePlatformData * > & Pair : ImageToPlatformDataMap )
2022-09-26 15:12:13 -04:00
{
delete Pair . Value ; // If this is not null then it must mean it hasn't been used, otherwise they would have taken ownership and nulled it
}
ImageToPlatformDataMap . Reset ( ) ;
}
2022-10-10 07:09:51 -04:00
2023-10-17 03:57:37 -04:00
void Task_Game_Callbacks ( const TSharedRef < FUpdateContextPrivate > & OperationData )
2022-09-26 15:12:13 -04:00
{
MUTABLE_CPUPROFILER_SCOPE ( Task_Game_Callbacks )
2023-10-25 07:05:08 -04:00
FMutableScopeTimer Timer ( OperationData - > TaskCallbacksTime ) ;
2022-09-26 15:12:13 -04:00
check ( IsInGameThread ( ) ) ;
UCustomizableObjectSystem * System = UCustomizableObjectSystem : : GetInstance ( ) ;
if ( ! System | | ! System - > IsValidLowLevel ( ) | | System - > HasAnyFlags ( RF_BeginDestroyed ) )
{
2023-10-17 03:57:37 -04:00
OperationData - > UpdateResult = EUpdateResult : : Error ;
FinishUpdateGlobal ( OperationData ) ;
2022-09-26 15:12:13 -04:00
return ;
}
2023-09-07 04:23:11 -04:00
UCustomizableObjectInstance * CustomizableObjectInstance = OperationData - > Instance . Get ( ) ;
2022-09-26 15:12:13 -04:00
// TODO: Review checks.
if ( ! CustomizableObjectInstance | | ! CustomizableObjectInstance - > IsValidLowLevel ( ) )
{
System - > ClearCurrentMutableOperation ( ) ;
2023-10-17 03:57:37 -04:00
OperationData - > UpdateResult = EUpdateResult : : Error ;
FinishUpdateGlobal ( OperationData ) ;
2022-09-26 15:12:13 -04:00
return ;
}
2023-09-07 04:23:11 -04:00
FCustomizableObjectSystemPrivate * CustomizableObjectSystemPrivateData = System - > GetPrivateChecked ( ) ;
2023-01-24 08:45:18 -05:00
2022-09-26 15:12:13 -04:00
// Actual work
2023-01-24 08:45:18 -05:00
// TODO MTBL-391: Review This hotfix
2023-10-17 03:57:37 -04:00
UpdateSkeletalMesh ( OperationData ) ;
2022-09-26 15:12:13 -04:00
2023-07-18 09:36:44 -04:00
// All work is done, release unused textures.
if ( CustomizableObjectSystemPrivateData - > bReleaseTexturesImmediately )
{
FMutableResourceCache & Cache = CustomizableObjectSystemPrivateData - > GetObjectCache ( CustomizableObjectInstance - > GetCustomizableObject ( ) ) ;
UCustomizableInstancePrivateData * CustomizableObjectInstancePrivateData = CustomizableObjectInstance - > GetPrivate ( ) ;
for ( FGeneratedTexture & GeneratedTexture : CustomizableObjectInstancePrivateData - > TexturesToRelease )
{
UCustomizableInstancePrivateData : : ReleaseMutableTexture ( GeneratedTexture . Key , Cast < UTexture2D > ( GeneratedTexture . Texture ) , Cache ) ;
}
CustomizableObjectInstancePrivateData - > TexturesToRelease . Empty ( ) ;
}
2022-09-26 15:12:13 -04:00
// End Update
System - > ClearCurrentMutableOperation ( ) ;
2023-10-16 12:05:17 -04:00
2023-10-25 06:41:33 -04:00
FinishUpdateGlobal ( OperationData ) ;
2022-09-26 15:12:13 -04:00
}
2023-10-17 03:57:37 -04:00
void Task_Game_ConvertResources ( const TSharedRef < FUpdateContextPrivate > & OperationData )
2022-09-26 15:12:13 -04:00
{
MUTABLE_CPUPROFILER_SCOPE ( Task_Game_ConvertResources )
2023-10-25 07:05:08 -04:00
FMutableScopeTimer Timer ( OperationData - > TaskConvertResourcesTime ) ;
2022-09-26 15:12:13 -04:00
check ( IsInGameThread ( ) ) ;
UCustomizableObjectSystem * System = UCustomizableObjectSystem : : GetInstance ( ) ;
if ( ! System | | ! System - > IsValidLowLevel ( ) | | System - > HasAnyFlags ( RF_BeginDestroyed ) )
{
2023-10-17 03:57:37 -04:00
OperationData - > UpdateResult = EUpdateResult : : Error ;
FinishUpdateGlobal ( OperationData ) ;
2022-09-26 15:12:13 -04:00
return ;
}
2023-09-07 04:23:11 -04:00
UCustomizableObjectInstance * CustomizableObjectInstance = OperationData - > Instance . Get ( ) ;
2022-09-26 15:12:13 -04:00
// Actual work
2023-04-06 16:56:51 -04:00
// TODO: Review checks.
const bool bInstanceInvalid = ! CustomizableObjectInstance | | ! CustomizableObjectInstance - > IsValidLowLevel ( ) ;
if ( ! bInstanceInvalid )
2022-09-26 15:12:13 -04:00
{
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
UCustomizableInstancePrivateData * CustomizableInstancePrivateData = CustomizableObjectInstance - > GetPrivate ( ) ;
2022-09-26 15:12:13 -04:00
# if WITH_EDITOR
2023-11-22 05:11:56 -05:00
CustomizableObjectInstance - > LastUpdateMutableRuntimeCycles = OperationData - > MutableRuntimeCycles ;
2022-09-26 15:12:13 -04:00
# endif
2023-11-22 05:11:56 -05:00
// Convert Step
//-------------------------------------------------------------
2022-09-26 15:12:13 -04:00
2023-11-22 05:11:56 -05:00
// \TODO: Bring that code here instead of keeping it in the UCustomizableObjectInstance
if ( CustomizableInstancePrivateData - > UpdateSkeletalMesh_PostBeginUpdate0 ( CustomizableObjectInstance , OperationData ) )
{
// This used to be CustomizableObjectInstance::UpdateSkeletalMesh_PostBeginUpdate1
2022-09-26 15:12:13 -04:00
{
2023-11-22 05:11:56 -05:00
MUTABLE_CPUPROFILER_SCOPE ( UpdateSkeletalMesh_PostBeginUpdate1 ) ;
// \TODO: Bring here
CustomizableInstancePrivateData - > BuildMaterials ( OperationData , CustomizableObjectInstance ) ;
}
// This used to be CustomizableObjectInstance::UpdateSkeletalMesh_PostBeginUpdate2
{
MUTABLE_CPUPROFILER_SCOPE ( UpdateSkeletalMesh_PostBeginUpdate2 ) ;
for ( int32 Component = 0 ; Component < CustomizableObjectInstance - > SkeletalMeshes . Num ( ) ; + + Component )
2022-09-26 15:12:13 -04:00
{
2023-11-22 05:11:56 -05:00
if ( CustomizableObjectInstance - > SkeletalMeshes [ Component ] & & CustomizableObjectInstance - > SkeletalMeshes [ Component ] - > GetLODInfoArray ( ) . Num ( ) )
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
{
2023-11-22 05:11:56 -05:00
MUTABLE_CPUPROFILER_SCOPE ( UpdateSkeletalMesh_PostEditChangeProperty ) ;
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
2023-11-22 05:11:56 -05:00
CustomizableInstancePrivateData - > PostEditChangePropertyWithoutEditor ( CustomizableObjectInstance - > SkeletalMeshes [ Component ] ) ;
2022-09-26 15:12:13 -04:00
}
}
}
2023-11-22 05:11:56 -05:00
}
2023-04-06 16:56:51 -04:00
} // if (!bInstanceValid)
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
2023-09-07 04:23:11 -04:00
FCustomizableObjectSystemPrivate * CustomizableObjectSystemPrivateData = System - > GetPrivateChecked ( ) ;
2022-09-26 15:12:13 -04:00
// Next Task: Release Mutable. We need this regardless if we cancel or not
//-------------------------------------------------------------
{
2023-09-07 04:23:11 -04:00
const mu : : Ptr < mu : : System > MutableSystem = CustomizableObjectSystemPrivateData - > MutableSystem ;
2023-05-15 05:50:59 -04:00
CustomizableObjectSystemPrivateData - > MutableTaskGraph . AddMutableThreadTask (
2022-09-26 15:12:13 -04:00
TEXT ( " Task_Mutable_ReleaseInstance " ) ,
2023-05-15 05:50:59 -04:00
[ OperationData , MutableSystem ] ( ) { Task_Mutable_ReleaseInstance ( OperationData , MutableSystem ) ; } ) ;
2022-09-26 15:12:13 -04:00
}
// Next Task: Release Platform Data
//-------------------------------------------------------------
2023-04-06 16:56:51 -04:00
if ( ! bInstanceInvalid )
2022-09-26 15:12:13 -04:00
{
TSharedPtr < FMutableReleasePlatformOperationData > ReleaseOperationData = MakeShared < FMutableReleasePlatformOperationData > ( ) ;
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
check ( ReleaseOperationData ) ;
2022-09-26 15:12:13 -04:00
ReleaseOperationData - > ImageToPlatformDataMap = MoveTemp ( OperationData - > ImageToPlatformDataMap ) ;
2023-05-15 05:50:59 -04:00
CustomizableObjectSystemPrivateData - > MutableTaskGraph . AddAnyThreadTask (
2022-09-26 15:12:13 -04:00
TEXT ( " Mutable_ReleasePlatformData " ) ,
2023-05-15 05:50:59 -04:00
[ ReleaseOperationData ] ( )
{
Task_Game_ReleasePlatformData ( ReleaseOperationData ) ;
}
2022-09-26 15:12:13 -04:00
) ;
// Unlock step
//-------------------------------------------------------------
if ( CustomizableObjectInstance - > GetCustomizableObject ( ) )
{
// Unlock the resource cache for the object used by this instance to avoid
// the destruction of resources that we may want to reuse.
System - > ClearResourceCacheProtected ( ) ;
}
// Next Task: Callbacks
//-------------------------------------------------------------
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
CustomizableObjectSystemPrivateData - > AddGameThreadTask (
2022-09-26 15:12:13 -04:00
{
FMutableTaskDelegate : : CreateLambda (
2023-09-07 04:23:11 -04:00
[ OperationData ] ( )
2022-09-26 15:12:13 -04:00
{
2023-09-07 04:23:11 -04:00
Task_Game_Callbacks ( OperationData ) ;
2022-09-26 15:12:13 -04:00
} ) ,
{ }
} ) ;
}
2023-04-06 16:56:51 -04:00
else
{
2023-10-17 03:57:37 -04:00
OperationData - > UpdateResult = EUpdateResult : : Error ;
FinishUpdateGlobal ( OperationData ) ;
2023-04-06 16:56:51 -04:00
}
2022-09-26 15:12:13 -04:00
}
2023-09-07 04:23:11 -04:00
/** Lock Cached Resources. */
2023-10-17 03:57:37 -04:00
void Task_Game_LockCache ( const TSharedRef < FUpdateContextPrivate > & OperationData )
2022-09-26 15:12:13 -04:00
{
2023-04-12 19:01:48 -04:00
MUTABLE_CPUPROFILER_SCOPE ( Task_Game_LockCache )
2023-10-25 07:05:08 -04:00
FMutableScopeTimer Timer ( OperationData - > TaskLockCacheTime ) ;
2023-03-23 08:20:51 -04:00
2022-09-26 15:12:13 -04:00
check ( IsInGameThread ( ) ) ;
UCustomizableObjectSystem * System = UCustomizableObjectSystem : : GetInstance ( ) ;
if ( ! System )
{
return ;
}
2023-09-07 04:23:11 -04:00
UCustomizableObjectInstance * ObjectInstance = OperationData - > Instance . Get ( ) ;
2022-09-26 15:12:13 -04:00
if ( ! ObjectInstance )
{
System - > ClearCurrentMutableOperation ( ) ;
2023-10-17 03:57:37 -04:00
OperationData - > UpdateResult = EUpdateResult : : Error ;
FinishUpdateGlobal ( OperationData ) ;
2022-09-26 15:12:13 -04:00
return ;
}
2023-01-10 15:48:59 -05:00
UCustomizableInstancePrivateData * ObjectInstancePrivateData = ObjectInstance - > GetPrivate ( ) ;
check ( ObjectInstancePrivateData ! = nullptr ) ;
if ( OperationData - > bLiveUpdateMode )
{
check ( OperationData - > InstanceID ! = 0 ) ;
if ( ObjectInstancePrivateData - > LiveUpdateModeInstanceID = = 0 )
{
// From now this instance will reuse this InstanceID until it gets out of LiveUpdateMode
ObjectInstancePrivateData - > LiveUpdateModeInstanceID = OperationData - > InstanceID ;
}
}
2022-09-26 15:12:13 -04:00
const UCustomizableObject * CustomizableObject = ObjectInstance - > GetCustomizableObject ( ) ;
if ( ! CustomizableObject )
{
System - > ClearCurrentMutableOperation ( ) ;
2023-10-17 03:57:37 -04:00
OperationData - > UpdateResult = EUpdateResult : : Error ;
FinishUpdateGlobal ( OperationData ) ;
2022-09-26 15:12:13 -04:00
return ;
}
2023-09-07 04:23:11 -04:00
if ( OperationData - > bBuildParameterRelevancy )
2022-09-26 15:12:13 -04:00
{
2023-04-25 06:07:49 -04:00
// Relevancy
ObjectInstancePrivateData - > RelevantParameters = OperationData - > RelevantParametersInProgress ;
2022-09-26 15:12:13 -04:00
}
2023-01-25 13:01:06 -05:00
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
// Selectively lock the resource cache for the object used by this instance to avoid the destruction of resources that we may want to reuse.
2022-09-26 15:12:13 -04:00
// When protecting textures there mustn't be any left from a previous update
check ( System - > ProtectedCachedTextures . Num ( ) = = 0 ) ;
2023-09-07 04:23:11 -04:00
FCustomizableObjectSystemPrivate * SystemPrivateData = System - > GetPrivateChecked ( ) ;
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
2023-04-05 11:20:44 -04:00
// TODO: If this is the first code that runs after the CO program has finished AND if it's
// guaranteed that the next CO program hasn't started yet, we need to call ClearActiveObject
// and CancelPendingLoads on SystemPrivateData->ExtensionDataStreamer.
//
// ExtensionDataStreamer->AreAnyLoadsPending should return false if the program succeeded.
//
// If the program aborted, AreAnyLoadsPending may return true, as the program doesn't cancel
// its own loads on exit (maybe it should?)
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
FMutableResourceCache & Cache = SystemPrivateData - > GetObjectCache ( CustomizableObject ) ;
2022-09-26 15:12:13 -04:00
System - > ProtectedCachedTextures . Reset ( Cache . Images . Num ( ) ) ;
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
SystemPrivateData - > ProtectedObjectCachedImages . Reset ( Cache . Images . Num ( ) ) ;
2022-09-26 15:12:13 -04:00
for ( const FInstanceUpdateData : : FImage & Image : OperationData - > InstanceUpdateData . Images )
{
2022-10-21 19:53:30 -04:00
FMutableImageCacheKey Key ( Image . ImageID , OperationData - > MipsToSkip ) ;
2023-09-07 04:23:11 -04:00
const TWeakObjectPtr < UTexture2D > * TexturePtr = Cache . Images . Find ( Key ) ;
2022-09-26 15:12:13 -04:00
2023-07-18 09:36:44 -04:00
if ( TexturePtr & & TexturePtr - > Get ( ) & & SystemPrivateData - > TextureHasReferences ( Key ) )
2022-09-26 15:12:13 -04:00
{
System - > ProtectedCachedTextures . Add ( TexturePtr - > Get ( ) ) ;
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
SystemPrivateData - > ProtectedObjectCachedImages . Add ( Image . ImageID ) ;
2022-09-26 15:12:13 -04:00
}
}
2022-10-04 09:10:32 -04:00
// Any external texture that may be needed for this update will be requested from Mutable Core's GetImage
// which will safely access the GlobalExternalImages map, and then just get the cached image or issue a disk read
2022-09-26 15:12:13 -04:00
// Copy data generated in the mutable thread over to the instance
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
ObjectInstancePrivateData - > PrepareForUpdate ( OperationData ) ;
2022-09-26 15:12:13 -04:00
// Task: Mutable GetImages
//-------------------------------------------------------------
2023-02-08 04:20:33 -05:00
# ifdef MUTABLE_USE_NEW_TASKGRAPH
UE : : Tasks : : FTask Mutable_GetImagesTask ;
# else
2022-09-26 15:12:13 -04:00
FGraphEventRef Mutable_GetImagesTask ;
2023-02-08 04:20:33 -05:00
# endif
2022-09-26 15:12:13 -04:00
{
// Task inputs
2023-05-15 05:50:59 -04:00
Mutable_GetImagesTask = SystemPrivateData - > MutableTaskGraph . AddMutableThreadTask (
2023-09-07 04:23:11 -04:00
TEXT ( " Task_Mutable_GetImages " ) ,
[ OperationData ] ( )
{
impl : : Task_Mutable_Update_GetImages ( OperationData ) ;
} ) ;
2022-09-26 15:12:13 -04:00
}
// Next Task: Load Unreal Assets
//-------------------------------------------------------------
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
FGraphEventRef Game_LoadUnrealAssets = ObjectInstancePrivateData - > LoadAdditionalAssetsAsync ( OperationData , ObjectInstance , UCustomizableObjectSystem : : GetInstance ( ) - > GetStreamableManager ( ) ) ;
if ( Game_LoadUnrealAssets )
{
Game_LoadUnrealAssets - > SetDebugName ( TEXT ( " LoadAdditionalAssetsAsync " ) ) ;
}
2022-09-26 15:12:13 -04:00
// Next-next Task: Convert Resources
//-------------------------------------------------------------
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
SystemPrivateData - > AddGameThreadTask (
2022-09-26 15:12:13 -04:00
{
FMutableTaskDelegate : : CreateLambda (
2023-09-07 04:23:11 -04:00
[ OperationData ] ( )
2022-09-26 15:12:13 -04:00
{
2023-09-07 04:23:11 -04:00
Task_Game_ConvertResources ( OperationData ) ;
2022-09-26 15:12:13 -04:00
} ) ,
# ifdef MUTABLE_USE_NEW_TASKGRAPH
{ } ,
# endif
Game_LoadUnrealAssets ,
Mutable_GetImagesTask
} ) ;
}
2023-01-10 15:48:59 -05:00
/** Enqueue the release ID operation in the Mutable queue */
void Task_Game_ReleaseInstanceID ( const mu : : Instance : : ID IDToRelease )
{
2023-03-23 08:20:51 -04:00
MUTABLE_CPUPROFILER_SCOPE ( Task_Game_ReleaseInstanceID )
2023-09-07 04:23:11 -04:00
UCustomizableObjectSystem * System = UCustomizableObjectSystem : : GetInstanceChecked ( ) ;
FCustomizableObjectSystemPrivate * SystemPrivateData = System - > GetPrivateChecked ( ) ;
2023-01-10 15:48:59 -05:00
2023-09-07 04:23:11 -04:00
const mu : : Ptr < mu : : System > MutableSystem = SystemPrivateData - > MutableSystem ;
2023-01-10 15:48:59 -05:00
// Task: Release Instance ID
//-------------------------------------------------------------
{
// Task inputs
2023-09-07 04:23:11 -04:00
SystemPrivateData - > MutableTaskGraph . AddMutableThreadTask (
2023-01-10 15:48:59 -05:00
TEXT ( " Task_Mutable_ReleaseInstanceID " ) ,
2023-10-17 03:57:37 -04:00
[ IDToRelease , MutableSystem ] ( )
2023-01-10 15:48:59 -05:00
{
2023-10-17 03:57:37 -04:00
impl : : Task_Mutable_ReleaseInstanceID ( IDToRelease , MutableSystem ) ;
2023-05-15 05:50:59 -04:00
} ) ;
2023-01-10 15:48:59 -05:00
}
}
2023-11-03 14:21:25 -04:00
void Task_Game_LockMeshCache ( const TSharedRef < FUpdateContextPrivate > & Operation )
{
MUTABLE_CPUPROFILER_SCOPE ( Task_Game_LockMeshCache ) ;
UCustomizableObjectSystem * System = UCustomizableObjectSystem : : GetInstanceChecked ( ) ;
FCustomizableObjectSystemPrivate * SystemPrivate = System - > GetPrivateChecked ( ) ;
const UCustomizableObject * CustomizableObject = Operation - > Instance - > GetCustomizableObject ( ) ;
FCustomizableObjectPrivateData * CustomizableObjectPrivate = CustomizableObject - > GetPrivate ( ) ;
for ( const TArray < mu : : FResourceID > & MeshId : Operation - > MeshDescriptors )
{
if ( USkeletalMesh * CachedMesh = CustomizableObject - > GetPrivate ( ) - > MeshCache . Get ( MeshId ) )
{
Operation - > Objects . Add ( CachedMesh ) ;
}
}
// Task inputs
TSharedPtr < mu : : Model > Model = CustomizableObject - > GetPrivate ( ) - > GetModel ( ) ;
# ifdef MUTABLE_USE_NEW_TASKGRAPH
UE : : Tasks : : FTask Dependency ;
# else
FGraphEventRef Dependency ;
# endif
Dependency = SystemPrivate - > MutableTaskGraph . AddMutableThreadTask (
TEXT ( " Task_Mutable_Update_GetMesh " ) ,
[ Operation , Model ] ( )
{
impl : : Task_Mutable_Update_GetMesh ( Operation , Model ) ;
} ) ;
SystemPrivate - > AddGameThreadTask (
{
FMutableTaskDelegate : : CreateLambda (
[ Operation ] ( )
{
impl : : Task_Game_LockCache ( Operation ) ;
} ) ,
Dependency ,
} ) ;
}
void Task_Mutable_GetMeshID ( const TSharedRef < FUpdateContextPrivate > & Operation )
{
MUTABLE_CPUPROFILER_SCOPE ( Task_Mutable_GetMeshID ) ;
UCustomizableObjectSystem * System = UCustomizableObjectSystem : : GetInstanceChecked ( ) ; // Save since UCustomizableObjectSystem::BeginDestroy always waits for all tasks to finish
FCustomizableObjectSystemPrivate * SystemPrivate = System - > GetPrivateChecked ( ) ;
CreateMutableInstance ( Operation ) ;
FixLODs ( Operation ) ;
2023-11-08 08:42:39 -05:00
const int32 NumComponents = Operation - > NumComponents ;
2023-11-03 14:21:25 -04:00
Operation - > MeshDescriptors . SetNum ( NumComponents ) ;
for ( int32 ComponentIndex = 0 ; ComponentIndex < NumComponents ; + + ComponentIndex )
{
TArray < mu : : FResourceID > & MeshId = Operation - > MeshDescriptors [ ComponentIndex ] ;
MeshId . Init ( MAX_uint64 , MAX_MESH_LOD_COUNT ) ;
for ( int32 LODIndex = Operation - > CurrentMinLOD ; LODIndex < = Operation - > CurrentMaxLOD ; + + LODIndex )
{
const bool bGenerateLOD = Operation - > RequestedLODs . IsValidIndex ( ComponentIndex ) ? ( Operation - > RequestedLODs [ ComponentIndex ] & ( 1 < < LODIndex ) ) ! = 0 : true ;
if ( bGenerateLOD )
{
MeshId [ LODIndex ] = Operation - > MutableInstance - > GetMeshId ( LODIndex , ComponentIndex , 0 ) ;
}
}
}
}
2022-09-26 15:12:13 -04:00
/** "Start Update" */
2023-10-17 03:57:37 -04:00
void Task_Game_StartUpdate ( const TSharedRef < FUpdateContextPrivate > & Operation )
2022-09-26 15:12:13 -04:00
{
2023-03-23 08:20:51 -04:00
MUTABLE_CPUPROFILER_SCOPE ( Task_Game_StartUpdate )
2023-10-25 06:41:33 -04:00
Operation - > StartUpdateTime = FPlatformTime : : Seconds ( ) ;
2023-05-15 05:50:59 -04:00
UCustomizableObjectSystem : : GetInstance ( ) - > GetPrivate ( ) - > MutableTaskGraph . AllowLaunchingMutableTaskLowPriority ( false , false ) ;
2022-09-26 15:12:13 -04:00
UCustomizableObjectSystem * System = UCustomizableObjectSystem : : GetInstance ( ) ;
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
check ( System ! = nullptr ) ;
2022-09-26 15:12:13 -04:00
2023-10-17 03:57:37 -04:00
if ( ! Operation - > Instance . IsValid ( ) | | ! Operation - > Instance - > IsValidLowLevel ( ) ) // Only start if it hasn't been already destroyed (i.e. GC after finish PIE)
2022-09-26 15:12:13 -04:00
{
System - > ClearCurrentMutableOperation ( ) ;
2023-10-17 03:57:37 -04:00
Operation - > UpdateResult = EUpdateResult : : Error ;
FinishUpdateGlobal ( Operation ) ;
2022-09-26 15:12:13 -04:00
return ;
}
2023-10-17 03:57:37 -04:00
UCustomizableObjectInstance * CandidateInstance = Operation - > Instance . Get ( ) ;
2023-01-24 08:45:18 -05:00
UCustomizableInstancePrivateData * CandidateInstancePrivateData = CandidateInstance - > GetPrivate ( ) ;
2023-03-06 13:06:53 -05:00
if ( ! CandidateInstancePrivateData )
{
System - > ClearCurrentMutableOperation ( ) ;
2023-10-17 03:57:37 -04:00
Operation - > UpdateResult = EUpdateResult : : Error ;
FinishUpdateGlobal ( Operation ) ;
2023-03-06 13:06:53 -05:00
return ;
}
2023-10-03 08:47:48 -04:00
2023-04-06 16:56:51 -04:00
if ( CandidateInstancePrivateData - > HasCOInstanceFlags ( PendingLODsUpdate ) )
2022-09-26 15:12:13 -04:00
{
2023-01-24 08:45:18 -05:00
CandidateInstancePrivateData - > ClearCOInstanceFlags ( PendingLODsUpdate ) ;
2022-09-26 15:12:13 -04:00
// TODO: Is anything needed for this now?
//Operation->CustomizableObjectInstance->ReleaseMutableInstanceId(); // To make mutable regenerate the LODs even if the instance parameters have not changed
}
2023-09-26 06:57:49 -04:00
// Skip update, the requested update is equal to the running update.
if ( Operation - > InstanceDescriptorRuntimeHash . IsSubset ( CandidateInstance - > GetDescriptorRuntimeHash ( ) ) )
{
System - > ClearCurrentMutableOperation ( ) ;
2023-10-17 03:57:37 -04:00
2023-11-30 10:15:51 -05:00
Operation - > UpdateResult = EUpdateResult : : Success ;
2023-10-17 03:57:37 -04:00
UpdateSkeletalMesh ( Operation ) ;
2023-10-25 06:41:33 -04:00
FinishUpdateGlobal ( Operation ) ;
2023-09-26 06:57:49 -04:00
return ;
}
2022-09-26 15:12:13 -04:00
bool bCancel = false ;
// If the object is locked (for instance, compiling) we skip any instance update.
2023-01-24 08:45:18 -05:00
TObjectPtr < UCustomizableObject > CustomizableObject = CandidateInstance - > GetCustomizableObject ( ) ;
if ( ! CustomizableObject )
2022-09-26 15:12:13 -04:00
{
bCancel = true ;
}
2022-09-27 08:28:56 -04:00
else
{
2023-01-24 08:45:18 -05:00
if ( CustomizableObject - > GetPrivate ( ) - > bLocked )
2022-09-27 08:28:56 -04:00
{
bCancel = true ;
}
2022-09-26 15:12:13 -04:00
}
2023-01-24 08:45:18 -05:00
// Only update resources if the instance is in range (it could have got far from the player since the task was queued)
check ( System - > CurrentInstanceLODManagement ! = nullptr ) ;
if ( System - > CurrentInstanceLODManagement - > IsOnlyUpdateCloseCustomizableObjectsEnabled ( )
2023-01-27 14:45:45 -05:00
& & CandidateInstancePrivateData
2023-01-24 08:45:18 -05:00
& & CandidateInstancePrivateData - > LastMinSquareDistFromComponentToPlayer > FMath : : Square ( System - > CurrentInstanceLODManagement - > GetOnlyUpdateCloseCustomizableObjectsDist ( ) )
& & CandidateInstancePrivateData - > LastMinSquareDistFromComponentToPlayer ! = FLT_MAX // This means it is the first frame so it has to be updated
)
{
bCancel = true ;
}
2023-10-17 03:57:37 -04:00
mu : : Ptr < const mu : : Parameters > Parameters = Operation - > Parameters ;
2023-01-24 08:45:18 -05:00
if ( ! Parameters )
{
bCancel = true ;
}
2022-09-26 15:12:13 -04:00
if ( bCancel )
{
System - > ClearCurrentMutableOperation ( ) ;
2023-04-06 16:56:51 -04:00
2023-10-17 03:57:37 -04:00
Operation - > UpdateResult = EUpdateResult : : Error ;
FinishUpdateGlobal ( Operation ) ;
2022-09-26 15:12:13 -04:00
return ;
}
2023-09-07 04:23:11 -04:00
FCustomizableObjectSystemPrivate * SystemPrivateData = System - > GetPrivateChecked ( ) ;
2022-09-26 15:12:13 -04:00
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
SystemPrivateData - > CurrentInstanceBeingUpdated = CandidateInstance ;
2022-09-26 15:12:13 -04:00
// Prepare streaming for the current customizable object
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
check ( SystemPrivateData - > Streamer ! = nullptr ) ;
SystemPrivateData - > Streamer - > PrepareStreamingForObject ( CustomizableObject ) ;
2022-09-26 15:12:13 -04:00
2023-04-05 11:20:44 -04:00
check ( SystemPrivateData - > ExtensionDataStreamer ! = nullptr ) ;
SystemPrivateData - > ExtensionDataStreamer - > SetActiveObject ( CustomizableObject ) ;
2022-11-28 07:21:35 -05:00
CandidateInstance - > CommitMinMaxLOD ( ) ;
2023-01-10 15:48:59 -05:00
2023-01-19 10:44:15 -05:00
FString StateName = CandidateInstance - > GetCustomizableObject ( ) - > GetStateName ( CandidateInstance - > GetState ( ) ) ;
const FParameterUIData * StateData = CandidateInstance - > GetCustomizableObject ( ) - > StateUIDataMap . Find ( StateName ) ;
2023-10-17 03:57:37 -04:00
Operation - > bLiveUpdateMode = false ;
2023-01-11 14:44:41 -05:00
if ( SystemPrivateData - > EnableMutableLiveUpdate )
{
2023-10-17 03:57:37 -04:00
Operation - > bLiveUpdateMode = StateData ? StateData - > bLiveUpdateMode : false ;
2023-01-11 14:44:41 -05:00
}
2023-01-10 15:48:59 -05:00
2023-10-17 03:57:37 -04:00
Operation - > bNeverStream = false ;
Operation - > MipsToSkip = 0 ;
2023-09-14 05:31:42 -04:00
2023-10-17 03:57:37 -04:00
SystemPrivateData - > GetMipStreamingConfig ( * CandidateInstance , Operation - > bNeverStream , Operation - > MipsToSkip ) ;
2023-09-14 05:31:42 -04:00
2023-10-17 03:57:37 -04:00
if ( Operation - > bLiveUpdateMode & & ( ! Operation - > bNeverStream | | Operation - > MipsToSkip > 0 ) )
2023-01-10 15:48:59 -05:00
{
UE_LOG ( LogMutable , Warning , TEXT ( " Instance LiveUpdateMode does not yet support progressive streaming of Mutable textures. Disabling LiveUpdateMode for this update. " ) ) ;
2023-10-17 03:57:37 -04:00
Operation - > bLiveUpdateMode = false ;
2023-01-10 15:48:59 -05:00
}
2023-10-17 03:57:37 -04:00
Operation - > bReuseInstanceTextures = false ;
2023-01-19 10:44:15 -05:00
if ( SystemPrivateData - > EnableReuseInstanceTextures )
{
2023-10-17 03:57:37 -04:00
Operation - > bReuseInstanceTextures = StateData ? StateData - > bReuseInstanceTextures : false ;
Operation - > bReuseInstanceTextures | = CandidateInstancePrivateData - > HasCOInstanceFlags ( ReuseTextures ) ;
2023-03-10 05:20:20 -05:00
2023-10-17 03:57:37 -04:00
if ( Operation - > bReuseInstanceTextures & & ! Operation - > bNeverStream )
2023-01-19 10:44:15 -05:00
{
UE_LOG ( LogMutable , Warning , TEXT ( " Instance texture reuse requires that the current Mutable state is in non-streaming mode. Change it in the Mutable graph base node in the state definition. " ) ) ;
2023-10-17 03:57:37 -04:00
Operation - > bReuseInstanceTextures = false ;
2023-01-19 10:44:15 -05:00
}
}
2023-10-17 03:57:37 -04:00
if ( ! Operation - > bLiveUpdateMode & & CandidateInstancePrivateData - > LiveUpdateModeInstanceID ! = 0 )
2023-01-10 15:48:59 -05:00
{
// The instance was in live update mode last update, but now it's not. So the Id and resources have to be released.
// Enqueue a new mutable task to release them
Task_Game_ReleaseInstanceID ( CandidateInstancePrivateData - > LiveUpdateModeInstanceID ) ;
CandidateInstancePrivateData - > LiveUpdateModeInstanceID = 0 ;
}
2023-09-14 05:31:42 -04:00
2022-11-28 07:21:35 -05:00
2022-09-26 15:12:13 -04:00
// Task: Mutable Update and GetMesh
//-------------------------------------------------------------
2023-10-17 03:57:37 -04:00
Operation - > CurrentMinLOD = Operation - > InstanceDescriptorRuntimeHash . GetMinLOD ( ) ;
Operation - > CurrentMaxLOD = Operation - > InstanceDescriptorRuntimeHash . GetMaxLOD ( ) ;
Operation - > InstanceID = Operation - > bLiveUpdateMode ? CandidateInstancePrivateData - > LiveUpdateModeInstanceID : 0 ;
2023-11-03 14:21:25 -04:00
Operation - > bUseMeshCache = CustomizableObject - > IsMeshCacheEnabled ( ) & & ! Operation - > bLiveUpdateMode & & CVarEnableMeshCache . GetValueOnGameThread ( ) ;
2023-09-13 06:59:56 -04:00
# if WITH_EDITOR
2023-10-17 03:57:37 -04:00
Operation - > PixelFormatOverride = SystemPrivateData - > ImageFormatOverrideFunc ;
2023-09-13 06:59:56 -04:00
# endif
2023-08-14 11:32:30 -04:00
if ( ! CandidateInstancePrivateData - > HasCOInstanceFlags ( ForceGenerateMipTail ) )
{
2023-10-17 03:57:37 -04:00
CustomizableObject - > GetLowPriorityTextureNames ( Operation - > LowPriorityTextures ) ;
2023-08-14 11:32:30 -04:00
}
2023-01-24 08:45:18 -05:00
2023-09-14 05:31:42 -04:00
bool bIsInEditorViewport = false ;
# if WITH_EDITOR
2023-10-24 08:17:10 -04:00
for ( TObjectIterator < UCustomizableObjectInstanceUsage > CustomizableObjectInstanceUsage ; CustomizableObjectInstanceUsage & & ! bIsInEditorViewport ; + + CustomizableObjectInstanceUsage )
2023-09-14 05:31:42 -04:00
{
2023-11-09 06:25:16 -05:00
if ( IsValid ( * CustomizableObjectInstanceUsage ) & & CustomizableObjectInstanceUsage - > IsNetMode ( NM_DedicatedServer ) )
2023-09-22 04:26:19 -04:00
{
continue ;
}
2023-11-09 06:25:16 -05:00
if ( IsValid ( * CustomizableObjectInstanceUsage ) & &
2023-10-24 08:17:10 -04:00
CustomizableObjectInstanceUsage - > GetCustomizableObjectInstance ( ) = = CandidateInstance )
2023-09-14 05:31:42 -04:00
{
EWorldType : : Type WorldType = EWorldType : : Type : : None ;
2023-11-03 09:30:32 -04:00
USkeletalMeshComponent * Parent = Cast < USkeletalMeshComponent > ( CustomizableObjectInstanceUsage - > GetAttachParent ( ) ) ;
if ( Parent & & Parent - > GetWorld ( ) )
2023-09-14 05:31:42 -04:00
{
2023-11-03 09:30:32 -04:00
WorldType = Parent - > GetWorld ( ) - > WorldType ;
2023-09-14 05:31:42 -04:00
}
switch ( WorldType )
{
// Editor preview instances
case EWorldType : : EditorPreview :
case EWorldType : : None :
bIsInEditorViewport = true ;
default : ;
}
}
}
# endif // WITH_EDITOR
2023-11-03 09:34:38 -04:00
if ( ! System - > IsOnlyGenerateRequestedLODsEnabled ( ) | |
! System - > CurrentInstanceLODManagement - > IsOnlyGenerateRequestedLODLevelsEnabled ( ) | |
bIsInEditorViewport )
2023-01-24 08:45:18 -05:00
{
2023-11-08 08:42:39 -05:00
Operation - > RequestedLODs . Init ( MAX_uint8 , Operation - > NumComponents ) ;
Operation - > InstanceDescriptorRuntimeHash . UpdateRequestedLODs ( Operation - > RequestedLODs ) ;
2023-01-24 08:45:18 -05:00
}
2022-09-26 15:12:13 -04:00
2023-02-08 04:20:33 -05:00
# ifdef MUTABLE_USE_NEW_TASKGRAPH
UE : : Tasks : : FTask Mutable_GetMeshTask ;
# else
2022-09-26 15:12:13 -04:00
FGraphEventRef Mutable_GetMeshTask ;
2023-02-08 04:20:33 -05:00
# endif
2023-11-03 14:21:25 -04:00
if ( Operation - > bUseMeshCache )
{
Mutable_GetMeshTask = SystemPrivateData - > MutableTaskGraph . AddMutableThreadTask (
TEXT ( " Task_Mutable_GetMeshID " ) ,
[ Operation ] ( )
{
impl : : Task_Mutable_GetMeshID ( Operation ) ;
} ) ;
2023-12-01 10:03:28 -05:00
SystemPrivateData - > AddGameThreadTask (
2023-11-03 14:21:25 -04:00
{
FMutableTaskDelegate : : CreateLambda (
[ Operation ] ( )
{
impl : : Task_Game_LockMeshCache ( Operation ) ;
} ) ,
Mutable_GetMeshTask
} ) ;
}
else
2022-09-26 15:12:13 -04:00
{
// Task inputs
2023-09-07 04:23:11 -04:00
TSharedPtr < mu : : Model > Model = CustomizableObject - > GetPrivate ( ) - > GetModel ( ) ;
2022-09-26 15:12:13 -04:00
2023-05-15 05:50:59 -04:00
Mutable_GetMeshTask = SystemPrivateData - > MutableTaskGraph . AddMutableThreadTask (
2022-09-26 15:12:13 -04:00
TEXT ( " Task_Mutable_Update_GetMesh " ) ,
2023-10-17 03:57:37 -04:00
[ Operation , Model ] ( )
2022-09-26 15:12:13 -04:00
{
2023-10-17 03:57:37 -04:00
impl : : Task_Mutable_Update_GetMesh ( Operation , Model ) ;
2023-05-15 05:50:59 -04:00
} ) ;
2022-09-26 15:12:13 -04:00
2023-11-03 14:21:25 -04:00
// Task: Lock cache
//-------------------------------------------------------------
{
// Task inputs
SystemPrivateData - > AddGameThreadTask (
2022-09-26 15:12:13 -04:00
{
2023-11-03 14:21:25 -04:00
FMutableTaskDelegate : : CreateLambda (
[ Operation ] ( )
{
impl : : Task_Game_LockCache ( Operation ) ;
} ) ,
Mutable_GetMeshTask
} ) ;
}
2022-09-26 15:12:13 -04:00
}
}
} // namespace impl
void UCustomizableObjectSystem : : AdvanceCurrentOperation ( )
{
2022-12-01 06:49:41 -05:00
MUTABLE_CPUPROFILER_SCOPE ( AdvanceCurrentOperation ) ;
2022-09-26 15:12:13 -04:00
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
check ( Private ! = nullptr ) ;
2022-09-26 15:12:13 -04:00
// See if we have a game-thread task to process
FMutableTask * PendingTask = Private - > PendingTasks . Peek ( ) ;
if ( PendingTask )
{
if ( PendingTask - > AreDependenciesComplete ( ) )
{
PendingTask - > ClearDependencies ( ) ;
PendingTask - > Function . Execute ( ) ;
Private - > PendingTasks . Pop ( ) ;
}
// Don't do anything else until the pending work is completed.
return ;
}
// It is safe to do this now.
2023-05-24 02:50:03 -04:00
Private - > UpdateMemoryLimit ( ) ;
2022-09-26 15:12:13 -04:00
// If we don't have an ongoing operation, don't do anything.
if ( ! Private - > CurrentMutableOperation . IsValid ( ) )
{
return ;
}
// If we reach here it means:
// - we have an ongoing operations
// - we have no pending work for the ongoing operation
// - so we are starting it.
{
2023-06-22 06:24:44 -04:00
MUTABLE_CPUPROFILER_SCOPE ( OperationUpdate ) ;
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
2023-06-22 06:24:44 -04:00
// Start the first task of the update process. See namespace impl comments above.
2023-10-17 03:57:37 -04:00
impl : : Task_Game_StartUpdate ( Private - > CurrentMutableOperation . ToSharedRef ( ) ) ;
2022-09-26 15:12:13 -04:00
}
}
bool UCustomizableObjectSystem : : Tick ( float DeltaTime )
{
MUTABLE_CPUPROFILER_SCOPE ( UCustomizableObjectSystem : : Tick )
2023-06-22 06:24:44 -04:00
// Building instances is not enabled in servers. If at some point relevant collision or animation data is necessary for server logic this will need to be changed.
2022-09-26 15:12:13 -04:00
# if UE_SERVER
return true ;
# endif
if ( ! Private . IsValid ( ) )
{
return true ;
}
2023-09-07 04:23:11 -04:00
if ( GWorld )
2022-09-26 15:12:13 -04:00
{
2023-09-07 04:23:11 -04:00
const EWorldType : : Type WorldType = GWorld - > WorldType ;
2022-09-26 15:12:13 -04:00
if ( WorldType ! = EWorldType : : PIE & & WorldType ! = EWorldType : : Game & & WorldType ! = EWorldType : : Editor & & WorldType ! = EWorldType : : GamePreview )
{
return true ;
}
}
// \TODO: Review: We should never compile an object from this tick, so this could be removed
# if WITH_EDITOR
2023-09-07 04:23:11 -04:00
const FAssetRegistryModule & AssetRegistryModule = FModuleManager : : LoadModuleChecked < FAssetRegistryModule > ( " AssetRegistry " ) ;
2022-09-26 15:12:13 -04:00
if ( AssetRegistryModule . Get ( ) . IsLoadingAssets ( ) )
{
return true ; // Assets are still being loaded, so subobjects won't be found, compiled objects incomplete and thus updates wrong
}
2023-07-20 07:38:13 -04:00
// Do not tick if the CookCommandlet is running.
if ( IsRunningCookCommandlet ( ) )
{
return true ;
}
2022-09-26 15:12:13 -04:00
# endif
2023-05-15 05:50:59 -04:00
2023-08-31 13:21:05 -04:00
TickPendingReleaseMaterials ( ) ;
2023-10-25 06:41:33 -04:00
Private - > UpdateStats ( ) ;
2022-09-26 15:12:13 -04:00
// Get a new operation if we aren't working on one
if ( ! Private - > CurrentMutableOperation )
{
2023-01-24 08:45:18 -05:00
// Reset the instance relevancy
2023-06-22 06:24:44 -04:00
// The RequestedUpdates only refer to LOD changes. User Customization and discards are handled separately
FMutableInstanceUpdateMap RequestedLODUpdates ;
CurrentInstanceLODManagement - > UpdateInstanceDistsAndLODs ( RequestedLODUpdates ) ;
2023-01-24 08:45:18 -05:00
for ( TObjectIterator < UCustomizableObjectInstance > CustomizableObjectInstance ; CustomizableObjectInstance ; + + CustomizableObjectInstance )
{
2023-11-09 06:25:16 -05:00
if ( IsValid ( * CustomizableObjectInstance ) & & CustomizableObjectInstance - > GetPrivate ( ) )
2023-01-24 08:45:18 -05:00
{
UCustomizableInstancePrivateData * ObjectInstancePrivateData = CustomizableObjectInstance - > GetPrivate ( ) ;
if ( ObjectInstancePrivateData - > HasCOInstanceFlags ( UsedByComponentInPlay ) )
{
2023-07-21 03:28:52 -04:00
ObjectInstancePrivateData - > TickUpdateCloseCustomizableObjects ( * * CustomizableObjectInstance , RequestedLODUpdates ) ;
2023-01-24 08:45:18 -05:00
}
else if ( ObjectInstancePrivateData - > HasCOInstanceFlags ( UsedByComponent ) )
{
2023-06-22 06:24:44 -04:00
ensure ( ! RequestedLODUpdates . Contains ( * CustomizableObjectInstance ) ) ;
ObjectInstancePrivateData - > UpdateInstanceIfNotGenerated ( * * CustomizableObjectInstance , RequestedLODUpdates ) ;
}
else
{
ensure ( ! RequestedLODUpdates . Contains ( * CustomizableObjectInstance ) ) ;
2023-01-24 08:45:18 -05:00
}
ObjectInstancePrivateData - > ClearCOInstanceFlags ( ( ECOInstanceFlags ) ( UsedByComponent | UsedByComponentInPlay | PendingLODsUpdate ) ) ; // TODO MTBL-391: Makes no sense to clear it here, what if an update is requested before we set it back to true
}
2023-06-22 06:24:44 -04:00
else
{
ensure ( ! RequestedLODUpdates . Contains ( * CustomizableObjectInstance ) ) ;
}
2023-01-24 08:45:18 -05:00
}
2023-06-22 06:24:44 -04:00
{
// Look for the highest priority update between the pending updates and the LOD Requested Updates
EQueuePriorityType MaxPriorityFound = EQueuePriorityType : : Low ;
double MaxSquareDistanceFound = TNumericLimits < double > : : Max ( ) ;
double MinTimeFound = TNumericLimits < double > : : Max ( ) ;
const FMutablePendingInstanceUpdate * PendingInstanceUpdateFound = nullptr ;
FMutableUpdateCandidate * LODUpdateCandidateFound = nullptr ;
// Look for the highest priority Pending Update
for ( auto Iterator = Private - > MutablePendingInstanceWork . GetUpdateIterator ( ) ; Iterator ; + + Iterator )
{
FMutablePendingInstanceUpdate & PendingUpdate = * Iterator ;
2023-10-17 03:57:37 -04:00
if ( PendingUpdate . Context - > Instance . IsValid ( ) )
2023-06-22 06:24:44 -04:00
{
2023-10-17 03:57:37 -04:00
const EQueuePriorityType PriorityType = Private - > GetUpdatePriority ( * PendingUpdate . Context - > Instance , false ) ;
2023-06-22 06:24:44 -04:00
2023-10-17 03:57:37 -04:00
if ( PendingUpdate . Context - > PriorityType < = MaxPriorityFound )
2023-06-22 06:24:44 -04:00
{
2023-10-17 03:57:37 -04:00
const double MinSquareDistFromComponentToPlayer = PendingUpdate . Context - > Instance - > GetPrivate ( ) - > MinSquareDistFromComponentToPlayer ;
2023-06-22 06:24:44 -04:00
if ( MinSquareDistFromComponentToPlayer < MaxSquareDistanceFound | |
2023-11-21 10:47:27 -05:00
( MinSquareDistFromComponentToPlayer = = MaxSquareDistanceFound & & PendingUpdate . Context - > StartQueueTime < MinTimeFound ) )
2023-06-22 06:24:44 -04:00
{
MaxPriorityFound = PriorityType ;
MaxSquareDistanceFound = MinSquareDistFromComponentToPlayer ;
2023-11-21 10:47:27 -05:00
MinTimeFound = PendingUpdate . Context - > StartQueueTime ;
2023-06-22 06:24:44 -04:00
PendingInstanceUpdateFound = & PendingUpdate ;
LODUpdateCandidateFound = nullptr ;
}
}
}
else
{
Iterator . RemoveCurrent ( ) ;
}
}
// Look for a higher priority LOD update
for ( TPair < const UCustomizableObjectInstance * , FMutableUpdateCandidate > & LODUpdateTuple : RequestedLODUpdates )
{
const UCustomizableObjectInstance * Instance = LODUpdateTuple . Key ;
if ( Instance )
{
FMutableUpdateCandidate & LODUpdateCandidate = LODUpdateTuple . Value ;
ensure ( LODUpdateCandidate . HasBeenIssued ( ) ) ;
if ( LODUpdateCandidate . Priority < = MaxPriorityFound )
{
if ( LODUpdateCandidate . CustomizableObjectInstance - > GetPrivate ( ) - > MinSquareDistFromComponentToPlayer < MaxSquareDistanceFound )
{
MaxPriorityFound = LODUpdateCandidate . Priority ;
MaxSquareDistanceFound = LODUpdateCandidate . CustomizableObjectInstance - > GetPrivate ( ) - > MinSquareDistFromComponentToPlayer ;
PendingInstanceUpdateFound = nullptr ;
LODUpdateCandidateFound = & LODUpdateCandidate ;
}
}
}
}
Private - > MutablePendingInstanceWork . SetLODUpdatesLastTick ( RequestedLODUpdates . Num ( ) ) ;
// If the chosen LODUpdate has the same instance as a PendingUpdate, choose the PendingUpdate to apply both the LOD update
// and customization change
if ( LODUpdateCandidateFound )
{
if ( const FMutablePendingInstanceUpdate * PendingUpdateWithSameInstance = Private - > MutablePendingInstanceWork . GetUpdate ( LODUpdateCandidateFound - > CustomizableObjectInstance ) )
{
PendingInstanceUpdateFound = PendingUpdateWithSameInstance ;
LODUpdateCandidateFound = nullptr ;
// In the processing of the PendingUpdate just below, it will add the LODUpdate's LOD params
}
}
if ( PendingInstanceUpdateFound )
{
check ( ! LODUpdateCandidateFound ) ;
2023-10-17 03:57:37 -04:00
UCustomizableObjectInstance * PendingInstance = PendingInstanceUpdateFound - > Context - > Instance . Get ( ) ;
2023-09-14 05:31:42 -04:00
check ( PendingInstance ) ;
2023-06-22 06:24:44 -04:00
// Maybe there's a LODUpdate that has the same instance, merge both updates as an optimization
FMutableUpdateCandidate * LODUpdateWithSameInstance = RequestedLODUpdates . Find ( PendingInstance ) ;
if ( LODUpdateWithSameInstance )
{
2023-10-17 03:57:37 -04:00
LODUpdateWithSameInstance - > ApplyLODUpdateParamsToInstance ( & PendingInstanceUpdateFound - > Context . Get ( ) ) ;
2023-06-22 06:24:44 -04:00
}
2023-10-17 03:57:37 -04:00
Private - > StartUpdateSkeletalMesh ( PendingInstanceUpdateFound - > Context ) ;
Private - > MutablePendingInstanceWork . RemoveUpdate ( PendingInstanceUpdateFound - > Context - > Instance ) ;
2023-06-22 06:24:44 -04:00
}
2023-09-14 05:31:42 -04:00
else if ( LODUpdateCandidateFound )
2023-06-22 06:24:44 -04:00
{
// Commit the LOD changes
LODUpdateCandidateFound - > ApplyLODUpdateParamsToInstance ( ) ;
2023-10-17 03:57:37 -04:00
const TSharedRef < FUpdateContextPrivate > Context = MakeShared < FUpdateContextPrivate > ( * LODUpdateCandidateFound - > CustomizableObjectInstance ) ;
Private - > StartUpdateSkeletalMesh ( Context ) ;
2023-06-22 06:24:44 -04:00
}
}
{
2023-01-24 08:45:18 -05:00
for ( TObjectIterator < UCustomizableObjectInstance > CustomizableObjectInstance ; CustomizableObjectInstance ; + + CustomizableObjectInstance )
{
2023-11-09 06:25:16 -05:00
if ( IsValid ( * CustomizableObjectInstance ) & & CustomizableObjectInstance - > GetPrivate ( ) )
2023-01-24 08:45:18 -05:00
{
CustomizableObjectInstance - > GetPrivate ( ) - > LastMinSquareDistFromComponentToPlayer = CustomizableObjectInstance - > GetPrivate ( ) - > MinSquareDistFromComponentToPlayer ;
CustomizableObjectInstance - > GetPrivate ( ) - > MinSquareDistFromComponentToPlayer = FLT_MAX ;
}
}
}
2022-09-26 15:12:13 -04:00
// Update the streaming limit if it has changed. It is safe to do this now.
2023-05-24 02:50:03 -04:00
Private - > UpdateMemoryLimit ( ) ;
2022-09-26 15:12:13 -04:00
2023-06-22 06:24:44 -04:00
// Free memory before starting the new update
DiscardInstances ( ) ;
ReleaseInstanceIDs ( ) ;
2022-09-26 15:12:13 -04:00
}
2023-09-14 05:31:42 -04:00
2022-09-26 15:12:13 -04:00
// Advance the current operation
if ( Private - > CurrentMutableOperation )
{
AdvanceCurrentOperation ( ) ;
}
# if WITH_EDITOR
TickRecompileCustomizableObjects ( ) ;
# endif
2023-05-15 05:50:59 -04:00
Private - > MutableTaskGraph . Tick ( ) ;
2023-10-25 06:41:33 -04:00
Private - > LogBenchmarkUtil . UpdateStats ( ) ; // Must to be the last thing to perform
2022-09-26 15:12:13 -04:00
return true ;
}
2023-06-22 06:24:44 -04:00
TAutoConsoleVariable < int32 > CVarMaxNumInstancesToDiscardPerTick (
TEXT ( " mutable.MaxNumInstancesToDiscardPerTick " ) ,
30 ,
TEXT ( " The maximum number of stale instances that will be discarded per tick by Mutable. " ) ,
ECVF_Scalability ) ;
void UCustomizableObjectSystem : : DiscardInstances ( )
{
// Handle instance discards
int32 NumInstancesDiscarded = 0 ;
const int32 DiscardLimitPerTick = CVarMaxNumInstancesToDiscardPerTick . GetValueOnGameThread ( ) ;
2023-09-07 04:23:11 -04:00
for ( TSet < FMutablePendingInstanceDiscard , FPendingInstanceDiscardKeyFuncs > : : TIterator Iterator = Private - > MutablePendingInstanceWork . GetDiscardIterator ( ) ;
Iterator & & NumInstancesDiscarded < DiscardLimitPerTick ;
+ + Iterator )
2023-06-22 06:24:44 -04:00
{
MUTABLE_CPUPROFILER_SCOPE ( OperationDiscard ) ;
UCustomizableObjectInstance * COI = Iterator - > CustomizableObjectInstance . Get ( ) ;
2023-10-17 03:57:37 -04:00
const bool bUpdating = Private - > CurrentMutableOperation & & Private - > CurrentMutableOperation - > Instance ! = Iterator - > CustomizableObjectInstance ;
2023-10-02 05:40:58 -04:00
if ( COI & & ! bUpdating )
2023-06-22 06:24:44 -04:00
{
UCustomizableInstancePrivateData * COIPrivateData = COI ? COI - > GetPrivate ( ) : nullptr ;
// Only discard resources if the instance is still out range (it could have got closer to the player since the task was queued)
if ( ! CurrentInstanceLODManagement - > IsOnlyUpdateCloseCustomizableObjectsEnabled ( ) | |
! COI | |
( ( COIPrivateData ! = nullptr ) & &
( COIPrivateData - > LastMinSquareDistFromComponentToPlayer > FMath : : Square ( CurrentInstanceLODManagement - > GetOnlyUpdateCloseCustomizableObjectsDist ( ) ) )
)
)
{
if ( COI & & COI - > IsValidLowLevel ( ) )
{
check ( COIPrivateData ! = nullptr ) ;
COIPrivateData - > DiscardResourcesAndSetReferenceSkeletalMesh ( COI ) ;
}
}
}
Iterator . RemoveCurrent ( ) ;
NumInstancesDiscarded + + ;
}
}
TAutoConsoleVariable < int32 > CVarMaxNumInstanceIDsToReleasePerTick (
TEXT ( " mutable.MaxNumInstanceIDsToReleasePerTick " ) ,
30 ,
TEXT ( " The maximum number of stale instances IDs that will be released per tick by Mutable. " ) ,
ECVF_Scalability ) ;
void UCustomizableObjectSystem : : ReleaseInstanceIDs ( )
{
// Handle ID discards
int32 NumIDsReleased = 0 ;
const int32 IDReleaseLimitPerTick = CVarMaxNumInstanceIDsToReleasePerTick . GetValueOnGameThread ( ) ;
for ( auto Iterator = Private - > MutablePendingInstanceWork . GetIDsToReleaseIterator ( ) ;
Iterator & & NumIDsReleased < IDReleaseLimitPerTick ; + + Iterator )
{
impl : : Task_Game_ReleaseInstanceID ( * Iterator ) ;
Iterator . RemoveCurrent ( ) ;
NumIDsReleased + + ;
}
}
2023-10-02 05:40:58 -04:00
bool UCustomizableObjectSystem : : IsUpdating ( const UCustomizableObjectInstance * Instance ) const
{
if ( ! Instance )
{
return false ;
}
return GetPrivateChecked ( ) - > IsUpdating ( * Instance ) ;
}
2022-09-26 15:12:13 -04:00
TArray < FCustomizableObjectExternalTexture > UCustomizableObjectSystem : : GetTextureParameterValues ( )
{
TArray < FCustomizableObjectExternalTexture > Result ;
2023-05-24 10:22:36 -04:00
for ( const TWeakObjectPtr < UCustomizableSystemImageProvider > Provider : GetPrivateChecked ( ) - > GetImageProviderChecked ( ) - > ImageProviders )
2022-09-26 15:12:13 -04:00
{
if ( Provider . IsValid ( ) )
{
Provider - > GetTextureParameterValues ( Result ) ;
}
}
return Result ;
}
void UCustomizableObjectSystem : : RegisterImageProvider ( UCustomizableSystemImageProvider * Provider )
{
2023-05-24 10:22:36 -04:00
GetPrivateChecked ( ) - > GetImageProviderChecked ( ) - > ImageProviders . Add ( Provider ) ;
2022-09-26 15:12:13 -04:00
}
void UCustomizableObjectSystem : : UnregisterImageProvider ( UCustomizableSystemImageProvider * Provider )
{
2023-05-24 10:22:36 -04:00
GetPrivateChecked ( ) - > GetImageProviderChecked ( ) - > ImageProviders . Remove ( Provider ) ;
2022-09-26 15:12:13 -04:00
}
2023-08-10 14:14:20 -04:00
static bool bRevertCacheTextureParameters = false ;
static FAutoConsoleVariableRef CVarRevertCacheTextureParameters (
TEXT ( " mutable.RevertCacheTextureParameters " ) , bRevertCacheTextureParameters ,
2023-10-17 03:57:37 -04:00
TEXT ( " If true, FUpdateContextPrivate will not cache/uncache texture parameters. If false, FUpdateContextPrivate will add an additional reference to the TextureParameters being used in the update. " ) ) ;
2023-08-10 14:14:20 -04:00
void CacheTexturesParameters ( const TArray < FName > & TextureParameters )
{
if ( bRevertCacheTextureParameters )
{
return ;
}
if ( ! TextureParameters . IsEmpty ( ) & & UCustomizableObjectSystem : : IsCreated ( ) )
{
FUnrealMutableImageProvider * ImageProvider = UCustomizableObjectSystem : : GetInstance ( ) - > GetPrivateChecked ( ) - > GetImageProviderChecked ( ) ;
check ( ImageProvider ) ;
for ( const FName & TextureParameter : TextureParameters )
{
ImageProvider - > CacheImage ( TextureParameter , false ) ;
}
}
}
void UnCacheTexturesParameters ( const TArray < FName > & TextureParameters )
{
if ( bRevertCacheTextureParameters )
{
return ;
}
if ( ! TextureParameters . IsEmpty ( ) & & UCustomizableObjectSystem : : IsCreated ( ) )
{
FUnrealMutableImageProvider * ImageProvider = UCustomizableObjectSystem : : GetInstance ( ) - > GetPrivateChecked ( ) - > GetImageProviderChecked ( ) ;
check ( ImageProvider ) ;
for ( const FName & TextureParameter : TextureParameters )
{
ImageProvider - > UnCacheImage ( TextureParameter , false ) ;
}
}
}
2022-09-26 15:12:13 -04:00
int32 UCustomizableObjectSystem : : GetNumInstances ( ) const
{
2023-10-25 06:41:33 -04:00
int32 NumInstances ;
int32 NumBuiltInstances ;
int32 NumInstancesLOD0 ;
int32 NumInstancesLOD1 ;
int32 NumInstancesLOD2 ;
int32 NumAllocatedSkeletalMeshes ;
GetPrivateChecked ( ) - > LogBenchmarkUtil . GetInstancesStats ( NumInstances , NumBuiltInstances , NumInstancesLOD0 , NumInstancesLOD1 , NumInstancesLOD2 , NumAllocatedSkeletalMeshes ) ;
return NumBuiltInstances ;
2022-09-26 15:12:13 -04:00
}
int32 UCustomizableObjectSystem : : GetNumPendingInstances ( ) const
{
2023-10-25 06:41:33 -04:00
return GetPrivateChecked ( ) - > MutablePendingInstanceWork . Num ( ) ;
2022-09-26 15:12:13 -04:00
}
int32 UCustomizableObjectSystem : : GetTotalInstances ( ) const
{
2023-10-25 06:41:33 -04:00
int32 NumInstances = 0 ;
for ( TObjectIterator < UCustomizableObjectInstance > Instance ; Instance ; + + Instance )
{
2023-11-09 06:25:16 -05:00
if ( ! IsValid ( * Instance ) | |
2023-10-25 06:41:33 -04:00
Instance - > HasAnyFlags ( RF_ClassDefaultObject ) )
{
continue ;
}
+ + NumInstances ;
}
return NumInstances ;
2022-09-26 15:12:13 -04:00
}
int32 UCustomizableObjectSystem : : GetTextureMemoryUsed ( ) const
{
2023-10-25 06:41:33 -04:00
return 0 ; // Currently disabled since the reported value was incorrect due to MIP streaming.
2022-09-26 15:12:13 -04:00
}
int32 UCustomizableObjectSystem : : GetAverageBuildTime ( ) const
{
2023-10-25 06:41:33 -04:00
return GetPrivateChecked ( ) - > LogBenchmarkUtil . InstanceBuildTimeAvrg . GetValue ( ) * 1000 ;
2022-09-26 15:12:13 -04:00
}
2023-08-22 08:38:33 -04:00
int32 UCustomizableObjectSystem : : GetSkeletalMeshMinLODQualityLevel ( ) const
{
2023-09-07 04:23:11 -04:00
return GetPrivateChecked ( ) - > SkeletalMeshMinLodQualityLevel ;
2023-08-22 08:38:33 -04:00
}
2022-09-26 15:12:13 -04:00
bool UCustomizableObjectSystem : : IsSupport16BitBoneIndexEnabled ( ) const
{
2023-09-07 04:23:11 -04:00
return GetPrivateChecked ( ) - > bSupport16BitBoneIndex ;
2022-09-26 15:12:13 -04:00
}
2023-01-24 08:45:18 -05:00
2022-09-26 15:12:13 -04:00
bool UCustomizableObjectSystem : : IsProgressiveMipStreamingEnabled ( ) const
{
2023-09-07 04:23:11 -04:00
return GetPrivateChecked ( ) - > EnableMutableProgressiveMipStreaming ! = 0 ;
2022-09-26 15:12:13 -04:00
}
2023-02-16 01:44:25 -05:00
void UCustomizableObjectSystem : : SetProgressiveMipStreamingEnabled ( bool bIsEnabled )
{
2023-09-07 04:23:11 -04:00
GetPrivateChecked ( ) - > EnableMutableProgressiveMipStreaming = bIsEnabled ? 1 : 0 ;
2023-02-16 01:44:25 -05:00
}
2023-01-24 08:45:18 -05:00
bool UCustomizableObjectSystem : : IsOnlyGenerateRequestedLODsEnabled ( ) const
{
2023-09-07 04:23:11 -04:00
return GetPrivateChecked ( ) - > EnableOnlyGenerateRequestedLODs ! = 0 ;
2023-01-24 08:45:18 -05:00
}
2023-02-16 01:44:25 -05:00
void UCustomizableObjectSystem : : SetOnlyGenerateRequestedLODsEnabled ( bool bIsEnabled )
{
2023-09-07 04:23:11 -04:00
GetPrivateChecked ( ) - > EnableOnlyGenerateRequestedLODs = bIsEnabled ? 1 : 0 ;
2023-02-16 01:44:25 -05:00
}
2023-09-13 06:59:56 -04:00
# if WITH_EDITOR
void UCustomizableObjectSystem : : SetImagePixelFormatOverride ( const mu : : FImageOperator : : FImagePixelFormatFunc & InFunc )
{
if ( Private ! = nullptr )
{
Private - > ImageFormatOverrideFunc = InFunc ;
}
}
# endif
2023-06-12 09:36:23 -04:00
void UCustomizableObjectSystem : : AddUncompiledCOWarning ( const UCustomizableObject & InObject , FString const * OptionalLogInfo )
2022-09-26 15:12:13 -04:00
{
FString Msg ;
2023-06-28 03:48:44 -04:00
Msg + = FString : : Printf ( TEXT ( " Warning: Customizable Object [%s] not compiled. " ) , * InObject . GetName ( ) ) ;
2023-06-12 09:36:23 -04:00
GEngine - > AddOnScreenDebugMessage ( ( uint64 ) ( ( PTRINT ) & InObject ) , 10.0f , FColor : : Red , Msg ) ;
2022-09-26 15:12:13 -04:00
Added logging an Error to UCustomizableObjectSystem::AddUncompiledCOWarning, and also added an optional parameter for the caller to add more info to the log (so we can easily log the source of the call to figure out what is being called that is trying to use a CO that hasn't been compiled yet).
Created a private helper function FCustomizableObjectInstanceDescriptor::AddUncompiledCOWarning(...), which makes sure the System exists, is valid, and isn't being destroyed before calling to AddUncompiledCOWarning on the System.
SetIntParameterSelectedOption(FString ParameterName,...) now ensures and calls to AddUncompiledCOWarning (which logs an error, makes an on-screen display, and sends a notfiication in Editor) if the CO that the descriptor is associated with is not compiled. If it is compiled, but the named parameter is not found, it ensures (in non-shipping builds only) and logs an error (in all builds).
SetIntParameterSelectedOption((const int32 IntParamIndex, ...) now also ensure and calls AddUncompiledCOWarning as the string version does if its CO is not compiled. If it is compiled, but the IntParamIndex is invalid, it logs an error and bails.
(We should make similar ensure/logging changes to all other parameter type setters.
I'll investigate that in the near future.)
#RB Joel.Anderson, Pere.Rifa
#UE5
[CL 25219708 by daniel broder in ue5-main branch]
2023-04-27 14:01:55 -04:00
# if WITH_EDITOR
2023-06-28 03:48:44 -04:00
// Mutable will spam these warnings constantly due to the tick and LOD manager checking for instances to update with every tick. Send only one message per CO in the editor.
if ( UncompiledCustomizableObjectIds . Find ( InObject . GetVersionId ( ) ) ! = INDEX_NONE )
{
return ;
}
// Add notification
UncompiledCustomizableObjectIds . Add ( InObject . GetVersionId ( ) ) ;
FMessageLog MessageLog ( " Mutable " ) ;
MessageLog . Warning ( FText : : FromString ( Msg ) ) ;
if ( ! UncompiledCustomizableObjectsNotificationPtr . IsValid ( ) )
{
FNotificationInfo Info ( FText : : FromString ( " Uncompiled Customizable Object/s found. Please, check the Message Log - Mutable for more information. " ) ) ;
Info . bFireAndForget = true ;
Info . bUseThrobber = true ;
Info . FadeOutDuration = 1.0f ;
Info . ExpireDuration = 5.0f ;
UncompiledCustomizableObjectsNotificationPtr = FSlateNotificationManager : : Get ( ) . AddNotification ( Info ) ;
}
Added logging an Error to UCustomizableObjectSystem::AddUncompiledCOWarning, and also added an optional parameter for the caller to add more info to the log (so we can easily log the source of the call to figure out what is being called that is trying to use a CO that hasn't been compiled yet).
Created a private helper function FCustomizableObjectInstanceDescriptor::AddUncompiledCOWarning(...), which makes sure the System exists, is valid, and isn't being destroyed before calling to AddUncompiledCOWarning on the System.
SetIntParameterSelectedOption(FString ParameterName,...) now ensures and calls to AddUncompiledCOWarning (which logs an error, makes an on-screen display, and sends a notfiication in Editor) if the CO that the descriptor is associated with is not compiled. If it is compiled, but the named parameter is not found, it ensures (in non-shipping builds only) and logs an error (in all builds).
SetIntParameterSelectedOption((const int32 IntParamIndex, ...) now also ensure and calls AddUncompiledCOWarning as the string version does if its CO is not compiled. If it is compiled, but the IntParamIndex is invalid, it logs an error and bails.
(We should make similar ensure/logging changes to all other parameter type setters.
I'll investigate that in the near future.)
#RB Joel.Anderson, Pere.Rifa
#UE5
[CL 25219708 by daniel broder in ue5-main branch]
2023-04-27 14:01:55 -04:00
const FString ErrorString = FString : : Printf (
TEXT ( " Customizable Object [%s] not compiled. Compile via the editor or via code before instancing. %s " ) ,
2023-06-28 03:48:44 -04:00
* InObject . GetName ( ) , OptionalLogInfo ? * * OptionalLogInfo : TEXT ( " " ) ) ;
Added logging an Error to UCustomizableObjectSystem::AddUncompiledCOWarning, and also added an optional parameter for the caller to add more info to the log (so we can easily log the source of the call to figure out what is being called that is trying to use a CO that hasn't been compiled yet).
Created a private helper function FCustomizableObjectInstanceDescriptor::AddUncompiledCOWarning(...), which makes sure the System exists, is valid, and isn't being destroyed before calling to AddUncompiledCOWarning on the System.
SetIntParameterSelectedOption(FString ParameterName,...) now ensures and calls to AddUncompiledCOWarning (which logs an error, makes an on-screen display, and sends a notfiication in Editor) if the CO that the descriptor is associated with is not compiled. If it is compiled, but the named parameter is not found, it ensures (in non-shipping builds only) and logs an error (in all builds).
SetIntParameterSelectedOption((const int32 IntParamIndex, ...) now also ensure and calls AddUncompiledCOWarning as the string version does if its CO is not compiled. If it is compiled, but the IntParamIndex is invalid, it logs an error and bails.
(We should make similar ensure/logging changes to all other parameter type setters.
I'll investigate that in the near future.)
#RB Joel.Anderson, Pere.Rifa
#UE5
[CL 25219708 by daniel broder in ue5-main branch]
2023-04-27 14:01:55 -04:00
# else // !WITH_EDITOR
const FString ErrorString = FString : : Printf (
2023-04-27 14:07:44 -04:00
TEXT ( " Customizable Object [%s] not compiled. This is not an Editor build, so this is an unrecoverable bad state; could be due to code or a cook failure. %s " ) ,
2023-06-28 03:48:44 -04:00
* InObject . GetName ( ) , OptionalLogInfo ? * * OptionalLogInfo : TEXT ( " " ) ) ;
Added logging an Error to UCustomizableObjectSystem::AddUncompiledCOWarning, and also added an optional parameter for the caller to add more info to the log (so we can easily log the source of the call to figure out what is being called that is trying to use a CO that hasn't been compiled yet).
Created a private helper function FCustomizableObjectInstanceDescriptor::AddUncompiledCOWarning(...), which makes sure the System exists, is valid, and isn't being destroyed before calling to AddUncompiledCOWarning on the System.
SetIntParameterSelectedOption(FString ParameterName,...) now ensures and calls to AddUncompiledCOWarning (which logs an error, makes an on-screen display, and sends a notfiication in Editor) if the CO that the descriptor is associated with is not compiled. If it is compiled, but the named parameter is not found, it ensures (in non-shipping builds only) and logs an error (in all builds).
SetIntParameterSelectedOption((const int32 IntParamIndex, ...) now also ensure and calls AddUncompiledCOWarning as the string version does if its CO is not compiled. If it is compiled, but the IntParamIndex is invalid, it logs an error and bails.
(We should make similar ensure/logging changes to all other parameter type setters.
I'll investigate that in the near future.)
#RB Joel.Anderson, Pere.Rifa
#UE5
[CL 25219708 by daniel broder in ue5-main branch]
2023-04-27 14:01:55 -04:00
# endif
// Also log an error so if this happens as part of a bug report we'll have this info.
UE_LOG ( LogMutable , Error , TEXT ( " %s " ) , * ErrorString ) ;
2022-09-26 15:12:13 -04:00
}
2023-08-23 09:23:59 -04:00
2022-09-26 15:12:13 -04:00
void UCustomizableObjectSystem : : EnableBenchmark ( )
{
2023-11-21 10:47:27 -05:00
CVarEnableBenchmark - > Set ( true ) ;
2022-09-26 15:12:13 -04:00
}
2023-08-23 09:23:59 -04:00
2022-09-26 15:12:13 -04:00
void UCustomizableObjectSystem : : EndBenchmark ( )
{
2023-11-21 10:47:27 -05:00
CVarEnableBenchmark - > Set ( false ) ;
2022-09-26 15:12:13 -04:00
}
void UCustomizableObjectSystem : : SetReleaseMutableTexturesImmediately ( bool bReleaseTextures )
{
2023-09-07 04:23:11 -04:00
GetPrivateChecked ( ) - > bReleaseTexturesImmediately = bReleaseTextures ;
2022-09-26 15:12:13 -04:00
}
# if WITH_EDITOR
void UCustomizableObjectSystem : : OnPreBeginPIE ( const bool bIsSimulatingInEditor )
{
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
if ( ! EditorSettings . bCompileRootObjectsOnStartPIE | | IsRunningGame ( ) | | IsCompilationDisabled ( ) )
2022-09-26 15:12:13 -04:00
{
return ;
}
// Find root customizable objects
FARFilter AssetRegistryFilter ;
2023-04-04 06:06:06 -04:00
UE_MUTABLE_GET_CLASSPATHS ( AssetRegistryFilter ) . Add ( UE_MUTABLE_TOPLEVELASSETPATH ( TEXT ( " /Script/CustomizableObject " ) , TEXT ( " CustomizableObject " ) ) ) ;
2022-09-26 15:12:13 -04:00
AssetRegistryFilter . TagsAndValues . Add ( FName ( " IsRoot " ) , FString : : FromInt ( 1 ) ) ;
TArray < FAssetData > OutAssets ;
const FAssetRegistryModule & AssetRegistryModule = FModuleManager : : LoadModuleChecked < FAssetRegistryModule > ( " AssetRegistry " ) ;
AssetRegistryModule . Get ( ) . GetAssets ( AssetRegistryFilter , OutAssets ) ;
TArray < FAssetData > TempObjectsToRecompile ;
for ( const FAssetData & Asset : OutAssets )
{
// If it is referenced by PIE it should be loaded
if ( ! Asset . IsAssetLoaded ( ) )
{
continue ;
}
const UCustomizableObject * Object = Cast < UCustomizableObject > ( Asset . GetAsset ( ) ) ;
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
if ( ! Object | | Object - > IsCompiled ( ) | | Object - > IsLocked ( ) | | Object - > bIsChildObject )
2022-09-26 15:12:13 -04:00
{
continue ;
}
// Add uncompiled objects to the objects to cook list
TempObjectsToRecompile . Add ( Asset ) ;
}
if ( ! TempObjectsToRecompile . IsEmpty ( ) )
{
2023-09-07 04:23:11 -04:00
const FText Msg = FText : : FromString ( TEXT ( " Warning: one or more Customizable Objects used in PIE are uncompiled. \n \n Do you want to compile them? " ) ) ;
2022-09-26 15:12:13 -04:00
if ( FMessageDialog : : Open ( EAppMsgType : : OkCancel , Msg ) = = EAppReturnType : : Ok )
{
ObjectsToRecompile . Empty ( TempObjectsToRecompile . Num ( ) ) ;
RecompileCustomizableObjects ( TempObjectsToRecompile ) ;
}
}
}
void UCustomizableObjectSystem : : StartNextRecompile ( )
{
2023-08-17 10:26:18 -04:00
if ( GEngine )
{
GEngine - > ForceGarbageCollection ( ) ;
}
2022-09-26 15:12:13 -04:00
FAssetData Itr = ObjectsToRecompile . Pop ( ) ;
2023-09-07 04:23:11 -04:00
if ( UCustomizableObject * CustomizableObject = Cast < UCustomizableObject > ( Itr . GetAsset ( ) ) )
2022-09-26 15:12:13 -04:00
{
2023-09-07 04:23:11 -04:00
const FText UpdateMsg = FText : : FromString ( FString : : Printf ( TEXT ( " Compiling Customizable Objects: \n %s " ) , * CustomizableObject - > GetName ( ) ) ) ;
2022-09-26 15:12:13 -04:00
FSlateNotificationManager : : Get ( ) . UpdateProgressNotification ( RecompileNotificationHandle , NumObjectsCompiled , TotalNumObjectsToRecompile , UpdateMsg ) ;
// Use default options
FCompilationOptions Options = CustomizableObject - > CompileOptions ;
Options . bSilentCompilation = true ;
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
check ( RecompileCustomizableObjectsCompiler ! = nullptr ) ;
2022-09-26 15:12:13 -04:00
RecompileCustomizableObjectsCompiler - > Compile ( * CustomizableObject , Options , true ) ;
}
}
void UCustomizableObjectSystem : : RecompileCustomizableObjectAsync ( const FAssetData & InAssetData ,
const UCustomizableObject * InObject )
{
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
if ( IsRunningGame ( ) | | IsCompilationDisabled ( ) )
2022-09-26 15:12:13 -04:00
{
return ;
}
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
if ( ( InObject & & InObject - > IsLocked ( ) ) | | ObjectsToRecompile . Find ( ( InAssetData ) ) ! = INDEX_NONE )
2022-09-26 15:12:13 -04:00
{
return ;
}
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
if ( ! ObjectsToRecompile . IsEmpty ( ) )
2022-09-26 15:12:13 -04:00
{
ObjectsToRecompile . Add ( InAssetData ) ;
}
else
{
RecompileCustomizableObjects ( { InAssetData } ) ;
}
}
void UCustomizableObjectSystem : : RecompileCustomizableObjects ( const TArray < FAssetData > & InObjects )
{
if ( IsRunningGame ( ) | | IsCompilationDisabled ( ) )
{
return ;
}
if ( InObjects . Num ( ) )
{
if ( ! RecompileCustomizableObjectsCompiler )
{
RecompileCustomizableObjectsCompiler = GetNewCompiler ( ) ;
if ( ! RecompileCustomizableObjectsCompiler )
{
return ;
}
}
ObjectsToRecompile . Append ( InObjects ) ;
TotalNumObjectsToRecompile = ObjectsToRecompile . Num ( ) ;
NumObjectsCompiled = 0 ;
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
if ( RecompileNotificationHandle . IsValid ( ) )
2022-09-26 15:12:13 -04:00
{
+ + TotalNumObjectsToRecompile ;
FSlateNotificationManager : : Get ( ) . UpdateProgressNotification ( RecompileNotificationHandle , NumObjectsCompiled , TotalNumObjectsToRecompile ) ;
}
else
{
RecompileNotificationHandle = FSlateNotificationManager : : Get ( ) . StartProgressNotification ( FText : : FromString ( TEXT ( " Compiling Customizable Objects " ) ) , TotalNumObjectsToRecompile ) ;
StartNextRecompile ( ) ;
}
}
}
void UCustomizableObjectSystem : : TickRecompileCustomizableObjects ( )
{
bool bUpdated = false ;
if ( RecompileCustomizableObjectsCompiler )
{
bUpdated = RecompileCustomizableObjectsCompiler - > Tick ( ) | | RecompileCustomizableObjectsCompiler - > GetCompilationState ( ) = = ECustomizableObjectCompilationState : : Failed ;
}
if ( bUpdated )
{
NumObjectsCompiled + + ;
if ( ! ObjectsToRecompile . IsEmpty ( ) )
{
StartNextRecompile ( ) ;
}
else // All objects compiled, clean up
{
// Delete compiler
delete RecompileCustomizableObjectsCompiler ;
RecompileCustomizableObjectsCompiler = nullptr ;
// Remove progress bar
FSlateNotificationManager : : Get ( ) . UpdateProgressNotification ( RecompileNotificationHandle , NumObjectsCompiled , TotalNumObjectsToRecompile ) ;
FSlateNotificationManager : : Get ( ) . CancelProgressNotification ( RecompileNotificationHandle ) ;
RecompileNotificationHandle . Reset ( ) ;
2023-08-17 10:26:18 -04:00
if ( GEngine )
{
GEngine - > ForceGarbageCollection ( ) ;
}
2022-09-26 15:12:13 -04:00
}
}
}
uint64 UCustomizableObjectSystem : : GetMaxChunkSizeForPlatform ( const ITargetPlatform * TargetPlatform )
{
const FString & PlatformName = TargetPlatform ? TargetPlatform - > IniPlatformName ( ) : FPlatformProperties : : IniPlatformName ( ) ;
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
if ( const int64 * CachedMaxChunkSize = PlatformMaxChunkSize . Find ( PlatformName ) )
2022-09-26 15:12:13 -04:00
{
return * CachedMaxChunkSize ;
}
int64 MaxChunkSize = - 1 ;
if ( ! FParse : : Value ( FCommandLine : : Get ( ) , TEXT ( " ExtraFlavorChunkSize= " ) , MaxChunkSize ) | | MaxChunkSize < 0 )
{
FConfigFile PlatformIniFile ;
FConfigCacheIni : : LoadLocalIniFile ( PlatformIniFile , TEXT ( " Game " ) , true , * PlatformName ) ;
FString ConfigString ;
if ( PlatformIniFile . GetString ( TEXT ( " /Script/UnrealEd.ProjectPackagingSettings " ) , TEXT ( " MaxChunkSize " ) , ConfigString ) )
{
MaxChunkSize = FCString : : Atoi64 ( * ConfigString ) ;
}
}
// If no limit is specified default it to MUTABLE_STREAMED_DATA_MAXCHUNKSIZE
While Investigating a client hang, found some code that is either unsafe, not clearly safe, or violates UE coding standards.
Code cleanup:
* Added a lot of checks() to make sure we crash explicitly with useful information rather than hoping a crash will have enough info to work from.
** NOTE: I'm aware that _some_ of the "GetPrivate()" calls have a check internal to them, but they're not named to indicate that, so it may change, and other GetPrivate() calls do NOT have internal checks for nullptr. So to reduce the need for specific implementation knowledge and the possible confusion between them, I just re-assert in those cases if the pointer is nullptr.
* Fixed a number of coding standard issues, including:
** Variable names must start with initial capitals
** Spacing, indentation, and bracing issues that didn't match UE coding standards.
* Cleaned up some other spacing and indentation issues to be consistent within the file and for general readability.
Also, removed a line of code that would cause a crash due to dereferencing a pointer that's guaranteed to be nullptr or invalid.
Added a few temporary comments to investigate some other oddities in the code.
#RB Alexei.Lebedev, Pere.Rifa, Joel.Anderson
#UE5 #RNX #NoReleaseNotes
[CL 23519838 by daniel broder in ue5-main branch]
2022-12-14 17:05:40 -05:00
if ( MaxChunkSize < = 0 )
2022-09-26 15:12:13 -04:00
{
MaxChunkSize = MUTABLE_STREAMED_DATA_MAXCHUNKSIZE ;
}
PlatformMaxChunkSize . Add ( PlatformName , MaxChunkSize ) ;
return MaxChunkSize ;
}
2022-11-04 09:18:44 -04:00
# endif // WITH_EDITOR
2022-10-04 09:10:32 -04:00
2023-07-31 03:24:06 -04:00
void UCustomizableObjectSystem : : CacheImage ( FName ImageId )
2022-10-04 09:10:32 -04:00
{
2023-05-24 10:22:36 -04:00
GetPrivateChecked ( ) - > GetImageProviderChecked ( ) - > CacheImage ( ImageId , true ) ;
2022-10-04 09:10:32 -04:00
}
2023-07-31 03:24:06 -04:00
void UCustomizableObjectSystem : : UnCacheImage ( FName ImageId )
2022-10-04 09:10:32 -04:00
{
2023-05-24 10:22:36 -04:00
GetPrivateChecked ( ) - > GetImageProviderChecked ( ) - > UnCacheImage ( ImageId , true ) ;
2022-10-04 09:10:32 -04:00
}
void UCustomizableObjectSystem : : ClearImageCache ( )
{
2023-05-24 10:22:36 -04:00
GetPrivateChecked ( ) - > GetImageProviderChecked ( ) - > ClearCache ( true ) ;
2022-11-22 04:57:22 -05:00
}
bool FCustomizableObjectSystemPrivate : : IsMutableAnimInfoDebuggingEnabled ( ) const
{
# if WITH_EDITORONLY_DATA
return EnableMutableAnimInfoDebugging > 0 ;
# else
return false ;
# endif
}
2023-05-24 10:22:36 -04:00
FUnrealMutableImageProvider * FCustomizableObjectSystemPrivate : : GetImageProviderChecked ( ) const
{
check ( ImageProvider )
return ImageProvider . Get ( ) ;
}
2023-10-17 03:57:37 -04:00
void FCustomizableObjectSystemPrivate : : StartUpdateSkeletalMesh ( const TSharedRef < FUpdateContextPrivate > & Context )
2023-10-02 05:40:58 -04:00
{
2023-10-25 06:41:33 -04:00
Context - > UpdateStarted = true ;
TRACE_BEGIN_REGION ( UE_MUTABLE_UPDATE_REGION ) ;
2023-10-02 05:40:58 -04:00
check ( ! CurrentMutableOperation ) ; // Can not start an update if there is already another in progress
2023-10-17 03:57:37 -04:00
check ( Context - > Instance . IsValid ( ) ) // The instance has to be alive to start the update
2023-11-21 10:47:27 -05:00
const uint32 InstanceId = Context - > Instance - > GetUniqueID ( ) ;
UE_LOG ( LogMutable , Log , TEXT ( " Started UpdateSkeletalMesh Async. Instance=%d, Frame=%d " ) , InstanceId , GFrameNumber ) ;
2023-10-17 03:57:37 -04:00
CurrentMutableOperation = Context ;
2023-10-02 05:40:58 -04:00
}
bool FCustomizableObjectSystemPrivate : : IsUpdating ( const UCustomizableObjectInstance & Instance ) const
{
2023-10-17 03:57:37 -04:00
if ( CurrentMutableOperation & & CurrentMutableOperation - > Instance . Get ( ) = = & Instance )
2023-10-02 05:40:58 -04:00
{
return true ;
}
if ( MutablePendingInstanceWork . GetUpdate ( TWeakObjectPtr < const UCustomizableObjectInstance > ( & Instance ) ) )
{
return true ;
}
return false ;
}
2023-10-25 06:41:33 -04:00
void FCustomizableObjectSystemPrivate : : UpdateStats ( )
{
NumSkeletalMeshes = 0 ;
for ( TObjectIterator < UCustomizableObjectInstance > Instance ; Instance ; + + Instance )
{
2023-11-09 06:25:16 -05:00
if ( ! IsValid ( * Instance ) )
2023-10-25 06:41:33 -04:00
{
continue ;
}
NumSkeletalMeshes + = Instance - > SkeletalMeshes . Num ( ) ;
}
}
2022-11-22 04:57:22 -05:00
bool UCustomizableObjectSystem : : IsMutableAnimInfoDebuggingEnabled ( ) const
{
# if WITH_EDITOR
2023-05-24 10:22:36 -04:00
return GetPrivateChecked ( ) - > IsMutableAnimInfoDebuggingEnabled ( ) ;
2022-11-22 04:57:22 -05:00
# else
return false ;
# endif
}