Skip to content

Add KHR_mesh_primitive_restart#2569

Open
donmccurdy wants to merge 3 commits intoKhronosGroup:mainfrom
CesiumGS:donmccurdy/KHR_mesh_primitive_restart
Open

Add KHR_mesh_primitive_restart#2569
donmccurdy wants to merge 3 commits intoKhronosGroup:mainfrom
CesiumGS:donmccurdy/KHR_mesh_primitive_restart

Conversation

@donmccurdy
Copy link
Copy Markdown
Contributor

@donmccurdy donmccurdy commented Apr 16, 2026

Motivation

glTF 2.0 includes seven primitive modes:

  • 0 POINTS
  • 1 LINES
  • 2 LINE_LOOP
  • 3 LINE_STRIP
  • 4 TRIANGLES
  • 5 TRIANGLE_STRIP
  • 6 TRIANGLE_FAN

Four of these (LINE_LOOP, LINE_STRIP, TRIANGLE_STRIP, TRIANGLE_FAN) define topologies that may contain any number of vertices. Each glTF mesh primitive defines a single contiguous topology for these types, because primitive restart values — which would instruct the graphics API to begin a new topological primitive, without a new draw call — are disallowed by the core specification for maximum compatibility (see: WebGL 1).

This PR proposes a KHR_mesh_primitive_restart extension, which can be added to any glTF asset, removing the restriction against primitive restart values. The mechanism and implementation are intentionally very similar to KHR_mesh_quantization, which removes restrictions on particular vertex attribute component types.

Primitive restart values allow a scene to contain arbitrary numbers of line loops, line strips, triangle strips, and triangle fans, without requiring arbitrary numbers of mesh primitives, along with costly processing and draw calls. This also greatly reduces the amount of JSON (primitive and accessor) definitions required to represent such scenes.

Background

The existing EXT_mesh_primitive_restart allows primitive restart values, but does so by encoding each primitive topology as a separate glTF mesh primitive, defined in JSON and having a distinct indices accessor. The extension adds indices with restart values as metadata, allowing runtimes to stitch these primitives together as a single draw call, but the runtime must still download and parse data for the original N primitives. Unfortunately, the performance implications of this approach are not ideal. See CesiumGS#100.

EXT vs. KHR

I'm open to modifying the existing EXT_mesh_primitive_restart extension, but modifying an existing EXT extension would be an unusual step. While I believe it has only very limited implementations today, initial feedback has been on the side of avoiding changes to an existing EXT extension.

For that reason, and hoping the approach here might be broadly useful for anyone using these primitive topologies in glTF 2.0, I'm proposing a simplified/optimized approach as a new extension, KHR_mesh_primitive_restart.

Fallback

If a runtime doesn't support primitive restart values, it would need to pre-process the index list. But this optimizes the extension for present-day and future use, where primitive restart support is standard, and imposes the cost of fallback only on the small (and shrinking) cases where primitive restart is not supported in hardware. I believe that's an important improvement for adoption and production use of the extension.

Fallback may not necessarily require separate draw calls for each topological primitive. Multi-draw Indirect (MDI) would be an alternative (if there exists a graphic API that supports MDI but not primitive restart values). I'm not familiar with how a path-tracing renderer would want to handle primitive restart indices.

Samples

PrimitiveRestartLineStrip.glb.zip

hilbert3d

Figure: A Hilbert space-filling curve, rendered in 3D. The asset is structured as a glTF scene and a single mesh primitive, containing a series of LINE_STRIP topologies separated by primitive restart values. Created with glTF Transform.

In some viewers (including https://gltf-viewer.donmccurdy.com/) the model will display correctly without any modifications to support KHR_mesh_primitive_restart, because primitive restart is already enabled by default by the WebGL 2 API.

Implementations

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant