105b261ecSmrg/*
205b261ecSmrg * Copyright (c) 1998-2001 by The XFree86 Project, Inc.
305b261ecSmrg *
405b261ecSmrg * Permission is hereby granted, free of charge, to any person obtaining a
505b261ecSmrg * copy of this software and associated documentation files (the "Software"),
605b261ecSmrg * to deal in the Software without restriction, including without limitation
705b261ecSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
805b261ecSmrg * and/or sell copies of the Software, and to permit persons to whom the
905b261ecSmrg * Software is furnished to do so, subject to the following conditions:
1005b261ecSmrg *
1105b261ecSmrg * The above copyright notice and this permission notice shall be included in
1205b261ecSmrg * all copies or substantial portions of the Software.
1305b261ecSmrg *
1405b261ecSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1505b261ecSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1605b261ecSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1705b261ecSmrg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
1805b261ecSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1905b261ecSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2005b261ecSmrg * OTHER DEALINGS IN THE SOFTWARE.
2105b261ecSmrg *
2205b261ecSmrg * Except as contained in this notice, the name of the copyright holder(s)
2305b261ecSmrg * and author(s) shall not be used in advertising or otherwise to promote
2405b261ecSmrg * the sale, use or other dealings in this Software without prior written
2505b261ecSmrg * authorization from the copyright holder(s) and author(s).
2605b261ecSmrg */
2705b261ecSmrg
2805b261ecSmrg#ifdef HAVE_XORG_CONFIG_H
2905b261ecSmrg#include <xorg-config.h>
3005b261ecSmrg#endif
3105b261ecSmrg
321b5d61b8Smrg#if defined(_XOPEN_SOURCE) || defined(__sun) && defined(__SVR4)
3305b261ecSmrg#include <math.h>
3405b261ecSmrg#else
3535c4bbdfSmrg#define _XOPEN_SOURCE           /* to get prototype for pow on some systems */
3605b261ecSmrg#include <math.h>
3705b261ecSmrg#undef _XOPEN_SOURCE
3805b261ecSmrg#endif
3905b261ecSmrg
4005b261ecSmrg#include <X11/X.h>
4105b261ecSmrg#include "misc.h"
4205b261ecSmrg#include <X11/Xproto.h>
4305b261ecSmrg#include "colormapst.h"
4405b261ecSmrg#include "scrnintstr.h"
4505b261ecSmrg
4605b261ecSmrg#include "resource.h"
4705b261ecSmrg
4805b261ecSmrg#include "xf86.h"
4905b261ecSmrg#include "xf86_OSproc.h"
5005b261ecSmrg#include "xf86str.h"
5105b261ecSmrg#include "micmap.h"
521b5d61b8Smrg#include "xf86RandR12.h"
536747b715Smrg#include "xf86Crtc.h"
5405b261ecSmrg
5505b261ecSmrg#ifdef XFreeXDGA
566747b715Smrg#include <X11/extensions/xf86dgaproto.h>
5705b261ecSmrg#include "dgaproc.h"
5805b261ecSmrg#endif
5905b261ecSmrg
6005b261ecSmrg#include "xf86cmap.h"
6105b261ecSmrg
6205b261ecSmrg#define SCREEN_PROLOGUE(pScreen, field) ((pScreen)->field = \
634642e01fSmrg    ((CMapScreenPtr)dixLookupPrivate(&(pScreen)->devPrivates, CMapScreenKey))->field)
6405b261ecSmrg#define SCREEN_EPILOGUE(pScreen, field, wrapper)\
6505b261ecSmrg    ((pScreen)->field = wrapper)
6605b261ecSmrg
676747b715Smrg#define LOAD_PALETTE(pmap) \
686747b715Smrg    ((pmap == GetInstalledmiColormap(pmap->pScreen)) && \
6905b261ecSmrg     ((pScreenPriv->flags & CMAP_LOAD_EVEN_IF_OFFSCREEN) || \
7035c4bbdfSmrg      xf86ScreenToScrn(pmap->pScreen)->vtSema || pScreenPriv->isDGAmode))
7105b261ecSmrg
7205b261ecSmrgtypedef struct _CMapLink {
7335c4bbdfSmrg    ColormapPtr cmap;
7435c4bbdfSmrg    struct _CMapLink *next;
7505b261ecSmrg} CMapLink, *CMapLinkPtr;
7605b261ecSmrg
7705b261ecSmrgtypedef struct {
7835c4bbdfSmrg    CloseScreenProcPtr CloseScreen;
7935c4bbdfSmrg    CreateColormapProcPtr CreateColormap;
8035c4bbdfSmrg    DestroyColormapProcPtr DestroyColormap;
8135c4bbdfSmrg    InstallColormapProcPtr InstallColormap;
8235c4bbdfSmrg    StoreColorsProcPtr StoreColors;
8335c4bbdfSmrg    Bool (*EnterVT) (ScrnInfoPtr);
8435c4bbdfSmrg    Bool (*SwitchMode) (ScrnInfoPtr, DisplayModePtr);
8535c4bbdfSmrg    int (*SetDGAMode) (ScrnInfoPtr, int, DGADevicePtr);
8635c4bbdfSmrg    xf86ChangeGammaProc *ChangeGamma;
8735c4bbdfSmrg    int maxColors;
8835c4bbdfSmrg    int sigRGBbits;
8935c4bbdfSmrg    int gammaElements;
9035c4bbdfSmrg    LOCO *gamma;
9135c4bbdfSmrg    int *PreAllocIndices;
9235c4bbdfSmrg    CMapLinkPtr maps;
9335c4bbdfSmrg    unsigned int flags;
9435c4bbdfSmrg    Bool isDGAmode;
9505b261ecSmrg} CMapScreenRec, *CMapScreenPtr;
9605b261ecSmrg
9705b261ecSmrgtypedef struct {
9835c4bbdfSmrg    int numColors;
9935c4bbdfSmrg    LOCO *colors;
10035c4bbdfSmrg    Bool recalculate;
10135c4bbdfSmrg    int overscan;
10205b261ecSmrg} CMapColormapRec, *CMapColormapPtr;
10305b261ecSmrg
1046747b715Smrgstatic DevPrivateKeyRec CMapScreenKeyRec;
10535c4bbdfSmrg
1066747b715Smrg#define CMapScreenKeyRegistered dixPrivateKeyRegistered(&CMapScreenKeyRec)
1076747b715Smrg#define CMapScreenKey (&CMapScreenKeyRec)
1086747b715Smrgstatic DevPrivateKeyRec CMapColormapKeyRec;
10935c4bbdfSmrg
1106747b715Smrg#define CMapColormapKey (&CMapColormapKeyRec)
11105b261ecSmrg
11205b261ecSmrgstatic void CMapInstallColormap(ColormapPtr);
11305b261ecSmrgstatic void CMapStoreColors(ColormapPtr, int, xColorItem *);
11435c4bbdfSmrgstatic Bool CMapCloseScreen(ScreenPtr);
11535c4bbdfSmrgstatic Bool CMapCreateColormap(ColormapPtr);
11635c4bbdfSmrgstatic void CMapDestroyColormap(ColormapPtr);
11735c4bbdfSmrg
11835c4bbdfSmrgstatic Bool CMapEnterVT(ScrnInfoPtr);
11935c4bbdfSmrgstatic Bool CMapSwitchMode(ScrnInfoPtr, DisplayModePtr);
12005b261ecSmrg
1216747b715Smrg#ifdef XFreeXDGA
12235c4bbdfSmrgstatic int CMapSetDGAMode(ScrnInfoPtr, int, DGADevicePtr);
1236747b715Smrg#endif
12435c4bbdfSmrgstatic int CMapChangeGamma(ScrnInfoPtr, Gamma);
12505b261ecSmrg
12635c4bbdfSmrgstatic void ComputeGamma(ScrnInfoPtr, CMapScreenPtr);
12705b261ecSmrgstatic Bool CMapAllocateColormapPrivate(ColormapPtr);
12835c4bbdfSmrgstatic void CMapRefreshColors(ColormapPtr, int, int *);
12905b261ecSmrgstatic void CMapSetOverscan(ColormapPtr, int, int *);
13005b261ecSmrgstatic void CMapReinstallMap(ColormapPtr);
13105b261ecSmrgstatic void CMapUnwrapScreen(ScreenPtr pScreen);
13205b261ecSmrg
13335c4bbdfSmrgBool
13435c4bbdfSmrgxf86ColormapAllocatePrivates(ScrnInfoPtr pScrn)
1356747b715Smrg{
1366747b715Smrg    if (!dixRegisterPrivateKey(&CMapScreenKeyRec, PRIVATE_SCREEN, 0))
13735c4bbdfSmrg        return FALSE;
1386747b715Smrg
1396747b715Smrg    if (!dixRegisterPrivateKey(&CMapColormapKeyRec, PRIVATE_COLORMAP, 0))
14035c4bbdfSmrg        return FALSE;
1416747b715Smrg    return TRUE;
1426747b715Smrg}
14305b261ecSmrg
14435c4bbdfSmrgBool
14535c4bbdfSmrgxf86HandleColormaps(ScreenPtr pScreen,
14635c4bbdfSmrg                    int maxColors,
14735c4bbdfSmrg                    int sigRGBbits,
14835c4bbdfSmrg                    xf86LoadPaletteProc * loadPalette,
14935c4bbdfSmrg                    xf86SetOverscanProc * setOverscan, unsigned int flags)
15035c4bbdfSmrg{
15135c4bbdfSmrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
15205b261ecSmrg    ColormapPtr pDefMap = NULL;
15335c4bbdfSmrg    CMapScreenPtr pScreenPriv;
15435c4bbdfSmrg    LOCO *gamma;
15535c4bbdfSmrg    int *indices;
15605b261ecSmrg    int elements;
15705b261ecSmrg
1581b5d61b8Smrg    if (!maxColors || !sigRGBbits ||
1591b5d61b8Smrg        (!loadPalette && !xf86_crtc_supports_gamma(pScrn)))
16035c4bbdfSmrg        return FALSE;
16105b261ecSmrg
16205b261ecSmrg    elements = 1 << sigRGBbits;
16305b261ecSmrg
16435c4bbdfSmrg    if (!(gamma = xallocarray(elements, sizeof(LOCO))))
16535c4bbdfSmrg        return FALSE;
16605b261ecSmrg
16735c4bbdfSmrg    if (!(indices = xallocarray(maxColors, sizeof(int)))) {
16835c4bbdfSmrg        free(gamma);
16935c4bbdfSmrg        return FALSE;
17005b261ecSmrg    }
17135c4bbdfSmrg
17235c4bbdfSmrg    if (!(pScreenPriv = malloc(sizeof(CMapScreenRec)))) {
17335c4bbdfSmrg        free(gamma);
17435c4bbdfSmrg        free(indices);
17535c4bbdfSmrg        return FALSE;
17605b261ecSmrg    }
17705b261ecSmrg
1786747b715Smrg    dixSetPrivate(&pScreen->devPrivates, &CMapScreenKeyRec, pScreenPriv);
17935c4bbdfSmrg
18005b261ecSmrg    pScreenPriv->CloseScreen = pScreen->CloseScreen;
18105b261ecSmrg    pScreenPriv->CreateColormap = pScreen->CreateColormap;
18205b261ecSmrg    pScreenPriv->DestroyColormap = pScreen->DestroyColormap;
18305b261ecSmrg    pScreenPriv->InstallColormap = pScreen->InstallColormap;
18405b261ecSmrg    pScreenPriv->StoreColors = pScreen->StoreColors;
18505b261ecSmrg    pScreen->CloseScreen = CMapCloseScreen;
18605b261ecSmrg    pScreen->CreateColormap = CMapCreateColormap;
18705b261ecSmrg    pScreen->DestroyColormap = CMapDestroyColormap;
18805b261ecSmrg    pScreen->InstallColormap = CMapInstallColormap;
18905b261ecSmrg    pScreen->StoreColors = CMapStoreColors;
19005b261ecSmrg
19105b261ecSmrg    pScrn->LoadPalette = loadPalette;
19205b261ecSmrg    pScrn->SetOverscan = setOverscan;
19305b261ecSmrg    pScreenPriv->maxColors = maxColors;
19405b261ecSmrg    pScreenPriv->sigRGBbits = sigRGBbits;
19505b261ecSmrg    pScreenPriv->gammaElements = elements;
19605b261ecSmrg    pScreenPriv->gamma = gamma;
19705b261ecSmrg    pScreenPriv->PreAllocIndices = indices;
19805b261ecSmrg    pScreenPriv->maps = NULL;
19905b261ecSmrg    pScreenPriv->flags = flags;
20005b261ecSmrg    pScreenPriv->isDGAmode = FALSE;
20105b261ecSmrg
20205b261ecSmrg    pScreenPriv->EnterVT = pScrn->EnterVT;
20305b261ecSmrg    pScreenPriv->SwitchMode = pScrn->SwitchMode;
20435c4bbdfSmrg    pScreenPriv->SetDGAMode = pScrn->SetDGAMode;
2056747b715Smrg    pScreenPriv->ChangeGamma = pScrn->ChangeGamma;
20605b261ecSmrg
20705b261ecSmrg    if (!(flags & CMAP_LOAD_EVEN_IF_OFFSCREEN)) {
20835c4bbdfSmrg        pScrn->EnterVT = CMapEnterVT;
20935c4bbdfSmrg        if ((flags & CMAP_RELOAD_ON_MODE_SWITCH) && pScrn->SwitchMode)
21035c4bbdfSmrg            pScrn->SwitchMode = CMapSwitchMode;
21105b261ecSmrg    }
21205b261ecSmrg#ifdef XFreeXDGA
21305b261ecSmrg    pScrn->SetDGAMode = CMapSetDGAMode;
21405b261ecSmrg#endif
21505b261ecSmrg    pScrn->ChangeGamma = CMapChangeGamma;
21635c4bbdfSmrg
21735c4bbdfSmrg    ComputeGamma(pScrn, pScreenPriv);
21805b261ecSmrg
21905b261ecSmrg    /* get the default map */
22035c4bbdfSmrg    dixLookupResourceByType((void **) &pDefMap, pScreen->defColormap,
22135c4bbdfSmrg                            RT_COLORMAP, serverClient, DixInstallAccess);
22235c4bbdfSmrg
22335c4bbdfSmrg    if (!CMapAllocateColormapPrivate(pDefMap)) {
22405b261ecSmrg        CMapUnwrapScreen(pScreen);
22535c4bbdfSmrg        return FALSE;
22605b261ecSmrg    }
22705b261ecSmrg
2281b5d61b8Smrg    if (xf86_crtc_supports_gamma(pScrn)) {
2291b5d61b8Smrg        pScrn->LoadPalette = xf86RandR12LoadPalette;
2301b5d61b8Smrg
2311b5d61b8Smrg        if (!xf86RandR12InitGamma(pScrn, elements)) {
2321b5d61b8Smrg            CMapUnwrapScreen(pScreen);
2331b5d61b8Smrg            return FALSE;
2341b5d61b8Smrg        }
2351b5d61b8Smrg    }
2361b5d61b8Smrg
23705b261ecSmrg    /* Force the initial map to be loaded */
2386747b715Smrg    SetInstalledmiColormap(pScreen, NULL);
23905b261ecSmrg    CMapInstallColormap(pDefMap);
24005b261ecSmrg    return TRUE;
24105b261ecSmrg}
24205b261ecSmrg
24305b261ecSmrg/**** Screen functions ****/
24405b261ecSmrg
24505b261ecSmrgstatic Bool
24635c4bbdfSmrgCMapCloseScreen(ScreenPtr pScreen)
24705b261ecSmrg{
24805b261ecSmrg    CMapUnwrapScreen(pScreen);
24905b261ecSmrg
25035c4bbdfSmrg    return (*pScreen->CloseScreen) (pScreen);
25105b261ecSmrg}
25205b261ecSmrg
25305b261ecSmrgstatic Bool
25405b261ecSmrgCMapColormapUseMax(VisualPtr pVisual, CMapScreenPtr pScreenPriv)
25505b261ecSmrg{
25605b261ecSmrg    if (pVisual->nplanes > 16)
25705b261ecSmrg        return TRUE;
25805b261ecSmrg    return ((1 << pVisual->nplanes) > pScreenPriv->maxColors);
25905b261ecSmrg}
26005b261ecSmrg
26105b261ecSmrgstatic Bool
26205b261ecSmrgCMapAllocateColormapPrivate(ColormapPtr pmap)
26305b261ecSmrg{
26435c4bbdfSmrg    CMapScreenPtr pScreenPriv =
26535c4bbdfSmrg        (CMapScreenPtr) dixLookupPrivate(&pmap->pScreen->devPrivates,
26635c4bbdfSmrg                                         CMapScreenKey);
26705b261ecSmrg    CMapColormapPtr pColPriv;
26805b261ecSmrg    CMapLinkPtr pLink;
26905b261ecSmrg    int numColors;
27005b261ecSmrg    LOCO *colors;
27105b261ecSmrg
27205b261ecSmrg    if (CMapColormapUseMax(pmap->pVisual, pScreenPriv))
27335c4bbdfSmrg        numColors = pmap->pVisual->ColormapEntries;
27435c4bbdfSmrg    else
27535c4bbdfSmrg        numColors = 1 << pmap->pVisual->nplanes;
27605b261ecSmrg
27735c4bbdfSmrg    if (!(colors = xallocarray(numColors, sizeof(LOCO))))
27835c4bbdfSmrg        return FALSE;
27905b261ecSmrg
28035c4bbdfSmrg    if (!(pColPriv = malloc(sizeof(CMapColormapRec)))) {
28135c4bbdfSmrg        free(colors);
28235c4bbdfSmrg        return FALSE;
28335c4bbdfSmrg    }
28405b261ecSmrg
2854642e01fSmrg    dixSetPrivate(&pmap->devPrivates, CMapColormapKey, pColPriv);
28635c4bbdfSmrg
28705b261ecSmrg    pColPriv->numColors = numColors;
28805b261ecSmrg    pColPriv->colors = colors;
28905b261ecSmrg    pColPriv->recalculate = TRUE;
29005b261ecSmrg    pColPriv->overscan = -1;
29105b261ecSmrg
29205b261ecSmrg    /* add map to list */
2936747b715Smrg    pLink = malloc(sizeof(CMapLink));
29435c4bbdfSmrg    if (pLink) {
29535c4bbdfSmrg        pLink->cmap = pmap;
29635c4bbdfSmrg        pLink->next = pScreenPriv->maps;
29735c4bbdfSmrg        pScreenPriv->maps = pLink;
29805b261ecSmrg    }
29905b261ecSmrg
30005b261ecSmrg    return TRUE;
30105b261ecSmrg}
30205b261ecSmrg
30335c4bbdfSmrgstatic Bool
30435c4bbdfSmrgCMapCreateColormap(ColormapPtr pmap)
30505b261ecSmrg{
30605b261ecSmrg    ScreenPtr pScreen = pmap->pScreen;
30735c4bbdfSmrg    CMapScreenPtr pScreenPriv =
30835c4bbdfSmrg        (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, CMapScreenKey);
30905b261ecSmrg    Bool ret = FALSE;
31005b261ecSmrg
31105b261ecSmrg    pScreen->CreateColormap = pScreenPriv->CreateColormap;
31235c4bbdfSmrg    if ((*pScreen->CreateColormap) (pmap)) {
31335c4bbdfSmrg        if (CMapAllocateColormapPrivate(pmap))
31435c4bbdfSmrg            ret = TRUE;
31505b261ecSmrg    }
31605b261ecSmrg    pScreen->CreateColormap = CMapCreateColormap;
31705b261ecSmrg
31805b261ecSmrg    return ret;
31905b261ecSmrg}
32005b261ecSmrg
32105b261ecSmrgstatic void
32235c4bbdfSmrgCMapDestroyColormap(ColormapPtr cmap)
32305b261ecSmrg{
32405b261ecSmrg    ScreenPtr pScreen = cmap->pScreen;
32535c4bbdfSmrg    CMapScreenPtr pScreenPriv =
32635c4bbdfSmrg        (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, CMapScreenKey);
32735c4bbdfSmrg    CMapColormapPtr pColPriv =
32835c4bbdfSmrg        (CMapColormapPtr) dixLookupPrivate(&cmap->devPrivates, CMapColormapKey);
32905b261ecSmrg    CMapLinkPtr prevLink = NULL, pLink = pScreenPriv->maps;
33005b261ecSmrg
33135c4bbdfSmrg    if (pColPriv) {
33235c4bbdfSmrg        free(pColPriv->colors);
33335c4bbdfSmrg        free(pColPriv);
33405b261ecSmrg    }
33535c4bbdfSmrg
33605b261ecSmrg    /* remove map from list */
33735c4bbdfSmrg    while (pLink) {
33835c4bbdfSmrg        if (pLink->cmap == cmap) {
33935c4bbdfSmrg            if (prevLink)
34035c4bbdfSmrg                prevLink->next = pLink->next;
34135c4bbdfSmrg            else
34235c4bbdfSmrg                pScreenPriv->maps = pLink->next;
34335c4bbdfSmrg            free(pLink);
34435c4bbdfSmrg            break;
34535c4bbdfSmrg        }
34635c4bbdfSmrg        prevLink = pLink;
34735c4bbdfSmrg        pLink = pLink->next;
34805b261ecSmrg    }
34905b261ecSmrg
35035c4bbdfSmrg    if (pScreenPriv->DestroyColormap) {
35135c4bbdfSmrg        pScreen->DestroyColormap = pScreenPriv->DestroyColormap;
35235c4bbdfSmrg        (*pScreen->DestroyColormap) (cmap);
35335c4bbdfSmrg        pScreen->DestroyColormap = CMapDestroyColormap;
35405b261ecSmrg    }
35505b261ecSmrg}
35605b261ecSmrg
35705b261ecSmrgstatic void
35835c4bbdfSmrgCMapStoreColors(ColormapPtr pmap, int ndef, xColorItem * pdefs)
35935c4bbdfSmrg{
36035c4bbdfSmrg    ScreenPtr pScreen = pmap->pScreen;
36135c4bbdfSmrg    VisualPtr pVisual = pmap->pVisual;
36235c4bbdfSmrg    CMapScreenPtr pScreenPriv =
36335c4bbdfSmrg        (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, CMapScreenKey);
36435c4bbdfSmrg    int *indices = pScreenPriv->PreAllocIndices;
36535c4bbdfSmrg    int num = ndef;
36605b261ecSmrg
36705b261ecSmrg    /* At the moment this isn't necessary since there's nobody below us */
36805b261ecSmrg    pScreen->StoreColors = pScreenPriv->StoreColors;
36935c4bbdfSmrg    (*pScreen->StoreColors) (pmap, ndef, pdefs);
37005b261ecSmrg    pScreen->StoreColors = CMapStoreColors;
37105b261ecSmrg
37205b261ecSmrg    /* should never get here for these */
37335c4bbdfSmrg    if ((pVisual->class == TrueColor) ||
37435c4bbdfSmrg        (pVisual->class == StaticColor) || (pVisual->class == StaticGray))
37535c4bbdfSmrg        return;
37635c4bbdfSmrg
37735c4bbdfSmrg    if (pVisual->class == DirectColor) {
37835c4bbdfSmrg        CMapColormapPtr pColPriv =
37935c4bbdfSmrg            (CMapColormapPtr) dixLookupPrivate(&pmap->devPrivates,
38035c4bbdfSmrg                                               CMapColormapKey);
38135c4bbdfSmrg        int i;
38235c4bbdfSmrg
38335c4bbdfSmrg        if (CMapColormapUseMax(pVisual, pScreenPriv)) {
38435c4bbdfSmrg            int index;
38535c4bbdfSmrg
38635c4bbdfSmrg            num = 0;
38735c4bbdfSmrg            while (ndef--) {
38835c4bbdfSmrg                if (pdefs[ndef].flags & DoRed) {
38935c4bbdfSmrg                    index = (pdefs[ndef].pixel & pVisual->redMask) >>
39035c4bbdfSmrg                        pVisual->offsetRed;
39135c4bbdfSmrg                    i = num;
39235c4bbdfSmrg                    while (i--)
39335c4bbdfSmrg                        if (indices[i] == index)
39435c4bbdfSmrg                            break;
39535c4bbdfSmrg                    if (i == -1)
39635c4bbdfSmrg                        indices[num++] = index;
39735c4bbdfSmrg                }
39835c4bbdfSmrg                if (pdefs[ndef].flags & DoGreen) {
39935c4bbdfSmrg                    index = (pdefs[ndef].pixel & pVisual->greenMask) >>
40035c4bbdfSmrg                        pVisual->offsetGreen;
40135c4bbdfSmrg                    i = num;
40235c4bbdfSmrg                    while (i--)
40335c4bbdfSmrg                        if (indices[i] == index)
40435c4bbdfSmrg                            break;
40535c4bbdfSmrg                    if (i == -1)
40635c4bbdfSmrg                        indices[num++] = index;
40735c4bbdfSmrg                }
40835c4bbdfSmrg                if (pdefs[ndef].flags & DoBlue) {
40935c4bbdfSmrg                    index = (pdefs[ndef].pixel & pVisual->blueMask) >>
41035c4bbdfSmrg                        pVisual->offsetBlue;
41135c4bbdfSmrg                    i = num;
41235c4bbdfSmrg                    while (i--)
41335c4bbdfSmrg                        if (indices[i] == index)
41435c4bbdfSmrg                            break;
41535c4bbdfSmrg                    if (i == -1)
41635c4bbdfSmrg                        indices[num++] = index;
41735c4bbdfSmrg                }
41835c4bbdfSmrg            }
41935c4bbdfSmrg
42035c4bbdfSmrg        }
42135c4bbdfSmrg        else {
42235c4bbdfSmrg            /* not really as overkill as it seems */
42335c4bbdfSmrg            num = pColPriv->numColors;
42435c4bbdfSmrg            for (i = 0; i < pColPriv->numColors; i++)
42535c4bbdfSmrg                indices[i] = i;
42635c4bbdfSmrg        }
42735c4bbdfSmrg    }
42835c4bbdfSmrg    else {
42935c4bbdfSmrg        while (ndef--)
43035c4bbdfSmrg            indices[ndef] = pdefs[ndef].pixel;
43135c4bbdfSmrg    }
43205b261ecSmrg
43305b261ecSmrg    CMapRefreshColors(pmap, num, indices);
43405b261ecSmrg}
43505b261ecSmrg
43605b261ecSmrgstatic void
43705b261ecSmrgCMapInstallColormap(ColormapPtr pmap)
43805b261ecSmrg{
43935c4bbdfSmrg    ScreenPtr pScreen = pmap->pScreen;
44035c4bbdfSmrg    CMapScreenPtr pScreenPriv =
44135c4bbdfSmrg        (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, CMapScreenKey);
44205b261ecSmrg
4436747b715Smrg    if (pmap == GetInstalledmiColormap(pmap->pScreen))
44435c4bbdfSmrg        return;
44505b261ecSmrg
44605b261ecSmrg    pScreen->InstallColormap = pScreenPriv->InstallColormap;
44735c4bbdfSmrg    (*pScreen->InstallColormap) (pmap);
44805b261ecSmrg    pScreen->InstallColormap = CMapInstallColormap;
44905b261ecSmrg
45035c4bbdfSmrg    /* Important. We let the lower layers, namely DGA,
45105b261ecSmrg       overwrite the choice of Colormap to install */
4526747b715Smrg    if (GetInstalledmiColormap(pmap->pScreen))
45335c4bbdfSmrg        pmap = GetInstalledmiColormap(pmap->pScreen);
45405b261ecSmrg
45505b261ecSmrg    if (!(pScreenPriv->flags & CMAP_PALETTED_TRUECOLOR) &&
45635c4bbdfSmrg        (pmap->pVisual->class == TrueColor) &&
45735c4bbdfSmrg        CMapColormapUseMax(pmap->pVisual, pScreenPriv))
45835c4bbdfSmrg        return;
45905b261ecSmrg
46035c4bbdfSmrg    if (LOAD_PALETTE(pmap))
46135c4bbdfSmrg        CMapReinstallMap(pmap);
46205b261ecSmrg}
46305b261ecSmrg
46405b261ecSmrg/**** ScrnInfoRec functions ****/
46505b261ecSmrg
46635c4bbdfSmrgstatic Bool
46735c4bbdfSmrgCMapEnterVT(ScrnInfoPtr pScrn)
46805b261ecSmrg{
46935c4bbdfSmrg    ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
4706747b715Smrg    Bool ret;
47135c4bbdfSmrg    CMapScreenPtr pScreenPriv =
47235c4bbdfSmrg        (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, CMapScreenKey);
47305b261ecSmrg
4746747b715Smrg    pScrn->EnterVT = pScreenPriv->EnterVT;
47535c4bbdfSmrg    ret = (*pScreenPriv->EnterVT) (pScrn);
4766747b715Smrg    pScreenPriv->EnterVT = pScrn->EnterVT;
4776747b715Smrg    pScrn->EnterVT = CMapEnterVT;
47835c4bbdfSmrg    if (ret) {
47935c4bbdfSmrg        if (GetInstalledmiColormap(pScreen))
48035c4bbdfSmrg            CMapReinstallMap(GetInstalledmiColormap(pScreen));
48135c4bbdfSmrg        return TRUE;
48205b261ecSmrg    }
48305b261ecSmrg    return FALSE;
48405b261ecSmrg}
48505b261ecSmrg
48635c4bbdfSmrgstatic Bool
48735c4bbdfSmrgCMapSwitchMode(ScrnInfoPtr pScrn, DisplayModePtr mode)
48805b261ecSmrg{
48935c4bbdfSmrg    ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
49035c4bbdfSmrg    CMapScreenPtr pScreenPriv =
49135c4bbdfSmrg        (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, CMapScreenKey);
49235c4bbdfSmrg
49335c4bbdfSmrg    if ((*pScreenPriv->SwitchMode) (pScrn, mode)) {
49435c4bbdfSmrg        if (GetInstalledmiColormap(pScreen))
49535c4bbdfSmrg            CMapReinstallMap(GetInstalledmiColormap(pScreen));
49635c4bbdfSmrg        return TRUE;
49705b261ecSmrg    }
49805b261ecSmrg    return FALSE;
49905b261ecSmrg}
50005b261ecSmrg
50105b261ecSmrg#ifdef XFreeXDGA
50235c4bbdfSmrgstatic int
50335c4bbdfSmrgCMapSetDGAMode(ScrnInfoPtr pScrn, int num, DGADevicePtr dev)
50405b261ecSmrg{
50535c4bbdfSmrg    ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
50635c4bbdfSmrg    CMapScreenPtr pScreenPriv =
50735c4bbdfSmrg        (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, CMapScreenKey);
50805b261ecSmrg    int ret;
50905b261ecSmrg
51035c4bbdfSmrg    ret = (*pScreenPriv->SetDGAMode) (pScrn, num, dev);
51105b261ecSmrg
51235c4bbdfSmrg    pScreenPriv->isDGAmode = DGAActive(pScrn->scrnIndex);
51305b261ecSmrg
51435c4bbdfSmrg    if (!pScreenPriv->isDGAmode && GetInstalledmiColormap(pScreen)
51535c4bbdfSmrg        && xf86ScreenToScrn(pScreen)->vtSema)
51635c4bbdfSmrg        CMapReinstallMap(GetInstalledmiColormap(pScreen));
51705b261ecSmrg
51805b261ecSmrg    return ret;
51905b261ecSmrg}
52005b261ecSmrg#endif
52105b261ecSmrg
52205b261ecSmrg/**** Utilities ****/
52305b261ecSmrg
52405b261ecSmrgstatic void
52505b261ecSmrgCMapReinstallMap(ColormapPtr pmap)
52605b261ecSmrg{
52735c4bbdfSmrg    CMapScreenPtr pScreenPriv =
52835c4bbdfSmrg        (CMapScreenPtr) dixLookupPrivate(&pmap->pScreen->devPrivates,
52935c4bbdfSmrg                                         CMapScreenKey);
53035c4bbdfSmrg    CMapColormapPtr cmapPriv =
53135c4bbdfSmrg        (CMapColormapPtr) dixLookupPrivate(&pmap->devPrivates, CMapColormapKey);
53235c4bbdfSmrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pmap->pScreen);
53305b261ecSmrg    int i = cmapPriv->numColors;
53405b261ecSmrg    int *indices = pScreenPriv->PreAllocIndices;
53505b261ecSmrg
53635c4bbdfSmrg    while (i--)
53735c4bbdfSmrg        indices[i] = i;
53835c4bbdfSmrg
53935c4bbdfSmrg    if (cmapPriv->recalculate)
54035c4bbdfSmrg        CMapRefreshColors(pmap, cmapPriv->numColors, indices);
54105b261ecSmrg    else {
54235c4bbdfSmrg        (*pScrn->LoadPalette) (pScrn, cmapPriv->numColors,
54335c4bbdfSmrg                               indices, cmapPriv->colors, pmap->pVisual);
54435c4bbdfSmrg        if (pScrn->SetOverscan) {
54505b261ecSmrg#ifdef DEBUGOVERSCAN
54635c4bbdfSmrg            ErrorF("SetOverscan() called from CMapReinstallMap\n");
54705b261ecSmrg#endif
54835c4bbdfSmrg            pScrn->SetOverscan(pScrn, cmapPriv->overscan);
54935c4bbdfSmrg        }
55005b261ecSmrg    }
55105b261ecSmrg
55205b261ecSmrg    cmapPriv->recalculate = FALSE;
55305b261ecSmrg}
55405b261ecSmrg
55535c4bbdfSmrgstatic void
55635c4bbdfSmrgCMapRefreshColors(ColormapPtr pmap, int defs, int *indices)
55705b261ecSmrg{
55835c4bbdfSmrg    CMapScreenPtr pScreenPriv =
55935c4bbdfSmrg        (CMapScreenPtr) dixLookupPrivate(&pmap->pScreen->devPrivates,
56035c4bbdfSmrg                                         CMapScreenKey);
56135c4bbdfSmrg    CMapColormapPtr pColPriv =
56235c4bbdfSmrg        (CMapColormapPtr) dixLookupPrivate(&pmap->devPrivates, CMapColormapKey);
56305b261ecSmrg    VisualPtr pVisual = pmap->pVisual;
56435c4bbdfSmrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pmap->pScreen);
56505b261ecSmrg    int numColors, i;
56605b261ecSmrg    LOCO *gamma, *colors;
56705b261ecSmrg    EntryPtr entry;
56805b261ecSmrg    int reds, greens, blues, maxValue, index, shift;
56905b261ecSmrg
57005b261ecSmrg    numColors = pColPriv->numColors;
57105b261ecSmrg    shift = 16 - pScreenPriv->sigRGBbits;
57205b261ecSmrg    maxValue = (1 << pScreenPriv->sigRGBbits) - 1;
57305b261ecSmrg    gamma = pScreenPriv->gamma;
57405b261ecSmrg    colors = pColPriv->colors;
57505b261ecSmrg
57605b261ecSmrg    reds = pVisual->redMask >> pVisual->offsetRed;
57705b261ecSmrg    greens = pVisual->greenMask >> pVisual->offsetGreen;
57805b261ecSmrg    blues = pVisual->blueMask >> pVisual->offsetBlue;
57905b261ecSmrg
58035c4bbdfSmrg    switch (pVisual->class) {
58105b261ecSmrg    case StaticGray:
58235c4bbdfSmrg        for (i = 0; i < numColors; i++) {
58335c4bbdfSmrg            index = (i + 1) * maxValue / numColors;
58435c4bbdfSmrg            colors[i].red = gamma[index].red;
58535c4bbdfSmrg            colors[i].green = gamma[index].green;
58635c4bbdfSmrg            colors[i].blue = gamma[index].blue;
58735c4bbdfSmrg        }
58835c4bbdfSmrg        break;
58905b261ecSmrg    case TrueColor:
59005b261ecSmrg        if (CMapColormapUseMax(pVisual, pScreenPriv)) {
59135c4bbdfSmrg            for (i = 0; i <= reds; i++)
59235c4bbdfSmrg                colors[i].red = gamma[i * maxValue / reds].red;
59335c4bbdfSmrg            for (i = 0; i <= greens; i++)
59435c4bbdfSmrg                colors[i].green = gamma[i * maxValue / greens].green;
59535c4bbdfSmrg            for (i = 0; i <= blues; i++)
59635c4bbdfSmrg                colors[i].blue = gamma[i * maxValue / blues].blue;
59735c4bbdfSmrg            break;
59835c4bbdfSmrg        }
59935c4bbdfSmrg        for (i = 0; i < numColors; i++) {
60035c4bbdfSmrg            colors[i].red = gamma[((i >> pVisual->offsetRed) & reds) *
60135c4bbdfSmrg                                  maxValue / reds].red;
60235c4bbdfSmrg            colors[i].green = gamma[((i >> pVisual->offsetGreen) & greens) *
60335c4bbdfSmrg                                    maxValue / greens].green;
60435c4bbdfSmrg            colors[i].blue = gamma[((i >> pVisual->offsetBlue) & blues) *
60535c4bbdfSmrg                                   maxValue / blues].blue;
60635c4bbdfSmrg        }
60735c4bbdfSmrg        break;
60805b261ecSmrg    case StaticColor:
60905b261ecSmrg    case PseudoColor:
61005b261ecSmrg    case GrayScale:
61135c4bbdfSmrg        for (i = 0; i < defs; i++) {
61235c4bbdfSmrg            index = indices[i];
61335c4bbdfSmrg            entry = (EntryPtr) &pmap->red[index];
61435c4bbdfSmrg
61535c4bbdfSmrg            if (entry->fShared) {
61635c4bbdfSmrg                colors[index].red =
61735c4bbdfSmrg                    gamma[entry->co.shco.red->color >> shift].red;
61835c4bbdfSmrg                colors[index].green =
61935c4bbdfSmrg                    gamma[entry->co.shco.green->color >> shift].green;
62035c4bbdfSmrg                colors[index].blue =
62135c4bbdfSmrg                    gamma[entry->co.shco.blue->color >> shift].blue;
62235c4bbdfSmrg            }
62335c4bbdfSmrg            else {
62435c4bbdfSmrg                colors[index].red = gamma[entry->co.local.red >> shift].red;
62535c4bbdfSmrg                colors[index].green =
62635c4bbdfSmrg                    gamma[entry->co.local.green >> shift].green;
62735c4bbdfSmrg                colors[index].blue = gamma[entry->co.local.blue >> shift].blue;
62835c4bbdfSmrg            }
62935c4bbdfSmrg        }
63035c4bbdfSmrg        break;
63105b261ecSmrg    case DirectColor:
63205b261ecSmrg        if (CMapColormapUseMax(pVisual, pScreenPriv)) {
63335c4bbdfSmrg            for (i = 0; i < defs; i++) {
63435c4bbdfSmrg                index = indices[i];
63535c4bbdfSmrg                if (index <= reds)
63635c4bbdfSmrg                    colors[index].red =
63735c4bbdfSmrg                        gamma[pmap->red[index].co.local.red >> shift].red;
63835c4bbdfSmrg                if (index <= greens)
63935c4bbdfSmrg                    colors[index].green =
64035c4bbdfSmrg                        gamma[pmap->green[index].co.local.green >> shift].green;
64135c4bbdfSmrg                if (index <= blues)
64235c4bbdfSmrg                    colors[index].blue =
64335c4bbdfSmrg                        gamma[pmap->blue[index].co.local.blue >> shift].blue;
64405b261ecSmrg
64535c4bbdfSmrg            }
64635c4bbdfSmrg            break;
64735c4bbdfSmrg        }
64835c4bbdfSmrg        for (i = 0; i < defs; i++) {
64935c4bbdfSmrg            index = indices[i];
65035c4bbdfSmrg
65135c4bbdfSmrg            colors[index].red = gamma[pmap->red[(index >> pVisual->
65235c4bbdfSmrg                                                 offsetRed) & reds].co.local.
65335c4bbdfSmrg                                      red >> shift].red;
65435c4bbdfSmrg            colors[index].green =
65535c4bbdfSmrg                gamma[pmap->green[(index >> pVisual->offsetGreen) & greens].co.
65635c4bbdfSmrg                      local.green >> shift].green;
65735c4bbdfSmrg            colors[index].blue =
65835c4bbdfSmrg                gamma[pmap->blue[(index >> pVisual->offsetBlue) & blues].co.
65935c4bbdfSmrg                      local.blue >> shift].blue;
66035c4bbdfSmrg        }
66135c4bbdfSmrg        break;
66235c4bbdfSmrg    }
66305b261ecSmrg
66435c4bbdfSmrg    if (LOAD_PALETTE(pmap))
66535c4bbdfSmrg        (*pScrn->LoadPalette) (pScrn, defs, indices, colors, pmap->pVisual);
66605b261ecSmrg
66705b261ecSmrg    if (pScrn->SetOverscan)
66835c4bbdfSmrg        CMapSetOverscan(pmap, defs, indices);
66905b261ecSmrg
67005b261ecSmrg}
67105b261ecSmrg
67205b261ecSmrgstatic Bool
67335c4bbdfSmrgCMapCompareColors(LOCO * color1, LOCO * color2)
67405b261ecSmrg{
67505b261ecSmrg    /* return TRUE if the color1 is "closer" to black than color2 */
67605b261ecSmrg#ifdef DEBUGOVERSCAN
67705b261ecSmrg    ErrorF("#%02x%02x%02x vs #%02x%02x%02x (%d vs %d)\n",
67835c4bbdfSmrg           color1->red, color1->green, color1->blue,
67935c4bbdfSmrg           color2->red, color2->green, color2->blue,
68035c4bbdfSmrg           color1->red + color1->green + color1->blue,
68135c4bbdfSmrg           color2->red + color2->green + color2->blue);
68205b261ecSmrg#endif
68305b261ecSmrg    return (color1->red + color1->green + color1->blue <
68435c4bbdfSmrg            color2->red + color2->green + color2->blue);
68505b261ecSmrg}
68605b261ecSmrg
68705b261ecSmrgstatic void
68805b261ecSmrgCMapSetOverscan(ColormapPtr pmap, int defs, int *indices)
68905b261ecSmrg{
69035c4bbdfSmrg    CMapScreenPtr pScreenPriv =
69135c4bbdfSmrg        (CMapScreenPtr) dixLookupPrivate(&pmap->pScreen->devPrivates,
69235c4bbdfSmrg                                         CMapScreenKey);
69335c4bbdfSmrg    CMapColormapPtr pColPriv =
69435c4bbdfSmrg        (CMapColormapPtr) dixLookupPrivate(&pmap->devPrivates, CMapColormapKey);
69535c4bbdfSmrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pmap->pScreen);
69605b261ecSmrg    VisualPtr pVisual = pmap->pVisual;
69705b261ecSmrg    int i;
69805b261ecSmrg    LOCO *colors;
69905b261ecSmrg    int index;
70005b261ecSmrg    Bool newOverscan = FALSE;
70105b261ecSmrg    int overscan, tmpOverscan;
70205b261ecSmrg
70305b261ecSmrg    colors = pColPriv->colors;
70405b261ecSmrg    overscan = pColPriv->overscan;
70505b261ecSmrg
70605b261ecSmrg    /*
70705b261ecSmrg     * Search for a new overscan index in the following cases:
70805b261ecSmrg     *
70905b261ecSmrg     *   - The index hasn't yet been initialised.  In this case search
71005b261ecSmrg     *     for an index that is black or a close match to black.
71105b261ecSmrg     *
71205b261ecSmrg     *   - The colour of the old index is changed.  In this case search
71305b261ecSmrg     *     all indices for a black or close match to black.
71405b261ecSmrg     *
71505b261ecSmrg     *   - The colour of the old index wasn't black.  In this case only
71605b261ecSmrg     *     search the indices that were changed for a better match to black.
71705b261ecSmrg     */
71805b261ecSmrg
71905b261ecSmrg    switch (pVisual->class) {
72005b261ecSmrg    case StaticGray:
72105b261ecSmrg    case TrueColor:
72235c4bbdfSmrg        /* Should only come here once.  Initialise the overscan index to 0 */
72335c4bbdfSmrg        overscan = 0;
72435c4bbdfSmrg        newOverscan = TRUE;
72535c4bbdfSmrg        break;
72605b261ecSmrg    case StaticColor:
72735c4bbdfSmrg        /*
72805b261ecSmrg         * Only come here once, but search for the overscan in the same way
72905b261ecSmrg         * as for the other cases.
73035c4bbdfSmrg         */
73105b261ecSmrg    case DirectColor:
73205b261ecSmrg    case PseudoColor:
73305b261ecSmrg    case GrayScale:
73435c4bbdfSmrg        if (overscan < 0 || overscan > pScreenPriv->maxColors - 1) {
73535c4bbdfSmrg            /* Uninitialised */
73635c4bbdfSmrg            newOverscan = TRUE;
73735c4bbdfSmrg        }
73835c4bbdfSmrg        else {
73935c4bbdfSmrg            /* Check if the overscan was changed */
74035c4bbdfSmrg            for (i = 0; i < defs; i++) {
74135c4bbdfSmrg                index = indices[i];
74235c4bbdfSmrg                if (index == overscan) {
74335c4bbdfSmrg                    newOverscan = TRUE;
74435c4bbdfSmrg                    break;
74535c4bbdfSmrg                }
74635c4bbdfSmrg            }
74735c4bbdfSmrg        }
74835c4bbdfSmrg        if (newOverscan) {
74935c4bbdfSmrg            /* The overscan is either uninitialised or it has been changed */
75035c4bbdfSmrg
75135c4bbdfSmrg            if (overscan < 0 || overscan > pScreenPriv->maxColors - 1)
75235c4bbdfSmrg                tmpOverscan = pScreenPriv->maxColors - 1;
75335c4bbdfSmrg            else
75435c4bbdfSmrg                tmpOverscan = overscan;
75535c4bbdfSmrg
75635c4bbdfSmrg            /* search all entries for a close match to black */
75735c4bbdfSmrg            for (i = pScreenPriv->maxColors - 1; i >= 0; i--) {
75835c4bbdfSmrg                if (colors[i].red == 0 && colors[i].green == 0 &&
75935c4bbdfSmrg                    colors[i].blue == 0) {
76035c4bbdfSmrg                    overscan = i;
76105b261ecSmrg#ifdef DEBUGOVERSCAN
76235c4bbdfSmrg                    ErrorF("Black found at index 0x%02x\n", i);
76305b261ecSmrg#endif
76435c4bbdfSmrg                    break;
76535c4bbdfSmrg                }
76635c4bbdfSmrg                else {
76705b261ecSmrg#ifdef DEBUGOVERSCAN
76835c4bbdfSmrg                    ErrorF("0x%02x: ", i);
76905b261ecSmrg#endif
77035c4bbdfSmrg                    if (CMapCompareColors(&colors[i], &colors[tmpOverscan])) {
77135c4bbdfSmrg                        tmpOverscan = i;
77205b261ecSmrg#ifdef DEBUGOVERSCAN
77335c4bbdfSmrg                        ErrorF("possible \"Black\" at index 0x%02x\n", i);
77405b261ecSmrg#endif
77535c4bbdfSmrg                    }
77635c4bbdfSmrg                }
77735c4bbdfSmrg            }
77835c4bbdfSmrg            if (i < 0)
77935c4bbdfSmrg                overscan = tmpOverscan;
78035c4bbdfSmrg        }
78135c4bbdfSmrg        else {
78235c4bbdfSmrg            /* Check of the old overscan wasn't black */
78335c4bbdfSmrg            if (colors[overscan].red != 0 || colors[overscan].green != 0 ||
78435c4bbdfSmrg                colors[overscan].blue != 0) {
78535c4bbdfSmrg                int oldOverscan = tmpOverscan = overscan;
78635c4bbdfSmrg
78735c4bbdfSmrg                /* See of there is now a better match */
78835c4bbdfSmrg                for (i = 0; i < defs; i++) {
78935c4bbdfSmrg                    index = indices[i];
79035c4bbdfSmrg                    if (colors[index].red == 0 && colors[index].green == 0 &&
79135c4bbdfSmrg                        colors[index].blue == 0) {
79235c4bbdfSmrg                        overscan = index;
79305b261ecSmrg#ifdef DEBUGOVERSCAN
79435c4bbdfSmrg                        ErrorF("Black found at index 0x%02x\n", index);
79505b261ecSmrg#endif
79635c4bbdfSmrg                        break;
79735c4bbdfSmrg                    }
79835c4bbdfSmrg                    else {
79905b261ecSmrg#ifdef DEBUGOVERSCAN
80035c4bbdfSmrg                        ErrorF("0x%02x: ", index);
80105b261ecSmrg#endif
80235c4bbdfSmrg                        if (CMapCompareColors(&colors[index],
80335c4bbdfSmrg                                              &colors[tmpOverscan])) {
80435c4bbdfSmrg                            tmpOverscan = index;
80505b261ecSmrg#ifdef DEBUGOVERSCAN
80635c4bbdfSmrg                            ErrorF("possible \"Black\" at index 0x%02x\n",
80735c4bbdfSmrg                                   index);
80805b261ecSmrg#endif
80935c4bbdfSmrg                        }
81035c4bbdfSmrg                    }
81135c4bbdfSmrg                }
81235c4bbdfSmrg                if (i == defs)
81335c4bbdfSmrg                    overscan = tmpOverscan;
81435c4bbdfSmrg                if (overscan != oldOverscan)
81535c4bbdfSmrg                    newOverscan = TRUE;
81635c4bbdfSmrg            }
81735c4bbdfSmrg        }
81835c4bbdfSmrg        break;
81905b261ecSmrg    }
82005b261ecSmrg    if (newOverscan) {
82135c4bbdfSmrg        pColPriv->overscan = overscan;
82235c4bbdfSmrg        if (LOAD_PALETTE(pmap)) {
82305b261ecSmrg#ifdef DEBUGOVERSCAN
82435c4bbdfSmrg            ErrorF("SetOverscan() called from CmapSetOverscan\n");
82505b261ecSmrg#endif
82635c4bbdfSmrg            pScrn->SetOverscan(pScrn, overscan);
82735c4bbdfSmrg        }
82805b261ecSmrg    }
82905b261ecSmrg}
83005b261ecSmrg
83105b261ecSmrgstatic void
83205b261ecSmrgCMapUnwrapScreen(ScreenPtr pScreen)
83305b261ecSmrg{
83435c4bbdfSmrg    CMapScreenPtr pScreenPriv =
83535c4bbdfSmrg        (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates, CMapScreenKey);
83635c4bbdfSmrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
83705b261ecSmrg
83805b261ecSmrg    pScreen->CloseScreen = pScreenPriv->CloseScreen;
83905b261ecSmrg    pScreen->CreateColormap = pScreenPriv->CreateColormap;
84005b261ecSmrg    pScreen->DestroyColormap = pScreenPriv->DestroyColormap;
84105b261ecSmrg    pScreen->InstallColormap = pScreenPriv->InstallColormap;
84205b261ecSmrg    pScreen->StoreColors = pScreenPriv->StoreColors;
84305b261ecSmrg
84435c4bbdfSmrg    pScrn->EnterVT = pScreenPriv->EnterVT;
84535c4bbdfSmrg    pScrn->SwitchMode = pScreenPriv->SwitchMode;
84635c4bbdfSmrg    pScrn->SetDGAMode = pScreenPriv->SetDGAMode;
8476747b715Smrg    pScrn->ChangeGamma = pScreenPriv->ChangeGamma;
84805b261ecSmrg
8496747b715Smrg    free(pScreenPriv->gamma);
8506747b715Smrg    free(pScreenPriv->PreAllocIndices);
8516747b715Smrg    free(pScreenPriv);
85205b261ecSmrg}
85305b261ecSmrg
85435c4bbdfSmrgstatic void
85535c4bbdfSmrgComputeGamma(ScrnInfoPtr pScrn, CMapScreenPtr priv)
85605b261ecSmrg{
85705b261ecSmrg    int elements = priv->gammaElements - 1;
85805b261ecSmrg    double RedGamma, GreenGamma, BlueGamma;
85905b261ecSmrg    int i;
86005b261ecSmrg
86105b261ecSmrg#ifndef DONT_CHECK_GAMMA
86205b261ecSmrg    /* This check is to catch drivers that are not initialising pScrn->gamma */
86335c4bbdfSmrg    if (pScrn->gamma.red < GAMMA_MIN || pScrn->gamma.red > GAMMA_MAX ||
86435c4bbdfSmrg        pScrn->gamma.green < GAMMA_MIN || pScrn->gamma.green > GAMMA_MAX ||
86535c4bbdfSmrg        pScrn->gamma.blue < GAMMA_MIN || pScrn->gamma.blue > GAMMA_MAX) {
86635c4bbdfSmrg
86735c4bbdfSmrg        xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, 0,
86835c4bbdfSmrg                       "The %s driver didn't call xf86SetGamma() to initialise\n"
86935c4bbdfSmrg                       "\tthe gamma values.\n", pScrn->driverName);
87035c4bbdfSmrg        xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, 0,
87135c4bbdfSmrg                       "PLEASE FIX THE `%s' DRIVER!\n",
87235c4bbdfSmrg                       pScrn->driverName);
87335c4bbdfSmrg        pScrn->gamma.red = 1.0;
87435c4bbdfSmrg        pScrn->gamma.green = 1.0;
87535c4bbdfSmrg        pScrn->gamma.blue = 1.0;
87605b261ecSmrg    }
87705b261ecSmrg#endif
87805b261ecSmrg
87935c4bbdfSmrg    RedGamma = 1.0 / (double) pScrn->gamma.red;
88035c4bbdfSmrg    GreenGamma = 1.0 / (double) pScrn->gamma.green;
88135c4bbdfSmrg    BlueGamma = 1.0 / (double) pScrn->gamma.blue;
88235c4bbdfSmrg
88335c4bbdfSmrg    for (i = 0; i <= elements; i++) {
88435c4bbdfSmrg        if (RedGamma == 1.0)
88535c4bbdfSmrg            priv->gamma[i].red = i;
88635c4bbdfSmrg        else
88735c4bbdfSmrg            priv->gamma[i].red = (CARD16) (pow((double) i / (double) elements,
88835c4bbdfSmrg                                               RedGamma) * (double) elements +
88935c4bbdfSmrg                                           0.5);
89035c4bbdfSmrg
89135c4bbdfSmrg        if (GreenGamma == 1.0)
89235c4bbdfSmrg            priv->gamma[i].green = i;
89335c4bbdfSmrg        else
89435c4bbdfSmrg            priv->gamma[i].green = (CARD16) (pow((double) i / (double) elements,
89535c4bbdfSmrg                                                 GreenGamma) *
89635c4bbdfSmrg                                             (double) elements + 0.5);
89735c4bbdfSmrg
89835c4bbdfSmrg        if (BlueGamma == 1.0)
89935c4bbdfSmrg            priv->gamma[i].blue = i;
90035c4bbdfSmrg        else
90135c4bbdfSmrg            priv->gamma[i].blue = (CARD16) (pow((double) i / (double) elements,
90235c4bbdfSmrg                                                BlueGamma) * (double) elements +
90335c4bbdfSmrg                                            0.5);
90405b261ecSmrg    }
90505b261ecSmrg}
90605b261ecSmrg
90705b261ecSmrgint
90835c4bbdfSmrgCMapChangeGamma(ScrnInfoPtr pScrn, Gamma gamma)
90935c4bbdfSmrg{
9106747b715Smrg    int ret = Success;
91135c4bbdfSmrg    ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
91205b261ecSmrg    CMapColormapPtr pColPriv;
91305b261ecSmrg    CMapScreenPtr pScreenPriv;
91405b261ecSmrg    CMapLinkPtr pLink;
91535c4bbdfSmrg
91605b261ecSmrg    /* Is this sufficient checking ? */
91735c4bbdfSmrg    if (!CMapScreenKeyRegistered)
91835c4bbdfSmrg        return BadImplementation;
91935c4bbdfSmrg
92035c4bbdfSmrg    pScreenPriv = (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates,
92135c4bbdfSmrg                                                   CMapScreenKey);
92235c4bbdfSmrg    if (!pScreenPriv)
92335c4bbdfSmrg        return BadImplementation;
92435c4bbdfSmrg
92505b261ecSmrg    if (gamma.red < GAMMA_MIN || gamma.red > GAMMA_MAX ||
92635c4bbdfSmrg        gamma.green < GAMMA_MIN || gamma.green > GAMMA_MAX ||
92735c4bbdfSmrg        gamma.blue < GAMMA_MIN || gamma.blue > GAMMA_MAX)
92835c4bbdfSmrg        return BadValue;
92905b261ecSmrg
93005b261ecSmrg    pScrn->gamma.red = gamma.red;
93105b261ecSmrg    pScrn->gamma.green = gamma.green;
93205b261ecSmrg    pScrn->gamma.blue = gamma.blue;
93305b261ecSmrg
93435c4bbdfSmrg    ComputeGamma(pScrn, pScreenPriv);
93505b261ecSmrg
93605b261ecSmrg    /* mark all colormaps on this screen */
93705b261ecSmrg    pLink = pScreenPriv->maps;
93835c4bbdfSmrg    while (pLink) {
93935c4bbdfSmrg        pColPriv = (CMapColormapPtr) dixLookupPrivate(&pLink->cmap->devPrivates,
94035c4bbdfSmrg                                                      CMapColormapKey);
94135c4bbdfSmrg        pColPriv->recalculate = TRUE;
94235c4bbdfSmrg        pLink = pLink->next;
94305b261ecSmrg    }
94405b261ecSmrg
94535c4bbdfSmrg    if (GetInstalledmiColormap(pScreen) &&
94635c4bbdfSmrg        ((pScreenPriv->flags & CMAP_LOAD_EVEN_IF_OFFSCREEN) ||
94735c4bbdfSmrg         pScrn->vtSema || pScreenPriv->isDGAmode)) {
94835c4bbdfSmrg        ColormapPtr pMap = GetInstalledmiColormap(pScreen);
94935c4bbdfSmrg
95035c4bbdfSmrg        if (!(pScreenPriv->flags & CMAP_PALETTED_TRUECOLOR) &&
95135c4bbdfSmrg            (pMap->pVisual->class == TrueColor) &&
95235c4bbdfSmrg            CMapColormapUseMax(pMap->pVisual, pScreenPriv)) {
95335c4bbdfSmrg
95435c4bbdfSmrg            /* if the current map doesn't have a palette look
95535c4bbdfSmrg               for another map to change the gamma on. */
95635c4bbdfSmrg
95735c4bbdfSmrg            pLink = pScreenPriv->maps;
95835c4bbdfSmrg            while (pLink) {
95935c4bbdfSmrg                if (pLink->cmap->pVisual->class == PseudoColor)
96035c4bbdfSmrg                    break;
96135c4bbdfSmrg                pLink = pLink->next;
96235c4bbdfSmrg            }
96335c4bbdfSmrg
96435c4bbdfSmrg            if (pLink) {
96535c4bbdfSmrg                /* need to trick CMapRefreshColors() into thinking
96635c4bbdfSmrg                   this is the currently installed map */
96735c4bbdfSmrg                SetInstalledmiColormap(pScreen, pLink->cmap);
96835c4bbdfSmrg                CMapReinstallMap(pLink->cmap);
96935c4bbdfSmrg                SetInstalledmiColormap(pScreen, pMap);
97035c4bbdfSmrg            }
97135c4bbdfSmrg        }
97235c4bbdfSmrg        else
97335c4bbdfSmrg            CMapReinstallMap(pMap);
97405b261ecSmrg    }
97505b261ecSmrg
9766747b715Smrg    pScrn->ChangeGamma = pScreenPriv->ChangeGamma;
9776747b715Smrg    if (pScrn->ChangeGamma)
97835c4bbdfSmrg        ret = pScrn->ChangeGamma(pScrn, gamma);
9796747b715Smrg    pScrn->ChangeGamma = CMapChangeGamma;
9806747b715Smrg
9816747b715Smrg    return ret;
98205b261ecSmrg}
98305b261ecSmrg
98405b261ecSmrgstatic void
98535c4bbdfSmrgComputeGammaRamp(CMapScreenPtr priv,
98635c4bbdfSmrg                 unsigned short *red,
98735c4bbdfSmrg                 unsigned short *green, unsigned short *blue)
98835c4bbdfSmrg{
98905b261ecSmrg    int elements = priv->gammaElements;
99005b261ecSmrg    LOCO *entry = priv->gamma;
99105b261ecSmrg    int shift = 16 - priv->sigRGBbits;
99205b261ecSmrg
99335c4bbdfSmrg    while (elements--) {
99435c4bbdfSmrg        entry->red = *(red++) >> shift;
99535c4bbdfSmrg        entry->green = *(green++) >> shift;
99635c4bbdfSmrg        entry->blue = *(blue++) >> shift;
99735c4bbdfSmrg        entry++;
99805b261ecSmrg    }
99905b261ecSmrg}
100005b261ecSmrg
10016747b715Smrgint
100235c4bbdfSmrgxf86ChangeGammaRamp(ScreenPtr pScreen,
100335c4bbdfSmrg                    int size,
100435c4bbdfSmrg                    unsigned short *red,
100535c4bbdfSmrg                    unsigned short *green, unsigned short *blue)
100635c4bbdfSmrg{
100735c4bbdfSmrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
100805b261ecSmrg    CMapColormapPtr pColPriv;
100905b261ecSmrg    CMapScreenPtr pScreenPriv;
101005b261ecSmrg    CMapLinkPtr pLink;
101105b261ecSmrg
101235c4bbdfSmrg    if (!CMapScreenKeyRegistered)
101305b261ecSmrg        return BadImplementation;
101405b261ecSmrg
101535c4bbdfSmrg    pScreenPriv = (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates,
101635c4bbdfSmrg                                                   CMapScreenKey);
101735c4bbdfSmrg    if (!pScreenPriv)
101805b261ecSmrg        return BadImplementation;
101905b261ecSmrg
102035c4bbdfSmrg    if (pScreenPriv->gammaElements != size)
102135c4bbdfSmrg        return BadValue;
102205b261ecSmrg
102305b261ecSmrg    ComputeGammaRamp(pScreenPriv, red, green, blue);
102405b261ecSmrg
102505b261ecSmrg    /* mark all colormaps on this screen */
102605b261ecSmrg    pLink = pScreenPriv->maps;
102735c4bbdfSmrg    while (pLink) {
102835c4bbdfSmrg        pColPriv = (CMapColormapPtr) dixLookupPrivate(&pLink->cmap->devPrivates,
102935c4bbdfSmrg                                                      CMapColormapKey);
103005b261ecSmrg        pColPriv->recalculate = TRUE;
103105b261ecSmrg        pLink = pLink->next;
103205b261ecSmrg    }
103305b261ecSmrg
103435c4bbdfSmrg    if (GetInstalledmiColormap(pScreen) &&
103535c4bbdfSmrg        ((pScreenPriv->flags & CMAP_LOAD_EVEN_IF_OFFSCREEN) ||
103635c4bbdfSmrg         pScrn->vtSema || pScreenPriv->isDGAmode)) {
10376747b715Smrg        ColormapPtr pMap = GetInstalledmiColormap(pScreen);
103805b261ecSmrg
103905b261ecSmrg        if (!(pScreenPriv->flags & CMAP_PALETTED_TRUECOLOR) &&
104005b261ecSmrg            (pMap->pVisual->class == TrueColor) &&
104135c4bbdfSmrg            CMapColormapUseMax(pMap->pVisual, pScreenPriv)) {
104205b261ecSmrg
104305b261ecSmrg            /* if the current map doesn't have a palette look
104435c4bbdfSmrg               for another map to change the gamma on. */
104505b261ecSmrg
104605b261ecSmrg            pLink = pScreenPriv->maps;
104735c4bbdfSmrg            while (pLink) {
104835c4bbdfSmrg                if (pLink->cmap->pVisual->class == PseudoColor)
104905b261ecSmrg                    break;
105005b261ecSmrg                pLink = pLink->next;
105105b261ecSmrg            }
105205b261ecSmrg
105335c4bbdfSmrg            if (pLink) {
105405b261ecSmrg                /* need to trick CMapRefreshColors() into thinking
105505b261ecSmrg                   this is the currently installed map */
10566747b715Smrg                SetInstalledmiColormap(pScreen, pLink->cmap);
105705b261ecSmrg                CMapReinstallMap(pLink->cmap);
10586747b715Smrg                SetInstalledmiColormap(pScreen, pMap);
105905b261ecSmrg            }
106035c4bbdfSmrg        }
106135c4bbdfSmrg        else
106205b261ecSmrg            CMapReinstallMap(pMap);
106305b261ecSmrg    }
106405b261ecSmrg
106505b261ecSmrg    return Success;
106605b261ecSmrg}
106705b261ecSmrg
10686747b715Smrgint
106905b261ecSmrgxf86GetGammaRampSize(ScreenPtr pScreen)
107005b261ecSmrg{
107105b261ecSmrg    CMapScreenPtr pScreenPriv;
107205b261ecSmrg
107335c4bbdfSmrg    if (!CMapScreenKeyRegistered)
107435c4bbdfSmrg        return 0;
107505b261ecSmrg
107635c4bbdfSmrg    pScreenPriv = (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates,
107735c4bbdfSmrg                                                   CMapScreenKey);
107835c4bbdfSmrg    if (!pScreenPriv)
107935c4bbdfSmrg        return 0;
108005b261ecSmrg
108105b261ecSmrg    return pScreenPriv->gammaElements;
108205b261ecSmrg}
108305b261ecSmrg
10846747b715Smrgint
108535c4bbdfSmrgxf86GetGammaRamp(ScreenPtr pScreen,
108635c4bbdfSmrg                 int size,
108735c4bbdfSmrg                 unsigned short *red,
108835c4bbdfSmrg                 unsigned short *green, unsigned short *blue)
108935c4bbdfSmrg{
109005b261ecSmrg    CMapScreenPtr pScreenPriv;
109105b261ecSmrg    LOCO *entry;
109205b261ecSmrg    int shift, sigbits;
109305b261ecSmrg
109435c4bbdfSmrg    if (!CMapScreenKeyRegistered)
109535c4bbdfSmrg        return BadImplementation;
109605b261ecSmrg
109735c4bbdfSmrg    pScreenPriv = (CMapScreenPtr) dixLookupPrivate(&pScreen->devPrivates,
109835c4bbdfSmrg                                                   CMapScreenKey);
109935c4bbdfSmrg    if (!pScreenPriv)
110035c4bbdfSmrg        return BadImplementation;
110105b261ecSmrg
110235c4bbdfSmrg    if (size > pScreenPriv->gammaElements)
110335c4bbdfSmrg        return BadValue;
110405b261ecSmrg
110505b261ecSmrg    entry = pScreenPriv->gamma;
110605b261ecSmrg    sigbits = pScreenPriv->sigRGBbits;
110705b261ecSmrg
110835c4bbdfSmrg    while (size--) {
110935c4bbdfSmrg        *red = entry->red << (16 - sigbits);
111035c4bbdfSmrg        *green = entry->green << (16 - sigbits);
111135c4bbdfSmrg        *blue = entry->blue << (16 - sigbits);
111235c4bbdfSmrg        shift = sigbits;
111335c4bbdfSmrg        while (shift < 16) {
111435c4bbdfSmrg            *red |= *red >> shift;
111535c4bbdfSmrg            *green |= *green >> shift;
111635c4bbdfSmrg            *blue |= *blue >> shift;
111735c4bbdfSmrg            shift += sigbits;
111835c4bbdfSmrg        }
111935c4bbdfSmrg        red++;
112035c4bbdfSmrg        green++;
112135c4bbdfSmrg        blue++;
112205b261ecSmrg        entry++;
112305b261ecSmrg    }
112405b261ecSmrg
112505b261ecSmrg    return Success;
112605b261ecSmrg}
112705b261ecSmrg
112805b261ecSmrgint
112935c4bbdfSmrgxf86ChangeGamma(ScreenPtr pScreen, Gamma gamma)
113035c4bbdfSmrg{
113135c4bbdfSmrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
113235c4bbdfSmrg
113335c4bbdfSmrg    if (pScrn->ChangeGamma)
113435c4bbdfSmrg        return (*pScrn->ChangeGamma) (pScrn, gamma);
113505b261ecSmrg
11366747b715Smrg    return BadImplementation;
113705b261ecSmrg}
1138