CConstantBuffer, CTypedConstantBuffer

Warning! Some information on this page is older than 5 years now. I keep it for reference, but it probably doesn't reflect my current knowledge and beliefs.

# CConstantBuffer, CTypedConstantBuffer

Wed
30
Jan 2013

DirectX 10 and 11 have new, redesigned API that has its pros and cons. One can say that it is now more clean and well organized, but on the other hand it requires more (or as those who code in higher-level languages than C++ or use existing game engines would say - *even more*) lines of code than old Direct3D 9. So I created classes that encapsulate some most typical boilerplate D3D11 code. Here is first one - CConstantBuffer, which handles constant buffer, required now to pass any uniform parameters to a shader.

class CConstantBuffer {
public:
    CConstantBuffer(
        size_t bytesLength,
        const void* initialData = nullptr,
        bool immutable = false );
    ~CConstantBuffer();
    ID3D11Buffer* Buffer() { return m_Buffer.get(); }
    void Update(const void* src);
    void SetForVS(UINT slot);
    // ...and so on for HS, DS, GS, PS, CS.
private:
    size_t m_Length;
    unique_ptr<ID3D11Buffer, ReleaseDeleter> m_Buffer;
};
CConstantBuffer::CConstantBuffer(
    size_t bytesLength,
    const void* initialData,
    bool immutable ) :
    m_Length(bytesLength)
{
    assert(initialData || !immutable);

    D3D11_BUFFER_DESC desc;
    ZeroMemory(&desc, sizeof desc);
    desc.ByteWidth = (UINT)m_Length;
    desc.Usage = immutable ? D3D11_USAGE_IMMUTABLE : D3D11_USAGE_DEFAULT;
    desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;

    D3D11_SUBRESOURCE_DATA subresourceData;
    D3D11_SUBRESOURCE_DATA* subresourceDataPtr = nullptr;
    if(initialData) {
        ZeroMemory(&subresourceData, sizeof subresourceData);
        subresourceData.pSysMem = initialData;
        subresourceDataPtr = &subresourceData;
    }

    ID3D11Buffer* buffer;
    g_Device->CreateBuffer(&desc, subresourceDataPtr, &buffer);
    m_Buffer.reset(buffer);
}

CConstantBuffer::~CConstantBuffer()
{
}

void CConstantBuffer::Update(const void* src)
{
    g_Context->UpdateSubresource(m_Buffer.get(), 0, nullptr, src, 0, 0);
}

void CConstantBuffer::SetForVS(UINT slot)
{
    ID3D11Buffer* buf = m_Buffer.get();
    g_Context->VSSetConstantBuffers(slot, 1, &buf);
}

// ...and so on for HS, DS, GS, PS, CS.

It would be even more convenient if we could pass specific type of a structure used for particular constant buffer as template parameter to such class and use it instead of casting to void*. So I created derived class:

template<typename T>
class CTypedConstantBuffer : public CConstantBuffer {
public:
    typedef T BufferType;
    CTypedConstantBuffer(
        const T* initialData = nullptr,
        bool immutable = false) :
        CConstantBuffer(sizeof(T), initialData, immutable) { }
    using CConstantBuffer::Update;
    void Update(const T& src) { Update((const void*)&src); }
};

Usage is very simple. If we have following definition in HLSL shade:

cbuffer PixelShaderConstantBuffer : register(b0) {
    float4 Color;
    float SpecularIntensity;
    float SpecularExponent;
};

Then its C++ equivalent is (never forget about proper alignment and padding to width of float4 vector!):

struct SPixelShaderBuffer
{
    vec4 Color;
    float SpecularIntensity;
    float SpecularExponent;
    vec2 Padding0;
};

Now to pass these parameters as constant buffer, it's enough to define variable:

CTypedConstantBuffer<SPixelShaderBuffer> m_PixelShaderBuffer;

And every frame:

1. Write data.

SPixelShaderBuffer psBuf;
psBuf.Color = ...
psBuf.SpecularIntensity = ...
psBuf.SpecularExponent = ...
m_PixelShaderBuffer.Update(psBuf);

2. Bind it to correct slot and correct shader type.

m_PixelShaderBuffer.SetForPS(0);

Comments | #directx Share

Comments

STAT NO AD
[Stat] [STAT NO AD] [Download] [Dropbox] [pub] [Mirror] [Privacy policy]
Copyright © 2004-2019