Site hosted by Angelfire.com: Build your free website today!

Hands-on Projects for the Linux Graphics Subsystem

New book from Christos Karayiannis

Available in Amazon Kindle format at:

amazon.com   amazon.co.uk   amazon.de   amazon.es   amazon.fr   amazon.it

AddScreen()

Before starting with AddScreen() we continue InitOutput() with the following parts of code:

  for (i = 0; i < xf86NumScreens; i++) {    
   	xf86EnableAccess(xf86Screens[i]);
	/*
	 * Almost everything uses these defaults, and many of those that
	 * don't, will wrap them.
	 */
	xf86Screens[i]->EnableDisableFBAccess = xf86EnableDisableFBAccess;
	xf86Screens[i]->SetDGAMode = xf86SetDGAMode;
	xf86Screens[i]->DPMSSet = NULL;
	xf86Screens[i]->LoadPalette = NULL; 
	xf86Screens[i]->SetOverscan = NULL;
	xf86Screens[i]->DriverFunc = NULL;
	xf86Screens[i]->pScreen = NULL;
	scr_index = AddScreen(xf86Screens[i]->ScreenInit, argc, argv);
      if (scr_index == i) {
	/*
	 * Hook in our ScrnInfoRec, and initialise some other pScreen
	 * fields.
	 */
	screenInfo.screens[scr_index]->devPrivates[xf86ScreenIndex].ptr
	  = (pointer)xf86Screens[i];
	xf86Screens[i]->pScreen = screenInfo.screens[scr_index];
	/* The driver should set this, but make sure it is set anyway */
	vtSema = TRUE;
      } else {
	/* This shouldn't normally happen */
	FatalError("AddScreen/ScreenInit failed for driver %d\n", i);
      }

The xf86Screens[] initialization that started in section 3.2.2.6 continues here by assigning mostly NULL values to other ScrnInfoRec fields.

Then AddScreen() is called as:

scr_index = AddScreen(xf86Screens[i]->ScreenInit, argc, argv);

This routine is examined next.

AddScreen()

AddScreen is described in section 5.16 of the DESIGN document:

5.16  AddScreen (ScreenInit)

At this point, the valid screens are known.  AddScreen() is called for each
of them, passing ChipScreenInit() as the argument.  AddScreen() is a DIX
function that allocates a new screenInfo.screen[] entry (aka pScreen), and
does some basic initialisation of it. It then calls the ChipScreenInit()
function, with pScreen as one of its arguments.  If ChipScreenInit() returns
FALSE, AddScreen() returns -1.  Otherwise it returns the index of the screen.

AddScreen() is implemented as:

int
AddScreen(
    Bool	(* pfnInit)(
	int /*index*/,
	ScreenPtr /*pScreen*/,
	int /*argc*/,
	char ** /*argv*/
		),
    int argc,
    char **argv)
{

    int i;
    int scanlinepad, format, depth, bitsPerPixel, j, k;
    ScreenPtr pScreen;
#ifdef DEBUG
    void	(**jNI) ();
#endif /* DEBUG */

    i = screenInfo.numScreens;
    if (i == MAXSCREENS)
	return -1;

    pScreen = (ScreenPtr) xcalloc(1, sizeof(ScreenRec));
    if (!pScreen)
	return -1;

    pScreen->devPrivates = (DevUnion *)xcalloc(sizeof(DevUnion),
						screenPrivateCount);
    if (!pScreen->devPrivates && screenPrivateCount)
    {
	xfree(pScreen);
	return -1;
    }
    pScreen->myNum = i;
    pScreen->WindowPrivateLen = 0;
    pScreen->WindowPrivateSizes = (unsigned *)NULL;
    pScreen->totalWindowSize =
        ((sizeof(WindowRec) + sizeof(long) - 1) / sizeof(long)) * sizeof(long);
    pScreen->GCPrivateLen = 0;
    pScreen->GCPrivateSizes = (unsigned *)NULL;
    pScreen->totalGCSize =
        ((sizeof(GC) + sizeof(long) - 1) / sizeof(long)) * sizeof(long);
#ifdef PIXPRIV
    pScreen->PixmapPrivateLen = 0;
    pScreen->PixmapPrivateSizes = (unsigned *)NULL;
    pScreen->totalPixmapSize = BitmapBytePad(sizeof(PixmapRec)*8);
#endif
    pScreen->ClipNotify = 0;	/* for R4 ddx compatibility */
    pScreen->CreateScreenResources = 0;
    
#ifdef DEBUG
    for (jNI = &pScreen->QueryBestSize; 
	 jNI < (void (**) ()) &pScreen->SendGraphicsExpose;
	 jNI++)
	*jNI = NotImplemented;
#endif /* DEBUG */

    /*
     * This loop gets run once for every Screen that gets added,
     * but thats ok.  If the ddx layer initializes the formats
     * one at a time calling AddScreen() after each, then each
     * iteration will make it a little more accurate.  Worst case
     * we do this loop N * numPixmapFormats where N is # of screens.
     * Anyway, this must be called after InitOutput and before the
     * screen init routine is called.
     */
    for (format=0; format<screenInfo.numPixmapFormats; format++)
    {
 	depth = screenInfo.formats[format].depth;
 	bitsPerPixel = screenInfo.formats[format].bitsPerPixel;
  	scanlinepad = screenInfo.formats[format].scanlinePad;
 	j = indexForBitsPerPixel[ bitsPerPixel ];
  	k = indexForScanlinePad[ scanlinepad ];
 	PixmapWidthPaddingInfo[ depth ].padPixelsLog2 = answer[j][k];
 	PixmapWidthPaddingInfo[ depth ].padRoundUp =
 	    (scanlinepad/bitsPerPixel) - 1;
 	j = indexForBitsPerPixel[ 8 ]; /* bits per byte */
 	PixmapWidthPaddingInfo[ depth ].padBytesLog2 = answer[j][k];
	PixmapWidthPaddingInfo[ depth ].bitsPerPixel = bitsPerPixel;
	if (answerBytesPerPixel[bitsPerPixel])
	{
	    PixmapWidthPaddingInfo[ depth ].notPower2 = 1;
	    PixmapWidthPaddingInfo[ depth ].bytesPerPixel =
		answerBytesPerPixel[bitsPerPixel];
	}
	else
	{
	    PixmapWidthPaddingInfo[ depth ].notPower2 = 0;
	}
    }
  
    /* This is where screen specific stuff gets initialized.  Load the
       screen structure, call the hardware, whatever.
       This is also where the default colormap should be allocated and
       also pixel values for blackPixel, whitePixel, and the cursor
       Note that InitScreen is NOT allowed to modify argc, argv, or
       any of the strings pointed to by argv.  They may be passed to
       multiple screens. 
    */ 
    pScreen->rgf = ~0L;  /* there are no scratch GCs yet*/
    WindowTable[i] = NullWindow;
    screenInfo.screens[i] = pScreen;
    screenInfo.numScreens++;
    if (!(*pfnInit)(i, pScreen, argc, argv))
    {
	FreeScreen(pScreen);
	screenInfo.numScreens--;
	return -1;
    }
    return i;
}

screenInfo.screens[i] = pScreen;

As the comment of the DESIGN document notes Addscreen() "allocates a new screenInfo.screen[] entry (a.k.a. pScreen), and does some basic initialisation of it". screenInfo is the main struct that InitOutput fills. It is described in section 3.2.2. pScreen is of type ScreenPtr, a pointer to ScreenRec. This struct is also described in section 3.3.2.

i indicates the next available ScreenRec of screenInfo:

i = screenInfo.numScreens;

After the allocation of the screenInfo.screen[] entry it increases by one:
screenInfo.numScreens++;

Then the 'ScreenInit' is called then. For the current example this is MGAScreenInit(), which is examined in section 3.2.2.11.

    if (!(*pfnInit)(i, pScreen, argc, argv))

back to InitOutput()

By returning to InitOutput() from AddScreen() the following part is executing:

      if (scr_index == i) {
	/*
	 * Hook in our ScrnInfoRec, and initialise some other pScreen
	 * fields.
	 */
	screenInfo.screens[scr_index]->devPrivates[xf86ScreenIndex].ptr
	  = (pointer)xf86Screens[i];
	xf86Screens[i]->pScreen = screenInfo.screens[scr_index];

The previous lines show how the basic InitOutput() data structures, as described in section 3.2.2, are connected. The following figure shows the relation between screenInfo, the ScreenRec (that a ScreenPtr of the screens[] field from screenInfo points to) and the ScrnInfoRec of a specific xf86Screens[] item:

NOTES:

Colored text is used for the assigned values to the fields of the three basic InitOutput() data structures of section 3.2.2:
Green code text assigns values to screenInfo fields.
Blue code text assigns values to a xf86Screens[] item.
Purple code text assigns values to ScreenRec fields.