Search code examples
c++linuxx11xlib

How to create a game loop with xlib


I am trying to create a game loop for an xlib window, but I cannot manage to paint the window correctly. Right now I am creating a window with XCreateSimpleWindow(...), and using a for loop to paint all pixels one at a time. (The color of these pixels is read from a large integer array, for now I've set all pixels to be blue.) The actual game loop right now is the following:

void loop() {
    while (true) {
        // Clear the window (the background color is set to white)
        XClearWindow(dsp, win);

        // Loop through all pixels of the 800*600 window
        for (int j = 0; j < 600; j++) {
            for (int i = 0; i < 800; i++) {
                // Read the color from the pixels array (always blue for now)
                long int color = pixels[i + 800*j];
                // Set the foreground color for drawing
                XSetForeground(dsp, gc, color);
                // Draw the pixel
                XDrawPoint(dsp, win, gc, i, j);
            }
        }

        // Flush the output buffer
        XFlush();
    }
}

The variables dsp, win, pixels, gc are defined globally.

Now when I compile and execute the binary file, the rows with low y coordinate are mostly blue, but the rows with high y coordinate are mostly white. In between it is easy to see how it simply takes too much time to draw all pixels at once. I expect that this effect is because the top rows (low y) are drawn first, which means a short delay between XClearWindow() and XDrawPoint() for those pixels. (I also tested the fps, it takes around 7 milliseconds to run the while(true) loop once.)

I did some research, and read about how double buffering might solve this issue. I did follow a guide on double buffering with xlib (Xdbe), but it does not seem to solve the issue. Is there a faster way of drawing with xlib than just looping through all pixels? Is double buffering not supposed to solve this, or am I implementing it incorrectly?


Solution

  • Communicating directly with Xlib is so early-90s (read: noone has done this, unless he's a framework designer, in the last 20 years!).

    You're right, looping through pixels to update them on the screen is incredibly slow. That's why almost all modern GUI Frameworks use their own Xbuffers that they just draw on and instruct X to render.

    As a comment on your approach: Game development on raw X doesn't make the least sense, as there are more protable, better performing, easier to use, small, well-tested libraries. Take SDL as an example.

    Update March 2021: As Pablo Ariel pointed out below, it might be important by now to point out that investing time in learning X11 isn't the wises investment by now: X is going away; it took a few decades, but the largest Linux distros (after Debian 10 does that, Ubuntu 21.04 does too, and thus all derivates like Mint use Wayland by default; Fedora 34 does the same) are using Wayland by default; using X11 is still possible on these, but it's an extra step to use something old...

    Note that this doesn't mean Wayland is what you should learn if you're trying to learn how to produce games. Or raw OpenGL. Or Vulkan. A graphics/game engine is your friend, because you a) don't want to deal with all the low-level stuff yourself of abstracting the subtle differences between different versions of the same thing, and b) you're not getting any faster than a well-written enginge, and the people writing game engines are going to be better than you at that. Concentrate on the relevant part, not on dealing with lowest-level libraries!