auto-frameskip calculations

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
auto-frameskip calculations
by on (#77350)
question for you guys, what is the best way to go about calculating an automatic frameskip value? this is what i've got in the FreeBASIC version of my emulator. wondering if there's a more accurate/better method, or if there are any inherent problems in this algorithm?

this loop is right after rendering each frame:

Code:
   Do
      #Ifdef __FB_WIN32__
         QueryPerformanceCounter(CPtr(Any Ptr, @curtimer))
      #Else 'then it's linux
         gettimeofday(@timing, NULL)
         curtimer = timing.tv_usec
      #EndIf
      'calculate auto-frameskip
      timertemp = curtimer - lasttimer
      If timertemp >= (timerfreq / ((60/frameskip)\2)) Then frameskip = frameskip + 1
      If timertemp < (timerfreq / 60) Then frameskip = frameskip - 1
      If frameskip > 30 Then frameskip = 30 'limit max frameskip count.. if your system is THAT slow, you shouldn't even be trying this.
      If frameskip < 1 Then frameskip = 1
      'end auto-frameskip calcs
      If timertemp >= (timerfreq / 60) Then Exit Do
      #Ifdef __FB_WIN32__
         SwitchToThread() 'give up remainder of CPU timeslice if we shouldn't resume yet
      #EndIf
   Loop

by on (#77352)
Another way to think of automatic frameskip is "Skip Video Frames When Behind". So you look at time. If you're ahead, you're fine. If you're behind, repeatedly skip frames (up to a maximum) until you are on time again.

I'll go copy-paste the Actionscript 1.x code I made for autoframeskip in a flash game here... Code's a little bit messy, hopefully you can figure out some kind of logic from this, some variables aren't even used.

Code:
function startup()
{
   if (intMain==undefined)
   {
      if (targetFPS==undefined) targetFPS=60;
      frame_interval=1000/targetFPS;
      FPS="FPS:";
      var myDate:Date=new Date();
      myDate.getDate();
      lasttime=myDate.valueOf();
      onesecondago=lasttime;
      slacktime=0;
      gamecyclesperformed=0;
      framesdrawn=0;
      cyclesrun=0;
      cyclesrejected=0;

      intMain = setInterval(doframe, 1);
   }
}
   
function doframe()
{
   var myDate:Date=new Date();
   myDate.getDate();
   thistime=myDate.valueOf();
   var elapsedtime=thistime-lasttime;

   if (elapsedtime<0) elapsedtime=0;
   var cyclestorun=int(elapsedtime/frame_interval);
   var slacktime=0;
   if (cyclestorun==0)
   {
      cyclesrejected++;
      return;
   }
   if (cyclestorun>6)
   {
      cyclestorun=6;
      lasttime=thistime;
   }
   else
   {
      lasttime=lasttime+cyclestorun*frame_interval;
      slacktime=thistime-lasttime;
   }
   var onesecondtime=thistime-onesecondago;
   if (onesecondtime<0) onesecondtime=0;
   var i;
   for (i=0;i<cyclestorun;i++)
   {
      frame();
      cyclesrun++;
   }
   framesdrawn++;
   if (onesecondtime>=1000)
   {
      onesecondago=thistime;
      FPS="FPS: "+framesdrawn+"/"+cyclesrun;
      framesdrawn=0;
      cyclesrun=0;
   }
   updateAfterEvent();
}


by on (#77354)
yeah, that looks like a pretty good way to do it. it might be slightly more accurate that way, i'm going to play around with both methods and see how they do.

by on (#78086)
Here's what I did way back when. Worked great:

http://nesdev.com/bbs/viewtopi ... 0667#40667