Jump to content
  • Advertisement
Sign in to follow this  
Yours3!f

OpenGL opengl 4 tessellation linker error

This topic is 2267 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi,

I'm trying to do some basic tessellation, but I've ran into a strange problem. My glsl code compiles fine, but when I try to render some geometry with it, I get the invalid operation error. I tried to debug this issue with gdebugger, and interestingly it gives me a AP_PROGRAM_LINK_FAILED_ERROR. This is strange because I do check if the linking went right (GL_LINK_STATUS), and I get no errors even if I directly check the linking with glGetError. The geometry that I tried to render works fine with other shaders.
I followed this tutorial: http://prideout.net/blog/?p=48

Here's the glsl code:

[vertex shader]
#version 410

in vec4 in_vertex; //incoming vertex attribute in object space

out cross_shader_data
{
vec3 position;
} o;

void main()
{
o.position = in_vertex.xyz; //pass the data to the TC shader
}

[tessellation control shader]
#version 410

layout(vertices = 3) out; //a patch should consist of 3 vertices, thus essentially defining a vertex

in cross_shader_data
{
vec3 position;
} i[];

out cross_shader_data
{
vec3 position;
} o[];

uniform float tess_level_inner;
uniform float tess_level_outer;

void main()
{
o[gl_InvocationID].position = i[gl_InvocationID].position; //pass the vertex data to the TE shader

if(gl_InvocationID == 0) //define tessellation levels
{
gl_TessLevelInner[0] = tess_level_inner;

gl_TessLevelOuter[0] = tess_level_outer;
gl_TessLevelOuter[1] = tess_level_outer;
gl_TessLevelOuter[2] = tess_level_outer;
}
}

[tessellation evaluation shader]
#version 410

layout(triangles, equal_spacing, ccw) in; //process triangles, using equal spacing, and they'll be in counter-clockwise order

in cross_shader_data
{
vec3 position;
} i[];

out cross_shader_data
{
vec3 position;
vec3 patch_distance;
} o;

uniform mat4 modelviewproj;

void main()
{
vec3 p0 = gl_TessCoord.x * i[0].position;
vec3 p1 = gl_TessCoord.y * i[1].position;
vec3 p2 = gl_TessCoord.z * i[2].position;

o.patch_distance = gl_TessCoord;
o.position = normalize(p0 + p1 + p2); //create the new vertex
gl_Position = modelviewproj * vec4(o.position, 1); //do the transformation before passing to the geometry shader
}

[geometry shader]
#version 410

layout(triangles) in; //process triangles
layout(triangle_strip, max_vertices = 3) out; //spit out triangle strips that consist of max 3 vertices

in cross_shader_data
{
vec3 position;
vec3 patch_distance;
} i[3];

out cross_shader_data
{
vec3 face_normal;
vec3 patch_distance;
vec3 tri_distance;
} o;

uniform mat3 normal_mat;

void main()
{
vec3 a = i[2].position - i[0].position;
vec3 b = i[1].position - i[0].position;
o.face_normal = normal_mat * normalize(cross(a, b)); //transform face normal into view space

o.patch_distance = i[0].patch_distance;
o.tri_distance = vec3(1, 0, 0);
gl_Position = gl_in[0].gl_Position;
EmitVertex();

o.patch_distance = i[1].patch_distance;
o.tri_distance = vec3(0, 1, 0);
gl_Position = gl_in[1].gl_Position;
EmitVertex();

o.patch_distance = i[2].patch_distance;
o.tri_distance = vec3(0, 0, 1);
gl_Position = gl_in[2].gl_Position;
EmitVertex();
}

[pixel shader]
#version 410

in cross_shader_data
{
vec3 face_normal;
vec3 tri_distance;
vec3 patch_distance;
} i;

out vec4 color;

float amplify(float d, float scale, float offset)
{
d = scale * d + offset;
d = clamp(d, 0, 1);
d = 1 - exp2(-2 * d * d);
return d;
}

void main()
{
vec3 n = normalize(i.face_normal);
vec3 l = vec3(0, 1, 0);

float ndotl = max(dot(n, l), 0);

vec3 result = ndotl * vec3(1, 1, 1); //do some lighting

float d1 = min(min(i.tri_distance.x, i.tri_distance.y), i.tri_distance.z);
float d2 = min(min(i.patch_distance.x, i.patch_distance.y), i.patch_distance.z);

result *= amplify(d1, 40, -0.5) * amplify(d2, 60, -0.5); //just some edge outlining

color = vec4(result, 1);
}


Best regards,
Yours3!f Edited by Yours3!f

Share this post


Link to post
Share on other sites
Advertisement
Hi!

For some reason passing structs between shader stages doesn’t work anymore (at least the way you/I did it…). At some point it did. I remember it fairly well, since I was very happy to see that GLSL finally allowed it, too (like HLSL). But with current drivers it doesn’t work anymore. I had to rewrite some of my old shaders, too. Maybe it just wasn’t specification compliant and only nVidia drivers allowed it.

If you follow the tutorial you linked above, you should be fine. So, something like:
in vec3 i_position[];
out vec3 o_position[];

And so on.

And yes, I was also confused that the GLSL compiler doesn't complain at all.

Cheers!

Share this post


Link to post
Share on other sites

Hi!

For some reason passing structs between shader stages doesn’t work anymore (at least the way you/I did it…). At some point it did. I remember it fairly well, since I was very happy to see that GLSL finally allowed it, too (like HLSL). But with current drivers it doesn’t work anymore. I had to rewrite some of my old shaders, too. Maybe it just wasn’t specification compliant and only nVidia drivers allowed it.

If you follow the tutorial you linked above, you should be fine. So, something like:
in vec3 i_position[];
out vec3 o_position[];

And so on.

And yes, I was also confused that the GLSL compiler doesn't complain at all.

Cheers!


Thank you Tsus for the reply smile.png

I tried to convert the interface blocks to traditional in-outs but somethings still wrong... What am I missing?

drivers... I even made a segfault to the compiler while converting the shaders... (I mean it segfaulted when linking, and the last function in the stack was somewhere in the catalyst drivers... 12.4 64bit linux)

this is how the shaders look like now:

[vertex shader]
#version 410
in vec4 in_vertex;
out vec3 v_position;
void main()
{
v_position = in_vertex.xyz;
}
[tessellation control shader]
#version 410
layout(vertices = 3) out;
in vec3 v_position[];
out vec3 tc_position[];
uniform float tess_level_inner;
uniform float tess_level_outer;
void main()
{
tc_position[gl_InvocationID] = v_position[gl_InvocationID];
if(gl_InvocationID == 0)
{
gl_TessLevelInner[0] = tess_level_inner;
gl_TessLevelOuter[0] = tess_level_outer;
gl_TessLevelOuter[1] = tess_level_outer;
gl_TessLevelOuter[2] = tess_level_outer;
}
}
[tessellation evaluation shader]
#version 410
layout(triangles, equal_spacing, ccw) in;
in vec3 tc_position[];
out vec3 te_position;
out vec3 te_patch_distance;
uniform mat4 modelviewproj;
void main()
{
vec3 p0 = gl_TessCoord.x * tc_position[0];
vec3 p1 = gl_TessCoord.y * tc_position[1];
vec3 p2 = gl_TessCoord.z * tc_position[2];

te_patch_distance = gl_TessCoord;
te_position = normalize(p0 + p1 + p2);
gl_Position = modelviewproj * vec4(te_position, 1);
}
[geometry shader]
#version 410
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;
in vec3 te_position[3];
in vec3 te_patch_distance[3];
out vec3 g_face_normal;
out vec3 g_patch_distance;
out vec3 g_tri_distance;
uniform mat3 normal_mat;
void main()
{
vec3 a = te_position[2] - te_position[0];
vec3 b = te_position[1] - te_position[0];
g_face_normal = normal_mat * normalize(cross(a, b));

g_patch_distance = te_patch_distance[0];
g_tri_distance = vec3(1, 0, 0);
gl_Position = gl_in[0].gl_Position;
EmitVertex();

g_patch_distance = te_patch_distance[1];
g_tri_distance = vec3(0, 1, 0);
gl_Position = gl_in[1].gl_Position;
EmitVertex();

g_patch_distance = te_patch_distance[2];
g_tri_distance = vec3(0, 0, 1);
gl_Position = gl_in[2].gl_Position;
EmitVertex();
}
[pixel shader]
#version 410
in vec3 g_face_normal;
in vec3 g_tri_distance;
in vec3 g_patch_distance;
out vec4 color;
float amplify(float d, float scale, float offset)
{
d = scale * d + offset;
d = clamp(d, 0, 1);
d = 1 - exp2(-2 * d * d);
return d;
}
void main()
{
vec3 n = normalize(g_face_normal);
vec3 l = vec3(0, 1, 0);

float ndotl = max(dot(n, l), 0);

vec3 result = ndotl * vec3(1, 1, 1);

float d1 = min(min(g_tri_distance.x, g_tri_distance.y), g_tri_distance.z);
float d2 = min(min(g_patch_distance.x, g_patch_distance.y), g_patch_distance.z);

result *= amplify(d1, 40, -0.5) * amplify(d2, 60, -0.5);

color = vec4(result, 1);
}


Best regards,
Yours3!f Edited by Yours3!f

Share this post


Link to post
Share on other sites
Hi!

The code you posted worked fairly well. I just changed some minor things to make it fit to my demo app, here.
In particular, I used explicit vertex attribute binding in the vertex shader:
layout(location=0) in vec3 in_vertex;

For all uniform parameters I utilized a uniform buffer object, e.g.:
layout(std140) uniform TessFactor
{
float tess_level_inner;
float tess_level_outer;
};


Eventually, I removed the normalization of te_position in your tessellation evaluation shader (barycentric interpolation doesn't require it).
//te_position = normalize(p0 + p1 + p2);
te_position = p0 + p1 + p2;


It works on my end. I tested on a GeForce 460 GTX (Win 7, 64 Bit).

Good luck! Hopefully you find a way to get it running, too.
Best regards

Share this post


Link to post
Share on other sites
just a couple of questions in connection with your modifications:


The code you posted worked fairly well. I just changed some minor things to make it fit to my demo app, here.
In particular, I used explicit vertex attribute binding in the vertex shader:
layout(location=0) in vec3 in_vertex;


I use special "shader controller" files for this :) so I don't have to worry about which attribute belong to which location.

For all uniform parameters I utilized a uniform buffer object, e.g.:
layout(std140) uniform TessFactor
{
float tess_level_inner;
float tess_level_outer;
};

[/quote]

is that a performance win, or you just like to use uniforms this way?


Eventually, I removed the normalization of te_position in your tessellation evaluation shader (barycentric interpolation doesn't require it).
//te_position = normalize(p0 + p1 + p2);
te_position = p0 + p1 + p2;

[/quote]

yeah I still need to dig deeper into the barycentric coordinates...

It works on my end. I tested on a GeForce 460 GTX (Win 7, 64 Bit).[/quote]

I guess this is the relevant bit. I have an AMD Radeon HD 5670 (Linux, 64 bit, same problem on Win 7 64 bit with same drivers) with newest drivers. So can you please verify the code on AMD as well? Because if thats the problem, then I guess I should contact the AMD dev guys to fix this...

Share this post


Link to post
Share on other sites
Hi,

I did the modifications only to get the code running in a small tessellation exercise I wrote a while back. I didn’t want to change much on the CPU side, so I just used the uniform buffer objects that were passed in already.
On the CPU side I didn’t specify the attribute binding, so I had to do it in GLSL. Doing this in GLSL is just a personal favor.


[quote name='Tsus' timestamp='1336296166' post='4937734']
For all uniform parameters I utilized a uniform buffer object, e.g.:
layout(std140) uniform TessFactor
{
float tess_level_inner;
float tess_level_outer;
};


is that a performance win, or you just like to use uniforms this way?
[/quote]
I think the performance win isn’t that big. It’s more that I like that sort of grouping as it reminds me of constant buffers in Dx.


[quote name='Tsus' timestamp='1336296166' post='4937734']
It works on my end. I tested on a GeForce 460 GTX (Win 7, 64 Bit).

I guess this is the relevant bit. I have an AMD Radeon HD 5670 (Linux, 64 bit, same problem on Win 7 64 bit with same drivers) with newest drivers. So can you please verify the code on AMD as well? Because if thats the problem, then I guess I should contact the AMD dev guys to fix this...
[/quote]
Sorry, I neither have an AMD at home nor in the lab.
I attached the code so you can test it yourself.

Yes, you should probably report this to AMD if it turns out to be some sort of bug.

Cheers!

Share this post


Link to post
Share on other sites

Hi,

I did the modifications only to get the code running in a small tessellation exercise I wrote a while back. I didn’t want to change much on the CPU side, so I just used the uniform buffer objects that were passed in already.
On the CPU side I didn’t specify the attribute binding, so I had to do it in GLSL. Doing this in GLSL is just a personal favor.

[quote name='Yours3!f' timestamp='1336304020' post='4937748']
[quote name='Tsus' timestamp='1336296166' post='4937734']
For all uniform parameters I utilized a uniform buffer object, e.g.:
layout(std140) uniform TessFactor
{
float tess_level_inner;
float tess_level_outer;
};


is that a performance win, or you just like to use uniforms this way?
[/quote]
I think the performance win isn’t that big. It’s more that I like that sort of grouping as it reminds me of constant buffers in Dx.


[quote name='Tsus' timestamp='1336296166' post='4937734']
It works on my end. I tested on a GeForce 460 GTX (Win 7, 64 Bit).

I guess this is the relevant bit. I have an AMD Radeon HD 5670 (Linux, 64 bit, same problem on Win 7 64 bit with same drivers) with newest drivers. So can you please verify the code on AMD as well? Because if thats the problem, then I guess I should contact the AMD dev guys to fix this...
[/quote]
Sorry, I neither have an AMD at home nor in the lab.
I attached the code so you can test it yourself.

Yes, you should probably report this to AMD if it turns out to be some sort of bug.

Cheers!
[/quote]

Thank you smile.png this saved me writing an example.

Well I had to do some modifications to get it running, but eventually it was running, so I guess I'm doing something wrong.
I've attached the modified code. (tessellation.dom, and Tessellation_end.cpp, plus file renamings and I added headers, libs and dlls) Edited by Yours3!f

Share this post


Link to post
Share on other sites
HEUREKA XD

SOLVED smile.png

I examined your example, and found out one thing that's entirely different: how you draw your mesh.

so I just had to include the glPatchParameter function and change the glDrawElements from GL_TRIANGLES to GL_PATCHES... this is quite stupid... so this is what a working source does to me smile.png

Thank your for the help!!! Edited by Yours3!f

Share this post


Link to post
Share on other sites
Hi,

just out of curiosity I tried the technique with interface blocks, and it worked, so that wasn't the problem smile.png seems like the newest drivers are capable of this.

another thing is that the normalization in the tessellation evaluation shader IS needed, without it the geometry won't "emerge" out of the surface. (see pictures)

Share this post


Link to post
Share on other sites
Hi,


just out of curiosity I tried the technique with interface blocks, and it worked, so that wasn't the problem smile.png seems like the newest drivers are capable of this.

Nice! Thanks for the info! I’ll give it a try again, later.


another thing is that the normalization in the tessellation evaluation shader IS needed, without it the geometry won't "emerge" out of the surface.

Wouldn't this only work for unit-spheres?
Most often, I just pick an easy tessellation scheme like phong tessellation. Edited by Tsus

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!