Creating Buffer Resources (Direct3D 10)

Creating buffers requires defining the data that the buffer will store, providing initialization data, and setting up appropriate usage and binding flags. To create textures, see Creating Texture Resources (Direct3D 10).

Create a Vertex Buffer

The steps to creating a vertex buffer are as follows.

Create a Buffer Description

When creating a vertex buffer, a buffer description (see D3D10_BUFFER_DESC) is used to define how data is organized within the buffer, how the pipeline can access the buffer, and how the buffer will be used.

The following example demonstrates how to create a buffer description for a single triangle with vertices that contain position and color values.

struct SimpleVertex
{
    D3DXVECTOR3 Position;  
    D3DXVECTOR3 Color;  
};

    D3D10_BUFFER_DESC bufferDesc;
    bufferDesc.Usage            = D3D10_USAGE_DEFAULT;
    bufferDesc.ByteWidth        = sizeof( SimpleVertex ) * 3;
    bufferDesc.BindFlags        = D3D10_BIND_VERTEX_BUFFER;
    bufferDesc.CPUAccessFlags   = 0;
    bufferDesc.MiscFlags        = 0;

In this example, the buffer description is initialized with almost all default settings for usage, CPU access and miscellaneous flags. The other settings are for the bind flag which identifies the resource as a vertex buffer only, and the size of the buffer.

The usage and CPU access flags are important for performance. These two flags together determine how often a resource gets accessed, what type of memory the resource could be loaded into, and what processor needs to access the resource. Default usage this resource will not be updated very often. Setting CPU access to 0 means that the CPU will not need to either read or write the resource. Taken in combination, this means that the runtime can load the resource into the highest performing memory for the GPU since the resource does not require CPU access.

As expected, there is a tradeoff between best performance and any-time accessibility by either processor. For example, the default usage with no CPU access means that the resource can be made available to the GPU exclusively. This could include loading the resource into memory not directly accessible by the CPU. The resource could only be modified with UpdateSubresource.

Create the Initialization Data for the Buffer

A buffer is just a collection of elements and is laid out as a 1D array. As a result, the system memory pitch and system memory slice pitch are both the same; the size of the vertex data declaration. An application can provide initialization data when a buffer is created using a subresource description, which contains a pointer to the actual resource data and contains information about the size and layout of that data.

Any buffer created with immutable usage (see D3D10_USAGE_IMMUTABLE) must be initialized at creation time. Buffers that use any of the other usage flags can be updated after initialization using CopyResource, CopySubresourceRegion, and UpdateSubresource, or by accessing its underlying memory using the Map method.

Create the Buffer

Using the buffer description and the initialization data (which is optional) call CreateBuffer to create a vertex buffer. The following code snippet demonstrates how to create a vertex buffer from an array of vertex data declared by the application.

struct SimpleVertexCombined
{
    D3DXVECTOR3 Pos;  
    D3DXVECTOR3 Col;  
};


ID3D10InputLayout* g_pVertexLayout = NULL;
ID3D10Buffer*      g_pVertexBuffer[2] = { NULL, NULL };
ID3D10Buffer*      g_pIndexBuffer = NULL;


SimpleVertexCombined verticesCombo[] =
{
    D3DXVECTOR3( 0.0f, 0.5f, 0.5f ),
    D3DXVECTOR3( 0.0f, 0.0f, 0.5f ),
    D3DXVECTOR3( 0.5f, -0.5f, 0.5f ),
    D3DXVECTOR3( 0.5f, 0.0f, 0.0f ),
    D3DXVECTOR3( -0.5f, -0.5f, 0.5f ),
    D3DXVECTOR3( 0.0f, 0.5f, 0.0f ),
};


    D3D10_BUFFER_DESC bufferDesc;
    bufferDesc.Usage            = D3D10_USAGE_DEFAULT;
    bufferDesc.ByteWidth        = sizeof( SimpleVertexCombined ) * 3;
    bufferDesc.BindFlags        = D3D10_BIND_VERTEX_BUFFER;
    bufferDesc.CPUAccessFlags   = 0;
    bufferDesc.MiscFlags        = 0;
    
    D3D10_SUBRESOURCE_DATA InitData;
    InitData.pSysMem = verticesCombo;
    InitData.SysMemPitch = 0;
    InitData.SysMemSlicePitch = 0;
    hr = g_pd3dDevice->CreateBuffer( &bufferDesc, &InitData, &g_pVertexBuffer[0] );

Create an Index Buffer

Creating an index buffer is very similar to creating a vertex buffer; with two differences. An index buffer contains only 16-bit or 32-bit data (instead of the wide range of formats available to a vertex buffer. An index buffer also requires an index-buffer bind flag.

The following example demonstrates how to create an index buffer from an array of index data.

ID3D10Buffer *g_pIndexBuffer = NULL;

    // Create indices
    unsigned int indices[] = { 0, 1, 2 };

    D3D10_BUFFER_DESC bufferDesc;
    bufferDesc.Usage           = D3D10_USAGE_DEFAULT;
    bufferDesc.ByteWidth       = sizeof( unsigned int ) * 3;
    bufferDesc.BindFlags       = D3D10_BIND_INDEX_BUFFER;
    bufferDesc.CPUAccessFlags  = 0;
    bufferDesc.MiscFlags       = 0;

    D3D10_SUBRESOURCE_DATA InitData;
    InitData.pSysMem = indices;
    InitData.SysMemPitch = 0;
    InitData.SysMemSlicePitch = 0;
    hr = g_pd3dDevice->CreateBuffer( &bufferDesc, &InitData, &g_pIndexBuffer );
    if( FAILED( hr ) )
        return hr;
  
    g_pd3dDevice->IASetIndexBuffer( g_pIndexBuffer, DXGI_FORMAT_R32_UINT, 0 );

Create a Constant Buffer

Direct3D 10 introduces a constant buffer. A constant buffer, or shader constant buffer, is a buffer that contains shader constants. Here is an example of creating a constant buffer, taken from the HLSLWithoutFX10 Sample.

ID3D10Buffer*   g_pConstantBuffer10 = NULL;

struct VS_CONSTANT_BUFFER
{
    D3DXMATRIX mWorldViewProj;      //mWorldViewProj will probably be global to all shaders in a project.
                                    //It's a good idea not to move it around between shaders.
    D3DXVECTOR4 vSomeVectorThatMayBeNeededByASpecificShader;
    float fSomeFloatThatMayBeNeededByASpecificShader;
    float fTime;                    //fTime may also be global to all shaders in a project.
    float fSomeFloatThatMayBeNeededByASpecificShader2;
    float fSomeFloatThatMayBeNeededByASpecificShader3;
};

    D3D10_BUFFER_DESC cbDesc;
    cbDesc.ByteWidth = sizeof( VS_CONSTANT_BUFFER );
    cbDesc.Usage = D3D10_USAGE_DYNAMIC;
    cbDesc.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
    cbDesc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
    cbDesc.MiscFlags = 0;
    hr = g_pd3dDevice->CreateBuffer( &cbDesc, NULL, &g_pConstantBuffer10 );
    if( FAILED( hr ) )
       return hr;

    g_pd3dDevice->VSSetConstantBuffers( 0, 1, g_pConstantBuffer10 );

Note that when using the ID3D10Effect Interface interface the process of creating, binding and comitting a constant buffer is handled by the ID3D10Effect Interface instance. In that case it is only nescesary to get the variable from the effect with one of the GetVariable methods such as GetVariableByName and update the variable with one of the SetVariable methods such as SetMatrix. For an example of using ID3D10Effect Interface to manage a constant buffer see Tutorial 7: Texture Mapping and Constant Buffers.

Resources (Direct3D 10)