summaryrefslogtreecommitdiffstats
path: root/tools/guest-diag/gz_pbuf.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-12 18:28:16 -0500
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-12 18:28:16 -0500
commit800c108f9d2463066a221a0e4ff56867304551a6 (patch)
treef9fec57a2402c5022f19f4a0be164e58f96b7fe5 /tools/guest-diag/gz_pbuf.c
parent8dce7e59027e8d07ccdf4aa6ac3da02b6e9e9fd9 (diff)
downloadopen-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.c154
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;
+ }
+}