]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/xserver.git/blob - hw/xfree86/common/xf86fbman.c
Imported Upstream version 1.11.4
[glsdk/xserver.git] / hw / xfree86 / common / xf86fbman.c
2 /*
3  * Copyright (c) 1998-2001 by The XFree86 Project, Inc.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21  * OTHER DEALINGS IN THE SOFTWARE.
22  *
23  * Except as contained in this notice, the name of the copyright holder(s)
24  * and author(s) shall not be used in advertising or otherwise to promote
25  * the sale, use or other dealings in this Software without prior written
26  * authorization from the copyright holder(s) and author(s).
27  */
29 #ifdef HAVE_XORG_CONFIG_H
30 #include <xorg-config.h>
31 #endif
33 #include "misc.h"
34 #include "xf86.h"
36 #include <X11/X.h>
37 #include "scrnintstr.h"
38 #include "regionstr.h"
39 #include "xf86fbman.h"
41 /* 
42 #define DEBUG
43 */
45 static DevPrivateKeyRec xf86FBManagerKeyRec;
46 static DevPrivateKey xf86FBManagerKey;
48 Bool xf86RegisterOffscreenManager(
49     ScreenPtr pScreen, 
50     FBManagerFuncsPtr funcs
51 ){
53    xf86FBManagerKey = &xf86FBManagerKeyRec;
55    if (!dixRegisterPrivateKey(&xf86FBManagerKeyRec, PRIVATE_SCREEN, 0))
56        return FALSE;
58    dixSetPrivate(&pScreen->devPrivates, xf86FBManagerKey, funcs);
60    return TRUE;
61 }
64 Bool
65 xf86FBManagerRunning(ScreenPtr pScreen)
66 {
67     if (xf86FBManagerKey == NULL)
68         return FALSE;
70     if(!dixLookupPrivate(&pScreen->devPrivates, xf86FBManagerKey))
71         return FALSE;
73     return TRUE;
74 }
76 Bool
77 xf86RegisterFreeBoxCallback(
78     ScreenPtr pScreen,  
79     FreeBoxCallbackProcPtr FreeBoxCallback,
80     pointer devPriv
81 ){
82    FBManagerFuncsPtr funcs;
84    if(xf86FBManagerKey == NULL) 
85         return FALSE;
86    if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(&pScreen->devPrivates,
87                                                     xf86FBManagerKey)))
88         return FALSE;
90    return (*funcs->RegisterFreeBoxCallback)(pScreen, FreeBoxCallback, devPriv);
91 }
94 FBAreaPtr
95 xf86AllocateOffscreenArea(
96    ScreenPtr pScreen, 
97    int w, int h,
98    int gran,
99    MoveAreaCallbackProcPtr moveCB,
100    RemoveAreaCallbackProcPtr removeCB,
101    pointer privData
102 ){
103    FBManagerFuncsPtr funcs;
105    if(xf86FBManagerKey == NULL) 
106         return NULL;
107    if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(&pScreen->devPrivates,
108                                                     xf86FBManagerKey)))
109         return NULL;
111    return (*funcs->AllocateOffscreenArea)(
112                 pScreen, w, h, gran, moveCB, removeCB, privData);
116 FBLinearPtr
117 xf86AllocateOffscreenLinear(
118     ScreenPtr pScreen, 
119     int length,
120     int gran,
121     MoveLinearCallbackProcPtr moveCB,
122     RemoveLinearCallbackProcPtr removeCB,
123     pointer privData
124 ){
125    FBManagerFuncsPtr funcs;
127    if(xf86FBManagerKey == NULL) 
128         return NULL;
129    if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(&pScreen->devPrivates,
130                                                     xf86FBManagerKey)))
131         return NULL;
133    return (*funcs->AllocateOffscreenLinear)(
134                 pScreen, length, gran, moveCB, removeCB, privData);
138 void
139 xf86FreeOffscreenArea(FBAreaPtr area)
141    FBManagerFuncsPtr funcs;
143    if(!area) return;
145    if(xf86FBManagerKey == NULL) 
146         return;
147    if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(
148             &area->pScreen->devPrivates, xf86FBManagerKey)))
149         return;
151    (*funcs->FreeOffscreenArea)(area);
153    return;
157 void
158 xf86FreeOffscreenLinear(FBLinearPtr linear)
160    FBManagerFuncsPtr funcs;
162    if(!linear) return;
164    if(xf86FBManagerKey == NULL) 
165         return;
166    if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(
167             &linear->pScreen->devPrivates, xf86FBManagerKey)))
168         return;
170    (*funcs->FreeOffscreenLinear)(linear);
172    return;
176 Bool
177 xf86ResizeOffscreenArea(
178    FBAreaPtr resize,
179    int w, int h
180 ){
181    FBManagerFuncsPtr funcs;
183    if(!resize) return FALSE;
185    if(xf86FBManagerKey == NULL) 
186         return FALSE;
187    if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(
188             &resize->pScreen->devPrivates, xf86FBManagerKey)))
189         return FALSE;
191    return (*funcs->ResizeOffscreenArea)(resize, w, h);
194 Bool
195 xf86ResizeOffscreenLinear(
196    FBLinearPtr resize,
197    int size
198 ){
199    FBManagerFuncsPtr funcs;
201    if(!resize) return FALSE;
203    if(xf86FBManagerKey == NULL) 
204         return FALSE;
205    if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(
206             &resize->pScreen->devPrivates, xf86FBManagerKey)))
207         return FALSE;
209    return (*funcs->ResizeOffscreenLinear)(resize, size);
213 Bool
214 xf86QueryLargestOffscreenArea(
215     ScreenPtr pScreen,
216     int *w, int *h,
217     int gran,
218     int preferences,
219     int severity
220 ){
221    FBManagerFuncsPtr funcs;
223    *w = 0;
224    *h = 0;
226    if(xf86FBManagerKey == NULL) 
227         return FALSE;
228    if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(&pScreen->devPrivates,
229                                                     xf86FBManagerKey)))
230         return FALSE;
232    return (*funcs->QueryLargestOffscreenArea)(
233                 pScreen, w, h, gran, preferences, severity);
236 Bool
237 xf86QueryLargestOffscreenLinear(
238     ScreenPtr pScreen,
239     int *size,
240     int gran,
241     int severity
242 ){
243    FBManagerFuncsPtr funcs;
245    *size = 0;
247    if(xf86FBManagerKey == NULL) 
248         return FALSE;
249    if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(&pScreen->devPrivates,
250                                                     xf86FBManagerKey)))
251         return FALSE;
253    return (*funcs->QueryLargestOffscreenLinear)(
254                 pScreen, size, gran, severity);
258 Bool
259 xf86PurgeUnlockedOffscreenAreas(ScreenPtr pScreen)
261    FBManagerFuncsPtr funcs;
263    if(xf86FBManagerKey == NULL) 
264         return FALSE;
265    if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(&pScreen->devPrivates,
266                                                     xf86FBManagerKey)))
267         return FALSE;
269    return (*funcs->PurgeOffscreenAreas)(pScreen);
272 /************************************************************\ 
274    Below is a specific implementation of an offscreen manager.
276 \************************************************************/ 
278 static DevPrivateKeyRec xf86FBScreenKeyRec;
279 #define xf86FBScreenKey (&xf86FBScreenKeyRec)
281 typedef struct _FBLink {
282   FBArea area;
283   struct _FBLink *next;  
284 } FBLink, *FBLinkPtr;
286 typedef struct _FBLinearLink {
287   FBLinear linear;
288   int free;     /* need to add free here as FBLinear is publicly accessible */
289   FBAreaPtr area;       /* only used if allocation came from XY area */
290   struct _FBLinearLink *next;  
291 } FBLinearLink, *FBLinearLinkPtr;
294 typedef struct {
295    ScreenPtr                    pScreen;
296    RegionPtr                    InitialBoxes;
297    RegionPtr                    FreeBoxes;
298    FBLinkPtr                    UsedAreas;
299    int                          NumUsedAreas;
300    FBLinearLinkPtr              LinearAreas;
301    CloseScreenProcPtr           CloseScreen;
302    int                          NumCallbacks;
303    FreeBoxCallbackProcPtr       *FreeBoxesUpdateCallback;
304    DevUnion                     *devPrivates;
305 } FBManager, *FBManagerPtr;
308 static void
309 SendCallFreeBoxCallbacks(FBManagerPtr offman)
311    int i = offman->NumCallbacks;
313    while(i--) {
314         (*offman->FreeBoxesUpdateCallback[i])(
315            offman->pScreen, offman->FreeBoxes, offman->devPrivates[i].ptr);
316    }
319 static Bool
320 localRegisterFreeBoxCallback(
321     ScreenPtr pScreen,  
322     FreeBoxCallbackProcPtr FreeBoxCallback,
323     pointer devPriv
324 ){
325    FBManagerPtr offman;
326    FreeBoxCallbackProcPtr *newCallbacks;
327    DevUnion *newPrivates; 
329    offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates,
330                                            xf86FBScreenKey);
331    newCallbacks = realloc( offman->FreeBoxesUpdateCallback,
332                 sizeof(FreeBoxCallbackProcPtr) * (offman->NumCallbacks + 1));
334    newPrivates = realloc(offman->devPrivates,
335                           sizeof(DevUnion) * (offman->NumCallbacks + 1));
337    if(!newCallbacks || !newPrivates)
338         return FALSE;     
340    offman->FreeBoxesUpdateCallback = newCallbacks;
341    offman->devPrivates = newPrivates;
343    offman->FreeBoxesUpdateCallback[offman->NumCallbacks] = FreeBoxCallback;
344    offman->devPrivates[offman->NumCallbacks].ptr = devPriv;
345    offman->NumCallbacks++;
347    SendCallFreeBoxCallbacks(offman);
349    return TRUE;
353 static FBAreaPtr
354 AllocateArea(
355    FBManagerPtr offman,
356    int w, int h,
357    int granularity,
358    MoveAreaCallbackProcPtr moveCB,
359    RemoveAreaCallbackProcPtr removeCB,
360    pointer privData
361 ){
362    ScreenPtr pScreen = offman->pScreen;
363    FBLinkPtr link = NULL;
364    FBAreaPtr area = NULL;
365    RegionRec NewReg;
366    int i, x = 0, num;
367    BoxPtr boxp;
369    if(granularity <= 1) granularity = 0;
371    boxp = RegionRects(offman->FreeBoxes);
372    num = RegionNumRects(offman->FreeBoxes);
374    /* look through the free boxes */
375    for(i = 0; i < num; i++, boxp++) {
376         x = boxp->x1;
377         if (granularity > 1)
378             x = ((x + granularity - 1) / granularity) * granularity;
380         if(((boxp->y2 - boxp->y1) < h) || ((boxp->x2 - x) < w))
381            continue;
383         link = malloc(sizeof(FBLink));
384         if(!link) return NULL;
386         area = &(link->area);
387         link->next = offman->UsedAreas;
388         offman->UsedAreas = link;
389         offman->NumUsedAreas++;
390         break;
391    }
393    /* try to boot a removeable one out if we are not expendable ourselves */
394    if(!area && !removeCB) {
395         link = offman->UsedAreas;
397         while(link) {
398            if(!link->area.RemoveAreaCallback) {
399                 link = link->next;
400                 continue;
401            }
403            boxp = &(link->area.box);
404            x = boxp->x1;
405            if (granularity > 1)
406                 x = ((x + granularity - 1) / granularity) * granularity;
408            if(((boxp->y2 - boxp->y1) < h) || ((boxp->x2 - x) < w)) {
409                 link = link->next;
410                 continue;
411            }
413            /* bye, bye */
414            (*link->area.RemoveAreaCallback)(&link->area);
415            RegionInit(&NewReg, &(link->area.box), 1);
416            RegionUnion(offman->FreeBoxes, offman->FreeBoxes, &NewReg);
417            RegionUninit(&NewReg);
419            area = &(link->area);
420            break;
421         }
422    }
424    if(area) {
425         area->pScreen = pScreen;
426         area->granularity = granularity;
427         area->box.x1 = x;
428         area->box.x2 = x + w;
429         area->box.y1 = boxp->y1;
430         area->box.y2 = boxp->y1 + h;
431         area->MoveAreaCallback = moveCB;
432         area->RemoveAreaCallback = removeCB;
433         area->devPrivate.ptr = privData;
435         RegionInit(&NewReg, &(area->box), 1);
436         RegionSubtract(offman->FreeBoxes, offman->FreeBoxes, &NewReg);
437         RegionUninit(&NewReg);
438    }
440    return area;
443 static FBAreaPtr
444 localAllocateOffscreenArea(
445    ScreenPtr pScreen, 
446    int w, int h,
447    int gran,
448    MoveAreaCallbackProcPtr moveCB,
449    RemoveAreaCallbackProcPtr removeCB,
450    pointer privData
451 ){
452    FBManagerPtr offman;
453    FBAreaPtr area = NULL;
455    offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates,
456                                            xf86FBScreenKey);
457    if((area = AllocateArea(offman, w, h, gran, moveCB, removeCB, privData)))
458         SendCallFreeBoxCallbacks(offman);
460    return area;
464 static void
465 localFreeOffscreenArea(FBAreaPtr area)
467    FBManagerPtr offman;
468    FBLinkPtr pLink, pLinkPrev = NULL;
469    RegionRec FreedRegion;
470    ScreenPtr pScreen;
472    pScreen = area->pScreen;
473    offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates,
474                                            xf86FBScreenKey);
475    pLink = offman->UsedAreas;
476    if(!pLink) return;  
477  
478    while(&(pLink->area) != area) {
479         pLinkPrev = pLink;
480         pLink = pLink->next;
481         if(!pLink) return;
482    }
484    /* put the area back into the pool */
485    RegionInit(&FreedRegion, &(pLink->area.box), 1);
486    RegionUnion(offman->FreeBoxes, offman->FreeBoxes, &FreedRegion);
487    RegionUninit(&FreedRegion);
489    if(pLinkPrev)
490         pLinkPrev->next = pLink->next;
491    else offman->UsedAreas = pLink->next;
493    free(pLink);
494    offman->NumUsedAreas--;
496    SendCallFreeBoxCallbacks(offman);
498    
501 static Bool
502 localResizeOffscreenArea(
503    FBAreaPtr resize,
504    int w, int h
505 ){
506    FBManagerPtr offman;
507    ScreenPtr pScreen;
508    BoxRec OrigArea;
509    RegionRec FreedReg;
510    FBAreaPtr area = NULL;
511    FBLinkPtr pLink, newLink, pLinkPrev = NULL;
513    pScreen = resize->pScreen;
514    offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates,
515                                            xf86FBScreenKey);
516    /* find this link */
517    if(!(pLink = offman->UsedAreas))
518         return FALSE;  
519  
520    while(&(pLink->area) != resize) {
521         pLinkPrev = pLink;
522         pLink = pLink->next;
523         if(!pLink) return FALSE;
524    }
526    OrigArea.x1 = resize->box.x1;
527    OrigArea.x2 = resize->box.x2;
528    OrigArea.y1 = resize->box.y1;
529    OrigArea.y2 = resize->box.y2;
531    /* if it's smaller, this is easy */
533    if((w <= (resize->box.x2 - resize->box.x1)) && 
534       (h <= (resize->box.y2 - resize->box.y1))) {
535         RegionRec NewReg;
537         resize->box.x2 = resize->box.x1 + w;
538         resize->box.y2 = resize->box.y1 + h;
540         if((resize->box.y2 == OrigArea.y2) &&
541            (resize->box.x2 == OrigArea.x2))
542                 return TRUE;
544         RegionInit(&FreedReg, &OrigArea, 1);
545         RegionInit(&NewReg, &(resize->box), 1);
546         RegionSubtract(&FreedReg, &FreedReg, &NewReg);
547         RegionUnion(offman->FreeBoxes, offman->FreeBoxes, &FreedReg);
548         RegionUninit(&FreedReg);
549         RegionUninit(&NewReg);
551         SendCallFreeBoxCallbacks(offman);
553         return TRUE;
554    }
557    /* otherwise we remove the old region */
559    RegionInit(&FreedReg, &OrigArea, 1);
560    RegionUnion(offman->FreeBoxes, offman->FreeBoxes, &FreedReg);
561   
562    /* remove the old link */
563    if(pLinkPrev)
564         pLinkPrev->next = pLink->next;
565    else offman->UsedAreas = pLink->next;
567    /* and try to add a new one */
569    if((area = AllocateArea(offman, w, h, resize->granularity,
570                 resize->MoveAreaCallback, resize->RemoveAreaCallback,
571                 resize->devPrivate.ptr))) {
573         /* copy data over to our link and replace the new with old */
574         memcpy(resize, area, sizeof(FBArea));
576         pLinkPrev = NULL;
577         newLink = offman->UsedAreas;
579         while(&(newLink->area) != area) {
580             pLinkPrev = newLink;
581             newLink = newLink->next;
582         }
584         if(pLinkPrev)
585             pLinkPrev->next = newLink->next;
586         else offman->UsedAreas = newLink->next;
588         pLink->next = offman->UsedAreas;
589         offman->UsedAreas = pLink;
591         free(newLink);
593         /* AllocateArea added one but we really only exchanged one */
594         offman->NumUsedAreas--;  
595    } else {
596       /* reinstate the old region */
597       RegionSubtract(offman->FreeBoxes, offman->FreeBoxes, &FreedReg);
598       RegionUninit(&FreedReg);
600       pLink->next = offman->UsedAreas;
601       offman->UsedAreas = pLink;
602       return FALSE;
603    }
606    RegionUninit(&FreedReg);
608    SendCallFreeBoxCallbacks(offman);
610    return TRUE;
613 static Bool
614 localQueryLargestOffscreenArea(
615     ScreenPtr pScreen,
616     int *width, int *height,
617     int granularity,
618     int preferences,
619     int severity
620 ){
621     FBManagerPtr offman;
622     RegionPtr newRegion = NULL;
623     BoxPtr pbox;
624     int nbox;
625     int x, w, h, area, oldArea;
627     *width = *height = oldArea = 0;
629     if(granularity <= 1) granularity = 0;
631     if((preferences < 0) || (preferences > 3))
632         return FALSE;   
634     offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates,
635                                             xf86FBScreenKey);
636     if(severity < 0) severity = 0;
637     if(severity > 2) severity = 2;
639     switch(severity) {
640     case 2:
641         if(offman->NumUsedAreas) {
642             FBLinkPtr pLink;
643             RegionRec tmpRegion;
644             newRegion = RegionCreate(NULL, 1);
645             RegionCopy(newRegion, offman->InitialBoxes);
646             pLink = offman->UsedAreas;
648             while(pLink) {
649                 if(!pLink->area.RemoveAreaCallback) {
650                     RegionInit(&tmpRegion, &(pLink->area.box), 1);
651                     RegionSubtract(newRegion, newRegion, &tmpRegion);
652                     RegionUninit(&tmpRegion);
653                 }
654                 pLink = pLink->next;
655             }
657             nbox = RegionNumRects(newRegion);
658             pbox = RegionRects(newRegion);
659             break;
660         }
661     case 1:
662         if(offman->NumUsedAreas) {
663             FBLinkPtr pLink;
664             RegionRec tmpRegion;
665             newRegion = RegionCreate(NULL, 1);
666             RegionCopy(newRegion, offman->FreeBoxes);
667             pLink = offman->UsedAreas;
669             while(pLink) {
670                 if(pLink->area.RemoveAreaCallback) {
671                     RegionInit(&tmpRegion, &(pLink->area.box), 1);
672                     RegionAppend(newRegion, &tmpRegion);
673                     RegionUninit(&tmpRegion);
674                 }
675                 pLink = pLink->next;
676             }
678             nbox = RegionNumRects(newRegion);
679             pbox = RegionRects(newRegion);
680             break;
681         }
682     default:
683         nbox = RegionNumRects(offman->FreeBoxes);
684         pbox = RegionRects(offman->FreeBoxes);
685         break;
686     }
688     while(nbox--) {
689         x = pbox->x1;
690         if (granularity > 1)
691            x = ((x + granularity - 1) / granularity) * granularity;
693         w = pbox->x2 - x;
694         h = pbox->y2 - pbox->y1;
695         area = w * h;
697         if(w > 0) {
698             Bool gotIt = FALSE;
699             switch(preferences) {
700             case FAVOR_AREA_THEN_WIDTH:
701                 if((area > oldArea) || ((area == oldArea) && (w > *width))) 
702                     gotIt = TRUE;
703                 break;
704             case FAVOR_AREA_THEN_HEIGHT:
705                 if((area > oldArea) || ((area == oldArea) && (h > *height)))
706                     gotIt = TRUE;
707                 break;
708             case FAVOR_WIDTH_THEN_AREA:
709                 if((w > *width) || ((w == *width) && (area > oldArea)))
710                     gotIt = TRUE;
711                 break;
712             case FAVOR_HEIGHT_THEN_AREA:
713                 if((h > *height) || ((h == *height) && (area > oldArea)))
714                     gotIt = TRUE;
715                 break;
716             }
717             if(gotIt) {
718                 *width = w;
719                 *height = h;
720                 oldArea = area;
721             }
722         }
723         pbox++;
724     }
726     if(newRegion)
727         RegionDestroy(newRegion);
729     return TRUE;
732 static Bool
733 localPurgeUnlockedOffscreenAreas(ScreenPtr pScreen)
735    FBManagerPtr offman;
736    FBLinkPtr pLink, tmp, pPrev = NULL;
737    RegionRec FreedRegion;
738    Bool anyUsed = FALSE;
740    offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates,
741                                            xf86FBScreenKey);
742    pLink = offman->UsedAreas;
743    if(!pLink) return TRUE;  
744  
745    while(pLink) {
746         if(pLink->area.RemoveAreaCallback) {
747             (*pLink->area.RemoveAreaCallback)(&pLink->area);
749             RegionInit(&FreedRegion, &(pLink->area.box), 1);
750             RegionAppend(offman->FreeBoxes, &FreedRegion);
751             RegionUninit(&FreedRegion);
753             if(pPrev)
754               pPrev->next = pLink->next;
755             else offman->UsedAreas = pLink->next;
757             tmp = pLink;
758             pLink = pLink->next;
759             free(tmp);
760             offman->NumUsedAreas--;
761             anyUsed = TRUE;
762         } else {
763             pPrev = pLink;
764             pLink = pLink->next;
765         }
766    }
768    if(anyUsed) {
769         RegionValidate(offman->FreeBoxes, &anyUsed);
770         SendCallFreeBoxCallbacks(offman);
771    }
773    return TRUE;
776 static void 
777 LinearMoveCBWrapper(FBAreaPtr from, FBAreaPtr to)
779     /* this will never get called */
782 static void 
783 LinearRemoveCBWrapper(FBAreaPtr area)
785    FBManagerPtr offman;
786    FBLinearLinkPtr pLink, pLinkPrev = NULL;
787    ScreenPtr pScreen = area->pScreen;
789    offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates,
790                                            xf86FBScreenKey);
791    pLink = offman->LinearAreas;
792    if(!pLink) return;  
793  
794    while(pLink->area != area) {
795         pLinkPrev = pLink;
796         pLink = pLink->next;
797         if(!pLink) return;
798    }
800    /* give the user the callback it is expecting */
801    (*pLink->linear.RemoveLinearCallback)(&(pLink->linear));
803    if(pLinkPrev)
804         pLinkPrev->next = pLink->next;
805    else offman->LinearAreas = pLink->next;
807    free(pLink);
810 static void
811 DumpDebug(FBLinearLinkPtr pLink)
813 #ifdef DEBUG
814    if (!pLink) ErrorF("MMmm, PLINK IS NULL!\n");
816    while (pLink) {
817          ErrorF("  Offset:%08x, Size:%08x, %s,%s\n",
818                 pLink->linear.offset,
819                 pLink->linear.size,
820                 pLink->free ? "Free" : "Used",
821                 pLink->area ? "Area" : "Linear");
823          pLink = pLink->next;
824    }
825 #endif
828 static FBLinearPtr
829 AllocateLinear(
830    FBManagerPtr offman,
831    int size,
832    int granularity,
833    pointer privData
834 ){
835    ScreenPtr pScreen = offman->pScreen;
836    FBLinearLinkPtr linear = NULL;
837    FBLinearLinkPtr newlink = NULL;
838    int offset, end;
840    if(size <= 0) return NULL;
842    if (!offman->LinearAreas) return NULL;
844    linear = offman->LinearAreas;
845    while (linear) {
846         /* Make sure we get a free area that's not an XY fallback case */
847       if (!linear->area && linear->free) {
848          offset = linear->linear.offset;
849          if (granularity > 1)
850             offset = ((offset + granularity - 1) / granularity) * granularity;
851          end = offset+size;
852          if (end <= (linear->linear.offset + linear->linear.size))
853             break;
854       }
855       linear = linear->next;
856    }
857    if (!linear)
858       return NULL;
860    /* break left */
861    if (offset > linear->linear.offset) {
862       newlink = malloc(sizeof(FBLinearLink));
863       if (!newlink)
864          return NULL;
865       newlink->area = NULL;
866       newlink->linear.offset = offset;
867       newlink->linear.size = linear->linear.size - (offset - linear->linear.offset);
868       newlink->free = 1;
869       newlink->next = linear->next;
870       linear->linear.size -= newlink->linear.size;
871       linear->next = newlink;
872       linear = newlink;
873    }
875    /* break right */
876    if (size < linear->linear.size) {
877       newlink = malloc(sizeof(FBLinearLink));
878       if (!newlink)
879          return NULL;
880       newlink->area = NULL;
881       newlink->linear.offset = offset + size;
882       newlink->linear.size = linear->linear.size - size;
883       newlink->free = 1;
884       newlink->next = linear->next;
885       linear->linear.size = size;
886       linear->next = newlink;
887    }
889    /* p = middle block */
890    linear->linear.granularity = granularity;
891    linear->free = 0;
892    linear->linear.pScreen = pScreen;
893    linear->linear.MoveLinearCallback = NULL;
894    linear->linear.RemoveLinearCallback = NULL;
895    linear->linear.devPrivate.ptr = NULL;
897    DumpDebug(offman->LinearAreas);
899    return &(linear->linear);
902 static FBLinearPtr
903 localAllocateOffscreenLinear(
904     ScreenPtr pScreen, 
905     int length,
906     int gran,
907     MoveLinearCallbackProcPtr moveCB,
908     RemoveLinearCallbackProcPtr removeCB,
909     pointer privData
910 ){
911    FBManagerPtr offman;
912    FBLinearLinkPtr link;
913    FBAreaPtr area;
914    FBLinearPtr linear = NULL;
915    BoxPtr extents;
916    int w, h, pitch;
918    offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates,
919                                            xf86FBScreenKey);
921    /* Try to allocate from linear memory first...... */
922    DebugF("ALLOCATING LINEAR\n");
923    if ((linear = AllocateLinear(offman, length, gran, privData)))
924         return linear;
926    DebugF("NOPE, ALLOCATING AREA\n");
928    if(!(link = malloc(sizeof(FBLinearLink))))
929      return NULL;
931    /* No linear available, so try and pinch some from the XY areas */
932    extents = RegionExtents(offman->InitialBoxes);
933    pitch = extents->x2 - extents->x1;
935    if (gran > 1) {
936         if (gran > pitch) {
937             /* we can't match the specified alignment with XY allocations */
938             free(link);
939             return NULL;
940         }
942         if (pitch % gran) {
943             /* pitch and granularity aren't a perfect match, let's allocate
944              * a bit more so we can align later on
945              */
946             length += gran - 1;
947         }
948     }
950    if(length < pitch) { /* special case */
951         w = length;
952         h = 1;
953    } else {
954         w = pitch;
955         h = (length + pitch - 1) / pitch;
956    }
958    if((area = localAllocateOffscreenArea(pScreen, w, h, gran, 
959                         moveCB   ? LinearMoveCBWrapper   : NULL, 
960                         removeCB ? LinearRemoveCBWrapper : NULL, 
961                         privData))) 
962    {
963         link->area = area;
964         link->free = 0;
965         link->next = offman->LinearAreas;
966         offman->LinearAreas = link;
967         linear = &(link->linear);
968         linear->pScreen = pScreen;
969         linear->size = h * w;
970         linear->offset = (pitch * area->box.y1) + area->box.x1;
971         if (gran > 1)
972             linear->offset = ((linear->offset + gran - 1) / gran) * gran;
973         linear->granularity = gran;
974         linear->MoveLinearCallback = moveCB;
975         linear->RemoveLinearCallback = removeCB;
976         linear->devPrivate.ptr = privData;
977    } else 
978         free(link);
980    DumpDebug(offman->LinearAreas);
982    return linear;
986 static void 
987 localFreeOffscreenLinear(FBLinearPtr linear)
989    FBManagerPtr offman;
990    FBLinearLinkPtr pLink, pLinkPrev = NULL;
991    ScreenPtr pScreen = linear->pScreen;
993    offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates,
994                                            xf86FBScreenKey);
995    pLink = offman->LinearAreas;
996    if(!pLink) return;  
997  
998    while(&(pLink->linear) != linear) {
999         pLinkPrev = pLink;
1000         pLink = pLink->next;
1001         if(!pLink) return;
1002    }
1004    if(pLink->area) {  /* really an XY area */
1005         DebugF("FREEING AREA\n");
1006         localFreeOffscreenArea(pLink->area);
1007         if(pLinkPrev)
1008             pLinkPrev->next = pLink->next;
1009         else offman->LinearAreas = pLink->next;
1010         free(pLink);
1011         DumpDebug(offman->LinearAreas);
1012         return;
1013    }
1015    pLink->free = 1;
1017    if (pLink->next && pLink->next->free) {
1018       FBLinearLinkPtr p = pLink->next;
1019       pLink->linear.size += p->linear.size;
1020       pLink->next = p->next;
1021       free(p);
1022    }
1024    if(pLinkPrev) {
1025         if (pLinkPrev->next && pLinkPrev->next->free && !pLinkPrev->area) {
1026             FBLinearLinkPtr p = pLinkPrev->next;
1027             pLinkPrev->linear.size += p->linear.size;
1028             pLinkPrev->next = p->next;
1029             free(p);
1030         }
1031    } 
1032    
1033    DebugF("FREEING LINEAR\n");
1034    DumpDebug(offman->LinearAreas);
1038 static Bool 
1039 localResizeOffscreenLinear(FBLinearPtr resize, int length)
1041    FBManagerPtr offman;
1042    FBLinearLinkPtr pLink;
1043    ScreenPtr pScreen = resize->pScreen;
1045    offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates,
1046                                            xf86FBScreenKey);
1047    pLink = offman->LinearAreas;
1048    if(!pLink) return FALSE;  
1049  
1050    while(&(pLink->linear) != resize) {
1051         pLink = pLink->next;
1052         if(!pLink) return FALSE;
1053    }
1055    /* This could actually be alot smarter and try to move allocations
1056       from XY to linear when available.  For now if it was XY, we keep
1057       it XY */
1059    if(pLink->area) {  /* really an XY area */
1060         BoxPtr extents;
1061         int pitch, w, h;
1063         extents = RegionExtents(offman->InitialBoxes);
1064         pitch = extents->x2 - extents->x1;
1066         if(length < pitch) { /* special case */
1067             w = length;
1068             h = 1;
1069         } else {
1070             w = pitch;
1071             h = (length + pitch - 1) / pitch;
1072         }
1074         if(localResizeOffscreenArea(pLink->area, w, h)) {
1075             resize->size = h * w;
1076             resize->offset = (pitch * pLink->area->box.y1) + pLink->area->box.x1;
1077             return TRUE;        
1078         }
1079    } else {
1080         /* TODO!!!! resize the linear area */
1081    }
1083    return FALSE;
1087 static Bool
1088 localQueryLargestOffscreenLinear(
1089     ScreenPtr pScreen,
1090     int *size,
1091     int gran,
1092     int priority
1095     FBManagerPtr offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates,
1096                                                          xf86FBScreenKey);
1097     FBLinearLinkPtr pLink;
1098     FBLinearLinkPtr pLinkRet;
1100     *size = 0;
1101     
1102     pLink = offman->LinearAreas;
1104     if (pLink && !pLink->area) {
1105         pLinkRet = pLink;
1106         while (pLink) {
1107             if (pLink->free) {
1108                 if (pLink->linear.size > pLinkRet->linear.size)
1109                     pLinkRet = pLink;
1110             }
1111             pLink = pLink->next;
1112         }
1114         if (pLinkRet->free) {
1115             *size = pLinkRet->linear.size;
1116             return TRUE;
1117         }
1118     } else {
1119         int w, h;
1121         if(localQueryLargestOffscreenArea(pScreen, &w, &h, gran, 
1122                                 FAVOR_WIDTH_THEN_AREA, priority))
1123         {
1124             FBManagerPtr offman;
1125             BoxPtr extents;
1127             offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates,
1128                                                     xf86FBScreenKey);
1129             extents = RegionExtents(offman->InitialBoxes);
1130             if((extents->x2 - extents->x1) == w)
1131                 *size = w * h;
1132             return TRUE;
1133         }
1134     }
1136     return FALSE;
1141 static FBManagerFuncs xf86FBManFuncs = {
1142    localAllocateOffscreenArea,
1143    localFreeOffscreenArea,
1144    localResizeOffscreenArea,
1145    localQueryLargestOffscreenArea,
1146    localRegisterFreeBoxCallback,
1147    localAllocateOffscreenLinear,
1148    localFreeOffscreenLinear,
1149    localResizeOffscreenLinear,
1150    localQueryLargestOffscreenLinear,
1151    localPurgeUnlockedOffscreenAreas
1152  };
1155 static Bool
1156 xf86FBCloseScreen (int i, ScreenPtr pScreen)
1158    FBLinkPtr pLink, tmp;
1159    FBLinearLinkPtr pLinearLink, tmp2;
1160    FBManagerPtr offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates,
1161                                                         xf86FBScreenKey);
1162    
1163    pScreen->CloseScreen = offman->CloseScreen;
1165    pLink = offman->UsedAreas;
1166    while(pLink) {
1167         tmp = pLink;
1168         pLink = pLink->next;
1169         free(tmp);
1170    }
1172    pLinearLink = offman->LinearAreas;
1173    while(pLinearLink) {
1174         tmp2 = pLinearLink;
1175         pLinearLink = pLinearLink->next;
1176         free(tmp2);
1177    }
1179    RegionDestroy(offman->InitialBoxes);
1180    RegionDestroy(offman->FreeBoxes);
1182    free(offman->FreeBoxesUpdateCallback);
1183    free(offman->devPrivates);
1184    free(offman);
1185    dixSetPrivate(&pScreen->devPrivates, xf86FBScreenKey, NULL);
1187    return (*pScreen->CloseScreen) (i, pScreen);
1190 Bool
1191 xf86InitFBManager(
1192     ScreenPtr pScreen,  
1193     BoxPtr FullBox
1194 ){
1195    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1196    RegionRec ScreenRegion;
1197    RegionRec FullRegion;
1198    BoxRec ScreenBox;
1199    Bool ret;
1201    ScreenBox.x1 = 0;
1202    ScreenBox.y1 = 0;
1203    ScreenBox.x2 = pScrn->virtualX;
1204    ScreenBox.y2 = pScrn->virtualY;
1206    if((FullBox->x1 >  ScreenBox.x1) || (FullBox->y1 >  ScreenBox.y1) ||
1207       (FullBox->x2 <  ScreenBox.x2) || (FullBox->y2 <  ScreenBox.y2)) {
1208         return FALSE;   
1209    }
1211    if (FullBox->y2 < FullBox->y1) return FALSE;
1212    if (FullBox->x2 < FullBox->x1) return FALSE;
1214    RegionInit(&ScreenRegion, &ScreenBox, 1);
1215    RegionInit(&FullRegion, FullBox, 1);
1217    RegionSubtract(&FullRegion, &FullRegion, &ScreenRegion);
1219    ret = xf86InitFBManagerRegion(pScreen, &FullRegion);
1221    RegionUninit(&ScreenRegion);
1222    RegionUninit(&FullRegion);
1223     
1224    return ret;
1227 Bool
1228 xf86InitFBManagerArea(
1229     ScreenPtr pScreen,
1230     int PixelArea,
1231     int Verbosity
1234     ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1235     xRectangle Rect[3];
1236     RegionPtr pRegion, pScreenRegion;
1237     int nRect;
1238     Bool ret = FALSE;
1240     if (PixelArea < (pScrn->displayWidth * pScrn->virtualY))
1241         return FALSE;
1243     Rect[0].x = Rect[0].y = 0;
1244     Rect[0].width = pScrn->displayWidth;
1245     Rect[0].height = PixelArea / pScrn->displayWidth;
1246     nRect = 1;
1248     /* Add a possible partial scanline */
1249     if ((Rect[1].height = Rect[1].width = PixelArea % pScrn->displayWidth)) {
1250         Rect[1].x = 0;
1251         Rect[1].y = Rect[0].height;
1252         Rect[1].height = 1;
1253         nRect++;
1254     }
1256     /* Factor out virtual resolution */
1257     pRegion = RegionFromRects(nRect, Rect, 0);
1258     if (pRegion) {
1259         if (!RegionNar(pRegion)) {
1260             Rect[2].x = Rect[2].y = 0;
1261             Rect[2].width = pScrn->virtualX;
1262             Rect[2].height = pScrn->virtualY;
1264             pScreenRegion = RegionFromRects(1, &Rect[2], 0);
1265             if (pScreenRegion) {
1266                 if (!RegionNar(pScreenRegion)) {
1267                     RegionSubtract(pRegion, pRegion, pScreenRegion);
1269                     ret = xf86InitFBManagerRegion(pScreen, pRegion);
1271                     if (ret && xf86GetVerbosity() >= Verbosity) {
1272                         int scrnIndex = pScrn->scrnIndex;
1274                         xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity,
1275                             "Largest offscreen areas (with overlaps):\n");
1277                         if (Rect[2].width < Rect[0].width) {
1278                             xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity,
1279                                 "\t%d x %d rectangle at %d,0\n",
1280                                 Rect[0].width - Rect[2].width,
1281                                 Rect[0].height,
1282                                 Rect[2].width);
1283                         }
1284                         if (Rect[2].width < Rect[1].width) {
1285                             xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity,
1286                                 "\t%d x %d rectangle at %d,0\n",
1287                                 Rect[1].width - Rect[2].width,
1288                                 Rect[0].height + Rect[1].height,
1289                                 Rect[2].width);
1290                         }
1291                         if (Rect[2].height < Rect[0].height) {
1292                             xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity,
1293                                 "\t%d x %d rectangle at 0,%d\n",
1294                                 Rect[0].width,
1295                                 Rect[0].height - Rect[2].height,
1296                                 Rect[2].height);
1297                         }
1298                         if (Rect[1].height) {
1299                             xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity,
1300                                 "\t%d x %d rectangle at 0,%d\n",
1301                                 Rect[1].width,
1302                                 Rect[0].height - Rect[2].height +
1303                                     Rect[1].height,
1304                                 Rect[2].height);
1305                         }
1306                     }
1307                 }
1309                 RegionDestroy(pScreenRegion);
1310             }
1311         }
1313         RegionDestroy(pRegion);
1314     }
1316     return ret;
1319 Bool
1320 xf86InitFBManagerRegion(
1321     ScreenPtr pScreen,  
1322     RegionPtr FullRegion
1323 ){
1324    FBManagerPtr offman;
1326    if(RegionNil(FullRegion))
1327         return FALSE;
1329    if (!dixRegisterPrivateKey(&xf86FBScreenKeyRec, PRIVATE_SCREEN, 0))
1330        return FALSE;
1332    if(!xf86RegisterOffscreenManager(pScreen, &xf86FBManFuncs))
1333         return FALSE;
1335    offman = malloc(sizeof(FBManager));
1336    if(!offman) return FALSE;
1338    dixSetPrivate(&pScreen->devPrivates, xf86FBScreenKey, offman);
1340    offman->CloseScreen = pScreen->CloseScreen;
1341    pScreen->CloseScreen = xf86FBCloseScreen;
1343    offman->InitialBoxes = RegionCreate(NULL, 1);
1344    offman->FreeBoxes = RegionCreate(NULL, 1);
1346    RegionCopy(offman->InitialBoxes, FullRegion);
1347    RegionCopy(offman->FreeBoxes, FullRegion);
1349    offman->pScreen = pScreen;
1350    offman->UsedAreas = NULL;
1351    offman->LinearAreas = NULL;
1352    offman->NumUsedAreas = 0;  
1353    offman->NumCallbacks = 0;
1354    offman->FreeBoxesUpdateCallback = NULL;
1355    offman->devPrivates = NULL;
1357    return TRUE;
1358
1360 Bool
1361 xf86InitFBManagerLinear(
1362     ScreenPtr pScreen,  
1363     int offset,
1364     int size
1365 ){
1366    FBManagerPtr offman;
1367    FBLinearLinkPtr link;
1368    FBLinearPtr linear;
1370    if (size <= 0)
1371         return FALSE;
1373    /* we expect people to have called the Area setup first for pixmap cache */
1374    if (!dixLookupPrivate(&pScreen->devPrivates, xf86FBScreenKey))
1375         return FALSE;
1377    offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates,
1378                                            xf86FBScreenKey);
1379    offman->LinearAreas = malloc(sizeof(FBLinearLink));
1380    if (!offman->LinearAreas)
1381         return FALSE;
1383    link = offman->LinearAreas;
1384    link->area = NULL;
1385    link->next = NULL;
1386    link->free = 1;
1387    linear = &(link->linear);
1388    linear->pScreen = pScreen;
1389    linear->size = size;
1390    linear->offset = offset;
1391    linear->granularity = 0;
1392    linear->MoveLinearCallback = NULL;
1393    linear->RemoveLinearCallback = NULL;
1394    linear->devPrivate.ptr = NULL;
1396    return TRUE;
1400 /* This is an implementation specific function and should 
1401    disappear after the next release.  People should use the
1402    real linear functions instead */
1404 FBAreaPtr
1405 xf86AllocateLinearOffscreenArea (
1406    ScreenPtr pScreen, 
1407    int length,
1408    int gran,
1409    MoveAreaCallbackProcPtr moveCB,
1410    RemoveAreaCallbackProcPtr removeCB,
1411    pointer privData
1412 ){
1413    FBManagerFuncsPtr funcs;
1414    FBManagerPtr offman;
1415    BoxPtr extents;
1416    int w, h;
1418    if(xf86FBManagerKey == NULL) 
1419         return NULL;
1420    if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(&pScreen->devPrivates,
1421                                                     xf86FBManagerKey)))
1422         return NULL;
1424    offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates,
1425                                            xf86FBScreenKey);
1426    extents = RegionExtents(offman->InitialBoxes);
1427    w = extents->x2 - extents->x1;
1429    if (gran > 1) {
1430         if (gran > w)
1431             return NULL;
1433         if (w % gran)
1434             length += gran - 1;
1435    }
1437    if(length <= w) { /* special case */
1438         h = 1;
1439         w = length;
1440    } else {
1441         h = (length + w - 1) / w;
1442    }
1444    return (*funcs->AllocateOffscreenArea)(
1445                 pScreen, w, h, gran, moveCB, removeCB, privData);