当前位置: 首页 > article >正文

观察一个StaticMesh加载其对应DDC文件的流程

无用的前言

很久前我观察过DDC的一些代码了解了些浅显的知识。
最近我遇到个DDC相关的问题,于是将之前写的东西又复习了一遍。同时我也将记录下我最近研究这个问题时,一些重要的部分以作备忘。

目标

观察一个StaticMesh加载其对应DDC文件的流程,记录其中的一些要点。

(注意:此处引擎版本是4.26,UE5里DDC相关代码已有较大调整)

0. 代码入手处

DDC接口的GetSynchronousGetAsynchronous函数是获得DDC数据的统一接口,断点在这里一定能触发到。

不过,我现在只想观察一个特定StaticMesh的DDC,那么如果我一开始就将断点打在GetSynchronousGetAsynchronous内部,则会断到很多其他资源。
所以,我选择首先将断点打在StaticMesh调用DDC接口的地方,然后,双击加载一个我想观察的StaticMesh资源比如这个:
在这里插入图片描述
然后断点就能触发:(可以通过Owner的值确认下触发的StaticMesh资源是自己想要观察的那个)
在这里插入图片描述
现在,即是这个StaticMesh准备获取DDC数据的时刻。

随后,再在 GetSynchronous 函数内部下断点来触发:(可以通过CacheKey值确认是这个资源)
在这里插入图片描述

这里调用的函数是 GetSynchronous,即同步的方式,所以接下来会立即执行这个任务(而不是放在另一个线程中执行)。

GetSynchronous函数核心是创建一个 FAsyncTask<FBuildAsyncWorker> 来执行任务。

1. FBuildAsyncWorker

FAsyncTask安排了一个可异步执行的任务(也可同步执行),其基础用法可见上一篇。
而任务的具体内容则由FBuildAsyncWorker定义,它本身有些成员变量,可以参考下注释对他们的解释:

/** true in the case of a cache hit, otherwise the result of the deriver build call **/
bool							bSuccess;
/** true if we should record the timing **/
bool							bSynchronousForStats;
/** true if we had to build the data */
bool							bDataWasBuilt;
/** Data dervier we are operating on **/
FDerivedDataPluginInterface*	DataDeriver;
/** Cache key associated with this build **/
FString							CacheKey;
/** Data to return to caller, later **/
TArray<uint8>					Data;

而执行的逻辑,则在 DoWork()函数中,其中最重要的是通过FDerivedDataBackend获得DDC数据。

  • 如果成功则局部变量bGetResult会记为真,那么FBuildAsyncWorker本身的成员bSuccess会变为真,且成员Data也是有值的。
  • 如果失败,那么bSuccess为假,Data也是空的。

在这里插入图片描述
这样,当任务结束后,就可以通过FBuildAsyncWorker本身的成员变量bSuccessData的值,来明白DDC是否获取成功和DDC数据是什么。

接下来,需要看FDerivedDataBackend::Get().GetRoot().GetCachedData

2. 众多的 DerivedDataBackend?

正如 《观察DerivedDataBackendInterface各个子类的关系》 所看到,DerivedDataBackend 由多个子类,且之间并非并列,而是嵌套的关系。

所以,尽管这里作为 Root 的 DerivedDataBackend 是 DerivedDataLimitKeyLengthWrapper:
在这里插入图片描述
但随后它又会调用其他的 DerivedDataBackend 来尝试获得DDC数据。

UE设计成这样众多Backend的结构肯定是有理由的,不过我还没理解清楚,所以不做讨论。

但有一点可以肯定:如果最终通过文件获得DDC数据,则一定是通过FFileSystemDerivedDataBackend

3. 在FFileSystemDerivedDataBackend::GetCachedData 下断点可以获得对应文件的路径

随后,在 FFileSystemDerivedDataBackend::GetCachedData 下断点,可以通过Filename的值知道对应的DDC文件路径:
在这里插入图片描述
可以直接在磁盘上找到这个文件:
在这里插入图片描述

4*. 缓存缺失重新构建的情况

也可以在之后手动删除这个文件,来模拟DDC文件没有找到的情况。
此时可以看到FBuildAsyncWorkerDoWork()会走到这里,结束后bSuccess为假,Data也是空的。
在这里插入图片描述
GetSynchronous由于返回的是PendingTask.GetTask().bSuccess,所以返回的是假。

那么StaticMesh调用后就会走向另一个分支
在这里插入图片描述

随后,DDC的数据会被重建。

最后,在GetDerivedDataCacheRef().Put调用后:
在这里插入图片描述

DDC文件会被重新保存(由于这次调用应该是异步的,所以这个函数返回后不会立即看到文件的产生)

总结

  1. StaticMesh 调用DDC的通用接口GetSynchronous获得DDC数据
  2. GetSynchronous内部创建一个 FAsyncTask<FBuildAsyncWorker> 来执行任务。
  3. FBuildAsyncWorkerDoWork() 是其核心,可以看到它通过DerivedDataBackend获得DDC数据。
  4. 众多的 DerivedDataBackend 相互连接,定义了找DDC数据的逻辑。
  5. 可在FFileSystemDerivedDataBackend::GetCachedData下断点知道资源加载的DDC文件路径。

小记最近的问题

最近遇到的问题从堆栈上看是,StaticMesh加载的DDC数据中一个数组的元素大小不匹配现在的定义。一般来说,DDC的问题首先要尝试的肯定是清除一遍DDC让它重新生成一遍。但是我(自以为)清除了之后,还是同样的错误。

最后,通过找到那个StaticMesh对应的DDC文件的具体路径才发现——其获得数据的文件并没有清除,而是一个共享的位置,不在本地。而且这个位置是很久前已经弃用的,之所以找到这个位置是因为之前配置了一个环境变量。


http://www.kler.cn/a/37786.html

相关文章:

  • 【2023 年第二届钉钉杯大学生大数据挑战赛初赛】 初赛 A:智能手机用户监测数据分析 问题一Python代码分析
  • HMLT学习笔记
  • 尚硅谷Docker实战教程-笔记06【Docker容器数据卷】
  • Spring Boot 操作 Redis 的各种实现
  • Linux 动态主机配置协议 DHCP
  • 高并发的哲学原理(二)-- Apache 的性能瓶颈与 Nginx 的性能优势
  • 37、Spring框架中都用到了哪些设计模式
  • Matplotlib---3D图
  • Docker安装Rabbitmq超详细教程
  • AI 对抗超级细菌:麦克马斯特大学利用深度学习发现新型抗生素 abaucin
  • 复习第七课 C语言-指针数组,函数,string
  • Kubernetes 集群管理和编排
  • Java之SpringCloud Alibaba【三】【微服务Nacos-config配置中心】
  • ELK之logstash四大组件
  • 第二周周报
  • Redis+IDEA极速了解和实现单机锁和分布式锁
  • 机器学习与深度学习——自定义函数进行线性回归模型
  • Android Glide预加载preload ,kotlin
  • 低代码在边缘计算工业软件中的应用
  • windows下mingw 编译boost-1.78.0