feat(d3d12): 新增纹理资源类,修复 Surface 重复释放问题
核心变更: - 新增 d3d12_texture 和 d3d12_render_texture 类 - 新增 d3d12_texture_init_info 结构,支持三种资源创建方式 - 新增 D3D12Helpers.h,提供堆属性辅助结构 - 改用 utl::free_list 管理 surface,解决重复释放问题 - 为 d3d12_surface 添加移动语义,支持撕裂检测 文档完善: - 为 FreeList.h 和 Vector.h 添加完整 Doxygen 中文注释 - 更新 D3D12 学习 Wiki,添加 SRV、资源创建方式、纹理资源类章节 - 新增变更记录文档
This commit is contained in:
@@ -2,113 +2,137 @@
|
||||
#include "D3D12Core.h"
|
||||
|
||||
|
||||
namespace XEngine::graphics::d3d12 {
|
||||
namespace{
|
||||
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;
|
||||
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);
|
||||
assert(factory && cmd_queue);
|
||||
|
||||
// 应为可以多次调用,所以需要先释放旧的 swap chain
|
||||
release();
|
||||
// 应为可以多次调用,所以需要先释放旧的 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显示)
|
||||
if (SUCCEEDED(factory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &_allow_tearing, sizeof(u32))) && _allow_tearing)
|
||||
{
|
||||
_present_flags = DXGI_PRESENT_ALLOW_TEARING;
|
||||
}
|
||||
|
||||
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);
|
||||
DXGI_SWAP_CHAIN_DESC1 desc{};
|
||||
desc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; // Alpha通道模式(窗口透明度相关)
|
||||
desc.BufferCount = buffer_count; // 后台缓冲区数量(用于双缓冲/多缓冲)
|
||||
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // 缓冲区用途(作为渲染目标输出)
|
||||
desc.Flags = _allow_tearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 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.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; // 交换链效果(翻转并丢弃旧缓冲区)
|
||||
desc.Stereo = false; // 立体显示模式(3D显示)
|
||||
|
||||
_current_bb_index = _swap_chain->GetCurrentBackBufferIndex();
|
||||
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);
|
||||
|
||||
for(u32 i = 0; i < frame_buffer_count; ++i)
|
||||
{
|
||||
_render_target_data[i].rtv = core::rtv_heap().allocate();
|
||||
}
|
||||
_current_bb_index = _swap_chain->GetCurrentBackBufferIndex();
|
||||
|
||||
finalize();
|
||||
for (u32 i = 0; i < 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();
|
||||
assert(_swap_chain);
|
||||
// 设置是否使用垂直同步
|
||||
// 0 表示不使用垂直同步,1 表示使用垂直同步
|
||||
// 第二个参数设置有无特殊行为,0 表示无特殊行为
|
||||
DXCall(_swap_chain->Present(0, _present_flags));
|
||||
_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);
|
||||
}
|
||||
// 为每个缓冲区创建渲染目标视图
|
||||
for (u32 i = 0; i < 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);
|
||||
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;
|
||||
_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};
|
||||
_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);
|
||||
}
|
||||
for (u32 i = 0; i < 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);
|
||||
}
|
||||
core::release(_swap_chain);
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_surface::resize()
|
||||
{
|
||||
}
|
||||
|
||||
u32
|
||||
d3d12_surface::width()
|
||||
{
|
||||
return _window.width();
|
||||
}
|
||||
|
||||
u32
|
||||
d3d12_surface::height()
|
||||
{
|
||||
return _window.height();
|
||||
}
|
||||
|
||||
|
||||
} // namespace XEngine::graphics::d3d12
|
||||
Reference in New Issue
Block a user