Weird performance issue with Galaxy Tab
Asked Answered
C

3

12

I am working on a 2d tutorial and was able to test my current tutorial part on a Samsung Galaxy Tab.

The tutorial simply moves the default icon randomly over the screen. With a tap I create a new moving icon. Everything works fine (constantly 60fps) on the Galaxy as long as I have 25 elements or less on the screen.

With the 26th element the frame rate drops to 25fps.

When I change the size/dimension of the image to a much bigger one, I reach less than 25fps before the 26th element. Thats ok. But at some not really reproducible number of elements the frame drops from (mostly more than) 10fps to 1fps.

On my Nexus One I can add 150 elements and still have 50fps.

What I have done: I changed the bitmap variable to a static one, so not every element has his own image but all use the same. That removed the behavior, but I doubt this solution is a good one. The magic number of 25 would suggest that I can use only 25 different images in that way.

Does someone have any idea what can cause this behavior? Is it a bug in the modified android version of Samsung?

My sample eclipse project is available. I would appreciate if some Samsung owner would check their performance with the sample.

edit

A colleague found a solution. He changed the way the bitmap is loaded from

mBitmap = BitmapFactory.decodeResource(res, R.drawable.icon);

to

mBitmap = BitmapFactory.decodeStream(new BufferedInputStream(res.openRawResource(R.drawable.icon)));

But we still don't really get it why it works this way...

Crossstaff answered 18/3, 2011 at 10:46 Comment(2)
Just tried this on my Galaxy Tab and the framerates seem to match yours.Knucklehead
On my Nexus S, it goes down to 50fps at about 210 elementsKnucklehead
D
5

Well, I've been looking on your project and everything seems to be fine, but I have one idea about what's causing you the frame rate drop.

You're allocating objects during runtime. If you don't do that, it will make you create all objects at start, and therefore you should notice a significant drop directly (if my solution doesn't solve your problem).

That said; I'm not sure whether an object pool will solve your problem, but you can try. Initialize your objects in a constructor and instead of making this call in onTouchEvent():

new Element(getResources(), (int) event.getX(), (int) event.getY())

You should have something like mElement.add(objectPool.allocate()), where the object pool finds an unused object in the pool. Also, we should have a specified amount of objects in that object pool and from there you can check if it is the allocating that is causing this error or if it is something else.

With the 26th element the frame rate drops to 25fps.

When (or if) you implements this, you should see the frame rate drop directly (if this doesn't solve your problem though), since the object pool will make you allocating a fixed amount (e.g. maybe 100 elements?) at start (but you're not using them visually).

Also, I have used the memory pool pattern (object pool) in one of my sample applications for Android. In that sample; I add a line to the Canvas on an onTouchEvent() using an object pool (without allocating during runtime). In that source code you can easily change the total amounts of objects and check it out and try it yourself. Write a comment if you want to look at my sample application (and source code) and I will gladly share it since it's not public yet. My comments are in Swedish, but I think you should be able to understand, since the variables and methods are in English. :)

Side note: You wrote that you've tried (and even success) with removing the behaviour by making your Bitmap static. As it is right now, your elements have different instances of a Bitmap, which will make you allocate a new Bitmap everytime you're constructing a new object. That means that every object is pointing to a different Bitmap when they are using the same resource. static is a fully valid solution (although a magic number of 25 seems wierd).

This Bitmap case can be compared to the OpenGL system. If you have 20 objects which all should use the same resource, there are two possible solutions: They can point to the same VRAM texture or either they can point to a different VRAM texture (like your case when you're not using static), but still same resource.

EDIT:

Here is my sample application for Android that demonstrates the Memory Pool.

Regarding your solution with BitmapFactory, that probably depends on how that class works. I'm not sure, but I think that one of the decode...() methods generates a new Bitmap even if it is the same resource. It can be the case that new BufferedInputStream(res.openRawResource(R.drawable.icon)) is reusing the BufferedInputStream from memory, although, that is a big guess.

What you should do (in that case) is to decode a resource and store a reference from it in the Panel class and pass that reference into the new Element(bitmapReference, ...) instead. In that way, you're only allocating it once and every element is pointing to the same Bitmap in memory.

Downing answered 18/3, 2011 at 10:46 Comment(4)
If you can share your sample code, I would really like to see it. I tried it with a very simple object pool, where I created 100 elements first but showing only a number of them. With every touch event, the number of displayed elements increase and even with 100 loaded elements and 25 displayed, I got 60fps. With the 26th the drop to 25fps is still there. Anyway a colleague found a solution, added to my answer as an editCrossstaff
@WarrenFaith: Updated my answer with a link to my project. I have also added a little information about how you can reuse the same Bitmap reference, so that you do not need to return a new Bitmap from the BitmapFactory class everytime you're creating a new element.Triazine
Thank you for sharing. In general I would create a bitmap cache where I store the bitmaps and share the same instance to everybody who wants to display it. Thats in general the best solution, I think. But thats a bit off topic, because the performance drop shouldn't ever happen so soon. Not with 25 elements... at least I wouldn't expect that..Crossstaff
@WarrenFaith: No problems. And the solution you mentioned is probably the best.Triazine
Z
3

I have tried your code on HTC Desire HD and the frame rate drops down to unusable after added 20th image using Android 2.2 target. When I exported the same code as android version 2.1 then it worked fine and could handle over 200 instances! I suspect that it is to do with creating instances of your GraphicObject class on 2.2, but not quite sure...

Zoology answered 18/3, 2011 at 11:38 Comment(4)
Thanks for testing. The question is why. The class in not complex, the bitmap has 4kb and 72pixel dimension (the hdpi version). I will try to test the sample on different devices here at work. Thanks for your feedback!Crossstaff
Note that I used the same device, just changed the target OS.Zoology
The tab has 2.2, my project targeting 2.1. Changing it to 2.2 (and the minSdkVersion, too) didn't change anything.Crossstaff
Something is strange, because it works well on HTC Desire HD (2.2), when installed as a project targeting 2.1. Sorry that I cannot help more.Zoology
P
1

I believe i can shed some light on this problem.

At least on my Galaxy S, Gingerbread 2.3.5 the first code loads my test.png into Bitmap with Bitmap.Config = ARGB_8888, while the second code loads with Bitmap.Config = RGB565. The strange thing is, while Gingerbread by default supposed to create 32bit surface, the RGB565 'renders' (I profiled and compared native call to drawBitmap) much faster.

Hence, The second idea, more appropriate for the your example as a whole, is that ARGB888 Bitmap does have alpha, so in that case rendering overlapping images of 25+ sprites could create some bottleneck in alpha calculation algorithm, while RGB565 image would be fine and fast.

Piles answered 20/5, 2012 at 17:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.