Hands-on Projects for the Linux Graphics Subsystem
|
We read from the Distributed Multihead X design:
{mi,*fb}ScreenInit()
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.
It is called from MGAScreenInit() as:
ret = fbScreenInit(pScreen, FBStart, width, height, pScrn->xDpi, pScrn->yDpi, displayWidth, pScrn->bitsPerPixel); |
For a description of the fbScreenInit() arguments see section 3.2.2.11.
|
fbScreenInit() is implemented as:
Bool fbScreenInit(ScreenPtr pScreen, pointer pbits, int xsize, int ysize, int dpix, int dpiy, int width, int bpp) { if (!fbSetupScreen(pScreen, pbits, xsize, ysize, dpix, dpiy, width, bpp)) return FALSE; if (!fbFinishScreenInit(pScreen, pbits, xsize, ysize, dpix, dpiy, width, bpp)) return FALSE; return TRUE; } |
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. |
fbSetupScreen() is implemented as:
Bool fbSetupScreen(ScreenPtr pScreen, pointer pbits, /* pointer to screen bitmap */ int xsize, /* in pixels */ int ysize, int dpix, /* dots per inch */ int dpiy, int width, /* pixel width of frame buffer */ int bpp) /* bits per pixel for screen */ { if (!fbAllocatePrivates(pScreen, (int *) 0)) return FALSE; pScreen->defColormap = FakeClientID(0); /* let CreateDefColormap do whatever it wants for pixels */ pScreen->blackPixel = pScreen->whitePixel = (Pixel) 0; pScreen->QueryBestSize = fbQueryBestSize; /* SaveScreen */ pScreen->GetImage = fbGetImage; pScreen->GetSpans = fbGetSpans; pScreen->CreateWindow = fbCreateWindow; pScreen->DestroyWindow = fbDestroyWindow; pScreen->PositionWindow = fbPositionWindow; pScreen->ChangeWindowAttributes = fbChangeWindowAttributes; pScreen->RealizeWindow = fbMapWindow; pScreen->UnrealizeWindow = fbUnmapWindow; pScreen->PaintWindowBackground = fbPaintWindow; pScreen->PaintWindowBorder = fbPaintWindow; pScreen->CopyWindow = fbCopyWindow; pScreen->CreatePixmap = fbCreatePixmap; pScreen->DestroyPixmap = fbDestroyPixmap; pScreen->RealizeFont = fbRealizeFont; pScreen->UnrealizeFont = fbUnrealizeFont; pScreen->CreateGC = fbCreateGC; pScreen->CreateColormap = fbInitializeColormap; pScreen->DestroyColormap = (void (*)(ColormapPtr))NoopDDA; pScreen->InstallColormap = fbInstallColormap; pScreen->UninstallColormap = fbUninstallColormap; pScreen->ListInstalledColormaps = fbListInstalledColormaps; pScreen->StoreColors = (void (*)(ColormapPtr, int, xColorItem *))NoopDDA; pScreen->ResolveColor = fbResolveColor; pScreen->BitmapToRegion = fbPixmapToRegion; #ifndef FB_OLD_SCREEN pScreen->GetWindowPixmap = _fbGetWindowPixmap; pScreen->SetWindowPixmap = _fbSetWindowPixmap; pScreen->BackingStoreFuncs.SaveAreas = fbSaveAreas; pScreen->BackingStoreFuncs.RestoreAreas = fbRestoreAreas; pScreen->BackingStoreFuncs.SetClipmaskRgn = 0; pScreen->BackingStoreFuncs.GetImagePixmap = 0; pScreen->BackingStoreFuncs.GetSpansPixmap = 0; #endif return TRUE; } |
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().
fbFinishScreenInit() is implemented as:
Bool fbFinishScreenInit(ScreenPtr pScreen, pointer pbits, int xsize, int ysize, int dpix, int dpiy, int width, int bpp) { VisualPtr visuals; DepthPtr depths; int nvisuals; int ndepths; int rootdepth; VisualID defaultVisual; int imagebpp = bpp; #ifdef FB_DEBUG int stride; ysize -= 2; stride = (width * bpp) / 8; fbSetBits ((FbStip *) pbits, stride / sizeof (FbStip), FB_HEAD_BITS); pbits = (void *) ((char *) pbits + stride); fbSetBits ((FbStip *) ((char *) pbits + stride * ysize), stride / sizeof (FbStip), FB_TAIL_BITS); #endif /* * By default, a 24bpp screen will use 32bpp images, this avoids * problems with many applications which just can't handle packed * pixels. If you want real 24bit images, include a 24bpp * format in the pixmap formats */ #ifdef FB_24_32BIT if (bpp == 24) { int f; imagebpp = 32; /* * Check to see if we're advertising a 24bpp image format, * in which case windows will use it in preference to a 32 bit * format. */ for (f = 0; f < screenInfo.numPixmapFormats; f++) { if (screenInfo.formats[f].bitsPerPixel == 24) { imagebpp = 24; break; } } } #endif #ifdef FB_SCREEN_PRIVATE if (imagebpp == 32) { fbGetScreenPrivate(pScreen)->win32bpp = bpp; fbGetScreenPrivate(pScreen)->pix32bpp = bpp; } else { fbGetScreenPrivate(pScreen)->win32bpp = 32; fbGetScreenPrivate(pScreen)->pix32bpp = 32; } #endif rootdepth = 0; if (!fbInitVisuals (&visuals, &depths, &nvisuals, &ndepths, &rootdepth, &defaultVisual,((unsigned long)1<<(imagebpp-1)), 8)) return FALSE; if (! miScreenInit(pScreen, pbits, xsize, ysize, dpix, dpiy, width, rootdepth, ndepths, depths, defaultVisual, nvisuals, visuals #ifdef FB_OLD_MISCREENINIT , (miBSFuncPtr) 0 #endif )) return FALSE; /* overwrite miCloseScreen with our own */ pScreen->CloseScreen = fbCloseScreen; #ifdef FB_24_32BIT if (bpp == 24 && imagebpp == 32) { pScreen->ModifyPixmapHeader = fb24_32ModifyPixmapHeader; pScreen->CreateScreenResources = fb24_32CreateScreenResources; } #endif #if 0 /* leave backing store initialization to the enclosing code so * it can choose the correct order of wrappers */ /* init backing store here so we can overwrite CloseScreen without stepping * on the backing store wrapped version */ fbInitializeBackingStore (pScreen); #endif return TRUE; } |
From this wiki we read about stride:
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:
1024 pixels * 2 bytes/pixel = 2048 bytesAt 32 bits/pixel (4 bytes/pixel), your stride would be: 1024 pixels * 4 bytes/pixel = 4096 bytes Stride is important as it delineates where each line of the buffer starts and ends. With a linear buffer format, each line of the buffer follows the previous linearly in video ram: framebuffer address 0 2048 4096 |---------------|---------------|---------------| ... |---------------| |
The fbSetBits() usage is only for debugging purposes (#ifdef FB_DEBUG). It is implemented as:
void fbSetBits (FbStip *bits, int stride, FbStip data) { while (stride--) *bits++ = data; } |
Also macros FB_HEAD_BITS and FB_TAIL_BITS are defined in fd.h as:
#define FB_HEAD_BITS (FbStip) (0xbaadf00d) #define FB_TAIL_BITS (FbStip) (0xbaddf0ad) |
fbInitVisuals() handles 'visuals'.
For some texts on visuals see the following links:
|
fbInitVisuals() is implemented as:
/* * Given a list of formats for a screen, create a list * of visuals and depths for the screen which correspond to * the set which can be used with this version of fb. */ Bool fbInitVisuals (VisualPtr *visualp, DepthPtr *depthp, int *nvisualp, int *ndepthp, int *rootDepthp, VisualID *defaultVisp, unsigned long sizes, int bitsPerRGB) { int i, j = 0, k; VisualPtr visual; DepthPtr depth; VisualID *vid; int d, b; int f; int ndepth, nvisual; int nvtype; int vtype; fbVisualsPtr visuals, nextVisuals; /* none specified, we'll guess from pixmap formats */ if (!fbVisuals) { for (f = 0; f < screenInfo.numPixmapFormats; f++) { d = screenInfo.formats[f].depth; b = screenInfo.formats[f].bitsPerPixel; if (sizes & (1 << (b - 1))) { if (d > MAX_PSEUDO_DEPTH) vtype = LARGE_VISUALS; else if (d == 1) vtype = StaticGrayMask; else vtype = ALL_VISUALS; } else vtype = 0; if (!fbSetVisualTypes (d, vtype, bitsPerRGB)) return FALSE; } } nvisual = 0; ndepth = 0; for (visuals = fbVisuals; visuals; visuals = nextVisuals) { nextVisuals = visuals->next; ndepth++; nvisual += visuals->count; } depth = (DepthPtr) xalloc (ndepth * sizeof (DepthRec)); visual = (VisualPtr) xalloc (nvisual * sizeof (VisualRec)); if (!depth || !visual) { xfree (depth); xfree (visual); return FALSE; } *depthp = depth; *visualp = visual; *ndepthp = ndepth; *nvisualp = nvisual; for (visuals = fbVisuals; visuals; visuals = nextVisuals) { nextVisuals = visuals->next; d = visuals->depth; vtype = visuals->visuals; nvtype = visuals->count; vid = NULL; if (nvtype) { vid = (VisualID *) xalloc (nvtype * sizeof (VisualID)); if (!vid) return FALSE; } depth->depth = d; depth->numVids = nvtype; depth->vids = vid; depth++; for (i = 0; i < NUM_PRIORITY; i++) { if (! (vtype & (1 << fbVisualPriority[i]))) continue; visual->class = fbVisualPriority[i]; visual->bitsPerRGBValue = visuals->bitsPerRGB; visual->ColormapEntries = 1 << d; visual->nplanes = d; visual->vid = *vid = FakeClientID (0); switch (visual->class) { case PseudoColor: case GrayScale: case StaticGray: case StaticColor: visual->redMask = 0; visual->greenMask = 0; visual->blueMask = 0; visual->offsetRed = 0; visual->offsetGreen = 0; visual->offsetBlue = 0; break; case DirectColor: case TrueColor: visual->ColormapEntries = _CE(d); visual->redMask = visuals->redMask; visual->greenMask = visuals->greenMask; visual->blueMask = visuals->blueMask; visual->offsetRed = maskShift (visuals->redMask); visual->offsetGreen = maskShift (visuals->greenMask); visual->offsetBlue = maskShift (visuals->blueMask); } vid++; visual++; } xfree (visuals); } fbVisuals = NULL; visual = *visualp; depth = *depthp; for (i = 0; i < ndepth; i++) { if (*rootDepthp && *rootDepthp != depth[i].depth) continue; for (j = 0; j < depth[i].numVids; j++) { for (k = 0; k < nvisual; k++) if (visual[k].vid == depth[i].vids[j]) break; if (k == nvisual) continue; if (defaultColorVisualClass < 0 || visual[k].class == defaultColorVisualClass) break; } if (j != depth[i].numVids) break; } if (i == ndepth) { for (i = 0; i < ndepth; i++) { if (depth[i].numVids) break; } if (i == ndepth) return FALSE; j = 0; } *rootDepthp = depth[i].depth; *defaultVisp = depth[i].vids[j]; return TRUE; } |
miScreenInit() is implemented as:
Bool miScreenInit(pScreen, pbits, xsize, ysize, dpix, dpiy, width, rootDepth, numDepths, depths, rootVisual, numVisuals, visuals) register ScreenPtr pScreen; pointer pbits; /* pointer to screen bits */ int xsize, ysize; /* in pixels */ int dpix, dpiy; /* dots per inch */ int width; /* pixel width of frame buffer */ int rootDepth; /* depth of root window */ int numDepths; /* number of depths supported */ DepthRec *depths; /* supported depths */ VisualID rootVisual; /* root visual */ int numVisuals; /* number of visuals supported */ VisualRec *visuals; /* supported visuals */ { pScreen->width = xsize; pScreen->height = ysize; pScreen->mmWidth = (xsize * 254 + dpix * 5) / (dpix * 10); pScreen->mmHeight = (ysize * 254 + dpiy * 5) / (dpiy * 10); pScreen->numDepths = numDepths; pScreen->rootDepth = rootDepth; pScreen->allowedDepths = depths; pScreen->rootVisual = rootVisual; /* defColormap */ pScreen->minInstalledCmaps = 1; pScreen->maxInstalledCmaps = 1; pScreen->backingStoreSupport = NotUseful; pScreen->saveUnderSupport = NotUseful; /* whitePixel, blackPixel */ pScreen->ModifyPixmapHeader = miModifyPixmapHeader; pScreen->CreateScreenResources = miCreateScreenResources; pScreen->GetScreenPixmap = miGetScreenPixmap; pScreen->SetScreenPixmap = miSetScreenPixmap; pScreen->numVisuals = numVisuals; pScreen->visuals = visuals; if (width) { #ifdef MITSHM ShmRegisterFbFuncs(pScreen); #endif pScreen->CloseScreen = miCloseScreen; } /* else CloseScreen */ /* QueryBestSize, SaveScreen, GetImage, GetSpans */ pScreen->PointerNonInterestBox = (PointerNonInterestBoxProcPtr) 0; pScreen->SourceValidate = (SourceValidateProcPtr) 0; /* CreateWindow, DestroyWindow, PositionWindow, ChangeWindowAttributes */ /* RealizeWindow, UnrealizeWindow */ pScreen->ValidateTree = miValidateTree; pScreen->PostValidateTree = (PostValidateTreeProcPtr) 0; pScreen->WindowExposures = miWindowExposures; /* PaintWindowBackground, PaintWindowBorder, CopyWindow */ pScreen->ClearToBackground = miClearToBackground; pScreen->ClipNotify = (ClipNotifyProcPtr) 0; pScreen->RestackWindow = (RestackWindowProcPtr) 0; /* CreatePixmap, DestroyPixmap */ /* RealizeFont, UnrealizeFont */ /* CreateGC */ /* CreateColormap, DestroyColormap, InstallColormap, UninstallColormap */ /* ListInstalledColormaps, StoreColors, ResolveColor */ #ifdef NEED_SCREEN_REGIONS pScreen->RegionCreate = miRegionCreate; pScreen->RegionInit = miRegionInit; pScreen->RegionCopy = miRegionCopy; pScreen->RegionDestroy = miRegionDestroy; pScreen->RegionUninit = miRegionUninit; pScreen->Intersect = miIntersect; pScreen->Union = miUnion; pScreen->Subtract = miSubtract; pScreen->Inverse = miInverse; pScreen->RegionReset = miRegionReset; pScreen->TranslateRegion = miTranslateRegion; pScreen->RectIn = miRectIn; pScreen->PointInRegion = miPointInRegion; pScreen->RegionNotEmpty = miRegionNotEmpty; pScreen->RegionEqual = miRegionEqual; pScreen->RegionBroken = miRegionBroken; pScreen->RegionBreak = miRegionBreak; pScreen->RegionEmpty = miRegionEmpty; pScreen->RegionExtents = miRegionExtents; pScreen->RegionAppend = miRegionAppend; pScreen->RegionValidate = miRegionValidate; #endif /* NEED_SCREEN_REGIONS */ /* BitmapToRegion */ #ifdef NEED_SCREEN_REGIONS pScreen->RectsToRegion = miRectsToRegion; #endif /* NEED_SCREEN_REGIONS */ pScreen->SendGraphicsExpose = miSendGraphicsExpose; pScreen->BlockHandler = (ScreenBlockHandlerProcPtr)NoopDDA; pScreen->WakeupHandler = (ScreenWakeupHandlerProcPtr)NoopDDA; pScreen->blockData = (pointer)0; pScreen->wakeupData = (pointer)0; pScreen->MarkWindow = miMarkWindow; pScreen->MarkOverlappedWindows = miMarkOverlappedWindows; pScreen->ChangeSaveUnder = miChangeSaveUnder; pScreen->PostChangeSaveUnder = miPostChangeSaveUnder; pScreen->MoveWindow = miMoveWindow; pScreen->ResizeWindow = miSlideAndSizeWindow; pScreen->GetLayerWindow = miGetLayerWindow; pScreen->HandleExposures = miHandleValidateExposures; pScreen->ReparentWindow = (ReparentWindowProcPtr) 0; pScreen->ChangeBorderWidth = miChangeBorderWidth; #ifdef SHAPE pScreen->SetShape = miSetShape; #endif pScreen->MarkUnrealizedWindow = miMarkUnrealizedWindow; pScreen->SaveDoomedAreas = 0; pScreen->RestoreAreas = 0; pScreen->ExposeCopy = 0; pScreen->TranslateBackingStore = 0; pScreen->ClearBackingStore = 0; pScreen->DrawGuarantee = 0; miSetZeroLineBias(pScreen, DEFAULTZEROLINEBIAS); return miScreenDevPrivateInit(pScreen, width, pbits); } |
miScreenDevPrivateInit() is implemented as:
Bool miScreenDevPrivateInit(pScreen, width, pbits) register ScreenPtr pScreen; int width; pointer pbits; { miScreenInitParmsPtr pScrInitParms; /* Stash pbits and width in a short-lived miScreenInitParmsRec attached * to the screen, until CreateScreenResources can put them in the * screen pixmap. */ pScrInitParms = (miScreenInitParmsPtr)xalloc(sizeof(miScreenInitParmsRec)); if (!pScrInitParms) return FALSE; pScrInitParms->pbits = pbits; pScrInitParms->width = width; pScreen->devPrivate = (pointer)pScrInitParms; return TRUE; } |
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:
for (i = 0; i < screenInfo.numScreens; i++) { ScreenPtr pScreen = screenInfo.screens[i]; if (!CreateScratchPixmapsForScreen(i)) FatalError("failed to create scratch pixmaps"); if (pScreen->CreateScreenResources && !(*pScreen->CreateScreenResources)(pScreen)) FatalError("failed to create screen resources"); |
Previously as CreateScreenResources() was set miCreateScreenResources() by miScreenInit().
miCreateScreenResources() is implemented 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:
InitExtensions(argc, argv);This is called from main() just after InitOutput().
fbCreatePixmap() is imlpemented as:
PixmapPtr fbCreatePixmap (ScreenPtr pScreen, int width, int height, int depth) { int bpp; bpp = BitsPerPixel (depth); #ifdef FB_SCREEN_PRIVATE if (bpp == 32 && depth <= 24) bpp = fbGetScreenPrivate(pScreen)->pix32bpp; #endif return fbCreatePixmapBpp (pScreen, width, height, depth, bpp); } |
where fbCreatePixmapBpp() is implemented in the same file as:
PixmapPtr fbCreatePixmapBpp (ScreenPtr pScreen, int width, int height, int depth, int bpp) { PixmapPtr pPixmap; size_t datasize; size_t paddedWidth; int adjust; int base; paddedWidth = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof (FbBits); if (paddedWidth / 4 > 32767 || height > 32767) return NullPixmap; datasize = height * paddedWidth; #ifdef PIXPRIV base = pScreen->totalPixmapSize; #else base = sizeof (PixmapRec); #endif adjust = 0; if (base & 7) adjust = 8 - (base & 7); datasize += adjust; #ifdef FB_DEBUG datasize += 2 * paddedWidth; #endif pPixmap = AllocatePixmap(pScreen, datasize); if (!pPixmap) return NullPixmap; pPixmap->drawable.type = DRAWABLE_PIXMAP; pPixmap->drawable.class = 0; pPixmap->drawable.pScreen = pScreen; pPixmap->drawable.depth = depth; pPixmap->drawable.bitsPerPixel = bpp; pPixmap->drawable.id = 0; pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; pPixmap->drawable.x = 0; pPixmap->drawable.y = 0; pPixmap->drawable.width = width; pPixmap->drawable.height = height; pPixmap->devKind = paddedWidth; pPixmap->refcnt = 1; pPixmap->devPrivate.ptr = (pointer) ((char *)pPixmap + base + adjust); #ifdef FB_DEBUG pPixmap->devPrivate.ptr = (void *) ((char *) pPixmap->devPrivate.ptr + paddedWidth); fbInitializeDrawable (&pPixmap->drawable); #endif #ifdef COMPOSITE pPixmap->screen_x = 0; pPixmap->screen_y = 0; #endif return pPixmap; } |
AllocatePixmap() is implemented as:
/* callable by ddx */ PixmapPtr AllocatePixmap(ScreenPtr pScreen, int pixDataSize) { PixmapPtr pPixmap; #ifdef PIXPRIV char *ptr; DevUnion *ppriv; unsigned *sizes; unsigned size; int i; if (pScreen->totalPixmapSize > ((size_t)-1) - pixDataSize) return NullPixmap; pPixmap = (PixmapPtr)xalloc(pScreen->totalPixmapSize + pixDataSize); if (!pPixmap) return NullPixmap; ppriv = (DevUnion *)(pPixmap + 1); pPixmap->devPrivates = ppriv; sizes = pScreen->PixmapPrivateSizes; ptr = (char *)(ppriv + pScreen->PixmapPrivateLen); for (i = pScreen->PixmapPrivateLen; --i >= 0; ppriv++, sizes++) { if ((size = *sizes) != 0) { ppriv->ptr = (pointer)ptr; ptr += size; } else ppriv->ptr = (pointer)NULL; } #else pPixmap = (PixmapPtr)xalloc(sizeof(PixmapRec) + pixDataSize); #endif return pPixmap; } |
Given that pPixmap points at the start of PixmapRec the following fbCreatePixmapBpp() instruction points pPixmap->devPrivate.ptr after PixmapRec at pixmap data. pPixmap->devPrivate.ptr = (pointer) ((char *)pPixmap + base + adjust); |
pPixmap, the pointer to the pixmap created previously (of type PixmapPtr) is passed then to ModifyPixmapHeader(), which is actually miModifyPixmapHeader(), implemented as:
/* this plugs into pScreen->ModifyPixmapHeader */ Bool miModifyPixmapHeader(pPixmap, width, height, depth, bitsPerPixel, devKind, pPixData) PixmapPtr pPixmap; int width; int height; int depth; int bitsPerPixel; int devKind; pointer pPixData; { if (!pPixmap) return FALSE; /* * If all arguments are specified, reinitialize everything (including * validated state). */ if ((width > 0) && (height > 0) && (depth > 0) && (bitsPerPixel > 0) && (devKind > 0) && pPixData) { pPixmap->drawable.depth = depth; pPixmap->drawable.bitsPerPixel = bitsPerPixel; pPixmap->drawable.id = 0; pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; pPixmap->drawable.x = 0; pPixmap->drawable.y = 0; pPixmap->drawable.width = width; pPixmap->drawable.height = height; pPixmap->devKind = devKind; pPixmap->refcnt = 1; pPixmap->devPrivate.ptr = pPixData; } else { /* * Only modify specified fields, keeping all others intact. */ if (width > 0) pPixmap->drawable.width = width; if (height > 0) pPixmap->drawable.height = height; if (depth > 0) pPixmap->drawable.depth = depth; if (bitsPerPixel > 0) pPixmap->drawable.bitsPerPixel = bitsPerPixel; else if ((bitsPerPixel < 0) && (depth > 0)) pPixmap->drawable.bitsPerPixel = BitsPerPixel(depth); /* * CAVEAT: Non-SI DDXen may use devKind and devPrivate fields for * other purposes. */ if (devKind > 0) pPixmap->devKind = devKind; else if ((devKind < 0) && ((width > 0) || (depth > 0))) pPixmap->devKind = PixmapBytePad(pPixmap->drawable.width, pPixmap->drawable.depth); if (pPixData) pPixmap->devPrivate.ptr = pPixData; } return TRUE; } |
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. |
We continue to section 3.2.2.13. |
NOTES:
Purple code text assigns values to ScreenRec fields
REFERENCES:
How Video Cards Work
Backing Store Attribute
Distributed Multihead X design