The "invocation" is similar to instancing, but has a slightly different use.
Consider the call:
glDrawArray(GL_POINTS, 0, N );
With a shader layout:
layout (points, invocations=6) in;
Notice the order of invocations given in the OpenGL wiki:
(prim0, invoc0), (prim0, invoc1), (prim0, invoc2), (prim1, invoc0), ... (primN, invoc1), (primN, invoc2)
The purpose of invocation is to process each invocation in order before starting the next primitive. There as some times you need this. However, using invocations is very costly for the GPU, because they must happen in order, and are not easily parallelized.
You can achieve an order-independent invocations by using a uniform buffer.
const int NUM_INVOC = 6;
for (int i = 0; i < NUM_INVOC; ++i) {
glUniform1i( glGetUniformLocation("uiInvocID"), i);
glDrawArray( GL_POINTS, 0, N );
}
Then, in the GS use the uniform uiInvocID instead of the gl_InvocationID.
The process order of this will be:
(prim0, invoc0), (prim1, invoc0), (prim2, invoc0), (prim0, invoc1), (prim1, invoc1), (prim2, invoc1), ..
In many cases, the order may not matter. For example, if you are expanding a set of points into a cube, its still perfectly acceptable to render all the top-faces first, then all side, etc. because the Z-buffer will resolve everything. This will be much faster.
Recall, what instancing does is different:
(prim0, inst0), (prim1, inst1), (prim2, inst2) .. (primN, instN)
For regular instancing there is a 1-to-1 relationship between prims and gl_InstanceIDs.