找回密码
 立即注册
查看: 311|回复: 0

Unreal 资源加载和卸载道理机制源码分解

[复制链接]
发表于 2023-6-20 09:09 | 显示全部楼层 |阅读模式
首发地址:Unreal 资源加载和卸载道理机制源码分解

概要


  • Unreal 主要基于 FStreamableManager 、FAsyncLoadingThread(按需也可为 FAsyncLoadingThread2)、 FLinkerLoad 等进行资源的异步加载。
  • 资源加载主要基于Package来进行,一个Package中包含多种类型的数据信息,Package的加载完成前提是这些资源全部加载完毕。加载完毕还涉及到此中各类型资源的类型构造、属性等的反序列化设置以及依赖资源的加载。全部完成后Package才算加载完毕。
说明


  • 本文基于 UE4.27.2 默认设置及 非 EDL 和 非 WITH_ASYNCLOADING2 总结而来,请按照实际引擎版本、源码及项目实际设置等来阅读理解。
  • WITH_ASYNCLOADING2 宏的启用法则

    • #define WITH_ASYNCLOADING2 (WITH_IOSTORE_IN_EDITOR || !WITH_EDITORONLY_DATA)

  • 关于 GEventDrivenLoaderEnabled 下的异同

    • 不异之处

      • 加载的触发、初始化、回调及反序列化等基本一致。
      • 加载的核心法式细节基本一致,如 FLinkerLoad 的各种具体操作。

    • 主要区别

      • 在 FAsyncLoadingThread::ProcessAsyncLoading 中不是逐个Package的法式进行判断和措置,而是主要基于 FAsyncLoadEventQueue 对 EventQueue 进行 PopAndExecute 来触发各法式(如 QueueEvent_FinishLinker 等,其又是对 FinishLinker 的调用)







流程

加载

流程图

简化版(以文字概述主要流程)





详细版(带关键调用函数)





说明


  • UE中的加载接口有多个,本文基于 UAsyncActionLoadPrimaryAsset::AsyncLoadPrimaryAsset 来触发资源的加载,底层基于 FStreamableManager::RequestAsyncLoad 。此为主流异步加载方式。
  • 加载时会先从内存中找对应的资源是否已加载(FStreamableManager::FindInMemory),如果找到则返回,没有才需要加载。
  • 加载前先初始化,把加载通过 AddPendingRequest 插手 PendingRequests 队列。基于加载路径等信息创建 FAsyncPackageDesc2 ,插手 QueuedPackages 。
  • 加载时,通过 ProcessAsyncLoading 执行加载。其会调用 GPackageLoader 的 ProcessLoading (在 AsyncPackageLoader.cpp 的 InitAsyncThread 的时候,按照 WITH_ASYNCLOADING2 来决定 GPackageLoader 是 FAsyncLoadingThread 还是 FAsyncLoadingThread2)。
  • 加载涉及的关键方式有:FAsyncLoadingThread::ProcessAsyncLoading 、FAsyncPackage::TickAsyncPackage 以及 FLinkerLoad::Tick 等。 此中 FAsyncPackage::TickAsyncPackage 主要负责Package的加载流程,FLinkerLoad::Tick 则负责资源的类型获取及反序列化等。
  • 加载tick开始是,先把已经加载完毕的措置了,执行回调(FAsyncLoadingThread::ProcessLoadedPackages)。
  • 从 QueuedPackages 中获取和筹备要加载的资源包,对他们执行 FAsyncPackage::TickAsyncPackage 。
  • 资源加载主要基于 FLinkerLoad ,其在加载开始时会基于方针资源路径进行创建(FLinkerLoad::CreateLoader)。
  • FLinkerLoad 创建后,执行反序列化,尤为重要的是 ImportMap 和 ExportMap 等的反序列化。
  • 在 FLinkerLoad::Tick 中,基于 Linker 的 ExportMap 循环创建 FObjectExport。
  • 通过反射等机制调用 StaticConstructObject_Internal 等,以及借助 FLinkerLoad::IndexToObject 等从反射出的数据中拿到资源对应的基础类型。
  • 对基础资源类型进行 FLinkerLoad::Preload ,主要做反序列化,给属性赋值等。
  • 资源加载完毕后,加到已加载队列(FUObjectSerializeContext::AddLoadedObject)
  • Package 加载完毕后,加到已加载Package队列(PackageObjLoaded.Add(Object)),注意:一个Package可能包罗很多子资源。
  • 全部Package都加载完毕后,执行加载完毕的回调(FAsyncPackage::CallCompletionCallbacks)
卸载


  • 此处基于 UAssetManager::UnloadPrimaryAssets 进行资源的卸载的简单说明。
  • UAssetManager::UnloadPrimaryAssets 的感化:卸载先前已加载的主要资产列表。如果将这些资产保留在内存中的独一方式是之前的加载调用,则它们将被释放。
  • UnloadPrimaryAssets 其主要对方针资源列表中的资源的 CurrentState 和 PendingState 执行 FPrimaryAssetLoadState::Reset 。




  • FPrimaryAssetLoadState::Reset 中主要是对 Handle(FStreamableHandle)执行 CancelHandle




  • FStreamableHandle::CancelHandle :如果加载完毕的资源还没 release,则执行 ReleaseHandle ;执行 canceldelegate ;解绑所有回调;把本身从引用中移除;从子handle中移除本身。




关键类

类图





说明


  • UAssetManager

    • 负责加载和卸载主要资产并维护游戏特定资产引用的单例对象,可覆盖以做项目自定义。

  • FStreamableManager

    • 用于打点流式资产并将其保留在内存中的本机类。 AssetManager 是本类的具有蓝图访谒权限的全局单例版本

  • FStreamable

    • 内部对象,存储有Object的引用、加载中及激活中的句柄。

  • FStreamableHandle

    • 同步或异步加载的句柄。 只要句柄处于活动状态,加载的资产就会保留在内存中。内有优先级、请求的资源列表、各种回调等。

  • FAsyncPackage

    • 包含异步加载 FLinkerLoad 的所有导入和导出所需的中间数据的布局。TickAsyncPackage 是 Package 的异步加载的关键函数。

  • FAsyncLoadingThread

    • 异步加载线程。 在异步加载线程上预加载/序列化包。 在游戏线程上 Postloads 对象。存储和更新加载中的以及完毕的资源和包列表等。

  • FLinkerLoad

    • 措置加载虚幻包文件,包罗从磁盘读取和反序列化 UObject 数据。祖父类 FLinkerTables 中存储了从文件中反序列化而来的 ImportMap 、 ExportMap 、 DependsMap 等数据,这些是获取和创建类的关键。

  • FArchive

    • 序列化和反序列化的关键类,详见文末“Unreal 序列化和反序列化道理机制源码解析”,此处主要存眷加载卸载,不合错误此进行赘述。

相关链接

Unreal 序列化和反序列化道理机制源码解析

声明:本文来自公众号:Unity 与Unreal 游戏开发(GameDevLearning),转载请附上原文链接及本声明。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-4-27 17:54 , Processed in 0.352898 second(s), 27 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表