Setting up DirectX issues...

Started by
17 comments, last by SteveHatcher 10 years, 4 months ago

Hi Guys,
I have been working on some directX tutorials and am having trouble with one step. I am setting up separate functions for each step of my program, and Visual Studio crashes when it reaches my Render() function. Using the debugger I can see that my backBufferTarget_ has a value of 0x00000000. So even though I think I am initializing it in InitD3D(), it is not remembering or something. My code is below, if anyone has an advice that would be greatly appreciated. I am sure it is a simple thing I am missing.


#include<Windows.h> 
#include<memory>
#include<xnamath.h>
#include<d3d11.h>
#include<d3dx11.h>
#include<DxErr.h>

#pragma comment(lib, "winmm.lib")
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d3dx11.lib")
#pragma comment(lib, "dxerr.lib")

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

HWND hwnd = NULL;
HINSTANCE hInstance = NULL;

ID3D11DeviceContext* d3dContext_ = NULL;
ID3D11Device* d3dDevice_ = NULL;
IDXGISwapChain* swapChain_ = NULL;
ID3D11RenderTargetView* backBufferTarget_ = NULL;

//********************
//Function prototypes*
//********************
void MessagePump(void);
bool GetFullScreen(void);
bool InitWindow(void);
void KillWindow(void);
bool InitD3D(void);
void Render(void);
bool InitScene(void);
bool InitObjects(void);

bool progFinished = FALSE;
bool progFullScreen = FALSE;

#define APP_NAME "Kenneth Game"

//************************
//Application entry point*
//************************
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPWSTR cmdLine, int cmdShow)
{

	if (!GetFullScreen())
	{
		OutputDebugString("User abort\n");
		exit(5);
	}

	InitWindow();

	InitD3D();

	InitScene();

	while (!progFinished)
	{
		
		MessagePump(); //Check for window messages

		Render(); //Draw our graphics
	}

	KillWindow(); //Unload resources

	return 0;
}

//****************************************************************************************
//Initialise a window (full-screen or otherwise) in which our graphics will be displayed.*
//****************************************************************************************
bool InitWindow(void) 
{

	//UNREFERENCED_PARAMETER(prevInstance);
	//UNREFERENCED_PARAMETER(cmdLine);

	WNDCLASSEX wndClass = { 0 };
	wndClass.cbSize = sizeof(WNDCLASSEX);
	wndClass.style = CS_HREDRAW | CS_VREDRAW;
	wndClass.lpfnWndProc = WndProc;
	wndClass.hInstance = hInstance;
	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wndClass.lpszMenuName = NULL;
	wndClass.lpszClassName = "DX11BookWindowClass";

	if (!RegisterClassEx(&wndClass))
		return false;

	RECT rc = { 0, 0, 640, 480 };
	AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);

	HWND hwnd = CreateWindowA("DX11BookWindowClass", "Blank Win32 Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance, NULL);

	if (!hwnd)
		return false;

	ShowWindow(hwnd, SW_SHOW);
	//UpdateWindow(hwnd);

	return true;
}

//*************************************************
//Terminate the window that was previously opened.*
//*************************************************
void KillWindow(void)
{
	MSG msg;

	while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
	{
		DispatchMessage(&msg);
	}

	//ghAppWindow = NULL;
	ShowCursor(true);
}

//***************************
//Windows message processor.*
//***************************
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	PAINTSTRUCT paintStruct;
	HDC hDC;

	switch (message)
	{
	case WM_PAINT:
		hDC = BeginPaint(hwnd, &paintStruct);
		EndPaint(hwnd, &paintStruct);
		break;

	case WM_DESTROY:
		progFinished = true;
		PostQuitMessage(0);
		break;

	default:
		return DefWindowProc(hwnd, message, wParam, lParam);
	}

	return 0;
}

//**********************************************
//Process any messages that Windows has sent us*
//**********************************************
void MessagePump(void)
{
	MSG msg;

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

}

//*************************************
//Prompt selection of full screen mode*
//*************************************
bool GetFullScreen(void)
{
	int iResult;
	bool bRet = true;

	iResult = MessageBox(NULL, "Run fullscreen?", APP_NAME, MB_YESNOCANCEL | MB_ICONQUESTION);
	switch (iResult)
	{
	case IDCANCEL:
		bRet = false;
		break;
	case IDNO:
		progFullScreen = false;
		break;
	case IDYES:
		progFullScreen = true;
		break;
	case 0:
		OutputDebugString("Couldn't open MessageBox, closing");
		exit(10);
		break;
	}

	return bRet;
}

//**************************************
//Creates a hardware device in Direct3D*
//**************************************
bool InitD3D(void)
{
	D3D_DRIVER_TYPE driverType_;
	D3D_FEATURE_LEVEL featureLevel_;
	RECT dimensions;
	GetClientRect(hwnd, &dimensions);

	unsigned int width = dimensions.right - dimensions.left;
	unsigned int height = dimensions.bottom - dimensions.top;

	D3D_DRIVER_TYPE driverTypes[] =
	{
		D3D_DRIVER_TYPE_HARDWARE, D3D_DRIVER_TYPE_WARP,
		D3D_DRIVER_TYPE_REFERENCE, D3D_DRIVER_TYPE_SOFTWARE
	};

	unsigned int totalDriverTypes = ARRAYSIZE(driverTypes);

	D3D_FEATURE_LEVEL featureLevels[] =
	{
		D3D_FEATURE_LEVEL_11_0,
		D3D_FEATURE_LEVEL_10_1,
		D3D_FEATURE_LEVEL_10_0
	};

	unsigned int totalFeatureLevels = ARRAYSIZE(featureLevels);

	DXGI_SWAP_CHAIN_DESC swapChainDesc;
	ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));
	swapChainDesc.BufferCount = 1;
	swapChainDesc.BufferDesc.Width = width;
	swapChainDesc.BufferDesc.Height = height;
	swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	swapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
	swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
	swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	swapChainDesc.OutputWindow = hwnd;
	swapChainDesc.Windowed = true;
	swapChainDesc.SampleDesc.Count = 1;
	swapChainDesc.SampleDesc.Quality = 0;

	unsigned int creationFlags = 0;

#ifdef _DEBUG
	creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif

	HRESULT result;
	unsigned int driver = 0;

	for (driver = 0; driver < totalDriverTypes; ++driver)
	{
		result = D3D11CreateDeviceAndSwapChain(0, driverTypes[driver], 0, creationFlags, featureLevels, totalFeatureLevels, D3D11_SDK_VERSION, &swapChainDesc, &swapChain_,
			&d3dDevice_, &featureLevel_, &d3dContext_);

		if (SUCCEEDED(result))
		{
			driverType_ = driverTypes[driver];
			break;
		}
	}

	if (FAILED(result))
	{
		DXTRACE_MSG("Failed to create the Direct3D device!");
		return false;
	}

	ID3D11Texture2D* backBufferTexture;

	result = swapChain_->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&backBufferTexture);

	if (FAILED(result))
	{
		DXTRACE_MSG("Failed to get the swap chain back buffer!");
		return false;
	}

	result = d3dDevice_->CreateRenderTargetView(backBufferTexture, 0, &backBufferTarget_);

	if (backBufferTexture)
		backBufferTexture->Release();

	if (FAILED(result))
	{
		DXTRACE_MSG("Failed to create the render target view!");
		return false;
	}

	d3dContext_->OMSetRenderTargets(1, &backBufferTarget_, 0);

	D3D11_VIEWPORT viewport;
	viewport.Width = static_cast<float>(width);
	viewport.Height = static_cast<float>(height);
	viewport.MinDepth = 0.0f;
	viewport.MaxDepth = 1.0f;
	viewport.TopLeftX = 0.0f;
	viewport.TopLeftY = 0.0f;

	d3dContext_->RSSetViewports(1, &viewport);

	return true;
}

//****************************************************
// Initialise DirectX ready for us to start rendering*
//****************************************************
bool InitScene(void)
{


	
	return true;
}

//*******************************************
//Initialise the 3d objects we will be using*
//*******************************************
bool InitObjects(void)
{




	return true;
}

void Render(void)
{

	float clearColor[4] = { 0.0f, 0.0f, 0.25f, 1.0f };
	d3dContext_->ClearRenderTargetView(backBufferTarget_, clearColor);

	swapChain_->Present(0, 0);

}
Advertisement

That's the problem:


HWND hwnd = CreateWindowA("DX11BookWindowClass", "Blank Win32 Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance, NULL);

You use a local variable to store the HWND, but then when you call D3D11CreateDeviceAndSwapChain(), you use a global variable with the same name. Since the global variable was never set correctly and is still NULL, D3D11CreateDeviceAndSwapChain() fails. When you run it in debug mode, it shows the failure in the debug log.

Change the line above to:


// Initialize the GLOBAL hwnd
hwnd = CreateWindowA("DX11BookWindowClass", "Blank Win32 Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance, NULL); 

To avoid confusing global and local variables, you need a better naming convention. Specifically for HWND - you don't need it as global variable, as it's required only for initialization. Same goes for other variables. The only ones you want to keep as globals are the device and the swap-chain.

Oh dude, thank you SO MUCH - that fixed it. I was trying for hours last night heaps of stuff. Still wrapping my head around this extra laywer of complexity (after just finishing a C++ book).

Thanks!

Hi Again,

I come with more perils. I am now trying to add keyboard support, and like before, the program is crashing when it comes to the device I thought I have created. I am keeping my eye out for uninitiated global variables as you taught me before but cannot find the problem. The added code is:


//**********************
//DirectInput variables*
//**********************
#define KEYDOWN( name, key ) ( name[key] & 0x80 )
LPDIRECTINPUT8 directInput_ = NULL;
LPDIRECTINPUTDEVICE8 keyboardDevice_ = NULL;
char keyboardKeys_[256];
char prevKeyboardKeys_[256];

For the Initialization routine (which is called before Update() and Render():


bool InitInput(void)
{
    HRESULT result;

    ZeroMemory(keyboardKeys_, sizeof(keyboardKeys_));
    ZeroMemory(prevKeyboardKeys_, sizeof(prevKeyboardKeys_));

    result = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&directInput_, 0); //Initialize DirectInput8

    if (FAILED(result))
    {
        return false;
    }

    result = directInput_->CreateDevice(GUID_SysKeyboard, &keyboardDevice_, 0);

    if (FAILED(result))
    {
        return false;
    }

    result = keyboardDevice_->SetDataFormat(&c_dfDIKeyboard);

    if (FAILED(result))
    {
        return false;
    }

    result = keyboardDevice_->SetCooperativeLevel(ghHwnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);

    if (FAILED(result))
    {
        return false;
    }

    result = keyboardDevice_->Acquire();

    if (FAILED(result))
    {
        return false;
    }

    return true;
}

And for the Update() routine:


//******************************
//Get current state of Keyboard*
//******************************
void Update(void)
{
	float fElapsed;
	float rotZ = 0;
	float fY = 0.0f;

	keyboardDevice_->GetDeviceState(sizeof(keyboardKeys_), (LPVOID)&keyboardKeys_);

	if (GetAsyncKeyState(VK_ESCAPE))
	{
		PostQuitMessage(0);
	}

	// Button up event.
	if (KEYDOWN(prevKeyboardKeys_, DIK_DOWN) && !KEYDOWN(keyboardKeys_, DIK_DOWN))
	{
		fY -= 0.1f;
	}


	if (KEYDOWN(prevKeyboardKeys_, DIK_UP) && !KEYDOWN(keyboardKeys_, DIK_UP))
	{
		fY += 0.1f;
	}

	memcpy(prevKeyboardKeys_, keyboardKeys_, sizeof(keyboardKeys_));

	gfTimeScale = 0.001f;
	fElapsed = GetElapsedTime();
	rotZ += fElapsed;
}


It is crashing at keyboardDevice_->GetDeviceState(sizeof(keyboardKeys_), (LPVOID)&keyboardKeys_);

The debugger shows keyboardDevice_ becomes a 0x00000000 (similar to before). Again this is adapting code that works when it was done in the way the book shows.

Again any help is greatly appreciated.

Thanks

The debugger shows keyboardDevice_ becomes a 0x00000000 (similar to before). Again this is adapting code that works when it was done in the way the book shows.

After a quick glance at your code in not sure what's wrong, but I did notice one thing: you don't seem to ever check the result of your Init functions. In InitInput you return false if anything failed, but then you never check if InitInput returns true or not (I'm assuming, based on the code in the original post).

You should check the return values of your Init functions, and at the very least log something if they're false. It's possible that keyboardDevice_ never initialized properly (and thus was always NULL) but you won't catch that until you're update loop. You want to try and find errors as soon as possible! Crash early and crash often, as the saying goes.

EDIT: Looked at your code again. Looks like hInstance is uninitialized. You can get hInstance from WinMain.

Thank you very much! In my main I changed it to:


	if (!InitInput())
	{
		OutputDebugString("  Input initialisation failed\n");
		exit(5);
	}

and could see it was failing here. You were spot on about hInstance. The way I got it was with


hInstance = GetModuleHandle(NULL); 

Do you think that's okay? Or is another better way to do it?

Thanks heaps!

Hi Guys..

Stuck yet again. This time I am simply trying to display my triangle slightly rotated.

I have added some vertices:


VertexPos gVertices[] = 
{
	XMFLOAT3(0.5f, 0.5f, 0.5f), 
	XMFLOAT3(0.5f, -0.5f, 0.5f),
	XMFLOAT3(-0.5f, -0.5f, 0.5f)
};

which come into play here in InitObjects(void)


	ZeroMemory(&resourceData, sizeof(resourceData));
	resourceData.pSysMem = gVertices;
	d3dResult = d3dDevice_->CreateBuffer(&vertexDesc, &resourceData, &vertexBuffer_);

	D3D11_BUFFER_DESC constDesc;
	ZeroMemory(&constDesc, sizeof(constDesc));
	constDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	constDesc.ByteWidth = sizeof(XMMATRIX);
	constDesc.Usage = D3D11_USAGE_DEFAULT;

	d3dResult = d3dDevice_->CreateBuffer(&constDesc, 0, &mvpCB_);

with the final Render() function as


void Render(void)
{
	if (d3dContext_ == 0) //Checks that the Direct3D context is valid. 
		return;


	float clearColor[4] = { 0.0f, 0.0f, 0.25f, 1.0f };
	d3dContext_->ClearRenderTargetView(backBufferTarget_, clearColor);
	unsigned int stride = sizeof(VertexPos);
	unsigned int offset = 0;

	//Setting up the input assembly
	d3dContext_->IASetInputLayout(inputLayout_); 
	d3dContext_->IASetVertexBuffers(0, 1, &vertexBuffer_, &stride, &offset); 
	d3dContext_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); 
	d3dContext_->VSSetShader(solidColorVS_, 0, 0);
	d3dContext_->PSSetShader(solidColorPS_, 0, 0);


	XMMATRIX view = XMMatrixIdentity();
	XMMATRIX projection = XMMatrixOrthographicOffCenterLH(0.0f, 800.0f, 0.0f, 600.0f, 0.1f, 100.0f); //1a. Creates an orthographic projection matrix using LHS. Return value is a XMMATRIX structure where the resulting projection matrix is placed.
	XMMATRIX vpMatrix_ = XMMatrixMultiply(view, projection);

	XMMATRIX translation = XMMatrixTranslation(10.0f, 10.0f, 10.0f);
	XMMATRIX rotationZ = XMMatrixRotationZ(30.0f);
	XMMATRIX scale = XMMatrixScaling(0.0f, 0.0f, 0.0f);
	XMMATRIX TriangleWorld = translation * rotationZ;

	XMMATRIX mvp = TriangleWorld*vpMatrix_*translation;
	mvp = XMMatrixTranspose(mvp);

	d3dContext_->UpdateSubresource(mvpCB_, 0, 0, &mvp, 0, 0);
	d3dContext_->VSSetConstantBuffers(0, 1, &mvpCB_);

	d3dContext_->Draw(3, 0); 
	swapChain_->Present(0, 0);
}

No matter what I change in the XMMatrixRotationZ or XMMatrixTranslation, my triangle stays the same. Its as if since the buffer is created I am not altering it at all.

I have tried many combinations of matrix multiplication ways and large numbers to no avail. It is as if the mvp matrix is having no effect on the final image. Thank you for your time - I have spent many hours trying to figure this out and only come here as a last resort. I find the best way to learn is trying to figure out broken code...

And what does your vertex shader do ? Pass-through ? Show us, please.

Not 100% sure what you mean, but my vertex shader is created here:


bool InitObjects(void)
{
	
	DWORD shaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;

#if defined( DEBUG ) || defined( _DEBUG )
	shaderFlags |= D3DCOMPILE_DEBUG;
#endif

	ID3DBlob* errorBuffer = 0;
	ID3DBlob* vsBuffer = 0;

	//bool compileResult = CompileD3DShader("SolidGreenColor.fx", "VS_Main", "vs_4_0", &vsBuffer); //Loads vertex shader from the text file and compiles it into byte code. 
	//bool compileResult = D3DX11CompileFromFile("SolidGreenColor.fx", 0, 0, "VS_Main", "vs_4_0", shaderFlags, 0, 0, &vsBuffer, &errorBuffer, 0);

	HRESULT result;
	result =  D3DX11CompileFromFile("SolidGreenColor.fx", 0, 0, "VS_Main", "vs_4_0", shaderFlags, 0, 0, &vsBuffer, &errorBuffer, 0);

	if (FAILED(result))
	{
		if (errorBuffer != 0)
		{
			OutputDebugStringA((char*)errorBuffer->GetBufferPointer());
			errorBuffer->Release();
		}

		return false;
	}

	HRESULT d3dResult;

	d3dResult = d3dDevice_->CreateVertexShader(vsBuffer->GetBufferPointer(), vsBuffer->GetBufferSize(), 0, &solidColorVS_);

	if (FAILED(d3dResult))
	{
		if (vsBuffer)
			vsBuffer->Release();

		return false;
	}

	D3D11_INPUT_ELEMENT_DESC solidColorLayout[] = //Used to describe the vertex latout of a vertex streucture. (msdn). 
	{
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 } //3b
	};

	unsigned int totalLayoutElements = ARRAYSIZE(solidColorLayout);

	d3dResult = d3dDevice_->CreateInputLayout(solidColorLayout, totalLayoutElements, //3c The input layout uses the type of ID3D11InputLayout. Created with a call to the D3D device function CreateInputLayout. 
		vsBuffer->GetBufferPointer(), vsBuffer->GetBufferSize(), &inputLayout_);

	vsBuffer->Release();

	if (FAILED(d3dResult))
	{
		return false;
	}

	ID3DBlob* psBuffer = 0;

	result = D3DX11CompileFromFile("SolidGreenColor.fx", 0, 0, "PS_Main", "ps_4_0", shaderFlags, 0, 0, &psBuffer, &errorBuffer, 0);

	if (FAILED(result))
	{
		if (errorBuffer != 0)
		{
			OutputDebugStringA((char*)errorBuffer->GetBufferPointer());
			errorBuffer->Release();
		}

		return false;
	}

	d3dResult = d3dDevice_->CreatePixelShader(psBuffer->GetBufferPointer(), psBuffer->GetBufferSize(), 0, &solidColorPS_);

	psBuffer->Release();

	ZeroMemory(&vertexDesc, sizeof(vertexDesc));
	vertexDesc.Usage = D3D11_USAGE_DEFAULT;
	vertexDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	vertexDesc.ByteWidth = sizeof(VertexPos)* 3;

	ZeroMemory(&resourceData, sizeof(resourceData));
	resourceData.pSysMem = gVertices;
	d3dResult = d3dDevice_->CreateBuffer(&vertexDesc, &resourceData, &vertexBuffer_);

	D3D11_BUFFER_DESC constDesc;
	ZeroMemory(&constDesc, sizeof(constDesc));
	constDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	constDesc.ByteWidth = sizeof(XMMATRIX);
	constDesc.Usage = D3D11_USAGE_DEFAULT;

	d3dResult = d3dDevice_->CreateBuffer(&constDesc, 0, &mvpCB_);

	if (FAILED(d3dResult))
	{
		return false;
	}

	return true;

}

My goal is to modify the triangle in world space so the rotation or translation matrices have an effect on it. Thanks for your time.

Nope, I meant the HLSL, the source code of your vertex shader: VS_Main.

This topic is closed to new replies.

Advertisement