DX12

环境搭建

我们可以向UE一样,把需要的头文件封印在 ThirdParty 中:

诸如 dxgi1_6.h dxgiformat.h 这样的头文件,我们可以在这里找到:https://github.com/microsoft/win32metadata/tree/main/generation/WinSDK/RecompiledIdlHeaders/shared

其实本地装了Windows sdk,这些文件就会在这里:

C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\shared

而 d3dx12.h,我们则可以在这里找到:https://github.com/microsoft/DirectXTK12/tree/main/Src

关于 UE 的做法

ue可以看到把相关的一些文件都放在 third party 了,

这样子就不需要依赖Windows SDK。而我们目前是依赖Windows SDK,需要在cmake中链接:

target_link_libraries(HEngineRuntime PUBLIC d3d11.lib d3d12.lib dxgi.lib dxguid.lib D3DCompiler.lib d2d1.lib dwrite.lib winmm.lib)

初始化

我们想用 EnumAdapterByGpuPreference 去按照性能来排序枚举系统中的适配器,这需要用到IDXGIFactory6,参考:

https://blog.csdn.net/u014038143/article/details/102493360

参考官方文档:https://learn.microsoft.com/en-us/windows/win32/api/_direct3ddxgi/

每一代dxgi都会升级一些新的接口,同时保持旧的接口兼容,这些也是包含在 Windows sdk 里的,应该也就和驱动相关了。

Device

https://directx11.tech/#/part1/01

https://learn.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-d3d12createdevice

参考上面链接,D3D12CreateDevice 函数其实是统一创建一个 ID3D11Device,我们可以需要哪个更高型号再转型查看可不可用。例如ue的做法:

Engine\Source\Runtime\D3D12RHI\Private\D3D12Adapter.cpp

同样根据之前说的,我们想用 IDXGIFactory6 版本的 EnumAdapterByGpuPreference 方法,ue 是这样做的:

不过事实上除了 RootDevice->QueryInterface,如果是 ComPtr 的话(UE没用微软的 ComPtr,而是自己包出了 TRefCountPtr ),可以直接用 ComPtr::As,例如:

相当于调用 IUnknown::QueryInterface,失败了也只不过是返回一个nullptr指针(对应上图即 dxgiFactory2 为 nullptr)

D3D_FEATURE_LEVEL

参考:https://directx11.tech/#/part1/01

我们可以轮询特性数组 D3D_FEATURE_LEVEL featureLevels 来检测所支持的特性等级,它的定义可以在 d3dcommon 里找到,具体安装位置在安装的 Windows sdk 的 C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\um 里面。而 10.0.19041.0 是没有 D3D_FEATURE_LEVEL_12_2 的,这就没法使用 Shader model 6.5,具体特性等级的差异可以看:https://learn.microsoft.com/en-us/windows/win32/direct3d11/overviews-direct3d-11-devices-downlevel-intro

这一特性等级需要在 10.0.20348.0 及以上的版本才能开启。

描述符管理

http://diligentgraphics.com/diligent-engine/architecture/d3d12/ https://zhuanlan.zhihu.com/p/129257338 https://github.com/DiligentGraphics/DiligentCore/blob/master/Graphics/GraphicsAccessories/interface/VariableSizeAllocationsManager.hpp

内存分配

当和 Descriptor 关联的 Resource View 释放时,Descriptor 在逻辑上就成为可重用的状态,而这一切都需要 API 使用者自己来保证,所以可以一些常用的内存分配算法如 Buddy 来管理 Descriptor 的分配和释放,以此达到 Descriptor 重用的目的。

微软官方给的例子就是 Buddy Allocator:https://github.com/microsoft/DirectX-Graphics-Samples/blob/master/MiniEngine/Core/BuddyAllocator.h

我们也能参考前面的链接:http://diligentgraphics.com/diligent-engine/architecture/d3d12/

104使用的vulkan,用到了第三方库VulkanMemoryAllocator:https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator/blob/master/include/vk_mem_alloc.h

我发现这个库也有d3d12版本(官方说明的上面这个vulkan版本的等效库):https://github.com/GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator

对应的文档:https://gpuopen-librariesandsdks.github.io/D3D12MemoryAllocator/html/

RenderGraph

参考:https://github.com/mateeeeeee/Adria-DX12/tree/master/Adria

封装

参考:

https://github.com/SuikaSibyl/SibylEngine2021

https://github.com/J-Mat/ZeroEngine/tree/main/ZeroEngine/Engine/Source/Runtime/Render/RHI

https://www.zhihu.com/column/c_1414208206361587713

https://www.zhihu.com/column/c_1434895110592552960

主要参考:

https://github.com/jpvanoosten/LearningDirectX12/tree/main

https://www.3dgep.com/learning-directx-12-2/

D3D12MA:

https://github.dev/mateeeeeee/Adria-DX12/tree/master/Adria/Graphics

发现它主要是在 Buffer 和 Texture 使用 D3D12MA 管理。

更多资料

https://developer.nvidia.com/dx12-dos-and-donts

http://diligentgraphics.com/diligent-engine/architecture/d3d12/managing-descriptor-heaps/

https://gpuopen.com/learn/get-the-most-out-of-smart-access-memory/

https://stackoverflow.com/questions/37277332/directx-12-descriptor-heaps

https://www.intel.com/content/www/us/en/developer/articles/technical/introduction-to-resource-binding-in-microsoft-directx-12.html

https://microsoft.github.io/DirectX-Specs/d3d/ResourceBinding.html#memory-residency-management-separated-from-binding

https://microsoft.github.io/DirectX-Specs/

Last updated