Something about programming

HLSL Shader Compiling in DirectX 11

Previous tutorial: Direct3D 11.1 initialization

As we learned earlier, shaders are important part in graphics creation in Direct3D 11. In this tutorial I will show the simplest way of loading shaders in the application. Firstly we need to create files, where shader's source code will be stored.

Creation of files with shaders

Shaders are stored in separate files, which has .hlsl extension. For this tutorial I've added in the project two files: PixelShader.hlsl and VertexShader.hlsl. File with shader you can add through menu Project → Add New Item and then in the opened window you should choose needed type of shader:

Shader compiling

In DirectX 11 under Windows 8 shader could be compiled in three different ways. Two of them are uses D3D11 device. Third way - D3DCompileFromFile function. We will use this function for shader compiling. This is the quickest and simplest way.

Documentation says that applications that uses function D3DCompileFromFile could not be submitted to Windows Store.

For using shader compiler you need to include header file D3DCompiler.h and add library d3dcompiler.lib:

#include <D3Dcompiler.h> #pragma comment(lib,"D3dcompiler.lib")

D3DCompileFromFile function

D3DCompileFromFile function compiles HLSL shaders. It takes file with source code of shader and returns (last but one argument) interface object ID3DBlob (blob - Binary Large Object, this is just large array of data):

HRESULT WINAPI D3DCompileFromFile( LPCWSTR pFileName, const D3D_SHADER_MACRO *pDefines, ID3DInclude *pInclude, LPCSTR pEntrypoint, LPCSTR pTarget, UINT Flags1, UINT Flags2, ID3DBlob **ppCode, ID3DBlob **ppErrorMsgs );

1. pFileName - name of the file with source code of shader.

2. pDefines - array of macros of shader. Just set it to NULL for now.

3. pInclude - this argument is set when in shader file there is #include directive. Set it to NULL.

4. pEntrypoint - shader's entry point - name of the function with shader's code. By default Visual Studio uses main.

5. pTarget - version and type of the shader: compute, domain, geometry, hull, pixel, vertex. We need by now the last two: pixel and vertex. In DirectX 11 you need to use 5th shader version. Set this value to: vs_5_0 - vertex, ps_5_0 - pixel.

6-7. Flags. Set it to NULL for now.

8. ID3DBlob object where compiled shader will be stored.

9. ppErrorMsgs - error messages will be stored in this object. Set it to NULL.

So, let's compile vertex and pixel shaders:

ID3DBlob* vsBlob; ID3DBlob* psBlob; D3DCompileFromFile(L"VertexShader.hlsl", NULL, NULL, "main", "vs_5_0", NULL, NULL, &vsBlob, NULL); D3DCompileFromFile(L"PixelShader.hlsl", NULL, NULL, "main", "ps_5_0", NULL, NULL, &psBlob, NULL);

Vertex shader we compile in vsBlob, and pixel shader in psBlob.

Creation of shader objects in DirectX 11

Having compiled shader with D3D11 device you can create shader objects - it is representation of shader in the application. For creation of different shader types ID3D11Device interface uses different methods. We need two methods: ID3D11Device::CreateVertexShader and ID3D11Device::CreatePixelShader. They are alike (only last arguments are different). Let's look at the prototype of the first:

HRESULT CreateVertexShader( const void *pShaderBytecode, SIZE_T BytecodeLength, ID3D11ClassLinkage *pClassLinkage, ID3D11VertexShader **ppVertexShader );

1. pShaderBytecode - address of compiled shader in memory.

2. BytecodeLength - size of the compiled shader.

ID3DBlob interface has two methods which stores two previous values: GetBufferPointer - address of the compiled shader, GetBufferSize - size. This methods doesn't take arguments.

3. pClassLinkage - this argument used for linking. Set it to NULL.

4. ppVertexShader - in this variable will be stored shader object.

The code:

ID3D11VertexShader* vs; ID3D11PixelShader* ps; dev->CreateVertexShader(vsBlob->GetBufferPointer(), vsBlob->GetBufferSize(), NULL, &vs); dev->CreatePixelShader(psBlob->GetBufferPointer(), psBlob->GetBufferSize(), NULL, &ps);

Now we need to make created shaders active:

devContext->VSSetShader(vs, NULL, NULL); devContext->PSSetShader(ps, NULL, NULL);

Here device context sets current vertex and pixel shaders. 2nd and 3rd arguments doesn't matter now.


In attached project shaders contains code which is created by Visual Studio by default. These pixel and vertex shaders doesn't do anything with data. When you'll start application, you don't see any differences with the program from previous lesson. Just make sure (in debugger) that vsBlob, psBlob, vs and ps has real addresses (not null).

In this tutorial we learned how to set up two important stages of the graphics pipeline of DirectX 11: vertex and pixel shaders. Now we need to start graphics pipeline with data.


No comments yet