DirectX11--ComPtr智能指针

综述

DirectX11 With Windows SDK完整目录

欢迎加入QQ群: 727623616 可以一起探讨DX11,以及有什么问题也可以在这里汇报。

IUnknown接口类

DirectX11的API是由一系列的COM组件来管理的,这些前缀带I的接口类最终都继承自IUnknown接口类。IUnknown的三个方法如下:

方法描述
IUnknown::AddRef内部引用计数加1。在每次复制了一个这样的指针后,应当调用该方法以保证计数准确性
IUnknown::QueryInterface查询该实例是否实现了另一个接口,如果存在则返回该接口的指针,并且对该接口的引用计数加1
IUnknown::Release内部引用数减1。只有当内部引用数到达0时才会真正释放

在实际的使用情况来看,通常我们几乎不会使用第一个方法。而用的最多的就是第三个方法了,每次用完该实例后,我们必须要使用类似下面的宏来释放:

#define ReleaseCOM(x) { if(x){ x->Release(); x = nullptr; } }

而且如果出现了忘记释放某个接口指针的情况话,内存泄漏的提醒就有可能够你去调试一整天了。

ComPtr智能指针

为了解决上述问题,从繁杂的人工释放中解脱,在本教程中大量使用了ComPtr智能指针。而且在龙书12的教程源码中也用到了该智能指针。该智能指针可以帮助我们来管理这些COM组件实现的接口实例,而无需过多担心内存的泄漏。该智能指针的大小和一般的指针大小是一致的,没有额外的内存空间占用。所以本教程可以不需要用到接口类ID3D11Debug来协助检查内存泄漏。

使用该智能指针需要包含头文件wrl/client.h,并且智能指针类模板ComPtr位于名称空间Microsoft::WRL内。

首先有五个比较常用的方法需要了解一下:

方法描述
ComPtr::Get该方法返回T*,并且不会触发引用计数加1,常用在COM组件接口的函数输入
ComPtr::GetAddressOf该方法返回T**,常用在COM组件接口的函数输出
ComPtr::Reset该方法对里面的实例调用Release方法,并将指针置为nullptr
ComPtr::ReleaseAndGetAddressOf该方法相当于先调用Reset方法,再调用GetAddressOf方法获取T**,常用在COM组件接口的函数输出,适用于实例可能会被反复构造的情况下
ComPtr::As一个模板函数,可以替代IUnknown::QueryInterface的调用,需要传递一个ComPtr实例的地址

然后是一些运算符重载的方法:

运算符描述
&相当于调用了ComPtr<T>::ReleaseAndGetAddressOf方法,不推荐使用
->和裸指针的行为一致
=不要将裸指针指向的实例赋给它,若传递的是ComPtr的不同实例则发生交换
==和!=可以和nullptr,或者另一个ComPtr实例进行比较

注意:大致在比10.0.16299.0更早的Windows SDK版本中,ComPtr使用了一个RemoveIUnknownBase类模板将IUnknown的三个接口都设为了private,以防止用户直接操作这些方法,这也就使得ComPtr无法直接使用COM组件的QueryInterface方法。因此,使用ComPtr<T>::As是一种合适的选择。

个人建议,在使用该智能指针后就应该要避免使用IUnknown提供的三个接口方法来进行操作。

虽然替换成ComPtr后代码量变长了,但是带来的收益肯定比你自己花费大量时间在检查释放内存上强的多。

下面的D3DApp将所有COM组件指针都换成了ComPtr

class D3DApp
{
public:
    D3DApp(HINSTANCE hInstance);              // 在构造函数的初始化列表应当设置好初始参数
    virtual ~D3DApp();

    HINSTANCE AppInst()const;                 // 获取应用实例的句柄
    HWND      MainWnd()const;                 // 获取主窗口句柄
    float     AspectRatio()const;             // 获取屏幕宽高比

    int Run();                                // 运行程序,进行游戏主循环

                                              // 框架方法。客户派生类需要重载这些方法以实现特定的应用需求
    virtual bool Init();                      // 该父类方法需要初始化窗口和Direct3D部分
    virtual void OnResize();                  // 该父类方法需要在窗口大小变动的时候调用
    virtual void UpdateScene(float dt) = 0;   // 子类需要实现该方法,完成每一帧的更新
    virtual void DrawScene() = 0;             // 子类需要实现该方法,完成每一帧的绘制
    virtual LRESULT MsgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
    // 窗口的消息回调函数
protected:
    bool InitMainWindow();      // 窗口初始化
    bool InitDirect3D();        // Direct3D初始化

    void CalculateFrameStats(); // 计算每秒帧数并在窗口显示

protected:

    HINSTANCE m_hAppInst;        // 应用实例句柄
    HWND      m_hMainWnd;        // 主窗口句柄
    bool      m_AppPaused;       // 应用是否暂停
    bool      m_Minimized;       // 应用是否最小化
    bool      m_Maximized;       // 应用是否最大化
    bool      m_Resizing;        // 窗口大小是否变化
    bool      m_Enable4xMsaa;    // 是否开启4倍多重采样
    UINT      m_4xMsaaQuality;   // MSAA支持的质量等级


    GameTimer m_Timer;           // 计时器

    // 使用模板别名(C++11)简化类型名
    template <class T>
    using ComPtr = Microsoft::WRL::ComPtr<T>;
    // Direct3D 11
    ComPtr<ID3D11Device> m_pd3dDevice;                    // D3D11设备
    ComPtr<ID3D11DeviceContext> m_pd3dImmediateContext;   // D3D11设备上下文
    ComPtr<IDXGISwapChain> m_pSwapChain;                  // D3D11交换链
    // Direct3D 11.1
    ComPtr<ID3D11Device1> m_pd3dDevice1;                  // D3D11.1设备
    ComPtr<ID3D11DeviceContext1> m_pd3dImmediateContext1; // D3D11.1设备上下文
    ComPtr<IDXGISwapChain1> m_pSwapChain1;                // D3D11.1交换链
    // 常用资源
    ComPtr<ID3D11Texture2D> m_pDepthStencilBuffer;        // 深度模板缓冲区
    ComPtr<ID3D11RenderTargetView> m_pRenderTargetView;   // 渲染目标视图
    ComPtr<ID3D11DepthStencilView> m_pDepthStencilView;   // 深度模板视图
    D3D11_VIEWPORT m_ScreenViewport;                      // 视口

    // 派生类应该在构造函数设置好这些自定义的初始参数
    std::wstring m_MainWndCaption;                       // 主窗口标题
    int m_ClientWidth;                                   // 视口宽度
    int m_ClientHeight;                                  // 视口高度
};

DirectX11 With Windows SDK完整目录

欢迎加入QQ群: 727623616 可以一起探讨DX11,以及有什么问题也可以在这里汇报。

转载于:https://www.cnblogs.com/X-Jun/p/10189859.html

`d3dXXX.dll` 是 Direct3D 系列动态链接库的通用命名格式(如 `d3d9.dll`、`d3d11.dll`、`d3d12.dll`),属于微软 DirectX 图形 API 的核心组件,负责在 Windows 系统中实现 3D 图形渲染、硬件加速和游戏开发中的底层图形操作。以下是详细说明和技术解析: --- ### **1. 核心功能** #### **(1) 图形渲染管线** - **顶点处理**:通过 `d3dXXX.dll` 提供的 API 转换 3D 模型顶点坐标(模型空间→世界空间→视口空间)。 - **像素着色**:支持 HLSL(High-Level Shading Language)编写着色器,实现光照、纹理映射等效果。 - **光栅化**:将三角形网格转换为屏幕像素,支持抗锯齿(MSAA/FXAA)和深度测试。 #### **(2) 硬件加速** - 调用 GPU 指令集(如 NVIDIA CUDA、AMD ROCm)执行并行计算,提升渲染性能。 - 示例:`d3d11.dll` 中的 `ID3D11DeviceContext::Draw()` 方法通过 GPU 绘制数百万个三角形。 #### **(3) 资源管理** - 管理显存中的纹理、缓冲区、着色器等资源。 - 示例:`d3d12.dll` 的描述符堆(Descriptor Heap)机制优化资源访问效率。 #### **(4) 多线程支持** - `d3d11.dll` 和 `d3d12.dll` 支持多线程命令提交,减少 CPU 瓶颈。 - 示例:`d3d12.dll` 的命令队列(Command Queue)允许异步执行渲染、计算和复制操作。 --- ### **2. 常见 `d3dXXX.dll` 文件** | 文件名 | 对应 DirectX 版本 | 典型应用场景 | |-----------------|-------------------|----------------------------------| | `d3d9.dll` | Direct3D 9 | 老旧游戏(如《魔兽争霸3》) | | `d3d10.dll` | Direct3D 10 | Windows Vista/7 默认图形驱动 | | `d3d11.dll` | Direct3D 11 | 现代游戏(如《GTA V》) | | `d3d12.dll` | Direct3D 12 | 高性能游戏(如《赛博朋克2077》) | | `d3dcompiler_XX.dll` | 着色器编译器 | 动态编译 HLSL 着色器代码 | --- ### **3. 开发者如何调用 `d3dXXX.dll`(C++ 示例)** #### **(1) 初始化 Direct3D 11 设备** ```cpp #include <d3d11.h> #include <wrl/client.h> // ComPtr 智能指针 using Microsoft::WRL::ComPtr; void InitD3D11(HWND hwnd) { // 创建设备与交换链 DXGI_SWAP_CHAIN_DESC sd = {}; sd.BufferCount = 1; sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; sd.OutputWindow = hwnd; sd.SampleDesc.Count = 1; sd.Windowed = TRUE; ComPtr<IDXGISwapChain> swapChain; ComPtr<ID3D11Device> device; ComPtr<ID3D11DeviceContext> context; D3D11CreateDeviceAndSwapChain( nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, nullptr, 0, D3D11_SDK_VERSION, &sd, &swapChain, &device, nullptr, &context ); // 创建渲染目标视图(Render Target View) ComPtr<ID3D11RenderTargetView> rtv; ComPtr<ID3D11Texture2D> backBuffer; swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), &backBuffer); device->CreateRenderTargetView(backBuffer.Get(), nullptr, &rtv); context->OMSetRenderTargets(1, rtv.GetAddressOf(), nullptr); } ``` #### **(2) 加载动态库并调用函数(手动映射)** ```cpp #include <windows.h> #include <iostream> typedef HRESULT(WINAPI* D3D11CreateDeviceFunc)( IDXGIAdapter*, D3D_DRIVER_TYPE, HMODULE, UINT, const D3D_FEATURE_LEVEL*, UINT, UINT, ID3D11Device**, D3D_FEATURE_LEVEL*, ID3D11DeviceContext** ); void LoadD3D11Manually() { HMODULE hD3D11 = LoadLibrary(L"d3d11.dll"); if (!hD3D11) { std::cerr << "Failed to load d3d11.dll" << std::endl; return; } D3D11CreateDeviceFunc createDevice = (D3D11CreateDeviceFunc)GetProcAddress( hD3D11, "D3D11CreateDevice" ); if (createDevice) { ID3D11Device* device = nullptr; ID3D11DeviceContext* context = nullptr; createDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, nullptr, 0, D3D11_SDK_VERSION, &device, nullptr, &context); std::cout << "D3D11 device created successfully!" << std::endl; } FreeLibrary(hD3D11); } ``` --- ### **4. 关键技术点** #### **(1) 版本兼容性** - **向下兼容**:`d3d12.dll` 程序可在仅安装 `d3d11.dll` 的系统上通过 D3D11On12 层运行。 - **功能级别(Feature Level)**:通过 `D3D_FEATURE_LEVEL` 指定最低支持的硬件规格(如 `11_0` 对应支持 Direct3D 11 的 GPU)。 #### **(2) 调试与优化** - **PIX 工具**:微软官方图形调试器,可捕获 `d3dXXX.dll` 的调用堆栈和资源状态。 - **GPU 性能分析器**:通过 `d3d12.dll` 的 `ID3D12DebugDevice` 接口分析渲染瓶颈。 #### **(3) 错误处理** - 检查 `HRESULT` 返回值(如 `DXGI_ERROR_DEVICE_REMOVED` 表示 GPU 驱动崩溃)。 - 示例: ```cpp HRESULT hr = device->CreateBuffer(&bufferDesc, nullptr, &buffer); if (FAILED(hr)) { std::cerr << "CreateBuffer failed: " << hr << std::endl; } ``` --- ### **5. 国产图形引擎中的 `d3dXXX.dll` 应用** - **Cocos Creator**:支持通过 `d3d11.dll` 渲染 2D/3D 场景,提供 WebGL 跨平台兼容方案。 - **LayaAir**:基于 Direct3D 113D 引擎,优化移动端与 PC 端的图形性能。 - **腾讯 TRPG**:自研图形引擎底层调用 `d3d12.dll`,实现大规模场景的实时渲染。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值