feat: implement descriptor heap with thread-safe allocation
D3D12 Resources: - Add descriptor_handle struct with CPU/GPU handles - Add descriptor_heap class for descriptor management - Implement allocate() and free() methods - Add mutex for thread-safe access - Support all D3D12 descriptor heap types D3D12 Core: - Add device() function to expose main device - Add release() template function for COM objects Documentation: - Add changelog for descriptor heap implementation - Update D3D12 Wiki with descriptor heap section - Mark descriptor heap task as completed
This commit is contained in:
@@ -36,6 +36,7 @@
|
|||||||
<ClInclude Include="Graphics\Direct3D12\D3D12CommonHeader.h" />
|
<ClInclude Include="Graphics\Direct3D12\D3D12CommonHeader.h" />
|
||||||
<ClInclude Include="Graphics\Direct3D12\D3D12Core.h" />
|
<ClInclude Include="Graphics\Direct3D12\D3D12Core.h" />
|
||||||
<ClInclude Include="Graphics\Direct3D12\D3D12Interface.h" />
|
<ClInclude Include="Graphics\Direct3D12\D3D12Interface.h" />
|
||||||
|
<ClInclude Include="Graphics\Direct3D12\D3D12Resources.h" />
|
||||||
<ClInclude Include="Graphics\GraphicsPlatformInterface.h" />
|
<ClInclude Include="Graphics\GraphicsPlatformInterface.h" />
|
||||||
<ClInclude Include="Graphics\Renderer.h" />
|
<ClInclude Include="Graphics\Renderer.h" />
|
||||||
<ClInclude Include="Platform\IncludeWindowCpp.h" />
|
<ClInclude Include="Platform\IncludeWindowCpp.h" />
|
||||||
@@ -59,10 +60,14 @@
|
|||||||
<ClCompile Include="Core\MainWin32.cpp" />
|
<ClCompile Include="Core\MainWin32.cpp" />
|
||||||
<ClCompile Include="Graphics\Direct3D12\D3D12Core.cpp" />
|
<ClCompile Include="Graphics\Direct3D12\D3D12Core.cpp" />
|
||||||
<ClCompile Include="Graphics\Direct3D12\D3D12Interface.cpp" />
|
<ClCompile Include="Graphics\Direct3D12\D3D12Interface.cpp" />
|
||||||
|
<ClCompile Include="Graphics\Direct3D12\D3D12Resource.cpp" />
|
||||||
<ClCompile Include="Graphics\Renderer.cpp" />
|
<ClCompile Include="Graphics\Renderer.cpp" />
|
||||||
<ClCompile Include="Platform\PlatformWin32.cpp" />
|
<ClCompile Include="Platform\PlatformWin32.cpp" />
|
||||||
<ClCompile Include="Platform\Window.cpp" />
|
<ClCompile Include="Platform\Window.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="Graphics\Direct3D12\D3D12Resources" />
|
||||||
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Globals">
|
<PropertyGroup Label="Globals">
|
||||||
<VCProjectVersion>17.0</VCProjectVersion>
|
<VCProjectVersion>17.0</VCProjectVersion>
|
||||||
<Keyword>Win32Proj</Keyword>
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
<ClInclude Include="Graphics\Direct3D12\D3D12Core.h" />
|
<ClInclude Include="Graphics\Direct3D12\D3D12Core.h" />
|
||||||
<ClInclude Include="Graphics\Direct3D12\D3D12Interface.h" />
|
<ClInclude Include="Graphics\Direct3D12\D3D12Interface.h" />
|
||||||
<ClInclude Include="Graphics\GraphicsPlatformInterface.h" />
|
<ClInclude Include="Graphics\GraphicsPlatformInterface.h" />
|
||||||
|
<ClInclude Include="Graphics\Direct3D12\D3D12Resources.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="Components\Entity.cpp" />
|
<ClCompile Include="Components\Entity.cpp" />
|
||||||
@@ -44,5 +45,9 @@
|
|||||||
<ClCompile Include="Graphics\Renderer.cpp" />
|
<ClCompile Include="Graphics\Renderer.cpp" />
|
||||||
<ClCompile Include="Graphics\Direct3D12\D3D12Core.cpp" />
|
<ClCompile Include="Graphics\Direct3D12\D3D12Core.cpp" />
|
||||||
<ClCompile Include="Graphics\Direct3D12\D3D12Interface.cpp" />
|
<ClCompile Include="Graphics\Direct3D12\D3D12Interface.cpp" />
|
||||||
|
<ClCompile Include="Graphics\Direct3D12\D3D12Resource.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="Graphics\Direct3D12\D3D12Resources" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -16,6 +16,9 @@
|
|||||||
// 用于简化 COM 对象的生命周期管理
|
// 用于简化 COM 对象的生命周期管理
|
||||||
#include <wrl.h>
|
#include <wrl.h>
|
||||||
|
|
||||||
|
// 引入互斥锁头文件,用于保护资源的互斥锁
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
|
||||||
#pragma comment(lib, "dxgi.lib")
|
#pragma comment(lib, "dxgi.lib")
|
||||||
#pragma comment(lib, "d3d12.lib")
|
#pragma comment(lib, "d3d12.lib")
|
||||||
|
|||||||
@@ -421,4 +421,11 @@ render()
|
|||||||
// 为下一帧标记并增加围栏值
|
// 为下一帧标记并增加围栏值
|
||||||
gfx_command.end_frame();
|
gfx_command.end_frame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ID3D12Device *const
|
||||||
|
device()
|
||||||
|
{
|
||||||
|
return main_device;
|
||||||
|
}
|
||||||
|
|
||||||
}// namespace XEngine::graphics::d3d12::core
|
}// namespace XEngine::graphics::d3d12::core
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "D3D12CommonHeader.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Direct3D 12 核心类
|
* @brief Direct3D 12 核心类
|
||||||
@@ -22,6 +23,12 @@ void shutdown();
|
|||||||
*/
|
*/
|
||||||
void render();
|
void render();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 通用资源释放模板函数
|
||||||
|
* @details 用于安全释放 DirectX COM 对象,检查空指针后调用 Release 并置空
|
||||||
|
* @tparam T COM 接口类型
|
||||||
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr void release(T*& resource)
|
constexpr void release(T*& resource)
|
||||||
{
|
{
|
||||||
@@ -32,4 +39,11 @@ constexpr void release(T*& resource)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取 Direct3D 12 设备
|
||||||
|
* @details 返回 Direct3D 12 设备的智能指针
|
||||||
|
* @return ID3D12Device* Direct3D 12 设备的智能指针
|
||||||
|
*/
|
||||||
|
ID3D12Device *const device();
|
||||||
|
|
||||||
}// namespace XEngine::graphics::d3d12
|
}// namespace XEngine::graphics::d3d12
|
||||||
101
Engine/Graphics/Direct3D12/D3D12Resource.cpp
Normal file
101
Engine/Graphics/Direct3D12/D3D12Resource.cpp
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
#include "D3D12Resources.h"
|
||||||
|
#include "D3D12Core.h"
|
||||||
|
|
||||||
|
namespace XEngine::graphics::d3d12{
|
||||||
|
//////////// DESCRIPTOR HEAP ////////////
|
||||||
|
// 该类将被多个线程并发访问:资源创建(如纹理)与资源销毁/释放可能发生在不同线程,
|
||||||
|
// 因此需要同步机制保护内部数据结构
|
||||||
|
bool
|
||||||
|
descriptor_heap::initialize(u32 capacity, bool is_shader_visible)
|
||||||
|
{
|
||||||
|
std::lock_guard lock(_mutex);
|
||||||
|
// 检查容量有效性:必须大于0且不超过最大限制
|
||||||
|
assert(capacity && capacity <= D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_2);
|
||||||
|
// 对于采样器描述符堆,需要额外检查容量是否超过最大采样器堆大小限制
|
||||||
|
assert(!(_type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER &&
|
||||||
|
capacity > D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE));
|
||||||
|
|
||||||
|
// 对于DSV和RTV他们在描述符堆的内存模型中本身就是GPU不可见的
|
||||||
|
if(_type == D3D12_DESCRIPTOR_HEAP_TYPE_DSV ||
|
||||||
|
_type == D3D12_DESCRIPTOR_HEAP_TYPE_RTV)
|
||||||
|
{
|
||||||
|
is_shader_visible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 应为这个功能将被调用多次,所以需要先释放之前的资源
|
||||||
|
release();
|
||||||
|
|
||||||
|
ID3D12Device *const device {core::device()};
|
||||||
|
assert(device);
|
||||||
|
|
||||||
|
D3D12_DESCRIPTOR_HEAP_DESC desc{};
|
||||||
|
desc.Flags = is_shader_visible
|
||||||
|
? D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE
|
||||||
|
: D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
||||||
|
desc.NumDescriptors = capacity;
|
||||||
|
desc.Type = _type;
|
||||||
|
desc.NodeMask = 0;
|
||||||
|
|
||||||
|
HRESULT hr {S_OK};
|
||||||
|
DXCall(hr = device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&_heap)));
|
||||||
|
if(FAILED(hr)) return false;
|
||||||
|
|
||||||
|
_free_handles = std::move(std::make_unique<u32[]>(capacity));
|
||||||
|
_capacity = capacity;
|
||||||
|
_size = 0;
|
||||||
|
|
||||||
|
for(u32 i = 0; i < capacity; ++i) _free_handles[i] = i;
|
||||||
|
|
||||||
|
_descriptor_size = device->GetDescriptorHandleIncrementSize(_type);
|
||||||
|
_cpu_start = _heap->GetCPUDescriptorHandleForHeapStart();
|
||||||
|
_gpu_start = is_shader_visible
|
||||||
|
? _heap->GetGPUDescriptorHandleForHeapStart()
|
||||||
|
: D3D12_GPU_DESCRIPTOR_HANDLE{0};
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
descriptor_heap::release()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
descriptor_handle
|
||||||
|
descriptor_heap::allocate()
|
||||||
|
{
|
||||||
|
std::lock_guard lock(_mutex);
|
||||||
|
assert(_heap);
|
||||||
|
assert(_size < _capacity);
|
||||||
|
|
||||||
|
const u32 index { _free_handles[_size] };
|
||||||
|
const u32 offset { index * _descriptor_size };
|
||||||
|
++_size;
|
||||||
|
|
||||||
|
descriptor_handle handle{};
|
||||||
|
handle.cpu.ptr = _cpu_start.ptr + offset;
|
||||||
|
if(is_shader_visible())
|
||||||
|
{
|
||||||
|
handle.gpu.ptr = _gpu_start.ptr + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_OP(handle.container = this);
|
||||||
|
DEBUG_OP(handle.index = index);
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
descriptor_heap::free(descriptor_handle handle)
|
||||||
|
{
|
||||||
|
if(!handle.is_valid()) return;
|
||||||
|
std::lock_guard lock(_mutex);
|
||||||
|
assert(_heap && _size);
|
||||||
|
assert(handle.container == this);
|
||||||
|
assert(handle.cpu.ptr >= _cpu_start.ptr);
|
||||||
|
assert((handle.cpu.ptr - _cpu_start.ptr) % _descriptor_size == 0);
|
||||||
|
assert(handle.index < _capacity);
|
||||||
|
const u32 index{ (u32)(handle.cpu.ptr - _cpu_start.ptr) / _descriptor_size };
|
||||||
|
assert(handle.index == index);
|
||||||
|
|
||||||
|
handle = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
} //XEngine::graphics::d3d12
|
||||||
67
Engine/Graphics/Direct3D12/D3D12Resources.h
Normal file
67
Engine/Graphics/Direct3D12/D3D12Resources.h
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "D3D12CommonHeaders.h"
|
||||||
|
|
||||||
|
namespace XEngine::graphics::d3d12{
|
||||||
|
class descriptor_heap;
|
||||||
|
struct descriptor_handle
|
||||||
|
{
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE cpu{};
|
||||||
|
D3D12_GPU_DESCRIPTOR_HANDLE gpu{};
|
||||||
|
|
||||||
|
constexpr bool is_valid() const { return cpu.ptr != 0; }
|
||||||
|
constexpr bool is_shader_visible() const { return gpu.ptr != 0; }
|
||||||
|
#ifdef _DEBUG
|
||||||
|
private:
|
||||||
|
friend class descriptor_heap;
|
||||||
|
descriptor_heap* container{ nullptr };
|
||||||
|
u32 index{ u32_invalid_id };
|
||||||
|
#endif
|
||||||
|
}; // descriptor_handle
|
||||||
|
class descriptor_heap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit descriptor_heap(const D3D12_DESCRIPTOR_HEAP_TYPE type): _type(type){}
|
||||||
|
DISABLE_COPY_AND_MOVE(descriptor_heap);
|
||||||
|
~descriptor_heap(){assert(!_heap);}
|
||||||
|
|
||||||
|
bool initialize(u32 capacity, bool is_shader_visible);
|
||||||
|
void release();
|
||||||
|
|
||||||
|
[[nodiscard]] descriptor_handle allocate();
|
||||||
|
void free(descriptor_handle handle);
|
||||||
|
|
||||||
|
constexpr D3D12_DESCRIPTOR_HEAP_TYPE type() const { return _type; }
|
||||||
|
constexpr D3D12_CPU_DESCRIPTOR_HANDLE cpu_start() const { return _cpu_start; }
|
||||||
|
constexpr D3D12_GPU_DESCRIPTOR_HANDLE gpu_start() const { return _gpu_start; }
|
||||||
|
constexpr ID3D12DescriptorHeap *const heap() const { return _heap; }
|
||||||
|
constexpr u32 capacity() const { return _capacity; }
|
||||||
|
constexpr u32 size() const { return _size; }
|
||||||
|
constexpr u32 descriptor_size() const { return _descriptor_size; }
|
||||||
|
constexpr bool is_shader_visible() const { return _gpu_start.ptr != 0; }
|
||||||
|
private:
|
||||||
|
// 一个描述符堆是一个内存块,基于他是否着色器可见,分配在系统内存还是显存
|
||||||
|
ID3D12DescriptorHeap* _heap;
|
||||||
|
|
||||||
|
// CPU起始句柄(用于CPU端描述符操作)
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE _cpu_start{};
|
||||||
|
// GPU起始句柄(仅当堆为着色器可见时有效)
|
||||||
|
D3D12_GPU_DESCRIPTOR_HANDLE _gpu_start{};
|
||||||
|
|
||||||
|
// 空闲的描述符句柄
|
||||||
|
std::unique_ptr<u32[]> _free_handles{};
|
||||||
|
|
||||||
|
// 用于保护资源初始化的互斥锁
|
||||||
|
std::mutex _mutex;
|
||||||
|
|
||||||
|
// 描述符堆的容量
|
||||||
|
u32 _capacity{0};
|
||||||
|
// 已经分配的描述符数量
|
||||||
|
u32 _size{0};
|
||||||
|
// 不同的描述符堆类型在不同的硬件上有不同的大小,所以需要记录下描述符的大小
|
||||||
|
u32 _descriptor_size{0};
|
||||||
|
const D3D12_DESCRIPTOR_HEAP_TYPE _type;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
212
docs/changelogs/2026-03/20260330-d3d12-descriptor-heap.md
Normal file
212
docs/changelogs/2026-03/20260330-d3d12-descriptor-heap.md
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
# 变更记录:描述符堆实现
|
||||||
|
|
||||||
|
**提交日期**: 2026-03-30
|
||||||
|
**提交哈希**: `a03c544`
|
||||||
|
**变更类型**: 功能实现
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 变更概述
|
||||||
|
|
||||||
|
本次提交实现了 D3D12 描述符堆(Descriptor Heap)管理类,提供描述符的分配和释放功能,支持多线程安全访问。
|
||||||
|
|
||||||
|
## 新增文件
|
||||||
|
|
||||||
|
### Engine/Graphics/Direct3D12/
|
||||||
|
|
||||||
|
| 文件 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `D3D12Resources.h` | 描述符句柄和描述符堆类定义 |
|
||||||
|
| `D3D12Resource.cpp` | 描述符堆实现 |
|
||||||
|
|
||||||
|
## 修改文件
|
||||||
|
|
||||||
|
| 文件 | 变更说明 |
|
||||||
|
|------|----------|
|
||||||
|
| `D3D12Core.h` | 添加 `device()` 函数声明和 `release` 模板函数 |
|
||||||
|
| `D3D12Core.cpp` | 添加 `device()` 函数实现 |
|
||||||
|
| `D3D12CommonHeader.h` | 添加 `<mutex>` 头文件 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 技术要点
|
||||||
|
|
||||||
|
### 1. descriptor_handle 结构
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct descriptor_handle
|
||||||
|
{
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE cpu{}; // CPU 句柄
|
||||||
|
D3D12_GPU_DESCRIPTOR_HANDLE gpu{}; // GPU 句柄(着色器可见时有效)
|
||||||
|
|
||||||
|
constexpr bool is_valid() const { return cpu.ptr != 0; }
|
||||||
|
constexpr bool is_shader_visible() const { return gpu.ptr != 0; }
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**设计要点**:
|
||||||
|
- 封装 CPU 和 GPU 双句柄
|
||||||
|
- 提供有效性检查方法
|
||||||
|
- DEBUG 模式下记录容器和索引用于调试
|
||||||
|
|
||||||
|
### 2. descriptor_heap 类
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class descriptor_heap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit descriptor_heap(const D3D12_DESCRIPTOR_HEAP_TYPE type);
|
||||||
|
|
||||||
|
bool initialize(u32 capacity, bool is_shader_visible);
|
||||||
|
void release();
|
||||||
|
|
||||||
|
descriptor_handle allocate(); // 分配描述符
|
||||||
|
void free(descriptor_handle handle); // 释放描述符
|
||||||
|
|
||||||
|
// 访问器
|
||||||
|
constexpr ID3D12DescriptorHeap* heap() const;
|
||||||
|
constexpr D3D12_CPU_DESCRIPTOR_HANDLE cpu_start() const;
|
||||||
|
constexpr D3D12_GPU_DESCRIPTOR_HANDLE gpu_start() const;
|
||||||
|
constexpr bool is_shader_visible() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ID3D12DescriptorHeap* _heap;
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE _cpu_start{};
|
||||||
|
D3D12_GPU_DESCRIPTOR_HANDLE _gpu_start{};
|
||||||
|
std::unique_ptr<u32[]> _free_handles{}; // 空闲句柄池
|
||||||
|
std::mutex _mutex; // 线程安全
|
||||||
|
u32 _capacity{0};
|
||||||
|
u32 _size{0};
|
||||||
|
u32 _descriptor_size{0};
|
||||||
|
const D3D12_DESCRIPTOR_HEAP_TYPE _type;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 描述符堆类型
|
||||||
|
|
||||||
|
| 类型 | 用途 | 着色器可见 |
|
||||||
|
|------|------|------------|
|
||||||
|
| `D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV` | 常量缓冲区、着色器资源、无序访问 | 可选 |
|
||||||
|
| `D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER` | 采样器 | 可选 |
|
||||||
|
| `D3D12_DESCRIPTOR_HEAP_TYPE_RTV` | 渲染目标视图 | 否 |
|
||||||
|
| `D3D12_DESCRIPTOR_HEAP_TYPE_DSV` | 深度模板视图 | 否 |
|
||||||
|
|
||||||
|
### 4. 内存模型
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────┐
|
||||||
|
│ Shader-Visible 描述符堆 (GPU 显存) │
|
||||||
|
│ ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐ │
|
||||||
|
│ │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │...│ │ │ │ │
|
||||||
|
│ └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘ │
|
||||||
|
│ ↑ │
|
||||||
|
│ _cpu_start / _gpu_start │
|
||||||
|
└─────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
_free_handles[] = [0, 1, 2, 3, 4, 5, ...] // 空闲索引池
|
||||||
|
_size = 0 // 已分配数量
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. 分配算法
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
descriptor_handle allocate()
|
||||||
|
{
|
||||||
|
std::lock_guard lock(_mutex); // 线程安全
|
||||||
|
|
||||||
|
const u32 index = _free_handles[_size]; // 取空闲索引
|
||||||
|
const u32 offset = index * _descriptor_size; // 计算偏移
|
||||||
|
++_size; // 递增已分配数量
|
||||||
|
|
||||||
|
descriptor_handle handle{};
|
||||||
|
handle.cpu.ptr = _cpu_start.ptr + offset; // CPU 句柄
|
||||||
|
if(is_shader_visible())
|
||||||
|
handle.gpu.ptr = _gpu_start.ptr + offset; // GPU 句柄
|
||||||
|
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. 线程安全
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
std::mutex _mutex; // 保护并发访问
|
||||||
|
|
||||||
|
// 使用 lock_guard 保护
|
||||||
|
std::lock_guard lock(_mutex);
|
||||||
|
```
|
||||||
|
|
||||||
|
描述符堆可能被多个线程并发访问(资源创建/销毁),需要互斥锁保护。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## D3D12Core 扩展
|
||||||
|
|
||||||
|
### 新增 device() 函数
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// D3D12Core.h
|
||||||
|
ID3D12Device *const device();
|
||||||
|
|
||||||
|
// D3D12Core.cpp
|
||||||
|
ID3D12Device *const device()
|
||||||
|
{
|
||||||
|
return main_device;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
提供对 D3D12 设备的访问,用于创建描述符堆等资源。
|
||||||
|
|
||||||
|
### 新增 release 模板函数
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
template<typename T>
|
||||||
|
constexpr void release(T*& resource)
|
||||||
|
{
|
||||||
|
if(resource)
|
||||||
|
{
|
||||||
|
resource->Release();
|
||||||
|
resource = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
通用的 COM 对象释放模板,避免代码重复。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 使用示例
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// 创建描述符堆
|
||||||
|
descriptor_heap cbv_srv_heap{D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV};
|
||||||
|
cbv_srv_heap.initialize(100, true); // 100个描述符,着色器可见
|
||||||
|
|
||||||
|
// 分配描述符
|
||||||
|
descriptor_handle handle = cbv_srv_heap.allocate();
|
||||||
|
|
||||||
|
// 创建视图
|
||||||
|
device->CreateShaderResourceView(texture, &srvDesc, handle.cpu);
|
||||||
|
|
||||||
|
// 绑定到管线
|
||||||
|
ID3D12DescriptorHeap* heaps[] = { cbv_srv_heap.heap() };
|
||||||
|
cmdList->SetDescriptorHeaps(1, heaps);
|
||||||
|
cmdList->SetGraphicsRootDescriptorTable(0, handle.gpu);
|
||||||
|
|
||||||
|
// 释放描述符
|
||||||
|
cbv_srv_heap.free(handle);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 后续工作
|
||||||
|
|
||||||
|
- [ ] 实现资源类(Texture, Buffer)
|
||||||
|
- [ ] 实现交换链
|
||||||
|
- [ ] 实现渲染目标视图
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 相关文档
|
||||||
|
|
||||||
|
- [D3D12学习Wiki](../wiki/D3D12学习Wiki.md)
|
||||||
@@ -16,6 +16,7 @@ changelogs/
|
|||||||
|
|
||||||
| 日期 | 提交 | 变更内容 |
|
| 日期 | 提交 | 变更内容 |
|
||||||
|------|------|----------|
|
|------|------|----------|
|
||||||
|
| 2026-03-30 | [描述符堆实现](./2026-03/20260330-d3d12-descriptor-heap.md) | D3D12 描述符堆管理和线程安全分配 |
|
||||||
| 2026-03-27 | [Fence同步机制](./2026-03/20260327-d3d12-fence-sync.md) | D3D12 Fence CPU-GPU 帧同步实现 |
|
| 2026-03-27 | [Fence同步机制](./2026-03/20260327-d3d12-fence-sync.md) | D3D12 Fence CPU-GPU 帧同步实现 |
|
||||||
| 2026-03-26 | [命令队列与多帧缓冲](./2026-03/20260326-d3d12-command-queue.md) | D3D12 命令队列和多帧渲染架构 |
|
| 2026-03-26 | [命令队列与多帧缓冲](./2026-03/20260326-d3d12-command-queue.md) | D3D12 命令队列和多帧渲染架构 |
|
||||||
| 2026-03-26 | [D3D12设备初始化](./2026-03/20260326-d3d12-device-init.md) | D3D12 设备创建与调试层实现 |
|
| 2026-03-26 | [D3D12设备初始化](./2026-03/20260326-d3d12-device-init.md) | D3D12 设备创建与调试层实现 |
|
||||||
|
|||||||
@@ -238,9 +238,76 @@ _cmd_queue->Signal(_fence, _fence_value);
|
|||||||
|
|
||||||
**围栏值溢出**:64位无符号整数,每秒1000帧需要5.8亿年才回绕,无需担心。
|
**围栏值溢出**:64位无符号整数,每秒1000帧需要5.8亿年才回绕,无需担心。
|
||||||
|
|
||||||
## 7. 渲染表面与窗口
|
## 7. 描述符堆
|
||||||
|
|
||||||
### 7.1 render_surface 结构
|
### 7.1 什么是描述符堆?
|
||||||
|
|
||||||
|
描述符堆是一块连续内存,用于存储描述符(Descriptor)。描述符是告诉 GPU 如何访问资源的数据结构。
|
||||||
|
|
||||||
|
### 7.2 描述符堆类型
|
||||||
|
|
||||||
|
| 类型 | 用途 | 着色器可见 |
|
||||||
|
|------|------|------------|
|
||||||
|
| `CBV_SRV_UAV` | 常量缓冲区、着色器资源、无序访问 | 可选 |
|
||||||
|
| `SAMPLER` | 采样器 | 可选 |
|
||||||
|
| `RTV` | 渲染目标视图 | 否 |
|
||||||
|
| `DSV` | 深度模板视图 | 否 |
|
||||||
|
|
||||||
|
### 7.3 descriptor_handle 结构
|
||||||
|
|
||||||
|
项目封装了描述符句柄:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct descriptor_handle
|
||||||
|
{
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE cpu{}; // CPU 句柄
|
||||||
|
D3D12_GPU_DESCRIPTOR_HANDLE gpu{}; // GPU 句柄
|
||||||
|
|
||||||
|
constexpr bool is_valid() const { return cpu.ptr != 0; }
|
||||||
|
constexpr bool is_shader_visible() const { return gpu.ptr != 0; }
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.4 descriptor_heap 类
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class descriptor_heap
|
||||||
|
{
|
||||||
|
bool initialize(u32 capacity, bool is_shader_visible);
|
||||||
|
descriptor_handle allocate(); // 分配描述符
|
||||||
|
void free(descriptor_handle); // 释放描述符
|
||||||
|
|
||||||
|
private:
|
||||||
|
ID3D12DescriptorHeap* _heap;
|
||||||
|
std::unique_ptr<u32[]> _free_handles{}; // 空闲索引池
|
||||||
|
std::mutex _mutex; // 线程安全
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.5 内存模型
|
||||||
|
|
||||||
|
```
|
||||||
|
描述符堆内存布局:
|
||||||
|
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
|
||||||
|
│ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │...│ │ │ │
|
||||||
|
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
|
||||||
|
↑
|
||||||
|
_cpu_start / _gpu_start
|
||||||
|
|
||||||
|
_free_handles[] = [0, 1, 2, 3, ...] // 空闲索引池
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.6 线程安全
|
||||||
|
|
||||||
|
描述符堆可能被多线程并发访问,使用互斥锁保护:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
std::lock_guard lock(_mutex);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. 渲染表面与窗口
|
||||||
|
|
||||||
|
### 8.1 render_surface 结构
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
struct render_surface {
|
struct render_surface {
|
||||||
@@ -249,7 +316,7 @@ struct render_surface {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
### 7.2 多窗口支持
|
### 8.2 多窗口支持
|
||||||
|
|
||||||
TestRenderer 测试展示了多窗口渲染:
|
TestRenderer 测试展示了多窗口渲染:
|
||||||
|
|
||||||
@@ -262,7 +329,7 @@ for (u32 i{0}; i < _countof(_surfaces); ++i) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 7.3 全屏切换
|
### 8.3 全屏切换
|
||||||
|
|
||||||
通过 `WM_SYSCHAR` 消息处理 Alt+Enter:
|
通过 `WM_SYSCHAR` 消息处理 Alt+Enter:
|
||||||
|
|
||||||
@@ -272,42 +339,42 @@ if (wparam == VK_RETURN && (HIWORD(lparam) & KF_ALTDOWN)) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## 8. 后续学习路径
|
## 9. 后续学习路径
|
||||||
|
|
||||||
### 8.1 基础阶段
|
### 9.1 基础阶段
|
||||||
|
|
||||||
- [x] 完成设备创建和适配器枚举
|
- [x] 完成设备创建和适配器枚举
|
||||||
- [x] 创建命令队列和命令列表
|
- [x] 创建命令队列和命令列表
|
||||||
|
- [x] 描述符堆管理
|
||||||
- [ ] 实现交换链和后台缓冲区
|
- [ ] 实现交换链和后台缓冲区
|
||||||
- [ ] 渲染第一个三角形
|
- [ ] 渲染第一个三角形
|
||||||
|
|
||||||
### 8.2 进阶阶段
|
### 9.2 进阶阶段
|
||||||
|
|
||||||
- [ ] 描述符堆管理
|
|
||||||
- [ ] 根签名和管线状态对象
|
- [ ] 根签名和管线状态对象
|
||||||
- [ ] 资源屏障和同步
|
- [ ] 资源屏障和同步
|
||||||
- [ ] 常量缓冲区和着色器资源
|
- [ ] 常量缓冲区和着色器资源
|
||||||
|
|
||||||
### 8.3 高级阶段
|
### 9.3 高级阶段
|
||||||
|
|
||||||
- [ ] 多线程渲染
|
- [ ] 多线程渲染
|
||||||
- [ ] 资源绑定策略
|
- [ ] 资源绑定策略
|
||||||
- [ ] 动态资源管理
|
- [ ] 动态资源管理
|
||||||
- [ ] 性能优化
|
- [ ] 性能优化
|
||||||
|
|
||||||
## 9. 参考资源
|
## 10. 参考资源
|
||||||
|
|
||||||
### 9.1 官方文档
|
### 10.1 官方文档
|
||||||
|
|
||||||
- [Microsoft D3D12 文档](https://docs.microsoft.com/en-us/windows/win32/direct3d12/direct3d-12-graphics)
|
- [Microsoft D3D12 文档](https://docs.microsoft.com/en-us/windows/win32/direct3d12/direct3d-12-graphics)
|
||||||
- [DXGI 文档](https://docs.microsoft.com/en-us/windows/win32/direct3ddxgi/dx-graphics-dxgi)
|
- [DXGI 文档](https://docs.microsoft.com/en-us/windows/win32/direct3ddxgi/dx-graphics-dxgi)
|
||||||
|
|
||||||
### 9.2 推荐书籍
|
### 10.2 推荐书籍
|
||||||
|
|
||||||
- 《Introduction to 3D Game Programming with DirectX 12》
|
- 《Introduction to 3D Game Programming with DirectX 12》
|
||||||
- 《Real-Time 3D Rendering with DirectX and HLSL》
|
- 《Real-Time 3D Rendering with DirectX and HLSL》
|
||||||
|
|
||||||
### 9.3 项目相关文档
|
### 10.3 项目相关文档
|
||||||
|
|
||||||
- [Graphics渲染架构分析](./Graphics渲染架构分析.md)
|
- [Graphics渲染架构分析](./Graphics渲染架构分析.md)
|
||||||
- [项目约定规范](./项目约定规范.md)
|
- [项目约定规范](./项目约定规范.md)
|
||||||
|
|||||||
Reference in New Issue
Block a user