diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-11-12 18:28:16 -0500 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-11-12 18:28:16 -0500 |
| commit | 800c108f9d2463066a221a0e4ff56867304551a6 (patch) | |
| tree | f9fec57a2402c5022f19f4a0be164e58f96b7fe5 /tools/guest-diag/gz_pbuf.c | |
| parent | 8dce7e59027e8d07ccdf4aa6ac3da02b6e9e9fd9 (diff) | |
| download | open-iov-800c108f9d2463066a221a0e4ff56867304551a6.tar.gz open-iov-800c108f9d2463066a221a0e4ff56867304551a6.zip | |
tools: fix r1780 cycle prerequisites and add SDL GLX-pbuffer shim
- cycle-r1780.sh: load vfio modules one per modprobe (the multi-module
form was silently treating the extra names as parameters and never
loading mdev); auto-detect the vgpu mdev type and prefer the 2 GiB
type used by the campaign.
- sdl_cap.c: gate capture-file creation to processes that can actually
read GL pixels (a child was truncating the capture), and log the
capture pid/pointers.
- gz_pbuf.c: LD_PRELOAD shim that gives an SDL2 GL client a GLX pbuffer
context on the guest's NVIDIA X server (the proven gl_frames path),
with SDL_GL_GetDrawableSize/SwapWindow interception.
Diffstat (limited to 'tools/guest-diag/gz_pbuf.c')
| -rw-r--r-- | tools/guest-diag/gz_pbuf.c | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/tools/guest-diag/gz_pbuf.c b/tools/guest-diag/gz_pbuf.c new file mode 100644 index 0000000..5c03732 --- /dev/null +++ b/tools/guest-diag/gz_pbuf.c @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: BSD-3-Clause +// gz_pbuf.c - LD_PRELOAD shim that gives an SDL2 GL client a GLX pbuffer +// context instead of a window context. The pbuffer path is proven on the +// emulated vGPU (gl_frames); the window drawable path wedges the X server. +// Build: gcc -shared -fPIC -O2 -o gz_pbuf.so gz_pbuf.c -lGL -lX11 -ldl + +#define _GNU_SOURCE +#include <dlfcn.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <X11/Xlib.h> +#include <GL/glx.h> +#include <GL/gl.h> + +typedef struct SDL_Window SDL_Window; + +static GLXContext g_ctx; +static GLXPbuffer g_pb; +static Display *g_dpy; +static int g_w, g_h; +static void *g_win; + +static void *(*real_GetWindowSize)(SDL_Window *, int *, int *); +static int (*real_MakeCurrent)(SDL_Window *, void *); +static void (*real_SwapWindow)(SDL_Window *); + +static void resolve(void) +{ + if (!real_GetWindowSize) + real_GetWindowSize = dlsym(RTLD_NEXT, "SDL_GetWindowSize"); + if (!real_MakeCurrent) + real_MakeCurrent = dlsym(RTLD_NEXT, "SDL_GL_MakeCurrent"); + if (!real_SwapWindow) + real_SwapWindow = dlsym(RTLD_NEXT, "SDL_GL_SwapWindow"); +} + +static int make_pb(int w, int h) +{ + static int attribs[] = { + GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT, + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, + GLX_ALPHA_SIZE, 8, + GLX_DOUBLEBUFFER, False, + None + }; + GLXFBConfig *fb; + int n = 0, scr; + + if (!g_dpy) + g_dpy = XOpenDisplay(NULL); + if (!g_dpy) + return 0; + scr = DefaultScreen(g_dpy); + fb = glXChooseFBConfig(g_dpy, scr, attribs, &n); + if (!fb || n < 1) + return 0; + g_pb = glXCreatePbuffer(g_dpy, fb[0], (int[]){ + GLX_PBUFFER_WIDTH, w, GLX_PBUFFER_HEIGHT, h, None }); + if (!g_pb) + return 0; + g_ctx = glXCreateNewContext(g_dpy, fb[0], GLX_RGBA_TYPE, NULL, True); + if (!g_ctx) { + glXDestroyPbuffer(g_dpy, g_pb); + g_pb = 0; + return 0; + } + g_w = w; + g_h = h; + return 1; +} + +void *SDL_GL_CreateContext(SDL_Window *win) +{ + int w = 640, h = 480; + const char *ew, *eh; + resolve(); + ew = getenv("GZPBUF_W"); eh = getenv("GZPBUF_H"); + if (ew && eh) { w = atoi(ew); h = atoi(eh); } + else if (real_GetWindowSize) { + real_GetWindowSize(win, &w, &h); + if (w <= 0 || h <= 0) { w = 640; h = 480; } + } + if (!make_pb(w, h)) { + fprintf(stderr, "[gzpbuf] pbuffer create failed\n"); + return NULL; + } + g_win = win; + glXMakeCurrent(g_dpy, g_pb, g_ctx); + fprintf(stderr, "[gzpbuf] pbuffer %dx%d ctx=%p\n", g_w, g_h, (void *)g_ctx); + return (void *)g_ctx; +} + +int SDL_GL_MakeCurrent(SDL_Window *win, void *ctx) +{ + resolve(); + if (ctx && g_pb) { + glXMakeCurrent(g_dpy, g_pb, g_ctx); + return 0; + } + if (real_MakeCurrent) + return real_MakeCurrent(win, ctx); + return 0; +} + +void SDL_GL_SwapWindow(SDL_Window *win) +{ + (void)win; + glFinish(); +} + +void SDL_GL_GetDrawableSize(SDL_Window *win, int *w, int *h) +{ + resolve(); + if (g_w > 0 && g_h > 0) { + if (w) *w = g_w; + if (h) *h = g_h; + return; + } + if (real_GetWindowSize) { + real_GetWindowSize(win, w, h); + return; + } + if (w) *w = 640; + if (h) *h = 480; +} + +void SDL_GL_GetWindowSize(SDL_Window *win, int *w, int *h) +{ + SDL_GL_GetDrawableSize(win, w, h); +} + +void *SDL_GL_GetCurrentContext(void) +{ + return (void *)g_ctx; +} + +SDL_Window *SDL_GL_GetCurrentWindow(void) +{ + return (SDL_Window *)g_win; +} + +void SDL_GL_DeleteContext(void *ctx) +{ + if (g_ctx && (!ctx || ctx == (void *)g_ctx)) { + glXMakeCurrent(g_dpy, None, NULL); + glXDestroyContext(g_dpy, g_ctx); + if (g_pb) + glXDestroyPbuffer(g_dpy, g_pb); + g_ctx = NULL; + g_pb = 0; + } +} |
