Alternative to NSTimer

Member
Posts: 166
Joined: 2009.04
Post: #46
DoG Wrote:Not sure where that is coming from, but that statement isn't universally valid, and most certainly you can get much finer granularity from a timer, depending on the environmental factors.

Also, I think there's a confusion about what I am saying.

There's two things:
A) use of a second thread
B) use of a custom loop

You can do A) without doing B) by instantiating a run loop on the second thread. Since that run loop would not handle *any* other source than your timer, it should fire at the exact expected intervals, as long as your callback doesnt take too long.

If you have congestion on the main thread, then going to a second thread will help will help with the apparent jitter of the updates, but it will also increase latency, since whatever happens in the main thread and your game thread will have to be executed in parallel, so both tasks will take longer than when running alone. So there's always a trade-off.


A custom loop is a better choice ... it is dead easy to code and having another thread just for handling timing is a waste.

After all, your game is driven by its own update loop and thus you can get just about perfect timing ( if you are done ahead of time , simply forward any further processing to the default loop for whatever amount of time you have left. )
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #47
Folks who find NSTimer insufficient should file a feature request for a better API.

For example, if want to know when the screen refresh happened so that you can redraw your scene, you should ask for API that lets you register for notification of screen refreshes. That way you're responding to a real hardware event, not some arbitrary timer that has no relation to anything.
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #48
arekkusu Wrote:Folks who find NSTimer insufficient should file a feature request for a better API.

For example, if want to know when the screen refresh happened so that you can redraw your scene, you should ask for API that lets you register for notification of screen refreshes. That way you're responding to a real hardware event, not some arbitrary timer that has no relation to anything.

It's a mystery. In all the years OS X has been around now, Apple has apparently shown no interest in providing a hardware generated VBL callback (irq, or whatever). I gave up complaining about it years ago. Glad to see there is a new breed of whiners in this thread to take my place!

That said, there is a lot of [mis]information in this thread. Folks would be wise to read DoG's posts a little more carefully.

[edit] I meant to say *mis*information, but had a Freudian slip and said *dis*information originally because it seems to me there is a bit of misinformed bias from a few angles.
Quote this message in a reply
Member
Posts: 166
Joined: 2009.04
Post: #49
arekkusu Wrote:Folks who find NSTimer insufficient should file a feature request for a better API.

For example, if want to know when the screen refresh happened so that you can redraw your scene, you should ask for API that lets you register for notification of screen refreshes. That way you're responding to a real hardware event, not some arbitrary timer that has no relation to anything.

Uhh .... that's generally handled by eglSwapBuffers which unfortunately is not available because we are not really rendering to a framebuffer but to what is essentially a texture ( which then gets composited with other system layers)

Incidentally, that's the reason (I suspect) why there is no anti-aliasing available for OpenGL ES apps on the iphone.
While the GPU is perfectly happy to anti-alias when rendering to a framebuffer, it doesn't support it for rtt renders.
Quote this message in a reply
Member
Posts: 283
Joined: 2006.05
Post: #50
AnotherJake Wrote:In all the years OS X has been around now, Apple has apparently shown no interest in providing a hardware generated VBL callback (irq, or whatever).

Weren't Core Video display links were meant to sort that? (No use for iPhone)
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #51
warmi Wrote:that's generally handled by eglSwapBuffers

It certainly is not.

Swap (whatever the API flavor) presents your framebuffer so you can see it. This action may interact with hardware beam sync or a window compositor, and therefore have timing implications.

But, the Swap itself has nothing to do with telling you when to draw.
Quote this message in a reply
Member
Posts: 166
Joined: 2009.04
Post: #52
arekkusu Wrote:It certainly is not.

Swap (whatever the API flavor) presents your framebuffer so you can see it. This action may interact with hardware beam sync or a window compositor, and therefore have timing implications.

But, the Swap itself has nothing to do with telling you when to draw.

Yeah, but if you are drawing to a backbuffer then it doesn't matter when you draw - what matters is if your swap is synchronized.
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #53
maximile Wrote:Weren't Core Video display links were meant to sort that? (No use for iPhone)

Display links are just high priority timers. Yes, the purpose is to be better than regular timers for graphics purposes. I've tested my stuff extensively with display links and found zero improvement in timing over a simple over-revved 1k timer on the Mac (i.e, they don't eliminate beat frequencies between the drawing code and the display refresh). Over-revved timers don't help on iPhone, and can actually make performance worse if they're too high a frequency.
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #54
warmi Wrote:Yeah, but if you are drawing to a backbuffer then it doesn't matter when you draw.

It matters if you're going to draw more than one frame.

Everyone on this forum is writing games, and games generally draw more than one frame, with the goal of producing smooth animation.

The definition of "smooth animation" is: one frame drawn per display refresh.

The problem with implementing that is that you need to know what the display refresh rate is, and when the display refresh starts. The naiive implementation of using an NSTimer at 60.0 Hz doesn't work, because "60.0" is an arbitrary number with no correlation to either the hardware refresh rate or refresh start time.

As discussed in this thread, overdriving the timer can work (if your drawing thread blocks on sync, which is true on Mac OS X) but that's really an abuse of the system to request more notification than you need.

What you really need to have is a notification when the hardware has just refreshed the display. Every game console has this. Even Apple used to have it.
Quote this message in a reply
Member
Posts: 166
Joined: 2009.04
Post: #55
arekkusu Wrote:If matters if you're going to draw more than one frame.

Everyone on this forum is writing games, and games generally draw more than one frame, with the goal of producing smooth animation.

The definition of "smooth animation" is: one frame drawn per display refresh.

The problem with implementing that is that you need to know what the display refresh rate is, and when the display refresh starts. The naiive implementation of using an NSTimer at 60.0 Hz doesn't work, because "60.0" is an arbitrary number with no correlation to either the hardware refresh rate or refresh start time.

As discussed in this thread, overdriving the timer can work (if your drawing thread blocks on sync, which is true on Mac OS X) but that's really an abuse of the system to request more notification than you need.

What you really need to have is a notification when the hardware has just refreshed the display. Every game console has this. Even Apple used to have it.

We are talking about two different things ... you are talking about animations driven (or synchronized ) to a fixed refresh rate (something quite common on consoles) and I am talking about the opposite .. using synchronized swap just to avoid tearing and related issues ... while keeping the animation rate based on a system timer ( basically variable rate).
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #56
Fair enough. If you want a system timer at an arbitrary rate, NSTimer is great for that.

That's not generally a good way to drive rendering, was my point.
Quote this message in a reply
Member
Posts: 166
Joined: 2009.04
Post: #57
arekkusu Wrote:Fair enough. If you want a system timer at an arbitrary rate, NSTimer is great for that.

That's not generally a good way to drive rendering, was my point.


Not arbitrary but rather relatively predictable ... something NSTimer is not good for.

Yeah, it would be perfect if you could code for the iPhone the way people code on consoles ... assume a fixed frame rate and be done with it.

The iPhone already has two hardware profiles out there not to mention unrelated background processes which you cannot control, so in this regard is more like a PC than a console.
Quote this message in a reply
DoG
Moderator
Posts: 869
Joined: 2003.01
Post: #58
warmi Wrote:Not arbitrary but rather relatively predictable ... something NSTimer is not good for.

The iPhone/Mac OS is a preemptive multitasking system. Whatever you do in your little custom loop won't change that fact. A custom loop will not have any measurable advantage over a plain runloop with a single NSTimer on the *same thread* as the custom loop.

I also neglected to mention that if you set your NSTimer to a really small interval, but your buffer swap blocks the thread anyway, it's probably as efficient as it gets, as your timer will fire once per frame, as soon as the scheduler permits.

Anyhow, as for the screen-synced timer, that is also a bit difficult to handle. As threads are preemptive, the OS doesn't guarantee any execution time limits. Thus, even if your callback was called at the exactly right time, you could still miss the next screen refresh, if your thread didn't get enough CPU time. Temporal aliasing is unavoidable to some degree if the CPU load is high, which with a game, it typically is. Even if the amount of computation per game frame is constant, the execution time may still vary wildly. Incidentally, if you only measure time once per frame, you don't know if the culprit is that the timing is off, or that execution is taking too long. **

On a desktop Mac, input processing probably takes an order of magnitude less time to execute, due to the faster processor, etc, than on the iPhone. So if input processing on the phone takes 30% CPU time, it probably takes 3% on the desktop, and so produces much less noticable jitter, all else being constant. Also, with multiple cores, contention is even less of a problem, and even with a high load, the scheduling latency is greatly reduced.

If you had control of the thread scheduler, and a hardware interrupt for screen sync, and bounded execution time, you could probably reduce jitter a bit. However, if the amount of CPU time you use is variable, and sometimes more than what you got per screen refresh, you'll have to accept some amount of temporal aliasing.



(** if your buffer swap is synced, it'll always seem as if NSTimer skips firing some frames, eg you'll have 0.033, 0.033, 0.066, 0.033 as frame time intervals. But that isn't the fault of NSTimer, as your thread could have been blocked for 0.032s of that 0.066, simply because the buffer swap was initiated a fraction too late, and the timer can only fire after it has been completed. A custom game loop will show the exact same symptoms.)
Quote this message in a reply
Member
Posts: 166
Joined: 2009.04
Post: #59
DoG Wrote:The iPhone/Mac OS is a preemptive multitasking system. Whatever you do in your little custom loop won't change that fact. A custom loop will not have any measurable advantage over a plain runloop with a single NSTimer on the *same thread* as the custom loop.

I also neglected to mention that if you set your NSTimer to a really small interval, but your buffer swap blocks the thread anyway, it's probably as efficient as it gets, as your timer will fire once per frame, as soon as the scheduler permits.

Anyhow, as for the screen-synced timer, that is also a bit difficult to handle. As threads are preemptive, the OS doesn't guarantee any execution time limits. Thus, even if your callback was called at the exactly right time, you could still miss the next screen refresh, if your thread didn't get enough CPU time. Temporal aliasing is unavoidable to some degree if the CPU load is high, which with a game, it typically is. Even if the amount of computation per game frame is constant, the execution time may still vary wildly. Incidentally, if you only measure time once per frame, you don't know if the culprit is that the timing is off, or that execution is taking too long. **

On a desktop Mac, input processing probably takes an order of magnitude less time to execute, due to the faster processor, etc, than on the iPhone. So if input processing on the phone takes 30% CPU time, it probably takes 3% on the desktop, and so produces much less noticable jitter, all else being constant. Also, with multiple cores, contention is even less of a problem, and even with a high load, the scheduling latency is greatly reduced.

If you had control of the thread scheduler, and a hardware interrupt for screen sync, and bounded execution time, you could probably reduce jitter a bit. However, if the amount of CPU time you use is variable, and sometimes more than what you got per screen refresh, you'll have to accept some amount of temporal aliasing.



(** if your buffer swap is synced, it'll always seem as if NSTimer skips firing some frames, eg you'll have 0.033, 0.033, 0.066, 0.033 as frame time intervals. But that isn't the fault of NSTimer, as your thread could have been blocked for 0.032s of that 0.066, simply because the buffer swap was initiated a fraction too late, and the timer can only fire after it has been completed. A custom game loop will show the exact same symptoms.)


Of course I won't get real-time response .. I know that.

All I am saying is that I got more stable timing using my own loop rather than NSTimer ... especially when dealing with heavy input event loads.

PS.
I guess I could go with setting NSTimer to fire as fast as possible but then , if my my game loop actually is running below 60 MHZ, I will end up synchronizing running at 60 FPS, which may or may not be the best option.

It comes down to the fact that I can't control the swap interval parameter on the iPhone.
Quote this message in a reply
Member
Posts: 61
Joined: 2009.01
Post: #60
Just to add to this:

If you're doing your own loop like this, new versions of the iPhone OS beyond 2.2.1 will hang on startup, unless you use:

Code:
[self performSelectorOnMainThread:@selector(mainLoop) withObject:nil waitUntilDone:NO];

In order to launch into the loop. If you simply say [self mainLoop] the app will never start up in new OS versions. In old versions, this was allowed, but it must be avoided in new ones.

Hopefully that will help.
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  NSTimer fine, CADisplayLink having some issues monteboyd 5 10,200 Aug 31, 2010 07:05 PM
Last Post: Skorche
  NSTimer hiccups/choppy/jerky jeonghyunhan 2 3,069 Sep 24, 2009 07:35 PM
Last Post: jeonghyunhan
  Using an NSTimer to progressively draw a view StevenD 4 4,714 May 14, 2009 07:57 AM
Last Post: StevenD
  OpenGL render loop - NSTimer vs rendering thread smallstepforman 27 24,422 Feb 2, 2009 10:22 AM
Last Post: ThemsAllTook
  Alternative Input/Control Ideas chrisco 8 4,640 Aug 6, 2008 03:21 PM
Last Post: bruss14