When compiling a glsl fragment shader which reads gl_PrimitiveID with glslc compiler I get the spirv-1.0 with Geometry capability enabled, which is technically correct, as it's stated in spirv spec. Vulkan 1.0 spec says that Geometry capability must be supported if geometryShader feature is enabled.

So I assume that unless geometryShader is enabled, one can't use gl_PrimitiveID. Specifically, using gl_PrimitiveID is impossible on moltenVK, as it does not support this feature, isn't it?

In my pipeline I used gl_PrimitiveID to fetch per-face data from global ssbo and to render face ids to attachment for later reuse. Is it possible to achieve similar result without gl_PrimitiveID?

  • $\begingroup$ Sure, you can use gl_VertexID / 3 (for triangles). however this only works for non-indexed rendering. $\endgroup$
    – user8592
    Commented Dec 28, 2019 at 17:28
  • 1
    $\begingroup$ @httpdigest: It also only works for drawing triangle lists. $\endgroup$ Commented Dec 29, 2019 at 16:48
  • $\begingroup$ How do you see that SPIR-V specs say that geometry capability must be supported to have PrimitiveID? The specs say that PrimitiveID is enable by either of Geometry or Tesselation. So it seems that turning on geometry is over the requirements. I am running on MoltenVK which does not support geometry but supports tesselation. Use of gl_PrimitiveID triggers a warning in the validation layers about geometry being flagged yet not available. However gl_PrimitiveID does work. This lead me to this discussion. $\endgroup$
    – Michel
    Commented Mar 7, 2020 at 17:27

1 Answer 1


It seems likely that the mechanism by which the gl_PrimitiveID is generated is, in some way, based on the hardware that makes geometry shaders possible.

OpenGL ES 3.1 contains compute shaders but not geometry shaders (or tessellation). But it doesn't have gl_PrimitiveID. By contrast, ES 3.2 contains GS's and gl_PrimitiveID. The same goes for desktop OpenGL 3.1 vs. 3.2 and its GS functionality. Having a GS and having the ability to identify primitives in a sequence seem to be part of the same general functionality.

In my pipeline I used gl_PrimitiveID to fetch per-face data from global ssbo and to render face ids to attachment for later reuse.

Without the hardware functionality, there is no general way to compute a count of primitives. There are only specific solutions for specific circumstances.

For example, if you are using non-index rendering of triangle lists, then you can use gl_VertexID / 3 to compute a primitive ID. Obviously that's a pretty tight restriction, but it would work in that circumstance.

You could also provide each vertex with a per-vertex face ID. The VS would output this value using flat interpolation. By carefully matching the face ID with the provoking vertex for the primitive topology, you can effectively assign a face ID to a face. This works best with indexed triangle lists, as you can play around with the order of indices in a triangle more than you can with strips. You basically have to decide which vertex maps to which face, and make sure that that face uses that vertex as the first one.

  • $\begingroup$ The idea of using the VS in combination with the provoking vertex is attractive but in most cases it is not possible. The reason is that even for the most simple type of regular triangular mesh, asymptotically, there are twice as many triangles as there are vertices. Mathematically, you would need to build a mesh that has at most as many triangles as there are vertices. To fill a 2D flat space, since every vertex would have 3 triangles connected to it on average, the average angle of each triangle summit is 120°. That's not possible since the sum of angles in a triangle is 180°. $\endgroup$
    – Michel
    Commented Mar 6, 2020 at 19:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.