1
\$\begingroup\$

How can I debug why the time take to issue exactly the same GL commands to render a frame, especially the call to GLES20.glDrawArrays(), is highly variable even when there is no garbage collection and no change in the scene? I'm developing for Android using Android Studio.

The slowest part of my render loop consists of rendering ~ 175 rectangles (2 triangles each) that are each transformed by a different matrix and each have a different texture. I'm using a VBO for the rectangle vertices and texture coordinates, however I load the matrix for each rectangle separately when I draw it. Since the images are up to 512x512 pixels each, I haven't bothered combining them into texture atlases. I could probably save memory bandwidth by mipmapping, but haven't done that yet.

All rectangles are currently draw using texture unit 0 (cycling through them doesn't seem to make a difference).

The main part of my onDrawFrame() code is:

for (int i = 0; i < images.length; i++) {
  int textureId = images[i].textureId;
  float[] modelMatrix = images[i].modelMatrix;
  GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
  GLES20.glUniformMatrix4fv(modelMatrixId, 1, false, modelMatrix, 0);
  GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);
}

I narrowed the variability down using System.nanoTime() measurements and found that the GLES20.glDrawArrays() call is the one with the most (but not all of the) variability: For a frame (175 calls), it averages about 3msec total but goes up to 8msec a couple of times per second, and 13msec every couple of seconds.

How can I find the cause of this variability?

My render loop doesn't allocate any objects, so there is no garbage collection. I also don't think it can be the data bandwidth between CPU and GPU because the glUniformMatrix4fv() call executes super quickly (always < 2msec).

I don't know how asynchronous the CPU-GPU communication is so I don't know how directly I can attribute slowness to particular method calls. That said, the glDrawArrays() call is the one that blocks (on the CPU) for the most, and for the most variable, amount of time.

Any ideas how to debug this?

PS. Since it was asked, here are my shaders:

Fragment shader:

precision mediump float;
uniform sampler2D textureMap;
varying vec2 fragmentTextureCoord;
void main() {
  gl_FragColor = texture2D(textureMap, fragmentTextureCoord);
}

Vertex shader:

uniform mat4 modelMatrix;
uniform mat4 viewProjectionMatrix;
attribute vec4 position;
attribute vec2 vertexTextureCoord;
varying vec2 fragmentTextureCoord;
void main() {
  gl_Position = viewProjectionMatrix
               * modelMatrix
               * position;
 fragmentTextureCoord = vertexTextureCoord;
}
\$\endgroup\$
  • 1
    \$\begingroup\$ Obviously, changing texture for each mesh is not going to give extraordinary performance but in order to give you a comprehensive answer, could you please expose the shaders used? \$\endgroup\$ – elenfoiro78 Dec 20 '15 at 9:42
  • \$\begingroup\$ I updated my question by adding the shader sources. \$\endgroup\$ – Tobias Dec 20 '15 at 10:45
  • \$\begingroup\$ Any suggestion on how to avoid changing the texture 175 times? My understanding is that Texture Arrays are not available in OpenGL ES at all (not even in OpenGL ES 3), and texture atlases only work for small textures. My textures are at unit distance from the observer, so the depth buffer doesn't help, although I can probably figure out which ones will overdrawn and remove them (will be some work to implement). \$\endgroup\$ – Tobias Dec 20 '15 at 10:52
  • \$\begingroup\$ If it's possible, pack the maximum textures in one big texture being careful with max texture size, then sort your objects by texture. Otherwise, you can reduce memory bandwidth consumption with compressed textures. You can probably lower your texture resolution without loosing a lot on visual quality. \$\endgroup\$ – elenfoiro78 Dec 20 '15 at 11:08
  • \$\begingroup\$ Thanks for the suggestion. Unfortunately my textures are fairly big (512x512) so I can't fit too many into the maximum texture size supported on my phone (2048x2048). However I haven't investigated if there is a good library to make texture atlases easier to implement. My textures are compressed. I agree I can probably get away with much lower resolution textures, it just makes the implementation more complex. (My images are arranged in a sphere around the camera, usually at unit distances, but occasionally one or two images move closer). \$\endgroup\$ – Tobias Dec 20 '15 at 13:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.