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