TL;DR:

Even when doing no drawing at all, it seems impossible to maintain a
60Hz update rate on an OpenGL ES rendering thread on an Android
device. Mysterious spikes frequently crop up (demonstrated in the code
at the bottom of this post), and every effort that I've made to figure
out why or how has lead to a dead end. Timing in more complicated
examples with a custom rendering thread has consistently shown
eglSwapBuffers() to be the culprit, frequently coming in over
17ms-32ms. Help?

More details:

This is particularly damning because the rendering requirements for
our project is screen-aligned elements smoothly scrolling horizontally
at a fixed, high rate of speed from one side of the screen to the
other. In other words, a platforming game. The frequent drops from
60Hz result in noticeable popping and lurching, both with and without
time-based movement. Rendering at 30Hz isn't an option because of the
high rate of scrolling speed, which is a non-negotiable part of the
design.

Our project is Java-based to maximize compatibility and uses OpenGL ES
2.0. We only dip down into the NDK for OpenGL ES 2.0 rendering on API
7-8 devices and ETC1 support on API 7 devices. In both it and the test
code given below, I have verified no allocations/GC events except for
the log print and automatic threads beyond my control.

I've recreated the problem in a single file that uses stock Android
classes and no NDK. The code below can be pasted into a new Android
project created in Eclipse and should pretty much work out-of-the-box
so long as you choose API level 8 or above.

The test has been reproduced on a variety of devices with a range of
GPUs and OS versions:
* Galaxy Tab 10.1 running Android 3.1
* Nexus S running Android 2.3.4
* Galaxy S II running Android 2.3.3
* XPERIA Play running Android 2.3.2
* Droid Incredible running Android 2.2
* Galaxy S running Android 2.1-update1 (when dropping API requirements
down to level 7)

Sample output (gathered from under 1 second of run time):
Spike: 0.017554
Spike: 0.017767
Spike: 0.018017
Spike: 0.016855
Spike: 0.016759
Spike: 0.016669
Spike: 0.024925
Spike: 0.017083999
Spike: 0.032984
Spike: 0.026052998
Spike: 0.017372

I've been chasing this one for a while and have about hit a brick
wall. If a fix isn't available, then at least an explanation about why
this happens and advice on how this has been overcome in projects with
similar requirements would be greatly appreciated.

Thanks,
Bill Roeske
Kittehface Software
--------------------------------------------------

package com.test.spikeglsurfview;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Window;
import android.view.WindowManager;
import android.widget.LinearLayout;

/**
 * A simple Activity that demonstrates frequent frame rate dips from
60Hz,
 * even when doing no rendering at all.
 *
 * This class targets API level 8 and is meant to be drop-in
compatible with a
 * fresh auto-generated Android project in Eclipse.
 *
 * This example uses stock Android classes whenever possible.
 *
 * @author Bill Roeske
 */
public class SpikeActivity extends Activity
{
        @Override
        public void onCreate( Bundle savedInstanceState )
        {
                super.onCreate( savedInstanceState );

                // Make the activity fill the screen.
                requestWindowFeature( Window.FEATURE_NO_TITLE );
                getWindow().setFlags( 
WindowManager.LayoutParams.FLAG_FULLSCREEN,
                                      
WindowManager.LayoutParams.FLAG_FULLSCREEN );

                // Get a reference to the default layout.
                final LayoutInflater factory = getLayoutInflater();
                final LinearLayout layout =
(LinearLayout)factory.inflate( R.layout.main, null );

                // Clear the layout to remove the default "Hello World" 
TextView.
                layout.removeAllViews();

                // Create a GLSurfaceView and add it to the layout.
                GLSurfaceView glView = new GLSurfaceView( 
getApplicationContext() );
                layout.addView( glView );

                // Configure the GLSurfaceView for OpenGL ES 2.0 rendering with 
the
test renderer.
                glView.setEGLContextClientVersion( 2 );
                glView.setRenderer( new SpikeRenderer() );

                // Apply the modified layout to this activity's UI.
                setContentView( layout );
        }
}

class SpikeRenderer implements GLSurfaceView.Renderer
{
        @Override
        public void onDrawFrame( GL10 gl )
        {
                // Update base time values.
                final long  timeCurrentNS = System.nanoTime();
                final long  timeDeltaNS = timeCurrentNS - timePreviousNS;
                timePreviousNS = timeCurrentNS;

                // Determine time since last frame in seconds.
                final float timeDeltaS = timeDeltaNS * 1.0e-9f;

                // Print a notice if rendering falls behind 60Hz.
                if( timeDeltaS > (1.0f / 60.0f) )
                {
                        Log.d( "SpikeTest", "Spike: " + timeDeltaS );
                }

                /*// Clear the screen.
                gl.glClear( GLES20.GL_COLOR_BUFFER_BIT );*/
        }

        @Override
        public void onSurfaceChanged( GL10 gl, int width, int height )
        {
        }

        @Override
        public void onSurfaceCreated( GL10 gl, EGLConfig config )
        {
                // Set clear color to purple.
                gl.glClearColor( 0.5f, 0.0f, 0.5f, 1.0f );
        }

        private long timePreviousNS = System.nanoTime();
}

-- 
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to android-developers@googlegroups.com
To unsubscribe from this group, send email to
android-developers+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en

Reply via email to