summaryrefslogtreecommitdiffstats
path: root/tools/guest-diag/test_tri.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-12 20:01:04 -0500
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-12 20:01:04 -0500
commit725898e44666b4def396f7f3c5e50712fd37aa33 (patch)
tree261bba910db49036624cc2cf89baac6554a6f58d /tools/guest-diag/test_tri.c
parent800c108f9d2463066a221a0e4ff56867304551a6 (diff)
downloadopen-iov-725898e44666b4def396f7f3c5e50712fd37aa33.tar.gz
open-iov-725898e44666b4def396f7f3c5e50712fd37aa33.zip
vgsp: stop fabricating 0xFFFF into the nvPush error notifier; add r1780 GL ops tooling
The uncommitted keep-alive change wrote 0xFFFF into slot 0's status field (u16 at notifier+0x0e) on the X DDX / GLX kick-idle channel families. Ground truth (570.144 reference sources + stock nvidia_drv.so disassembly): slot 0 of an nvPush notifier block is the ERROR notifier; nvPushCheckChannelError reads that status and 0xFFFF aborts every nvPushWaitForNotifier/idle wait as a channel error. There is no pb_kickIfIdle in 570.144 - the DDX DMA-idle test reads the progress-tracker semaphore word, not this slot. Leave slot 0 untouched; keep the 0x8000->0 completion ack for the remaining slots and the r864 0xFFFF/0x8000 completion on the RC-watchdog/beef families. Correct the CONT.408/409 comments accordingly. New host/guest tooling: gpa.py (QMP gva2gpa), tick_gen.py (guest-RM timer BO tick), guest_mode.sh (shared nvClip modeNum reader), gl_verify.sh (X/GLX bring-up with ScreenInit-lottery retries), push_gl_tools.sh, the gzdoom_pbuf_run.sh guest recipe and the test_tri SDL2 harness validation program; ignore tools/guest-diag/build/.
Diffstat (limited to 'tools/guest-diag/test_tri.c')
-rw-r--r--tools/guest-diag/test_tri.c112
1 files changed, 112 insertions, 0 deletions
diff --git a/tools/guest-diag/test_tri.c b/tools/guest-diag/test_tri.c
new file mode 100644
index 0000000..dc42876
--- /dev/null
+++ b/tools/guest-diag/test_tri.c
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright (c) 2026 Open-IOV contributors
+// test_tri.c - minimal SDL2 + OpenGL triangle for the offscreen pbuffer
+// harness. Intended to be run with SDL_VIDEODRIVER=offscreen and the
+// gz_pbuf.so shim preloaded (plus sdl_cap.so to capture the swaps):
+//
+// SDL_VIDEODRIVER=offscreen DISPLAY=:0 \
+// LD_PRELOAD="/tmp/sdl_cap.so /tmp/gz_pbuf.so" GZCAP=/tmp/testframes.bin \
+// ./test_tri 20 640 480
+//
+// It creates an SDL2 GL window/context (the shim turns the context into a
+// GLX pbuffer), clears to a colour, draws a rotating triangle, reads the
+// centre pixel back (non-black proof), and calls SDL_GL_SwapWindow each
+// frame. The sdl_cap.so hook captures the swap; the gz_pbuf.so hook turns
+// the swap into glFinish. Build:
+// gcc -O2 -o test_tri test_tri.c $(pkg-config --cflags --libs sdl2) -lGL
+#include <SDL2/SDL.h>
+#include <GL/gl.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv)
+{
+ int frames = argc > 1 ? atoi(argv[1]) : 20;
+ int w = argc > 2 ? atoi(argv[2]) : 640;
+ int h = argc > 3 ? atoi(argv[3]) : 480;
+ SDL_Window *win;
+ SDL_GLContext ctx;
+ int i;
+
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ if (SDL_Init(SDL_INIT_VIDEO) != 0) {
+ fprintf(stderr, "test_tri: SDL_Init: %s\n", SDL_GetError());
+ return 1;
+ }
+ printf("test_tri: videodriver=%s\n",
+ SDL_GetCurrentVideoDriver() ? SDL_GetCurrentVideoDriver() : "?");
+
+ SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+ win = SDL_CreateWindow("test_tri", SDL_WINDOWPOS_UNDEFINED,
+ SDL_WINDOWPOS_UNDEFINED, w, h,
+ SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN);
+ if (!win) {
+ fprintf(stderr, "test_tri: SDL_CreateWindow: %s\n", SDL_GetError());
+ SDL_Quit();
+ return 2;
+ }
+
+ ctx = SDL_GL_CreateContext(win);
+ if (!ctx) {
+ fprintf(stderr, "test_tri: SDL_GL_CreateContext: %s\n",
+ SDL_GetError());
+ SDL_DestroyWindow(win);
+ SDL_Quit();
+ return 3;
+ }
+ if (SDL_GL_MakeCurrent(win, ctx) != 0)
+ fprintf(stderr, "test_tri: SDL_GL_MakeCurrent: %s\n",
+ SDL_GetError());
+ SDL_GL_SetSwapInterval(0);
+
+ printf("test_tri: GL %s | %s | %s\n",
+ (const char *)glGetString(GL_VENDOR),
+ (const char *)glGetString(GL_RENDERER),
+ (const char *)glGetString(GL_VERSION));
+
+ for (i = 0; i < frames; i++) {
+ float a = (float)i * 0.10f;
+ unsigned char px[4] = { 0, 0, 0, 0 };
+
+ glViewport(0, 0, w, h);
+ glClearColor(0.05f, 0.05f, 0.10f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glRotatef(a * 57.29578f, 0.0f, 0.0f, 1.0f);
+
+ glBegin(GL_TRIANGLES);
+ glColor3f(1.0f, 0.2f, 0.1f);
+ glVertex2f(0.0f, 0.8f);
+ glColor3f(0.1f, 1.0f, 0.3f);
+ glVertex2f(-0.8f, -0.6f);
+ glColor3f(0.2f, 0.3f, 1.0f);
+ glVertex2f(0.8f, -0.6f);
+ glEnd();
+ glFinish();
+
+ glReadPixels(w / 2, h / 2, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, px);
+ printf("test_tri: frame=%d centre=%02x%02x%02x%02x err=0x%x\n",
+ i, px[0], px[1], px[2], px[3], glGetError());
+
+ SDL_GL_SwapWindow(win);
+ SDL_Delay(20);
+ }
+
+ printf("test_tri: done frames=%d %dx%d\n", frames, w, h);
+ SDL_GL_DeleteContext(ctx);
+ SDL_DestroyWindow(win);
+ SDL_Quit();
+ return 0;
+}