// If we have a full UObject name then attempt to find the object in memory first, if (bAllowObjectReconciliation && (bContainsObjectName #if WITH_EDITOR || GIsImportingT3D #endif )) { Result = StaticFindObjectFast(ObjectClass, InOuter, *StrName); if (Result && Result->HasAnyFlags(RF_NeedLoad | RF_NeedPostLoad | RF_NeedPostLoadSubobjects | RF_WillBeLoaded)) { // Object needs loading so load it before returning Result = nullptr; } }
如果对象未找到且Outer所在包不是编译进来的,加载整个包。
1 2 3 4 5 6 7
if (!Result) { if (!InOuter->GetOutermost()->HasAnyPackageFlags(PKG_CompiledIn)) { // now that we have one asset per package, we load the entire package whenever a single object is requested LoadPackage(NULL, *InOuter->GetOutermost()->GetName(), LoadFlags & ~LOAD_Verify, nullptr, InstancingContext); }
包加载后再次查找对象。
1 2 3 4 5 6
// now, find the object in the package Result = StaticFindObjectFast(ObjectClass, InOuter, *StrName); if (GEventDrivenLoaderEnabled && Result && Result->HasAnyFlags(RF_NeedLoad | RF_NeedPostLoad | RF_NeedPostLoadSubobjects | RF_WillBeLoaded)) { UE_LOG(LogUObjectGlobals, Fatal, TEXT("Return an object still needing load from StaticLoadObjectInternal %s"), *GetFullNameSafe(Result)); }
如果没找到对象,且允许重定向,尝试查找重定向器
1 2 3 4 5 6 7 8 9
// If the object was not found, check for a redirector and follow it if the class matches if (!Result && !(LoadFlags & LOAD_NoRedirects)) { UObjectRedirector* Redirector = FindObjectFast<UObjectRedirector>(InOuter, *StrName); if (Redirector && Redirector->DestinationObject && Redirector->DestinationObject->IsA(ObjectClass)) { return Redirector->DestinationObject; } }
如果没有找到对象,且名称不包含.,则假设对象是包内主资产,构造完整名称后递归调用自身加载。
1 2 3 4 5 6 7 8 9
if (!Result && !bContainsObjectName) { // Assume that the object we're trying to load is the main asset inside of the package // which usually has the same name as the short package name. StrName = InName; StrName += TEXT("."); StrName += FPackageName::GetShortName(InName); Result = StaticLoadObjectInternal(ObjectClass, InOuter, *StrName, Filename, LoadFlags, Sandbox, bAllowObjectReconciliation, InstancingContext); }
if (Package) { // The package is already sitting in the queue. Make sure the its priority, and the priority of all its // dependencies is at least as high as the priority of this request UpdateExistingPackagePriorities(Package, InRequest->Priority); }
如果未找到,尝试在已加载包集合中查找
1 2 3 4 5 6 7 8 9 10 11 12
if (Package) { ... } else { // [BLOCKING] LoadedPackages are accessed on the main thread too, so lock to be able to add a completion callback #if THREADSAFE_UOBJECTS FScopeLock LoadedLock(&LoadedPackagesCritical); #endif Package = FindExistingPackageAndAddCompletionCallback(InRequest, LoadedPackagesNameLookup, FlushTree); }
如果仍未找到,尝试在待处理加载包集合中查找
1 2 3 4 5 6 7 8
if (!Package) { // [BLOCKING] LoadedPackagesToProcess are modified on the main thread, so lock to be able to add a completion callback #if THREADSAFE_UOBJECTS FScopeLock LoadedLock(&LoadedPackagesToProcessCritical); #endif Package = FindExistingPackageAndAddCompletionCallback(InRequest, LoadedPackagesToProcessNameLookup, FlushTree); }
if (!Package) { // New package that needs to be loaded or a package has already been loaded long time ago { // GC can't run in here FGCScopeGuard GCGuard; Package = newFAsyncPackage(*this, *InRequest, EDLBootNotificationManager); } if (InRequest->PackageLoadedDelegate.IsValid()) { constbool bInternalCallback = false; Package->AddCompletionCallback(MoveTemp(InRequest->PackageLoadedDelegate), bInternalCallback); } Package->SetDependencyRootPackage(InRootPackage); if (FlushTree) { Package->PopulateFlushTree(FlushTree); }
// Add to queue according to priority. InsertPackage(Package, false, EAsyncPackageInsertMode::InsertAfterMatchingPriorities);
// For all other cases this is handled in FindExistingPackageAndAddCompletionCallback const int32 QueuedPackagesCount = QueuedPackagesCounter.Decrement(); NotifyAsyncLoadingStateHasMaybeChanged(); check(QueuedPackagesCount >= 0); }
FName PackageFName(*InPackageName); #if WITH_IOSTORE_IN_EDITOR // Use the old loader if an uncooked package exists on disk constbool bDoesUncookedPackageExist = FPackageName::DoesPackageExist(InPackageName, nullptr, nullptr, true) && !DoesPackageExistInIoStore(FName(*InPackageName)); if (!bDoesUncookedPackageExist) #endif { if (FCoreDelegates::OnSyncLoadPackage.IsBound()) { FCoreDelegates::OnSyncLoadPackage.Broadcast(InName); }
classFLinkerTables { public: /** The list of FObjectImports found in the package */ TArray<FObjectImport> ImportMap; /** The list of FObjectExports found in the package */ TArray<FObjectExport> ExportMap; /** List of dependency lists for each export */ TArray<TArray<FPackageIndex> > DependsMap; /** List of packages that are soft referenced by this package */ TArray<FName> SoftPackageReferenceList; /** List of Searchable Names, by object containing them. Not in MultiMap to allow sorting, and sizes are usually small enough where TArray makes sense */ TMap<FPackageIndex, TArray<FName> > SearchableNamesMap;
/** * Ticks an in-flight linker and spends InTimeLimit seconds on creation. This is a soft time limit used * if bInUseTimeLimit is true. * * @param InTimeLimit Soft time limit to use if bInUseTimeLimit is true * @param bInUseTimeLimit Whether to use a (soft) timelimit * @param bInUseFullTimeLimit Whether to use the entire time limit, even if blocked on I/O * * @return true if linker has finished creation, false if it is still in flight */ FLinkerLoad::ELinkerStatus FLinkerLoad::Tick( float InTimeLimit, bool bInUseTimeLimit, bool bInUseFullTimeLimit, TMap<TPair<FName, FPackageIndex>, FPackageIndex>* ObjectNameWithOuterToExportMap) { ELinkerStatus Status = LINKER_Loaded;
if( bHasFinishedInitialization == false ) { // Store variables used by functions below. TickStartTime = FPlatformTime::Seconds(); bTimeLimitExceeded = false; bUseTimeLimit = bInUseTimeLimit; bUseFullTimeLimit = bInUseFullTimeLimit; TimeLimit = InTimeLimit;
do { bool bCanSerializePackageFileSummary = false; if (GEventDrivenLoaderEnabled) { check(Loader || bDynamicClassLinker); bCanSerializePackageFileSummary = true; } else { // Create loader, aka FArchive used for serialization and also precache the package file summary. // false is returned until any precaching is complete. SCOPED_LOADTIMER(LinkerLoad_CreateLoader); Status = CreateLoader(TFunction<void()>([]() {}));
// Serialize the package file summary and presize the various arrays (name, import & export map) if (bCanSerializePackageFileSummary) { SCOPED_LOADTIMER(LinkerLoad_SerializePackageFileSummary); Status = SerializePackageFileSummary(); }
// Serialize the name map and register the names. if( Status == LINKER_Loaded ) { SCOPED_LOADTIMER(LinkerLoad_SerializeNameMap); Status = SerializeNameMap(); }
// Serialize the gatherable text data map. if( Status == LINKER_Loaded ) { SCOPED_LOADTIMER(LinkerLoad_SerializeGatherableTextDataMap); Status = SerializeGatherableTextDataMap(); }
// Serialize the import map. if( Status == LINKER_Loaded ) { SCOPED_LOADTIMER(LinkerLoad_SerializeImportMap); Status = SerializeImportMap(); }
// Serialize the export map. if( Status == LINKER_Loaded ) { SCOPED_LOADTIMER(LinkerLoad_SerializeExportMap); Status = SerializeExportMap(); }
#if WITH_TEXT_ARCHIVE_SUPPORT // Reconstruct the import and export maps for text assets if (Status == LINKER_Loaded) { SCOPED_LOADTIMER(LinkerLoad_ReconstructImportAndExportMap); Status = ReconstructImportAndExportMap(); } #endif
// Fix up import map for backward compatible serialization. if( Status == LINKER_Loaded ) { SCOPED_LOADTIMER(LinkerLoad_FixupImportMap); Status = FixupImportMap(); }
// Populate the linker instancing context for instance loading if needed. if (Status == LINKER_Loaded) { SCOPED_LOADTIMER(LinkerLoad_PopulateInstancingContext); Status = PopulateInstancingContext(); }
// Fix up export map for object class conversion if( Status == LINKER_Loaded ) { SCOPED_LOADTIMER(LinkerLoad_FixupExportMap); Status = FixupExportMap(); }
// Serialize the dependency map. if( Status == LINKER_Loaded ) { SCOPED_LOADTIMER(LinkerLoad_SerializeDependsMap); Status = SerializeDependsMap(); }
// Hash exports. if( Status == LINKER_Loaded ) { SCOPED_LOADTIMER(LinkerLoad_CreateExportHash); Status = CreateExportHash(); }
// Find existing objects matching exports and associate them with this linker. if( Status == LINKER_Loaded ) { SCOPED_LOADTIMER(LinkerLoad_FindExistingExports); Status = FindExistingExports(); }
if (Status == LINKER_Loaded) { SCOPED_LOADTIMER(LinkerLoad_SerializePreloadDependencies); Status = SerializePreloadDependencies(); }
// Finalize creation process. if( Status == LINKER_Loaded ) { SCOPED_LOADTIMER(LinkerLoad_FinalizeCreation); Status = FinalizeCreation(ObjectNameWithOuterToExportMap); } } // Loop till we are done if no time limit is specified, or loop until the real time limit is up if we want to use full time while (Status == LINKER_TimedOut && (!bUseTimeLimit || (bUseFullTimeLimit && !IsTimeLimitExceeded(TEXT("Checking Full Timer")))) ); }
if (Status == LINKER_Failed) { LinkerRoot->LinkerLoad = nullptr; #if WITH_EDITOR
if(!GEventDrivenLoaderEnabled || !EVENT_DRIVEN_ASYNC_LOAD_ACTIVE_AT_RUNTIME) { // DynamicClass could be created without calling CreateImport. The imported objects will be required later when a CDO is created. if (UDynamicClass* DynamicClass = Cast<UDynamicClass>(LoadedObject)) { for (int32 ImportIndex = 0; ImportIndex < ImportMap.Num(); ++ImportIndex) { CreateImport(ImportIndex); } } }
if(!GEventDrivenLoaderEnabled || !EVENT_DRIVEN_ASYNC_LOAD_ACTIVE_AT_RUNTIME) { // DynamicClass could be created without calling CreateImport. The imported objects will be required later when a CDO is created. if (UDynamicClass* DynamicClass = Cast<UDynamicClass>(LoadedObject)) { for (int32 ImportIndex = 0; ImportIndex < ImportMap.Num(); ++ImportIndex) { CreateImport(ImportIndex); } } }
// Main pass to go through and fix-up any references pointing to data from the old package to point to data from the new package // todo: multi-thread this like FHotReloadModule::ReplaceReferencesToReconstructedCDOs? for (FThreadSafeObjectIterator ObjIter(UObject::StaticClass(), false, RF_NoFlags, EInternalObjectFlags::PendingKill); ObjIter; ++ObjIter) { UObject* PotentialReferencer = *ObjIter;
// Mutating the old versions of classes can result in us replacing the SuperStruct pointer, which results // in class layout change and subsequently crashes because instances will not match this new class layout: UClass* AsClass = Cast<UClass>(PotentialReferencer); if (!AsClass) { AsClass = PotentialReferencer->GetTypedOuter<UClass>(); }
PackageReloadInternal::FReplaceObjectReferencesArchive ReplaceRefsArchive(PotentialReferencer, OldObjectToNewData, ExistingPackages.Refs, NewPackages.Refs); PotentialReferencer->Serialize(ReplaceRefsArchive); // Deal with direct references during Serialization PotentialReferencer->GetClass()->CallAddReferencedObjects(PotentialReferencer, ReplaceRefsArchive); // Deal with indirect references via AddReferencedObjects }
因为看到 release 方法是把 RHI 资源放入删除队列中,并且 class FD3D11UniformBuffer : public FRHIUniformBuffer, class FRHIUniformBuffer : public FRHIResource 所以应该是有人调用了 FRHIUniformBuffer 的 Release()