For years now I've maintained a Tandy Color Computer Emulator applet on my home page. With the purchase of an Incredible I decided to do a port. Getting it going in Android didn't take long but I'm really surprised how slow it runs. You can literally see the pixels painting. I know there are other successful Android emulators so I must be doing something wrong.
My approach was to use a SurfaceView for rendering. There's a separate thread that runs a virtual 6809 CPU. Whenever that thread updates the emulated video memory, it calls SurfaceHolder.lockCanvas() with a Rect describing the part of the screen requiring a repaint. Then it calls the gfx routines with the resulting Canvas...this is where I did a repaint() in AWT/Swing. The gfx routines are smart enough to just render what's in the clipRect. Perhaps I'm still stuck in AWT but I can't think of any way to make this thing run at an acceptable speed. I tried to coalesce the gfx calls but that didn't work either. Any thoughts?
SurfaceView should be fast enough. All the drawing routines are smart enough to not do anything if outside of the clip region but you can cull the calls ahead of time if you want. It looks like you need to profile your app and see where you spend too much time.
Related
Over the last month, I've taken a dive into trying my hand at a simple 2d side scroller using Android's default canvas APIs.
In short, my question boils down to "Is the Canvas API performant enough to pull 60fps with a simple side scroller with a multi-layer, parallaxing background?".
Now hear me out, because I've tried a ton of different approaches, and so far I've come up fairly empty handed on how to squeeze any more efficiency out of what I've attempted.
First, to address the easy problems:
I'm not allocating anything in the game loop
The Surface is Hardware Accelerated
Bitmaps are being loaded prior to starting the game, and drawn without scaling.
I don't believe I'm doing anything significant aside from the bitmap drawing in the game loop (mostly updating position variables and getting time)
The problems started, as you may have guessed, with the parallaxing BG. Seven layers in total, though I've been experimenting with as few as 3 while still unable to maintain 60fps. I'm clipping the parts that are overlapping to minimize overdraw, but I would guess I'm still drawing ~2-3x overdraw, all summed up.
As the game runs, I often start out at ~ 60fps, but about 30/40 seconds in, the fps drops to about 20. The time is random, and it seems to be a state of the phone, rather than a result of anything in the code (force killing the app & restarting causes the new app to start at ~20fps, but letting the phone sit for a while results in higher fps). My guess here is thermal throttling on the CPU...
Now I'm testing on a 5x, and naively thought these issues might disappear on a faster device (6P). Of course, due to the larger screen, the problems got worse, as it ran at ~15fps continuously.
A co-worker had suggested loading in small bitmaps and stretching them on draw, instead of scaling the bitmaps on load to the size they would appear on the screen. Implementing this by making each bitmap 1/3rd the size, and using the canvas.drawBitmap(bitmap, srcRect, destRect, Paint) method to compensate for size and scale yielded worse performance overall (though I'm sure it helped the memory footprint). I haven't tried the drawMesh method, but I imagined it wouldn't be more performant that the plain old drawBitmap.
In another attempt, I gave an array of ImageViews a shot, thinking the Android View class might be doing some magic I wasn't, but after an hour of fiddling with it, it didn't look any more promising.
Lastly, the GPU profiling on the device remains far beneath the green line, indicating 60fps, but the screen doesn't seem to reflect that. Not sure what's going on there.
Should I bite the bullet and switch over to OpenGL? I thought that Canvas would be up to the task of a side-scroller with a parallaxing background, but I'm either doin' it wrong™, or using the wrong tool for the job, it seems.
Any help or suggestions are sincerely appreciated, and apologies for the long-winded post.
I am building a game like application using android NDK and openGL ES 2.0
So far I understand the concept of vertices and shaders and programs.
The main game loop would be a loop in a single thread as follows
step 1. Read all the user input
step 2. Update game objects (if needed) based on the input
step 3. make draw calls for all the objects
step 4. call glSwapBuffers
then loop back to step 1
But I ran into various confusions regarding sync and threading so I'm listing all the question together.
1.Since open GL draw calls are asynchronous the draw calls and glSwapBuffers may get called many times before the gpu has even rendered actually a single frame from calls from last iteration of loop. Will this be problematic? buffer overflow or tearing ?
2.Assuming VSYNC is enabled then does point 1 still causes problem?
3.Since all calls are async how do I measure the time spent rendering each frame? glSwapBuffers would return immediately so how can I know when was the frame actually done?
4.loading textures will occupy space in the ram is checking free memory before loading texture standard way or I should keep loading textures until I reach OUT_OF_MEMORY_ERROR?
5.If I switch to multithreaded approach calling just glswapbuffers at a fixed 60 times per second without any regard to the thread which is processing input and giving out draw calls then what is supposed to happen?
Also how do I control the fps in game loop? I know the exact fps depends on a large no of factors but how can you go close to that
The SwapBuffers() will not be executed out of order. Issuing it after all of the draw commands for the frame is fine. The driver will take care about it, you don't need to sync anything. You can only screw this about by using multiple threads or multiple contexts, but even that would take a lot of effort.
There is no problem with 1, and VSYNC does not directly change anything here.
The calls might be asynchronous, but the driver will not queue up an unlimit amount of work. Sooner or later, it will have to block, if you try to issue too many calls in advance. When vsync is on, the typicial behavior is that the driver will queue up at most a few frames (or just one, depending on the driver settings), and SwapBuffers() will block when that limit is reached. So the timing statistics you get there are accurate, after the first few frames. Note that this is still much better than completely flushing the queue, as the driver unblocks as soon as the first pending buffer swap was carried out.
This is a totally new topic, which probably belongs into another question. However: It is very unlikely that you get any of the current desktop GL implementations to ever generate GL_OUT_OF_MEMORY. The driver will automatically page textures (and other objects) between VRAM and system RAM (and the OS might even page that to disk). The GL also provides no means to query the available memory.
In that scenario, you will need to synchronize manually. That approach does not make the slightest sense and seems like trying to solve a problem which does not exist. If you want your game to use multithreading, still put all the gl rendering (and swapbuffers) into the same thread. You can use different threads for input processing, sound, physics, update of the scene, general game logic and whatever. But you should just use a single thread/single context approach for the GL. That way, it also won't hurt you when SwapBuffers() blocks your render thread, as your game logic and input handling is still done, and the render thread will just render new frames with the newest available data in the frequency the display needs (with vsync on) or as fast as the CPU and GPU can work (if vsync is off).
I have a problem with very low rendering time on an android tablet using the NDK and the egl commands. I have timed calls to eglSwapBuffers and is taking a variable amount of time, frequently exceeded the device frame rate. I know it synchronizes to the refresh, but that is around 60FPS, and the times here drop well below that.
The only command I issue between calls to swap is glClear, so I know it isn't anything that I'm drawing causing the problem. Even just by clearing the frame rate drops to 30FPS (erratic though).
On the same device a simple GL program in Java easily renders at 60FPS, thus I know it isn't fundamentally a hardware issue. I've looked through the Android Java code for setting up the GL context and can't see any significant difference. I've also played with every config attribute, and while some alter the speed slightly, none (that I can find) change this horrible frame rate drop.
To ensure the event polling wasn't an issue I moved the rendering into a thread. That thread now only does rendering, thus just calls clear and swap repeatedly. The slow performance still persists.
I'm out of ideas what to check and am looking for suggestions as to what the problem might be.
There's really not enough info (like what device you are testing on, what was you exact config etc) to answer this 100% reliable but this kind of behavior is usually caused by window and surface pixel format mismatch eg. 16bit (RGB565) vs 32bit.
FB_MULTI_BUFFER=3 environment variable will enable the multi buffering on Freescale i.MX 6 (Sabrelite) board with some recent LTIB build (without X). Your GFX driver may needs something like this.
I've cobbled together a simple game loop, mostly using the techniques that seem be be prevelent, particually in the Killer Game Programming in Java book and in this tutorial I just found: Here
Just a simple, timed gameloop with a back buffer.
The problem is that it won't redraw the screen at a good FPS. The best I can get out of my Motorola Xoom is 15FPS, aiming for 24.
If I half the size of the back buffer, the speed shoots up considerably so I'm guesing the problem may have something to do with utilizing the screen on the Xoom ( the size of my SurfaceView is 1280x727 )... yet other games seen to run perfectly well at the same size.
I don't have any other devices to test on so I'm a little stuck for what to do at the moment.
What am I doing wrong/missing/ignorant of?
Maybe that the pixel formats of your bitmap and the surface differ, causing a conversion whenever you draw the bitmap? That would certainly induce overhead. Try and experiment with SurfaceHolder.setFormat() to see if that helps.
Since your bitmap is using Bitmap.Config.ARGB_8888, you could try to set the surface holder format to PixelFormat.RGBA_8888. Or, if you can, then try and use Bitmap.Config.RGB_565, and PixelFormat.RGB_565.
Going to need some code but I suspect you are not using any threads? If you are not using Threads then you program will be unstable and crash quite often due to all your processing being on the same Thread
In short make sure you have created a new Thread, I use OpenGL which requires a thread anyway so that may be your best route to go down
I'm trying to put a particle system together in Android, using OpenGL. I want a few thousand particles, most of which will probably be offscreen at any given time. They're fairly simple particles visually, and my world is 2D, but they will be moving, changing colour (not size - they're 2x2), and I need to be able to add and remove then.
I currently have an array which I iterate through, handling velocity changes, managing lifecyling (killing old ones, adding new ones), and plotting them, using glDrawArrays. What OpenGl is pointing at, though, for this call, is a single vertex; I glTranslatex it to the relevant co-ords for each particle I want to plot, one at a time, set the colour with glColor4x then glDrawArrays it. It works, but it's a bit slow and only works for a few hundred particles. I'm handling the clipping myself.
I've written a system to support static particles which I have loaded into a vertex/colourarray and plot using glDrawArrays, but this approach only seems suitable for particles which will never change relative location (ie I move all of them using glTranslate), colour and where I don't need to add/remove particles. A few tests on my phone (HTC Desire) suggest that trying to alter the contents of those arrays (which are ByteBuffers, pointed to by OpenGL) is extremely slow.
Perhaps there's some way of manually writing the screen myself with the CPU. If I'm just plotting 1x1/2x2 dots on the screen, and I'm purely interested in writing and not doing any blending/antialiasing, is this an option? Would it be quicker than whatever OpenGl is doing?
(200 or so particles on a 1ghz machine with megs of ram. This is way slower than I was getting 20 years ago on a 7mhz machine with <500k of ram! I appreciate I'm using Java here, but surely there must be a better solution. Do I have to use the NDK to get the power of C++, or is what I'm after possible)
I've been hoping somebody might answer this definitively, as I'll be needing particles on Android myself. (I'm working in C++, though -- Currently using glDrawArrays(), but haven't pushed particles to the limit yet.)
I found this thread on gamedev.stackexchange.com (not Android-specific), and nobody can agree on the best approach there, but you might want to try a few things out and see for yourself.
I was going to suggest glDrawArrays(GL_POINTS, ...) with glPointSize(), but the guy asking the question there seemed unhappy with it.
Let us know if you find a good solution!