metalmetal-performance-shaders

Two examples of Metal struct sizes seem to contradict each other


The size of this struct is 36 bytes:

struct Mat
{
    enum Type { Lam, Met, Dia };
    int type;
    packed_float3 albedo;
    packed_float3 emissive;
    float roughness;
    float ri;
};

That makes sense when floats and ints are 4 bytes each and a packed_float3 is 12 bytes.

The size of this is 88 bytes:

struct Cam
{
    packed_float3 origin;
    packed_float3 lowerLeftCorner;
    packed_float3 horizontal;
    packed_float3 vertical;
    packed_float3 u, v, w;
    float lensRadius;
};

That makes sense when floats are 8 bytes and the packed_float3 is 16 bytes.

These are in the same Metal shader. What is happening with the alignment here that would cause this to be true?

I can only get the match to work if a packed_float3 must fit within a contiguous 16-byte space, so in the first example it fits right after the first int, but in the second example each must start its own. Is that it? If so, this magic number 16 does not appear to be documented anywhere I can find in the Metal Shading guide.


Solution

  • I think you're just counting wrong. This:

    struct Cam
    {
        packed_float3 origin;
        packed_float3 lowerLeftCorner;
        packed_float3 horizontal;
        packed_float3 vertical;
        packed_float3 u, v, w;
        float lensRadius;
    };
    

    is equivalent to:

    struct Cam
    {
        packed_float3 origin;
        packed_float3 lowerLeftCorner;
        packed_float3 horizontal;
        packed_float3 vertical;
        packed_float3 u;
        packed_float3 v;
        packed_float3 w;
        float lensRadius;
    };
    

    That's 7 packed_float3s, for 21 floats, plus a lone float for a total of 22 floats. When float is 4 bytes, that's 88 bytes. There's no contradiction.