feat(d3d12): 实现交换链与渲染表面管理
- 新增 d3d12_surface 类,管理交换链和渲染目标 - 实现三重缓冲后台缓冲区管理 - 添加视口和裁剪矩形配置 - 修复 GraphicsPlatformInterface.h 循环包含问题 - 添加完整的中文 Doxygen 注释 - 更新 D3D12 学习 Wiki,添加交换链章节
This commit is contained in:
210
Engine/Graphics/Direct3D12/D3D12Surface.h
Normal file
210
Engine/Graphics/Direct3D12/D3D12Surface.h
Normal file
@@ -0,0 +1,210 @@
|
||||
#pragma once
|
||||
#include "D3D12CommonHeader.h"
|
||||
#include "D3D12Resources.h"
|
||||
|
||||
namespace XEngine::graphics::d3d12 {
|
||||
|
||||
/**
|
||||
* @class d3d12_surface
|
||||
* @brief 管理 D3D12 交换链和渲染目标的表面类
|
||||
*
|
||||
* @details
|
||||
* 该类封装了 Direct3D 12 的交换链(Swap Chain)和后台缓冲区管理,
|
||||
* 提供渲染表面的完整生命周期管理。
|
||||
*
|
||||
* ## 核心职责
|
||||
*
|
||||
* - **交换链管理**:创建和管理 IDXGISwapChain4,处理前后缓冲区交换
|
||||
* - **渲染目标管理**:为每个后台缓冲区创建和维护渲染目标视图(RTV)
|
||||
* - **视口和裁剪矩形**:管理渲染区域的视口和裁剪设置
|
||||
* - **窗口关联**:与平台窗口绑定,处理窗口大小调整
|
||||
*
|
||||
* ## 多缓冲机制
|
||||
*
|
||||
* 使用 `frame_buffer_count`(通常为 3)个后台缓冲区实现三重缓冲:
|
||||
* - 减少画面撕裂
|
||||
* - 提高 CPU-GPU 并行性
|
||||
* - 平滑帧率波动
|
||||
*
|
||||
* ## 生命周期
|
||||
*
|
||||
* @code
|
||||
* d3d12_surface surface(window);
|
||||
* surface.create_swap_chain(factory, cmd_queue, DXGI_FORMAT_R8G8B8A8_UNORM);
|
||||
*
|
||||
* // 渲染循环
|
||||
* surface.present(); // 呈现当前帧
|
||||
* surface.resize(); // 窗口大小改变时调用
|
||||
*
|
||||
* // 自动析构时释放资源
|
||||
* @endcode
|
||||
*
|
||||
* @see IDXGISwapChain4
|
||||
* @see ID3D12Resource
|
||||
* @see descriptor_handle
|
||||
*/
|
||||
class d3d12_surface
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief 构造函数,绑定到指定窗口
|
||||
*
|
||||
* @param window 平台窗口对象
|
||||
*
|
||||
* @details
|
||||
* 仅保存窗口引用,不创建交换链。
|
||||
* 必须随后调用 create_swap_chain() 完成初始化。
|
||||
*
|
||||
* @pre window.handle() 必须返回有效的窗口句柄
|
||||
*/
|
||||
explicit d3d12_surface(platform::window window)
|
||||
:_window(window)
|
||||
{
|
||||
assert(window.handle());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 析构函数,自动释放所有资源
|
||||
*
|
||||
* @details
|
||||
* 调用 release() 清理交换链和渲染目标资源。
|
||||
*/
|
||||
~d3d12_surface(){release();}
|
||||
|
||||
/**
|
||||
* @brief 创建交换链和渲染目标视图
|
||||
*
|
||||
* @param factory DXGI 工厂对象,用于创建交换链
|
||||
* @param cmd_queue 命令队列,交换链将与此队列同步
|
||||
* @param format 后台缓冲区的像素格式(如 DXGI_FORMAT_R8G8B8A8_UNORM)
|
||||
*
|
||||
* @details
|
||||
* 执行以下操作:
|
||||
* 1. 创建 IDXGISwapChain4 对象
|
||||
* 2. 获取所有后台缓冲区资源
|
||||
* 3. 为每个后台缓冲区创建 RTV
|
||||
* 4. 初始化视口和裁剪矩形
|
||||
*
|
||||
* @pre factory 和 cmd_queue 必须有效
|
||||
* @pre 尚未创建交换链(或已调用 release())
|
||||
*/
|
||||
void create_swap_chain(IDXGIFactory7* factory, ID3D12CommandQueue* cmd_queue, DXGI_FORMAT format);
|
||||
|
||||
/**
|
||||
* @brief 呈现当前渲染帧
|
||||
*
|
||||
* @details
|
||||
* 调用 IDXGISwapChain::Present() 将当前后台缓冲区内容显示到屏幕。
|
||||
* 呈现后,后台缓冲区索引自动递增(轮转)。
|
||||
*
|
||||
* @note 使用 DXGI_SWAP_EFFECT_FLIP_DISCARD 模式时,
|
||||
* 呈现后当前后台缓冲区内容不再有效
|
||||
*/
|
||||
void present() const;
|
||||
|
||||
/**
|
||||
* @brief 调整交换链大小以匹配窗口
|
||||
*
|
||||
* @details
|
||||
* 当窗口大小改变时调用此方法:
|
||||
* 1. 释放旧的渲染目标资源
|
||||
* 2. 调整交换链缓冲区大小
|
||||
* 3. 重新创建渲染目标视图
|
||||
* 4. 更新视口和裁剪矩形
|
||||
*
|
||||
* @note 必须在 GPU 完成使用当前资源后调用
|
||||
*/
|
||||
void resize();
|
||||
|
||||
/**
|
||||
* @brief 获取渲染表面宽度
|
||||
* @return 宽度(像素)
|
||||
*/
|
||||
u32 width();
|
||||
|
||||
/**
|
||||
* @brief 获取渲染表面高度
|
||||
* @return 高度(像素)
|
||||
*/
|
||||
u32 height();
|
||||
|
||||
/**
|
||||
* @brief 获取当前后台缓冲区资源
|
||||
* @return 指向 ID3D12Resource 的指针
|
||||
*
|
||||
* @details
|
||||
* 返回当前帧应渲染到的后台缓冲区。
|
||||
* 索引由 _current_bb_index 指定,每次 present() 后更新。
|
||||
*/
|
||||
constexpr ID3D12Resource *const back_buffer() const {return _render_target_data[_current_bb_index].resource;}
|
||||
|
||||
/**
|
||||
* @brief 获取当前后台缓冲区的渲染目标视图句柄
|
||||
* @return RTV 描述符句柄
|
||||
*
|
||||
* @details
|
||||
* 用于 OMSetRenderTargets() 绑定渲染目标。
|
||||
*/
|
||||
constexpr descriptor_handle rtv() const {return _render_target_data[_current_bb_index].rtv;}
|
||||
|
||||
/**
|
||||
* @brief 获取视口描述
|
||||
* @return D3D12_VIEWPORT 常量引用
|
||||
*
|
||||
* @details
|
||||
* 用于 RSSetViewports() 设置光栅化视口。
|
||||
*/
|
||||
constexpr const D3D12_VIEWPORT& viewport() const {return _viewport;}
|
||||
|
||||
/**
|
||||
* @brief 获取裁剪矩形描述
|
||||
* @return D3D12_RECT 常量引用
|
||||
*
|
||||
* @details
|
||||
* 用于 RSSetScissorRects() 设置裁剪区域。
|
||||
* 裁剪区域外的像素将被丢弃。
|
||||
*/
|
||||
constexpr const D3D12_RECT& scissor_rect() const {return _scissor_rect;}
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief 释放所有资源
|
||||
*
|
||||
* @details
|
||||
* 释放交换链和所有后台缓冲区资源。
|
||||
* 使用延迟释放机制确保 GPU 安全。
|
||||
*/
|
||||
void release();
|
||||
|
||||
/**
|
||||
* @brief 完成资源创建的最终设置
|
||||
*
|
||||
* @details
|
||||
* 在创建或调整大小后调用,设置视口和裁剪矩形。
|
||||
*/
|
||||
void finalize();
|
||||
|
||||
/**
|
||||
* @struct render_target_data
|
||||
* @brief 单个后台缓冲区的渲染目标数据
|
||||
*
|
||||
* @details
|
||||
* 每个后台缓冲区对应一个此结构体,存储:
|
||||
* - 资源指针:实际的缓冲区纹理资源
|
||||
* - RTV 句柄:用于绑定到渲染管线
|
||||
*/
|
||||
struct render_target_data
|
||||
{
|
||||
ID3D12Resource* resource{nullptr}; ///< 后台缓冲区资源
|
||||
descriptor_handle rtv{}; ///< 渲染目标视图描述符句柄
|
||||
};
|
||||
|
||||
IDXGISwapChain4* _swap_chain{nullptr}; ///< DXGI 交换链对象
|
||||
render_target_data _render_target_data[frame_buffer_count];///< 后台缓冲区数据数组
|
||||
platform::window _window{}; ///< 关联的平台窗口
|
||||
mutable u32 _current_bb_index{0}; ///< 当前后台缓冲区索引
|
||||
D3D12_VIEWPORT _viewport{}; ///< 视口描述
|
||||
D3D12_RECT _scissor_rect{}; ///< 裁剪矩形
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user