1 
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  */
28 
29 #ifdef HAVE_XORG_CONFIG_H
30 #include <xorg-config.h>
31 #endif
32 
33 #include "misc.h"
34 #include "xf86.h"
35 
36 #include <X11/X.h>
37 #include "scrnintstr.h"
38 #include "regionstr.h"
39 #include "xf86fbman.h"
40 
41 /*
42 #define DEBUG
43 */
44 
45 static DevPrivateKeyRec xf86FBManagerKeyRec;
46 static DevPrivateKey xf86FBManagerKey;
47 
48 Bool
xf86RegisterOffscreenManager(ScreenPtr pScreen,FBManagerFuncsPtr funcs)49 xf86RegisterOffscreenManager(ScreenPtr pScreen, FBManagerFuncsPtr funcs)
50 {
51 
52     xf86FBManagerKey = &xf86FBManagerKeyRec;
53 
54     if (!dixRegisterPrivateKey(&xf86FBManagerKeyRec, PRIVATE_SCREEN, 0))
55         return FALSE;
56 
57     dixSetPrivate(&pScreen->devPrivates, xf86FBManagerKey, funcs);
58 
59     return TRUE;
60 }
61 
62 Bool
xf86FBManagerRunning(ScreenPtr pScreen)63 xf86FBManagerRunning(ScreenPtr pScreen)
64 {
65     if (xf86FBManagerKey == NULL)
66         return FALSE;
67 
68     if (!dixLookupPrivate(&pScreen->devPrivates, xf86FBManagerKey))
69         return FALSE;
70 
71     return TRUE;
72 }
73 
74 Bool
xf86RegisterFreeBoxCallback(ScreenPtr pScreen,FreeBoxCallbackProcPtr FreeBoxCallback,void * devPriv)75 xf86RegisterFreeBoxCallback(ScreenPtr pScreen,
76                             FreeBoxCallbackProcPtr FreeBoxCallback,
77                             void *devPriv)
78 {
79     FBManagerFuncsPtr funcs;
80 
81     if (xf86FBManagerKey == NULL)
82         return FALSE;
83     if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates,
84                                                        xf86FBManagerKey)))
85         return FALSE;
86 
87     return (*funcs->RegisterFreeBoxCallback) (pScreen, FreeBoxCallback,
88                                               devPriv);
89 }
90 
91 FBAreaPtr
xf86AllocateOffscreenArea(ScreenPtr pScreen,int w,int h,int gran,MoveAreaCallbackProcPtr moveCB,RemoveAreaCallbackProcPtr removeCB,void * privData)92 xf86AllocateOffscreenArea(ScreenPtr pScreen,
93                           int w, int h,
94                           int gran,
95                           MoveAreaCallbackProcPtr moveCB,
96                           RemoveAreaCallbackProcPtr removeCB, void *privData)
97 {
98     FBManagerFuncsPtr funcs;
99 
100     if (xf86FBManagerKey == NULL)
101         return NULL;
102     if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates,
103                                                        xf86FBManagerKey)))
104         return NULL;
105 
106     return (*funcs->AllocateOffscreenArea) (pScreen, w, h, gran, moveCB,
107                                             removeCB, privData);
108 }
109 
110 FBLinearPtr
xf86AllocateOffscreenLinear(ScreenPtr pScreen,int length,int gran,MoveLinearCallbackProcPtr moveCB,RemoveLinearCallbackProcPtr removeCB,void * privData)111 xf86AllocateOffscreenLinear(ScreenPtr pScreen,
112                             int length,
113                             int gran,
114                             MoveLinearCallbackProcPtr moveCB,
115                             RemoveLinearCallbackProcPtr removeCB,
116                             void *privData)
117 {
118     FBManagerFuncsPtr funcs;
119 
120     if (xf86FBManagerKey == NULL)
121         return NULL;
122     if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates,
123                                                        xf86FBManagerKey)))
124         return NULL;
125 
126     return (*funcs->AllocateOffscreenLinear) (pScreen, length, gran, moveCB,
127                                               removeCB, privData);
128 }
129 
130 void
xf86FreeOffscreenArea(FBAreaPtr area)131 xf86FreeOffscreenArea(FBAreaPtr area)
132 {
133     FBManagerFuncsPtr funcs;
134 
135     if (!area)
136         return;
137 
138     if (xf86FBManagerKey == NULL)
139         return;
140     if (!
141         (funcs =
142          (FBManagerFuncsPtr) dixLookupPrivate(&area->pScreen->devPrivates,
143                                               xf86FBManagerKey)))
144         return;
145 
146     (*funcs->FreeOffscreenArea) (area);
147 
148     return;
149 }
150 
151 void
xf86FreeOffscreenLinear(FBLinearPtr linear)152 xf86FreeOffscreenLinear(FBLinearPtr linear)
153 {
154     FBManagerFuncsPtr funcs;
155 
156     if (!linear)
157         return;
158 
159     if (xf86FBManagerKey == NULL)
160         return;
161     if (!
162         (funcs =
163          (FBManagerFuncsPtr) dixLookupPrivate(&linear->pScreen->devPrivates,
164                                               xf86FBManagerKey)))
165         return;
166 
167     (*funcs->FreeOffscreenLinear) (linear);
168 
169     return;
170 }
171 
172 Bool
xf86ResizeOffscreenArea(FBAreaPtr resize,int w,int h)173 xf86ResizeOffscreenArea(FBAreaPtr resize, int w, int h)
174 {
175     FBManagerFuncsPtr funcs;
176 
177     if (!resize)
178         return FALSE;
179 
180     if (xf86FBManagerKey == NULL)
181         return FALSE;
182     if (!
183         (funcs =
184          (FBManagerFuncsPtr) dixLookupPrivate(&resize->pScreen->devPrivates,
185                                               xf86FBManagerKey)))
186         return FALSE;
187 
188     return (*funcs->ResizeOffscreenArea) (resize, w, h);
189 }
190 
191 Bool
xf86ResizeOffscreenLinear(FBLinearPtr resize,int size)192 xf86ResizeOffscreenLinear(FBLinearPtr resize, int size)
193 {
194     FBManagerFuncsPtr funcs;
195 
196     if (!resize)
197         return FALSE;
198 
199     if (xf86FBManagerKey == NULL)
200         return FALSE;
201     if (!
202         (funcs =
203          (FBManagerFuncsPtr) dixLookupPrivate(&resize->pScreen->devPrivates,
204                                               xf86FBManagerKey)))
205         return FALSE;
206 
207     return (*funcs->ResizeOffscreenLinear) (resize, size);
208 }
209 
210 Bool
xf86QueryLargestOffscreenArea(ScreenPtr pScreen,int * w,int * h,int gran,int preferences,int severity)211 xf86QueryLargestOffscreenArea(ScreenPtr pScreen,
212                               int *w, int *h,
213                               int gran, int preferences, int severity)
214 {
215     FBManagerFuncsPtr funcs;
216 
217     *w = 0;
218     *h = 0;
219 
220     if (xf86FBManagerKey == NULL)
221         return FALSE;
222     if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates,
223                                                        xf86FBManagerKey)))
224         return FALSE;
225 
226     return (*funcs->QueryLargestOffscreenArea) (pScreen, w, h, gran,
227                                                 preferences, severity);
228 }
229 
230 Bool
xf86QueryLargestOffscreenLinear(ScreenPtr pScreen,int * size,int gran,int severity)231 xf86QueryLargestOffscreenLinear(ScreenPtr pScreen,
232                                 int *size, int gran, int severity)
233 {
234     FBManagerFuncsPtr funcs;
235 
236     *size = 0;
237 
238     if (xf86FBManagerKey == NULL)
239         return FALSE;
240     if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates,
241                                                        xf86FBManagerKey)))
242         return FALSE;
243 
244     return (*funcs->QueryLargestOffscreenLinear) (pScreen, size, gran,
245                                                   severity);
246 }
247 
248 Bool
xf86PurgeUnlockedOffscreenAreas(ScreenPtr pScreen)249 xf86PurgeUnlockedOffscreenAreas(ScreenPtr pScreen)
250 {
251     FBManagerFuncsPtr funcs;
252 
253     if (xf86FBManagerKey == NULL)
254         return FALSE;
255     if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates,
256                                                        xf86FBManagerKey)))
257         return FALSE;
258 
259     return (*funcs->PurgeOffscreenAreas) (pScreen);
260 }
261 
262 /************************************************************\
263 
264    Below is a specific implementation of an offscreen manager.
265 
266 \************************************************************/
267 
268 static DevPrivateKeyRec xf86FBScreenKeyRec;
269 
270 #define xf86FBScreenKey (&xf86FBScreenKeyRec)
271 
272 typedef struct _FBLink {
273     FBArea area;
274     struct _FBLink *next;
275 } FBLink, *FBLinkPtr;
276 
277 typedef struct _FBLinearLink {
278     FBLinear linear;
279     int free;                   /* need to add free here as FBLinear is publicly accessible */
280     FBAreaPtr area;             /* only used if allocation came from XY area */
281     struct _FBLinearLink *next;
282 } FBLinearLink, *FBLinearLinkPtr;
283 
284 typedef struct {
285     ScreenPtr pScreen;
286     RegionPtr InitialBoxes;
287     RegionPtr FreeBoxes;
288     FBLinkPtr UsedAreas;
289     int NumUsedAreas;
290     FBLinearLinkPtr LinearAreas;
291     CloseScreenProcPtr CloseScreen;
292     int NumCallbacks;
293     FreeBoxCallbackProcPtr *FreeBoxesUpdateCallback;
294     DevUnion *devPrivates;
295 } FBManager, *FBManagerPtr;
296 
297 static void
SendCallFreeBoxCallbacks(FBManagerPtr offman)298 SendCallFreeBoxCallbacks(FBManagerPtr offman)
299 {
300     int i = offman->NumCallbacks;
301 
302     while (i--) {
303         (*offman->FreeBoxesUpdateCallback[i]) (offman->pScreen,
304                                                offman->FreeBoxes,
305                                                offman->devPrivates[i].ptr);
306     }
307 }
308 
309 static Bool
localRegisterFreeBoxCallback(ScreenPtr pScreen,FreeBoxCallbackProcPtr FreeBoxCallback,void * devPriv)310 localRegisterFreeBoxCallback(ScreenPtr pScreen,
311                              FreeBoxCallbackProcPtr FreeBoxCallback,
312                              void *devPriv)
313 {
314     FBManagerPtr offman;
315     FreeBoxCallbackProcPtr *newCallbacks;
316     DevUnion *newPrivates;
317 
318     offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
319                                              xf86FBScreenKey);
320     newCallbacks = reallocarray(offman->FreeBoxesUpdateCallback,
321                                 offman->NumCallbacks + 1,
322                                 sizeof(FreeBoxCallbackProcPtr));
323     if (!newCallbacks)
324         return FALSE;
325     else
326         offman->FreeBoxesUpdateCallback = newCallbacks;
327 
328     newPrivates = reallocarray(offman->devPrivates,
329                                offman->NumCallbacks + 1,
330                                sizeof(DevUnion));
331     if (!newPrivates)
332         return FALSE;
333     else
334         offman->devPrivates = newPrivates;
335 
336     offman->FreeBoxesUpdateCallback[offman->NumCallbacks] = FreeBoxCallback;
337     offman->devPrivates[offman->NumCallbacks].ptr = devPriv;
338     offman->NumCallbacks++;
339 
340     SendCallFreeBoxCallbacks(offman);
341 
342     return TRUE;
343 }
344 
345 static FBAreaPtr
AllocateArea(FBManagerPtr offman,int w,int h,int granularity,MoveAreaCallbackProcPtr moveCB,RemoveAreaCallbackProcPtr removeCB,void * privData)346 AllocateArea(FBManagerPtr offman,
347              int w, int h,
348              int granularity,
349              MoveAreaCallbackProcPtr moveCB,
350              RemoveAreaCallbackProcPtr removeCB, void *privData)
351 {
352     ScreenPtr pScreen = offman->pScreen;
353     FBLinkPtr link = NULL;
354     FBAreaPtr area = NULL;
355     RegionRec NewReg;
356     int i, x = 0, num;
357     BoxPtr boxp;
358 
359     if (granularity <= 1)
360         granularity = 0;
361 
362     boxp = RegionRects(offman->FreeBoxes);
363     num = RegionNumRects(offman->FreeBoxes);
364 
365     /* look through the free boxes */
366     for (i = 0; i < num; i++, boxp++) {
367         x = boxp->x1;
368         if (granularity > 1)
369             x = ((x + granularity - 1) / granularity) * granularity;
370 
371         if (((boxp->y2 - boxp->y1) < h) || ((boxp->x2 - x) < w))
372             continue;
373 
374         link = malloc(sizeof(FBLink));
375         if (!link)
376             return NULL;
377 
378         area = &(link->area);
379         link->next = offman->UsedAreas;
380         offman->UsedAreas = link;
381         offman->NumUsedAreas++;
382         break;
383     }
384 
385     /* try to boot a removable one out if we are not expendable ourselves */
386     if (!area && !removeCB) {
387         link = offman->UsedAreas;
388 
389         while (link) {
390             if (!link->area.RemoveAreaCallback) {
391                 link = link->next;
392                 continue;
393             }
394 
395             boxp = &(link->area.box);
396             x = boxp->x1;
397             if (granularity > 1)
398                 x = ((x + granularity - 1) / granularity) * granularity;
399 
400             if (((boxp->y2 - boxp->y1) < h) || ((boxp->x2 - x) < w)) {
401                 link = link->next;
402                 continue;
403             }
404 
405             /* bye, bye */
406             (*link->area.RemoveAreaCallback) (&link->area);
407             RegionInit(&NewReg, &(link->area.box), 1);
408             RegionUnion(offman->FreeBoxes, offman->FreeBoxes, &NewReg);
409             RegionUninit(&NewReg);
410 
411             area = &(link->area);
412             break;
413         }
414     }
415 
416     if (area) {
417         area->pScreen = pScreen;
418         area->granularity = granularity;
419         area->box.x1 = x;
420         area->box.x2 = x + w;
421         area->box.y1 = boxp->y1;
422         area->box.y2 = boxp->y1 + h;
423         area->MoveAreaCallback = moveCB;
424         area->RemoveAreaCallback = removeCB;
425         area->devPrivate.ptr = privData;
426 
427         RegionInit(&NewReg, &(area->box), 1);
428         RegionSubtract(offman->FreeBoxes, offman->FreeBoxes, &NewReg);
429         RegionUninit(&NewReg);
430     }
431 
432     return area;
433 }
434 
435 static FBAreaPtr
localAllocateOffscreenArea(ScreenPtr pScreen,int w,int h,int gran,MoveAreaCallbackProcPtr moveCB,RemoveAreaCallbackProcPtr removeCB,void * privData)436 localAllocateOffscreenArea(ScreenPtr pScreen,
437                            int w, int h,
438                            int gran,
439                            MoveAreaCallbackProcPtr moveCB,
440                            RemoveAreaCallbackProcPtr removeCB, void *privData)
441 {
442     FBManagerPtr offman;
443     FBAreaPtr area = NULL;
444 
445     offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
446                                              xf86FBScreenKey);
447     if ((area = AllocateArea(offman, w, h, gran, moveCB, removeCB, privData)))
448         SendCallFreeBoxCallbacks(offman);
449 
450     return area;
451 }
452 
453 static void
localFreeOffscreenArea(FBAreaPtr area)454 localFreeOffscreenArea(FBAreaPtr area)
455 {
456     FBManagerPtr offman;
457     FBLinkPtr pLink, pLinkPrev = NULL;
458     RegionRec FreedRegion;
459     ScreenPtr pScreen;
460 
461     pScreen = area->pScreen;
462     offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
463                                              xf86FBScreenKey);
464     pLink = offman->UsedAreas;
465     if (!pLink)
466         return;
467 
468     while (&(pLink->area) != area) {
469         pLinkPrev = pLink;
470         pLink = pLink->next;
471         if (!pLink)
472             return;
473     }
474 
475     /* put the area back into the pool */
476     RegionInit(&FreedRegion, &(pLink->area.box), 1);
477     RegionUnion(offman->FreeBoxes, offman->FreeBoxes, &FreedRegion);
478     RegionUninit(&FreedRegion);
479 
480     if (pLinkPrev)
481         pLinkPrev->next = pLink->next;
482     else
483         offman->UsedAreas = pLink->next;
484 
485     free(pLink);
486     offman->NumUsedAreas--;
487 
488     SendCallFreeBoxCallbacks(offman);
489 }
490 
491 static Bool
localResizeOffscreenArea(FBAreaPtr resize,int w,int h)492 localResizeOffscreenArea(FBAreaPtr resize, int w, int h)
493 {
494     FBManagerPtr offman;
495     ScreenPtr pScreen;
496     BoxRec OrigArea;
497     RegionRec FreedReg;
498     FBAreaPtr area = NULL;
499     FBLinkPtr pLink, newLink, pLinkPrev = NULL;
500 
501     pScreen = resize->pScreen;
502     offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
503                                              xf86FBScreenKey);
504     /* find this link */
505     if (!(pLink = offman->UsedAreas))
506         return FALSE;
507 
508     while (&(pLink->area) != resize) {
509         pLinkPrev = pLink;
510         pLink = pLink->next;
511         if (!pLink)
512             return FALSE;
513     }
514 
515     OrigArea.x1 = resize->box.x1;
516     OrigArea.x2 = resize->box.x2;
517     OrigArea.y1 = resize->box.y1;
518     OrigArea.y2 = resize->box.y2;
519 
520     /* if it's smaller, this is easy */
521 
522     if ((w <= (resize->box.x2 - resize->box.x1)) &&
523         (h <= (resize->box.y2 - resize->box.y1))) {
524         RegionRec NewReg;
525 
526         resize->box.x2 = resize->box.x1 + w;
527         resize->box.y2 = resize->box.y1 + h;
528 
529         if ((resize->box.y2 == OrigArea.y2) && (resize->box.x2 == OrigArea.x2))
530             return TRUE;
531 
532         RegionInit(&FreedReg, &OrigArea, 1);
533         RegionInit(&NewReg, &(resize->box), 1);
534         RegionSubtract(&FreedReg, &FreedReg, &NewReg);
535         RegionUnion(offman->FreeBoxes, offman->FreeBoxes, &FreedReg);
536         RegionUninit(&FreedReg);
537         RegionUninit(&NewReg);
538 
539         SendCallFreeBoxCallbacks(offman);
540 
541         return TRUE;
542     }
543 
544     /* otherwise we remove the old region */
545 
546     RegionInit(&FreedReg, &OrigArea, 1);
547     RegionUnion(offman->FreeBoxes, offman->FreeBoxes, &FreedReg);
548 
549     /* remove the old link */
550     if (pLinkPrev)
551         pLinkPrev->next = pLink->next;
552     else
553         offman->UsedAreas = pLink->next;
554 
555     /* and try to add a new one */
556 
557     if ((area = AllocateArea(offman, w, h, resize->granularity,
558                              resize->MoveAreaCallback,
559                              resize->RemoveAreaCallback,
560                              resize->devPrivate.ptr))) {
561 
562         /* copy data over to our link and replace the new with old */
563         memcpy(resize, area, sizeof(FBArea));
564 
565         pLinkPrev = NULL;
566         newLink = offman->UsedAreas;
567 
568         while (&(newLink->area) != area) {
569             pLinkPrev = newLink;
570             newLink = newLink->next;
571         }
572 
573         if (pLinkPrev)
574             pLinkPrev->next = newLink->next;
575         else
576             offman->UsedAreas = newLink->next;
577 
578         pLink->next = offman->UsedAreas;
579         offman->UsedAreas = pLink;
580 
581         free(newLink);
582 
583         /* AllocateArea added one but we really only exchanged one */
584         offman->NumUsedAreas--;
585     }
586     else {
587         /* reinstate the old region */
588         RegionSubtract(offman->FreeBoxes, offman->FreeBoxes, &FreedReg);
589         RegionUninit(&FreedReg);
590 
591         pLink->next = offman->UsedAreas;
592         offman->UsedAreas = pLink;
593         return FALSE;
594     }
595 
596     RegionUninit(&FreedReg);
597 
598     SendCallFreeBoxCallbacks(offman);
599 
600     return TRUE;
601 }
602 
603 static Bool
localQueryLargestOffscreenArea(ScreenPtr pScreen,int * width,int * height,int granularity,int preferences,int severity)604 localQueryLargestOffscreenArea(ScreenPtr pScreen,
605                                int *width, int *height,
606                                int granularity, int preferences, int severity)
607 {
608     FBManagerPtr offman;
609     RegionPtr newRegion = NULL;
610     BoxPtr pbox;
611     int nbox;
612     int x, w, h, area, oldArea;
613 
614     *width = *height = oldArea = 0;
615 
616     if (granularity <= 1)
617         granularity = 0;
618 
619     if ((preferences < 0) || (preferences > 3))
620         return FALSE;
621 
622     offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
623                                              xf86FBScreenKey);
624     if (severity < 0)
625         severity = 0;
626     if (severity > 2)
627         severity = 2;
628 
629     switch (severity) {
630     case 2:
631         if (offman->NumUsedAreas) {
632             FBLinkPtr pLink;
633             RegionRec tmpRegion;
634 
635             newRegion = RegionCreate(NULL, 1);
636             RegionCopy(newRegion, offman->InitialBoxes);
637             pLink = offman->UsedAreas;
638 
639             while (pLink) {
640                 if (!pLink->area.RemoveAreaCallback) {
641                     RegionInit(&tmpRegion, &(pLink->area.box), 1);
642                     RegionSubtract(newRegion, newRegion, &tmpRegion);
643                     RegionUninit(&tmpRegion);
644                 }
645                 pLink = pLink->next;
646             }
647 
648             nbox = RegionNumRects(newRegion);
649             pbox = RegionRects(newRegion);
650             break;
651         }
652     case 1:
653         if (offman->NumUsedAreas) {
654             FBLinkPtr pLink;
655             RegionRec tmpRegion;
656 
657             newRegion = RegionCreate(NULL, 1);
658             RegionCopy(newRegion, offman->FreeBoxes);
659             pLink = offman->UsedAreas;
660 
661             while (pLink) {
662                 if (pLink->area.RemoveAreaCallback) {
663                     RegionInit(&tmpRegion, &(pLink->area.box), 1);
664                     RegionAppend(newRegion, &tmpRegion);
665                     RegionUninit(&tmpRegion);
666                 }
667                 pLink = pLink->next;
668             }
669 
670             nbox = RegionNumRects(newRegion);
671             pbox = RegionRects(newRegion);
672             break;
673         }
674     default:
675         nbox = RegionNumRects(offman->FreeBoxes);
676         pbox = RegionRects(offman->FreeBoxes);
677         break;
678     }
679 
680     while (nbox--) {
681         x = pbox->x1;
682         if (granularity > 1)
683             x = ((x + granularity - 1) / granularity) * granularity;
684 
685         w = pbox->x2 - x;
686         h = pbox->y2 - pbox->y1;
687         area = w * h;
688 
689         if (w > 0) {
690             Bool gotIt = FALSE;
691 
692             switch (preferences) {
693             case FAVOR_AREA_THEN_WIDTH:
694                 if ((area > oldArea) || ((area == oldArea) && (w > *width)))
695                     gotIt = TRUE;
696                 break;
697             case FAVOR_AREA_THEN_HEIGHT:
698                 if ((area > oldArea) || ((area == oldArea) && (h > *height)))
699                     gotIt = TRUE;
700                 break;
701             case FAVOR_WIDTH_THEN_AREA:
702                 if ((w > *width) || ((w == *width) && (area > oldArea)))
703                     gotIt = TRUE;
704                 break;
705             case FAVOR_HEIGHT_THEN_AREA:
706                 if ((h > *height) || ((h == *height) && (area > oldArea)))
707                     gotIt = TRUE;
708                 break;
709             }
710             if (gotIt) {
711                 *width = w;
712                 *height = h;
713                 oldArea = area;
714             }
715         }
716         pbox++;
717     }
718 
719     if (newRegion)
720         RegionDestroy(newRegion);
721 
722     return TRUE;
723 }
724 
725 static Bool
localPurgeUnlockedOffscreenAreas(ScreenPtr pScreen)726 localPurgeUnlockedOffscreenAreas(ScreenPtr pScreen)
727 {
728     FBManagerPtr offman;
729     FBLinkPtr pLink, tmp, pPrev = NULL;
730     RegionRec FreedRegion;
731     Bool anyUsed = FALSE;
732 
733     offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
734                                              xf86FBScreenKey);
735     pLink = offman->UsedAreas;
736     if (!pLink)
737         return TRUE;
738 
739     while (pLink) {
740         if (pLink->area.RemoveAreaCallback) {
741             (*pLink->area.RemoveAreaCallback) (&pLink->area);
742 
743             RegionInit(&FreedRegion, &(pLink->area.box), 1);
744             RegionAppend(offman->FreeBoxes, &FreedRegion);
745             RegionUninit(&FreedRegion);
746 
747             if (pPrev)
748                 pPrev->next = pLink->next;
749             else
750                 offman->UsedAreas = pLink->next;
751 
752             tmp = pLink;
753             pLink = pLink->next;
754             free(tmp);
755             offman->NumUsedAreas--;
756             anyUsed = TRUE;
757         }
758         else {
759             pPrev = pLink;
760             pLink = pLink->next;
761         }
762     }
763 
764     if (anyUsed) {
765         RegionValidate(offman->FreeBoxes, &anyUsed);
766         SendCallFreeBoxCallbacks(offman);
767     }
768 
769     return TRUE;
770 }
771 
772 static void
LinearMoveCBWrapper(FBAreaPtr from,FBAreaPtr to)773 LinearMoveCBWrapper(FBAreaPtr from, FBAreaPtr to)
774 {
775     /* this will never get called */
776 }
777 
778 static void
LinearRemoveCBWrapper(FBAreaPtr area)779 LinearRemoveCBWrapper(FBAreaPtr area)
780 {
781     FBManagerPtr offman;
782     FBLinearLinkPtr pLink, pLinkPrev = NULL;
783     ScreenPtr pScreen = area->pScreen;
784 
785     offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
786                                              xf86FBScreenKey);
787     pLink = offman->LinearAreas;
788     if (!pLink)
789         return;
790 
791     while (pLink->area != area) {
792         pLinkPrev = pLink;
793         pLink = pLink->next;
794         if (!pLink)
795             return;
796     }
797 
798     /* give the user the callback it is expecting */
799     (*pLink->linear.RemoveLinearCallback) (&(pLink->linear));
800 
801     if (pLinkPrev)
802         pLinkPrev->next = pLink->next;
803     else
804         offman->LinearAreas = pLink->next;
805 
806     free(pLink);
807 }
808 
809 static void
DumpDebug(FBLinearLinkPtr pLink)810 DumpDebug(FBLinearLinkPtr pLink)
811 {
812 #ifdef DEBUG
813     if (!pLink)
814         ErrorF("MMmm, PLINK IS NULL!\n");
815 
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", pLink->area ? "Area" : "Linear");
821 
822         pLink = pLink->next;
823     }
824 #endif
825 }
826 
827 static FBLinearPtr
AllocateLinear(FBManagerPtr offman,int size,int granularity,void * privData)828 AllocateLinear(FBManagerPtr offman, int size, int granularity, void *privData)
829 {
830     ScreenPtr pScreen = offman->pScreen;
831     FBLinearLinkPtr linear = NULL;
832     FBLinearLinkPtr newlink = NULL;
833     int offset, end;
834 
835     if (size <= 0)
836         return NULL;
837 
838     if (!offman->LinearAreas)
839         return NULL;
840 
841     linear = offman->LinearAreas;
842     while (linear) {
843         /* Make sure we get a free area that's not an XY fallback case */
844         if (!linear->area && linear->free) {
845             offset = linear->linear.offset;
846             if (granularity > 1)
847                 offset =
848                     ((offset + granularity - 1) / granularity) * granularity;
849             end = offset + size;
850             if (end <= (linear->linear.offset + linear->linear.size))
851                 break;
852         }
853         linear = linear->next;
854     }
855     if (!linear)
856         return NULL;
857 
858     /* break left */
859     if (offset > linear->linear.offset) {
860         newlink = malloc(sizeof(FBLinearLink));
861         if (!newlink)
862             return NULL;
863         newlink->area = NULL;
864         newlink->linear.offset = offset;
865         newlink->linear.size =
866             linear->linear.size - (offset - linear->linear.offset);
867         newlink->free = 1;
868         newlink->next = linear->next;
869         linear->linear.size -= newlink->linear.size;
870         linear->next = newlink;
871         linear = newlink;
872     }
873 
874     /* break right */
875     if (size < linear->linear.size) {
876         newlink = malloc(sizeof(FBLinearLink));
877         if (!newlink)
878             return NULL;
879         newlink->area = NULL;
880         newlink->linear.offset = offset + size;
881         newlink->linear.size = linear->linear.size - size;
882         newlink->free = 1;
883         newlink->next = linear->next;
884         linear->linear.size = size;
885         linear->next = newlink;
886     }
887 
888     /* p = middle block */
889     linear->linear.granularity = granularity;
890     linear->free = 0;
891     linear->linear.pScreen = pScreen;
892     linear->linear.MoveLinearCallback = NULL;
893     linear->linear.RemoveLinearCallback = NULL;
894     linear->linear.devPrivate.ptr = NULL;
895 
896     DumpDebug(offman->LinearAreas);
897 
898     return &(linear->linear);
899 }
900 
901 static FBLinearPtr
localAllocateOffscreenLinear(ScreenPtr pScreen,int length,int gran,MoveLinearCallbackProcPtr moveCB,RemoveLinearCallbackProcPtr removeCB,void * privData)902 localAllocateOffscreenLinear(ScreenPtr pScreen,
903                              int length,
904                              int gran,
905                              MoveLinearCallbackProcPtr moveCB,
906                              RemoveLinearCallbackProcPtr removeCB,
907                              void *privData)
908 {
909     FBManagerPtr offman;
910     FBLinearLinkPtr link;
911     FBAreaPtr area;
912     FBLinearPtr linear = NULL;
913     BoxPtr extents;
914     int w, h, pitch;
915 
916     offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
917                                              xf86FBScreenKey);
918 
919     /* Try to allocate from linear memory first...... */
920     DebugF("ALLOCATING LINEAR\n");
921     if ((linear = AllocateLinear(offman, length, gran, privData)))
922         return linear;
923 
924     DebugF("NOPE, ALLOCATING AREA\n");
925 
926     if (!(link = malloc(sizeof(FBLinearLink))))
927         return NULL;
928 
929     /* No linear available, so try and pinch some from the XY areas */
930     extents = RegionExtents(offman->InitialBoxes);
931     pitch = extents->x2 - extents->x1;
932 
933     if (gran > 1) {
934         if (gran > pitch) {
935             /* we can't match the specified alignment with XY allocations */
936             free(link);
937             return NULL;
938         }
939 
940         if (pitch % gran) {
941             /* pitch and granularity aren't a perfect match, let's allocate
942              * a bit more so we can align later on
943              */
944             length += gran - 1;
945         }
946     }
947 
948     if (length < pitch) {       /* special case */
949         w = length;
950         h = 1;
951     }
952     else {
953         w = pitch;
954         h = (length + pitch - 1) / pitch;
955     }
956 
957     if ((area = localAllocateOffscreenArea(pScreen, w, h, gran,
958                                            moveCB ? LinearMoveCBWrapper : NULL,
959                                            removeCB ? LinearRemoveCBWrapper :
960                                            NULL, privData))) {
961         link->area = area;
962         link->free = 0;
963         link->next = offman->LinearAreas;
964         offman->LinearAreas = link;
965         linear = &(link->linear);
966         linear->pScreen = pScreen;
967         linear->size = h * w;
968         linear->offset = (pitch * area->box.y1) + area->box.x1;
969         if (gran > 1)
970             linear->offset = ((linear->offset + gran - 1) / gran) * gran;
971         linear->granularity = gran;
972         linear->MoveLinearCallback = moveCB;
973         linear->RemoveLinearCallback = removeCB;
974         linear->devPrivate.ptr = privData;
975     }
976     else
977         free(link);
978 
979     DumpDebug(offman->LinearAreas);
980 
981     return linear;
982 }
983 
984 static void
localFreeOffscreenLinear(FBLinearPtr linear)985 localFreeOffscreenLinear(FBLinearPtr linear)
986 {
987     FBManagerPtr offman;
988     FBLinearLinkPtr pLink, pLinkPrev = NULL;
989     ScreenPtr pScreen = linear->pScreen;
990 
991     offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
992                                              xf86FBScreenKey);
993     pLink = offman->LinearAreas;
994     if (!pLink)
995         return;
996 
997     while (&(pLink->linear) != linear) {
998         pLinkPrev = pLink;
999         pLink = pLink->next;
1000         if (!pLink)
1001             return;
1002     }
1003 
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
1010             offman->LinearAreas = pLink->next;
1011         free(pLink);
1012         DumpDebug(offman->LinearAreas);
1013         return;
1014     }
1015 
1016     pLink->free = 1;
1017 
1018     if (pLink->next && pLink->next->free) {
1019         FBLinearLinkPtr p = pLink->next;
1020 
1021         pLink->linear.size += p->linear.size;
1022         pLink->next = p->next;
1023         free(p);
1024     }
1025 
1026     if (pLinkPrev) {
1027         if (pLinkPrev->next && pLinkPrev->next->free && !pLinkPrev->area) {
1028             FBLinearLinkPtr p = pLinkPrev->next;
1029 
1030             pLinkPrev->linear.size += p->linear.size;
1031             pLinkPrev->next = p->next;
1032             free(p);
1033         }
1034     }
1035 
1036     DebugF("FREEING LINEAR\n");
1037     DumpDebug(offman->LinearAreas);
1038 }
1039 
1040 static Bool
localResizeOffscreenLinear(FBLinearPtr resize,int length)1041 localResizeOffscreenLinear(FBLinearPtr resize, int length)
1042 {
1043     FBManagerPtr offman;
1044     FBLinearLinkPtr pLink;
1045     ScreenPtr pScreen = resize->pScreen;
1046 
1047     offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
1048                                              xf86FBScreenKey);
1049     pLink = offman->LinearAreas;
1050     if (!pLink)
1051         return FALSE;
1052 
1053     while (&(pLink->linear) != resize) {
1054         pLink = pLink->next;
1055         if (!pLink)
1056             return FALSE;
1057     }
1058 
1059     /* This could actually be a lot smarter and try to move allocations
1060        from XY to linear when available.  For now if it was XY, we keep
1061        it XY */
1062 
1063     if (pLink->area) {          /* really an XY area */
1064         BoxPtr extents;
1065         int pitch, w, h;
1066 
1067         extents = RegionExtents(offman->InitialBoxes);
1068         pitch = extents->x2 - extents->x1;
1069 
1070         if (length < pitch) {   /* special case */
1071             w = length;
1072             h = 1;
1073         }
1074         else {
1075             w = pitch;
1076             h = (length + pitch - 1) / pitch;
1077         }
1078 
1079         if (localResizeOffscreenArea(pLink->area, w, h)) {
1080             resize->size = h * w;
1081             resize->offset =
1082                 (pitch * pLink->area->box.y1) + pLink->area->box.x1;
1083             return TRUE;
1084         }
1085     }
1086     else {
1087         /* TODO!!!! resize the linear area */
1088     }
1089 
1090     return FALSE;
1091 }
1092 
1093 static Bool
localQueryLargestOffscreenLinear(ScreenPtr pScreen,int * size,int gran,int priority)1094 localQueryLargestOffscreenLinear(ScreenPtr pScreen,
1095                                  int *size, int gran, int priority)
1096 {
1097     FBManagerPtr offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
1098                                                           xf86FBScreenKey);
1099     FBLinearLinkPtr pLink;
1100     FBLinearLinkPtr pLinkRet;
1101 
1102     *size = 0;
1103 
1104     pLink = offman->LinearAreas;
1105 
1106     if (pLink && !pLink->area) {
1107         pLinkRet = pLink;
1108         while (pLink) {
1109             if (pLink->free) {
1110                 if (pLink->linear.size > pLinkRet->linear.size)
1111                     pLinkRet = pLink;
1112             }
1113             pLink = pLink->next;
1114         }
1115 
1116         if (pLinkRet->free) {
1117             *size = pLinkRet->linear.size;
1118             return TRUE;
1119         }
1120     }
1121     else {
1122         int w, h;
1123 
1124         if (localQueryLargestOffscreenArea(pScreen, &w, &h, gran,
1125                                            FAVOR_WIDTH_THEN_AREA, priority)) {
1126             BoxPtr extents;
1127 
1128             extents = RegionExtents(offman->InitialBoxes);
1129             if ((extents->x2 - extents->x1) == w)
1130                 *size = w * h;
1131             return TRUE;
1132         }
1133     }
1134 
1135     return FALSE;
1136 }
1137 
1138 static FBManagerFuncs xf86FBManFuncs = {
1139     localAllocateOffscreenArea,
1140     localFreeOffscreenArea,
1141     localResizeOffscreenArea,
1142     localQueryLargestOffscreenArea,
1143     localRegisterFreeBoxCallback,
1144     localAllocateOffscreenLinear,
1145     localFreeOffscreenLinear,
1146     localResizeOffscreenLinear,
1147     localQueryLargestOffscreenLinear,
1148     localPurgeUnlockedOffscreenAreas
1149 };
1150 
1151 static Bool
xf86FBCloseScreen(ScreenPtr pScreen)1152 xf86FBCloseScreen(ScreenPtr pScreen)
1153 {
1154     FBLinkPtr pLink, tmp;
1155     FBLinearLinkPtr pLinearLink, tmp2;
1156     FBManagerPtr offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
1157                                                           xf86FBScreenKey);
1158 
1159     pScreen->CloseScreen = offman->CloseScreen;
1160 
1161     pLink = offman->UsedAreas;
1162     while (pLink) {
1163         tmp = pLink;
1164         pLink = pLink->next;
1165         free(tmp);
1166     }
1167 
1168     pLinearLink = offman->LinearAreas;
1169     while (pLinearLink) {
1170         tmp2 = pLinearLink;
1171         pLinearLink = pLinearLink->next;
1172         free(tmp2);
1173     }
1174 
1175     RegionDestroy(offman->InitialBoxes);
1176     RegionDestroy(offman->FreeBoxes);
1177 
1178     free(offman->FreeBoxesUpdateCallback);
1179     free(offman->devPrivates);
1180     free(offman);
1181     dixSetPrivate(&pScreen->devPrivates, xf86FBScreenKey, NULL);
1182 
1183     return (*pScreen->CloseScreen) (pScreen);
1184 }
1185 
1186 Bool
xf86InitFBManager(ScreenPtr pScreen,BoxPtr FullBox)1187 xf86InitFBManager(ScreenPtr pScreen, BoxPtr FullBox)
1188 {
1189     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1190     RegionRec ScreenRegion;
1191     RegionRec FullRegion;
1192     BoxRec ScreenBox;
1193     Bool ret;
1194 
1195     ScreenBox.x1 = 0;
1196     ScreenBox.y1 = 0;
1197     ScreenBox.x2 = pScrn->virtualX;
1198     ScreenBox.y2 = pScrn->virtualY;
1199 
1200     if ((FullBox->x1 > ScreenBox.x1) || (FullBox->y1 > ScreenBox.y1) ||
1201         (FullBox->x2 < ScreenBox.x2) || (FullBox->y2 < ScreenBox.y2)) {
1202         return FALSE;
1203     }
1204 
1205     if (FullBox->y2 < FullBox->y1)
1206         return FALSE;
1207     if (FullBox->x2 < FullBox->x1)
1208         return FALSE;
1209 
1210     RegionInit(&ScreenRegion, &ScreenBox, 1);
1211     RegionInit(&FullRegion, FullBox, 1);
1212 
1213     RegionSubtract(&FullRegion, &FullRegion, &ScreenRegion);
1214 
1215     ret = xf86InitFBManagerRegion(pScreen, &FullRegion);
1216 
1217     RegionUninit(&ScreenRegion);
1218     RegionUninit(&FullRegion);
1219 
1220     return ret;
1221 }
1222 
1223 Bool
xf86InitFBManagerArea(ScreenPtr pScreen,int PixelArea,int Verbosity)1224 xf86InitFBManagerArea(ScreenPtr pScreen, int PixelArea, int Verbosity)
1225 {
1226     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1227     xRectangle Rect[3];
1228     RegionPtr pRegion, pScreenRegion;
1229     int nRect;
1230     Bool ret = FALSE;
1231 
1232     if (PixelArea < (pScrn->displayWidth * pScrn->virtualY))
1233         return FALSE;
1234 
1235     Rect[0].x = Rect[0].y = 0;
1236     Rect[0].width = pScrn->displayWidth;
1237     Rect[0].height = PixelArea / pScrn->displayWidth;
1238     nRect = 1;
1239 
1240     /* Add a possible partial scanline */
1241     if ((Rect[1].height = Rect[1].width = PixelArea % pScrn->displayWidth)) {
1242         Rect[1].x = 0;
1243         Rect[1].y = Rect[0].height;
1244         Rect[1].height = 1;
1245         nRect++;
1246     }
1247 
1248     /* Factor out virtual resolution */
1249     pRegion = RegionFromRects(nRect, Rect, 0);
1250     if (pRegion) {
1251         if (!RegionNar(pRegion)) {
1252             Rect[2].x = Rect[2].y = 0;
1253             Rect[2].width = pScrn->virtualX;
1254             Rect[2].height = pScrn->virtualY;
1255 
1256             pScreenRegion = RegionFromRects(1, &Rect[2], 0);
1257             if (pScreenRegion) {
1258                 if (!RegionNar(pScreenRegion)) {
1259                     RegionSubtract(pRegion, pRegion, pScreenRegion);
1260 
1261                     ret = xf86InitFBManagerRegion(pScreen, pRegion);
1262 
1263                     if (ret && xf86GetVerbosity() >= Verbosity) {
1264                         int scrnIndex = pScrn->scrnIndex;
1265 
1266                         xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity,
1267                                        "Largest offscreen areas (with overlaps):\n");
1268 
1269                         if (Rect[2].width < Rect[0].width) {
1270                             xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity,
1271                                            "\t%d x %d rectangle at %d,0\n",
1272                                            Rect[0].width - Rect[2].width,
1273                                            Rect[0].height, Rect[2].width);
1274                         }
1275                         if (Rect[2].width < Rect[1].width) {
1276                             xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity,
1277                                            "\t%d x %d rectangle at %d,0\n",
1278                                            Rect[1].width - Rect[2].width,
1279                                            Rect[0].height + Rect[1].height,
1280                                            Rect[2].width);
1281                         }
1282                         if (Rect[2].height < Rect[0].height) {
1283                             xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity,
1284                                            "\t%d x %d rectangle at 0,%d\n",
1285                                            Rect[0].width,
1286                                            Rect[0].height - Rect[2].height,
1287                                            Rect[2].height);
1288                         }
1289                         if (Rect[1].height) {
1290                             xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity,
1291                                            "\t%d x %d rectangle at 0,%d\n",
1292                                            Rect[1].width,
1293                                            Rect[0].height - Rect[2].height +
1294                                            Rect[1].height, Rect[2].height);
1295                         }
1296                     }
1297                 }
1298 
1299                 RegionDestroy(pScreenRegion);
1300             }
1301         }
1302 
1303         RegionDestroy(pRegion);
1304     }
1305 
1306     return ret;
1307 }
1308 
1309 Bool
xf86InitFBManagerRegion(ScreenPtr pScreen,RegionPtr FullRegion)1310 xf86InitFBManagerRegion(ScreenPtr pScreen, RegionPtr FullRegion)
1311 {
1312     FBManagerPtr offman;
1313 
1314     if (RegionNil(FullRegion))
1315         return FALSE;
1316 
1317     if (!dixRegisterPrivateKey(&xf86FBScreenKeyRec, PRIVATE_SCREEN, 0))
1318         return FALSE;
1319 
1320     if (!xf86RegisterOffscreenManager(pScreen, &xf86FBManFuncs))
1321         return FALSE;
1322 
1323     offman = malloc(sizeof(FBManager));
1324     if (!offman)
1325         return FALSE;
1326 
1327     dixSetPrivate(&pScreen->devPrivates, xf86FBScreenKey, offman);
1328 
1329     offman->CloseScreen = pScreen->CloseScreen;
1330     pScreen->CloseScreen = xf86FBCloseScreen;
1331 
1332     offman->InitialBoxes = RegionCreate(NULL, 1);
1333     offman->FreeBoxes = RegionCreate(NULL, 1);
1334 
1335     RegionCopy(offman->InitialBoxes, FullRegion);
1336     RegionCopy(offman->FreeBoxes, FullRegion);
1337 
1338     offman->pScreen = pScreen;
1339     offman->UsedAreas = NULL;
1340     offman->LinearAreas = NULL;
1341     offman->NumUsedAreas = 0;
1342     offman->NumCallbacks = 0;
1343     offman->FreeBoxesUpdateCallback = NULL;
1344     offman->devPrivates = NULL;
1345 
1346     return TRUE;
1347 }
1348 
1349 Bool
xf86InitFBManagerLinear(ScreenPtr pScreen,int offset,int size)1350 xf86InitFBManagerLinear(ScreenPtr pScreen, int offset, int size)
1351 {
1352     FBManagerPtr offman;
1353     FBLinearLinkPtr link;
1354     FBLinearPtr linear;
1355 
1356     if (size <= 0)
1357         return FALSE;
1358 
1359     /* we expect people to have called the Area setup first for pixmap cache */
1360     if (!dixLookupPrivate(&pScreen->devPrivates, xf86FBScreenKey))
1361         return FALSE;
1362 
1363     offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
1364                                              xf86FBScreenKey);
1365     offman->LinearAreas = malloc(sizeof(FBLinearLink));
1366     if (!offman->LinearAreas)
1367         return FALSE;
1368 
1369     link = offman->LinearAreas;
1370     link->area = NULL;
1371     link->next = NULL;
1372     link->free = 1;
1373     linear = &(link->linear);
1374     linear->pScreen = pScreen;
1375     linear->size = size;
1376     linear->offset = offset;
1377     linear->granularity = 0;
1378     linear->MoveLinearCallback = NULL;
1379     linear->RemoveLinearCallback = NULL;
1380     linear->devPrivate.ptr = NULL;
1381 
1382     return TRUE;
1383 }
1384 
1385 /* This is an implementation specific function and should
1386    disappear after the next release.  People should use the
1387    real linear functions instead */
1388 
1389 FBAreaPtr
xf86AllocateLinearOffscreenArea(ScreenPtr pScreen,int length,int gran,MoveAreaCallbackProcPtr moveCB,RemoveAreaCallbackProcPtr removeCB,void * privData)1390 xf86AllocateLinearOffscreenArea(ScreenPtr pScreen,
1391                                 int length,
1392                                 int gran,
1393                                 MoveAreaCallbackProcPtr moveCB,
1394                                 RemoveAreaCallbackProcPtr removeCB,
1395                                 void *privData)
1396 {
1397     FBManagerFuncsPtr funcs;
1398     FBManagerPtr offman;
1399     BoxPtr extents;
1400     int w, h;
1401 
1402     if (xf86FBManagerKey == NULL)
1403         return NULL;
1404     if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates,
1405                                                        xf86FBManagerKey)))
1406         return NULL;
1407 
1408     offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
1409                                              xf86FBScreenKey);
1410     extents = RegionExtents(offman->InitialBoxes);
1411     w = extents->x2 - extents->x1;
1412 
1413     if (gran > 1) {
1414         if (gran > w)
1415             return NULL;
1416 
1417         if (w % gran)
1418             length += gran - 1;
1419     }
1420 
1421     if (length <= w) {          /* special case */
1422         h = 1;
1423         w = length;
1424     }
1425     else {
1426         h = (length + w - 1) / w;
1427     }
1428 
1429     return (*funcs->AllocateOffscreenArea) (pScreen, w, h, gran, moveCB,
1430                                             removeCB, privData);
1431 }
1432