Vulkan: using gl_PrimitiveID without geometryShader feature 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?
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.