Bind sampler as uniform to all shaders

Started by
7 comments, last by Juliean 10 years, 5 months ago

Hello,

I've recently started to implemented the OpenGL4-renderer for my game engine. I've been using DirectX9 and 11 so far, and I've been used to binding textures/samplers globally to the device, and share them between shaders. Now it happens to be in my design that the texture bind commands are executed before actually binding the shader (that would be a bit more to explain, lets just say that for a good reason). Now in OpenGL this is a problem, since from what I understand I'd have to bind the shader program in order to set the sampler to the correct uniform location:

In my render queue, under normal circumstances these two command blocks


glUseProgram(shader);

....

glActiveTexture(GL_TEXTURE0 + slot);
glBindTexture(GL_TEXTURE_2D, m_texture);
glUniform1i(slot, slot); // I'm already requiring the samplers to be at the first uniform locations not to make things even more complicated -.-

would be executed in reverse order, so the sampler would be bound to the wrong shader program. I could of course safe the currently bound shader and textures, and whenever a shader is switched bind them again, but this appears rather dirty and unnatural and would require a few precautions on my side. Is there any native way to avoid this? I've read about uniform buffers, but they seem not to work with samplers (thats just great), any other ideas?

Advertisement
In my understanding the glUniform1i call doesn't have to happen every time you bind a texture. I would do all the glUniform1i calls after loading the program, then never again. You only need to call it once to tell the program which texture image unit each sampler uses. After you've done that all you need to do is bind textures to the right texture image units.

+1 Samith, there is no need to constantly set the uniform value unless the texture is being switched to another texture unit. The binding can happen once at program creation..

compile/link the shader

call glUseProgram(...)

get the uniform location for the tex unit

set the uniform.

when you want to use the texture call glActiveTexture(...) then glBindTexture(...).

This is what you normally would do. You can bind the texture objects to the texture units before the shaders are compiled, glUsed, etc ...and that shouldnt be affected by how you load the shaders and get the uniformlocations(later).

Ah thanks all, thats certainly good to know, that in fact makes things very easy again.

Since on the topic, does this work the same for e.g. uniform buffer objects, and such?

EDIT: Also, is there a function for enumerating the number of samplers a shader program has? I already require a certain layout for my uniforms in order to apply to my API-independant interfaces, so I I could say


size_t numSampler = glGetNumSampler(program); // any equivalent to this call?
for(size_t i = 0; i < numSampler; i++)
{
      glUniform1i(i, i);
}

that would make things preferably easy.

Ah thanks all, thats certainly good to know, that in fact makes things very easy again.

Since on the topic, does this work the same for e.g. uniform buffer objects, and such?

EDIT: Also, is there a function for enumerating the number of samplers a shader program has? I already require a certain layout for my uniforms in order to apply to my API-independant interfaces, so I I could say


size_t numSampler = glGetNumSampler(program); // any equivalent to this call?
for(size_t i = 0; i < numSampler; i++)
{
      glUniform1i(i, i);
}
that would make things preferably easy.

With uniform buffer objects you set their bind point by calling glUniformBlockBinding, which can be done at program creation time along with the glUniform1i calls that you make to set up sampler bindings.

As for a glGetNumSamplers function: no such function exists that I am aware of. You just have to iterate through all the uniforms using glGetProgram with GL_ACTIVE_UNIFORMS to get the number of uniforms and then using glGetActiveUniform for each uniform to get its type. If the type is a sampler type (GL_SAMPLER_2D, GL_SAMPLER_3D, etc) then you know it's a sampler and you can set up its bind point with glUniform.
With uniform buffer objects you set their bind point by calling glUniformBlockBinding, which can be done at program creation time along with the glUniform1i calls that you make to set up sampler bindings.

You can't put samplers into a uniform block - see the section on "opaque types" in the GLSL spec.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

With uniform buffer objects you set their bind point by calling glUniformBlockBinding, which can be done at program creation time along with the glUniform1i calls that you make to set up sampler bindings.

You can't put samplers into a uniform block - see the section on "opaque types" in the GLSL spec.

?? I didn't say you could put samplers inside a uniform block. Maybe I didn't write that post clearly. I was only trying to say that the binding for a uniform buffer object could be set up at program creation time by using glUniformBlockBinding.


With uniform buffer objects you set their bind point by calling glUniformBlockBinding, which can be done at program creation time along with the glUniform1i calls that you make to set up sampler bindings.

Sweet, now that is for much less "Y u force me to rewrite high level abstraction OpenGL???"-than I thought I had before.


As for a glGetNumSamplers function: no such function exists that I am aware of. You just have to iterate through all the uniforms using glGetProgram with GL_ACTIVE_UNIFORMS to get the number of uniforms and then using glGetActiveUniform for each uniform to get its type. If the type is a sampler type (GL_SAMPLER_2D, GL_SAMPLER_3D, etc) then you know it's a sampler and you can set up its bind point with glUniform.

Well, that already helps - I've just implemented my own meta-language for shader, and therefore all uniforms I create are quaranted to be SAMPLER anyway, since I'm using uniform blocks due to my design for setting all other data anyway - having glGetProgram and glGetActiveUniform should do the job, thanks again.

@mhagain:

I also think you may have misread his post, at least I did get that he wanted to say how to bind the uniform blocks and not misinform me about being able to bind samplers to it... Thanks for the hint about opague types though, I still have so much fundamental stuff to understand about OGL.

This topic is closed to new replies.

Advertisement