Weird performance issue with Galaxy Tab - android

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...

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.

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...

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.

Related

AS3 rendering bitmaps in GPU mode

Flash Pro CC, AS3, Air for Android (v17), rendering mode GPU, stage quality.LOW, FPS: 60, testing device: an old Nexus One smartphone (Android 2.3.3).
The guides say that GPU makes rendering the bitmaps cheap, somehow i can't grasp how exactly it works.
So i have 49 separate bitmap squares covering the stage and one MovieClip in the middle with a bitmap inside tweened to move up and down (jumping ball). Pretty simple, right?
This is the view: http://i.stack.imgur.com/EKcJ6.png
All graphics are bitmaps (not vectors). Yet i get 55 fps (it varies arround 53-57).
Then i select all 49 squares and put them inside a symbol (MovieClip). Visually nothing changes. It seems to increase the FPS a tiny bit, the average fps is now ~57 (55-59).
Then i take the MovieClip (with all the squares inside it) and set cacheAsBitmap=true. Voila, now i have 60 fps!
What is happening in all 3 different cases? Why i need to put bitmaps into one MC and cache this MC as bitmap - aren't the squares already bitmaps?
I have also tried to make each square a MovieClip and cache it as bitmap, but i still got 55 fps.
Is it possible to keep squares separate at 60 fps?
In my real project i have many MovieClips on the stage (~100) but in most cases only one of them is animated at a time. Yet somehow it seems that the mere presence of other movieclips reduce the performance (fps). Obviously, i cannot put them all into one MC and cache it as bitmap as in the simplified example above.
How can i solve this, what should i do?
Thanks!
I think it relates to this best practice recommendation:
Limit the numbers of items visible on stage. Each item takes some time
to render and composite with the other items around it. When you no
longer want to display a display object, set its visible property to
false. Do not simply move it off stage, hide it behind another object,
or set its alpha property to 0. If the display object is no longer
needed at all, remove it from the stage with removeChild().
By putting all the bitmaps in a single container and setting cacheAsBitmap=true you are essentially turning them into a single bitmap as far as the compositor is concerned. This tends to be faster to composite than multiple individual bitmaps. Setting a bitmap to cacheAsBitmap=true (or in a single container with cacheAsBitmap=true) has no effect because it's already a bitmap.
Also note that GPU mode isn't recommended anymore, it was Adobe's first attempt at GPU accelerating the display and they basically gave up on that path in favor of the new Stage3D rendering pipeline. While GPU render mode can work really well when used just right, it can be somewhat unpredictable and confusing, so I would highly recommend you check out Stage3D.
Hope that helps.

Correct way to partially update Hardware Accelarated Android view with Bitmaps

I have an Android App that is custom drawing a View (full-screen). I want to invalidate a part of it, then just draw that part in the next onDraw() call. I want to do this in a cycle, drawing each part of the screen at a time. What I have found is that it works well on Nexus 7 (Android 4.4.2) not too bad on Galaxy Nexus (4.3) but never draws the whole screen at one time on HTC Sensation XL (4.0.3). Did some bugs get fixed with the pipeline rendering, or am I doing something wrong? -- What is the correct way to do this?
More detail: I have a set of Rect objects. There is an update method in a handler that regularly calls Invalidate(Rect). Each time, based on an index. in the onDraw() I use
canvas.drawBitmap(background, src, dest, null);
Where src and dest are the same Rect that were used for the invalidate call. At the end of the onDraw method, the index is updated. It appears that in Android 4.0.3 the whole canvas has been blanked, but in 4.3 and 4.4.2 it has not.
What am I really trying to achieve? Spend as little time as possible in each call to onDraw (< 1mS) so that the CPU is free to do other things, and at the same time maintain a UI with a number of bitmaps being drawn, rotated etc. This is most important on the older-less capable phones that are likely to be running 4.0.3
In the end I took a different approach as I could not find a direct way to resolve the problem. I have implemented an OpenGL surfaceView based on this tutorial. I put everything in one Texture (png file) and recycle the verticies, indicies and uvs arrays and associated direct Buffers. The result is that the onDrawFrame in the Renderer class is completing in about 0.4 mS every time even on slower phones. This is what I needed.

scaling images in libgdx only once

In my android game, I am using images of fixed resolution lets say 256x256. Now for different device screens, I am rendering them by calculating their width and height as appropriate for that device.
Assume that on galaxy note2 I calculated width=128 and height=128... similarly for different devices, width and height will vary.
This is how I created texture..
....
imageTexture = new Texture(...);
....
in render()..
....
spriteBatch.draw(imageTexture,x,y,width,height);
....
So, every time when I call draw() method, does libgdx/opengl scale image from 256x256 to 128x128, which I think, yes!
Is there any way to tell opengl/libgdx to calculate all scaling only once ?
I have no idea how images were rendered? loaded into memory? scaled etc ?
How does Sprite in libgdx work? I tried understanding the code of Sprite and looks to me like they are also getting image width and height and then scale it every time, even though they have setScale() method.
First rule of optimizing: get some numbers. Premature optimization is the root of many problems. That said, there are still some good rules of thumb to know.
The texture data will be uploaded by libgdx/OpenGL to the GPU when you invoke new Texture. When you actually draw the texture with spriteBatch.draw instructions are uploaded to the GPU by OpenGL that tell the hardware to use your existing texture and to fit it to the bounds. The draw call just uploads coordinates (the corners of the box that defines the Sprite) and a pointer to the texture. The actual texture data is not uploaded.
So, in practice your image is "scaled" on every frame. However, this is not that bad, as this is exactly what GPUs are designed to do very, very well. You only really need to worry about uploading so many textures that the GPU has trouble keeping track of them all, you do not need to worry much about scaling the textures beforehand.
The costs of scaling and transforming the four corners of the sprite are relatively trivial next to the costs of sending the data to the GPU and the cost of refreshing the screen, so they probably are not worth worrying about too much. The "batch" in SpriteBatch is all about "batching up" (or gathering together) a lot of coordinates to send up to the GPU at once, as roughly, each call out to the GPU can be expensive. So, its always good to do as much work within a single batch's begin/end as you can.
Again, though, modern machines are stupidly fast, and you should be able to do whatever is easiest to get your app running first. Then once you have something working correctly, you can figure out which parts are actually slow and fix those. The parts that are "inefficient" but are not actually measurably impacting your application can be left alone.

Cocos2d android Texture issue on Motorola xoom

I am developing a game in android with Cocos2d framework with latest build from github(Weikuan Zhou).
In my game, I used lots of images(total images size is around 11MB).
Problem:
I am getting the black box instead of images when I play my game more than 3 times.
What steps will reproduce the problem?
1. When I play my game more than 3 times via "Play Again" functionality of my game.
What is the expected output? What do you see instead?
- images should be displayed properly instead of "BLACK BOX".
and in my logcat, I see the Heap memory goes around 13Mb.
I already release Texture via below method
CCTextureCache.sharedTextureCache().removeAllTextures();
I also tried to remove sprite manually ex. removeChild() method.
But so far not succeeding to find any solution.
If any one have solution for this please let me know.
From what you're describing, you're hitting exactly the same problem i did, which is that cocos2d for android is really buggy when dealing with lots of single sprites loaded individually.
The best route to take to resolve this problem is to get hold of (unless you've got a mac) the free flash version of zwoptex from here http://zwopple.com/zwoptex/static/downloads/zwoptex-flashversion.zip
this will let you build up spritesheets, i suggest relating as many sprites as you can onto each sheet, whilst trying to keep them sensibly grouped.
This is mainly down to cocos doing a single render for ALL sprites in a spritesheet, rather than one render per sprite for normal sprites, hence massively reduced processing time, and much less memory usage.
you can then load the spritesheet with code such as (can't guarantee this code will execute as i'm grabbing snippets from a structured project but it will lead you to the right solution)
CCSpriteFrameCache.sharedSpriteFrameCache().addSpriteFrames("menus.plist"); // loads the spritesheet into the frame cache
CCSpriteSheet menuSpriteSheet = CCSpriteSheet.spriteSheet("menus.png", 20); // loads the spritesheet from the cache ready for use
.... // menu is a CCLayer
CCSprite sprite = CCSprite.sprite(CCSpriteFrameCache.sharedSpriteFrameCache().spriteFrameByName("name of sprite from inside spritesheet.png"));
menuSpriteSheet.addChild(sprite, 1, 1); / you add the sprite to its spritesheet
menu.addChild(menuSpriteSheet, 1); // then add the spritesheet to the layer
This problem happens when you load resources at run time. So it is better to load resources before the scene starts.You can do as follows.
Using the sprite sheets for resources in your game.
Implement your Ui in constructor of your class.
Implement your functionality in overridden method onEnter() in your layer.
You must unload your sprite sheets after finishing your scene.
These is the procedure that I am following.
Thanks.

Strange artifacts when rendering lots of bitmaps

I'm writing a simple 2D game engine and rendering various objects to a locked SurfaceVew by calling Canvas.drawBitmap (all the same source bitmap but generally not with 1:1 source to destination scaling).
Everything appears to work as expected until there are a lot of calls per frame to drawBitmap. When this happens I occasionally see a stall (100mS or so) accompanied by an effect that looks as if several frames of rendering have occurred together, i.e. some objects will be drawn twice at two screen locations or a pair of objects moving at the same speed will appear to momentarily get closer together or further apart.
The application is structured as follows (simplified for the sake of example);
initialiseGameObjects();
while(quit==false)
{
processGameLogic(); // update object positions
Canvas c = surface_holder.lockCanvas();
if (c != null) {
drawGameObjects(c); // draw all objects
surface_holder.unlockCanvasAndPost(c);
}
}
As I understand it, the Canvas is a holder for draw requests which get executed when the Post is issued. Presumably there is a limit to the number of requests it can hold and I'm wondering if I'm exceeding this limit (I'm drawing up to a hundred small bitmaps depending on what's on screen at any one time) and inadvertently provoking some kind of flush and upsetting the double buffering in some way, although I've not managed to find any documentation to confirm or disprove this.
Does anyone have any idea what might be going on?
Regards,
Steve
You need to sychronize calls to canvas drawing. Check this example of a game driving thread: OnDraw() is not fired, nothing is drawn in surfaceView - Android
EDIT:
However I think it may be related to this problem:
Android SurfaceView/Canvas flickering after trying to clear it

Categories

Resources