Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Page 1 of 2 12 LastLast
Results 1 to 10 of 11

Thread: Fps drops when passing multiplied vector to gl_FragColor

  1. #1
    Junior Member Newbie
    Join Date
    Aug 2014
    Posts
    21

    Exclamation Fps drops when passing multiplied vector to gl_FragColor

    Hey! First of all, sorry for the name of the topic, I have no idea how to call the problem I am having.

    First of, here are my shaders because there's no way you'll understand without seeing them.
    VertexShader:
    Code :
    attribute vec3 a_position; //attributes of vertex
    attribute vec3 a_normal; 
    attribute vec2 a_texCoord0;
     
    uniform mat4 u_worldTrans;
    uniform mat4 u_projViewTrans; //some uniforms like transform of model, and camera matrix
    uniform vec3 lightPos; //position of light
    varying vec3 toCameraVector; //sending a toCameraVector to fragment shader (vector that points to camera)
     
    varying vec2 v_texCoord0; //sending texCoords
    varying vec3 normal; // sending Normal of vertex
    varying vec3 toLightNormal; //sending toLightVector (vector that points to light)
     
    void main() {
        v_texCoord0 = a_texCoord0; //setting texCoords for fragment shader
     
        vec4 worldTrans = u_worldTrans * vec4(a_position, 1.0); //calculate worldTransform of vertex
     
        gl_Position = u_projViewTrans * worldTrans; //setting the position of vertex
     
        normal = (u_worldTrans * vec4(a_normal, 0.0)).xyz; //setting the normal in worldCoords
        toLightNormal = lightPos - worldTrans.xyz; // setting toLightVector 
     
        toCameraVector = (inverse(u_projViewTrans) * vec4(0.0, 0.0, 0.0, 1.0)).xyz - worldTrans.xyz; //setting toCameraVector
    }

    FragmentShader:
    Code :
    #ifdef GL_ES 
    precision mediump float; //have no idea what this does but it is needed I think
    #endif
     
    varying vec2 v_texCoord0; //getting all the info from vertexShader like texCoords, normal, and those 2 directional vectors
    varying vec3 normal;
    varying vec3 toLightNormal;
    varying vec3 toCameraVector;
     
    uniform sampler2D grass; //my textures. grass, dirt, path, flowers are than placed onto the mesh depending on the BlendMap color at corresponding pixel
    uniform sampler2D dirt;
    uniform sampler2D path;
    uniform sampler2D flowers;
    uniform sampler2D blendMap;
    uniform sampler2D pathSpec; // specular map for path texture
     
    uniform vec3 lightColour; //Colour of the light
     
    float damper = 20; // some settings for customizable specular lighting
    float reflectivity = 1;
     
    void main() {
           vec4 blendMapColour = texture(blendMap, v_texCoord0); //get the color of the blendMap at the corresponding pixel to vector
     
          float grassColour = 1 - (blendMapColour.r + blendMapColour.g + blendMapColour.b); //I want to place grass when there is black color on the BlendMap so I create float that indicates that and then I will multiply grass texture with it.
     
          vec2 texCoord = v_texCoord0 * 40; // multiply texCoords for tiling the texture
     
          vec4 grassC = texture(grass, texCoord) * grassColour; //get all the textures at the corresponding pixel and then I multiply those by a color of the blendMap, basically, if there's black color I want to place grass, if red color I want to place //dirt texture and so on. You know, if there's no red color at the pixel of the Blendmap then the dirtTex.rgba are 0 so there's  no dirt texture at all
          vec4 dirtC = texture(dirt, texCoord) * blendMapColour.r;
          vec4 pathC = texture(path, texCoord) * blendMapColour.b;
          vec4 flowersC = texture(flowers, texCoord) * blendMapColour.g;
          vec4 pathS = texture(pathSpec, texCoord) * blendMapColour.b;
     
          vec4 finalColor = grassC + dirtC + pathC + flowersC; //mix all the textures together 
     
          vec3 UniteNormal = normalize(normal); //here the diffuse lighting calculations  starts, no need to comment it I think
          vec3 UnitLightNormal = normalize(toLightNormal);
     
          float nDotl = dot(UniteNormal, UnitLightNormal);
          float brightness = max(nDotl, 0.2);
     
          vec3 diffuse = lightColour * brightness; //the diffuse lighting calculations ends
     
          if (pathC.r > 0) { //if there is path texture at the corresponding pixel, I want to calculate the specular light of it so I do that  here
          vec3 UnitCameraVector = normalize(toCameraVector);
     
          vec3 fromLightNormal = -UnitLightNormal;
     
          vec3 reflectedVector = reflect(fromLightNormal, UniteNormal);
     
          float SpecFactor = dot(reflectedVector, UnitCameraVector);
          SpecFactor = max(SpecFactor, 0.0);
     
          float Dumped = pow(SpecFactor, damper);
     
          vec3 finalSpec = Dumped * reflectivity * lightColour;
     
          gl_FragColor = vec4(diffuse, 1.0) * finalColor + vec4(finalSpec, 1.0) * pathS.r; // and now just apply the diffuse light, finalColor(which is now the path Texture basically) and specularlight onto the pixel
          } else {
          gl_FragColor = vec4(diffuse, 1.0) * finalColor; //if there is not path texture at the corresponding pixel but there's grass or whatever else, I dont do specular light.
          }
        }

    Basically, my shaders are pretty advanced(they do diffuse lighting, specular lighting, multitexturing) and I noticed quite bad performance with it. The main problem occured when I wanted to optimize it. I tried to "profile" what slows it all down, so I tried to modify everything and found out that if I pass red(vec4(1,0,0,1)) or any other color to gl_FragColor(the color of pixel), so I dont draw the lighting and textures, everything works pretty good. What a weird thing? I still do all the light and multitexturing calculations in fragment Shader, but I dont draw them and FPS are good. This means, there is not any problem in calculations, but there's problem in displaying the result. Then I played around with it little more and found out that if I just mix all the textures together(without multiplying them by color of the blendMap) and pass it onto pixel color the performance is still good. but then if I multiply the result with diffuse vec. it starts to be worse and worse.

    My question is, is this how it should work? I mean, I could understand that displaying the textures may slow down game, but as I mentioned, this doesn't..

    I really appreciate any advice. Thanks in advance!

  2. #2
    Intern Newbie
    Join Date
    Sep 2014
    Posts
    30
    Quote Originally Posted by Kalir44 View Post
    I tried to "profile" what slows it all down, so I tried to modify everything and found out that if I pass red(vec4(1,0,0,1)) or any other color to gl_FragColor(the color of pixel), so I dont draw the lighting and textures, everything works pretty good. What a weird thing?
    It's called dead code elimination. If calculations have no effect on the final output the compiler simply removes them.

  3. #3
    Junior Member Newbie
    Join Date
    Aug 2014
    Posts
    21
    Thanks for the information

    But, by to "profile" I mean, I just tried different variations of fragment Shader and then had a look at FPS I am getting. I didn't use any profiling tool.
    Last edited by Kalir44; 07-14-2015 at 04:04 AM.

  4. #4
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,411
    It doesn't matter how you measure performance.

    If a calculation has no effect upon the shaders outputs (which can include atomic counters, images, and buffer variables, as well as the shader's "out" variables), the compiler will simply remove it.

  5. #5
    Junior Member Newbie
    Join Date
    Aug 2014
    Posts
    21
    Idk what you mean. The compiler has to do all everything written in code, doesn't it? You probably mean some profile compiler that profiles your game and after that pops you which functions are expensive, but I just did normal "run" function in the IDE and tried different variations of shaderCode to see what works the best

  6. #6
    Junior Member Newbie
    Join Date
    Jun 2014
    Posts
    18
    what GClements means is, your output of the fragment shader is what you set inside gl_FragColor. After all that s what is going to be rendered for that fragment. Now when you do all your calculation and your texturing but that doesnt affect at all the final color you set in the gl_FragColor is like you are not doing anything useful. The compilers are super smart and can see that, and since doesn't contribute in any way to the final computation it just removes that code from the final exectuable. If you ever had a look to assembly code of c++ code you would be much surprised of how much stuff the compiler does and the final code might look so different. You want to do a quick test? Create an attribute in your code, maybe something like attribute vec3 a_position2; and do nothing else, after you compile the shader try to query the location of that attribute, opengl will return a -1, because It cannot find that attribute, it was not used for anything so the compiler just took it away.

  7. #7
    Senior Member OpenGL Lord
    Join Date
    May 2009
    Posts
    5,907
    Idk what you mean. The compiler has to do all everything written in code, doesn't it?
    No, it does not.

    If you have this code (in C):

    Code :
    int Foo(int x, int y) {return x + y;}

    All the outside world knows about this function is that it adds x and y. If you changed the code to this:

    Code :
    int Foo2(int x, int y)
    {
      int temp = x * y;
      float temp2 = (float)(temp * temp);
      double temp3 = temp2 + temp;
      return x + y;
    }

    Could anyone in the outside world notice the change? No. All of the changes are local, and nothing outside of this function can get at any of the local variables. Therefore, the difference is purely academic to the caller of the function.

    So if you're writing an optimizing compiler, it is perfectly legal for your compiler to detect that `temp3` is not used, and thus cull out the expression that generates it. Then, you detect that `temp2` is not used, so you cull out that expression. And then you detect that `temp` is not used, so you cull it out. Thus, you have reduced `Foo2` to `Foo`.

    Your optimizing compiler has done its job by making this code faster. And this is just as true of GLSL as C.

    The only difference with GLSL is that the "return value" of a shader instantiation are the shader stage output variables. The principle is the same: any expressions which do not affect the generation of output variables will be removed by the compiler.

  8. #8
    Junior Member Newbie
    Join Date
    Aug 2014
    Posts
    21
    Oh I get it now. After all it seems that sampling more than 1 texture causes the slowdowns. Or, to be honest sampling the BlendMap texture causes the biggest slow downs. there's probably something wrong with the image, or it's just too big(1024 x 1024px).

    Thank you all!

  9. #9
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,411
    Quote Originally Posted by Kalir44 View Post
    there's probably something wrong with the image, or it's just too big(1024 x 1024px).
    Ensure that all of the textures are mipmapped (have all mipmap levels and use a minification filter with mipmapping)

    Minifying a texture without mipmapping can significantly increase texture bandwidth.

    To gauge the effect texture bandwidth has on performance, try varying the level-of-detail (LoD) bias for the textures (with glTexParameter(GL_TEXTURE_LOD_BIAS), or with the bias parameter to texture() in the fragment shader). If performance varies significantly with bias, texture bandwidth is a limiting factor; consider reducing the resolution or the bit depth or using a compressed format.

  10. #10
    Junior Member Newbie
    Join Date
    Aug 2014
    Posts
    21
    All the images already had mipmapping applied. Now I just applied the mipmaps onto the BlendMap texture and I also reduced the bit depth of all images, but the performance is pretty much the same. It improved the FPS a little bit, though. Anyway I am getting 2000 FPS while looking at it from big distance, closer I am, worse it is. but generally I get 1000 - 1700 FPS while I look at it from close distance. These aren't good results, are they? Because what I am rendering is a terrain(splitted into chunks), I think adding some buildings, character, skybox, NPCs would destroy it completly because 1000 - 1700 FPS while rendering just terrain is not quite good I think. Testing it on mid-end computer.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •