My project is for Android. I need to run code after rendering the frame. This is because rendering time could vary vaguely for different frames. I have some time consuming mesh and collider creation routines (So basically there is no room for multithreading because of direct interaction with unity's API). Let's say the profiler shows something like this:
When I do my coroutines I can't know how much time the rendering takes. So I can't decide how much time budget I have for the coroutine and when to yield it. It could be 20ms or it could be 1ms.
Let's reserve a constant time ,say 10ms, for coroutine execution and assume that target frame rate is 30 and physx time is negligible . Now if rendering take 5ms then 5+10=15ms and I dropped the opportunity to use 15 more milliseconds. On the contrary if the frame had a spike and took 25ms, Then 25+10=35ms and that is greater than the 30FPS target framerate resulting in a visible FPS drop. So either way the constant time has very bad consequence.
But if I could run code after rendering time, I could know exactly how much time I have before the screen refresh and yield at the right moment without losing precious time or the risk of creating a spike with my own hands!!!
I know the codes run according to unity's execution order http://docs.unity3d.com/Manual/ExecutionOrder.html. I need a workaround or any viable strategy to do coroutines reliably.
IEnumerator MyCoroutine()
{
while(true){
yield return new WaitForEndOfFrame();
// My code
}
}
http://docs.unity3d.com/ScriptReference/WaitForEndOfFrame.html
As mentioned in the docs, waits for all to be done, right before swapping the buffer. I don't think you can do anything after that without hacking the engine.
Related
I'm checking profiler performance of my game on an Android device. When I check CPU Usage I noticed that PlayerLoop is at 99.6% and the biggest percentage is consumed in Semaphore.WaitForSignal with 32.5% and the second is PlayerConnection.Poll with 27%.
Can someone explain if there is a way to improve this? Is the PlayerLoop at 99.6% "normal" or is too high?
Below screenshot results from Xiaomi MI 5 Android 8
Provided percent in the profiler is "How mutch this item, contributes to the current execute time" and not "How much CPU you are using.
What is interesting to you is time in milliseconds for the biggest items. And whether something is too much or too little depends on what framerate you want to achieve.
What is Player Loop
The Player loop is the total time your game took to render 1 frame. In there you can find, all your scripts, rendering, and other engine functions.
What is Semaphore.WaitForSignal
Your Graphics pipeline is waiting for something else to finish. Usually, it means rendering is taking a while to finish, and some other parts of the graphics pipeline can't proceed until rendering is complete.
Is Player loop 99.6% normal
Yes, it preferably should always be around 100% unless you are in the editor.
What is exactly 27ms in the player loop
Total time required to process and render one frame. To achieve 30fps in-game you need to have all frames below 33ms (1000ms/30fps)
You can find more information here: https://docs.unity3d.com/Manual/ProfilerCPU.html
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 developing a GL live wallpaper that uses very little CPU and only modest GPU. On my older test phone, it can run at a full 58fps or so most of the time. But occasionally the effects ramp up, and then the render times jitter between 16ms and 50ms per frame. For example, it'll render several frames at 16ms, slide up to 50ms over a dozen frames or so, render several more frames at 50ms, then slide back down to 16ms and repeat. I discovered that if I set the CPU governor to "performance" (or "conservative", curiously enough) instead of the default "ondemand" it'll render with full effects at full speed. Alternatively, if I leave the governor alone and insert a busy loop in my code (increment a variable 100,000 times per frame) that bumps my CPU usage up enough to transition to a higher clock rate and render smoothly as well.
So it seems on this phone my app is bottlenecked by the GPU, but only when it throttles down. Now, I wouldn't mind if the GLSurfaceView rendered at a slower rate according to the GPU clock, but my problem here is that I'm getting the bursts of alternating high and low frame rates which makes my animation look fluid/frameskippy/fluid/frameskippy/etc. several times per second. It seems like the GPU clock is ramping up and down like crazy?
I got a visible improvement by using RENDERMODE_WHEN_DIRTY and calling requestRender() on a strictly timed thread, but the darn GPU keeps ramping up and down. Why won't it either render as fast as it can at the slower clock, or just jump to and STAY AT the higher clock?
The best solution I've come up with so far is using a sliding window to detect the average frame update time, then applying the difference from the target frame time until the two values converge. The time between render updates is slower but at least it's roughly constant. So that works in theory, but it takes several seconds to reach a steady state and it looks bad in the meantime.
I think a third option might be to cannibalize the GLSurfaceView source and make a custom version. From what I understand, the blocking GL calls are made in there, so it would be much easier for me to time render calls and react accordingly. I'm not very comfortable attempting that though because there's a lot of code in there that I'd have to spend a lot of time understanding before I could even begin to mess with it. Plus I'd then have to worry about how well version X of GLSurfaceView plays with any version Y of Android.
So, with all that said, do I have any other options here? Is there an easier fix to this?
try fixing the frame rate by pausing the thread (thread sleep) for the remaining time to reach a constant frame rate.
How can I regulate the framerate in my android app? I would like the game to run at a constant speed. My app doesn't require a high framerate so I don't want one because that would take up more battery then necessary.
Don't use frame rate to measure time. Use time to measure time. A GC pass can take 3/10 of a second, other tasks can fire up in the background, etc etc.
There's always a system/setup that will run slower than you thought possible.
Then you don't specify velocities in pixels, but in pixels/second. Each frame of animation takes a certain amount of time, etc etc. In your game engine, when computing the next frame, one of your inputs is "how much time has passed since the last frame". You determine that value as a fraction of a second, and multiply your velocity/sec by that fraction. The result is how far a Given Thing has moved since the last frame.
Note that really slow frame rates can wreak havoc on collision detection, particularly with fast moving objects. If Thing 1 passes completely through Thing 2 between frames, just checking BBoxes or radii isn't going to cut it.
Having said all that, sleep() is your friend. At the start of a frame's processing, call System.currentTimeMilis(). At the end of a frame's processing (including rendering), check the current time again. If the difference isn't long enough, sleep(N) for enough time to match your desired frame rate.
So if you want 20fps max, then each frame should take 50ms (1000ms / 20 = 50ms). If a frame only took 10ms to simulate and render, then you need to sleep for another (50ms - 10ms = ) 40ms before moving on to the next frame.
Alternatively, you can keep running the simulation as fast as possible, and only render the screen every so often. This won't help battery life much (though OpenGL hardware acceleration is expensive if the heat coming off my Evo is any indication), but can make for a Very Smooth experience. Heck, you can start calculating things like motion blur at that point.