2016-12-15 149 views
1

我一直在学习DirectX,但是每次我自己输入一些内容时,DirectX都不起作用。这里是我无法的研究小时后修复最新的错误示例:调试DirectX代码

 //Header.h 
    static HWND hWnd; 
    static IDXGISwapChain* swapChain; 
    static ID3D11Device* dev; 
    static ID3D11DeviceContext* devCon; 
    static ID3D11RenderTargetView* renderTarget; 

    //DirectX.cpp 
    bool InitD3D11(HINSTANCE hInst) 
{ 
    HRESULT hr; 
    DXGI_MODE_DESC bufferDesc; 
    ZeroMemory(&bufferDesc, sizeof(DXGI_MODE_DESC)); 
    bufferDesc.Width = 800; 
    bufferDesc.Height = 600; 
    bufferDesc.RefreshRate.Numerator = 60; 
    bufferDesc.RefreshRate.Denominator = 1; 
    bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 
    bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; 
    bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; 

    DXGI_SWAP_CHAIN_DESC swapChainDesc; 
    ZeroMemory(&swapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC)); 
    swapChainDesc.BufferDesc = bufferDesc; 
    swapChainDesc.SampleDesc.Count = 1; 
    swapChainDesc.SampleDesc.Quality = 0; 
    swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 
    swapChainDesc.BufferCount = 1; 
    swapChainDesc.OutputWindow = hWnd; 
    swapChainDesc.Windowed = true; 
    swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; 

    hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, NULL, NULL, NULL, D3D11_SDK_VERSION, &swapChainDesc, &swapChain, &dev, NULL, &devCon); 

    ID3D11Texture2D* backBuffer; 
    hr = swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&backBuffer); 
    hr = dev->CreateRenderTargetView(backBuffer, NULL, &renderTarget); 
    backBuffer->Release(); 
    devCon->OMSetRenderTargets(1, &renderTarget, NULL); 
    return true; 
} 
//This is not the full code - I linked directx and lib files and stuff like that. 
//If I copy and paste code from tutorials, everything runs fine 

每当我打电话InitD3d11,我得到一个错误说,swapChain是一个空指针。我假设bufferDesc和/或swapChainDesc有一些无效的数据,但编译器不能给我任何线索是什么导致了错误。有人可以告诉我如何跟踪和修复这样的错误吗?谢谢。

回答

3

您没有检查HRESULT值,因此您缺少所有错误处理。对于COM编程,即使使用Direct3D,必须也检查HRESULT的每个方法,可以返回一个失败的方法。如果返回值可以忽略,则返回void

检查旧版C/C++程序中的HRESULT值是通过FAILEDSUCCEEDED宏来完成的。

hr = D3D11CreateDeviceAndSwapChain(/* ... */ *); 
if (FAILED(hr)) 
    return false; 

在大多数情况下,失败的HRESULT被视为“快倒”或致命错误。换句话说,如果呼叫失败,程序不能继续。

在其他情况下,可能会出现特殊情况处理,以便通过使用不同的选项从错误中恢复。有关详细示例,请参阅Anatomy of Direct3D 11 Create Device

在基于传统DXUT框架旧的Microsoft样本,错误处理与像VV_RETURN其中做了一些跟踪或跟踪&致命的退出宏来完成。

在现代C++的样品,我们实际使用的辅助DX::ThrowIfFailed,关于失败的HRESULT为fast-fail场景生成C++异常。这使得代码更精简和可读性:

DX::ThrowIfFailed(
    D3D11CreateDeviceAndSwapChain(/* ... */ *) 
); 

功能本身被定义为:

#include <exception> 

namespace DX 
{ 
    inline void ThrowIfFailed(HRESULT hr) 
    { 
     if (FAILED(hr)) 
     { 
      // Set a breakpoint on this line to catch DirectX API errors 
      throw std::exception(); 
     } 
    } 
} 

你的程序应该与/EHsc这已经是默认的Visual Studio模板进行编译。有关更多详细信息,请参阅this topic page

从上面的代码片段可以看到一个漂亮的老派教程。即使对于DirectX 11开发人员而言,也发生了很多变化,大多数较老的教程都会导致混淆。由于您是DirectX的新手,我建议您先看看DirectX Tool Kittutorials。然后,您可以更好地了解“现代”的Direct3D,并且能够从旧的东西中提取更多相关信息,从而回到较老的教程。

检查所有HRESULTS,你应该做的下一件事后是启用的Direct3D调试层提供在输出窗口额外调试信息。

DWORD createDeviceFlags = 0; 
#ifdef _DEBUG 
    createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; 
#endif 

hr = D3D11CreateDeviceAndSwapChain(
    nullptr, D3D_DRIVER_TYPE_HARDWARE, 
    nullptr, createDeviceFlags, nullptr, 
    0, D3D11_SDK_VERSION, 
    &swapChainDesc, &swapChain, &dev, nullptr, &devCon); 

你会注意到我使用的是C++ 11 nullptr这是支持的Visual C++ 2010或更高版本,而不是老派NULL。这是因为它是键入的。您在版本中的两个地方使用NULL,其中参数实际上不是指针,而是数字。

有了这个,你会得到基本的错误很多的反馈,这将有助于诊断为什么在您的特定情况下,swapchain未能建立。我怀疑这是因为您提供的某些值仅对“独占全屏模式”有意义,而不适用于窗口模式(bufferDesc.RefreshRate)。相反,尝试:

DXGI_SWAP_CHAIN_DESC swapChainDesc = {}; 
swapChainDesc.BufferDesc.Width = 800; 
swapChainDesc.BufferDesc.Height = 600; 
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 
swapChainDesc.SampleDesc.Count = 1; 
swapChainDesc.SampleDesc.Quality = 0; 
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 
swapChainDesc.BufferCount = 1; 
swapChainDesc.OutputWindow = hWnd; 
swapChainDesc.Windowed = TRUE; 
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; 

这适用于VS 2013年或2015年VS将结构与={};语法初始化为0。在较老的编译器上,您需要使用ZeroMemory,就像您在上面的旧版代码中一样。

请注意,在没有仅供开发人员使用的调试设备的系统上使用D3D11_CREATE_DEVICE_DEBUG会失败。有关获取调试设备层的位置的详细信息取决于您使用的Windows版本。见Direct3D SDK Debug Layer Tricks,底部有一张小汇总表。

另外,调试存在未初始化的变量是一个巨大的痛苦。特别是未初始化的指针可能会浪费大量时间。

static HWND hWnd = nullptr; 
static IDXGISwapChain* swapChain = nullptr; 
static ID3D11Device* dev = nullptr; 
static ID3D11DeviceContext* devCon = nullptr; 
static ID3D11RenderTargetView* renderTarget = nullptr; 

更妙的是,而不是使用原始指针为您的COM对象,你应该使用C++智能指针像Microsoft::WRL::ComPtr:如果你做了以下这将有助于。详情请参阅this topic page。我们的现代样本使用它,它适用于经典的Win32桌面应用程序以及Windows Store,UWP和Xbox One应用程序,因为它只是一个C++模板。