Skip to main content

Vertex Formats

The format of a vertex attribute indicates how data in a vertex buffer is laid out, and how it will exposed to the shader. Each format has a name that encodes

  • the order of components
  • bits per component
  • and vertex data type for the component.

The VertexFormat type is a string union of all the defined vertex formats.

Vertex FormatAvailability CheckWGSL typesGLSL TypesNotes
uint8N/Au32uintChrome v133+
uint8x2N/Avec2<u32>uvec2—
uint8x4N/Avec2<u32>uvec4—
sint8N/Ai32intChrome v133+
sint8x2N/Avec2<i32>ivec2—
sint8x4N/Avec2<i32>ivec4—
unorm8N/Af16, f32floatChrome v133+
unorm8x2N/Avec2<f16>, vec2<f32>vec2—
unorm8x4N/Avec2<f16>, vec2<f32>vec4—
unorm8x4-bgraN/Avec4<f16>, vec4<f32>❌Chrome v133+
unorm10-10-10-2N/Avec4<f16>, vec4<f32>❌Chrome v119+
snorm8N/Af16, f32floatChrome v133+
snorm8x2N/Avec2<f16>, vec2<f32>vec2—
snorm8x4N/Avec2<f16>, vec2<f32>vec4—
uint16N/Au32uintChrome v133+
uint16x2N/Avec2<u32>ivec2—
uint16x4N/Avec3<u32>ivec4—
sint16N/Ai32intChrome v133+
sint16x2N/Avec2<i32>ivec2—
sint16x4N/Avec2<i32>ivec4—
unorm16N/Af16, f32floatChrome v133+
unorm16x2N/Avec2<f16>, vec2<f32>vec2—
unorm16x4N/Avec3<f16>, vec4<f32>vec4—
snorm16N/Af16, f32floatChrome v133+
snorm16x2N/Avec2<f16>, vec2<f32>vec2—
snorm16x4N/Avec4<f16>, vec4<f32>vec4—
float16N/Af16, f32❌Chrome v133+
float16x2N/Avec2<f16>, vec2<f32>❌—
float16x4N/Avec4<f16>, vec4<f32>❌—
float32N/Af32float—
float32x2N/Avec2<f32>vec2—
float32x3N/Avec3<f32>vec3—
float32x4N/Avec4<f32>vec4—
uint32N/Au32uint—
uint32x2N/Avec2<u32>uvec2—
uint32x3N/Avec3<u32>uvec3—
uint32x4N/Avec4<u32>uvec4—
sint32N/Ai32int—
sint32x2N/Avec2<i32>ivec2—
sint32x3N/Avec3<i32>ivec3—
sint32x4N/Avec4<i32>ivec4—

Shader Type mappings​

Each vertex data type can map to any WGSL scalar type of the same base type, regardless of the bits per component:

Vertex format prefixVertex data typeCompatible WGSL typesCompatible GLSL types
uintunsigned intu32uint, uvec2, uvec3, uvec4
sintsigned inti32int, ivec2, ivec3, ivec4
unormunsigned normalizedf16, f32float, vec2, vec3, vec4
snormsigned normalizedf16, f32float, vec2, vec3, vec4
float16floating pointf16, f32float, vec2, vec3, vec4
float32floating pointf32float, vec2, vec3, vec4

GPU Backend Differences​

luma.gl attempts to provide a consistent API across WebGPU and WebGL, but there are significant differences in vertex format supported across the two APIs.

  • The multi-component formats specify the number of components after "x".
  • Mismatches in the number of components between the vertex format and shader type are allowed, with components being either dropped or filled with default values to compensate.

When it comes to attributes, WebGPU is significantly more restrictive than WebGL:

FeatureWebGLWebGPUComment
8-bit x1 alignment✅(✅)WebGPU 8 bit integers must be aligned to 16, 32 bits (uint8x1, uint8x3, unorm8x1, unorm8x3 etc` are not supported)
8-bit x3 alignment✅❌WebGPU 8 bit integers must be aligned to 8, 16, 32 bits (uint8x1, uint8x3, unorm8x1, unorm8x3 etc` are not supported)
16-bit x1 alignment✅(✅)WebGPU 16 bit integers must be aligned to 32 bits (uint16x1, uint16x3, unorm16x1, unorm16x3 etc` are not supported)
16-bit x3 alignment✅❌WebGPU 16 bit integers must be aligned to 32 bits (uint16x1, uint16x3, unorm16x1, unorm16x3 etc` are not supported)
Component mismatch✅(✅)Use buffers with more or fewer components than expected by the shader (missing values will be filled with [0, 0, 0, 1]).
Normalized 32-bit integers✅❌WebGPU 32 bit integer formats cannot be normalized
Per-attributestepMode✅❌stepMode (WebGL: divisor, controls whether an attribute is instanced) can be set per-attribute, even when multiple attributes bind to the same buffer.
Per-attributebyteStride✅❌byteStride (controls byte distance between two successive values in memory) can be set per-attribute, even when multiple attributes bind to the same buffer.
Dynamic VertexFormat✅❌Buffers with different structure (different BufferLayout) can be provided without relinking the RenderPipeline
Constant attributes✅❌(attribute locations can be disabled in which case a constant value is read from the WebGLRenderingContext)
Non-normalized integers✅❌Non-normalized integer attributes can be assigned to floating point GLSL shader variables (e.g. vec4).

Presumably, the heavy restrictions in WebGPU are motivated by:

  • portability across Vulkan/Metal/D3D12.
  • additional optimizations during shader compilation
  • reduced run-time validation overhead

In general, an argument can be made that in WebGPU / WGLS, attributes are less important since storage buffers are much more flexible, allowing arbitrary memory layouts, random access, and less limitations on number of bindings etc. Attributes may be faster than storage bindings, but at the moment there is no clear evidence that this is the case.

Notes:

  • WebGPU: 8 and 16 bit formats only support 1, 2 or 4 components (only 2 or 4 components pre Chrome c133).
  • WebGL: GLSL supports bool and bvec* but these are not portable to WebGPU and are not included by luma.gl.
  • WebGL: GLSL types double and dvec* are not supported in any WebGL version (nor is f64 supported in WebGPU).