修复碎片模型卸载的在飞 GPU 引用(vkDestroyBuffer in-use):门面批量卸载先 WaitDeviceIdle 再销毁(与 ReloadMaterialAsset 同一先例)
This commit is contained in:
@@ -259,19 +259,20 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 墙销毁(PIE stop 换血 / 手动删除):碎片实体由场景清亡处理,
|
// 墙销毁(PIE stop 换血 / 手动删除):碎片实体由场景清亡处理,
|
||||||
// 独占碎片模型全部回收(模型不被快照恢复的场景引用——唯一代键)
|
// 独占碎片模型统一批量回收(模型不被快照恢复的场景引用——
|
||||||
|
// 唯一代键;批量接口内部 GPU 停飞后再销毁)
|
||||||
void OnDestroy() override {
|
void OnDestroy() override {
|
||||||
auto& assets = App().GetAssets();
|
std::vector<std::string> paths;
|
||||||
|
paths.reserve(m_Fragments.size() + m_PendingUnload.size());
|
||||||
for (const Fragment& f : m_Fragments) {
|
for (const Fragment& f : m_Fragments) {
|
||||||
if (!f.modelPath.empty()) {
|
if (!f.modelPath.empty()) paths.push_back(f.modelPath);
|
||||||
assets.UnloadModelByPath(f.modelPath);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
m_Fragments.clear();
|
m_Fragments.clear();
|
||||||
for (const std::string& p : m_PendingUnload) {
|
paths.insert(paths.end(),
|
||||||
assets.UnloadModelByPath(p);
|
std::make_move_iterator(m_PendingUnload.begin()),
|
||||||
}
|
std::make_move_iterator(m_PendingUnload.end()));
|
||||||
m_PendingUnload.clear();
|
m_PendingUnload.clear();
|
||||||
|
App().GetAssets().UnloadModelsByPaths(paths);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -449,13 +450,12 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- 模型回收:延迟一帧执行(Destroy 是帧尾延迟,碎片实体
|
// ---- 模型回收:延迟一帧 + 批量停飞卸载(Destroy 是帧尾延迟,
|
||||||
// 本帧渲染收集仍会引用模型;下一帧实体已灭,卸载才安全)----
|
// 碎片实体本帧渲染收集仍会引用模型;下一帧实体已灭,但上一帧
|
||||||
|
// 提交的命令缓冲仍可能引用顶点缓冲/sampler——批量接口先
|
||||||
|
// WaitDeviceIdle 再销毁,与资产重建换绑同一引擎先例)----
|
||||||
void ApplyPendingUnload() {
|
void ApplyPendingUnload() {
|
||||||
auto& assets = App().GetAssets();
|
App().GetAssets().UnloadModelsByPaths(m_PendingUnload);
|
||||||
for (const std::string& p : m_PendingUnload) {
|
|
||||||
assets.UnloadModelByPath(p);
|
|
||||||
}
|
|
||||||
m_PendingUnload.clear();
|
m_PendingUnload.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -182,11 +182,17 @@ namespace Engine
|
|||||||
ModelRef LoadModel(const std::string& path, ParsedModel&& parsed);
|
ModelRef LoadModel(const std::string& path, ParsedModel&& parsed);
|
||||||
Model* GetModel(ModelRef h) const { return m_Models.Get(h); }
|
Model* GetModel(ModelRef h) const { return m_Models.Get(h); }
|
||||||
void UnloadModel(ModelRef h) { m_Models.Unload(h); }
|
void UnloadModel(ModelRef h) { m_Models.Unload(h); }
|
||||||
// 按路径卸载模型(未加载为 no-op;手上只有路径的场景,
|
// 批量按路径卸载模型(未加载为 no-op)。先 GPU 全停飞再销毁
|
||||||
// 如脚本程序化碎片模型回收)
|
//(在飞命令缓冲可能仍引用顶点缓冲/默认纹理 sampler——
|
||||||
void UnloadModelByPath(const std::string& path)
|
// 与 ReloadMaterialAsset 的 WaitDeviceIdle 同一先例);一次
|
||||||
|
// 停飞摊薄整批,调用方攒批降频(脚本碎片回收每帧一批)
|
||||||
|
void UnloadModelsByPaths(const std::vector<std::string>& paths)
|
||||||
{
|
{
|
||||||
m_Models.UnloadByPath(path);
|
if (paths.empty()) return;
|
||||||
|
m_Uploader.WaitDeviceIdle();
|
||||||
|
for (const std::string& p : paths) {
|
||||||
|
m_Models.UnloadByPath(p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 按路径查已加载的模型(未加载返回 null,不触发加载)——
|
// 按路径查已加载的模型(未加载返回 null,不触发加载)——
|
||||||
// 面板 hover 信息卡用
|
// 面板 hover 信息卡用
|
||||||
|
|||||||
Reference in New Issue
Block a user