[comp.windows.x] DirectColor pre- bug report

spencer@eecs.umich.edu (Spencer W. Thomas) (05/16/91)

I'm running into very strange behavior from 8-bit DirectColor visuals.
(Test program enclosed below.)  Synopsis of problem: DirectColor
colormap entries are not loaded correctly, and the map is not
reinstalled correctly after it has been uninstalled.  Some servers
crash.

Has anyone seen this?  Is there a fix? (wait for R5?)  If you've got a
different configuration from the ones described below, can you try my
program and describe the results?  Thanks.

The test procedure is
	1. Create a DirectColor colormap, and a window that uses it.
	2. Install the colormap (by window manager or program, the result
			is the same)
	3. Call XAllocColorPlanes to get 2 red, 2 green, and 2 blue
		planes.
	4. Load values into the colormap (I'm trying to create a 2x2x2
		color cube, so I load (0,0,0), (1,1,1), (2,2,2), and
		(3,3,3) with "gray" values.)  According to the
		documentation, this should cause all 64 entries to be
		filled.)
	5. Uninstall the colormap.
	6. Install the colormap.

Test results.  Most servers work fine in PseudoColor, but those with
8-bit DirectColor visuals fail in various ways.
DEC 3100, 8-bit color, running MIT X11R4 (I'm not sure which fixes):
	Step 2 "blacks out" only the first 8 entries of the colormap.
	Step 4 loads exactly 4 colormap entries.  (The interesting
		thing is that the right thing happens if the visual is
		PseudoColor instead of DirectColor.)
	Step 6 reloads only the first 8 entries of the colormap with
		a 4-entry red ramp and 4 blacks.
	More curious behavior: with a GrayScale visual, this still
		creates a COLORED map.

DEC 5000-200, 24-bit color, running DECwindows
	Works fine. (24-bit DirectColor visual)

Sparcstation 1, 8-bit color, MIT X11R4
	Step 4 crashes the server.  (It sometimes survives to step 6?)

IBM RS-6000, 8-bit color, IBM X11R3
	Step 2 or 3 crashes the server. (Server has PseudoColor only.)

Mac IIx, 8-bit color, Mac X 1.1
	Step 4 loads 4 "gray" colormap cells.  
	Steps 5 and 6 have no effect.

Finally, the program.  You might want to run it with no window manager
"in the way", as it does it's own XInstallColormap/XUninstallColormap
(to keep the exact time and sequence of installation controlled).
Compile with 
	cc -o xcmapbug xcmapbug.c -lX11

Usage:
xcmapbug [-v] [-l] [-d display] [visual]
	-v	Verbose mode.  Prints out colormap contents.
	-l	Explicitly loads 64 entries instead of the 4 that
		"should work".
	-d display	Display name.
	visual	Type of visual.  Default is PseudoColor.  You must
		type the full name of the visual type, but case is
		irrelevant.  
I ran
	xcmapbug -v directcolor

=S

: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
all=FALSE
if [ $1x = -ax ]; then
	all=TRUE
fi
/bin/echo 'Extracting xcmapbug.c'
sed 's/^X//' <<'//go.sysin dd *' >xcmapbug.c
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <ctype.h>
X/* Make Sys V macros map to BSD macros */
#ifndef _tolower
#define _tolower tolower
#define _toupper toupper
#endif

#define COUNT_OF(_array_)	( sizeof (_array_) / sizeof (_array_[0]) )

X/* Build a pixel from RGB values. Note variable name dependencies. */
#define SHIFT_MASK_PIXEL(r, g, b) \
    (( (((r)<<rs)&rm ) | (((g)<<gs)&gm) | (((b)<<bs)&bm)) + pixel_base)

char *visual_class_to_string();

int verbose;

main( argc, argv )
char **argv;
{
    static int depths[] = { 8, 12, 24 };	/* List of depths to try. */
    char *flagp, *display = 0;
    Colormap cmap = 0;
    Display *dpy;
    Window w;
    XVisualInfo vi;
    int vis_class = PseudoColor;
    int depth, i;
    XSetWindowAttributes xswa;
    unsigned long mask = 0;
    int stage = 0;
    XEvent ev;
    int longflag = 0;

    while ( argc-- > 1 ) {
	++argv;
	if ( **argv == '-' ) {
	    flagp = *argv;
	    while ( *++flagp )
		switch( *flagp ) {
		case 'l': longflag = 1;			break;
		case 'v': verbose = 1;			break;
		case 'd': display = *++argv; argc--;	break;
		}
	}
	else if ( isdigit( **argv ) )
	    vis_class = atoi( *argv );
	else
	    vis_class = visual_string_to_class( *argv );
    }

    if ( !(dpy = XOpenDisplay(display)) ) {
	printf( "Can't open display.\n" );
	exit(1);
    }

    /* Look for a matching visual. */
    for ( depth = i = 0; i < COUNT_OF(depths); i++ ) {
	if ( XMatchVisualInfo( dpy, 0, depths[i], vis_class, &vi ) ) {
	    depth = depths[i];
	    break;
	}
    }
    if ( depth == 0 ) {
	printf( "No visuals of type %s\n",
		visual_class_to_string( vis_class ) );
	exit(0);
    }
    else
	printf( "Trying %d-bit visual of type %s\n",
		depth, visual_class_to_string( vis_class ) );
    xswa.colormap = cmap = XCreateColormap( dpy, DefaultRootWindow( dpy ),
					    vi.visual, AllocNone );
    if ( cmap == 0 ) {
	printf( "Unable to create colormap.\n" );
	exit(0);
    }
    mask |= CWColormap;

    xswa.event_mask = ButtonPressMask | ExposureMask;
    mask |= CWEventMask;

    xswa.border_pixel = xswa.background_pixel = 0;
    mask |= CWBackPixel | CWBorderPixel;

    w = XCreateWindow( dpy, DefaultRootWindow(dpy), 0, 0, 256, 256,
		       1, depth, InputOutput, vi.visual, mask, &xswa );
    XMapRaised( dpy, w );

    for (;;) {
	XNextEvent( dpy, &ev );

	switch( ev.type ) {
	case Expose:
	    draw( dpy, w, &vi );
	    break;

	case ButtonPress:
	    switch( stage++ ) {
	    case 0:
		/* Important to have cmap installed at this point. */
		XInstallColormap( dpy, cmap );
		make_map( dpy, cmap, longflag );
		printf( "Created colormap.\n" );
		break;
	    case 1:
		XUninstallColormap( dpy, cmap );
		printf( "Uninstalled colormap.\n" );
		break;
	    case 2:
		XInstallColormap( dpy, cmap );
		printf( "Reinstalled colormap.\n" );
		break;
	    case 3:
		printf( "Bye bye\n" );
		exit(0);
		/* NOTREACHED */
	    }
	    break;
	}
    }
}

draw( dpy, w, v )
Display *dpy;
Window w;
XXVisualInfo *v;
{
    int x, y, c;
    GC gc;
    unsigned long rm, gm, bm;
    int rs, gs, bs, pixel_base = 0;
    int depth, rows, cols;

    if ( v->depth > 12 )
	depth = v->bits_per_rgb;
    else
	depth = v->depth;
    rows = 1 << ((depth + 1) / 2);
    cols = 1 << (depth / 2);

    /* Assume masks if depth > 12. */
    if ( v->depth > 12 ) {
	rm = v->red_mask;
	rs = shift_match_right( rm );
	gm = v->green_mask;
	gs = shift_match_right( gm );
	bm = v->blue_mask;
	bs = shift_match_right( bm );
    }
    else {
	rm = gm = bm = (1 << depth) - 1;
	rs = gs = bs = 0;
    }	

    gc = XCreateGC( dpy, w, 0L, (XGCValues *)0 );
    for ( c = 0; c < 1 << depth; c++ ) {
	x = (256 / cols) * (c % cols);
	y = (256 / rows) * (c / cols);
	
	XSetForeground( dpy, gc, SHIFT_MASK_PIXEL(c,c,c) );
	XFillRectangle( dpy, w, gc, x, y, 256/cols, 256/rows );
    }
}

int
shift_match_right (mask)
unsigned long int	mask;
{
    register int	shift;
    register unsigned long int	low_bit;
    
    if (mask == 0) return (0);
    
    low_bit = 1;
    
    for (shift = 0; (low_bit & mask) == 0; shift++) {
	low_bit <<= 1;
    }
    
    return (shift);
    
}


X/* Create a 2x2x2 color cube. */
make_map( dpy, cmap, longflag )
Display *dpy;
Colormap cmap;
{
    int i, j, k, idx;
    XColor color_defs[64];
    unsigned long int rm, gm, bm, pixel_base;
    int rs, gs, bs;

    if ( !XAllocColorPlanes( dpy, cmap, 1, &pixel_base,
			     1, 2, 2, 2, &rm, &gm, &bm ) ) {
	printf( "Can't alloc color planes.\n" );
	exit(0);
    }

    rs = shift_match_right(rm);
    gs = shift_match_right(gm);
    bs = shift_match_right(bm);

    if ( verbose )
	printf( "Base: %04x Masks: %04x %04x %04x, Shifts: %d %d %d\n",
		pixel_base, rm, gm, bm, rs, gs, bs );


    /* 
     * Set up the color map entries.
     */
    if ( !longflag )
	for (i = 0; i < 4; i++) {
	    color_defs[i].pixel = SHIFT_MASK_PIXEL(i, i, i) + pixel_base;
		    
	    color_defs[i].red   = 
	    color_defs[i].green = 
	    color_defs[i].blue  = (i * 85) << 8;
		    
	    color_defs[i].flags = DoRed | DoGreen | DoBlue;
	    if ( verbose )
		printf( "Color %04x: %04x %04x %04x\n",
			color_defs[i].pixel, color_defs[i].red,
			color_defs[i].green, color_defs[i].blue );
	}
    else
	for ( k = 0; k < 4; k++ )
	    for ( j = 0; j < 4; j++ )
		for (i = 0; i < 4; i++) {
		    idx = i + 4 * (j + 4 * k);
		    color_defs[idx].pixel = SHIFT_MASK_PIXEL(i, j, k) +
			pixel_base;

		    color_defs[idx].red   = (i * 85) << 8;
		    color_defs[idx].green = (j * 85) << 8;
		    color_defs[idx].blue  = (k * 85) << 8;

		    color_defs[idx].flags = DoRed | DoGreen | DoBlue;
		    if ( verbose )
			printf( "Color %04x: %04x %04x %04x\n",
				color_defs[idx].pixel, color_defs[idx].red,
				color_defs[idx].green, color_defs[idx].blue );
		}

    XStoreColors( dpy, cmap, color_defs, (longflag ? 64 : 4) );
    XFlush( dpy );
}

int visual_string_to_class(vis_type)
char *vis_type;
{
    static struct {
	char	*string;
	int		type;
    }  visual_type_table[] = {

	{ "grayscale", GrayScale},
	{ "greyscale", GrayScale},
	{ "staticgrey", StaticGray},
	{ "staticgray", StaticGray},
	{ "staticcolor", StaticColor},
	{ "pseudocolor", PseudoColor},
	{ "truecolor", TrueColor},
	{ "directcolor", DirectColor}
    };
    int i;
    int visual_type = 9999;
    char *ptr;

    for (ptr = vis_type; *ptr != '\0'; ptr++) 
	if (isupper(*ptr)) *ptr = _tolower(*ptr);
    for (i = 0; i < COUNT_OF(visual_type_table); i++) 
	if (strcmp (visual_type_table[i].string, vis_type) == 0) {
	    visual_type = visual_type_table[i].type;
	    break;
	}
    return visual_type;
}

char *visual_class_to_string(visual_type)
    int visual_type;
{
    char *type_string;
    switch (visual_type) {
    case DirectColor:	type_string = "DirectColor";	break;
    case PseudoColor:	type_string = "PseudoColor";	break;
    case TrueColor:	type_string = "TrueColor";	break;
    case StaticColor:	type_string = "StaticColor";	break;
    case GrayScale:	type_string = "GrayScale";	break;
    case StaticGray:	type_string = "StaticGray";	break;
    default: 		type_string = "any/unknown";	break;
    }
    return type_string;
}

//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 xcmapbug.c
	/bin/echo -n '	'; /bin/ls -ld xcmapbug.c
fi

exit
--
=Spencer W. Thomas 		EECS Dept, U of Michigan, Ann Arbor, MI 48109
spencer@eecs.umich.edu		313-936-2616 (8-6 E[SD]T M-F)

rws@expo.lcs.mit.EDU (Bob Scheifler) (05/16/91)

    Has anyone seen this?

Yes.

    Is there a fix? (wait for R5?)

Yes.  (At least, if I can manage to keep Somebody from deleting the code
again between prereleases.)

ntakahas@parole.is.tsukuba.ac.jp (TAKAHASHI Naoto) (05/17/91)

In article <SPENCER.91May15152351@spline.eecs.umich.edu> spencer@eecs.umich.edu (Spencer W. Thomas) writes:

> Is there a fix? (wait for R5?)

If you cannot wait for R5, get my 24-bit colour server for Suns and
apply the patch to dix/colormap.c.
--
TAKAHASHI Naoto
Machine Intelligence Lab., Inst. of Inf. Sci. & Elec., Univ. of Tsukuba
1-1-1 Tennodai, Tsukuba, 305 Japan