105 lines
3.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: FRenderCommandFence
date: 2025-06-25 23:11:25
excerpt:
tags:
rating: ⭐
---
在 Unreal Engine 5 (UE5) 中,`FRenderCommandFence` 是一个关键的**线程同步工具**,主要用于协调**游戏线程Game Thread** 和**渲染线程Render Thread** 之间的执行顺序。它的核心作用是确保渲染相关的操作(如资源创建、更新或销毁)在特定时间点前完成,避免多线程环境下的竞态条件。
---
### 核心作用
1. **跨线程同步**
- 游戏线程向渲染线程提交渲染命令后,这些命令不会立即执行(渲染线程有自己的任务队列)。
- `FRenderCommandFence` 允许游戏线程**阻塞等待**,直到所有已提交的渲染命令(包括栅栏之前的所有命令)在渲染线程中执行完毕。
2. **确保资源安全**
- 当游戏线程需要操作渲染资源(如纹理、网格)时,必须确保渲染线程不再使用这些资源(例如释放 `UTexture`)。
- 通过栅栏同步,可以安全地销毁或修改资源,避免访问无效内存。
---
### 关键方法
- **`BeginFence(bool bSyncToRHIAndGPU = false)`**
- 在渲染命令队列中插入一个“栅栏标记”,表示同步点。调用后游戏线程可以继续执行其他任务。
- `bSyncToRHIAndGPU` - 是否等待 RHI 线程或 GPU否则只等待渲染线程。
- **`Wait(bool bProcessGameThreadTasks = false)`**
- 阻塞游戏线程,直到渲染线程处理到栅栏位置(即执行完栅栏之前的所有渲染命令)。
- `bProcessGameThreadTasks`: 若为 `true`,等待期间允许游戏线程处理其他任务(如消息泵)。
- **`IsFenceComplete()`**
- 非阻塞检查栅栏是否已完成(渲染线程是否已越过栅栏点)。
---
### 典型使用场景
#### 1. 安全释放渲染资源
```c++
// 游戏线程代码
void ReleaseTexture(UTexture* Texture)
{
// 将资源释放命令提交到渲染线程
ENQUEUE_RENDER_COMMAND(ReleaseTextureCommand)(
[Texture](FRHICommandListImmediate& RHICmdList) {
Texture->ReleaseResource();
}
);
// 创建栅栏并等待释放完成
FRenderCommandFence Fence;
Fence.BeginFence();
Fence.Wait(); // 阻塞直到渲染线程执行完 ReleaseResource()
}
```
#### 2. 确保渲染操作完成后再继续
```c++
// 更新动态纹理后确保数据已提交到GPU
void UpdateDynamicTexture()
{
// 提交更新命令到渲染线程
ENQUEUE_RENDER_COMMAND(UpdateTexture)(
[...](...) { /* 更新纹理数据 */ }
);
FRenderCommandFence Fence;
Fence.BeginFence();
Fence.Wait(); // 等待纹理更新完成
// 此时可以安全读取纹理或进行后续操作
}
```
#### 3. 异步加载资源时同步
```c++
void LoadAssetAsync()
{
StreamableManager.RequestAsyncLoad(..., [this]()
{
// 资源加载完成后,确保渲染线程初始化完毕
FRenderCommandFence Fence;
Fence.BeginFence();
Fence.Wait(); // 等待渲染线程处理完资源初始化
OnAssetLoaded();
});
}
```
---
### 注意事项
1. **性能影响**
`Wait()` 会阻塞游戏线程,过度使用可能导致帧率下降。应仅在必要时同步(如资源卸载)。
2. **替代方案**
- 对于非紧急任务,可用 `AsyncTask` 或 `TaskGraph` 异步处理。
- 使用 `FGraphEvent` 实现无阻塞等待。
3. **与 `FlushRenderingCommands()` 的区别**
`FlushRenderingCommands()` 会强制**立即刷新**整个渲染命令队列(更重操作),而 `FRenderCommandFence` 只等待到特定同步点,更轻量可控。
---
### 总结
`FRenderCommandFence` 是 UE5 多线程架构中的**安全阀**,通过它开发者可以:
✅ 确保渲染操作在指定时间点前完成
✅ 安全操作渲染资源(创建/更新/销毁)
✅ 避免游戏线程与渲染线程的竞态条件