Profiling OpenGL ES App

I'm just about at my wits end today. I had a game started that I was hoping to just use UIKit for all the graphics. Yes, it's hackish but it worked until I got about 95% of the stuff in the game.

Now I've switch over to OpenGL but I cannot for the life of me figure out why it's running at about 46-47 fps instead of 60. Right now I'm drawing three quads (as three triangle strips). All three are textured and sampled from one 512x512 sprite sheet (so I never switch textures). This isn't my entire game, so I'm worried that it's already at 46-47 fps when it really should be able to tear into this and get 60fps.

I think I need to be using Instruments for this but I can't figure out what to look for in terms of bottle neck. I used the OpenGL template (which is how I found out the frame rate), but I can't figure out what to look at to determine the bottleneck.

Since i couldn't quite figure out Instruments or Shark, and my project is so small right now, I started just taking out lines until something made a difference. In my custom EAGLViewController, in my viewDidLoad method, I had this line:

Where self.view is the EAGLView itself. Apparently this was my problem. Once I took it out, the whole thing started running faster. Not entirely sure why, but then I'm not entirely sure why I had that line in there to begin with.

Edit: Looks like I spoke too soon. This helped, but did not solve the entire problem. Back to trying to figure out Instruments/Shark.

If you're using an NSTimer to drive frames you'll want to crank up the interval. Running a timer at 60Hz won't necessarily give you 60 FPS due to VBL syncing and other blocking event updates. Some folks recommend using a separate thread for rendering but I've never run into any problems with NSTimer - you just gotta crank it up - but note that you'll never exceed 60FPS on the iPhone since that's the hard-coded VBL rate.

What I do is run my frame timer at 120Hz and de-couple the logic/physics steps from the graphics updates using the technique described here. But I also cap the graphics updates, so I run physics at 60Hz, and draw at 30Hz. The timer might spin needlessly at times in this scenario but that 120Hz ensures you have some breathing room to catch up on updates when things are bogging down.

Hm. Guess I'll have to look into that. My EAGLView class is basically ripped from the template, but I just added in a delegate to farm out the code in the middle of the draw method as well as handle the touch input for the view.

I've worked on a lot of games that worked similarly to Frank C's description. There's a discrete physics frame that's running at 60, 90, or 120 fps. The graphics render whenever possible. We did this all the time for PC games, where performance of the system was highly variable.

After all, future iPhones could come along with faster processors and graphics. So I think it's a good way to go.

I'm not as far as you are yet. Is there a callbacks you get when a frame has rendered? Is there a callback when it's been displayed? Or our we filling a queue with frames?

Nosredna Wrote:I'm not as far as you are yet. Is there a callbacks you get when a frame has rendered? Is there a callback when it's been displayed? Or our we filling a queue with frames?

Callback.

There are two schools of thought on this: loop or timer (either being optionally threaded, and I don't like threaded on iPhone). I'm with Frank and use the NSTimer, with which you register a method to be called back at a regular interval. This timer technique is what is used in the OpenGL ES application template. Frank does it at 120. I do it at 60 and it seems to work okay for me.

I too decouple the draw from the update (which is not demonstrated in the template, unfortunately). Everything tends to stay smoother that way, and it also helps physics integration remain stable. My update (or "tick") is set to be 60 Hz on iPhone. So drawing can be (and is) variable by the very nature of the capabilities of the system and hardware, but the tick rate remains stable at all times. It's not pristine perfection, but it's the best all-around trade-off that I've seen.

AnotherJake Wrote:I too decouple the draw from the update (which is not demonstrated in the template, unfortunately). Everything tends to stay smoother that way, and it also helps physics integration remain stable. My update (or "tick") is set to be 60 Hz on iPhone. So drawing can be (and is) variable by the very nature of the capabilities of the system and hardware, but the tick rate remains stable at all times. It's not pristine perfection, but it's the best all-around trade-off that I've seen.

Might you be willing to share some of that code. I've been reading over the link Frank posted but for some reason I can't seem to wrap my head around how to do that using Objective-C. Mainly I'm having issues with figuring out exactly how much time has passed. If I use the time() method, it returns integer seconds which isn't useful. I've tried using [NSDate date], storing the last tick, and subtracting the two, but that doesn't seem to yield accurate results so I must be doing something wrong.

So would either of you be willing to share a bit of your timing code for the rest of us to learn from?

Hopefully the other functions (gameStep, gameDrawFrame) are self explanatory. I keep gameTime exposed globally since it's handy to have around everywhere, ditto for gameState. My typical settings for the frame constants are:

So - kGameFrameIntervalNormal is the timer frequency, kGameFrameIntervalIdle is the timer frequency when the app is "idle" (the app delegate decides when to use that). kGameFrameStepInterval is the guaranteed frequency for physics/logic steps and kGameFrameDrawInterval is the maximum frame rate (not guaranteed). Note that I set kGameFrameDrawInterval 10% higher than I actually need it, since you still get some blocking issues with the timer at 120Hz. kGameFrameMaxDelta is there to ensure simulations won't explode when the renderer is bogging - if the game hits that limit it won't be realtime, but at least it won't freeze up or go totally wacky.

I should also note that I don't bother doing any drawing interpolation on the iPhone, since physics updates are never fewer than screen updates. This greatly simplifies gameRunFrame and gameDrawFrame.

// calculate the time base for this platform, only on the first time through
if (timebase == 0)
{
mach_timebase_info_data_t timebaseInfo;
mach_timebase_info(&timebaseInfo);
timebase = timebaseInfo.numer / timebaseInfo.denom;
}

This is a *good* idea, and let me tell you why, hehe... I had accidentally converted the time from double precision to single precision at one point. Everything worked great up until some seemingly random point in the game it seemed to freeze. Actually it just stopped updating because the way the math worked out (cutting out the precision wound up giving me like a 50 minute negative delta). That was a tricky bug to track down. If this check was in place, it would have had a tiny unexplained hiccup every 50 minutes, but at least the game would have continued to play!

Just bumping this to note that I've fixed a bug with the code I previously posted. It was returning deltaTime when it was time to draw but that time slice didn't make much sense. It now tracks and returns the delta between render updates (drawDelta) which can be used for non-critical variable rate updates while drawing - e.g. texture or color animations etc.

Oh wow, I'm glad I saw this thread. My game's framerate seems highly variable even though I'm rendering the same objects every frame, but since I only started about two weeks ago I haven't been very concerned about it. Is the NSTimer really that wonky?