Emulation Timing

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
WedNESday
Posts: 1231
Joined: Thu Sep 15, 2005 9:23 am
Location: Berlin, Germany
Contact:

Emulation Timing

Post by WedNESday »

I am confused by how QueryPerformanceCounter works. I have used QueryPerformanceFrequency to get my CPU ticks, and I know that works because it returns the speed of my CPU in Hz correctly. Now I have searched Google and have come up with this kind of thing;

Code: Select all

QueryPerformanceCounter(&lpPerformanceCount);
(Run a frame)
QueryPerformanceCounter(&lpPerformanceCount);
Now apparently you're supposed to save the before value and compare it to the after one. However when I do the following;

Code: Select all

QueryPerformanceCounter(&lpPerformanceCount);
(Message Box Displaying lpPerformanceCount)
QueryPerformanceCounter(&lpPerformanceCount);
(Message Box Displaying lpPerformanceCount)
It's like 10000000 different when it should only be a couple of thousand. So what does QueryPerformanceCounter actually return? It always seems to wrap at around the 32-bit 4 billion mark.

Any help/examples?
mic_
Posts: 922
Joined: Thu Oct 05, 2006 6:29 am

Post by mic_ »

What does counter2.QuadPart - counter1.QuadPart give you?
mic_
Posts: 922
Joined: Thu Oct 05, 2006 6:29 am

Post by mic_ »

And if you've got a MessageBox call in between the two calls you could get a high value because MessageBox doesn't return until you press OK/Cancel/whatever.
WedNESday
Posts: 1231
Joined: Thu Sep 15, 2005 9:23 am
Location: Berlin, Germany
Contact:

Post by WedNESday »

mic_ wrote:What does counter2.QuadPart - counter1.QuadPart give you?
That appears to give me the amount of time a frame takes, in Hz. Perfect! Holy crap, 21Mhz for just one frame... :D

Now that I've got the length of one frame, what kind of calculations must I do?
mic_
Posts: 922
Joined: Thu Oct 05, 2006 6:29 am

Post by mic_ »

what kind of calculations must I do?
To get what..?
WedNESday
Posts: 1231
Joined: Thu Sep 15, 2005 9:23 am
Location: Berlin, Germany
Contact:

Post by WedNESday »

To limit the emulator to just 60FPS using Sleep() or whatever, that kind of thing.
mic_
Posts: 922
Joined: Thu Oct 05, 2006 6:29 am

Post by mic_ »

Google says:

Code: Select all

//limit FPS to 60
void Sleep()
{
	static LARGE_INTEGER s_lastTime = m_starttime;
	LARGE_INTEGER currentTime;
	float  fps;

	do {
		Sleep(1);
		QueryPerformanceCounter(&currentTime);
		fps = (float)m_ticksPerSecond.QuadPart/(currentTime.QuadPart - s_lastTime.QuadPart);
	} while (fps > 60);

	s_lastTime = currentTime;

}
Though using Sleep(1) will hog the CPU quite a bit, so you should probably do it in two stages. First with longer sleeps, and then with Sleep(1) as you get closer to the limit.
WedNESday
Posts: 1231
Joined: Thu Sep 15, 2005 9:23 am
Location: Berlin, Germany
Contact:

Post by WedNESday »

And that's the problem for me. I know that I can use methods that will work, but will use the CPU 100% of the time, so I need the kind of method that other emulator authors use.
User avatar
dXtr
Posts: 375
Joined: Tue Sep 21, 2004 12:11 am
Location: Karlshamn (Sweden)

Post by dXtr »

Here's another tip for you if you're using QueryPerformacene*

I discovered this one after trying our code at the office on another computer.. it seems like computers with more then one core can have a problem with those functions making it very unstable. To solve this you call SetThreadAffinityMask() before and after the QueryPerformance call.

Example

Code: Select all

DWORD oldMask = SetThreadAffinityMask(GetCurrentThread(), 1);

bool bUsingQPF = QueryPerformanceFrequency(&m_TicksPerSecond);

SetThreadAffinityMask(GetCurrentThread(), oldMask);
edit:
Worth to note though, is that I've heard mixed response to this solution with some saying that this still won't guarantee anything. But it seems to work good so far ;)
Post Reply