Longs Peak Program Objects

From the newsletter:

In OpenGL 2.1 only one program object can be in use (bound) for rendering. If the application wants to replace both the vertex and fragment stage of the rendering pipeline with its own shaders, it needs to incorporate all shaders in that single program object. This is a fine model when there are only two programmable stages, but it starts to break down when the number of programmable stages increases because the number of possible combinations of stages, and therefore the number of program objects, increases. In OpenGL Longs Peak it will be possible to bind multiple program objects to be used for rendering. Each program object can contain only the shaders that make up a single programmable stage; either the vertex, geometry or fragment stage. However, it is still possible to create a program object that contains the shaders for more than one programmable stage.
Anyone care to expand or speculate on these ideas?

I’m thinking “set of compiled shaders that can be quickly linked at runtime”, but then things get a bit fuzzy :wink:

Cheers

Anyone care to expand or speculate on these ideas?
No need for speculation.

All it’s saying is that you can have fully linked programs that don’t have to include all of the stages that you intend to use. So you can have a vertex program and a fragment program, both compiled and linked, and then you decide to use both when rendering something.

Before, you would have had to create a combined vertex&fragment program, one program that contains both stages. Now, you don’t.

So we’d have something like this:

...
glUseProgram(vsSet);
glUseProgram(gsSet);
glUseProgram(fsSet);
...
SpecifyWhichShadersToApply();
DrawLotsOfStuffUsingThisSet(); 

Each of the shader sets is considered to be a valid program in its own right, in this model (total program validation presumably deferred to the next draw command). Am I right?

Where I get fuzzy is in how one would specify the particular {vs,gs,ps} from the active set that is intended for use, and how this selection might interact with uniform (block) updates.

I realize it’s a bit early for specific details, but I just can’t resist asking :slight_smile:

Thanks,
Cheers

Right now we link multiple fragment, geometry and vertex shaders into one program that gets executed - so more than one type of shaders creates a program.
From now on you will link multiple fragment shaders into one fragment program, multiple vertex shaders into one vertex program - so only one type of shader can be linked together into one program.
You will not link fragment and vertex shaders into one program.
You can then enable/disable single fragment/vertex/geometry program separately.

The API is different thing. Note that

glUseProgram( vp );

is OK, because we know vp is a set of vertex shaders linked into one vetex program (they’re allready linked).
But this:

glUseProgram( 0 );

Is no longer valid, because is tells to unbind (bind default) program, but does not tell which stage it reffers to (fragment? geometry?)
Something like this would be OK:

glUseProgram(GL_DEFAULT_FRAGMENT_PROGRAM);

That GL_DEFAULT_FRAGMENT_PROGRAM would be defined as external variable being a program object. So unbinding proagam is actually binding default program of that type.
Perhaps instead we would have glUnbindProgram( vp ) or glUnbindProgram(GL_VERTEX_PROGRAM) - It doesn’t mak much difference to me.

I have no clue how new API will look, but I think the idea (not the API) will be more less what I described.

Again - don’t consider this to be a confirmed fact - it’s just how I understand it.

The way I understand it is that a program object may contain 1 of each of the shader types (vertex, geometry, fragment). You can then do the following:

glUseProgram(programWithOnlyAVertexShader);
glUseProgram(programWithOnlyAFragmentShader);

And it’ll work just as if the vertex and fragment shader were in the same program.

You could also do the following:

glUseProgram(programWithAVertexAndFragmentShader);
//..draw stuff
glUseProgram(programWithOnlyAGeometryShader);
//..draw more stuff

The first draw would just use the vertex and fragment program, and the second draw would use all 3.

The bit I’m not sure on is if 2 currently bound programs have matching shader types. I assume the last one to be bound is the one that will be used. E.g.

glUseProgram(programWithAVertexAndFragmentShader);
glUseProgram(programWithOnlyAFragmentShader);

In this example it would use the vertex shader from the first program, and the fragment shader from the second program.

Of course they’d probably change the semantics to bind/unbind, e.g.

glBindProgram();
glUnbindProgram();

Regards
elFarto

I don’t think there will be a default program.

The bit I’m not sure on is if 2 currently bound programs have matching shader types.
I think that won’t be allowed. It’s a bit fuzzy on that point, but as I read it, you have two choices:

  • link everything into a single program and use this
  • link only shaders of the same stage into a program, and combine multiple programs

IMHO:
I think you can bind multiple programs, but only one ‘main()’ function for a shader of each type will be allowed. So it’s pretty much like current approach, just imagine only that the bound programs will be linked automatically.

I don’t think there will be a default program.
Yes, you’re right. I think semantics “unbind” and “bind default” are equivalent when comes to most of implementations, but from the API’s point of view fixed functionality still exists. There will be probably something like: glUnbind( <program_type> ).

I think you can bind multiple programs, but only one ‘main()’ function (…) linked automatically
You can implement it allready - if you want to use a set of shaders you can create temporary program, attach, link and destroy program after you’re done using it. I wouldn’t say that doing it multiple times every frame is performance-wise.
It’s better to prepare such ‘sets’ of shaders we intend to use on init and pre-link them and that leads us back to idea of programs.

The only difference now is that program object is not for all stages but just for one stage. You can attach them freely with no performance loss as vertex shader does not have to be linked with fragment shader. It never had to. :slight_smile:

but from the API’s point of view fixed functionality still exists
Are you sure? I don’t think so :wink:

Ah, sorry, I haven’t read it throughly… I missed the “Each program object can contain only the shaders that make up a single programmable stage” part :-/

Are you sure?
No I’m not. I just assume that “lean and mean” pofile won’t have FF, but there will be backward compatible profile and it will allow some of the new stuff, right? I think separate programs for every stage is not in conflict with existing model - it’s just an extension of it.
If there will be absolutely no FF, do I have to create shaders for all stages to render anything or is there some default behavior for, let’s say, geometry shaders defined? If yes, then it’s defalt shader/FF or whatever you wish to call it.
If no, I’m gonna have to do the homework :slight_smile:

I’ll try to clear up the confusion.

There are two classes of linkage which occur with programs:

  1. Intra-stage linking occurs when multiple shader modules are combine to form a single pipeline stage.

  2. Inter-stage linking occurs when multiple stages are combined to form a complete pipeline.

In GL2, both forms of linkage occurs when you call LinkProgram(). You bind the program with UseProgram(), and any stages not present in the program revert to fixed function.

In Longs Peak, Intra-stage linking always occurs during program creation. If multiple stages are present in the program, Inter-stage linking also occurs. However, you have the option of creating a pipeline from separate program objects, e.g. you might have a vertex program which you wish to use with multiple fragment programs. In GL2 you are required to create a separate program object for each combination of per-stage programs. In contrast, Longs Peak allows inter-stage linking when you bind the program objects. It may look something like:

glUsePrograms(GLprogram *programs, GLint count);

All required stages (currently vertex and fragment) must be represented by the list of programs provided. For efficiency, we currently require that the set of varyings passed between the stages be an exact match.

You still have the option of linking all stages into a single program object, in which case the varyings need not exactly match, provided that the outputs from one stage are a superset of the inputs to the next stage.

At this point, there are no plans to support fixed function in Longs Peak.

is there some default behavior for, let’s say, geometry shaders defined?
No default behaviour, but the geometry shader is optional. That means you don’t need one, not even a default implementation :wink:

Yep. Homework it is :smiley:
Guess I’ll lay low for a while, so Michael Gold and others will not have spend time explaining new API to me and fucus on actually developing it :slight_smile:

It’s a good thing to discuss upcoming API with community, but poeple not aware of some design decisions that have been allready made (like me) can produce too much noise. Most of us just don’t see the whole picture, and the truth is: whatever the new OpenGL will look like, I’ll be damn happy about it :smiley:

Thanks guys, much clearer now.

So just to recap, we would bind a list of programs, each of which containing only a single vertex or fragment shader?

How would uniform updates fit into this scenario? I suppose we’d need to update the uniforms for each program (vs or fs) independently, or together once used in a list? Of course currently we have our uniforms applied to these stages together as a group, so I’m a bit curious as to how this plays out in the proposal.

glUsePrograms(GLprogram *programs, GLint count);
Now that’s an API. (What was I thinking :smiley: )

Cheers

In contrast, Longs Peak allows inter-stage linking when you bind the program objects. It may look something like:

glUsePrograms(GLprogram *programs, GLint count);
In contrast, Longs Peak allows inter-stage linking when you bind the program objects. It may look something like:

glUsePrograms(GLprogram *programs, GLint count);
Would it be difficult to support intra-stage linking in a similar way?

Would it be difficult to support intra-stage linking in a similar way?
Why would you want to? I mean, that’s basically doing what we have now.

The purpose of having independent, fully linked fragment, vertex, and geometry programs is to have most of the linking work be done and make it performant to mix-and-match linked programs without having to go through a full relinking stage.

Once you get into having two partial programs combined, you’re basically back to just the compile and link step, which we already have.

We’re not losing the ability to compile multiple shaders of the same type and do intrastage linking. We’re simply allowing people to mix and match stages together without the performance penalty that one would have when doing so under the current GL implementation.

Yes, the more I think about this, the more I like it! We get on-the-fly program construction from stages, and it only costs us a lightweight link/validation step.
(This seems like fragment linking in DX, only better :wink: )

To have a stab at my own question, post glUsePrograms seems like the right place to specify uniforms, unless there’s a better way to block/group uniforms with independent stages, to possibly reduce updates somehow (maybe I just need more coffee).

Cheers

The purpose of having independent, fully linked fragment, vertex, and geometry programs is to have most of the linking work be done and make it performant to mix-and-match linked programs without having to go through a full relinking stage.

Yes and this would be also very useful for shader objects.

Once you get into having two partial programs combined, you’re basically back to just the compile and link step, which we already have.
Is this really necessary? It would be acceptable if the driver cannot perform a whole program optimization between the shader objects.