Forums - Multiple Uniform Buffer Objects failing

10 posts / 0 new
Last post
Multiple Uniform Buffer Objects failing
Rajveer
Join Date: 6 Dec 13
Posts: 7
Posted: Wed, 2015-12-16 12:16

The following shader fails to draw meshes correctly on a Nexus 5 (Adreno 330), Marshmallow 6.0.1:

 

EDIT: Forgot to mention this also fails on a Galaxy S5 and a Moto G 2nd Gen (Android 5)

 

Vertex shader:


#version 300 es
 
precision highp float;
precision highp int;
 
layout(std140) uniform object_matrices
{
mat3 normalMatrix;
};
 
//uniform mat3 normalMatrix;
 
layout(std140) uniform object_view_matrices
{
mat4 modelViewMatrix;
mat4 modelViewProjectionMatrix;
mat4 boundsModelViewProjectionMatrix;
};
 
//Bones
const int maxBones = 50;
uniform vec4 boneMatrices[4*maxBones];
 
//Vertex information
in vec3 position;
in vec4 colour;
in vec2 texCoord;
in vec3 normal;
in vec4 boneWeights;
in ivec4 boneIndices;
 
out vec4 _colour;
out vec2 _texCoord;
out vec3 _normal;
out vec3 _eyePos;
 
//Function prototypes
mat4 boneTransformMatrix();
 
void main(void)
{
vec4 positionSkinned;
vec4 normalSkinned;
mat4 matTransform = boneTransformMatrix();
 
positionSkinned = matTransform * vec4(position, 1.0);
normalSkinned = matTransform * vec4(normal, 0.0);
 
gl_Position = modelViewProjectionMatrix * positionSkinned;
_colour = colour;
_texCoord = texCoord;
_normal = normalize(normalMatrix * normalize(normalSkinned.xyz));
_eyePos = (modelViewMatrix * positionSkinned).xyz;
}
 
mat4 boneTransformMatrix()
{
mat4 matTransform = boneWeights[0] * mat4(boneMatrices[4*boneIndices[0]], boneMatrices[4*boneIndices[0]+1], boneMatrices[4*boneIndices[0]+2], boneMatrices[4*boneIndices[0]+3]);
matTransform += boneWeights[1] * mat4(boneMatrices[4*boneIndices[1]], boneMatrices[4*boneIndices[1]+1], boneMatrices[4*boneIndices[1]+2], boneMatrices[4*boneIndices[1]+3]);
matTransform += boneWeights[2] * mat4(boneMatrices[4*boneIndices[2]], boneMatrices[4*boneIndices[2]+1], boneMatrices[4*boneIndices[2]+2], boneMatrices[4*boneIndices[2]+3]);
matTransform += boneWeights[3] * mat4(boneMatrices[4*boneIndices[3]], boneMatrices[4*boneIndices[3]+1], boneMatrices[4*boneIndices[3]+2], boneMatrices[4*boneIndices[3]+3]);
 
return matTransform;
}

 

Fragment shader:


#version 300 es
 
precision highp float;
precision highp int;
 
in vec4 _colour;
in vec2 _texCoord;
in vec3 _normal;
in vec3 _eyePos;
 
layout(location = 0) out vec4 fragColor;
 
//Main functions
 
void main(void)
{
fragColor = vec4(_normal.x, _normal.y, _normal.z, 1.0);
}

 

The issue seems to be the line:

 

_normal = normalize(normalMatrix * normalize(normalSkinned.xyz));

 

I can verify that normalSkinned is correct by setting _normal to normalSkinned, in which case the mesh draws.

I can also verify that normalMatrix is correct by setting _normal to either of it's 3 columns which draws the mesh with the expected colour of the column (moving the view around and seeing a colour change verifies this), or by replacing normalSkinned with a hardcoded vector e.g. vec3(1.0, 1.0, 0.0). Weirdly though, replacing it with vec3(1.0, 1.0, 1.0) fails.

 If I comment out either of the uniform blocks and replace them with uniforms, everything works fine. Having both uniform blocks active fails. Using an unskinned normal also works (taken from my static mesh shader):

 

_normal = normalize(normalMatrix * normalize(normal));

 

I've tried this with buffers large enough for one item and using glBindBuffer(), and also with buffers that have multiple items using glBindBufferRange (and taking care that the data is aligned correctly). As a note, this works fine on Windows. Any help would be appreciated!

  • Up0
  • Down0
Rajveer
Join Date: 6 Dec 13
Posts: 7
Posted: Mon, 2015-12-21 04:26

BTW would it help if I provided an APK with this bug?

  • Up0
  • Down0
mhfeldma Moderator
Join Date: 29 Nov 12
Posts: 310
Posted: Mon, 2015-12-28 07:45

An apk would be helpful.  Have you had more luck running on more current devices using Adreno GPUs more recent than the Adreno 330?

  • Up0
  • Down0
Rajveer
Join Date: 6 Dec 13
Posts: 7
Posted: Tue, 2015-12-29 04:12

Unfortunately I don't have any devices with more recent Adreno GPUs, however over the holidays I was able to test with a Nvidia K1 (Nexus 9) which worked fine. I've sent you a PM with links to 2 APKs for testing, please let me know your findings.

  • Up0
  • Down0
Rajveer
Join Date: 6 Dec 13
Posts: 7
Posted: Mon, 2016-01-04 04:21

I've also tested this on an iPad Mini 2 without any issue, so it works on the following hardware:

 

Nvidia - GTX 980 Ti (Windows), K1 (Android)

PowerVR - G6430 (iOS)

  • Up0
  • Down0
Rajveer
Join Date: 6 Dec 13
Posts: 7
Posted: Wed, 2016-01-13 02:31

Have you guys looked in to this yet? I sent 2 APKs to you directly, I can post them somewhere else but I'd rather not make them public.

 

Even confirming that this is a bug in the driver and providing a suitable workaround would be a massive help.

  • Up0
  • Down0
alina.lyvette
Join Date: 27 Aug 13
Posts: 2
Posted: Tue, 2016-08-16 19:21

I can confirm that the issue exists on Adreno 330. I've ran into it on Galaxy S5 while trying to do similar things to the OP. Adding a second UBO certainly breaks things, with exactly the same code working perfectly on PowerVR and Mali GPUs. 

 

  • Up0
  • Down0
mhfeldma Moderator
Join Date: 29 Nov 12
Posts: 310
Posted: Wed, 2016-08-17 12:25

Working offline with Rajveer, we confirmed this problem has been fixed in later Adreno 4xx gpus

  • Up0
  • Down0
alina.lyvette
Join Date: 27 Aug 13
Posts: 2
Posted: Thu, 2016-08-18 15:54

This is great news! Can you advise me what would be the recommended fallback for older Adrenos though? Let me describe quickly what I'm trying to do.

In my case, the relevant part of the scene consists of a few hundres of objects with skeletal animations. My approach was to use two UBOs; one per-frame UBO (let's call it "Frame UBO", approximately 4kB of data) that gets reloaded once per frame. Second, let's call it "Object UBO" (again, about 4kB of data) is loaded once for every object and never changes. Both UBOs are, essentially, arrays of matrices.

I am considering three possible courses of action:

1) merge both UBOs into one, which implies reloading this combined UBO for every object and every frame, essentially calling glBufferSubData hundred times per frame. Naturally I expect this to be extremely slow.

2) replace one of UBOs ("Object UBO" so to say) with float immutable texture and construct matrices in the vertex shader with texelFetch(). This would mean reloading only one UBO, once per frame. Would there be any potential compatibility or performance issues?

3) Fall back to ES 2.0 behavior, with creative swizzling and packing the data to fit into regular uniforms. It works, yet the frame rate drops expectedly from about 30 FPS to about 10. 

Of these three possible ways, what would you expect to perform best?

  • Up0
  • Down0
mhfeldma Moderator
Join Date: 29 Nov 12
Posts: 310
Posted: Mon, 2016-08-22 06:59

It's difficult to determine exactly what the fix was, but your third option might be the safest for running on Adreno 3xx hardware

  • 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.