I have a per-instance uniform buffer where each element in the buffer is 64-bytes but I only use the first 16-bytes (float3) of each element in the vertex shader. I set the stride up to describe this. The problem is it does not stride over the other 48 bytes unless I add padding to the struct in the shader so that it is also 64 bytes.
// Particle Instance Position
vertexDescriptor.attributes[2].format = .Float3 // 16 bytes with padding.
vertexDescriptor.attributes[2].offset = 0
vertexDescriptor.attributes[2].bufferIndex = 2
vertexDescriptor.layouts[2].stride = strideof(Particle)
vertexDescriptor.layouts[2].stepFunction = .PerInstance
...
commandEncoder.setVertexBuffer(instanceUniformBuffer, offset:0, atIndex:2)
App side particle struct:
struct Particle {
var position = float3()
var prevPos = float3()
var attractPoint = float3()
var ref: DataRef!
var state = State.Free
enum State: Int {
case Free = 0
case Active
}
}
And here's the corresponding Metal struct, i.e. Particle.position corresponds to InstanceUniforms.instanceTranslate in the shader. I expect the stride setup above to mean that this gets loaded with the Particle.position for each instance and the other 48 bytes of each Particle in the buffer is skipped over.
struct InstanceUniforms
{
float3 instanceTranslate [[ attribute(2) ]];
};
Some sanity checks, everything makes sense:
sizeof(float3) 16
alignof(float3) 16
sizeof(Particle) 57
alignof(Particle) 16
strideof(Particle) 64
But it doesn't work unless I pad the shader struct out to 64 bytes:
struct InstanceUniforms
{
float3 instanceTranslate [[ attribute(2) ]];
float4 pad[3];
};
Otherwise for the second instance the shader actually sets instanceTranslate to the Particle.prevPos of the first element in the buffer, like it only strides over the size of the InstanceUniforms struct, regardless of what the stride is set to in the vertex descriptor.
I'm sure I must be doing something wrong here, it seems like you shouldn't need to pad your shader structs.