Using OPENGL under Linux and X11

Hi, I’m trying to get OPENGL working on my machine. Here are some general informations:

  • OS: Linux (PopOs)
  • CPU: AMD A8-6410 APU with AMD Radeon R5 Graphics (4) @ 2.000GHz
  • GPU: AMD ATI Radeon R4/R5 Graphics
  • DE: Gnome
  • WM: X11

And the code I’m trying to execute is the following:

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

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

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glx.h>
#include <GL/glext.h>

main(int argc, char **argv) {

        Display *display;
        display = XOpenDisplay(NULL);
        if (display == NULL) {
                fprintf(stderr, "ERR:  could not create the X display.\n");

        Window root;
        root = DefaultRootWindow(display);

        XVisualInfo *vinfo;
        int visual_attrs[] = {
                GLX_DEPTH_SIZE, 24,
                GLX_DOUBLEBUFFER, None
        vinfo= glXChooseVisual(display, 0, visual_attrs);
        if (vinfo == NULL) {
                fprintf(stderr, "ERR:  could not choose a visual info.\n");

        Colormap color_map;
        color_map = XCreateColormap(display, root, vinfo->visual, AllocNone);

        XSetWindowAttributes set_window_attrs;
        set_window_attrs.colormap       = color_map;
        set_window_attrs.event_mask     = ExposureMask | KeyPressMask;

        Window window;
        window = XCreateWindow(display, root, 0, 0, 800, 600, 0,
                                vinfo->depth, InputOutput, vinfo->visual,
                                CWColormap | CWEventMask, &set_window_attrs);

        XMapWindow(display, window);
        XStoreName(display, window, "0xPLOT");

        GLXContext gl_ctx;
        gl_ctx = glXCreateContext(display, vinfo, NULL, true);
        glXMakeCurrent(display, window, gl_ctx);

        // query the APIs.
        PFNGLGENBUFFERSPROC              glGenBuffers;
        PFNGLBINDBUFFERPROC              glBindBuffer;
        PFNGLBUFFERDATAPROC              glBufferData;
        PFNGLCREATESHADERPROC            glCreateShader;
        PFNGLSHADERSOURCEPROC            glShaderSource;
        PFNGLCOMPILESHADERPROC           glCompileShader;
        PFNGLCREATEPROGRAMPROC           glCreateProgram;
        PFNGLATTACHSHADERPROC            glAttachShader;
        PFNGLLINKPROGRAMPROC             glLinkProgram;
        PFNGLUSEPROGRAMPROC              glUseProgram;
        PFNGLDELETESHADERPROC            glDeleteShader;
        PFNGLVERTEXATTRIBPOINTERPROC     glVertexAttribPointer;
        PFNGLGENVERTEXARRAYSPROC         glGenVertexArrays;
        PFNGLBINDVERTEXARRAYPROC         glBindVertexArray;
        PFNGLGETSHADERIVPROC             glGetShaderiv;
        PFNGLGETSHADERINFOLOGPROC        glGetShaderInfoLog;

        glGenBuffers                    = (PFNGLGENBUFFERSPROC)glXGetProcAddress((const GLubyte*)"glGenBuffers");
        glBindBuffer                    = (PFNGLBINDBUFFERPROC)glXGetProcAddress((const GLubyte*)"glBindBuffer");
        glBufferData                    = (PFNGLBUFFERDATAPROC)glXGetProcAddress((const GLubyte*)"glBufferData");
        glCreateShader                  = (PFNGLCREATESHADERPROC)glXGetProcAddress((const GLubyte*)"glCreateShader");
        glShaderSource                  = (PFNGLSHADERSOURCEPROC)glXGetProcAddress((const GLubyte*)"glShaderSource");
        glCompileShader                 = (PFNGLCOMPILESHADERPROC)glXGetProcAddress((const GLubyte*)"glCompileShader");
        glCreateProgram                 = (PFNGLCREATEPROGRAMPROC)glXGetProcAddress((const GLubyte*)"glCreateProgram");
        glAttachShader                  = (PFNGLATTACHSHADERPROC)glXGetProcAddress((const GLubyte*)"glAttachShader");
        glLinkProgram                   = (PFNGLLINKPROGRAMPROC)glXGetProcAddress((const GLubyte*)"glLinkProgram");
        glUseProgram                    = (PFNGLUSEPROGRAMPROC)glXGetProcAddress((const GLubyte*)"glUseProgram");
        glDeleteShader                  = (PFNGLDELETESHADERPROC)glXGetProcAddress((const GLubyte*)"glDeleteShader");
        glVertexAttribPointer           = (PFNGLVERTEXATTRIBPOINTERPROC)glXGetProcAddress((const GLubyte*)"glVertexAttribPointer");
        glEnableVertexAttribArray       = (PFNGLENABLEVERTEXATTRIBARRAYPROC)glXGetProcAddress((const GLubyte*)"glEnableVertexAttribArray");
        glGenVertexArrays               = (PFNGLGENVERTEXARRAYSPROC)glXGetProcAddress((const GLubyte*)"glGenVertexArrays");
        glBindVertexArray               = (PFNGLBINDVERTEXARRAYPROC)glXGetProcAddress((const GLubyte*)"glBindVertexArray");
        glGetShaderiv                   = (PFNGLGETSHADERIVPROC)glXGetProcAddress((const GLubyte*)"glGetShaderiv");
        glGetShaderInfoLog              = (PFNGLGETSHADERINFOLOGPROC)glXGetProcAddress((const GLubyte*)"glGetShaderInfoLog");

        if (glGenBuffers                == NULL ||
            glBindBuffer                == NULL ||
            glBufferData                == NULL ||
            glCreateShader              == NULL ||
            glShaderSource              == NULL ||
            glCompileShader             == NULL ||
            glCreateProgram             == NULL ||
            glAttachShader              == NULL ||
            glLinkProgram               == NULL ||
            glUseProgram                == NULL ||
            glDeleteShader              == NULL ||
            glVertexAttribPointer       == NULL ||
            glEnableVertexAttribArray   == NULL ||
            glGenVertexArrays           == NULL ||
            glBindVertexArray           == NULL ||
            glGetShaderiv               == NULL ||
            glGetShaderInfoLog          == NULL) {
                fprintf(stderr, "ERR:  could not query the GL function(s).\n");

        float vertices[] = {
                -0.5f, -0.5f,
                +0.5f, -0.5f,
                +0.0f, +0.5f

        unsigned int vao;
        glGenVertexArrays(1, &vao);

        unsigned int vbo;
        glGenBuffers(1, &vbo);
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glBufferData(GL_ARRAY_BUFFER, sizeof (vertices), vertices, GL_STATIC_DRAW);

        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof (float), (void*)0);

        const char *vertex_content = ""
        "#version 330 core\n"
        "layout (location = 0) "
        "in vec2 a_pos; "
        "void "
        "main() {"
        "       gl_Position = vec4(a_pos.x, a_pos.y, 1.0f, 1.0f);"

        unsigned int vertex_shader;
        vertex_shader = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vertex_shader, 1, &vertex_content, NULL);

#ifdef Z0_DEBUG
        int  success;
        char log[512];

        glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
        if (!success) {
                glGetShaderInfoLog(vertex_shader, sizeof (log), NULL, log);
                fprintf(stderr, "ERR: %s\n", log);
        const char *fragment_content = ""
        "#version 330 core\n"
        "out vec4 f_color; "
        "void "
        "main() {"
        "       f_color = vec4(1.0f, 0.5f, 0.5f, 1.0f);"

        unsigned int fragment_shader;
        fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fragment_shader, 1, &fragment_content, NULL);

#ifdef Z0_DEBUG
        glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
        if (!success) {
                glGetShaderInfoLog(fragment_shader, sizeof (log), NULL, log);
                fprintf(stderr, "ERR: %s\n", log);

        unsigned int shader_program;
        shader_program = glCreateProgram();
        glAttachShader(shader_program, vertex_shader);
        glAttachShader(shader_program, fragment_shader);

#ifdef Z0_DEBUG
        glGetShaderiv(shader_program, GL_LINK_STATUS, &success);
        if (!success) {
                glGetShaderInfoLog(shader_program, sizeof (log), NULL, log);
                fprintf(stderr, "ERR: %s\n", log);


#ifdef Z0_DEBUG
        printf("INFO: finished the setup.\n");

        XEvent event;
        XWindowAttributes window_attrs;
        while (true) {
                XNextEvent(display, &event);

                switch (event.type) {
                case Expose:
                        XGetWindowAttributes(display, window, &window_attrs);
                        glViewport(0, 0, window_attrs.width, window_attrs.height);

                        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

                        glDrawArrays(GL_TRIANGLES, 0, 3);

                        glXSwapBuffers(display, window);
                case KeyPress:
                        glXMakeCurrent(display, None, NULL);
                        glXDestroyContext(display, gl_ctx);
                        XDestroyWindow(display, window);

        return 0;

However I only do get black screen.
(The example is stolen from learnopengl (with some modifications))

Here is the command for compiling it:

gcc -DZ0_DEBUG main.c -o plot.out -Wall -Wextra -fsanitize=leak,undefined,address -lX11 -lm -lGL -lGLU

First, a NDC Z value of 1.0 is exactly on the far plane, so the triangle may be discarded by clipping. But even if it isn’t, the default glDepthFunc setting is GL_LESS, so fragments are only rendered if they are (strictly) less than the value in the depth buffer, but a Z value of 1.0 will result in the greatest representable depth value, so it will be either greater than or equal to the value already in the depth buffer and thus fail the depth test. Finally, you aren’t clearing the depth buffer.

If I change the lines in question to

        "       gl_Position = vec4(a_pos.x, a_pos.y, 0.0f, 1.0f);"


                        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

then the triangle is rendered.

1 Like