X Server Device Developer's Guide
只搜尋這本書
以 PDF 格式下載這本書

Colormap Interface

8

This chapter describes the colormap interfaces (CMAP) visible to Solaris Independent Hardware Vendors (IHVs) writing DDX ports. The topics discussed are:
  • Introduction to CMAP
  • CMAP Call Summary
  • Compiling and Linking
  • MPG and WID Initialization
  • CMAP Initialization and Utilities
  • Controlling Multiple Hardware Colormap (MHC) device's WIDs
  • Changing a Window's WID
  • Changing a Window's Colormap

Introduction to CMAP

The CMAP interface provides colormap management for devices with hardware color lookup tables. Call it from your DDX handler to initialize the colormap functions of your device's pScreen.
CMAP manages colormaps for devices with both a single hardware color lookup table and multiple hardware color lookup tables.

Note - If you do not use CMAP to manage your colormaps, part of the DGA interface will not work. For information, see "DGA and Colormaps" on page 204.

Sharing Equivalent Colormaps

Programs can assign a colormap of one visual to a window that was created with a different visual, as long as the two visuals are colormap equivalent. This means that they share the same plane group and have the same number of colormap entries. For more information on colormap equivalence, see the XSolarisCheckColormapEquivalence(3) man page.

CMAP Call Summary

General Calls

The CMAP interface provides these functions for initializing colormap management for devices, retrieving the device colormap attributes, and releasing memory:
  • cmapScreenInit
  • cmapCloseScreen
  • cmapGetDevFuncs
  • cmapGetMultiple
  • cmapGetCmapPriv
  • cmapGetWidType
When calling cmapScreenInit, you must specify whether the device has a single-color lookup table or multiple-color lookup tables.

MHC Calls

When you call cmapGetMultiple, multiple color LUT management has been selected and CMAP provides the following additional routines. These routines only operate when multiple color LUT management has been selected; they return error status in the single-color LUT case.
  • cmapMhcForceOverload
  • cmapMhcReleaseOverload
  • cmapMhcWindowAttachWid
  • cmapMhcWindowDetachWid
  • cmapMhcChangeFlavor
  • cmapMhcAllocWids

Compiling and Linking

If you have a color device, use cmapScreenInit to initialize CMAP. The interface to these routines is provided by these header files:
  • colormapst.h
  • cmap.h
These routines are built into the server, so symbolic references to these routines are resolved when your DDX handler shared object is loaded into the server.
Additionally, MPG DDX handlers should use mpgScreenInit to initialize MPG. The interface to this routine, and associated routines, is provided by the following header file:
  • mpg.h
These routines are provided by libmpg.so. Dynamically link the device handler with this shared object.
Finally, dynamically link DDX handlers that use the following routines with libmhc.so:
  • cmapMhcForceOverload
  • cmapMhcReleaseOverload
  • cmapMhcWindowAttachWid
  • cmapMhcWindowDetachWid
  • cmapMhcChangeFlavor
  • cmapMhcAllocWids

MPG and WID Initialization

The Multiple Hardware Colormap (MHC) devices supported by CMAP are MPG devices that mostly use window IDs (WIDs). The Solaris DDK provides the WID interface for managing these aspects of device control. See Chapter 7, "Window ID Interface."
Prior to initializing CMAP for multiple color LUT management, initialize MPG by calling mpgScreenInit and mpgGetScreenState. For more information, see Chapter 5, "Multiple Plane Group Interface."
If the device also has WIDs, call widScreenInit. For more information see Chapter 7, "Window ID Interface."

CMAP Initialization and Utilities

Screen Initialization Routine

To initialize either single or multiple color lookup table management, call cmapScreenInit. For MHC devices, call this routine after the MPG and WID packages have been appropriately initialized.

cmapScreenInit


  Bool  
  cmapScreenInit (ScreenPtr pScreen, CmapDevFuncs *pDevFuncs,  
           Bool multiple, int numClutPools,  
           CmapClutPoolDesc *pClutPoolDescs, CmapWidType widType)  

Purpose....Initialize colormap management for the given screen. This routine changes the following members of the screen:
                  CreateColormap, DestroyColormap,
                  InstallColormap, UninstallColormap,
                  ListInstalledColormaps, and StoreColors.

The device must supply device-dependent routines for accessing its hardware color LUT(s).
Arguments...pDevFuncs points to a structure with pointers to these functions. This pointer must be non-NULL.
If multiple is FALSE, single hardware color lookup table management is initialized.
If multiple is TRUE, multiple hardware color lookup table management is selected. If this mode is selected, information describing the configuration of the hardware color lookup tables must be passed in the arguments numClutPools and pClutPoolDescs.
If multiple is TRUE, the argument widType indicates whether the device uses WIDs and, if so, what type of WID device it is.
If multiple is TRUE, mpgScreenInit must have been already called. If not, this routine returns FALSE. Furthermore, if multiple is TRUE and widType is
                  CmapWidIndirect or CmapWidDirect, widScreenInit
                  must have already been called. Otherwise, this routine
                  returns FALSE.

Results....The contents of pDevFuncs and pClutPoolDescs are copied into an internal structure rather than copying the pointers.
The data types used by cmapScreenInit are described in the following section.

Device-Dependent Color LUT Access Routines

A pointer to the CmapDevFuncs structure is passed to cmapScreenInit.

CmapDevFuncs


  typedef struct {  
  Bool (*writeClutFunc) (ColormapPtr pCmap, CARD32 clutId)  
  Bool (*storeColorsFunc)(ColormapPtr pCmap, CARD32 clutId,  
                                 int ndef, xColorItem *pdefs)  
  /* reserved for future expansion */  
  pointer reserved[4];  
  } CmapDevFuncs;  

PurposeSpecifies device-dependent routines for accessing the device's hardware color LUTs. Use WriteClutFunc in your device handler to write an entire colormap into one of the hardware color LUTs. This structure member must always be non-NULL.
ArgumentsclutId is the device-dependent hardware identifier of the hardware color LUT into which the color data is written. If a single hardware color LUT operation has been selected, the value of clutId is arbitrary.
storeColorsFunc is provided by the device handler to update a hardware color LUT with a set of XColorItem changes. ndef is the number changes specified in the list of changes in pdefs.
Returns....TRUE on success; FALSE on failure.

Implementing writeClutFunc

When updating a color LUT, a DDX handler should avoid updating color LUT entries whose corresponding colormap entry is unallocated. This reduces colormap flashing. The following sections discuss the various ways to implement this behavior.
Loading Color Lookup Tables Some devices are mapped-access devices--devices with color LUTs memory-mapped into the X server process. The DDX handler can access the contents of these LUTs quickly. Other devices are request-access devices--devices with color LUTs accessed through a request, such as a kernel driver ioctl.
For best results, request-access devices require a different color LUT update strategy than mapped-access devices because the time required per access is different.
For request-access devices, the possible strategies are:
  • Get the entire color LUT contents, update it with allocated colormap cells, and put the entire color LUT back.
  • Get the color data for the allocated colormap cells and the list of allocated cells. Determine contiguous ranges of allocated entries. Invoke several requests to put the color data for these ranges into the hardware.
For mapped-access devices, the best strategy is:
  • Get the color data for the allocated colormap cells and the list of allocated cells. Use the allocation information to directly copy the data into the hardware.
Do not use the strategy of caching color LUT contents in the DDX handler because this does not work with DGA colormap-grabbing clients. Instead, use one of the above strategies.

cmapGetColorData8


  int  
  cmapGetColorData8 (ColormapPtr pCmap, unsigned char *pRmap,  
           unsigned char *pGmap, unsigned char *pBmap,  
           Bool *pRallocs, Bool *pGallocs, Bool *pBallocs)  

PurposeGets color data and allocation information from a colormap. Use it if the hardware color LUTs have 8 output bits per channel.
ArgumentsFor indexed colormaps, the data for entry i is placed in pRmap[i], pGmap[i], and pBmap[i].
For direct colormaps, the data for red entry i is placed in pRmap[i], for green entry i in pGmap[i], and for blue entry i in pBmap[i].
The pRmap, pGmap, and pBmap locations corresponding to unallocated entries in pCmap are unchanged.
If you are not interested in allocation information for pRallocs, pGallocs, and pBallocs, the arguments are NULL.
Returns....The value 1 is returned on success, 0 on failure.
In pRmap, pGmap, and pBmap the color data allocated in pCmap. It is assumed that the number of output bits per channel is eight. The pRmap, pGmap, and pBmap arrays must be long enough to hold all of the entries of pCmap.
Information on allocated entries, if requested. To request allocation information, supply non-NULL arguments to pRallocs, pGallocs, and pBallocs.
For indexed colormaps, if entry i is allocated in pCmap, pRallocs[i] is returned as TRUE, otherwise FALSE.
For direct colormaps, if red entry i is allocated in pCmap, pRallocs[i] is returned as TRUE, otherwise FALSE. Likewise, pGallocs and pBallocs are used to return the allocation status of the green and blue entries.

cmapGetColorData16


  int  
  cmapGetColorData16 (ColormapPtr pCmap, unsigned short *pRmap,  
                unsigned short *pGmap, unsigned short *pBmap,  
                Bool *pRallocs, Bool *pGallocs, Bool *pBallocs)  

Returns....This routine returns the color data for allocated entries in pCmap in pRmap, pGmap, and pBmap.

Note - This function returns the full 16 bits of color data for each channel. It is up to the caller to convert this data to the output bits of the hardware color LUT.

Implementing storeColorsFunc

Code Example 8-1 shows how to implement this device-dependent function in your DDX handler.

Note - In Code Example 8-1, the color LUTs are indexed, the pixel size is 8 bits, and hardware color LUT channel outputs size is 8 bits each.

Code Example 8-1 Direct or Indirect Colormap Into Indirect Color LUT

  Bool  
  exampleDDstoreColors (ColormapPtr pCmap, CARD32 clutId,  
           int ndef, xColorItem *pdefs)  
  {  
           unsigned char rmap[256], gmap[256], bmap[256];  
           xColorItem       expanddefs[256];  
  
                /* Since the color LUTs are indexed, if we have a direct  
                 * colormap, we must translate the pdefs.*/  
           if ((pCmap->pVisual->class | DynamicClass) == DirectColor) {  
                ndef = cfbExpandDirectColors(pCmap, ndef, pdefs,  
                    expanddefs);  
                pdefs = expanddefs;  
                }  

Code Example 8-1 Direct or Indirect Colormap Into Indirect Color LUT (Continued)

                /* Optimization: A common case for optimization is for the  
                 * change to be to all channels of a single entry. This  
                 * frequently happens when XAllocColor is called on a dynamic  
                 * colormap. */  
           if (ndef == 1 &&  
           (pdefs->flags & (DoRed|DoGreen|DoBlue)==(DoRed|DoGreen|DoBlue))) {  
                unsigned char red, green, blue;  
                red = pdefs->red >> 8;  
                green = pdefs->green >> 8;  
                blue = pdefs->blue >> 8;  
  
                << put red, green, blue into color LUT clutId at pdefs->pixel >>  
  
                return (TRUE);  
  
           }  
  
           << get entire current contents of color LUT clutId into rmap, gmap, bmap>>  
  
           /* apply changes */  
           while (ndef--) {  
                if (pdefs->flags & DoRed)  
                    rmap[pdefs->pixel] = pdefs->red >> 8;  
                if (pdefs->flags & DoGreen)  
                    gmap[pdefs->pixel] = pdefs->green >> 8;  
                    if (pdefs->flags & DoBlue)  
                             bmap[pdefs->pixel] = pdefs->blue >> 8;  
                    pdefs++;  
                }  
  
                <<put entire rmap, gmap, bmap into the color LUT for clutId>>  
  
                return (TRUE);  
  
  }  

Code Example 8-1 shows a special case when only a single entry is being changed and all three channels of that entry are being changed. This is a significant optimization because this situation happens very frequently when color applications are started. For devices that use a system call to get the color LUT contents out of the hardware, this optimization avoids an extra system call.
Simulating a Direct Color LUT With an Indirect Color LUT In Code Example 8-1, something special must be done when the colormap is direct (either TrueColor or DirectColor) and the color LUT is indexed.
When an XStoreColors is performed on a single channel of a direct color LUT, it affects the displayed colors for all pixels containing the bit pattern of the channel entry changed. For example, if red entry 0x05 was updated, the colors change for pixels 0x05GGBB, where GG and BB are any legal value for the green and blue portions of the pixel. In this example, a single change to the red entry changes the colors of multiple pixels.
When the color LUT is indexed rather than direct, several color LUT entries must be changed to get this same effect. This is done by calling cfbExpandDirectColors. It converts the pdefs change list describing the changed channel entries into another change list which, when applied, updates an indexed color LUT to achieve the desired effect.
The specification of cfbExpandDirectColors is:

  int  
  cfbExpandDirectColors (ColormapPtr pCmap, int ndef,  
           xColorItem *indefs, xColorItem *outdefs)  

This DDX function can be used by devices with any arbitrary number of color LUT output bits. It is not limited to devices with eight bits of output per channel.
Simulating an Indirect Colormap With a Direct Color LUT The preceding section dealt with the case where the device has indexed color LUTs and the device handler chooses to export indexed visuals. It is also possible to simulate indexed visuals if the device color LUTs are direct. This is the subject of the next section.
Code Example 8-2 is a routine that can load either indirect or direct colormaps into a direct color LUT. The only difference is in the treatment of the pixel value. For an indirect colormap, the same pixel value is used to index into all three color channels. For a direct colormap, the pixel value is divided into separate channel indexes.
Code Example 8-2 Direct or Indirect Colormap Into Direct Color LUT

  Bool  
  exampleDDstoreColor (ColormapPtr pCmap, CARD32 clutId, int ndef,  
                xColorItem *pdefs)  
  {  
       unsigned char rmap[256], gmap[256], bmap[256];  
       Pixel pix;  
       VisualPtr pVis = pCmap->pVisual;  
       int direct = (pVis->class|DynamicClass) == DirectColor;  
  
       <<get entire current contents of color LUT clutId into rmap, gmap, bmap>>  
  
       /* apply changes */  
       while (ndef--) {  
                pix = pdefs->pixel;  
                if (direct) {  
                    /* Direct colormap */  
                    if (pdefs->flags & DoRed)  
                             rmap[(pix&pVis->redmask)>>pvis->redoffset] = pdefs-  
  >red>>8;  
                    if (pdefs->flags & DoGreen)  
                             gmap[pix&pVis->greenmask)>>pVis->greenoffset] = pdefs-  
  >green>>8;  
                    if (pdefs->flags & DoBlue)  
                             bmap[pix&pVis->bluemask)>>pVis->blueoffset] = pdefs-  
  >blue>>8;  
                } else {  
                    /* Indirect colormap */  
                    if (pdefs->flag & DoRed)  
                             rmap[pix] = pdefs->red>>8;  
                    if (pdefs->flags & DoGreen)  
                             gmap[ix] = pdefs->green>>8;  
                    if (pdefs->flags & DoBlue)  
                             bmap[pix] = pdefs->blue>>8;  
                }  
                pdefs++;  
       }  
       <<put entire rmap, gmap, bmap into the color LUT for clutId>>  
  
       return (TRUE);  
  }  


Note - The single-entry optimization in "Simulating a Direct Color LUT With an Indirect Color LUT" on page 112 can also be used in this situation, although it is not shown in Code Example 8-2.

Color LUT Pool Description

For multiple color LUT devices, each MPG mpgInfo structure uses a specific color LUT pool, called a clut pool. A clut pool contains one or more color LUTs. Windows with a particular mpgInfo have their colormaps installed into the color LUTs in this pool. The color LUTs in a pool are assigned on a first-come- first-served basis. Throughout its existence mpgInfo always refers to the same color LUT.
The mpgInfo structure is in the MPG library. It defines the plane groups used by a window, what they are used for, and the window management operations that are performed on them. For more information, see Chapter 5, "Multiple Plane Group Interface".
A color LUT is identified with a clut ID that is a small positive number. The value is only interpreted by the device handler and is opaque to CMAP.
In the call to cmapScreenInit, the device handler must supply a description of the device's clut pools, the pool each color LUT resides in, and the pools used by the device's default mpgInfos. The default mpgInfos are the ones that the device handler specifies in the mpgVisInfo structure passed to mpgScreenInit. The device handler provides this description by passing in an array of CmapClutPoolDesc structures, one for each clut pool. The number of clut pools is passed as an argument to cmapScreenInit.
There are limitations on how mpgInfos use clut pools. These are described below.

CmapClutPoolDesc Structure

Code Example 8-3 shows the CmapClutPoolDesc structure that describes the color LUTs assigned to a particular pool and the MPG infos that use them.
Code Example 8-3 CmapClutPoolDesc Structure

  typedef struct {  
       /* number of cluts in pool */  
       unsigned int     numCluts;  
       /* array of clut IDs in pool */  
       CARD32           pClutIds[CMAP_POOL_MAX_CLUTS];  
       /* number of MPG infos using pool */  
       unsigned int     numPgs;  
       /* array of MPG info dids */  
       CARD32           pPgs[CMAP_MAX_PGS];  
       /*  
       ** maximum number of flavors for MPG infos  
       ** using this pool  
       */  
       unsigned int     maxFlavors;  
  } CmapClutPoolDesc;  

For each clut pool, numCluts specifies the number of color LUTs in the pool. pClutIds is an array containing color LUT IDs for each color LUT in the pool. numPgs is the number of mpgInfos using the pool. pPgs is an array containing drawing IDs (DIDs) for each mpgInfo using the pool. The DID is the internal ID (iid) of the drawing plane group of that mpgInfo (this is the last plane group inserted into the mpgInfo with op MPG_DRAW). numPgs is the number of mpgInfo DIDs in the pPgs array. An mpgInfo DID can appear in no more than one clut pool description.

Note - Currently, numPgs must always be equal to 1. See "Multi-Depth Color LUT Pool Sharing" on page 119 for more details on this constraint.

The maximum number of flavors (maxFlavors) for the pool must also be specified. See "Flavors" on page 120 for more detailed information.

Note - The CMAP interface refers to an mpgInfo with the abbreviations "Pg" or "PG." These do not refer to individual plane groups. These abbreviations refer to combinations of plane groups and correspond to mpg Info structures.


Note - Currently, CMAP_POOL_MAX_CLUTS is 32 and CMAP_MAX_PGS is 32.

Relationship to MPG

This section describes the relationship between windows, visuals, mpgInfos, and clut pools in greater detail. See also Chapter 5, "Multiple Plane Group Interface" for additional information.
When mpgScreenInit is called, the device handler supplies an mpgVisInfo table that specifies, for each visual ID in the table, the default mpgInfo that is to be assigned to windows created with that visual. When cmapScreenInit is called, CMAP uses this table to map visual IDs to clut pools. It uses this mapping to determine the color LUT into which a window's colormap should be installed. This depends on the window's visual.
Window contents are stored in device memory buffers called plane groups. Multiple plane groups can be associated with a window. The plane group in which the image color data is stored is called the drawing plane group. Besides the drawing plane group, the window might require other plane groups to control rendering and to properly display the window contents. For example, it might require a window id plane group to control visibility or a Z buffer plane group to control 3D rendering. All the plane groups associated with a window are described in its mpgInfo.
When an X window is created, the X client selects a visual for the window. This visual is a type descriptor describing how the window should be displayed. It contains information such as class and colormap entries. At the same time the client selects a visual for the window, a depth is also selected. Both the depth and visual remain constant for a window throughout its existence. The device handler must assign each visual a unique visual ID.
The mpgVisInfo table passed to mpgScreenInit contains, for each visual, the default mpgInfo for that visual. This means that when a window is created, this table is used to find the mpgInfo for the window's visual. This mpgInfo is assigned to the window and controls display of the window
contents and render to the window. In the mpgVisInfo table, more than one visual ID can point to the same mpgInfo. For example, this can happen if the visuals differ only in the type of colormap they use for display--an 8-bit PseudoColor visual and an 8-bit StaticColor visual can share the same mpgInfo.

Note - Currently, the number of visuals that can refer to the same mpgInfo is limited to 6.

The mpgVisInfo table is shown in Figure 8-1.

圖形

Figure 8-1 mpgInfompgVisInfo

After a window has been created, the X client may do something to it that requires a different mpgInfo. For example, the window might become multibuffered, grabbed through DGA, or a Z buffer attached. It might be necessary to move the window contents to a different drawing plane group. It
might also be necessary to add plane groups to the combination used by the window. MPG provides a routine, mpgChangeInfo, to allow a DDX handler to change the mpgInfo of a window. This is shown in Figure 8-2.

圖形

Figure 8-2 mpgInfo

Because the visual and depth of a window never change, the new mpgInfo must have the same depth as the original mpgInfo. In addition, the new mpgInfo must always use the same clut pool as the original mpgInfo. For this reason, it is only necessary to specify to cmapScreenInit the clut pools used by the default mpgInfos.
The first entry in the pPgs array of a clut pool description (pPgs[0]) defines the default mpgInfo that uses that clut pool. Other variants of this default mpgInfo, attached to windows using mpgChangeInfo, also use that same clut pool. This is shown in Figure 8-3.

圖形

Figure 8-3 mpgInfo

Multi-Depth Color LUT Pool Sharing

The CmapClutPoolDesc structure has an array of mpgInfo DIDs instead of just a single DID so that future configurations with multiple depths can share the same color LUT pool. These are called multi-depth configurations.

Note - Multi-depth configurations are not supported in the current release. Consequently, the numPgs of a clut pool description must always be 1. This restriction might be relaxed in a future release.

In a multi-depth configuration, a set of color LUTs is used by mpgInfos of different depths. In such a configuration, the pPgs array contains more than one mpgInfo DID. It contains one for each default mpgInfo that used the clut pool. The different mpgInfos in the array could be referred to by visuals of different depths. This is shown in Figure 8-4.

圖形

Figure 8-4 mpgVisInfonot supported


Note - Sharing clut pools between default mpgInfos of different depths is not supported in the current release. Also, sharing clut pools between default mpgInfos of the same depth, but which differ in some other characteristic, is not supported either.

Flavors

CMAP needs to know the flavors of the mpgInfos using its clut pools. At any one time, a window has an mpgInfo. On WID devices, a window's WID depends on this mpgInfo. The visible shape of the window is filled with this WID. The hardware uses the WID to control display of and rendering into the window. The type of the WID is called its flavor. CMAP uses the flavor of a WID to promote the sharing of WIDs between similar windows.
When CMAP is first initialized and the clut pools are described, the device handler needs to know the maximum number of flavors used by the set of all mpgInfos using each clut pool. On non-WID devices, maxFlavors is always 0 for each clut pool description.
A flavor is a distinct combination of hardware WID attributes. It is identified by a small positive number. This number is opaque to CMAP and its value is not interpreted by CMAP. Because the number uniquely identifies a flavor, the term "flavor" is often applied to the number itself, although it really means the combination of WID attributes it represents.
For a particular hardware WID, the flavor of a WID depends on the hardware characteristics. The hardware WID is the bit pattern that the video display hardware uses to display a particular pixel on the screen. The bit pattern can also be used to control rendering to that pixel. Each pixel on the screen has an associated WID. On Direct WID devices, the controlling bit pattern is derived from the WID value itself. On Indirect WID devices, the WID value is used as an index into a table to find the controlling bit pattern. The controlling bit pattern of a WID is called its attributes. The attributes bit pattern is subdivided into a number of fields, each of which controls a particular characteristic, such as depth, double-buffer selection, or color LUT selection.

Note - Direct WID devices are not supported.

Since the purpose of flavors is to promote sharing of WIDs among similar windows, any WID attribute field that is specific to an individual window, and not sharable with other windows, is not a part of the flavor. For example, the double-buffer selection field of a WID is not part of the flavor because buffer changes to one window should not affect other windows. These types of WID attribute fields are referred to as unique fields. This means that each window that requires a WID in which a unique field changes, requires a unique WID. It cannot share the WID of another window.
Another example of a unique field is hardware clipping. It is unique because we don't want hardware-clipped rendering into one window to spill out into another window. On some hardware, a WID field controlling the selection of a fast clear set might be a unique field. (A fast clear set is a hardware construct for rapidly setting the entire shape of a window to a specified pixel value).
Only sharable WID attribute fields are a part of the flavor. Examples include depth and Z-buffer-enable fields. These fields are called flavor fields.
The attribute fields of a WID vary from device to device. Follow this list of rules to determine the flavor fields for a device:
  1. Start with the list of WID attribute fields that the hardware supports.

  2. Eliminate the fields that are constant for all WIDs.

  3. Eliminate those fields that, if enabled, prevent the WID from being shared by other windows. Examples: hardware clip, fast clear set.

  4. Eliminate those fields that will be dynamically manipulated for an individual window. Examples: double buffer display select.

  5. Eliminate those fields whose values are dependent on the values of other fields.

  6. Eliminate the color LUT select field.

The remaining fields are the flavor fields. To derive the set of flavor IDs, assign unique small positive integers to all possible combinations of the flavor attributes.
The following is an example of four possible flavors that might be used by a device:
  • Flavor 0: 8-bit, no Z buffer
  • Flavor 1: 8-bit, Z buffer
  • Flavor 2: 24-bit, no Z buffer
  • Flavor 3: 24-bit, Z buffer
The maxFlavors of a clut pool is the sum of the flavors of the mpgInfos that can use the pool. Continuing the above example, if clut pool 0 can be used by both an mpgInfo with an 8-bit Z buffer flavor and one with an 8-bit non-Z buffer flavor, the maxFlavors of this pool is 2.
When multiple windows using the same mpgInfo share the same colormap, only one WID is necessary to display the window contents. This is the WID for that mpgInfo. However, if the windows have different colormaps, then one WID per colormap is necessary. This is because CMAP installs each colormap into its own color LUT.
For example, there are three 24-bit Z buffered windows, each with its own colormap. These colormaps are installed into color LUTs 0, 1, and 2. These windows require three distinct WIDs, each differing only in the color LUT selection field. But the flavor attributes of these WIDs are all set to 24-bit and Z-buffered.
If a fourth window is created that shares the same colormap as the first window, it can share the first window's WID; it does not need a new WID. CMAP is designed to notice these opportunities for sharing.
For MHC WID devices, CMAP keeps track of the WIDs of windows using the colormaps it is managing. Whenever it needs to allocate a new WID for a window, it first checks to see if an appropriate sharable WID is already available. An appropriate WID is defined as a WID having the same color LUT as the window's colormap and flavor attributes the same as the desired flavor.
More on Flavors It is important to understand how flavors are related to software colormaps and hardware color lookup tables (color LUTs). Earlier, there was a discussion of flavor attributes versus unique attributes of a hardware WID. It is important to understand that colormaps and color LUTs are neither flavor attributes nor unique attributes.
Since one of the purposes of defining flavors and defining unique attributes is so MHC can wisely distribute color LUTs in real time, we must omit color LUTs as a WID attribute when defining flavors and uniques.
Software colormaps are obviously not a WID attribute. But it is useful to understand that MHC keeps track of WIDs assigned to flavors on a colormap basis. So for each software colormap, there is a structure that holds WIDs being used with this colormap, and their associated flavors. MHC uses this information to share WIDs between colormaps. Two colormaps are checked to see if they both have a WID in a certain flavor. If they do, the two colormaps share one of the WIDs and the other one is freed.
For example, defining a flavor as "flavor 1 is for the default colormap" is incorrect. As described above, colormaps do not play a role in distinguishing between flavors. Defining a flavor for a particular software colormap defeats the purpose of flavors, and is not expected to work properly.
Correctly defining flavors is critical to proper operation of MHC.

Initialization Example - Multiple Color LUT

Code Example 8-4 hows how to initialize colormap management for a device with two mpgInfos. The first mpgInfo has one dedicated color LUT and the second one has four dedicated color LUTs.
Code Example 8-4 Initialize CMAP For a Device With Two Plane Groups

  CmapClutPoolDesc      myclutDescArray[] = {  
  
       /* Pool for 8-bit mpgInfo */  
       {  
           /* clut ids */  
           1, { 0 },  
  
           /* used by which mpgInfo */  
           1, { 0 },  
  
            /* max flavors */  
           3  
       },  
  
       /* Pool for 24-bit mpgInfo */  
       {  
           /* clut ids */  
           3, { 1, 2, 3 },  
  
           /* used by which mpgInfo */  
           1, { 1 },  
  
           /* max flavors */  
           1  
       }  
  };  
  
  cmapScreenInit(pMyScreen, pMyDevFuncs, TRUE, 2,  
           &myclutDescArray, cmapWidIndirect);  

pMyDevFuncs is a pointer to a structure with the device-dependent colormap access functions.

Initialization Example - Single Color LUT

To initialize colormap management for a single color LUT, the following call should be used:

  cmapScreenInit(pMyScreen, pMyDevFuncs, FALSE, 0, NULL, CmapWidNone);  

pMyDevFuncs is a pointer to a structure with the device-dependent colormap access functions.

WID Types

When initialized for multiple color LUT management, CMAP needs to know whether the device uses WIDs. If the device uses WIDS, it needs to know whether the device is an indirect or direct WID device. Use the widType argument to cmapScreenInit to indicate this with one of the following values:

  typedef enum {  
       CmapWidUnknown,  
       CmapWidNone,  
       CmapWidIndirect,  
       CmapWidDirect,  
  } CmapWidType;  


Note - The value of the widType argument to cmapScreenInit is ignored in single-color LUT mode. CmapWidUnknown is for use by the system; do not use it in your DDX handler.


Note - Direct WID devices are not supported in this release.

Utility Routines

The following utility routines are provided for cleaning up after colormap management is no longer needed, accessing arguments to cmapScreenInit, and making the storage method of these data opaque to the calling function.

cmapCloseScreen


  Bool  
  cmapCloseScreen (int index,ScreenPtr pScreen)  

PurposeThis function cleans up state initialized by cmapScreenInit. This function is responsible for restoring the color lut, the hardware wid, and other device dependent hardware states to correctly display the black and white colors of the glass tty console.
Called bycmapGetDevFuncsThe device-dependent CloseScreen.
CmapDevFuncs*
ReturnscmapGetMultipleThe device-dependent colormap access functions passed to cmapScreenInit.
Bool
ReturnsTRUE if the given screen has been initialized with multiple color lookup table management.

cmapGetClutPoolDescs


  void  
  cmapGetClutPoolDescs (ScreenPtr pScreen, int *pNumClutPools,  
                     CmapClutPoolDesc **pClutPoolDescs)  

ResultsThe output arguments are untouched in the single-color LUT management case.
ReturnscmapGetWidTypeIn the multiple-color LUT management case, this procedure returns the number and array of pool descriptions given to cmapScreenInit.
CmapWidType
ReturnswidType argument passed to cmapScreenInit, in multiple-color LUT mode.
CmapWidUnknown, in single-color LUT mode.

Colormap Private Data

CMAP uses the devPriv member of ColormapRec for its own purposes. If you want to attach device-dependent data to a colormap, it must coordinate with CMAP.
CMAP attaches its own private data structure to all colormaps. The colormap devPriv member points to this structure. CMAP reserves in its structure a data member called devPriv. Set devPriv to point to your own data.
To access devPriv, call cmapGetCmapPriv.

cmapGetCmapPriv


  CmapPrivPtr  
  cmapGetCmapPriv (ColormapPtr pCmap)  

ResultsIf devPriv is NULL, a CmapPrivRec is created and devPriv is pointed to it.
ReturnsThe devPriv member of a colormap. This function returns a pointer to a structure of the following format:

  typedef {  
       pointer      cmapOpaque1;  
       pointer      cmapOpaque2;  
       int          cmapOpaque3;  
       pointer      devPriv;  
  } CmapPrivRec, *CmapPrivPtr;  

You can read and write to CmapPrivRec.devPriv as needed by your DDX handler. The cmapopaqueX members are opaque; do not read or write to them. So, if pCmapPriv is the pointer returned by cmapGetCmapPriv, read or write to the pCmapPriv->devPriv data member to attach device-dependent data to the colormap.

Controlling MHC's WIDs

Most MHC devices are also WID devices. This section applies only to MHC devices that have WIDs.
An example of an MHC device that does not have WIDs, is a device with an 8-bit plane group and a 24-bit plane group whose visibility is selected by a 1-bit control plane. The value 0 in the control plane selects display of the 8-bit plane group and 1 selects the 24-bit plane group. Each plane group has a single, dedicated color LUT. This is an MHC device because it has two color LUTs; one each for the 8-bit and 24-bit plane groups. However, visibility is controlled by a control plane, not WIDs. If visibility was selected using a WID, then the device would be a WID device.
Devices that support more than one color LUT per plane group are usually WID devices. This sections applies to these devices also.
MHC devices with WIDs need to initialize the WID package. See Chapter 7, "Window ID Interface" for more information on WIDs.
CMAP uses a set of hardware WIDs to display colormaps in windows. CMAP is flexible about the number of WIDs it requires. It can be told to use more or less WIDs. If it uses less, color flashing might increase. The flashing condition persists until CMAP is told to use more WIDs, or until one of the colormaps causing the flashing is destroyed. See "Overloading Control Routines" on page 130 for information on how to tell CMAP the number of WIDs to use.

Overloading WIDs

CMAP uses WIDs to display different hardware color LUTs in different windows. Since, even on advanced display devices, WIDs are a relatively scarce resource, there might be times when you need a WID, but cannot get one.
The CMAP package is designed to be flexible about the number of WIDs it uses. In normal operation, it tries to use as many WIDs as it needs. However, if it tries to allocate a WID for a colormap and cannot, it shares the WID of another colormap that has a similar WID. This colormap is called an overload partner. When a colormap shares a WID with an overload partner, it uses the color LUT of the partner. Visually, the colormap flashes against the partner colormap. If all WIDs are used, this kind of flashing can occur even if there are free hardware color LUTs because there must be a free WID and a free hardware color LUT for a window to have its own LUT. This WID sharing technique is called overloading.
Depending on the type of device, CMAP might not be the only consumer of WIDs; the handler itself might need to use WIDs. For example, if it assigns special WIDs to hardware clipped windows or hardware double-buffered windows. In some situations, when the handler needs a WID it absolutely must acquire it; it cannot share the WID with some other window. In this case, the handler uses a unique WID.
You need to handle WID allocation failure if your handler uses WIDs. Rather than failing the operation requiring the WID, the handler is permitted to steal a WID from CMAP. It does this by forcing CMAP into an overloading situation.
In most cases, this approach is preferable: overloading CMAP means that there is more colormap flashing, but failing means that the application window needing the WID cannot be created at all.
It is recommended, therefore, that when you try to allocate a unique WID, and the allocation fails, call cmapMhcForceOverload. (The only exception to this is from the device-dependent widAllocate function.) This routine forces CMAP to give up a WID by overloading two colormaps onto each other. However, this routine does not always result in a free WID--there might not be any more free WIDs. When cmapMhcForceOverload fails (returns 0), the handler has no other option but to return failure.
When forcing an overload condition, be sure to also call cmapMhcReleaseOverload whenever it frees a WID. This allows CMAP to remove any overloading conditions that exist and go back to less flashing. Always do this from the device-dependent WID free function, freeFunc. See Chapter 7, "Window ID Interface" for more information.

Note - The use of cmapMhcReleaseOverload and cmapMhcForceOverload from the WID free function is not symmetric. Even when the free function calls cmapMhcReleaseOverload, its counterpart allocation function should never call cmapMhcForceOverload. The cmapMhcForceOverload call is made elsewhere in the device-independent layers of the system.

Overloading Control Routines

cmapMhcForceOverload


  int  
  cmapMhcForceOverload (ScreenPtr pScreen, VisualID visual)  

PurposeForces CMAP to give up a WID.
Called byA device handler that needs a unique WID for another purpose, such as double buffering.
Argumentsvisual indicates the visual type of the WID.
Returns1 if it gives up a WID; 0 otherwise.
This code seeks to free a WID of any flavor for the visual. It starts at the least recently installed colormap in the visual's color LUT pool and progresses toward more recently installed ones. For each colormap, it attempts to find a viable overload partner colormap of the same flavor. To find the overload partner, it starts at the least recently installed colormap and progresses toward the most recently installed. It prefers partners that are not already overloaded, but accepts partners already overloaded. If it finds a partner that is already overloaded, the colormap becomes over-overloaded.

Note - This heuristic attempts to minimize the effect on windows with hot (most recently installed) colormaps by confining flashing effects on less recently used colormaps, even if it has to over-overload to do it.


Note - Call this routine only if the device handler needs a unique WID and cannot get one. Do not call this function when creating a sharable WID for a window. Instead, let cmapMhcWindowAttachId handle it.

cmapMhcReleaseOverload


  void  
  cmapMhcReleaseOverload (ScreenPtr pScreen, VisualID visual)  

Purpose....This routine tries to take back any overloaded colormaps. This requires a WID, so this routine is called when the caller has reason to expect that a WID is available. This is the case when the caller has just freed a WID.
The installed list of that visual's color LUT pool is searched for a colormap that is overloaded. The search progresses from the most recently installed colormap toward less recently installed ones until one is found that is overloaded or the end of the list is reached. When it finds one, it allocates a new WID and assigns it to all windows using that colormap. The overload condition is then removed.
Arguments..visual indicates the visual type of the WID that is needed.

Changing a Window's WID

When the DDX handler for a non-MHC device creates a window, or changes a window's WID, it uses the WID routines of the MPG package to make the change. For example, when a window is first created the CreateWindow routine of the device's screen is called. This routine calls widAllocate to allocate a WID and then widSetWindowWid to attach the WID to the window.
If the device is MHC, it must let CMAP change the WID. To promote WID sharing, the CMAP package needs to keep track of both WIDs and colormaps used by windows. Specifically, CMAP must be notified when the DDX handler does one of the following operations:
  • Creates a window
  • Destroys a window
  • Changes a window's colormap
  • Changes a window from software clipping to hardware clipping
  • Changes a window from single buffered to hardware double buffered
In either the MHC or non-MHC case, the DDX handler has ultimate responsibility for deciding when WIDs get allocated and when WID attributes are changed. MHC DDX handlers must use CMAP for these operations.

cmapMhcWindowAttachWid


  int  
  cmapMhcWindowAttachWid (WindowPtr pWin, Bool unique, CARD32 flavor)  

A device that uses WIDs must wrap the pScreen->CreateWindow routine to create the window by assigning the window a WID.
When the wrapping routine is called, it first calls the wrapped CreateWindow. Next, it calls the following routine that ensures that the window is assigned an appropriate WID. This routine checks if there is another window with an appropriate WID, and uses that; if not, it allocates a new WID. It can force an overload to get this WID.
This routine chooses an appropriate WID for the given window. The choice of WID depends on:
  • The window's colormap
  • The specified flavor
  • The specified uniqueness
ArgumentsIf unique is FALSE, CMAP tries to use an existing sharable WID of the given flavor. If it cannot find an existing one, a new WID is allocated.
ResultsIf the window already has a WID, it is freed.
Returns1 is returned on success and 0 on failure.

cmapMhcWindowDetachWid

Prior to destroying a window on an MHC device, CMAP must be notified. To do this, the device handler wraps pScreen->DestroyWindow. It calls the following routine and then destroys the window. When the window is destroyed the reference count of the attached WID decreases. If this was the only reference to this particular WID, the WID is freed.

  int  
  cmapMhcWindowDetachWid (WindowPtr pWin)  

Changing A Window's Colormap

The device handler should wrap pScreen->ChangeWindowAttributes. This way, the device handler detects if a CWColormap change is occurring. If it does not, then call the wrapped ChangeWindowAttributes normally.
If the colormap is being changed, then it calls cmapMhcWindowDetachWid on the window first, the wrapped ChangeWindowAttributes next. then the cmapMhcWindowAttachWid last.

Note - If the call to cmapMhcWindowAttachWid fails, the device handler returns an error.

If a CMAP routine returns failure status during the the device handler's wrapped ChangeWindowAttributes or during the call to cmapMhcWindowAttachWid, then this indicates the MHC could not allocate a WID. If this is the case, the device handler needs to back out of the change it
was trying to make. To do this, the device handler should attach the old colormap to the window using the wrapped ChangeWindowAttributes. Next, it should call cmapMhcWindowAttachWid using the flavor and unique values of the old WID (that is, the WID that used to be attached to the window).

Note - This call to cmapMhcWindowAttachWid should never fail since the old WID was returned to the free pool of WIDs and should still be there.

Finally, the device handler's wrapped ChangeWindowAttributes should return a BadAlloc failure status.

cmapMhcChangeFlavor

Whenever a window is modified in a way that changes its flavor, CMAP must be notified. A new WID needs to be assigned to the window, one with the new flavor. It is CMAP that makes this reassignment.
Call the following routine whenever the device handler is about to make a change that affects a WID's flavor. The routine is given the desired flavor and it attempts to either share a WID of the same flavor or else allocate a new one. In either case, it finds a WID and assigns it to the window.

  int  
  cmapMhcChangeFlavor (WindowPtr pWin, CARD32 newFlavor)  

This function tells CMAP that you want a WID of a different flavor attached to the window. CMAP selects a new WID for the window, using either an existing sharable WID or a new WID.

Note - Call this function only for windows with sharable WIDs.

This function returns 1 on success and 0 on failure. A failure return indicates that a WID of the desired flavor could not be acquired for the window. In this case, the previous WID of the window is left untouched.

Example

Code Example 8-5 shows you how to change the flavor of a window in pseudo-code. Attaching a Z buffer to a window is used as a hypothetical example. This code might be called from the DGA GPI routine DgaZbufSetup in response to a call to the libdga XDgaZbufGrab API routine. See Chapter 9, "Direct Graphics Access Drawable Client Interface" for more information.

Note - This is only a hypothetical example to illustrate the changing of a WID flavor attribute. MPG provides a superior service for attaching a Zbuffer to a window. For most devices, the MPG service is preferred because it sets up the Z buffer contents to be moved when the window moves. See Chapter 5, "Multiple Plane Group Interface" for more information. The actual possibilities for changeable flavor attributes are device-dependent.


Note - Depth is a WID flavor attribute, but dynamically changing the depth of a window is not permitted under the X model.

Code Example 8-5 Changing the Flavor of a Window Pseudo-Code

  #define DDZBufFlavor<< device-dependent >>  
  
  DDAttachZBuffer (WindowPtr pWin)  
  {  
       WidPtr           pWid;  
       unsigned long    value;  
  
       pWid = mpgWindowGetWid(pWin);  
       value = widGetValue(pWid);  
  
       if (widGetUnique(pWid)) {  
           if (device has indirect WIDs) {  
                widAttrs = get WID LUT entry 'value'  
                <change widAttrs to specify Z buffer attached>  
                WID LUT entry 'value' = widAttrs  
       }   } else {  
                /* device has direct WIDs */  
                <change 'value' to specify hardware clipping>  
                widSetValue(pWid, value);  
           }  
       } else {  
           if (!mhcChangeFlavor(pWin, DDZBufFlavor))  

Code Example 8-5 Changing the Flavor of a Window Pseudo-Code

                return failure;  
       }  
  
       <Do other device-dependent operations to attach Z buffer>  
       /* For Direct WId devices, whenever you change a WID  
        * attribute, you must reprepare the WID plan group of the  
        * window. To do this, set the window's WID to same WID and  
        * specify repreparation. You do not need to do this for  
        * Indirect WID devices.  
        */  
       mpgWindowSetWid(pWin, pWid, 1);  
       return Success;  
  
  }  

Allocating Unique WIDs

There are times when one or more non-sharable WIDs are needed for a window--double buffering and XGL stenciling. These techniques require unique WIDs. Use the following function to allocate unique WIDs; it forces an overload if the WID allocation fails.

  int  
  cmapMhcAllocWids (WindowPtr pWin, int number)  

This function allocates the specified number of WIDs for the window. The window's current WID is dereferenced and the WID object representing the new WIDs is attached. The WIDs allocated are contiguous to a power-of-two boundary determined by rounding up number to the next power of two. The WIDs are unique.
The value of number must be >= 1.
This function returns 1 on success and 0 on failure. If 0, pWin's original WID is left untouched.

Example

Code Example 8-6 shows you how to allocate multiple unique WIDs. This is an example of a DGA-based graphics library that wants to clip rendering to a sub-region of the window. In the first part of the example, two consecutive unique WIDs are allocated by the device handler and returned via the DGA mechanism.
Code Example 8-6 Allocating Multiple Unique WIDs in Pseudo-Code

  DDGetClippingWids (WindowPtr pWin)  
  {  
       WidPtr           pWid;  
       unsigned long    value;  
  
       if (!cmapMhcAllocWids(pWin, 2))  
           return failure;  
  
       pWid = widGetWindow(pWin);  
       value = widGetValue(pWid);  
  
       <place value and value+1 in the DGA shared information page>  
  
       return Success;  
  }  

Initialize this routine as the DGA GPI routine, WidSetup. This routine is invoked via a call to the libdga API routine, XDgaGrabWids. For more information on these routines, see Chapter 9, "Direct Graphics Access Drawable Client Interface."
To complete the example, the graphics library calls XDgaGrabWids, getting back the two WID values. The library then does the following:
  • Enables the hardware clipping attribute of the WID 1. (This can be done because WID 1 is unique.)
  • Prepares the WID plane group throughout the entire drawable region of the window to WID 2.
  • Prepares the WID plane group in the interior of the clipping sub-region to WID 1.
  • Sets up the hardware to render, clipped to WID 1.
  • Renders the graphics.
This will result in the graphics being clipped to the sub-region, as desired.

Note - Currently, this example is applicable only to indirect WID devices. Multiple hardware WIDs per WID object are not supported on direct WID devices. If the same feature is desired on a direct WID device, write the routine to allocate two separate WID objects rather than using cmapMhcAllocWids. In this case, if either of the WID allocations fails, call cmapMhcForceOverload, and retry the failing WID allocation. Once allocated, the hardware WID values can be derived from the WID objects by calling widGetValue on each one. Finally, store pointers to these WID objects in the handler's devPrivates area of the window so they can later be freed when the window is destroyed. This may change in future releases.