105 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			105 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| 
								 | 
							
								---
							 | 
						|||
| 
								 | 
							
								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 多线程架构中的**安全阀**,通过它开发者可以:  
							 | 
						|||
| 
								 | 
							
								✅ 确保渲染操作在指定时间点前完成  
							 | 
						|||
| 
								 | 
							
								✅ 安全操作渲染资源(创建/更新/销毁)  
							 | 
						|||
| 
								 | 
							
								✅ 避免游戏线程与渲染线程的竞态条件
							 |