A 500ms camera clear spike, seriously?

MicktuMicktu UkrainePosts: 21Member
edited August 2013 in Unity on OUYA
I lurked around the net looking for information on clear spikes - they seem to be happening a lot on Android. However, I found no definite answer. And then I got this:

image

Now that's disgusting. Can any of the Unity gurus here elaborate on why this could be happening? Is it something wrong with Unity or Android, or can it be addressed by me?
Post edited by Micktu on

Comments

  • tgraupmanntgraupmann Posts: 2,869Administrator, Team OUYA
    That is a bit insane. Do you get the same spikes if you set the camera to Don't clear? I know it won't look right but maybe something else is going on?
    ~Tim Graupmann
    OUYA Inc | Android Developer
    Skype: tgraupmann_prey

    http://github.com/ouya/docs
    http://github.com/ouya/ouya-sdk-examples

    Check out the latest docs for your game engine: [setup] [adobe air] [android] [clickteam fusion] [construct 2] [corona] [libGDX] [game maker] [html5] [marmalade] [monogame] [unity] [unreal]

    Use caution when setting [persistent wireless mode].
  • MicktuMicktu UkrainePosts: 21Member
    Going to test with Depth and Nothing settings.
  • MicktuMicktu UkrainePosts: 21Member
    edited August 2013
    The spikes are still there, but are now identified as DrawVBO now by the profiler. I'm fairly confident that the problem is not directly in my code, nothing is happening at the time spikes happen.

    The single 600-tri mesh I am rendering is not even being modified at that time. The mesh is MarkDynamic() and is not double-buffered.
    Post edited by Micktu on
  • tgraupmanntgraupmann Posts: 2,869Administrator, Team OUYA
    How does the overdraw look? If all 600 tris are overlapping that could be bad?
    ~Tim Graupmann
    OUYA Inc | Android Developer
    Skype: tgraupmann_prey

    http://github.com/ouya/docs
    http://github.com/ouya/ouya-sdk-examples

    Check out the latest docs for your game engine: [setup] [adobe air] [android] [clickteam fusion] [construct 2] [corona] [libGDX] [game maker] [html5] [marmalade] [monogame] [unity] [unreal]

    Use caution when setting [persistent wireless mode].
  • MicktuMicktu UkrainePosts: 21Member
    It's a tightly packed tile map, so no overdraw should be happening, setting aside minor off-screen overdraw for smooth scrolling.

    Actually, I was wrong and for some reason the mesh is being updated every frame even though no change occurs - let's consider this a bug, but that's irrelevant because updating the mesh every frame will be a common scenario for the most of the time in the game.




  • Killa_MaakiKilla_Maaki Posts: 504Member
    edited August 2013
    micktu said:
    It's a tightly packed tile map, so no overdraw should be happening, setting aside minor off-screen overdraw for smooth scrolling.

    Actually, I was wrong and for some reason the mesh is being updated every frame even though no change occurs - let's consider this a bug, but that's irrelevant because updating the mesh every frame will be a common scenario for the most of the time in the game.
    Just wanted to say - updating the mesh every frame in Unity is surprisingly slow, unfortunately. It's I think a consequence of how their Mesh API does its stuff.
    This is on all platforms, too - not just OUYA. For instance, I noted that I had an NGUI UI that had a radar sweep, which caused the entire UI to update every frame. When profiling I realized this was actually taking a large chunk of CPU time, and getting rid of the radar sweep fixed it - on Desktop, no less. Imagine how it would be on mobile.

    So try fixing the mesh update and see if that fixes it.
    Post edited by Killa_Maaki on
    You didn't remember the plot of the Doctor Who movie because there was none; Just a bunch of plot holes strung together.
  • MicktuMicktu UkrainePosts: 21Member
    I disagree on this, updating the mesh is fast enough even without tricks like double buffering since Unity 4.0. My game and rendering logic running on top of Futile framework is profiled to be capable of maintaining 4000 fps on my PC and 120fps on Ouya while updating the mesh every frame. I think that if it actually was the mesh modification problem, I'd have huge CreateVBO times. From what I've seen on the internet, OpenGLES DrawVBO spikes usually happen to people using specific shaders.

    After I fix my funny little update bug to make sure I am not updating the mesh unless I have to, I'll tell you if the spikes are still there. I assume they will be.
  • tgraupmanntgraupmann Posts: 2,869Administrator, Team OUYA
    Try delaying doing a mesh.Apply() by 100ms and see what happens?
    ~Tim Graupmann
    OUYA Inc | Android Developer
    Skype: tgraupmann_prey

    http://github.com/ouya/docs
    http://github.com/ouya/ouya-sdk-examples

    Check out the latest docs for your game engine: [setup] [adobe air] [android] [clickteam fusion] [construct 2] [corona] [libGDX] [game maker] [html5] [marmalade] [monogame] [unity] [unreal]

    Use caution when setting [persistent wireless mode].
  • MicktuMicktu UkrainePosts: 21Member
    I don't really understand what do you mean by mesh.Apply() and what would that achieve.

    Anyway, I fixed my little bug, and the mesh is no longer updated when nothing is happening. And spikes are still there.
  • MicktuMicktu UkrainePosts: 21Member
    Using the Mobile/Particles/Alpha Blended shader instead of Sprites/Pixel Snap/Alpha Blended reduced the prominence of DrawVBO spikes to a completely satisfactory level. However, once I changed camera clearing back to SolidColor... IT KEEPS HAPPENING!

    Thus we're back to square one.
  • tgraupmanntgraupmann Posts: 2,869Administrator, Team OUYA
    Ah I guess Apply is my own function which sets the changed verts, tris, uvs but only if changed.

    ~Tim Graupmann
    OUYA Inc | Android Developer
    Skype: tgraupmann_prey

    http://github.com/ouya/docs
    http://github.com/ouya/ouya-sdk-examples

    Check out the latest docs for your game engine: [setup] [adobe air] [android] [clickteam fusion] [construct 2] [corona] [libGDX] [game maker] [html5] [marmalade] [monogame] [unity] [unreal]

    Use caution when setting [persistent wireless mode].
  • tgraupmanntgraupmann Posts: 2,869Administrator, Team OUYA
    At least you can prepare the mesh arrays in another thread. And then just do the assignment in the main thread.
    ~Tim Graupmann
    OUYA Inc | Android Developer
    Skype: tgraupmann_prey

    http://github.com/ouya/docs
    http://github.com/ouya/ouya-sdk-examples

    Check out the latest docs for your game engine: [setup] [adobe air] [android] [clickteam fusion] [construct 2] [corona] [libGDX] [game maker] [html5] [marmalade] [monogame] [unity] [unreal]

    Use caution when setting [persistent wireless mode].
  • MicktuMicktu UkrainePosts: 21Member
    Ah I guess Apply is my own function which sets the changed verts, tris, uvs but only if changed.

    I definitely could but I have no reason to, that's not the cause of the issue. Camera clear still produces spikes that are absent in a Don't Clear scenario.
  • tgraupmanntgraupmann Posts: 2,869Administrator, Team OUYA
    Did you try setting the Java Class Name in the OUYA panel to OuyaNativeActivity? It shouldn't make a difference, but it's worth a try?
    ~Tim Graupmann
    OUYA Inc | Android Developer
    Skype: tgraupmann_prey

    http://github.com/ouya/docs
    http://github.com/ouya/ouya-sdk-examples

    Check out the latest docs for your game engine: [setup] [adobe air] [android] [clickteam fusion] [construct 2] [corona] [libGDX] [game maker] [html5] [marmalade] [monogame] [unity] [unreal]

    Use caution when setting [persistent wireless mode].
  • MicktuMicktu UkrainePosts: 21Member
    Did you try setting the Java Class Name in the OUYA panel to OuyaNativeActivity? It shouldn't make a difference, but it's worth a try?
    Thanks, I am going to try and see if it makes a difference.
  • MicktuMicktu UkrainePosts: 21Member
    By the way, should I be using a specific versions of SDKs to avoid additional issues? I'm using JDK 1.6.0_45, Android SDK Rev. 21, and NDK r8e.
  • tgraupmanntgraupmann Posts: 2,869Administrator, Team OUYA
    NDK r9 is out. But all that sounds fine. JDK 32-bit 1.6.
    ~Tim Graupmann
    OUYA Inc | Android Developer
    Skype: tgraupmann_prey

    http://github.com/ouya/docs
    http://github.com/ouya/ouya-sdk-examples

    Check out the latest docs for your game engine: [setup] [adobe air] [android] [clickteam fusion] [construct 2] [corona] [libGDX] [game maker] [html5] [marmalade] [monogame] [unity] [unreal]

    Use caution when setting [persistent wireless mode].
  • MicktuMicktu UkrainePosts: 21Member
    After a bit of play testing I can testify that the above mentioned camera spike does not seem to affect the game in any way - it actually runs perfectly well at 60Hz@1080p. One of my assumptions is that it is actually introduced by the presence of the profiler, or only relevant to development builds. However, if it turns out later that this is not the case, I'll update the thread.

    Tim, if you're still there, I have an unrelated question in mind. Even a whole story. So here it is.

    A few days ago I was basically ripping my hair out because after a series of optimizations my game was running choppy on the device for not obvious reason. I actually tested my virtual camera movement alone, and it was perfectly smooth. However, character movement was in ruins, as if I had a major screen refresh desync.

    After wandering aimlessly for a bit I have suddenly managed to connect the dots: in my tests, I was moving the camera with static offset per frame. There was no delta. Promptly, I abandoned Time.deltaTime and started feeding my Update() with 1f / Screen.currentResolution.refreshRate instead. And it turned out perfectly smooth, not a twitch, not a slowdown.

    So, to the actual questions.

    Is it normal that Time.deltaTime is so inaccurate on the device, and do you happen to know a reason behind this? I should note that smoothDeltaTime also wasn't doing well, so the timing error was pretty damn high. 

    Is it okay to use the fixed delta approach as long as I can maintain a steady framerate w/vsync?

    Will Ouya try and run at 120Hz if it happens to be connected to such a display (thus forcing my game to run at 120FPS - I wanna know if I should take care of this scenario)?

  • Killa_MaakiKilla_Maaki Posts: 504Member
    micktu said:
    After a bit of play testing I can testify that the above mentioned camera spike does not seem to affect the game in any way - it actually runs perfectly well at 60Hz@1080p. One of my assumptions is that it is actually introduced by the presence of the profiler, or only relevant to development builds. However, if it turns out later that this is not the case, I'll update the thread.

    Tim, if you're still there, I have an unrelated question in mind. Even a whole story. So here it is.

    A few days ago I was basically ripping my hair out because after a series of optimizations my game was running choppy on the device for not obvious reason. I actually tested my virtual camera movement alone, and it was perfectly smooth. However, character movement was in ruins, as if I had a major screen refresh desync.

    After wandering aimlessly for a bit I have suddenly managed to connect the dots: in my tests, I was moving the camera with static offset per frame. There was no delta. Promptly, I abandoned Time.deltaTime and started feeding my Update() with 1f / Screen.currentResolution.refreshRate instead. And it turned out perfectly smooth, not a twitch, not a slowdown.

    So, to the actual questions.

    Is it normal that Time.deltaTime is so inaccurate on the device, and do you happen to know a reason behind this? I should note that smoothDeltaTime also wasn't doing well, so the timing error was pretty damn high. 

    Is it okay to use the fixed delta approach as long as I can maintain a steady framerate w/vsync?

    Will Ouya try and run at 120Hz if it happens to be connected to such a display (thus forcing my game to run at 120FPS - I wanna know if I should take care of this scenario)?

    No, that's most definitely not normal. You might want to run some tests on Time.deltaTime - maybe log the value of 1f / Time.deltaTime (current framerate)?
    You didn't remember the plot of the Doctor Who movie because there was none; Just a bunch of plot holes strung together.
  • MicktuMicktu UkrainePosts: 21Member
    No, that's most definitely not normal. You might want to run some tests on Time.deltaTime - maybe log the value of 1f / Time.deltaTime (current framerate)?

    I could if you're interested. I didn't do that just because I didn't realize it was the problem, and when I did realize, I fixed it this wierd way.
  • MicktuMicktu UkrainePosts: 21Member
    Here you go, Time.deltaTime recorded every Update().

    min 0.015385, max 0.507612, avg 0.01677468, total 324.3321s.

    It kinda averages out fine, but let's measure the difference introduced between frames instead, as in Mathf.Abs(Time.deltaTime - lastDelta):

    min 0, max 8.555999, avg 0.2318643, total 1136.831ms.

    An average of 0.2ms of error per frame. Still not the end of the world.

    Okay, let's take a look at the actual differences between frames:

    ... 0.01100078, -0.01499988, 0.04199892, -0.06200001, 0.04800037, -0.03699958, 0.01399964, 0.02299994, -0.01199916, 0.003999099, 1.427, -1.318, -0.1079999, 0.2730004,
    -0.438001, 0.1560003, 0.00699982, 2.028002, -4.089001, 2.068999, -0.02499856, 0.1229998, -0.2100002, 0.07699989, 0.0180006, 0.0169985, -0.01799874, -0.004000962
    , -0.002998859, 0.031, 0.002998859, -0.05399995, 2.702, -2.586, -0.07000007, ...

    2-5ms spikes all over the place could be the cause of the choppiness.

    My game features a 2D scrolling map, that makes even a pixel-wide jump very noticeable.
  • Killa_MaakiKilla_Maaki Posts: 504Member
    Have you tested this on a different Android device?

    That actually sounds to me a lot like garbage collection.
    You didn't remember the plot of the Doctor Who movie because there was none; Just a bunch of plot holes strung together.
  • tgraupmanntgraupmann Posts: 2,869Administrator, Team OUYA
    edited August 2013
    You could even use NDK to get the clock cycles versus using time.deltaTime, but something else must be going on. It sounds fishy. And of course if your rendering is getting 100ms spikes that would account for the choppiness.

    I typically instead of moving objects using delta time, I calculate when an action will finish and lerp between the two points. For example:

    DateTime startTime = DateTime.Now; //start of action

    DateTime endTime = DateTime.Now + TimeSpan.FromSeconds(3); //in N seconds the action will finish

    Get the elapsed time in the update frame:

    float elapsed = (DateTime.Now - startTime).TotalSeconds / 3.0f; //expecting a range 1 to 0 over the duration of endTime

    float t = 1 - elapsed; //normalize the range to 0 to 1

    now use in a lerp

    transform.position = Vector3.Lerp(startPos, endPos, t); //and now you'll get a smooth move regardless of any choppiness
    Post edited by tgraupmann on
    ~Tim Graupmann
    OUYA Inc | Android Developer
    Skype: tgraupmann_prey

    http://github.com/ouya/docs
    http://github.com/ouya/ouya-sdk-examples

    Check out the latest docs for your game engine: [setup] [adobe air] [android] [clickteam fusion] [construct 2] [corona] [libGDX] [game maker] [html5] [marmalade] [monogame] [unity] [unreal]

    Use caution when setting [persistent wireless mode].
  • MicktuMicktu UkrainePosts: 21Member
    edited August 2013
    Have you tested this on a different Android device?

    That actually sounds to me a lot like garbage collection.
    No, I haven't tested it on any other device. No GC happens at play time, it's taken care of.

    @tgraupmann

    If I haven't been able to maintain my FPS steady (i.e., if I had real spikes), I would've gotten inconsistent speed using my fixed delta, as I'm completely framerate-dependent. But in fact, it's silky smooth. It looks like Time.deltaTime lies, that's what I'm talking about.

    Yeah, my movement is calculated pretty much the way you proposed. I add the delta to my object's moving time every update, and my renderer calculates its pixel position offset as moveTime / MOVE_DURATION * TILE_SIZE. The only difference is that you use real time difference instead of Time.deltaTime (which should be the same in theory, but apparently they're not). So your solution is to calculate your own delta as well.
    Post edited by Micktu on
Sign In or Register to comment.