I started playing with shaders in earnest a few days ago, and I find that they're actually pretty nifty, so I'm working on improving the shader API in minisphere 3.1. But I'm having issues understanding how OpenGL handles them, particularly this issue below:
It seems the GL API only allows you to set uniforms on the active shader program set by glUseProgram(), so could someone familiar with GL tell me (FJ maybe?), are the values you set for uniforms lost when you change programs, or are they in fact saved as part of the state of the shader program itself? I can't find anything about this in the OpenGL docs.
The reason I ask is that I'm trying to figure out the best way to set up the shader API for minisphere 3.1, and whether it makes more sense to have the uniform setting methods on the Group object vs. the ShaderProgram itself. I'm leaning towards the former but if OpenGL only tracks uniforms for the active shader, that requires me to cache the values.
Yes, the uniforms must be set for the new shader on every program change. This is why I chose to make groups the basic division in Galileo, to avoid switching shaders as much as possible.
However, it is MUCH more expensive to activate or deactivate a uniform name than it is to set the value of a uniform, and which uniforms are active supposedly remain valid across shaders (although I had mixed success with this working in reality).
NVidia cards, however, react poorly when you tell them which names/locations to use for each uniform, since many of their optimizations are related to the driver always choosing which location to use, and it's just sort of random chance if two different shaders will use the same location for the same uniform. AMD cards don't care, you can tell them and it will be similar in performance to asking with glGetUniformLocation. Of course, explicitly setting the location might still fail anyway :/
I remember Apple's docs actually being the most useful for shader info, so you may want to check their docs on these things, too. The official OpenGL docs are not really very good for anything but wondering which order a function's arguments are in, and which enum values are valid for which call.
Long story short: If you're worried about performance, and you don't want to muck about with different setups for different card types, the best is to check which uniform names/locations were used in the old shader but not the new one, deactivate those, then check which uniform location/names are needed in the new shader but not in the old shader, and activate those. Then, set each uniform whenever you change shaders.