Commit | Line | Data |
---|---|---|
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 | ||
45 | static DevPrivateKeyRec xf86FBManagerKeyRec; | |
46 | static DevPrivateKey xf86FBManagerKey; | |
47 | ||
48 | Bool | |
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 | |
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 | |
75 | xf86RegisterFreeBoxCallback(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 | ||
91 | FBAreaPtr | |
92 | xf86AllocateOffscreenArea(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 | ||
110 | FBLinearPtr | |
111 | xf86AllocateOffscreenLinear(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 | ||
130 | void | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
310 | localRegisterFreeBoxCallback(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 | ||
344 | static FBAreaPtr | |
345 | AllocateArea(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 | ||
434 | static FBAreaPtr | |
435 | localAllocateOffscreenArea(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 | ||
452 | static void | |
453 | localFreeOffscreenArea(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 | ||
490 | static Bool | |
491 | localResizeOffscreenArea(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 | ||
602 | static Bool | |
603 | localQueryLargestOffscreenArea(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 | ||
724 | static Bool | |
725 | localPurgeUnlockedOffscreenAreas(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 | ||
771 | static void | |
772 | LinearMoveCBWrapper(FBAreaPtr from, FBAreaPtr to) | |
773 | { | |
774 | /* this will never get called */ | |
775 | } | |
776 | ||
777 | static void | |
778 | LinearRemoveCBWrapper(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 | ||
808 | static void | |
809 | DumpDebug(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 | ||
826 | static FBLinearPtr | |
827 | AllocateLinear(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 | ||
900 | static FBLinearPtr | |
901 | localAllocateOffscreenLinear(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 | ||
983 | static void | |
984 | localFreeOffscreenLinear(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 | ||
1039 | static Bool | |
1040 | localResizeOffscreenLinear(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 | ||
1092 | static Bool | |
1093 | localQueryLargestOffscreenLinear(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 | ||
1140 | static FBManagerFuncs xf86FBManFuncs = { | |
1141 | localAllocateOffscreenArea, | |
1142 | localFreeOffscreenArea, | |
1143 | localResizeOffscreenArea, | |
1144 | localQueryLargestOffscreenArea, | |
1145 | localRegisterFreeBoxCallback, | |
1146 | localAllocateOffscreenLinear, | |
1147 | localFreeOffscreenLinear, | |
1148 | localResizeOffscreenLinear, | |
1149 | localQueryLargestOffscreenLinear, | |
1150 | localPurgeUnlockedOffscreenAreas | |
1151 | }; | |
1152 | ||
1153 | static Bool | |
1154 | xf86FBCloseScreen(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 | ||
1188 | Bool | |
1189 | xf86InitFBManager(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 | ||
1225 | Bool | |
1226 | xf86InitFBManagerArea(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 | ||
1311 | Bool | |
1312 | xf86InitFBManagerRegion(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 | ||
1351 | Bool | |
1352 | xf86InitFBManagerLinear(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 | ||
1391 | FBAreaPtr | |
1392 | xf86AllocateLinearOffscreenArea(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 | } |