10
\$\begingroup\$

Does it help to declare variables outside of your main function scope in GLSL? Do these variables actually get reused and is it more efficient?

Here is the code in question:

varying vec2 vposition;
uniform float seed;
uniform float top;
uniform float bottom;
uniform float phi;
uniform float theta;
uniform float scaledPI;
uniform float yn;
uniform float ym;
uniform float rx;
uniform float ry;
uniform float radius;

const float PI = 3.141592653589793238462643383;

float left;
float right;
float mscaled;
float xn;
float xm;
void main() {
    float t = vposition.y * yn + ym;

    if(t <= 0.0 || t >= PI){
        left = phi - PI;
        right = phi + PI;
    }else{
        mscaled = scaledPI / (1 - abs(Math.cos(theta)));
        mscaled = mscaled < PI ? mscaled : PI;
        left = phi - mscaled;
        right = phi + mscaled;
    }
    xn = (left - right) / ((-rx / 2.0) - (rx / 2.0));
    xm = left - ((-rx/2.0) * xn);
    float p = vposition.x * xn + xm;

    vec3 coords = vec3( sin(p) * sin(t), cos(t), cos(p) * sin(t) );
    float nv = surface( vec4( coords, seed ) );
    gl_FragColor = vec4( vec3( nv, nv, nv ), 1.0 );
}
\$\endgroup\$
  • 3
    \$\begingroup\$ This question is confusing. GLSL does not have a main loop. Do you mean the main() function? Are your values actually global variables (uniforms or attributes in GLSL parlance) or constant values? \$\endgroup\$ – Sean Middleditch Aug 25 '13 at 1:49
  • \$\begingroup\$ Can you post some code as an example of what you're talking about? \$\endgroup\$ – Nathan Reed Aug 25 '13 at 2:09
  • \$\begingroup\$ I updated the question with code. \$\endgroup\$ – RodgerDodger Aug 25 '13 at 4:10
  • \$\begingroup\$ @user1286792: That doesn't change the fact that GLSL does not have a main loop. It's not clear what you're talking about. What exactly are you thinking will be saved by doing this? \$\endgroup\$ – Nicol Bolas Aug 25 '13 at 4:47
  • \$\begingroup\$ @NicolBolas I've updated the question to be more clear. Hopefully it is useful now for someone in the future. \$\endgroup\$ – RodgerDodger Aug 25 '13 at 14:47
32
\$\begingroup\$

I think I get what you're trying to ask. I assume your primary concern are the non-uniform variables defined outside of main():

float left;
float right;
float mscaled;
float xn;
float xm;

Let's take a look at how the GPU and GLSL work. The GPU does not have a stack or a call activation records. There is not a way to simulate scope or local variablaes in GLSL like a C compiler can do on most CPUs. All that exists are the registers, which are either uniform registers, shader stage inputs, outputs, and the local register file unique to that shader invocation.

In other words, as there is no such thing as a function or the stack or a heap, all variables declared anywhere live in a register. Whether they're local to some scope in GLSL or global to the whole file makes no difference. They're just registers.

However, the register allocator is not part of the GLSL standard. Different OpenGL implementations can have varying levels of quality when it comes to converting high-level GLSL code into the low-level machine code the GPU understands. One of the more complicated parts of a compiler (GLSL or otherwise) is register allocation. This is the part of the compiler that determines which registers a given variable occupies. C has it a bit harder as it usually has to deal with very tiny register files (especially on x86) and it has to deal with register spilling (moving variables to the stack) and aliasing (saving variables back to RAM before calling functions) and odd instructions which demand the output be in a particular register (x86's idiv for instance). GPUs have a large-ish register file on account of having no stack or heap, so the allocator can be simpler.

However, the register file is not infinite. If you have more variables than registers supported by your hardware the compiler will have to try fit all your variables in the registers. This usually requires some form of liveness range checking. That is, if you use a variable xn for one calculation then never use it again, the compiler can determine this and then know that the register occupied by xn could be used by another variable later on, thus allowing more variables than there are registers (so long as there's not too many live variables at once).

The compiler might not do this, however. It doesn't have. Or it might do it only in some cases. Scopes given simpler compilers a much easier problem to solve. All the registers allocated to local function variables can be reused after that function exits because it knows the variables are dead. Global variables have no such easy guarantee. Hence, some less capable compilers may not optimize their lifetimes as well, and the global variables will always eat up a register. This won't make anything slower but it may on some drivers limit the size of the shader you can write.

In general, I would highly recommend keeping all variables localized. Keep the definition as close to the use of the variable as makes sense. This applies to all programming languages, not just GLSL. I would also recommend making every "variable" const in every case you possible can. It can again be a hint to certain less-capable compilers that certain optimizations are possible, and more importantly, it makes your code more self-documenting and easy to maintain.

And of course, here's your obligatory "just profile to test and find out for sure" advice. Write your shader with and without your globals and profile it. Any and all performance advice online should be mistrusted and assumed to either be steeped in supposition or out of date.

\$\endgroup\$
  • \$\begingroup\$ That is exactly what I meant. You answered my question perfectly and also better explained what I was asking. \$\endgroup\$ – RodgerDodger Aug 25 '13 at 14:49
  • 1
    \$\begingroup\$ Actually sometimes declaring arrays as const instead of non-const makes the whole shader slower (A LOT slower). I noticed that problem on my GTX 460. \$\endgroup\$ – Tara Nov 2 '15 at 16:04
  • \$\begingroup\$ I just got rid of a weird error and strongly suspect it was an Adreno GPU (OpenGL ES 3.1) failing to compile a shader because variables were declared outside of main. \$\endgroup\$ – comodoro Jan 3 '18 at 19:31
  • \$\begingroup\$ One of the most thorough SO answers I've ever seen--well done! \$\endgroup\$ – duhaime Oct 17 at 23:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.