diff options
author | fschildt <florian.schildt@protonmail.com> | 2025-08-22 15:23:11 +0200 |
---|---|---|
committer | fschildt <florian.schildt@protonmail.com> | 2025-08-22 15:23:11 +0200 |
commit | 2050c0e0576f05156f192aa4caf48834d2f28b14 (patch) | |
tree | ee58bd35b0df0a1bacfbc9700ed99ce80c99294e /src/graveyard/lin_glx_modern.c |
Diffstat (limited to 'src/graveyard/lin_glx_modern.c')
-rw-r--r-- | src/graveyard/lin_glx_modern.c | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/src/graveyard/lin_glx_modern.c b/src/graveyard/lin_glx_modern.c new file mode 100644 index 0000000..853e3c7 --- /dev/null +++ b/src/graveyard/lin_glx_modern.c @@ -0,0 +1,243 @@ + +static bool g_glx_context_error_occured = false; + +static int glx_context_error_handler(Display *display, XErrorEvent *event) +{ + printf("glx_context_error_handler received error\n"); + g_glx_context_error_occured = true; + return 0; +} + +// Helper to check for extension string presence. Copied from: +// http://www.opengl.org/resources/features/OGLextensions/ +static bool gl_extension_supported(const char *extList, const char *extension) +{ + const char *start; + const char *where, *terminator; + + // Extension names should not have spaces. + where = strchr(extension, ' '); + if (where || *extension == '\0') + return false; + + for (start=extList;;) + { + where = strstr(start, extension); + if (!where) + break; + + terminator = where + strlen(extension); + + if (where == start || *(where - 1) == ' ') + if (*terminator == ' ' || *terminator == '\0') + return true; + + start = terminator; + } + + return false; +} + +static GLXContext create_current_glx_context(Display *display, Window window, GLXFBConfig fbc) +{ + // get glXCreateContextAttribsARB + const char *glx_extensions = glXQueryExtensionsString(display, DefaultScreen( display)); + + glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0; + glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) glXGetProcAddressARB((const GLubyte*)"glXCreateContextAttribsARB"); + + if (!gl_extension_supported(glx_extensions, "GLX_ARB_create_context") || + !glXCreateContextAttribsARB) + { + printf("glXCreateContextAttribsARB() not found\n"); + return 0; + } + + // Install an X error handler so the application won't exit if GL 3.0 + // context allocation fails. + // + // Note this error handler is global. All display connections in all threads + // of a process use the same error handler, so be sure to guard against other + // threads issuing X commands while this code is running. + g_glx_context_error_occured = false; + int (*oldHandler)(Display*, XErrorEvent*) = XSetErrorHandler(&glx_context_error_handler); + + // create glx context + GLXContext glx_context = 0; + int context_attribs[] = { + GLX_CONTEXT_MAJOR_VERSION_ARB, 4, + GLX_CONTEXT_MINOR_VERSION_ARB, 3, + GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB | GLX_CONTEXT_DEBUG_BIT_ARB, + GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + None + }; + + glx_context = glXCreateContextAttribsARB(display, fbc, 0, True, context_attribs); + + // check for errors + XSync(display, False); + if (g_glx_context_error_occured || !glx_context) + { + printf("failed to create glx context\n"); + return 0; + } + XSetErrorHandler(oldHandler); + + glXMakeCurrent(display, window, glx_context); + return glx_context; +} + +// Note: special case when debugging +// stepping over glXChooseFBConfig or glXGetFBConfigs cause +// _dl_catch_exception in libc +// stepping more leads to +// ?? () from /usr/lib/libnvidia-glcore.so.510.68.02 +// +// Originally I used glXChooseFBConfig, then tried to fix it with glXGetFBConfigs +// and now I leave it at that for the time being +// +// You can still debug by setting breakpoint later and continuing (c) until +// that breakpoint is hit +static bool get_framebuffer_config(Display *display, GLXFBConfig *config) +{ + int screen = XDefaultScreen(display); + + int fbcs_count; + GLXFBConfig *fbcs = glXGetFBConfigs(display, screen, &fbcs_count); + if (!fbcs) + { + printf("no framebuffer configs received\n"); + return 0; + } + + int best_fbc = -1, worst_fbc = -1, best_num_samp = -1, worst_num_samp = 999; + for (int i = 0; i < fbcs_count; i++) + { + int fbc_attribs[11]; + glXGetFBConfigAttrib(display, fbcs[i], GLX_X_RENDERABLE, &fbc_attribs[0]); + glXGetFBConfigAttrib(display, fbcs[i], GLX_DRAWABLE_TYPE, &fbc_attribs[1]); + glXGetFBConfigAttrib(display, fbcs[i], GLX_RENDER_TYPE, &fbc_attribs[2]); + glXGetFBConfigAttrib(display, fbcs[i], GLX_X_VISUAL_TYPE, &fbc_attribs[3]); + glXGetFBConfigAttrib(display, fbcs[i], GLX_RED_SIZE, &fbc_attribs[4]); + glXGetFBConfigAttrib(display, fbcs[i], GLX_GREEN_SIZE, &fbc_attribs[5]); + glXGetFBConfigAttrib(display, fbcs[i], GLX_BLUE_SIZE, &fbc_attribs[6]); + glXGetFBConfigAttrib(display, fbcs[i], GLX_ALPHA_SIZE, &fbc_attribs[7]); + glXGetFBConfigAttrib(display, fbcs[i], GLX_DEPTH_SIZE, &fbc_attribs[8]); + glXGetFBConfigAttrib(display, fbcs[i], GLX_STENCIL_SIZE, &fbc_attribs[9]); + glXGetFBConfigAttrib(display, fbcs[i], GLX_DOUBLEBUFFER, &fbc_attribs[10]); + + if (fbc_attribs[0] == True && + fbc_attribs[1] & GLX_WINDOW_BIT && + fbc_attribs[2] & GLX_RGBA_BIT && + fbc_attribs[3] == GLX_TRUE_COLOR && + fbc_attribs[4] == 8 && + fbc_attribs[5] == 8 && + fbc_attribs[6] == 8 && + fbc_attribs[7] == 8 && + fbc_attribs[8] == 24 && + fbc_attribs[9] == 8 && + fbc_attribs[10] == True) + { + XVisualInfo *visual_info = glXGetVisualFromFBConfig(display, fbcs[i]); + if (visual_info) + { + int samp_buf, samples; + glXGetFBConfigAttrib(display, fbcs[i], GLX_SAMPLE_BUFFERS, &samp_buf); + glXGetFBConfigAttrib(display, fbcs[i], GLX_SAMPLES , &samples); + + if (best_fbc < 0 || (samp_buf && samples) > best_num_samp) + { + best_fbc = i; + best_num_samp = samples; + } + if (worst_fbc < 0 || !samp_buf || samples < worst_num_samp) + { + worst_fbc = i; + worst_num_samp = samples; + } + } + XFree(visual_info); + } + } + + if (best_fbc == -1) + { + return false; + } + + *config = fbcs[best_fbc]; + XFree(fbcs); + + return true; +} + +struct Platform_Window* platform_create_window(const char *name, int width, int height) +{ + Display *display = XOpenDisplay(0); + if (!display) + { + printf("XOpenDisplay(0) failed\n"); + return 0; + } + + Window root_window = XDefaultRootWindow(display); + if (!root_window) + { + printf("XDefaultRootWindow(display) failed\n"); + XCloseDisplay(display); + return 0; + } + + // glx version 1.3 required (for framebuffer configs and modern context creation) + int glx_major, glx_minor; + if (!glXQueryVersion(display, &glx_major, &glx_minor) || + (glx_major == 1 && glx_minor < 3) || + (glx_major < 1)) + { + printf("invalid glx version\n"); + return 0; + } + + GLXFBConfig fbc; + if (!get_framebuffer_config(display, &fbc)) + { + printf("no framebuffer config found\n"); + return 0; + } + + // set window attributes + XVisualInfo *visual_info = glXGetVisualFromFBConfig(display, fbc); + Colormap colormap = XCreateColormap(display, root_window, visual_info->visual, AllocNone); + long event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask; + int attribute_mask = CWEventMask | CWColormap; + + XSetWindowAttributes attributes = {}; + attributes.colormap = colormap; + attributes.event_mask = event_mask; + + // create window + Window window = XCreateWindow(display, root_window, 0, 0, width, height, 0, visual_info->depth, InputOutput, visual_info->visual, attribute_mask, &attributes); + XFree(visual_info); + XStoreName(display, window, name); + XMapWindow(display, window); + + GLXContext glx_context = create_current_glx_context(display, window, fbc); + if (!glx_context) + { + return 0; + } + + // create platform window + struct Platform_Window *platform_window = (struct Platform_Window*)malloc(sizeof(struct Platform_Window)); + if (!platform_window) + { + printf("malloc failed\n"); + XCloseDisplay(display); + return 0; + } + + platform_window->display = display; + platform_window->window = window; + + return platform_window; +} |