Chapter 11. Video Extensions

Chapter 6, “Resource Control Extensions”, describes a set of GLX extensions that can be used to control resources. This chapter provides information on the following set of GLX extensions that support video functionality:

SGI_swap_control—The Swap Control Extension

Provided the time required to draw each frame can be bounded, the swap control extension, SGI_swap_control, allows applications to display frames at a regular rate . The extension allows an application to set a minimum period for buffer swaps, counted in display retrace periods.

To set the buffer swap interval, call glXSwapIntervalSGI(), which has the following format:

int glXSwapIntervalSGI( int interval )

Specify the minimum number of retraces between buffer swaps in the interval parameter. For example, a value of 2 means that the color buffer is swapped at most every other display retrace. The new swap interval takes effect on the first execution of glXSwapBuffers() after the execution of glXSwapIntervalSGI().

The functioin glXSwapIntervalSGI() affects only buffer swaps for the GLX write drawable for the current context. Note that glXSwapBuffers() may be called with a drawable parameter that is not the current GLX drawable; in this case, glXSwapIntervalSGI() has no affect on that buffer swap.

New Functions

The SGI_swap_control extension introduces the function glXSwapIntervalSGI().

SGI_video_sync—The Video Synchronization Extension

The video synchronization extension, SGI_video_sync, allows an application to synchronize drawing with the vertical retrace of a monitor or, more generically, to the boundary between to video frames. In the case of an interlaced monitor, the synchronization is actually with the field rate instead. Using the video synchronization extension, an application can put itself to sleep until a counter corresponding to the number of screen refreshes reaches a desired value. This enables an application to synchronize itself with the start of a new video frame. The application can also query the current value of the counter.

The system maintains a video sync counter (an unsigned 32-bit integer) for each screen in a system. The counter is incremented upon each vertical retrace.

The counter runs as long as the graphics subsystem is running; it is initialized by the /usr/gfx/ gfxinit command.


Note: A process can query or sleep on the counter only when a direct context is current; otherwise, an error code is returned. See the man page for gfxinit more information.


Using the Video Sync Extension

To use the video sync extension, follow these steps:

  1. Create a rendering context and make it current.

  2. Call  glXGetVideoSyncSGI() to obtain the value of the vertical retrace counter.

  3. Call glXWaitVideoSyncSGI(), whose format follows, to put the current process to sleep until the specified retrace counter:

    int glXWaitVideoSyncSGI( int divisor, int remainder,
                             unsigned int *count )
    

    The parameters are defined as follows:

    divisor, remainder  

    The function glXWaitVideoSyncSGI() puts the calling process to sleep until the value of the vertical retrace counter (count) modulo divisor equals remainder.

    count 

    This is a pointer to the variable that receives the value of the vertical retrace counter when the calling process wakes up.

New Functions

The SGI_video_sync extension introduces the following functions:

  • glXGetVideoSyncSGI()

  • glXWaitVideoSyncSGI()

SGIX_swap_barrier—The Swap Barrier Extension


Note: The OpenGL swap barrier functionality requires special hardware support and is currently supported only on InfiniteReality graphics.

The swap barrier extension, SGIX_swap_barrier, allows applications to synchronize the buffer swaps of different swap groups—that is, on different machines. For information on swap groups, see “SGIX_swap_group—The Swap Group Extension”.

Why Use the Swap Barrier Extension?

For example, two Onyx InfiniteReality systems may be working together to generate a single visual experience. The first Onyx system may be generating an “out the window view” while the second Onyx system may be generating a sensor display. The swap group extension would work well if the two InfiniteReality graphics pipelines were in the same system, but a swap group cannot span two Onyx systems. Even though the two displays are driven by independent systems, you still want the swaps to be synchronized.

The swap barrier solution requires the user to connect a physical coaxial cable to the Swap Ready port of each InfiniteReality pipeline. The multiple pipelines should also be genlocked together (synchronizing their video refresh rates). Genlocking a system means synchronizing it with another video signal serving as a master timing source.

You can use the swap barrier extension through the OpenGL Performer API rather than calling the extension directly.

Using the Swap Barrier Extension

A swap group is bound to a swap barrier. The buffer swaps of each swap group using that barrier will wait until every swap group using that barrier is ready to swap (where readiness is defined in “Buffer Swap Conditions”). All buffer swaps of all groups using that barrier will take place concurrently when every group is ready.

The set of swap groups using the swap barrier include not only all swap groups on the calling application's system, but also any swap groups set up by other systems that have been cabled together by the Swap Ready ports of their graphics pipeline. This extension extends the set of conditions that must be met before a buffer swap can take place.

Applications call glXBindSwapBarriersSGIX(), which has the following format:

void glXBindSwapBarrierSGIX(Display *dpy, GLXDrawable drawable, int barrier)

The function glXBindSwapBarriersSGIX() binds the swap group that contains drawable to barrier. Subsequent buffer swaps for that group will be subject to this binding until the group is unbound from barrier. If barrier is zero, the group is unbound from its current barrier, if any.

To find out how many swap barriers a graphics pipeline (an X screen) supports, applications call glXQueryMaxSwapbarriersSGIX(), which has the following syntax:

Bool glXQueryMaxSwapBarriersSGIX (Display *dpy, int screen, int max)

The function glXQueryMaxSwapBarriersSGIX() returns in max the maximum number of barriers supported by an implementation on screen.

The function glXQueryMaxSwapBarriersSGIX() returns GL_TRUE if it succeeds and GL_FALSE if it fails. If it fails, max is unchanged.

While the swap barrier extension has the capability to support multiple swap barriers per graphics pipeline, InfiniteReality (the only graphics hardware currently supporting the swap barrier extension) provides only one swap barrier.

Buffer Swap Conditions

Before a buffer swap can take place when a swap barrier is used, some new conditions must be satisfied. The conditions are defined in terms of when a drawable is ready to swap and when a group is ready to swap.

  • Any GLX drawable that is not a window is always ready.

  • When a window is unmapped, it is always ready.

  • When a window is mapped, it is ready when both of the following are true:

    • A buffer swap command has been issued for it.

    • Its swap interval has elapsed.

  • A group is ready when all windows in the group are ready.

  • Before a buffer swap for a window can take place, all of the following must be satisfied:

    • The window is ready.

    • If the window belongs to a group, the group is ready.

    • If the window belongs to a group and that group is bound to a barrier, all groups using that barrier are ready.

Buffer swaps for all windows in a swap group will take place concurrently after the conditions are satisfied for every window in the group.

Buffer swaps for all groups using a barrier will take place concurrently after the conditions are satisfied for every window of every group using the barrier, if and only if the vertical retraces of the screens of all the groups are synchronized (genlocked). If they are not synchronized, there is no guarantee of concurrency between groups.

Both glXBindSwapBarrierSGIX() and glXQueryMaxSwapBarrierSGIX() are part of the X stream.

New Functions

The SGI_swap_barrier extension introduces the following functions:

  • glBindSwapBarrierSGIX()

  • glQueryMaxSwapBarriersSGIX()

SGIX_swap_group—The Swap Group Extension

The swap group extension, SGIX_swap_group, allows applications to synchronize the buffer swaps of a group of GLX drawables. The application creates a swap group and adds drawables to the swap group. After the group has been established, buffer swaps to members of the swap group will take place concurrently.

In effect, this extension extends the set of conditions that must be met before a buffer swap can take place.

Why Use the Swap Group Extension?

Synchronizing the swapping of multiple drawables ensures that buffer swaps among multiple windows (potentially on different screens) swap at exactly the same time.

Consider the following example:

render(left_window);
render(right_window);
glXSwapBuffers(left_window);
glXSwapBuffers(right_window);

The left_window and right_window are on two different screens (different monitors) but are meant to generate a single logical scene (split across the two screens). While the programmer intends for the two swaps to happen simultaneously, the two glXSwapBuffers() calls are distinct requests, and buffer swaps are tied to the monitor's rate of vertical refresh. Most of the time, the two glXSwapBuffers() calls will swap both windows at the next monitor vertical refresh. Because the two glXSwapBuffers() calls are not atomic, the following cases are possible:

  • The first glXSwapBuffers() call may execute just before a vertical refresh, allowing left_window to swap immediately.

  • The second glXSwapBuffers() call is made after the vertical refresh, forcing right_window to wait a full vertical refresh (typically a 1/60th or1/72th of a second).

Someone watching the results in the two windows would very briefly see the new left_window contents, but alongside the old right_window contents. This “stutter” between the two window swaps is always annoying and at times simply unacceptable.

The swap group extension allows applications to “tie together” the swapping of multiple windows. Joining the left_window and right_window into a swap group ensures that the windows swap together atomically. This could be done during initialization by making the following call:


glXJoinSwapGroupSGIX(dpy, left_window, right_window);

Subsequent windows can also be added to the swap group. For example, if there was also a middle window, it could be added to the swap group by making the following call:

glXJoinSwapGroupSGIX(dpy, middle_window, right_window);

Swap Group Details

The only routine added by the swap group extension is glXJoinSwapGroupSGIX(), which has following format:

void glXJoinSwapGroupSGIX(Display *dpy, GLXDrawable drawable, 
                          GLXDrawable member) 

Applications can call glXJoinSwapGroupSGIX() to add drawable to the swap group containing member as a member. If drawable is already a member of a different group, it is implicitly removed from that group first. If member is None, drawable is removed from its swap group, if any.

Applications can reference a swap group by naming any drawable in the group; there is no other way to refer to a group.

Before a buffer swap can take place, a set of conditions must be satisfied. Both the drawable and the group must be ready, satisfying the following conditions:

  • GLX drawables, except windows, are always ready to swap.

  • When a window is unmapped, it is always ready.

  • When a window is mapped, it is ready when both of the following are true:

    • A buffer swap command has been issued for it.

    • Its swap interval has elapsed.

 A group is ready if all windows in the group are ready.

The function glXJoinSwapGroupSGIX() is part of the X stream. Note that a swap group is limited to GLX drawables managed by a single X server. If you have to synchronize buffer swaps between monitors on different machines, you need the swap barrier extension (see “SGIX_swap_barrier—The Swap Barrier Extension”).

New Function

The SGIX_swap_group extension introduces the function glJoinSwapGroupSGIX().

SGIX_video_resize—The Video Resize Extension


Note: This extension is only supported on InfiniteReality systems.

The video resize extension, SGIX_video_resize, is an extension to GLX that allows the framebuffer to be dynamically resized to the output resolution of the video channel when glXSwapBuffers is called for the window that is bound to the video channel. The video resize extension can also be used to minify (reduce in size) a framebuffer image for display on a video output channel (such as NTSC or PAL broadcast video). For example, a 1280 x 1024 computer-generated scene could be minified for output to the InfiniteReality NTSC/PAL encoder channel. InfiniteReality performs bilinear filtering of the minified channel for reasonable quality.

As a result, an application can draw into a smaller viewport and spend less time performing pixel fill operations. The reduced size viewport is then magnified up to the video output resolution using the SGIX_video_resize extension.

In addition to the magnify and minify resizing capabilities, the video resize extension allows 2D panning. By overrendering at swap rates and panning at video refresh rates, it is possible to perform video refresh (frame) synchronous updates.

Controlling When the Video Resize Update Occurs

Whether frame synchronous or swap synchronous update is used is set by calling glXChannelRectSyncSGIX(), which has the following format:

int glXChannelRectSyncSGIX (Display *dpy, int screen,int channel,
                            GLenum synctype);

The synctype parameter can be either GLX_SYNC_FRAME_SGIX or GLX_SYNC_SWAP_SGIX.

The extension can control fill-rate requirements for real-time visualization applications or to support a larger number of video output channels on a system with limited framebuffer memory.

Using the Video Resize Extension

To use the video resize extensions, follow these steps:

  1. Open the display and create a window.

  2. Call glXBindChannelToWindowSGIX() to associate a channel with an X window so that when the X window is destroyed, the channel input area can revert to the default channel resolution.

    The other reason for this binding is that the bound channel updates only when a swap takes place on the associated X window (assuming swap sync updates—see “Controlling When the Video Resize Update Occurs”).

    The function has the following format:

    int glXBindChannelToWindowSGIX( Display *display, int screen,
                                    int channel, Window window )
    
    

    The parameters are defined as follows:

    display 

    Specifies the connection to the X server.

    screen 

    Specifies the screen of the X server.

    channel 

    Specifies the video channel number.

    window 

    Specifies the window that is to be bound to channel. Note that InfiniteReality systems support multiple output channels (two or eight depending on the Display Generator board type). Each channel can be dynamically resized independently.

  3. Call glXQueryChannelDeltasSGIX() to retrieve the precision constraints for any frame buffer area that is to be resized to match the video resolution. In effect, glXQueryChannelDeltasSGIX() returns the resolution at which one can place and size a video input area.

    The function has the following format:

    int glXQueryChannelDeltasSGIX( Display *display, int screen, int channel,
                                  int *dx, int *dy, int *dw, int *dh ) 
    

    The parameters are defined as follows:

    display 

    Specifies the connection to the X server.

    screen 

    Specifies the screen of the X server.

    channel 

    Specifies the video channel number.

    dx, dy, dw, dh 

    Specify the precision deltas for the origin and size of the area specified by glXChannelRectSGIX().

  4. Call XSGIvcQueryChannelInfo() (an interface to the X video control extension) to determine the default size of the channel.

  5. Open an X window, preferably with no borders.

  6. Start a loop in which you perform the following activities:

    • Based on performance requirements, determine the area that will be drawn. If the application is fill-limited, make the area smaller. You can make a rough estimate of the fill rate required for a frame by timing the actual rendering time in milliseconds. On InfiniteReality systems, the SGIX_ir_instrument1 OpenGL extension can be used to query the pipeline performance to better estimate the fill rate.

    • Call glViewPort(), providing the width and height, to set the OpenGL viewport (the rectangular region of the screen where the window is drawn). Base this viewport on the information returned by glXQueryChannelDeltasSGIX().

    • Call glXChannelRectSGIX() to set the input video rectangle that will take effect the next swap or next frame (based on glXChannelRectSyncSGIX() setting). The coordinates of the input video rectangle are those of the viewport just set up for drawing. This function has the following format:

      int glXChannelRectSGIX( Display *display, int screen, 
                    int channel, int x, int y, int w, int h) 
      

      The parameters are defined as follows:

      display—Specifies the connection to the X server

      screen—Specifies the screen of the X server.

      channel—Specifies the video channel number.

      x, y, w, h—Specify the origin and size of the area of the window that will be converted to the output resolution of the video channel. (x,y) is relative to the bottom left corner of the channel specified by the current video combination.

    • Draw the scene.

    • Call glXSwapBuffers() for the window in question.

Example

The following example from the man page for glxChannelRectSGIX() illustrates how to use the extension:

Example 11-1. Video Resize Extension Example

XSGIvcChannelInfo   *pChanInfo = NULL;

... open display and screen ...
glXBindChannelToWindowSGIX( display,screen,channel,window );
glXQueryChannelDeltasSGIX( display,screen,channel, &dx,&dy,&dw,&dh );

XSGIvcQueryChannelInfo( display, screen, channel, &pChanInfo );

X = pChanInfo->source.x;
Y = pChanInfo->source.y;
W = pChanInfo->source.width;
H = pChanInfo->source.height;

... open an X window (preferably with no borders so will not get ...
... moved by window manager) at location X,Y,W,H (X coord system) ...

while( ... )
{
    ...determine area(width,height) that will be drawn based on... 
    ...requirements. Make area smaller if application is fill limited..

    w =  width - ( width % dw );
    h =  height - ( height % dh );

    glViewport( 0,0,w,h );

    glXChannelRectSGIX( display,screen,channel, 0,0,w,h );

    ... draw scene ...

    glXSwapBuffers( display,window );
}


New Functions

The SGIX_video_resize extension introduces the following functions:

  • glXBindChannelToWindowSGIX()

  • glXChannelRectSGIX()

  • glXChannelRectSyncSGIX()

  • glXQueryChannelRectSGIX()