Wednesday, April 13, 2011

Constant Buffer

This tutorial will demonstrate the use of constant buffers to update multiple variables in a shader in a single call.

We group constant buffers based on the frequency of their usage. For example, world transformation matrix changes every frame for each and every object (assumption), so does it's inverse transpose. So we group it as a constant buffer. Similarly, assuming projection matrix remains static, we group it as a static constant buffer.

// Constant buffer that's static
cbuffer CBStatic
row_major matrix m_matProjection; // Projection matrix

// Constant buffer that changes every frame
cbuffer CBEveryFrame
matrix m_matWorld; // World matrix
matrix m_matInverseTransposeWorld; // Inverse transpose of world matrix

Their corresponding structure in our C++ code:

// Constant buffer that remains unchanged
struct SStaticConstantBuffer
XMMATRIX m_oProjectionMatrix; // Projection matrix

// Constant buffer that changes every frame
struct SChangesEveryFrameConstantBuffer
XMMATRIX m_oWorldMatrix; // World matrix
XMMATRIX  m_oInverseTransposeWorldMatrix; // Inverse transpose of world matrix

// Constant buffer description

D3D11_BUFFER_DESC oD3DBufferDesc = {0};
oD3DBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; // Bind constant buffer

// Create constant buffer that's static
oD3DBufferDesc.Usage = D3D11_USAGE_DEFAULT; // GPU read/write
oD3DBufferDesc.ByteWidth = sizeof(SStaticConstantBuffer);
CHECK_COM(pD3DDevice->CreateBuffer(&oD3DBufferDesc, nullptr, &m_pD3DStaticConstBuffer));

oD3DBufferDesc.Usage = D3D11_USAGE_DYNAMIC; // GPU read only; CPU write only permissions
oD3DBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; // CPU can change it's contents

// Create constant buffer that changes every frame
oD3DBufferDesc.ByteWidth = sizeof(SChangesEveryFrameConstantBuffer);
CHECK_COM(pD3DDevice->CreateBuffer(&oD3DBufferDesc, nullptr, &m_pD3DChangesEveryFrameConstBuffer));

It's time to update the constant buffer that changes every frame:

D3D11_MAPPED_SUBRESOURCE oD3DMappedSubresource;

// Get a pointer to the data that contains HLSL constant buffers
CHECK_COM(pD3DDeviceContext->Map(m_pD3DChangesEveryFrameConstBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &oD3DMappedSubresource));

// Update the constant buffer data that changes every frame
::memcpy(oD3DMappedSubresource.pData, g_pChangesEveryFrameConstBuffer, sizeof(SChangesEveryFrameConstantBuffer)); // g_pChangesEveryFrameConstBuffer is a pointer to SChangesEveryFrameConstantBuffer

pD3DDeviceContext->Unmap(m_pD3DChangesEveryFrameConstBuffer, 0); // Unmap the pointer to the data

pD3DDeviceContext->VSSetConstantBuffers(0, 1, &m_pD3DChangesEveryFrameConstBuffer); // Set constant buffer that changes every frame

So in this way we update multiple variables in a constant buffer in a single call

No comments:

Post a Comment