I am rendering objects via OpenGL, and got a nice smooth framerate of 60fps in most situations.
UNTIL I do something heavy in a background thread, like fetching stuff from a REST API, processing it, and adding objects to the graph (low-priority stuff, I care more about UI fluidity). The renderer will then pause for a very long period, up to 1 second (ca. as long as the background thread runs), and then resume as if nothing had happened. I noticed this because an animation is started at the same time, and it gets stuck for this period. The background thread is set to minimum priority, and garbage collection does take up to 100-200ms, but not the whole second. When I set a debug point anywhere in the background task, rendering continues just fine, without any delays.
Is it possible that my heavy background thread starves the OpenGL thread? If so, what can I do?
Of course! A GPU needs to be fed data, and that's done by the CPU. So, if something in the system bottlenecks, like I/O or CPU processing, then the GPU can't get fed. For example, animation is traditionally done on the CPU. This is why you get a lot of games on the PC getting higher frame rates with the same graphic chips but with different CPUs.
I also agree that profiling is a very good idea. If you can, I would suggest profiling to make sure it's actually the REST call, or if the REST call is one of many things
One thing I noticed about REST processing, and this happened to me. Since REST sometimes processes a lot of strings, and if you don't use StringBuilder, you can end up firing off a lot of garbage collection. However, it doesn't sound like you are getting this.
Related
I am a mediocore android developer for years. I like android but there's a big problem; frame drops. Even the most powerful ones can stutter so frequently while IOS devices can run at constant 60fps. I just can't understand why. I want to know it. So first thing i did was watching an I/O presentation about performance. And i didn't really understand one thing. Why can't ui and render thread run at the same time ? Yeah i know the basics like render thread can't know what to render while ui thread is doing it's thing but why can't render thread render the frame before? You can see the video here:
https://youtu.be/9HtTL_RO2wI?t=491
And here's a diagram what am i asking for:
You get the idea. I don't know about low level things about android, can anyone explain this like i'm five.
Your process' main thread is responsible for the rendering of the frames that will be presented to the user, so you should keep the code running there as fast and light as possible. If you have to do some heavy processing or access any IO (network, sdcard, etc) that may impact on the fluidity of the application since the thread may be waiting for a response.
As a good practice you should start that IO access/heavy processing on another thread to run in background and let the system decide the priority to run it, if necessary is recommended to present some feedback to the user like a ProgressBar or something to indicate that something is being processed.
Also, the Render Thread need to know what to render before it does it, so the UI Thread have to process which information the app would like to present to the user.
As #JonGoodwin points out, they both run in parallel, but usually in two cores of the same processor, as nowadays phones have at least two cores. Both threads are run in CPU, where RenderThread sends rendering commands to the GPU. Notice that this is true since API 21 (RenderThread is what enables things like ripple effect).
The problem, though, is what #LucianoFerruzzi points out: usually poor code that does too many things in the UI thread (RenderThread is not accessible, at least not with standard mechanisms).
Also, see the following episode of Android Developers Backstage: Episode 74: Graphics
I've been working on an android game for awhile now. I have the basic game implemented so now I'm going back and trying to optimize. It seems like the battery drain and CPU usage are too high for what I'm doing. I really only have my main thread and then all the drawing and updating is done on a separate thread.
Below is the code for the actual game thread that does updating and all the drawing. All of the actual code has been removed, what's left is what I've been experimenting with to figure out the abnormal CPU usage/battery drain.
So basically if I start the below thread with only an infinite while loop the app uses about 315mAh or about 9% of my phones battery in 30 minutes of use. If I start the thread with no code inside the run method so that it expires after one run through it uses roughly 70mAh or 2% of the phone battery in the same amount of time. The CPU usage also jumps from 2%-3% without the thread running to about 14%-15% when the thread running and just running the infinite loop.
To summarize it seems like running the thread with only an infinite while loop, that does nothing, increases the battery usage by 7% over 30 minutes. I don't see how this is possible and think I must be missing something. I'll keep working to figure this out but there's no more code to take out. If anyone has any suggestions or can provide some insight as to why this is happening I'd greatly appreciate it. Thanks in advance.
class InnerThread extends Thread
{
public InnerThread()
{
super();
}
public void run()
{
while(true){}
}
}
Loops with no delay or pacing are notorious for hogging CPU and battery. Think carefully about whether you really need to be processing continuously, or if once per frame, once per arbitrary time interval, or once each time some external event occurs would be sufficient. Try adding a small arbitrary delay in the loop, and you'll probably see an immediate improvement.
Many games use a main game loop. That's a searchable term. Basically, an endless loop performs some computations, draws a frame, then usually sleeps for some time. (See SystemClock.sleep() vs. Thread.sleep().) Your main loop could pass a frame number and timestamp to the rest of your code. You might compute the positions of moving objects every frame, but you could do more complex things like update the AI of your enemies only at certain intervals of time or frames. If you use a game engine like Unity, the main loop is still there, but you don't write it yourself. You just write the code that it calls every frame.
while(true) is a classical endless loop and probably not required in Java.
it does not even matter on which thread it runs, it's most likely draining the juice.
see Are "while(true)" loops so bad?
I went through and edited my code. Utilizing thread.sleep to limit the overall drawing and updating code to 60 frames per second. Also I made use of the Object.wait() and Object.notify() methods to reduce the unnecessary processing of the thread. I've seen huge improvements, thanks for the help, I really appreciate it. My problem was most definitely that I was wasting battery and CPU power processing nothing.
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'm trying to use Android and OpenGL 2.0 to create a sort-of desert racing game. At least that's the end goal. For the time being I'm really just working with generating an endless desert, through the use of a Perlin noise algorithm. However, I'm coming across a lot of problems with regard to concurrency and synchronization. The program consists of three threads: a "render" thread, a "geometry" thread which essentially sits in the background generating tiles of perlin noise (eventually sending them through to the render thread to process in its own time) and a "main" thread which updates the camera's position and updates the geometry thread if new perlin noise tiles need to be created.
Aforementioned perlin tiles are stored in VBOs and only rendered when they're within a certain distance of the camera. Buffer initialization always begins immediately.
This all works well, without any noticeable problems.
HOWEVER.
When the tiles are uploaded to the GPU through glBufferData() (after processing by the separate geometry thread), the render thread always appears to block. I presume this is because Android implicitly calls glFinish() before the screen buffer is rendered. Obviously, I'd like the data uploading to be performed in the background while everything else is being drawn - even taking place over multiple frames if necessary.
I've looked on google and the only solution I could find is to use glMapBuffer/glMapBufferRange(), but these two methods aren't supported in GLES2.0. Neither are any of the synchronization objects - glFenceSync etc. so...
....
any help?
P.S. I haven't provided any code as I didn't think it was necessary, as the problem seems more theoretical to me. However I can certainly produce some on request.
A screenshot of the game so far:
http://i.stack.imgur.com/Q6S0k.png
Android does not call glFinish() (glFinish() is actually a no-op on IMG's GPUs). The problem is that glBufferData() is not an asynchronous API. What you really want is PBOs which are only available in OpenGL ES 3.0 and do offer the ability to perform asynchronous copies (including texture uploads.)
Are you always using glBufferData()? You should use glBufferSubData() as much as possible to avoid reallocating your VBO every time.
I am porting my game, from iOS to Android. Mostly, it's working just fine. I'm mostly using C/C++ code, with the NDK / JNI, and a little Java to manage the app life-cycle and send touches and accelerometer info to my game.
As far as I can tell, there are 2 threads, the main UI thread, and a thread created by GLSurfaceView to handle display and flipping OpenGL back-buffers etc.
So, all is working well, apart from the touches. They feel sluggish and unresponsive, compared to other apps I have tried on my devices. After doing some research, I believe the issue may relate to how I am using threads. Specifically, I think, it could be related to not sleeping the display thread after it does it's work, and so, it's holding things up on the main UI thread. Does that sound plausible?
I tried computing how many ms I need the GLSurfaceView display thread to sleep, and then sleep(), and it improves the touches, but the animation is no longer a constant 60FPS on my devices. My suspicion is that I am computing the number of ms to sleep for the previous frame, and using that number to sleep for the current frame.
Or, it could be something altogether different? I don't know. I'm still very new to Android...
Hope someone can shed some light on the matter, or point me in the right direction.
Thanks,
You don't have to sleep the GL thread. In fact, I'd say sleeping the GL thread would make it even more sluggish since it's the thing rendering the images on the screen.
Sluggish UI is caused primarily by the main UI thread being held up. If you're doing a lot of processing on the main thread (accelerometer data for example), the main thread will have to do the work first and THEN handle your user input. This can give the "feeling" of sluggishness. All touch events and non-opengl drawing events must happen in the UI thread. Anything else can occur in a background thread which wouldn't block the UI thread for an extended period of time.
Aside from that, the other possibility is you're simply overloading the processor. Your GL thread might be taking a long time to draw. It's probably receiving and handling touch events and accelerometer data. However, if the render takes a really long time, then you'd be seeing out-dated data. Thus, it again feels "sluggish". You mentioned that it's not a constant 60 FPS so this is a very real possibility. You may have optimize your drawing code so the render is faster.