Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium


Constant frame rate using threads and win32

Posted on 2004-09-22
Medium Priority
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

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 1000 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.

Technology Partners: 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

[Webinar On Demand] Database Backup and Recovery

Does your company store data on premises, off site, in the cloud, or a combination of these? If you answered “yes”, you need a data backup recovery plan that fits each and every platform. Watch now as as Percona teaches us how to build agile data backup recovery plan.

Question has a verified solution.

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

Introduction This article is a continuation of the C/C++ Visual Studio Express debugger series. Part 1 provided a quick start guide in using the debugger. Part 2 focused on additional topics in breakpoints. As your assignments become a little more …
C++ Properties One feature missing from standard C++ that you will find in many other Object Oriented Programming languages is something called a Property (http://www.experts-exchange.com/Programming/Languages/CPP/A_3912-Object-Properties-in-C.ht…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
Suggested Courses

564 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