auto-frameskip calculations

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Post Reply
User avatar
miker00lz
Posts: 235
Joined: Thu Sep 23, 2010 7:28 pm

auto-frameskip calculations

Post by miker00lz »

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: Select all

	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
User avatar
Dwedit
Posts: 5083
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Post by Dwedit »

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: Select all

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();
}

Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
User avatar
miker00lz
Posts: 235
Joined: Thu Sep 23, 2010 7:28 pm

Post by miker00lz »

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.
User avatar
Disch
Posts: 1848
Joined: Wed Nov 10, 2004 6:47 pm

Post by Disch »

Here's what I did way back when. Worked great:

http://nesdev.com/bbs/viewtopic.php?p=40667#40667
Post Reply