xf86fbman.c (40680B)
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 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 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 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 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 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 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 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 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 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 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 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 773 LinearMoveCBWrapper(FBAreaPtr from, FBAreaPtr to) 774 { 775 /* this will never get called */ 776 } 777 778 static void 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 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 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 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 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 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 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 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 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 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 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 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 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 }