DirectX10 Tutorial 1: Setting up the D3D10 device


So if you read my review of Wendy Jones’ book, you know my feelings on the state of DX10 tutorials and books, I want to try and maybe help some people out with tutorials in getting started with DX10, I am by no means an expert and the tutorials will basically cover everything that I’ve learnt so far. They will not be rehashes of the SDK tutorials nor Wendy Jones’ book. I’m hoping to slowly build up a dxManager wrapper class that can be easily used for some basic D3D apps. So let’s get started with the most basic topic: setting up the D3D device for drawing.

Note: The DX10 SDK tutorials are excellent, they are a must read and my early tutorials will be a concatenation of the information found in them!

Win32

The entry point of most 3D tutorials is win32 and so I’m not going to rewrite all those tutorials. If you want an excellent win32 tutorial Google forger’s win32 tutorials, they are the best I’ve found. Basically a simple win32 window consists of two things: the window and the window processing function (acts as an event handler). Inside of the tutorial project I’ve attached you’ll see three functions that create a window: the winMain function, the initialize window function and the wndProc, the functions are very basic and so I’m not going to go into any more detail. There are plenty of tutorials available online if you want more detail on win32.

dxManager

Before I start with the directX initialization stuff, I just want to cover something: the dxManager class. Most tutorials you’ll find will have the directX variables as global with a few global functions in a single file to render a simple triangle. Even Wendy Jones does so in her book, but I’m not, simply because it’s a terrible practice, its messy, inextensible and just plain silly. I’m going to instead create a dxManager class to wrap all my directX functions and just neaten things up.

In later tutorials you’ll see the justification for this more clearly. Enough of me prattling on, let’s dig in.

3D basics

Okay let just cover some very basic concepts about 3D graphics, the graphics API (directX/openGL) is what you’ll use to draw your objects out to the screen. The API is basically a layer that sits between your graphics card and you, you tell the layer what to do and the layer then tells the card.

The card makes use of a pipeline structure to display objects, I’m not going to go into the justifications about this since Google is your friend. Basically there a few key stages (their names differ across APIs), below is a diagram of the stages in DX10 followed by a brief description (taken from the SDK docs):

  • Input-Assembler Stage - The input-assembler stage is responsible for supplying data (triangles, lines and points) to the pipeline.
  • Vertex-Shader Stage – The vertex-shader stage processes vertices, typically performing operations such as transformations, skinning, and lighting. A vertex shader always takes a single input vertex and produces a single output vertex.
  • Geometry-Shader Stage - The geometry-shader stage processes entire primitives. Its input is a full primitive (which is three vertices for a triangle, two vertices for a line, or a single vertex for a point). In addition, each primitive can also include the vertex data for any edge-adjacent primitives. This could include at most an additional three vertices for a triangle or an additional two vertices for a line. The Geometry Shader also supports limited geometry amplification and de-amplification. Given an input primitive, the Geometry Shader can discard the primitive, or emit one or more new primitives.
  • Stream-Output Stage – The stream-output stage is designed for streaming primitive data from the pipeline to memory on its way to the rasterizer. Data can be streamed out and/or passed into the rasterizer. Data streamed out to memory can be recirculated back into the pipeline as input data or read-back from the CPU.
  • Rasterizer Stage - The rasterizer is responsible for clipping primitives, preparing primitives for the pixel shader and determining how to invoke pixel shaders.
  • Pixel-Shader Stage – The pixel-shader stage receives interpolated data for a primitive and generates per-pixel data such as color.
  • Output-Merger Stage - The output-merger stage is responsible for combining various types of output data (pixel shader values, depth and stencil information) with the contents of the render target and depth/stencil buffers to generate the final pipeline result.

The aim of this tutorial is to set up the D3D device to be ready for later tutorials. We will set up the swap chain, the D3D device, the render target, the viewport and finally just set up a view and projection matrix for the future.

The SwapChain and the D3D device

This is what is written in the SDK regarding the swapchain: “An IDXGISwapChain interface implements one or more surfaces for storing rendered data before presenting it to an output.” What this basically means is that you will set up a few “frames” or “buffers” to which you will draw and then swap out when you’re finished drawing. This is how you enable double or triple buffering in DX10.

Once we’ve set up our swapchain we create a D3D device with that swapchain, pretty simple.

To achieve this we need to fill out a DXGI_SWAP_CHAIN_DESC structure and then call D3D10CreateDeviceAndSwapChain to create our swap chain and our D3D device. The function parameters are in the SDK docs and I’m not going to describe what each one does since I’m pretty sure you can read it yourself. You will need pointers to both a swap chain interface and a D3D device interface. Here’s the code to set up and create the swap chain and D3D device.


//Set up DX swap chain
//--------------------------------------------------------------

DXGI_SWAP_CHAIN_DESC swapChainDesc;
ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));

//set buffer dimensions and format
swapChainDesc.BufferCount = 2;
swapChainDesc.BufferDesc.Width = width;
swapChainDesc.BufferDesc.Height = height;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;;

//set refresh rate
swapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;

//sampling settings
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.SampleDesc.Count = 1;

//output window handle
swapChainDesc.OutputWindow = *hWnd;
swapChainDesc.Windowed = true;

//Create the D3D device
//--------------------------------------------------------------

if ( FAILED( D3D10CreateDeviceAndSwapChain(	NULL,
											D3D10_DRIVER_TYPE_HARDWARE,
											NULL,
											0,
											D3D10_SDK_VERSION,
											&swapChainDesc,
											&pSwapChain,
											&pD3DDevice ) ) ) return fatalError("D3D device creation failed");

The RenderTarget

The render target describes what the format of output of the output merger stage will be. This output format is the same the format of the swapchain buffers. So what we need to do is get all the details from the swapchain about its buffer format and use that to create a render target.

//Create render target view
//--------------------------------------------------------------

//try to get the back buffer
ID3D10Texture2D* pBackBuffer;

if ( FAILED( pSwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (LPVOID*)&pBackBuffer) ) ) return fatalError("Could not get back buffer");

//try to create render target view
if ( FAILED( pD3DDevice->CreateRenderTargetView(pBackBuffer, NULL, &pRenderTargetView) ) ) return fatalError("Could not create render target view");

//release the back buffer
pBackBuffer->Release();

//set the render target
pD3DDevice->OMSetRenderTargets(1, &pRenderTargetView, NULL);

Note: Something that should be mentioned here is the “Release” call, basically all resources are semi-managed, basically resources are only freed once nothing is using them, whenever a resource is used an internal counter is incremented (semaphore) , once something doesn’t need the resource any more the counter is decremented. Once this counter reaches 0, the resource is freed. Here we don’t need the pBackBuffer resource any longer so we release it, if nothing else is using it then the resource is freed.

The Viewport

The viewport defines an area in the render target that you can draw to, in some cases it is necessary to have multiple viewports but for now we will be setting the viewport to take up our entire render target. Creating this structure is really simple, it basically takes the height and width of your window and the starting positions of the window (usually 0 and 0). The depth variables should be set to 0 and 1 for min and max respectively.

//create viewport structure
viewPort.Width = width;
viewPort.Height = height;
viewPort.MinDepth = 0.0f;
viewPort.MaxDepth = 1.0f;
viewPort.TopLeftX = 0;
viewPort.TopLeftY = 0;

//set the viewport
pD3DDevice->RSSetViewports(1, &viewPort);

The View and Projection Matrices

Okay now we’re nearly done, the last thing we need to set up is the view and projection matrices. The view matrix basically positions and orients the camera in the scene. The matrix usage and transformations will be covered in the next tutorial.

The projection matrix basically defines the range of the view from the camera. This is explained extremely well in the 4th tutorial in the SDK docs! I really suggest reading it. It can also apply perspective to the scene; this basically allows near objects to be large and far objects to be small. In our case we’re going to set up a basic perspective projection with a view angle of 45 degrees and a max depth of 100 units. The near depth must not be set to 0, I will explain why in a later tutorial regarding picking and unprojecting co-ordinates.

// Set up the view matrix
//--------------------------------------------------------------

D3DXVECTOR3 eye(0.0f, 0.0f, -5.0f);
D3DXVECTOR3 view(0.0f, 0.0f, 1.0f);
D3DXVECTOR3 up(0.0f, 1.0f, 0.0f));

D3DXMatrixLookAtLH( &viewMatrix, eye, view, up );

//Set up projection matrix
//--------------------------------------------------------------
D3DXMatrixPerspectiveFovLH(&projectionMatrix, (float)D3DX_PI * 0.5f, (float)width/height, 0.1f, 100.0f);

Rendering of the Scene

Okay so we’ve set up our D3D device, let just output something. Unfortuneatly in DX10 doing that isnt all that simple and there are several more stage we need to do before we can proceed. So for now lets just clear the screen and flip the buffers.


//clear scene
pD3DDevice->ClearRenderTargetView( pRenderTargetView, D3DXCOLOR(0,0,0,0) );

//SCENE RENDERING GOES HERE!!!

//flip buffers
pSwapChain->Present(0,0);

Conclusion

So that’s it for my first tutorial! I didn’t cover a lot of material but I’ve set up the base for the rest of the tutorials, and time-permitting I’ll put up several more in the coming weeks.

Source Code

Tutorial 1 VS2k8 project and Source Code: tutorial1.zip

About these ads

About Bobby
I'm a programmer at Ubisoft. My work interests include Animation and Artificial Intelligence. All opinions are my own!

40 Responses to DirectX10 Tutorial 1: Setting up the D3D10 device

  1. Wenjian says:

    Hi,
    I am not sure about the explain for the use of Release(), as the GetBuffer() function will increase the reference by 1 to 2. So when Release() is called, the internal count is set to 1. Therefore the back buffer is still there, otherwise how can we render to that.

  2. gregory says:

    global variables are a terrible practice, then why keep hwnd, width and height as globals then ? :)

  3. Bobby says:

    get buffer increments the count to 1 not 2, since pBackbuffer is an empty pointer initially. Also we don’t render to the backbuffer, we just get the dimensions and the format from it to create a rendertargetview, which is what we ultimately render to.

    Yeh, globals are pretty bad but to get rid of them I’d have to create another class to store them and handle all the windows stuff and there is no real point. I can live with a few globals. If you want a nightmare go through the sdk tutorials, everything is global! Makes me feel sick just thinking about it.

  4. RuDeveloper says:

    Hi Bobby! This Lesson is very useful!
    May I translate your tutorials for russian game developers? (with direct link to your blog :)

  5. will says:

    Just want to say thanks for these tuts.
    they really helped my kick off in dx10. I have books and the sdk. but they did not help.

  6. Bobby says:

    @ruDeveloper – you’re more than welcome to translate them and use them :P

    I’m really glad people are finding them useful, I’ll hopefully get a chance to carry on with them in the next week.

  7. Evgeny says:

    Can you explain difference between D3D10CreateDevice/D3D10CreateDeviceAndSwapChain/D3D10CreateDeviceAndSwapChain1? Which is preferable?

  8. Bobby says:

    D3D10CreateDevice simply creates a d3d device that represents the video card. This is an interface from d3d to your video card’s driver.

    The swap chain is the chain/list of buffer that you will write to and swap to display each frame. you create a swapchain with the D3D10CreateSwapChain function.

    The D3D10CreateDeviceAndSwapChain function combines the two functions into a single one for simplicity’s sake.

    the one on the end of the function signifies that you want to create a DX10.1 device and not a DX10 device.

  9. Evgeny says:

    I found some of mistakes:
    1. New without delete:
    D3DXMatrixLookAtLH( &viewMatrix,
    new D3DXVECTOR3(0.0f, 0.0f, -5.0f),
    new D3DXVECTOR3(0.0f, 0.0f, 1.0f),
    new D3DXVECTOR3(0.0f, 1.0f, 0.0f));

    2. D3D10CreateSwapChain unavailable. We can use IDXGIFactory::CreateSwapChain instead.

  10. Bobby says:

    the new without delete is my bad, that was just slapped in right at the end, granted its not a major issues since it only happens once.

    i don’t understand what you mean by D3D10CreateSwapChain unavailable? Using the DXGI library is not right unless you specifically need DXGI functionality.

  11. Evgeny says:

    no function in SDK (Mar 08) with the same name

  12. Bobby says:

    yeah you’re right, but i don’t use that function… you don’t need to create the swapchain and the device separately, that’s why i use the D3D10CreateDeviceAndSwapChain.

    haha, i realize i said in my last comment that there is a create swapchain function, that’s incorrect! I was assuming that such a function existed, you are absolutely correct in the fact that you need to make use of the DXGI factory if you wish to create a swap chain manually.

  13. zach says:

    This is really good and all, but it would help if you typed out the types of the variables such as viewMatrix, viewPoint, etc. Just reading this, I don’t know what they are. I used the DX tutorials supplied with VS to help me out.

  14. Nick says:

    hehe i think it adds some myster to it and something for the readr to figer out them self, i had no hard time fixing all that!

  15. Scippie says:

    Can you maybe add something about how to handle windowed-to-fullscreen switches and window-resizing? How to make sure the full screen resolution can be selected and the window can still be in another size?

  16. naivegal says:

    can you explain how to read text file?

  17. naivegal says:

    can the size point can be adjust?

  18. Citizen says:

    Hi, I rarely leave comments on articles, but as someone who has been subjected to some really crummy books, I’d just like to thank you for presenting the information with some clarity.
    Much of the available text on this is either an academic screed or fragments of badly commented source code. Just saying what it is and what it’s for is the best approach to technical writing. You’ve really helped me out. Thanks !

  19. W. B. says:

    BUMP for Scippie’s Comment.
    I would also like to know how to windowed/fullscreen switching.

  20. idiot says:

    mayby you will tell us what we have to download ?!

  21. developero says:

    Thanks man, very helpful. Greetings from mother Bulgaria ;)

  22. Anoop Narang says:

    Hey If i use VC++ 2010 beta 2 …. is there any problem??

  23. Equal says:

    Hi Bobby

    I just have a question about the DX10 SDK tutorials, because i installed the lastes DX10SDK Feb, and i can ONLY find the documentation to the directx9. Pls help

    greets Equal

  24. Bobby says:

    the SDK documentation is split into two help files: the SDK docs and the directx graphics documentation.

    unfortunately they are both in the directx9 folder, even tho they contain all the information about DX9/10/11 and HLSL. If you actually open them up you’ll find what you are looking for!

  25. Equal says:

    Thx alot, i have found it and i also have looked a bit in the browser, its great. But as mentioned in this tutorial i started from the beginning and im currently doing the forgers win32 tut, but as new as i em i try to understand as much as possible, the problem is i got stuck at

    int ret = DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_ABOUT), hwnd, AboutDlgProc);

    it always returns me -1, no matter what i do, i em absolutly unable to get this to work, i have asked some ppl at c-chatrooms, but they could not help me, i also tried to solve it on my own and found out that

    void InitCommonControls(void);

    should help, but its a older version of the Ex of it, so mb that the problem, … puh lots of text
    Sry for the long post but pls help me out there,

    grets Equal

    • Equal says:

      I have solved the problem, after over 3 hours try’n’error, and the problem was in the setting up of the project, somwhere in the beginning i must have klicked or checkd somthing wrong, like mb using cpp instead of c or some othe thing.

      i hope you dont mind my post, and your ofc free to remove them.

      greets Equal

  26. stefanobeck says:

    how to read text file?can you explain?Thx

  27. sweetos says:

    How do you make multiple Viewports in one window application??? Please Help.

    • Bobby says:

      you simply create several viewport structs, and then just set the viewport you want to render to before drawing using the RSSetViewports Method.

      • sweetos says:

        Thanks for reply,
        All I can think is that ONE of my viewport is out of the screen, the others viewport doesn’t work.
        and here is my code

        D3D10_VIEWPORT vp[2];
        vp[0].TopLeftX = 0;
        vp[0].TopLeftY = 0;
        vp[0].Width = mClientWidth/2;
        vp[0].Height = mClientHeight;
        vp[0].MinDepth = 0.0f;
        vp[0].MaxDepth = 1.0f;

        vp[1].TopLeftX = mClientWidth/2;
        vp[1].TopLeftY = 0;
        vp[1].Width = mClientWidth/2;
        vp[1].Height = mClientHeight;
        vp[1].MinDepth = 0.0f;
        vp[1].MaxDepth = 1.0f;

        md3dDevice->RSSetViewports(2,vp);

        Is something wrong with this ?

      • Bobby says:

        There are two ways to change the view port:

        The first is simply call RSSetViewport(1,&vp[1]) before you render the viewport 1 contents. Then call RSSetViewport(1,&vp[1]) before rendering viewport 2′s contents.

        The other method is how you did it except now you need a geometry shader program. This sahder must output a struct which contains a variable with the SV_ViewportArrayIndex semantic, this semantic specifies the target viewport to use during clipping and screen mapping by the rasterizer stage.

        Here is a very basic geometry shader progam:

        struct GS_OUTPUT
        {
        	float4 Pos : SV_POSITION;
            float4 Color : COLOR0;	
        	uint viewport : SV_ViewportArrayIndex;
        };
        
        [maxvertexcount(3)]
        void GS( triangle PS_INPUT In[3], inout TriangleStream TriStream )
        {
        	GS_OUTPUT output;
           	output.viewport = 1; //use viewport index 1
        
            for( int v = 0; v < 3; v++ )
            {
        		output.Pos = In[v].Pos;
                output.Color = In[v].Color; 			
        		TriStream.Append( psInput );
            }
        }
        

        Hope that helps!!!

  28. sweetos says:

    Thank you,
    I’m sorry, I don’t have much experience with geometry shader program. I did the first way you told me about it, but still same problem, I think I have something wrong with my code.

    Can you look to my code to tell me what was the problem is, please? here is my code http://paste2.org/p/932604
    Thank you very much.

    • Bobby says:

      you need to set viewports in your render function!

      ie.

      pD3DDevice->RSSetViewports(1, &vp[0]);
      
      	for( UINT p = 0; p < techDesc.Passes; ++p )
      	{
      		//apply technique
      		pBasicTechnique->GetPassByIndex( p )->Apply( 0 );
      					
      		//draw
      		pD3DDevice->Draw( numVertices, 0 );
      	}
      
      	pD3DDevice->RSSetViewports(1, &vp[1]);
      
      	for( UINT p = 0; p < techDesc.Passes; ++p )
      	{
      		//apply technique
      		pBasicTechnique->GetPassByIndex( p )->Apply( 0 );
      					
      		//draw
      		pD3DDevice->Draw( numVertices, 0 );
      	}
      	
      
  29. sweetos says:

    THANK YOU VERY VERY MUCH!!!! IT WORKS :D

  30. Raul says:

    Thanx for the help. I worked a lot on directx9, and now i moved to 10 and got a little overwhelmed by the changes. I never worked with shaders just plain old pre-build transformations and functions. Anyway you explained better than standard documentation.
    Regarding the global variables, i tend to use const or #define statement with some of them like the width or hight. I know it doesn’t change much, but at least i don’t create new variables with the same name accidentally in other functions and get a huge mix-up in code.

  31. renderomut says:

    Thanks for the tutorial. There are not much tutorials for DX10 , and it’s a great deal you wrote one ..

  32. sammy says:

    hi, I need to make 5 moving object ie. teapot, cube, sphere etc… in c++ direct x 3d and i have no clue where to begin with. can u help me in any way please? im desperate for help. pleasee

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: