Hey all,
I have this project, that has a default shader, that just draws models and textures. Recently I decided to add a second shader that does a fancy effect, and is used only on some of the objects drawn.After compiling the project for Linux or Windows, it all works as expected. When compiling the project to Android, only on specific devices, the new shader doesn't work, while on other devices I tried, it all works.
My shadersBelow is my default vertex shader specifically made for Android devices, this one works on all devices and draws everything without any editing or effect. As far as I understand, the fragment shaders work, so I'll omit them.
#version 310 es in vec4 position; in vec3 colour; in vec2 texCoord; uniform mat4 matrix; uniform mat4 matrixProjection; out vec2 outTexCoord; out vec4 outColour; void main() { gl_Position = matrixProjection *matrix *position; outTexCoord = texCoord; outColour = vec4(colour.rgb, 1); }
#version 310 es in vec4 position; in vec3 colour; in vec2 texCoord; uniform mat4 matrix; uniform mat4 matrixProjection; uniform float animationCurrent; out vec2 outTexCoord; out vec4 outColour; void main() { vec4 pos = matrixProjection *matrix *position; if (animationCurrent > 0.0) { pos.y += 5.0; } gl_Position = pos; outColour = vec4(colour.rgb, 1.0); outTexCoord = texCoord; }
What I've triedFrom the new shader, if I remove the entire `if` statement, it all works and it displays objects as-is. If I replace the `if` statement with `if (true)` it still works, but it just displays all vertices of objects drawn with it slightly higher. If I replace it with `if (false)` it still works as expected and draws the object without any transformations or effects.So for some reason, just referencing `animationCurrent` causes the object to not be drawn.I also tried replacing the `if` statement with `if (matrix[0][0] > 0.0)` and it still draws the object, it looks like there's something specifically wrong with `animationCurrent`. I tried adding another matrix uniform variable, and set its value the same way as I do `matrix`, but it would give me weird (undefined?) results.It seems that the value of `animationCurrent` is not relevant.
I've also checked the values of `glGetShaderInfoLog` and `glGetProgramInfoLog` but got nothing.
HardwareThe problem occurs on an android phone with this hardware: Device: Moto E (4) Plus - 7.1.1 Vendor graphic card: ARM Renderer: Mali-T720 Version OpenGL: OpenGL ES 3.1 v1.r12p1-01alp0.62f282720426ab7712f1c6b996a6dc82 Version GLSL: OpenGL ES GLSL ES 3.10The problem also occurs on this android tablet with similar hardware: Device: Kindle Fire 8 Vendor graphic card: ARM Renderer: Mali-T720 Version GL: OpenGL ES 3.1 v1.r26p0-01rel0.526d936ea9da20486773a9aaceecd920 Version GLSL: OpenGL ES GLSL ES 3.10This is an android tablet where the problem does not occur: Device: Lenovo TB-X505F - 10 Vendor graphic card: Qualcomm Renderer: Adreno (TM) 504 Version GL: OpenGL ES 3.2 V@415.0 (GIT@f345350, I0760943699, 1580221225) (Date:01/28/20) Version GLSL: OpenGL ES GLSL ES 3.20And this is a slightly older device where the problem does not occur either. I've modified the shader a bit to support an older glsl version, but the idea is the same: Device: Kindle Fire 7 Vendor graphic card: ARM Renderer: Mali-450 MP Version GL: OpenGL ES 2.0 Version GLSL: OpenGL ES GLSL ES 1.00
QuestionMy primary goal, is to understand what is causing this. Have I missed something very obvious? Is this a very edge-case bug related to the hardware?I'm still learning how to support different devices with different versions of glsl, so it's very likely I've missed something.Any information you have, let me know. I'm willing to try a few things on different devices to find more about this issue.
Hi! How are you setting the value of the uniform 'animationCurrent'? I would recommend using RenderDoc to see if the value is passed to the shader correctly.Another option would be to do the if statement before launching the shader and pass something like 'deltaY' (which will be equal to 0, if the statement is false). It is a common practice to avoid conditions and loops in shaders, when it's possible.
Check you are binding the data to the correct uniform locations - if you are making any assumptions about binding location rather than querying it at runtime that may cause problems (location order depends on compiler optimizations).
I'm currently getting the uniform locations and set their values every time an object is drawn. Here is my code for it:
glUseProgram(newProgram); GLuint MatrixID2 = glGetUniformLocation(newProgram, "matrixProjection"); glUniformMatrix4fv(MatrixID2, 1, GL_FALSE, (float *)&matPerspective); GLuint MatrixID = glGetUniformLocation(newProgram, "matrix"); glUniformMatrix4fv(MatrixID , 1, GL_FALSE, (float *)dd_matrix_globalGet()); GLuint animLoc = glGetUniformLocation(newProgram, "animationCurrent"); glUniform1f(animLoc, m->animationCurrent); /* draw object code */ glUniform1f(animLoc, 40); glUseProgram(defaultProgram);
I'm aware this is not optimal for performance, but it's my temporary implementation until this issue is solved.
Pavel Rudko said:I would recommend using RenderDoc to see if the value is passed to the shader correctly.
I took a look at `RenderDoc`, and it looks interesting. I'll give it a go sometime today and post an update here.
Pavel Rudko said:Another option would be to do the if statement before launching the shader and pass something like 'deltaY' (which will be equal to 0, if the statement is false). It is a common practice to avoid conditions and loops in shaders, when it's possible.
Avoiding loops sounds like excellent advice. Unfortunately in this case it still didn't work. I tried replacing the whole `if` statement with `pos.y += animationCurrent;`. I tested this on 2 of the devices mentioned above, one where the issue appears, and one where it doesn't, and the issue still appears on the one device (Moto E (4) Plus - 7.1.1) and objects drawn with that shader don't appear at all.
For the sake of completeness, if I comment out the line `pos.y += animationCurrent;`, the shader draws the object without any effects on both devices (as expected).
Hi Pavel Rudko,
I've taken a look at RenderDoc, created a capture, and by looking at it, I can see the values being passed correctly. I modified my project to only draw 3 objects with the new shader. I correctly saw in the "Event Browser" 3 calls to `glDrawArrays`, and on each of them I could see all the calls to set values to the uniforms, including for the variable `animationCurrent` which causes the issue. I can see its value being set properly through the "API Inspector", but I can't tell if that's the value I sent from OpenGL, or if that's the value the shader receives.
Upon looking online, RenderDoc doesn't support debugging OpenGL shaders (based on https://renderdoc.org/docs/how/how_debug_shader.html). I'm not sure how to proceed further.
Pavel Rudko said:How are you setting the value of the uniform 'animationCurrent'?
Apologies I missed that on my previous reply. I set the value of `animationCurrent` the same way I do for `matrix` and `matrixProjection`, but by using `glUniform1f`. Here is the code:
glUseProgram(newProgram); GLuint MatrixID2 = glGetUniformLocation(newProgram, "matrixProjection"); glUniformMatrix4fv(MatrixID2, 1, GL_FALSE, (float *)&matPerspective); GLuint MatrixID = glGetUniformLocation(newProgram, "matrix"); glUniformMatrix4fv(MatrixID , 1, GL_FALSE, (float *)dd_matrix_globalGet()); GLuint animLoc = glGetUniformLocation(newProgram, "animationCurrent"); glUniform1f(animLoc, m->animationCurrent); /* * draw object code, by setting up and using `glDrawArrays` */ glUniform1f(animLoc, 40); glUseProgram(defaultProgram);
I've just found what the problem is, and the workaround for it.On those specific devices, it seems that declaring the uniforms in a specific order matters. I'm not sure if that's a bug with `Mali-T720` (since both devices use it) or with GLSL 3.10, as I don't have enough devices to test this.My solution was changing from this:
uniform mat4 matrix; uniform mat4 matrixProjection; uniform float animationCurrent;
uniform float animationCurrent; uniform mat4 matrix; uniform mat4 matrixProjection;
Thanks everyone for the answers.
The attribute order can definitely change between program variants - are you querying the location separately for each linked binary?If you are, then it smells like a bug in the driver.
Peter Harris said:are you querying the location separately for each linked binary?
By "linked binary" are you referring to the programs? If so, yes I'm getting the location of uniforms separately for each program I'm using and not assuming they share the same location.
Peter Harris said:If you are, then it smells like a bug in the driver.
From the beginning this felt like a weird issue. I wouldn't be surprised if it was indeed a bug in the driver, although the devices I'm using are not *that* new, so I assumed if it was a driver bug, more people would have encountered it.