Search code examples
metalmetalkit

Lack of non-normalized 10_10_10_2 vertex format in Metal


In my OpenGL ES 3.0+ apps I use non-normalized GL_INT_2_10_10_10_REV data types which is perfectly fine according to specs - https://docs.gl/es3/glVertexAttribPointer

When porting to Metal I've found that it does support 10_10_10_2 data type for vertex attributes but only as normalized ones - https://developer.apple.com/documentation/metal/mtlvertexformat

iOS 12 used to support OpenGL ES 3.0 which means hardware is perfectly capable of handling both normalized and non-normalized 10_10_10_2 data types.

Am I missing something or is this indeed an artificial limitation by Apple? Metal doesn't provide additional flag for normalized attribute so it indeed seems like they just "forgot" that 10_10_10_2 could be useful as non-normalized too... I know this is not quite typical usage for this data type but precision is good enough for my use case and it is more compact than 3 half floats.

Currently I see two workarounds to alleviate this:

  1. De-normalize data in vertex shader with multiplication by 512.
  2. Re-export meshes to use half floats instead of this more compact packed data type.

Please advise.


Solution

  • Unfortunatenyl, I don't think there's a version of MTLVertexFormatUInt1010102Normalized or MTLVertexFormatInt1010102Normalized that is not normalized.

    What you could do instead is write a vertex shader manually that reads a 32-bit value from the buffer and decomposes into the same non-normalized 10-bit components with another one being 2-bit using regular bitwise functions.

    More unfortunately, there isn't even a version of the pack/unpack functions such as unpack_unorm10a2_to_half that accepts or outputs non-normalized values.