Forums - non constant indexing not supported in Adreno vertex shaders

8 posts / 0 new
Last post
non constant indexing not supported in Adreno vertex shaders
Maykin53
Join Date: 20 Jul 14
Posts: 10
Posted: Sun, 2014-07-20 20:50

Hi.

It looks like the Adreno 330 driver for Google Nexus 5 does not correctly support non constant indexing of uniform arrays in a vertex shader.
Below is an example - my Java code generates part of the vertex shader source like this:
 

String vertexSource

"#version 300 es\n\n"
+"#define ENTITY_COUNT "+meshEntitiesPerDraw+"\n"

+"const int c_zero_int = 0;\n"
+"const int c_one_int = 1;\n"
+"const int c_two_int = 2;\n"
+"const float c_zero = 0.0;\n"
+"const float c_one = 1.0;\n"
+"uniform mat4 viewMatrix;\n"
+"uniform vec4 miscData;\n"
+"uniform mat4 modelMatrixList[ENTITY_COUNT];\n";
+"uniform vec4 lightDiffuseList[ENTITY_COUNT];\n";
+"uniform vec4 lightSpecularList[ENTITY_COUNT];\n";
+"uniform vec4 lightDirectionList[ENTITY_COUNT];\n";
+"uniform vec4 lightLocationList[ENTITY_COUNT];\n";
 

... some other stuff here ...
+" int instanceID = gl_InstanceID;\n"
... some other stuff here ...

+" diffuse = lightDiffuseList[instanceID];\n"
+" specular = lightSpecularList[instanceID];\n"
+" directionUniform = lightDirectionList[instanceID];\n"
+" locationUniform = lightLocationList[instanceID];\n"

... some other stuff here ...

This works fine on all modern Android devices I've tested with except for those running Adreno.
For those running Adreno (such as Nexus 5), my lighting ends up with unpredictable results.
Note '
meshEntitiesPerDraw' is equal to 20 on Nexus 5 (obtained by dividng GL_MAX_VERTEX_UNIFORM_COMPONENTS based on the unform arrays).

However, if I change the last bit of quoted code to:

for(int x=0; x<20; x++)
{
vertexSource=vertexSource
+"if(instanceID=="+x+")\n"
+"{\n"
+" diffuse = lightDiffuseList["+x+"];\n"
+" specular = lightSpecularList["+x+"];\n"
+" directionUniform = lightDirectionList["+x+"];\n"
+" locationUniform = lightLocationList["+x+"];\n"
+"}\n";
}

It works fine.
This means when I'm attempting to access the uniform arrays using an integer variable (obtained from gl_InstanceID) I'm getting strange results, but when I access the arrays using a constant integer (using an if statement on the instanceID) it works fine.

Does Adreno support uniform array indexing using non-constants?
According to the OpenGL ES 3.0 spec, vertex shaders should support not constant indexing of uniform arrays.

Note also that if I decrease meshEntitiesPerDraw to 11 (instead of 20), it works fine as well. This is odd because with a value of 20 I should still have plenty of spare uniforms left over.

  • Up0
  • Down0
mhfeldma Moderator
Join Date: 29 Nov 12
Posts: 310
Posted: Mon, 2014-07-21 09:14

At first glance, the accessing of the uniform arrays using an integer variable should work as you have coded them.

1) Is it possible the problem lies with gl_InstanceID? - can you set the integer variable by using another value

2) Would it be possible to provide the exact shader code - Are you able to share apks with both techniques of accessing the arrays?

3) Could you provide a few more of the Adreno devices that you have tried (are they all usingAdreno 330)?

thanks

 

 

  • Up0
  • Down0
Maykin53
Join Date: 20 Jul 14
Posts: 10
Posted: Mon, 2014-07-21 17:58

I changed to

instanceID = 0;

and it worked.
I also changed to

instanceID = int(inPosition.x*0.0)

and it worked.

I then changed it to

instanceID = int(inPosition.x*0.0)+gl_InstanceID

and got the wrong lighting (same as just using gl_InstanceID).

I then changed it to

instanceID = int(inPosition.x*0.0)*gl_InstanceID

and got the wrong lighting - but different results to just using gl_InstanceID.

I've attached screen shots of all 3 scenarios (using gl_InstanceID, using a constant or inPosition.x*0.0, and the *gl_InstanceID).
The shader source is below.

Vertex shader:
 

#version 300 es
 #define ENTITY_COUNT 30
const int c_zero_int = 0;
const int c_one_int = 1;
const int c_two_int = 2;
const float c_zero = 0.0;
const float c_one = 1.0;
uniform mat4 viewMatrix;
uniform vec4 miscData;
uniform mat4 modelMatrixList[ENTITY_COUNT];
uniform vec4 lightDiffuseList0[ENTITY_COUNT];
uniform vec4 lightSpecularList0[ENTITY_COUNT];
uniform vec4 lightDirectionList0[ENTITY_COUNT];
uniform vec4 lightLocationList0[ENTITY_COUNT];
 
in vec3 inPosition;
in vec3 inNormal;
in vec3 inUv;
out vec4 passVarA;
out vec4 passVarB;
 
void main(void)
{
  int instanceID = gl_InstanceID;
mat4 modelMatrix = modelMatrixList[instanceID];
  vec4 tempVertexPosition = modelMatrix * vec4(inPosition, c_one);
  vec3 vertexPosition = tempVertexPosition.xyz;
mat4 normalMatrix = transpose(inverse(modelMatrix));
vec3 normal = normalize(mat3(normalMatrix)*inNormal);
gl_Position = viewMatrix * tempVertexPosition;
 
float textureShine = inUv.z;
passVarA = vec4(inUv.xy, c_zero, textureShine);
  vec3 eyeVector = miscData.xyz-vertexPosition;
float lightCount = c_zero;
vec3 lightColor = vec3(c_zero, c_zero, c_zero);
 
int lightType;
float intensity;
vec3 direction;
vec3 halfVector;
float dotNormalHalfVector;
vec3 aux;
vec3 lightDirection;
float lightDistance;
float dotNormalLight;
vec4 diffuse;
vec4 specular;
vec4 directionUniform;
vec4 locationUniform;
float spotEffect;
if(textureShine>c_zero)
{
diffuse = lightDiffuseList0[instanceID];
specular = lightSpecularList0[instanceID];
directionUniform = lightDirectionList0[instanceID];
locationUniform = lightLocationList0[instanceID];
lightType = int(diffuse.w);
direction = -directionUniform.xyz;
intensity = dot(normal, direction);
if(intensity>c_zero)
{
lightCount = lightCount+c_one;
lightColor = lightColor+(diffuse.rgb*intensity);
if(specular.w>c_zero)
{
halfVector = normalize(eyeVector-direction);
dotNormalHalfVector = max(dot(normal, halfVector), c_zero);
lightColor = lightColor+(specular.rgb*(dotNormalHalfVector*(textureShine*specular.w)));
}
}
}
 
if(lightCount>c_zero)
{
passVarB = vec4(lightColor.r/lightCount, lightColor.g/lightCount, lightColor.b/lightCount, lightCount);
}
else
{
passVarB = vec4(c_zero, c_zero, c_zero, lightCount);
}
}
Fragment shader:

#version 300 es
 const int c_zero_int = 0;
const int c_one_int = 1;
 const float c_zero = 0.0;
const float c_one = 1.0;
const float c_invisible = 0.0005;
uniform sampler2D tex[16];
uniform vec4 ambientData;
in vec4 passVarA;
in vec4 passVarB;
 out vec4 outColor;
 void main(void)
{
vec4 texel = texture(tex[c_zero_int], passVarA.xy);
if(texel.a<c_invisible)
{
  discard;
}
if(int(round(ambientData.a))==c_one_int && passVarA.w>c_zero)
{
texel = vec4(texel.rgb*ambientData.rgb, texel.a);
}
if(passVarB.a>c_zero)
{
texel = vec4(passVarB.rgb, texel.a);
}
 
outColor = texel;
 }

Please excuse the poor formatting (copy/paste issues).

I did some more testing and found that if I removed all the branching (if statements) from the vertex shader source, it worked fine with gl_InstanceID. Could it be something to do with the compiler's optimisation that is causing issues?

I'm currently waiting on some colleagues to provide me the list of tested devices - but I've confirmed it with the Nexus 5 myself.
Thanks for looking into this.

  • Up0
  • Down0
Maykin53
Join Date: 20 Jul 14
Posts: 10
Posted: Mon, 2014-07-21 18:05

Attached screenshots:

Working lights (using a constant or an attribute multiplied by 0.0):
https://drive.google.com/file/d/0B9XpTXH7iwk-VjNSMHlUc250a1U/edit?usp=sh...

Not working (using gl_instanceID or a variable assigned to the same value as gl_instanceID):
https://drive.google.com/file/d/0B9XpTXH7iwk-QS0zSEY1QjJ2ZGc/edit?usp=sh...

Not working but different results (using an attribute multipled by 0.0 then multiplied by gl_instanceID):
  • Up0
  • Down0
Maykin53
Join Date: 20 Jul 14
Posts: 10
Posted: Mon, 2014-07-21 18:23

By the way when I said I changed the value of instanceID, it was after this line:

mat4 modelMatrix = modelMatrixList[instanceID];

  • Up0
  • Down0
mhfeldma Moderator
Join Date: 29 Nov 12
Posts: 310
Posted: Tue, 2014-07-22 08:30

THanks for the additional testing.

1) It's possible that the compiler's optimization is having some problems with this shader.  Are you able to provide us with a sample apk (with shader simplied as much as possible, yet producing incorrect results) and bitmap of expected result?

2) Have you updated your Nexus 5 to the latest build (and thus, graphics drivers)?  What is the build version/date currently loaded on your Nexus 5?

 

  • Up0
  • Down0
Maykin53
Join Date: 20 Jul 14
Posts: 10
Posted: Tue, 2014-09-23 07:35

Thanks for the reply.
The Nexus 5 is updated to the latest version: 

Android: 4.4.4
Baseband: M8974A-2.0.50.1.16
Build number: KTU84P

We decided to remove all branching from the shader (to improve performance) and that fixed the problem with using gl_InstanceID to access the arrays. So the bug appears to still be there but we aren't worried about it now.

We are, however, having more issues as discussed in post 28107.

  • Up0
  • Down0
Maykin53
Join Date: 20 Jul 14
Posts: 10
Posted: Tue, 2014-09-23 07:35

Thanks for the reply.
The Nexus 5 is updated to the latest version: 

Android: 4.4.4
Baseband: M8974A-2.0.50.1.16
Build number: KTU84P

We decided to remove all branching from the shader (to improve performance) and that fixed the problem with using gl_InstanceID to access the arrays. So the bug appears to still be there but we aren't worried about it now.

We are, however, having more issues as discussed in post 28107.

  • Up0
  • Down0
or Register

Opinions expressed in the content posted here are the personal opinions of the original authors, and do not necessarily reflect those of Qualcomm Incorporated or its subsidiaries (“Qualcomm”). The content is provided for informational purposes only and is not meant to be an endorsement or representation by Qualcomm or any other party. This site may also provide links or references to non-Qualcomm sites and resources. Qualcomm makes no representations, warranties, or other commitments whatsoever about any non-Qualcomm sites or third-party resources that may be referenced, accessible from, or linked to this site.