jellyfication
jellyfication

Reputation: 1605

SurfaceHolder.lockCanvas() is too expensive

Everytime i call these methods, it takes 14-20ms to proceed.

Canvas canvas = holder.lockCanvas();
holder.unlockCanvasAndPost(canvas);

Is this normal behaviour ? Should I take a different approach ?

Here is the whole code

public class Render extends SurfaceView {
    Context c = null;
    SurfaceHolder holder;
    volatile boolean running = true;

    public Render(Context c) {
        super(c);
        this.c = c;
        this.holder = getHolder();
    }

    public void run() {
        if(running) { 
            if(!holder.getSurface().isValid()){
                System.out.println("not valid");
                return;          
            }

            Canvas canvas = holder.lockCanvas();
            holder.unlockCanvasAndPost(canvas);

        }
    }
}

Trace:

01-05 15:49:20.322: I/System.out(4892): Frame time: 0 ms frame291
01-05 15:49:20.322: I/System.out(4892): not valid
01-05 15:49:20.322: I/System.out(4892): Frame time: 0 ms frame292
01-05 15:49:20.332: I/System.out(4892): Frame time: 2 ms frame293
01-05 15:49:20.357: I/System.out(4892): Frame time: 22 ms frame294
01-05 15:49:20.357: I/System.out(4892): Frame time: 1 ms frame295
01-05 15:49:20.362: I/System.out(4892): Frame time: 1 ms frame296
01-05 15:49:20.367: D/CLIPBOARD(4892): Hide Clipboard dialog at Starting input: finished by someone else... !
01-05 15:49:20.367: I/System.out(4892): Frame time: 8 ms frame297
01-05 15:49:20.377: I/System.out(4892): Frame time: 10 ms frame298
01-05 15:49:20.397: I/System.out(4892): Frame time: 16 ms frame299
01-05 15:49:20.412: I/System.out(4892): Frame time: 16 ms frame300
01-05 15:49:20.427: I/System.out(4892): Frame time: 16 ms frame301

UPDATE


Same thing hapens when i use OpenGL

package android.apps.td;

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

import android.content.Context;
import android.opengl.GLSurfaceView;
import android.opengl.GLSurfaceView.Renderer;

public class Render extends GLSurfaceView implements Renderer {

    private final int MILLION = 1000000;
    private long frame;

    public Render(Context context) {
        super(context);
        setRenderer(this);
        // TODO Auto-generated constructor stub
    }

    public void onDrawFrame(GL10 arg0) {
        System.out.println("Frame "+(System.nanoTime()-frame)/MILLION+" ms");
        frame = System.nanoTime();
    }

    public void onSurfaceChanged(GL10 gl, int width, int height) {
        System.out.println("Surface changed w:"+width+" h:"+height);
    }

    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        System.out.println("Surface created");
    }
}

Upvotes: 3

Views: 2763

Answers (2)

Qwertie
Qwertie

Reputation: 17186

I have been investigating this problem myself. What I found on the Galaxy Tab GT-P7500 was that

  • The minimum time between pairs of unlockCanvasAndPost+lockCanvas is 1/60 of a second or 17 ms.
  • However, you can do up to 6 ms of work and the framerate will stay at 60 fps.
  • The minimum time taken by a page flip (unlockCanvasAndPost+lockCanvas) is about 3 msec.
  • Above 6 ms of work, the lockCanvas() function MAY introduce an additional delay that forces the framerate down to 40 fps, 30 fps, 20 fps, or 15 fps. In the worst case, the page flip may take longer than 1/60 second. For example if you do 48 msec of work per frame (when you add 3 msec for the page flip, this is not quite fast enough for 20 fps), the page flip wastes 19-20 ms in order to force the framerate down to 15 frames per second. Below 15 fps, a page flip may take 17 msec consistently.
  • This phenomenon does not always happen. After observing this behavior in a benchmark, I created a dedicated activity to investigate further and in that dedicated activity, the phenomenon did not occur. So far I have not been able to figure out the difference between my original benchmark and the new one: both of them draw frames on a SurfaceView in a worker thread, but in the second activity, the page flip takes 3 ms consistently, while in the first one, the page flip takes 3 ms initially but suddenly rises after about 1/2 second, to a maximum of 20 ms in steady state.
  • Plugging into wall power made no difference.

Upvotes: 0

jellyfication
jellyfication

Reputation: 1605

I have discovered this article: http://replicaisland.blogspot.com/2009/10/rendering-with-two-threads.html

eglSwapBuffers() is probably called after onDrawFrame and blocks until the hardware completes drawing and than swaps buffers, which takes minimul delay of 16.67 ms.

Upvotes: 2

Related Questions