2.9 KiB
2.9 KiB
OpenGLFence
命名空间: XCEngine::RHI
类型: class
头文件: XCEngine/RHI/OpenGL/OpenGLFence.h
描述: OpenGL 后端的同步对象封装,使用单个 GLsync 和两份 CPU 侧原子计数,近似实现 RHIFence 的 timeline 风格接口。
概览
OpenGL 原生提供的是一次性的 GLsync 栅栏,而不是 D3D12/Vulkan 那种严格单调、可长期复用的 timeline fence。OpenGLFence 的实现思路是:
- GPU 侧只保留一个当前有效的
GLsync - CPU 侧记录“最近一次 signal 的值”
- 再记录“最近一次确认完成的值”
这样做可以让跨后端 RHI 保持统一的 Signal(value) / Wait(value) / GetCompletedValue() 接口形状,但底层语义仍然是 OpenGL 风格的单栅栏模型。
当前实现的真实行为
- 同一时间只维护一个
GLsync - Initialize 只设置计数值,不创建同步对象
- Signal 新值时,如果旧
GLsync还在,会先等待并删除旧栅栏 Signal(value)会先glFlush(),再插入新的glFenceSync- Wait 成功等待后,会把
m_completedValue直接写成当前m_signaledValue - GetCompletedValue 只做轮询,不会在查询时清理同步对象
- GetNativeHandle 是懒创建接口,本身可能新增一段栅栏
Signal()的无参重载并不是“递增 1”,而是固定转发为Signal(1)
设计背景
商业级引擎在 OpenGL 后端里,通常都会做这类“接口现代化,底层实现务实化”的适配。原因很简单:
- 上层系统希望用统一的 fence API 驱动命令队列、截图、测试和提交流程
- OpenGL 没有真正的 timeline fence,可选方案本来就有限
- 单个
GLsync包装器已经足够覆盖当前引擎里最常见的“提交后等待完成”需求
换句话说,当前类的目标不是完美模拟显式 API,而是把 OpenGL 的同步原语整理成对引擎友好的形式。
生命周期
- OpenGLFence() 初始化为空状态
- Initialize 设置起始计数
- Signal 插入新的 GPU 栅栏并记录 signal 值
- Wait 在 CPU 侧等待当前栅栏完成
- Shutdown 删除同步对象并清零计数
重要限制
- 不是严格意义上的 timeline fence
- 不保证值单调递增
- 不保留多段 in-flight 历史,只关注“当前这一个 sync”
GetNativeHandle()有副作用- 通过
OpenGLDevice::CreateFence(...)创建时,initialValue > 0会被折叠成1