I don't understand why, but when I increase the Fixed TimeStep in the Time setting in Unity3D, I have a bad frame issue on Android only.
In iOS, I have a better performance, but Android the animation is very very bad..
Somebody can tell me why increasing the Fixed TimeStep have an issue with the FPS, but on Android, not on iOS.
A fixed time step of 60 (Hz) means Unity guarantees that the FixedUpdate method runs this many times per second, regardless of framerate. FixedUpdate can be set to run multiple times per frame even.
However you can't force a CPU to do ever more per frame/second. Eventually this will affect the framerate because there isn't enough time to compute and render a frame in the time necessary.
For instance, to get a constant 60 frames per second each frame must be computed and rendered within a 0.01666 second time window. If the computation and rendering takes 0.017 seconds Unity is no longer rendering 60 fps. If vertical synch is enabled (as it is on mobile devices) a constant time per frame of just over 0.01666 means the framerate will be 30 fps (not 55 or something). So on mobile you're more likely to notice the effect of constantly being over the 0.01666 time per frame.
If there are enough FixedUpdate iterations running per second the app has more to compute and thus takes longer per frame. Eventually the FixedUpdate iterations per frame (plus the time it takes to render) no longer complete within 0.01666 seconds, that's what you see as a drop in framerate.
Related
I try to run a high frame rate opengl program on Android. It was no more than 60 FPS.
But it was 400+ FPS running in GLTextureView. https://gist.github.com/eleventigers/9545428
As I know, SurfaceView's efficiency is much higher than TextureView. How can I set GLSurfaceView's max fps. Or write a custom SurfaceView with OpenGL.
On Android, you cannot disable screen vertical sync so anything that you display on screen is capped to 60FPS (because screen has a 60Hz refresh rate, maybe some android phones exist with a higher rate but they would be the exception).
It may be possible to disable Vsync by using custom ROMs but you cannot force your users to use those and you would probably get screen tearing which would not look good anyway.
When you report 400 FPS with GLTextureView it seems what is measured is the time needed to render into an offscreen GL texture ... so of course you can render at a very high rate in an offscreen texture but you cannot display it at more than 60FPS on screen (meaning that the extra frames are skipped and never displayed)
I've written an OpenGL ES 2 app using NativeActivity that renders around 6 textured triangles that you can drag around using touch input. The app is rendering as fast as possible, calling glClear() before and eglSwapBuffers() after rendering. As expected the frame rate is capped to the display frequency of around 60 fps and the scene moves around smoothly. However, after some time (10 to 60 seconds) the movement starts to stutter even though the frame rate is still 60 fps. The device I'm using is OnePlus 3.
At first I suspected the culprit was battery saving mode, but investigation revealed no correlation between cpus' frequencies and the stutter.
I did notice something interesting though, the stutter starts when queueBuffer() execution time goes up.
This is the systrace before stutter:
This is the systrace after stutter:
This is the systrace during the transition from before to after:
How do I stop the app from stuttering?
I still don't know the exact cause of the stuttering, but I managed to find a work-around: Only render frames on Choreographer.postFrameCallback and set eglPresentationTimeANDROID to two vsyncs in the future. This avoids filling up the buffer queue, which seems to be one of the causes of the stuttering.
As a bonus it also improved the touch input latency a little.
More info here: Minimize Android GLSurfaceView lag
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.
I'm developing an Android app which acts like a movie clapperboard/clapboard/slate. Is there any way in which I can set the display's refresh rate?
It is very important because when you edit the movie it's necessary to "land" on specific frames. The point is that if the timer is set to 25 frames per second, I need the display to update exactly 25 times per second, when the timer changes its value.
The problem on physical devices is that, let's say my Samsung Spica GT-I5700 returns a refresh rate of 62.016 which is totally inappropriate for a 25 fps timecode, and when editing you can see Frame1-Frame1-Frame2-Frame2 etc. or intermediaries, when you should see exactly Frame1-Frame2 etc.
The point is that I would need the refresh rate to be in sync with the timecode. If the user sets 25 fps, then the display should refresh exactly 25 times per second.
Any ideas, please? Thank you!
Unfortunately, there is no way to set an arbitrary refresh rate for any given device, whether it be android or not. Video circuitry is limited to the fidelity of its timers, and like all discrete systems, cannot operate with continuous precision. However, this shouldn't be too much of a problem. If you're performing a dirty render (on demand), simply base your frame build around a 25Hz system timer, and the video hardware will render it during the next raster pass - a 60Hz raster pass will almost certainly occur within your 25Hz interval. You'll also have to consider frame-dropping when the system is too busy to honour a 25Hz interval. If you're using fixed rate rendering, simply use the elapsed time between renders in order to determine the appropriate frame for a given 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.