I've been learning DirectX by following some tutorials but every time I type something myself then DirectX won't work. Here is an example of the latest error that I can't fix after hours of research:
//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
Whenever I call InitD3d11, I get an error saying that the swapChain is a NULL pointer. I assume that bufferDesc and/or swapChainDesc has some invalid data but the compiler can't give me any clue what is responsible for the error. Can someone please show me how to trace and fix errors like this? Thanks.
You are not checking the
HRESULTvalues so you are missing all error-handling. For COM programming, even with Direct3D, you must check theHRESULTof every method that can return one for failure. If the return value is safe to ignore, it returnsvoidinstead.Checking
HRESULTvalues in old-school C/C++ programs is done with either theFAILEDorSUCCEEDEDmacros.In most cases, a failed
HRESULTis 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 modern C++ samples, we actually use a helper
DX::ThrowIfFailedthat generates a C++ exception on a failed HRESULT for thefast-failscenario. This makes the code more streamlined and readable:The function itself is defined as:
Your program should be compiled with
/EHscwhich is already in the default Visual Studio templates. See this topic page for more details.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.
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:Note that using
D3D11_CREATE_DEVICE_DEBUGwill 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:
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.