Buffers

For the purposes of rendering, we will need to supply the API with data to use. For this, we create buffers. Buffers are objects responsible for containing data usable by the API. For the purposes of this demo, we will make 3 different buffers:

  • Vertex buffer: Supplies the position and texture coordinate data per vertex
  • Index buffer: Supplies the indices of triangles to be rendered, enabling reuse of the same vertices
  • Constant buffer: Supplies static data to all vertex- and/or pixel shader invocations

Each of these buffers are created with respective bind flags, specifying to the API what kind of buffers they are allowed to be used as.

result = renderer->device->lpVtbl->CreateBuffer (
    renderer->device,
    &(D3D11_BUFFER_DESC){
        .ByteWidth = (uint32_t)scene->vertexDataSizeInBytes,
        .Usage     = D3D11_USAGE_DEFAULT,
        .BindFlags = D3D11_BIND_VERTEX_BUFFER,
    },
    &(D3D11_SUBRESOURCE_DATA){
        .pSysMem     = scene->vertexData,
        .SysMemPitch = (uint32_t)scene->vertexDataSizeInBytes,
    },
    &renderer->vb
);
if ( !SUCCEEDED ( result ) )
    RETURN_ERROR(-1, "CreateBuffer failed (0x%08X)", result );
result = renderer->device->lpVtbl->CreateBuffer (
    renderer->device,
    &(D3D11_BUFFER_DESC){
        .ByteWidth = (uint32_t)scene->indexDataSizeInBytes,
        .Usage     = D3D11_USAGE_DEFAULT,
        .BindFlags = D3D11_BIND_INDEX_BUFFER,
    },
    &(D3D11_SUBRESOURCE_DATA){
        .pSysMem     = scene->indexData,
        .SysMemPitch = (uint32_t)scene->indexDataSizeInBytes,
    },
    &renderer->ib
);
if ( !SUCCEEDED ( result ) )
    RETURN_ERROR(-1, "CreateBuffer failed (0x%08X)", result );
result = renderer->device->lpVtbl->CreateBuffer (
    renderer->device,
    &(D3D11_BUFFER_DESC){
        .ByteWidth      = RVM_ALIGN_UP_POW2 ( sizeof ( rvm_aos_mat4 ), 16 ),
        .Usage          = D3D11_USAGE_DYNAMIC,
        .BindFlags      = D3D11_BIND_CONSTANT_BUFFER,
        .CPUAccessFlags = D3D11_CPU_ACCESS_WRITE,
    },
    NULL,
    &renderer->cb
);
if ( !SUCCEEDED ( result ) )
    RETURN_ERROR(-1, "CreateBuffer failed (0x%08X)", result );

The D3D11_SUBRESOURCE_DATA specified in the vertex- and index buffer create function calls are the default data for the resource. This can be edited by the GPU, or even by the CPU if access is granted, but for the purposes of this application we do not intend to change the data in these buffers.

In the case of the constant buffer, we do not specify original data. Instead, we specify that we would like to be able to edit the resource. This is controlled by two different properties: Usage and CPUAccessFlags. Usage is set to D3D11_USAGE_DYNAMIC. This indicates to the API that it should expect the data to change, and the CPU can be allowed to access the resource. CPUAccessFlags is set to D3D11_CPU_ACCESS_WRITE, confirming we would like to be able to edit the contents of this resource by writing to it through the CPU.

What should also be noted is that constant buffers have some interesting rules in terms of the size and alignment of elements. Constant buffers are addressed per 16-bytes rather than per byte. As such, the size of a constant buffer needs to be a multiple of 16-bytes. In addition, it should be noted that in HLSL, no element is allowed to cross this 16-byte boundary, potentially givng unexpected offsets for properties.