gl_PrimitiveID in tess controll shader?

Trying to compile my tessellation control shader that needs gl_primitiveID results in:
0(14) : error c5108: unknown semantics “PRIMITIVEID” specified for gl_PrimitiveID"

I’m pretty sure GL_ARB_tessellation_shader mentioned that gl_PrimitiveID should be available in a tessellation control shader, so, can anyone see what i did wrong?

–snipp–
#version 150 compatibility
#extension GL_ARB_tessellation_shader : require

layout(Vertices = 4) out;

uniform samplerBuffer positionSampler;

void main(){
vec4 tp = texelFetchBuffer(positionSampler, gl_PrimitiveID);

–snipp–

oh, this is on a gtx480 using the 257.15 driver

I have the same problem.
Does anyone know how to solve it?

I only program in OpenGL 4.0, so I don’t know particulars about GLSL 1.5, which goes with OpenGL 3.2 . The reason I program only in OpenGL 4 is because that is the first version of the API to support the tessellation shaders. (OpenGL 3.3, released simultaneously with OpenGL 4.0, supports the tessellation primitive generator which has existed for a few years in ATI GPUs, but not the programmable tessellation shaders. I don’t know whether Nvidia GPUs ever had that functionality.)

Rather than using OpenGL 3.2 with the GL_ARB_tessellation_shader, why not just use OpenGL 4? The main new feature of OpenGL 4.0 was the tessellation shaders. It seems to me the only reason to use OpenGL 3.2 is if you are programming hardware that doesn’t support tessellation. Given that your hardware does, why not use the API intended for it?

Anyway, I use gl_PrimitiveID in my GLSL 400 tessellation control shaders without problem (I have an AMD GPU).

I have code that looks like:

#version 400 core
layout (vertices = 16) out;
uniform sampler1D  Patch_texture1d;

void main (void) {
  vec4  texel;

  texel = texelFetch (Patch_texture1d, gl_PrimitiveID, 0);
  ...
}

Actually, I use OpenGL 4 too.
My tessellation control shader is something like this:


#version 410
#extension GL_EXT_gpu_shader4 : enable

layout(vertices = 3) out;
in vec3 vPosition[];
out vec3 tcPosition[];
uniform float TessLevelInner;
uniform float TessLevelOuter;

void main()
{
    int a = gl_PrimitiveID;
    tcPosition[gl_InvocationID] = vPosition[gl_InvocationID];
    if (gl_InvocationID == 0)
    {
        gl_TessLevelInner[0] = TessLevelInner;
        gl_TessLevelOuter[0] = TessLevelOuter;
        gl_TessLevelOuter[1] = TessLevelOuter;
        gl_TessLevelOuter[2] = TessLevelOuter;
    }
}

The second line is necessary, otherwise the compiler would complain :
error C7531: global variable gl_PrimitiveID requires “#extension GL_EXT_gpu_shader4 : enable” before use

When I added that line of code, the tessellation control shader compilation succeed. But the problem I mentioned above happened :
error C5108: unknown semantics “PRIMITIVEID” specified for “gl_PrimitiveID”.
I got this message by using glGetProgramInfoLog after glLinkProgram.

My GPU is GeForce GTX 465, OS is Ubuntu 10.10 64bit.
So maybe it’s a problem only happens on NVIDIA GPU?

The second line is necessary, otherwise the compiler would complain :
error C7531: global variable gl_PrimitiveID requires “#extension GL_EXT_gpu_shader4 : enable” before use

Then the compiler is broken.

Broken? Is there anything I can do to fix it?
As I know, GLSL compiler is part of OpenGL driver.
Maybe I should reinstall my GPU driver?
I’ve already tried several driver editions, but none of them works.

Complain to NVIDIA until they fix it. That’s pretty much all you can do.

GL_EXT_gpu_shader4 has nothing to do with gl_PrimitiveID in tessellation shaders. The OpenGL Shading Language specification version 4.10 requires that gl_PrimitiveID be made available to both tessellation shader stages. If their implementation of 4.10 is asking for something like this, then it isn’t working right.

A couple comments. You do not need to test gl_InvocationID before you define the gl_TessLevel* variables. You could just have something like:

void main()
{
    int a = gl_PrimitiveID;
    tcPosition[gl_InvocationID] = vPosition[gl_InvocationID];
    gl_TessLevelInner[0] = TessLevelInner;
    gl_TessLevelOuter[0] = TessLevelOuter;
    gl_TessLevelOuter[1] = TessLevelOuter;
    gl_TessLevelOuter[2] = TessLevelOuter;
}

The Tessellation Control shader is executed once for each vertex of the patch primitive. So, you probably don’t save any computation cycles by testing gl_InvocationID and only assigning gl_TessLevel* during one of them. Probably, all you are doing is adding computation cycles to your Tessellation Control shader, by making it execute the “if” statement every invocation. “if” statements are very expensive, because they break the pipeline and they interfere with parallelism.

The other thing is, you have referenced gl_PrimitiveID to define variable “a” but you never use variable “a.” Consequently, the GLSL compiler may be optimizing “a” out of your program, and then it might just be getting all weird about the dead reference to gl_PrimitiveID. In my experience (with AMD OpenGL drivers), I get unreliable results sometimes when the GLSL compiler optimizes variables out of programs. So, I make it a point to never have any dead code in any of my shaders. (This is only an issue during debugging because I’d never leave dead code in a production shader, but I find you can’t be lazy and assume the GLSL compiler will do things right when you’re just trying different things out.)

Your first advice is very good, thanks. I’ve changed my code. But I think there’s a little problem in your reply: you said that “The Tessellation Control shader is executed once for each vertex of the patch primitive”, actually it is not.
According to Overview of OpenGL 4.0:

The number of vertices that the control shader will output is controlled by a required line of GLSL like the following:
layout (vertices = n) out;
The value set by the vertices parameter in the layout directive does two things: it sets the size of output vertex array in the control shader, which is called gl_out; and specifies how many times the control shader will execute.

So, the execution time is decided by

layout (vertices = n) out

Usually we have the same amount of vertices in and out of tessellation control shader, so we always write

out[gl_InvocationID] = in[gl_InvocationID]

But I think they can be different, although I haven’t used them like that before.

Your second advice is very good, too. I modified my code, removed all those “useless variables”. But I got the same problem just because I used gl_PrimitiveID in my tessellation evaluation shader. :frowning:

Anyway, thanks for your reply. :smiley:

OK, thanks for your reply. I’ll have a try.

Actually, you usually use the same amount of input patch vertices as output vertices in the tessellation control shader if you want some simple and efficient tessellation method. However, you can use e.g. 16 control points to output one quad to tessellate in case of more advanced interpolation methods.

But to answer your original question, I think the error message related to gl_PrimitiveID is a bug in the driver. I’ve seen a lot of different error messages in NVIDIA drivers when someone used the built-in counters like gl_InvocationID and gl_PrimitiveID.

Thank you for your reply.
It seems that it’s definitely a driver bug.
I was just wondering why they haven’t fixed it for such a long time since OpenGL 4 was released.