I am currently working on a game for Android. The game is a real time strategy game that uses tiles or cells and has actors (units, trees, rock, etc.) that will occupy those cells.
In my game, cells and actors are objects that have their own draw method. For fear of speed problems, I currently decode the resource in the map class and feed the decoded image to the object's draw method.
Like this:
_waterCell = BitmapFactory.decodeResource(context.getResources(), R.drawable.watertile);
...
_row.get(Cell).draw(_waterCell, canvas, _paint, _X, _Y);
This is fine for now, considering I have few cell types and only one actor but how would I go about this when I have hundreds of images to decode without having to decode the resource every time I draw the object? And if I were to decode all of my resources in the map class, would it cause out of memory errors?
I cannot say whether decoding the resources would cause an out of memory error since I don't know their size. However, the decoding of the resource itself, assuming there is enough memory to handle whatever is being decoded should not cause an out of memory exception. The more likley result is, depending on how frequently you need to decode resources, it will just slow your app down.
Have you considered using a cache? If you're decoding resources you could use a simple LRUcache as demonstrated in the android docs to avoid repeating this process. If you decode your resources as needed, store them to the cache, and then check the cache fore their presence before decoding again - you can probably save yourself a lot of time.
Related
Take an application containing a glSurfaceView which loads several separate images on start (GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0); for each image).
This application will then have to call gl.glBindTexture(GL10.GL_TEXTURE_2D, texture pointer int) before it can proceed to draw a different texture to a "texturable square" gl object.
Is it recommended to instead load one bitmap with all the textures (ie: a sprite sheet), and then create an array of "texturable squares" that each map a different area of the giant single image, like that gl.glBindTexture(...) only needs be called once...?
Or perhaps is there no significant difference between the two techniques?
As far as I know, once a texture has been loaded via texImage2D, binding a texture is simply a matter of pointing the native OpenGL library to the correct preloaded texture, so performance wise, it shouldn't be costly.
However, you raise a good option which you should probably consider regardless of performance issues.
Normally, the textures you need don't have to be in power of two dimensions, but are set to that size anyway because of the requirements of OpenGL. This often results in a very wasteful memory allocation. Utilising "sprite sheets" as you put it can help save the time & memory of loading multiple bitmaps into textures which are usually larger than the parts you'll be rendering anyway.
For this reason, I would recommend using sprite sheets anyway, simply because it saves calls to texImage2D (which are quite costly), and potentially saves memory as well. If you properly manage the texture coordinates when switching between objects you want to render, this is the method I would recommend.
Setup:
I have implemented a native (read JNI) mechanism to copy pixels from a Bitmap object, to native memory. This is done by malloc() uint23_t array in native memory and later using memcpy() to copy pixels to/from Bitmap's native pointer. This works well and have been tested. Pixels are successfully saved in native memory from a Bitmap object, and copied back to a Bitmap object, and visible on screen. Its pretty fast in copying, up to order of several milliseconds for fairly large bitmaps. But extremely slow in rendering it.
Intention:
The above was done to break free of heap limit on default android Bitmaps (refer to https://stackoverflow.com/a/1949205/1531054). There would be only 1 Java Bitmap object acting as buffer between native memory and target canvas.
Save a shape:
clear Buffer Bitmap.
Draw shape on Bitmap.
Copy pixels to native memory, and save the memory pointer.
Clear Buffer Bitmap.
So, any number of shapes can be saved to native memory, without running into heap size limits. This works.
Later when need to draw a shape (say in onDraw()):
clear Buffer Bitmap.
Copy pixels from native memory, to Buffer Bitmap, using the saved memory pointer.
Draw Buffer Bitmap on canvas.
Clear Buffer Bitmap.
Repeat again for next shape.
Problem When quickly drawing many shapes from memory, The Buffer Bitmap sorts of lags. Basically we're doing
clear bitmap -> load pixels from memory onto it -> draw it on view canvas
in Quick succession inside onDraw(), only the latest shape's pixels are drawn onto canvas. It appears as if:
The internal canvas.drawBitmap() is asynchronous and copies pixels off the bitmap later sometimes.
Android's Bitmaps have some hidden caching mechanism.
Has anyone run into such trouble before ? Or has some insight regarding this ?
I know one can get native skia lib's canvas instance in JNI and draw on it, but this is a non standard way.
In recent Android versions (3.0 and on, which is the majority of devices), pixels use regular Java memory heap. With the introduction of hardware acceleration, bitmaps are drawn asynchronously, and there is a caching system that manages bitmaps loaded as textures to the GPU. Therefore the hack you are trying to do will probably degrade performance on new devices. If you need more memory, try to use largeHeap="true" in your manifest.
On relatively new Androids (from 3.0 if I recall correctly) with hardware acceleration canvas.drawBitmap method does not actually draws anything (as well as dispatchDraw, draw, and onDraw). Instead, it creates record in display list which:
Might be cached for an indefinite amount of time.
Might (and will be) drawn in the future, not right away. It is not exactly asynchronous as for now, it just executed later in the same thread.
Those two points, I think are the answer to your question.
Alternatively, you can disable hardware acceleration for your view/window and see if your approach is working.
For further reading:
http://android-developers.blogspot.de/2011/03/android-30-hardware-acceleration.html
http://developer.android.com/guide/topics/graphics/hardware-accel.html#model
I need to find a way to track positions where the loaded textures are drawn. When some of the loaded textures are overwritten, i have to delete them from memory.
I have a Remote User Interface (RUI) server which sends me a lot of small images, which are assembled and then shown on the RUI client's screen. In this scenario, i have no clue which textures are behind some other textures, so i am unable to delete them. Also, overwriting must be complete (texture behind must be totally hidden).
Is there any efficient way to achieve this tracking and deleting?
My use-case is something like this: i have a menu with button images stored on a server. Whole screen is made of fragments (buttons, scrollbars, animations etc.).
For example, when i click on a button, server sends me a multiple thumbnails of pictures stored in its storage, and i display them in ,for example, right half of the screen.
On other button click, list of songs, videos, ebooks or something else are shown.
I need to remove textures of picture thumbnails from memory and then show list of songs, for example. In this way, overwriting will disappear, and my memory usage will be significantly reduced.
My openGL ES 2.0 implementation is on Android platform, where whole job is done in JNI layer. There is no complicated drawing, just decoding png images, converting to textures, and basic textures displaying.
You can do something along the lines of reference counting to keep track of how many times the same image has been used. When an instance is entirely occluded or off-screen, you decrement the reference count, and delete all the textures with 0 references.
Reference counting could be as simple as a std::map<Texture, int>.
Your occlusion check could just be an O(n^2) AABB intersection/containment test and an extra O(n) test against the screen's AABB. If that's not fast enough for you, try a better data structure like a quadtree or spatial hashing.
Depending on how your application is set up, you could also track instances of your texture with a type of smart pointer and figure out when all of your hidden views have been deleted.
That being said, this is probably a waste of time unless you're actually bound by the amount of VRAM on the device or getting close to it. Loading/unloading images from either disk or a network location is going to be orders of magnitude slower than just keeping it in VRAM if you have it available.
I would like to create a Canvas instance that is too big to be backed by a heap memory Bitmap, lets say 5000x5000 pixels (approx. 95MB). I would like this very large Canvas to send all the various draw operations directly to a bitmap file. Unfortunately the Bitmap class in Android is marked final so I can't provide my own implementation. Does anyone have an idea if and how this might be accomplished? I'm not very interested in performance, 10 seconds to write make a few dozen draw operations is fine, the goal is to not get out of memory errors.
There's no facility to provide the function you are asking, and even if there were, to do such operations to a file would provide horrendous performance.
Probably the only reasonable way is to only store the drawing operations, and create a Canvas that is the same size as the device screen that would serve as a "window" into the while 5000x5000 pixel canvas. For detailed explanation see my answer to a related question here: Android - is there a possibility to make infinite canvas?
Here is an idea I had that I think could theoretically work, but would probably require far too much effort:
Create a subclass of Canvas that contains many smaller Canvas objects inside it. These would represent tiles of the overall Canvas. These tiles should be small enough to fit in memory at least one at a time. Create one file for each inner tile Canvas and use it to store uncompressed pixel data from a Buffer.
When a draw operation occurs on the overall Canvas figure out which tiles need to be drawn to. One at a time read the file for that tile into a Bitmap in memory and perform the possibly clipped draw and then save the Bitmap data back to the file and close it.
Theoretically it sounds possible, realistically it sounds like too much work.
I have an application where I am generating many Bitmap objects. Once I create a bitmap, all the remaining bitmaps will be the same size.
Currently I can I load/create a new bitmap in about 50-80 ms on my phone, which works for what I need. However due to the rapid pace of creating these I am hitting constant GC.
I would like to re-use the same bitmap object, but am not sure how to do this through the sdk.
I did compile libjpeg and load my images through the NDK and re-use my bitmaps, however my loading speed dropped to about 200 ms, which is too slow.
I'll post code later when I have it in front of me.
Questions:
Is there a way to re-use my bitmap objects to avoid GC?
Is there a faster way to load my images through the NDK? Is it possible to hook in to the way the OS is loading the bitmaps? I know about libjpegTurbo, but I cannot get it to compile currently(another topic for another day).
Any other thoughts on the best way to do this.
Why not use a hashmap to store your bitmaps? Then when you load a bitmap, check to see if its in the hashmap first and if it is you can reuse it. If it is not in the hashmap, save it normally and then insert it into the hashmap.
I would recommend using IntBuffer(s) which contain the pixel data that you need to swap out. Then, create one bitmap of the size you need, and when you need to swap out the pixels, use bitmap.copyPixelsFromBuffer(). I imagine it will be MUCH faster than allocating/deallocating bitmap memory every time you need to change the pixel data. It might be a good idea to keep the buffers in a hashmap if you want to keep them in memory for quick retrieval.
Optionally you could use setPixels() with an array of int's. The nice thing about copyPixelsFromBuffer() is that no pixel conversion is attempted, and there are less options, so it might be a little faster.