14

Testing my game on a slower device (Orange San Francisco aka ZTE Blade) and I have been getting an appalling frame rate.

I put some debug code into the draw loop and discovered the following line is taking over 100ms:

c = mSurfaceHolder.lockCanvas();

Anyone else seen this behaviour? I temporarily replaced the surfaceview by extending View and implementing onDraw(), and I got a much better framerate.

Although in general surfaceView is much faster on my HTC Desire. I am suspicious this may be a Android 2.1 problem. I'm contemplating rooting the phone and upgrading it to 2.2 if possible, but I did want a device running on 2.1 so that might be counter-productive in the long run.

** update **

I've been working on this some more, and have discovered some more puzzling aspects to it.

I rooted the phone and installed 2.2 and the problem still happens. When the app is first started, the lockCanvas is working as expected (0-1 ms). Then at some point during my initialisation, lockCanvas suddenly starts taking approx 100ms.

It might be worth pointing out that I am loading my assets in an Async task, so that I can display a loading screen.

Despite my best efforts to pin down what the program is actually doing when the slowness occurrs I was not able to do so. In fact when I run it in debug mode and single step, it works fast!

Now I discovered that if I add a delay in the constructor of my SurfaceView (of about 10 seconds), the slowness doesn't occur and all works fine.

However if you press Home, and then switch back, the slowness comes back.

I'm pretty much at the end of my tether on this stupid illogical problem! I've got a mind to put it down to a device specific problem.

I feel it could have something to do with memory usage. Maybe something is being swapped out and it affects the video ram?

I'd be interested in theories at least.

Kevin
  • 1,200
  • 1
  • 11
  • 19
  • Describe what controls *when* rendering occurs ... are you using a dedicated thread, or do you invalidate() at the end of every draw(), or do you use a timing mechanism, or what? – Reuben Scratton Mar 03 '11 at 16:34
  • I using a thread to draw (in the same way as SpriteMethodTest). Just looping while true. – Kevin Mar 03 '11 at 21:42
  • Is it possible you are getting stuck in a big GC? I mean I agree the lockCanvas() isn't the cheapest of calls but it shouldn't take that long. If you were to get stuck in a GC though during the call during the iowait, the call then appears to take 100ms longer than it should. Do you have a logcat or some code examples? – Greg Giacovelli Mar 07 '11 at 02:44
  • I suppose it's possible, but I have optimised my code not to require any GC operations so that I get the best possible framerate. I will check again later though to be sure. If the GC is running every frame I'd have to be using resources like crazy! – Kevin Mar 07 '11 at 16:18
  • The impression I got from your previous posts was that the pause would only happen on some renders. So I don't know what is being generated on each stackframe but I just assumed it ran for X invocations and then took a long time unpredictably – Greg Giacovelli Mar 07 '11 at 16:30
  • I really wish S/O would notify me when people reply to comments! So - some days later - are you definitely pausing and resuming the thread from your onPause() and onResume() as per SpriteMethodTest's CanvasSurfaceView.java? What synchronization exists between your asset-loading thread and your rendering thread? – Reuben Scratton Mar 08 '11 at 12:18

4 Answers4

11

About lockCanvas() from docs:

If you call this repeatedly when the Surface is not ready (before Callback.surfaceCreated or after Callback.surfaceDestroyed), your calls will be throttled to a slow rate in order to avoid consuming CPU.

Is it possible that your draw loop is initiated too early for some devices? I think this is the problem, since you wrote:

Now I discovered that if I add a delay in the constructor of my SurfaceView (of about 10 seconds), the slowness doesn't occur and all works fine.

Simeon
  • 5,519
  • 3
  • 29
  • 51
  • I'm giving you +1 for finding that in the documentation. I did see that last week also and tested it and it did not fix the problem, although reading it again I need to double check what I did. I'm going to award this as best answer anyway. – Kevin Mar 10 '11 at 16:22
0

I have recently discovered that if large bitmaps are used to draw on the canvas and these bitmaps are stored in the activity class - the "_surfaceHolder.lockCanvas()" command itself takes very long (about 70ms depending on device). HOWEVER, moving these bitmaps storage to other class (in different file, say MY_DATA), and the activity has just a reference to that new class - solves the problem.

I'm have no explanation to this phenomenon.

Alex L.
  • 57
  • 7
0

I was encountered the same mysterious problem with Canvas drawing, but solved it by changing Canvas drawing to drawing on the SurfaceView. But now I have constantly slow lockCanvas() call. Here is my observation results. Problem is only present on some devices:

  • Galaxy Note 3 n900: has problems
  • Galaxy Note 3 n9005: has problems
  • Galaxy S4 i9505: has problems
  • Galaxy Gio: no problems
  • LG G2 D802: has problems
  • Galaxy S2 i9100: no problems

I temporarily replaced the surfaceview by extending View and implementing onDraw(), and I got a much better framerate

I also noticed, that Samsung phones using GLES20Canvas instead of regular Canvas with onDraw() drawing, as a result, better performance.

Dr. Failov
  • 311
  • 4
  • 7
0

So, maybe we could use holder.isCreating() to check state? this method will return true if canvas still creating.

Something like while(holder.isCreating()) {} can=holder.lockCanvas();

But I'm a bit confuse now. As i know colbeck is called when a surfaceview is creates. We should implement SurfaceHolder.Callback interface. And when surface is created callback method public void surfaceCreated(SurfaceHolder holder) { } will be called. From surfaceCreated method I'm starting gameloop thread.

Jova
  • 499
  • 4
  • 9