Mapping a dynamic buffer in Direct3D11 in a Windows Store App - c++

I'm trying to make instanced geometry in Direct3D11, and the ID3D11DeviceContext1->Map() call is failing with the very helpful error of "Invalid Parameter" when I'm attempting to update the instance buffer.
The buffer is declared as a member variable:
Microsoft::WRL::ComPtr<ID3D11Buffer> m_instanceBuffer;
Then I create it (which succeeds):
D3D11_BUFFER_DESC instanceDesc;
ZeroMemory(&instanceDesc, sizeof(D3D11_BUFFER_DESC));
instanceDesc.Usage = D3D11_USAGE_DYNAMIC;
instanceDesc.ByteWidth = sizeof(InstanceData) * MAX_INSTANCE_COUNT;
instanceDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
instanceDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
instanceDesc.MiscFlags = 0;
instanceDesc.StructureByteStride = 0;
DX::ThrowIfFailed(d3dDevice->CreateBuffer(&instanceDesc, NULL, &m_instanceBuffer));
However, when I try to map it:
D3D11_MAPPED_SUBRESOURCE inst;
DX::ThrowIfFailed(d3dContext->Map(m_instanceBuffer.Get(), 0, D3D11_MAP_WRITE, 0, &inst));
The map call fails with E_INVALIDARG. Nothing is NULL incorrectly, and this being one of my first D3D apps I'm currently stumped on what to do next to track it down. I'm thinking I must be creating the buffer incorrectly, but I can't see how. Any input would be appreciated.

Because the buffer was created with D3D11_USAGE_DYNAMIC, it had to be mapped with D3D_MAP_WRITE_DISCARD (or D3D_MAP_WRITE_NO_OVERWRITE, but that was inappropriate for my application).

I had the same problem when I tried to create a buffer for a shader. At the createBuffer it would always give me E_INVALIDARG.
The problem at my project was, that I forgot to align all the attributes to 16 Bytes. here is an example:
struct TessellationBufferType
{
float tessellationAmount; //4bytes
D3DXVECTOR3 cameraPosition; //12bytes
};
and if you don't get 16, add an additional variable (e.g padding) just to align up to 16:
struct LightBufferType
{
D3DXVECTOR4 ambientColor; //16
D3DXVECTOR4 diffuseColor; //16
D3DXVECTOR3 lightDirection; //12
float padding; //4
};

Related

How do I load multiple structs into a single UBO?

I am following the tutorials on: Here.
I have completed up till loading models so my code is similar to that point.
I am now trying to pass another struct to the Uniform Buffer Object, in a similar way to previously shown.
I have created another struct defined outside the application to store the data as follows:
struct Light{
alignas(16) glm::vec3 position;
alignas(16) glm::vec3 colour;
};
After doing this, I resized the uniform buffer size in the following way:
void createUniformBuffers() {
VkDeviceSize bufferSize = sizeof(CameraUBO) + sizeof(Light);
...
Next, when creating the descriptor sets, I added the lightBufferInfo below the already defined bufferInfo as shown below:
...
for (size_t i = 0; i < swapChainImages.size(); i++) {
VkDescriptorBufferInfo bufferInfo = {};
bufferInfo.buffer = uniformBuffers[i];
bufferInfo.offset = 0;
bufferInfo.range = sizeof(UniformBufferObject);
VkDescriptorBufferInfo lightBufferInfo = {};
lightBufferInfo.buffer = uniformBuffers[i];
lightBufferInfo.offset = 0;
lightBufferInfo.range = sizeof(Light);
...
I then added this to the descriptorWrites array:
...
descriptorWrites[2].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrites[2].dstSet = descriptorSets[i];
descriptorWrites[2].dstBinding = 2;
descriptorWrites[2].dstArrayElement = 0;
descriptorWrites[2].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptorWrites[2].descriptorCount = 1;
descriptorWrites[2].pBufferInfo = &lightBufferInfo;
...
Now similarly to the UniformBufferObject I plan to use the updateUniformBuffer(uint32_t currentImage) function to change the lights position and colour, but first I just tried to set the position to a desired value:
void updateUniformBuffer(uint32_t currentImage) {
...
ubo.proj[1][1] *= -1;
Light light = {};
light.position = glm::vec3(0, 10, 10);
light.colour = glm::vec3(1, 1, 0);
void* data;
vkMapMemory(device, uniformBuffersMemory[currentImage], 0, sizeof(ubo), 0, &data);
memcpy(data, &ubo, sizeof(ubo));
vkUnmapMemory(device, uniformBuffersMemory[currentImage]);
}
I do not understand how the offset works when trying to pass two objects to a uniform buffer, so I do not know how to copy the light object to uniformBuffersMemory.
How would the offsets be defined in order to get this to work?
A note before reading further: Splitting data for a single UBO into two different structs and descriptors makes passing data a bit more complicated, as all your sizes and writes need to be aligned to the minUniformBufferAlignment property of your device, making your code a bit more complicated. If you're starting with Vulkan you may want to split the data either into two UBOs (creating two buffers), or just pass all values as a single struct.
But if you want to continue with the way you described in your post:
First you need to properly size your array, because your copies need to be aligned to minUniformBufferAlignment you probably can't just copy your light data to the area right after your other data. If your device has an minUniformBufferAlignment of 256 bytes and you want to copy over two host structs you'r uniform buffers size needs to be at least 2 * 256 bytes and not just sizeof(matrices) + sizeof(lights). So you need to adjust your bufferSize in the VkDeviceSize structure accordingly.
Next you need to offset your lightBufferInfo VkDescriptorBufferInfo:
lightBufferInfo.offset = std::max(sizeof(Light), minUniformBufferOffsetAlignment);
This will let your vertex shader know where to start fetching data for that binding.
On most NVidia GPUs e.g., minUniformBufferOffsetAlignment is 256 bytes, where as the size of your Light struct is 32 bytes. So to make this work on such a GPU you have to align at 256 bytes instead of 32.
Inspecting your setup in RenderDoc should then look similar to this:
Note that for more complex allocations and scenarios you'd need to properly get the right alignment size depending on the size of your data structure instead of using a simple max like above.
And now when updating your uniform buffers you need to map and copy to the proper offset too:
void* mapped = nullptr;
// Copy matrix data to offset for binding 0
vkMapMemory(device, uniformBuffersMemory[currentImage].memory, 0, sizeof(ubo), 0, &mapped);
memcpy(mapped, &ubo, sizeof(ubo));
vkUnmapMemory(device, uniformBuffersMemory[currentImage].memory);
// Copy light data to offset for binding 1
vkMapMemory(device, uniformBuffersMemory[currentImage].memory, std::max(sizeof(ubo), minUniformBufferOffsetAlignment), sizeof(Light), 0, &mapped);
memcpy(mapped, &uboLight, sizeof(Light));
vkUnmapMemory(device, uniformBuffersMemory[currentImage].memory);
Note that you may want to only map once after creating the buffers for performance reasons rather than mapping on every update. Just store the offset pointer somewhere in your code.

OpenGL 4.5 - Shader storage buffer objects layout

I'm trying my hand at shader storage buffer objects (aka Buffer Blocks) and there are a couple of things I don't fully grasp. What I'm trying to do is to store the (simplified) data of an indeterminate number of lights n in them, so my shader can iterate through them and perform calculations.
Let me start by saying that I get the correct results, and no errors from OpenGL. However, it bothers me not to know why it is working.
So, in my shader, I got the following:
struct PointLight {
vec3 pos;
float intensity;
};
layout (std430, binding = 0) buffer PointLights {
PointLight pointLights[];
};
void main() {
PointLight light;
for (int i = 0; i < pointLights.length(); i++) {
light = pointLights[i];
// etc
}
}
and in my application:
struct PointLightData {
glm::vec3 pos;
float intensity;
};
class PointLight {
// ...
PointLightData data;
// ...
};
std::vector<PointLight*> pointLights;
glGenBuffers(1, &BBO);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, BBO);
glNamedBufferStorage(BBO, n * sizeof(PointLightData), NULL, GL_DYNAMIC_STORAGE_BIT);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, BBO);
...
for (unsigned int i = 0; i < pointLights.size(); i++) {
glNamedBufferSubData(BBO, i * sizeof(PointLightData), sizeof(PointLightData), &(pointLights[i]->data));
}
In this last loop I'm storing a PointLightData struct with an offset equal to its size times the number of them I've already stored (so offset 0 for the first one).
So, as I said, everything seems correct. Binding points are correctly set to the zeroeth, I have enough memory allocated for my objects, etc. The graphical results are OK.
Now to my questions. I am using std430 as the layout - in fact, if I change it to std140 as I originally did it breaks. Why is that? My hypothesis is that the layout generated by std430 for the shader's PointLights buffer block happily matches that generated by the compiler for my application's PointLightData struct (as you can see in that loop I'm blindingly storing one after the other). Do you think that's the case?
Now, assuming I'm correct in that assumption, the obvious solution would be to do the mapping for the sizes and offsets myself, querying opengl with glGetUniformIndices and glGetActiveUniformsiv (the latter called with GL_UNIFORM_SIZE and GL_UNIFORM_OFFSET), but I got the sneaking suspicion that these two guys only work with Uniform Blocks and not Buffer Blocks like I'm trying to do. At least, when I do the following OpenGL throws a tantrum, gives me back a 1281 error and returns a very weird number as the indices (something like 3432898282 or whatever):
const char * names[2] = {
"pos", "intensity"
};
GLuint indices[2];
GLint size[2];
GLint offset[2];
glGetUniformIndices(shaderProgram->id, 2, names, indices);
glGetActiveUniformsiv(shaderProgram->id, 2, indices, GL_UNIFORM_SIZE, size);
glGetActiveUniformsiv(shaderProgram->id, 2, indices, GL_UNIFORM_OFFSET, offset);
Am I correct in saying that glGetUniformIndices and glGetActiveUniformsiv do not apply to buffer blocks?
If they do not, or the fact that it's working is like I imagine just a coincidence, how could I do the mapping manually? I checked appendix H of the programming guide and the wording for array of structures is somewhat confusing. If I can't query OpenGL for sizes/offsets for what I'm tryind to do, I guess I could compute them manually (cumbersome as it is) but I'd appreciate some help in there, too.

Shader storage buffer object with bytes

I am working on a compute shader where the output is written to SSBO.Now,the consumer of this buffer is CUDA which expects it to contain unsigned bytes.I currently can't see find the way how to write a byte per index in SSBO.With texture or image the normalized float to unsigned byte conversion is handled by OpenGL.For example I can attach a texture with internal format R8 and store byte per entry.But nothing like this is possible with SSBO.Does it mean that except of bool data type all the numerical storage types in SSBO can be at least 4 bytes per entry only?
Practically speaking I would like to be able to do the following:
Compute shader:
#version 430 core
layout (local_size_x = 8,local_size_y = 8 ) in;
struct SSBOBlock
{
byte mydata;
};
layout(std430,binding = BUFFER_OUTPUT) writeonly buffer bBuffer
{
SSBOBlock Ouput[];
} Out;
void main()
{
//..... Compute shader stuff...
//.......
Out.Ouput[globalIndex].mydata = val;//where val is normalized float
}
The smallest type exposed on GPUs tends to be 32-bit for scalars. Even the boolean type you mentioned is actually 32-bit. The same goes for languages like C often; a boolean does not need anything more than 1-bit but even so bool is not synonymous with "give me the smallest data type available."
There are intrinsic functions you can use to pack and unpack data types however and I will show an example of how to use them below:
#version 420 core
layout (local_size_x = 8,local_size_y = 8 ) in;
struct SSBOBlock
{
uint mydata;
};
layout(std430,binding = BUFFER_OUTPUT) writeonly buffer bBuffer
{
SSBOBlock Ouput[];
} Out;
void main()
{
//..... Compute shader stuff...
//.......
Out.Output [globalIndex].mydata = packUnorm4x8 (val)
// where val is a 4-component unsigned normalized vector to pack into globalIndex
}
Your sample shader shows an attempt to write a single scalar to a "byte" data type, that is not possible and you are going to have to modify this somehow to work with indices that reference a packed group of 4 scalars. In the worst-case, this might mean unpacking three values and then re-packing the entire thing just to write one scalar.
This intrinsic function is discussed in the extension specification for GL_ARB_shading_languge_packing and is core in GL 4.2 and later.
Even if you were on an implementation that does not support that extension, it is explained in the text of the extension specification exactly what each does. The equivalent operation for packUnorm4x8 is:
uint fixed_val = round(clamp(float_val, 0, +1) * 255.0);
Some bit-shifts will be necessary to properly pack each component, but those are trivial.
I found a way to write unsigned byte data into buffer in compute shader.Buffer texture does the job.It is basically image texture with buffer as storage.This way I can specify image format to be R8 which allows me to store byte size values on each index of the buffer.
GLuint _tbo_buffer,_tbo_tex;
glGenBuffers(1, &_tbo_buffer);
glBindBuffer(GL_TEXTURE_BUFFER, _tbo_buffer);
glBufferData(GL_TEXTURE_BUFFER, SCREEN_WIDTH * SCREEN_HEIGHT, NULL, GL_DYNAMIC_COPY);
glGenTextures(1, &_tbo_tex);
glBindTexture(GL_TEXTURE_BUFFER, _tbo_tex);
//attach the TBO to the texture:
glTexBuffer(GL_TEXTURE_BUFFER, GL_R8, _tbo_buffer);
glBindImageTexture(0, _tbo_tex, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R8);
Compute shader:
#version 430 core
layout (local_size_x = 8,local_size_y = 8 ) in;
layout(binding=0) uniform sampler2D TEX_IN;
layout(r8) writeonly uniform imageBuffer mybuffer;
void main(){
vec2 texSize = vec2(textureSize(TEX_IN,0));
vec2 uv = vec2(gl_GlobalInvocationID.xy / texSize);
vec4 tex = texture(TEX_IN,uv);
uint globalIndex = gl_GlobalInvocationID.y * nThreads.x + gl_GlobalInvocationID.x;
//store only r:
imageStore(mybuffer,int(globalIndex),vec4(0.5,0,0,0));
}
Then we can read byte by byte on CPU or map to CUDA buffer resource:
GLubyte* ptr = (GLubyte*)glMapBuffer(GL_TEXTURE_BUFFER, GL_READ_ONLY);

OpenGL: Shader storage buffer mapping/binding

I'm currently working on a program which supports depth-independent (also known as order-independent) alpha blending. To do that, I implemented a per-pixel linked list, using a texture for the header (points for every pixel to the first entry in the linked list) and a texture buffer object for the linked list itself. While this works fine, I would like to exchange the texture buffer object with a shader storage buffer as an excercise.
I think I almost got it, but it took me about a week to get to a point where I could actually use the shader storage buffer. My question are:
Why I can't map the shader storage buffer?
Why is it a problem to bind the shader storage buffer again?
For debugging, I just display the contents of the shader storage buffer (which doesn't contain a linked list yet). I created the shader storage buffer in the following way:
glm::vec4* bufferData = new glm::vec4[windowOptions.width * windowOptions.height];
glm::vec4* readBufferData = new glm::vec4[windowOptions.width * windowOptions.height];
for(unsigned int y = 0; y < windowOptions.height; ++y)
{
for(unsigned int x = 0; x < windowOptions.width; ++x)
{
// Set the whole buffer to red
bufferData[x + y * windowOptions.width] = glm::vec4(1,0,0,1);
}
}
GLuint ssb;
// Get a handle
glGenBuffers(1, &ssb);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssb);
// Create buffer
glBufferData(GL_SHADER_STORAGE_BUFFER, windowOptions.width * windowOptions.height * sizeof(glm::vec4), bufferData, GL_DYNAMIC_COPY);
// Now bind the buffer to the shader
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssb);
In the shader, the shader storage buffer is defined as:
layout (std430, binding = 0) buffer BufferObject
{
vec4 points[];
};
In the rendering loop, I do the following:
glUseProgram(defaultProgram);
for(unsigned int y = 0; y < windowOptions.height; ++y)
{
for(unsigned int x = 0; x < windowOptions.width; ++x)
{
// Create a green/red color gradient
bufferData[x + y * windowOptions.width] =
glm::vec4((float)x / (float)windowOptions.width,
(float)y / (float)windowOptions.height, 0.0f, 1.0f);
}
}
glMemoryBarrier(GL_ALL_BARRIER_BITS); // Don't know if this is necessary, just a precaution
glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, windowOptions.width * windowOptions.height * sizeof(glm::vec4), bufferData);
// Retrieving the buffer also works fine
// glMemoryBarrier(GL_ALL_BARRIER_BITS);
// glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, windowOptions.width * windowOptions.height * sizeof(glm::vec4), readBufferData);
glMemoryBarrier(GL_ALL_BARRIER_BITS); // Don't know if this is necessary, just a precaution
// Draw a quad which fills the screen
// ...
This code works, but when I replace glBufferSubData with the following code,
glm::vec4* p = (glm::vec4*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, windowOptions.width * windowOptions.height, GL_WRITE_ONLY);
for(unsigned int x = 0; x < windowOptions.width; ++x)
{
for(unsigned int y = 0; y < windowOptions.height; ++y)
{
p[x + y * windowOptions.width] = glm::vec4(0,1,0,1);
}
}
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
the mapping fails, returning GL_INVALID_OPERATION. It seems like the shader storage buffer is still bound to something, so it can't be mapped. I read something about glGetProgramResourceIndex (http://www.opengl.org/wiki/GlGetProgramResourceIndex) and glShaderStorageBlockBinding (http://www.opengl.org/wiki/GlShaderStorageBlockBinding), but I don't really get it.
My second question is, why I can neither call
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssb);
, nor
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssb);
in the render loop after glBufferSubData and glMemoryBarrier. This code should not change a thing, since these calls are the same as during the creation of the shader storage buffer. If I can't bind different shader storage buffers, I can only use one. But I know that more than one shader storage buffer is supported, so I think I'm missing something else (like "releasing" the buffer).
First of all, the glMapBufferRange fails simply because GL_WRITE_ONLY is not a valid argument to it. That was used for the old glMapBuffer, but glMapBufferRange uses a collection of flags for more fine-grained control. In your case you need GL_MAP_WRITE_BIT instead. And since you seem to completely overwrite the whole buffer, without caring for the previous values, an additional optimization would probably be GL_MAP_INVALIDATE_BUFFER_BIT. So replace that call with:
glm::vec4* p = (glm::vec4*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0,
windowOptions.width * windowOptions.height,
GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
The other error is not described that well in the question. But fix this one first and maybe it will already help with the following error.

How do constant shaders need to be padded in order to avoid a E_INVALIDARG?

I am investigating a E_INVALIDARG exception that is thrown when I attempt to create a second constant buffer that stores the information for my lights:
// create matrix stack early
CD3D11_BUFFER_DESC constantMatrixBufferDesc(sizeof(ModelViewProjectionConstantBuffer), D3D11_BIND_CONSTANT_BUFFER);
DX::ThrowIfFailed(
m_d3dDevice->CreateBuffer(
&constantMatrixBufferDesc,
nullptr,
&m_constantMatrixBuffer
)
);
DX::ThrowIfFailed(
m_matrixStack.Initialize(m_d3dContext, m_constantMatrixBuffer, &m_constantMatrixBufferData)
);
// also create the light buffer early, we must create it now but we will later
// update it with the light information that we parsed from the model
CD3D11_BUFFER_DESC constantLightBufferDesc(sizeof(LightConstantBuffer), D3D11_BIND_CONSTANT_BUFFER);
/* !!!!---- AN E_INVALIDARG IS THROWN BY THE FOLLOWING LINE ----!!!! */
DX::ThrowIfFailed(
m_d3dDevice->CreateBuffer(
&constantLightBufferDesc,
nullptr,
&m_constantLightBuffer
)
);
At this point, it appears that the parameters being passed into the Light's CreateBuffer call are in the same state that the Matrix's are! The problem seems to have to do with the number of bytes being stored in the buffer description.
The buffer is defined as such in the module:
// a constant buffer that contains the 3 matrices needed to
// transform points so that they're rendered correctly
struct ModelViewProjectionConstantBuffer
{
DirectX::XMFLOAT4X4 model;
DirectX::XMFLOAT4X4 view;
DirectX::XMFLOAT4X4 projection;
};
// a constant buffer that contains up to 4 directional or point lights
struct LightConstantBuffer
{
DirectX::XMFLOAT3 ambient[4];
DirectX::XMFLOAT3 diffuse[4];
DirectX::XMFLOAT3 specular[4];
// the first spot in the array is the constant attenuation term,
// the second is the linear term, and the third is quadradic
DirectX::XMFLOAT3 attenuation[4];
// the position and direction of the light
DirectX::XMFLOAT3 position[4];
DirectX::XMFLOAT3 direction[4];
// the type of light that we're working with, defined in lights.h
UINT type[4];
// a number from 0 to 4 that tells us how many lights there are
UINT num;
};
And as such in the vertex shader (.hlsl):
cbuffer ModelViewProjectionConstantBuffer : register (b0)
{
matrix model;
matrix view;
matrix projection;
};
cbuffer LightConstantBuffer : register (b1)
{
float3 ambient[4];
float3 diffuse[4];
float3 specular[4];
// the first spot in the array is the constant attenuation term,
// the second is the linear term, and the third is quadradic
float3 attenuation[4];
// the position and direction of the light
float3 position[4];
float3 direction[4];
// the type of light that we're working with, defined in lights.h
uint type[4];
// a number from 0 to 4 that tells us how many lights there are
uint num;
}
In an attempt to figure out what is causing this, I have stumbled across this line in the MSDN HLSL Shader documentation (http://msdn.microsoft.com/en-us/library/windows/desktop/ff476898(v=vs.85).aspx):
Each element stores a 1-to-4 component constant, determined by the format of the data stored.
What does this mean and is it the reason for this exception? I have noticed that in the Visual Studio 3D Starter Kit (http://code.msdn.microsoft.com/wpapps/Visual-Studio-3D-Starter-455a15f1), the buffers have extra floats padding them:
///////////////////////////////////////////////////////////////////////////////////////////
//
// Constant buffer structures
//
// These structs use padding and different data types in places to adhere
// to the shader constant's alignment.
//
struct MaterialConstants
{
MaterialConstants()
{
Ambient = DirectX::XMFLOAT4(0.0f,0.0f,0.0f,1.0f);
Diffuse = DirectX::XMFLOAT4(1.0f,1.0f,1.0f,1.0f);
Specular = DirectX::XMFLOAT4(0.0f, 0.0f, 0.0f, 0.0f);
Emissive = DirectX::XMFLOAT4(0.0f, 0.0f, 0.0f, 0.0f);
SpecularPower = 1.0f;
Padding0 = 0.0f;
Padding1 = 0.0f;
Padding2 = 0.0f;
}
DirectX::XMFLOAT4 Ambient;
DirectX::XMFLOAT4 Diffuse;
DirectX::XMFLOAT4 Specular;
DirectX::XMFLOAT4 Emissive;
float SpecularPower;
float Padding0;
float Padding1;
float Padding2;
};
struct LightConstants
{
LightConstants()
{
ZeroMemory(this, sizeof(LightConstants));
Ambient = DirectX::XMFLOAT4(1.0f,1.0f,1.0f,1.0f);
}
DirectX::XMFLOAT4 Ambient;
DirectX::XMFLOAT4 LightColor[4];
DirectX::XMFLOAT4 LightAttenuation[4];
DirectX::XMFLOAT4 LightDirection[4];
DirectX::XMFLOAT4 LightSpecularIntensity[4];
UINT IsPointLight[4*4];
UINT ActiveLights;
float Padding0;
float Padding1;
float Padding2;
};
... // and there's even more where that came from
So am I just not padding these things correctly? And if so, how should I pad them? Or is it something completely different that I'm missing?
I greatly appreciate you reading this and trying to help.
It is hard to fix your problem because lack of important info, but let's make a try.
Obviously, 'E_INVALIDARG' says that invalid argument passed to function. Now we must figure out what parameter is wrong.
ID3D11Device::CreateBuffer method accepts 3 parameters: D3D11_BUFFER_DESC, D3D11_SUBRESOURCE_DATA, and ID3D11Buffer** itself.
And you feed to it &constantLightBufferDesc, nullptr, &m_constantLightBuffer.
Now you must carefully read all 4 MSDN articles to find out what is wrong.
constantLightBuffer it is not a problem, just check that it has ID3D11Buffer pointer type.
nullptr it is unlikely a problem, but AFAIK it is not C++ standard keyword, so probably simple '0' will be better here. Actually, it is a standard since C++11
Unfortunately you don't provide your constantLightBufferDesc definition, which is a candidate to be a problem:
as you've stated there can be buffer alignment mistake: if your constantLightBufferDesc.BindFlags has D3D11_BIND_CONSTANT_BUFFER flag and constantLightBufferDesc.ByteWidth is not a multiple of 16, buffer creation fails. But that's just a guess. You can have any other mismatch here, so, you can make a guesses infinetely.
Fortunalely, there are another way of diagnostic: if you creating your ID3D11Device with D3D11_CREATE_DEVICE_DEBUG flag, in Visual Studio output window you will see all the warnings and errors according to D3D11. For example, in case of misalignment you will see:
D3D11 ERROR: ID3D11Device::CreateBuffer: The Dimensions are invalid.
For ConstantBuffers, marked with the D3D11_BIND_CONSTANT_BUFFER
BindFlag, the ByteWidth (value = 10) must be a multiple of 16.
ByteWidth must also be less than or equal to 65536 on the current
driver. [ STATE_CREATION ERROR #66: CREATEBUFFER_INVALIDDIMENSIONS]
So, if CreateBuffer() failing because of wrong buffer size, there are several ways to handle this:
Resize your structures: add padding members so total sizeof() will become multiple of 16.
Declare your structures as 16-bit aligned. AFAIK there are only compiler-specific ways to do this: for example #pragma pack for msvc.
Assign to ByteWidth not a real structure size, but rounded up to next multiple of 16: link
Happy debugging! =)