Reputation: 909
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
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:
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