1/* 2 * Copyright (c) 1998-2001 by The XFree86 Project, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Except as contained in this notice, the name of the copyright holder(s) 23 * and author(s) shall not be used in advertising or otherwise to promote 24 * the sale, use or other dealings in this Software without prior written 25 * authorization from the copyright holder(s) and author(s). 26 */ 27 28#ifdef HAVE_XORG_CONFIG_H 29#include <xorg-config.h> 30#endif 31 32#if defined(_XOPEN_SOURCE) || defined(__sun) && defined(__SVR4) 33#include <math.h> 34#else 35#define _XOPEN_SOURCE /* to get prototype for pow on some systems */ 36#include <math.h> 37#undef _XOPEN_SOURCE 38#endif 39 40#include <X11/X.h> 41#include "misc.h" 42#include <X11/Xproto.h> 43#include "colormapst.h" 44#include "scrnintstr.h" 45 46#include "resource.h" 47 48#include "xf86.h" 49#include "xf86_OSproc.h" 50#include "xf86str.h" 51#include "micmap.h" 52#include "xf86RandR12.h" 53#include "xf86Crtc.h" 54 55#ifdef XFreeXDGA 56#include <X11/extensions/xf86dgaproto.h> 57#include "dgaproc.h" 58#endif 59 60#include "xf86cmap.h" 61 62#define SCREEN_PROLOGUE(pScreen, field) ((pScreen)->field = \ 63 ((CMapScreenPtr)dixLookupPrivate(&(pScreen)->devPrivates, CMapScreenKey))->field) 64#define SCREEN_EPILOGUE(pScreen, field, wrapper)\ 65 ((pScreen)->field = wrapper) 66 67#define LOAD_PALETTE(pmap) \ 68 ((pmap == GetInstalledmiColormap(pmap->pScreen)) && \ 69 ((pScreenPriv->flags & CMAP_LOAD_EVEN_IF_OFFSCREEN) || \ 70 xf86ScreenToScrn(pmap->pScreen)->vtSema || pScreenPriv->isDGAmode)) 71 72typedef struct _CMapLink { 73 ColormapPtr cmap; 74 struct _CMapLink *next; 75} CMapLink, *CMapLinkPtr; 76 77typedef struct { 78 CloseScreenProcPtr CloseScreen; 79 CreateColormapProcPtr CreateColormap; 80 DestroyColormapProcPtr DestroyColormap; 81 InstallColormapProcPtr InstallColormap; 82 StoreColorsProcPtr StoreColors; 83 Bool (*EnterVT) (ScrnInfoPtr); 84 Bool (*SwitchMode) (ScrnInfoPtr, DisplayModePtr); 85 int (*SetDGAMode) (ScrnInfoPtr, int, DGADevicePtr); 86 xf86ChangeGammaProc *ChangeGamma; 87 int maxColors; 88 int sigRGBbits; 89 int gammaElements; 90 LOCO *gamma; 91 int *PreAllocIndices; 92 CMapLinkPtr maps; 93 unsigned int flags; 94 Bool isDGAmode; 95} CMapScreenRec, *CMapScreenPtr; 96 97typedef struct { 98 int numColors; 99 LOCO *colors; 100 Bool recalculate; 101 int overscan; 102} CMapColormapRec, *CMapColormapPtr; 103 104static DevPrivateKeyRec CMapScreenKeyRec; 105 106#define CMapScreenKeyRegistered dixPrivateKeyRegistered(&CMapScreenKeyRec) 107#define CMapScreenKey (&CMapScreenKeyRec) 108static DevPrivateKeyRec CMapColormapKeyRec; 109 110#define CMapColormapKey (&CMapColormapKeyRec) 111 112static void CMapInstallColormap(ColormapPtr); 113static void CMapStoreColors(ColormapPtr, int, xColorItem *); 114static Bool CMapCloseScreen(ScreenPtr); 115static Bool CMapCreateColormap(ColormapPtr); 116static void CMapDestroyColormap(ColormapPtr); 117 118static Bool CMapEnterVT(ScrnInfoPtr); 119static Bool CMapSwitchMode(ScrnInfoPtr, DisplayModePtr); 120 121#ifdef XFreeXDGA 122static int CMapSetDGAMode(ScrnInfoPtr, int, DGADevicePtr); 123#endif 124static int CMapChangeGamma(ScrnInfoPtr, Gamma); 125 126static void ComputeGamma(ScrnInfoPtr, CMapScreenPtr); 127static Bool CMapAllocateColormapPrivate(ColormapPtr); 128static void CMapRefreshColors(ColormapPtr, int, int *); 129static void CMapSetOverscan(ColormapPtr, int, int *); 130static void CMapReinstallMap(ColormapPtr); 131static void CMapUnwrapScreen(ScreenPtr pScreen); 132 133Bool 134xf86ColormapAllocatePrivates(ScrnInfoPtr pScrn) 135{ 136 if (!dixRegisterPrivateKey(&CMapScreenKeyRec, PRIVATE_SCREEN, 0)) 137 return FALSE; 138 139 if (!dixRegisterPrivateKey(&CMapColormapKeyRec, PRIVATE_COLORMAP, 0)) 140 return FALSE; 141 return TRUE; 142} 143 144Bool 145xf86HandleColormaps(ScreenPtr pScreen, 146 int maxColors, 147 int sigRGBbits, 148 xf86LoadPaletteProc * loadPalette, 149 xf86SetOverscanProc * setOverscan, unsigned int flags) 150{ 151 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 152 ColormapPtr pDefMap = NULL; 153 CMapScreenPtr pScreenPriv; 154 LOCO *gamma; 155 int *indices; 156 int elements; 157 158 if (!maxColors || !sigRGBbits || 159 (!loadPalette && !xf86_crtc_supports_gamma(pScrn))) 160 return FALSE; 161 162 elements = 1 << sigRGBbits; 163 164 if (!(gamma = xallocarray(elements, sizeof(LOCO)))) 165 return FALSE; 166 167 if (!(indices = xallocarray(maxColors, sizeof(int)))) { 168 free(gamma); 169 return FALSE; 170 } 171 172 if (!(pScreenPriv = malloc(sizeof(CMapScreenRec)))) { 173 free(gamma); 174 free(indices); 175 return FALSE; 176 } 177 178 dixSetPrivate(&pScreen->devPrivates, &CMapScreenKeyRec, pScreenPriv); 179 180 pScreenPriv->CloseScreen = pScreen->CloseScreen; 181 pScreenPriv->CreateColormap = pScreen->CreateColormap; 182 pScreenPriv->DestroyColormap = pScreen->DestroyColormap; 183 pScreenPriv->InstallColormap = pScreen->InstallColormap; 184 pScreenPriv->StoreColors = pScreen->StoreColors; 185 pScreen->CloseScreen = CMapCloseScreen; 186 pScreen->CreateColormap = CMapCreateColormap; 187 pScreen->DestroyColormap = CMapDestroyColormap; 188 pScreen->InstallColormap = CMapInstallColormap; 189 pScreen->StoreColors = CMapStoreColors; 190 191 pScrn->LoadPalette = loadPalette; 192 pScrn->SetOverscan = setOverscan; 193 pScreenPriv->maxColors = maxColors; 194 pScreenPriv->sigRGBbits = sigRGBbits; 195 pScreenPriv->gammaElements = elements; 196 pScreenPriv->gamma = gamma; 197 pScreenPriv->PreAllocIndices = indices; 198 pScreenPriv->maps = NULL; 199 pScreenPriv->flags = flags; 200 pScreenPriv->isDGAmode = FALSE; 201 202 pScreenPriv->EnterVT = pScrn->EnterVT; 203 pScreenPriv->SwitchMode = pScrn->SwitchMode; 204 pScreenPriv->SetDGAMode = pScrn->SetDGAMode; 205 pScreenPriv->ChangeGamma = pScrn->ChangeGamma; 206 207 if (!(flags & CMAP_LOAD_EVEN_IF_OFFSCREEN)) { 208 pScrn->EnterVT = CMapEnterVT; 209 if ((flags & CMAP_RELOAD_ON_MODE_SWITCH) && pScrn->SwitchMode) 210 pScrn->SwitchMode = CMapSwitchMode; 211 } 212#ifdef XFreeXDGA 213 pScrn->SetDGAMode = CMapSetDGAMode; 214#endif 215 pScrn->ChangeGamma = CMapChangeGamma; 216 217 ComputeGamma(pScrn, pScreenPriv); 218 219 /* get the default map */ 220 dixLookupResourceByType((void **) &pDefMap, pScreen->defColormap, 221 RT_COLORMAP, serverClient, DixInstallAccess); 222 223 if (!CMapAllocateColormapPrivate(pDefMap)) { 224 CMapUnwrapScreen(pScreen); 225 return FALSE; 226 } 227 228 if (xf86_crtc_supports_gamma(pScrn)) { 229 pScrn->LoadPalette = xf86RandR12LoadPalette; 230 231 if (!xf86RandR12InitGamma(pScrn, elements)) { 232 CMapUnwrapScreen(pScreen); 233 return FALSE; 234 } 235 } 236 237 /* Force the initial map to be loaded */ 238 SetInstalledmiColormap(pScreen, NULL); 239 CMapInstallColormap(pDefMap); 240 return TRUE; 241} 242 243/**** Screen functions ****/ 244 245static Bool 246CMapCloseScreen(ScreenPtr pScreen) 247{ 248 CMapUnwrapScreen(pScreen); 249 250 return (*pScreen->CloseScreen) (pScreen); 251} 252 253static Bool 254CMapColormapUseMax(VisualPtr pVisual, CMapScreenPtr pScreenPriv) 255{ 256 if (pVisual->nplanes > 16) 257 return TRUE; 258 return ((1 << pVisual->nplanes) > pScreenPriv->maxColors); 259} 260 261static Bool 262CMapAllocateColormapPrivate(ColormapPtr pmap) 263{ 264 CMapScreenPtr pScreenPriv = 265 (CMapScreenPtr) dixLookupPrivate(&pmap->pScreen->devPrivates, 266 CMapScreenKey); 267 CMapColormapPtr pColPriv; 268 CMapLinkPtr pLink; 269 int numColors; 270 LOCO *colors; 271 272 if (CMapColormapUseMax(pmap->pVisual, pScreenPriv)) 273 numColors = pmap->pVisual->ColormapEntries; 274 else 275 numColors = 1 << pmap->pVisual->nplanes; 276 277 if (!(colors = xallocarray(numColors, sizeof(LOCO)))) 278 return FALSE; 279 280 if (!(pColPriv = malloc(sizeof(CMapColormapRec)))) { 281 free(colors); 282 return FALSE; 283 } 284 285 dixSetPrivate(&pmap->devPrivates, CMapColormapKey, pColPriv); 286 287 pColPriv->numColors = numColors; 288 pColPriv->colors = colors; 289 pColPriv->recalculate = TRUE; 290 pColPriv->overscan = -1; 291 292 /* add map to list */ 293 pLink = malloc(sizeof(CMapLink)); 294 if (pLink) { 295 pLink->cmap = pmap; 296 pLink->next = pScreenPriv->maps; 297 pScreenPriv->maps = pLink; 298 } 299 300 return TRUE; 301} 302 303static Bool 304CMapCreateColormap(ColormapPtr pmap) 305{ 306 ScreenPtr pScreen = pmap->pScreen; 307 CMapScreenPtr pScreenPriv = 308 (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, CMapScreenKey); 309 Bool ret = FALSE; 310 311 pScreen->CreateColormap = pScreenPriv->CreateColormap; 312 if ((*pScreen->CreateColormap) (pmap)) { 313 if (CMapAllocateColormapPrivate(pmap)) 314 ret = TRUE; 315 } 316 pScreen->CreateColormap = CMapCreateColormap; 317 318 return ret; 319} 320 321static void 322CMapDestroyColormap(ColormapPtr cmap) 323{ 324 ScreenPtr pScreen = cmap->pScreen; 325 CMapScreenPtr pScreenPriv = 326 (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, CMapScreenKey); 327 CMapColormapPtr pColPriv = 328 (CMapColormapPtr) dixLookupPrivate(&cmap->devPrivates, CMapColormapKey); 329 CMapLinkPtr prevLink = NULL, pLink = pScreenPriv->maps; 330 331 if (pColPriv) { 332 free(pColPriv->colors); 333 free(pColPriv); 334 } 335 336 /* remove map from list */ 337 while (pLink) { 338 if (pLink->cmap == cmap) { 339 if (prevLink) 340 prevLink->next = pLink->next; 341 else 342 pScreenPriv->maps = pLink->next; 343 free(pLink); 344 break; 345 } 346 prevLink = pLink; 347 pLink = pLink->next; 348 } 349 350 if (pScreenPriv->DestroyColormap) { 351 pScreen->DestroyColormap = pScreenPriv->DestroyColormap; 352 (*pScreen->DestroyColormap) (cmap); 353 pScreen->DestroyColormap = CMapDestroyColormap; 354 } 355} 356 357static void 358CMapStoreColors(ColormapPtr pmap, int ndef, xColorItem * pdefs) 359{ 360 ScreenPtr pScreen = pmap->pScreen; 361 VisualPtr pVisual = pmap->pVisual; 362 CMapScreenPtr pScreenPriv = 363 (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, CMapScreenKey); 364 int *indices = pScreenPriv->PreAllocIndices; 365 int num = ndef; 366 367 /* At the moment this isn't necessary since there's nobody below us */ 368 pScreen->StoreColors = pScreenPriv->StoreColors; 369 (*pScreen->StoreColors) (pmap, ndef, pdefs); 370 pScreen->StoreColors = CMapStoreColors; 371 372 /* should never get here for these */ 373 if ((pVisual->class == TrueColor) || 374 (pVisual->class == StaticColor) || (pVisual->class == StaticGray)) 375 return; 376 377 if (pVisual->class == DirectColor) { 378 CMapColormapPtr pColPriv = 379 (CMapColormapPtr) dixLookupPrivate(&pmap->devPrivates, 380 CMapColormapKey); 381 int i; 382 383 if (CMapColormapUseMax(pVisual, pScreenPriv)) { 384 int index; 385 386 num = 0; 387 while (ndef--) { 388 if (pdefs[ndef].flags & DoRed) { 389 index = (pdefs[ndef].pixel & pVisual->redMask) >> 390 pVisual->offsetRed; 391 i = num; 392 while (i--) 393 if (indices[i] == index) 394 break; 395 if (i == -1) 396 indices[num++] = index; 397 } 398 if (pdefs[ndef].flags & DoGreen) { 399 index = (pdefs[ndef].pixel & pVisual->greenMask) >> 400 pVisual->offsetGreen; 401 i = num; 402 while (i--) 403 if (indices[i] == index) 404 break; 405 if (i == -1) 406 indices[num++] = index; 407 } 408 if (pdefs[ndef].flags & DoBlue) { 409 index = (pdefs[ndef].pixel & pVisual->blueMask) >> 410 pVisual->offsetBlue; 411 i = num; 412 while (i--) 413 if (indices[i] == index) 414 break; 415 if (i == -1) 416 indices[num++] = index; 417 } 418 } 419 420 } 421 else { 422 /* not really as overkill as it seems */ 423 num = pColPriv->numColors; 424 for (i = 0; i < pColPriv->numColors; i++) 425 indices[i] = i; 426 } 427 } 428 else { 429 while (ndef--) 430 indices[ndef] = pdefs[ndef].pixel; 431 } 432 433 CMapRefreshColors(pmap, num, indices); 434} 435 436static void 437CMapInstallColormap(ColormapPtr pmap) 438{ 439 ScreenPtr pScreen = pmap->pScreen; 440 CMapScreenPtr pScreenPriv = 441 (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, CMapScreenKey); 442 443 if (pmap == GetInstalledmiColormap(pmap->pScreen)) 444 return; 445 446 pScreen->InstallColormap = pScreenPriv->InstallColormap; 447 (*pScreen->InstallColormap) (pmap); 448 pScreen->InstallColormap = CMapInstallColormap; 449 450 /* Important. We let the lower layers, namely DGA, 451 overwrite the choice of Colormap to install */ 452 if (GetInstalledmiColormap(pmap->pScreen)) 453 pmap = GetInstalledmiColormap(pmap->pScreen); 454 455 if (!(pScreenPriv->flags & CMAP_PALETTED_TRUECOLOR) && 456 (pmap->pVisual->class == TrueColor) && 457 CMapColormapUseMax(pmap->pVisual, pScreenPriv)) 458 return; 459 460 if (LOAD_PALETTE(pmap)) 461 CMapReinstallMap(pmap); 462} 463 464/**** ScrnInfoRec functions ****/ 465 466static Bool 467CMapEnterVT(ScrnInfoPtr pScrn) 468{ 469 ScreenPtr pScreen = xf86ScrnToScreen(pScrn); 470 Bool ret; 471 CMapScreenPtr pScreenPriv = 472 (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, CMapScreenKey); 473 474 pScrn->EnterVT = pScreenPriv->EnterVT; 475 ret = (*pScreenPriv->EnterVT) (pScrn); 476 pScreenPriv->EnterVT = pScrn->EnterVT; 477 pScrn->EnterVT = CMapEnterVT; 478 if (ret) { 479 if (GetInstalledmiColormap(pScreen)) 480 CMapReinstallMap(GetInstalledmiColormap(pScreen)); 481 return TRUE; 482 } 483 return FALSE; 484} 485 486static Bool 487CMapSwitchMode(ScrnInfoPtr pScrn, DisplayModePtr mode) 488{ 489 ScreenPtr pScreen = xf86ScrnToScreen(pScrn); 490 CMapScreenPtr pScreenPriv = 491 (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, CMapScreenKey); 492 493 if ((*pScreenPriv->SwitchMode) (pScrn, mode)) { 494 if (GetInstalledmiColormap(pScreen)) 495 CMapReinstallMap(GetInstalledmiColormap(pScreen)); 496 return TRUE; 497 } 498 return FALSE; 499} 500 501#ifdef XFreeXDGA 502static int 503CMapSetDGAMode(ScrnInfoPtr pScrn, int num, DGADevicePtr dev) 504{ 505 ScreenPtr pScreen = xf86ScrnToScreen(pScrn); 506 CMapScreenPtr pScreenPriv = 507 (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, CMapScreenKey); 508 int ret; 509 510 ret = (*pScreenPriv->SetDGAMode) (pScrn, num, dev); 511 512 pScreenPriv->isDGAmode = DGAActive(pScrn->scrnIndex); 513 514 if (!pScreenPriv->isDGAmode && GetInstalledmiColormap(pScreen) 515 && xf86ScreenToScrn(pScreen)->vtSema) 516 CMapReinstallMap(GetInstalledmiColormap(pScreen)); 517 518 return ret; 519} 520#endif 521 522/**** Utilities ****/ 523 524static void 525CMapReinstallMap(ColormapPtr pmap) 526{ 527 CMapScreenPtr pScreenPriv = 528 (CMapScreenPtr) dixLookupPrivate(&pmap->pScreen->devPrivates, 529 CMapScreenKey); 530 CMapColormapPtr cmapPriv = 531 (CMapColormapPtr) dixLookupPrivate(&pmap->devPrivates, CMapColormapKey); 532 ScrnInfoPtr pScrn = xf86ScreenToScrn(pmap->pScreen); 533 int i = cmapPriv->numColors; 534 int *indices = pScreenPriv->PreAllocIndices; 535 536 while (i--) 537 indices[i] = i; 538 539 if (cmapPriv->recalculate) 540 CMapRefreshColors(pmap, cmapPriv->numColors, indices); 541 else { 542 (*pScrn->LoadPalette) (pScrn, cmapPriv->numColors, 543 indices, cmapPriv->colors, pmap->pVisual); 544 if (pScrn->SetOverscan) { 545#ifdef DEBUGOVERSCAN 546 ErrorF("SetOverscan() called from CMapReinstallMap\n"); 547#endif 548 pScrn->SetOverscan(pScrn, cmapPriv->overscan); 549 } 550 } 551 552 cmapPriv->recalculate = FALSE; 553} 554 555static void 556CMapRefreshColors(ColormapPtr pmap, int defs, int *indices) 557{ 558 CMapScreenPtr pScreenPriv = 559 (CMapScreenPtr) dixLookupPrivate(&pmap->pScreen->devPrivates, 560 CMapScreenKey); 561 CMapColormapPtr pColPriv = 562 (CMapColormapPtr) dixLookupPrivate(&pmap->devPrivates, CMapColormapKey); 563 VisualPtr pVisual = pmap->pVisual; 564 ScrnInfoPtr pScrn = xf86ScreenToScrn(pmap->pScreen); 565 int numColors, i; 566 LOCO *gamma, *colors; 567 EntryPtr entry; 568 int reds, greens, blues, maxValue, index, shift; 569 570 numColors = pColPriv->numColors; 571 shift = 16 - pScreenPriv->sigRGBbits; 572 maxValue = (1 << pScreenPriv->sigRGBbits) - 1; 573 gamma = pScreenPriv->gamma; 574 colors = pColPriv->colors; 575 576 reds = pVisual->redMask >> pVisual->offsetRed; 577 greens = pVisual->greenMask >> pVisual->offsetGreen; 578 blues = pVisual->blueMask >> pVisual->offsetBlue; 579 580 switch (pVisual->class) { 581 case StaticGray: 582 for (i = 0; i < numColors; i++) { 583 index = (i + 1) * maxValue / numColors; 584 colors[i].red = gamma[index].red; 585 colors[i].green = gamma[index].green; 586 colors[i].blue = gamma[index].blue; 587 } 588 break; 589 case TrueColor: 590 if (CMapColormapUseMax(pVisual, pScreenPriv)) { 591 for (i = 0; i <= reds; i++) 592 colors[i].red = gamma[i * maxValue / reds].red; 593 for (i = 0; i <= greens; i++) 594 colors[i].green = gamma[i * maxValue / greens].green; 595 for (i = 0; i <= blues; i++) 596 colors[i].blue = gamma[i * maxValue / blues].blue; 597 break; 598 } 599 for (i = 0; i < numColors; i++) { 600 colors[i].red = gamma[((i >> pVisual->offsetRed) & reds) * 601 maxValue / reds].red; 602 colors[i].green = gamma[((i >> pVisual->offsetGreen) & greens) * 603 maxValue / greens].green; 604 colors[i].blue = gamma[((i >> pVisual->offsetBlue) & blues) * 605 maxValue / blues].blue; 606 } 607 break; 608 case StaticColor: 609 case PseudoColor: 610 case GrayScale: 611 for (i = 0; i < defs; i++) { 612 index = indices[i]; 613 entry = (EntryPtr) &pmap->red[index]; 614 615 if (entry->fShared) { 616 colors[index].red = 617 gamma[entry->co.shco.red->color >> shift].red; 618 colors[index].green = 619 gamma[entry->co.shco.green->color >> shift].green; 620 colors[index].blue = 621 gamma[entry->co.shco.blue->color >> shift].blue; 622 } 623 else { 624 colors[index].red = gamma[entry->co.local.red >> shift].red; 625 colors[index].green = 626 gamma[entry->co.local.green >> shift].green; 627 colors[index].blue = gamma[entry->co.local.blue >> shift].blue; 628 } 629 } 630 break; 631 case DirectColor: 632 if (CMapColormapUseMax(pVisual, pScreenPriv)) { 633 for (i = 0; i < defs; i++) { 634 index = indices[i]; 635 if (index <= reds) 636 colors[index].red = 637 gamma[pmap->red[index].co.local.red >> shift].red; 638 if (index <= greens) 639 colors[index].green = 640 gamma[pmap->green[index].co.local.green >> shift].green; 641 if (index <= blues) 642 colors[index].blue = 643 gamma[pmap->blue[index].co.local.blue >> shift].blue; 644 645 } 646 break; 647 } 648 for (i = 0; i < defs; i++) { 649 index = indices[i]; 650 651 colors[index].red = gamma[pmap->red[(index >> pVisual-> 652 offsetRed) & reds].co.local. 653 red >> shift].red; 654 colors[index].green = 655 gamma[pmap->green[(index >> pVisual->offsetGreen) & greens].co. 656 local.green >> shift].green; 657 colors[index].blue = 658 gamma[pmap->blue[(index >> pVisual->offsetBlue) & blues].co. 659 local.blue >> shift].blue; 660 } 661 break; 662 } 663 664 if (LOAD_PALETTE(pmap)) 665 (*pScrn->LoadPalette) (pScrn, defs, indices, colors, pmap->pVisual); 666 667 if (pScrn->SetOverscan) 668 CMapSetOverscan(pmap, defs, indices); 669 670} 671 672static Bool 673CMapCompareColors(LOCO * color1, LOCO * color2) 674{ 675 /* return TRUE if the color1 is "closer" to black than color2 */ 676#ifdef DEBUGOVERSCAN 677 ErrorF("#%02x%02x%02x vs #%02x%02x%02x (%d vs %d)\n", 678 color1->red, color1->green, color1->blue, 679 color2->red, color2->green, color2->blue, 680 color1->red + color1->green + color1->blue, 681 color2->red + color2->green + color2->blue); 682#endif 683 return (color1->red + color1->green + color1->blue < 684 color2->red + color2->green + color2->blue); 685} 686 687static void 688CMapSetOverscan(ColormapPtr pmap, int defs, int *indices) 689{ 690 CMapScreenPtr pScreenPriv = 691 (CMapScreenPtr) dixLookupPrivate(&pmap->pScreen->devPrivates, 692 CMapScreenKey); 693 CMapColormapPtr pColPriv = 694 (CMapColormapPtr) dixLookupPrivate(&pmap->devPrivates, CMapColormapKey); 695 ScrnInfoPtr pScrn = xf86ScreenToScrn(pmap->pScreen); 696 VisualPtr pVisual = pmap->pVisual; 697 int i; 698 LOCO *colors; 699 int index; 700 Bool newOverscan = FALSE; 701 int overscan, tmpOverscan; 702 703 colors = pColPriv->colors; 704 overscan = pColPriv->overscan; 705 706 /* 707 * Search for a new overscan index in the following cases: 708 * 709 * - The index hasn't yet been initialised. In this case search 710 * for an index that is black or a close match to black. 711 * 712 * - The colour of the old index is changed. In this case search 713 * all indices for a black or close match to black. 714 * 715 * - The colour of the old index wasn't black. In this case only 716 * search the indices that were changed for a better match to black. 717 */ 718 719 switch (pVisual->class) { 720 case StaticGray: 721 case TrueColor: 722 /* Should only come here once. Initialise the overscan index to 0 */ 723 overscan = 0; 724 newOverscan = TRUE; 725 break; 726 case StaticColor: 727 /* 728 * Only come here once, but search for the overscan in the same way 729 * as for the other cases. 730 */ 731 case DirectColor: 732 case PseudoColor: 733 case GrayScale: 734 if (overscan < 0 || overscan > pScreenPriv->maxColors - 1) { 735 /* Uninitialised */ 736 newOverscan = TRUE; 737 } 738 else { 739 /* Check if the overscan was changed */ 740 for (i = 0; i < defs; i++) { 741 index = indices[i]; 742 if (index == overscan) { 743 newOverscan = TRUE; 744 break; 745 } 746 } 747 } 748 if (newOverscan) { 749 /* The overscan is either uninitialised or it has been changed */ 750 751 if (overscan < 0 || overscan > pScreenPriv->maxColors - 1) 752 tmpOverscan = pScreenPriv->maxColors - 1; 753 else 754 tmpOverscan = overscan; 755 756 /* search all entries for a close match to black */ 757 for (i = pScreenPriv->maxColors - 1; i >= 0; i--) { 758 if (colors[i].red == 0 && colors[i].green == 0 && 759 colors[i].blue == 0) { 760 overscan = i; 761#ifdef DEBUGOVERSCAN 762 ErrorF("Black found at index 0x%02x\n", i); 763#endif 764 break; 765 } 766 else { 767#ifdef DEBUGOVERSCAN 768 ErrorF("0x%02x: ", i); 769#endif 770 if (CMapCompareColors(&colors[i], &colors[tmpOverscan])) { 771 tmpOverscan = i; 772#ifdef DEBUGOVERSCAN 773 ErrorF("possible \"Black\" at index 0x%02x\n", i); 774#endif 775 } 776 } 777 } 778 if (i < 0) 779 overscan = tmpOverscan; 780 } 781 else { 782 /* Check of the old overscan wasn't black */ 783 if (colors[overscan].red != 0 || colors[overscan].green != 0 || 784 colors[overscan].blue != 0) { 785 int oldOverscan = tmpOverscan = overscan; 786 787 /* See of there is now a better match */ 788 for (i = 0; i < defs; i++) { 789 index = indices[i]; 790 if (colors[index].red == 0 && colors[index].green == 0 && 791 colors[index].blue == 0) { 792 overscan = index; 793#ifdef DEBUGOVERSCAN 794 ErrorF("Black found at index 0x%02x\n", index); 795#endif 796 break; 797 } 798 else { 799#ifdef DEBUGOVERSCAN 800 ErrorF("0x%02x: ", index); 801#endif 802 if (CMapCompareColors(&colors[index], 803 &colors[tmpOverscan])) { 804 tmpOverscan = index; 805#ifdef DEBUGOVERSCAN 806 ErrorF("possible \"Black\" at index 0x%02x\n", 807 index); 808#endif 809 } 810 } 811 } 812 if (i == defs) 813 overscan = tmpOverscan; 814 if (overscan != oldOverscan) 815 newOverscan = TRUE; 816 } 817 } 818 break; 819 } 820 if (newOverscan) { 821 pColPriv->overscan = overscan; 822 if (LOAD_PALETTE(pmap)) { 823#ifdef DEBUGOVERSCAN 824 ErrorF("SetOverscan() called from CmapSetOverscan\n"); 825#endif 826 pScrn->SetOverscan(pScrn, overscan); 827 } 828 } 829} 830 831static void 832CMapUnwrapScreen(ScreenPtr pScreen) 833{ 834 CMapScreenPtr pScreenPriv = 835 (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, CMapScreenKey); 836 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 837 838 pScreen->CloseScreen = pScreenPriv->CloseScreen; 839 pScreen->CreateColormap = pScreenPriv->CreateColormap; 840 pScreen->DestroyColormap = pScreenPriv->DestroyColormap; 841 pScreen->InstallColormap = pScreenPriv->InstallColormap; 842 pScreen->StoreColors = pScreenPriv->StoreColors; 843 844 pScrn->EnterVT = pScreenPriv->EnterVT; 845 pScrn->SwitchMode = pScreenPriv->SwitchMode; 846 pScrn->SetDGAMode = pScreenPriv->SetDGAMode; 847 pScrn->ChangeGamma = pScreenPriv->ChangeGamma; 848 849 free(pScreenPriv->gamma); 850 free(pScreenPriv->PreAllocIndices); 851 free(pScreenPriv); 852} 853 854static void 855ComputeGamma(ScrnInfoPtr pScrn, CMapScreenPtr priv) 856{ 857 int elements = priv->gammaElements - 1; 858 double RedGamma, GreenGamma, BlueGamma; 859 int i; 860 861#ifndef DONT_CHECK_GAMMA 862 /* This check is to catch drivers that are not initialising pScrn->gamma */ 863 if (pScrn->gamma.red < GAMMA_MIN || pScrn->gamma.red > GAMMA_MAX || 864 pScrn->gamma.green < GAMMA_MIN || pScrn->gamma.green > GAMMA_MAX || 865 pScrn->gamma.blue < GAMMA_MIN || pScrn->gamma.blue > GAMMA_MAX) { 866 867 xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, 0, 868 "The %s driver didn't call xf86SetGamma() to initialise\n" 869 "\tthe gamma values.\n", pScrn->driverName); 870 xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, 0, 871 "PLEASE FIX THE `%s' DRIVER!\n", 872 pScrn->driverName); 873 pScrn->gamma.red = 1.0; 874 pScrn->gamma.green = 1.0; 875 pScrn->gamma.blue = 1.0; 876 } 877#endif 878 879 RedGamma = 1.0 / (double) pScrn->gamma.red; 880 GreenGamma = 1.0 / (double) pScrn->gamma.green; 881 BlueGamma = 1.0 / (double) pScrn->gamma.blue; 882 883 for (i = 0; i <= elements; i++) { 884 if (RedGamma == 1.0) 885 priv->gamma[i].red = i; 886 else 887 priv->gamma[i].red = (CARD16) (pow((double) i / (double) elements, 888 RedGamma) * (double) elements + 889 0.5); 890 891 if (GreenGamma == 1.0) 892 priv->gamma[i].green = i; 893 else 894 priv->gamma[i].green = (CARD16) (pow((double) i / (double) elements, 895 GreenGamma) * 896 (double) elements + 0.5); 897 898 if (BlueGamma == 1.0) 899 priv->gamma[i].blue = i; 900 else 901 priv->gamma[i].blue = (CARD16) (pow((double) i / (double) elements, 902 BlueGamma) * (double) elements + 903 0.5); 904 } 905} 906 907int 908CMapChangeGamma(ScrnInfoPtr pScrn, Gamma gamma) 909{ 910 int ret = Success; 911 ScreenPtr pScreen = xf86ScrnToScreen(pScrn); 912 CMapColormapPtr pColPriv; 913 CMapScreenPtr pScreenPriv; 914 CMapLinkPtr pLink; 915 916 /* Is this sufficient checking ? */ 917 if (!CMapScreenKeyRegistered) 918 return BadImplementation; 919 920 pScreenPriv = (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, 921 CMapScreenKey); 922 if (!pScreenPriv) 923 return BadImplementation; 924 925 if (gamma.red < GAMMA_MIN || gamma.red > GAMMA_MAX || 926 gamma.green < GAMMA_MIN || gamma.green > GAMMA_MAX || 927 gamma.blue < GAMMA_MIN || gamma.blue > GAMMA_MAX) 928 return BadValue; 929 930 pScrn->gamma.red = gamma.red; 931 pScrn->gamma.green = gamma.green; 932 pScrn->gamma.blue = gamma.blue; 933 934 ComputeGamma(pScrn, pScreenPriv); 935 936 /* mark all colormaps on this screen */ 937 pLink = pScreenPriv->maps; 938 while (pLink) { 939 pColPriv = (CMapColormapPtr) dixLookupPrivate(&pLink->cmap->devPrivates, 940 CMapColormapKey); 941 pColPriv->recalculate = TRUE; 942 pLink = pLink->next; 943 } 944 945 if (GetInstalledmiColormap(pScreen) && 946 ((pScreenPriv->flags & CMAP_LOAD_EVEN_IF_OFFSCREEN) || 947 pScrn->vtSema || pScreenPriv->isDGAmode)) { 948 ColormapPtr pMap = GetInstalledmiColormap(pScreen); 949 950 if (!(pScreenPriv->flags & CMAP_PALETTED_TRUECOLOR) && 951 (pMap->pVisual->class == TrueColor) && 952 CMapColormapUseMax(pMap->pVisual, pScreenPriv)) { 953 954 /* if the current map doesn't have a palette look 955 for another map to change the gamma on. */ 956 957 pLink = pScreenPriv->maps; 958 while (pLink) { 959 if (pLink->cmap->pVisual->class == PseudoColor) 960 break; 961 pLink = pLink->next; 962 } 963 964 if (pLink) { 965 /* need to trick CMapRefreshColors() into thinking 966 this is the currently installed map */ 967 SetInstalledmiColormap(pScreen, pLink->cmap); 968 CMapReinstallMap(pLink->cmap); 969 SetInstalledmiColormap(pScreen, pMap); 970 } 971 } 972 else 973 CMapReinstallMap(pMap); 974 } 975 976 pScrn->ChangeGamma = pScreenPriv->ChangeGamma; 977 if (pScrn->ChangeGamma) 978 ret = pScrn->ChangeGamma(pScrn, gamma); 979 pScrn->ChangeGamma = CMapChangeGamma; 980 981 return ret; 982} 983 984static void 985ComputeGammaRamp(CMapScreenPtr priv, 986 unsigned short *red, 987 unsigned short *green, unsigned short *blue) 988{ 989 int elements = priv->gammaElements; 990 LOCO *entry = priv->gamma; 991 int shift = 16 - priv->sigRGBbits; 992 993 while (elements--) { 994 entry->red = *(red++) >> shift; 995 entry->green = *(green++) >> shift; 996 entry->blue = *(blue++) >> shift; 997 entry++; 998 } 999} 1000 1001int 1002xf86ChangeGammaRamp(ScreenPtr pScreen, 1003 int size, 1004 unsigned short *red, 1005 unsigned short *green, unsigned short *blue) 1006{ 1007 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1008 CMapColormapPtr pColPriv; 1009 CMapScreenPtr pScreenPriv; 1010 CMapLinkPtr pLink; 1011 1012 if (!CMapScreenKeyRegistered) 1013 return BadImplementation; 1014 1015 pScreenPriv = (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, 1016 CMapScreenKey); 1017 if (!pScreenPriv) 1018 return BadImplementation; 1019 1020 if (pScreenPriv->gammaElements != size) 1021 return BadValue; 1022 1023 ComputeGammaRamp(pScreenPriv, red, green, blue); 1024 1025 /* mark all colormaps on this screen */ 1026 pLink = pScreenPriv->maps; 1027 while (pLink) { 1028 pColPriv = (CMapColormapPtr) dixLookupPrivate(&pLink->cmap->devPrivates, 1029 CMapColormapKey); 1030 pColPriv->recalculate = TRUE; 1031 pLink = pLink->next; 1032 } 1033 1034 if (GetInstalledmiColormap(pScreen) && 1035 ((pScreenPriv->flags & CMAP_LOAD_EVEN_IF_OFFSCREEN) || 1036 pScrn->vtSema || pScreenPriv->isDGAmode)) { 1037 ColormapPtr pMap = GetInstalledmiColormap(pScreen); 1038 1039 if (!(pScreenPriv->flags & CMAP_PALETTED_TRUECOLOR) && 1040 (pMap->pVisual->class == TrueColor) && 1041 CMapColormapUseMax(pMap->pVisual, pScreenPriv)) { 1042 1043 /* if the current map doesn't have a palette look 1044 for another map to change the gamma on. */ 1045 1046 pLink = pScreenPriv->maps; 1047 while (pLink) { 1048 if (pLink->cmap->pVisual->class == PseudoColor) 1049 break; 1050 pLink = pLink->next; 1051 } 1052 1053 if (pLink) { 1054 /* need to trick CMapRefreshColors() into thinking 1055 this is the currently installed map */ 1056 SetInstalledmiColormap(pScreen, pLink->cmap); 1057 CMapReinstallMap(pLink->cmap); 1058 SetInstalledmiColormap(pScreen, pMap); 1059 } 1060 } 1061 else 1062 CMapReinstallMap(pMap); 1063 } 1064 1065 return Success; 1066} 1067 1068int 1069xf86GetGammaRampSize(ScreenPtr pScreen) 1070{ 1071 CMapScreenPtr pScreenPriv; 1072 1073 if (!CMapScreenKeyRegistered) 1074 return 0; 1075 1076 pScreenPriv = (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, 1077 CMapScreenKey); 1078 if (!pScreenPriv) 1079 return 0; 1080 1081 return pScreenPriv->gammaElements; 1082} 1083 1084int 1085xf86GetGammaRamp(ScreenPtr pScreen, 1086 int size, 1087 unsigned short *red, 1088 unsigned short *green, unsigned short *blue) 1089{ 1090 CMapScreenPtr pScreenPriv; 1091 LOCO *entry; 1092 int shift, sigbits; 1093 1094 if (!CMapScreenKeyRegistered) 1095 return BadImplementation; 1096 1097 pScreenPriv = (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, 1098 CMapScreenKey); 1099 if (!pScreenPriv) 1100 return BadImplementation; 1101 1102 if (size > pScreenPriv->gammaElements) 1103 return BadValue; 1104 1105 entry = pScreenPriv->gamma; 1106 sigbits = pScreenPriv->sigRGBbits; 1107 1108 while (size--) { 1109 *red = entry->red << (16 - sigbits); 1110 *green = entry->green << (16 - sigbits); 1111 *blue = entry->blue << (16 - sigbits); 1112 shift = sigbits; 1113 while (shift < 16) { 1114 *red |= *red >> shift; 1115 *green |= *green >> shift; 1116 *blue |= *blue >> shift; 1117 shift += sigbits; 1118 } 1119 red++; 1120 green++; 1121 blue++; 1122 entry++; 1123 } 1124 1125 return Success; 1126} 1127 1128int 1129xf86ChangeGamma(ScreenPtr pScreen, Gamma gamma) 1130{ 1131 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1132 1133 if (pScrn->ChangeGamma) 1134 return (*pScrn->ChangeGamma) (pScrn, gamma); 1135 1136 return BadImplementation; 1137} 1138