DX11: Debugging Constant Buffers using the Shader Reflection API
DX11 uses constant buffers to share uniform variables between your C++ code and the shaders. This works very nicely most of the time, however I ran into an alignment issue in my constant buffer that was causing all kinds of strange behavior. The members within a constant buffer are assumed to have a certain alignment and if your C++ code doesn't respect the alignment rules, then you too will have bugs.
After spending longer than I care to admit, fiddling with my code and getting strange results I decided to investigate the shader reflection api.
After spending longer than I care to admit, fiddling with my code and getting strange results I decided to investigate the shader reflection api.
Shader Reflection API
The shader reflection api lets us find out what is in the constant buffer and more importantly how it is aligned. We can then compare this with how our C++ compiler aligned the data and ensure they match.
A quick poke around the internet led me to this article by Jason Zink which is a nice introduction to using the reflection API.
Here are the rules from Microsoft and packing in HLSL.
I also had to:
Using this function quickly showed me that the vector3 library I was using does not get padded to qword boundaries. Manually adding word size pads to ensure my data elements did not cross qword boundaries solved my bug.
A quick poke around the internet led me to this article by Jason Zink which is a nice introduction to using the reflection API.
Here are the rules from Microsoft and packing in HLSL.
I also had to:
- add an extra library: #pragma comment(lib, "d3dcompiler.lib")
- add an extra incliude: #include <D3D11Shader.h>
- and add a define at the top of the file where the reflection library is used: #define INITGUID
Using this function quickly showed me that the vector3 library I was using does not get padded to qword boundaries. Manually adding word size pads to ensure my data elements did not cross qword boundaries solved my bug.
The Code
//this is a simple stand alone function that takes a loaded shader and file name as input
//it inspects the constant buffers in the shader and writes them out to the file
void constantBufferReflect(ID3DBlob* shader,char *fileName)
{
HRESULT hr;
ofstream fout;
ID3D11ShaderReflection* pReflector = NULL;
hr = D3DReflect(shader->GetBufferPointer(),
shader->GetBufferSize(),
IID_ID3D11ShaderReflection, // See top of file: #define INITGUID //need to add this to get the shader reflection library working
(void**) &pReflector);
D3D11_SHADER_DESC desc;
pReflector->GetDesc( &desc );
fout.open(fileName);
fout << "Reflecting Constant Buffers (" <<desc.ConstantBuffers<<")\n";
for ( UINT i = 0; i < desc.ConstantBuffers; i++ )
{
D3D11_SHADER_BUFFER_DESC Description;
ID3D11ShaderReflectionConstantBuffer* pConstBuffer = pReflector->GetConstantBufferByIndex( i );
pConstBuffer->GetDesc( &Description );
for ( UINT j = 0; j < Description.Variables; j++ )
{
ID3D11ShaderReflectionVariable* pVariable = pConstBuffer->GetVariableByIndex( j );
D3D11_SHADER_VARIABLE_DESC var_desc;
pVariable->GetDesc( &var_desc );
fout << " Name: "<<var_desc.Name;
fout << " Size: "<<var_desc.Size ;
fout << " Offset: "<<var_desc.StartOffset<<"\n";
}
}
fout.close();
}
//it inspects the constant buffers in the shader and writes them out to the file
void constantBufferReflect(ID3DBlob* shader,char *fileName)
{
HRESULT hr;
ofstream fout;
ID3D11ShaderReflection* pReflector = NULL;
hr = D3DReflect(shader->GetBufferPointer(),
shader->GetBufferSize(),
IID_ID3D11ShaderReflection, // See top of file: #define INITGUID //need to add this to get the shader reflection library working
(void**) &pReflector);
D3D11_SHADER_DESC desc;
pReflector->GetDesc( &desc );
fout.open(fileName);
fout << "Reflecting Constant Buffers (" <<desc.ConstantBuffers<<")\n";
for ( UINT i = 0; i < desc.ConstantBuffers; i++ )
{
D3D11_SHADER_BUFFER_DESC Description;
ID3D11ShaderReflectionConstantBuffer* pConstBuffer = pReflector->GetConstantBufferByIndex( i );
pConstBuffer->GetDesc( &Description );
for ( UINT j = 0; j < Description.Variables; j++ )
{
ID3D11ShaderReflectionVariable* pVariable = pConstBuffer->GetVariableByIndex( j );
D3D11_SHADER_VARIABLE_DESC var_desc;
pVariable->GetDesc( &var_desc );
fout << " Name: "<<var_desc.Name;
fout << " Size: "<<var_desc.Size ;
fout << " Offset: "<<var_desc.StartOffset<<"\n";
}
}
fout.close();
}
Sample Output
In the shader:
cbuffer cbPerObject
{
float4x4 WVP;
float4x4 World;
float4 vMeshColor;
float4 lightCol;
float4 lightAmb;
float3 lightPosW;
float3 eyePosW;
};
File output:
Reflecting Constant Buffers (1)
Name: WVP Size: 64 Offset: 0
Name: World Size: 64 Offset: 64
Name: vMeshColor Size: 16 Offset: 128
Name: lightCol Size: 16 Offset: 144
Name: lightAmb Size: 16 Offset: 160
Name: lightPosW Size: 12 Offset: 176
Name: eyePosW Size: 12 Offset: 192
cbuffer cbPerObject
{
float4x4 WVP;
float4x4 World;
float4 vMeshColor;
float4 lightCol;
float4 lightAmb;
float3 lightPosW;
float3 eyePosW;
};
File output:
Reflecting Constant Buffers (1)
Name: WVP Size: 64 Offset: 0
Name: World Size: 64 Offset: 64
Name: vMeshColor Size: 16 Offset: 128
Name: lightCol Size: 16 Offset: 144
Name: lightAmb Size: 16 Offset: 160
Name: lightPosW Size: 12 Offset: 176
Name: eyePosW Size: 12 Offset: 192