fbScreenInit()

The DDX layer's ScreenInit() function usually calls another layer's ScreenInit() function (e.g., miScreenInit() or fbScreenInit()) to initialize the fallbacks that the DDX driver does not specifically handle.

After calling another layer's ScreenInit() function, any screen-specific functions either wrap or replace the other layer's function pointers. If a function is to be wrapped, each of the old function pointers from the other layer are stored in a screen private area. Common functions to wrap are CloseScreen() and SaveScreen().

fbScreenInit() is used to tell the fb layer where the video card framebuffer is.

Notice that fbScreenInit calls 'width' the seventh of its formal arguments, which was substituted by the actual argument 'displayWidth'. At the same time there is a third actual argument also called 'width' (see this Wiki). This might cause some misunderstanding. Anyway as width the displayWidth will be used next. This is the stride as we saw in section 3.2.2.11.

The pScreen pointer to the current ScreenRec, which is passed as the first argument to fbScreenInit() fills many of the of its pointer to functions fields. The process of filling the current ScreenRec started at section 3.2.2.10 with AddScreen().

Buffers in video ram generally have a stride (also called pitch) associated with them. The stride is the width of the buffer in bytes. For example, if you have a 1024x768 pixel buffer at 16 bits/pixel (2 bytes/pixel), your stride would be:

The framebuffer address (FBStart), which was named pbits in the functions called by fbScreenInit() is finally used here as a field of the struct that devPrivate points. Pointer devPrivate is a field of ScreenRec.

Note also the following comment at the definition of miScreenInitParmsRec:

/* We use this structure to propogate some information from miScreenInit to
* miCreateScreenResources. miScreenInit allocates the structure, fills it
* in, and puts it into pScreen->devPrivate. miCreateScreenResources
* extracts the info and frees the structure. We could've accomplished the
* same thing by adding fields to the screen structure, but they would have
* ended up being redundant, and would have exposed this mi implementation
* detail to the whole server.
*/
typedef struct
{
pointer pbits; /* pointer to framebuffer */
int width; /* delta to add to a framebuffer addr to move one row down */
} miScreenInitParmsRec, *miScreenInitParmsPtr;

As the comment in the source notes 'pbits' and 'width' will be used next by CreateScreenResources(), which was called in main() after the InitOutput() as:

/* With the introduction of pixmap privates, the "screen pixmap" can no
* longer be created in miScreenInit, since all the modules that could
* possibly ask for pixmap private space have not been initialized at
* that time. pScreen->CreateScreenResources is called after all
* possible private-requesting modules have been inited; we create the
* screen pixmap here.
*/
Bool
miCreateScreenResources(pScreen)
ScreenPtr pScreen;
{
miScreenInitParmsPtr pScrInitParms;
pointer value;
pScrInitParms = (miScreenInitParmsPtr)pScreen->devPrivate;
/* if width is non-zero, pScreen->devPrivate will be a pixmap
* else it will just take the value pbits
*/
if (pScrInitParms->width)
{
PixmapPtr pPixmap;
/* create a pixmap with no data, then redirect it to point to
* the screen
*/
pPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, pScreen->rootDepth);
if (!pPixmap)
return FALSE;
if (!(*pScreen->ModifyPixmapHeader)(pPixmap, pScreen->width,
pScreen->height, pScreen->rootDepth,
BitsPerPixel(pScreen->rootDepth),
PixmapBytePad(pScrInitParms->width, pScreen->rootDepth),
pScrInitParms->pbits))
return FALSE;
value = (pointer)pPixmap;
}
else
{
value = pScrInitParms->pbits;
}
xfree(pScreen->devPrivate); /* freeing miScreenInitParmsRec */
pScreen->devPrivate = value; /* pPixmap or pbits */
return TRUE;
}

At this point pScreen->devPrivate takes the value of either pbits (the pointer to the screen memory) or pPixmap (again the pointer to the screen memory, this time however there is a displayWidth a.k.a. 'stride').

The choice is made according to the value of pScrInitParms->width, which is the displayWidth. A value was assigned to displayWidth at MGAPreInit() when xf86ValidateModes() was called. As we read from its comment:

* The function fills in the following ScrnInfoRec fields:
* modePool A subset of the modes available to the monitor which
* are compatible with the driver.
* modes one mode entry for each of the requested modes, with the
* status field filled in to indicate if the mode has been
* accepted or not.
* virtualX the resulting virtual width
* virtualY the resulting virtual height
* displayWidth the resulting line pitch

The comment in the beginning of miCreateScreenResources() explains that this function should be called after "all possible private-requesting modules have been inited", which implies that the following instruction should be called:

Recall the comment of of miCreateScreenResources() "create a pixmap with no data, then redirect it to point to the screen". The routine that created the empty pixmap was (*pScreen->CreatePixmap) actually fbCreatePixmap() and the routine that (*pScreen->ModifyPixmapHeader), which is actually miModifyPixmapHeader() sets the address of the pixmap to the screen memory address is (*pScreen->ModifyPixmapHeader), which is actually miModifyPixmapHeader().

The address is passed as the last argument of (*pScreen->ModifyPixmapHeader) and as seen in miCreateScreenResources() this is pScrInitParms->pbits. This was set to pbits by miScreenDevPrivateInit() and pbits replaces the FBStart fbScreenInit(), which is the screen memory address. As we read in section 3.2.2.11: "Mga->FbStart is equal to pMga->FbBase since YDstOrg (the offset in bytes from video start to usable memory) is usually zero (see comment in MGAPreInit())".

The usage of the ModifyPixmapHeader() is also explained in the DESIGN document:

Additionally, if an aper-
ture used to access video memory is unmapped and remapped in this
fashion, ChipEnterVT() will also need to notify the framebuffer
layers of the aperture's new location in virtual memory. This is
done with a call to the screen's ModifyPixmapHeader() function, as
follows
(*pScreen->ModifyPixmapHeader)(pScrn->ppix,
-1, -1, -1, -1, -1, NewApertureAddress);
where the ``ppix'' field in a ScrnInfoRec
points to the pixmap used by the screen's
SaveRestoreImage() function to hold the
screen's contents while switched out.