How to upload 32 bit image to server-side pixmap
Asked Answered
H

2

17

I'm trying to create server-side RGBA pixmap from client side buffer. CreatePixmap & CreateImage work ok for 32 and 24 bit, but XPutImage result in Match Error returned by server

X Error of failed request:  BadMatch (invalid parameter attributes)
  Major opcode of failed request:  72 (X_PutImage)
  Serial number of failed request:  8
  Current serial number in output stream:  8

server does support 32 bit pixmaps (xdpyinfo output: https://gist.github.com/2582961). Same behaviour on ubuntu 12.04 (X.Org version: 1.11.3) and OSX with X.app (X.Org version: 1.10.3)

Why following code fails?

#include     <stdlib.h>
#include     <X11/Xlib.h>

int main(int argc, char **argv)
{
    int width = 100;
    int height = 100;
    int depth = 32; // works fine with depth = 24
    int bitmap_pad = 32; // 32 for 24 and 32 bpp, 16, for 15&16
    int bytes_per_line = 0; // number of bytes in the client image between the start of one scanline and the start of the next
    Display *display=XOpenDisplay(0);
    unsigned char *image32=(unsigned char *)malloc(width*height*4);
    XImage *img = XCreateImage(display, CopyFromParent, depth, ZPixmap, 0, image32, width, height, bitmap_pad, bytes_per_line);
    Pixmap p = XCreatePixmap(display, XDefaultRootWindow(display), width, height, depth);
    XPutImage(display, p, DefaultGC(display, 0), img, 0, 0, 0, 0, width, height); // 0, 0, 0, 0 are src x,y and dst x,y
    XEvent ev;
    while (1) {
       XNextEvent(display, &ev);
    }
}

Update: It looks like I finally got answer: use GC associated with pixmap instead of DefaultGC (which has depth of root window)

#include     <stdlib.h>
#include     <X11/Xlib.h>

int main(int argc, char **argv)
{
    int width = 100;
    int height = 100;
    int depth = 32; // works fine with depth = 24
    int bitmap_pad = 32; // 32 for 24 and 32 bpp, 16, for 15&16
    int bytes_per_line = 0; // number of bytes in the client image between the start of one scanline and the start of the next
    Display *display=XOpenDisplay(0);
    unsigned char *image32=(unsigned char *)malloc(width*height*4);
    XImage *img = XCreateImage(display, CopyFromParent, depth, ZPixmap, 0, image32, width, height, bitmap_pad, bytes_per_line);
    Pixmap p = XCreatePixmap(display, XDefaultRootWindow(display), width, height, depth);
    XGCValues gcvalues;
    GC gc = XCreateGC(display, p, 0, &gcvalues);
    XPutImage(display, p, gc, img, 0, 0, 0, 0, width, height); // 0, 0, 0, 0 are src x,y and dst x,y
    XEvent ev;
    while (1) {
       XNextEvent(display, &ev);
    }
}
Hop answered 8/5, 2012 at 3:46 Comment(0)
P
3

Well, your code works for 32 bits images if you just create a GC passing a drawable on argument which is 32 bits. XCreateGC(dpy, drawable, 0, 0), where drawable can be a pixmap with 32 bits depth. It works perfect with me.

Picture answered 30/4, 2013 at 14:14 Comment(6)
Now I have chicken and egg problem - I need 32 bit gc to create 32 bit pixmap and 32 bit drawable to create 32 bit gc. Do you have 32 bit depth for default visual?Hop
I will answer you next week when I go back to work again, cause now I am on vacations. I will look for that ok?Picture
Thanks! That's by no means urgentHop
I completly forgot this last time. But what do you mean that you need 32bit GC to create 32 bit pixmap? XCreatePixmap(display, d, width, height, depth); You just specify to the pixmap which depth you want on its creation. Why are you experiencing problem?Picture
The problem in original code was in XPutImage call failing to upload 32 bit bitmap. I'll update answer with working code. Using GC created for pixmap instead DefaultGC(display, 0) did the trickHop
You're right. I also used the created GC and never the DefaultGC. Hope this thread may help more people, since I was cracking my head on the desk for weeks to figure this thing out and it looks that it was the same to you hehe.Picture
C
6

The problem is with DefaultGC() which return a GC with bit depth of system default screen. If you look at line 53 of your gist paste you see that this is 24:

depth of root window: 24 planes

On line 63 you see that it uses 0x22 as default which is shown in more detail in line 64 to 70:

  visual:
    visual id: 0x22
    class: TrueColor
    depth: 24 planes
    available colormap entries: 256 per subfield
    red, green, blue masks: 0xff0000, 0xff00, 0xff
    significant bits in color specification: 8 bits

You could probably do this a bit nicer but as a start you can try this:

Note: This uses system visuals so most probably only support depth of 24 or 32.

#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>


#ifdef DEBUG
int dbg = 1;
#else
int dbg = 0;
#endif

/* Return a GC based on depth */
int gc_depth(int depth, Display *dpy, Window scr, Window root, GC *gc)
{
        Window win;
        Visual *visual;
        XVisualInfo vis_info;
        XSetWindowAttributes win_attr;
        unsigned long win_mask;

        if(!XMatchVisualInfo(dpy, scr, depth, TrueColor, &vis_info)) {
                fprintf(stderr,
                        " * ERR: %d depth not supported\n",
                        depth
                );
                return 1;
        }

        visual = vis_info.visual;

        win_attr.colormap = XCreateColormap(dpy, root, visual, AllocNone);
        win_attr.background_pixel = 0;
        win_attr.border_pixel = 0;

        win_mask = CWBackPixel | CWColormap | CWBorderPixel;

        win = XCreateWindow(
                        dpy, root,
                        0, 0,
                        100, 100,        /* dummy size */
                        0, depth,
                        InputOutput, visual,
                        win_mask, &win_attr);
        /* To flush out any errors */
        if (dbg) XSync(dpy, True);

        *gc = XCreateGC(dpy, win, 0, 0);
        if (dbg) XSync(dpy, True);

        XDestroyWindow(dpy, win);
        if (dbg) XSync(dpy, True);

        return 0;
}

int main(void)
{
        int w = 100;
        int h = 100;
        int depth = 32;
        int bitmap_pad = 32;
        int bpl = 0;

        Display *dpy;
        Window root;
        Window scr;
        GC gc;
        int root_depth;

        Pixmap pm;
        XImage *img;
        unsigned char *buf_img;

        if(!(dpy = XOpenDisplay(NULL))) {
                fprintf(stderr,
                        " * ERR: Failed to open display.\n");
                return 1;
        }

#ifdef DEBUG
        /* To get errors in order, slows down
         * One can also define int _Xdebug = 1;
         * */
        XSynchronize(dpy, True);
#endif

        root = XDefaultRootWindow(dpy);
        scr  = XDefaultScreen(dpy);

        if ((buf_img = malloc(w * h * 4)) == NULL) {
                fprintf(stderr,
                        " * ERR: Unable to alloacte %d bytes\n",
                        w * h * 4);
                return 1;
        }

        root_depth = DefaultDepth(dpy, scr);

        fprintf(stderr,
                "Default depth: %d\n",
                root_depth);

        /* This should be doen more nice */
        if (depth != root_depth) {
               if (gc_depth(depth, dpy, scr, root, &gc) != 0)
                        return 1;
        } else {
                gc = DefaultGC(dpy, 0);
        }

        img = XCreateImage(
                        dpy, CopyFromParent,
                        depth, ZPixmap,
                        0, (char *)buf_img,
                        w, h,
                        bitmap_pad, bpl);
        /* To flush out any errors */
        if (dbg) XSync(dpy, True);

        pm = XCreatePixmap(
                        dpy, root,
                        w, h,
                        depth);
        if (dbg) XSync(dpy, True);

        XPutImage(
                dpy, pm,
                gc, img,
                0, 0,
                0, 0,
                w, h);
        if (dbg) XSync(dpy, True);

        XFreePixmap(dpy, pm);
        XDestroyImage(img);
        XFreeGC(dpy, gc);
        if (dbg) XSync(dpy, True);

        fprintf(stderr,
                "OK!\n");

        return 0;
}
Ceyx answered 8/5, 2012 at 12:53 Comment(5)
Thanks! Unfortunately, your approach requires 32 bit visual (and dummy 32bit depth window), which is not available on OSX (see my dpyinfo).Hop
@AndreySidorov: Yes, I was joust about to post it as I read your gist more carefully. Bummer. Have to whip up something else then. Anyhow: the problem is more specified at least.Ceyx
as far as I know, GC is not specific to depth (none of possible GC attributes refer to depth). From x11 protocol PutImage request description: GC components: function, plane-mask, subwindow-mode, clip-x-origin, clip-y-origin, clip-mask; GC mode-dependent components: foreground, backgroundHop
I'll probably try to use two 24bit PutImage requests, two 24 bit pixmaps + one 32bit and combine them using CopyArea and plane mask, but I really hope there is simpler solutionHop
To bad. Hacked on it for a while still, but didn't find a usable solution.Ceyx
P
3

Well, your code works for 32 bits images if you just create a GC passing a drawable on argument which is 32 bits. XCreateGC(dpy, drawable, 0, 0), where drawable can be a pixmap with 32 bits depth. It works perfect with me.

Picture answered 30/4, 2013 at 14:14 Comment(6)
Now I have chicken and egg problem - I need 32 bit gc to create 32 bit pixmap and 32 bit drawable to create 32 bit gc. Do you have 32 bit depth for default visual?Hop
I will answer you next week when I go back to work again, cause now I am on vacations. I will look for that ok?Picture
Thanks! That's by no means urgentHop
I completly forgot this last time. But what do you mean that you need 32bit GC to create 32 bit pixmap? XCreatePixmap(display, d, width, height, depth); You just specify to the pixmap which depth you want on its creation. Why are you experiencing problem?Picture
The problem in original code was in XPutImage call failing to upload 32 bit bitmap. I'll update answer with working code. Using GC created for pixmap instead DefaultGC(display, 0) did the trickHop
You're right. I also used the created GC and never the DefaultGC. Hope this thread may help more people, since I was cracking my head on the desk for weeks to figure this thing out and it looks that it was the same to you hehe.Picture

© 2022 - 2024 — McMap. All rights reserved.