Constant frame rate using threads and win32

Posted on 2004-09-22
Last Modified: 2008-01-09
HI, my goal is to have a separate rendeirng thread be able to render and a constant frame rate of say, 30fps.  
Info: Single CPU, win32 App, openGL, C++.  
I have one rendering thread who's sole purpose in life is:  to be created, initialized, wait to start, render at a constant frame rate, wait for a signal to stop rendering, then exit.  Let's also assume the code is thread safe :)

So, at every 33.3 ms, the thread will execute some rendering functions, then "go to sleep" and do nothing until the next 33.3ms has ellapsed.  

Q1: What are good coding techniques in general to accomplish something like this.?

Q2:  Please comment on the following 2 methods:
Method A:
      switch (myWin->threadSync->waitEvent(T))
      case WAIT_TIMEOUT:
            //Sampling Interval, so render to screen
            //check the accuracy
      case WAIT_OBJECT_0:
            //signal from main to exit rendering loop

Method B:
      if (renderingTimer->GetTime()*1000 >= T)
            //check the accuracy
            //Sampling Interval, so render graphics

The renderingTimer uses the QueryPerformanceCounter, so should be pretty accurate(I think?).  In method B, another thread is needed to set threadMain.threadExit to TRUE to stop the loop, where as in Method A, another thread must use the SetEvent() to stop the thread.

In Method A, the sampling time is based on when there is a timeout in the WaitForSingleObject().  How accurate is this?  

I'd like to know more about thread priorities and process priority classes.  I did a small test to see the effects of thread priorities using the above 2 methods.  Console App, main thread, and one single thread for rendering using the default settings.  
The main() has the thread render for 5 seconds.  And I checked how accurate the sampling times were.  Below are the results:
Method A error: 6.0687
Method B error: 0.001158

Method A error: 6.0205
Method B error: 0.00086314

Method A error: 5.9933
Method B error: 0.0010459

Method A error: 5.7194
Method B error: 131200.0168

the error is the sum of the squared errors of each sampling time.  The key change is from THREAD_PRIORITY_ABOVE_NORMAL to THREAD_PRIORITY_NORMAL.  Can you please comment on the results.  Note I did not change the default process priority.  

At the end of the day, I need an accurate(as accurate as QueryPerformanceCounter) constant frame rate.  What is the solution?

Thanks for your help

Question by:minstrelz
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions

Expert Comment

ID: 12129211
i would suggest using a double buffer. i haven't done any openGL programming as of yet so i could be partially wrong. here is the pseudo code:

use double buffer
while ( ! signal to die ){
  render in the "ghost" buffer;
  wait for 33.3 ms signal;
  swap buffers;

an expert with more OpenGL experience should be able to provide more help.

LVL 39

Accepted Solution

itsmeandnobodyelse earned 250 total points
ID: 12131863

As Windows isn't a real-time system, it isn't guaranteed that your thread gets scheduled at 33 fps frequency. That means, that it highly depends on your CPU (e. g. hyperthreading or not) and the traffic on your machine. I would guess that any major file access by any other application will spoil your frame rate.

The next issue is the time your rendering will take. Use GetPerformanceCounter and GetPerformanceFrequency calls to find that out. I would say, if this time isn't less than 10 ms, there is no chance to ahieve 33fps.

In both methods the GetTime()*1000 isn't accurate (i assume GetTime() gives seconds). You have to use GetPerformanceCounter to have the accuracy needed. Method2 has no wait/sleep function, so it would catch all CPU time it could get. You have to include Sleep(1); to your loop. However, the timing isn't accurate (about 10ms), so i would prefer method  A (i assume you are using a waitable timer), though i don't know whether it's more accurate than Sleep.

Q3: see Q2

>>> the error is the sum of the squared errors of each sampling time.

I'm sorry, i don't know what you are measuring here. I would call GetSystemTime(), timeb() function or QueryPerformanceCounter to measure your real frequency (you have to calculate averages aof about 1000 runs).

Hope, i could help to find it.

Regards, Alex

LVL 22

Expert Comment

ID: 12132126
First, I'd see how much CPU time the rendering thread uses per frame.  It had better be considerably less than 1/33 sec!

The exact timing is mostly irrelevant.    Your screen is getting hardware refreshed at whatever rate you've set in the Display control panel (60 to 80 Hz are typical rates).    Most display libraries sync themselves to this rate whenever you call for a full-screen update.  If they didnt you'd see all kinds of tearing and jiggling.   so "33 fps" ends up being "whatever sub-multiple of the screen refresh rate is greater and 33fps.  For example, if your refresh rate is 60 Hz, the screen will get a fresh image every OTHER scan, effectively 30fps.   If you shoot for 30fps, you run the danger of missing the exact scan rate by a little bit and effectively getting 60/3 or 20fps.

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!


Author Comment

ID: 12135641
response to itsmeandnobodyelse:
I dont know what hyperthreading is, so can you please explain its effect on the question.  You mention that it could depedn a lot on the traffic on the machine.  So, what about setting process priority to THREAD_PRIORITY_TIME_CRITICAL?  When would be a good/bad time to do something like this?
Also, from your response, the renderingTimer does use QueryPerformanceCounter to get the sampling times.  Lastly, does anyone know whether the Sleep() is more/less accurate than WaitForSingleObject( ) with some timeout?

Author Comment

ID: 12135895
correction to above: I mean setting the process priority to REALTIME_PRIORITY_CLASS
LVL 39

Expert Comment

ID: 12141665
hyperthreading is the capability of some INTEL CPU's (newer Pentium IV, Itanium) to work similar to a double-processor unit. So, the threads of an application may work quasi-parallell and are scheduled more often than with a single CPU.


Any priority given doesn't make the system to a realtime system. However, if you can guarantee that there is only one thread that has this kind of priority you should have a chance that the average times of scheduling are near to your goal.

Regards, Alex

Author Comment

ID: 12175282
does anyone know whether the Sleep() is more/less/as accurate than WaitForSingleObject( ) with some timeout?  why or why not.  

Featured Post

Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Errors will happen. It is a fact of life for the programmer. How and when errors are detected have a great impact on quality and cost of a product. It is better to detect errors at compile time, when possible and practical. Errors that make their wa…
Many modern programming languages support the concept of a property -- a class member that combines characteristics of both a data member and a method.  These are sometimes called "smart fields" because you can add logic that is applied automaticall…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

734 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question