You are not logged in.

#1 2017-05-01 04:25:25

insanoflex
Member
Registered: 2017-04-29
Posts: 15

xlib trying to create a writeable framebuffer (SOLVED)

Hi all. I'm making a simple game, using X11 as the main window (graphics and input) library. The renderer is going to be software-based, so I need a frame buffer I can write to, then display to my x window. So far, I've tried using an XImage. This seems to be the method id Software used for Doom. Unfortunately, I'm not really sure how to go about this. Using XCreateImage, I can get an image, but I get BadMatch on my call to XPutImage, and I'm not sure why.

#include <stdlib.h>
#include <stdio.h>

#include <X11/Xutil.h>
#include <X11/Xos.h>

int main (int argc, char **argv) 
{
	Display *dpy;
	Window win;
	Window rootwin;
	int screen;
	XEvent event;
	XWindowAttributes rootwinattribs;
	int *framebuf = 0;
	XImage *ximage;
	XVisualInfo xvisinfo;
	Visual *xvisual;	
	GC gc;

	int width;
	int height;
	int i;

	dpy = XOpenDisplay(0);
	screen = DefaultScreen(dpy);

	rootwin = RootWindow(dpy, screen);

	XGetWindowAttributes(dpy, rootwin, &rootwinattribs);

	width = rootwinattribs.width;
	height = rootwinattribs.height;

	framebuf = malloc(width*height*4);
	if (!framebuf) {
		perror("malloc");
		exit(1);
	}

	for (i = 0; i < width*height; ++i) {
		*(framebuf+i) = 0xF0F0F0FF;
	}

	win = XCreateSimpleWindow(dpy, rootwin, 0, 0, width, height, 0, BlackPixel(dpy, screen), WhitePixel(dpy, screen));
	XMatchVisualInfo(dpy, screen, 32, DirectColor, &xvisinfo);
	xvisual = xvisinfo.visual;

	ximage = XCreateImage(dpy, xvisual, 32, XYPixmap, 0, (char *)framebuf, width, height, 32, 0);
	if (!ximage) {
		printf("XCreateImage() failed. Exiting...");
		exit(1);
	}

	XSelectInput(dpy, win, ExposureMask|KeyPressMask);
	XMapWindow(dpy, win);

	XGCValues xgcvals;
	xgcvals.graphics_exposures = 0;
	unsigned long valuemask = GCGraphicsExposures;	
	gc = XCreateGC(dpy, win, valuemask, &xgcvals);
	XPutImage(dpy, win, gc, ximage, 0, 0, 0, 0, width, height);
	for(;;) {
		XNextEvent(dpy, &event);
	}

	return 0;
}

Last edited by insanoflex (2017-05-03 13:49:09)

Offline

#2 2017-05-01 15:19:50

FlowIt
Member
Registered: 2014-10-25
Posts: 239

Re: xlib trying to create a writeable framebuffer (SOLVED)

BadMatch usually occurs when parameters/variables should have the same value but don't. I had an issue with different depths. So check your XImage, Window and GC and Visual if they match. This however, is machine dependent. Different monitors support different visuals so take that into account when you try to write portable code.
Anyway, your code segfaults for me.

Offline

#3 2017-05-01 15:56:57

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,452
Website

Re: xlib trying to create a writeable framebuffer (SOLVED)

I do prefer to use just bare Xlib wherever practical.  However, in this case I suspect it will give other problems.  Notably, your framebuffer is not aligned for efficient memory use.  I'd recommend using cairo which makes this very easy (and it interacts with xlib surfaces/targets quite easily).


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#4 2017-05-02 03:41:09

insanoflex
Member
Registered: 2017-04-29
Posts: 15

Re: xlib trying to create a writeable framebuffer (SOLVED)

I messed around with it some more, and after several fruitless attempts, I think I give up. I'm just going to use SDL. I'd really like to learn Xlib, but I think I'll read a book or two first. I read about Cairo, and this site: https://www.cairographics.org/Xlib/ says that it's not good for games.
Anyway, for what it's worth, the problem I have now, is that when the program runs, it seems to hang on XNextEvent (I've narrowed it down to XFlush, if I call XFlush before, it hangs there). The window doesn't display, and I have to kill the program manually using kill. I can still move the mouse around though, and I see a cursor.
Here's the code:

#include <stdlib.h>
#include <stdio.h>

#include <X11/Xutil.h>
#include <X11/Xos.h>

int main (int argc, char **argv) 
{
	Display *dpy;
	Window win;
	Window rootwin;
	int screen;
	XEvent event;
	XWindowAttributes rootwinattribs;
	int *framebuf = 0;
	XImage *ximage;
	XVisualInfo xvisinfo;
	Visual *xvisual;	
	GC gc;

	int width;
	int height;
	int i;

	dpy = XOpenDisplay(0);
	screen = DefaultScreen(dpy);

	rootwin = RootWindow(dpy, screen);

	XGetWindowAttributes(dpy, rootwin, &rootwinattribs);

	width = rootwinattribs.width;
	height = rootwinattribs.height;

	framebuf = malloc(width*height*4);
	if (!framebuf) {
		perror("malloc");
		exit(1);
	}

	for (i = 0; i < width*height; ++i) {
		*(framebuf+i) = 0xF0F0F0FF;
	}

	win = XCreateSimpleWindow(dpy, rootwin, 0, 0, width, height, 0, BlackPixel(dpy, screen), WhitePixel(dpy, screen));
	XMatchVisualInfo(dpy, screen, 32, DirectColor, &xvisinfo);
	xvisual = xvisinfo.visual;

	ximage = XCreateImage(dpy, xvisual, 32, XYPixmap, 0, (char *)framebuf, width, height, 32, 0);
	if (!ximage) {
		printf("XCreateImage() failed. Exiting...");
		exit(1);
	}

	XSelectInput(dpy, win, ExposureMask|KeyPressMask);
	XMapWindow(dpy, win);

	XGCValues xgcvals;
	xgcvals.graphics_exposures = 0;
	unsigned long valuemask = GCGraphicsExposures;	
	gc = XCreateGC(dpy, win, valuemask, &xgcvals);
	XPutImage(dpy, win, gc, ximage, 0, 0, 0, 0, width, height);
	for(;;) {
		XNextEvent(dpy, &event);
	}

	return 0;
}

Offline

#5 2017-05-02 10:15:28

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,452
Website

Re: xlib trying to create a writeable framebuffer (SOLVED)

insanoflex wrote:

I read about Cairo, and this site: https://www.cairographics.org/Xlib/ says that it's not good for games.

I think that might be the cairo people being humble and/or cautious.  Certainly cairo is not optimized for use in game engines the way other tools might be (SDL seems to claim this as a priority).  But cairo would be *far* better for use in a game that bare Xlib calls ... unless you did so much coding to ensure your xlib calls were optimized, and your memory buffers we're well aligned, etc, etc to the point that you had rewritten the cairo library.

Cairo may not be optimized for the types of interactions frequently needed in games, but it *is* optimized to do graphics on X11 extrememly well.

But if SDL works for you, that's a great way to go.  I'll see if I can pin down your current problem in a moment.

The above comments on games really also depends on what kind of game we're talking about.  For an arcade-like game (e.g. a frogger clone) cairo would work great.  For a doom/quake-like cairo would also work perfectly well.  For a more "modern" online multiplayer game with high resolution graphics, high frame rates, and a need for high precision timing and very low latency repsonse to inputs, thats where cairo (and xlib!) would just not work well.

EDIT: I think you posted the wrong code.  That's identical to your first code block.


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#6 2017-05-02 12:12:46

insanoflex
Member
Registered: 2017-04-29
Posts: 15

Re: xlib trying to create a writeable framebuffer (SOLVED)

Really? Oops, not sure how that happened.

#include <stdlib.h>
#include <stdio.h>

#include <X11/Xutil.h>
#include <X11/Xos.h>

int main (int argc, char **argv) 
{
	Display *dpy;
	Window win;
	Window rootwin;
	int screen;
	XEvent event;
	XWindowAttributes rootwinattribs;
	int *framebuf = 0;
	XImage *ximage;
	XVisualInfo xvisinfo;
	Visual *xvisual;	
	GC gc;
	Pixmap pixmap;
	XSetWindowAttributes attribs= {0};

	int width;
	int height;
	int i;

	dpy = XOpenDisplay(0);
	screen = DefaultScreen(dpy);

	rootwin = RootWindow(dpy, screen);

	XGetWindowAttributes(dpy, rootwin, &rootwinattribs);

	width = rootwinattribs.width;
	height = rootwinattribs.height;

	framebuf = malloc(width*height*4);
	if (!framebuf) {
		perror("malloc");
		exit(1);
	}

	for (i = 0; i < width*height; ++i) {
		*(framebuf+i) = 0xF0F0F0FF;
	}

	attribs.border_pixel = 0;
	attribs.event_mask = KeyPressMask|KeyReleaseMask|ExposureMask;
	XMatchVisualInfo(dpy, screen, 32, DirectColor, &xvisinfo);
	xvisual = xvisinfo.visual;

        /*The 24 for depth, I arrived at that as a guess. Other values, ie 32, result in a BadMatch Error*/
	win = XCreateWindow(dpy, rootwin, 0, 0, width, height, 0, CopyFromParent, InputOutput, xvisual, CWEventMask|CWBorderPixel, &attribs);
	pixmap = XCreatePixmap(dpy, win, width, height, 24);
	ximage = XCreateImage(dpy, xvisual, 24, ZPixmap, 0, (char *)framebuf, width, height, 32, 0);
	if (!ximage) {
		printf("XCreateImage() failed. Exiting...");
		exit(1);
	}

	XPutImage(dpy, pixmap, DefaultGC(dpy, screen), ximage, 0, 0, 0, 0, width, height);
	XCopyArea(dpy, pixmap, win, DefaultGC(dpy, screen), 0, 0, width, height, 0, 0);
	XSelectInput(dpy, win, ExposureMask|KeyPressMask);
	XMapWindow(dpy, win);

	for (;;)
	{
		XNextEvent(dpy, &event);
	}

	sleep(10);

	return 0;
}
Trilby wrote:

The above comments on games really also depends on what kind of game we're talking about.  For an arcade-like game (e.g. a frogger clone) cairo would work great.  For a doom/quake-like cairo would also work perfectly well.  For a more "modern" online multiplayer game with high resolution graphics, high frame rates, and a need for high precision timing and very low latency repsonse to inputs, thats where cairo (and xlib!) would just not work well.

Oh, I see. Well, that does make sense, and after rereading what the site said, it didn't say it wasn't good for games, it said it wasn't good for a high speed, graphics-intensive game. Guess I need to learn to read, heh. Anyway, I'm interested in learning more about xlib, and working through this problem, but maybe I'll switch to cairo as well. SDL seems to be giving me problems, and besides, I'd rather not use it if I don't have to. Not that SDL isn't good or anything.

Last edited by insanoflex (2017-05-02 12:34:02)

Offline

#7 2017-05-02 13:44:47

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,452
Website

Re: xlib trying to create a writeable framebuffer (SOLVED)

Thanks - there are a couple problems with that code.  First your for loop will never exit ... never.  So that sleep is also pointless.  A common way to write a main loop is with a while conditional on XNextEvent like the following:

while(!XNextEvent(dpy, &event)) {
	if (event.type == KeyPress) break;
};

Also note you don't need the XSelectInput as you already specify an event mask in the attribs you
pass to the create window call.

With the above event loop, this code works, creates a window, displays it, and it sits there until
you press a key, then it exits.

But there is another problem that can be a bit misleading - especially if you use a nonreparenting
WM: your window has absolutely nothing in it.  There's no background color, nothing.  So it doesn't
really look like it shows up - it's effectively invisible.


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#8 2017-05-02 14:20:54

insanoflex
Member
Registered: 2017-04-29
Posts: 15

Re: xlib trying to create a writeable framebuffer (SOLVED)

I thought my loop was a but odd. I took it from a tutorial I don't remember the name of. I do remember thinking, how does the program know when to exit? Anyway, so the window is invisible, but aren't I drawing an image to it? How would I get the image I've made to show? Also, on a side note, I really appreciate you taking the time to help me, so thanks.

Offline

#9 2017-05-02 14:53:12

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,452
Website

Re: xlib trying to create a writeable framebuffer (SOLVED)

There are many oddities of the current drawing code which lead to it not being displayed.  First, when you create your ximage you tell X that there are 0 bytes per line.  This should be either 3 * width or 4 * width.  Your buffer is 4 * width bytes per line, but you are trying to map that to a RGB pixmap which has 3 * width bytes per line - this will cause some oddities in the output as your source buffer data will not represent what you intend it to.

But the main problem is that you copy the pixmap to the window *before* it is mapped.  Xlib will *not* refresh your window for you unless you explicitly tell it to.  There are two options.  First, you could respond to an expose event and re-blit the pixmap to the window every time the window receives an expose event.  For example, in your main loop:

if (event.type == Expose) XCopyArea(dpy, pixmap, win, DefaultGC(dpy, screen), 0, 0, width, height, 0, 0);

The second option is to specify a backing_store for your main window.  This will tell Xlib that it is suppose to redraw the previous contents of the window whenever it is exposed (or at other times depending on the value of backing_store).  This is one of the window attributes you can either set directly with XSetWindowAttributes, or just pass it in the attrib struct you give to the create window function (and also set the appropriate fields flag).

Either one of these approaches will make your window "visible".  But it will not show what you want.

But if you really just want a solid color, set a background color when you create the window.  This would use much less memory, and far less data being sent between the client and server.  Note that even when your current approach is working, changing the contents of your framebuf data will *not* have any affect on what shows on the screen.  This is due to the indirect rendering nature of X11 clients and the server.  If you want direct access to actual graphical framebuffers, don't use Xlib.  Cairo may do this, openGL definitely does.

Again, I love Xlib, and there is a lot you can do with it.  But direct rendering is not one of the things you can really do with it.  You can most definitely draw with Xlib, but this is using it's own drawing functions like XDrawRectangle or XDrawLines.  These are actually quite powerful (despite what the wayland and GL people would claim) *if* they are all you need to do.  But if you need to do more, use a tool that does more.


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#10 2017-05-02 15:58:41

insanoflex
Member
Registered: 2017-04-29
Posts: 15

Re: xlib trying to create a writeable framebuffer (SOLVED)

Well, what I'm really trying to do is have an ximage I can draw to, then continuously update the window with the contents of the ximage. The solid color was just a test.

Offline

#11 2017-05-02 16:43:01

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,452
Website

Re: xlib trying to create a writeable framebuffer (SOLVED)

In that case you should cut out the middle-man of the pixmap and just XPutImage onto the window.

But this is also where cairo will make life much easier.


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#12 2017-05-02 19:50:44

insanoflex
Member
Registered: 2017-04-29
Posts: 15

Re: xlib trying to create a writeable framebuffer (SOLVED)

I remember creating the pixmap so I could have the ximage format I wanted. Seems pointless, and probably not correct now that I think about it. I'll check out Cairo a bit more.

Offline

#13 2017-05-03 04:44:35

insanoflex
Member
Registered: 2017-04-29
Posts: 15

Re: xlib trying to create a writeable framebuffer (SOLVED)

Okay, I fiddled around with the original source code, incorporating the changes you suggested. The window now correctly (I assume)  displays the frame buffer I write to. This is a step closer to where I want to be, so I'm happy. Thanks for all your help
-Edit: I'm going to label this as solved.

Last edited by insanoflex (2017-05-03 13:48:35)

Offline

Board footer

Powered by FluxBB