Chapter 17. pfPipeWindows and pfPipeVideoChannels

This chapter describes the additional windowing and video-channel based functionality provided by pfPipeWindows and pfPipeVideoChannels. These libpf objects, based on their libpr counterparts, pfWindows and pfVideoChannels, provide automatic configuration, multiprocessing, and extended functionality by being hooked together with pfChannels.

Using pfPipeWindows

OpenGL Performer can automatically create and open a full screen window with a default configuration for your pfPipe. At the other extreme, you can create and configure your own windows and set them on a pfPipe. There is a single interface for creating, configuring, and managing the windows. The pfPipeWindow is the mechanism by which a pfPipe knows about and keeps track of the windows to which it is to render, the size of the render area, and the framebuffer configuration. pfPipes and pfChannels need this information for proper viewport and frustum management and for using rendering features like antialiasing, transparency for fade LOD, and layers for decal geometry that are all affected by framebuffer configuration.

In the simplest case, OpenGL Performer automatically creates a pfPipeWindow for the application and automatically open a full screen window upon the first call to pfFrame(). This trivial case is demonstrated in Example 17-1.

Creating, Configuring and Opening pfPipeWindow

In most cases, there are some window parameters, such as size and origin, that you will want to set. You may also have custom graphics state that you need to set to fully initialize your rendering window. This section describes the basics for setting up windows through the pfPipeWindow mechanism.

A pfPipeWindow can be created for a pfPipe using pfNewPWin(pipe). If you create a pfPipeWindow, then you are responsible for explicitly opening it. The call to pfOpenPWin(pwin) from the application process causes the next call to pfFrame() to trigger the opening of the pfPipeWindow in the draw process. A pfPipeWindow created in the application will be a rubber-band window of undefined size for the user to stretch out. This is in contrast to the full screen window that OpenGL Performer creates on your behalf in the fully automatic case. To easily get a full screen window, you can use the pfPWinFullScreen() function. pfPWinOriginSize() can be used to set a fixed position and size for the window. The code in Example 17-1, placed in the application process, creates and opens a window in the lower-left corner of the screen of size 500 pixels on each side.

Example 17-1. Creating a pfPipeWindow

main() 
{
    pfPipe *pipe;
    pfPipeWindow *pwin;
    pfInit();
    ....
    pfConfig();
    /* Create pfPipeWindow for pfPipe 0 */
    pipe = pfGetPipe(0;
    pwin = pfNewPWin(pipe);
    /* Set the origin and size of the pfPipeWindow */
    pfPWinOriginSize(pwin, 0, 0, 500, 500);
    /* Tell OpenGL Performer that the pfPipeWindow is ready to
     * be opened 
     */
    pfOpenPWin(pwin);
    /* trigger the opening of the pfPipeWindow 
     * in the draw process 
     */
    pfFrame();
    ...
    while(!SimDone())
    { ... }
}

The pfPipeWindow is always physically opened in the draw process when processing the application frame that requested the window to be opened. When both the cull and draw processes are running as separate processes, there might be a 2-frame delay (two additional calls to pfFrame()) for the window do actually be opened. Additionally, if the draw is running as a separate process, the window will not be opened right after pfFrame but some time in that following frame. If the pfPhase is such that the application process is allowed to spin ahead while the draw process does expensive initialization (anything but PFPHASE_FREE_RUN), the application process may execute many pfFrame() calls before the window is physically opened in the draw process. If in the application process you need to check on a result from opening the window, such as framebuffer configuration, you will want to do something that is in effect equivalent to the following:

while (!pfIsPWinOpen(pwin)) pfFrame();

pfPipeWindows are actually built upon libpr pfWindows, but have added support for handling the multiprocessed environment of libpf applications and fit into the libpf display hierarchy of pfPipes, pfPipeWindows, and pfChannels. Additionally, pfPipeWindows support the multiprocessing environment of libpf by having a separate copy of each pfPipeWindow in each pipeline process. All of the “windowness” of pfPipeWindows really comes from the fact that there is a pfWindow internal to the pfPipeWindow. Many of the basic support routines, such pfPWinFullScreen() and pfWinFullScreen(), have very similar functionality for pfWindows and pfPipeWindows. However, there are situations where pfPipeWindows are able to provide the same functionality in a much more efficient manner. Management of dynamic window origin and size is one case where pfPipeWindows have a real advantage over pfWindows. pfPipeWindows are able to take advantage of the multiprocessed libpf environment to always be able to return an accurate window size and origin relative to the window parent. A process separate from the rendering process is notified by the window system of changes in the pfPipeWindow's size in an efficient manner without impacting the window system or the rendering process. This can be forced off for the real-time static displays of a deployed visual simulation system by making the pfPipeWindow of type PFPWIN_TYPE_NOXEVENTS, which prevents OpenGL Performer from tracking the window. Further details regarding basic window creation and configuration are discussed with pfWindows in Chapter 16, “Windows”.


Note: pfPWin*() routines expect a pfPipeWindow and the pfWin*() routines a pfWindow. These routines are not interchangeable: pfWindow routines cannot accept pfPipeWindows nor the reverse. The PFWIN_* tokens can be used with the pfPipeWindow routines.

Windows have some intrinsic type attributes that must be set before the window is opened. The selection of the screen of a window is determined by the pfPipe that it is opened on, set for both the pfWindow and its pfPipe with the call pfPWinScreen(), or else set by the value of the DISPLAY variable when the window is finally opened. The window system configuration of the window must also be set before the window is opened. Windows under OpenGL operation on IRIX and Linux systems will always be X windows. On Microsoft Windows, the windows will be HWNDs.


Note: Micrsoft Wndows virtualizes the concept of a screen as well as all available hardware. Hence, on such systems, you cannot specify the screen connection in a manner similar to using the DISPLAY environment variable.

An open window must be closed for its type to be changed. The window type argument is actually a bitmask and the type of a pfPipeWindow can include the attributes listed in Table 17-1.

Table 17-1. pfPWinType Tokens

PFPWIN_TYPE_* Bitmask Token

Type Attributes

X

The default. Rendering will be done to an X window. Ignored by OpenGL as all OpenGL rendering is done to X windows.

STATS

The window's normal drawing configuration supports graphics statistics. This affects framebuffer configuration and fill statistics.

SHARE

The pfPipeWindow automatically attaches to the first pfPipeWindow of the parent pipe with pfAttachPWin().

PBUFFER

The window drawable is a pbuffer (not visible on the screen).

NOXEVENTS

Window size and position tracking is not done.

UNMANAGED

No automatic window management operations other than select for rendering happens. Window is not auto-sized or tracked. Swapbuffers will not automatically be done.

pfPipeWindows have a target default framebuffer configuration. The ability to meet this target depends on the current graphics hardware configuration, as well as their type. The following parameters are part of the target default configuration and are listed in their order of priority. If the goal framebuffer configuration cannot be created on the current graphics hardware configuration, lower priority parameters are downgraded as specified in the following:

  1. double buffered

  2. RGB mode with 8 bits per color component (4 if 8 cannot be supported)

  3. z-buffer with depth of 23 or 24 bits, as available

  4. one-bit stencil buffer (window type PFWIN_TYPE_STATS still requires four bits of stencil)

  5. multisample buffer of 8, 4, or 0 samples as available

  6. four-bit stencil buffer if still available after the above is satisfied

pfPipeWindows have OpenGL Performer libpr rendering state automatically initialized when they are opened. Additionally the following graphics state is automatically initialized when a window is opened or upon any call to pfInitGfx() for an open window:

  1. RGB mode is enabled.

  2. z-buffer is enabled and a z range is set.

  3. Viewport clipping is enabled.

  4. subpixel vertex accuracy is enabled.

  5. The viewing matrix is initialized to a two-dimension, one-to--one mapping from eye coordinates to window coordinates.

  6. The model matrix is initialized to the identity matrix and made the current GL matrix.

  7. Backface removal is enabled.

  8. Smooth shading is enabled.

  9. If the current graphics hardware platform supports multisampling, multisampled antialiasing will be enabled with pfAntialias(PFAA_ON).

  10. A default modulating texture environment is created.

  11. A default lighting model is created.

Custom framebuffer configuration for a pfPipeWindow can be specified with pfPWinFBConfigAttrs(), pfPWinFBConfig(), and pfChoosePWinFBConfig(). These routines have identical functionality as each of the corresponding pfWindow routines. However, the function pfChoosePWinFBConfig() has the constraint that it be called in the draw process because it creates and stores internal data from the window server that must be kept local to the process in which it is called. Table 17-2 lists the different pfPipeWindow routines and describes multiprocessing constraints.

The flexibility in changing the framebuffer configuration of OpenGL/X windows or OpenGL/HWNDs is complex. The main window can remain in place but structures under it must be switched or replaced. If multiple framebuffer configurations are likely to be desired, multiple graphics contexts can be created for the window using pfWindows. pfPipeWindows and pfWindows both allow you to have a list of alternate pfWindows that render to exactly the same screen area but may have different framebuffer configuration. You then select the current configuration for a pfPipeWindow with pfPWinIndex(). There are two kinds of common alternate configuration windows that can be created automatically for you: overlay windows created in the overlay planes and windows to support hardware fill statistics (discussed in Chapter 23, “Statistics”). You can use pfPWinMode() to indicate that you would like these windows created for you automatically. Special tokens to pfPWinIndex() are used to select these common special alternate configuration windows— PFWIN_GFX_WIN, PFWIN_OVERLAY_WIN and PFWIN_STATS_WIN—where PFWIN_GFX_WIN selects the normal default drawing window. Note that only a pfWindow, never a pfPipeWindow, can be an alternate configuration window. The source code in Example 17-2 is taken from /usr/share/Performer/src/pguide/libpf/C/pipewin.c for IRIX and Linux and from %PFROOT%\Src\pguide\libpf\C\pipewin.c for Microsoft Windows. It demonstrates the automatic creation and selection of overlay and statistics windows for a pfPipeWindow. This also shows usage of pfChannels and interaction between pfPipeWindows and pfChannels discussed in the section “Creating and Configuring a pfChannel” in Chapter 2.

Example 17-2. pfPipeWindow With Alternate Configuration Windows for Statistics

main() 
{
    pfPipe *pipe;
    pfPipeWindow *pwin;
    pfInit();
    ....
    pfConfig();
 
    /* Create pfPipeWindow for pfPipe 0 */
    pipe = pfGetPipe(0);
    pwin = pfNewPWin(pipe);
    /* request automatic default overlay and stats windows */
    pfPWinMode(pwin, PFWIN_HAS_OVERLAY, PF_ON);
    pfPWinMode(pwin, PFWIN_HAS_STATS, PF_ON);
    /* Open the main graphics window */
    pfOpenPWin(pwin);
    pfFrame();
 
    while(!SimDone())
    {
    ...
    if (Shared->winSel == PFWIN_STATS_WIN))
    {
        /* select statistics window and enable fill stats */
        pfPWinIndex(Shared->pw, PFWIN_STATS_WIN);
        pfFStatsClass(fstats, 
              PFSTATSHW_ENGFXPIPE_FILL, PFSTATS_ON);
        pfEnableStatsHw(PFSTATSHW_ENGFXPIPE_FILL);
     }
     else
    {
        /* we are not doing statistics so turn them off */
        pfFStatsClass(fstats, 
            PFSTATSHW_ENGFXPIPE_FILL, PFSTATS_OFF);
        pfDisableStatsHw(PFSTATSHW_ENGFXPIPE_FILL);
        pfPWinIndex(Shared->pw, Shared->winSel);
    ...
    }
}
 
/* Channel draw process drawing function */
void DrawFunc(void pfChannel *chan)
{
    pfPipeWindow *pwin;
    pwin = pfGetChanPWin(chan);
    if (pfGetPWinIndex(pwin) == PFWIN_OVERLAY_WIN)
    {
        /* Draw overlay image */
        DrawOverlay();
        /* Put back the normal drawing window */
        pfPWinIndex(pwin, PFWIN_GFX_WIN);
        /* Indicate that we will now draw to the window */
        pfSelectPWin(pwin);
     }
     /* call the main OpenGL Performer drawing function */
     pfDraw();
}

Notice that in Example 17-2, although the pfPipeWindow is double buffered, the front and back color buffers are never explicitly swapped. For pfPipeWindows, this operation is done automatically after all channels on the parent pfPipe have completed their drawing for the given frame. The color buffers of a pfPipeWindow may be swapped explicitly with pfSwapWinBuffers. This call may be placed in a user-swap function call back placed on the pfPipe with pfPipeSwapFunc() to replace the pfPipe normal swap behavior. The swap callback will be called in the draw process at the end of the frame after all pfChannels in all pfWindows have been drawn for the pfPipe. The function is called for all of the pfPipeWindows on the pfPipe. This is additionally useful for doing end-of-frame rendering or readbacks from the framebuffer.

You may need to set additional window and graphics state to complete the initialization of your pfPipeWindow. Calling pfOpenPWin() from the application process does not give you the opportunity to do this. However, with pfPWinConfigFunc(), you can supply a window configuration callback function that will enable you to open and initialize your pfPipeWindow in the draw process. A call to pfConfigPWin() triggers one call of the window configuration callback in the draw process upon the next call to pfFrame(). pfConfigPWin() can be called at any time to trigger the calling of the current window configuration function in the draw process. Example 17-3 demonstrates initializing a pfPipeWindow from a draw process window configuration callback. It creates a global light to serve as the Sun in the window configuration callback. (see the /usr/share/Performer/src/pguide/libpf/C/complex.c example for IRIX and Linux and %PFROOT%\Src\pguide\libpf\C\complex.c for Microsoft Windows).

Example 17-3. Custom Initialization of pfPipeWindow State

main() 
{
    pfPipe *pipe;
    pfPipeWindow *pwin;
    pfInit();
    ....
    pfConfig();
 
    /* Create pfPipeWindow for pfPipe 0 */
    pipe = pfGetPipe(0);
    pwin = pfNewPWin(pipe);
    /* Set the configuration function for the pfPipeWindow */
    pfPWinConfigFunc(pwin, OpenPipeWindow);
    /* Indicate that OpenPipeWindow should be called in the 
     * draw process.
     */
    pfConfigPWin(pwin);
 
    /* trigger OpenPipeWindow to be called in the draw process */
    pfFrame();
    while(!SimDone())
    { ... }
}
 
/* Initialize graphics state in the draw process */
void
OpenPipeWindow(pfPipeWindow *pw)
{
    /* Set some configuration stuff */
    pfPWinOriginSize(pw, 0, 0, 500, 500);
    /* Open the window - will give us initialized libpr and      *     graphics state 
     */
    pfOpenPWin(pw);
    
    /* create a global light in the “south-west” (QIII) */
    Sun = pfNewLight(NULL);
    pfLightPos(Sun, -0.3f, -0.3f, 1.0f, 0.0f);
}

In Example 17-3 the functions pfPWinOriginSize() and pfOpenPWin() are now called in the draw process, as opposed to the application process as in Example 17-1. In general, configuring or editing any libpf object must be done in the application process. pfPipeWindows must be created in the application process. However, pfPipeWindows may be configured, edited, opened and closed in the pfPWinConfigFunc() configuration callback which will be called in the draw process. Window operations are best done in a configuration callback, though they can also be done in the drawing callback for a pfChannel on the window. Any function which aspires to directly affect the graphics context must be called in the drawing process. Table 17-2 shows which processes (application or draw via a configuration function) that pfPipeWindow calls can be made from and further detail about these functions can be found in the discussion of pfWindows in Chapter 16, “Windows”.

Table 17-2. Processes From Which to Call Main pfPipeWindow Functions

pfPipeWindow Function

Application Process

Draw Process

pfNewPWin()

Yes

No

pfPWinMode()

Yes

Yes

pfPWinIndex()

Yes

Yes

pfPWinConfigFunc()

Yes

No

pfOpenPWin()
pfClosePWin()
pfClosePWinGL()

Yes

Yes

pfPWinOriginSize()
pfPWinFullScreen()

Yes

Yes

pfGetPWinCurOriginSize()

Yes

Yes.

pfPWinFBConfigAttrs()

Yes

Yes.

pfChoosePWinFBConfig()

No

Yes.

pfPWinFBConfig()

Yes, but the pfFBConfig* must be valid for access in the draw process.

Yes.

pfPWinType()
pfPWinScreen()
pfPWinShare(), pfAttachWin()

Yes (before opened)

Yes (before opened).

pfPWinWSWindow()

Yes

Yes.

pfPWinGLCxt()

Yes, but the context must be created in the draw process.

Yes.

pfQueryWin()
pfMQueryWin()

No

Yes.

pfAddPWinPVChan()

Yes

Yes.

pfAttachPWinSwapGroup()

Yes

Yes

OpenGL Performer provides GL-independent framebuffer configuration utilities. In most cases, pfPWinFBConfigAttrs(pwin, attrs) can be used to select a framebuffer configuration for your pfPipeWindow based on the array of attribute tokens attrs. If attrs is NULL, the default framebuffer configuration will be selected. If attrs is not NULL, the rules for default values follow the rules for configuring windows in OpenGL and X, which are different from values in the OpenGL Performer default window configuration. Such window framebuffer configuration should be done in the draw process in a window configuration callback function before the call to pfOpenPWin(). Window framebuffer configuration for pfPipeWindows is identical to that of pfWindows and is discussed in more detail in Chapter 16, “Windows”, but the following is a simple example of the specification of framebuffer configuration taken from the sample source code example program /usr/share/Performer/src/pguide/libpf/C/pipewin.c for IRIX and Linux and from %PFROOT%\Src\pguide\libpf\C\pipewin.c for Microsoft Windows:

Example 17-4. Configuration of a pfPipeWindow Framebuffer

static int FBAttrs[] = {
    PFFB_RGBA,
    PFFB_DOUBLEBUFFER,
    PFFB_DEPTH_SIZE, 24,
    PFFB_RED_SIZE, 8,
    PFFB_SAMPLES, 8,
    PFFB_STENCIL_SIZE, 1,
    NULL,
};
 
main() 
{
    pfPipe *pipe;
    pfPipeWindow *pwin;
    pfInit();
    ....
    pfConfig();
 
    /* Create pfPipeWindow for pfPipe 0 */
    pipe = pfGetPipe(0);
    pwin = pfNewPWin(pipe);
    /* Set the framebuffer configuration */
    pfPWinFBConfigAttrs(Shared->pw, FBAttrs);
    /* Indicate that the window is ready to open */
    pfOpenPWin(pwin);
    /* trigger the opening of the window in the draw */
    pfFrame();
    ...
}

If you want to do all of your own window creation and management you can do so and just give OpenGL Performer the handles to your windows with the pfPWinWSDrawable() function; you may also provide a parent X window (or HWND on Microsoft Windows) with the pfPWinWSWindow() function. pfOpenPWin() makes use of any windows that have already been provided. More details regarding the creation and configuration of pfPipeWindows and pfWindows are discussed in Chapter 16, “Windows”.

pfPipeWindows in Action

pfPipeWindows allow for a reasonable amount of flexibility in the running application. pfPipeWindows can be re-ordered on their parent pfPipe to control the order that they are drawn in with the command pfMovePWin(pipe, index, pwin). pfPipeWindows can be dynamically opened and closed in the application or draw processes with pfOpenPWin() and pfClosePWin(). Additionally, pfConfigPWin() can be re-issued at any time from the application process to call the current window configuration function to dynamically open, close, and reconfigure pfPipeWindows.

The following example is taken from the distributed source code example file /usr/share/Performer/src/pguide/libpf/C/pipewin.c for IRIX and Linux and from %PFROOT%\Src\pguide\libpf\C\pipewin.c for Microsoft Windows. It demonstrates the dynamic closing of a window from the application process in the simulation loop and the reuse of pfConfigPWin() to reopen the window.

Example 17-5. Opening and Closing a pfPipeWindow

main()
{
    ...
    /* main simulation loop */
    while (!Shared->exitFlag)
    {
    /* wait until next frame boundary */
    pfSync();
    pfFrame();
    /* Set view parameters for next frame */
    UpdateView();
    pfChanView(chan, Shared->view.xyz, Shared->view.hpr);
 
    /* Close pfPipeWindow */
    if (Shared->closeWin == 1)
    {
        pfClosePWin(Shared->pw);
        ct = pfGetTime();
        Shared->closeWin = 2;
    } 
    /* then wait two seconds and reconfig window */
    else if ((Shared->closeWin == 2) && 
                        (pfGetTime() - ct > 2.0f))
    {
       pfConfigPWin(Shared->pw);
       Shared->closeWin = 3;
       pfNotify(PFNFY_NOTICE, PFNFY_PRINT, “OPEN”);
}   }
    ...
}


Motif

You may want your windows to reside within a larger Motif interface and window hierarchy. OpenGL Performer supports this and allows you to run the Motif main loop in a separate process so that you can maintain control of your simulation loop. The Motif interface is created in its own process and Motif event handlers and callbacks will be executed in that process. The Motif callbacks set flags in shared memory to communicate with the main application. Part of this communication is the sharing of X windows between OpenGL Performer and Motif. The example program /usr/share/Performer/src/pguide/libpf/C/motif.c for IRIX and Linux and program %PFROOT%\Src\pguide\libpf\C\motif.c for Microsoft Windows demonstrate the basic elements of this integrated OpenGL Performer-Motif hook-up.

Multiple pfPipeWindows and Multiple pfPipes

The use of multiple windows on a single graphics pipe can add overhead. The sharing of the graphics context between windows consumes almost all of this overhead. To simply share a single graphics context across windows of two pfPipe objects, include PFPWIN_TYPE_SHARE in the pfPWinType() call. The sharing of pfPipeWindows and attributes can be completely controlled by setting up the sharing manually to create pfPipeWindow share groups with pfPWinAttach(groupPWin, attachee) and pfPWinShare() as is done with pfWindows, discussed in Chapter 16, “Windows”. pfPipeWindows can have pfWindows in their share group if a pfPipeWindow is the main group window.

Multiple windows, particularly those on separate graphics pipelines, that are intended to produce results that can be seen as a single image, such as projected side by side on a large screen or to video outputs used for a stereo display, must have their video vertical retraces synchronized with genlock(7) and their double buffering synchronized. This is necessary for both image quality and performance reasons as the last window to finish operation can hold up all of the rendering processes. Window double-buffering synchronization can be done through pfChannel share groups with the PFCHAN_SWAPBUFFERS_HW token, as discussed in Chapter 2, “Setting Up the Display Environment”, or explicitly by attaching the windows to form window swap groups with pfAttachPWinSwapGroup(groupPWin, attachee) as discussed in Chapter 16, “Windows”. pfPipeWindows can have pfWindows in their swap groups if a pfPipeWindow is the main group window. The sample program in file /usr/share/Performer/src/pguide/libpf/C/multipipe.c for IRIX and Linux and in file %PFROOT%\Src\pguide\libpf\C\multipipe.c for Microsoft Windows demonstrates multipipe synchronization.

Controlling Video Displays

You use pfPipeVideoChannel to direct the output of pfChannels to specified video displays, as shown in Figure 17-1. OpenGL Performer uses the XSGIvc(3), which is a Silicon Graphics extension of the X library, for video channel management.

Figure 17-1. Directing Video Output

Directing Video Output

pfPipeVideoChannels are based on pfVideoChannels; however, pfPipeVideoChannels are maintained by libpf and are used by libpf to render the ou tput of pfChannels within a pfPipeWindow. The pfVideoChannel API is duplicated for pfPipeVideoChannels. pfPVChan*() methods operate on a pfPipeVideoChannel and pfVChan*() methods operate on a pfVideoChannel.

There are several sample programs to help understand the use of pfVideoChannels and pfPipeVideoChannels. The libpr program /usr/share/Performer/src/pguide/libpr/C/queryvchan.c for IRIX and Linux and the program %PFROOT%\Src\pguide\libpr\C\queryvchan.c for Microsoft Windows show how to query video channel attributes through OpenGL Performer and how to query additional attributes directly through the XSGIvc interface. The program /usr/share/Performer/src/pguide/libpr/C/vchan.c for IRIX and Linux and the program %PFROOT%\Src\pguide\libpr\C\vchan.c for Microsoft Windows show basic video channel creation. On an InfiniteReality, this example does resizing and translation of the video channel output area. The libpf program /usr/share/Performer/src/pguide/libpf/C/pvchan.c for IRIX and Linux and the program %PFROOT%\Src\pguide\libpf\C\pvchan.c for Microsoft Windows show basic pfPipeVideoChannel creation and hookup.

Creating a pfPipeVideoChannel

You create a pfPipeVideoChannel from a pfPipe using pfNewPVChan() and providing the parent pfPipe. The pfPipeVideoChannel is then attached to a pfPipeWindow with pfAddPWinPVChan(), which returns an index into the pfPipeWindow's video channel list. Additionally, if the pfPipeVideoChannel has not already been assigned a hardware video channel with pfPVChanId(), the next active video channel will be assigned.

pfPipe *p = pfGetPipe(0);
pfPipeVideoChannel *pvc = pfNewPVChan(p);
pfPVChanId(pvc,0);
pvcIndex = pfPWinAddPVChan(pwin, pvc);

To find out if a pfPipeVideoChannel with its current video channel assignment is active for displaying output, call pfIsPVChanActive(), which returns 0 if the video channel assignment is not fully defined or if the channel is not active and returns 1 otherwise. The assignment of a hardware video channel is not complete until the screen of the pfPipe is known and so might not be done immediately if the pfPipe screen has not been set with pfPipeScreen() or if the pfPipeWindow is not open. Even if you have explicitly assigned a hardware video channel ID, it is only meaningful relative to a known screen. The hardware video channel assignment can be changed at any time with pfPVChanId(). It is an error to have multiple pfPipeWindows and pfPipeVideoChannels attempt to manage the same hardware video channel. The index returned by pfAddPWinPVChan() is then used for a pfChannel to reference this pfPipeVideoChannel. pfPipeWindows always have an initial pfPipeVideoChannel already attached whose default video channel will be the first active video channel on the screen of the pfPipe. So, only add pfPipeVideoChannels if you actually need additional video channels.

Multiple pfPipeVideoChannels in a pfPipeWindow

The only video channels a pfPipeVideoChannel can manage are those of the screen of the pfPipe. Use pfGetNumScreenPVChans() to find out how many active video channels are on a given screen.

To add additional pfPipeVideoChannels to a single pfPipeWindow, use pfPWinAddPVChan(). The routine returns an index number associated with the pfPipeWindow, or -1 if an error occurs. If the pfPipeVideoChannel does not already have an assigned hardware video channel, the next active video channel relative to the video channels already attached to the pfPipeWindow will be assigned.

There are list routines to manage the list of pfPipeVideoChannels on a pfPipeWindow. Use pfGetPWinNumPVChans() to find out how many pfPipeVideoChannels are being managed by the pfPipeWindow. pfPWinRemovePVChan() and pfPWinRemovePVChanIndex() disassociate a pfPipeVideoChannel from a pfPipeWindow, using either the pfPipeWindow object or an index number to specify the pfPipeWindow.

There are additional utilities to find pfPipeVideoChannels on pfPipeWindows. You can obtain the index value of a pfPipeVideoChannel for a pfPipeWindow using pfGetPWinPVChanIndex(), which returns the index of a pfPipeVideoChannel, or -1 of the pfPipeVideoChannel is not registered with the pfPipeWindow. Use pfGetPWinPVChanId() to find a pfPipeVideoChannel on a pfPipeWindow with the specified hardware Id. NULL will be returned if no such pfPipeVideoChannel exists on the specified pfPipeWindow.

Configuring a pfPipeVideoChannel

pfPipeVideoChannels are bound to their hardware video channels in a lazy fashion as needed by configuration requests. Basic queries of a video channel do not require any explicit binding. Changing a video channel's properties does require explicit binding. pfPipeWindows manage this process. However, explicit binding and unbinding might be necessary if changes are made to video channels directly through the XSGIvc API and not through the pfPipeVideoChannel API. This is quite reasonable since pfPipeVideoChannels do not duplicate all of XSGIvc. A pfPipeVideoChannel is bound to its hardware video channel with pfBindPVChan(). All of the pfPipeVideoChannels associated with a pfPipeWindow can be bound in one step with pfBindPWinPVChans() and unbound with pfUnbindPWinPVChans(). You can get the XSGIvc handle from a pfPipeVideoChannel to do your own configuration or extended queries with pfGetPVChanInfo().

Use pfPipeVideoChannels to Control Frame Rate

There are two mechanisms by which pfPipeVideoChannels can help you maintain constant frame rate in your application. Dynamic Video Resolution (DVR) addresses reducing load caused by filling to many pixels. Pan/Zoom video scan-out to sample different parts of the frame buffer, under resize, to be selected asynchronously to a draw process. Both of these mechanisms make use of editing the size and or origin of the output area of a pfPipeVideoChannel, supported by InfiniteReality graphics platforms. Using pfPVChanOutputSize() and pfPVChanOutputAreaScale() changes the output area size of the bound video channel. pfPVChanOutputOrigin() changes the origin of the output area. The pfPipeVideoChannel(3) references more routines to manage video channel origin and size.

On InfiniteReality graphics platforms, you can use pfPipeVideoChannels to dynamically adjust the size of the output area of the video channel. The output area is then automatically zoomed up to full video channel size by the InfiniteReality hardware using bilinear filtering. This operation has no added performance cost or latency. This feature can be used to allow pfChannels to reduce their viewport size to the reduced video channel output area. Reducing the number of pixels drawn reduces the fill load for the pfPipe and can be used as a load management technique for maintaining constant frame rates. pfPipeVideoChannels support manual resizing, allowing you to implement your own load management, or automatically resizes the output area and the pfChannel viewports. You can enable and select a resizing mode with pfPVChanDVRMode() and providing PFPVC_DVR_MANUAL or PFPVC_DVR_AUTO. The default value is PFPVC_DVR_OFF. For more information, see “Level-of-Detail Management” in Chapter 5.

pfPipeVideoChannels also support asynchronous editing of their size and origin. This can be used in an asynchronous process, or in an application process that is reliably running at frame rate, to edit the origin and size of the video channel. These changes will affect the following video field if the pfPVChanMode() for PFVCHAN_AUTO_APPLY is set to 1 (default is 0) and the PFVCHAN_SYNC mode is set to PFVCHAN_SYNC_FIELD (default is PFVCHAN_SYNC_FRAME which selects apply upon swapbuffers).

Real-time changes to pfPipeVideoChannel origin or size should be done between pfSync() and pfFrame() to affect the next draw frame or video field.