X Server Device Developer's Guide
  Search only this book
Download this book in PDF

Screen Initialization

3

The ddxInitFunc device function should initialize the Screen structure and all of its function vectors. See "The Initialization Function" on page 11 for information on ddxInitFunc. This chapter provides information on some aspects of Screen initialization common to many devices. Additional initialization steps might be required depending on the utility layers you use in your DDX handler. These steps are documented in subsequent chapters describing the utility layers provided by the server.
A set of common utility functions is provided in the server that:
  • Allocate private data structures
  • Inquire current command-line options
  • Advertise pixmap formats and supported visuals

For SPARC systems - A complete sample implementation of the ddxInitFunc for a simple-memory frame buffer is available on line. See the cg3 DDX handler in the following directory:
ddk_2.6/xserver/server/ddx/solaris/sparc/cg3



For x86 systems - A complete sample implementation of the ddxInitFunc for a simple 256 color VGA display adapter is available on line. See the v256 DDX handler in the following directory: ddk_2.6/xserver/server/ddx/solaris/i386/displays/v256

Initialization Steps

Your device handler's ddxInitFunc function should perform the following steps to initialize the Screen structure:
  • Initialize the ScreenRec structure fields
  • Initialize the device
  • Map device registers and the frame buffer into the address space (if the device is memory-mappable)
  • Allocate required private data structures
  • Query command-line options that affect your DDX handler
  • Advertise pixmap formats, visuals, and depths the device supports
  • Initialize various utility layers you plan to use
It is important to know that ddxInitFunc could be called more than once during the lifetime of the server. The server is capable of restarting, and the ddxInitFunc is called again when this happens. This is why it is important to wrap pScreen->CloseScreen in your ddxInitFunc, and free all data structures allocated in the ddxInitFunc and elsewhere in the DDX handler.
Additionally, on multi-screen configurations which have multiple Screens of the same device type (hence served by a common DDX handler), the DDX handler module only needs to be loaded once into the server. Thereafter, the index of the Screen is used to distinguish between Screens. In this case, the ddxInitFunc will be called once for each Screen. It is recommended that any Screen private data required by the DDX handler be stored by allocating a devPrivate index on the Screen structure. The use of global variables in the DDX handler is discouraged for the same reason.

sunGetDDKVersion


  sunDDKVersionPtr  
  sunGetDDKVersion();  

One of the first things your DDX handler might do is check the DDK version number of the server that is attempting to load it. This is useful if your DDX handler depends on server functionality that was added in a specific minor version of the server DDK. Call the server function sunGetDDKVersion to obtain this information. See "DDX Versioning" on page 12 for a complete specification.

Note - The sample DDX handlers provided on line do not call sunGetDDKVersion because they are not dependent on any minor version functionality in the server DDK.

Initialize the ScreenRec Functions

Since some utility layers wrap the functions in the ScreenRec, it's important that your DDX handler initialize all the functions in the ScreenRec with valid function pointers, or NULL pointers for functions that are expected to be wrapped by other utility layers. The ScreenRec that is passed to the ddxInitFunc is uninitialized. It is the responsibility of ddxInitFunc to initialize ScreenRec with valid data or NULL as appropriate. To do this, at the beginning of your ddxInitFunc, include code that NULLs out all the Screen functions that are not supplied in your DDX handler. This could help prevent bugs due to uninitialized ScreenRec function pointers in your DDX handler.

Note - This step is not required if your ddxInitFunc provides valid function pointers for all the ScreenRec functions.


  /* For example, if your DDX handler does not provide an  
   * implementation of pScreen->BlockHandler or  
   * pScreen->WakeupHandler, but these are expected to be wrapped  
   * from the sunKbd device handler (for the keyboard) later in the  
   * Initialization sequence.  
  */  
  pScreen->BlockHandler = NULL;  
  pScreen->WakeupHandler = NULL;  

sunScreenAllocate


  Bool  
  sunScreenAllocate(ScreenPtr pScreen)  

PurposeThis function allocates a Screen private index (sunScreenIndex) and allocates the sunScreenRec data structure used by various utility layers (defined in
server/ddx/solaris/sun.h).
Called byYour ddxInitFunc before initializing any utility layers.
ResultsA pointer to the sunScreenRec structure is stored in
pScreen->devPrivates[sunScreenIndex].ptr.
ReturnsTRUE on success else FALSE
The sunScreenRec data structure must be freed in the CloseScreen routine of your DDX handler. Some of the fields of this data structure are filled by various Sun utility layers; however, a few fields need to be filled in by your
ddxInitFunc.


Note - A future release of the server might provide interfaces that will make this data structure opaque to the DDX handler.

Access the private data structure using the macros GetScreenPrivate and SetupScreen defined in sun.h.

  #define GetScreenPrivate(s) \  
  ((sunScreenPtr) ((s)->devPrivates[sunScreenIndex].ptr))  
  #define SetupScreen(s) \  
  sunScreenPtr pPrivate = GetScreenPrivate(s)  

Device-Dependent Initialization

Device-dependent initialization typically consists of the following steps:
  • Opening the device-special file for the graphics device
  • Mapping the device registers or the frame buffer into the server address space (if the device is memory-mappable)
  • Storing the file descriptor and memory mapping information in the private sunScreenRec data structure

Note - The sample DDX handlers (such as the cg3) use a private helper function called sunOpenFrameBuffer to open the device. This routine is called for example only; do not call it from your ddxInitFunc. It relies on ioctls that are private to the cg3 device driver, and are not required to be implemented in your device driver.

The device-special filename you should open in your ddxInitFunc can be obtained by calling the GetDevname macro in sun.h.

  char *  
  GetDevname(int index);         /* The Screen's index */  

The file descriptor and device name should be stored in the sunScreenRec private structure. These are used by other utility layers (such as DGA) in the server. The code in your ddxInitFunc might look like this:

  {  
  SetupScreen(pScreen);  
       ...  
       pPrivate->sunFbs.fd = open(GetDevname(index), O_RDWR, 0);  
       strcpy(pPrivate->sunFbs.devName, GetDevname(index));  
       ...  
  }  

If your cursor implementation uses the sunPointerScreenFuncs utility functions that implement Screen crossings and cursor warping, you should initialize the pPrivate->sunFbs.EnterLeave field to NULL in your ddxInitFunc. See Chapter 4, "Cursors" for information on sunPointerScreenFuncs.

Note - The sample DDX handlers store device-dependent information about the device memory-mappings in some of the other private fields of the sunScreenRec data structure, for use in the CloseScreen routine. It is
recommended that you minimize dependencies on the sunScreenRec private data structure, and store device-dependent information in data structures that are private to your own DDX handler. These data structures can be stored by allocating a devPrivate index on the Screen that is private to your DDX handler.

sunSetPixmapFormat


  Bool  
  sunSetPixmapFormat(PixmapFormatRec *request)  

PurposeThis function is used by each device to advertise the pixmap formats supported for each depth. If there are multiple Screens supporting the same depth, they should support a common pixmap format for that depth. The first pixmap format defined for that depth is the one used for all Screens that are added.
Called byYour ddxInitFunc calls this routine once for each depth that it plans to export in the pScreen->allowedDepths field.
ReturnsTRUE if it is the first pixmap format definition for specified depth, or if it is a repeat definition that agrees with the existing one
FALSE for any attempt to define a new format for an existing depth. The request variable is set to the defined format for that depth; use the format returned in your new Screen's DDX handler.
Table 3-1 lists the pixmap formats supported by some devices.
Table 3-1
DepthBitsPerPixelScanlinePad
11BITMAP_SCANLINE_PAD
44BITMAP_SCANLINE_PAD
48BITMAP_SCANLINE_PAD
Table 3-1 (Continued)
DepthBitsPerPixelScanlinePad
88BITMAP_SCANLINE_PAD
2432BITMAP_SCANLINE_PAD
3232BITMAP_SCANLINE_PAD
If you want your new device to support one of these depths, use one of the pixmap formats specified in Table 3-1 so that your device can be used with devices by other IHV's in a multi-screen configuration.

Note - The two 4-bit deep screen formats may not coexist simultaneously with other IHV's devices. The 4-bit deep, 4 BitsPerPixel format is the only 4-bit deep screen format supported during an X server session.

If a new depth is exported by a device, register the pixmap format with Sun for inclusion in this table, or be prepared to handle differing pixmap formats (that is, sunSetPixmapFormat returns FALSE) in your DDX handler.

sunGetMonitorRes


  void  
  sunGetMonitorRes(int screenIndex, int *dpix int *dpiy)  

PurposeThis function gets the monitor's resolution.
ResultsThe default value, 90 DPI, is used if a monitor resolution is not specified.

Note - Currently the monitor's resolution is specified with the -dev command-line option. Future releases of the OpenWindows server might offer alternate mechanisms to query the monitor resolution, such as specifying it in the OWconfig database.

sunGetVisualInfo


  void  
  sunGetVisualInfo(int screenIndex, int *defClass, int *defDepth,  
           Bool *grayVis);  

PurposeThis function gets the command-line options for Visual information specified by the user for the Screen. Since the user can specify the default visual class, the default depth, or gray visual, the DDX handler must query these values before setting up the visuals to be exported for this Screen.
ReturnsThe default visual class specified as defclass in the -dev command-line option, if specified; else the default specified with the -cc option; else -1.
The defDepth specified with the -dev option.
TRUE for grayVis, if the user specified the grayvis modifier to the -dev option. This suppresses color visuals and is useful if a grayscale monitor is connected to the device. If grayVis is TRUE, this function ensures that the user has selected a gray defClass, if a defClass has been specified; else defClass is set to -1.

Export Supported Visuals

The ddxInitFunc should advertise the visuals it supports, based on device capabilities and user preferences selected with command-line options.

Note - The sample cg3 DDX handler uses the cfb utility layer to select and advertise its visual list. See the sunCG3C.c file in the server/ddx/solaris/reference/cg3 directory for details.

Initialize Utility Layers

The various utility layers used by your DDX handler should be initialized in your ddxInitFunc. Depending on the utility layers used, the order of initialization might be important, as a number of the utility layers wrap the DDX functions.

Initialize the Banner Code


  extern int noBanner;  
  extern void sunInitBanner(ScreenPtr pScreen);  

PurposeThis function initializes the banner display code.
Called byThe following code in your ddxInitFunc:
{
ResultsA banner is displayed by the server on every Screen, unless openwin is started with the -nobanner command-line option.

Note - The sample cg3 DDX handler does not implement this directly. It calls a private helper function, sunScreenInit, to initialize the banner code and perform other miscellaneous initialization. sunScreenInit is called for example only; do not call it from your ddxInitFunc. It has the undesirable effect of installing a SaveScreen routine that relies on ioctls private to the cg3 device driver.

Supply a SaveScreen Function


  Bool  
  pScreen->SaveScreen(ScreenPtr pScreen, int on)  

The field on has the following values:
SCREEN_SAVER_ON          Turns on the screen saver; disables video

SCREEN_SAVER_OFF         Turns off the screen saver; enables video

SCREEN_SAVER_FORCER      Updates time of last screen saver mode change


Note - The sample DDX handlers install a private helper routine called sunSaveScreen as the pScreen->SaveScreen routine. Do not use this implementation in your DDX handler; it relies on ioctls private to the sample device implementation. Instead, implement your own SaveScreen routine.

The following is a simple SaveScreen implementation:

  Bool  
  xxxSaveScreen(ScreenPtr pScreen, int on)  
  {  
       if (on == SCREEN_SAVER_FORCER) {  
           SetTimeSinceLastInputEvent();  
       }  
       else {  
           if (on == SCREEN_SAVER_ON) {  
                VIDEO_OFF(); /* Device specific video disable */  
           }  
           else {  
                VIDEO_ON(); /* Device specific video enable */  
           }  
       }  
       return TRUE;  
  }  

Supply a CloseScreen Function

The CloseScreen function should be wrapped by ddxInitFunc. The CloseScreen routine should clean-up all the device state, to the extent required by the device. For example, you might follow these steps in your CloseScreen function:
  • Enable video, if the ScreenSaver disabled video
  • Clear the Screen before exiting
  • Reset the device's LUT with colors appropriate for displaying console messages, if the device also acts as a system console
  • Call the CloseScreen functions that were wrapped
  • Unmap the device registers and frame buffer, if it is a memory-mapped frame buffer
  • Close all file descriptors opened by the DDX handler
  • Free all allocated memory

For SPARC systems - For a sample CloseScreen implementation, see the ddk_2.6/xserver/server/ddx/solaris/sparc/cg3 directory.


For x86 systems - For a sample CloseScreen implementation, see the ddk_2.6/xserver/server/ddx/solaris/i386/displays/v256 directory.

Initializing Visual Gamma

If your device supports linear and nonlinear visuals, you might want to advertise the XSolarisGetVisualGamma property; otherwise, it is optional.

Gamma-Corrected Visuals

Some devices have linear, or gamma corrected visuals. Applications can distinguish between linear visuals and nonlinear visuals by calling XSolarisGetVisualGamma(3). For more information on this routine see the Solaris X Window System Developer's Guide and the manual page.
Devices that have linear visuals should export these visuals by adding them to the pScreen->visuals list just like any other visual. A root window property distinguishes it from the nonlinear visuals.

Note - If a device has a linear visual with a nonlinear counterpart having a gamma of approximately 2.22, it is a good idea to place the nonlinear one before the linear one on the screen visual list. Most X11 applications prefer a nonlinear visual with this gamma value. Make the server default visual nonlinear as well.

The Monitor Intensity Response Property

Linear and nonlinear visuals are differentiated by describing their gamma value through a root window property, XDCCC_LINEAR_RGB_CORRECTION. It is a standard X11 ICCCM property originally created for the X Color Management System. The routine XSolarisGetVisualGamma also reads it. This property specifies for a visual a set of tables (one for each of the red, green, and blue color channels) that describe how the intensity of colors coming out of the frame buffer map to actual display colors on the monitor screen. This is the intensity response of colors displayed in the visual. If the intensity response of more than one visual is described, the property contains more than one set of tables. See The X Window System for detailed information on XDCCC_LINEAR_RGB_CORRECTION.
Here are some guidelines for creating the property:
  1. Create the property with type XA_INTEGER and format 16.

  2. Visuals with a gamma of exactly 2.22 may be omitted from the property. In this case, XSolarisGetVisualGamma assumes a value of 2.22. This is the most efficient way to specify this value.

  3. Visuals with a gamma of exactly 1.0 should be represented using a 2-entry type 0 table. For each channel, the first entry should be (0, 0) and the second entry should be (numIntensities - 1, 0xffff), where numIntensities is (1 << visual->bitsPerRGBValue).

  4. All other visuals should be represented using a type 1 table. To create this type of table, the following expression should be evaluated for each color channel and for each value x between 0 and xmax:


                                                                           . y = (unsigned short) (( 65535.0 * pow((double)x/(double)xmax, )) + 0.5)  

where . is the gamma of the visual and xmax is numIntensities -1 (see guideline #3).
  1. bpr is the bitsPerRGBValue member of the visual structure. 5.

  2. If the gamma of all visuals is exactly 2.22, the property does not need to be created at all.


Note - XDCCC_LINEAR_RGB_CORRECTION describes the intensity response of the entire path from the frame buffer through the monitor, rather than just the gamma correction function.


Note - It may be acceptable if the intensity response described in this property is only approximate. The DDX may not know the specific monitor attached to the device and may need to provide an estimate. A gamma value of 2.22 is a good estimate for most monitors.

The next section describes how to create a root window property from within a DDX handler screen initialization function.

Initializing a Root Window Property

A root window property cannot be directly created from a DDX screen initialization routine because at the time this routine is called the root window has not yet been created. However, the initialization routine can arrange for the property to be created at a later time, after the root window has been created.
The first call to pScreen->CreateWindow is for the root window. This screen function should be wrapped. On the first call to the wrapper function, the property should be created on the argument window. This is guaranteed to be the root window.
A property is created by first determining the atoms for the property's name and type strings. If the string has a predefined atom, simply use the defined symbol for that atom (see /usr/openwin/include/Xatom.h for the list of predefined atoms). Otherwise, call MakeAtom to intern the string and receive back an atom.

  Atom  
  MakeAtom (char *string, unsigned len, Bool makeit)  

string is the name of the string to be interned, len is its length (in bytes), and makeit should be TRUE. A numeric value (the atom) is returned.
Next, the property is added to the window by calling ChangeWindowProperty:

  int  
  ChangeWindowProperty (WindowPtr pWin, Atom property, Atom type,  
           int format, int mode, unsigned long len, pointer value,  
           Bool sendevent)  

pWin is the argument to the CreateWindow wrapper routine, property is the interned atom for the string "XDCCC_LINEAR_RGB_CORRECTION", type is XA_INTEGER, format is 16, mode is PropModeReplace, len is the length of the property (in units of 16-bit short words), value is pointer to the property data and sendevent should be FALSE. Success is returned if the property creation succeeded.

Note - It is a good idea to unwrap pScreen->CreateWindow after the property has been created so other calls to CreateWindow do not incur extra overhead.