/* * Copyright (c) 1998-2001 by The XFree86 Project, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Except as contained in this notice, the name of the copyright holder(s) * and author(s) shall not be used in advertising or otherwise to promote * the sale, use or other dealings in this Software without prior written * authorization from the copyright holder(s) and author(s). */ #ifdef HAVE_XORG_CONFIG_H #include #endif #if defined(_XOPEN_SOURCE) || defined(__sun) && defined(__SVR4) #include #else #define _XOPEN_SOURCE /* to get prototype for pow on some systems */ #include #undef _XOPEN_SOURCE #endif #include #include "misc.h" #include #include "colormapst.h" #include "scrnintstr.h" #include "resource.h" #include "xf86.h" #include "xf86_OSproc.h" #include "xf86str.h" #include "micmap.h" #include "xf86RandR12.h" #include "xf86Crtc.h" #ifdef XFreeXDGA #include #include "dgaproc.h" #endif #include "xf86cmap.h" #define SCREEN_PROLOGUE(pScreen, field) ((pScreen)->field = \ ((CMapScreenPtr)dixLookupPrivate(&(pScreen)->devPrivates, CMapScreenKey))->field) #define SCREEN_EPILOGUE(pScreen, field, wrapper)\ ((pScreen)->field = wrapper) #define LOAD_PALETTE(pmap) \ ((pmap == GetInstalledmiColormap(pmap->pScreen)) && \ ((pScreenPriv->flags & CMAP_LOAD_EVEN_IF_OFFSCREEN) || \ xf86ScreenToScrn(pmap->pScreen)->vtSema || pScreenPriv->isDGAmode)) typedef struct _CMapLink { ColormapPtr cmap; struct _CMapLink *next; } CMapLink, *CMapLinkPtr; typedef struct { CloseScreenProcPtr CloseScreen; CreateColormapProcPtr CreateColormap; DestroyColormapProcPtr DestroyColormap; InstallColormapProcPtr InstallColormap; StoreColorsProcPtr StoreColors; Bool (*EnterVT) (ScrnInfoPtr); Bool (*SwitchMode) (ScrnInfoPtr, DisplayModePtr); int (*SetDGAMode) (ScrnInfoPtr, int, DGADevicePtr); xf86ChangeGammaProc *ChangeGamma; int maxColors; int sigRGBbits; int gammaElements; LOCO *gamma; int *PreAllocIndices; CMapLinkPtr maps; unsigned int flags; Bool isDGAmode; } CMapScreenRec, *CMapScreenPtr; typedef struct { int numColors; LOCO *colors; Bool recalculate; int overscan; } CMapColormapRec, *CMapColormapPtr; static DevPrivateKeyRec CMapScreenKeyRec; #define CMapScreenKeyRegistered dixPrivateKeyRegistered(&CMapScreenKeyRec) #define CMapScreenKey (&CMapScreenKeyRec) static DevPrivateKeyRec CMapColormapKeyRec; #define CMapColormapKey (&CMapColormapKeyRec) static void CMapInstallColormap(ColormapPtr); static void CMapStoreColors(ColormapPtr, int, xColorItem *); static Bool CMapCloseScreen(ScreenPtr); static Bool CMapCreateColormap(ColormapPtr); static void CMapDestroyColormap(ColormapPtr); static Bool CMapEnterVT(ScrnInfoPtr); static Bool CMapSwitchMode(ScrnInfoPtr, DisplayModePtr); #ifdef XFreeXDGA static int CMapSetDGAMode(ScrnInfoPtr, int, DGADevicePtr); #endif static int CMapChangeGamma(ScrnInfoPtr, Gamma); static void ComputeGamma(ScrnInfoPtr, CMapScreenPtr); static Bool CMapAllocateColormapPrivate(ColormapPtr); static void CMapRefreshColors(ColormapPtr, int, int *); static void CMapSetOverscan(ColormapPtr, int, int *); static void CMapReinstallMap(ColormapPtr); static void CMapUnwrapScreen(ScreenPtr pScreen); Bool xf86ColormapAllocatePrivates(ScrnInfoPtr pScrn) { if (!dixRegisterPrivateKey(&CMapScreenKeyRec, PRIVATE_SCREEN, 0)) return FALSE; if (!dixRegisterPrivateKey(&CMapColormapKeyRec, PRIVATE_COLORMAP, 0)) return FALSE; return TRUE; } Bool xf86HandleColormaps(ScreenPtr pScreen, int maxColors, int sigRGBbits, xf86LoadPaletteProc * loadPalette, xf86SetOverscanProc * setOverscan, unsigned int flags) { ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); ColormapPtr pDefMap = NULL; CMapScreenPtr pScreenPriv; LOCO *gamma; int *indices; int elements; if (!maxColors || !sigRGBbits || (!loadPalette && !xf86_crtc_supports_gamma(pScrn))) return FALSE; elements = 1 << sigRGBbits; if (!(gamma = xallocarray(elements, sizeof(LOCO)))) return FALSE; if (!(indices = xallocarray(maxColors, sizeof(int)))) { free(gamma); return FALSE; } if (!(pScreenPriv = malloc(sizeof(CMapScreenRec)))) { free(gamma); free(indices); return FALSE; } dixSetPrivate(&pScreen->devPrivates, &CMapScreenKeyRec, pScreenPriv); pScreenPriv->CloseScreen = pScreen->CloseScreen; pScreenPriv->CreateColormap = pScreen->CreateColormap; pScreenPriv->DestroyColormap = pScreen->DestroyColormap; pScreenPriv->InstallColormap = pScreen->InstallColormap; pScreenPriv->StoreColors = pScreen->StoreColors; pScreen->CloseScreen = CMapCloseScreen; pScreen->CreateColormap = CMapCreateColormap; pScreen->DestroyColormap = CMapDestroyColormap; pScreen->InstallColormap = CMapInstallColormap; pScreen->StoreColors = CMapStoreColors; pScrn->LoadPalette = loadPalette; pScrn->SetOverscan = setOverscan; pScreenPriv->maxColors = maxColors; pScreenPriv->sigRGBbits = sigRGBbits; pScreenPriv->gammaElements = elements; pScreenPriv->gamma = gamma; pScreenPriv->PreAllocIndices = indices; pScreenPriv->maps = NULL; pScreenPriv->flags = flags; pScreenPriv->isDGAmode = FALSE; pScreenPriv->EnterVT = pScrn->EnterVT; pScreenPriv->SwitchMode = pScrn->SwitchMode; pScreenPriv->SetDGAMode = pScrn->SetDGAMode; pScreenPriv->ChangeGamma = pScrn->ChangeGamma; if (!(flags & CMAP_LOAD_EVEN_IF_OFFSCREEN)) { pScrn->EnterVT = CMapEnterVT; if ((flags & CMAP_RELOAD_ON_MODE_SWITCH) && pScrn->SwitchMode) pScrn->SwitchMode = CMapSwitchMode; } #ifdef XFreeXDGA pScrn->SetDGAMode = CMapSetDGAMode; #endif pScrn->ChangeGamma = CMapChangeGamma; ComputeGamma(pScrn, pScreenPriv); /* get the default map */ dixLookupResourceByType((void **) &pDefMap, pScreen->defColormap, RT_COLORMAP, serverClient, DixInstallAccess); if (!CMapAllocateColormapPrivate(pDefMap)) { CMapUnwrapScreen(pScreen); return FALSE; } if (xf86_crtc_supports_gamma(pScrn)) { pScrn->LoadPalette = xf86RandR12LoadPalette; if (!xf86RandR12InitGamma(pScrn, elements)) { CMapUnwrapScreen(pScreen); return FALSE; } } /* Force the initial map to be loaded */ SetInstalledmiColormap(pScreen, NULL); CMapInstallColormap(pDefMap); return TRUE; } /**** Screen functions ****/ static Bool CMapCloseScreen(ScreenPtr pScreen) { CMapUnwrapScreen(pScreen); return (*pScreen->CloseScreen) (pScreen); } static Bool CMapColormapUseMax(VisualPtr pVisual, CMapScreenPtr pScreenPriv) { if (pVisual->nplanes > 16) return TRUE; return ((1 << pVisual->nplanes) > pScreenPriv->maxColors); } static Bool CMapAllocateColormapPrivate(ColormapPtr pmap) { CMapScreenPtr pScreenPriv = (CMapScreenPtr) dixLookupPrivate(&pmap->pScreen->devPrivates, CMapScreenKey); CMapColormapPtr pColPriv; CMapLinkPtr pLink; int numColors; LOCO *colors; if (CMapColormapUseMax(pmap->pVisual, pScreenPriv)) numColors = pmap->pVisual->ColormapEntries; else numColors = 1 << pmap->pVisual->nplanes; if (!(colors = xallocarray(numColors, sizeof(LOCO)))) return FALSE; if (!(pColPriv = malloc(sizeof(CMapColormapRec)))) { free(colors); return FALSE; } dixSetPrivate(&pmap->devPrivates, CMapColormapKey, pColPriv); pColPriv->numColors = numColors; pColPriv->colors = colors; pColPriv->recalculate = TRUE; pColPriv->overscan = -1; /* add map to list */ pLink = malloc(sizeof(CMapLink)); if (pLink) { pLink->cmap = pmap; pLink->next = pScreenPriv->maps; pScreenPriv->maps = pLink; } return TRUE; } static Bool CMapCreateColormap(ColormapPtr pmap) { ScreenPtr pScreen = pmap->pScreen; CMapScreenPtr pScreenPriv = (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, CMapScreenKey); Bool ret = FALSE; pScreen->CreateColormap = pScreenPriv->CreateColormap; if ((*pScreen->CreateColormap) (pmap)) { if (CMapAllocateColormapPrivate(pmap)) ret = TRUE; } pScreen->CreateColormap = CMapCreateColormap; return ret; } static void CMapDestroyColormap(ColormapPtr cmap) { ScreenPtr pScreen = cmap->pScreen; CMapScreenPtr pScreenPriv = (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, CMapScreenKey); CMapColormapPtr pColPriv = (CMapColormapPtr) dixLookupPrivate(&cmap->devPrivates, CMapColormapKey); CMapLinkPtr prevLink = NULL, pLink = pScreenPriv->maps; if (pColPriv) { free(pColPriv->colors); free(pColPriv); } /* remove map from list */ while (pLink) { if (pLink->cmap == cmap) { if (prevLink) prevLink->next = pLink->next; else pScreenPriv->maps = pLink->next; free(pLink); break; } prevLink = pLink; pLink = pLink->next; } if (pScreenPriv->DestroyColormap) { pScreen->DestroyColormap = pScreenPriv->DestroyColormap; (*pScreen->DestroyColormap) (cmap); pScreen->DestroyColormap = CMapDestroyColormap; } } static void CMapStoreColors(ColormapPtr pmap, int ndef, xColorItem * pdefs) { ScreenPtr pScreen = pmap->pScreen; VisualPtr pVisual = pmap->pVisual; CMapScreenPtr pScreenPriv = (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, CMapScreenKey); int *indices = pScreenPriv->PreAllocIndices; int num = ndef; /* At the moment this isn't necessary since there's nobody below us */ pScreen->StoreColors = pScreenPriv->StoreColors; (*pScreen->StoreColors) (pmap, ndef, pdefs); pScreen->StoreColors = CMapStoreColors; /* should never get here for these */ if ((pVisual->class == TrueColor) || (pVisual->class == StaticColor) || (pVisual->class == StaticGray)) return; if (pVisual->class == DirectColor) { CMapColormapPtr pColPriv = (CMapColormapPtr) dixLookupPrivate(&pmap->devPrivates, CMapColormapKey); int i; if (CMapColormapUseMax(pVisual, pScreenPriv)) { int index; num = 0; while (ndef--) { if (pdefs[ndef].flags & DoRed) { index = (pdefs[ndef].pixel & pVisual->redMask) >> pVisual->offsetRed; i = num; while (i--) if (indices[i] == index) break; if (i == -1) indices[num++] = index; } if (pdefs[ndef].flags & DoGreen) { index = (pdefs[ndef].pixel & pVisual->greenMask) >> pVisual->offsetGreen; i = num; while (i--) if (indices[i] == index) break; if (i == -1) indices[num++] = index; } if (pdefs[ndef].flags & DoBlue) { index = (pdefs[ndef].pixel & pVisual->blueMask) >> pVisual->offsetBlue; i = num; while (i--) if (indices[i] == index) break; if (i == -1) indices[num++] = index; } } } else { /* not really as overkill as it seems */ num = pColPriv->numColors; for (i = 0; i < pColPriv->numColors; i++) indices[i] = i; } } else { while (ndef--) indices[ndef] = pdefs[ndef].pixel; } CMapRefreshColors(pmap, num, indices); } static void CMapInstallColormap(ColormapPtr pmap) { ScreenPtr pScreen = pmap->pScreen; CMapScreenPtr pScreenPriv = (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, CMapScreenKey); if (pmap == GetInstalledmiColormap(pmap->pScreen)) return; pScreen->InstallColormap = pScreenPriv->InstallColormap; (*pScreen->InstallColormap) (pmap); pScreen->InstallColormap = CMapInstallColormap; /* Important. We let the lower layers, namely DGA, overwrite the choice of Colormap to install */ if (GetInstalledmiColormap(pmap->pScreen)) pmap = GetInstalledmiColormap(pmap->pScreen); if (!(pScreenPriv->flags & CMAP_PALETTED_TRUECOLOR) && (pmap->pVisual->class == TrueColor) && CMapColormapUseMax(pmap->pVisual, pScreenPriv)) return; if (LOAD_PALETTE(pmap)) CMapReinstallMap(pmap); } /**** ScrnInfoRec functions ****/ static Bool CMapEnterVT(ScrnInfoPtr pScrn) { ScreenPtr pScreen = xf86ScrnToScreen(pScrn); Bool ret; CMapScreenPtr pScreenPriv = (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, CMapScreenKey); pScrn->EnterVT = pScreenPriv->EnterVT; ret = (*pScreenPriv->EnterVT) (pScrn); pScreenPriv->EnterVT = pScrn->EnterVT; pScrn->EnterVT = CMapEnterVT; if (ret) { if (GetInstalledmiColormap(pScreen)) CMapReinstallMap(GetInstalledmiColormap(pScreen)); return TRUE; } return FALSE; } static Bool CMapSwitchMode(ScrnInfoPtr pScrn, DisplayModePtr mode) { ScreenPtr pScreen = xf86ScrnToScreen(pScrn); CMapScreenPtr pScreenPriv = (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, CMapScreenKey); if ((*pScreenPriv->SwitchMode) (pScrn, mode)) { if (GetInstalledmiColormap(pScreen)) CMapReinstallMap(GetInstalledmiColormap(pScreen)); return TRUE; } return FALSE; } #ifdef XFreeXDGA static int CMapSetDGAMode(ScrnInfoPtr pScrn, int num, DGADevicePtr dev) { ScreenPtr pScreen = xf86ScrnToScreen(pScrn); CMapScreenPtr pScreenPriv = (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, CMapScreenKey); int ret; ret = (*pScreenPriv->SetDGAMode) (pScrn, num, dev); pScreenPriv->isDGAmode = DGAActive(pScrn->scrnIndex); if (!pScreenPriv->isDGAmode && GetInstalledmiColormap(pScreen) && xf86ScreenToScrn(pScreen)->vtSema) CMapReinstallMap(GetInstalledmiColormap(pScreen)); return ret; } #endif /**** Utilities ****/ static void CMapReinstallMap(ColormapPtr pmap) { CMapScreenPtr pScreenPriv = (CMapScreenPtr) dixLookupPrivate(&pmap->pScreen->devPrivates, CMapScreenKey); CMapColormapPtr cmapPriv = (CMapColormapPtr) dixLookupPrivate(&pmap->devPrivates, CMapColormapKey); ScrnInfoPtr pScrn = xf86ScreenToScrn(pmap->pScreen); int i = cmapPriv->numColors; int *indices = pScreenPriv->PreAllocIndices; while (i--) indices[i] = i; if (cmapPriv->recalculate) CMapRefreshColors(pmap, cmapPriv->numColors, indices); else { (*pScrn->LoadPalette) (pScrn, cmapPriv->numColors, indices, cmapPriv->colors, pmap->pVisual); if (pScrn->SetOverscan) { #ifdef DEBUGOVERSCAN ErrorF("SetOverscan() called from CMapReinstallMap\n"); #endif pScrn->SetOverscan(pScrn, cmapPriv->overscan); } } cmapPriv->recalculate = FALSE; } static void CMapRefreshColors(ColormapPtr pmap, int defs, int *indices) { CMapScreenPtr pScreenPriv = (CMapScreenPtr) dixLookupPrivate(&pmap->pScreen->devPrivates, CMapScreenKey); CMapColormapPtr pColPriv = (CMapColormapPtr) dixLookupPrivate(&pmap->devPrivates, CMapColormapKey); VisualPtr pVisual = pmap->pVisual; ScrnInfoPtr pScrn = xf86ScreenToScrn(pmap->pScreen); int numColors, i; LOCO *gamma, *colors; EntryPtr entry; int reds, greens, blues, maxValue, index, shift; numColors = pColPriv->numColors; shift = 16 - pScreenPriv->sigRGBbits; maxValue = (1 << pScreenPriv->sigRGBbits) - 1; gamma = pScreenPriv->gamma; colors = pColPriv->colors; reds = pVisual->redMask >> pVisual->offsetRed; greens = pVisual->greenMask >> pVisual->offsetGreen; blues = pVisual->blueMask >> pVisual->offsetBlue; switch (pVisual->class) { case StaticGray: for (i = 0; i < numColors; i++) { index = (i + 1) * maxValue / numColors; colors[i].red = gamma[index].red; colors[i].green = gamma[index].green; colors[i].blue = gamma[index].blue; } break; case TrueColor: if (CMapColormapUseMax(pVisual, pScreenPriv)) { for (i = 0; i <= reds; i++) colors[i].red = gamma[i * maxValue / reds].red; for (i = 0; i <= greens; i++) colors[i].green = gamma[i * maxValue / greens].green; for (i = 0; i <= blues; i++) colors[i].blue = gamma[i * maxValue / blues].blue; break; } for (i = 0; i < numColors; i++) { colors[i].red = gamma[((i >> pVisual->offsetRed) & reds) * maxValue / reds].red; colors[i].green = gamma[((i >> pVisual->offsetGreen) & greens) * maxValue / greens].green; colors[i].blue = gamma[((i >> pVisual->offsetBlue) & blues) * maxValue / blues].blue; } break; case StaticColor: case PseudoColor: case GrayScale: for (i = 0; i < defs; i++) { index = indices[i]; entry = (EntryPtr) &pmap->red[index]; if (entry->fShared) { colors[index].red = gamma[entry->co.shco.red->color >> shift].red; colors[index].green = gamma[entry->co.shco.green->color >> shift].green; colors[index].blue = gamma[entry->co.shco.blue->color >> shift].blue; } else { colors[index].red = gamma[entry->co.local.red >> shift].red; colors[index].green = gamma[entry->co.local.green >> shift].green; colors[index].blue = gamma[entry->co.local.blue >> shift].blue; } } break; case DirectColor: if (CMapColormapUseMax(pVisual, pScreenPriv)) { for (i = 0; i < defs; i++) { index = indices[i]; if (index <= reds) colors[index].red = gamma[pmap->red[index].co.local.red >> shift].red; if (index <= greens) colors[index].green = gamma[pmap->green[index].co.local.green >> shift].green; if (index <= blues) colors[index].blue = gamma[pmap->blue[index].co.local.blue >> shift].blue; } break; } for (i = 0; i < defs; i++) { index = indices[i]; colors[index].red = gamma[pmap->red[(index >> pVisual-> offsetRed) & reds].co.local. red >> shift].red; colors[index].green = gamma[pmap->green[(index >> pVisual->offsetGreen) & greens].co. local.green >> shift].green; colors[index].blue = gamma[pmap->blue[(index >> pVisual->offsetBlue) & blues].co. local.blue >> shift].blue; } break; } if (LOAD_PALETTE(pmap)) (*pScrn->LoadPalette) (pScrn, defs, indices, colors, pmap->pVisual); if (pScrn->SetOverscan) CMapSetOverscan(pmap, defs, indices); } static Bool CMapCompareColors(LOCO * color1, LOCO * color2) { /* return TRUE if the color1 is "closer" to black than color2 */ #ifdef DEBUGOVERSCAN ErrorF("#%02x%02x%02x vs #%02x%02x%02x (%d vs %d)\n", color1->red, color1->green, color1->blue, color2->red, color2->green, color2->blue, color1->red + color1->green + color1->blue, color2->red + color2->green + color2->blue); #endif return (color1->red + color1->green + color1->blue < color2->red + color2->green + color2->blue); } static void CMapSetOverscan(ColormapPtr pmap, int defs, int *indices) { CMapScreenPtr pScreenPriv = (CMapScreenPtr) dixLookupPrivate(&pmap->pScreen->devPrivates, CMapScreenKey); CMapColormapPtr pColPriv = (CMapColormapPtr) dixLookupPrivate(&pmap->devPrivates, CMapColormapKey); ScrnInfoPtr pScrn = xf86ScreenToScrn(pmap->pScreen); VisualPtr pVisual = pmap->pVisual; int i; LOCO *colors; int index; Bool newOverscan = FALSE; int overscan, tmpOverscan; colors = pColPriv->colors; overscan = pColPriv->overscan; /* * Search for a new overscan index in the following cases: * * - The index hasn't yet been initialised.  In this case search * for an index that is black or a close match to black. * * - The colour of the old index is changed. In this case search * all indices for a black or close match to black. * * - The colour of the old index wasn't black. In this case only * search the indices that were changed for a better match to black. */ switch (pVisual->class) { case StaticGray: case TrueColor: /* Should only come here once. Initialise the overscan index to 0 */ overscan = 0; newOverscan = TRUE; break; case StaticColor: /* * Only come here once, but search for the overscan in the same way * as for the other cases. */ case DirectColor: case PseudoColor: case GrayScale: if (overscan < 0 || overscan > pScreenPriv->maxColors - 1) { /* Uninitialised */ newOverscan = TRUE; } else { /* Check if the overscan was changed */ for (i = 0; i < defs; i++) { index = indices[i]; if (index == overscan) { newOverscan = TRUE; break; } } } if (newOverscan) { /* The overscan is either uninitialised or it has been changed */ if (overscan < 0 || overscan > pScreenPriv->maxColors - 1) tmpOverscan = pScreenPriv->maxColors - 1; else tmpOverscan = overscan; /* search all entries for a close match to black */ for (i = pScreenPriv->maxColors - 1; i >= 0; i--) { if (colors[i].red == 0 && colors[i].green == 0 && colors[i].blue == 0) { overscan = i; #ifdef DEBUGOVERSCAN ErrorF("Black found at index 0x%02x\n", i); #endif break; } else { #ifdef DEBUGOVERSCAN ErrorF("0x%02x: ", i); #endif if (CMapCompareColors(&colors[i], &colors[tmpOverscan])) { tmpOverscan = i; #ifdef DEBUGOVERSCAN ErrorF("possible \"Black\" at index 0x%02x\n", i); #endif } } } if (i < 0) overscan = tmpOverscan; } else { /* Check of the old overscan wasn't black */ if (colors[overscan].red != 0 || colors[overscan].green != 0 || colors[overscan].blue != 0) { int oldOverscan = tmpOverscan = overscan; /* See of there is now a better match */ for (i = 0; i < defs; i++) { index = indices[i]; if (colors[index].red == 0 && colors[index].green == 0 && colors[index].blue == 0) { overscan = index; #ifdef DEBUGOVERSCAN ErrorF("Black found at index 0x%02x\n", index); #endif break; } else { #ifdef DEBUGOVERSCAN ErrorF("0x%02x: ", index); #endif if (CMapCompareColors(&colors[index], &colors[tmpOverscan])) { tmpOverscan = index; #ifdef DEBUGOVERSCAN ErrorF("possible \"Black\" at index 0x%02x\n", index); #endif } } } if (i == defs) overscan = tmpOverscan; if (overscan != oldOverscan) newOverscan = TRUE; } } break; } if (newOverscan) { pColPriv->overscan = overscan; if (LOAD_PALETTE(pmap)) { #ifdef DEBUGOVERSCAN ErrorF("SetOverscan() called from CmapSetOverscan\n"); #endif pScrn->SetOverscan(pScrn, overscan); } } } static void CMapUnwrapScreen(ScreenPtr pScreen) { CMapScreenPtr pScreenPriv = (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, CMapScreenKey); ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); pScreen->CloseScreen = pScreenPriv->CloseScreen; pScreen->CreateColormap = pScreenPriv->CreateColormap; pScreen->DestroyColormap = pScreenPriv->DestroyColormap; pScreen->InstallColormap = pScreenPriv->InstallColormap; pScreen->StoreColors = pScreenPriv->StoreColors; pScrn->EnterVT = pScreenPriv->EnterVT; pScrn->SwitchMode = pScreenPriv->SwitchMode; pScrn->SetDGAMode = pScreenPriv->SetDGAMode; pScrn->ChangeGamma = pScreenPriv->ChangeGamma; free(pScreenPriv->gamma); free(pScreenPriv->PreAllocIndices); free(pScreenPriv); } static void ComputeGamma(ScrnInfoPtr pScrn, CMapScreenPtr priv) { int elements = priv->gammaElements - 1; double RedGamma, GreenGamma, BlueGamma; int i; #ifndef DONT_CHECK_GAMMA /* This check is to catch drivers that are not initialising pScrn->gamma */ if (pScrn->gamma.red < GAMMA_MIN || pScrn->gamma.red > GAMMA_MAX || pScrn->gamma.green < GAMMA_MIN || pScrn->gamma.green > GAMMA_MAX || pScrn->gamma.blue < GAMMA_MIN || pScrn->gamma.blue > GAMMA_MAX) { xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, 0, "The %s driver didn't call xf86SetGamma() to initialise\n" "\tthe gamma values.\n", pScrn->driverName); xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, 0, "PLEASE FIX THE `%s' DRIVER!\n", pScrn->driverName); pScrn->gamma.red = 1.0; pScrn->gamma.green = 1.0; pScrn->gamma.blue = 1.0; } #endif RedGamma = 1.0 / (double) pScrn->gamma.red; GreenGamma = 1.0 / (double) pScrn->gamma.green; BlueGamma = 1.0 / (double) pScrn->gamma.blue; for (i = 0; i <= elements; i++) { if (RedGamma == 1.0) priv->gamma[i].red = i; else priv->gamma[i].red = (CARD16) (pow((double) i / (double) elements, RedGamma) * (double) elements + 0.5); if (GreenGamma == 1.0) priv->gamma[i].green = i; else priv->gamma[i].green = (CARD16) (pow((double) i / (double) elements, GreenGamma) * (double) elements + 0.5); if (BlueGamma == 1.0) priv->gamma[i].blue = i; else priv->gamma[i].blue = (CARD16) (pow((double) i / (double) elements, BlueGamma) * (double) elements + 0.5); } } int CMapChangeGamma(ScrnInfoPtr pScrn, Gamma gamma) { int ret = Success; ScreenPtr pScreen = xf86ScrnToScreen(pScrn); CMapColormapPtr pColPriv; CMapScreenPtr pScreenPriv; CMapLinkPtr pLink; /* Is this sufficient checking ? */ if (!CMapScreenKeyRegistered) return BadImplementation; pScreenPriv = (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, CMapScreenKey); if (!pScreenPriv) return BadImplementation; if (gamma.red < GAMMA_MIN || gamma.red > GAMMA_MAX || gamma.green < GAMMA_MIN || gamma.green > GAMMA_MAX || gamma.blue < GAMMA_MIN || gamma.blue > GAMMA_MAX) return BadValue; pScrn->gamma.red = gamma.red; pScrn->gamma.green = gamma.green; pScrn->gamma.blue = gamma.blue; ComputeGamma(pScrn, pScreenPriv); /* mark all colormaps on this screen */ pLink = pScreenPriv->maps; while (pLink) { pColPriv = (CMapColormapPtr) dixLookupPrivate(&pLink->cmap->devPrivates, CMapColormapKey); pColPriv->recalculate = TRUE; pLink = pLink->next; } if (GetInstalledmiColormap(pScreen) && ((pScreenPriv->flags & CMAP_LOAD_EVEN_IF_OFFSCREEN) || pScrn->vtSema || pScreenPriv->isDGAmode)) { ColormapPtr pMap = GetInstalledmiColormap(pScreen); if (!(pScreenPriv->flags & CMAP_PALETTED_TRUECOLOR) && (pMap->pVisual->class == TrueColor) && CMapColormapUseMax(pMap->pVisual, pScreenPriv)) { /* if the current map doesn't have a palette look for another map to change the gamma on. */ pLink = pScreenPriv->maps; while (pLink) { if (pLink->cmap->pVisual->class == PseudoColor) break; pLink = pLink->next; } if (pLink) { /* need to trick CMapRefreshColors() into thinking this is the currently installed map */ SetInstalledmiColormap(pScreen, pLink->cmap); CMapReinstallMap(pLink->cmap); SetInstalledmiColormap(pScreen, pMap); } } else CMapReinstallMap(pMap); } pScrn->ChangeGamma = pScreenPriv->ChangeGamma; if (pScrn->ChangeGamma) ret = pScrn->ChangeGamma(pScrn, gamma); pScrn->ChangeGamma = CMapChangeGamma; return ret; } static void ComputeGammaRamp(CMapScreenPtr priv, unsigned short *red, unsigned short *green, unsigned short *blue) { int elements = priv->gammaElements; LOCO *entry = priv->gamma; int shift = 16 - priv->sigRGBbits; while (elements--) { entry->red = *(red++) >> shift; entry->green = *(green++) >> shift; entry->blue = *(blue++) >> shift; entry++; } } int xf86ChangeGammaRamp(ScreenPtr pScreen, int size, unsigned short *red, unsigned short *green, unsigned short *blue) { ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); CMapColormapPtr pColPriv; CMapScreenPtr pScreenPriv; CMapLinkPtr pLink; if (!CMapScreenKeyRegistered) return BadImplementation; pScreenPriv = (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, CMapScreenKey); if (!pScreenPriv) return BadImplementation; if (pScreenPriv->gammaElements != size) return BadValue; ComputeGammaRamp(pScreenPriv, red, green, blue); /* mark all colormaps on this screen */ pLink = pScreenPriv->maps; while (pLink) { pColPriv = (CMapColormapPtr) dixLookupPrivate(&pLink->cmap->devPrivates, CMapColormapKey); pColPriv->recalculate = TRUE; pLink = pLink->next; } if (GetInstalledmiColormap(pScreen) && ((pScreenPriv->flags & CMAP_LOAD_EVEN_IF_OFFSCREEN) || pScrn->vtSema || pScreenPriv->isDGAmode)) { ColormapPtr pMap = GetInstalledmiColormap(pScreen); if (!(pScreenPriv->flags & CMAP_PALETTED_TRUECOLOR) && (pMap->pVisual->class == TrueColor) && CMapColormapUseMax(pMap->pVisual, pScreenPriv)) { /* if the current map doesn't have a palette look for another map to change the gamma on. */ pLink = pScreenPriv->maps; while (pLink) { if (pLink->cmap->pVisual->class == PseudoColor) break; pLink = pLink->next; } if (pLink) { /* need to trick CMapRefreshColors() into thinking this is the currently installed map */ SetInstalledmiColormap(pScreen, pLink->cmap); CMapReinstallMap(pLink->cmap); SetInstalledmiColormap(pScreen, pMap); } } else CMapReinstallMap(pMap); } return Success; } int xf86GetGammaRampSize(ScreenPtr pScreen) { CMapScreenPtr pScreenPriv; if (!CMapScreenKeyRegistered) return 0; pScreenPriv = (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, CMapScreenKey); if (!pScreenPriv) return 0; return pScreenPriv->gammaElements; } int xf86GetGammaRamp(ScreenPtr pScreen, int size, unsigned short *red, unsigned short *green, unsigned short *blue) { CMapScreenPtr pScreenPriv; LOCO *entry; int shift, sigbits; if (!CMapScreenKeyRegistered) return BadImplementation; pScreenPriv = (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, CMapScreenKey); if (!pScreenPriv) return BadImplementation; if (size > pScreenPriv->gammaElements) return BadValue; entry = pScreenPriv->gamma; sigbits = pScreenPriv->sigRGBbits; while (size--) { *red = entry->red << (16 - sigbits); *green = entry->green << (16 - sigbits); *blue = entry->blue << (16 - sigbits); shift = sigbits; while (shift < 16) { *red |= *red >> shift; *green |= *green >> shift; *blue |= *blue >> shift; shift += sigbits; } red++; green++; blue++; entry++; } return Success; } int xf86ChangeGamma(ScreenPtr pScreen, Gamma gamma) { ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); if (pScrn->ChangeGamma) return (*pScrn->ChangeGamma) (pScrn, gamma); return BadImplementation; }