105b261ecSmrg
205b261ecSmrg/*
305b261ecSmrg * Copyright (c) 1998-2001 by The XFree86 Project, Inc.
405b261ecSmrg *
505b261ecSmrg * Permission is hereby granted, free of charge, to any person obtaining a
605b261ecSmrg * copy of this software and associated documentation files (the "Software"),
705b261ecSmrg * to deal in the Software without restriction, including without limitation
805b261ecSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
905b261ecSmrg * and/or sell copies of the Software, and to permit persons to whom the
1005b261ecSmrg * Software is furnished to do so, subject to the following conditions:
1105b261ecSmrg *
1205b261ecSmrg * The above copyright notice and this permission notice shall be included in
1305b261ecSmrg * all copies or substantial portions of the Software.
1405b261ecSmrg *
1505b261ecSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1605b261ecSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1705b261ecSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1805b261ecSmrg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
1905b261ecSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2005b261ecSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2105b261ecSmrg * OTHER DEALINGS IN THE SOFTWARE.
2205b261ecSmrg *
2305b261ecSmrg * Except as contained in this notice, the name of the copyright holder(s)
2405b261ecSmrg * and author(s) shall not be used in advertising or otherwise to promote
2505b261ecSmrg * the sale, use or other dealings in this Software without prior written
2605b261ecSmrg * authorization from the copyright holder(s) and author(s).
2705b261ecSmrg */
2805b261ecSmrg
2905b261ecSmrg#ifdef HAVE_XORG_CONFIG_H
3005b261ecSmrg#include <xorg-config.h>
3105b261ecSmrg#endif
3205b261ecSmrg
3305b261ecSmrg#include "misc.h"
3405b261ecSmrg#include "xf86.h"
3505b261ecSmrg
3605b261ecSmrg#include <X11/X.h>
3705b261ecSmrg#include "scrnintstr.h"
3805b261ecSmrg#include "regionstr.h"
3905b261ecSmrg#include "xf86fbman.h"
4005b261ecSmrg
4135c4bbdfSmrg/*
4205b261ecSmrg#define DEBUG
4305b261ecSmrg*/
4405b261ecSmrg
456747b715Smrgstatic DevPrivateKeyRec xf86FBManagerKeyRec;
464642e01fSmrgstatic DevPrivateKey xf86FBManagerKey;
4705b261ecSmrg
4835c4bbdfSmrgBool
4935c4bbdfSmrgxf86RegisterOffscreenManager(ScreenPtr pScreen, FBManagerFuncsPtr funcs)
5035c4bbdfSmrg{
5105b261ecSmrg
5235c4bbdfSmrg    xf86FBManagerKey = &xf86FBManagerKeyRec;
536747b715Smrg
5435c4bbdfSmrg    if (!dixRegisterPrivateKey(&xf86FBManagerKeyRec, PRIVATE_SCREEN, 0))
5535c4bbdfSmrg        return FALSE;
566747b715Smrg
5735c4bbdfSmrg    dixSetPrivate(&pScreen->devPrivates, xf86FBManagerKey, funcs);
5805b261ecSmrg
5935c4bbdfSmrg    return TRUE;
6005b261ecSmrg}
6105b261ecSmrg
626747b715SmrgBool
6305b261ecSmrgxf86FBManagerRunning(ScreenPtr pScreen)
6405b261ecSmrg{
656747b715Smrg    if (xf86FBManagerKey == NULL)
6635c4bbdfSmrg        return FALSE;
676747b715Smrg
6835c4bbdfSmrg    if (!dixLookupPrivate(&pScreen->devPrivates, xf86FBManagerKey))
6935c4bbdfSmrg        return FALSE;
7005b261ecSmrg
7105b261ecSmrg    return TRUE;
7205b261ecSmrg}
7305b261ecSmrg
746747b715SmrgBool
7535c4bbdfSmrgxf86RegisterFreeBoxCallback(ScreenPtr pScreen,
7635c4bbdfSmrg                            FreeBoxCallbackProcPtr FreeBoxCallback,
7735c4bbdfSmrg                            void *devPriv)
7835c4bbdfSmrg{
7935c4bbdfSmrg    FBManagerFuncsPtr funcs;
8035c4bbdfSmrg
8135c4bbdfSmrg    if (xf86FBManagerKey == NULL)
8235c4bbdfSmrg        return FALSE;
8335c4bbdfSmrg    if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates,
8435c4bbdfSmrg                                                       xf86FBManagerKey)))
8535c4bbdfSmrg        return FALSE;
8605b261ecSmrg
8735c4bbdfSmrg    return (*funcs->RegisterFreeBoxCallback) (pScreen, FreeBoxCallback,
8835c4bbdfSmrg                                              devPriv);
8935c4bbdfSmrg}
9005b261ecSmrg
916747b715SmrgFBAreaPtr
9235c4bbdfSmrgxf86AllocateOffscreenArea(ScreenPtr pScreen,
9335c4bbdfSmrg                          int w, int h,
9435c4bbdfSmrg                          int gran,
9535c4bbdfSmrg                          MoveAreaCallbackProcPtr moveCB,
9635c4bbdfSmrg                          RemoveAreaCallbackProcPtr removeCB, void *privData)
9735c4bbdfSmrg{
9835c4bbdfSmrg    FBManagerFuncsPtr funcs;
9905b261ecSmrg
10035c4bbdfSmrg    if (xf86FBManagerKey == NULL)
10135c4bbdfSmrg        return NULL;
10235c4bbdfSmrg    if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates,
10335c4bbdfSmrg                                                       xf86FBManagerKey)))
10435c4bbdfSmrg        return NULL;
10505b261ecSmrg
10635c4bbdfSmrg    return (*funcs->AllocateOffscreenArea) (pScreen, w, h, gran, moveCB,
10735c4bbdfSmrg                                            removeCB, privData);
10805b261ecSmrg}
10905b261ecSmrg
11035c4bbdfSmrgFBLinearPtr
11135c4bbdfSmrgxf86AllocateOffscreenLinear(ScreenPtr pScreen,
11235c4bbdfSmrg                            int length,
11335c4bbdfSmrg                            int gran,
11435c4bbdfSmrg                            MoveLinearCallbackProcPtr moveCB,
11535c4bbdfSmrg                            RemoveLinearCallbackProcPtr removeCB,
11635c4bbdfSmrg                            void *privData)
11735c4bbdfSmrg{
11835c4bbdfSmrg    FBManagerFuncsPtr funcs;
11935c4bbdfSmrg
12035c4bbdfSmrg    if (xf86FBManagerKey == NULL)
12135c4bbdfSmrg        return NULL;
12235c4bbdfSmrg    if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates,
12335c4bbdfSmrg                                                       xf86FBManagerKey)))
12435c4bbdfSmrg        return NULL;
12535c4bbdfSmrg
12635c4bbdfSmrg    return (*funcs->AllocateOffscreenLinear) (pScreen, length, gran, moveCB,
12735c4bbdfSmrg                                              removeCB, privData);
12835c4bbdfSmrg}
12905b261ecSmrg
1306747b715Smrgvoid
13105b261ecSmrgxf86FreeOffscreenArea(FBAreaPtr area)
13205b261ecSmrg{
13335c4bbdfSmrg    FBManagerFuncsPtr funcs;
13405b261ecSmrg
13535c4bbdfSmrg    if (!area)
13635c4bbdfSmrg        return;
13705b261ecSmrg
13835c4bbdfSmrg    if (xf86FBManagerKey == NULL)
13935c4bbdfSmrg        return;
14035c4bbdfSmrg    if (!
14135c4bbdfSmrg        (funcs =
14235c4bbdfSmrg         (FBManagerFuncsPtr) dixLookupPrivate(&area->pScreen->devPrivates,
14335c4bbdfSmrg                                              xf86FBManagerKey)))
14435c4bbdfSmrg        return;
14505b261ecSmrg
14635c4bbdfSmrg    (*funcs->FreeOffscreenArea) (area);
14705b261ecSmrg
14835c4bbdfSmrg    return;
14905b261ecSmrg}
15005b261ecSmrg
1516747b715Smrgvoid
15205b261ecSmrgxf86FreeOffscreenLinear(FBLinearPtr linear)
15305b261ecSmrg{
15435c4bbdfSmrg    FBManagerFuncsPtr funcs;
15505b261ecSmrg
15635c4bbdfSmrg    if (!linear)
15735c4bbdfSmrg        return;
15805b261ecSmrg
15935c4bbdfSmrg    if (xf86FBManagerKey == NULL)
16035c4bbdfSmrg        return;
16135c4bbdfSmrg    if (!
16235c4bbdfSmrg        (funcs =
16335c4bbdfSmrg         (FBManagerFuncsPtr) dixLookupPrivate(&linear->pScreen->devPrivates,
16435c4bbdfSmrg                                              xf86FBManagerKey)))
16535c4bbdfSmrg        return;
16605b261ecSmrg
16735c4bbdfSmrg    (*funcs->FreeOffscreenLinear) (linear);
16805b261ecSmrg
16935c4bbdfSmrg    return;
17005b261ecSmrg}
17105b261ecSmrg
1726747b715SmrgBool
17335c4bbdfSmrgxf86ResizeOffscreenArea(FBAreaPtr resize, int w, int h)
17435c4bbdfSmrg{
17535c4bbdfSmrg    FBManagerFuncsPtr funcs;
17605b261ecSmrg
17735c4bbdfSmrg    if (!resize)
17835c4bbdfSmrg        return FALSE;
17905b261ecSmrg
18035c4bbdfSmrg    if (xf86FBManagerKey == NULL)
18135c4bbdfSmrg        return FALSE;
18235c4bbdfSmrg    if (!
18335c4bbdfSmrg        (funcs =
18435c4bbdfSmrg         (FBManagerFuncsPtr) dixLookupPrivate(&resize->pScreen->devPrivates,
18535c4bbdfSmrg                                              xf86FBManagerKey)))
18635c4bbdfSmrg        return FALSE;
18735c4bbdfSmrg
18835c4bbdfSmrg    return (*funcs->ResizeOffscreenArea) (resize, w, h);
18905b261ecSmrg}
19005b261ecSmrg
1916747b715SmrgBool
19235c4bbdfSmrgxf86ResizeOffscreenLinear(FBLinearPtr resize, int size)
19335c4bbdfSmrg{
19435c4bbdfSmrg    FBManagerFuncsPtr funcs;
19505b261ecSmrg
19635c4bbdfSmrg    if (!resize)
19735c4bbdfSmrg        return FALSE;
19805b261ecSmrg
19935c4bbdfSmrg    if (xf86FBManagerKey == NULL)
20035c4bbdfSmrg        return FALSE;
20135c4bbdfSmrg    if (!
20235c4bbdfSmrg        (funcs =
20335c4bbdfSmrg         (FBManagerFuncsPtr) dixLookupPrivate(&resize->pScreen->devPrivates,
20435c4bbdfSmrg                                              xf86FBManagerKey)))
20535c4bbdfSmrg        return FALSE;
20635c4bbdfSmrg
20735c4bbdfSmrg    return (*funcs->ResizeOffscreenLinear) (resize, size);
20805b261ecSmrg}
20905b261ecSmrg
2106747b715SmrgBool
21135c4bbdfSmrgxf86QueryLargestOffscreenArea(ScreenPtr pScreen,
21235c4bbdfSmrg                              int *w, int *h,
21335c4bbdfSmrg                              int gran, int preferences, int severity)
21435c4bbdfSmrg{
21535c4bbdfSmrg    FBManagerFuncsPtr funcs;
21635c4bbdfSmrg
21735c4bbdfSmrg    *w = 0;
21835c4bbdfSmrg    *h = 0;
21935c4bbdfSmrg
22035c4bbdfSmrg    if (xf86FBManagerKey == NULL)
22135c4bbdfSmrg        return FALSE;
22235c4bbdfSmrg    if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates,
22335c4bbdfSmrg                                                       xf86FBManagerKey)))
22435c4bbdfSmrg        return FALSE;
22535c4bbdfSmrg
22635c4bbdfSmrg    return (*funcs->QueryLargestOffscreenArea) (pScreen, w, h, gran,
22735c4bbdfSmrg                                                preferences, severity);
22805b261ecSmrg}
22905b261ecSmrg
2306747b715SmrgBool
23135c4bbdfSmrgxf86QueryLargestOffscreenLinear(ScreenPtr pScreen,
23235c4bbdfSmrg                                int *size, int gran, int severity)
23335c4bbdfSmrg{
23435c4bbdfSmrg    FBManagerFuncsPtr funcs;
23535c4bbdfSmrg
23635c4bbdfSmrg    *size = 0;
23705b261ecSmrg
23835c4bbdfSmrg    if (xf86FBManagerKey == NULL)
23935c4bbdfSmrg        return FALSE;
24035c4bbdfSmrg    if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates,
24135c4bbdfSmrg                                                       xf86FBManagerKey)))
24235c4bbdfSmrg        return FALSE;
24335c4bbdfSmrg
24435c4bbdfSmrg    return (*funcs->QueryLargestOffscreenLinear) (pScreen, size, gran,
24535c4bbdfSmrg                                                  severity);
24635c4bbdfSmrg}
24705b261ecSmrg
2486747b715SmrgBool
24905b261ecSmrgxf86PurgeUnlockedOffscreenAreas(ScreenPtr pScreen)
25005b261ecSmrg{
25135c4bbdfSmrg    FBManagerFuncsPtr funcs;
25205b261ecSmrg
25335c4bbdfSmrg    if (xf86FBManagerKey == NULL)
25435c4bbdfSmrg        return FALSE;
25535c4bbdfSmrg    if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates,
25635c4bbdfSmrg                                                       xf86FBManagerKey)))
25735c4bbdfSmrg        return FALSE;
25805b261ecSmrg
25935c4bbdfSmrg    return (*funcs->PurgeOffscreenAreas) (pScreen);
26005b261ecSmrg}
26105b261ecSmrg
26235c4bbdfSmrg/************************************************************\
26305b261ecSmrg
26405b261ecSmrg   Below is a specific implementation of an offscreen manager.
26505b261ecSmrg
26635c4bbdfSmrg\************************************************************/
26705b261ecSmrg
2686747b715Smrgstatic DevPrivateKeyRec xf86FBScreenKeyRec;
26935c4bbdfSmrg
2706747b715Smrg#define xf86FBScreenKey (&xf86FBScreenKeyRec)
27105b261ecSmrg
27205b261ecSmrgtypedef struct _FBLink {
27335c4bbdfSmrg    FBArea area;
27435c4bbdfSmrg    struct _FBLink *next;
27505b261ecSmrg} FBLink, *FBLinkPtr;
27605b261ecSmrg
27705b261ecSmrgtypedef struct _FBLinearLink {
27835c4bbdfSmrg    FBLinear linear;
27935c4bbdfSmrg    int free;                   /* need to add free here as FBLinear is publicly accessible */
28035c4bbdfSmrg    FBAreaPtr area;             /* only used if allocation came from XY area */
28135c4bbdfSmrg    struct _FBLinearLink *next;
28205b261ecSmrg} FBLinearLink, *FBLinearLinkPtr;
28305b261ecSmrg
28405b261ecSmrgtypedef struct {
28535c4bbdfSmrg    ScreenPtr pScreen;
28635c4bbdfSmrg    RegionPtr InitialBoxes;
28735c4bbdfSmrg    RegionPtr FreeBoxes;
28835c4bbdfSmrg    FBLinkPtr UsedAreas;
28935c4bbdfSmrg    int NumUsedAreas;
29035c4bbdfSmrg    FBLinearLinkPtr LinearAreas;
29135c4bbdfSmrg    CloseScreenProcPtr CloseScreen;
29235c4bbdfSmrg    int NumCallbacks;
29335c4bbdfSmrg    FreeBoxCallbackProcPtr *FreeBoxesUpdateCallback;
29435c4bbdfSmrg    DevUnion *devPrivates;
29505b261ecSmrg} FBManager, *FBManagerPtr;
29605b261ecSmrg
29705b261ecSmrgstatic void
29805b261ecSmrgSendCallFreeBoxCallbacks(FBManagerPtr offman)
29905b261ecSmrg{
30035c4bbdfSmrg    int i = offman->NumCallbacks;
30105b261ecSmrg
30235c4bbdfSmrg    while (i--) {
30335c4bbdfSmrg        (*offman->FreeBoxesUpdateCallback[i]) (offman->pScreen,
30435c4bbdfSmrg                                               offman->FreeBoxes,
30535c4bbdfSmrg                                               offman->devPrivates[i].ptr);
30635c4bbdfSmrg    }
30705b261ecSmrg}
30805b261ecSmrg
30905b261ecSmrgstatic Bool
31035c4bbdfSmrglocalRegisterFreeBoxCallback(ScreenPtr pScreen,
31135c4bbdfSmrg                             FreeBoxCallbackProcPtr FreeBoxCallback,
31235c4bbdfSmrg                             void *devPriv)
31335c4bbdfSmrg{
31435c4bbdfSmrg    FBManagerPtr offman;
31535c4bbdfSmrg    FreeBoxCallbackProcPtr *newCallbacks;
31635c4bbdfSmrg    DevUnion *newPrivates;
31735c4bbdfSmrg
31835c4bbdfSmrg    offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
31935c4bbdfSmrg                                             xf86FBScreenKey);
32035c4bbdfSmrg    newCallbacks = reallocarray(offman->FreeBoxesUpdateCallback,
32135c4bbdfSmrg                                offman->NumCallbacks + 1,
32235c4bbdfSmrg                                sizeof(FreeBoxCallbackProcPtr));
32335c4bbdfSmrg    if (!newCallbacks)
32435c4bbdfSmrg        return FALSE;
32535c4bbdfSmrg    else
32635c4bbdfSmrg        offman->FreeBoxesUpdateCallback = newCallbacks;
32735c4bbdfSmrg
32835c4bbdfSmrg    newPrivates = reallocarray(offman->devPrivates,
32935c4bbdfSmrg                               offman->NumCallbacks + 1,
33035c4bbdfSmrg                               sizeof(DevUnion));
33135c4bbdfSmrg    if (!newPrivates)
33235c4bbdfSmrg        return FALSE;
33335c4bbdfSmrg    else
33435c4bbdfSmrg        offman->devPrivates = newPrivates;
33535c4bbdfSmrg
33635c4bbdfSmrg    offman->FreeBoxesUpdateCallback[offman->NumCallbacks] = FreeBoxCallback;
33735c4bbdfSmrg    offman->devPrivates[offman->NumCallbacks].ptr = devPriv;
33835c4bbdfSmrg    offman->NumCallbacks++;
33935c4bbdfSmrg
34035c4bbdfSmrg    SendCallFreeBoxCallbacks(offman);
34105b261ecSmrg
34235c4bbdfSmrg    return TRUE;
34305b261ecSmrg}
34405b261ecSmrg
34505b261ecSmrgstatic FBAreaPtr
34635c4bbdfSmrgAllocateArea(FBManagerPtr offman,
34735c4bbdfSmrg             int w, int h,
34835c4bbdfSmrg             int granularity,
34935c4bbdfSmrg             MoveAreaCallbackProcPtr moveCB,
35035c4bbdfSmrg             RemoveAreaCallbackProcPtr removeCB, void *privData)
35135c4bbdfSmrg{
35235c4bbdfSmrg    ScreenPtr pScreen = offman->pScreen;
35335c4bbdfSmrg    FBLinkPtr link = NULL;
35435c4bbdfSmrg    FBAreaPtr area = NULL;
35535c4bbdfSmrg    RegionRec NewReg;
35635c4bbdfSmrg    int i, x = 0, num;
35735c4bbdfSmrg    BoxPtr boxp;
35835c4bbdfSmrg
35935c4bbdfSmrg    if (granularity <= 1)
36035c4bbdfSmrg        granularity = 0;
36135c4bbdfSmrg
36235c4bbdfSmrg    boxp = RegionRects(offman->FreeBoxes);
36335c4bbdfSmrg    num = RegionNumRects(offman->FreeBoxes);
36435c4bbdfSmrg
36535c4bbdfSmrg    /* look through the free boxes */
36635c4bbdfSmrg    for (i = 0; i < num; i++, boxp++) {
36735c4bbdfSmrg        x = boxp->x1;
36835c4bbdfSmrg        if (granularity > 1)
36935c4bbdfSmrg            x = ((x + granularity - 1) / granularity) * granularity;
37035c4bbdfSmrg
37135c4bbdfSmrg        if (((boxp->y2 - boxp->y1) < h) || ((boxp->x2 - x) < w))
37235c4bbdfSmrg            continue;
37335c4bbdfSmrg
37435c4bbdfSmrg        link = malloc(sizeof(FBLink));
37535c4bbdfSmrg        if (!link)
37635c4bbdfSmrg            return NULL;
37705b261ecSmrg
37805b261ecSmrg        area = &(link->area);
37905b261ecSmrg        link->next = offman->UsedAreas;
38005b261ecSmrg        offman->UsedAreas = link;
38105b261ecSmrg        offman->NumUsedAreas++;
38235c4bbdfSmrg        break;
38335c4bbdfSmrg    }
38435c4bbdfSmrg
385ed6184dfSmrg    /* try to boot a removable one out if we are not expendable ourselves */
38635c4bbdfSmrg    if (!area && !removeCB) {
38735c4bbdfSmrg        link = offman->UsedAreas;
38835c4bbdfSmrg
38935c4bbdfSmrg        while (link) {
39035c4bbdfSmrg            if (!link->area.RemoveAreaCallback) {
39135c4bbdfSmrg                link = link->next;
39235c4bbdfSmrg                continue;
39335c4bbdfSmrg            }
39435c4bbdfSmrg
39535c4bbdfSmrg            boxp = &(link->area.box);
39635c4bbdfSmrg            x = boxp->x1;
39735c4bbdfSmrg            if (granularity > 1)
39835c4bbdfSmrg                x = ((x + granularity - 1) / granularity) * granularity;
39935c4bbdfSmrg
40035c4bbdfSmrg            if (((boxp->y2 - boxp->y1) < h) || ((boxp->x2 - x) < w)) {
40135c4bbdfSmrg                link = link->next;
40235c4bbdfSmrg                continue;
40335c4bbdfSmrg            }
40435c4bbdfSmrg
40535c4bbdfSmrg            /* bye, bye */
40635c4bbdfSmrg            (*link->area.RemoveAreaCallback) (&link->area);
40735c4bbdfSmrg            RegionInit(&NewReg, &(link->area.box), 1);
40835c4bbdfSmrg            RegionUnion(offman->FreeBoxes, offman->FreeBoxes, &NewReg);
40935c4bbdfSmrg            RegionUninit(&NewReg);
41035c4bbdfSmrg
41135c4bbdfSmrg            area = &(link->area);
41235c4bbdfSmrg            break;
41335c4bbdfSmrg        }
41435c4bbdfSmrg    }
41535c4bbdfSmrg
41635c4bbdfSmrg    if (area) {
41735c4bbdfSmrg        area->pScreen = pScreen;
41835c4bbdfSmrg        area->granularity = granularity;
41935c4bbdfSmrg        area->box.x1 = x;
42035c4bbdfSmrg        area->box.x2 = x + w;
42135c4bbdfSmrg        area->box.y1 = boxp->y1;
42235c4bbdfSmrg        area->box.y2 = boxp->y1 + h;
42335c4bbdfSmrg        area->MoveAreaCallback = moveCB;
42435c4bbdfSmrg        area->RemoveAreaCallback = removeCB;
42535c4bbdfSmrg        area->devPrivate.ptr = privData;
42605b261ecSmrg
4276747b715Smrg        RegionInit(&NewReg, &(area->box), 1);
42835c4bbdfSmrg        RegionSubtract(offman->FreeBoxes, offman->FreeBoxes, &NewReg);
42935c4bbdfSmrg        RegionUninit(&NewReg);
43035c4bbdfSmrg    }
43105b261ecSmrg
43235c4bbdfSmrg    return area;
43305b261ecSmrg}
43405b261ecSmrg
43505b261ecSmrgstatic FBAreaPtr
43635c4bbdfSmrglocalAllocateOffscreenArea(ScreenPtr pScreen,
43735c4bbdfSmrg                           int w, int h,
43835c4bbdfSmrg                           int gran,
43935c4bbdfSmrg                           MoveAreaCallbackProcPtr moveCB,
44035c4bbdfSmrg                           RemoveAreaCallbackProcPtr removeCB, void *privData)
44135c4bbdfSmrg{
44235c4bbdfSmrg    FBManagerPtr offman;
44335c4bbdfSmrg    FBAreaPtr area = NULL;
44405b261ecSmrg
44535c4bbdfSmrg    offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
44635c4bbdfSmrg                                             xf86FBScreenKey);
44735c4bbdfSmrg    if ((area = AllocateArea(offman, w, h, gran, moveCB, removeCB, privData)))
44835c4bbdfSmrg        SendCallFreeBoxCallbacks(offman);
44935c4bbdfSmrg
45035c4bbdfSmrg    return area;
45135c4bbdfSmrg}
45205b261ecSmrg
45305b261ecSmrgstatic void
45405b261ecSmrglocalFreeOffscreenArea(FBAreaPtr area)
45505b261ecSmrg{
45635c4bbdfSmrg    FBManagerPtr offman;
45735c4bbdfSmrg    FBLinkPtr pLink, pLinkPrev = NULL;
45835c4bbdfSmrg    RegionRec FreedRegion;
45935c4bbdfSmrg    ScreenPtr pScreen;
46035c4bbdfSmrg
46135c4bbdfSmrg    pScreen = area->pScreen;
46235c4bbdfSmrg    offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
46335c4bbdfSmrg                                             xf86FBScreenKey);
46435c4bbdfSmrg    pLink = offman->UsedAreas;
46535c4bbdfSmrg    if (!pLink)
46635c4bbdfSmrg        return;
46735c4bbdfSmrg
46835c4bbdfSmrg    while (&(pLink->area) != area) {
46935c4bbdfSmrg        pLinkPrev = pLink;
47035c4bbdfSmrg        pLink = pLink->next;
47135c4bbdfSmrg        if (!pLink)
47235c4bbdfSmrg            return;
47335c4bbdfSmrg    }
47435c4bbdfSmrg
47535c4bbdfSmrg    /* put the area back into the pool */
47635c4bbdfSmrg    RegionInit(&FreedRegion, &(pLink->area.box), 1);
47735c4bbdfSmrg    RegionUnion(offman->FreeBoxes, offman->FreeBoxes, &FreedRegion);
47835c4bbdfSmrg    RegionUninit(&FreedRegion);
47935c4bbdfSmrg
48035c4bbdfSmrg    if (pLinkPrev)
48135c4bbdfSmrg        pLinkPrev->next = pLink->next;
48235c4bbdfSmrg    else
48335c4bbdfSmrg        offman->UsedAreas = pLink->next;
48405b261ecSmrg
48535c4bbdfSmrg    free(pLink);
48635c4bbdfSmrg    offman->NumUsedAreas--;
48735c4bbdfSmrg
48835c4bbdfSmrg    SendCallFreeBoxCallbacks(offman);
48935c4bbdfSmrg}
49005b261ecSmrg
49105b261ecSmrgstatic Bool
49235c4bbdfSmrglocalResizeOffscreenArea(FBAreaPtr resize, int w, int h)
49335c4bbdfSmrg{
49435c4bbdfSmrg    FBManagerPtr offman;
49535c4bbdfSmrg    ScreenPtr pScreen;
49635c4bbdfSmrg    BoxRec OrigArea;
49735c4bbdfSmrg    RegionRec FreedReg;
49835c4bbdfSmrg    FBAreaPtr area = NULL;
49935c4bbdfSmrg    FBLinkPtr pLink, newLink, pLinkPrev = NULL;
50035c4bbdfSmrg
50135c4bbdfSmrg    pScreen = resize->pScreen;
50235c4bbdfSmrg    offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
50335c4bbdfSmrg                                             xf86FBScreenKey);
50435c4bbdfSmrg    /* find this link */
50535c4bbdfSmrg    if (!(pLink = offman->UsedAreas))
50635c4bbdfSmrg        return FALSE;
50735c4bbdfSmrg
50835c4bbdfSmrg    while (&(pLink->area) != resize) {
50935c4bbdfSmrg        pLinkPrev = pLink;
51035c4bbdfSmrg        pLink = pLink->next;
51135c4bbdfSmrg        if (!pLink)
51235c4bbdfSmrg            return FALSE;
51335c4bbdfSmrg    }
51435c4bbdfSmrg
51535c4bbdfSmrg    OrigArea.x1 = resize->box.x1;
51635c4bbdfSmrg    OrigArea.x2 = resize->box.x2;
51735c4bbdfSmrg    OrigArea.y1 = resize->box.y1;
51835c4bbdfSmrg    OrigArea.y2 = resize->box.y2;
51935c4bbdfSmrg
52035c4bbdfSmrg    /* if it's smaller, this is easy */
52135c4bbdfSmrg
52235c4bbdfSmrg    if ((w <= (resize->box.x2 - resize->box.x1)) &&
52335c4bbdfSmrg        (h <= (resize->box.y2 - resize->box.y1))) {
52435c4bbdfSmrg        RegionRec NewReg;
52535c4bbdfSmrg
52635c4bbdfSmrg        resize->box.x2 = resize->box.x1 + w;
52735c4bbdfSmrg        resize->box.y2 = resize->box.y1 + h;
52835c4bbdfSmrg
52935c4bbdfSmrg        if ((resize->box.y2 == OrigArea.y2) && (resize->box.x2 == OrigArea.x2))
53035c4bbdfSmrg            return TRUE;
53135c4bbdfSmrg
53235c4bbdfSmrg        RegionInit(&FreedReg, &OrigArea, 1);
53335c4bbdfSmrg        RegionInit(&NewReg, &(resize->box), 1);
53435c4bbdfSmrg        RegionSubtract(&FreedReg, &FreedReg, &NewReg);
53535c4bbdfSmrg        RegionUnion(offman->FreeBoxes, offman->FreeBoxes, &FreedReg);
53635c4bbdfSmrg        RegionUninit(&FreedReg);
53735c4bbdfSmrg        RegionUninit(&NewReg);
53835c4bbdfSmrg
53935c4bbdfSmrg        SendCallFreeBoxCallbacks(offman);
54035c4bbdfSmrg
54135c4bbdfSmrg        return TRUE;
54235c4bbdfSmrg    }
54335c4bbdfSmrg
54435c4bbdfSmrg    /* otherwise we remove the old region */
54535c4bbdfSmrg
54635c4bbdfSmrg    RegionInit(&FreedReg, &OrigArea, 1);
54735c4bbdfSmrg    RegionUnion(offman->FreeBoxes, offman->FreeBoxes, &FreedReg);
54835c4bbdfSmrg
54935c4bbdfSmrg    /* remove the old link */
55035c4bbdfSmrg    if (pLinkPrev)
55135c4bbdfSmrg        pLinkPrev->next = pLink->next;
55235c4bbdfSmrg    else
55335c4bbdfSmrg        offman->UsedAreas = pLink->next;
55435c4bbdfSmrg
55535c4bbdfSmrg    /* and try to add a new one */
55635c4bbdfSmrg
55735c4bbdfSmrg    if ((area = AllocateArea(offman, w, h, resize->granularity,
55835c4bbdfSmrg                             resize->MoveAreaCallback,
55935c4bbdfSmrg                             resize->RemoveAreaCallback,
56035c4bbdfSmrg                             resize->devPrivate.ptr))) {
56105b261ecSmrg
56205b261ecSmrg        /* copy data over to our link and replace the new with old */
56335c4bbdfSmrg        memcpy(resize, area, sizeof(FBArea));
56405b261ecSmrg
56505b261ecSmrg        pLinkPrev = NULL;
56635c4bbdfSmrg        newLink = offman->UsedAreas;
56705b261ecSmrg
56835c4bbdfSmrg        while (&(newLink->area) != area) {
56935c4bbdfSmrg            pLinkPrev = newLink;
57035c4bbdfSmrg            newLink = newLink->next;
57105b261ecSmrg        }
57205b261ecSmrg
57335c4bbdfSmrg        if (pLinkPrev)
57435c4bbdfSmrg            pLinkPrev->next = newLink->next;
57535c4bbdfSmrg        else
57635c4bbdfSmrg            offman->UsedAreas = newLink->next;
57705b261ecSmrg
57805b261ecSmrg        pLink->next = offman->UsedAreas;
57905b261ecSmrg        offman->UsedAreas = pLink;
58005b261ecSmrg
58135c4bbdfSmrg        free(newLink);
58205b261ecSmrg
58335c4bbdfSmrg        /* AllocateArea added one but we really only exchanged one */
58435c4bbdfSmrg        offman->NumUsedAreas--;
58535c4bbdfSmrg    }
58635c4bbdfSmrg    else {
58735c4bbdfSmrg        /* reinstate the old region */
58835c4bbdfSmrg        RegionSubtract(offman->FreeBoxes, offman->FreeBoxes, &FreedReg);
58935c4bbdfSmrg        RegionUninit(&FreedReg);
59005b261ecSmrg
59135c4bbdfSmrg        pLink->next = offman->UsedAreas;
59235c4bbdfSmrg        offman->UsedAreas = pLink;
59335c4bbdfSmrg        return FALSE;
59435c4bbdfSmrg    }
59505b261ecSmrg
59635c4bbdfSmrg    RegionUninit(&FreedReg);
59705b261ecSmrg
59835c4bbdfSmrg    SendCallFreeBoxCallbacks(offman);
59905b261ecSmrg
60035c4bbdfSmrg    return TRUE;
60105b261ecSmrg}
60205b261ecSmrg
60305b261ecSmrgstatic Bool
60435c4bbdfSmrglocalQueryLargestOffscreenArea(ScreenPtr pScreen,
60535c4bbdfSmrg                               int *width, int *height,
60635c4bbdfSmrg                               int granularity, int preferences, int severity)
60735c4bbdfSmrg{
60805b261ecSmrg    FBManagerPtr offman;
60905b261ecSmrg    RegionPtr newRegion = NULL;
61005b261ecSmrg    BoxPtr pbox;
61105b261ecSmrg    int nbox;
61205b261ecSmrg    int x, w, h, area, oldArea;
61305b261ecSmrg
61405b261ecSmrg    *width = *height = oldArea = 0;
61505b261ecSmrg
61635c4bbdfSmrg    if (granularity <= 1)
61735c4bbdfSmrg        granularity = 0;
61805b261ecSmrg
61935c4bbdfSmrg    if ((preferences < 0) || (preferences > 3))
62035c4bbdfSmrg        return FALSE;
62105b261ecSmrg
62235c4bbdfSmrg    offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
62335c4bbdfSmrg                                             xf86FBScreenKey);
62435c4bbdfSmrg    if (severity < 0)
62535c4bbdfSmrg        severity = 0;
62635c4bbdfSmrg    if (severity > 2)
62735c4bbdfSmrg        severity = 2;
62805b261ecSmrg
62935c4bbdfSmrg    switch (severity) {
63005b261ecSmrg    case 2:
63135c4bbdfSmrg        if (offman->NumUsedAreas) {
63235c4bbdfSmrg            FBLinkPtr pLink;
63335c4bbdfSmrg            RegionRec tmpRegion;
63435c4bbdfSmrg
63535c4bbdfSmrg            newRegion = RegionCreate(NULL, 1);
63635c4bbdfSmrg            RegionCopy(newRegion, offman->InitialBoxes);
63735c4bbdfSmrg            pLink = offman->UsedAreas;
63835c4bbdfSmrg
63935c4bbdfSmrg            while (pLink) {
64035c4bbdfSmrg                if (!pLink->area.RemoveAreaCallback) {
64135c4bbdfSmrg                    RegionInit(&tmpRegion, &(pLink->area.box), 1);
64235c4bbdfSmrg                    RegionSubtract(newRegion, newRegion, &tmpRegion);
64335c4bbdfSmrg                    RegionUninit(&tmpRegion);
64435c4bbdfSmrg                }
64535c4bbdfSmrg                pLink = pLink->next;
64635c4bbdfSmrg            }
64735c4bbdfSmrg
64835c4bbdfSmrg            nbox = RegionNumRects(newRegion);
64935c4bbdfSmrg            pbox = RegionRects(newRegion);
65035c4bbdfSmrg            break;
65135c4bbdfSmrg        }
65205b261ecSmrg    case 1:
65335c4bbdfSmrg        if (offman->NumUsedAreas) {
65435c4bbdfSmrg            FBLinkPtr pLink;
65535c4bbdfSmrg            RegionRec tmpRegion;
65635c4bbdfSmrg
65735c4bbdfSmrg            newRegion = RegionCreate(NULL, 1);
65835c4bbdfSmrg            RegionCopy(newRegion, offman->FreeBoxes);
65935c4bbdfSmrg            pLink = offman->UsedAreas;
66035c4bbdfSmrg
66135c4bbdfSmrg            while (pLink) {
66235c4bbdfSmrg                if (pLink->area.RemoveAreaCallback) {
66335c4bbdfSmrg                    RegionInit(&tmpRegion, &(pLink->area.box), 1);
66435c4bbdfSmrg                    RegionAppend(newRegion, &tmpRegion);
66535c4bbdfSmrg                    RegionUninit(&tmpRegion);
66635c4bbdfSmrg                }
66735c4bbdfSmrg                pLink = pLink->next;
66835c4bbdfSmrg            }
66935c4bbdfSmrg
67035c4bbdfSmrg            nbox = RegionNumRects(newRegion);
67135c4bbdfSmrg            pbox = RegionRects(newRegion);
67235c4bbdfSmrg            break;
67335c4bbdfSmrg        }
67405b261ecSmrg    default:
67535c4bbdfSmrg        nbox = RegionNumRects(offman->FreeBoxes);
67635c4bbdfSmrg        pbox = RegionRects(offman->FreeBoxes);
67735c4bbdfSmrg        break;
67805b261ecSmrg    }
67905b261ecSmrg
68035c4bbdfSmrg    while (nbox--) {
68135c4bbdfSmrg        x = pbox->x1;
68235c4bbdfSmrg        if (granularity > 1)
68335c4bbdfSmrg            x = ((x + granularity - 1) / granularity) * granularity;
68435c4bbdfSmrg
68535c4bbdfSmrg        w = pbox->x2 - x;
68635c4bbdfSmrg        h = pbox->y2 - pbox->y1;
68735c4bbdfSmrg        area = w * h;
68835c4bbdfSmrg
68935c4bbdfSmrg        if (w > 0) {
69035c4bbdfSmrg            Bool gotIt = FALSE;
69135c4bbdfSmrg
69235c4bbdfSmrg            switch (preferences) {
69335c4bbdfSmrg            case FAVOR_AREA_THEN_WIDTH:
69435c4bbdfSmrg                if ((area > oldArea) || ((area == oldArea) && (w > *width)))
69535c4bbdfSmrg                    gotIt = TRUE;
69635c4bbdfSmrg                break;
69735c4bbdfSmrg            case FAVOR_AREA_THEN_HEIGHT:
69835c4bbdfSmrg                if ((area > oldArea) || ((area == oldArea) && (h > *height)))
69935c4bbdfSmrg                    gotIt = TRUE;
70035c4bbdfSmrg                break;
70135c4bbdfSmrg            case FAVOR_WIDTH_THEN_AREA:
70235c4bbdfSmrg                if ((w > *width) || ((w == *width) && (area > oldArea)))
70335c4bbdfSmrg                    gotIt = TRUE;
70435c4bbdfSmrg                break;
70535c4bbdfSmrg            case FAVOR_HEIGHT_THEN_AREA:
70635c4bbdfSmrg                if ((h > *height) || ((h == *height) && (area > oldArea)))
70735c4bbdfSmrg                    gotIt = TRUE;
70835c4bbdfSmrg                break;
70935c4bbdfSmrg            }
71035c4bbdfSmrg            if (gotIt) {
71135c4bbdfSmrg                *width = w;
71235c4bbdfSmrg                *height = h;
71335c4bbdfSmrg                oldArea = area;
71435c4bbdfSmrg            }
71505b261ecSmrg        }
71635c4bbdfSmrg        pbox++;
71705b261ecSmrg    }
71805b261ecSmrg
71935c4bbdfSmrg    if (newRegion)
72035c4bbdfSmrg        RegionDestroy(newRegion);
72105b261ecSmrg
72205b261ecSmrg    return TRUE;
72305b261ecSmrg}
72405b261ecSmrg
72505b261ecSmrgstatic Bool
72605b261ecSmrglocalPurgeUnlockedOffscreenAreas(ScreenPtr pScreen)
72705b261ecSmrg{
72835c4bbdfSmrg    FBManagerPtr offman;
72935c4bbdfSmrg    FBLinkPtr pLink, tmp, pPrev = NULL;
73035c4bbdfSmrg    RegionRec FreedRegion;
73135c4bbdfSmrg    Bool anyUsed = FALSE;
73235c4bbdfSmrg
73335c4bbdfSmrg    offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
73435c4bbdfSmrg                                             xf86FBScreenKey);
73535c4bbdfSmrg    pLink = offman->UsedAreas;
73635c4bbdfSmrg    if (!pLink)
73735c4bbdfSmrg        return TRUE;
73835c4bbdfSmrg
73935c4bbdfSmrg    while (pLink) {
74035c4bbdfSmrg        if (pLink->area.RemoveAreaCallback) {
74135c4bbdfSmrg            (*pLink->area.RemoveAreaCallback) (&pLink->area);
74235c4bbdfSmrg
74335c4bbdfSmrg            RegionInit(&FreedRegion, &(pLink->area.box), 1);
74435c4bbdfSmrg            RegionAppend(offman->FreeBoxes, &FreedRegion);
74535c4bbdfSmrg            RegionUninit(&FreedRegion);
74635c4bbdfSmrg
74735c4bbdfSmrg            if (pPrev)
74835c4bbdfSmrg                pPrev->next = pLink->next;
74935c4bbdfSmrg            else
75035c4bbdfSmrg                offman->UsedAreas = pLink->next;
75135c4bbdfSmrg
75235c4bbdfSmrg            tmp = pLink;
75335c4bbdfSmrg            pLink = pLink->next;
7546747b715Smrg            free(tmp);
75535c4bbdfSmrg            offman->NumUsedAreas--;
75635c4bbdfSmrg            anyUsed = TRUE;
75735c4bbdfSmrg        }
75835c4bbdfSmrg        else {
75935c4bbdfSmrg            pPrev = pLink;
76035c4bbdfSmrg            pLink = pLink->next;
76135c4bbdfSmrg        }
76235c4bbdfSmrg    }
76335c4bbdfSmrg
76435c4bbdfSmrg    if (anyUsed) {
76535c4bbdfSmrg        RegionValidate(offman->FreeBoxes, &anyUsed);
76635c4bbdfSmrg        SendCallFreeBoxCallbacks(offman);
76735c4bbdfSmrg    }
76835c4bbdfSmrg
76935c4bbdfSmrg    return TRUE;
77005b261ecSmrg}
77105b261ecSmrg
77235c4bbdfSmrgstatic void
77305b261ecSmrgLinearMoveCBWrapper(FBAreaPtr from, FBAreaPtr to)
77405b261ecSmrg{
77505b261ecSmrg    /* this will never get called */
77605b261ecSmrg}
77705b261ecSmrg
77835c4bbdfSmrgstatic void
77905b261ecSmrgLinearRemoveCBWrapper(FBAreaPtr area)
78005b261ecSmrg{
78135c4bbdfSmrg    FBManagerPtr offman;
78235c4bbdfSmrg    FBLinearLinkPtr pLink, pLinkPrev = NULL;
78335c4bbdfSmrg    ScreenPtr pScreen = area->pScreen;
78435c4bbdfSmrg
78535c4bbdfSmrg    offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
78635c4bbdfSmrg                                             xf86FBScreenKey);
78735c4bbdfSmrg    pLink = offman->LinearAreas;
78835c4bbdfSmrg    if (!pLink)
78935c4bbdfSmrg        return;
79035c4bbdfSmrg
79135c4bbdfSmrg    while (pLink->area != area) {
79205b261ecSmrg        pLinkPrev = pLink;
79305b261ecSmrg        pLink = pLink->next;
79435c4bbdfSmrg        if (!pLink)
79535c4bbdfSmrg            return;
79635c4bbdfSmrg    }
79705b261ecSmrg
79835c4bbdfSmrg    /* give the user the callback it is expecting */
79935c4bbdfSmrg    (*pLink->linear.RemoveLinearCallback) (&(pLink->linear));
80005b261ecSmrg
80135c4bbdfSmrg    if (pLinkPrev)
80205b261ecSmrg        pLinkPrev->next = pLink->next;
80335c4bbdfSmrg    else
80435c4bbdfSmrg        offman->LinearAreas = pLink->next;
80505b261ecSmrg
80635c4bbdfSmrg    free(pLink);
80705b261ecSmrg}
80805b261ecSmrg
80905b261ecSmrgstatic void
8106747b715SmrgDumpDebug(FBLinearLinkPtr pLink)
81105b261ecSmrg{
8126747b715Smrg#ifdef DEBUG
81335c4bbdfSmrg    if (!pLink)
81435c4bbdfSmrg        ErrorF("MMmm, PLINK IS NULL!\n");
81505b261ecSmrg
81635c4bbdfSmrg    while (pLink) {
81735c4bbdfSmrg        ErrorF("  Offset:%08x, Size:%08x, %s,%s\n",
81835c4bbdfSmrg               pLink->linear.offset,
81935c4bbdfSmrg               pLink->linear.size,
82035c4bbdfSmrg               pLink->free ? "Free" : "Used", pLink->area ? "Area" : "Linear");
82105b261ecSmrg
82235c4bbdfSmrg        pLink = pLink->next;
82335c4bbdfSmrg    }
82405b261ecSmrg#endif
8256747b715Smrg}
82605b261ecSmrg
82705b261ecSmrgstatic FBLinearPtr
82835c4bbdfSmrgAllocateLinear(FBManagerPtr offman, int size, int granularity, void *privData)
82935c4bbdfSmrg{
83035c4bbdfSmrg    ScreenPtr pScreen = offman->pScreen;
83135c4bbdfSmrg    FBLinearLinkPtr linear = NULL;
83235c4bbdfSmrg    FBLinearLinkPtr newlink = NULL;
83335c4bbdfSmrg    int offset, end;
83435c4bbdfSmrg
83535c4bbdfSmrg    if (size <= 0)
83635c4bbdfSmrg        return NULL;
83735c4bbdfSmrg
83835c4bbdfSmrg    if (!offman->LinearAreas)
83935c4bbdfSmrg        return NULL;
84035c4bbdfSmrg
84135c4bbdfSmrg    linear = offman->LinearAreas;
84235c4bbdfSmrg    while (linear) {
84335c4bbdfSmrg        /* Make sure we get a free area that's not an XY fallback case */
84435c4bbdfSmrg        if (!linear->area && linear->free) {
84535c4bbdfSmrg            offset = linear->linear.offset;
84635c4bbdfSmrg            if (granularity > 1)
84735c4bbdfSmrg                offset =
84835c4bbdfSmrg                    ((offset + granularity - 1) / granularity) * granularity;
84935c4bbdfSmrg            end = offset + size;
85035c4bbdfSmrg            if (end <= (linear->linear.offset + linear->linear.size))
85135c4bbdfSmrg                break;
85235c4bbdfSmrg        }
85335c4bbdfSmrg        linear = linear->next;
85435c4bbdfSmrg    }
85535c4bbdfSmrg    if (!linear)
85635c4bbdfSmrg        return NULL;
85735c4bbdfSmrg
85835c4bbdfSmrg    /* break left */
85935c4bbdfSmrg    if (offset > linear->linear.offset) {
86035c4bbdfSmrg        newlink = malloc(sizeof(FBLinearLink));
86135c4bbdfSmrg        if (!newlink)
86235c4bbdfSmrg            return NULL;
86335c4bbdfSmrg        newlink->area = NULL;
86435c4bbdfSmrg        newlink->linear.offset = offset;
86535c4bbdfSmrg        newlink->linear.size =
86635c4bbdfSmrg            linear->linear.size - (offset - linear->linear.offset);
86735c4bbdfSmrg        newlink->free = 1;
86835c4bbdfSmrg        newlink->next = linear->next;
86935c4bbdfSmrg        linear->linear.size -= newlink->linear.size;
87035c4bbdfSmrg        linear->next = newlink;
87135c4bbdfSmrg        linear = newlink;
87235c4bbdfSmrg    }
87335c4bbdfSmrg
87435c4bbdfSmrg    /* break right */
87535c4bbdfSmrg    if (size < linear->linear.size) {
87635c4bbdfSmrg        newlink = malloc(sizeof(FBLinearLink));
87735c4bbdfSmrg        if (!newlink)
87835c4bbdfSmrg            return NULL;
87935c4bbdfSmrg        newlink->area = NULL;
88035c4bbdfSmrg        newlink->linear.offset = offset + size;
88135c4bbdfSmrg        newlink->linear.size = linear->linear.size - size;
88235c4bbdfSmrg        newlink->free = 1;
88335c4bbdfSmrg        newlink->next = linear->next;
88435c4bbdfSmrg        linear->linear.size = size;
88535c4bbdfSmrg        linear->next = newlink;
88635c4bbdfSmrg    }
88735c4bbdfSmrg
88835c4bbdfSmrg    /* p = middle block */
88935c4bbdfSmrg    linear->linear.granularity = granularity;
89035c4bbdfSmrg    linear->free = 0;
89135c4bbdfSmrg    linear->linear.pScreen = pScreen;
89235c4bbdfSmrg    linear->linear.MoveLinearCallback = NULL;
89335c4bbdfSmrg    linear->linear.RemoveLinearCallback = NULL;
89435c4bbdfSmrg    linear->linear.devPrivate.ptr = NULL;
89535c4bbdfSmrg
89635c4bbdfSmrg    DumpDebug(offman->LinearAreas);
89735c4bbdfSmrg
89835c4bbdfSmrg    return &(linear->linear);
89905b261ecSmrg}
90005b261ecSmrg
90105b261ecSmrgstatic FBLinearPtr
90235c4bbdfSmrglocalAllocateOffscreenLinear(ScreenPtr pScreen,
90335c4bbdfSmrg                             int length,
90435c4bbdfSmrg                             int gran,
90535c4bbdfSmrg                             MoveLinearCallbackProcPtr moveCB,
90635c4bbdfSmrg                             RemoveLinearCallbackProcPtr removeCB,
90735c4bbdfSmrg                             void *privData)
90835c4bbdfSmrg{
90935c4bbdfSmrg    FBManagerPtr offman;
91035c4bbdfSmrg    FBLinearLinkPtr link;
91135c4bbdfSmrg    FBAreaPtr area;
91235c4bbdfSmrg    FBLinearPtr linear = NULL;
91335c4bbdfSmrg    BoxPtr extents;
91435c4bbdfSmrg    int w, h, pitch;
91535c4bbdfSmrg
91635c4bbdfSmrg    offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
91735c4bbdfSmrg                                             xf86FBScreenKey);
91835c4bbdfSmrg
91935c4bbdfSmrg    /* Try to allocate from linear memory first...... */
92035c4bbdfSmrg    DebugF("ALLOCATING LINEAR\n");
92135c4bbdfSmrg    if ((linear = AllocateLinear(offman, length, gran, privData)))
92235c4bbdfSmrg        return linear;
92335c4bbdfSmrg
92435c4bbdfSmrg    DebugF("NOPE, ALLOCATING AREA\n");
92535c4bbdfSmrg
92635c4bbdfSmrg    if (!(link = malloc(sizeof(FBLinearLink))))
92735c4bbdfSmrg        return NULL;
92835c4bbdfSmrg
92935c4bbdfSmrg    /* No linear available, so try and pinch some from the XY areas */
93035c4bbdfSmrg    extents = RegionExtents(offman->InitialBoxes);
93135c4bbdfSmrg    pitch = extents->x2 - extents->x1;
93235c4bbdfSmrg
93335c4bbdfSmrg    if (gran > 1) {
93405b261ecSmrg        if (gran > pitch) {
93505b261ecSmrg            /* we can't match the specified alignment with XY allocations */
9366747b715Smrg            free(link);
93705b261ecSmrg            return NULL;
93805b261ecSmrg        }
93905b261ecSmrg
94005b261ecSmrg        if (pitch % gran) {
94105b261ecSmrg            /* pitch and granularity aren't a perfect match, let's allocate
94205b261ecSmrg             * a bit more so we can align later on
94305b261ecSmrg             */
94405b261ecSmrg            length += gran - 1;
94505b261ecSmrg        }
94605b261ecSmrg    }
94705b261ecSmrg
94835c4bbdfSmrg    if (length < pitch) {       /* special case */
94935c4bbdfSmrg        w = length;
95035c4bbdfSmrg        h = 1;
95135c4bbdfSmrg    }
95235c4bbdfSmrg    else {
95335c4bbdfSmrg        w = pitch;
95435c4bbdfSmrg        h = (length + pitch - 1) / pitch;
95535c4bbdfSmrg    }
95635c4bbdfSmrg
95735c4bbdfSmrg    if ((area = localAllocateOffscreenArea(pScreen, w, h, gran,
95835c4bbdfSmrg                                           moveCB ? LinearMoveCBWrapper : NULL,
95935c4bbdfSmrg                                           removeCB ? LinearRemoveCBWrapper :
96035c4bbdfSmrg                                           NULL, privData))) {
96135c4bbdfSmrg        link->area = area;
96235c4bbdfSmrg        link->free = 0;
96335c4bbdfSmrg        link->next = offman->LinearAreas;
96435c4bbdfSmrg        offman->LinearAreas = link;
96535c4bbdfSmrg        linear = &(link->linear);
96635c4bbdfSmrg        linear->pScreen = pScreen;
96735c4bbdfSmrg        linear->size = h * w;
96835c4bbdfSmrg        linear->offset = (pitch * area->box.y1) + area->box.x1;
96935c4bbdfSmrg        if (gran > 1)
97005b261ecSmrg            linear->offset = ((linear->offset + gran - 1) / gran) * gran;
97135c4bbdfSmrg        linear->granularity = gran;
97235c4bbdfSmrg        linear->MoveLinearCallback = moveCB;
97335c4bbdfSmrg        linear->RemoveLinearCallback = removeCB;
97435c4bbdfSmrg        linear->devPrivate.ptr = privData;
97535c4bbdfSmrg    }
97635c4bbdfSmrg    else
97735c4bbdfSmrg        free(link);
97805b261ecSmrg
97935c4bbdfSmrg    DumpDebug(offman->LinearAreas);
98005b261ecSmrg
98135c4bbdfSmrg    return linear;
98205b261ecSmrg}
98305b261ecSmrg
98435c4bbdfSmrgstatic void
98505b261ecSmrglocalFreeOffscreenLinear(FBLinearPtr linear)
98605b261ecSmrg{
98735c4bbdfSmrg    FBManagerPtr offman;
98835c4bbdfSmrg    FBLinearLinkPtr pLink, pLinkPrev = NULL;
98935c4bbdfSmrg    ScreenPtr pScreen = linear->pScreen;
99035c4bbdfSmrg
99135c4bbdfSmrg    offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
99235c4bbdfSmrg                                             xf86FBScreenKey);
99335c4bbdfSmrg    pLink = offman->LinearAreas;
99435c4bbdfSmrg    if (!pLink)
99535c4bbdfSmrg        return;
99635c4bbdfSmrg
99735c4bbdfSmrg    while (&(pLink->linear) != linear) {
99805b261ecSmrg        pLinkPrev = pLink;
99905b261ecSmrg        pLink = pLink->next;
100035c4bbdfSmrg        if (!pLink)
100135c4bbdfSmrg            return;
100235c4bbdfSmrg    }
100335c4bbdfSmrg
100435c4bbdfSmrg    if (pLink->area) {          /* really an XY area */
100535c4bbdfSmrg        DebugF("FREEING AREA\n");
100635c4bbdfSmrg        localFreeOffscreenArea(pLink->area);
100735c4bbdfSmrg        if (pLinkPrev)
100835c4bbdfSmrg            pLinkPrev->next = pLink->next;
100935c4bbdfSmrg        else
101035c4bbdfSmrg            offman->LinearAreas = pLink->next;
10116747b715Smrg        free(pLink);
101235c4bbdfSmrg        DumpDebug(offman->LinearAreas);
101335c4bbdfSmrg        return;
101435c4bbdfSmrg    }
101505b261ecSmrg
101635c4bbdfSmrg    pLink->free = 1;
101705b261ecSmrg
101835c4bbdfSmrg    if (pLink->next && pLink->next->free) {
101935c4bbdfSmrg        FBLinearLinkPtr p = pLink->next;
102035c4bbdfSmrg
102135c4bbdfSmrg        pLink->linear.size += p->linear.size;
102235c4bbdfSmrg        pLink->next = p->next;
102335c4bbdfSmrg        free(p);
102435c4bbdfSmrg    }
102535c4bbdfSmrg
102635c4bbdfSmrg    if (pLinkPrev) {
102735c4bbdfSmrg        if (pLinkPrev->next && pLinkPrev->next->free && !pLinkPrev->area) {
102835c4bbdfSmrg            FBLinearLinkPtr p = pLinkPrev->next;
102935c4bbdfSmrg
103035c4bbdfSmrg            pLinkPrev->linear.size += p->linear.size;
103135c4bbdfSmrg            pLinkPrev->next = p->next;
103235c4bbdfSmrg            free(p);
103335c4bbdfSmrg        }
103435c4bbdfSmrg    }
103535c4bbdfSmrg
103635c4bbdfSmrg    DebugF("FREEING LINEAR\n");
103735c4bbdfSmrg    DumpDebug(offman->LinearAreas);
103835c4bbdfSmrg}
103935c4bbdfSmrg
104035c4bbdfSmrgstatic Bool
104105b261ecSmrglocalResizeOffscreenLinear(FBLinearPtr resize, int length)
104205b261ecSmrg{
104335c4bbdfSmrg    FBManagerPtr offman;
104435c4bbdfSmrg    FBLinearLinkPtr pLink;
104535c4bbdfSmrg    ScreenPtr pScreen = resize->pScreen;
104635c4bbdfSmrg
104735c4bbdfSmrg    offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
104835c4bbdfSmrg                                             xf86FBScreenKey);
104935c4bbdfSmrg    pLink = offman->LinearAreas;
105035c4bbdfSmrg    if (!pLink)
105135c4bbdfSmrg        return FALSE;
105235c4bbdfSmrg
105335c4bbdfSmrg    while (&(pLink->linear) != resize) {
105405b261ecSmrg        pLink = pLink->next;
105535c4bbdfSmrg        if (!pLink)
105635c4bbdfSmrg            return FALSE;
105735c4bbdfSmrg    }
105835c4bbdfSmrg
1059ed6184dfSmrg    /* This could actually be a lot smarter and try to move allocations
106035c4bbdfSmrg       from XY to linear when available.  For now if it was XY, we keep
106135c4bbdfSmrg       it XY */
106235c4bbdfSmrg
106335c4bbdfSmrg    if (pLink->area) {          /* really an XY area */
106435c4bbdfSmrg        BoxPtr extents;
106535c4bbdfSmrg        int pitch, w, h;
106635c4bbdfSmrg
106735c4bbdfSmrg        extents = RegionExtents(offman->InitialBoxes);
106835c4bbdfSmrg        pitch = extents->x2 - extents->x1;
106935c4bbdfSmrg
107035c4bbdfSmrg        if (length < pitch) {   /* special case */
107135c4bbdfSmrg            w = length;
107235c4bbdfSmrg            h = 1;
107335c4bbdfSmrg        }
107435c4bbdfSmrg        else {
107535c4bbdfSmrg            w = pitch;
107635c4bbdfSmrg            h = (length + pitch - 1) / pitch;
107735c4bbdfSmrg        }
107805b261ecSmrg
107935c4bbdfSmrg        if (localResizeOffscreenArea(pLink->area, w, h)) {
108035c4bbdfSmrg            resize->size = h * w;
108135c4bbdfSmrg            resize->offset =
108235c4bbdfSmrg                (pitch * pLink->area->box.y1) + pLink->area->box.x1;
108335c4bbdfSmrg            return TRUE;
108435c4bbdfSmrg        }
108535c4bbdfSmrg    }
108635c4bbdfSmrg    else {
108735c4bbdfSmrg        /* TODO!!!! resize the linear area */
108835c4bbdfSmrg    }
108935c4bbdfSmrg
109035c4bbdfSmrg    return FALSE;
109135c4bbdfSmrg}
109205b261ecSmrg
109305b261ecSmrgstatic Bool
109435c4bbdfSmrglocalQueryLargestOffscreenLinear(ScreenPtr pScreen,
109535c4bbdfSmrg                                 int *size, int gran, int priority)
109605b261ecSmrg{
109735c4bbdfSmrg    FBManagerPtr offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
109835c4bbdfSmrg                                                          xf86FBScreenKey);
109905b261ecSmrg    FBLinearLinkPtr pLink;
110005b261ecSmrg    FBLinearLinkPtr pLinkRet;
110105b261ecSmrg
110205b261ecSmrg    *size = 0;
110335c4bbdfSmrg
110405b261ecSmrg    pLink = offman->LinearAreas;
110505b261ecSmrg
110605b261ecSmrg    if (pLink && !pLink->area) {
110735c4bbdfSmrg        pLinkRet = pLink;
110835c4bbdfSmrg        while (pLink) {
110935c4bbdfSmrg            if (pLink->free) {
111035c4bbdfSmrg                if (pLink->linear.size > pLinkRet->linear.size)
111135c4bbdfSmrg                    pLinkRet = pLink;
111235c4bbdfSmrg            }
111335c4bbdfSmrg            pLink = pLink->next;
111435c4bbdfSmrg        }
111535c4bbdfSmrg
111635c4bbdfSmrg        if (pLinkRet->free) {
111735c4bbdfSmrg            *size = pLinkRet->linear.size;
111835c4bbdfSmrg            return TRUE;
111905b261ecSmrg        }
112005b261ecSmrg    }
112135c4bbdfSmrg    else {
112235c4bbdfSmrg        int w, h;
112305b261ecSmrg
112435c4bbdfSmrg        if (localQueryLargestOffscreenArea(pScreen, &w, &h, gran,
112535c4bbdfSmrg                                           FAVOR_WIDTH_THEN_AREA, priority)) {
112635c4bbdfSmrg            BoxPtr extents;
112705b261ecSmrg
112835c4bbdfSmrg            extents = RegionExtents(offman->InitialBoxes);
112935c4bbdfSmrg            if ((extents->x2 - extents->x1) == w)
113035c4bbdfSmrg                *size = w * h;
113135c4bbdfSmrg            return TRUE;
113235c4bbdfSmrg        }
113335c4bbdfSmrg    }
113405b261ecSmrg
113535c4bbdfSmrg    return FALSE;
113635c4bbdfSmrg}
113705b261ecSmrg
113805b261ecSmrgstatic FBManagerFuncs xf86FBManFuncs = {
113935c4bbdfSmrg    localAllocateOffscreenArea,
114035c4bbdfSmrg    localFreeOffscreenArea,
114135c4bbdfSmrg    localResizeOffscreenArea,
114235c4bbdfSmrg    localQueryLargestOffscreenArea,
114335c4bbdfSmrg    localRegisterFreeBoxCallback,
114435c4bbdfSmrg    localAllocateOffscreenLinear,
114535c4bbdfSmrg    localFreeOffscreenLinear,
114635c4bbdfSmrg    localResizeOffscreenLinear,
114735c4bbdfSmrg    localQueryLargestOffscreenLinear,
114835c4bbdfSmrg    localPurgeUnlockedOffscreenAreas
114935c4bbdfSmrg};
115005b261ecSmrg
115105b261ecSmrgstatic Bool
115235c4bbdfSmrgxf86FBCloseScreen(ScreenPtr pScreen)
115305b261ecSmrg{
115435c4bbdfSmrg    FBLinkPtr pLink, tmp;
115535c4bbdfSmrg    FBLinearLinkPtr pLinearLink, tmp2;
115635c4bbdfSmrg    FBManagerPtr offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
115735c4bbdfSmrg                                                          xf86FBScreenKey);
115835c4bbdfSmrg
115935c4bbdfSmrg    pScreen->CloseScreen = offman->CloseScreen;
116035c4bbdfSmrg
116135c4bbdfSmrg    pLink = offman->UsedAreas;
116235c4bbdfSmrg    while (pLink) {
116335c4bbdfSmrg        tmp = pLink;
116435c4bbdfSmrg        pLink = pLink->next;
116535c4bbdfSmrg        free(tmp);
116635c4bbdfSmrg    }
116735c4bbdfSmrg
116835c4bbdfSmrg    pLinearLink = offman->LinearAreas;
116935c4bbdfSmrg    while (pLinearLink) {
117035c4bbdfSmrg        tmp2 = pLinearLink;
117135c4bbdfSmrg        pLinearLink = pLinearLink->next;
117235c4bbdfSmrg        free(tmp2);
117335c4bbdfSmrg    }
117435c4bbdfSmrg
117535c4bbdfSmrg    RegionDestroy(offman->InitialBoxes);
117635c4bbdfSmrg    RegionDestroy(offman->FreeBoxes);
117735c4bbdfSmrg
117835c4bbdfSmrg    free(offman->FreeBoxesUpdateCallback);
117935c4bbdfSmrg    free(offman->devPrivates);
118035c4bbdfSmrg    free(offman);
118135c4bbdfSmrg    dixSetPrivate(&pScreen->devPrivates, xf86FBScreenKey, NULL);
118235c4bbdfSmrg
118335c4bbdfSmrg    return (*pScreen->CloseScreen) (pScreen);
118405b261ecSmrg}
118505b261ecSmrg
11866747b715SmrgBool
118735c4bbdfSmrgxf86InitFBManager(ScreenPtr pScreen, BoxPtr FullBox)
118835c4bbdfSmrg{
118935c4bbdfSmrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
119035c4bbdfSmrg    RegionRec ScreenRegion;
119135c4bbdfSmrg    RegionRec FullRegion;
119235c4bbdfSmrg    BoxRec ScreenBox;
119335c4bbdfSmrg    Bool ret;
119435c4bbdfSmrg
119535c4bbdfSmrg    ScreenBox.x1 = 0;
119635c4bbdfSmrg    ScreenBox.y1 = 0;
119735c4bbdfSmrg    ScreenBox.x2 = pScrn->virtualX;
119835c4bbdfSmrg    ScreenBox.y2 = pScrn->virtualY;
119935c4bbdfSmrg
120035c4bbdfSmrg    if ((FullBox->x1 > ScreenBox.x1) || (FullBox->y1 > ScreenBox.y1) ||
120135c4bbdfSmrg        (FullBox->x2 < ScreenBox.x2) || (FullBox->y2 < ScreenBox.y2)) {
120235c4bbdfSmrg        return FALSE;
120335c4bbdfSmrg    }
120435c4bbdfSmrg
120535c4bbdfSmrg    if (FullBox->y2 < FullBox->y1)
120635c4bbdfSmrg        return FALSE;
120735c4bbdfSmrg    if (FullBox->x2 < FullBox->x1)
120835c4bbdfSmrg        return FALSE;
120935c4bbdfSmrg
121035c4bbdfSmrg    RegionInit(&ScreenRegion, &ScreenBox, 1);
121135c4bbdfSmrg    RegionInit(&FullRegion, FullBox, 1);
121235c4bbdfSmrg
121335c4bbdfSmrg    RegionSubtract(&FullRegion, &FullRegion, &ScreenRegion);
121435c4bbdfSmrg
121535c4bbdfSmrg    ret = xf86InitFBManagerRegion(pScreen, &FullRegion);
121635c4bbdfSmrg
121735c4bbdfSmrg    RegionUninit(&ScreenRegion);
121835c4bbdfSmrg    RegionUninit(&FullRegion);
121935c4bbdfSmrg
122035c4bbdfSmrg    return ret;
122105b261ecSmrg}
122205b261ecSmrg
12236747b715SmrgBool
122435c4bbdfSmrgxf86InitFBManagerArea(ScreenPtr pScreen, int PixelArea, int Verbosity)
122505b261ecSmrg{
122635c4bbdfSmrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
122705b261ecSmrg    xRectangle Rect[3];
122805b261ecSmrg    RegionPtr pRegion, pScreenRegion;
122905b261ecSmrg    int nRect;
123005b261ecSmrg    Bool ret = FALSE;
123105b261ecSmrg
123205b261ecSmrg    if (PixelArea < (pScrn->displayWidth * pScrn->virtualY))
123335c4bbdfSmrg        return FALSE;
123405b261ecSmrg
123505b261ecSmrg    Rect[0].x = Rect[0].y = 0;
123605b261ecSmrg    Rect[0].width = pScrn->displayWidth;
123705b261ecSmrg    Rect[0].height = PixelArea / pScrn->displayWidth;
123805b261ecSmrg    nRect = 1;
123905b261ecSmrg
124005b261ecSmrg    /* Add a possible partial scanline */
124105b261ecSmrg    if ((Rect[1].height = Rect[1].width = PixelArea % pScrn->displayWidth)) {
124235c4bbdfSmrg        Rect[1].x = 0;
124335c4bbdfSmrg        Rect[1].y = Rect[0].height;
124435c4bbdfSmrg        Rect[1].height = 1;
124535c4bbdfSmrg        nRect++;
124605b261ecSmrg    }
124705b261ecSmrg
124805b261ecSmrg    /* Factor out virtual resolution */
12496747b715Smrg    pRegion = RegionFromRects(nRect, Rect, 0);
125005b261ecSmrg    if (pRegion) {
125135c4bbdfSmrg        if (!RegionNar(pRegion)) {
125235c4bbdfSmrg            Rect[2].x = Rect[2].y = 0;
125335c4bbdfSmrg            Rect[2].width = pScrn->virtualX;
125435c4bbdfSmrg            Rect[2].height = pScrn->virtualY;
125535c4bbdfSmrg
125635c4bbdfSmrg            pScreenRegion = RegionFromRects(1, &Rect[2], 0);
125735c4bbdfSmrg            if (pScreenRegion) {
125835c4bbdfSmrg                if (!RegionNar(pScreenRegion)) {
125935c4bbdfSmrg                    RegionSubtract(pRegion, pRegion, pScreenRegion);
126035c4bbdfSmrg
126135c4bbdfSmrg                    ret = xf86InitFBManagerRegion(pScreen, pRegion);
126235c4bbdfSmrg
126335c4bbdfSmrg                    if (ret && xf86GetVerbosity() >= Verbosity) {
126435c4bbdfSmrg                        int scrnIndex = pScrn->scrnIndex;
126535c4bbdfSmrg
126635c4bbdfSmrg                        xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity,
126735c4bbdfSmrg                                       "Largest offscreen areas (with overlaps):\n");
126835c4bbdfSmrg
126935c4bbdfSmrg                        if (Rect[2].width < Rect[0].width) {
127035c4bbdfSmrg                            xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity,
127135c4bbdfSmrg                                           "\t%d x %d rectangle at %d,0\n",
127235c4bbdfSmrg                                           Rect[0].width - Rect[2].width,
127335c4bbdfSmrg                                           Rect[0].height, Rect[2].width);
127435c4bbdfSmrg                        }
127535c4bbdfSmrg                        if (Rect[2].width < Rect[1].width) {
127635c4bbdfSmrg                            xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity,
127735c4bbdfSmrg                                           "\t%d x %d rectangle at %d,0\n",
127835c4bbdfSmrg                                           Rect[1].width - Rect[2].width,
127935c4bbdfSmrg                                           Rect[0].height + Rect[1].height,
128035c4bbdfSmrg                                           Rect[2].width);
128135c4bbdfSmrg                        }
128235c4bbdfSmrg                        if (Rect[2].height < Rect[0].height) {
128335c4bbdfSmrg                            xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity,
128435c4bbdfSmrg                                           "\t%d x %d rectangle at 0,%d\n",
128535c4bbdfSmrg                                           Rect[0].width,
128635c4bbdfSmrg                                           Rect[0].height - Rect[2].height,
128735c4bbdfSmrg                                           Rect[2].height);
128835c4bbdfSmrg                        }
128935c4bbdfSmrg                        if (Rect[1].height) {
129035c4bbdfSmrg                            xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity,
129135c4bbdfSmrg                                           "\t%d x %d rectangle at 0,%d\n",
129235c4bbdfSmrg                                           Rect[1].width,
129335c4bbdfSmrg                                           Rect[0].height - Rect[2].height +
129435c4bbdfSmrg                                           Rect[1].height, Rect[2].height);
129535c4bbdfSmrg                        }
129635c4bbdfSmrg                    }
129735c4bbdfSmrg                }
129835c4bbdfSmrg
129935c4bbdfSmrg                RegionDestroy(pScreenRegion);
130035c4bbdfSmrg            }
130135c4bbdfSmrg        }
130235c4bbdfSmrg
130335c4bbdfSmrg        RegionDestroy(pRegion);
130405b261ecSmrg    }
130505b261ecSmrg
130605b261ecSmrg    return ret;
130705b261ecSmrg}
130805b261ecSmrg
13096747b715SmrgBool
131035c4bbdfSmrgxf86InitFBManagerRegion(ScreenPtr pScreen, RegionPtr FullRegion)
131135c4bbdfSmrg{
131235c4bbdfSmrg    FBManagerPtr offman;
131305b261ecSmrg
131435c4bbdfSmrg    if (RegionNil(FullRegion))
131535c4bbdfSmrg        return FALSE;
131605b261ecSmrg
131735c4bbdfSmrg    if (!dixRegisterPrivateKey(&xf86FBScreenKeyRec, PRIVATE_SCREEN, 0))
131835c4bbdfSmrg        return FALSE;
13196747b715Smrg
132035c4bbdfSmrg    if (!xf86RegisterOffscreenManager(pScreen, &xf86FBManFuncs))
132135c4bbdfSmrg        return FALSE;
132205b261ecSmrg
132335c4bbdfSmrg    offman = malloc(sizeof(FBManager));
132435c4bbdfSmrg    if (!offman)
132535c4bbdfSmrg        return FALSE;
132605b261ecSmrg
132735c4bbdfSmrg    dixSetPrivate(&pScreen->devPrivates, xf86FBScreenKey, offman);
132805b261ecSmrg
132935c4bbdfSmrg    offman->CloseScreen = pScreen->CloseScreen;
133035c4bbdfSmrg    pScreen->CloseScreen = xf86FBCloseScreen;
133105b261ecSmrg
133235c4bbdfSmrg    offman->InitialBoxes = RegionCreate(NULL, 1);
133335c4bbdfSmrg    offman->FreeBoxes = RegionCreate(NULL, 1);
133405b261ecSmrg
133535c4bbdfSmrg    RegionCopy(offman->InitialBoxes, FullRegion);
133635c4bbdfSmrg    RegionCopy(offman->FreeBoxes, FullRegion);
133705b261ecSmrg
133835c4bbdfSmrg    offman->pScreen = pScreen;
133935c4bbdfSmrg    offman->UsedAreas = NULL;
134035c4bbdfSmrg    offman->LinearAreas = NULL;
134135c4bbdfSmrg    offman->NumUsedAreas = 0;
134235c4bbdfSmrg    offman->NumCallbacks = 0;
134335c4bbdfSmrg    offman->FreeBoxesUpdateCallback = NULL;
134435c4bbdfSmrg    offman->devPrivates = NULL;
134505b261ecSmrg
134635c4bbdfSmrg    return TRUE;
134735c4bbdfSmrg}
134805b261ecSmrg
13496747b715SmrgBool
135035c4bbdfSmrgxf86InitFBManagerLinear(ScreenPtr pScreen, int offset, int size)
135135c4bbdfSmrg{
135235c4bbdfSmrg    FBManagerPtr offman;
135335c4bbdfSmrg    FBLinearLinkPtr link;
135435c4bbdfSmrg    FBLinearPtr linear;
135535c4bbdfSmrg
135635c4bbdfSmrg    if (size <= 0)
135735c4bbdfSmrg        return FALSE;
135835c4bbdfSmrg
135935c4bbdfSmrg    /* we expect people to have called the Area setup first for pixmap cache */
136035c4bbdfSmrg    if (!dixLookupPrivate(&pScreen->devPrivates, xf86FBScreenKey))
136135c4bbdfSmrg        return FALSE;
136235c4bbdfSmrg
136335c4bbdfSmrg    offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
136435c4bbdfSmrg                                             xf86FBScreenKey);
136535c4bbdfSmrg    offman->LinearAreas = malloc(sizeof(FBLinearLink));
136635c4bbdfSmrg    if (!offman->LinearAreas)
136735c4bbdfSmrg        return FALSE;
136835c4bbdfSmrg
136935c4bbdfSmrg    link = offman->LinearAreas;
137035c4bbdfSmrg    link->area = NULL;
137135c4bbdfSmrg    link->next = NULL;
137235c4bbdfSmrg    link->free = 1;
137335c4bbdfSmrg    linear = &(link->linear);
137435c4bbdfSmrg    linear->pScreen = pScreen;
137535c4bbdfSmrg    linear->size = size;
137635c4bbdfSmrg    linear->offset = offset;
137735c4bbdfSmrg    linear->granularity = 0;
137835c4bbdfSmrg    linear->MoveLinearCallback = NULL;
137935c4bbdfSmrg    linear->RemoveLinearCallback = NULL;
138035c4bbdfSmrg    linear->devPrivate.ptr = NULL;
138105b261ecSmrg
138235c4bbdfSmrg    return TRUE;
138335c4bbdfSmrg}
138405b261ecSmrg
138535c4bbdfSmrg/* This is an implementation specific function and should
138605b261ecSmrg   disappear after the next release.  People should use the
138705b261ecSmrg   real linear functions instead */
138805b261ecSmrg
13896747b715SmrgFBAreaPtr
139035c4bbdfSmrgxf86AllocateLinearOffscreenArea(ScreenPtr pScreen,
139135c4bbdfSmrg                                int length,
139235c4bbdfSmrg                                int gran,
139335c4bbdfSmrg                                MoveAreaCallbackProcPtr moveCB,
139435c4bbdfSmrg                                RemoveAreaCallbackProcPtr removeCB,
139535c4bbdfSmrg                                void *privData)
139635c4bbdfSmrg{
139735c4bbdfSmrg    FBManagerFuncsPtr funcs;
139835c4bbdfSmrg    FBManagerPtr offman;
139935c4bbdfSmrg    BoxPtr extents;
140035c4bbdfSmrg    int w, h;
140135c4bbdfSmrg
140235c4bbdfSmrg    if (xf86FBManagerKey == NULL)
140305b261ecSmrg        return NULL;
140435c4bbdfSmrg    if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates,
140535c4bbdfSmrg                                                       xf86FBManagerKey)))
140605b261ecSmrg        return NULL;
140705b261ecSmrg
140835c4bbdfSmrg    offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
140935c4bbdfSmrg                                             xf86FBScreenKey);
141035c4bbdfSmrg    extents = RegionExtents(offman->InitialBoxes);
141135c4bbdfSmrg    w = extents->x2 - extents->x1;
141205b261ecSmrg
141335c4bbdfSmrg    if (gran > 1) {
141435c4bbdfSmrg        if (gran > w)
141535c4bbdfSmrg            return NULL;
141605b261ecSmrg
141735c4bbdfSmrg        if (w % gran)
141835c4bbdfSmrg            length += gran - 1;
141935c4bbdfSmrg    }
142005b261ecSmrg
142135c4bbdfSmrg    if (length <= w) {          /* special case */
142235c4bbdfSmrg        h = 1;
142335c4bbdfSmrg        w = length;
142435c4bbdfSmrg    }
142535c4bbdfSmrg    else {
142635c4bbdfSmrg        h = (length + w - 1) / w;
142735c4bbdfSmrg    }
142805b261ecSmrg
142935c4bbdfSmrg    return (*funcs->AllocateOffscreenArea) (pScreen, w, h, gran, moveCB,
143035c4bbdfSmrg                                            removeCB, privData);
143105b261ecSmrg}
1432