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