From 0f834b91a4768673833ab4917e87d86c237bb1a6 Mon Sep 17 00:00:00 2001 From: marha Date: Fri, 23 Mar 2012 10:05:55 +0100 Subject: libX11 xserver fontconfig mesa pixman xkbcomp xkeyboard-config git update 23 Mar 2012 --- xorg-server/hw/xfree86/common/xf86fbman.c | 2877 ++++++++++++++--------------- 1 file changed, 1431 insertions(+), 1446 deletions(-) (limited to 'xorg-server/hw/xfree86/common/xf86fbman.c') diff --git a/xorg-server/hw/xfree86/common/xf86fbman.c b/xorg-server/hw/xfree86/common/xf86fbman.c index ccb761a2c..3c29bf531 100644 --- a/xorg-server/hw/xfree86/common/xf86fbman.c +++ b/xorg-server/hw/xfree86/common/xf86fbman.c @@ -1,1446 +1,1431 @@ - -/* - * Copyright (c) 1998-2001 by The XFree86 Project, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Except as contained in this notice, the name of the copyright holder(s) - * and author(s) shall not be used in advertising or otherwise to promote - * the sale, use or other dealings in this Software without prior written - * authorization from the copyright holder(s) and author(s). - */ - -#ifdef HAVE_XORG_CONFIG_H -#include -#endif - -#include "misc.h" -#include "xf86.h" - -#include -#include "scrnintstr.h" -#include "regionstr.h" -#include "xf86fbman.h" - -/* -#define DEBUG -*/ - -static DevPrivateKeyRec xf86FBManagerKeyRec; -static DevPrivateKey xf86FBManagerKey; - -Bool xf86RegisterOffscreenManager( - ScreenPtr pScreen, - FBManagerFuncsPtr funcs -){ - - xf86FBManagerKey = &xf86FBManagerKeyRec; - - if (!dixRegisterPrivateKey(&xf86FBManagerKeyRec, PRIVATE_SCREEN, 0)) - return FALSE; - - dixSetPrivate(&pScreen->devPrivates, xf86FBManagerKey, funcs); - - return TRUE; -} - - -Bool -xf86FBManagerRunning(ScreenPtr pScreen) -{ - if (xf86FBManagerKey == NULL) - return FALSE; - - if(!dixLookupPrivate(&pScreen->devPrivates, xf86FBManagerKey)) - return FALSE; - - return TRUE; -} - -Bool -xf86RegisterFreeBoxCallback( - ScreenPtr pScreen, - FreeBoxCallbackProcPtr FreeBoxCallback, - pointer devPriv -){ - FBManagerFuncsPtr funcs; - - if(xf86FBManagerKey == NULL) - return FALSE; - if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBManagerKey))) - return FALSE; - - return (*funcs->RegisterFreeBoxCallback)(pScreen, FreeBoxCallback, devPriv); -} - - -FBAreaPtr -xf86AllocateOffscreenArea( - ScreenPtr pScreen, - int w, int h, - int gran, - MoveAreaCallbackProcPtr moveCB, - RemoveAreaCallbackProcPtr removeCB, - pointer privData -){ - FBManagerFuncsPtr funcs; - - if(xf86FBManagerKey == NULL) - return NULL; - if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBManagerKey))) - return NULL; - - return (*funcs->AllocateOffscreenArea)( - pScreen, w, h, gran, moveCB, removeCB, privData); -} - - -FBLinearPtr -xf86AllocateOffscreenLinear( - ScreenPtr pScreen, - int length, - int gran, - MoveLinearCallbackProcPtr moveCB, - RemoveLinearCallbackProcPtr removeCB, - pointer privData -){ - FBManagerFuncsPtr funcs; - - if(xf86FBManagerKey == NULL) - return NULL; - if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBManagerKey))) - return NULL; - - return (*funcs->AllocateOffscreenLinear)( - pScreen, length, gran, moveCB, removeCB, privData); -} - - -void -xf86FreeOffscreenArea(FBAreaPtr area) -{ - FBManagerFuncsPtr funcs; - - if(!area) return; - - if(xf86FBManagerKey == NULL) - return; - if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate( - &area->pScreen->devPrivates, xf86FBManagerKey))) - return; - - (*funcs->FreeOffscreenArea)(area); - - return; -} - - -void -xf86FreeOffscreenLinear(FBLinearPtr linear) -{ - FBManagerFuncsPtr funcs; - - if(!linear) return; - - if(xf86FBManagerKey == NULL) - return; - if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate( - &linear->pScreen->devPrivates, xf86FBManagerKey))) - return; - - (*funcs->FreeOffscreenLinear)(linear); - - return; -} - - -Bool -xf86ResizeOffscreenArea( - FBAreaPtr resize, - int w, int h -){ - FBManagerFuncsPtr funcs; - - if(!resize) return FALSE; - - if(xf86FBManagerKey == NULL) - return FALSE; - if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate( - &resize->pScreen->devPrivates, xf86FBManagerKey))) - return FALSE; - - return (*funcs->ResizeOffscreenArea)(resize, w, h); -} - -Bool -xf86ResizeOffscreenLinear( - FBLinearPtr resize, - int size -){ - FBManagerFuncsPtr funcs; - - if(!resize) return FALSE; - - if(xf86FBManagerKey == NULL) - return FALSE; - if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate( - &resize->pScreen->devPrivates, xf86FBManagerKey))) - return FALSE; - - return (*funcs->ResizeOffscreenLinear)(resize, size); -} - - -Bool -xf86QueryLargestOffscreenArea( - ScreenPtr pScreen, - int *w, int *h, - int gran, - int preferences, - int severity -){ - FBManagerFuncsPtr funcs; - - *w = 0; - *h = 0; - - if(xf86FBManagerKey == NULL) - return FALSE; - if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBManagerKey))) - return FALSE; - - return (*funcs->QueryLargestOffscreenArea)( - pScreen, w, h, gran, preferences, severity); -} - -Bool -xf86QueryLargestOffscreenLinear( - ScreenPtr pScreen, - int *size, - int gran, - int severity -){ - FBManagerFuncsPtr funcs; - - *size = 0; - - if(xf86FBManagerKey == NULL) - return FALSE; - if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBManagerKey))) - return FALSE; - - return (*funcs->QueryLargestOffscreenLinear)( - pScreen, size, gran, severity); -} - - -Bool -xf86PurgeUnlockedOffscreenAreas(ScreenPtr pScreen) -{ - FBManagerFuncsPtr funcs; - - if(xf86FBManagerKey == NULL) - return FALSE; - if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBManagerKey))) - return FALSE; - - return (*funcs->PurgeOffscreenAreas)(pScreen); -} - -/************************************************************\ - - Below is a specific implementation of an offscreen manager. - -\************************************************************/ - -static DevPrivateKeyRec xf86FBScreenKeyRec; -#define xf86FBScreenKey (&xf86FBScreenKeyRec) - -typedef struct _FBLink { - FBArea area; - struct _FBLink *next; -} FBLink, *FBLinkPtr; - -typedef struct _FBLinearLink { - FBLinear linear; - int free; /* need to add free here as FBLinear is publicly accessible */ - FBAreaPtr area; /* only used if allocation came from XY area */ - struct _FBLinearLink *next; -} FBLinearLink, *FBLinearLinkPtr; - - -typedef struct { - ScreenPtr pScreen; - RegionPtr InitialBoxes; - RegionPtr FreeBoxes; - FBLinkPtr UsedAreas; - int NumUsedAreas; - FBLinearLinkPtr LinearAreas; - CloseScreenProcPtr CloseScreen; - int NumCallbacks; - FreeBoxCallbackProcPtr *FreeBoxesUpdateCallback; - DevUnion *devPrivates; -} FBManager, *FBManagerPtr; - - -static void -SendCallFreeBoxCallbacks(FBManagerPtr offman) -{ - int i = offman->NumCallbacks; - - while(i--) { - (*offman->FreeBoxesUpdateCallback[i])( - offman->pScreen, offman->FreeBoxes, offman->devPrivates[i].ptr); - } -} - -static Bool -localRegisterFreeBoxCallback( - ScreenPtr pScreen, - FreeBoxCallbackProcPtr FreeBoxCallback, - pointer devPriv -){ - FBManagerPtr offman; - FreeBoxCallbackProcPtr *newCallbacks; - DevUnion *newPrivates; - - offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - newCallbacks = realloc( offman->FreeBoxesUpdateCallback, - sizeof(FreeBoxCallbackProcPtr) * (offman->NumCallbacks + 1)); - - newPrivates = realloc(offman->devPrivates, - sizeof(DevUnion) * (offman->NumCallbacks + 1)); - - if(!newCallbacks || !newPrivates) - return FALSE; - - offman->FreeBoxesUpdateCallback = newCallbacks; - offman->devPrivates = newPrivates; - - offman->FreeBoxesUpdateCallback[offman->NumCallbacks] = FreeBoxCallback; - offman->devPrivates[offman->NumCallbacks].ptr = devPriv; - offman->NumCallbacks++; - - SendCallFreeBoxCallbacks(offman); - - return TRUE; -} - - -static FBAreaPtr -AllocateArea( - FBManagerPtr offman, - int w, int h, - int granularity, - MoveAreaCallbackProcPtr moveCB, - RemoveAreaCallbackProcPtr removeCB, - pointer privData -){ - ScreenPtr pScreen = offman->pScreen; - FBLinkPtr link = NULL; - FBAreaPtr area = NULL; - RegionRec NewReg; - int i, x = 0, num; - BoxPtr boxp; - - if(granularity <= 1) granularity = 0; - - boxp = RegionRects(offman->FreeBoxes); - num = RegionNumRects(offman->FreeBoxes); - - /* look through the free boxes */ - for(i = 0; i < num; i++, boxp++) { - x = boxp->x1; - if (granularity > 1) - x = ((x + granularity - 1) / granularity) * granularity; - - if(((boxp->y2 - boxp->y1) < h) || ((boxp->x2 - x) < w)) - continue; - - link = malloc(sizeof(FBLink)); - if(!link) return NULL; - - area = &(link->area); - link->next = offman->UsedAreas; - offman->UsedAreas = link; - offman->NumUsedAreas++; - break; - } - - /* try to boot a removeable one out if we are not expendable ourselves */ - if(!area && !removeCB) { - link = offman->UsedAreas; - - while(link) { - if(!link->area.RemoveAreaCallback) { - link = link->next; - continue; - } - - boxp = &(link->area.box); - x = boxp->x1; - if (granularity > 1) - x = ((x + granularity - 1) / granularity) * granularity; - - if(((boxp->y2 - boxp->y1) < h) || ((boxp->x2 - x) < w)) { - link = link->next; - continue; - } - - /* bye, bye */ - (*link->area.RemoveAreaCallback)(&link->area); - RegionInit(&NewReg, &(link->area.box), 1); - RegionUnion(offman->FreeBoxes, offman->FreeBoxes, &NewReg); - RegionUninit(&NewReg); - - area = &(link->area); - break; - } - } - - if(area) { - area->pScreen = pScreen; - area->granularity = granularity; - area->box.x1 = x; - area->box.x2 = x + w; - area->box.y1 = boxp->y1; - area->box.y2 = boxp->y1 + h; - area->MoveAreaCallback = moveCB; - area->RemoveAreaCallback = removeCB; - area->devPrivate.ptr = privData; - - RegionInit(&NewReg, &(area->box), 1); - RegionSubtract(offman->FreeBoxes, offman->FreeBoxes, &NewReg); - RegionUninit(&NewReg); - } - - return area; -} - -static FBAreaPtr -localAllocateOffscreenArea( - ScreenPtr pScreen, - int w, int h, - int gran, - MoveAreaCallbackProcPtr moveCB, - RemoveAreaCallbackProcPtr removeCB, - pointer privData -){ - FBManagerPtr offman; - FBAreaPtr area = NULL; - - offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - if((area = AllocateArea(offman, w, h, gran, moveCB, removeCB, privData))) - SendCallFreeBoxCallbacks(offman); - - return area; -} - - -static void -localFreeOffscreenArea(FBAreaPtr area) -{ - FBManagerPtr offman; - FBLinkPtr pLink, pLinkPrev = NULL; - RegionRec FreedRegion; - ScreenPtr pScreen; - - pScreen = area->pScreen; - offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - pLink = offman->UsedAreas; - if(!pLink) return; - - while(&(pLink->area) != area) { - pLinkPrev = pLink; - pLink = pLink->next; - if(!pLink) return; - } - - /* put the area back into the pool */ - RegionInit(&FreedRegion, &(pLink->area.box), 1); - RegionUnion(offman->FreeBoxes, offman->FreeBoxes, &FreedRegion); - RegionUninit(&FreedRegion); - - if(pLinkPrev) - pLinkPrev->next = pLink->next; - else offman->UsedAreas = pLink->next; - - free(pLink); - offman->NumUsedAreas--; - - SendCallFreeBoxCallbacks(offman); -} - - - -static Bool -localResizeOffscreenArea( - FBAreaPtr resize, - int w, int h -){ - FBManagerPtr offman; - ScreenPtr pScreen; - BoxRec OrigArea; - RegionRec FreedReg; - FBAreaPtr area = NULL; - FBLinkPtr pLink, newLink, pLinkPrev = NULL; - - pScreen = resize->pScreen; - offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - /* find this link */ - if(!(pLink = offman->UsedAreas)) - return FALSE; - - while(&(pLink->area) != resize) { - pLinkPrev = pLink; - pLink = pLink->next; - if(!pLink) return FALSE; - } - - OrigArea.x1 = resize->box.x1; - OrigArea.x2 = resize->box.x2; - OrigArea.y1 = resize->box.y1; - OrigArea.y2 = resize->box.y2; - - /* if it's smaller, this is easy */ - - if((w <= (resize->box.x2 - resize->box.x1)) && - (h <= (resize->box.y2 - resize->box.y1))) { - RegionRec NewReg; - - resize->box.x2 = resize->box.x1 + w; - resize->box.y2 = resize->box.y1 + h; - - if((resize->box.y2 == OrigArea.y2) && - (resize->box.x2 == OrigArea.x2)) - return TRUE; - - RegionInit(&FreedReg, &OrigArea, 1); - RegionInit(&NewReg, &(resize->box), 1); - RegionSubtract(&FreedReg, &FreedReg, &NewReg); - RegionUnion(offman->FreeBoxes, offman->FreeBoxes, &FreedReg); - RegionUninit(&FreedReg); - RegionUninit(&NewReg); - - SendCallFreeBoxCallbacks(offman); - - return TRUE; - } - - - /* otherwise we remove the old region */ - - RegionInit(&FreedReg, &OrigArea, 1); - RegionUnion(offman->FreeBoxes, offman->FreeBoxes, &FreedReg); - - /* remove the old link */ - if(pLinkPrev) - pLinkPrev->next = pLink->next; - else offman->UsedAreas = pLink->next; - - /* and try to add a new one */ - - if((area = AllocateArea(offman, w, h, resize->granularity, - resize->MoveAreaCallback, resize->RemoveAreaCallback, - resize->devPrivate.ptr))) { - - /* copy data over to our link and replace the new with old */ - memcpy(resize, area, sizeof(FBArea)); - - pLinkPrev = NULL; - newLink = offman->UsedAreas; - - while(&(newLink->area) != area) { - pLinkPrev = newLink; - newLink = newLink->next; - } - - if(pLinkPrev) - pLinkPrev->next = newLink->next; - else offman->UsedAreas = newLink->next; - - pLink->next = offman->UsedAreas; - offman->UsedAreas = pLink; - - free(newLink); - - /* AllocateArea added one but we really only exchanged one */ - offman->NumUsedAreas--; - } else { - /* reinstate the old region */ - RegionSubtract(offman->FreeBoxes, offman->FreeBoxes, &FreedReg); - RegionUninit(&FreedReg); - - pLink->next = offman->UsedAreas; - offman->UsedAreas = pLink; - return FALSE; - } - - - RegionUninit(&FreedReg); - - SendCallFreeBoxCallbacks(offman); - - return TRUE; -} - -static Bool -localQueryLargestOffscreenArea( - ScreenPtr pScreen, - int *width, int *height, - int granularity, - int preferences, - int severity -){ - FBManagerPtr offman; - RegionPtr newRegion = NULL; - BoxPtr pbox; - int nbox; - int x, w, h, area, oldArea; - - *width = *height = oldArea = 0; - - if(granularity <= 1) granularity = 0; - - if((preferences < 0) || (preferences > 3)) - return FALSE; - - offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - if(severity < 0) severity = 0; - if(severity > 2) severity = 2; - - switch(severity) { - case 2: - if(offman->NumUsedAreas) { - FBLinkPtr pLink; - RegionRec tmpRegion; - newRegion = RegionCreate(NULL, 1); - RegionCopy(newRegion, offman->InitialBoxes); - pLink = offman->UsedAreas; - - while(pLink) { - if(!pLink->area.RemoveAreaCallback) { - RegionInit(&tmpRegion, &(pLink->area.box), 1); - RegionSubtract(newRegion, newRegion, &tmpRegion); - RegionUninit(&tmpRegion); - } - pLink = pLink->next; - } - - nbox = RegionNumRects(newRegion); - pbox = RegionRects(newRegion); - break; - } - case 1: - if(offman->NumUsedAreas) { - FBLinkPtr pLink; - RegionRec tmpRegion; - newRegion = RegionCreate(NULL, 1); - RegionCopy(newRegion, offman->FreeBoxes); - pLink = offman->UsedAreas; - - while(pLink) { - if(pLink->area.RemoveAreaCallback) { - RegionInit(&tmpRegion, &(pLink->area.box), 1); - RegionAppend(newRegion, &tmpRegion); - RegionUninit(&tmpRegion); - } - pLink = pLink->next; - } - - nbox = RegionNumRects(newRegion); - pbox = RegionRects(newRegion); - break; - } - default: - nbox = RegionNumRects(offman->FreeBoxes); - pbox = RegionRects(offman->FreeBoxes); - break; - } - - while(nbox--) { - x = pbox->x1; - if (granularity > 1) - x = ((x + granularity - 1) / granularity) * granularity; - - w = pbox->x2 - x; - h = pbox->y2 - pbox->y1; - area = w * h; - - if(w > 0) { - Bool gotIt = FALSE; - switch(preferences) { - case FAVOR_AREA_THEN_WIDTH: - if((area > oldArea) || ((area == oldArea) && (w > *width))) - gotIt = TRUE; - break; - case FAVOR_AREA_THEN_HEIGHT: - if((area > oldArea) || ((area == oldArea) && (h > *height))) - gotIt = TRUE; - break; - case FAVOR_WIDTH_THEN_AREA: - if((w > *width) || ((w == *width) && (area > oldArea))) - gotIt = TRUE; - break; - case FAVOR_HEIGHT_THEN_AREA: - if((h > *height) || ((h == *height) && (area > oldArea))) - gotIt = TRUE; - break; - } - if(gotIt) { - *width = w; - *height = h; - oldArea = area; - } - } - pbox++; - } - - if(newRegion) - RegionDestroy(newRegion); - - return TRUE; -} - -static Bool -localPurgeUnlockedOffscreenAreas(ScreenPtr pScreen) -{ - FBManagerPtr offman; - FBLinkPtr pLink, tmp, pPrev = NULL; - RegionRec FreedRegion; - Bool anyUsed = FALSE; - - offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - pLink = offman->UsedAreas; - if(!pLink) return TRUE; - - while(pLink) { - if(pLink->area.RemoveAreaCallback) { - (*pLink->area.RemoveAreaCallback)(&pLink->area); - - RegionInit(&FreedRegion, &(pLink->area.box), 1); - RegionAppend(offman->FreeBoxes, &FreedRegion); - RegionUninit(&FreedRegion); - - if(pPrev) - pPrev->next = pLink->next; - else offman->UsedAreas = pLink->next; - - tmp = pLink; - pLink = pLink->next; - free(tmp); - offman->NumUsedAreas--; - anyUsed = TRUE; - } else { - pPrev = pLink; - pLink = pLink->next; - } - } - - if(anyUsed) { - RegionValidate(offman->FreeBoxes, &anyUsed); - SendCallFreeBoxCallbacks(offman); - } - - return TRUE; -} - -static void -LinearMoveCBWrapper(FBAreaPtr from, FBAreaPtr to) -{ - /* this will never get called */ -} - -static void -LinearRemoveCBWrapper(FBAreaPtr area) -{ - FBManagerPtr offman; - FBLinearLinkPtr pLink, pLinkPrev = NULL; - ScreenPtr pScreen = area->pScreen; - - offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - pLink = offman->LinearAreas; - if(!pLink) return; - - while(pLink->area != area) { - pLinkPrev = pLink; - pLink = pLink->next; - if(!pLink) return; - } - - /* give the user the callback it is expecting */ - (*pLink->linear.RemoveLinearCallback)(&(pLink->linear)); - - if(pLinkPrev) - pLinkPrev->next = pLink->next; - else offman->LinearAreas = pLink->next; - - free(pLink); -} - -static void -DumpDebug(FBLinearLinkPtr pLink) -{ -#ifdef DEBUG - if (!pLink) ErrorF("MMmm, PLINK IS NULL!\n"); - - while (pLink) { - ErrorF(" Offset:%08x, Size:%08x, %s,%s\n", - pLink->linear.offset, - pLink->linear.size, - pLink->free ? "Free" : "Used", - pLink->area ? "Area" : "Linear"); - - pLink = pLink->next; - } -#endif -} - -static FBLinearPtr -AllocateLinear( - FBManagerPtr offman, - int size, - int granularity, - pointer privData -){ - ScreenPtr pScreen = offman->pScreen; - FBLinearLinkPtr linear = NULL; - FBLinearLinkPtr newlink = NULL; - int offset, end; - - if(size <= 0) return NULL; - - if (!offman->LinearAreas) return NULL; - - linear = offman->LinearAreas; - while (linear) { - /* Make sure we get a free area that's not an XY fallback case */ - if (!linear->area && linear->free) { - offset = linear->linear.offset; - if (granularity > 1) - offset = ((offset + granularity - 1) / granularity) * granularity; - end = offset+size; - if (end <= (linear->linear.offset + linear->linear.size)) - break; - } - linear = linear->next; - } - if (!linear) - return NULL; - - /* break left */ - if (offset > linear->linear.offset) { - newlink = malloc(sizeof(FBLinearLink)); - if (!newlink) - return NULL; - newlink->area = NULL; - newlink->linear.offset = offset; - newlink->linear.size = linear->linear.size - (offset - linear->linear.offset); - newlink->free = 1; - newlink->next = linear->next; - linear->linear.size -= newlink->linear.size; - linear->next = newlink; - linear = newlink; - } - - /* break right */ - if (size < linear->linear.size) { - newlink = malloc(sizeof(FBLinearLink)); - if (!newlink) - return NULL; - newlink->area = NULL; - newlink->linear.offset = offset + size; - newlink->linear.size = linear->linear.size - size; - newlink->free = 1; - newlink->next = linear->next; - linear->linear.size = size; - linear->next = newlink; - } - - /* p = middle block */ - linear->linear.granularity = granularity; - linear->free = 0; - linear->linear.pScreen = pScreen; - linear->linear.MoveLinearCallback = NULL; - linear->linear.RemoveLinearCallback = NULL; - linear->linear.devPrivate.ptr = NULL; - - DumpDebug(offman->LinearAreas); - - return &(linear->linear); -} - -static FBLinearPtr -localAllocateOffscreenLinear( - ScreenPtr pScreen, - int length, - int gran, - MoveLinearCallbackProcPtr moveCB, - RemoveLinearCallbackProcPtr removeCB, - pointer privData -){ - FBManagerPtr offman; - FBLinearLinkPtr link; - FBAreaPtr area; - FBLinearPtr linear = NULL; - BoxPtr extents; - int w, h, pitch; - - offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - - /* Try to allocate from linear memory first...... */ - DebugF("ALLOCATING LINEAR\n"); - if ((linear = AllocateLinear(offman, length, gran, privData))) - return linear; - - DebugF("NOPE, ALLOCATING AREA\n"); - - if(!(link = malloc(sizeof(FBLinearLink)))) - return NULL; - - /* No linear available, so try and pinch some from the XY areas */ - extents = RegionExtents(offman->InitialBoxes); - pitch = extents->x2 - extents->x1; - - if (gran > 1) { - if (gran > pitch) { - /* we can't match the specified alignment with XY allocations */ - free(link); - return NULL; - } - - if (pitch % gran) { - /* pitch and granularity aren't a perfect match, let's allocate - * a bit more so we can align later on - */ - length += gran - 1; - } - } - - if(length < pitch) { /* special case */ - w = length; - h = 1; - } else { - w = pitch; - h = (length + pitch - 1) / pitch; - } - - if((area = localAllocateOffscreenArea(pScreen, w, h, gran, - moveCB ? LinearMoveCBWrapper : NULL, - removeCB ? LinearRemoveCBWrapper : NULL, - privData))) - { - link->area = area; - link->free = 0; - link->next = offman->LinearAreas; - offman->LinearAreas = link; - linear = &(link->linear); - linear->pScreen = pScreen; - linear->size = h * w; - linear->offset = (pitch * area->box.y1) + area->box.x1; - if (gran > 1) - linear->offset = ((linear->offset + gran - 1) / gran) * gran; - linear->granularity = gran; - linear->MoveLinearCallback = moveCB; - linear->RemoveLinearCallback = removeCB; - linear->devPrivate.ptr = privData; - } else - free(link); - - DumpDebug(offman->LinearAreas); - - return linear; -} - - -static void -localFreeOffscreenLinear(FBLinearPtr linear) -{ - FBManagerPtr offman; - FBLinearLinkPtr pLink, pLinkPrev = NULL; - ScreenPtr pScreen = linear->pScreen; - - offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - pLink = offman->LinearAreas; - if(!pLink) return; - - while(&(pLink->linear) != linear) { - pLinkPrev = pLink; - pLink = pLink->next; - if(!pLink) return; - } - - if(pLink->area) { /* really an XY area */ - DebugF("FREEING AREA\n"); - localFreeOffscreenArea(pLink->area); - if(pLinkPrev) - pLinkPrev->next = pLink->next; - else offman->LinearAreas = pLink->next; - free(pLink); - DumpDebug(offman->LinearAreas); - return; - } - - pLink->free = 1; - - if (pLink->next && pLink->next->free) { - FBLinearLinkPtr p = pLink->next; - pLink->linear.size += p->linear.size; - pLink->next = p->next; - free(p); - } - - if(pLinkPrev) { - if (pLinkPrev->next && pLinkPrev->next->free && !pLinkPrev->area) { - FBLinearLinkPtr p = pLinkPrev->next; - pLinkPrev->linear.size += p->linear.size; - pLinkPrev->next = p->next; - free(p); - } - } - - DebugF("FREEING LINEAR\n"); - DumpDebug(offman->LinearAreas); -} - - -static Bool -localResizeOffscreenLinear(FBLinearPtr resize, int length) -{ - FBManagerPtr offman; - FBLinearLinkPtr pLink; - ScreenPtr pScreen = resize->pScreen; - - offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - pLink = offman->LinearAreas; - if(!pLink) return FALSE; - - while(&(pLink->linear) != resize) { - pLink = pLink->next; - if(!pLink) return FALSE; - } - - /* This could actually be alot smarter and try to move allocations - from XY to linear when available. For now if it was XY, we keep - it XY */ - - if(pLink->area) { /* really an XY area */ - BoxPtr extents; - int pitch, w, h; - - extents = RegionExtents(offman->InitialBoxes); - pitch = extents->x2 - extents->x1; - - if(length < pitch) { /* special case */ - w = length; - h = 1; - } else { - w = pitch; - h = (length + pitch - 1) / pitch; - } - - if(localResizeOffscreenArea(pLink->area, w, h)) { - resize->size = h * w; - resize->offset = (pitch * pLink->area->box.y1) + pLink->area->box.x1; - return TRUE; - } - } else { - /* TODO!!!! resize the linear area */ - } - - return FALSE; -} - - -static Bool -localQueryLargestOffscreenLinear( - ScreenPtr pScreen, - int *size, - int gran, - int priority -) -{ - FBManagerPtr offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - FBLinearLinkPtr pLink; - FBLinearLinkPtr pLinkRet; - - *size = 0; - - pLink = offman->LinearAreas; - - if (pLink && !pLink->area) { - pLinkRet = pLink; - while (pLink) { - if (pLink->free) { - if (pLink->linear.size > pLinkRet->linear.size) - pLinkRet = pLink; - } - pLink = pLink->next; - } - - if (pLinkRet->free) { - *size = pLinkRet->linear.size; - return TRUE; - } - } else { - int w, h; - - if(localQueryLargestOffscreenArea(pScreen, &w, &h, gran, - FAVOR_WIDTH_THEN_AREA, priority)) - { - FBManagerPtr offman; - BoxPtr extents; - - offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - extents = RegionExtents(offman->InitialBoxes); - if((extents->x2 - extents->x1) == w) - *size = w * h; - return TRUE; - } - } - - return FALSE; -} - - - -static FBManagerFuncs xf86FBManFuncs = { - localAllocateOffscreenArea, - localFreeOffscreenArea, - localResizeOffscreenArea, - localQueryLargestOffscreenArea, - localRegisterFreeBoxCallback, - localAllocateOffscreenLinear, - localFreeOffscreenLinear, - localResizeOffscreenLinear, - localQueryLargestOffscreenLinear, - localPurgeUnlockedOffscreenAreas - }; - - -static Bool -xf86FBCloseScreen (int i, ScreenPtr pScreen) -{ - FBLinkPtr pLink, tmp; - FBLinearLinkPtr pLinearLink, tmp2; - FBManagerPtr offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - - pScreen->CloseScreen = offman->CloseScreen; - - pLink = offman->UsedAreas; - while(pLink) { - tmp = pLink; - pLink = pLink->next; - free(tmp); - } - - pLinearLink = offman->LinearAreas; - while(pLinearLink) { - tmp2 = pLinearLink; - pLinearLink = pLinearLink->next; - free(tmp2); - } - - RegionDestroy(offman->InitialBoxes); - RegionDestroy(offman->FreeBoxes); - - free(offman->FreeBoxesUpdateCallback); - free(offman->devPrivates); - free(offman); - dixSetPrivate(&pScreen->devPrivates, xf86FBScreenKey, NULL); - - return (*pScreen->CloseScreen) (i, pScreen); -} - -Bool -xf86InitFBManager( - ScreenPtr pScreen, - BoxPtr FullBox -){ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - RegionRec ScreenRegion; - RegionRec FullRegion; - BoxRec ScreenBox; - Bool ret; - - ScreenBox.x1 = 0; - ScreenBox.y1 = 0; - ScreenBox.x2 = pScrn->virtualX; - ScreenBox.y2 = pScrn->virtualY; - - if((FullBox->x1 > ScreenBox.x1) || (FullBox->y1 > ScreenBox.y1) || - (FullBox->x2 < ScreenBox.x2) || (FullBox->y2 < ScreenBox.y2)) { - return FALSE; - } - - if (FullBox->y2 < FullBox->y1) return FALSE; - if (FullBox->x2 < FullBox->x1) return FALSE; - - RegionInit(&ScreenRegion, &ScreenBox, 1); - RegionInit(&FullRegion, FullBox, 1); - - RegionSubtract(&FullRegion, &FullRegion, &ScreenRegion); - - ret = xf86InitFBManagerRegion(pScreen, &FullRegion); - - RegionUninit(&ScreenRegion); - RegionUninit(&FullRegion); - - return ret; -} - -Bool -xf86InitFBManagerArea( - ScreenPtr pScreen, - int PixelArea, - int Verbosity -) -{ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - xRectangle Rect[3]; - RegionPtr pRegion, pScreenRegion; - int nRect; - Bool ret = FALSE; - - if (PixelArea < (pScrn->displayWidth * pScrn->virtualY)) - return FALSE; - - Rect[0].x = Rect[0].y = 0; - Rect[0].width = pScrn->displayWidth; - Rect[0].height = PixelArea / pScrn->displayWidth; - nRect = 1; - - /* Add a possible partial scanline */ - if ((Rect[1].height = Rect[1].width = PixelArea % pScrn->displayWidth)) { - Rect[1].x = 0; - Rect[1].y = Rect[0].height; - Rect[1].height = 1; - nRect++; - } - - /* Factor out virtual resolution */ - pRegion = RegionFromRects(nRect, Rect, 0); - if (pRegion) { - if (!RegionNar(pRegion)) { - Rect[2].x = Rect[2].y = 0; - Rect[2].width = pScrn->virtualX; - Rect[2].height = pScrn->virtualY; - - pScreenRegion = RegionFromRects(1, &Rect[2], 0); - if (pScreenRegion) { - if (!RegionNar(pScreenRegion)) { - RegionSubtract(pRegion, pRegion, pScreenRegion); - - ret = xf86InitFBManagerRegion(pScreen, pRegion); - - if (ret && xf86GetVerbosity() >= Verbosity) { - int scrnIndex = pScrn->scrnIndex; - - xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity, - "Largest offscreen areas (with overlaps):\n"); - - if (Rect[2].width < Rect[0].width) { - xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity, - "\t%d x %d rectangle at %d,0\n", - Rect[0].width - Rect[2].width, - Rect[0].height, - Rect[2].width); - } - if (Rect[2].width < Rect[1].width) { - xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity, - "\t%d x %d rectangle at %d,0\n", - Rect[1].width - Rect[2].width, - Rect[0].height + Rect[1].height, - Rect[2].width); - } - if (Rect[2].height < Rect[0].height) { - xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity, - "\t%d x %d rectangle at 0,%d\n", - Rect[0].width, - Rect[0].height - Rect[2].height, - Rect[2].height); - } - if (Rect[1].height) { - xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity, - "\t%d x %d rectangle at 0,%d\n", - Rect[1].width, - Rect[0].height - Rect[2].height + - Rect[1].height, - Rect[2].height); - } - } - } - - RegionDestroy(pScreenRegion); - } - } - - RegionDestroy(pRegion); - } - - return ret; -} - -Bool -xf86InitFBManagerRegion( - ScreenPtr pScreen, - RegionPtr FullRegion -){ - FBManagerPtr offman; - - if(RegionNil(FullRegion)) - return FALSE; - - if (!dixRegisterPrivateKey(&xf86FBScreenKeyRec, PRIVATE_SCREEN, 0)) - return FALSE; - - if(!xf86RegisterOffscreenManager(pScreen, &xf86FBManFuncs)) - return FALSE; - - offman = malloc(sizeof(FBManager)); - if(!offman) return FALSE; - - dixSetPrivate(&pScreen->devPrivates, xf86FBScreenKey, offman); - - offman->CloseScreen = pScreen->CloseScreen; - pScreen->CloseScreen = xf86FBCloseScreen; - - offman->InitialBoxes = RegionCreate(NULL, 1); - offman->FreeBoxes = RegionCreate(NULL, 1); - - RegionCopy(offman->InitialBoxes, FullRegion); - RegionCopy(offman->FreeBoxes, FullRegion); - - offman->pScreen = pScreen; - offman->UsedAreas = NULL; - offman->LinearAreas = NULL; - offman->NumUsedAreas = 0; - offman->NumCallbacks = 0; - offman->FreeBoxesUpdateCallback = NULL; - offman->devPrivates = NULL; - - return TRUE; -} - -Bool -xf86InitFBManagerLinear( - ScreenPtr pScreen, - int offset, - int size -){ - FBManagerPtr offman; - FBLinearLinkPtr link; - FBLinearPtr linear; - - if (size <= 0) - return FALSE; - - /* we expect people to have called the Area setup first for pixmap cache */ - if (!dixLookupPrivate(&pScreen->devPrivates, xf86FBScreenKey)) - return FALSE; - - offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - offman->LinearAreas = malloc(sizeof(FBLinearLink)); - if (!offman->LinearAreas) - return FALSE; - - link = offman->LinearAreas; - link->area = NULL; - link->next = NULL; - link->free = 1; - linear = &(link->linear); - linear->pScreen = pScreen; - linear->size = size; - linear->offset = offset; - linear->granularity = 0; - linear->MoveLinearCallback = NULL; - linear->RemoveLinearCallback = NULL; - linear->devPrivate.ptr = NULL; - - return TRUE; -} - - -/* This is an implementation specific function and should - disappear after the next release. People should use the - real linear functions instead */ - -FBAreaPtr -xf86AllocateLinearOffscreenArea ( - ScreenPtr pScreen, - int length, - int gran, - MoveAreaCallbackProcPtr moveCB, - RemoveAreaCallbackProcPtr removeCB, - pointer privData -){ - FBManagerFuncsPtr funcs; - FBManagerPtr offman; - BoxPtr extents; - int w, h; - - if(xf86FBManagerKey == NULL) - return NULL; - if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBManagerKey))) - return NULL; - - offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - extents = RegionExtents(offman->InitialBoxes); - w = extents->x2 - extents->x1; - - if (gran > 1) { - if (gran > w) - return NULL; - - if (w % gran) - length += gran - 1; - } - - if(length <= w) { /* special case */ - h = 1; - w = length; - } else { - h = (length + w - 1) / w; - } - - return (*funcs->AllocateOffscreenArea)( - pScreen, w, h, gran, moveCB, removeCB, privData); -} + +/* + * Copyright (c) 1998-2001 by The XFree86 Project, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + +#ifdef HAVE_XORG_CONFIG_H +#include +#endif + +#include "misc.h" +#include "xf86.h" + +#include +#include "scrnintstr.h" +#include "regionstr.h" +#include "xf86fbman.h" + +/* +#define DEBUG +*/ + +static DevPrivateKeyRec xf86FBManagerKeyRec; +static DevPrivateKey xf86FBManagerKey; + +Bool +xf86RegisterOffscreenManager(ScreenPtr pScreen, FBManagerFuncsPtr funcs) +{ + + xf86FBManagerKey = &xf86FBManagerKeyRec; + + if (!dixRegisterPrivateKey(&xf86FBManagerKeyRec, PRIVATE_SCREEN, 0)) + return FALSE; + + dixSetPrivate(&pScreen->devPrivates, xf86FBManagerKey, funcs); + + return TRUE; +} + +Bool +xf86FBManagerRunning(ScreenPtr pScreen) +{ + if (xf86FBManagerKey == NULL) + return FALSE; + + if (!dixLookupPrivate(&pScreen->devPrivates, xf86FBManagerKey)) + return FALSE; + + return TRUE; +} + +Bool +xf86RegisterFreeBoxCallback(ScreenPtr pScreen, + FreeBoxCallbackProcPtr FreeBoxCallback, + pointer devPriv) +{ + FBManagerFuncsPtr funcs; + + if (xf86FBManagerKey == NULL) + return FALSE; + if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates, + xf86FBManagerKey))) + return FALSE; + + return (*funcs->RegisterFreeBoxCallback) (pScreen, FreeBoxCallback, + devPriv); +} + +FBAreaPtr +xf86AllocateOffscreenArea(ScreenPtr pScreen, + int w, int h, + int gran, + MoveAreaCallbackProcPtr moveCB, + RemoveAreaCallbackProcPtr removeCB, pointer privData) +{ + FBManagerFuncsPtr funcs; + + if (xf86FBManagerKey == NULL) + return NULL; + if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates, + xf86FBManagerKey))) + return NULL; + + return (*funcs->AllocateOffscreenArea) (pScreen, w, h, gran, moveCB, + removeCB, privData); +} + +FBLinearPtr +xf86AllocateOffscreenLinear(ScreenPtr pScreen, + int length, + int gran, + MoveLinearCallbackProcPtr moveCB, + RemoveLinearCallbackProcPtr removeCB, + pointer privData) +{ + FBManagerFuncsPtr funcs; + + if (xf86FBManagerKey == NULL) + return NULL; + if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates, + xf86FBManagerKey))) + return NULL; + + return (*funcs->AllocateOffscreenLinear) (pScreen, length, gran, moveCB, + removeCB, privData); +} + +void +xf86FreeOffscreenArea(FBAreaPtr area) +{ + FBManagerFuncsPtr funcs; + + if (!area) + return; + + if (xf86FBManagerKey == NULL) + return; + if (! + (funcs = + (FBManagerFuncsPtr) dixLookupPrivate(&area->pScreen->devPrivates, + xf86FBManagerKey))) + return; + + (*funcs->FreeOffscreenArea) (area); + + return; +} + +void +xf86FreeOffscreenLinear(FBLinearPtr linear) +{ + FBManagerFuncsPtr funcs; + + if (!linear) + return; + + if (xf86FBManagerKey == NULL) + return; + if (! + (funcs = + (FBManagerFuncsPtr) dixLookupPrivate(&linear->pScreen->devPrivates, + xf86FBManagerKey))) + return; + + (*funcs->FreeOffscreenLinear) (linear); + + return; +} + +Bool +xf86ResizeOffscreenArea(FBAreaPtr resize, int w, int h) +{ + FBManagerFuncsPtr funcs; + + if (!resize) + return FALSE; + + if (xf86FBManagerKey == NULL) + return FALSE; + if (! + (funcs = + (FBManagerFuncsPtr) dixLookupPrivate(&resize->pScreen->devPrivates, + xf86FBManagerKey))) + return FALSE; + + return (*funcs->ResizeOffscreenArea) (resize, w, h); +} + +Bool +xf86ResizeOffscreenLinear(FBLinearPtr resize, int size) +{ + FBManagerFuncsPtr funcs; + + if (!resize) + return FALSE; + + if (xf86FBManagerKey == NULL) + return FALSE; + if (! + (funcs = + (FBManagerFuncsPtr) dixLookupPrivate(&resize->pScreen->devPrivates, + xf86FBManagerKey))) + return FALSE; + + return (*funcs->ResizeOffscreenLinear) (resize, size); +} + +Bool +xf86QueryLargestOffscreenArea(ScreenPtr pScreen, + int *w, int *h, + int gran, int preferences, int severity) +{ + FBManagerFuncsPtr funcs; + + *w = 0; + *h = 0; + + if (xf86FBManagerKey == NULL) + return FALSE; + if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates, + xf86FBManagerKey))) + return FALSE; + + return (*funcs->QueryLargestOffscreenArea) (pScreen, w, h, gran, + preferences, severity); +} + +Bool +xf86QueryLargestOffscreenLinear(ScreenPtr pScreen, + int *size, int gran, int severity) +{ + FBManagerFuncsPtr funcs; + + *size = 0; + + if (xf86FBManagerKey == NULL) + return FALSE; + if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates, + xf86FBManagerKey))) + return FALSE; + + return (*funcs->QueryLargestOffscreenLinear) (pScreen, size, gran, + severity); +} + +Bool +xf86PurgeUnlockedOffscreenAreas(ScreenPtr pScreen) +{ + FBManagerFuncsPtr funcs; + + if (xf86FBManagerKey == NULL) + return FALSE; + if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates, + xf86FBManagerKey))) + return FALSE; + + return (*funcs->PurgeOffscreenAreas) (pScreen); +} + +/************************************************************\ + + Below is a specific implementation of an offscreen manager. + +\************************************************************/ + +static DevPrivateKeyRec xf86FBScreenKeyRec; + +#define xf86FBScreenKey (&xf86FBScreenKeyRec) + +typedef struct _FBLink { + FBArea area; + struct _FBLink *next; +} FBLink, *FBLinkPtr; + +typedef struct _FBLinearLink { + FBLinear linear; + int free; /* need to add free here as FBLinear is publicly accessible */ + FBAreaPtr area; /* only used if allocation came from XY area */ + struct _FBLinearLink *next; +} FBLinearLink, *FBLinearLinkPtr; + +typedef struct { + ScreenPtr pScreen; + RegionPtr InitialBoxes; + RegionPtr FreeBoxes; + FBLinkPtr UsedAreas; + int NumUsedAreas; + FBLinearLinkPtr LinearAreas; + CloseScreenProcPtr CloseScreen; + int NumCallbacks; + FreeBoxCallbackProcPtr *FreeBoxesUpdateCallback; + DevUnion *devPrivates; +} FBManager, *FBManagerPtr; + +static void +SendCallFreeBoxCallbacks(FBManagerPtr offman) +{ + int i = offman->NumCallbacks; + + while (i--) { + (*offman->FreeBoxesUpdateCallback[i]) (offman->pScreen, + offman->FreeBoxes, + offman->devPrivates[i].ptr); + } +} + +static Bool +localRegisterFreeBoxCallback(ScreenPtr pScreen, + FreeBoxCallbackProcPtr FreeBoxCallback, + pointer devPriv) +{ + FBManagerPtr offman; + FreeBoxCallbackProcPtr *newCallbacks; + DevUnion *newPrivates; + + offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + newCallbacks = realloc(offman->FreeBoxesUpdateCallback, + sizeof(FreeBoxCallbackProcPtr) * + (offman->NumCallbacks + 1)); + + newPrivates = realloc(offman->devPrivates, + sizeof(DevUnion) * (offman->NumCallbacks + 1)); + + if (!newCallbacks || !newPrivates) + return FALSE; + + offman->FreeBoxesUpdateCallback = newCallbacks; + offman->devPrivates = newPrivates; + + offman->FreeBoxesUpdateCallback[offman->NumCallbacks] = FreeBoxCallback; + offman->devPrivates[offman->NumCallbacks].ptr = devPriv; + offman->NumCallbacks++; + + SendCallFreeBoxCallbacks(offman); + + return TRUE; +} + +static FBAreaPtr +AllocateArea(FBManagerPtr offman, + int w, int h, + int granularity, + MoveAreaCallbackProcPtr moveCB, + RemoveAreaCallbackProcPtr removeCB, pointer privData) +{ + ScreenPtr pScreen = offman->pScreen; + FBLinkPtr link = NULL; + FBAreaPtr area = NULL; + RegionRec NewReg; + int i, x = 0, num; + BoxPtr boxp; + + if (granularity <= 1) + granularity = 0; + + boxp = RegionRects(offman->FreeBoxes); + num = RegionNumRects(offman->FreeBoxes); + + /* look through the free boxes */ + for (i = 0; i < num; i++, boxp++) { + x = boxp->x1; + if (granularity > 1) + x = ((x + granularity - 1) / granularity) * granularity; + + if (((boxp->y2 - boxp->y1) < h) || ((boxp->x2 - x) < w)) + continue; + + link = malloc(sizeof(FBLink)); + if (!link) + return NULL; + + area = &(link->area); + link->next = offman->UsedAreas; + offman->UsedAreas = link; + offman->NumUsedAreas++; + break; + } + + /* try to boot a removeable one out if we are not expendable ourselves */ + if (!area && !removeCB) { + link = offman->UsedAreas; + + while (link) { + if (!link->area.RemoveAreaCallback) { + link = link->next; + continue; + } + + boxp = &(link->area.box); + x = boxp->x1; + if (granularity > 1) + x = ((x + granularity - 1) / granularity) * granularity; + + if (((boxp->y2 - boxp->y1) < h) || ((boxp->x2 - x) < w)) { + link = link->next; + continue; + } + + /* bye, bye */ + (*link->area.RemoveAreaCallback) (&link->area); + RegionInit(&NewReg, &(link->area.box), 1); + RegionUnion(offman->FreeBoxes, offman->FreeBoxes, &NewReg); + RegionUninit(&NewReg); + + area = &(link->area); + break; + } + } + + if (area) { + area->pScreen = pScreen; + area->granularity = granularity; + area->box.x1 = x; + area->box.x2 = x + w; + area->box.y1 = boxp->y1; + area->box.y2 = boxp->y1 + h; + area->MoveAreaCallback = moveCB; + area->RemoveAreaCallback = removeCB; + area->devPrivate.ptr = privData; + + RegionInit(&NewReg, &(area->box), 1); + RegionSubtract(offman->FreeBoxes, offman->FreeBoxes, &NewReg); + RegionUninit(&NewReg); + } + + return area; +} + +static FBAreaPtr +localAllocateOffscreenArea(ScreenPtr pScreen, + int w, int h, + int gran, + MoveAreaCallbackProcPtr moveCB, + RemoveAreaCallbackProcPtr removeCB, pointer privData) +{ + FBManagerPtr offman; + FBAreaPtr area = NULL; + + offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + if ((area = AllocateArea(offman, w, h, gran, moveCB, removeCB, privData))) + SendCallFreeBoxCallbacks(offman); + + return area; +} + +static void +localFreeOffscreenArea(FBAreaPtr area) +{ + FBManagerPtr offman; + FBLinkPtr pLink, pLinkPrev = NULL; + RegionRec FreedRegion; + ScreenPtr pScreen; + + pScreen = area->pScreen; + offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + pLink = offman->UsedAreas; + if (!pLink) + return; + + while (&(pLink->area) != area) { + pLinkPrev = pLink; + pLink = pLink->next; + if (!pLink) + return; + } + + /* put the area back into the pool */ + RegionInit(&FreedRegion, &(pLink->area.box), 1); + RegionUnion(offman->FreeBoxes, offman->FreeBoxes, &FreedRegion); + RegionUninit(&FreedRegion); + + if (pLinkPrev) + pLinkPrev->next = pLink->next; + else + offman->UsedAreas = pLink->next; + + free(pLink); + offman->NumUsedAreas--; + + SendCallFreeBoxCallbacks(offman); +} + +static Bool +localResizeOffscreenArea(FBAreaPtr resize, int w, int h) +{ + FBManagerPtr offman; + ScreenPtr pScreen; + BoxRec OrigArea; + RegionRec FreedReg; + FBAreaPtr area = NULL; + FBLinkPtr pLink, newLink, pLinkPrev = NULL; + + pScreen = resize->pScreen; + offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + /* find this link */ + if (!(pLink = offman->UsedAreas)) + return FALSE; + + while (&(pLink->area) != resize) { + pLinkPrev = pLink; + pLink = pLink->next; + if (!pLink) + return FALSE; + } + + OrigArea.x1 = resize->box.x1; + OrigArea.x2 = resize->box.x2; + OrigArea.y1 = resize->box.y1; + OrigArea.y2 = resize->box.y2; + + /* if it's smaller, this is easy */ + + if ((w <= (resize->box.x2 - resize->box.x1)) && + (h <= (resize->box.y2 - resize->box.y1))) { + RegionRec NewReg; + + resize->box.x2 = resize->box.x1 + w; + resize->box.y2 = resize->box.y1 + h; + + if ((resize->box.y2 == OrigArea.y2) && (resize->box.x2 == OrigArea.x2)) + return TRUE; + + RegionInit(&FreedReg, &OrigArea, 1); + RegionInit(&NewReg, &(resize->box), 1); + RegionSubtract(&FreedReg, &FreedReg, &NewReg); + RegionUnion(offman->FreeBoxes, offman->FreeBoxes, &FreedReg); + RegionUninit(&FreedReg); + RegionUninit(&NewReg); + + SendCallFreeBoxCallbacks(offman); + + return TRUE; + } + + /* otherwise we remove the old region */ + + RegionInit(&FreedReg, &OrigArea, 1); + RegionUnion(offman->FreeBoxes, offman->FreeBoxes, &FreedReg); + + /* remove the old link */ + if (pLinkPrev) + pLinkPrev->next = pLink->next; + else + offman->UsedAreas = pLink->next; + + /* and try to add a new one */ + + if ((area = AllocateArea(offman, w, h, resize->granularity, + resize->MoveAreaCallback, + resize->RemoveAreaCallback, + resize->devPrivate.ptr))) { + + /* copy data over to our link and replace the new with old */ + memcpy(resize, area, sizeof(FBArea)); + + pLinkPrev = NULL; + newLink = offman->UsedAreas; + + while (&(newLink->area) != area) { + pLinkPrev = newLink; + newLink = newLink->next; + } + + if (pLinkPrev) + pLinkPrev->next = newLink->next; + else + offman->UsedAreas = newLink->next; + + pLink->next = offman->UsedAreas; + offman->UsedAreas = pLink; + + free(newLink); + + /* AllocateArea added one but we really only exchanged one */ + offman->NumUsedAreas--; + } + else { + /* reinstate the old region */ + RegionSubtract(offman->FreeBoxes, offman->FreeBoxes, &FreedReg); + RegionUninit(&FreedReg); + + pLink->next = offman->UsedAreas; + offman->UsedAreas = pLink; + return FALSE; + } + + RegionUninit(&FreedReg); + + SendCallFreeBoxCallbacks(offman); + + return TRUE; +} + +static Bool +localQueryLargestOffscreenArea(ScreenPtr pScreen, + int *width, int *height, + int granularity, int preferences, int severity) +{ + FBManagerPtr offman; + RegionPtr newRegion = NULL; + BoxPtr pbox; + int nbox; + int x, w, h, area, oldArea; + + *width = *height = oldArea = 0; + + if (granularity <= 1) + granularity = 0; + + if ((preferences < 0) || (preferences > 3)) + return FALSE; + + offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + if (severity < 0) + severity = 0; + if (severity > 2) + severity = 2; + + switch (severity) { + case 2: + if (offman->NumUsedAreas) { + FBLinkPtr pLink; + RegionRec tmpRegion; + + newRegion = RegionCreate(NULL, 1); + RegionCopy(newRegion, offman->InitialBoxes); + pLink = offman->UsedAreas; + + while (pLink) { + if (!pLink->area.RemoveAreaCallback) { + RegionInit(&tmpRegion, &(pLink->area.box), 1); + RegionSubtract(newRegion, newRegion, &tmpRegion); + RegionUninit(&tmpRegion); + } + pLink = pLink->next; + } + + nbox = RegionNumRects(newRegion); + pbox = RegionRects(newRegion); + break; + } + case 1: + if (offman->NumUsedAreas) { + FBLinkPtr pLink; + RegionRec tmpRegion; + + newRegion = RegionCreate(NULL, 1); + RegionCopy(newRegion, offman->FreeBoxes); + pLink = offman->UsedAreas; + + while (pLink) { + if (pLink->area.RemoveAreaCallback) { + RegionInit(&tmpRegion, &(pLink->area.box), 1); + RegionAppend(newRegion, &tmpRegion); + RegionUninit(&tmpRegion); + } + pLink = pLink->next; + } + + nbox = RegionNumRects(newRegion); + pbox = RegionRects(newRegion); + break; + } + default: + nbox = RegionNumRects(offman->FreeBoxes); + pbox = RegionRects(offman->FreeBoxes); + break; + } + + while (nbox--) { + x = pbox->x1; + if (granularity > 1) + x = ((x + granularity - 1) / granularity) * granularity; + + w = pbox->x2 - x; + h = pbox->y2 - pbox->y1; + area = w * h; + + if (w > 0) { + Bool gotIt = FALSE; + + switch (preferences) { + case FAVOR_AREA_THEN_WIDTH: + if ((area > oldArea) || ((area == oldArea) && (w > *width))) + gotIt = TRUE; + break; + case FAVOR_AREA_THEN_HEIGHT: + if ((area > oldArea) || ((area == oldArea) && (h > *height))) + gotIt = TRUE; + break; + case FAVOR_WIDTH_THEN_AREA: + if ((w > *width) || ((w == *width) && (area > oldArea))) + gotIt = TRUE; + break; + case FAVOR_HEIGHT_THEN_AREA: + if ((h > *height) || ((h == *height) && (area > oldArea))) + gotIt = TRUE; + break; + } + if (gotIt) { + *width = w; + *height = h; + oldArea = area; + } + } + pbox++; + } + + if (newRegion) + RegionDestroy(newRegion); + + return TRUE; +} + +static Bool +localPurgeUnlockedOffscreenAreas(ScreenPtr pScreen) +{ + FBManagerPtr offman; + FBLinkPtr pLink, tmp, pPrev = NULL; + RegionRec FreedRegion; + Bool anyUsed = FALSE; + + offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + pLink = offman->UsedAreas; + if (!pLink) + return TRUE; + + while (pLink) { + if (pLink->area.RemoveAreaCallback) { + (*pLink->area.RemoveAreaCallback) (&pLink->area); + + RegionInit(&FreedRegion, &(pLink->area.box), 1); + RegionAppend(offman->FreeBoxes, &FreedRegion); + RegionUninit(&FreedRegion); + + if (pPrev) + pPrev->next = pLink->next; + else + offman->UsedAreas = pLink->next; + + tmp = pLink; + pLink = pLink->next; + free(tmp); + offman->NumUsedAreas--; + anyUsed = TRUE; + } + else { + pPrev = pLink; + pLink = pLink->next; + } + } + + if (anyUsed) { + RegionValidate(offman->FreeBoxes, &anyUsed); + SendCallFreeBoxCallbacks(offman); + } + + return TRUE; +} + +static void +LinearMoveCBWrapper(FBAreaPtr from, FBAreaPtr to) +{ + /* this will never get called */ +} + +static void +LinearRemoveCBWrapper(FBAreaPtr area) +{ + FBManagerPtr offman; + FBLinearLinkPtr pLink, pLinkPrev = NULL; + ScreenPtr pScreen = area->pScreen; + + offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + pLink = offman->LinearAreas; + if (!pLink) + return; + + while (pLink->area != area) { + pLinkPrev = pLink; + pLink = pLink->next; + if (!pLink) + return; + } + + /* give the user the callback it is expecting */ + (*pLink->linear.RemoveLinearCallback) (&(pLink->linear)); + + if (pLinkPrev) + pLinkPrev->next = pLink->next; + else + offman->LinearAreas = pLink->next; + + free(pLink); +} + +static void +DumpDebug(FBLinearLinkPtr pLink) +{ +#ifdef DEBUG + if (!pLink) + ErrorF("MMmm, PLINK IS NULL!\n"); + + while (pLink) { + ErrorF(" Offset:%08x, Size:%08x, %s,%s\n", + pLink->linear.offset, + pLink->linear.size, + pLink->free ? "Free" : "Used", pLink->area ? "Area" : "Linear"); + + pLink = pLink->next; + } +#endif +} + +static FBLinearPtr +AllocateLinear(FBManagerPtr offman, int size, int granularity, pointer privData) +{ + ScreenPtr pScreen = offman->pScreen; + FBLinearLinkPtr linear = NULL; + FBLinearLinkPtr newlink = NULL; + int offset, end; + + if (size <= 0) + return NULL; + + if (!offman->LinearAreas) + return NULL; + + linear = offman->LinearAreas; + while (linear) { + /* Make sure we get a free area that's not an XY fallback case */ + if (!linear->area && linear->free) { + offset = linear->linear.offset; + if (granularity > 1) + offset = + ((offset + granularity - 1) / granularity) * granularity; + end = offset + size; + if (end <= (linear->linear.offset + linear->linear.size)) + break; + } + linear = linear->next; + } + if (!linear) + return NULL; + + /* break left */ + if (offset > linear->linear.offset) { + newlink = malloc(sizeof(FBLinearLink)); + if (!newlink) + return NULL; + newlink->area = NULL; + newlink->linear.offset = offset; + newlink->linear.size = + linear->linear.size - (offset - linear->linear.offset); + newlink->free = 1; + newlink->next = linear->next; + linear->linear.size -= newlink->linear.size; + linear->next = newlink; + linear = newlink; + } + + /* break right */ + if (size < linear->linear.size) { + newlink = malloc(sizeof(FBLinearLink)); + if (!newlink) + return NULL; + newlink->area = NULL; + newlink->linear.offset = offset + size; + newlink->linear.size = linear->linear.size - size; + newlink->free = 1; + newlink->next = linear->next; + linear->linear.size = size; + linear->next = newlink; + } + + /* p = middle block */ + linear->linear.granularity = granularity; + linear->free = 0; + linear->linear.pScreen = pScreen; + linear->linear.MoveLinearCallback = NULL; + linear->linear.RemoveLinearCallback = NULL; + linear->linear.devPrivate.ptr = NULL; + + DumpDebug(offman->LinearAreas); + + return &(linear->linear); +} + +static FBLinearPtr +localAllocateOffscreenLinear(ScreenPtr pScreen, + int length, + int gran, + MoveLinearCallbackProcPtr moveCB, + RemoveLinearCallbackProcPtr removeCB, + pointer privData) +{ + FBManagerPtr offman; + FBLinearLinkPtr link; + FBAreaPtr area; + FBLinearPtr linear = NULL; + BoxPtr extents; + int w, h, pitch; + + offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + + /* Try to allocate from linear memory first...... */ + DebugF("ALLOCATING LINEAR\n"); + if ((linear = AllocateLinear(offman, length, gran, privData))) + return linear; + + DebugF("NOPE, ALLOCATING AREA\n"); + + if (!(link = malloc(sizeof(FBLinearLink)))) + return NULL; + + /* No linear available, so try and pinch some from the XY areas */ + extents = RegionExtents(offman->InitialBoxes); + pitch = extents->x2 - extents->x1; + + if (gran > 1) { + if (gran > pitch) { + /* we can't match the specified alignment with XY allocations */ + free(link); + return NULL; + } + + if (pitch % gran) { + /* pitch and granularity aren't a perfect match, let's allocate + * a bit more so we can align later on + */ + length += gran - 1; + } + } + + if (length < pitch) { /* special case */ + w = length; + h = 1; + } + else { + w = pitch; + h = (length + pitch - 1) / pitch; + } + + if ((area = localAllocateOffscreenArea(pScreen, w, h, gran, + moveCB ? LinearMoveCBWrapper : NULL, + removeCB ? LinearRemoveCBWrapper : + NULL, privData))) { + link->area = area; + link->free = 0; + link->next = offman->LinearAreas; + offman->LinearAreas = link; + linear = &(link->linear); + linear->pScreen = pScreen; + linear->size = h * w; + linear->offset = (pitch * area->box.y1) + area->box.x1; + if (gran > 1) + linear->offset = ((linear->offset + gran - 1) / gran) * gran; + linear->granularity = gran; + linear->MoveLinearCallback = moveCB; + linear->RemoveLinearCallback = removeCB; + linear->devPrivate.ptr = privData; + } + else + free(link); + + DumpDebug(offman->LinearAreas); + + return linear; +} + +static void +localFreeOffscreenLinear(FBLinearPtr linear) +{ + FBManagerPtr offman; + FBLinearLinkPtr pLink, pLinkPrev = NULL; + ScreenPtr pScreen = linear->pScreen; + + offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + pLink = offman->LinearAreas; + if (!pLink) + return; + + while (&(pLink->linear) != linear) { + pLinkPrev = pLink; + pLink = pLink->next; + if (!pLink) + return; + } + + if (pLink->area) { /* really an XY area */ + DebugF("FREEING AREA\n"); + localFreeOffscreenArea(pLink->area); + if (pLinkPrev) + pLinkPrev->next = pLink->next; + else + offman->LinearAreas = pLink->next; + free(pLink); + DumpDebug(offman->LinearAreas); + return; + } + + pLink->free = 1; + + if (pLink->next && pLink->next->free) { + FBLinearLinkPtr p = pLink->next; + + pLink->linear.size += p->linear.size; + pLink->next = p->next; + free(p); + } + + if (pLinkPrev) { + if (pLinkPrev->next && pLinkPrev->next->free && !pLinkPrev->area) { + FBLinearLinkPtr p = pLinkPrev->next; + + pLinkPrev->linear.size += p->linear.size; + pLinkPrev->next = p->next; + free(p); + } + } + + DebugF("FREEING LINEAR\n"); + DumpDebug(offman->LinearAreas); +} + +static Bool +localResizeOffscreenLinear(FBLinearPtr resize, int length) +{ + FBManagerPtr offman; + FBLinearLinkPtr pLink; + ScreenPtr pScreen = resize->pScreen; + + offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + pLink = offman->LinearAreas; + if (!pLink) + return FALSE; + + while (&(pLink->linear) != resize) { + pLink = pLink->next; + if (!pLink) + return FALSE; + } + + /* This could actually be alot smarter and try to move allocations + from XY to linear when available. For now if it was XY, we keep + it XY */ + + if (pLink->area) { /* really an XY area */ + BoxPtr extents; + int pitch, w, h; + + extents = RegionExtents(offman->InitialBoxes); + pitch = extents->x2 - extents->x1; + + if (length < pitch) { /* special case */ + w = length; + h = 1; + } + else { + w = pitch; + h = (length + pitch - 1) / pitch; + } + + if (localResizeOffscreenArea(pLink->area, w, h)) { + resize->size = h * w; + resize->offset = + (pitch * pLink->area->box.y1) + pLink->area->box.x1; + return TRUE; + } + } + else { + /* TODO!!!! resize the linear area */ + } + + return FALSE; +} + +static Bool +localQueryLargestOffscreenLinear(ScreenPtr pScreen, + int *size, int gran, int priority) +{ + FBManagerPtr offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + FBLinearLinkPtr pLink; + FBLinearLinkPtr pLinkRet; + + *size = 0; + + pLink = offman->LinearAreas; + + if (pLink && !pLink->area) { + pLinkRet = pLink; + while (pLink) { + if (pLink->free) { + if (pLink->linear.size > pLinkRet->linear.size) + pLinkRet = pLink; + } + pLink = pLink->next; + } + + if (pLinkRet->free) { + *size = pLinkRet->linear.size; + return TRUE; + } + } + else { + int w, h; + + if (localQueryLargestOffscreenArea(pScreen, &w, &h, gran, + FAVOR_WIDTH_THEN_AREA, priority)) { + FBManagerPtr offman; + BoxPtr extents; + + offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + extents = RegionExtents(offman->InitialBoxes); + if ((extents->x2 - extents->x1) == w) + *size = w * h; + return TRUE; + } + } + + return FALSE; +} + +static FBManagerFuncs xf86FBManFuncs = { + localAllocateOffscreenArea, + localFreeOffscreenArea, + localResizeOffscreenArea, + localQueryLargestOffscreenArea, + localRegisterFreeBoxCallback, + localAllocateOffscreenLinear, + localFreeOffscreenLinear, + localResizeOffscreenLinear, + localQueryLargestOffscreenLinear, + localPurgeUnlockedOffscreenAreas +}; + +static Bool +xf86FBCloseScreen(int i, ScreenPtr pScreen) +{ + FBLinkPtr pLink, tmp; + FBLinearLinkPtr pLinearLink, tmp2; + FBManagerPtr offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + + pScreen->CloseScreen = offman->CloseScreen; + + pLink = offman->UsedAreas; + while (pLink) { + tmp = pLink; + pLink = pLink->next; + free(tmp); + } + + pLinearLink = offman->LinearAreas; + while (pLinearLink) { + tmp2 = pLinearLink; + pLinearLink = pLinearLink->next; + free(tmp2); + } + + RegionDestroy(offman->InitialBoxes); + RegionDestroy(offman->FreeBoxes); + + free(offman->FreeBoxesUpdateCallback); + free(offman->devPrivates); + free(offman); + dixSetPrivate(&pScreen->devPrivates, xf86FBScreenKey, NULL); + + return (*pScreen->CloseScreen) (i, pScreen); +} + +Bool +xf86InitFBManager(ScreenPtr pScreen, BoxPtr FullBox) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + RegionRec ScreenRegion; + RegionRec FullRegion; + BoxRec ScreenBox; + Bool ret; + + ScreenBox.x1 = 0; + ScreenBox.y1 = 0; + ScreenBox.x2 = pScrn->virtualX; + ScreenBox.y2 = pScrn->virtualY; + + if ((FullBox->x1 > ScreenBox.x1) || (FullBox->y1 > ScreenBox.y1) || + (FullBox->x2 < ScreenBox.x2) || (FullBox->y2 < ScreenBox.y2)) { + return FALSE; + } + + if (FullBox->y2 < FullBox->y1) + return FALSE; + if (FullBox->x2 < FullBox->x1) + return FALSE; + + RegionInit(&ScreenRegion, &ScreenBox, 1); + RegionInit(&FullRegion, FullBox, 1); + + RegionSubtract(&FullRegion, &FullRegion, &ScreenRegion); + + ret = xf86InitFBManagerRegion(pScreen, &FullRegion); + + RegionUninit(&ScreenRegion); + RegionUninit(&FullRegion); + + return ret; +} + +Bool +xf86InitFBManagerArea(ScreenPtr pScreen, int PixelArea, int Verbosity) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xRectangle Rect[3]; + RegionPtr pRegion, pScreenRegion; + int nRect; + Bool ret = FALSE; + + if (PixelArea < (pScrn->displayWidth * pScrn->virtualY)) + return FALSE; + + Rect[0].x = Rect[0].y = 0; + Rect[0].width = pScrn->displayWidth; + Rect[0].height = PixelArea / pScrn->displayWidth; + nRect = 1; + + /* Add a possible partial scanline */ + if ((Rect[1].height = Rect[1].width = PixelArea % pScrn->displayWidth)) { + Rect[1].x = 0; + Rect[1].y = Rect[0].height; + Rect[1].height = 1; + nRect++; + } + + /* Factor out virtual resolution */ + pRegion = RegionFromRects(nRect, Rect, 0); + if (pRegion) { + if (!RegionNar(pRegion)) { + Rect[2].x = Rect[2].y = 0; + Rect[2].width = pScrn->virtualX; + Rect[2].height = pScrn->virtualY; + + pScreenRegion = RegionFromRects(1, &Rect[2], 0); + if (pScreenRegion) { + if (!RegionNar(pScreenRegion)) { + RegionSubtract(pRegion, pRegion, pScreenRegion); + + ret = xf86InitFBManagerRegion(pScreen, pRegion); + + if (ret && xf86GetVerbosity() >= Verbosity) { + int scrnIndex = pScrn->scrnIndex; + + xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity, + "Largest offscreen areas (with overlaps):\n"); + + if (Rect[2].width < Rect[0].width) { + xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity, + "\t%d x %d rectangle at %d,0\n", + Rect[0].width - Rect[2].width, + Rect[0].height, Rect[2].width); + } + if (Rect[2].width < Rect[1].width) { + xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity, + "\t%d x %d rectangle at %d,0\n", + Rect[1].width - Rect[2].width, + Rect[0].height + Rect[1].height, + Rect[2].width); + } + if (Rect[2].height < Rect[0].height) { + xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity, + "\t%d x %d rectangle at 0,%d\n", + Rect[0].width, + Rect[0].height - Rect[2].height, + Rect[2].height); + } + if (Rect[1].height) { + xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity, + "\t%d x %d rectangle at 0,%d\n", + Rect[1].width, + Rect[0].height - Rect[2].height + + Rect[1].height, Rect[2].height); + } + } + } + + RegionDestroy(pScreenRegion); + } + } + + RegionDestroy(pRegion); + } + + return ret; +} + +Bool +xf86InitFBManagerRegion(ScreenPtr pScreen, RegionPtr FullRegion) +{ + FBManagerPtr offman; + + if (RegionNil(FullRegion)) + return FALSE; + + if (!dixRegisterPrivateKey(&xf86FBScreenKeyRec, PRIVATE_SCREEN, 0)) + return FALSE; + + if (!xf86RegisterOffscreenManager(pScreen, &xf86FBManFuncs)) + return FALSE; + + offman = malloc(sizeof(FBManager)); + if (!offman) + return FALSE; + + dixSetPrivate(&pScreen->devPrivates, xf86FBScreenKey, offman); + + offman->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = xf86FBCloseScreen; + + offman->InitialBoxes = RegionCreate(NULL, 1); + offman->FreeBoxes = RegionCreate(NULL, 1); + + RegionCopy(offman->InitialBoxes, FullRegion); + RegionCopy(offman->FreeBoxes, FullRegion); + + offman->pScreen = pScreen; + offman->UsedAreas = NULL; + offman->LinearAreas = NULL; + offman->NumUsedAreas = 0; + offman->NumCallbacks = 0; + offman->FreeBoxesUpdateCallback = NULL; + offman->devPrivates = NULL; + + return TRUE; +} + +Bool +xf86InitFBManagerLinear(ScreenPtr pScreen, int offset, int size) +{ + FBManagerPtr offman; + FBLinearLinkPtr link; + FBLinearPtr linear; + + if (size <= 0) + return FALSE; + + /* we expect people to have called the Area setup first for pixmap cache */ + if (!dixLookupPrivate(&pScreen->devPrivates, xf86FBScreenKey)) + return FALSE; + + offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + offman->LinearAreas = malloc(sizeof(FBLinearLink)); + if (!offman->LinearAreas) + return FALSE; + + link = offman->LinearAreas; + link->area = NULL; + link->next = NULL; + link->free = 1; + linear = &(link->linear); + linear->pScreen = pScreen; + linear->size = size; + linear->offset = offset; + linear->granularity = 0; + linear->MoveLinearCallback = NULL; + linear->RemoveLinearCallback = NULL; + linear->devPrivate.ptr = NULL; + + return TRUE; +} + +/* This is an implementation specific function and should + disappear after the next release. People should use the + real linear functions instead */ + +FBAreaPtr +xf86AllocateLinearOffscreenArea(ScreenPtr pScreen, + int length, + int gran, + MoveAreaCallbackProcPtr moveCB, + RemoveAreaCallbackProcPtr removeCB, + pointer privData) +{ + FBManagerFuncsPtr funcs; + FBManagerPtr offman; + BoxPtr extents; + int w, h; + + if (xf86FBManagerKey == NULL) + return NULL; + if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates, + xf86FBManagerKey))) + return NULL; + + offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + extents = RegionExtents(offman->InitialBoxes); + w = extents->x2 - extents->x1; + + if (gran > 1) { + if (gran > w) + return NULL; + + if (w % gran) + length += gran - 1; + } + + if (length <= w) { /* special case */ + h = 1; + w = length; + } + else { + h = (length + w - 1) / w; + } + + return (*funcs->AllocateOffscreenArea) (pScreen, w, h, gran, moveCB, + removeCB, privData); +} -- cgit v1.2.3