Chapter 10. Controlling Frame Rate

Frame rate is the number of times a scene is redrawn per second. Frame rate is constrained by three factors:

For example, one system may have a refresh rate of 60 frames per second. Other systems may have frame rates limited to the frame rate divided by an integer, for example, 30, 20, 15, 12, and 10 frames per second.

This chapter describes how to control the frame rate in the following sections:

Double Buffering

OpenGL Performer uses the standard double buffering mechanism for displaying scenes:

  • The front buffer sends a complete description of the scene to the graphics pipeline.

  • The back buffer is filled with the next frame of information to be displayed.

At a frame boundary, if the drawing to the back buffer is complete and a swap buffer has been issued, the front and back buffers are swapped so that:

  • The back buffer becomes the new front buffer whose graphic information is scanned out.

  • The front buffer becomes the new back buffer to hold the next frame, as shown in Figure 10-1.

    Figure 10-1. Double Buffering

    Double Buffering

Specifying a Target Frame Rate

You can only specify a target frame rate, not the frame rate, because sometimes calculating and drawing a frame can require more time than the time between screen refreshes. If a screen is not entirely drawn, rather than drawing part of a scene, the current frame is redisplayed while the drawing of the next scene completes.

You can specify the target frame rate using one of two methods:

  • pfFrameRate()

  • pfFieldRate()

pfFrameRate

You can set the target frame rate directly using the following pfFrame method:

void pfFrameRate(float rate);

rate is rounded to the nearest frame rate that corresponds to an integral number of screen refreshes, for example, a value of 33 frames per second (FPS) is rounded to 30 FPS.

The target time required to draw a frame is the reciprocal of the frame rate.

Figure 10-2. Frame Rate

Frame Rate

With a screen refresh rate of 60 Hz, Figure 10-2 shows the frame boundaries for two different frame rates.

pfFieldRate

You can set the frame rate indirectly using the following pfFrame method:

void pfFieldRate(int fields);

fields refers to the number of screen refreshes per frame. The corresponding frame rate is the video field rate divided by fields.

Frame Synchronization

pfSync synchronizes the graphics pipeline to the frame rate. This method makes all processes start on frame boundaries. This keeps computations between multiple processes consistent and based on data, such as eyepoint, rather that computation time. Because computation time is variable, basing motion on the completion of computations thereby creates unsmooth motion. Moving at the start of frame boundaries produces smoother motion.

Exactly how pfSync responds to DRAW time overruns is specified by the phase control.

pfFrame, which sets off processes (APP, CULL), calls pfSync automatically if the user has not called it for the current frame.

Phase Control

When drawing of the scene is complete in the background buffer, use pfPhase to specify when to display the next frame (when it takes longer than the refresh rate to draw a scene.)

PHPHASE_FREE_RUN
 

tells the application to run as fast as possible—to display each new frame as soon as it is ready, without attempting to maintain a constant frame rate.

PFPHASE_LIMIT
 

tells the application to run as fast as possible, but the rendering rate is limited to the frame rate specified by pfFrameRate.

PHPHASE_FLOAT
 

allows the drawing process of a new frame (using swapbuffers(3G)) to begin at any time, regardless of frame boundaries, but the display of the frame is synchronized with the next frame boundary. If the DRAW extends beyond the frame boundary, APP can continue. Application frames might get skipped by DRAW, which is asynchronous.

PHPHASE_LOCK
 

requires the DRAW process to wait for a frame boundary before displaying a new frame.

Figure 10-3 shows these four options.

Figure 10-3. Phase Control over Three Frames

Phase Control over Three Frames

Note the following in Figure 10-3:

  • Screen refresh = 60 Hz.

  • Frame rate = 30 Hz.

  • Frame 1 requires too much time to draw.

Adjusting the Frame Rate Automatically

Erratic frame rates cause jumpy images. Rather than changing frame rates according to whether or not a scene is drawn quickly enough, OpenGL Performer uses two mechanisms to smooth out frame rates:

  • Stress filters in pfChannel.

  • Dynamic Video Resolution (DVR).

Stress Filters

pfChanStressFilter() automatically adjusts the level of detail (LOD) displayed according to the speed at which the frames are being processed. As long as the speed is within a range of values, the stress level and the LODs displayed remain the same. If the stress level falls below that range, the LOD is increased. If the stress level moves above the accepted stress range, the LOD is decreased.

pfChanStress() allows you to handle the LOD display manually.

For more information about stress filters, see Chapter 5, “Frame and Load Control ,” in the OpenGL Performer Programmer's Guide.

Dynamic Video Resolution

On InfiniteReality machines, you can use Dynamic Video Resolution (DVR) to help maintain a constant frame rate. The methods in pfPipeVideoChannel monitor how much time is required to draw each frame. If the frame takes too long to draw, the size of the pfChannel is reduced so that it requires fewer pixels to render. The output is then scaled back to the correct size, so the image appears to be the correct size. If the frame requires too little time to draw; the video output is not reduced.

When using DVR, the origin and size of a channel are dynamic. For example, a viewport whose lower-left corner is at the center of a pfPipe (with coordinates 0.5, 0.5) would be changed to an origin of (0.25, 0.25) with respect to the full pfPipe window if the DVR settings were scaled by factors of 0.5 in both X and Y dimensions. This allows fewer pixels to be drawn per pfChannel for a faster rendering of the scene. Video hardware automatically rescales the image to full size with no penalty or added latency.

Setting the DVR Stress Filter

To set the stress filter, use psPVChanStressFilter, defined as follows:

void pfPipeVideoChannel::psPVChanStressFilter(pfPipeVideoChannel*pv,float *frameFrac,float *lowLoad, float *highLoad, float *pipeLoadScale,
float *stressScale, float *maxStress);

          

frameFrac is the fraction of a frame that pfPipeVideoChannel is expected to require to render the frame. For example, if the rendering time is equal to the period of the frame rate, frameFrac is 1.

If there is only one pfPipeVideoChannel, it is best to set frameFrac to 1. If there is more than one pfPipeVideoChannel, it is best to divide frameFrac among the pfPipeVideoChannels, such that a channel rendering complex scenes is allocated more time than a channel rendering simple scenes.

For more information about DVR, see Chapter 5, “Frame and Load Control ,” in the OpenGL Performer Programmer's Guide.