1706f2543Smrg/*
2706f2543Smrg * Copyright (c) 1998-2001 by The XFree86 Project, Inc.
3706f2543Smrg *
4706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5706f2543Smrg * copy of this software and associated documentation files (the "Software"),
6706f2543Smrg * to deal in the Software without restriction, including without limitation
7706f2543Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the
9706f2543Smrg * Software is furnished to do so, subject to the following conditions:
10706f2543Smrg *
11706f2543Smrg * The above copyright notice and this permission notice shall be included in
12706f2543Smrg * all copies or substantial portions of the Software.
13706f2543Smrg *
14706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15706f2543Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16706f2543Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17706f2543Smrg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18706f2543Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19706f2543Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20706f2543Smrg * OTHER DEALINGS IN THE SOFTWARE.
21706f2543Smrg *
22706f2543Smrg * Except as contained in this notice, the name of the copyright holder(s)
23706f2543Smrg * and author(s) shall not be used in advertising or otherwise to promote
24706f2543Smrg * the sale, use or other dealings in this Software without prior written
25706f2543Smrg * authorization from the copyright holder(s) and author(s).
26706f2543Smrg */
27706f2543Smrg
28706f2543Smrg#ifdef HAVE_XORG_CONFIG_H
29706f2543Smrg#include <xorg-config.h>
30706f2543Smrg#endif
31706f2543Smrg
32706f2543Smrg#if defined(_XOPEN_SOURCE) || defined(sun) && defined(__SVR4)
33706f2543Smrg#include <math.h>
34706f2543Smrg#else
35706f2543Smrg#define _XOPEN_SOURCE   /* to get prototype for pow on some systems */
36706f2543Smrg#include <math.h>
37706f2543Smrg#undef _XOPEN_SOURCE
38706f2543Smrg#endif
39706f2543Smrg
40706f2543Smrg#include <X11/X.h>
41706f2543Smrg#include "misc.h"
42706f2543Smrg#include <X11/Xproto.h>
43706f2543Smrg#include "colormapst.h"
44706f2543Smrg#include "scrnintstr.h"
45706f2543Smrg
46706f2543Smrg#include "resource.h"
47706f2543Smrg
48706f2543Smrg#include "xf86.h"
49706f2543Smrg#include "xf86_OSproc.h"
50706f2543Smrg#include "xf86str.h"
51706f2543Smrg#include "micmap.h"
52706f2543Smrg#include "xf86Crtc.h"
53706f2543Smrg
54706f2543Smrg#ifdef XFreeXDGA
55706f2543Smrg#include <X11/extensions/xf86dgaproto.h>
56706f2543Smrg#include "dgaproc.h"
57706f2543Smrg#endif
58706f2543Smrg
59706f2543Smrg#include "xf86cmap.h"
60706f2543Smrg
61706f2543Smrg#define SCREEN_PROLOGUE(pScreen, field) ((pScreen)->field = \
62706f2543Smrg    ((CMapScreenPtr)dixLookupPrivate(&(pScreen)->devPrivates, CMapScreenKey))->field)
63706f2543Smrg#define SCREEN_EPILOGUE(pScreen, field, wrapper)\
64706f2543Smrg    ((pScreen)->field = wrapper)
65706f2543Smrg
66706f2543Smrg#define LOAD_PALETTE(pmap) \
67706f2543Smrg    ((pmap == GetInstalledmiColormap(pmap->pScreen)) && \
68706f2543Smrg     ((pScreenPriv->flags & CMAP_LOAD_EVEN_IF_OFFSCREEN) || \
69706f2543Smrg      xf86Screens[pmap->pScreen->myNum]->vtSema || pScreenPriv->isDGAmode))
70706f2543Smrg
71706f2543Smrg
72706f2543Smrgtypedef struct _CMapLink {
73706f2543Smrg  ColormapPtr		cmap;
74706f2543Smrg  struct _CMapLink	*next;
75706f2543Smrg} CMapLink, *CMapLinkPtr;
76706f2543Smrg
77706f2543Smrgtypedef struct {
78706f2543Smrg  ScrnInfoPtr			pScrn;
79706f2543Smrg  CloseScreenProcPtr		CloseScreen;
80706f2543Smrg  CreateColormapProcPtr 	CreateColormap;
81706f2543Smrg  DestroyColormapProcPtr	DestroyColormap;
82706f2543Smrg  InstallColormapProcPtr	InstallColormap;
83706f2543Smrg  StoreColorsProcPtr		StoreColors;
84706f2543Smrg  Bool				(*EnterVT)(int, int);
85706f2543Smrg  Bool				(*SwitchMode)(int, DisplayModePtr, int);
86706f2543Smrg  int				(*SetDGAMode)(int, int, DGADevicePtr);
87706f2543Smrg  xf86ChangeGammaProc		*ChangeGamma;
88706f2543Smrg  int				maxColors;
89706f2543Smrg  int				sigRGBbits;
90706f2543Smrg  int				gammaElements;
91706f2543Smrg  LOCO				*gamma;
92706f2543Smrg  int				*PreAllocIndices;
93706f2543Smrg  CMapLinkPtr			maps;
94706f2543Smrg  unsigned int			flags;
95706f2543Smrg  Bool				isDGAmode;
96706f2543Smrg} CMapScreenRec, *CMapScreenPtr;
97706f2543Smrg
98706f2543Smrgtypedef struct {
99706f2543Smrg  int		numColors;
100706f2543Smrg  LOCO		*colors;
101706f2543Smrg  Bool		recalculate;
102706f2543Smrg  int		overscan;
103706f2543Smrg} CMapColormapRec, *CMapColormapPtr;
104706f2543Smrg
105706f2543Smrgstatic DevPrivateKeyRec CMapScreenKeyRec;
106706f2543Smrg#define CMapScreenKeyRegistered dixPrivateKeyRegistered(&CMapScreenKeyRec)
107706f2543Smrg#define CMapScreenKey (&CMapScreenKeyRec)
108706f2543Smrgstatic DevPrivateKeyRec CMapColormapKeyRec;
109706f2543Smrg#define CMapColormapKey (&CMapColormapKeyRec)
110706f2543Smrg
111706f2543Smrgstatic void CMapInstallColormap(ColormapPtr);
112706f2543Smrgstatic void CMapStoreColors(ColormapPtr, int, xColorItem *);
113706f2543Smrgstatic Bool CMapCloseScreen (int, ScreenPtr);
114706f2543Smrgstatic Bool CMapCreateColormap (ColormapPtr);
115706f2543Smrgstatic void CMapDestroyColormap (ColormapPtr);
116706f2543Smrg
117706f2543Smrgstatic Bool CMapEnterVT(int, int);
118706f2543Smrgstatic Bool CMapSwitchMode(int, DisplayModePtr, int);
119706f2543Smrg#ifdef XFreeXDGA
120706f2543Smrgstatic int  CMapSetDGAMode(int, int, DGADevicePtr);
121706f2543Smrg#endif
122706f2543Smrgstatic int  CMapChangeGamma(int, Gamma);
123706f2543Smrg
124706f2543Smrgstatic void ComputeGamma(CMapScreenPtr);
125706f2543Smrgstatic Bool CMapAllocateColormapPrivate(ColormapPtr);
126706f2543Smrgstatic void CMapRefreshColors(ColormapPtr, int, int*);
127706f2543Smrgstatic void CMapSetOverscan(ColormapPtr, int, int *);
128706f2543Smrgstatic void CMapReinstallMap(ColormapPtr);
129706f2543Smrgstatic void CMapUnwrapScreen(ScreenPtr pScreen);
130706f2543Smrg
131706f2543Smrg
132706f2543SmrgBool xf86ColormapAllocatePrivates(ScrnInfoPtr pScrn)
133706f2543Smrg{
134706f2543Smrg    /* If we support a better colormap system, then pretend we succeeded. */
135706f2543Smrg    if (xf86_crtc_supports_gamma(pScrn))
136706f2543Smrg	return TRUE;
137706f2543Smrg    if (!dixRegisterPrivateKey(&CMapScreenKeyRec, PRIVATE_SCREEN, 0))
138706f2543Smrg	return FALSE;
139706f2543Smrg
140706f2543Smrg    if (!dixRegisterPrivateKey(&CMapColormapKeyRec, PRIVATE_COLORMAP, 0))
141706f2543Smrg	return FALSE;
142706f2543Smrg    return TRUE;
143706f2543Smrg}
144706f2543Smrg
145706f2543SmrgBool xf86HandleColormaps(
146706f2543Smrg    ScreenPtr pScreen,
147706f2543Smrg    int maxColors,
148706f2543Smrg    int sigRGBbits,
149706f2543Smrg    xf86LoadPaletteProc *loadPalette,
150706f2543Smrg    xf86SetOverscanProc *setOverscan,
151706f2543Smrg    unsigned int flags
152706f2543Smrg){
153706f2543Smrg    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
154706f2543Smrg    ColormapPtr pDefMap = NULL;
155706f2543Smrg    CMapScreenPtr pScreenPriv;
156706f2543Smrg    LOCO *gamma;
157706f2543Smrg    int *indices;
158706f2543Smrg    int elements;
159706f2543Smrg
160706f2543Smrg    /* If we support a better colormap system, then pretend we succeeded. */
161706f2543Smrg    if (xf86_crtc_supports_gamma(pScrn))
162706f2543Smrg	return TRUE;
163706f2543Smrg
164706f2543Smrg    if(!maxColors || !sigRGBbits || !loadPalette)
165706f2543Smrg	return FALSE;
166706f2543Smrg
167706f2543Smrg    elements = 1 << sigRGBbits;
168706f2543Smrg
169706f2543Smrg    if(!(gamma = malloc(elements * sizeof(LOCO))))
170706f2543Smrg    	return FALSE;
171706f2543Smrg
172706f2543Smrg    if(!(indices = malloc(maxColors * sizeof(int)))) {
173706f2543Smrg	free(gamma);
174706f2543Smrg	return FALSE;
175706f2543Smrg    }
176706f2543Smrg
177706f2543Smrg    if(!(pScreenPriv = malloc(sizeof(CMapScreenRec)))) {
178706f2543Smrg	free(gamma);
179706f2543Smrg	free(indices);
180706f2543Smrg	return FALSE;
181706f2543Smrg    }
182706f2543Smrg
183706f2543Smrg    dixSetPrivate(&pScreen->devPrivates, &CMapScreenKeyRec, pScreenPriv);
184706f2543Smrg
185706f2543Smrg    pScreenPriv->CloseScreen = pScreen->CloseScreen;
186706f2543Smrg    pScreenPriv->CreateColormap = pScreen->CreateColormap;
187706f2543Smrg    pScreenPriv->DestroyColormap = pScreen->DestroyColormap;
188706f2543Smrg    pScreenPriv->InstallColormap = pScreen->InstallColormap;
189706f2543Smrg    pScreenPriv->StoreColors = pScreen->StoreColors;
190706f2543Smrg    pScreen->CloseScreen = CMapCloseScreen;
191706f2543Smrg    pScreen->CreateColormap = CMapCreateColormap;
192706f2543Smrg    pScreen->DestroyColormap = CMapDestroyColormap;
193706f2543Smrg    pScreen->InstallColormap = CMapInstallColormap;
194706f2543Smrg    pScreen->StoreColors = CMapStoreColors;
195706f2543Smrg
196706f2543Smrg    pScreenPriv->pScrn = pScrn;
197706f2543Smrg    pScrn->LoadPalette = loadPalette;
198706f2543Smrg    pScrn->SetOverscan = setOverscan;
199706f2543Smrg    pScreenPriv->maxColors = maxColors;
200706f2543Smrg    pScreenPriv->sigRGBbits = sigRGBbits;
201706f2543Smrg    pScreenPriv->gammaElements = elements;
202706f2543Smrg    pScreenPriv->gamma = gamma;
203706f2543Smrg    pScreenPriv->PreAllocIndices = indices;
204706f2543Smrg    pScreenPriv->maps = NULL;
205706f2543Smrg    pScreenPriv->flags = flags;
206706f2543Smrg    pScreenPriv->isDGAmode = FALSE;
207706f2543Smrg
208706f2543Smrg    pScreenPriv->EnterVT = pScrn->EnterVT;
209706f2543Smrg    pScreenPriv->SwitchMode = pScrn->SwitchMode;
210706f2543Smrg    pScreenPriv->SetDGAMode = pScrn->SetDGAMode;
211706f2543Smrg    pScreenPriv->ChangeGamma = pScrn->ChangeGamma;
212706f2543Smrg
213706f2543Smrg    if (!(flags & CMAP_LOAD_EVEN_IF_OFFSCREEN)) {
214706f2543Smrg	pScrn->EnterVT = CMapEnterVT;
215706f2543Smrg	if ((flags & CMAP_RELOAD_ON_MODE_SWITCH) && pScrn->SwitchMode)
216706f2543Smrg	    pScrn->SwitchMode = CMapSwitchMode;
217706f2543Smrg    }
218706f2543Smrg#ifdef XFreeXDGA
219706f2543Smrg    pScrn->SetDGAMode = CMapSetDGAMode;
220706f2543Smrg#endif
221706f2543Smrg    pScrn->ChangeGamma = CMapChangeGamma;
222706f2543Smrg
223706f2543Smrg    ComputeGamma(pScreenPriv);
224706f2543Smrg
225706f2543Smrg    /* get the default map */
226706f2543Smrg    dixLookupResourceByType((pointer *)&pDefMap, pScreen->defColormap,
227706f2543Smrg			    RT_COLORMAP, serverClient, DixInstallAccess);
228706f2543Smrg
229706f2543Smrg    if(!CMapAllocateColormapPrivate(pDefMap)) {
230706f2543Smrg        CMapUnwrapScreen(pScreen);
231706f2543Smrg	return FALSE;
232706f2543Smrg    }
233706f2543Smrg
234706f2543Smrg    /* Force the initial map to be loaded */
235706f2543Smrg    SetInstalledmiColormap(pScreen, NULL);
236706f2543Smrg    CMapInstallColormap(pDefMap);
237706f2543Smrg    return TRUE;
238706f2543Smrg}
239706f2543Smrg
240706f2543Smrg
241706f2543Smrg/**** Screen functions ****/
242706f2543Smrg
243706f2543Smrg
244706f2543Smrgstatic Bool
245706f2543SmrgCMapCloseScreen (int i, ScreenPtr pScreen)
246706f2543Smrg{
247706f2543Smrg    CMapUnwrapScreen(pScreen);
248706f2543Smrg
249706f2543Smrg    return (*pScreen->CloseScreen) (i, pScreen);
250706f2543Smrg}
251706f2543Smrg
252706f2543Smrgstatic Bool
253706f2543SmrgCMapColormapUseMax(VisualPtr pVisual, CMapScreenPtr pScreenPriv)
254706f2543Smrg{
255706f2543Smrg    if (pVisual->nplanes > 16)
256706f2543Smrg        return TRUE;
257706f2543Smrg    return ((1 << pVisual->nplanes) > pScreenPriv->maxColors);
258706f2543Smrg}
259706f2543Smrg
260706f2543Smrgstatic Bool
261706f2543SmrgCMapAllocateColormapPrivate(ColormapPtr pmap)
262706f2543Smrg{
263706f2543Smrg    CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate(
264706f2543Smrg	&pmap->pScreen->devPrivates, CMapScreenKey);
265706f2543Smrg    CMapColormapPtr pColPriv;
266706f2543Smrg    CMapLinkPtr pLink;
267706f2543Smrg    int numColors;
268706f2543Smrg    LOCO *colors;
269706f2543Smrg
270706f2543Smrg    if (CMapColormapUseMax(pmap->pVisual, pScreenPriv))
271706f2543Smrg	numColors = pmap->pVisual->ColormapEntries;
272706f2543Smrg    else
273706f2543Smrg	numColors = 1 << pmap->pVisual->nplanes;
274706f2543Smrg
275706f2543Smrg    if(!(colors = malloc(numColors * sizeof(LOCO))))
276706f2543Smrg	return FALSE;
277706f2543Smrg
278706f2543Smrg    if(!(pColPriv = malloc(sizeof(CMapColormapRec)))) {
279706f2543Smrg	free(colors);
280706f2543Smrg	return FALSE;
281706f2543Smrg    }
282706f2543Smrg
283706f2543Smrg    dixSetPrivate(&pmap->devPrivates, CMapColormapKey, pColPriv);
284706f2543Smrg
285706f2543Smrg    pColPriv->numColors = numColors;
286706f2543Smrg    pColPriv->colors = colors;
287706f2543Smrg    pColPriv->recalculate = TRUE;
288706f2543Smrg    pColPriv->overscan = -1;
289706f2543Smrg
290706f2543Smrg    /* add map to list */
291706f2543Smrg    pLink = malloc(sizeof(CMapLink));
292706f2543Smrg    if(pLink) {
293706f2543Smrg	pLink->cmap = pmap;
294706f2543Smrg	pLink->next = pScreenPriv->maps;
295706f2543Smrg	pScreenPriv->maps = pLink;
296706f2543Smrg    }
297706f2543Smrg
298706f2543Smrg    return TRUE;
299706f2543Smrg}
300706f2543Smrg
301706f2543Smrgstatic Bool
302706f2543SmrgCMapCreateColormap (ColormapPtr pmap)
303706f2543Smrg{
304706f2543Smrg    ScreenPtr pScreen = pmap->pScreen;
305706f2543Smrg    CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate(
306706f2543Smrg	&pScreen->devPrivates, CMapScreenKey);
307706f2543Smrg    Bool ret = FALSE;
308706f2543Smrg
309706f2543Smrg    pScreen->CreateColormap = pScreenPriv->CreateColormap;
310706f2543Smrg    if((*pScreen->CreateColormap)(pmap)) {
311706f2543Smrg	if(CMapAllocateColormapPrivate(pmap))
312706f2543Smrg	   ret = TRUE;
313706f2543Smrg    }
314706f2543Smrg    pScreen->CreateColormap = CMapCreateColormap;
315706f2543Smrg
316706f2543Smrg    return ret;
317706f2543Smrg}
318706f2543Smrg
319706f2543Smrgstatic void
320706f2543SmrgCMapDestroyColormap (ColormapPtr cmap)
321706f2543Smrg{
322706f2543Smrg    ScreenPtr pScreen = cmap->pScreen;
323706f2543Smrg    CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate(
324706f2543Smrg	&pScreen->devPrivates, CMapScreenKey);
325706f2543Smrg    CMapColormapPtr pColPriv = (CMapColormapPtr)dixLookupPrivate(
326706f2543Smrg	&cmap->devPrivates, CMapColormapKey);
327706f2543Smrg    CMapLinkPtr prevLink = NULL, pLink = pScreenPriv->maps;
328706f2543Smrg
329706f2543Smrg    if(pColPriv) {
330706f2543Smrg	free(pColPriv->colors);
331706f2543Smrg	free(pColPriv);
332706f2543Smrg    }
333706f2543Smrg
334706f2543Smrg    /* remove map from list */
335706f2543Smrg    while(pLink) {
336706f2543Smrg	if(pLink->cmap == cmap) {
337706f2543Smrg	   if(prevLink)
338706f2543Smrg		prevLink->next = pLink->next;
339706f2543Smrg	   else
340706f2543Smrg		pScreenPriv->maps = pLink->next;
341706f2543Smrg	   free(pLink);
342706f2543Smrg	   break;
343706f2543Smrg	}
344706f2543Smrg	prevLink = pLink;
345706f2543Smrg	pLink = pLink->next;
346706f2543Smrg    }
347706f2543Smrg
348706f2543Smrg    if(pScreenPriv->DestroyColormap) {
349706f2543Smrg    	pScreen->DestroyColormap = pScreenPriv->DestroyColormap;
350706f2543Smrg	(*pScreen->DestroyColormap)(cmap);
351706f2543Smrg    	pScreen->DestroyColormap = CMapDestroyColormap;
352706f2543Smrg    }
353706f2543Smrg}
354706f2543Smrg
355706f2543Smrg
356706f2543Smrg
357706f2543Smrgstatic void
358706f2543SmrgCMapStoreColors(
359706f2543Smrg     ColormapPtr	pmap,
360706f2543Smrg     int		ndef,
361706f2543Smrg     xColorItem	        *pdefs
362706f2543Smrg){
363706f2543Smrg    ScreenPtr 	pScreen = pmap->pScreen;
364706f2543Smrg    VisualPtr	pVisual = pmap->pVisual;
365706f2543Smrg    CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate(
366706f2543Smrg	&pScreen->devPrivates, CMapScreenKey);
367706f2543Smrg    int 	*indices = pScreenPriv->PreAllocIndices;
368706f2543Smrg    int		num = ndef;
369706f2543Smrg
370706f2543Smrg    /* At the moment this isn't necessary since there's nobody below us */
371706f2543Smrg    pScreen->StoreColors = pScreenPriv->StoreColors;
372706f2543Smrg    (*pScreen->StoreColors)(pmap, ndef, pdefs);
373706f2543Smrg    pScreen->StoreColors = CMapStoreColors;
374706f2543Smrg
375706f2543Smrg    /* should never get here for these */
376706f2543Smrg    if(	(pVisual->class == TrueColor) ||
377706f2543Smrg	(pVisual->class == StaticColor) ||
378706f2543Smrg	(pVisual->class == StaticGray))
379706f2543Smrg	return;
380706f2543Smrg
381706f2543Smrg    if(pVisual->class == DirectColor) {
382706f2543Smrg	CMapColormapPtr pColPriv = (CMapColormapPtr)dixLookupPrivate(
383706f2543Smrg	    &pmap->devPrivates, CMapColormapKey);
384706f2543Smrg	int i;
385706f2543Smrg
386706f2543Smrg	if (CMapColormapUseMax(pVisual, pScreenPriv)) {
387706f2543Smrg	    int index;
388706f2543Smrg
389706f2543Smrg	    num = 0;
390706f2543Smrg	    while(ndef--) {
391706f2543Smrg		if(pdefs[ndef].flags & DoRed) {
392706f2543Smrg		    index = (pdefs[ndef].pixel & pVisual->redMask) >>
393706f2543Smrg					pVisual->offsetRed;
394706f2543Smrg		    i = num;
395706f2543Smrg		    while(i--)
396706f2543Smrg			if(indices[i] == index) break;
397706f2543Smrg		    if(i == -1)
398706f2543Smrg			indices[num++] = index;
399706f2543Smrg		}
400706f2543Smrg		if(pdefs[ndef].flags & DoGreen) {
401706f2543Smrg		    index = (pdefs[ndef].pixel & pVisual->greenMask) >>
402706f2543Smrg					pVisual->offsetGreen;
403706f2543Smrg		    i = num;
404706f2543Smrg		    while(i--)
405706f2543Smrg			if(indices[i] == index) break;
406706f2543Smrg		    if(i == -1)
407706f2543Smrg			indices[num++] = index;
408706f2543Smrg		}
409706f2543Smrg		if(pdefs[ndef].flags & DoBlue) {
410706f2543Smrg		    index = (pdefs[ndef].pixel & pVisual->blueMask) >>
411706f2543Smrg					pVisual->offsetBlue;
412706f2543Smrg		    i = num;
413706f2543Smrg		    while(i--)
414706f2543Smrg			if(indices[i] == index) break;
415706f2543Smrg		    if(i == -1)
416706f2543Smrg			indices[num++] = index;
417706f2543Smrg		}
418706f2543Smrg	    }
419706f2543Smrg
420706f2543Smrg	} else {
421706f2543Smrg	    /* not really as overkill as it seems */
422706f2543Smrg	    num = pColPriv->numColors;
423706f2543Smrg	    for(i = 0; i < pColPriv->numColors; i++)
424706f2543Smrg		indices[i] = i;
425706f2543Smrg	}
426706f2543Smrg    } else {
427706f2543Smrg	while(ndef--)
428706f2543Smrg	   indices[ndef] = pdefs[ndef].pixel;
429706f2543Smrg    }
430706f2543Smrg
431706f2543Smrg    CMapRefreshColors(pmap, num, indices);
432706f2543Smrg}
433706f2543Smrg
434706f2543Smrg
435706f2543Smrgstatic void
436706f2543SmrgCMapInstallColormap(ColormapPtr pmap)
437706f2543Smrg{
438706f2543Smrg    ScreenPtr 	  pScreen = pmap->pScreen;
439706f2543Smrg    CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate(
440706f2543Smrg	&pScreen->devPrivates, CMapScreenKey);
441706f2543Smrg
442706f2543Smrg    if (pmap == GetInstalledmiColormap(pmap->pScreen))
443706f2543Smrg	return;
444706f2543Smrg
445706f2543Smrg    pScreen->InstallColormap = pScreenPriv->InstallColormap;
446706f2543Smrg    (*pScreen->InstallColormap)(pmap);
447706f2543Smrg    pScreen->InstallColormap = CMapInstallColormap;
448706f2543Smrg
449706f2543Smrg    /* Important. We let the lower layers, namely DGA,
450706f2543Smrg       overwrite the choice of Colormap to install */
451706f2543Smrg    if (GetInstalledmiColormap(pmap->pScreen))
452706f2543Smrg	pmap = GetInstalledmiColormap(pmap->pScreen);
453706f2543Smrg
454706f2543Smrg    if (!(pScreenPriv->flags & CMAP_PALETTED_TRUECOLOR) &&
455706f2543Smrg	 (pmap->pVisual->class == TrueColor) &&
456706f2543Smrg	 CMapColormapUseMax(pmap->pVisual, pScreenPriv))
457706f2543Smrg	return;
458706f2543Smrg
459706f2543Smrg    if(LOAD_PALETTE(pmap))
460706f2543Smrg	CMapReinstallMap(pmap);
461706f2543Smrg}
462706f2543Smrg
463706f2543Smrg
464706f2543Smrg/**** ScrnInfoRec functions ****/
465706f2543Smrg
466706f2543Smrgstatic Bool
467706f2543SmrgCMapEnterVT(int index, int flags)
468706f2543Smrg{
469706f2543Smrg    ScrnInfoPtr pScrn = xf86Screens[index];
470706f2543Smrg    ScreenPtr pScreen = screenInfo.screens[index];
471706f2543Smrg    Bool ret;
472706f2543Smrg    CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate(
473706f2543Smrg	&pScreen->devPrivates, CMapScreenKey);
474706f2543Smrg
475706f2543Smrg    pScrn->EnterVT = pScreenPriv->EnterVT;
476706f2543Smrg    ret = (*pScreenPriv->EnterVT)(index, flags);
477706f2543Smrg    pScreenPriv->EnterVT = pScrn->EnterVT;
478706f2543Smrg    pScrn->EnterVT = CMapEnterVT;
479706f2543Smrg    if(ret) {
480706f2543Smrg	if(GetInstalledmiColormap(pScreen))
481706f2543Smrg	    CMapReinstallMap(GetInstalledmiColormap(pScreen));
482706f2543Smrg	return TRUE;
483706f2543Smrg    }
484706f2543Smrg    return FALSE;
485706f2543Smrg}
486706f2543Smrg
487706f2543Smrg
488706f2543Smrgstatic Bool
489706f2543SmrgCMapSwitchMode(int index, DisplayModePtr mode, int flags)
490706f2543Smrg{
491706f2543Smrg    ScreenPtr pScreen = screenInfo.screens[index];
492706f2543Smrg    CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate(
493706f2543Smrg	&pScreen->devPrivates, CMapScreenKey);
494706f2543Smrg
495706f2543Smrg    if((*pScreenPriv->SwitchMode)(index, mode, flags)) {
496706f2543Smrg	if(GetInstalledmiColormap(pScreen))
497706f2543Smrg	    CMapReinstallMap(GetInstalledmiColormap(pScreen));
498706f2543Smrg	return TRUE;
499706f2543Smrg    }
500706f2543Smrg    return FALSE;
501706f2543Smrg}
502706f2543Smrg
503706f2543Smrg#ifdef XFreeXDGA
504706f2543Smrgstatic int
505706f2543SmrgCMapSetDGAMode(int index, int num, DGADevicePtr dev)
506706f2543Smrg{
507706f2543Smrg    ScreenPtr pScreen = screenInfo.screens[index];
508706f2543Smrg    CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate(
509706f2543Smrg	&pScreen->devPrivates, CMapScreenKey);
510706f2543Smrg    int ret;
511706f2543Smrg
512706f2543Smrg    ret = (*pScreenPriv->SetDGAMode)(index, num, dev);
513706f2543Smrg
514706f2543Smrg    pScreenPriv->isDGAmode = DGAActive(index);
515706f2543Smrg
516706f2543Smrg    if(!pScreenPriv->isDGAmode && GetInstalledmiColormap(pScreen)
517706f2543Smrg         && xf86Screens[pScreen->myNum]->vtSema)
518706f2543Smrg	CMapReinstallMap(GetInstalledmiColormap(pScreen));
519706f2543Smrg
520706f2543Smrg    return ret;
521706f2543Smrg}
522706f2543Smrg#endif
523706f2543Smrg
524706f2543Smrg
525706f2543Smrg/**** Utilities ****/
526706f2543Smrg
527706f2543Smrgstatic void
528706f2543SmrgCMapReinstallMap(ColormapPtr pmap)
529706f2543Smrg{
530706f2543Smrg    CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate(
531706f2543Smrg	&pmap->pScreen->devPrivates, CMapScreenKey);
532706f2543Smrg    CMapColormapPtr cmapPriv = (CMapColormapPtr)dixLookupPrivate(
533706f2543Smrg	&pmap->devPrivates, CMapColormapKey);
534706f2543Smrg    ScrnInfoPtr pScrn = xf86Screens[pmap->pScreen->myNum];
535706f2543Smrg    int i = cmapPriv->numColors;
536706f2543Smrg    int *indices = pScreenPriv->PreAllocIndices;
537706f2543Smrg
538706f2543Smrg    while(i--)
539706f2543Smrg	indices[i] = i;
540706f2543Smrg
541706f2543Smrg    if(cmapPriv->recalculate)
542706f2543Smrg	CMapRefreshColors(pmap, cmapPriv->numColors, indices);
543706f2543Smrg    else {
544706f2543Smrg	(*pScrn->LoadPalette)(pScrn, cmapPriv->numColors,
545706f2543Smrg 			indices, cmapPriv->colors, pmap->pVisual);
546706f2543Smrg	if (pScrn->SetOverscan) {
547706f2543Smrg#ifdef DEBUGOVERSCAN
548706f2543Smrg	    ErrorF("SetOverscan() called from CMapReinstallMap\n");
549706f2543Smrg#endif
550706f2543Smrg	    pScrn->SetOverscan(pScrn, cmapPriv->overscan);
551706f2543Smrg	}
552706f2543Smrg    }
553706f2543Smrg
554706f2543Smrg    cmapPriv->recalculate = FALSE;
555706f2543Smrg}
556706f2543Smrg
557706f2543Smrg
558706f2543Smrgstatic void
559706f2543SmrgCMapRefreshColors(ColormapPtr pmap, int defs, int* indices)
560706f2543Smrg{
561706f2543Smrg    CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate(
562706f2543Smrg	&pmap->pScreen->devPrivates, CMapScreenKey);
563706f2543Smrg    CMapColormapPtr pColPriv = (CMapColormapPtr)dixLookupPrivate(
564706f2543Smrg	&pmap->devPrivates, CMapColormapKey);
565706f2543Smrg    VisualPtr pVisual = pmap->pVisual;
566706f2543Smrg    ScrnInfoPtr pScrn = xf86Screens[pmap->pScreen->myNum];
567706f2543Smrg    int numColors, i;
568706f2543Smrg    LOCO *gamma, *colors;
569706f2543Smrg    EntryPtr entry;
570706f2543Smrg    int reds, greens, blues, maxValue, index, shift;
571706f2543Smrg
572706f2543Smrg    numColors = pColPriv->numColors;
573706f2543Smrg    shift = 16 - pScreenPriv->sigRGBbits;
574706f2543Smrg    maxValue = (1 << pScreenPriv->sigRGBbits) - 1;
575706f2543Smrg    gamma = pScreenPriv->gamma;
576706f2543Smrg    colors = pColPriv->colors;
577706f2543Smrg
578706f2543Smrg    reds = pVisual->redMask >> pVisual->offsetRed;
579706f2543Smrg    greens = pVisual->greenMask >> pVisual->offsetGreen;
580706f2543Smrg    blues = pVisual->blueMask >> pVisual->offsetBlue;
581706f2543Smrg
582706f2543Smrg    switch(pVisual->class) {
583706f2543Smrg    case StaticGray:
584706f2543Smrg	for(i = 0; i < numColors; i++) {
585706f2543Smrg	    index = (i+1) * maxValue / numColors;
586706f2543Smrg	    colors[i].red   = gamma[index].red;
587706f2543Smrg	    colors[i].green = gamma[index].green;
588706f2543Smrg	    colors[i].blue  = gamma[index].blue;
589706f2543Smrg	}
590706f2543Smrg	break;
591706f2543Smrg    case TrueColor:
592706f2543Smrg        if (CMapColormapUseMax(pVisual, pScreenPriv)) {
593706f2543Smrg	    for(i = 0; i <= reds; i++)
594706f2543Smrg		colors[i].red   = gamma[i * maxValue / reds].red;
595706f2543Smrg	    for(i = 0; i <= greens; i++)
596706f2543Smrg		colors[i].green = gamma[i * maxValue / greens].green;
597706f2543Smrg	    for(i = 0; i <= blues; i++)
598706f2543Smrg		colors[i].blue  = gamma[i * maxValue / blues].blue;
599706f2543Smrg	    break;
600706f2543Smrg	}
601706f2543Smrg	for(i = 0; i < numColors; i++) {
602706f2543Smrg	    colors[i].red   = gamma[((i >> pVisual->offsetRed) & reds) *
603706f2543Smrg					maxValue / reds].red;
604706f2543Smrg	    colors[i].green = gamma[((i >> pVisual->offsetGreen) & greens) *
605706f2543Smrg					maxValue / greens].green;
606706f2543Smrg	    colors[i].blue  = gamma[((i >> pVisual->offsetBlue) & blues) *
607706f2543Smrg					maxValue / blues].blue;
608706f2543Smrg	}
609706f2543Smrg	break;
610706f2543Smrg    case StaticColor:
611706f2543Smrg    case PseudoColor:
612706f2543Smrg    case GrayScale:
613706f2543Smrg	for(i = 0; i < defs; i++) {
614706f2543Smrg	    index = indices[i];
615706f2543Smrg	    entry = (EntryPtr)&pmap->red[index];
616706f2543Smrg
617706f2543Smrg	    if(entry->fShared) {
618706f2543Smrg		colors[index].red =
619706f2543Smrg			gamma[entry->co.shco.red->color >> shift].red;
620706f2543Smrg		colors[index].green =
621706f2543Smrg			gamma[entry->co.shco.green->color >> shift].green;
622706f2543Smrg		colors[index].blue =
623706f2543Smrg			gamma[entry->co.shco.blue->color >> shift].blue;
624706f2543Smrg	    } else {
625706f2543Smrg		colors[index].red   =
626706f2543Smrg				gamma[entry->co.local.red >> shift].red;
627706f2543Smrg		colors[index].green =
628706f2543Smrg				gamma[entry->co.local.green >> shift].green;
629706f2543Smrg		colors[index].blue  =
630706f2543Smrg				gamma[entry->co.local.blue >> shift].blue;
631706f2543Smrg	    }
632706f2543Smrg	}
633706f2543Smrg	break;
634706f2543Smrg    case DirectColor:
635706f2543Smrg        if (CMapColormapUseMax(pVisual, pScreenPriv)) {
636706f2543Smrg	    for(i = 0; i < defs; i++) {
637706f2543Smrg		index = indices[i];
638706f2543Smrg		if(index <= reds)
639706f2543Smrg		    colors[index].red   =
640706f2543Smrg			gamma[pmap->red[index].co.local.red >> shift].red;
641706f2543Smrg		if(index <= greens)
642706f2543Smrg		    colors[index].green =
643706f2543Smrg			gamma[pmap->green[index].co.local.green >> shift].green;
644706f2543Smrg		if(index <= blues)
645706f2543Smrg		    colors[index].blue   =
646706f2543Smrg			gamma[pmap->blue[index].co.local.blue >> shift].blue;
647706f2543Smrg
648706f2543Smrg	    }
649706f2543Smrg	    break;
650706f2543Smrg	}
651706f2543Smrg	for(i = 0; i < defs; i++) {
652706f2543Smrg	    index = indices[i];
653706f2543Smrg
654706f2543Smrg	    colors[index].red   = gamma[pmap->red[
655706f2543Smrg				(index >> pVisual->offsetRed) & reds
656706f2543Smrg				].co.local.red >> shift].red;
657706f2543Smrg	    colors[index].green = gamma[pmap->green[
658706f2543Smrg				(index >> pVisual->offsetGreen) & greens
659706f2543Smrg				].co.local.green >> shift].green;
660706f2543Smrg	    colors[index].blue  = gamma[pmap->blue[
661706f2543Smrg				(index >> pVisual->offsetBlue) & blues
662706f2543Smrg				].co.local.blue >> shift].blue;
663706f2543Smrg	}
664706f2543Smrg	break;
665706f2543Smrg    }
666706f2543Smrg
667706f2543Smrg
668706f2543Smrg    if(LOAD_PALETTE(pmap))
669706f2543Smrg	(*pScrn->LoadPalette)(pScreenPriv->pScrn, defs, indices,
670706f2543Smrg 					colors, pmap->pVisual);
671706f2543Smrg
672706f2543Smrg    if (pScrn->SetOverscan)
673706f2543Smrg	CMapSetOverscan(pmap, defs, indices);
674706f2543Smrg
675706f2543Smrg}
676706f2543Smrg
677706f2543Smrgstatic Bool
678706f2543SmrgCMapCompareColors(LOCO *color1, LOCO *color2)
679706f2543Smrg{
680706f2543Smrg    /* return TRUE if the color1 is "closer" to black than color2 */
681706f2543Smrg#ifdef DEBUGOVERSCAN
682706f2543Smrg    ErrorF("#%02x%02x%02x vs #%02x%02x%02x (%d vs %d)\n",
683706f2543Smrg	color1->red, color1->green, color1->blue,
684706f2543Smrg	color2->red, color2->green, color2->blue,
685706f2543Smrg	color1->red + color1->green + color1->blue,
686706f2543Smrg	color2->red + color2->green + color2->blue);
687706f2543Smrg#endif
688706f2543Smrg    return (color1->red + color1->green + color1->blue <
689706f2543Smrg	    color2->red + color2->green + color2->blue);
690706f2543Smrg}
691706f2543Smrg
692706f2543Smrgstatic void
693706f2543SmrgCMapSetOverscan(ColormapPtr pmap, int defs, int *indices)
694706f2543Smrg{
695706f2543Smrg    CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate(
696706f2543Smrg	&pmap->pScreen->devPrivates, CMapScreenKey);
697706f2543Smrg    CMapColormapPtr pColPriv = (CMapColormapPtr)dixLookupPrivate(
698706f2543Smrg	&pmap->devPrivates, CMapColormapKey);
699706f2543Smrg    ScrnInfoPtr pScrn = xf86Screens[pmap->pScreen->myNum];
700706f2543Smrg    VisualPtr pVisual = pmap->pVisual;
701706f2543Smrg    int i;
702706f2543Smrg    LOCO *colors;
703706f2543Smrg    int index;
704706f2543Smrg    Bool newOverscan = FALSE;
705706f2543Smrg    int overscan, tmpOverscan;
706706f2543Smrg
707706f2543Smrg    colors = pColPriv->colors;
708706f2543Smrg    overscan = pColPriv->overscan;
709706f2543Smrg
710706f2543Smrg    /*
711706f2543Smrg     * Search for a new overscan index in the following cases:
712706f2543Smrg     *
713706f2543Smrg     *   - The index hasn't yet been initialised.  In this case search
714706f2543Smrg     *     for an index that is black or a close match to black.
715706f2543Smrg     *
716706f2543Smrg     *   - The colour of the old index is changed.  In this case search
717706f2543Smrg     *     all indices for a black or close match to black.
718706f2543Smrg     *
719706f2543Smrg     *   - The colour of the old index wasn't black.  In this case only
720706f2543Smrg     *     search the indices that were changed for a better match to black.
721706f2543Smrg     */
722706f2543Smrg
723706f2543Smrg    switch (pVisual->class) {
724706f2543Smrg    case StaticGray:
725706f2543Smrg    case TrueColor:
726706f2543Smrg	/* Should only come here once.  Initialise the overscan index to 0 */
727706f2543Smrg	overscan = 0;
728706f2543Smrg	newOverscan = TRUE;
729706f2543Smrg	break;
730706f2543Smrg    case StaticColor:
731706f2543Smrg	/*
732706f2543Smrg         * Only come here once, but search for the overscan in the same way
733706f2543Smrg         * as for the other cases.
734706f2543Smrg	 */
735706f2543Smrg    case DirectColor:
736706f2543Smrg    case PseudoColor:
737706f2543Smrg    case GrayScale:
738706f2543Smrg	if (overscan < 0 || overscan > pScreenPriv->maxColors - 1) {
739706f2543Smrg	    /* Uninitialised */
740706f2543Smrg	    newOverscan = TRUE;
741706f2543Smrg	} else {
742706f2543Smrg	    /* Check if the overscan was changed */
743706f2543Smrg	    for (i = 0; i < defs; i++) {
744706f2543Smrg		index = indices[i];
745706f2543Smrg		if (index == overscan) {
746706f2543Smrg		    newOverscan = TRUE;
747706f2543Smrg		    break;
748706f2543Smrg		}
749706f2543Smrg	    }
750706f2543Smrg	}
751706f2543Smrg	if (newOverscan) {
752706f2543Smrg	    /* The overscan is either uninitialised or it has been changed */
753706f2543Smrg
754706f2543Smrg	    if (overscan < 0 || overscan > pScreenPriv->maxColors - 1)
755706f2543Smrg		tmpOverscan = pScreenPriv->maxColors - 1;
756706f2543Smrg	    else
757706f2543Smrg		tmpOverscan = overscan;
758706f2543Smrg
759706f2543Smrg	    /* search all entries for a close match to black */
760706f2543Smrg	    for (i = pScreenPriv->maxColors - 1; i >= 0; i--) {
761706f2543Smrg		if (colors[i].red == 0 && colors[i].green == 0 &&
762706f2543Smrg		    colors[i].blue == 0) {
763706f2543Smrg		    overscan = i;
764706f2543Smrg#ifdef DEBUGOVERSCAN
765706f2543Smrg		    ErrorF("Black found at index 0x%02x\n", i);
766706f2543Smrg#endif
767706f2543Smrg		    break;
768706f2543Smrg		} else {
769706f2543Smrg#ifdef DEBUGOVERSCAN
770706f2543Smrg		    ErrorF("0x%02x: ", i);
771706f2543Smrg#endif
772706f2543Smrg		    if (CMapCompareColors(&colors[i], &colors[tmpOverscan])) {
773706f2543Smrg			tmpOverscan = i;
774706f2543Smrg#ifdef DEBUGOVERSCAN
775706f2543Smrg			ErrorF("possible \"Black\" at index 0x%02x\n", i);
776706f2543Smrg#endif
777706f2543Smrg		    }
778706f2543Smrg		}
779706f2543Smrg	    }
780706f2543Smrg	    if (i < 0)
781706f2543Smrg		overscan = tmpOverscan;
782706f2543Smrg	} else {
783706f2543Smrg	    /* Check of the old overscan wasn't black */
784706f2543Smrg	    if (colors[overscan].red != 0 || colors[overscan].green != 0 ||
785706f2543Smrg		colors[overscan].blue != 0) {
786706f2543Smrg		int oldOverscan = tmpOverscan = overscan;
787706f2543Smrg		/* See of there is now a better match */
788706f2543Smrg		for (i = 0; i < defs; i++) {
789706f2543Smrg		    index = indices[i];
790706f2543Smrg		    if (colors[index].red == 0 && colors[index].green == 0 &&
791706f2543Smrg			colors[index].blue == 0) {
792706f2543Smrg			overscan = index;
793706f2543Smrg#ifdef DEBUGOVERSCAN
794706f2543Smrg			ErrorF("Black found at index 0x%02x\n", index);
795706f2543Smrg#endif
796706f2543Smrg			break;
797706f2543Smrg		    } else {
798706f2543Smrg#ifdef DEBUGOVERSCAN
799706f2543Smrg			ErrorF("0x%02x: ", index);
800706f2543Smrg#endif
801706f2543Smrg			if (CMapCompareColors(&colors[index],
802706f2543Smrg					      &colors[tmpOverscan])) {
803706f2543Smrg			    tmpOverscan = index;
804706f2543Smrg#ifdef DEBUGOVERSCAN
805706f2543Smrg			    ErrorF("possible \"Black\" at index 0x%02x\n",
806706f2543Smrg				   index);
807706f2543Smrg#endif
808706f2543Smrg			}
809706f2543Smrg		    }
810706f2543Smrg		}
811706f2543Smrg		if (i == defs)
812706f2543Smrg		    overscan = tmpOverscan;
813706f2543Smrg		if (overscan != oldOverscan)
814706f2543Smrg		    newOverscan = TRUE;
815706f2543Smrg	    }
816706f2543Smrg	}
817706f2543Smrg	break;
818706f2543Smrg    }
819706f2543Smrg    if (newOverscan) {
820706f2543Smrg	pColPriv->overscan = overscan;
821706f2543Smrg	if (LOAD_PALETTE(pmap)) {
822706f2543Smrg#ifdef DEBUGOVERSCAN
823706f2543Smrg	    ErrorF("SetOverscan() called from CmapSetOverscan\n");
824706f2543Smrg#endif
825706f2543Smrg	    pScrn->SetOverscan(pScreenPriv->pScrn, overscan);
826706f2543Smrg	}
827706f2543Smrg    }
828706f2543Smrg}
829706f2543Smrg
830706f2543Smrgstatic void
831706f2543SmrgCMapUnwrapScreen(ScreenPtr pScreen)
832706f2543Smrg{
833706f2543Smrg    CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate(
834706f2543Smrg	&pScreen->devPrivates, CMapScreenKey);
835706f2543Smrg    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
836706f2543Smrg
837706f2543Smrg    pScreen->CloseScreen = pScreenPriv->CloseScreen;
838706f2543Smrg    pScreen->CreateColormap = pScreenPriv->CreateColormap;
839706f2543Smrg    pScreen->DestroyColormap = pScreenPriv->DestroyColormap;
840706f2543Smrg    pScreen->InstallColormap = pScreenPriv->InstallColormap;
841706f2543Smrg    pScreen->StoreColors = pScreenPriv->StoreColors;
842706f2543Smrg
843706f2543Smrg    pScrn->EnterVT = pScreenPriv->EnterVT;
844706f2543Smrg    pScrn->SwitchMode = pScreenPriv->SwitchMode;
845706f2543Smrg    pScrn->SetDGAMode = pScreenPriv->SetDGAMode;
846706f2543Smrg    pScrn->ChangeGamma = pScreenPriv->ChangeGamma;
847706f2543Smrg
848706f2543Smrg    free(pScreenPriv->gamma);
849706f2543Smrg    free(pScreenPriv->PreAllocIndices);
850706f2543Smrg    free(pScreenPriv);
851706f2543Smrg}
852706f2543Smrg
853706f2543Smrg
854706f2543Smrgstatic void
855706f2543SmrgComputeGamma(CMapScreenPtr priv)
856706f2543Smrg{
857706f2543Smrg    int elements = priv->gammaElements - 1;
858706f2543Smrg    double RedGamma, GreenGamma, BlueGamma;
859706f2543Smrg    int i;
860706f2543Smrg
861706f2543Smrg#ifndef DONT_CHECK_GAMMA
862706f2543Smrg    /* This check is to catch drivers that are not initialising pScrn->gamma */
863706f2543Smrg    if (priv->pScrn->gamma.red < GAMMA_MIN ||
864706f2543Smrg	priv->pScrn->gamma.red > GAMMA_MAX ||
865706f2543Smrg	priv->pScrn->gamma.green < GAMMA_MIN ||
866706f2543Smrg	priv->pScrn->gamma.green > GAMMA_MAX ||
867706f2543Smrg	priv->pScrn->gamma.blue < GAMMA_MIN ||
868706f2543Smrg	priv->pScrn->gamma.blue > GAMMA_MAX) {
869706f2543Smrg
870706f2543Smrg	xf86DrvMsgVerb(priv->pScrn->scrnIndex, X_WARNING, 0,
871706f2543Smrg	    "The %s driver didn't call xf86SetGamma() to initialise\n"
872706f2543Smrg	    "\tthe gamma values.\n", priv->pScrn->driverName);
873706f2543Smrg	xf86DrvMsgVerb(priv->pScrn->scrnIndex, X_WARNING, 0,
874706f2543Smrg	    "PLEASE FIX THE `%s' DRIVER!\n", priv->pScrn->driverName);
875706f2543Smrg	priv->pScrn->gamma.red = 1.0;
876706f2543Smrg	priv->pScrn->gamma.green = 1.0;
877706f2543Smrg	priv->pScrn->gamma.blue = 1.0;
878706f2543Smrg    }
879706f2543Smrg#endif
880706f2543Smrg
881706f2543Smrg    RedGamma = 1.0 / (double)priv->pScrn->gamma.red;
882706f2543Smrg    GreenGamma = 1.0 / (double)priv->pScrn->gamma.green;
883706f2543Smrg    BlueGamma = 1.0 / (double)priv->pScrn->gamma.blue;
884706f2543Smrg
885706f2543Smrg    for(i = 0; i <= elements; i++) {
886706f2543Smrg	if(RedGamma == 1.0)
887706f2543Smrg	    priv->gamma[i].red = i;
888706f2543Smrg	else
889706f2543Smrg	    priv->gamma[i].red = (CARD16)(pow((double)i/(double)elements,
890706f2543Smrg			RedGamma) * (double)elements + 0.5);
891706f2543Smrg
892706f2543Smrg	if(GreenGamma == 1.0)
893706f2543Smrg	    priv->gamma[i].green = i;
894706f2543Smrg	else
895706f2543Smrg	    priv->gamma[i].green = (CARD16)(pow((double)i/(double)elements,
896706f2543Smrg			GreenGamma) * (double)elements + 0.5);
897706f2543Smrg
898706f2543Smrg	if(BlueGamma == 1.0)
899706f2543Smrg	    priv->gamma[i].blue = i;
900706f2543Smrg	else
901706f2543Smrg	    priv->gamma[i].blue = (CARD16)(pow((double)i/(double)elements,
902706f2543Smrg			BlueGamma) * (double)elements + 0.5);
903706f2543Smrg    }
904706f2543Smrg}
905706f2543Smrg
906706f2543Smrg
907706f2543Smrgint
908706f2543SmrgCMapChangeGamma(
909706f2543Smrg   int index,
910706f2543Smrg   Gamma gamma
911706f2543Smrg){
912706f2543Smrg    int ret = Success;
913706f2543Smrg    ScrnInfoPtr pScrn = xf86Screens[index];
914706f2543Smrg    ScreenPtr pScreen = pScrn->pScreen;
915706f2543Smrg    CMapColormapPtr pColPriv;
916706f2543Smrg    CMapScreenPtr pScreenPriv;
917706f2543Smrg    CMapLinkPtr pLink;
918706f2543Smrg
919706f2543Smrg    /* Is this sufficient checking ? */
920706f2543Smrg    if(!CMapScreenKeyRegistered)
921706f2543Smrg	return BadImplementation;
922706f2543Smrg
923706f2543Smrg    pScreenPriv = (CMapScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
924706f2543Smrg						  CMapScreenKey);
925706f2543Smrg    if(!pScreenPriv)
926706f2543Smrg	return BadImplementation;
927706f2543Smrg
928706f2543Smrg    if (gamma.red < GAMMA_MIN || gamma.red > GAMMA_MAX ||
929706f2543Smrg	gamma.green < GAMMA_MIN || gamma.green > GAMMA_MAX ||
930706f2543Smrg	gamma.blue < GAMMA_MIN || gamma.blue > GAMMA_MAX)
931706f2543Smrg	return BadValue;
932706f2543Smrg
933706f2543Smrg    pScrn->gamma.red = gamma.red;
934706f2543Smrg    pScrn->gamma.green = gamma.green;
935706f2543Smrg    pScrn->gamma.blue = gamma.blue;
936706f2543Smrg
937706f2543Smrg    ComputeGamma(pScreenPriv);
938706f2543Smrg
939706f2543Smrg    /* mark all colormaps on this screen */
940706f2543Smrg    pLink = pScreenPriv->maps;
941706f2543Smrg    while(pLink) {
942706f2543Smrg    	pColPriv = (CMapColormapPtr)dixLookupPrivate(&pLink->cmap->devPrivates,
943706f2543Smrg						     CMapColormapKey);
944706f2543Smrg	pColPriv->recalculate = TRUE;
945706f2543Smrg	pLink = pLink->next;
946706f2543Smrg    }
947706f2543Smrg
948706f2543Smrg    if(GetInstalledmiColormap(pScreen) &&
949706f2543Smrg       ((pScreenPriv->flags & CMAP_LOAD_EVEN_IF_OFFSCREEN) ||
950706f2543Smrg	pScrn->vtSema || pScreenPriv->isDGAmode)) {
951706f2543Smrg	ColormapPtr pMap = GetInstalledmiColormap(pScreen);
952706f2543Smrg
953706f2543Smrg	if (!(pScreenPriv->flags & CMAP_PALETTED_TRUECOLOR) &&
954706f2543Smrg	    (pMap->pVisual->class == TrueColor) &&
955706f2543Smrg	    CMapColormapUseMax(pMap->pVisual, pScreenPriv)) {
956706f2543Smrg
957706f2543Smrg	    /* if the current map doesn't have a palette look
958706f2543Smrg		for another map to change the gamma on. */
959706f2543Smrg
960706f2543Smrg	    pLink = pScreenPriv->maps;
961706f2543Smrg	    while(pLink) {
962706f2543Smrg		if(pLink->cmap->pVisual->class == PseudoColor)
963706f2543Smrg		    break;
964706f2543Smrg		pLink = pLink->next;
965706f2543Smrg	    }
966706f2543Smrg
967706f2543Smrg	    if(pLink) {
968706f2543Smrg		/* need to trick CMapRefreshColors() into thinking
969706f2543Smrg		   this is the currently installed map */
970706f2543Smrg		SetInstalledmiColormap(pScreen, pLink->cmap);
971706f2543Smrg		CMapReinstallMap(pLink->cmap);
972706f2543Smrg		SetInstalledmiColormap(pScreen, pMap);
973706f2543Smrg	    }
974706f2543Smrg	} else
975706f2543Smrg	    CMapReinstallMap(pMap);
976706f2543Smrg    }
977706f2543Smrg
978706f2543Smrg    pScrn->ChangeGamma = pScreenPriv->ChangeGamma;
979706f2543Smrg    if (pScrn->ChangeGamma)
980706f2543Smrg	ret = pScrn->ChangeGamma(index, gamma);
981706f2543Smrg    pScrn->ChangeGamma = CMapChangeGamma;
982706f2543Smrg
983706f2543Smrg    return ret;
984706f2543Smrg}
985706f2543Smrg
986706f2543Smrg
987706f2543Smrgstatic void
988706f2543SmrgComputeGammaRamp (
989706f2543Smrg    CMapScreenPtr priv,
990706f2543Smrg    unsigned short *red,
991706f2543Smrg    unsigned short *green,
992706f2543Smrg    unsigned short *blue
993706f2543Smrg){
994706f2543Smrg    int elements = priv->gammaElements;
995706f2543Smrg    LOCO *entry = priv->gamma;
996706f2543Smrg    int shift = 16 - priv->sigRGBbits;
997706f2543Smrg
998706f2543Smrg    while(elements--) {
999706f2543Smrg	entry->red = *(red++) >> shift;
1000706f2543Smrg	entry->green = *(green++) >> shift;
1001706f2543Smrg	entry->blue = *(blue++) >> shift;
1002706f2543Smrg	entry++;
1003706f2543Smrg    }
1004706f2543Smrg}
1005706f2543Smrg
1006706f2543Smrgint
1007706f2543Smrgxf86ChangeGammaRamp(
1008706f2543Smrg   ScreenPtr pScreen,
1009706f2543Smrg   int size,
1010706f2543Smrg   unsigned short *red,
1011706f2543Smrg   unsigned short *green,
1012706f2543Smrg   unsigned short *blue
1013706f2543Smrg){
1014706f2543Smrg    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1015706f2543Smrg    CMapColormapPtr pColPriv;
1016706f2543Smrg    CMapScreenPtr pScreenPriv;
1017706f2543Smrg    CMapLinkPtr pLink;
1018706f2543Smrg
1019706f2543Smrg    if (xf86_crtc_supports_gamma(pScrn)) {
1020706f2543Smrg	RRCrtcPtr crtc = xf86CompatRRCrtc(pScrn);
1021706f2543Smrg
1022706f2543Smrg	if (crtc) {
1023706f2543Smrg	    if (crtc->gammaSize != size)
1024706f2543Smrg		return BadValue;
1025706f2543Smrg
1026706f2543Smrg	    RRCrtcGammaSet(crtc, red, green, blue);
1027706f2543Smrg
1028706f2543Smrg	    return Success;
1029706f2543Smrg	}
1030706f2543Smrg    }
1031706f2543Smrg
1032706f2543Smrg    if(!CMapScreenKeyRegistered)
1033706f2543Smrg        return BadImplementation;
1034706f2543Smrg
1035706f2543Smrg    pScreenPriv = (CMapScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
1036706f2543Smrg						  CMapScreenKey);
1037706f2543Smrg    if(!pScreenPriv)
1038706f2543Smrg        return BadImplementation;
1039706f2543Smrg
1040706f2543Smrg    if(pScreenPriv->gammaElements != size)
1041706f2543Smrg	return BadValue;
1042706f2543Smrg
1043706f2543Smrg    ComputeGammaRamp(pScreenPriv, red, green, blue);
1044706f2543Smrg
1045706f2543Smrg    /* mark all colormaps on this screen */
1046706f2543Smrg    pLink = pScreenPriv->maps;
1047706f2543Smrg    while(pLink) {
1048706f2543Smrg    	pColPriv = (CMapColormapPtr)dixLookupPrivate(&pLink->cmap->devPrivates,
1049706f2543Smrg						     CMapColormapKey);
1050706f2543Smrg        pColPriv->recalculate = TRUE;
1051706f2543Smrg        pLink = pLink->next;
1052706f2543Smrg    }
1053706f2543Smrg
1054706f2543Smrg    if(GetInstalledmiColormap(pScreen) &&
1055706f2543Smrg       ((pScreenPriv->flags & CMAP_LOAD_EVEN_IF_OFFSCREEN) ||
1056706f2543Smrg        pScrn->vtSema || pScreenPriv->isDGAmode)) {
1057706f2543Smrg        ColormapPtr pMap = GetInstalledmiColormap(pScreen);
1058706f2543Smrg
1059706f2543Smrg        if (!(pScreenPriv->flags & CMAP_PALETTED_TRUECOLOR) &&
1060706f2543Smrg            (pMap->pVisual->class == TrueColor) &&
1061706f2543Smrg	    CMapColormapUseMax(pMap->pVisual, pScreenPriv)) {
1062706f2543Smrg
1063706f2543Smrg            /* if the current map doesn't have a palette look
1064706f2543Smrg                for another map to change the gamma on. */
1065706f2543Smrg
1066706f2543Smrg            pLink = pScreenPriv->maps;
1067706f2543Smrg            while(pLink) {
1068706f2543Smrg                if(pLink->cmap->pVisual->class == PseudoColor)
1069706f2543Smrg                    break;
1070706f2543Smrg                pLink = pLink->next;
1071706f2543Smrg            }
1072706f2543Smrg
1073706f2543Smrg            if(pLink) {
1074706f2543Smrg                /* need to trick CMapRefreshColors() into thinking
1075706f2543Smrg                   this is the currently installed map */
1076706f2543Smrg                SetInstalledmiColormap(pScreen, pLink->cmap);
1077706f2543Smrg                CMapReinstallMap(pLink->cmap);
1078706f2543Smrg                SetInstalledmiColormap(pScreen, pMap);
1079706f2543Smrg            }
1080706f2543Smrg        } else
1081706f2543Smrg            CMapReinstallMap(pMap);
1082706f2543Smrg    }
1083706f2543Smrg
1084706f2543Smrg    return Success;
1085706f2543Smrg}
1086706f2543Smrg
1087706f2543Smrgint
1088706f2543Smrgxf86GetGammaRampSize(ScreenPtr pScreen)
1089706f2543Smrg{
1090706f2543Smrg    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1091706f2543Smrg    CMapScreenPtr pScreenPriv;
1092706f2543Smrg
1093706f2543Smrg    if (xf86_crtc_supports_gamma(pScrn)) {
1094706f2543Smrg	RRCrtcPtr crtc = xf86CompatRRCrtc(pScrn);
1095706f2543Smrg
1096706f2543Smrg	if (crtc)
1097706f2543Smrg	    return crtc->gammaSize;
1098706f2543Smrg    }
1099706f2543Smrg
1100706f2543Smrg    if(!CMapScreenKeyRegistered) return 0;
1101706f2543Smrg
1102706f2543Smrg    pScreenPriv = (CMapScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
1103706f2543Smrg						  CMapScreenKey);
1104706f2543Smrg    if(!pScreenPriv) return 0;
1105706f2543Smrg
1106706f2543Smrg    return pScreenPriv->gammaElements;
1107706f2543Smrg}
1108706f2543Smrg
1109706f2543Smrgint
1110706f2543Smrgxf86GetGammaRamp(
1111706f2543Smrg   ScreenPtr pScreen,
1112706f2543Smrg   int size,
1113706f2543Smrg   unsigned short *red,
1114706f2543Smrg   unsigned short *green,
1115706f2543Smrg   unsigned short *blue
1116706f2543Smrg){
1117706f2543Smrg    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1118706f2543Smrg    CMapScreenPtr pScreenPriv;
1119706f2543Smrg    LOCO *entry;
1120706f2543Smrg    int shift, sigbits;
1121706f2543Smrg
1122706f2543Smrg    if (xf86_crtc_supports_gamma(pScrn)) {
1123706f2543Smrg	RRCrtcPtr crtc = xf86CompatRRCrtc(pScrn);
1124706f2543Smrg
1125706f2543Smrg	if (crtc) {
1126706f2543Smrg	    if (crtc->gammaSize < size)
1127706f2543Smrg		return BadValue;
1128706f2543Smrg
1129706f2543Smrg	    if (!RRCrtcGammaGet(crtc))
1130706f2543Smrg		return BadImplementation;
1131706f2543Smrg
1132706f2543Smrg	    memcpy(red, crtc->gammaRed, size * sizeof(*red));
1133706f2543Smrg	    memcpy(green, crtc->gammaGreen, size * sizeof(*green));
1134706f2543Smrg	    memcpy(blue, crtc->gammaBlue, size * sizeof(*blue));
1135706f2543Smrg
1136706f2543Smrg	    return Success;
1137706f2543Smrg	}
1138706f2543Smrg    }
1139706f2543Smrg
1140706f2543Smrg    if(!CMapScreenKeyRegistered)
1141706f2543Smrg	return BadImplementation;
1142706f2543Smrg
1143706f2543Smrg    pScreenPriv = (CMapScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
1144706f2543Smrg						  CMapScreenKey);
1145706f2543Smrg    if(!pScreenPriv)
1146706f2543Smrg	return BadImplementation;
1147706f2543Smrg
1148706f2543Smrg    if(size > pScreenPriv->gammaElements)
1149706f2543Smrg	return BadValue;
1150706f2543Smrg
1151706f2543Smrg    entry = pScreenPriv->gamma;
1152706f2543Smrg    sigbits = pScreenPriv->sigRGBbits;
1153706f2543Smrg
1154706f2543Smrg    while(size--) {
1155706f2543Smrg	*red = entry->red << (16 - sigbits);
1156706f2543Smrg	*green = entry->green << (16 - sigbits);
1157706f2543Smrg	*blue = entry->blue << (16 - sigbits);
1158706f2543Smrg	shift = sigbits;
1159706f2543Smrg	while(shift < 16) {
1160706f2543Smrg	    *red |= *red >> shift;
1161706f2543Smrg	    *green |= *green >> shift;
1162706f2543Smrg	    *blue |= *blue >> shift;
1163706f2543Smrg	    shift += sigbits;
1164706f2543Smrg	}
1165706f2543Smrg	red++; green++; blue++;
1166706f2543Smrg        entry++;
1167706f2543Smrg    }
1168706f2543Smrg
1169706f2543Smrg    return Success;
1170706f2543Smrg}
1171706f2543Smrg
1172706f2543Smrgint
1173706f2543Smrgxf86ChangeGamma(
1174706f2543Smrg   ScreenPtr pScreen,
1175706f2543Smrg   Gamma gamma
1176706f2543Smrg){
1177706f2543Smrg    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1178706f2543Smrg
1179706f2543Smrg    if(pScrn->ChangeGamma)
1180706f2543Smrg	return (*pScrn->ChangeGamma)(pScreen->myNum, gamma);
1181706f2543Smrg
1182706f2543Smrg    return BadImplementation;
1183706f2543Smrg}
1184