Edit

IABSD.fr/xenocara/xserver/render/miindex.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2016-05-29 12:02:34
    Hash : e927c03e
    Message : Update to xserver 1.18.3. Tested by shadchin@ and naddy@. Note that indirect GLX is now disbled by default.

  • xserver/render/miindex.c
  • /*
     *
     * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
     *
     * Permission to use, copy, modify, distribute, and sell this software and its
     * documentation for any purpose is hereby granted without fee, provided that
     * the above copyright notice appear in all copies and that both that
     * copyright notice and this permission notice appear in supporting
     * documentation, and that the name of Keith Packard not be used in
     * advertising or publicity pertaining to distribution of the software without
     * specific, written prior permission.  Keith Packard makes no
     * representations about the suitability of this software for any purpose.  It
     * is provided "as is" without express or implied warranty.
     *
     * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
     * PERFORMANCE OF THIS SOFTWARE.
     */
    
    #ifdef HAVE_DIX_CONFIG_H
    #include <dix-config.h>
    #endif
    
    #ifndef _MIINDEX_H_
    #define _MIINDEX_H_
    
    #include "scrnintstr.h"
    #include "gcstruct.h"
    #include "pixmapstr.h"
    #include "windowstr.h"
    #include "mi.h"
    #include "picturestr.h"
    #include "mipict.h"
    #include "colormapst.h"
    
    #define NUM_CUBE_LEVELS	4
    #define NUM_GRAY_LEVELS	13
    
    static Bool
    miBuildRenderColormap(ColormapPtr pColormap, Pixel * pixels, int *nump)
    {
        int r, g, b;
        unsigned short red, green, blue;
        Pixel pixel;
        Bool used[MI_MAX_INDEXED];
        int needed;
        int policy;
        int cube, gray;
        int i, n;
    
        if (pColormap->mid != pColormap->pScreen->defColormap) {
            policy = PictureCmapPolicyAll;
        }
        else {
            int avail = pColormap->pVisual->ColormapEntries;
    
            policy = PictureCmapPolicy;
            if (policy == PictureCmapPolicyDefault) {
                if (avail >= 256 &&
                    (pColormap->pVisual->class | DynamicClass) == PseudoColor)
                    policy = PictureCmapPolicyColor;
                else if (avail >= 64)
                    policy = PictureCmapPolicyGray;
                else
                    policy = PictureCmapPolicyMono;
            }
        }
        /*
         * Make sure enough cells are free for the chosen policy
         */
        for (;;) {
            switch (policy) {
            case PictureCmapPolicyAll:
                needed = 0;
                break;
            case PictureCmapPolicyColor:
                needed = 71;
                break;
            case PictureCmapPolicyGray:
                needed = 11;
                break;
            case PictureCmapPolicyMono:
            default:
                needed = 0;
                break;
            }
            if (needed <= pColormap->freeRed)
                break;
            policy--;
        }
    
        /*
         * Compute size of cube and gray ramps
         */
        cube = gray = 0;
        switch (policy) {
        case PictureCmapPolicyAll:
            /*
             * Allocate as big a cube as possible
             */
            if ((pColormap->pVisual->class | DynamicClass) == PseudoColor) {
                for (cube = 1;
                     cube * cube * cube < pColormap->pVisual->ColormapEntries;
                     cube++);
                cube--;
                if (cube == 1)
                    cube = 0;
            }
            else
                cube = 0;
            /*
             * Figure out how many gray levels to use so that they
             * line up neatly with the cube
             */
            if (cube) {
                needed = pColormap->pVisual->ColormapEntries - (cube * cube * cube);
                /* levels to fill in with */
                gray = needed / (cube - 1);
                /* total levels */
                gray = (gray + 1) * (cube - 1) + 1;
            }
            else
                gray = pColormap->pVisual->ColormapEntries;
            break;
    
        case PictureCmapPolicyColor:
            cube = NUM_CUBE_LEVELS;
            /* fall through ... */
        case PictureCmapPolicyGray:
            gray = NUM_GRAY_LEVELS;
            break;
        case PictureCmapPolicyMono:
        default:
            gray = 2;
            break;
        }
    
        memset(used, '\0', pColormap->pVisual->ColormapEntries * sizeof(Bool));
        for (r = 0; r < cube; r++)
            for (g = 0; g < cube; g++)
                for (b = 0; b < cube; b++) {
                    pixel = 0;
                    red = (r * 65535 + (cube - 1) / 2) / (cube - 1);
                    green = (g * 65535 + (cube - 1) / 2) / (cube - 1);
                    blue = (b * 65535 + (cube - 1) / 2) / (cube - 1);
                    if (AllocColor(pColormap, &red, &green,
                                   &blue, &pixel, 0) != Success)
                        return FALSE;
                    used[pixel] = TRUE;
                }
        for (g = 0; g < gray; g++) {
            pixel = 0;
            red = green = blue = (g * 65535 + (gray - 1) / 2) / (gray - 1);
            if (AllocColor(pColormap, &red, &green, &blue, &pixel, 0) != Success)
                return FALSE;
            used[pixel] = TRUE;
        }
        n = 0;
        for (i = 0; i < pColormap->pVisual->ColormapEntries; i++)
            if (used[i])
                pixels[n++] = i;
    
        *nump = n;
    
        return TRUE;
    }
    
    /* 0 <= red, green, blue < 32 */
    static Pixel
    FindBestColor(miIndexedPtr pIndexed, Pixel * pixels, int num,
                  int red, int green, int blue)
    {
        Pixel best = pixels[0];
        int bestDist = 1 << 30;
        int dist;
        int dr, dg, db;
    
        while (num--) {
            Pixel pixel = *pixels++;
            CARD32 v = pIndexed->rgba[pixel];
    
            dr = ((v >> 19) & 0x1f);
            dg = ((v >> 11) & 0x1f);
            db = ((v >> 3) & 0x1f);
            dr = dr - red;
            dg = dg - green;
            db = db - blue;
            dist = dr * dr + dg * dg + db * db;
            if (dist < bestDist) {
                bestDist = dist;
                best = pixel;
            }
        }
        return best;
    }
    
    /* 0 <= gray < 32768 */
    static Pixel
    FindBestGray(miIndexedPtr pIndexed, Pixel * pixels, int num, int gray)
    {
        Pixel best = pixels[0];
        int bestDist = 1 << 30;
        int dist;
        int dr;
        int r;
    
        while (num--) {
            Pixel pixel = *pixels++;
            CARD32 v = pIndexed->rgba[pixel];
    
            r = v & 0xff;
            r = r | (r << 8);
            dr = gray - (r >> 1);
            dist = dr * dr;
            if (dist < bestDist) {
                bestDist = dist;
                best = pixel;
            }
        }
        return best;
    }
    
    Bool
    miInitIndexed(ScreenPtr pScreen, PictFormatPtr pFormat)
    {
        ColormapPtr pColormap = pFormat->index.pColormap;
        VisualPtr pVisual = pColormap->pVisual;
        miIndexedPtr pIndexed;
        Pixel pixels[MI_MAX_INDEXED];
        xrgb rgb[MI_MAX_INDEXED];
        int num;
        int i;
        Pixel p, r, g, b;
    
        if (pVisual->ColormapEntries > MI_MAX_INDEXED)
            return FALSE;
    
        if (pVisual->class & DynamicClass) {
            if (!miBuildRenderColormap(pColormap, pixels, &num))
                return FALSE;
        }
        else {
            num = pVisual->ColormapEntries;
            for (p = 0; p < num; p++)
                pixels[p] = p;
        }
    
        pIndexed = malloc(sizeof(miIndexedRec));
        if (!pIndexed)
            return FALSE;
    
        pFormat->index.nvalues = num;
        pFormat->index.pValues = xallocarray(num, sizeof(xIndexValue));
        if (!pFormat->index.pValues) {
            free(pIndexed);
            return FALSE;
        }
    
        /*
         * Build mapping from pixel value to ARGB
         */
        QueryColors(pColormap, num, pixels, rgb, serverClient);
        for (i = 0; i < num; i++) {
            p = pixels[i];
            pFormat->index.pValues[i].pixel = p;
            pFormat->index.pValues[i].red = rgb[i].red;
            pFormat->index.pValues[i].green = rgb[i].green;
            pFormat->index.pValues[i].blue = rgb[i].blue;
            pFormat->index.pValues[i].alpha = 0xffff;
            pIndexed->rgba[p] = (0xff000000 |
                                 ((rgb[i].red & 0xff00) << 8) |
                                 ((rgb[i].green & 0xff00)) |
                                 ((rgb[i].blue & 0xff00) >> 8));
        }
    
        /*
         * Build mapping from RGB to pixel value.  This could probably be
         * done a bit quicker...
         */
        switch (pVisual->class | DynamicClass) {
        case GrayScale:
            pIndexed->color = FALSE;
            for (r = 0; r < 32768; r++)
                pIndexed->ent[r] = FindBestGray(pIndexed, pixels, num, r);
            break;
        case PseudoColor:
            pIndexed->color = TRUE;
            p = 0;
            for (r = 0; r < 32; r++)
                for (g = 0; g < 32; g++)
                    for (b = 0; b < 32; b++) {
                        pIndexed->ent[p] = FindBestColor(pIndexed, pixels, num,
                                                         r, g, b);
                        p++;
                    }
            break;
        }
        pFormat->index.devPrivate = pIndexed;
        return TRUE;
    }
    
    void
    miCloseIndexed(ScreenPtr pScreen, PictFormatPtr pFormat)
    {
        free(pFormat->index.devPrivate);
        pFormat->index.devPrivate = NULL;
        free(pFormat->index.pValues);
        pFormat->index.pValues = NULL;
    }
    
    void
    miUpdateIndexed(ScreenPtr pScreen,
                    PictFormatPtr pFormat, int ndef, xColorItem * pdef)
    {
        miIndexedPtr pIndexed = pFormat->index.devPrivate;
    
        if (pIndexed) {
            while (ndef--) {
                pIndexed->rgba[pdef->pixel] = (0xff000000 |
                                               ((pdef->red & 0xff00) << 8) |
                                               ((pdef->green & 0xff00)) |
                                               ((pdef->blue & 0xff00) >> 8));
                pdef++;
            }
        }
    }
    
    #endif                          /* _MIINDEX_H_ */