feat(d3d12): 实现交换链与渲染表面管理
- 新增 d3d12_surface 类,管理交换链和渲染目标 - 实现三重缓冲后台缓冲区管理 - 添加视口和裁剪矩形配置 - 修复 GraphicsPlatformInterface.h 循环包含问题 - 添加完整的中文 Doxygen 注释 - 更新 D3D12 学习 Wiki,添加交换链章节
This commit is contained in:
114
Engine/Graphics/Direct3D12/D3D12Surface.cpp
Normal file
114
Engine/Graphics/Direct3D12/D3D12Surface.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
#include "D3D12Surface.h"
|
||||
#include "D3D12Core.h"
|
||||
|
||||
|
||||
namespace XEngine::graphics::d3d12 {
|
||||
namespace{
|
||||
constexpr DXGI_FORMAT
|
||||
to_non_srgb(DXGI_FORMAT format)
|
||||
{
|
||||
if(format == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB) return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
return format;
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
void
|
||||
d3d12_surface::create_swap_chain(IDXGIFactory7* factory, ID3D12CommandQueue* cmd_queue, DXGI_FORMAT format)
|
||||
{
|
||||
assert(!factory && cmd_queue);
|
||||
|
||||
// 应为可以多次调用,所以需要先释放旧的 swap chain
|
||||
release();
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC1 desc{};
|
||||
desc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; // Alpha通道模式(窗口透明度相关)
|
||||
desc.BufferCount = frame_buffer_count; // 后台缓冲区数量(用于双缓冲/多缓冲)
|
||||
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // 缓冲区用途(作为渲染目标输出)
|
||||
desc.Flags = 0; // 交换链标志位(无)
|
||||
desc.Format = to_non_srgb(format); // 像素格式(转换为非SRGB格式)
|
||||
desc.Height = _window.height(); // 交换链高度(与窗口高度一致)
|
||||
desc.Width = _window.width(); // 交换链宽度(与窗口宽度一致)
|
||||
desc.SampleDesc.Count = 1; // 多重采样数量(1表示禁用MSAA)
|
||||
desc.SampleDesc.Quality = 0; // 多重采样质量等级(0表示禁用)
|
||||
desc.Scaling = DXGI_SCALING_STRETCH; // 缓冲区缩放模式(窗口大小变化时的处理方式)
|
||||
desc.Stereo = false; // 立体显示模式(3D显示)
|
||||
|
||||
IDXGISwapChain1* swap_chain;
|
||||
HWND hwnd {(HWND)_window.handle()};
|
||||
// 为窗口创建交换链,指定交换链描述结构体
|
||||
DXCall(factory->CreateSwapChainForHwnd(cmd_queue, hwnd, &desc, nullptr, nullptr, &swap_chain));
|
||||
// 控制 DXGI 如何响应特定的系统按键,阻止 DXGI 响应 Alt+Enter 按键序列,由应用程序手动处理全屏切换逻辑。
|
||||
DXCall(factory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER));
|
||||
// 将局部变量 swap_chain 创建的交换链对象“转移”给类成员 _swap_chain 来长期持有。
|
||||
// 免了直接赋值(_swap_chain = swap_chain)可能导致的引用计数问题:直接赋值不增加
|
||||
// 计数,后续释放 swap_chain 会使对象计数归零而被销毁,_swap_chain 就会变成悬空指针。
|
||||
DXCall(swap_chain->QueryInterface(IID_PPV_ARGS(&_swap_chain)));
|
||||
core::release(swap_chain);
|
||||
|
||||
_current_bb_index = _swap_chain->GetCurrentBackBufferIndex();
|
||||
|
||||
for(u32 i = 0; i < frame_buffer_count; ++i)
|
||||
{
|
||||
_render_target_data[i].rtv = core::rtv_heap().allocate();
|
||||
}
|
||||
|
||||
finalize();
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_surface::present() const
|
||||
{
|
||||
assert(_swap_chain);
|
||||
// 设置是否使用垂直同步
|
||||
// 0 表示不使用垂直同步,1 表示使用垂直同步
|
||||
// 第二个参数设置有无特殊行为,0 表示无特殊行为
|
||||
DXCall(_swap_chain->Present(0, 0));
|
||||
_current_bb_index = _swap_chain->GetCurrentBackBufferIndex();
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_surface::finalize()
|
||||
{
|
||||
// 为每个缓冲区创建渲染目标视图
|
||||
for(u32 i = 0; i < frame_buffer_count; ++i)
|
||||
{
|
||||
render_target_data& data{ _render_target_data[i] };
|
||||
assert(!data.resource);
|
||||
DXCall(_swap_chain->GetBuffer(i, IID_PPV_ARGS(&data.resource)));
|
||||
D3D12_RENDER_TARGET_VIEW_DESC desc{};
|
||||
desc.Format = core::default_render_target_format();
|
||||
desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
|
||||
core::device()->CreateRenderTargetView(data.resource, &desc, data.rtv.cpu);
|
||||
}
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC desc{};
|
||||
DXCall(_swap_chain->GetDesc(&desc));
|
||||
const u32 width{ desc.BufferDesc.Width };
|
||||
const u32 height{ desc.BufferDesc.Height };
|
||||
assert(_window.width() == width && _window.height() == height);
|
||||
|
||||
|
||||
_viewport.TopLeftX = 0.0f;
|
||||
_viewport.TopLeftY = 0.0f;
|
||||
_viewport.Width = (float)width;
|
||||
_viewport.Height = (float)height;
|
||||
_viewport.MaxDepth = 1.0f;
|
||||
_viewport.MinDepth = 0.0f;
|
||||
|
||||
_scissor_rect = {0, 0, (s32)width, (s32)height};
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_surface::release()
|
||||
{
|
||||
for(u32 i = 0; i < frame_buffer_count; ++i)
|
||||
{
|
||||
render_target_data& data{ _render_target_data[i] };
|
||||
core::release(data.resource);
|
||||
core::rtv_heap().free(data.rtv);
|
||||
}
|
||||
|
||||
core::release(_swap_chain);
|
||||
}
|
||||
|
||||
} // namespace XEngine::graphics::d3d12
|
||||
Reference in New Issue
Block a user