Hands-on Projects for the Linux Graphics Subsystem
|
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 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;
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))
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.