5.2 KiB
OpenGLDepthStencilView
命名空间: XCEngine::RHI
类型: class
头文件: XCEngine/RHI/OpenGL/OpenGLDepthStencilView.h
描述: OpenGL 后端的轻量级深度/模板视图封装,为单个纹理子资源创建并管理一个专用 framebuffer。
概览
在现代图形 API 里,深度视图通常表示“同一张纹理资源的某个可渲染子资源视角”。这样做的价值是把“资源怎么分配”和“本次渲染如何把它当作深度附件使用”拆开,渲染图、阴影图、反射探针等系统都可以围绕同一张底层纹理复用不同 view。
OpenGL 没有 D3D12/Vulkan 那种独立的 depth-stencil view 对象,所以当前实现采用了引擎里常见的一种折中办法: 为每个 view 创建一个独立 FBO,再把指定纹理、mip 和 layer/face 附着到这个 FBO 上。这样上层可以继续沿用“先构造 view,再绑定 view”的组织方式,而不必每次手写 framebuffer 配置细节。
设计背景
OpenGLDepthStencilView 的定位更接近“后端适配层工具对象”,而不是完整的跨后端深度附件抽象。
- 好处是实现直接、调试简单,单元测试和工具代码很容易验证绑定行为。
- 好处是可以把
Texture2D、数组纹理切片、cubemap face 这几类常见子资源统一封装到一个接口里。 - 代价是它没有和更新一代的
OpenGLFramebuffer/OpenGLResourceView体系彻底对齐,很多字段只是保留了抽象层接口形状,并没有被完整消费。
如果目标是商业级引擎里的长期演进路径,通常会更偏向“显式 framebuffer 描述 + 统一 resource view”的方案,因为那条路线更容易支持多附件组合、渲染图编排、缓存复用和更严格的状态验证。OpenGLDepthStencilView 更适合作为旧路径兼容层或轻量工具接口。
相关声明
DepthStencilFormat
头文件中声明了四种格式枚举:
D16_UNORMD24_UNORM_S8_UINTD32_FLOATD32_FLOAT_S8X24_UINT
但当前类实现并不会从传入纹理推导真实格式,也没有公开接口返回实际 attachment 格式。内部成员 m_format 在构造时固定初始化为 D24_UNORM_S8_UINT,之后也不会更新。
DepthStencilType
当前支持三种视图类型:
Texture2DTexture2DArrayTextureCube
它们直接决定 Initialize() 内部选用 glFramebufferTexture2D() 还是 glFramebufferTextureLayer()。
OpenGLDepthStencilViewDesc
描述结构包含以下字段:
type: 选择纹理视图类别。mipLevel: 指定附着的 mip 级别。baseArraySlice: 对数组纹理表示层索引,对 cubemap 表示 face 偏移。arraySize: 当前实现未使用。layer: 当前实现未使用。
这说明它的接口形状已经在向更通用的 view 描述靠拢,但 OpenGL 后端的落地仍然是一个较薄的子集。
生命周期
- OpenGLDepthStencilView() 把对象初始化为空状态。
- Initialize 或 InitializeCubemap 创建 FBO 并附着指定子资源。
- Bind / Unbind 切换当前 framebuffer。
- ClearDepth、ClearStencil、ClearDepthStencil 在当前对象对应的 FBO 上执行清除。
- Shutdown 删除 FBO。
当前实现的真实行为
- 每次成功或失败的初始化路径都会先生成一个新的 FBO,并把它写入
m_framebuffer。 - 附着点始终来自
ToOpenGLDepthAttachment(),当前它固定返回GL_DEPTH_ATTACHMENT,并不会根据纹理格式切换到GL_STENCIL_ATTACHMENT或GL_DEPTH_STENCIL_ATTACHMENT。 - 初始化失败时函数会返回
false,但不会立即删除刚创建的 FBO,也不会回滚m_texture、m_mipLevel、m_type等成员。调用方应继续执行 Shutdown 或依赖析构清理。 GetWidth()/GetHeight()当前始终返回默认值0,因为实现没有从纹理查询并写回尺寸。Clear*方法会直接绑定自己的 framebuffer 并清除,但不会恢复调用前的 framebuffer 绑定状态。- 单元测试
tests/RHI/OpenGL/unit/test_depth_stencil_view.cpp只覆盖了初始化、绑定和简单 getter,不能把它视为格式兼容性或 stencil 行为的完备证明。
使用建议
- 当你只是需要“把某张纹理的某个子资源临时当作深度附件使用”时,这个类足够直接。
- 如果你需要多附件 FBO、统一的 render pass 组织、显式 attachment 配置或更强的后端一致性,优先考虑更完整的 framebuffer / resource view 路径。
- 当前不要依赖 GetWidth 和 GetHeight。
- 如果
Initialize()失败,最好显式调用一次 Shutdown,避免把半初始化状态留在对象里继续复用。