Frames appearing out of order on GLSurfaceView

时间:2015-07-28 16:19:27

标签: android animation opengl-es glsurfaceview doublebuffered

I'm writing an Android app using OpenGL ES and encountered this problem in the Nexus 5 emulator that comes with Android Studio. I have reduced my code to this small app, which simply draws a box going back and forth:

package net.jesbus.stuttertest;

import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.os.Bundle;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

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

public class MainActivity extends Activity
{
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        // Create GLSurfaceView
        GLSurfaceView glsv = new GLSurfaceView(this);
        glsv.setEGLConfigChooser(8, 8, 8, 8, 16, 0);

        // Create GLSurfaceView.Renderer
        glsv.setRenderer(new GLSurfaceView.Renderer()
        {
            float step = 0;
            boolean direction = false;
            ShortBuffer iBuff;
            FloatBuffer vBuff;
            @Override
            public void onSurfaceCreated(GL10 gl, EGLConfig config)
            {
                // Generate vertices index buffer
                short[] pIndex = {0, 1, 2, 3};
                ByteBuffer pbBuff = ByteBuffer.allocateDirect(pIndex.length * 2);
                pbBuff.order(ByteOrder.nativeOrder());
                iBuff = pbBuff.asShortBuffer();
                iBuff.put(pIndex);
                iBuff.position(0);

                // Generate vertices buffer
                float[] vs = new float[]
                        {
                                -1, +1, 0,
                                +1, +1, 0,
                                -1, -1, 0,
                                +1, -1, 0,
                        };
                ByteBuffer bBuff = ByteBuffer.allocateDirect(vs.length * 4);
                bBuff.order(ByteOrder.nativeOrder());
                vBuff = bBuff.asFloatBuffer();
                vBuff.put(vs);
                vBuff.position(0);
            }

            @Override
            public void onDrawFrame(final GL10 gl)
            {
                // Animation calculation
                step += direction ? 0.02f : -0.02f;
                if (step > 1) direction = false;
                else if (step < 0) direction = true;

                // Set background color
                gl.glClearColor(0.7f, 0.7f, 1, 1);

                // Clear screen
                gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

                // Set matrix to correct location
                gl.glLoadIdentity();
                gl.glTranslatef(-1 + step * 2, 0, 0);
                gl.glScalef(0.25f, 0.4f, 1);

                // Draw box
                gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
                gl.glFrontFace(GL10.GL_CW);
                gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vBuff);
                gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, 4, GL10.GL_UNSIGNED_SHORT, iBuff);
                gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
            }

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

I looked at it frame by frame, and it seems that instead of showing the next frame, it shows the previous frame, and then skips the frame it was supposed to show and continues:

Wrong order of frames

The circles represent frames produced in onDrawFrame, and the arrows represent the flow of time.

Video showing the problem

1 个答案:

答案 0 :(得分:0)

I don't exactly know how threading is used OpenGL, but try this:

    // Animation calculation
    synchronized (this) {
        step += direction ? 0.02f : -0.02f;
        if (step > 1) direction = false;
        else if (step < 0) direction = true;
    }

or make the whole onDrawFrame() method synchronized if the compiler consents and OpenGL doesn't lock up...