views:

672

answers:

5

This is what happens:

  • The drawGL function is called at the exact end of the frame thanks to a usleep, as suggested. This already maintains a steady framerate.

  • The actual presentation of the renderbuffer takes place with drawGL(). Measuring the time it takes to do this, gives me fluctuating execution times, resulting in a stutter in my animation. This timer uses mach_absolute_time so it's extremely accurate.

  • At the end of my frame, I measure timeDifference. Yes, it's on average 1 millisecond, but it deviates a lot, ranging from 0.8 milliseconds to 1.2 with peaks of up to more than 2 milliseconds.

Example:

// Every something of a second I call tick
-(void)tick
{
  drawGL(); 
}

- (void)drawGL
{   
  // startTime using mach_absolute_time;

  glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); 
  [context presentRenderbuffer:GL_RENDERBUFFER_OES];

 // endTime using mach_absolute_time;
 // timeDifference = endTime - startTime;
}

My understanding is that once the framebuffer has been created, presenting the renderbuffer should always take the same effort, regardless of the complexity of the frame? Is this true? And if not, how can I prevent this?

By the way, this is an example for an iPhone app. So we're talking OpenGL ES here, though I don't think it's a platform specific problem. If it is, than what is going on? And shouldn't this be not happening? And again, if so, how can I prevent this from happening?

+1  A: 

The deviations you encounter maybe be caused by a lot of factors, including OS scheduler that kicks in and gives cpu to another process or similar issues. In fact normal human won't tell a difference between 1 and 2 ms render times. Motion pictures run at 25 fps, which means each frame is shown for roughly 40ms and it looks fluid for human eye.

As for animation stuttering you should examine how you maintain constant animation speed. Most common approach I've seen looks roughly like this:

while(loop)
{
  lastFrameTime; // time it took for last frame to render
  timeSinceLastUpdate+= lastFrameTime;

  if(timeSinceLastUpdate > (1 second / DESIRED_UPDATES_PER_SECOND))
  {
     updateAnimation(timeSinceLastUpdate);
     timeSinceLastUpdate = 0;
  }

  // do the drawing

  presentScene();
}

Or you could just pass lastFrameTime to updateAnimation every frame and interpolate between animation states. The result will be even more fluid.

If you're already using something like the above, maybe you should look for culprits in other parts of your render loop. In Direct3D the costly things were calls for drawing primitives and changing render states, so you might want to check around OpenGL analogues of those.

frgtn
I indeed already time my calculations in order to maintaina stable framerate. The actual drawing always takes place at the exact end of the frame. (I use a sleep timer for that)I'll clarify the question for this.
Kriem
A: 

It is best not to rely on a high constant frame rate for a number of reasons, the most important being that the OS may do something in the background that slows things down. Better to sample a timer and work out how much time has passed each frame, this should ensure smooth animation.

jheriko
A: 

Is it possible that the timer is not accurate to the sub ms level even though it is returning decimals 0.8->2.0?

Could be. It's an NSTimer. Despite that, even if, the framerate seems to stutter.
Kriem
+1  A: 

My favorite OpenGL expression of all times: "implementation specific". I think it applies here very well.

Ivan Vučica
Could you elaborate?
Kriem
I don't think it is absolutely demanded by the spec that rendering time for subsequent frames of same content must be absolutely the same. That is, GPU manufacturer is probably permitted to make the time fluctuate.
Ivan Vučica
+1  A: 

A quick search for mach_absolute_time results in this article: Link

Looks like precision of that timer on an iPhone is only 166.67 ns (and maybe worse). While that may explain the large difference, it doesn't explain that there is a difference at all.

The three main reasons are probably:

  • Different execution paths during renderbuffer presentation. A lot can happen in 1ms and just because you call the same functions with the same parameters doesn't mean the exact same instructions are executed. This is especially true if other hardware is involved.
  • Interrupts/other processes, there is always something else going on that distracts the CPU. As far as I know the iPhone OS is not a real-time OS and so there's no guarantee that any operation will complete within a certain time limit (and even a real-time OS will have time variations).
  • If there are any other OpenGL calls still being processed by the GPU that might delay presentRenderbuffer. That's the easiest to test, just call glFinish() before getting the start time.
Maurice Gilden