Tank2005
Tank2005

Reputation: 909

Is optimization of Android's RenderBuffer possible?

I'm using RenderBuffer and OpenGL instead of Canvas and Bitmap on Android Java. However, drawing to a texture takes time. I referred to this question and tried speed improvement (Reduces the call of glEnableVertexAttribArray, glClearColor, glBindFramebuffer), but it's ineffective. Is this limitations of GPU and Android OS?

*This is an extract of the program.

GLES20.glAttachShader(program, vertex);
GLES20.glAttachShader(program, fragment);
GLES20.glLinkProgram(program);
GLES20.glUseProgram(program);

GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[i]);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, s, s,
0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);

GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbs[i]);
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER,
GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, textures[i], 0);

GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, renders[i]);
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16, s, s);
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER,
GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER, renders[i]);


GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbs[i]);
GLES20.glClearColor(fr, fg, fb, fa);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

GLES20.glGetIntegerv(GLES20.GL_FRAMEBUFFER_BINDING, old, 0);

GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbs[pos]);
GLES20.glViewport(0, 0, ww, hh);

:
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
:

GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, old[0]);
GLES20.glViewport(0, 0, scw, sch);

Upvotes: 1

Views: 830

Answers (1)

Rick77
Rick77

Reputation: 3221

If, as I understand, you use all the code you pasted each time you need to draw something, it's not a surprise that your program is running slow.

OpenGL (wheter ES or not) is based on a "state machine" model: the OpenGL context retains the changes you make to it (using the various glXXX commands), and modify the way OpenGL will react to future commands (most notably to the ones you use for drawing).

This means that when you issue the command:

GLES20.glClearColor(fr, fg, fb, fa);

what you are really doing is set the

GL_COLOR_CLEAR_VALUE

variable inside the state machine to [fr, fg, fb, fa]. From that moment on, GL_COLOR_CLEAR_VALUE is already set to [fr, fg, fb, fa], and every extra call to glClearColor with the same arguments will change nothing in the machine.

OpenGL ES 2.0 glClearColor reference page

Why am I going into this? Because OpenGL state changes are performance critical (and some are more than others): changing the state of the context has a performance hit that often goes beyond a simple variable assignment, as it may require OpenGL to "talk" to the GPU, discard caches and whatnot. It's a necessary evil when done in a setup stage, but frequent changes might have a huge performance hit when done every frame.

Therefore the first thing you should do is to minimize the sheer number of glXXX command per second in your program by creating an initialization method and a drawframe method.

The standard approach is to use the GLSurfaceView.Renderer class

Android GLSurfaceView.Renderer class reference

cram all initialization commands into

public abstract void onSurfaceCreated (GL10 gl, EGLConfig config)

and

public abstract void onSurfaceChanged (GL10 gl, int width, int height)

and put in the method:

public abstract void onDrawFrame (GL10 gl)

the least possible amount of OpenGL commands (just what you need to actually draw stuff)

Leaving the theory aside and going into the specific, here is a list of optimizations I would suggest you to consider:

  • if you are using a single program, leave the whole:
    GLES20.glAttachShader(program, vertex);
    GLES20.glAttachShader(program, fragment);
    GLES20.glLinkProgram(program);
    GLES20.glUseProgram(program);

block in the setup section (and even if you don't, just switch between programs with glUseProgram: you don't have to link it over and over again!). glLinkProgram is likely to have a big performance hit!

  • texture initialization goes in the setup (on top of the "state change" thing you are actually moving the same very data from CPU memory to GPU memory over and over again, each frame)

  • framebuffer initialization (with all the renderbuffer creation and binding) goes in setup as well. Besides, why do you need multiple framebuffers anyway? :)

  • glViewport goes in the onSurfaceChanged method

  • it seems to me that you are using different framebuffers to draw different objects: I'm not sure of what you are trying to accomplish, but I'd suggest you to change strategy: draw to the whole screen and on the same buffer, unless you have a very good reason to do otherwise.

Last but not least, here is a good book on the topic:

OpenGL ES 2.0 Programming Guide

it's both a good introduction to OpenGL ES 2.0 and a nice introduction to OpenGL in general (I don't get a cut on their sales ;-) )

Hope it helps

Upvotes: 2

Related Questions