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