You are not checking the HRESULT
values so you are missing all error-handling. For COM programming, even with Direct3D, you must check the HRESULT
of every method that can return one for failure. If the return value is safe to ignore, it returns void
instead.
Checking HRESULT
values in old-school C/C++ programs is done with either the FAILED
or SUCCEEDED
macros.
hr = D3D11CreateDeviceAndSwapChain( /* ... */ *);
if (FAILED(hr))
return false;
In most cases, a failed HRESULT
is treated as a 'fast-fail' or a fatal error. In other words, the program cannot proceed if the call fails.
In other cases there can be special case handling to recover from the error perhaps by using different options. For a detailed example of that, see Anatomy of Direct3D 11 Create Device.
In older Microsoft samples based on the legacy DXUT framework, the error handling was done with macros like V
or V_RETURN
which did some tracing or tracing & fatal exit.
In modern C++ samples, we actually use a helper DX::ThrowIfFailed
that generates a C++ exception on a failed HRESULT for the fast-fail
scenario. This makes the code more streamlined and readable:
DX::ThrowIfFailed(
D3D11CreateDeviceAndSwapChain( /* ... */ *)
);
The function itself is defined as:
#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();
}
}
}
Your program should be compiled with /EHsc
which is already in the default Visual Studio templates. See this topic page for more details.
From your code snippet above, you are following a pretty old-school tutorial. A lot has changed even for DirectX 11 development and most of those older tutorials are going to lead to confusion. As you are new to DirectX, I recommend you take a look at the DirectX Tool Kit and the tutorials there first. You can then come back to the older tutorials with a better understanding of 'modern' Direct3D and be able to extract more relevant information from the old stuff.
After checking all HRESULTS, the next thing you should do is enable the Direct3D debug layer which provides extra debugging information in the output window.
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);
You'll note I'm using the C++11 nullptr
which is supported on Visual C++ 2010 or later instead of the old-school NULL
. That's because it is typed. You were using NULL
in two places in your version where the parameter wasn't actually a pointer, it's a number.
With this, you'll get a lot of feedback on basic errors that would help diagnose why in your particular case the swapchain is failing to create. I suspect it's because you are providing some values that are only meaningful for "exclusive fullscreen mode" and not for windowed mode (bufferDesc.RefreshRate
). Instead, try:
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;
This works on VS 2013 or VS 2015 which will initialize the structure to 0 with the ={};
syntax. On older compilers, you'll need to use ZeroMemory
like you did in your old-school code above.
Note that using D3D11_CREATE_DEVICE_DEBUG
will fail on a system that lacks the debugging device which is intended only for developers to use. Details on where you obtain the debug device layer differs based on which version of Windows you are using. See Direct3D SDK Debug Layer Tricks which has a little summary table at the bottom.
Also, debugging in the presence of uninitialized variables is a huge pain. Uninitialized pointers in particular can be a huge time waster. It would help if you did the following:
static HWND hWnd = nullptr;
static IDXGISwapChain* swapChain = nullptr;
static ID3D11Device* dev = nullptr;
static ID3D11DeviceContext* devCon = nullptr;
static ID3D11RenderTargetView* renderTarget = nullptr;
Even better, instead of using raw pointers for your COM objects, you should be using a C++ smart-pointer like Microsoft::WRL::ComPtr
. See this topic page for details. Our modern samples use it, and it works for classic Win32 desktop apps as well as for Windows Store, UWP, and Xbox One apps since it's just a C++ template.