PDA

View Full Version : ARB_serperate_shader_objects sharing uniforms



Leith Bade
02-04-2011, 07:31 PM
I have just read ARB_serperate_shader_objects and when combined with GLSL layout qualifiers it is very easy to mix/match different parts of the pipeline.

E.g. in my program I have a single fragment program for filling a solid 2D shape. For triangles I use a simple MVP vertex shader with this fragment shader.

For thick/thin lines I use a different vertex shader that only does MV * vert which I combine with a geometry shader that does the P * vert part.

So I have a shared fragment shader, and seperate geomertry pipeline:
Triangles -> Vertex -> Fragment
Lines -> Vertex -> Geometry -> Triangles -> Fragment

Thus I will have 3 program objects:
1 - Triangle Vertex only
2 - Line Vertex & Geometry
3 - Fragment only

Using the layout qualifiers I know that vertex data always goes into slot 0, and fragments always output into slot 0.

But I also have some uniforms that are shared between programs 1 & 2.

The modelViewMatrix exists in vertex 1 and vertex 2 shader. The projectionMatrix exisits in vertex 1, and geometry 2.

In my drawStart function I would like to simply set these uniforms with the same functions regardless of the current program.

So is there a way to use layout qualifier with uniforms shared between the 3 shaders (vertex 1,2 and geometry 2).

e.g.

set_uniform(index 0, modelViewMatrix);
set_uniform(index 1, projectionMatrix);

ZbuffeR
02-04-2011, 07:47 PM
Just to fix misspelling in your post and make it "findable", it is ARB_separate_shader_objects, spec page here : http://www.opengl.org/registry/specs/ARB/separate_shader_objects.txt

(sorry can not help for the actual question)

Alfonse Reinheart
02-04-2011, 07:51 PM
So is there a way to use layout qualifier with uniforms shared between the 3 shaders (vertex 1,2 and geometry 2).

No. Uniform locations are assigned by the compiler for each program individually.

Leith Bade
02-04-2011, 08:58 PM
Thats a bummer.

I guess 4.2 will need to add layout qualifiers for uniforms...

Alfonse Reinheart
02-04-2011, 09:07 PM
I guess 4.2 will need to add layout qualifiers for uniforms...

That's simply not going to happen. Unlike inputs and outputs, uniforms can be complicated structures. Different hardware will want to layout structures in different ways. Having uniform locations generated by the compiler/linker means that different hardware can give them uniform locations that are most convenient for that hardware.

Now, you might say that UBOs already allow the user to request a fixed layout, with std140. However, if you're going to do that, you might as well just use a UBO to store the uniform data to begin with. Then you don't have to worry about it.

One of the reasons UBOs exist is to allow easy sharing of uniform data between programs.

Leith Bade
02-05-2011, 12:19 AM
Interesting, I didn't know about uniform blocks and uniform buffers.

They seem to do the trick according to the tutorial I found at:
http://www.arcsynthesis.org/gltut/Positioning/Tut07%20Shared%20Uniforms.html

One really annyoing thing about the UBO API is that you have to query GL to get the uniform block index for _every_ program, even if you share that block...

That is soooo GL 3.2...

They need to expand ARB_explicit_attrib_location to cover uniform blocks too.

ARB_explicit_attrib_location removed the need for glBindAttribLocation for vertex shaders and glBindFragDataLocation/glBindFragDataIndex for fragment shaders.

So why can't we also remove the need for glGetUniformBlockIndex and glUniformBlockBinding.

I suppose we could also remove the need for glGetUniformLocation, but if it is too complicated, I can live with placing every single one of my uniforms into uniform blocks (or even a shared 'uber' block)...

I propose something like this:


layout(std140, location = 0) uniform matrices
{
mat4 modelViewMatrix;
mat4 projectionMatrix;
};

Which would automatically make whatever is in uniform buffer binding 0 be linked with this. It might be better to call it 'binding', then we could also have 'index' specify the uniform
index too.

While we are at it the same could be done with samplers and texture units, e.g:

layout(unit = 0) uniform sampler2D texture;

Will automatically bind this variable to texture unit 0.

Alfonse Reinheart
02-05-2011, 01:12 AM
One really annyoing thing about the UBO API is that you have to query GL to get the uniform block index for _every_ program, even if you share that block...

If you're sharing buffer objects by setting all programs that use it to the same binding index, then you can set this up at program initialization time. That's how my example code does it; all that querying and so forth is done in the program initialization function.

So however annoying it may be, it's a one-time thing. It's not like you have to store the block index with the program object or anything.


So why can't we also remove the need for glGetUniformBlockIndex and glUniformBlockBinding.

For global shared buffer objects, you wouldn't need to change what binding index is used. But there are ways to use UBOs where you might not want a fixed block binding index. I'm not opposed to this kind of thing, but even if you had it, you would still need those functions. On occasion.

Oh, and it probably shouldn't be called "location". The other things that "location" set are all fixed at link time. The binding index is something that can (theoretically) change. It's more like a default uniform value: it's set by the program, but the user can change it later.


While we are at it the same could be done with samplers and texture units, e.g:

The syntax for that should probably be simply initializing the uniform to an integer.

Leith Bade
02-05-2011, 04:26 AM
I had a peek at how Direct3D handles this stuff.

In HLSL the equivalent to the 'layout(location = X)' syntax is ': register(cX)'

It is described here: http://msdn.microsoft.com/en-us/library/dd607359(VS.85).aspx

They let you explicitly set the index for:
* constant buffers aka uniform buffer objects
* constant buffer member offset aka std140 layout (not as flexible)
* textures aka texture objects
* samplers aka sampler objects (can't actually do this yet)
* texture buffers aka texture buffer objects
* unordered access view aka EXT_shader_image_load_store

The API they use for constant buffers (and the other binding points) is per shader stage but not attached to the shader object itself. Thus you can directly mix and match the same or different constant buffers per stage freely.

I can now see what OpenGL really needs to do to make this cleaner is to move all the uniform/sampler/vertex attrib/frag color binding from the program object to some sort of shader stage binding. That way when you swap shaders/programs/pipeline objects the stuff remains bound to the particular indexes.

Also what is the purpose of giving uniform buffer bindings 2 levels of indirection (ie bindings -> index -> shader)? Wouldn't have been better to do what they did with all the other bindings (ie index -> shader)?

Two more things I noticed missing from GL that D3D has:
* separate textures and samplers in the shader. GL has separated them at the API with ARB_sampler_objects, but GLSL doesn't get access to it. If this were implemented it would be the death of texture units, and we can use as many samplers/textures as we want.
* explicit packing of uniform buffers. Would allow the benefits of std140 for shared buffers, but also allow the efficiency of packing.

Alfonse Reinheart
02-05-2011, 10:26 AM
I can now see what OpenGL really needs to do to make this cleaner is to move all the uniform/sampler/vertex attrib/frag color binding from the program object to some sort of shader stage binding. That way when you swap shaders/programs/pipeline objects the stuff remains bound to the particular indexes.

How does that make anything "cleaner"? D3D makes all of these things program state, just like OpenGL. Separating essential state like this from the program (the only place where that state has context) makes no sense.

The only difference between D3D and OpenGL on this is that in D3D, this state is set by the shader source code, while in OpenGL, much of it is set by the user in OpenGL code.


Also what is the purpose of giving uniform buffer bindings 2 levels of indirection (ie bindings -> index -> shader)?

There aren't two levels of indirection. The block index is just like the uniform location; it's an alias for the string name of the uniform block. Each uniform block is assigned an index by the linker. Each index has a binding point set by the user, which refers to a uniform buffer slot in the context.


If this were implemented it would be the death of texture units, and we can use as many samplers/textures as we want.

The number of texture units is a hardware limitation. I don't see how giving GLSL control over the sampling parameters removes this limitation in any way.


explicit packing of uniform buffers.

That's more low-level than a high-level language should get.

Leith Bade
02-06-2011, 03:45 PM
So where do we suggest stuff for the ARB to add to future GL versions?

It seems that the equivalent for layout(location = 0) on uniform blocks is the only decent idea.

Alfonse Reinheart
02-06-2011, 04:41 PM
We have a whole section for suggestions. Though given the pretty terrible signal-to-noise ratio of that area, I wouldn't be surprised if few people in charge of this sort of thing actively read it.