From 222f1a2693d1371409a71e8adf3c0c0d57f83020 Mon Sep 17 00:00:00 2001
From: Cameron Gutman <[EMAIL REDACTED]>
Date: Mon, 15 Aug 2022 22:51:15 -0500
Subject: [PATCH] testgles2: Add --threaded option to use a render thread per
window
This is helpful for reproducing bugs like #6056
---
test/testgles2.c | 151 +++++++++++++++++++++++++++++++++--------------
1 file changed, 108 insertions(+), 43 deletions(-)
diff --git a/test/testgles2.c b/test/testgles2.c
index 4b9e5d250c3..6ef805b0b12 100644
--- a/test/testgles2.c
+++ b/test/testgles2.c
@@ -51,6 +51,13 @@ typedef struct shader_data
GLuint color_buffer;
} shader_data;
+typedef struct thread_data
+{
+ SDL_Thread *thread;
+ int done;
+ int index;
+} thread_data;
+
static SDLTest_CommonState *state;
static SDL_GLContext *context = NULL;
static int depth = 16;
@@ -434,6 +441,7 @@ Render(unsigned int width, unsigned int height, shader_data* data)
if(data->angle_z >= 360) data->angle_z -= 360;
if(data->angle_z < 0) data->angle_z += 360;
+ GL_CHECK(ctx.glViewport(0, 0, width, height));
GL_CHECK(ctx.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT));
GL_CHECK(ctx.glDrawArrays(GL_TRIANGLES, 0, 36));
}
@@ -441,56 +449,84 @@ Render(unsigned int width, unsigned int height, shader_data* data)
int done;
Uint32 frames;
shader_data *datas;
+thread_data *threads;
+
+static void
+render_window(int index)
+{
+ int w, h, status;
+
+ if (!state->windows[index]) {
+ return;
+ }
+
+ status = SDL_GL_MakeCurrent(state->windows[index], context[index]);
+ if (status) {
+ SDL_Log("SDL_GL_MakeCurrent(): %s\n", SDL_GetError());
+ return;
+ }
+
+ SDL_GL_GetDrawableSize(state->windows[index], &w, &h);
+ Render(w, h, &datas[index]);
+ SDL_GL_SwapWindow(state->windows[index]);
+ ++frames;
+}
-void loop()
+static int SDLCALL
+render_thread_fn(void* render_ctx)
+{
+ thread_data *thread = render_ctx;
+
+ while (!done && !thread->done && state->windows[thread->index]) {
+ render_window(thread->index);
+ }
+
+ SDL_GL_MakeCurrent(state->windows[thread->index], NULL);
+ return 0;
+}
+
+static void
+loop_threaded()
{
SDL_Event event;
int i;
- int status;
- /* Check for events */
- ++frames;
- while (SDL_PollEvent(&event) && !done) {
- switch (event.type) {
- case SDL_WINDOWEVENT:
- switch (event.window.event) {
- case SDL_WINDOWEVENT_SIZE_CHANGED:
- for (i = 0; i < state->num_windows; ++i) {
- if (event.window.windowID == SDL_GetWindowID(state->windows[i])) {
- int w, h;
- status = SDL_GL_MakeCurrent(state->windows[i], context[i]);
- if (status) {
- SDL_Log("SDL_GL_MakeCurrent(): %s\n", SDL_GetError());
- break;
- }
- /* Change view port to the new window dimensions */
- SDL_GL_GetDrawableSize(state->windows[i], &w, &h);
- ctx.glViewport(0, 0, w, h);
- state->window_w = event.window.data1;
- state->window_h = event.window.data2;
- /* Update window content */
- Render(event.window.data1, event.window.data2, &datas[i]);
- SDL_GL_SwapWindow(state->windows[i]);
- break;
+ /* Wait for events */
+ while (SDL_WaitEvent(&event) && !done) {
+ if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE) {
+ SDL_Window *window = SDL_GetWindowFromID(event.window.windowID);
+ if (window) {
+ for (i = 0; i < state->num_windows; ++i) {
+ if (window == state->windows[i]) {
+ /* Stop the render thread when the window is closed */
+ threads[i].done = 1;
+ if (threads[i].thread) {
+ SDL_WaitThread(threads[i].thread, NULL);
+ threads[i].thread = NULL;
}
+ break;
}
- break;
+ }
}
}
SDLTest_CommonEvent(state, &event, &done);
}
+}
+
+static void
+loop()
+{
+ SDL_Event event;
+ int i;
+
+ /* Check for events */
+ while (SDL_PollEvent(&event) && !done) {
+ SDLTest_CommonEvent(state, &event, &done);
+ }
if (!done) {
- for (i = 0; i < state->num_windows; ++i) {
- status = SDL_GL_MakeCurrent(state->windows[i], context[i]);
- if (status) {
- SDL_Log("SDL_GL_MakeCurrent(): %s\n", SDL_GetError());
-
- /* Continue for next window */
- continue;
- }
- Render(state->window_w, state->window_h, &datas[i]);
- SDL_GL_SwapWindow(state->windows[i]);
- }
+ for (i = 0; i < state->num_windows; ++i) {
+ render_window(i);
+ }
}
#ifdef __EMSCRIPTEN__
else {
@@ -502,7 +538,7 @@ void loop()
int
main(int argc, char *argv[])
{
- int fsaa, accel;
+ int fsaa, accel, threaded;
int value;
int i;
SDL_DisplayMode mode;
@@ -513,6 +549,7 @@ main(int argc, char *argv[])
/* Initialize parameters */
fsaa = 0;
accel = 0;
+ threaded = 0;
/* Initialize test framework */
state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
@@ -530,6 +567,9 @@ main(int argc, char *argv[])
} else if (SDL_strcasecmp(argv[i], "--accel") == 0) {
++accel;
consumed = 1;
+ } else if (SDL_strcasecmp(argv[i], "--threaded") == 0) {
+ ++threaded;
+ consumed = 1;
} else if (SDL_strcasecmp(argv[i], "--zdepth") == 0) {
i++;
if (!argv[i]) {
@@ -543,7 +583,7 @@ main(int argc, char *argv[])
}
}
if (consumed < 0) {
- static const char *options[] = { "[--fsaa]", "[--accel]", "[--zdepth %d]", NULL };
+ static const char *options[] = { "[--fsaa]", "[--accel]", "[--zdepth %d], [--threaded]", NULL };
SDLTest_CommonLogUsage(state, argv[0], options);
quit(1);
}
@@ -551,7 +591,7 @@ main(int argc, char *argv[])
}
/* Set OpenGL parameters */
- state->window_flags |= SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_BORDERLESS;
+ state->window_flags |= SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE;
state->gl_red_size = 5;
state->gl_green_size = 5;
state->gl_blue_size = 5;
@@ -603,6 +643,7 @@ main(int argc, char *argv[])
}
SDL_GetCurrentDisplayMode(0, &mode);
+ SDL_Log("Threaded : %s\n", threaded ? "yes" : "no");
SDL_Log("Screen bpp: %d\n", SDL_BITSPERPIXEL(mode.format));
SDL_Log("\n");
SDL_Log("Vendor : %s\n", ctx.glGetString(GL_VENDOR));
@@ -724,6 +765,8 @@ main(int argc, char *argv[])
GL_CHECK(ctx.glEnable(GL_CULL_FACE));
GL_CHECK(ctx.glEnable(GL_DEPTH_TEST));
+
+ SDL_GL_MakeCurrent(state->windows[i], NULL);
}
/* Main render loop */
@@ -734,8 +777,30 @@ main(int argc, char *argv[])
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop(loop, 0, 1);
#else
- while (!done) {
- loop();
+ if (threaded) {
+ threads = (thread_data*)SDL_calloc(state->num_windows, sizeof(thread_data));
+
+ /* Start a render thread for each window */
+ for (i = 0; i < state->num_windows; ++i) {
+ threads[i].index = i;
+ threads[i].thread = SDL_CreateThread(render_thread_fn, "RenderThread", &threads[i]);
+ }
+
+ while (!done) {
+ loop_threaded();
+ }
+
+ /* Join the remaining render threads (if any) */
+ for (i = 0; i < state->num_windows; ++i) {
+ threads[i].done = 1;
+ if (threads[i].thread) {
+ SDL_WaitThread(threads[i].thread, NULL);
+ }
+ }
+ } else {
+ while (!done) {
+ loop();
+ }
}
#endif