Finalize library bootstrap status and stabilize async asset regressions
This commit is contained in:
692
docs/plan/Library启动预热与运行时异步加载混合重构计划_2026-04-04.md
Normal file
692
docs/plan/Library启动预热与运行时异步加载混合重构计划_2026-04-04.md
Normal file
@@ -0,0 +1,692 @@
|
||||
# Library启动预热与运行时异步加载混合重构计划
|
||||
|
||||
文档日期:2026-04-04
|
||||
|
||||
适用范围:当前仓库中的 `project` 单项目工作流。
|
||||
|
||||
文档目标:在现有 `Library` 资产导入与缓存系统基础上,继续收口为一套更接近 Unity 的正式方案,即“启动阶段前置索引与缓存有效性恢复,运行时按需异步加载资源 payload”,同时避免重新引入旧版本兼容、迁移工具、路径双写等过渡态实现。
|
||||
|
||||
---
|
||||
|
||||
## 1. 这轮重构要解决什么问题
|
||||
|
||||
当前 `Library` 模块已经完成了第一阶段收口,具备了以下能力:
|
||||
|
||||
- `Assets.meta` / `*.meta` / `AssetGUID`
|
||||
- `Library/SourceAssetDB`
|
||||
- `Library/ArtifactDB`
|
||||
- `Library/Artifacts`
|
||||
- `AssetImportService`
|
||||
- `ProjectAssetIndex`
|
||||
- `ResourceManager` 运行时缓存与异步调度
|
||||
- `AssetRef` 驱动的项目资产恢复
|
||||
- `mesh/material/texture` artifact 体系
|
||||
|
||||
但最近几轮实际使用已经暴露出两个非常关键的问题:
|
||||
|
||||
### 1.1 问题一:artifact 命中路径不够纯净
|
||||
|
||||
已经生成好的 artifact 路径,例如:
|
||||
|
||||
- `Library/Artifacts/.../main.xcmesh`
|
||||
- `Library/Artifacts/.../material_0.xcmat`
|
||||
- `Library/Artifacts/.../texture_0.xctex`
|
||||
|
||||
在某些运行时链路里被误当成源资源再次送回 `EnsureArtifact()`,导致:
|
||||
|
||||
- 报错 `Failed to build asset artifact: Library/Artifacts/...`
|
||||
- 资源恢复失败
|
||||
- 运行时重复做无意义工作
|
||||
- UI 上出现误导性的导入失败状态
|
||||
|
||||
这个问题已经定位并修复,但它说明当前系统在“源资源路径”和“artifact 路径”的边界定义上还不够硬。
|
||||
|
||||
### 1.2 问题二:缓存命中了,但热路径仍然很重
|
||||
|
||||
这是最近 “为什么打开带 obj 的 scene 还是会卡” 的根本原因。
|
||||
|
||||
当 `backpack.obj` 这类模型已经有 artifact 时,理论上应该走:
|
||||
|
||||
- 命中 `ArtifactDB`
|
||||
- 直接读取 `xcmesh/xcmat/xctex`
|
||||
- 异步恢复运行时对象
|
||||
|
||||
但实际上旧实现里在 `AreDependenciesCurrent()` 阶段还会对依赖文件反复做重成本校验:
|
||||
|
||||
- `backpack.mtl`
|
||||
- `diffuse.jpg`
|
||||
- `normal.png`
|
||||
- `specular.jpg`
|
||||
|
||||
尤其是对大贴图重复做 hash,会把“缓存命中”退化成“每次打开 scene 都重新扫描大资源”。
|
||||
|
||||
这也是为什么用户体感上会觉得:
|
||||
|
||||
- 明明已经有 `Library`
|
||||
- 明明已经不是第一次打开
|
||||
- 但打开带大模型的场景依然卡顿很明显
|
||||
|
||||
这个问题也已经定位并修复,当前改为缓存命中时只使用 `fileSize + writeTime` 快速校验,而不是每次重算依赖 hash。
|
||||
|
||||
### 1.3 问题三:当前系统仍偏“运行时按需补救”,缺少正式的启动前置阶段
|
||||
|
||||
目前系统已经比较偏向:
|
||||
|
||||
- 编辑器启动快
|
||||
- 打开 scene 时按需异步恢复 mesh/material/texture
|
||||
|
||||
这条路线本身没有问题,但如果不补一个正式的“项目启动预热阶段”,就会有几个副作用:
|
||||
|
||||
- 项目启动后第一次打开大场景,工作量全部堆在 scene open 时刻
|
||||
- 视口、Inspector、Picker 等编辑器系统更容易在首帧触发同步兜底
|
||||
- 用户对 `Library` 的感知会变成“有缓存但还是随机卡”
|
||||
- 问题定位难,因为启动阶段和运行时阶段职责混在一起
|
||||
|
||||
### 1.4 问题四:编辑器主线程仍存在同步兜底风险
|
||||
|
||||
虽然 deferred scene load 与异步恢复已经打通,但编辑器里仍有若干系统会在渲染或交互路径中触发:
|
||||
|
||||
- `GetMesh()`
|
||||
- `GetMaterial()`
|
||||
- 选择框、Gizmo、拾取、Inspector 读取资源状态
|
||||
|
||||
如果这些路径访问时机不对,仍然可能把本该后台完成的工作拉回主线程。
|
||||
|
||||
也就是说,现在系统已经不是“完全同步导入”,但还没完全达到“严格异步、主线程只消费结果”的成熟状态。
|
||||
|
||||
---
|
||||
|
||||
## 2. 这轮要采用的正式方向
|
||||
|
||||
这轮不走两个极端:
|
||||
|
||||
- 不走 Unity 式“把几乎所有成本都压到启动时”的纯前置模式
|
||||
- 也不走“什么都按需,启动几乎不做准备”的纯懒加载模式
|
||||
|
||||
正式目标是混合式方案:
|
||||
|
||||
### 2.1 启动阶段前置做什么
|
||||
|
||||
项目启动时只前置做轻量但必要的内容:
|
||||
|
||||
- 读取 `SourceAssetDB`
|
||||
- 读取 `ArtifactDB`
|
||||
- 建立 `GUID <-> path <-> AssetRef` 快照索引
|
||||
- 恢复 `ProjectAssetIndex`
|
||||
- 对项目资源做轻量级有效性校验
|
||||
- 检查 artifact 文件是否存在
|
||||
- 对最近使用场景或关键高频资源做 metadata 级预热
|
||||
|
||||
这些工作应该:
|
||||
|
||||
- 不解码大贴图
|
||||
- 不重建 mesh
|
||||
- 不恢复完整 material runtime object
|
||||
- 不做 GPU payload 上传
|
||||
|
||||
### 2.2 运行时按需异步做什么
|
||||
|
||||
真正重的 payload 继续按需异步进入:
|
||||
|
||||
- `xcmesh` -> runtime mesh
|
||||
- `xcmat` -> runtime material
|
||||
- `xctex` -> runtime texture
|
||||
- 贴图绑定的延迟解析与加载
|
||||
|
||||
也就是说:
|
||||
|
||||
- 启动阶段前置“状态”
|
||||
- 运行时异步加载“内容”
|
||||
|
||||
### 2.3 这套方案为什么更适合当前项目
|
||||
|
||||
因为当前项目的真实诉求是:
|
||||
|
||||
- 编辑器本身不要像 Unity 那样每次启动都等很久
|
||||
- 但打开带大模型的场景也不能把主窗口卡死
|
||||
- 同时 `Library` 要真的发挥缓存价值,而不是只在目录结构上看起来像 Unity
|
||||
|
||||
对这个目标来说,最佳平衡点就是:
|
||||
|
||||
- 启动时恢复索引和缓存状态
|
||||
- 打开 scene 时只反序列化结构
|
||||
- 重资源 payload 严格异步
|
||||
- cache hit 路径绝不重新做大计算
|
||||
|
||||
---
|
||||
|
||||
## 3. 本轮重构后的目标架构
|
||||
|
||||
### 3.1 模块职责划分
|
||||
|
||||
#### `AssetDatabase`
|
||||
|
||||
只作为底层数据库与导入实现细节:
|
||||
|
||||
- 源资源记录
|
||||
- artifact 记录
|
||||
- `.meta` 文件管理
|
||||
- importer 分派
|
||||
- artifact 构建
|
||||
- 依赖采集
|
||||
- 缓存有效性校验
|
||||
|
||||
不直接承担 editor 级工作流协调。
|
||||
|
||||
#### `AssetImportService`
|
||||
|
||||
作为项目级导入与缓存服务层:
|
||||
|
||||
- 项目根目录绑定
|
||||
- 启动阶段缓存恢复
|
||||
- 轻量校验
|
||||
- `EnsureArtifact`
|
||||
- `Refresh`
|
||||
- `ReimportAsset`
|
||||
- `ReimportAllAssets`
|
||||
- `ClearLibraryCache`
|
||||
- 启动预热状态输出
|
||||
|
||||
后续新增的“启动预热流程”也应放在这一层,而不是塞回 `ResourceManager`。
|
||||
|
||||
#### `ProjectAssetIndex`
|
||||
|
||||
只承担索引快照职责:
|
||||
|
||||
- `AssetRef -> project path`
|
||||
- `project path -> AssetRef`
|
||||
- 项目资源查找缓存
|
||||
- 场景反序列化后的快速路径恢复
|
||||
|
||||
不参与真正的 artifact 构建。
|
||||
|
||||
#### `ResourceManager`
|
||||
|
||||
只承担运行时加载与缓存职责:
|
||||
|
||||
- runtime object cache
|
||||
- async queue
|
||||
- in-flight coalescing
|
||||
- 源资源与 artifact 路径路由
|
||||
- deferred scene load 期间的异步恢复入口
|
||||
|
||||
明确禁止它重新承担“项目导入管理器”角色。
|
||||
|
||||
### 3.2 正式的三段式生命周期
|
||||
|
||||
#### 阶段 A:Project Startup Bootstrap
|
||||
|
||||
项目打开时:
|
||||
|
||||
- 恢复 `Library` 数据库
|
||||
- 建索引
|
||||
- 快速验证缓存状态
|
||||
- 后台预热 metadata
|
||||
|
||||
不恢复大资源 payload。
|
||||
|
||||
#### 阶段 B:Scene Structural Load
|
||||
|
||||
打开 scene 时:
|
||||
|
||||
- 只做场景结构反序列化
|
||||
- 组件恢复 `AssetRef` 和资源路径 hint
|
||||
- 不在主线程同步恢复大 mesh/material/texture
|
||||
|
||||
#### 阶段 C:Runtime Payload Stream-In
|
||||
|
||||
场景打开后:
|
||||
|
||||
- 按需异步拉取 `xcmesh`
|
||||
- 再按需恢复 `xcmat`
|
||||
- 贴图绑定继续 lazy resolve / lazy load
|
||||
- 视口只消费当前已完成资源
|
||||
|
||||
---
|
||||
|
||||
## 4. 当前已完成内容与后续计划分界
|
||||
|
||||
## 4.1 已完成
|
||||
|
||||
以下内容已经可以视为本轮新方案的基础,不需要推倒重来:
|
||||
|
||||
- `Library` 目录结构已落地
|
||||
- `SourceAssetDB` / `ArtifactDB` 已落地
|
||||
- `.meta + AssetGUID` 已稳定
|
||||
- `AssetRef` 驱动的 scene/component 恢复已落地
|
||||
- `MeshFilterComponent` / `MeshRendererComponent` deferred async restore 已打通
|
||||
- `ProjectPanel` 已有最小 import status 输出
|
||||
- orphan artifact 清理已接入
|
||||
- artifact 路径误进 `EnsureArtifact()` 的问题已修
|
||||
- cache hit 时重复 hash 大依赖导致卡顿的问题已修
|
||||
- `AssetImportService::BootstrapProject()` 已落地,项目启动存在正式 bootstrap 生命周期
|
||||
- `ResourceManager::SetResourceRoot()` 已切到显式 bootstrap 路径,不再依赖首次资源查询时的隐式补救
|
||||
- `AssetDatabase::Initialize()` 已改为只恢复 DB 状态,不再在绑定项目根目录时隐式全量扫描
|
||||
- `ClearLibraryCache()` 已在清空后立即重建 source lookup,避免清库后留下半残状态
|
||||
- `ResourceHandle` 已改为持有稳定 `ResourceGUID`,`UnloadAll/Shutdown` 后不再因为悬空指针在析构期崩溃
|
||||
- `ResourceManager` 的 `Unload/UnloadAll/UnloadGroup` 已同步清理 `ResourceCache` 陈旧条目
|
||||
- `Material` 析构顺序问题已修,OBJ source-import 与 mesh artifact reimport 链路不再触发 debug heap 崩溃
|
||||
- `mesh/material/scene/components` 关键回归已重新验证通过
|
||||
|
||||
## 4.2 本轮仍然需要正式收口的内容
|
||||
|
||||
本轮重点不再是“把 `Library` 做出来”,而是把下面这些未完成项正式落地:
|
||||
|
||||
- 正式的启动阶段 bootstrap
|
||||
- 启动阶段的 metadata 预热策略
|
||||
- 项目打开后、scene 首次打开前的轻量准备
|
||||
- editor 主线程同步兜底点审计
|
||||
- 视口 / Inspector / Picker 对未加载资源的正式占位策略
|
||||
- `AssetImportService` 层级的启动状态与进度模型
|
||||
- 更清晰的“正在预热 / 正在导入 / 正在异步恢复”的 UI 区分
|
||||
|
||||
---
|
||||
|
||||
## 5. 详细实施阶段
|
||||
|
||||
## 阶段 0:基线固化与指标采样
|
||||
|
||||
### 目标
|
||||
|
||||
先把当前性能问题量化,避免后续优化没有参照系。
|
||||
|
||||
### 任务
|
||||
|
||||
- 为以下阶段分别记录耗时:
|
||||
- 项目启动到 editor 可交互
|
||||
- 打开 `Backpack.xc` 到 scene graph 可见
|
||||
- 打开 `Backpack.xc` 到 mesh 可见
|
||||
- 打开 `Backpack.xc` 到首帧可渲染
|
||||
- 记录 `AssetImportService` 各操作状态:
|
||||
- `Bootstrap`
|
||||
- `Refresh`
|
||||
- `Import Asset`
|
||||
- `Reimport`
|
||||
- 记录 `ResourceManager` 各类异步请求计数:
|
||||
- mesh
|
||||
- material
|
||||
- texture
|
||||
- 对 `backpack.obj` 链路增加 focused trace 开关
|
||||
|
||||
### 交付物
|
||||
|
||||
- 明确的启动时长基线
|
||||
- 明确的 scene 打开耗时基线
|
||||
- 一组稳定可复现的回归测试与日志样本
|
||||
|
||||
### 完成标准
|
||||
|
||||
- 以后任何优化都可以明确比较 “优化前 vs 优化后”
|
||||
|
||||
---
|
||||
|
||||
## 阶段 1:启动阶段 Bootstrap 正式化
|
||||
|
||||
### 目标
|
||||
|
||||
把当前隐式分散在多个点的项目初始化流程,收成一个正式的启动阶段。
|
||||
|
||||
### 要做的事
|
||||
|
||||
- 在 `AssetImportService` 中新增明确的启动流程,例如:
|
||||
- `BeginProjectBootstrap()`
|
||||
- `RunProjectBootstrap()`
|
||||
- `GetBootstrapStatus()`
|
||||
- 启动阶段同步完成:
|
||||
- 绑定项目根目录
|
||||
- 读取 `SourceAssetDB`
|
||||
- 读取 `ArtifactDB`
|
||||
- 构建 `LookupSnapshot`
|
||||
- 恢复 `ProjectAssetIndex`
|
||||
- 快速检查 artifact 文件存在性
|
||||
- 启动阶段禁止:
|
||||
- 解码纹理
|
||||
- 读取 `.obj` 顶点数据
|
||||
- 恢复完整 material runtime object
|
||||
- 重算所有依赖 hash
|
||||
|
||||
### 推荐实现细节
|
||||
|
||||
- `SetProjectRoot()` 只负责绑定项目,不隐式做重活
|
||||
- 显式 bootstrap 负责状态恢复
|
||||
- `ResourceManager::SetResourceRoot()` 完成后应当触发一次 bootstrap,而不是等首次 `LoadResource()` 时再补救
|
||||
- `ProjectAssetIndex::RefreshFrom(...)` 要明确依赖 bootstrap 产出的快照,而不是在运行时随机 fallback
|
||||
|
||||
### 结果要求
|
||||
|
||||
- 项目启动后,`AssetRef` 和项目资源索引已经可用
|
||||
- 打开 scene 时不需要再顺便补建整套索引
|
||||
|
||||
---
|
||||
|
||||
## 阶段 2:缓存命中路径彻底轻量化
|
||||
|
||||
### 目标
|
||||
|
||||
保证 “有 artifact 且未变化” 真正意味着快。
|
||||
|
||||
### 要做的事
|
||||
|
||||
- 固化当前已经完成的两个修复:
|
||||
- artifact 路径直载,不再送回 `EnsureArtifact`
|
||||
- cache hit 时依赖校验只走 `fileSize + writeTime`
|
||||
- 继续补强边界判定:
|
||||
- `builtin://...`
|
||||
- `Library/Artifacts/...`
|
||||
- `.xcmesh/.xcmat/.xctex/.xcshader`
|
||||
- `Assets/...`
|
||||
- 项目外绝对路径
|
||||
- 只允许明确的源资源路径触发导入
|
||||
- cache hit 时不允许再发生:
|
||||
- 重扫依赖目录
|
||||
- 重解析 `obj/mtl`
|
||||
- 重算大贴图 hash
|
||||
|
||||
### 推荐实现细节
|
||||
|
||||
- 在 `ResourceManager` 中形成统一 helper:
|
||||
- `ShouldUseProjectArtifactImport(path, type)`
|
||||
- 在 `AssetDatabase` 中形成统一 helper:
|
||||
- `IsFastCacheValidationEligible(...)`
|
||||
- 深度 hash 改为仅在这些场景触发:
|
||||
- 显式 Reimport
|
||||
- 怀疑 DB 损坏
|
||||
- 调试模式人工开启深校验
|
||||
|
||||
### 结果要求
|
||||
|
||||
- 二次打开 `Backpack.xc` 这类场景时,命中链路不应再接近首次导入成本
|
||||
|
||||
---
|
||||
|
||||
## 阶段 3:Scene Open 零阻塞主路径收口
|
||||
|
||||
### 目标
|
||||
|
||||
打开 scene 时只恢复结构,不同步等 payload。
|
||||
|
||||
### 要做的事
|
||||
|
||||
- 审计 scene load 首帧中所有可能触发同步资源恢复的位置:
|
||||
- `MeshFilterComponent::GetMesh()`
|
||||
- `MeshRendererComponent::GetMaterial()`
|
||||
- render item 构建
|
||||
- scene picker
|
||||
- gizmo frame builder
|
||||
- inspector 材质预览
|
||||
- 禁止在 scene 刚打开时,视口渲染链路用同步 `Load<T>()` 兜底
|
||||
- 对未完成的资源加载使用正式占位策略:
|
||||
- mesh 未到位:跳过 render item 或显示加载占位
|
||||
- material 未到位:使用稳定 fallback material
|
||||
- texture 未到位:保持材质对象,但贴图槽位为空
|
||||
|
||||
### 推荐实现细节
|
||||
|
||||
- `GetMesh()` / `GetMaterial()` 保持“只触发异步请求,不阻塞等待”
|
||||
- 场景渲染代码消费的是“当前已完成状态”,而不是强行等待最终状态
|
||||
- `Loading scene assets...` 应仅表示后台恢复中,不应意味着主线程仍被卡住
|
||||
|
||||
### 结果要求
|
||||
|
||||
- 打开大场景时主窗口保持可交互
|
||||
- 首帧允许缺资源,但不能卡死
|
||||
- 资源陆续完成后画面逐步完善
|
||||
|
||||
---
|
||||
|
||||
## 阶段 4:启动预热策略
|
||||
|
||||
### 目标
|
||||
|
||||
在不走 Unity 全量前置的前提下,把最常用项目数据提前准备好。
|
||||
|
||||
### 候选预热内容
|
||||
|
||||
- 最近一次打开的 scene 列表
|
||||
- 当前项目默认 scene
|
||||
- 最近访问的材质/模型索引
|
||||
- `AssetRef -> path` 高频映射
|
||||
- scene 文件中出现过的主 mesh asset ref
|
||||
|
||||
### 预热分层
|
||||
|
||||
#### 同步预热
|
||||
|
||||
- 只预热索引和 metadata
|
||||
|
||||
#### 后台预热
|
||||
|
||||
- 检查对应 artifact 是否存在
|
||||
- 预先解析 scene 内引用的主资源清单
|
||||
- 但不真正构建 runtime payload
|
||||
|
||||
### 推荐实现细节
|
||||
|
||||
- 新增简单的 `Library/SessionCache` 或 `Library/BootstrapCache` 元数据文件
|
||||
- 记录最近场景和高频资源,不需要做复杂推荐系统
|
||||
- 预热任务进入专用后台队列,不占用用户交互关键线程
|
||||
|
||||
### 结果要求
|
||||
|
||||
- 项目打开后第一次打开最近场景更快
|
||||
- 不把全部项目资源都拉进启动成本
|
||||
|
||||
---
|
||||
|
||||
## 阶段 5:编辑器调用点清理
|
||||
|
||||
### 目标
|
||||
|
||||
把 editor 里所有“资源还没准备好时的坏行为”收掉。
|
||||
|
||||
### 要做的事
|
||||
|
||||
- 清理以下系统中的同步依赖:
|
||||
- `SceneViewportPicker`
|
||||
- `SceneViewportTransformGizmoFrameBuilder`
|
||||
- `RenderSceneUtility`
|
||||
- `InspectorPanel`
|
||||
- 材质/mesh 相关组件编辑器
|
||||
- 明确这些系统在资源未到位时的行为:
|
||||
- 不报错
|
||||
- 不触发重导入
|
||||
- 不锁主线程
|
||||
- 不污染 import status
|
||||
|
||||
### 推荐实现细节
|
||||
|
||||
- picker:未完成 mesh 时直接跳过,不同步等待
|
||||
- gizmo center:拿不到 mesh bounds 时退回 transform position
|
||||
- inspector:未完成材质时显示 loading / unresolved,而不是同步 `Load`
|
||||
- viewport:资源未到位时继续渲染其它可用对象
|
||||
|
||||
### 结果要求
|
||||
|
||||
- “打开 scene 不阻塞” 不仅存在于测试里,也存在于真实编辑器交互中
|
||||
|
||||
---
|
||||
|
||||
## 阶段 6:状态与观测模型正式化
|
||||
|
||||
### 目标
|
||||
|
||||
用户能看懂系统当前在干什么。
|
||||
|
||||
### 现状问题
|
||||
|
||||
现在 `ProjectPanel` 顶部已经有导入状态,但还不足以区分:
|
||||
|
||||
- 项目启动预热
|
||||
- 显式导入
|
||||
- 场景异步恢复
|
||||
- 运行时 payload stream-in
|
||||
|
||||
### 要做的事
|
||||
|
||||
- 将状态拆成至少三类:
|
||||
- `Bootstrap`
|
||||
- `Import/Reimport`
|
||||
- `Scene Asset Streaming`
|
||||
- UI 明确区分:
|
||||
- 正在恢复项目索引
|
||||
- 正在重建 artifact
|
||||
- 正在后台加载场景资源
|
||||
- 增加更清楚的 tooltip:
|
||||
- 当前目标路径
|
||||
- 剩余异步数量
|
||||
- 最近失败原因
|
||||
|
||||
### 推荐实现细节
|
||||
|
||||
- `AssetImportService::ImportStatusSnapshot` 扩展为更通用的 operation model
|
||||
- `ResourceManager` 增加 lightweight streaming status snapshot
|
||||
- `ProjectPanel` 与 viewport status text 分工:
|
||||
- `ProjectPanel` 展示项目级状态
|
||||
- viewport 展示当前 scene 级 streaming 状态
|
||||
|
||||
### 结果要求
|
||||
|
||||
- 用户不会再把“后台恢复中”和“导入失败”混淆
|
||||
|
||||
---
|
||||
|
||||
## 阶段 7:最终收口与归档
|
||||
|
||||
### 目标
|
||||
|
||||
把这套方案从“已经能用”收成“正式基线”。
|
||||
|
||||
### 要做的事
|
||||
|
||||
- 整理最终架构说明
|
||||
- 删除不再需要的临时日志和调试开关
|
||||
- 固化测试矩阵
|
||||
- 更新 README / Editor 架构文档中的 Library 模块说明
|
||||
- 将本计划归档到 `docs/plan/used`
|
||||
|
||||
### 完成标准
|
||||
|
||||
- `Library` 模块不再被视为过渡态系统
|
||||
- 项目启动与大场景打开的行为稳定、可解释、可回归
|
||||
|
||||
---
|
||||
|
||||
## 6. 需要修改或重点审查的代码范围
|
||||
|
||||
本轮预计主要涉及以下文件:
|
||||
|
||||
- `engine/src/Core/Asset/AssetDatabase.cpp`
|
||||
- `engine/include/XCEngine/Core/Asset/AssetDatabase.h`
|
||||
- `engine/src/Core/Asset/AssetImportService.cpp`
|
||||
- `engine/include/XCEngine/Core/Asset/AssetImportService.h`
|
||||
- `engine/src/Core/Asset/ProjectAssetIndex.cpp`
|
||||
- `engine/include/XCEngine/Core/Asset/ProjectAssetIndex.h`
|
||||
- `engine/src/Core/Asset/ResourceManager.cpp`
|
||||
- `engine/include/XCEngine/Core/Asset/ResourceManager.h`
|
||||
- `engine/src/Core/Asset/AsyncLoader.cpp`
|
||||
- `engine/src/Components/MeshFilterComponent.cpp`
|
||||
- `engine/src/Components/MeshRendererComponent.cpp`
|
||||
- `engine/src/Rendering/RenderSceneUtility.cpp`
|
||||
- `editor/src/Viewport/SceneViewportPicker.cpp`
|
||||
- `editor/src/Viewport/SceneViewportTransformGizmoFrameBuilder.h`
|
||||
- `editor/src/panels/InspectorPanel.cpp`
|
||||
- `editor/src/Viewport/ViewportHostService.h`
|
||||
- `editor/src/Managers/SceneManager.cpp`
|
||||
- `tests/Scene/test_scene.cpp`
|
||||
- `tests/Components/test_mesh_render_components.cpp`
|
||||
- `tests/Resources/Texture/test_texture_loader.cpp`
|
||||
- `tests/Core/Asset/test_resource_manager.cpp`
|
||||
|
||||
---
|
||||
|
||||
## 7. 验收标准
|
||||
|
||||
## 7.1 功能层
|
||||
|
||||
- 关闭 editor 再打开 `Backpack.xc` 时,模型 mesh/material/texture 能稳定恢复
|
||||
- 内置 primitive 不会因为缓存系统回归而丢失
|
||||
- 打开含 OBJ 的 scene 时,不再出现 artifact 路径误导入报错
|
||||
|
||||
## 7.2 性能层
|
||||
|
||||
- 项目启动时不会做完整 payload 导入
|
||||
- 打开 `Backpack.xc` 不会长时间阻塞主窗口
|
||||
- artifact 命中耗时显著低于首次导入
|
||||
- cache hit 路径不会再重复扫描大贴图 hash
|
||||
|
||||
## 7.3 架构层
|
||||
|
||||
- 启动阶段、scene open 阶段、runtime payload 阶段边界清晰
|
||||
- `AssetImportService`、`ProjectAssetIndex`、`ResourceManager` 职责边界清晰
|
||||
- editor 主线程不再承担重资源恢复职责
|
||||
|
||||
## 7.4 观测层
|
||||
|
||||
- 用户能区分 `Bootstrap`、`Import`、`Scene Streaming`
|
||||
- 失败原因可见
|
||||
- 后台工作数量可见
|
||||
|
||||
## 7.5 回归测试层
|
||||
|
||||
至少保住以下 focused 回归:
|
||||
|
||||
- `Scene_ProjectSample.AsyncLoadBackpackMeshArtifactCompletes`
|
||||
- `Scene_ProjectSample.DeferredLoadBackpackSceneEventuallyRestoresBackpackMesh`
|
||||
- `Scene_ProjectSample.DeferredLoadBackpackSceneEventuallyProducesVisibleRenderItems`
|
||||
- `MeshRendererComponent_Test.DeferredSceneDeserializeLoadsProjectMaterialAsync`
|
||||
- `TextureLoader.ResourceManagerLoadsLibraryArtifactTextureWithoutReimportingIt`
|
||||
- `ResourceManager_Test.ConcurrentAsyncLoadsCoalesceSameMeshPath`
|
||||
|
||||
---
|
||||
|
||||
## 8. 当前阶段完成情况
|
||||
|
||||
截至 2026-04-04 当前这一轮代码与测试状态,按这份新计划计:
|
||||
|
||||
| 阶段 | 状态 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| 阶段 0:基线固化 | 进行中 | focused test 已补强,但还缺项目启动耗时与 editor 实机场景打开指标归档 |
|
||||
| 阶段 1:启动阶段 Bootstrap 正式化 | 已完成 | `BootstrapProject()` / `BootstrapProjectAssets()` 已接入正式启动链路 |
|
||||
| 阶段 2:缓存命中路径轻量化 | 已完成 | artifact 直载、依赖快速校验、误重导入路径问题均已修复 |
|
||||
| 阶段 3:Scene Open 零阻塞主路径 | 已完成首轮 | backpack 场景异步恢复链路已稳定,scene open 不再因为 Library 命中路径本身阻塞主线程 |
|
||||
| 阶段 4:启动预热策略 | 未开始 | 还没有最近场景/高频资源 metadata 预热 |
|
||||
| 阶段 5:编辑器调用点清理 | 进行中 | 主要阻塞点已清掉,但 Inspector / Picker / viewport 仍需继续做系统化审计 |
|
||||
| 阶段 6:状态与观测模型 | 进行中 | 已有 bootstrap/import 状态基础,但还未正式区分 bootstrap / streaming / scene restore |
|
||||
| 阶段 7:最终收口与归档 | 未开始 | 等上述阶段完成后执行 |
|
||||
|
||||
补充说明:
|
||||
|
||||
- 本轮新增并通过的关键回归包括:
|
||||
- `AssetImportService_Test.BootstrapProjectBuildsLookupSnapshotAndReportsStatus`
|
||||
- `ResourceManager_Test.SetResourceRootBootstrapsProjectAssetCache`
|
||||
- `ResourceHandle.ResetDoesNotDereferenceDestroyedResourcePointer`
|
||||
- `MeshLoader.AssetDatabaseReimportsModelWhenDependencyChanges`
|
||||
- `MeshLoader.ResourceManagerLoadsModelByAssetRefFromProjectAssets`
|
||||
- 这意味着当前 `Library` 模块的主要风险已经从“缓存不生效/路径误判”转移为“剩余 editor 调用点审计、状态模型清晰化、预热策略补全”。
|
||||
|
||||
---
|
||||
|
||||
## 9. 推荐执行顺序
|
||||
|
||||
建议严格按下面顺序推进:
|
||||
|
||||
1. 先继续做阶段 5,把 editor 主线程剩余同步兜底点系统性扫完。
|
||||
2. 然后做阶段 4,把“最近场景 metadata 预热”补上。
|
||||
3. 接着做阶段 6,把状态模型和 UI 区分补完整。
|
||||
4. 再做阶段 0,把项目启动和大场景打开指标正式采样落档。
|
||||
5. 最后统一做阶段 7 收口归档。
|
||||
|
||||
原因很明确:
|
||||
|
||||
- 如果不先清主线程调用点,任何异步链路都可能再次被同步兜底破坏。
|
||||
- 如果不补预热策略,首次打开高频场景仍然会把轻量准备工作堆到打开时刻。
|
||||
- 如果不把状态模型做清楚,用户会继续把“后台恢复”误解成“又卡死了”。
|
||||
- 如果不把基线指标整理出来,后续收口就没有稳定对照。
|
||||
|
||||
---
|
||||
|
||||
## 10. 一句话结论
|
||||
|
||||
本轮不是继续“补 Library”,而是把现有 `Library` 系统正式提升为 Unity 式混合架构:
|
||||
|
||||
项目启动时前置恢复索引与缓存状态,运行时严格按需异步流入 mesh/material/texture payload,让缓存命中真正变快,同时保证打开大场景不再阻塞 editor 主线程。
|
||||
91
docs/plan/Library启动预热与运行时异步加载混合重构计划_进度更新_2026-04-04.md
Normal file
91
docs/plan/Library启动预热与运行时异步加载混合重构计划_进度更新_2026-04-04.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# Library 启动预热与运行时异步加载混合重构计划进度更新
|
||||
|
||||
文档日期:2026-04-04
|
||||
|
||||
对应主计划:
|
||||
- `docs/plan/Library启动预热与运行时异步加载混合重构计划_2026-04-04.md`
|
||||
|
||||
## 本轮已完成
|
||||
|
||||
- `mesh_tests` 全量 `34/34` 通过。
|
||||
- `scene_tests` 全量 `63/63` 通过。
|
||||
- `asset_tests` 全量 `55/55` 通过。
|
||||
- `texture_tests` 全量 `28/28` 通过。
|
||||
- `XCEditor` Debug 构建通过。
|
||||
|
||||
- `Main.xc` 轻量场景测试预期已和当前项目夹具同步:
|
||||
- 当前场景对象是 `Sphere`
|
||||
- 不再沿用旧的 `Cube` 预期
|
||||
|
||||
- `AssetImportService::ImportStatusSnapshot` 已增加:
|
||||
- `startedAtMs`
|
||||
- `completedAtMs`
|
||||
- `durationMs`
|
||||
|
||||
- `ProjectPanel` 的 Library 状态展示已增强:
|
||||
- 状态文案可显示耗时
|
||||
- tooltip 可区分 operation / state / duration / target / imported count / removed count
|
||||
|
||||
- 一个阻塞当前回归验证的无关编译问题已修复:
|
||||
- `engine/src/Resources/UI/UIDocumentLoaders.cpp`
|
||||
- 不再非法调用 `IResourceLoader::GetExtension()` 的 protected 接口
|
||||
|
||||
## 当前阶段判断
|
||||
|
||||
当前这条 Library 重构线已经达到下面这个阶段性状态:
|
||||
|
||||
- 启动阶段负责恢复索引和缓存状态
|
||||
- 运行时继续按需异步恢复 mesh / material / texture payload
|
||||
- 关键回归测试已经稳定通过
|
||||
- Editor 主程序可以正常构建
|
||||
|
||||
也就是说,前面最容易反复回退的两类问题已经清掉了:
|
||||
|
||||
- `Library` / artifact / `AssetRef` 主链路回归
|
||||
- scene fixture 漂移导致的假失败
|
||||
|
||||
## 相对主计划的完成情况
|
||||
|
||||
- 阶段 1:已完成
|
||||
- `BootstrapProject()` / `BootstrapProjectAssets()` 已正式接入启动链路
|
||||
|
||||
- 阶段 2:已完成
|
||||
- artifact 直载
|
||||
- cache hit 快速校验
|
||||
- 避免把 artifact 路径重新误送回导入链路
|
||||
|
||||
- 阶段 3:已完成首轮并稳定
|
||||
- scene open 不再因为 Library 命中路径本身阻塞主线程
|
||||
- backpack 场景异步恢复链路回归通过
|
||||
|
||||
- 阶段 5:推进中
|
||||
- 主要阻塞点已经清掉
|
||||
- 但 editor 里剩余同步兜底访问点仍需继续系统化审计
|
||||
|
||||
- 阶段 6:推进中
|
||||
- 现在已经有 bootstrap/import 状态
|
||||
- 但还需要继续区分 bootstrap / scene restore / runtime streaming
|
||||
|
||||
- 阶段 0 / 阶段 4 / 阶段 7:未收口
|
||||
- 启动与首帧指标基线还没正式固化
|
||||
- metadata 预热策略还没补完
|
||||
- 最终收口文档和归档还没做
|
||||
|
||||
## 下一步建议
|
||||
|
||||
下一阶段不要再回头重做 `Library` 主链路本身,重点应当转到“观测”和“收口”:
|
||||
|
||||
1. 固化启动基线与场景首帧指标
|
||||
2. 审计 editor 主线程剩余同步兜底点
|
||||
3. 给 viewport / inspector / picker 加上未完成异步资源的占位与状态提示
|
||||
4. 把“正在预热 / 正在导入 / 正在异步恢复”拆成更明确的 UI 状态
|
||||
|
||||
## 这一轮改动直接涉及的文件
|
||||
|
||||
- `engine/include/XCEngine/Core/Asset/AssetImportService.h`
|
||||
- `engine/src/Core/Asset/AssetImportService.cpp`
|
||||
- `editor/src/panels/ProjectPanel.cpp`
|
||||
- `tests/core/Asset/test_resource_manager.cpp`
|
||||
- `tests/Resources/Texture/test_texture_loader.cpp`
|
||||
- `tests/Scene/test_scene.cpp`
|
||||
- `engine/src/Resources/UI/UIDocumentLoaders.cpp`
|
||||
Reference in New Issue
Block a user