2016-12-15 169 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++模板。