8
votes

For example, if I use vertex shader like the following:

#version 400 core

uniform mat4 projM;
uniform mat4 viewM;
uniform mat4 modelM;

in vec4 in_Position;

out vec4 pass_position_model;

void main(void) {
    gl_Position = projM * viewM * modelM * in_Position;
    pass_position_model = modelM * in_Position;
}

Will it do projM * viewM * modelM matrix multiplication for each vertex, or it it smart enough to calculate if once and do not recalculate until uniform variables are changed? If it isn't "smart enough", then is there a way to optimize it other than computing all uniform-dependent values on CPU and send them as uniform variables to GPU?
Also I'm interested in solutions that can be ported to OpenGL ES 2.0 later without problems.

4

4 Answers

10
votes

So there is no general answer, as I understand. I did some tests on my hardware, though. I have 2 GPUs in my inventory, Intel HD Graphics 3000 and NVidia GeForce GT 555M. I tested my program (the program itself is written in java/scala) with matrix multiplication in vertex shader, and then moved multiplication to the CPU program and tested again.

(sphereN - it's a continuously rotating sphere with 2*N^2 quads, drawn with glDrawElements(GL_QUADS,...) with 1 texture and without any lighting/other effects)

matrix multiplication in vertex shader:

intel:
    sphere400: 57.17552887364208 fps
    sphere40: 128.1394156842645 fps
nvidia:
    sphere400: 134.9527665317139 fps
    sphere40: 242.0135527589545 fps

matrix multiplication on cpu:

intel:
    sphere400: 57.37234652897303 fps
    sphere40: 128.2051282051282 fps
nvidia:
    sphere400: 142.28799089356858 fps
    sphere40: 247.1576866040534 fps

Tests show that multiplicating (uniform) matrices in vertex shader is bad idea, at least on this hardware. So in general one may not rely on corresponding GLSL compiler optimization.

3
votes

Will it do projM * viewM * modelM matrix multiplication for each vertex, or it it smart enough to calculate if once and do not recalculate until uniform variables are changed?

Ask the developer of the OpenGL implementation in question. The OpenGL specification has nothing to say about this, but driver and GLSL compiler writers may have implemented optimizations for this.

If it isn't "smart enough", then is there a way to optimize it other than computing all uniform-dependent values on CPU and send them as uniform variables to GPU?

No. You have to do the legwork yourself.

1
votes

All OpenGL and GLSL optimizations are vendor specific. It is quite hard to tell what is the final output from the glsl compiler.

You can look here for vendor specific information: http://renderingpipeline.com/graphics-literature/low-level-gpu-documentation/

For your code you can always 'pack' matrices into new uniform: matModelViewProjection, multiply it in the application and send it to the vertex shader.

0
votes

That depends entirely on the driver. OpenGL is a specification, if you pay them for the rights to make an implimentation they'll give you a sample implimentation to use, but that's it.

Aside from that you need to consider matrix multiplications restrictions, doing projM * viewM * modelM * vertex is not the same as doing vertex * projM * viewM * modelM. That's because matrices are multiplyed right to left, and the order does matter with that. So the shader could'nt pre-computed projM * viewM * modelM to share between vertices, because that would give you bogus results.