tags:

views:

44

answers:

2

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));  
}  

}

A: 

I'm stuck with the same problem on my htc desire 2.2 using opengl es 2.0. :-/

do you already have a clue what is causing this behaviour?

Wolfgang
Not at all, I'm afraid. I've been investigating a lot; my own take in this problem is, probably the driver has a bug that makes it wait for 2 refresh cycles if it measures at least 1 millisecond between frames. That's what it looks like anyway, though I don't know for sure. Upgrading my Desire to Froyo seemed to make the problem better, but not go away. If you learn anything post please :/
Jean
Maybe I've got the answer:
Wolfgang
A: 

Maybe I've got the answer: The opengl driver may decide to do a large part of the actual rendering in a later step. This step is by default done right after onDrawFrame and seems to be the reason why the device is idling after leaving the method. The good news is that you can include this step right into your onDrawFrame method: just call gl.glFinish() - this will do the final rendering and returns when it is finished. There should be no idle time afterwards. However, the bad news is that there was actually no idling time, so you won't be able to get this time back (I had some illusions about how fast my rendering was... now I have to face the real slowness of my implementation ;) ). What you should know about glFinish: There seems to be an os level bug that causes deadlocks on some htc devices (like the desire), which is still present in 2.2 as far as i understood. It seems to happen if the animation runs for some hours. However, on the net exists a patched opengl surface view implementation, which you could use to avoid this problem. Unfortunately I don't have the link right now, but you should be able to find it via google (sorry for that!). There might be some way to use the time spent in glFinish(): It may be gpu activity for some (all?) part, so the cpu would be free to do other processing.

Wolfgang