• Advertisement
Sign in to follow this  

Constant buffer padding

This topic is 1472 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've been thinking about how to go about doing this for a while now. I've got a shader parameter system that basically creates a chunk of data from a parameter list and allows them to be set using a map of names and offsets. The thing I can't figure out though, is how I should calculate padding for the parameters. Basically I allocate the data and store offsets like this: 

bool IShaderParameterBuffer::init(const std::vector<SShaderParameterDesc>& paramDesc)
{
	size_t offset = 0;

	for ( unsigned int i=0; i<paramDesc.size(); ++i )
	{
		size_t paramSz = IInputLayout::getElementSize(paramDesc[i].Format);

		m_offsetMap[paramDesc[i].Name] = offset;
		offset += paramSz;
	}

	m_paramBuffer = (char*)malloc(offset);
	m_bufferSz = offset;

	return true;
}

And I take this information to create a constant buffer, but const buffer size has to be a multiple of 16. What would be the best way to go about making sure that the data size is a multiple of 16?

Share this post


Link to post
Share on other sites
Advertisement
m_bufferSz = (offset + 15) & 0xfffffff0;

m_bufferSz = ((offset + 15) / 16) * 16. //same thing without hex and bitwise-and if you don't like those

It sounded like that's all you were asking (pad for 16B boundary). If I misinterpreted, please clarify what you're looking for.

 

Edit: originally had 0x100, which is obviously wrong. (2nd edit: more fail)

Edited by richardurich

Share this post


Link to post
Share on other sites

I've deleted a lot of data just to make the post smaller.

 

My formula for a variable size is:

return (arraySize - 1) * 16 + VariableType_GetSizeByes(type);
where array size for non arrays is 1

Where array size for non-arrays is 1. VariableType_GetSizeByes returns the size in bytes for(float, int, float2, float3.. ect)

 

U32 GetTotalSizeBytes() const
{
const int numVariables = GetNumVariables();
 
U32 totalSize = 0;
bool bForceNewVectorPadding = false;
 
for(int t = 0; t < numVariables; ++t)
{
const VariableReflection& var = GetVariable(t);
const U32 varSize = var.GetSizeBytes();
 
if (var.arraySize > 1 || bForceNewVectorPadding)//array or forced variable
{
totalSize += totalSize % 16; // add padding
totalSize += varSize;
 
//bForceNewVectorPadding = var.arraySize > 1; //next variable starts new vector
}
else //non forced variable
{
U32 freeSpaceUntilNextVector = 16 - totalSize % 16;
 
if (varSize <= freeSpaceUntilNextVector) totalSize += varSize;
else totalSize += varSize + freeSpaceUntilNextVector;
}
}
 
return totalSize + 16 - totalSize % 16;
}
 

 

 

 

To check things fast use install the "hello triangle" demo form the DXSDK June2010 and add that code under the vertex shader compilation:

 

ID3D11ShaderReflection* pReflection = nullptr;
D3DReflect(pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), IID_ID3D11ShaderReflection, (void**)&pReflection);
 
D3D11_SHADER_DESC shaderDesc;
pReflection->GetDesc(&shaderDesc);
 
for (UINT i = 0; i < shaderDesc.BoundResources; i++)
{
D3D11_SHADER_INPUT_BIND_DESC resourceDesc;
pReflection->GetResourceBindingDesc(i, &resourceDesc);
 
switch (resourceDesc.Type)
{
//CBuffer
case D3D_SIT_CBUFFER:
{
const char* pCBufferName = resourceDesc.Name;
ID3D11ShaderReflectionConstantBuffer* pCBufferReflection = (pReflection->GetConstantBufferByName(pCBufferName));
 
D3D11_SHADER_BUFFER_DESC desc;
pCBufferReflection->GetDesc(&desc);
 
for (unsigned int t = 0; t < desc.Variables; ++t)
{
 
ID3D11ShaderReflectionVariable* pVariable = (pCBufferReflection->GetVariableByIndex(t));
 
D3D11_SHADER_VARIABLE_DESC varDesc;
pVariable->GetDesc(&varDesc);
 
int x = 10;//bla bla
};
}
}
};

 

 

Edited by imoogiBG

Share this post


Link to post
Share on other sites

 

U32 GetTotalSizeBytes() const
{
const int numVariables = GetNumVariables();
 
U32 totalSize = 0;
bool bForceNewVectorPadding = false;
 
for(int t = 0; t < numVariables; ++t)
{
const VariableReflection& var = GetVariable(t);
const U32 varSize = var.GetSizeBytes();
 
if (var.arraySize > 1 || bForceNewVectorPadding)//array or forced variable
{
totalSize += totalSize % 16; // add padding
totalSize += varSize;
 
//bForceNewVectorPadding = var.arraySize > 1; //next variable starts new vector
}
else //non forced variable
{
U32 freeSpaceUntilNextVector = 16 - totalSize % 16;
 
if (varSize <= freeSpaceUntilNextVector) totalSize += varSize;
else totalSize += varSize + freeSpaceUntilNextVector;
}
}
 
return totalSize + 16 - totalSize % 16;
}

 

I know you said you deleted a lot of your post to make it smaller, so I worry you might have deleted something important that makes it seem weird right now.

 

I can't figure out what the code intends to do with "totalSize += totalSize %16;". As listed, if you pass in char[2] elem1, char[2] elem2, char[2] elem3, you get elem1, 2 bytes of padding, elem2, 6 bytes of padding, elem3, 14 bytes of padding, elem4. Maybe that is the intent, but it seems really weird.

 

For OP, it's worth noting "- totalSize % 16" is mathematically the same as "& 0xfffffff0", ">>4)<<4", "/16) * 16". I suspect the only reason %16 isn't common in code is that it requires using 2 lines of code instead of one.

 

Edit: fixed f00 to f0 per L. Spiro's correction.

Edited by richardurich

Share this post


Link to post
Share on other sites

Yes i've deleted the wrong thing : 
 

if (var.arraySize > 1 || bForceNewVectorPadding)//array or forced variable
{
totalSize += 16 - totalSize % 16; // add padding
...

totalSize += 16 - totalSize % 16; // add padding that line starts a new vector(16 byte aligned block). Imagine cbuffer like that:
float2 var;
float array[3];

 

var -> 8 bytes (total size of the buffer until now is 8 bytes)

array -> according to MSDN arrays are forced to start in a new 16byte aligned block

 

//lets force it by adding the needed padding

totalSize += 16 - totalSize % 16; or totalSize += 16 - 8 % 16

 

also bForceNewVectorPadding is not needed.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement