try fix Failed to create /mesa_shader_cache for shader cache (Permiss… #9
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Test OpenGL Headless Environment | |
| on: | |
| push: | |
| branches: [ ci-opengl-setup ] | |
| pull_request: | |
| branches: [ ci-opengl-setup ] | |
| workflow_dispatch: | |
| env: | |
| # Headless Linux CI lacks hardware OpenGL and X11 display. These force Mesa software rendering, used alongside Xvfb - a virtual X11 server that we start before our tests. | |
| LIBGL_ALWAYS_SOFTWARE: 1 | |
| MESA_LOADER_DRIVER_OVERRIDE: llvmpipe | |
| jobs: | |
| test-opengl: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Install comprehensive Mesa and X11 development packages | |
| run: | | |
| echo "=== Installing comprehensive OpenGL and X11 development packages ===" | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| xvfb \ | |
| x11-xserver-utils \ | |
| x11-utils \ | |
| x11-apps \ | |
| mesa-utils \ | |
| libgl1-mesa-dev \ | |
| libgl1-mesa-dri \ | |
| libglu1-mesa-dev \ | |
| libglx-mesa0 \ | |
| libglx-dev \ | |
| libegl1-mesa-dev \ | |
| libx11-dev \ | |
| libxext-dev \ | |
| libxrandr-dev \ | |
| libxinerama-dev \ | |
| libxcursor-dev \ | |
| libxi-dev \ | |
| libxmu-dev \ | |
| build-essential \ | |
| gcc \ | |
| pkg-config | |
| echo "=== Verifying installed packages ===" | |
| dpkg -l | grep -E "(xvfb|mesa|glu|libgl|libx11)" | head -20 | |
| - name: Set up environment and start Xvfb | |
| run: | | |
| echo "=== Setting up Mesa environment variables ===" | |
| echo "LIBGL_ALWAYS_SOFTWARE=$LIBGL_ALWAYS_SOFTWARE" | |
| echo "MESA_LOADER_DRIVER_OVERRIDE=$MESA_LOADER_DRIVER_OVERRIDE" | |
| echo "=== Starting Xvfb virtual display server ===" | |
| # Start Xvfb exactly like in the justfile test-ci | |
| sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 & | |
| XVFB_PID=$! | |
| export DISPLAY=:99 | |
| echo "XVFB_PID=$XVFB_PID" >> $GITHUB_ENV | |
| echo "DISPLAY=:99" >> $GITHUB_ENV | |
| # Wait for Xvfb to fully start | |
| sleep 3 | |
| echo "Xvfb started with PID: $XVFB_PID on display :99" | |
| - name: Verify X11 and OpenGL environment | |
| run: | | |
| echo "=== Environment verification ===" | |
| echo "DISPLAY=$DISPLAY" | |
| echo "LIBGL_ALWAYS_SOFTWARE=$LIBGL_ALWAYS_SOFTWARE" | |
| echo "MESA_LOADER_DRIVER_OVERRIDE=$MESA_LOADER_DRIVER_OVERRIDE" | |
| echo "=== X11 server status ===" | |
| ps aux | grep Xvfb | grep -v grep || echo "No Xvfb processes found" | |
| echo "=== X11 display info ===" | |
| xdpyinfo -display :99 | head -20 || echo "xdpyinfo failed" | |
| echo "=== X11 connectivity test ===" | |
| xwininfo -root -display :99 || echo "xwininfo failed" | |
| echo "=== Mesa/GLX information ===" | |
| glxinfo -display :99 | grep -E "OpenGL vendor|OpenGL renderer|OpenGL version|GLX version|direct rendering" || echo "glxinfo failed" | |
| - name: Test OpenGL header availability | |
| run: | | |
| echo "=== Testing OpenGL headers and compilation ===" | |
| # Check if headers exist | |
| find /usr/include -name "gl.h" 2>/dev/null || echo "gl.h not found" | |
| find /usr/include -name "glx.h" 2>/dev/null || echo "glx.h not found" | |
| # Test basic compilation | |
| echo "Testing basic OpenGL compilation..." | |
| cat > simple_gl_test.c <<'EOF' | |
| #include <GL/gl.h> | |
| #include <stdio.h> | |
| int main(void) { | |
| printf("OpenGL headers compile successfully\n"); | |
| return 0; | |
| } | |
| EOF | |
| gcc simple_gl_test.c -o simple_gl_test -lGL | |
| ./simple_gl_test | |
| - name: Run comprehensive OpenGL context test | |
| run: | | |
| echo "=== Running comprehensive GLX context creation test ===" | |
| cat > comprehensive_gl_test.c <<'EOF' | |
| #include <GL/gl.h> | |
| #include <GL/glx.h> | |
| #include <X11/Xlib.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| void check_gl_error(const char* operation) { | |
| GLenum error = glGetError(); | |
| if (error != GL_NO_ERROR) { | |
| printf("OpenGL error after %s: %d\n", operation, error); | |
| } | |
| } | |
| int main(void) { | |
| printf("=== Starting comprehensive OpenGL test ===\n"); | |
| // Open X11 display | |
| printf("Opening X11 display...\n"); | |
| Display *dpy = XOpenDisplay(":99"); | |
| if (!dpy) { | |
| fprintf(stderr, "ERROR: Cannot open X11 display :99\n"); | |
| return 1; | |
| } | |
| printf("✓ X11 display opened successfully\n"); | |
| // Check GLX extension | |
| printf("Checking GLX extension...\n"); | |
| int glx_major, glx_minor; | |
| if (!glXQueryVersion(dpy, &glx_major, &glx_minor)) { | |
| fprintf(stderr, "ERROR: GLX extension not available\n"); | |
| XCloseDisplay(dpy); | |
| return 1; | |
| } | |
| printf("✓ GLX version: %d.%d\n", glx_major, glx_minor); | |
| // Choose visual | |
| printf("Choosing GLX visual...\n"); | |
| static int attribs[] = { | |
| GLX_RGBA, | |
| GLX_DEPTH_SIZE, 16, | |
| GLX_DOUBLEBUFFER, | |
| None | |
| }; | |
| XVisualInfo *vi = glXChooseVisual(dpy, DefaultScreen(dpy), attribs); | |
| if (!vi) { | |
| printf("WARNING: No double-buffered visual found, trying single-buffered...\n"); | |
| static int simple_attribs[] = { GLX_RGBA, GLX_DEPTH_SIZE, 16, None }; | |
| vi = glXChooseVisual(dpy, DefaultScreen(dpy), simple_attribs); | |
| } | |
| if (!vi) { | |
| fprintf(stderr, "ERROR: No appropriate GLX visual found\n"); | |
| XCloseDisplay(dpy); | |
| return 1; | |
| } | |
| printf("✓ GLX visual chosen (depth: %d, class: %d)\n", vi->depth, vi->class); | |
| // Create GLX context | |
| printf("Creating GLX context...\n"); | |
| GLXContext glc = glXCreateContext(dpy, vi, NULL, GL_TRUE); | |
| if (!glc) { | |
| fprintf(stderr, "ERROR: Failed to create GLX context\n"); | |
| XFree(vi); | |
| XCloseDisplay(dpy); | |
| return 1; | |
| } | |
| printf("✓ GLX context created successfully\n"); | |
| // Create window | |
| printf("Creating X11 window...\n"); | |
| Window root = DefaultRootWindow(dpy); | |
| XSetWindowAttributes swa; | |
| swa.colormap = XCreateColormap(dpy, root, vi->visual, AllocNone); | |
| swa.event_mask = ExposureMask | KeyPressMask; | |
| swa.background_pixel = 0; | |
| swa.border_pixel = 0; | |
| Window win = XCreateWindow(dpy, root, 0, 0, 100, 100, 0, | |
| vi->depth, InputOutput, vi->visual, | |
| CWColormap | CWEventMask | CWBackPixel | CWBorderPixel, &swa); | |
| if (!win) { | |
| fprintf(stderr, "ERROR: Failed to create X11 window\n"); | |
| glXDestroyContext(dpy, glc); | |
| XFree(vi); | |
| XCloseDisplay(dpy); | |
| return 1; | |
| } | |
| XMapWindow(dpy, win); | |
| printf("✓ X11 window created and mapped\n"); | |
| // Make context current | |
| printf("Making GLX context current...\n"); | |
| if (!glXMakeCurrent(dpy, win, glc)) { | |
| fprintf(stderr, "ERROR: Failed to make GLX context current\n"); | |
| XDestroyWindow(dpy, win); | |
| glXDestroyContext(dpy, glc); | |
| XFree(vi); | |
| XCloseDisplay(dpy); | |
| return 1; | |
| } | |
| printf("✓ GLX context is now current\n"); | |
| // Test OpenGL calls | |
| printf("Testing OpenGL calls...\n"); | |
| const GLubyte *vendor = glGetString(GL_VENDOR); | |
| const GLubyte *renderer = glGetString(GL_RENDERER); | |
| const GLubyte *version = glGetString(GL_VERSION); | |
| const GLubyte *extensions = glGetString(GL_EXTENSIONS); | |
| printf("✓ OpenGL Vendor: %s\n", vendor ? (char*)vendor : "NULL"); | |
| printf("✓ OpenGL Renderer: %s\n", renderer ? (char*)renderer : "NULL"); | |
| printf("✓ OpenGL Version: %s\n", version ? (char*)version : "NULL"); | |
| check_gl_error("glGetString calls"); | |
| // Test basic rendering | |
| printf("Testing basic OpenGL rendering...\n"); | |
| glClearColor(0.2f, 0.3f, 0.4f, 1.0f); | |
| check_gl_error("glClearColor"); | |
| glClear(GL_COLOR_BUFFER_BIT); | |
| check_gl_error("glClear"); | |
| glXSwapBuffers(dpy, win); | |
| printf("✓ Rendered and swapped buffers successfully\n"); | |
| // Test some basic OpenGL state | |
| GLint max_texture_size; | |
| glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); | |
| printf("✓ Max texture size: %d\n", max_texture_size); | |
| check_gl_error("glGetIntegerv"); | |
| // Cleanup | |
| printf("Cleaning up...\n"); | |
| glXMakeCurrent(dpy, None, NULL); | |
| glXDestroyContext(dpy, glc); | |
| XDestroyWindow(dpy, win); | |
| XFree(vi); | |
| XCloseDisplay(dpy); | |
| printf("=== OpenGL test completed successfully! ===\n"); | |
| return 0; | |
| } | |
| EOF | |
| echo "Compiling comprehensive OpenGL test..." | |
| gcc comprehensive_gl_test.c -o comprehensive_gl_test -lGL -lX11 -lGLU | |
| echo "Running comprehensive OpenGL test..." | |
| ./comprehensive_gl_test | |
| - name: Test PUGL-style context creation (matching Floe requirements) | |
| run: | | |
| echo "=== Testing PUGL-style OpenGL context creation ===" | |
| echo "Environment variables:" | |
| echo "DISPLAY=$DISPLAY" | |
| echo "LIBGL_ALWAYS_SOFTWARE=$LIBGL_ALWAYS_SOFTWARE" | |
| echo "MESA_LOADER_DRIVER_OVERRIDE=$MESA_LOADER_DRIVER_OVERRIDE" | |
| # Test that exactly matches PUGL's context creation approach | |
| cat > pugl_style_test.c <<'EOF' | |
| #include <GL/gl.h> | |
| #include <GL/glx.h> | |
| #include <X11/Xlib.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| // Function pointer for GLX_ARB_create_context | |
| typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSARBPROC)(Display*, GLXFBConfig, GLXContext, Bool, const int*); | |
| int main(void) { | |
| printf("=== Testing PUGL-style OpenGL context creation ===\n"); | |
| Display *display = XOpenDisplay(":99"); | |
| if (!display) { | |
| fprintf(stderr, "ERROR: Cannot open display :99\n"); | |
| return 1; | |
| } | |
| printf("✓ Display opened\n"); | |
| int screen = DefaultScreen(display); | |
| // PUGL-style FB config attributes (matching Floe's requirements) | |
| const int attrs[] = { | |
| GLX_X_RENDERABLE, True, | |
| GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, | |
| GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, | |
| GLX_RENDER_TYPE, GLX_RGBA_BIT, | |
| GLX_RED_SIZE, 8, | |
| GLX_GREEN_SIZE, 8, | |
| GLX_BLUE_SIZE, 8, | |
| GLX_ALPHA_SIZE, 8, | |
| GLX_DEPTH_SIZE, 24, | |
| GLX_STENCIL_SIZE, 8, | |
| GLX_DOUBLEBUFFER, True, | |
| None | |
| }; | |
| printf("Choosing FB config...\n"); | |
| int n_fbc = 0; | |
| GLXFBConfig* fbc = glXChooseFBConfig(display, screen, attrs, &n_fbc); | |
| if (n_fbc <= 0 || !fbc) { | |
| fprintf(stderr, "ERROR: No suitable FB config found\n"); | |
| XCloseDisplay(display); | |
| return 1; | |
| } | |
| printf("✓ Found %d FB configs\n", n_fbc); | |
| // Get visual info | |
| XVisualInfo* vi = glXGetVisualFromFBConfig(display, fbc[0]); | |
| if (!vi) { | |
| fprintf(stderr, "ERROR: Could not get visual from FB config\n"); | |
| XFree(fbc); | |
| XCloseDisplay(display); | |
| return 1; | |
| } | |
| printf("✓ Got visual info\n"); | |
| // Check for GLX extensions that PUGL uses | |
| const char* extensions = glXQueryExtensionsString(display, screen); | |
| printf("Available GLX extensions:\n"); | |
| if (strstr(extensions, "GLX_ARB_create_context")) { | |
| printf(" ✓ GLX_ARB_create_context\n"); | |
| } else { | |
| printf(" ✗ GLX_ARB_create_context NOT AVAILABLE\n"); | |
| } | |
| if (strstr(extensions, "GLX_EXT_swap_control")) { | |
| printf(" ✓ GLX_EXT_swap_control\n"); | |
| } else { | |
| printf(" ✗ GLX_EXT_swap_control\n"); | |
| } | |
| GLXContext ctx = NULL; | |
| // Try modern context creation (like PUGL does) | |
| if (strstr(extensions, "GLX_ARB_create_context")) { | |
| printf("Attempting modern context creation (OpenGL 3.3)...\n"); | |
| PFNGLXCREATECONTEXTATTRIBSARBPROC create_context = | |
| (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress( | |
| (const unsigned char*)"glXCreateContextAttribsARB"); | |
| if (create_context) { | |
| // Request OpenGL 3.3 Compatibility Profile (like Floe) | |
| const int ctx_attrs[] = { | |
| GLX_CONTEXT_MAJOR_VERSION_ARB, 3, | |
| GLX_CONTEXT_MINOR_VERSION_ARB, 3, | |
| GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, | |
| None | |
| }; | |
| ctx = create_context(display, fbc[0], 0, True, ctx_attrs); | |
| if (ctx) { | |
| printf("✓ Modern OpenGL 3.3 context created successfully!\n"); | |
| } else { | |
| printf("✗ Modern context creation failed\n"); | |
| } | |
| } else { | |
| printf("✗ glXCreateContextAttribsARB function not found\n"); | |
| } | |
| } | |
| // Fallback to legacy context (like PUGL does) | |
| if (!ctx) { | |
| printf("Falling back to legacy context creation...\n"); | |
| ctx = glXCreateNewContext(display, fbc[0], GLX_RGBA_TYPE, 0, True); | |
| if (ctx) { | |
| printf("✓ Legacy context created successfully\n"); | |
| } else { | |
| printf("✗ Legacy context creation also failed\n"); | |
| XFree(vi); | |
| XFree(fbc); | |
| XCloseDisplay(display); | |
| return 1; | |
| } | |
| } | |
| // Create a window | |
| Window root = RootWindow(display, screen); | |
| XSetWindowAttributes swa; | |
| swa.colormap = XCreateColormap(display, root, vi->visual, AllocNone); | |
| swa.event_mask = ExposureMask; | |
| Window win = XCreateWindow(display, root, 0, 0, 100, 100, 0, | |
| vi->depth, InputOutput, vi->visual, | |
| CWColormap | CWEventMask, &swa); | |
| XMapWindow(display, win); | |
| // Make context current and test | |
| if (!glXMakeCurrent(display, win, ctx)) { | |
| fprintf(stderr, "ERROR: Failed to make context current\n"); | |
| return 1; | |
| } | |
| printf("✓ Context made current\n"); | |
| // Test OpenGL | |
| printf("OpenGL Info:\n"); | |
| printf(" Vendor: %s\n", glGetString(GL_VENDOR)); | |
| printf(" Renderer: %s\n", glGetString(GL_RENDERER)); | |
| printf(" Version: %s\n", glGetString(GL_VERSION)); | |
| printf(" GLSL Version: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION)); | |
| // Test some OpenGL operations | |
| glClearColor(0.5f, 0.5f, 0.5f, 1.0f); | |
| glClear(GL_COLOR_BUFFER_BIT); | |
| GLenum error = glGetError(); | |
| if (error != GL_NO_ERROR) { | |
| printf("OpenGL error: %d\n", error); | |
| } else { | |
| printf("✓ Basic OpenGL operations successful\n"); | |
| } | |
| // Cleanup | |
| glXMakeCurrent(display, None, NULL); | |
| glXDestroyContext(display, ctx); | |
| XDestroyWindow(display, win); | |
| XFree(vi); | |
| XFree(fbc); | |
| XCloseDisplay(display); | |
| printf("=== PUGL-style test completed successfully! ===\n"); | |
| return 0; | |
| } | |
| EOF | |
| gcc pugl_style_test.c -o pugl_style_test -lGL -lX11 | |
| ./pugl_style_test | |
| - name: Test different OpenGL context configurations | |
| run: | | |
| echo "=== Testing different context attribute combinations ===" | |
| cat > context_variations_test.c <<'EOF' | |
| #include <GL/gl.h> | |
| #include <GL/glx.h> | |
| #include <X11/Xlib.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| void test_fb_config(Display* display, int screen, const char* name, const int* attrs) { | |
| printf("\n--- Testing %s ---\n", name); | |
| int n_fbc = 0; | |
| GLXFBConfig* fbc = glXChooseFBConfig(display, screen, attrs, &n_fbc); | |
| if (n_fbc <= 0 || !fbc) { | |
| printf("✗ No FB configs found for %s\n", name); | |
| return; | |
| } | |
| printf("✓ Found %d FB configs for %s\n", n_fbc, name); | |
| // Try to get visual | |
| XVisualInfo* vi = glXGetVisualFromFBConfig(display, fbc[0]); | |
| if (!vi) { | |
| printf("✗ Could not get visual for %s\n", name); | |
| XFree(fbc); | |
| return; | |
| } | |
| // Try legacy context creation | |
| GLXContext ctx = glXCreateNewContext(display, fbc[0], GLX_RGBA_TYPE, 0, True); | |
| if (ctx) { | |
| printf("✓ Legacy context creation successful for %s\n", name); | |
| glXDestroyContext(display, ctx); | |
| } else { | |
| printf("✗ Legacy context creation failed for %s\n", name); | |
| } | |
| XFree(vi); | |
| XFree(fbc); | |
| } | |
| int main(void) { | |
| Display *display = XOpenDisplay(":99"); | |
| if (!display) { | |
| fprintf(stderr, "ERROR: Cannot open display\n"); | |
| return 1; | |
| } | |
| int screen = DefaultScreen(display); | |
| // Test 1: Minimal config (should work) | |
| const int minimal[] = { | |
| GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, | |
| GLX_RENDER_TYPE, GLX_RGBA_BIT, | |
| None | |
| }; | |
| test_fb_config(display, screen, "Minimal config", minimal); | |
| // Test 2: Basic config without stencil | |
| const int basic[] = { | |
| GLX_X_RENDERABLE, True, | |
| GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, | |
| GLX_RENDER_TYPE, GLX_RGBA_BIT, | |
| GLX_RED_SIZE, 8, | |
| GLX_GREEN_SIZE, 8, | |
| GLX_BLUE_SIZE, 8, | |
| GLX_DEPTH_SIZE, 24, | |
| GLX_DOUBLEBUFFER, True, | |
| None | |
| }; | |
| test_fb_config(display, screen, "Basic config (no stencil)", basic); | |
| // Test 3: PUGL-style with smaller depth | |
| const int pugl_small_depth[] = { | |
| GLX_X_RENDERABLE, True, | |
| GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, | |
| GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, | |
| GLX_RENDER_TYPE, GLX_RGBA_BIT, | |
| GLX_RED_SIZE, 8, | |
| GLX_GREEN_SIZE, 8, | |
| GLX_BLUE_SIZE, 8, | |
| GLX_DEPTH_SIZE, 16, // Smaller depth | |
| GLX_DOUBLEBUFFER, True, | |
| None | |
| }; | |
| test_fb_config(display, screen, "PUGL-style (16-bit depth)", pugl_small_depth); | |
| // Test 4: Full PUGL config (what Floe actually requests) | |
| const int pugl_full[] = { | |
| GLX_X_RENDERABLE, True, | |
| GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, | |
| GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, | |
| GLX_RENDER_TYPE, GLX_RGBA_BIT, | |
| GLX_RED_SIZE, 8, | |
| GLX_GREEN_SIZE, 8, | |
| GLX_BLUE_SIZE, 8, | |
| GLX_ALPHA_SIZE, 8, | |
| GLX_DEPTH_SIZE, 24, | |
| GLX_STENCIL_SIZE, 8, | |
| GLX_DOUBLEBUFFER, True, | |
| None | |
| }; | |
| test_fb_config(display, screen, "Full PUGL config (what Floe uses)", pugl_full); | |
| // Test Mesa llvmpipe capabilities | |
| printf("\n=== Mesa llvmpipe capabilities ===\n"); | |
| // Create a basic context to query capabilities | |
| const int simple[] = { GLX_RGBA, None }; | |
| XVisualInfo* vi = glXChooseVisual(display, screen, (int*)simple); | |
| if (vi) { | |
| GLXContext ctx = glXCreateContext(display, vi, NULL, GL_TRUE); | |
| if (ctx) { | |
| Window root = RootWindow(display, screen); | |
| XSetWindowAttributes swa; | |
| swa.colormap = XCreateColormap(display, root, vi->visual, AllocNone); | |
| Window win = XCreateWindow(display, root, 0, 0, 1, 1, 0, | |
| vi->depth, InputOutput, vi->visual, | |
| CWColormap, &swa); | |
| if (glXMakeCurrent(display, win, ctx)) { | |
| printf("OpenGL Limits:\n"); | |
| GLint max_texture_size; | |
| glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); | |
| printf(" Max texture size: %d\n", max_texture_size); | |
| GLint max_samples = 0; | |
| glGetIntegerv(GL_MAX_SAMPLES, &max_samples); | |
| GLenum error = glGetError(); | |
| if (error == GL_NO_ERROR && max_samples > 0) { | |
| printf(" Max samples (MSAA): %d\n", max_samples); | |
| } else { | |
| printf(" MSAA not supported (error: %d)\n", error); | |
| } | |
| printf(" OpenGL version: %s\n", glGetString(GL_VERSION)); | |
| printf(" GLSL version: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION)); | |
| } | |
| glXDestroyContext(display, ctx); | |
| XDestroyWindow(display, win); | |
| } | |
| XFree(vi); | |
| } | |
| XCloseDisplay(display); | |
| return 0; | |
| } | |
| EOF | |
| gcc context_variations_test.c -o context_variations_test -lGL -lX11 | |
| ./context_variations_test | |
| - name: Debug Mesa drivers and GLX info | |
| run: | | |
| echo "=== Mesa driver debugging ===" | |
| # List available Mesa drivers | |
| find /usr/lib -name "*dri*" -type f 2>/dev/null | head -10 | |
| # Check Mesa environment variables | |
| echo "Mesa environment variables:" | |
| env | grep -E "(MESA|LIBGL|GLX)" || echo "No Mesa environment variables set" | |
| # Test GLX directly | |
| echo "=== GLX capabilities ===" | |
| glxinfo -display :99 | grep -A 20 "GLX version" || echo "glxinfo GLX check failed" | |
| echo "=== GLX extensions ===" | |
| glxinfo -display :99 | grep -A 10 "GLX extensions" || echo "glxinfo extensions check failed" | |
| echo "=== Direct rendering status ===" | |
| glxinfo -display :99 | grep "direct rendering" || echo "direct rendering check failed" | |
| - name: Cleanup | |
| if: always() | |
| run: | | |
| echo "=== Cleaning up ===" | |
| # Kill Xvfb if it's still running | |
| if [ -n "$XVFB_PID" ]; then | |
| sudo kill $XVFB_PID 2>/dev/null || true | |
| echo "Xvfb process $XVFB_PID terminated" | |
| fi | |
| # Clean up any remaining Xvfb processes | |
| sudo pkill Xvfb 2>/dev/null || true | |
| echo "Cleanup completed" | |
| - name: Summary | |
| if: always() | |
| run: | | |
| echo "=== Test Summary ===" | |
| echo "This workflow tested:" | |
| echo "1. ✓ Mesa package installation" | |
| echo "2. ✓ Xvfb virtual display setup" | |
| echo "3. ✓ OpenGL header compilation" | |
| echo "4. ✓ GLX context creation and OpenGL rendering" | |
| echo "5. ✓ Environment matching your main CI configuration" | |
| echo "" | |
| echo "If all steps passed, your OpenGL environment should work with Floe tests!" |