Hello,
I am trying to get a quite simple openGL ES 1 program run a smooth solid 60fps on a couple devices out there, and I get stuck on HTC desire. The phone itself is quick, snappy, powerful, and overall a breeze to use ; however, I can't seem to display anything fullscreen at 60fps with OpenGL. After getting stuck for a long time with my app, I decided to make a test app with code right out the sample code from the documentation.
Here is what I am doing. Simple initialization code with GLSurfaceView. I have three versions of onDrawFrame, all dead simple. One is empty. One contains only glClear. One contains just enough state to only draw a fullscreen quad. Trace times before, and after. There is no view other than my GLSurfaceView in my program. I can't explain the times I get.
In all cases, the onDrawFrame function itself always finishes under 2ms. But very often, onDrawFrame does not get called again before 30~40ms, dropping my frame rate all the way to 30fps or less. I get around 50fps with an empty onDrawFrame, 45 with glClear and 35 with a quad. The same code runs at 60 fps on the HTC Magic, on the Samsung Galaxy S, on the Sharp ISO1. Sony Experia X10 caps at a solid 30fps because of its screen. I have been doing much more complicated scenes at a solid 60fps on the HTC Magic which is very underpowered compared to the Desire. I don't have a Nexus One in handy to test. Sure, I except buffer swapping to block for a couple milliseconds. But it just jumps over frames all the time.
Trying to find out what the phone is doing outside of the onDrawFrame handler, I tried to use Debug.startMethodTracing. There is no way I can get the trace to reflect the actual time the phone spends out of the loop. At the end of onDrawFrame, I use startMethodTracing then save the current time (SystemClock.uptimeMillis) in a variable. At the start of the next one I Log.e the time difference since the function last exited, and stopMethodTracing. This will get called over and over so I arrange for stopping once I get a trace for an iteration with a 40+ ms pause. The time scale on the resulting trace is under 2ms time, as if the system was spending 38ms outside of my program.
I tried a lot of things. Enumerating EGL configs and try them all one after the other. Just to see if it changed anything, I switched to a render when dirty scheme requesting a redraw at each frame. To no avail. Whatever I do, the expected gap of 14~16ms to swap buffers will take 30+ms around half the time, and no matter what I do it seems like the device is waiting for two screen refreshes. ps on the device shows my application at around 10% cPU, and System_server at 35%. Of course I also tried the obvious, killing other processes, rebooting the device... I always get the same exact result.
I do not have the same problem with canvas drawing.
Does anyone know why the Desire (and afaict the Desire only) behaves like this ?
For reference, here is what my test code looks like :
public class GLTest extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGLView = new GLSurfaceView(this);
mGLView.setRenderer(new ClearRenderer());
setContentView(mGLView);
}
@Override
protected void onPause() {
super.onPause();
mGLView.onPause();
}
@Override
protected void onResume() {
super.onResume();
mGLView.onResume();
}
private GLSurfaceView mGLView;
}
class ClearRenderer implements GLSurfaceView.Renderer {
public void onSurfaceCreated(GL10 gl, EGLConfig config) {}
public void onSurfaceChanged(GL10 gl, int w, int h) { gl.glViewport(0, 0, w, h); }
long start;
long end;
public void onDrawFrame(GL10 gl)
{
start = System.currentTimeMillis();
if (start - end > 20)
Log.e("END TO START", Long.toString(start - end));
// gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
end = System.currentTimeMillis();
if (end - start > 15)
Log.e("START TO END", Long.toString(end - start));
}
}