From 800c108f9d2463066a221a0e4ff56867304551a6 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Thu, 12 Nov 2026 18:28:16 -0500 Subject: 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. --- tools/guest-diag/cycle-r1780.sh | 17 ++++- tools/guest-diag/gz_pbuf.c | 154 ++++++++++++++++++++++++++++++++++++++++ tools/guest-diag/sdl_cap.c | 10 ++- 3 files changed, 175 insertions(+), 6 deletions(-) create mode 100644 tools/guest-diag/gz_pbuf.c diff --git a/tools/guest-diag/cycle-r1780.sh b/tools/guest-diag/cycle-r1780.sh index 23cf0d1..0acab1c 100755 --- a/tools/guest-diag/cycle-r1780.sh +++ b/tools/guest-diag/cycle-r1780.sh @@ -16,7 +16,7 @@ ARGV_FILE="${INSMOD_PARAMS:-$HERE/params-r1780.txt}" BACKUP="$REPO/backups/evidence-20261002-victory/r1780" DISK="${GUEST_DISK:-/home/rmcore/.local/libvf.io/kernel/linux.qcow2}" MDEV_PARENT="0000:01:00.0" -MDEV_TYPE="nvidia-nvidia-vgpu-turing" +MDEV_TYPE="${MDEV_TYPE:-}" RUNDIR="$HERE/run" QEMU_SCRIPT="$HERE/launch_qemu_r1780.run.sh" mkdir -p "$RUNDIR" "$BACKUP" @@ -72,8 +72,7 @@ if [ -d /sys/module/vgsp ]; then fi echo "[cycle $TAG] load VFIO/mdev prerequisites" -sudo modprobe vfio vfio_iommu_type1 vfio_pci mdev 2>/dev/null || true -sudo modprobe vfio_iommu_type1 2>/dev/null || true +for m in vfio vfio_iommu_type1 vfio_pci mdev; do sudo modprobe "$m" 2>/dev/null || true; done echo "[cycle $TAG] stop nvidia-persistenced, power/control=on" sudo systemctl stop nvidia-persistenced 2>/dev/null || true @@ -84,6 +83,18 @@ echo "[cycle $TAG] insmod $(basename "$MODULE")" # shellcheck disable=SC2046 sudo insmod "$MODULE" $(cat "$ARGV_FILE") +for i in $(seq 1 40); do + [ -d "/sys/class/mdev_bus/$MDEV_PARENT/mdev_supported_types" ] && break + sleep 0.5 +done +if [ -z "$MDEV_TYPE" ]; then + MDEV_TYPE=$(ls "/sys/class/mdev_bus/$MDEV_PARENT/mdev_supported_types" 2>/dev/null | grep -m1 'vgpu-turing-2g$' || true) +fi +if [ -z "$MDEV_TYPE" ]; then + MDEV_TYPE=$(ls "/sys/class/mdev_bus/$MDEV_PARENT/mdev_supported_types" 2>/dev/null | grep -m1 'vgpu-turing$' || true) +fi +if [ -z "$MDEV_TYPE" ]; then echo "FATAL: no vgpu-turing mdev type under $MDEV_PARENT"; ls "/sys/class/mdev_bus/$MDEV_PARENT/mdev_supported_types" 2>/dev/null; exit 1; fi +echo "[cycle $TAG] mdev type $MDEV_TYPE" U=$(uuidgen) echo "$U" | sudo tee "/sys/class/mdev_bus/$MDEV_PARENT/mdev_supported_types/$MDEV_TYPE/create" >/dev/null if [ ! -d "/sys/bus/mdev/devices/$U" ]; then echo "FATAL: mdev create failed"; exit 1; fi 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 +#include +#include +#include +#include +#include +#include + +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; + } +} diff --git a/tools/guest-diag/sdl_cap.c b/tools/guest-diag/sdl_cap.c index 23c83ab..5b9c096 100644 --- a/tools/guest-diag/sdl_cap.c +++ b/tools/guest-diag/sdl_cap.c @@ -87,10 +87,12 @@ __attribute__((constructor)) static void cap_init(void) if (h) real_glReadPixels = dlsym(h, "glReadPixels"); } - fprintf(stderr, "[gzcap] init path=%s present=%p updwin=%p swap=%p read=%p gros=%p\n", - p, (void *)real_RenderPresent, (void *)real_UpdateWindowSurface, + fprintf(stderr, "[gzcap] init pid=%d path=%s present=%p updwin=%p swap=%p read=%p gros=%p\n", + (int)getpid(), p, (void *)real_RenderPresent, (void *)real_UpdateWindowSurface, (void *)real_GL_SwapWindow, (void *)real_RenderReadPixels, (void *)real_GetRendererOutputSize, (void *)real_glReadPixels); + if (!real_glReadPixels && !real_RenderReadPixels) + return; cap_fp = fopen(p, "wb"); if (!cap_fp) return; @@ -192,7 +194,9 @@ void SDL_GL_SwapWindow(SDL_Window *win) static size_t gbufsz; if (!hit++) - fprintf(stderr, "[gzcap] hook GLSwapWindow\n"); + fprintf(stderr, "[gzcap] hook GLSwapWindow pid=%d fp=%p read=%p gros=%p\n", + (int)getpid(), (void *)cap_fp, (void *)real_glReadPixels, + (void *)real_GL_GetDrawableSize); if (cap_fp && !cap_stop && real_glReadPixels && real_GL_GetDrawableSize) { int w = 0, h = 0; -- cgit v1.2.3