[PATCH] hw: Fix visual colormap_size mixup causing "missing" visuals.

Alex Orange crazycasta at gmail.com
Sun Nov 30 04:18:41 PST 2014


Likely fixes: https://bugs.freedesktop.org/show_bug.cgi?id=24642

dmx uses fb to handle many action. As such is uses fbScreenInit. The
trouble is that fbScreenInit uses mi to generate the visuals. mi has
trouble with 32-bit (rgba) depths.  It tries to treat these depths as
10-bits per pixels. This results in colormap_sizes in the visuals being
2048 instead of 256. Also, the comments in micmap.c about the macros,
_CE is the relevant one, suggest that these numbers may be driver
defined. To this end, this patch simply copies the visuals into the
visuals and depths structs instead of trying to coax mi into creating
the right visuals. The code was mostly just taken from xnest with
changes since dmx uses fb. The result depends on miScreenInit simply
stuffing visuals in the screen and not doing anything more with them. In
the future perhaps fbScreenInit can take an optional set of visuals to
use instead of calling miInitVisuals.

Signed-off-by: Alex Orange <crazycasta at gmail.com>
Tested-by: Alex Orange <crazycasta at gmail.com>
---
 hw/dmx/dmxscrinit.c | 212 +++++++++++++++++++++++++++++++++++++++++++---------
 hw/dmx/dmxscrinit.h |   5 ++
 2 files changed, 182 insertions(+), 35 deletions(-)

diff --git a/hw/dmx/dmxscrinit.c b/hw/dmx/dmxscrinit.c
index 963d3a9..d681d85 100644
--- a/hw/dmx/dmxscrinit.c
+++ b/hw/dmx/dmxscrinit.c
@@ -54,9 +54,12 @@
 
 #include "dmxpict.h"
 
-#include "fb.h"
+#include <X11/X.h>
+#include "mi.h"
 #include "mipointer.h"
 #include "micmap.h"
+#include "resource.h"
+#include "fb.h"
 
 extern Bool dmxCloseScreen(ScreenPtr pScreen);
 static Bool dmxSaveScreen(ScreenPtr pScreen, int what);
@@ -172,12 +175,28 @@ dmxBEScreenInit(ScreenPtr pScreen)
 	    }
 }
 
+static int
+offset(unsigned long mask)
+{
+    int count;
+
+    for (count = 0; !(mask & 1) && count < 32; count++)
+        mask >>= 1;
+
+    return count;
+}
+
 /** Initialize screen number \a pScreen->myNum. */
 Bool
 dmxScreenInit(ScreenPtr pScreen, int argc, char *argv[])
 {
     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
-    int i, j;
+    int i, j, depthIndex;
+    VisualPtr visuals;
+    DepthPtr depths;
+    int numVisuals, numDepths;
+    VisualID defaultBEVisual, defaultVisual;
+    int rootDepth;
 
     if (!dixRegisterPrivateKey(&dmxScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
         return FALSE;
@@ -202,49 +221,172 @@ dmxScreenInit(ScreenPtr pScreen, int argc, char *argv[])
     if (!dmxInitPixmap(pScreen))
 	return FALSE;
 
-    /*
-     * Initalise the visual types.  miSetVisualTypesAndMasks() requires
-     * that all of the types for each depth be collected together.  It's
-     * intended for slightly different usage to what we would like here.
-     * Maybe a miAddVisualTypeAndMask() function will be added to make
-     * things easier here.
-     */
-    for (i = 0; i < dmxScreen->beNumDepths; i++) {
-        int depth;
-        int visuals = 0;
-        int bitsPerRgb = 0;
-        int preferredClass = -1;
-        Pixel redMask = 0;
-        Pixel greenMask = 0;
-        Pixel blueMask = 0;
-
-        depth = dmxScreen->beDepths[i];
-        for (j = 0; j < dmxScreen->beNumVisuals; j++) {
-            XVisualInfo *vi;
-
-            vi = &dmxScreen->beVisuals[j];
-            if (vi->depth == depth) {
-                /* Assume the masks are all the same. */
-                visuals |= (1 << vi->class);
-                bitsPerRgb = vi->bits_per_rgb;
-                redMask = vi->red_mask;
-                greenMask = vi->green_mask;
-                blueMask = vi->blue_mask;
-                if (j == dmxScreen->beDefVisualIndex) {
-                    preferredClass = vi->class;
-                }
+    visuals = (VisualPtr) malloc(dmxScreen->beNumVisuals * sizeof(VisualRec));
+    numVisuals = 0;
+
+    depths = (DepthPtr) malloc(MAXDEPTH * sizeof(DepthRec));
+    depths[0].depth = 1;
+    depths[0].numVids = 0;
+    depths[0].vids = (VisualID *) malloc(MAXVISUALSPERDEPTH * sizeof(VisualID));
+    numDepths = 1;
+
+    defaultBEVisual = XVisualIDFromVisual(DefaultVisual(dmxScreen->beDisplay,
+                                                        DefaultScreen
+                                                        (dmxScreen->beDisplay)));
+    rootDepth = UNDEFINED;
+    defaultVisual = UNDEFINED;
+
+    for (i = 0; i < dmxScreen->beNumVisuals; i++) {
+        visuals[numVisuals].class = dmxScreen->beVisuals[i].class;
+        visuals[numVisuals].bitsPerRGBValue =
+            dmxScreen->beVisuals[i].bits_per_rgb;
+        visuals[numVisuals].ColormapEntries =
+            dmxScreen->beVisuals[i].colormap_size;
+        visuals[numVisuals].nplanes = dmxScreen->beVisuals[i].depth;
+        visuals[numVisuals].redMask = dmxScreen->beVisuals[i].red_mask;
+        visuals[numVisuals].greenMask = dmxScreen->beVisuals[i].green_mask;
+        visuals[numVisuals].blueMask = dmxScreen->beVisuals[i].blue_mask;
+        visuals[numVisuals].offsetRed =
+            offset(dmxScreen->beVisuals[i].red_mask);
+        visuals[numVisuals].offsetGreen =
+            offset(dmxScreen->beVisuals[i].green_mask);
+        visuals[numVisuals].offsetBlue =
+            offset(dmxScreen->beVisuals[i].blue_mask);
+
+        /* Check for and remove duplicates. */
+        for (j = 0; j < numVisuals; j++) {
+            if (visuals[numVisuals].class == visuals[j].class &&
+                visuals[numVisuals].bitsPerRGBValue ==
+                visuals[j].bitsPerRGBValue &&
+                visuals[numVisuals].ColormapEntries ==
+                visuals[j].ColormapEntries &&
+                visuals[numVisuals].nplanes == visuals[j].nplanes &&
+                visuals[numVisuals].redMask == visuals[j].redMask &&
+                visuals[numVisuals].greenMask == visuals[j].greenMask &&
+                visuals[numVisuals].blueMask == visuals[j].blueMask &&
+                visuals[numVisuals].offsetRed == visuals[j].offsetRed &&
+                visuals[numVisuals].offsetGreen == visuals[j].offsetGreen &&
+                visuals[numVisuals].offsetBlue == visuals[j].offsetBlue)
+                break;
+        }
+        if (j < numVisuals)
+            break;
+
+        visuals[numVisuals].vid = FakeClientID(0);
+
+        depthIndex = UNDEFINED;
+        for (j = 0; j < numDepths; j++)
+            if (depths[j].depth == dmxScreen->beVisuals[i].depth) {
+                depthIndex = j;
+                break;
             }
+
+        if (depthIndex == UNDEFINED) {
+            depthIndex = numDepths;
+            depths[depthIndex].depth = dmxScreen->beVisuals[i].depth;
+            depths[depthIndex].numVids = 0;
+            depths[depthIndex].vids =
+                (VisualID *) malloc(MAXVISUALSPERDEPTH * sizeof(VisualID));
+            numDepths++;
         }
-        miSetVisualTypesAndMasks(depth, visuals, bitsPerRgb, preferredClass,
-                                 redMask, greenMask, blueMask);
+        if (depths[depthIndex].numVids >= MAXVISUALSPERDEPTH) {
+            FatalError("Visual table overflow");
+        }
+        depths[depthIndex].vids[depths[depthIndex].numVids] =
+            visuals[numVisuals].vid;
+        depths[depthIndex].numVids++;
+
+        if (dmxScreen->beVisuals[i].visualid == defaultBEVisual) {
+            rootDepth = visuals[numVisuals].nplanes;
+            defaultVisual = visuals[numVisuals].vid;
+        }
+
+        numVisuals++;
     }
+    visuals = (VisualPtr) realloc(visuals, numVisuals * sizeof(VisualRec));
 
+    if (rootDepth == UNDEFINED) {
+        rootDepth = visuals[0].nplanes;
+    }
+    if (defaultVisual == UNDEFINED) {
+        defaultVisual = visuals[0].vid;
+    }
+
+    /* myNum */
+    /* id */
+//    miScreenInit(pScreen,
+//                 NULL,
+//                 dmxScreen->scrnWidth,
+//                 dmxScreen->scrnHeight,
+//                 dmxScreen->beXDPI,
+//                 dmxScreen->beYDPI,
+//                 dmxScreen->scrnWidth,
+//                 rootDepth,
+//                 numDepths,
+//                 depths,
+//                 defaultVisual, /* root visual */
+//                 numVisuals,
+//                 visuals);
+                 
+//    /*
+//     * Initalise the visual types.  miSetVisualTypesAndMasks() requires
+//     * that all of the types for each depth be collected together.  It's
+//     * intended for slightly different usage to what we would like here.
+//     * Maybe a miAddVisualTypeAndMask() function will be added to make
+//     * things easier here.
+//     */
+//    for (i = 0; i < dmxScreen->beNumDepths; i++) {
+//        int depth;
+//        int visuals = 0;
+//        int bitsPerRgb = 0;
+//        int preferredClass = -1;
+//        Pixel redMask = 0;
+//        Pixel greenMask = 0;
+//        Pixel blueMask = 0;
+//
+//        depth = dmxScreen->beDepths[i];
+//        for (j = 0; j < dmxScreen->beNumVisuals; j++) {
+//            XVisualInfo *vi;
+//
+//            vi = &dmxScreen->beVisuals[j];
+//            if (vi->depth == depth) {
+//                /* Assume the masks are all the same. */
+//                visuals |= (1 << vi->class);
+//                bitsPerRgb = vi->bits_per_rgb;
+//                redMask = vi->red_mask;
+//                greenMask = vi->green_mask;
+//                blueMask = vi->blue_mask;
+//                if (j == dmxScreen->beDefVisualIndex) {
+//                    preferredClass = vi->class;
+//                }
+//            }
+//        }
+//        miSetVisualTypesAndMasks(depth, visuals, bitsPerRgb, preferredClass,
+//                                 redMask, greenMask, blueMask);
+//    }
+//
     fbScreenInit(pScreen,
                  NULL,
                  dmxScreen->scrnWidth,
                  dmxScreen->scrnHeight,
                  dmxScreen->beXDPI,
                  dmxScreen->beXDPI, dmxScreen->scrnWidth, dmxScreen->beBPP);
+
+    // fbScreenInit calls fbInitVisuals which makes uncontrollable colormap
+    // sizes. The following fixes this (pending a better method).
+    for (i = 0; i < pScreen->numDepths; i++) {
+        free(pScreen->allowedDepths[i].vids);
+    }
+    free(pScreen->allowedDepths);
+    free(pScreen->visuals);
+
+    pScreen->visuals = visuals;
+    pScreen->numVisuals = numVisuals;
+    pScreen->rootVisual = defaultVisual;
+    pScreen->allowedDepths = depths;
+    pScreen->numDepths = numDepths;
+    pScreen->rootDepth = rootDepth;
+
     (void) dmxPictureInit(pScreen, 0, 0);
 
     /* Not yet... */
diff --git a/hw/dmx/dmxscrinit.h b/hw/dmx/dmxscrinit.h
index 9fe9c98..23d2f62 100644
--- a/hw/dmx/dmxscrinit.h
+++ b/hw/dmx/dmxscrinit.h
@@ -40,6 +40,11 @@
 
 #include "scrnintstr.h"
 
+#define UNDEFINED -1
+
+#define MAXDEPTH 32
+#define MAXVISUALSPERDEPTH 256
+
 extern Bool dmxScreenInit(ScreenPtr pScreen, int argc, char *argv[]);
 
 extern void dmxBEScreenInit(ScreenPtr pScreen);
-- 
1.8.5.5



More information about the xorg-devel mailing list