OpenGL 4.1 : did i misunderstood separate programs ?

Hello everyone,

I am trying to use a ProgramPipelineObject and I have not been able to make it work the way I want.
Maybe I am trying something that is not possible.
I have a “basic” example which works, and a “little bit more complexe” example which does not.

This is the example which works :
ProgramObject 1 :
[ul]
[li]load vertex shader, compile, set separable true, link
[/li][/ul]
ProgramObject 2 :
[ul]
[li]load fragment shader, compile, set separable true, link
[/li][/ul]
ProgramPipeline :
[ul]
[li]generate, bind ProgramPipeline
[/li][li]useStage(ProgramPipeline, Vertex, ProgramObject 1)
[/li][li]useStage(ProgramPipeline, Fragment, ProgramObject 2)
[/li][li]unbind ProgramPipeline
[/li][/ul]
Render pass :
[ul]
[li]programuniform(ProgramObject 1, “matrix etc…”)
[/li][li]programuniform(ProgramObject 2, “color etc…”)
[/li][li]bind ProgramPipeline
[/li][li]draw object
[/li][li]unbind ProgramPipeline
[/li][/ul]

This is the example which doest not work (the only modification is bold) :
ProgramObject 1 :
[ul]
[li]load vertex shader, load fragment shader, compile both, set separable true, link (so this is not a simple program with a vertex shader, but a program with a vertex and a fragment shader)
[/li][/ul]
ProgramObject 2 :
[ul]
[li]load fragment shader, compile, set separable true, link
[/li][/ul]
ProgramPipeline :
[ul]
[li]generate, bind ProgramPipeline
[/li][li]useStage(ProgramPipeline, Vertex, ProgramObject 1)
[/li][li]useStage(ProgramPipeline, Fragment, ProgramObject 2)
[/li][li]unbind ProgramPipeline
[/li][/ul]
Render pass :
[ul]
[li]programuniform(ProgramObject 1, “matrix etc…”)
[/li][li]programuniform(ProgramObject 2, “color etc…”)
[/li][li]bind ProgramPipeline
[/li][li]draw object
[/li][li]unbind ProgramPipeline
[/li][/ul]

My result is : no object on screen : maybe a uniform problem ?

->Is it possible to create a pipeline taking only one stage of a shaderprogram that contains many stages?
->Do you see any reason that can make it fail ?

Thanks you very much.

PS : I am under linux ubuntu 12.04, nvidia 304 drivers, gtx 480, glew 1.9

Is it possible to create a pipeline taking only one stage of a shaderprogram that contains many stages?

According to the specification, yes.

Do you see any reason that can make it fail ?

Yes.

The whole point of separable programs is to not have programs linked together. At all. Indeed, they created a whole new entrypoint dedicated to creating single-stage programs.

NVIDIA’s drivers certainly should allow this by the specification, so it’s probably a driver bug (assuming your code isn’t wrong in some other way), so feel free to file a report on it. But it’s not exactly a surprise that this doesn’t work.

In short, I wouldn’t rely on being able to replace one program’s stage with another program’s stage. It could and should work, but it’s a corner case that most users of this functionality (people who want D3D-like shaders) would never touch. So it doesn’t get as extensive testing in the field as the other cases.

Thanks you for that quick answer.

I could have been so amazing …

To make sure this is not a wrong code and a real driver problem, this is what I tested :
On the OpenGL Samples Pack 4.3.0.2 (OpenGL Samples Pack 4.3.0.2 released) I changed initSeparateProgram() of gl-410-program-separate.cpp.

This is the diff :

< std::string VertexSourceContent = glf::loadFile(VERTEX_SHADER_SOURCE);
< char const * VertexSourcePointer = VertexSourceContent.c_str();
< SeparateProgramName[program::VERTEX] = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &VertexSourcePointer);

> // create a shaderprogram containing 2 shader stages
> GLuint VertShaderName = glf::createShader(GL_VERTEX_SHADER, VERTEX_SHADER_SOURCE);
> GLuint FragShaderName = glf::createShader(GL_FRAGMENT_SHADER, FRAGMENT_SHADER_SOURCE);
>
> SeparateProgramName[program::VERTEX] = glCreateProgram();
> glAttachShader(SeparateProgramName[program::VERTEX], VertShaderName);
> glAttachShader(SeparateProgramName[program::VERTEX], FragShaderName); // If you comment this line, it works. If you do not (and the program has 2 shaders) it does not.
> glProgramParameteri(SeparateProgramName[program::VERTEX], GL_PROGRAM_SEPARABLE, GL_TRUE);
> glLinkProgram(SeparateProgramName[program::VERTEX]);

Consequently the following line should have taken only one stage :
glUseProgramStages(PipelineName, GL_VERTEX_SHADER_BIT, SeparateProgramName[program::VERTEX]);
// Check program id
int program_id = 0;
glGetProgramPipelineiv(PipelineName, GL_VERTEX_SHADER, &program_id);
std::cout << "Used (vertex) program id : " << program_id << std::endl; // display the correct program id
glGetProgramPipelineiv(PipelineName, GL_FRAGMENT_SHADER, &program_id);
std::cout << "Used (fragment) program id : " << program_id << std::endl; // display 0 which is what we want

So, the use stage “seems” to work, but the display does not work anymore :
glBindProgramPipeline(PipelineName);
glDrawElementsInstancedBaseVertex(GL_TRIANGLES, ElementCount, GL_UNSIGNED_INT, NULL, 1, 0); // crash here
glBindProgramPipeline(0);

OpenGL: error(high) 1282: GL_INVALID_OPERATION error generated. State(s) are invalid: program pipeline config.

If somebody can confirm me that I did not do wrong code, I will report the bug.
Thanks.

Thanks you for that quick answer.

I could have been so amazing …

To make sure this is not a wrong code and a real driver problem, this is what I tested :
On the OpenGL Samples Pack 4.3.0.2 (OpenGL Samples Pack 4.3.0.2 released) I changed initSeparateProgram() of gl-410-program-separate.cpp.

This is the diff :

< std::string VertexSourceContent = glf::loadFile(VERTEX_SHADER_SOURCE);
< char const * VertexSourcePointer = VertexSourceContent.c_str();
< SeparateProgramName[program::VERTEX] = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &VertexSourcePointer);

> // create a shaderprogram containing 2 shader stages
> GLuint VertShaderName = glf::createShader(GL_VERTEX_SHADER, VERTEX_SHADER_SOURCE);
> GLuint FragShaderName = glf::createShader(GL_FRAGMENT_SHADER, FRAGMENT_SHADER_SOURCE);
>
> SeparateProgramName[program::VERTEX] = glCreateProgram();
> glAttachShader(SeparateProgramName[program::VERTEX], VertShaderName);
> glAttachShader(SeparateProgramName[program::VERTEX], FragShaderName); // If you comment this line, it works. If you do not (and the program has 2 shaders) it does not.
> glProgramParameteri(SeparateProgramName[program::VERTEX], GL_PROGRAM_SEPARABLE, GL_TRUE);
> glLinkProgram(SeparateProgramName[program::VERTEX]);

Consequently the following line should have taken only one stage :
glUseProgramStages(PipelineName, GL_VERTEX_SHADER_BIT, SeparateProgramName[program::VERTEX]);
// Check program id
int program_id = 0;
glGetProgramPipelineiv(PipelineName, GL_VERTEX_SHADER, &program_id);
std::cout << "Used (vertex) program id : " << program_id << std::endl; // display the correct program id
glGetProgramPipelineiv(PipelineName, GL_FRAGMENT_SHADER, &program_id);
std::cout << "Used (fragment) program id : " << program_id << std::endl; // display 0 which is what we want

So, the use stage “seems” to work, but the display does not work anymore :
glBindProgramPipeline(PipelineName);
glDrawElementsInstancedBaseVertex(GL_TRIANGLES, ElementCount, GL_UNSIGNED_INT, NULL, 1, 0); // crash here
glBindProgramPipeline(0);

OpenGL: error(high) 1282: GL_INVALID_OPERATION error generated. State(s) are invalid: program pipeline config.

If somebody can confirm me that I did not do wrong code, I will report the bug.
Thanks.