// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "UObject/Object.h" #include "UObject/UObjectArray.h" #include "Stats/Stats2.h" DECLARE_STATS_GROUP_VERBOSE(TEXT("Async Load"), STATGROUP_AsyncLoad, STATCAT_Advanced); DECLARE_CYCLE_STAT(TEXT("Async Loading Time"), STAT_AsyncLoadingTime, STATGROUP_AsyncLoad); DECLARE_STATS_GROUP(TEXT("Async Load Game Thread"), STATGROUP_AsyncLoadGameThread, STATCAT_Advanced); DECLARE_CYCLE_STAT(TEXT("PostLoadObjects GT"), STAT_FAsyncPackage_PostLoadObjectsGameThread, STATGROUP_AsyncLoadGameThread); DECLARE_CYCLE_STAT(TEXT("TickAsyncLoading GT"), STAT_FAsyncPackage_TickAsyncLoadingGameThread, STATGROUP_AsyncLoadGameThread); DECLARE_CYCLE_STAT(TEXT("Flush Async Loading GT"), STAT_FAsyncPackage_FlushAsyncLoadingGameThread, STATGROUP_AsyncLoadGameThread); DECLARE_CYCLE_STAT(TEXT("CreateClusters GT"), STAT_FAsyncPackage_CreateClustersGameThread, STATGROUP_AsyncLoadGameThread); enum class ENotifyRegistrationType; enum class ENotifyRegistrationPhase; extern const FName PrestreamPackageClassNameLoad; /** Returns true if we're inside a FGCScopeLock */ extern bool IsGarbageCollectionLocked(); bool IsFullyLoadedObj(UObject* Obj); bool IsNativeCodePackage(UPackage* Package); /** Checks if the object can have PostLoad called on the Async Loading Thread */ bool CanPostLoadOnAsyncLoadingThread(UObject* Object); template void ClearFlagsAndDissolveClustersFromLoadedObjects(T& LoadedObjects) { const EObjectFlags ObjectLoadFlags = RF_NeedLoad | RF_NeedPostLoad | RF_NeedPostLoadSubobjects | RF_WasLoaded; for (UObject* ObjRef: LoadedObjects) { if (ObjRef) { ObjRef->AtomicallyClearFlags(ObjectLoadFlags); if (ObjRef->HasAnyInternalFlags(EInternalObjectFlags::ClusterRoot)) { GUObjectClusters.DissolveCluster(ObjRef); } } } } class IAsyncPackageLoader; class FPackageIndex; class LinkerInstancingContext; class IEDLBootNotificationManager { public: virtual ~IEDLBootNotificationManager() = default; virtual bool AddWaitingPackage(void* Pkg, FName PackageName, FName ObjectName, FPackageIndex Import, bool bIgnoreMissingPackage) = 0; virtual bool ConstructWaitingBootObjects() = 0; virtual bool FireCompletedCompiledInImports(bool bFinalRun = false) = 0; virtual bool IsWaitingForSomething() = 0; }; /** Structure that holds the async loading thread ini settings */ struct FAsyncLoadingThreadSettings { bool bAsyncLoadingThreadEnabled; bool bAsyncPostLoadEnabled; FAsyncLoadingThreadSettings(); /** Gets the ALT settigns from ini (or command line). */ static FAsyncLoadingThreadSettings& Get(); }; /** * Asynchronous package loader interface. */ class IAsyncPackageLoader { public: virtual ~IAsyncPackageLoader() {} /** * Initialize loading. */ virtual void InitializeLoading() = 0; /** * Shut down loading. */ virtual void ShutdownLoading() = 0; virtual void StartThread() = 0; /** * Asynchronously load a package. * * @param InName Name of package to load * @param InGuid GUID of the package to load, or nullptr for "don't care" * @param InPackageToLoadFrom If non-null, this is another package name. We load from this package name, into a (probably new) package named InName * @param InCompletionDelegate Delegate to be invoked when the packages has finished streaming * @param InPackageFlags Package flags used to construct loaded package in memory * @param InPIEInstanceID Play in Editor instance ID * @param InPackagePriority Loading priority * @return Unique ID associated with this load request (the same package can be associated with multiple IDs). */ virtual int32 LoadPackage( const FString& InPackageName, const FGuid* InGuid, const TCHAR* InPackageToLoadFrom, FLoadPackageAsyncDelegate InCompletionDelegate, EPackageFlags InPackageFlags, int32 InPIEInstanceID, int32 InPackagePriority, const FLinkerInstancingContext* InstancingContext) = 0; /** * Process all currently loading package requests. * * @param bUseTimeLimit Whether to use time limit or not * @param bUseFullTimeLimit * @param TimeLimit Time limit */ virtual EAsyncPackageState::Type ProcessLoading(bool bUseTimeLimit, bool bUseFullTimeLimit, float TimeLimit) = 0; /** * Process all loading package requests until completion predicate is satisfied. * * @param CompletionPredicate Completion predicate * @param TimeLimit Time limit */ virtual EAsyncPackageState::Type ProcessLoadingUntilComplete(TFunctionRef CompletionPredicate, float TimeLimit) = 0; /** * Cancels streaming. * * Note: Called from Game Thread. */ virtual void CancelLoading() = 0; /** * Suspends async loading thread * * Note: Called from Game Thread. */ virtual void SuspendLoading() = 0; /** * Resumes async loading thread * * Note: Called from Game Thread. */ virtual void ResumeLoading() = 0; /** * Flush pending loading request(s). * * Note: Called from Game Thread. */ virtual void FlushLoading(int32 PackageId) = 0; /** * Returns the number of queued packages. */ virtual int32 GetNumQueuedPackages() = 0; /** * Returns the number of loading packages. */ virtual int32 GetNumAsyncPackages() = 0; /** * [GAME THREAD] Gets the load percentage of the specified package * @param PackageName Name of the package to return async load percentage for * @return Percentage (0-100) of the async package load or -1 of package has not been found */ virtual float GetAsyncLoadPercentage(const FName& PackageName) = 0; /** * Returns whether the package loader is suspended or not. */ virtual bool IsAsyncLoadingSuspended() = 0; /** * Returns whether in package loader background thread or not. */ virtual bool IsInAsyncLoadThread() = 0; /** * Returns whether loading packages with multiple threads. * Note: GIsInitialLoad guards the package loader from creating background threads too early. * */ virtual bool IsMultithreaded() = 0; /** * Returns whether packages are currently being loaded on a background thread. * Note: GIsInitialLoad guards the package loader from creating background threads too early. * */ virtual bool IsAsyncLoadingPackages() = 0; virtual void NotifyConstructedDuringAsyncLoading(UObject* Object, bool bSubObject) = 0; virtual void NotifyUnreachableObjects(const TArrayView& UnreachableObjects) = 0; virtual void FireCompletedCompiledInImport(void* AsyncPackage, FPackageIndex Import) = 0; protected: static int32 GetNextRequestId(); private: static FThreadSafeCounter NextPackageRequestId; }; // Stats for ChartCreation.cpp extern COREUOBJECT_API double GFlushAsyncLoadingTime; extern COREUOBJECT_API uint32 GFlushAsyncLoadingCount; extern COREUOBJECT_API uint32 GSyncLoadCount; extern COREUOBJECT_API void ResetAsyncLoadingStats(); // Time limit extern COREUOBJECT_API int32 GWarnIfTimeLimitExceeded; extern COREUOBJECT_API float GTimeLimitExceededMultiplier; extern COREUOBJECT_API float GTimeLimitExceededMinTime; void IsTimeLimitExceededPrint( double InTickStartTime, double CurrentTime, double LastTestTime, float InTimeLimit, const TCHAR* InLastTypeOfWorkPerformed = nullptr, UObject* InLastObjectWorkWasPerformedOn = nullptr);