[DirectX] Beginning DX Learning - SwapChain::Present crashes program and driver

Started by
5 comments, last by thk123 13 years, 1 month ago
Hello, I am just starting out with Direct X 11. I have been following these tutorials but I am stuck at the first lesson with actual rendering (drawing a triangle). Specifically, my program crashes when I reach the present line. Actually, it doesn't crash but my computer freezes up, then the screen goes blank, then comes back on with a message saying my display driver has crashed and my program doesn't do anything more. I have updated my drivers and my graphics card is running Direct X 11. Heres the code

#include <Windows.h>
#include <WindowsX.h>
#include <d3d11.h>
#include <d3dx11.h>
#include <d3dx10.h>

#pragma comment (lib, "d3d11.lib")
#pragma comment (lib, "d3dx11.lib")
#pragma comment (lib, "d3dx10.lib")

#define ScreenWidth 800
#define ScreenHeight 600

IDXGISwapChain *swapChain;
ID3D11Device *device;
ID3D11DeviceContext *devcon;
ID3D11RenderTargetView *backBuffer;

ID3D11VertexShader *mVertexShader;
ID3D11PixelShader *mPixelShader;

ID3D11Buffer *mVideoBuffer;
ID3D11InputLayout *mInputLayout;

struct Vertex
{
float x, y, z;
D3DXCOLOR Color;
};


void Init3D(HWND windowHandle);
void RenderFrame();
void Clean3D();
void InitGraphics();
void InitPipeline();

LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
//MessageBox(NULL, "Hello world","My Window", MB_OK);
HWND windowHandle;
WNDCLASSEX windowClass;

ZeroMemory(&windowClass, sizeof(WNDCLASSEX));

windowClass.cbSize = sizeof(WNDCLASSEX);
windowClass.style = CS_HREDRAW | CS_VREDRAW;
windowClass.lpfnWndProc = WindowProc;
windowClass.hInstance = hInstance;
windowClass.hCursor = LoadCursor(NULL,IDC_ARROW);
//windowClass.hbrBackground = (HBRUSH)COLOR_WINDOW;
windowClass.lpszClassName = "WindowClass1";

RegisterClassEx(&windowClass);

RECT desiredSize = {0,0,500,400};
AdjustWindowRect(&desiredSize,WS_OVERLAPPEDWINDOW, FALSE);

windowHandle = CreateWindowEx(NULL,"WindowClass1","TK Program", WS_OVERLAPPEDWINDOW,0,0,ScreenWidth,ScreenHeight,NULL, NULL, hInstance, NULL);

ShowWindow(windowHandle, nCmdShow);

Init3D(windowHandle);

MSG msg = {0};

while(true)
{
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);

if(msg.message == WM_QUIT)
{
break;
}

//do some game related stuff
}
RenderFrame();
}
Clean3D();
return msg.wParam;
}

LRESULT CALLBACK WindowProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;

}break;
}

return DefWindowProc (hWnd, message,wParam,lParam);
}

void Init3D(HWND windowHandle)
{
DXGI_SWAP_CHAIN_DESC swapChainDescription;
ZeroMemory(&swapChainDescription, sizeof(DXGI_SWAP_CHAIN_DESC));

swapChainDescription.BufferCount = 1;
swapChainDescription.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDescription.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDescription.BufferDesc.Width = ScreenWidth;
swapChainDescription.BufferDesc.Height = ScreenHeight;
swapChainDescription.OutputWindow = windowHandle;
swapChainDescription.SampleDesc.Count = 4;
swapChainDescription.Windowed = true;
swapChainDescription.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;

D3D11CreateDeviceAndSwapChain(NULL,D3D_DRIVER_TYPE_HARDWARE,NULL,NULL,NULL,NULL, D3D11_SDK_VERSION,&swapChainDescription, &swapChain,&device,NULL,&devcon);

ID3D11Texture2D *pBackBuffer = NULL;
swapChain->GetBuffer(0,__uuidof(ID3D11Texture2D),(LPVOID*)&pBackBuffer);
device->CreateRenderTargetView(pBackBuffer, NULL, &backBuffer);
pBackBuffer->Release();

devcon->OMSetRenderTargets(1, &backBuffer,NULL);

D3D11_VIEWPORT viewport;
ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));

viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = ScreenWidth;
viewport.Height = ScreenHeight;

devcon->RSSetViewports(1,&viewport);

InitGraphics();
InitPipeline();
}

void InitPipeline()
{
ID3D10Blob *vertexShader, *pixelShader;
D3DX11CompileFromFile("Shaders.hlsl",0,0,"VShader","vs_5_0",0,0,0,&vertexShader,0,0);
D3DX11CompileFromFile("Shaders.hlsl",0,0,"PShader","ps_5_0",0,0,0,&pixelShader,0,0);

device->CreateVertexShader(vertexShader->GetBufferPointer(),vertexShader->GetBufferSize(),NULL,&mVertexShader);
device->CreatePixelShader(pixelShader->GetBufferPointer(),pixelShader->GetBufferSize(),NULL,&mPixelShader);

devcon->VSSetShader(mVertexShader,0,0);
devcon->PSSetShader(mPixelShader,0,0);

D3D11_INPUT_ELEMENT_DESC inputElementDesc[] =
{
{"POSITION",0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA,0},
{"COLOR",0,DXGI_FORMAT_R32G32B32_FLOAT, 0,12,D3D11_INPUT_PER_VERTEX_DATA,0},
};

device->CreateInputLayout(inputElementDesc,2,vertexShader->GetBufferPointer(),vertexShader->GetBufferSize(),&mInputLayout);
devcon->IASetInputLayout(mInputLayout);
}

void InitGraphics()
{
Vertex OurVertices[] = {{0.0f, 0.5f, 0.0f, D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f)},
{0.45f, -0.5, 0.0f, D3DXCOLOR(0.0f, 1.0f, 0.0f, 1.0f)},
{-0.45f, -0.5f, 0.0f, D3DXCOLOR(0.0f, 0.0f, 1.0f, 1.0f)},
{0.7f,0.6f,0.3f,D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f)}
};
D3D11_BUFFER_DESC bufferDescription;
ZeroMemory(&bufferDescription,sizeof(D3D11_BUFFER_DESC));

bufferDescription.Usage = D3D11_USAGE_DYNAMIC;
bufferDescription.ByteWidth = 3 * sizeof(Vertex);
bufferDescription.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bufferDescription.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;

device->CreateBuffer(&bufferDescription,NULL,&mVideoBuffer);

D3D11_MAPPED_SUBRESOURCE mappedSubResource;
devcon->Map(mVideoBuffer,NULL,D3D11_MAP_WRITE_DISCARD,NULL, &mappedSubResource);
memcpy(mappedSubResource.pData,OurVertices,sizeof(OurVertices));
devcon->Unmap(mVideoBuffer,NULL);
}

void RenderFrame()
{
devcon->ClearRenderTargetView(backBuffer, D3DXCOLOR(0.0f,0.2f,0.4f,1.0f));

UINT stride = sizeof(Vertex);
UINT offset = 0;
devcon->IASetVertexBuffers(0,1,&mVideoBuffer,&stride,&offset);
devcon->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
devcon->Draw(3,0);

swapChain->Present(0,0);
}

void Clean3D()
{
swapChain->SetFullscreenState(false,NULL);

mPixelShader->Release();
mVertexShader->Release();
swapChain->Release();
backBuffer->Release();
device->Release();
devcon->Release();
}
-thk123botworkstudio.blogspot.com - Shamelessly advertising my new developers blog ^^
Advertisement
Use the flag D3D11_CREATE_DEVICE_DEBUG for the flags in D3D11CreateDeviceAndSwapChain, and then run with the debugger. You should get debug output if anything is wrong. Overall your code is unsafe as you don't seem to be checking any return values at all. D3D11 functions usually return a HRESULT value which will tell you if they failed.

Use the flag D3D11_CREATE_DEVICE_DEBUG for the flags in D3D11CreateDeviceAndSwapChain, and then run with the debugger. You should get debug output if anything is wrong. Overall your code is unsafe as you don't seem to be checking any return values at all. D3D11 functions usually return a HRESULT value which will tell you if they failed.


Ok so I put in HRESULT results in front of all the methods that return HRESULT and the problem appear to be with the shader creation which returns "E_INVALIDARG". If I'm honest, the shader part was something the tutorial glossed over. What I did to incorporate the shader was add a file called "Shaders.hlsl" in to the source folder of the solution containing:

struct VOut
{
float4 position : SV_POSITION;
float4 color : COLOR;
};

VOut VShader(float4 position : POSITION, float4 color : COLOR)
{
VOut output;

output.position = position;
output.color = color;

return output;
}


float4 PShader(float4 position : SV_POSITION, float4 color : COLOR) : SV_TARGET
{
return color;
}


The shader loading code is:

ID3D10Blob *vertexShader, *pixelShader;
D3DX11CompileFromFile("Shaders.hlsl",0,0,"VShader","vs_5_0",0,0,0,&vertexShader,0,0);
D3DX11CompileFromFile("Shaders.hlsl",0,0,"PShader","ps_5_0",0,0,0,&pixelShader,0,0);
LPVOID vertexBufferPointer = vertexShader->GetBufferPointer();
SIZE_T vertexBufferSize = vertexShader->GetBufferSize();
//HRESULT result = device->CreateVertexShader(vertexShader->GetBufferPointer(),vertexShader->GetBufferSize(),NULL,&mVertexShader);
HRESULT result = device->CreateVertexShader(vertexBufferPointer, vertexBufferSize,NULL,&mVertexShader);
result = device->CreatePixelShader(pixelShader->GetBufferPointer(),pixelShader->GetBufferSize(),NULL,&mPixelShader);


Is this where I am going wrong? Also, on a more general note, At each of the HRESULT points, should I be checking that they're ok before continuing? Would hate to be picking up bad practices when I have hardly begun!
-thk123botworkstudio.blogspot.com - Shamelessly advertising my new developers blog ^^
Yes, generally you want to check as much as possible, or at least methods that are somewhat likely to fail. Compiling shaders is one of those. Does it fail at CreateVertexShader or CreatePixelShader?
If you have a DX11 capable card that is somewhat strange, if D3DX11CompileFromFile succeeds. D3DX11CompileFromFile also returns a HRESULT, and the last parameter can give you compile errors for the shader.

Did you use the debug flag when creating your device?
If you try to call a D3D11 method and have some invalid parameters you will get debug output in the 'Output' window when running with the debugger, which will tell you what's wrong. In VC++, just press F5 to run with the debugger, and make sure to select Debug in the target menu, which should be the default if you didn't change it to Release.

Anyway, to correctly check for errors when compiling the shader, do something like this:

HRESULT hResult;

ID3DBlob *pCompiledCode = NULL;
ID3DBlob *pErrorMsgs = NULL;
hResult = D3DX11CompileFromFile(TEXT("Shaders.hlsl"), NULL, NULL, "VShader", "vs_5_0", 0, 0, NULL, &pCompiledCode, &pErrorMsgs, NULL);
if(FAILED(hResult)) {
MessageBoxA(NULL, (char*)pErrorMsgs->GetBufferPointer(), "D3DX11CompileFromFile failed", MB_OK);
}

ID3D11VertexShader *pVertexShader;
hResult = pDevice->CreateVertexShader(pCompiledCode->GetBufferPointer(), pCompiledCode->GetBufferSize(), NULL, &pVertexShader);
if(FAILED(hResult)) {
asdf; // Add breakpoint here
}

if(pErrorMsgs != NULL)
pErrorMsgs->Release();

pCompiledCode->Release();


Couple that with D3D11_CREATE_DEVICE_DEBUG and you will be able to identify most errors easily.


From what I've heard directxtutorial.com has never been very good at any of this, and skips many things that are important to write safe and stable code. Then again there's not that many D3D11 tutorials I know about.. but you should definitely keep in mind that many functions can fail, and will fail, especially during development when you're changing things around. It's very easy to get a mistake into a shader, and without proper debug output you have no way of knowing which call failed.

...
From what I've heard directxtutorial.com has never been very good at any of this, and skips many things that are important to write safe and stable code. Then again there's not that many D3D11 tutorials I know about.. but you should definitely keep in mind that many functions can fail, and will fail, especially during development when you're changing things around. It's very easy to get a mistake into a shader, and without proper debug output you have no way of knowing which call failed.


Thank you so much for you help. The problem was the version number, apparently has to be 4 not 5? Thanks for the heads up about safety, will now make sure pointers point to null and I am actually handling error messages :P

Thanks,
-thk123botworkstudio.blogspot.com - Shamelessly advertising my new developers blog ^^
If it has to be 4, then that probably means you're running at feature level 10.0. What graphics card do you have?

You can check your feature level with pDevice->GetFeatureLevel(). The following values are valid, and depend on your graphics card:

D3D_FEATURE_LEVEL featureLevel = pDevice->GetFeatureLevel();

D3D_FEATURE_LEVEL_9_1;
D3D_FEATURE_LEVEL_9_2;
D3D_FEATURE_LEVEL_9_3;
D3D_FEATURE_LEVEL_10_0;
D3D_FEATURE_LEVEL_10_1;
D3D_FEATURE_LEVEL_11_0;


Shader version 5.0 only works with feature level 11.0.
Yeah it is only feature level 10, thanks again for your help :)
-thk123botworkstudio.blogspot.com - Shamelessly advertising my new developers blog ^^

This topic is closed to new replies.

Advertisement