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