PDA

View Full Version : Best way to handle multiple shaders



padawan
03-06-2011, 08:34 PM
Say that I have multiple shaders, linked in different programs. I was wondering what is the best way to switch between them. I don't think I have to do the whole process again, starting from glCreateShader, do I?
My guess is that linked programs are in the card's memory, and the steps I have to redo each time are the ones that move my shader, or my program, from the computer's memory to the card. I'm not sure it's right though, and I don't know exactly how to do it. It would be nice to have some insight.
Thanks

Alfonse Reinheart
03-06-2011, 09:51 PM
If you have two values:



int iValue1 = 4;
int iValue2 = 6;


What is the mechanism for switching between them? You use one and not the other:



SomeFunction(iValue1);


You've used the first value and not the second.

Programs are objects. You compile and link them. Once this is done, you may use them as much as you want with glUseProgram. So if you have some rendered objects that get rendered with program1, and some rendered objects that get rendered with program2, it's pretty simple:



glUseProgram(program1);
//render stuff.
glUseProgram(program2);
//render other stuff.


The only problems you may have will come from the fact that each program object has its own uniform locations and state.

padawan
03-07-2011, 03:50 AM
And that's it? No memory concerns? I can freely call glUseProgram() without worrying about leaving programs in the card's memory? Looks simple indeed.
Well, thanks.

mhagain
03-07-2011, 04:20 AM
That's pretty much it. glUseProgram just selects which shaders are currently active, it has nothing whatsoever to do with memory usage.

V-man
03-07-2011, 07:32 AM
Shaders are small programs.
With D3D, you can compile a shader to pseudo-executable and the size with be a few 1 KB or even under a 1 KB.

GL ES 2.0 has that feature as well but I never touched it.

GL has GL_ARB_get_program_binary. The shaders are small, just like D3D. It's normal, shaders just contain a few hundred instructions. How many would you have to create to run out of space on a 512 MB GPU?

padawan
03-07-2011, 12:32 PM
GL has GL_ARB_get_program_binary. The shaders are small, just like D3D. It's normal, shaders just contain a few hundred instructions. How many would you have to create to run out of space on a 512 MB GPU?
I don't know. I honestly had the impression that shaders can get pretty complex. I was also expecting a complex application to have quite a few. Considering that memory in a graphic card is important it looked to me a good idea to save some. Guess I was wrong.

mhagain
03-07-2011, 05:03 PM
Shaders can get complex for sure, but they're still very very small programs. Say a coupla thousand line C file is about 70k. Over 2 MB of C code can compile to an executable that's a coupla hundred K in size. That's the kind of size comparison we're talking about - absolute maximum - for all shaders (not each shader). By contrast a 512x512 texture is 1MB.

Now look at the lifetime of a shader. It's created, it's used and it's destroyed. A shader is only uploaded to video RAM when initially created, and this should be a one-time only operation. Each time you use it it's just set as "active" (or whatever happens behind the scenes); the actual act of using a shader doesn't consume any extra memory so there's no need for paranoia on that count. Then when you destroy it that memory is released.

Now consider the memory-saving option. Instead of creating shaders as a one-time-only operation you instead create and destroy them as required. Your program will run slow, because creating a shader is - like creating any object - a complex and time-consuming operation. And all to save a few kilobytes.

And now consider the purpose of memory. It's a resource. To be used. And if you're not using it, it's lying idle. Doing nothing for you. So (and pardon my language here ;) ) you're not some kind of goddam hero for only using a few MB of a 1 GB card, you're actually wasting the memory that you don't use.

That's not to say that you should go berserk with memory (in which case you're definitely not some kinda goddam hero!), just that being ultra-frugal has a very low return on investment, and often at the expense of performance.

So to sum up; what applies to shaders also applies to any other object you create in VRAM. Textures, VBOs, etc. And of all of these, shaders will consume by far the least amount of memory (like I said at the start, even a single texture can overwhelm the amount of memory that shaders use). So if you're going to optimize memory usage you should be looking at textures and VBOs first, and only consider shaders if even after that you're really really tight.

And glUseProgram is really no different to glBindTexture or glBindBuffer; it just selects a currently active object. Would you have memory concerns about glBindTexture or glBindBuffer?

(OK, I didn't mean to turn that into a semi rant... :) )

padawan
03-07-2011, 11:46 PM
(OK, I didn't mean to turn that into a semi rant... :) )
It was actually a very interesting post, thank you.
You made a mistake with your last line though, because another question is coming :). I'll go a bit off topic in my own thread.

The thing is that while I was just under the impression that I had to remove shaders from memory, I was actually pretty sure that I had to remove other objects.
Looking at an array buffer, with so many vertices in a picture it must take some memory already. However I guess I always need an array buffer, or I have no image. But other buffers, and the textures... that's quite some space, isn't it? Are you saying I should leave everything in the video memory?

Alfonse Reinheart
03-07-2011, 11:55 PM
At no time should your main rendering loop involve the creation or destruction of objects (except for certain buffer object streaming cases, and even then you're just calling glBufferData or glMapBufferRange with invalidate, not glGenBuffers/glDeleteBuffers).

If you have a buffer object, then you are using it for some purpose. If you will need the contents of that buffer object next frame, then there's no purpose in deleting it. If you will need the contents of that buffer object two frames from now, again, there's no purpose. You can keep going from there.

The only time you should remove objects is when you're not going to need them for the forseeable future, a time best measured in seconds or minutes. In the context of a game, this would be when the player leaves the area where that mesh/texture is used. In a modeling-type application, you delete it when the user deletes it. And if you're dealing with a streaming world like GTA or whatever, then you shouldn't even delete the object; just upload new data to it for any new meshes/textures that become available as you move from one place to another.

padawan
03-08-2011, 01:19 AM
I see. Interesting information. Looks like creation and destruction are quite expensive operations. That makes memory management a bit more challenging.
Ok, it's clearer now. Thanks.