wxTimer issue

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
SpecialMike
In need of some credit
In need of some credit
Posts: 3
Joined: Fri Jun 12, 2015 3:47 pm

wxTimer issue

Post by SpecialMike »

I'm having a bit of an issue with wxTimer not actually firing at the interval it's supposed to, and its really inconsistent. It seems like it wants to update at double the interval specified. Here's how I'm testing this:

Code: Select all

bool MainApp::OnInit(){
	...
	//Size is weird, 160x144 for the screen, 20 height for the tool bar and then some random amount.
	frame = new MainFrame(wxT("yanGBe"), wxDefaultPosition, wxSize(160 + 16, 144 + 20 + 37), g);
	panel = new ImagePanel(frame);

	...

	wxTimer* timer = new wxTimer(this, wxID_EXECUTE);
	timer->Start(16);

	watch = new wxStopWatch();
	
	lastUpdate = 0;
	return true;
}

void MainApp::Update(wxTimerEvent& event){
	unsigned long long thisUpdate = watch->Time();

	cout << "Update start " << thisUpdate - lastUpdate << "ms" << endl;
	lastUpdate = thisUpdate;
	if (frame->stateChangeRequested)
		return;
	if (g == nullptr)
		return;
	g->UpdateToVBlank();
	panel->SetData(&g->g->data[0][0][0]);
	panel->PaintNow();

	cout << "\tUpdate took " << watch->Time() - thisUpdate << "ms" << endl;
}
Update is what's called (hopefully) every 16ms or so. First I'm outputting the time between update calls, then how much time it takes for the Update function to run, to be sure that isn't holding it back. However, the intervals are consistently inconsistent as it has a short interval followed by two long intervals.

Image

Is there possibly some sort of system configuration that's causing this, or is there possibly a better way of doing this?

And as a side question, how exactly is the frame size calculated? I want a 160x144 size for the panel, so I add 20 pixels for the toolbar on the frame but it comes up short in width and height.
User avatar
doublemax
Moderator
Moderator
Posts: 19160
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxTimer issue

Post by doublemax »

Under Windows the timer granularity is 15.625 ms which explains the results you're seeing.

There is a way to change this, but this is a system-wide change, so it's not recommended to use.
https://msdn.microsoft.com/en-us/librar ... 85%29.aspx

This may also be useful:
https://wiki.wxwidgets.org/Making_a_render_loop
Use the source, Luke!
SpecialMike
In need of some credit
In need of some credit
Posts: 3
Joined: Fri Jun 12, 2015 3:47 pm

Re: wxTimer issue

Post by SpecialMike »

Sure, that makes sense. So if I drop it to 15, which is under the granularity interval, it will work fine under windows. But this approach might run faster in a different environment, depending on that OS's timer granularity.

So, short of spinning on the performance timer there's not much I can do, is there?
User avatar
doublemax
Moderator
Moderator
Posts: 19160
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxTimer issue

Post by doublemax »

I'd say you have three options:

a) Use timeBeginPeriod() from the MSDN link to set a smaller timer granularity, e.g. 1
This is the easiest one, but it affects all running applications, so theoretically a few may behave differently.

b) From the wiki link i posted: https://wiki.wxwidgets.org/Making_a_ren ... dle_events
Use IDLE events and measure the time since the last update yourself. Then either render or skip.

c) Google "windows high resolution timers". There are a few, but i've never used one, so i can't make any recommendation.
Use the source, Luke!
SpecialMike
In need of some credit
In need of some credit
Posts: 3
Joined: Fri Jun 12, 2015 3:47 pm

Re: wxTimer issue

Post by SpecialMike »

Option B works really well. I guess I didn't think of that due to not being familiar enough with wxWidget's events; I suppose I'll need to read up on them. Thanks for your help
mbeardsley
Experienced Solver
Experienced Solver
Posts: 74
Joined: Thu Sep 25, 2014 7:40 pm

Re: wxTimer issue

Post by mbeardsley »

I'm having a similar problem. I want a 60hz update/rendering loop (i.e. performed every 16.67ms).

Option A - using timeBeginPeriod() does not seem to work. The wxTimer update rate/resolution does not seem to be affected in any way. From the MSW docs it seems that timeBeginPeriod() only affects "high-performance timers", and I suspect that wxTimer is only using a "regular timer". Have you actually ever obtained a wxTimer resolution better than 15.625ms?

Option B - capturing continuous idle events will peg a core to 100% usage. While this is expected (since it is basically spin-waiting), it is unacceptable - as my application is a small utility that will need to run gracefully alongside other applications.

Option C - when you say use a "high performance timer", do you mean make direct MSW calls and create the loop independent of the wxWidgets event system? or is there some way to make wxTimer use a different timing mechanism?

In any case, it seems like the wxWidgets documentation should make mention of the fact that wxTimers only have a functional resolution in multiples of 15.625ms, since this is certainly a non-obvious limitation. This basically means that wxTimer-based "update loops" can only be 64hz, 32hz, 21hz, 16hz, etc.
User avatar
doublemax
Moderator
Moderator
Posts: 19160
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxTimer issue

Post by doublemax »

Option A - using timeBeginPeriod() does not seem to work. The wxTimer update rate/resolution does not seem to be affected in any way. From the MSW docs it seems that timeBeginPeriod() only affects "high-performance timers", and I suspect that wxTimer is only using a "regular timer". Have you actually ever obtained a wxTimer resolution better than 15.625ms?
Actually i was 100% sure that i've tried that in the past, but i just tried it again and it didn't work. What changes however is the actual delay when calling something like ::wxMilliSleep(1). Without timeBeginPeriod() you get the usual 15-16 ms. With timeBeginPeriod(1) you actually get a delay of ~1 ms. I think you could use this in a secondary thread to implement a high(er) resolution timer. You could even generate a "normal" wxTimerEvent so that the timer would be interchangeable with a wxTimer.
Option C - when you say use a "high performance timer", do you mean make direct MSW calls and create the loop independent of the wxWidgets event system? or is there some way to make wxTimer use a different timing mechanism?
I meant a third-party msw-specific implementation. However, i never followed that path myself, but when you google for "windows high resolution timer" you get some hits. If you find something, i'd by interested in the results :)
Use the source, Luke!
Post Reply