EM_Task/CoreUObject/Public/UObject/UObjectThreadContext.h
Boshuang Zhao 5144a49c9b add
2026-02-13 16:18:33 +08:00

264 lines
8.1 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
UnAsyncLoading.cpp: Unreal async loading code.
=============================================================================*/
#pragma once
#include "CoreMinimal.h"
#include "HAL/ThreadSingleton.h"
#include "HAL/ThreadSafeCounter.h"
#include "Templates/RefCounting.h"
class FObjectInitializer;
struct FUObjectSerializeContext;
class FLinkerLoad;
class IAsyncPackageLoader;
DECLARE_LOG_CATEGORY_EXTERN(LogUObjectThreadContext, Log, All);
class COREUOBJECT_API FUObjectThreadContext: public TThreadSingleton<FUObjectThreadContext>
{
friend TThreadSingleton<FUObjectThreadContext>;
FUObjectThreadContext();
virtual ~FUObjectThreadContext();
/** Stack of currently used FObjectInitializers for this thread */
TArray<FObjectInitializer*> InitializerStack;
public:
/**
* Remove top element from the stack.
*/
void PopInitializer()
{
InitializerStack.Pop(/*bAllowShrinking=*/false);
}
/**
* Push new FObjectInitializer on stack.
* @param Initializer Object initializer to push.
*/
void PushInitializer(FObjectInitializer* Initializer)
{
InitializerStack.Push(Initializer);
}
/**
* Retrieve current FObjectInitializer for current thread.
* @return Current FObjectInitializer.
*/
FObjectInitializer* TopInitializer()
{
return InitializerStack.Num() ? InitializerStack.Last() : nullptr;
}
/**
* Retrieves current FObjectInitializer for current thread. Will assert of no ObjectInitializer is currently set.
* @return Current FObjectInitializer reference.
*/
FObjectInitializer& TopInitializerChecked()
{
FObjectInitializer* ObjectInitializerPtr = TopInitializer();
UE_CLOG(!ObjectInitializerPtr, LogUObjectThreadContext, Fatal, TEXT("Tried to get the current ObjectInitializer, but none is set. Please use NewObject to construct new UObject-derived classes."));
return *ObjectInitializerPtr;
}
/** true when we are routing ConditionalPostLoad/PostLoad to objects */
bool IsRoutingPostLoad;
/** The object we are routing PostLoad from the Async Loading code for */
UObject* CurrentlyPostLoadedObjectByALT;
/** true when FLinkerManager deletes linkers */
bool IsDeletingLinkers;
/* Global flag so that FObjectFinders know if they are called from inside the UObject constructors or not. */
int32 IsInConstructor;
/* Object that is currently being constructed with ObjectInitializer */
UObject* ConstructedObject;
/** Async Package currently processing objects */
void* AsyncPackage;
#if WITH_IOSTORE_IN_EDITOR
/** Async package loader currently processing objects */
IAsyncPackageLoader* AsyncPackageLoader;
#endif
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
/** Stack to ensure that PostInitProperties is routed through Super:: calls. **/
TArray<UObject*, TInlineAllocator<16>> PostInitPropertiesCheck;
/** Used to verify that the Super::PostLoad chain is intact. */
TArray<UObject*, TInlineAllocator<16>> DebugPostLoad;
#endif
#if WITH_EDITORONLY_DATA
/** Maps a package name to all packages marked as editor-only due to the fact it was marked as editor-only */
TMap<FName, TSet<FName>> PackagesMarkedEditorOnlyByOtherPackage;
#endif
/** Gets the current serialization context */
FUObjectSerializeContext* GetSerializeContext()
{
return SerializeContext;
}
private:
/** Current serialization context */
TRefCountPtr<FUObjectSerializeContext> SerializeContext;
};
/** Structure that holds the current serialization state of UObjects */
struct COREUOBJECT_API FUObjectSerializeContext
{
friend class FUObjectThreadContext;
private:
/** Constructor */
FUObjectSerializeContext();
/** Destructor */
~FUObjectSerializeContext();
/** Reference count of this context */
int32 RefCount;
/** Imports for EndLoad optimization. */
int32 ImportCount;
/** Forced exports for EndLoad optimization. */
int32 ForcedExportCount;
/** Count for BeginLoad multiple loads. */
int32 ObjBeginLoadCount;
/** Objects that might need preloading. */
TArray<UObject*> ObjectsLoaded;
/** List of linkers that we want to close the loaders for (to free file handles) - needs to be delayed until EndLoad is called with GObjBeginLoadCount of 0 */
TArray<FLinkerLoad*> DelayedLinkerClosePackages;
/** List of linkers associated with this context */
TSet<FLinkerLoad*> AttachedLinkers;
public:
/** Points to the main UObject currently being serialized */
UObject* SerializedObject;
/** Points to the main PackageLinker currently being serialized (Defined in Linker.cpp) */
FLinkerLoad* SerializedPackageLinker;
/** The main Import Index currently being used for serialization by CreateImports() (Defined in Linker.cpp) */
int32 SerializedImportIndex;
/** Points to the main Linker currently being used for serialization by CreateImports() (Defined in Linker.cpp) */
FLinkerLoad* SerializedImportLinker;
/** The most recently used export Index for serialization by CreateExport() */
int32 SerializedExportIndex;
/** Points to the most recently used Linker for serialization by CreateExport() */
FLinkerLoad* SerializedExportLinker;
/** Adds a new loaded object */
void AddLoadedObject(UObject* InObject);
void AddUniqueLoadedObjects(const TArray<UObject*>& InObjects);
/** Checks if object loading has started */
bool HasStartedLoading() const
{
return ObjBeginLoadCount > 0;
}
int32 GetBeginLoadCount() const
{
return ObjBeginLoadCount;
}
int32 IncrementBeginLoadCount();
int32 DecrementBeginLoadCount();
int32 IncrementImportCount()
{
return ++ImportCount;
}
void ResetImportCount()
{
ImportCount = 0;
}
int32 IncrementForcedExportCount()
{
return ++ForcedExportCount;
}
void ResetForcedExports()
{
ForcedExportCount = 0;
}
bool HasPendingImportsOrForcedExports() const
{
return ImportCount || ForcedExportCount;
}
bool HasLoadedObjects() const
{
return !!ObjectsLoaded.Num();
}
bool PRIVATE_PatchNewObjectIntoExport(UObject* OldObject, UObject* NewObject);
/** This is only meant to be used by FAsyncPackage for performance reasons. The ObjectsLoaded array should not be manipulated directly! */
TArray<UObject*>& PRIVATE_GetObjectsLoadedInternalUseOnly()
{
return ObjectsLoaded;
}
void AppendLoadedObjectsAndEmpty(TArray<UObject*>& InLoadedObject)
{
InLoadedObject.Append(ObjectsLoaded);
ObjectsLoaded.Reset();
}
void ReserveObjectsLoaded(int32 InReserveSize)
{
ObjectsLoaded.Reserve(InReserveSize);
}
int32 GetNumObjectsLoaded() const
{
return ObjectsLoaded.Num();
}
void AddDelayedLinkerClosePackage(class FLinkerLoad* InLinker)
{
DelayedLinkerClosePackages.AddUnique(InLinker);
}
void RemoveDelayedLinkerClosePackage(class FLinkerLoad* InLinker)
{
DelayedLinkerClosePackages.Remove(InLinker);
}
void MoveDelayedLinkerClosePackages(TArray<class FLinkerLoad*>& OutDelayedLinkerClosePackages)
{
OutDelayedLinkerClosePackages = MoveTemp(DelayedLinkerClosePackages);
}
/** Attaches a linker to this context */
void AttachLinker(FLinkerLoad* InLinker);
/** Detaches a linker from this context */
void DetachLinker(FLinkerLoad* InLinker);
/** Detaches all linkers from this context */
void DetachFromLinkers();
//~ TRefCountPtr interface
int32 AddRef()
{
return ++RefCount;
}
int32 Release()
{
int32 CurrentRefCount = --RefCount;
check(CurrentRefCount >= 0);
if (CurrentRefCount == 0)
{
delete this;
}
return CurrentRefCount;
}
int32 GetRefCount() const
{
return RefCount;
}
//~ TRefCountPtr interface
};