Cost of re-uploading same value into uniform?

Changing uniforms is costly, so I use vertex attributes whenever I can (pseudo instancing).
However, I can’t fit everything into attribs, so I have to use some uniforms too.
I try to bind frequently changing values to attribs, and the remainder to uniforms.
Problem is, I can’t really tell if a value for a uniform has changed, unless I put in some extra code to do just that, so I re-upload the uniforms all the time.

Question is: is the driver smart enough to realize that I’m about to bind the same value, and just ignore it? Or should I check this myself?

How about the Cg library, is that any more efficient in this regard?

Problem is, I can’t really tell if a value for a uniform has changed, unless I put in some extra code to do just that, so I re-upload the uniforms all the time.

Sounds like your code is poorly structured. It should be easy to determine this.

Question is: is the driver smart enough to realize that I’m about to bind the same value, and just ignore it?
You tell me: do you want your applications performance to rely on what the driver may do, or do you want it to be under your control?

It’s not poorly structured, I just try to avoid adding extra features if they are not necessary.

I don’t see how you could do it without having extra management code and data. Basically you’d have to keep a copy of all your uniforms in a map or in a large array, and check every time you change it…

I can do it, but it’s annoying, and seems like something that someone else (the driver) should do. And yeah, I already depend on the driver for rendering pretty triangles, or do you suggest writing my own driver? :wink: So I’d rather not do it if I don’t have to.

And if someone could assure me that Cg does this for me, then I won’t have to depend on the driver either.

I don’t see how you could do it without having extra management code and data. Basically you’d have to keep a copy of all your uniforms in a map or in a large array, and check every time you change it…
In a proper abstraction, you shouldn’t be touching OpenGL from most code anyway. You should have some Uniform object that manages your interface to uniforms; it is then up to that object to know when data has been changed and to update the GL uniform internally.

And yeah, I already depend on the driver for rendering pretty triangles, or do you suggest writing my own driver?
Yes, but that’s because the specification says that it does. The spec says nothing about how the driver will internally upload uniform data, so you should not rely on specific behavior.

And if someone could assure me that Cg does this for me, then I won’t have to depend on the driver either.
Cg isn’t supported by OpenGL*; it’s something that sits on top of GL. So it simply makes the GL calls for you, and it does them in accord with nVidia driver wants and needs. As such, it would be of no guaranteed performance value on ATi cards.

Yes, but that’s because the specification says that it does.
Does the spec say anything about how fast/efficient it is? No.

Cg isn’t supported by OpenGL*; it’s something that sits on top of GL. So it simply makes the GL calls for you, and it does them in accord with nVidia driver wants and needs. As such, it would be of no guaranteed performance value on ATi cards.
Exactly, it just makes the OpenGL calls for me, and that’s exactly why it will work on ATi, Intel, etc… And if it checks the uniform before uploading then I don’t have to do it.

i check if the values are changed if so i update the uniform else i return
its not to difficult

eg

struct UniformInfo
{
string uniform_name;

int		uniform_index;
int		uniform_location;
GLuint	uniform_type;		// GL_FLOAT_MAT4, GL_SAMPLER_2D, GL_INT_VEC4 ...
int		uniform_size;		// number of components eg MAT4 == 16, VEC4 == 4, SAMPLER_3D == 1
int		uniform_base_type;	// either GL_FLOAT or GL_INE

bool	is_constant;


theres no difference with unioforms as with eg textures, checking to see if the current bound ID is the same as the new one, if it is dont rebind it
sure theres a bit of work but it is quicker (ive tested)

The problem with this is that let’s say I’m using the same shader in different places (eg. my font shader). Now I have to share this UniformInfo object between all of them (they could even be in separate DLLs!), otherwise the UniformInfo object will think that it’s unchanged, when in fact it is…

Does the spec say anything about how fast/efficient it is? No.
You’re relying on driver behavior in this case because you have no choice. You can’t write a driver (or, at least, not one that’s going to beat the IHV one in performance), so there’s no point in debating what performance you’re getting out of it.

You have a choice about uniform protection.

Exactly, it just makes the OpenGL calls for me, and that’s exactly why it will work on ATi, Intel, etc…
Work? Yes. Work well? There’s no guarantees on that.

Remember: the shader code that Cg generates is optimized for nVidia hardware; that’s how nVidia writes it. So, while you may not be using uniforms improperly, you certainly stand a pretty good chance of losing performance on non-nVidia hardware.

The problem with this is that let’s say I’m using the same shader in different places (eg. my font shader). Now I have to share this UniformInfo object between all of them (they could even be in separate DLLs!), otherwise the UniformInfo object will think that it’s unchanged, when in fact it is…
Hence the poorly-structured code.

Your main code shouldn’t be thinking in terms of low-level constructs like “shaders”, let alone uniforms within them. They should be dealing with objects that make sense to them. If you change a font’s color, you should change the font object’s color. The fact that this will, behind the scenes, affect some kind of uniform within a shader is totally irrelevant.

Plus, uniforms (or rather, uniform blocks) are bound to the shader that they are used in. As such, they belong with that shader. Conceptually, you should be able to say, “shader->GetUniformBlock()->SetValue()”. The uniform data is an intrinsic part of the shader.

“Plus, uniforms (or rather, uniform blocks) are bound to the shader that they are used in”

Yes, you should be able to do this

class MyShader
{
   int  JustAUniform;
   bool  JustAUniformUploaded?;

   void BindThisShader();
}

void MyShader::BindThisShader()
{
    //You need to bind the shader so that you
    //can use it to render something

    if(alreadyBound? == no)
    {
        alreadyBound=yes;
        glUseProgram();
    }

    if(JustAUniformUploaded? == no)
    {
        JustAUniformUploaded=yes;
        glUniform(JustAUniform);
    }
}

so you avoid bind the same shader.
You avoid uploading an unchanged uniform.
Even if you change a unform, you make no GL calls.
You only upload the uniform when it’s time to use the shader.

Hence the poorly-structured code.

Your main code shouldn’t be thinking in terms of low-level constructs like “shaders”, let alone uniforms within them. They should be dealing with objects that make sense to them. If you change a font’s color, you should change the font object’s color. The fact that this will, behind the scenes, affect some kind of uniform within a shader is totally irrelevant.
Actually, I do have a font object, and I do change the object’s color, not directly the uniform, but in the end, someone, somewhere, will have to go low level and set that uniform, right? And if I have multiple font objects, because one of them prints in red and the other prints in green somewhere else, but they share the same shader, then what do you do? Where do you put the checking? You can’t put it in your font object, you have to put it in the shader, because that’s shared.

And of course, I could do that, but again, I was not asking how to solve this myself, I know how to program too! :wink: But that’s extra complexity, that I would rather avoid.

If you think that it’s impossible to avoid extra code on my side, then just say that.

If you think that it’s impossible to avoid extra code on my side, then just say that.
I think that if this is something that you consider key for performance, then you should not leave it to the driver.

I think that if this is something that you consider key for performance, then you should not leave it to the driver.
Fair enough. But I’d still love to hear about Cg, because if it does this for me, then it will work equally well on every HW/driver combo.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.