Jump to content

  • Log In with Google      Sign In   
  • Create Account


uniforms


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
10 replies to this topic

#1 Yours3!f   Members   -  Reputation: 1251

Like
0Likes
Like

Posted 31 October 2012 - 04:35 AM

Hi,

I'm trying to move to using the new opengl layout qualifiers. I almost got everything working, however I ran into a small problem.
When I add the overlay_color uniform, I can't set it using the glUniform3fv(), and I don't know why. All the other uniforms, attributes, samplers can be set, except this one... The shader still compiles, links and validates successfully, and no warning is shown that would indicate anything.
When I try to set the overlay_color (using glUniform3fv) I get GL_INVALID_OPERATION. I checked the specs, but I can't figure out what I'm missing, because:
-the program object is set, and valid
-the variable's size matches the glUniform function
-the location (I think) is valid, and not -1
-the count is 1

here's the shader:

[ vertex shader ]

#version 420 core

layout(location=0) uniform mat4 mvp;

layout(location=0) in vec4 in_vertex;
layout(location=5) in vec2 in_texture;

out cross_shader_data
{
  vec2 tex_coord;
} o;

out vec4 color;

void main()
{
  o.tex_coord = in_texture;
  gl_Position = mvp * in_vertex;
}

[ pixel shader ]

#version 420 core

layout(location=1,binding=0) uniform sampler2D texture0;
layout(location=2) uniform vec3 overlay_color;

in cross_shader_data
{
  vec2 tex_coord;
} i;

out vec4 color;

void main()
{
  color = texture(texture0, i.tex_coord) + vec4(overlay_color, 1);
}

here's how I'm passing the values:
glUseProgram( this->shader );
vec3 overlay_color = {{ 1, 0, 0 }};
glUniform3fv( 2, 1, &overlay_color.v[0] );
glUniformMatrix4fv( 0, 1, false,
&o->ppl->get_model_view_projection_matrix( o->ppl ).m[0].v[0] );


Sponsor:

#2 Aks9   Members   -  Reputation: 769

Like
4Likes
Like

Posted 02 November 2012 - 07:28 AM

Why do you need this feature? If it is for the learning sake only, please wait until stable drivers release.
There are several sources of the problem.

What drivers are you using? GL_ARB_explicit_uniform_location is the part of GLSL 4.3 core spec, not 4.2. If you are using NV 310.xx drivers, then there could be a bug, since they are in a beta phase. If you are using previous releases, then you should check whether the extension is supported and probably enable it explicitly in GLSL (if it is supported).

I guess you don't have support GL_ARB_explicit_uniform_location and the reason it works for the first uniform is accidental correspondence with compiler's associated locations. NV uses alphabetical order of names. So, locations are as follows:
0 - mvp
2 - texture0
1 - overlay_color

Before trying to use some new feature check if it is presented and read specification to understand how it works. ;)

#3 Yours3!f   Members   -  Reputation: 1251

Like
1Likes
Like

Posted 03 November 2012 - 03:16 AM

Why do you need this feature? If it is for the learning sake only, please wait until stable drivers release.
There are several sources of the problem.

What drivers are you using? GL_ARB_explicit_uniform_location is the part of GLSL 4.3 core spec, not 4.2. If you are using NV 310.xx drivers, then there could be a bug, since they are in a beta phase. If you are using previous releases, then you should check whether the extension is supported and probably enable it explicitly in GLSL (if it is supported).

I guess you don't have support GL_ARB_explicit_uniform_location and the reason it works for the first uniform is accidental correspondence with compiler's associated locations. NV uses alphabetical order of names. So, locations are as follows:
0 - mvp
2 - texture0
1 - overlay_color

Before trying to use some new feature check if it is presented and read specification to understand how it works. ;)


:( I'm on AMD with only OGL4.2 drivers... I guess I'll have to stick with glGetUniformLocation...
as for the why: I just wanted to get rid of keeping track of uniform locations. It's not that cumbersome, but it would be great if I didn't have to.
I guess for the rest you're right, I just accidentally got the uniform locations right. Well, thank you for clarifying the situation. I just thought this was available since gl 3.1

#4 Aks9   Members   -  Reputation: 769

Like
1Likes
Like

Posted 03 November 2012 - 05:34 AM

I'm on AMD with only OGL4.2 drivers... I guess I'll have to stick with glGetUniformLocation...
as for the why: I just wanted to get rid of keeping track of uniform locations. It's not that cumbersome, but it would be great if I didn't have to.

T thought you are using NV hardware, since only NV currently has GL 4.3 support.

Well, I don't agree that getting uniforms' (or attributes') location is cumbersome, especially because that should be done only once, during the initialization phase.
I'm using class-wrapper for each shaders. Uniforms and attributes locations are attributes of the instance, and they are set in the Init() function (at the same place where I load and compile shaders, and link the program). After that, I just call appropriate function (method) of the particular object to set values. It cannot be easier.

Another remark: Setting attribute location is also not correct in your code, because you are wasting 4 locations.
layout(location=0) in vec4 in_vertex;
layout(location=5) in vec2 in_texture;

In the unpacked format, both vec2 and vec4 consumes just one location. In your case, layout is like follows:
location 0: | in_vertex.x | in_vertex.y | in_vertex.z | in_vertex.w |
location 1: | < empty > | < empty > | < empty > | < empty > |
location 2: | < empty > | < empty > | < empty > | < empty > |
location 3: | < empty > | < empty > | < empty > | < empty > |
location 4: | < empty > | < empty > | < empty > | < empty > |
location 5: | in_texture.s | in_texture.t | < empty > | < empty > |

As you can see, there is a lot of wasted space. So, if you don't have a particular reason to define layout and reuse it across multiple shader-objects, It would be wiser to just let compiler do it, or read specifications to see how it actually works.
Happy coding! Posted Image

#5 Yours3!f   Members   -  Reputation: 1251

Like
0Likes
Like

Posted 04 November 2012 - 02:08 AM


I'm on AMD with only OGL4.2 drivers... I guess I'll have to stick with glGetUniformLocation...
as for the why: I just wanted to get rid of keeping track of uniform locations. It's not that cumbersome, but it would be great if I didn't have to.

T thought you are using NV hardware, since only NV currently has GL 4.3 support.

Well, I don't agree that getting uniforms' (or attributes') location is cumbersome, especially because that should be done only once, during the initialization phase.
I'm using class-wrapper for each shaders. Uniforms and attributes locations are attributes of the instance, and they are set in the Init() function (at the same place where I load and compile shaders, and link the program). After that, I just call appropriate function (method) of the particular object to set values. It cannot be easier.

Another remark: Setting attribute location is also not correct in your code, because you are wasting 4 locations.
layout(location=0) in vec4 in_vertex;
layout(location=5) in vec2 in_texture;

In the unpacked format, both vec2 and vec4 consumes just one location. In your case, layout is like follows:
location 0: | in_vertex.x | in_vertex.y | in_vertex.z | in_vertex.w |
location 1: | < empty > | < empty > | < empty > | < empty > |
location 2: | < empty > | < empty > | < empty > | < empty > |
location 3: | < empty > | < empty > | < empty > | < empty > |
location 4: | < empty > | < empty > | < empty > | < empty > |
location 5: | in_texture.s | in_texture.t | < empty > | < empty > |

As you can see, there is a lot of wasted space. So, if you don't have a particular reason to define layout and reuse it across multiple shader-objects, It would be wiser to just let compiler do it, or read specifications to see how it actually works.
Happy coding! Posted Image


I know it should be done only once, but I just have't came up with a system to do it :)
Thanks, I wasn't aware of this behaviour of the attributes, I'll fix this.

#6 Hodgman   Moderators   -  Reputation: 27585

Like
6Likes
Like

Posted 04 November 2012 - 04:18 AM

Well, I don't agree that getting uniforms' (or attributes') location is cumbersome, especially because that should be done only once, during the initialization phase.
I'm using class-wrapper for each shaders. Uniforms and attributes locations are attributes of the instance, and they are set in the Init() function (at the same place where I load and compile shaders, and link the program). After that, I just call appropriate function (method) of the particular object to set values. It cannot be easier.

It can be a lot easier -- this is one of the long-standing design faults in GL, which has only recently been addressed with UBOs and explicit uniform locations.

On SM2 and early SM3 GPUs, uniform variables (i.e. constants that can be modified by the host API) didn't actually exist in hardware; uniforms were implemented by using hard-coded literal values in the shader code, and having the host API patch/recompile the shader code with new literal values when necessary.
Given this hardware design, the "old" GL way of managing uniforms is a perfect fit -- each "instance" of a shader can have it's uinforms set to some values, and those values are a property of the "instance". Two instances can't share values, and whenever switching instances they each retain their own values that were set on them.

Late SM3 GPUs replaced this design by actually adding hardware support for uniform variables. Instead of hard-coded literals, uniforms are now offsets into a shared "uniform" register bank. Now when the API sets a shader program, it's uniforms will contain the values in the register bank, so the API must also issue many command packets instructing the GPU to first set those registers to the values that 'belong' to that program instance.
Now the API no longer matches the hardware -- a more accurate API would instead expose the idea of there being a register bank in which values can be stored, and of shader programs that do not store uniform values as properties.
Under this hardware design, if two shader programs use the same uniform layout, and require the same values, then no work needs to be done when switching programs -- however, because GL's API is mismatched, the driver is forced to do a lot of useless work (setting redundant values, or caching/checking all values to avoid this) and the user is also forced to do a lot of useless work (any values to be shared between two different 'shader instances' have to be set on both instances).
Also, if the user is able to specify the register layout, then they can greatly reduce the number of API calls by setting arrays of contiguous registers instead of each uniform individually.

If the user is given the ability to explicitly state uniform locations, and the ability to write values to the shared uniform registers (instead of writing values to shader instance) then a smart rendering engine can greatly reduce the amount of time spent in the GPU API/driver.

However, SM4/SM5 GPUs also gave us the alternative of UBO's, which give you the same idea of having "shaders without values" and a "uniform register bank", except each UBO instance is it's own "register bank" that can be used by any shaders of your choosing -- so the UBO API is superior to both the "old" method, and GL4.3's "Explicit uniform location" API (which was the model used by D3D9), and I'd recommend you use UBO's, if targeting GL3.1 and up.

On a side note -- on all other APIs, I can write tools to pre-compile both my shader code and my UBO values, so that all the shaders and uniform values for a specific scene full of objects/materials can be saved in a file, and loaded straight into memory with no parsing/compiling/processing steps, which makes the runtime code about as easy as it gets.

Edited by Hodgman, 04 November 2012 - 04:26 AM.


#7 mhagain   Crossbones+   -  Reputation: 7422

Like
2Likes
Like

Posted 05 November 2012 - 04:17 AM

a more accurate API would instead expose the idea of there being a register bank in which values can be stored, and of shader programs that do not store uniform values as properties.
Under this hardware design, if two shader programs use the same uniform layout, and require the same values, then no work needs to be done when switching programs


It's interesting to note that the older ARB assembly extensions exposed this kind of setup (in an interesting manner, with both "local" and "env" parameters), so in many respects GLSL was actually quite a step backwards from even that (having to link vertex and fragment shaders into a program object was another example).

I believe that even with explicit uniform location GLSL still doesn't expose a way to just set a uniform once and have it available to all programs, short of using UBOs.

It's a case of: unless one has been exposed to something cleaner, neater and simpler, one really doesn't get the full appreciation of just how nasty, messy and awkward the way one is currently doing stuff really is.

Edited by mhagain, 05 November 2012 - 07:46 AM.

It appears that the gentleman thought C++ was extremely difficult and he was overjoyed that the machine was absorbing it; he understood that good C++ is difficult but the best C++ is well-nigh unintelligible.


#8 Aks9   Members   -  Reputation: 769

Like
0Likes
Like

Posted 05 November 2012 - 01:20 PM

I believe that even with explicit uniform location GLSL still doesn't expose a way to just set a uniform once and have it available to all programs, short of using UBOs.

I don't see what the problem is. Uniforms are the part of the program's state. They shouldn't be visible outside of the program and their state remains until they are explicitly changed for the particular program. There is nothing wrong with that. Explicit uniform location has nothing with sharing uniforms. It has the same purpose as explicit attrib. location. If uniforms have to be shared among multiple programs that's where UBOs should be used.

#9 mhagain   Crossbones+   -  Reputation: 7422

Like
1Likes
Like

Posted 05 November 2012 - 03:05 PM

I don't see what the problem is. Uniforms are the part of the program's state. They shouldn't be visible outside of the program and their state remains until they are explicitly changed for the particular program. There is nothing wrong with that. Explicit uniform location has nothing with sharing uniforms. It has the same purpose as explicit attrib. location. If uniforms have to be shared among multiple programs that's where UBOs should be used.


Well that's more or less exactly what I said, if erring a little on the side of "the way GL does it is best because it's the way GL does it", but I'd suggest that you re-read Hodgman's post above for a description of what's wrong with it.

Now, I'm not going split hairs over which is the best approach from an API standpoint; one can easily produce test cases in which either approach can be shown to be preferable to the other and in fact my own opinion is that ARB assembly's concept of "local" and "env" parameters is close to what I'd consider ideal, and which unfortunately neither of the current high-level languages in either GL or D3D can cleanly replicate.

Of course you can write your own layer of additional boilerplate to handle all of it, but that's kinda missing the point of using an API, methinks, as it's functionality that each API should be providing.

It appears that the gentleman thought C++ was extremely difficult and he was overjoyed that the machine was absorbing it; he understood that good C++ is difficult but the best C++ is well-nigh unintelligible.


#10 phantom   Moderators   -  Reputation: 6786

Like
0Likes
Like

Posted 05 November 2012 - 06:11 PM

Now, I'm not going split hairs over which is the best approach from an API standpoint; one can easily produce test cases in which either approach can be shown to be preferable to the other and in fact my own opinion is that ARB assembly's concept of "local" and "env" parameters is close to what I'd consider ideal, and which unfortunately neither of the current high-level languages in either GL or D3D can cleanly replicate.


I'm not sure the hardware would be happy with that anyway; given that all loads basically go via a L1/L2 cache system the idea of a 'register' across shaders is moot anyway.
Given the requirements for managing data upload the idea of being able to upload one bit of memory and reuse it doesn't seem like a great idea either.

Approiately sized and split cbuffer/UBOs where you can control the size and upload frequency is probably the best fit for the current hardware and will continue to be for a little while yet.

#11 Hodgman   Moderators   -  Reputation: 27585

Like
2Likes
Like

Posted 06 November 2012 - 05:58 AM

I don't see what the problem is. Uniforms are the part of the program's state.

That's the problem. This was an accurate reflection of some pixel shader hardware in 2005, but is now not at all reflective of actual GPU hardware. In order for GL to provide you with the abstraction that uniforms are part of a program's state, the GL driver is forced to emulate this behavior, which is extremely costly. There's no need for GL to emulate the behavior of half a decade old hardware any more.

Explicit uniform location has nothing with sharing uniforms.

In D3D it can be leveraged to reduce the cost of setting uniforms. D3D9's abstractions don't tie uniform values and programs together like GL does (i.e. when setting a uniform in D3D9, the value persists in that 'slot' until it's set to another value, regardless of which program is set), which allows a graphics engine to greatly simplify the process of setting uniform values.
If the previous draw-call has set 50 3x4 bone matrices in registers #42-192, and the current draw-call (which uses a different program) requires the same array of matrices in the same registers, then the engine can detect that condition with very little effort (e.g. a single comparison) and do zero work, relying on the fact that the GPU will already contain the correct uniform values.

In GL, because you're dealing with an emulation layer instead of a valid abstraction, the program is required to set all 50 matrices on both programs regardless, and then the GL driver is forced to perform 150 vec4 vs vec4 value comparisons in order to determine whether the new uniform values are redundant or not, and whether it should send them to the GPU registers.

The UBO abstraction is exactly the same as the D3D9 abstraction, except that multiple register banks of different sizes can be exist and/or be bound at a time, instead of there being a single global register bank. e.g.The D3D9 behavior could be emulated on GL3/D3D10 by creating a single global UBO, but that wouldn't be useful ;)

For SM3 GPUs, when comparing GL2 and D3D9, D3D9 allows a rendering engine to be several orders of magnitudes more efficient when it comes to managing uniform values.
For SM4/5 GPU's, the same is true for GL2 vs GL3 with UBOs.

If uniforms have to be shared among multiple programs that's where UBOs should be used.

If you're targeting GL3 or GL4, then GL2's way of managing uniforms should be entirely discarded, and GL3's UBO's should be used in all circumstances - because the UBO abstraction actually maps to the SM4/5 GPU hardware.

Edited by Hodgman, 06 November 2012 - 06:08 AM.





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS