micmap.c revision ed6184df
1/*
2 * Copyright (c) 1987, Oracle and/or its affiliates. All rights reserved.
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 (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24/*
25 * This is based on cfbcmap.c.  The functions here are useful independently
26 * of cfb, which is the reason for including them here.  How "mi" these
27 * are may be debatable.
28 */
29
30#ifdef HAVE_DIX_CONFIG_H
31#include <dix-config.h>
32#endif
33
34#include <X11/X.h>
35#include <X11/Xproto.h>
36#include "scrnintstr.h"
37#include "colormapst.h"
38#include "resource.h"
39#include "globals.h"
40#include "micmap.h"
41
42DevPrivateKeyRec micmapScrPrivateKeyRec;
43
44int
45miListInstalledColormaps(ScreenPtr pScreen, Colormap * pmaps)
46{
47    if (GetInstalledmiColormap(pScreen)) {
48        *pmaps = GetInstalledmiColormap(pScreen)->mid;
49        return 1;
50    }
51    return 0;
52}
53
54void
55miInstallColormap(ColormapPtr pmap)
56{
57    ColormapPtr oldpmap = GetInstalledmiColormap(pmap->pScreen);
58
59    if (pmap != oldpmap) {
60        /* Uninstall pInstalledMap. No hardware changes required, just
61         * notify all interested parties. */
62        if (oldpmap != (ColormapPtr) None)
63            WalkTree(pmap->pScreen, TellLostMap, (char *) &oldpmap->mid);
64        /* Install pmap */
65        SetInstalledmiColormap(pmap->pScreen, pmap);
66        WalkTree(pmap->pScreen, TellGainedMap, (char *) &pmap->mid);
67
68    }
69}
70
71void
72miUninstallColormap(ColormapPtr pmap)
73{
74    ColormapPtr curpmap = GetInstalledmiColormap(pmap->pScreen);
75
76    if (pmap == curpmap) {
77        if (pmap->mid != pmap->pScreen->defColormap) {
78            dixLookupResourceByType((void **) &curpmap,
79                                    pmap->pScreen->defColormap,
80                                    RT_COLORMAP, serverClient, DixUseAccess);
81            (*pmap->pScreen->InstallColormap) (curpmap);
82        }
83    }
84}
85
86void
87miResolveColor(unsigned short *pred, unsigned short *pgreen,
88               unsigned short *pblue, VisualPtr pVisual)
89{
90    int shift = 16 - pVisual->bitsPerRGBValue;
91    unsigned lim = (1 << pVisual->bitsPerRGBValue) - 1;
92
93    if ((pVisual->class | DynamicClass) == GrayScale) {
94        /* rescale to gray then rgb bits */
95        *pred = (30L * *pred + 59L * *pgreen + 11L * *pblue) / 100;
96        *pblue = *pgreen = *pred = ((*pred >> shift) * 65535) / lim;
97    }
98    else {
99        /* rescale to rgb bits */
100        *pred = ((*pred >> shift) * 65535) / lim;
101        *pgreen = ((*pgreen >> shift) * 65535) / lim;
102        *pblue = ((*pblue >> shift) * 65535) / lim;
103    }
104}
105
106Bool
107miInitializeColormap(ColormapPtr pmap)
108{
109    unsigned i;
110    VisualPtr pVisual;
111    unsigned lim, maxent, shift;
112
113    pVisual = pmap->pVisual;
114    lim = (1 << pVisual->bitsPerRGBValue) - 1;
115    shift = 16 - pVisual->bitsPerRGBValue;
116    maxent = pVisual->ColormapEntries - 1;
117    if (pVisual->class == TrueColor) {
118        unsigned limr, limg, limb;
119
120        limr = pVisual->redMask >> pVisual->offsetRed;
121        limg = pVisual->greenMask >> pVisual->offsetGreen;
122        limb = pVisual->blueMask >> pVisual->offsetBlue;
123        for (i = 0; i <= maxent; i++) {
124            /* rescale to [0..65535] then rgb bits */
125            pmap->red[i].co.local.red =
126                ((((i * 65535) / limr) >> shift) * 65535) / lim;
127            pmap->green[i].co.local.green =
128                ((((i * 65535) / limg) >> shift) * 65535) / lim;
129            pmap->blue[i].co.local.blue =
130                ((((i * 65535) / limb) >> shift) * 65535) / lim;
131        }
132    }
133    else if (pVisual->class == StaticColor) {
134        unsigned limr, limg, limb;
135
136        limr = pVisual->redMask >> pVisual->offsetRed;
137        limg = pVisual->greenMask >> pVisual->offsetGreen;
138        limb = pVisual->blueMask >> pVisual->offsetBlue;
139        for (i = 0; i <= maxent; i++) {
140            /* rescale to [0..65535] then rgb bits */
141            pmap->red[i].co.local.red =
142                ((((((i & pVisual->redMask) >> pVisual->offsetRed)
143                    * 65535) / limr) >> shift) * 65535) / lim;
144            pmap->red[i].co.local.green =
145                ((((((i & pVisual->greenMask) >> pVisual->offsetGreen)
146                    * 65535) / limg) >> shift) * 65535) / lim;
147            pmap->red[i].co.local.blue =
148                ((((((i & pVisual->blueMask) >> pVisual->offsetBlue)
149                    * 65535) / limb) >> shift) * 65535) / lim;
150        }
151    }
152    else if (pVisual->class == StaticGray) {
153        for (i = 0; i <= maxent; i++) {
154            /* rescale to [0..65535] then rgb bits */
155            pmap->red[i].co.local.red = ((((i * 65535) / maxent) >> shift)
156                                         * 65535) / lim;
157            pmap->red[i].co.local.green = pmap->red[i].co.local.red;
158            pmap->red[i].co.local.blue = pmap->red[i].co.local.red;
159        }
160    }
161    return TRUE;
162}
163
164/* When simulating DirectColor on PseudoColor hardware, multiple
165   entries of the colormap must be updated
166 */
167
168#define AddElement(mask) { \
169    pixel = red | green | blue; \
170    for (i = 0; i < nresult; i++) \
171  	if (outdefs[i].pixel == pixel) \
172    	    break; \
173    if (i == nresult) \
174    { \
175   	nresult++; \
176	outdefs[i].pixel = pixel; \
177	outdefs[i].flags = 0; \
178    } \
179    outdefs[i].flags |= (mask); \
180    outdefs[i].red = pmap->red[red >> pVisual->offsetRed].co.local.red; \
181    outdefs[i].green = pmap->green[green >> pVisual->offsetGreen].co.local.green; \
182    outdefs[i].blue = pmap->blue[blue >> pVisual->offsetBlue].co.local.blue; \
183}
184
185int
186miExpandDirectColors(ColormapPtr pmap, int ndef, xColorItem * indefs,
187                     xColorItem * outdefs)
188{
189    int red, green, blue;
190    int maxred, maxgreen, maxblue;
191    int stepred, stepgreen, stepblue;
192    VisualPtr pVisual;
193    int pixel;
194    int nresult;
195    int i;
196
197    pVisual = pmap->pVisual;
198
199    stepred = 1 << pVisual->offsetRed;
200    stepgreen = 1 << pVisual->offsetGreen;
201    stepblue = 1 << pVisual->offsetBlue;
202    maxred = pVisual->redMask;
203    maxgreen = pVisual->greenMask;
204    maxblue = pVisual->blueMask;
205    nresult = 0;
206    for (; ndef--; indefs++) {
207        if (indefs->flags & DoRed) {
208            red = indefs->pixel & pVisual->redMask;
209            for (green = 0; green <= maxgreen; green += stepgreen) {
210                for (blue = 0; blue <= maxblue; blue += stepblue) {
211                    AddElement(DoRed)
212                }
213            }
214        }
215        if (indefs->flags & DoGreen) {
216            green = indefs->pixel & pVisual->greenMask;
217            for (red = 0; red <= maxred; red += stepred) {
218                for (blue = 0; blue <= maxblue; blue += stepblue) {
219                    AddElement(DoGreen)
220                }
221            }
222        }
223        if (indefs->flags & DoBlue) {
224            blue = indefs->pixel & pVisual->blueMask;
225            for (red = 0; red <= maxred; red += stepred) {
226                for (green = 0; green <= maxgreen; green += stepgreen) {
227                    AddElement(DoBlue)
228                }
229            }
230        }
231    }
232    return nresult;
233}
234
235Bool
236miCreateDefColormap(ScreenPtr pScreen)
237{
238    unsigned short zero = 0, ones = 0xFFFF;
239    Pixel wp, bp;
240    VisualPtr pVisual;
241    ColormapPtr cmap;
242    int alloctype;
243
244    if (!dixRegisterPrivateKey(&micmapScrPrivateKeyRec, PRIVATE_SCREEN, 0))
245        return FALSE;
246
247    for (pVisual = pScreen->visuals;
248         pVisual->vid != pScreen->rootVisual; pVisual++);
249
250    if (pScreen->rootDepth == 1 || (pVisual->class & DynamicClass))
251        alloctype = AllocNone;
252    else
253        alloctype = AllocAll;
254
255    if (CreateColormap(pScreen->defColormap, pScreen, pVisual, &cmap,
256                       alloctype, 0) != Success)
257        return FALSE;
258
259    if (pScreen->rootDepth > 1) {
260        wp = pScreen->whitePixel;
261        bp = pScreen->blackPixel;
262        if ((AllocColor(cmap, &ones, &ones, &ones, &wp, 0) !=
263             Success) ||
264            (AllocColor(cmap, &zero, &zero, &zero, &bp, 0) != Success))
265            return FALSE;
266        pScreen->whitePixel = wp;
267        pScreen->blackPixel = bp;
268    }
269
270    (*pScreen->InstallColormap) (cmap);
271    return TRUE;
272}
273
274/*
275 * Default true color bitmasks, should be overridden by
276 * driver
277 */
278
279#define _RZ(d) ((d + 2) / 3)
280#define _RS(d) 0
281#define _RM(d) ((1U << _RZ(d)) - 1)
282#define _GZ(d) ((d - _RZ(d) + 1) / 2)
283#define _GS(d) _RZ(d)
284#define _GM(d) (((1U << _GZ(d)) - 1) << _GS(d))
285#define _BZ(d) (d - _RZ(d) - _GZ(d))
286#define _BS(d) (_RZ(d) + _GZ(d))
287#define _BM(d) (((1U << _BZ(d)) - 1) << _BS(d))
288#define _CE(d) (1U << _RZ(d))
289
290typedef struct _miVisuals {
291    struct _miVisuals *next;
292    int depth;
293    int bitsPerRGB;
294    int visuals;
295    int count;
296    int preferredCVC;
297    Pixel redMask, greenMask, blueMask;
298} miVisualsRec, *miVisualsPtr;
299
300static int miVisualPriority[] = {
301    PseudoColor, GrayScale, StaticColor, TrueColor, DirectColor, StaticGray
302};
303
304#define NUM_PRIORITY	6
305
306static miVisualsPtr miVisuals;
307
308void
309miClearVisualTypes(void)
310{
311    miVisualsPtr v;
312
313    while ((v = miVisuals)) {
314        miVisuals = v->next;
315        free(v);
316    }
317}
318
319Bool
320miSetVisualTypesAndMasks(int depth, int visuals, int bitsPerRGB,
321                         int preferredCVC,
322                         Pixel redMask, Pixel greenMask, Pixel blueMask)
323{
324    miVisualsPtr new, *prev, v;
325    int count;
326
327    new = malloc(sizeof *new);
328    if (!new)
329        return FALSE;
330    if (!redMask || !greenMask || !blueMask) {
331        redMask = _RM(depth);
332        greenMask = _GM(depth);
333        blueMask = _BM(depth);
334    }
335    new->next = 0;
336    new->depth = depth;
337    new->visuals = visuals;
338    new->bitsPerRGB = bitsPerRGB;
339    new->preferredCVC = preferredCVC;
340    new->redMask = redMask;
341    new->greenMask = greenMask;
342    new->blueMask = blueMask;
343    count = (visuals >> 1) & 033333333333;
344    count = visuals - count - ((count >> 1) & 033333333333);
345    count = (((count + (count >> 3)) & 030707070707) % 077);    /* HAKMEM 169 */
346    new->count = count;
347    for (prev = &miVisuals; (v = *prev); prev = &v->next);
348    *prev = new;
349    return TRUE;
350}
351
352Bool
353miSetVisualTypes(int depth, int visuals, int bitsPerRGB, int preferredCVC)
354{
355    return miSetVisualTypesAndMasks(depth, visuals, bitsPerRGB,
356                                    preferredCVC, 0, 0, 0);
357}
358
359int
360miGetDefaultVisualMask(int depth)
361{
362    if (depth > MAX_PSEUDO_DEPTH)
363        return LARGE_VISUALS;
364    else if (depth >= MIN_TRUE_DEPTH)
365        return ALL_VISUALS;
366    else if (depth == 1)
367        return StaticGrayMask;
368    else
369        return SMALL_VISUALS;
370}
371
372static Bool
373miVisualTypesSet(int depth)
374{
375    miVisualsPtr visuals;
376
377    for (visuals = miVisuals; visuals; visuals = visuals->next)
378        if (visuals->depth == depth)
379            return TRUE;
380    return FALSE;
381}
382
383Bool
384miSetPixmapDepths(void)
385{
386    int d, f;
387
388    /* Add any unlisted depths from the pixmap formats */
389    for (f = 0; f < screenInfo.numPixmapFormats; f++) {
390        d = screenInfo.formats[f].depth;
391        if (!miVisualTypesSet(d)) {
392            if (!miSetVisualTypes(d, 0, 0, -1))
393                return FALSE;
394        }
395    }
396    return TRUE;
397}
398
399/*
400 * Distance to least significant one bit
401 */
402static int
403maskShift(Pixel p)
404{
405    int s;
406
407    if (!p)
408        return 0;
409    s = 0;
410    while (!(p & 1)) {
411        s++;
412        p >>= 1;
413    }
414    return s;
415}
416
417/*
418 * Given a list of formats for a screen, create a list
419 * of visuals and depths for the screen which correspond to
420 * the set which can be used with this version of cfb.
421 */
422
423Bool
424miInitVisuals(VisualPtr * visualp, DepthPtr * depthp, int *nvisualp,
425              int *ndepthp, int *rootDepthp, VisualID * defaultVisp,
426              unsigned long sizes, int bitsPerRGB, int preferredVis)
427{
428    int i, j = 0, k;
429    VisualPtr visual;
430    DepthPtr depth;
431    VisualID *vid;
432    int d, b;
433    int f;
434    int ndepth, nvisual;
435    int nvtype;
436    int vtype;
437    miVisualsPtr visuals, nextVisuals;
438    int *preferredCVCs, *prefp;
439    int first_depth;
440
441    /* none specified, we'll guess from pixmap formats */
442    if (!miVisuals) {
443        for (f = 0; f < screenInfo.numPixmapFormats; f++) {
444            d = screenInfo.formats[f].depth;
445            b = screenInfo.formats[f].bitsPerPixel;
446            if (sizes & (1 << (b - 1)))
447                vtype = miGetDefaultVisualMask(d);
448            else
449                vtype = 0;
450            if (!miSetVisualTypes(d, vtype, bitsPerRGB, -1))
451                return FALSE;
452        }
453    }
454    nvisual = 0;
455    ndepth = 0;
456    for (visuals = miVisuals; visuals; visuals = nextVisuals) {
457        nextVisuals = visuals->next;
458        ndepth++;
459        nvisual += visuals->count;
460    }
461    depth = xallocarray(ndepth, sizeof(DepthRec));
462    visual = xallocarray(nvisual, sizeof(VisualRec));
463    preferredCVCs = xallocarray(ndepth, sizeof(int));
464    if (!depth || !visual || !preferredCVCs) {
465        free(depth);
466        free(visual);
467        free(preferredCVCs);
468        return FALSE;
469    }
470    *depthp = depth;
471    *visualp = visual;
472    *ndepthp = ndepth;
473    *nvisualp = nvisual;
474    prefp = preferredCVCs;
475    for (visuals = miVisuals; visuals; visuals = nextVisuals) {
476        nextVisuals = visuals->next;
477        d = visuals->depth;
478        vtype = visuals->visuals;
479        nvtype = visuals->count;
480        *prefp = visuals->preferredCVC;
481        prefp++;
482        vid = NULL;
483        if (nvtype) {
484            vid = xallocarray(nvtype, sizeof(VisualID));
485            if (!vid) {
486                free(depth);
487                free(visual);
488                free(preferredCVCs);
489                return FALSE;
490            }
491        }
492        depth->depth = d;
493        depth->numVids = nvtype;
494        depth->vids = vid;
495        depth++;
496        for (i = 0; i < NUM_PRIORITY; i++) {
497            if (!(vtype & (1 << miVisualPriority[i])))
498                continue;
499            visual->class = miVisualPriority[i];
500            visual->bitsPerRGBValue = visuals->bitsPerRGB;
501            visual->ColormapEntries = 1 << d;
502            visual->nplanes = d;
503            visual->vid = *vid = FakeClientID(0);
504            switch (visual->class) {
505            case PseudoColor:
506            case GrayScale:
507            case StaticGray:
508                visual->redMask = 0;
509                visual->greenMask = 0;
510                visual->blueMask = 0;
511                visual->offsetRed = 0;
512                visual->offsetGreen = 0;
513                visual->offsetBlue = 0;
514                break;
515            case DirectColor:
516            case TrueColor:
517                visual->ColormapEntries = _CE(d);
518                /* fall through */
519            case StaticColor:
520                visual->redMask = visuals->redMask;
521                visual->greenMask = visuals->greenMask;
522                visual->blueMask = visuals->blueMask;
523                visual->offsetRed = maskShift(visuals->redMask);
524                visual->offsetGreen = maskShift(visuals->greenMask);
525                visual->offsetBlue = maskShift(visuals->blueMask);
526            }
527            vid++;
528            visual++;
529        }
530        free(visuals);
531    }
532    miVisuals = NULL;
533    visual = *visualp;
534    depth = *depthp;
535
536    /*
537     * if we did not supplyied by a preferred visual class
538     * check if there is a preferred class in one of the depth
539     * structures - if there is, we want to start looking for the
540     * default visual/depth from that depth.
541     */
542    first_depth = 0;
543    if (preferredVis < 0 && defaultColorVisualClass < 0) {
544        for (i = 0; i < ndepth; i++) {
545            if (preferredCVCs[i] >= 0) {
546                first_depth = i;
547                break;
548            }
549        }
550    }
551
552    for (i = first_depth; i < ndepth; i++) {
553        int prefColorVisualClass = -1;
554
555        if (defaultColorVisualClass >= 0)
556            prefColorVisualClass = defaultColorVisualClass;
557        else if (preferredVis >= 0)
558            prefColorVisualClass = preferredVis;
559        else if (preferredCVCs[i] >= 0)
560            prefColorVisualClass = preferredCVCs[i];
561
562        if (*rootDepthp && *rootDepthp != depth[i].depth)
563            continue;
564
565        for (j = 0; j < depth[i].numVids; j++) {
566            for (k = 0; k < nvisual; k++)
567                if (visual[k].vid == depth[i].vids[j])
568                    break;
569            if (k == nvisual)
570                continue;
571            if (prefColorVisualClass < 0 ||
572                visual[k].class == prefColorVisualClass)
573                break;
574        }
575        if (j != depth[i].numVids)
576            break;
577    }
578    if (i == ndepth) {
579        i = 0;
580        j = 0;
581    }
582    *rootDepthp = depth[i].depth;
583    *defaultVisp = depth[i].vids[j];
584    free(preferredCVCs);
585
586    return TRUE;
587}
588