DX11 noobie question

Started by
4 comments, last by George88 12 years, 6 months ago
Hi guys,


Obviously I am a complete newby to DX and I'm having fun learning. I have literally been learning for a few days so I haven't got the best grasp over the concepts. The tutorials I've been following are from http://www.directxtutorial.com. They're great, easy to read, fun to do and very well presented. My problem is the final freebie tutorial whrere we are to draw a triangle to the screen. The code will compile fine, but will crash immediately upon running.

I know this could be a lot of things, but I was googling around and found another web site where a user was having the same problem with the same tutorial and once I post the code, I will post his message on how he solved the issue. The person doesn't give any detail, just a clue. Anyway, the code is:

Also, commenting out devcon[color="#666600"]->[color="#660066"]Draw[color="#666600"]([color="#006666"]3[color="#666600"], [color="#006666"]0[color="#666600"]); [color="#000000"]makes the code work.

Source code

// include the basic windows header files and the Direct3D header files
#include <windows.h>
#include <windowsx.h>
#include <d3d11.h>
#include <d3dx11.h>
#include <d3dx10.h>

// include the Direct3D Library file
#pragma comment (lib, "d3d11.lib")
#pragma comment (lib, "d3dx11.lib")
#pragma comment (lib, "d3dx10.lib")

// define the screen resolution
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600

// global declarations
IDXGISwapChain *swapchain; // the pointer to the swap chain interface
ID3D11Device *dev; // the pointer to our Direct3D device interface
ID3D11DeviceContext *devcon; // the pointer to our Direct3D device context
ID3D11RenderTargetView *backbuffer; // the pointer to our back buffer
ID3D11InputLayout *pLayout; // the pointer to the input layout
ID3D11VertexShader *pVS; // the pointer to the vertex shader
ID3D11PixelShader *pPS; // the pointer to the pixel shader
ID3D11Buffer *pVBuffer; // the pointer to the vertex buffer

// a struct to define a single vertex
struct VERTEX{FLOAT X, Y, Z; D3DXCOLOR Color;};

// function prototypes
void InitD3D(HWND hWnd); // sets up and initializes Direct3D
void RenderFrame(void); // renders a single frame
void CleanD3D(void); // closes Direct3D and releases memory
void InitGraphics(void); // creates the shape to render
void InitPipeline(void); // loads and prepares the shaders

// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);


// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HWND hWnd;
WNDCLASSEX wc;

ZeroMemory(&wc, sizeof(WNDCLASSEX));

wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = L"WindowClass";

RegisterClassEx(&wc);

RECT wr = {0, 0, SCREEN_WIDTH, SCREEN_HEIGHT};
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);

hWnd = CreateWindowEx(NULL,
L"WindowClass",
L"Our First Direct3D Program",
WS_OVERLAPPEDWINDOW,
300,
300,
wr.right - wr.left,
wr.bottom - wr.top,
NULL,
NULL,
hInstance,
NULL);

ShowWindow(hWnd, nCmdShow);

// set up and initialize Direct3D
InitD3D(hWnd);

// enter the main loop:

MSG msg;

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

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

RenderFrame();
}

// clean up DirectX and COM
CleanD3D();

return msg.wParam;
}


// this is the main message handler for the program
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);
}


// this function initializes and prepares Direct3D for use
void InitD3D(HWND hWnd)
{
// create a struct to hold information about the swap chain
DXGI_SWAP_CHAIN_DESC scd;

// clear out the struct for use
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));

// fill the swap chain description struct
scd.BufferCount = 1; // one back buffer
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color
scd.BufferDesc.Width = SCREEN_WIDTH; // set the back buffer width
scd.BufferDesc.Height = SCREEN_HEIGHT; // set the back buffer height
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used
scd.OutputWindow = hWnd; // the window to be used
scd.SampleDesc.Count = 4; // how many multisamples
scd.Windowed = TRUE; // windowed/full-screen mode
scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; // allow full-screen switching

// create a device, device context and swap chain using the information in the scd struct
D3D11CreateDeviceAndSwapChain(NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
NULL,
NULL,
NULL,
D3D11_SDK_VERSION,
&scd,
&swapchain,
&dev,
NULL,
&devcon);


// get the address of the back buffer
ID3D11Texture2D *pBackBuffer;
swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);

// use the back buffer address to create the render target
dev->CreateRenderTargetView(pBackBuffer, NULL, &backbuffer);
pBackBuffer->Release();

// set the render target as the back buffer
devcon->OMSetRenderTargets(1, &backbuffer, NULL);


// Set the viewport
D3D11_VIEWPORT viewport;
ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));

viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = SCREEN_WIDTH;
viewport.Height = SCREEN_HEIGHT;

devcon->RSSetViewports(1, &viewport);

InitPipeline();
InitGraphics();
}


// this is the function used to render a single frame
void RenderFrame(void)
{
// clear the back buffer to a deep blue
devcon->ClearRenderTargetView(backbuffer, D3DXCOLOR(0.0f, 0.2f, 0.4f, 1.0f));

// select which vertex buffer to display
UINT stride = sizeof(VERTEX);
UINT offset = 0;
devcon->IASetVertexBuffers(0, 1, &pVBuffer, &stride, &offset);

// select which primtive type we are using
devcon->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

// draw the vertex buffer to the back buffer
devcon->Draw(3, 0);

// switch the back buffer and the front buffer
swapchain->Present(0, 0);
}


// this is the function that cleans up Direct3D and COM
void CleanD3D(void)
{
swapchain->SetFullscreenState(FALSE, NULL); // switch to windowed mode

// close and release all existing COM objects
pLayout->Release();
pVS->Release();
pPS->Release();
pVBuffer->Release();
swapchain->Release();
backbuffer->Release();
dev->Release();
devcon->Release();
}


// this is the function that creates the shape to render
void InitGraphics()
{
// create a triangle using the VERTEX struct
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)}
};


// create the vertex buffer
D3D11_BUFFER_DESC bd;
ZeroMemory(&bd, sizeof(bd));

bd.Usage = D3D11_USAGE_DYNAMIC; // write access access by CPU and GPU
bd.ByteWidth = sizeof(VERTEX) * 3; // size is the VERTEX struct * 3
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; // use as a vertex buffer
bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; // allow CPU to write in buffer

dev->CreateBuffer(&bd, NULL, &pVBuffer); // create the buffer


// copy the vertices into the buffer
D3D11_MAPPED_SUBRESOURCE ms;
devcon->Map(pVBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms); // map the buffer
memcpy(ms.pData, OurVertices, sizeof(OurVertices)); // copy the data
devcon->Unmap(pVBuffer, NULL); // unmap the buffer
}


// this function loads and prepares the shaders
void InitPipeline()
{
// load and compile the two shaders
ID3D10Blob *VS, *PS;
D3DX11CompileFromFile(L"shaders.hlsl", 0, 0, "VShader", "vs_5_0", 0, 0, 0, &VS, 0, 0);
D3DX11CompileFromFile(L"shaders.hlsl", 0, 0, "PShader", "ps_5_0", 0, 0, 0, &PS, 0, 0);

// encapsulate both shaders into shader objects
dev->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &pVS);
dev->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &pPS);

// set the shader objects
devcon->VSSetShader(pVS, 0, 0);
devcon->PSSetShader(pPS, 0, 0);

// create the input layout object
D3D11_INPUT_ELEMENT_DESC ied[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
};

dev->CreateInputLayout(ied, 2, VS->GetBufferPointer(), VS->GetBufferSize(), &pLayout);
devcon->IASetInputLayout(pLayout);
}


Shader:

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 person who claimed to have solved the problem says:

"So, I fixed the above error, and it boils down to "dev->CreateVertexShader" throwing an error for some reason".


Obviously I don't really know what I'm doing yet and am having a problem with debugging. How could I even debug this kind of error?


Thanks for reading, hope someone can help!
Advertisement
Since you're a beginner, I'm going to bet you don't have a lot of experience with a debugger. Debuggers are practically made for this situation. It'll help you narrow down where the problem is. Set a break point at the beginning of your main function, and step through it line by line. You should be able to see when it crashes, and once you know what line it's crashing on, you can find out more about why, by checking the state of any variables your using or anything else that may be a potential problem.

What compiler/IDE are you using? If you aren't sure how to use the debugger, google is good resource, but I and I'm sure others here are willing to help you learn how to use it.
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]
Hi Cornstalks,

Thanks for responding. I tried debugging by stepping through my code and found where the error is coming from. I am using Visual C++ Express 2010. The error comes up and says:

[quote="Error message"]
Unhandled exception at 0x6d49be2d in main.exe: 0xC0000005: Access violation reading location 0x00000248.
[/quote]

I get this error when the code gets to line 219 [font="Consolas"][font="Consolas"]devcon->Draw(3, 0);

[font="Arial"]I took a screenshot of the debugger messages and have attached it, because it isn't giving me any clues in the output window.


Where can I go from here? Thanks![/font][/font][/font]
In your D3D11CreateDeviceAndSwapChain,

add the [font="Consolas, Courier, monospace"]D3D11_CREATE_DEVICE_DEBUG [/font]flag.

Please read the documentation @ Doc (fixed thanks!) and find out which parameter it is :)




When this mode is set, the DirectX Runtime will report (very good imho) errors.
Cool, thanks for doing the debugging step! I wasn't sure if it was a null pointer access or something. So that rules out a few things (well, they're still possible, but not as likely). Now let's go back to your OP. You said someone on another site with a similar problem said it came from CreateVertexShader failing. This is entirely possible, because you're trying to create a vertex shader, and then you assign that vertex shader to devcon. If you give it an invalid vertex shader, and then try to use that vertex shader (Draw will use the vertex shader), bad things will happen.

So you asked "How could I even debug this kind of error?" The answer, quite simply, is error checking. Lots of it. It's painful to do, but it's critical in any robust application. CreateVertexShader returns something. If you look at the documentation, you should check if the return code is equal to S_OK to know if it succeeded. If it fails, you have to either come up with a backup, or let your user know and gracefully exit the application. That's up to you.

Anyway, moral of the story is (assuming this is in fact the problem) is, if a function can possibly fail, and if it will give you some kind of return code or something to indicate if it failed or succeeded, you should check that result before proceeding to know if you're good to go.

Give that a try and let's see what you find.

@jameszhao00: I think that's a great idea, but you're link got a little messed up in the posting. The ending ')' didn't get included. For the curious, the correct link is http://msdn.microsoft.com/en-us/library/windows/desktop/ff476083(v=vs.85)
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]
Hi guys!

Thanks for the tips, I've added in the debugger code and am getting somewhere now. I still don't understand the error messages. I have two:

[quote="Error message #1"][font="Consolas"][size="1"][font="Courier New"]D3D11: ERROR: ID3D11DeviceContext::Draw: A Vertex Shader is always required when drawing, but none is currently bound. [ EXECUTION ERROR #341: DEVICE_DRAW_VERTEX_SHADER_NOT_SET ][/font][/font][/quote]
[quote="Error message #2][font="Consolas"][size="1"][font="Courier New"]D3D11: ERROR: ID3D11DeviceContext::Draw: Rasterization Unit is enabled (PixelShader is not NULL or Depth/Stencil test is enabled and RasterizedStream is not D3D11_SO_NO_RASTERIZED_STREAM) but position is not provided by the last shader before the Rasterization Unit. [ EXECUTION ERROR #362: DEVICE_DRAW_POSITION_NOT_PRESENT ][/font][/font][/quote]


So it's telling me there is no vertex shader currently bound. This means it isn't "set" correctly, right? The 2nd message is over my head. I've been googling these messages and one web site says:

[quote="Help"]These errors occur if you forget to have an output with the output semantic :COLOR on your pixel shader in d3d11.[/quote]


Which might as well be an error message itself to me. Perhaps I'm taking this a bit too fast? I don't actually understand much of the D3D code to be honest, and it's not as if I'm trying to do anything complicated. I started out in graphics using OpenGL and had no problem drawing shapes and 3D objects to the screen, but the documentation seems terrible compared to DX and for that reason I switched. I have no intentions of going back, but maybe I should go back to the very beginning?

Tips much appreciated :). Thanks!

This topic is closed to new replies.

Advertisement