Caanoo / WIZ Sleeping With The Wiz


DusteD

Still Fresh
Joined
Aug 29, 2009
Messages
66
Age
38
Location
Denmark
Website
dusted.dk
When using SDL_Delay or usleep it seems that my wiz sleeps way too long...

My mainloop is roughly:

int tickStart = SDL_GetTicks();
gameLogic();
draw();
int dTime=SDL_GetTicks()-tickStart;
if(dTime < 16)
SDL_Delay(16-dTime);

On windows and linux this gives the right result, 60 fps, on the wiz however, it gives me 34 fps, and the draw/blit time is around 2 ms on the wiz.

Have anyone experienced the same problem?
 
Although i am no fan of frame-limiting, try something like this:

Code:
Uint32 time = SDL_GetTicks();
while ( true ) // game loop
{
   gameLogic();
   draw();

   while ( time + FRAME_TIME > SDL_GetTicks() )
      ; // do nothing

   time += FRAME_TIME;
}

The problem with your code (i think) is that SDL_Delay() (and probably also SDL_GetTicks()) are very inaccurate. Their accuracy might be as bad as 10ms which is pretty bad since you are trying to measure between 0 to 16ms.
 
Another method is to delay/poll every 3 frames, this comes out to an even 50 ms.
1000/60=16.66*3=50

This will give you an even 60 fps, and also lower the accuracy requirements. Giana's Return is using this method.
 
u9i said:
Although i am no fan of frame-limiting

Why? A fixed frame rate looks smoother than one that is higher on average but jumpier, and it's preferable to limit to vsync to avoid tearing. Development documents by PowerVR and Apple (for SGX) both suggest frame limiting.

On that note, waiting for vsync is a good idea. Unfortunately, Linux on Wiz can't do this for you, so you can't sleep until a vsync interrupt. You can instead conservatively estimate the time until vsync, sleep until then (minus whatever granularity your sleep function takes), then poll until you hit it.

Usually functions that get current time are much more precise than functions that wait a certain amount of time.
 
Last edited by a moderator:
u9i:
My game is a 2D puzzle game, and I see no reason in eating up users battery time by spewing out 200 fps.
Your method of "doing nothing" is imo, a task better left to the OS.

Pickle, that sounds interesting.

Exophase, I didn't realize that I could poll for vsync, I'll look into that.

[Update]
I wrote a test case, using usleep, and the buttons to turn up/down the sleep period, here's what I found:

If I don't call usleep at all, i get from 140 to 170 fps, seems that I'm maxing it out.
But when I start playing with usleep, i gets strange:

Every call to usleep with any value in inteval [0..800] gives a steady 100 fps
[900..10800] gives a steady 50 fps.
[10900..20800] gives a steady 34 fps.
[20900..30800] gives a steady 25 fps.
[30900..40800] steady 20 fps.

After 40800 it drops again, this time to 17 fps.

What's happening? :)
 
Pickle said:
Another method is to delay/poll every 3 frames, this comes out to an even 50 ms.
1000/60=16.66*3=50

Hi Pickle, I was going to ask how that works out, if it is noticeable in any way, but of course, i could just try Giana Sisters myself ;) Thanks for sharing this concept. I have not even considered something like this, because it just sounds like it would give a weird effect.

Hi Exophase, I almost feel honored that you noticed my humble little post (even though it was a little critical ;) ) My opinion on frame-limiting code comes from the hugely varying range of PCs. I think if you run your game on a slower computer, the game logic should not run slower. You could say I am a fan of keeping rendering and logic separated. While writing my post i actually wrote that all the Wiz' are the same, so it works perfectly fine to limit the framerate, but for some reason I deleted that part. A laps of concentration. It makes perfect sense to limit the framerate on a console. I like your suggestion on waiting for vsync, but isn't the granularity of the sleep far too inaccurate to be used this way? As I understand it you sleep your app and hand over control to the OS, the timeslot for each process is typically 10ms, so it could be 10ms off before you get another timeslot. Mind you, I am in deep waters right now, so feel free (or even encouraged) to tell me the errors of my ways :)

DusteD said:
My game is a 2D puzzle game, and I see no reason in eating up users battery time by spewing out 200 fps. Your method of "doing nothing" is imo, a task better left to the OS.

Then Pickle's suggestion might be your best option. Without thinking too much about it, you could (maybe) just replace my "do nothing" with

Code:
SDL_Delay(time + FRAME_TIME - SDL_GetTicks())

But store SDL_GetTicks() in a variable so you use the same value for the entire duration of the frame because i don't know if you put a negative value into SDL_Delay() (but i have my suspicions) :)

I am looking forward to your game. I would love to see more games for the wiz. They are too few and too far between.

EDIT: The important part is that for each frame you add a fixed amount of "game time passed" and not the number of ms returned by the timers. This way you should be able to average out the inaccuracies of the timers and delays.

Regards
u9
 
Last edited by a moderator:
u9i said:
[...]My opinion on frame-limiting code comes from the hugely varying range of PCs. I think if you run your game on a slower computer, the game logic should not run slower.[...]

Frame capping doesn't mean that you sleep for a fixed amount of time each frame. Instead you limit the maximum number of frames. So, for example... on a fast machine the game will sleep just enough to bring the framerate down to 60 and on a slow machine there might be no sleep at all (it still might be unable to reach the target though).

The easiest frame capping method is "min delta". You simply check how many msecs have passed and then you sleep in 1msec steps until you've reached the target (e.g. 16msec for 62.5fps).

A slightly nicer way to do it is "catch up capping". It basically works the same was as "min delta", but if a frame is late the next frame can be finished sooner. It's important that the lag isn't accumulated - only take into account how late the last frame was. This method hits the target more reliably and it also means there will be less dropped frames with triple buffering enabled.

See sync():
http://java-game-lib.svn.sourceforge.net/viewvc/java-game-lib/trunk/LWJGL/src/java/org/lwjgl/opengl/Display.java?revision=3236&view=markup
 
Last edited by a moderator:
Hmm, still having trouble here,
I wrote a test case, using usleep, and the buttons to turn up/down the sleep period, here's what I found:

If I don't call usleep at all, i get from 140 to 170 fps, seems that I'm maxing it out.
But when I start playing with usleep, i gets strange:

Every call to usleep with any value in inteval [0..800] gives a steady 100 fps
[900..10800] gives a steady 50 fps.
[10900..20800] gives a steady 34 fps.
[20900..30800] gives a steady 25 fps.
[30900..40800] steady 20 fps.


I don't get it, seems like the SDL_Flip() waits for something, it acts the same if the time is being taken up by real work, so it's not the usleep that's acting up either.

[Update]
I didn't take into account that I'm using SDL_GetTicks() to measure time, I guess it could be at fault too, but the problem is only on the wiz, it works fine on lin/win..

[Update2]
Doing a while(frameTime < 16) { /* update frametime*/ } works, but takes 100% cpu, I imagine that's pure evil on the battery time?
Maybe I should clock it down to make up for that waste..
 
>I don't get it, seems like the SDL_Flip() waits for something[...]

It actually looks like you're using a timer with a 10msec resolution.

1000/10=100
1000/20=50
1000/30=33.33...
1000/40=25
1000/50=20

See?

Edit: Try this... count the number of frames you get within 10 seconds, then divide this number by 10 to get the FPS.
 
Pickle said:
Another method is to delay/poll every 3 frames, this comes out to an even 50 ms.
1000/60=16.66*3=50

This will give you an even 60 fps, and also lower the accuracy requirements. Giana's Return is using this method.

I tried it kind with:
Code:
frame=0;
while(1)
{
  frame++;
  if(frame==3)
  {
    frame=0;
    SDL_Delay(50);
  }
  draw();
}
Looking at how fluid Giana's return is, I guess that's wrong ;)
Seems the site is down atm, so I can't grab the source (if there is any).

So far, I thank everybody for your help :)

aho said:
It actually looks like you're using a timer with a 10msec resolution.

Edit: Try this... count the number of frames you get within 10 seconds, then divide this number by 10 to get the FPS.

Oh.. Yes, you're right... Trying to overcome that by using the same precision timer with the while loop is futile..
 
Last edited by a moderator:
What if you try it like this:

Code:
frame = 0;
time = SDL_GetTicks();

while(1) {
  if(++frame == 3) {
    while(SDL_GetTicks() - time < 50) continue; // or perhaps SDL_Delay(10)

    frame = 0;
    time = SDL_GetTicks();
  }

  draw();
}

I can't wait to try this with my own stuff, it sounds like a promising way of making 60fps games a little smoother :)
 
You can't reliably sleep smaller than 10ms intervals, this if often even true on PCs.

Kernel time functions are broken on wiz and can be considered as having only 10ms granularity, which also affect all higher level functions like SDL_GetTicks().
If that is not enough for you, you have to take several frames (like Alex shows) or use SoC timers directly.
 
Alex. said:
What if you try it like this[...]

Code:
I can't wait to try this with my own stuff, it sounds like a promising way of making 60fps games a little smoother :) 
[/quote]
Ah yes, I forgot to take into account the time in between.. While it gives a sharp 60 Fps, it looks like 20 Fps (which it is if you think about it, when only every third frame is shown for more than 1-2 ms).

[quote="notaz"]
You can't reliably sleep smaller than 10ms intervals, this if often even true on PCs.

Kernel time functions are broken on wiz and can be considered as having only 10ms granularity, which also affect all higher level functions like SDL_GetTicks().
If that is not enough for you, you have to take several frames (like Alex shows) or use SoC timers directly.
[/quote]

Yay, so much for me trying to get at it with the tv_nsec :D


[Edit]
It seems there is no problem getting a stable 50 hz out of it, so I'm going that route instead. Thank you all very much for your help so far! :) I'll be sure to post the news when I release my game (There's still a long way, graphics/sound/level wise..)
 
Last edited by a moderator:
notaz said:
You can't reliably sleep smaller than 10ms intervals, this if often even true on PCs.

Kernel time functions are broken on wiz and can be considered as having only 10ms granularity, which also affect all higher level functions like SDL_GetTicks().
If that is not enough for you, you have to take several frames (like Alex shows) or use SoC timers directly.

Oh boy, another kernel bug. So they don't know how to read the timer value mid-tick in order to get a better timestamp? There really needs to be a strong push towards Open2X on the Wiz. The sooner the better.
 
Last edited by a moderator:
Back
Top