Click here to Skip to main content
Click here to Skip to main content
Go to top

DirectX10 Geometry Shader with Stream Output

, 10 Oct 2012
Rate this:
Please Sign up or sign in to vote.
GS-SO tutorial for basic effects

Introduction

This article introduces DirectX10 (and DX11) with Geometry shader to novice and intermediate level graphics programmers. The attached code is to be referred while going through this article.

Stream output is also demonstrated here to read back values from the GPU.

Background

Geometry shader is the latest addition to the DX10 APIs, it gives programmers an ability to spawn new and destroy existing geometry using the graphics hardware, and this allows fancier effects such as explosions, realistic growth, decay, (add new effects here Smile | :) ) etc. without reloading the mesh.

Using the Code

The attached solution is created using VS2010-Beta2 and uses library files from DirectX-SDK (Aug/2009).

The first block explains creation of DirectX device, the objective here is to instantiate the device object to access methods to perform operations on the GPU.

DirectX device like any COM device must be created by using class factory. Fortunately, DX-SDK allows the programmer to do this via global APIs, this allows DX programming with minimum COM exposure except for the fact that every COM object is required to be released to avoid memory leaks.

D3D10CreateDeviceAndSwapChain( NULL, D3D10_DRIVER_TYPE_HARDWARE , 
	NULL,0, D3D10_SDK_VERSION, &sd, &pSwapChain, &pd3dDevice );

D3D10CreateDeviceAndSwapChain creates the device and the swap chain. Through the swap chain we get the back buffer (back buffering is used for flicker free animation). We then use the device to create a render target and use the back buffer to write on (please refer to the code).

The next block shows us how to create a vertex layout.

We first specify the layout for the vertices, this can done by using structure (refer to code). The vertex layout is required to tell the DX driver about the vertex format it can expect from the user. In the following example, we have specified that the first 3 floats are x-y-z coordinates and the next 2 will be texel coordinates.

D3D10_INPUT_ELEMENT_DESC

D3D10_INPUT_ELEMENT_DESC layout[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 }, 
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 }, 
};
UINT numElements = sizeof(layout)/sizeof(layout[0]);
D3D10_PASS_DESC PassDesc;
pTechnique->GetPassByIndex( 0 )->GetDesc( &PassDesc );
ID3D10InputLayout *pVertexLayout=0;
pd3dDevice->CreateInputLayout(layout, numElements, PassDesc.pIAInputSignature, 
	PassDesc.IAInputSignatureSize, &pVertexLayout );

We then have to set the vertex buffer layout using:

pd3dDevice->IASetInputLayout( pVertexLayout );

This vertex layout will be set as active layout, you can always set active layout multiple times during rendering depending on the vertex layout required for different objects, (most DX10 based engines expect only one type of layout):

struct SimpleVertex
{
D3DXVECTOR3 Pos; // Position
D3DXVECTOR2 Tex; // Texture Coordinate
};
SimpleVertex vertices[] = { D3DXVECTOR3( 0.5f, 0.5f, 0.0f ),
	D3DXVECTOR2(1.0,1.0), D3DXVECTOR3( -0.5f, -0.5f, 0.0f ),
	D3DXVECTOR2(0.0,0.0), D3DXVECTOR3( -0.5f, 0.5f, 0.0f ),D3DXVECTOR2(0.0,1.0), };

Notice that only three vertices are provided. This is important so as to provide coordinates of a triangle.

We then create a memory buffer for GPU read access and set it to use the coordinates specified in the simple vertex structure (refer to the code). This will help us to pump the vertex data to the GPU, note that this data must be aligned as per the active vertex layout discussed earlier:

...
InitData.pSysMem = vertices;
...
pd3dDevice->CreateBuffer( &bd, &InitData, &pVertexBuffer );

We then load the FX file (the shader file:- effects.txt) which holds the program for vertex shader, geometry shader, pixel shader, the object created is an effects pointer, this pointer can be used for setting up rendering similar to DX9-D3D.

Note that unlike DX9, the vertex shader here is required as fixed point transformations have been removed and all transformations have to be done by using the vertex shader and by passing parameters to variables set up in the vertex shader.

The Pixel shader is required to control rendering (and texturing as seen in the attached sample code), we can alter rendering by setting up variables for different effects (I might write an article about this later).

The geometry shader is not really required, we need it here … well it’s the reason why I am writing this article. Please refer to code to view how the effects pointer has been used to get the ID3D10EffectTechnique pointer which is used within the render loop.

D3DX10CreateEffectFromFile( L"effects.txt", NULL, NULL, "fx_4_0", 
D3D10_SHADER_ENABLE_STRICTNESS, 0, pd3dDevice, NULL,NULL, &pEffect, &pErrors, NULL );

Notice the geometry shader in the effects.txt file.

The Geometry shader is created using:

GeometryShader gStream=ConstructGSWithSO( CompileShader( gs_4_0, GS() ),"SV_POSITION.xyz" ); 
	SetGeometryShader( gStream); //to set the geometry shader

In the attached solution, the geometry shader is used to spawn an additional triangle using command: TriStream.Append. After executing this shader in the effects pass, the output on screen will result in a square (two triangles). Now comes the part to read back values from the graphics card.

This is done in three parts:

  1. The first involves creating a temporary buffer with CPU access, and the other to dump vertex data into.
    sbdesc.CPUAccessFlags =D3D10_CPU_ACCESS_READ ; //notice this setting 
    		//pd3dDevice->CreateBuffer( &sbdesc, NULL, &pStaging );
  2. The next step is to set streaming output (SO) using SOSetTargets(1,&pBuff,&offset). Note that in the effects file (effects.txt), the GS shader has been created using SO.
  3. The last step is to copy the data from the dump to the temporary buffer for reading purposes (or feedback: used to simulate growth effects). This is done by calling pd3dDevice->CopyResource(pStaging,pBuff);
    D3DXVECTOR3 *ptr = 0; 	//since buffer is created with 
    			//D3D10_BIND_VERTEX_BUFFER pStaging->Unmap();

Points of Interest

The Geometry shader with stream output can also be modified to provide GPGPU since we are now able to read back values from the GPU with ease.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

No Biography provided

Comments and Discussions

 
GeneralMy vote of 5 Pinmemberuj_13-Dec-10 19:22 
GeneralDX11 sample for GS-SO [modified] PinmemberAsif Bahrainwala20-Feb-10 6:40 
GeneralMy vote of 1 PinmemberJim Crafton26-Jan-10 5:03 
GeneralRe: My vote of 1 PinmemberAsif Bahrainwala31-Jan-10 9:53 
GeneralRe: My vote of 1 PinmemberAsif Bahrainwala31-Jan-10 22:22 
GeneralPoor Article PinmemberMW_Justin22-Jan-10 13:07 
GeneralRe: Poor Article PinmemberAsif Bahrainwala31-Jan-10 9:51 
GeneralMy vote of 2 PinmemberMW_Justin22-Jan-10 13:04 
General[My vote of 1] Need more information and formatting PinmvpRichard MacCutchan22-Jan-10 2:14 
GeneralCorrupted zip file PinmemberAlexandre GRANVAUD21-Jan-10 23:32 
GeneralRe: Corrupted zip file PinmemberAsif Bahrainwala31-Jan-10 9:49 
GeneralKnew it was you :) Pinmembersumitkm21-Jan-10 19:00 
GeneralRe: Knew it was you :) PinmemberAsif Bahrainwala31-Jan-10 9:48 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140916.1 | Last Updated 11 Oct 2012
Article Copyright 2010 by Asif Bahrainwala
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid