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.