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