From ef4ce8cec5fb130136ef575e544100ea68193bee Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Sun, 25 Jun 2023 10:18:58 -0400
Subject: [PATCH] test: Add flag to suspend drawing when occluded
Add the flag "--suspend-when-occluded" to testgl, testgles2, and testsprite, which, when used, will suspend rendering and throttle the event loop when the occlusion flag is set on the window.
---
test/testgl.c | 16 +++++++--
test/testgles2.c | 84 ++++++++++++++++++++++++++++++++++++++---------
test/testsprite.c | 15 ++++++++-
3 files changed, 97 insertions(+), 18 deletions(-)
diff --git a/test/testgl.c b/test/testgl.c
index 8ceb5093271a..0f592812b3c1 100644
--- a/test/testgl.c
+++ b/test/testgl.c
@@ -31,6 +31,7 @@ typedef struct GL_Context
static SDLTest_CommonState *state;
static SDL_GLContext context;
static GL_Context ctx;
+static SDL_bool suspend_when_occluded;
static int LoadContext(GL_Context *data)
{
@@ -237,12 +238,15 @@ int main(int argc, char *argv[])
} else if (SDL_strcasecmp(argv[i], "--accel") == 0 && i + 1 < argc) {
accel = SDL_atoi(argv[i + 1]);
consumed = 2;
+ } else if(SDL_strcasecmp(argv[i], "--suspend-when-occluded") == 0) {
+ suspend_when_occluded = SDL_TRUE;
+ consumed = 1;
} else {
consumed = -1;
}
}
if (consumed < 0) {
- static const char *options[] = { "[--fsaa n]", "[--accel n]", NULL };
+ static const char *options[] = { "[--fsaa n]", "[--accel n]", "[--suspend-when-occluded]", NULL };
SDLTest_CommonLogUsage(state, argv[0], options);
quit(1);
}
@@ -386,6 +390,7 @@ int main(int argc, char *argv[])
done = 0;
while (!done) {
SDL_bool update_swap_interval = SDL_FALSE;
+ int active_windows = 0;
/* Check for events */
++frames;
@@ -408,9 +413,11 @@ int main(int argc, char *argv[])
for (i = 0; i < state->num_windows; ++i) {
int w, h;
- if (state->windows[i] == NULL) {
+ if (state->windows[i] == NULL ||
+ (suspend_when_occluded && (SDL_GetWindowFlags(state->windows[i]) & SDL_WINDOW_OCCLUDED))) {
continue;
}
+ ++active_windows;
SDL_GL_MakeCurrent(state->windows[i], context);
if (update_swap_interval) {
SDL_GL_SetSwapInterval(swap_interval);
@@ -420,6 +427,11 @@ int main(int argc, char *argv[])
Render();
SDL_GL_SwapWindow(state->windows[i]);
}
+
+ /* If all windows are occluded, throttle event polling to 15hz. */
+ if (!active_windows) {
+ SDL_DelayNS(SDL_NS_PER_SECOND / 15);
+ }
}
/* Print out some timing information */
diff --git a/test/testgles2.c b/test/testgles2.c
index 05c49847bae4..6975adbafdd4 100644
--- a/test/testgles2.c
+++ b/test/testgles2.c
@@ -46,9 +46,18 @@ typedef struct shader_data
GLuint color_buffer;
} shader_data;
+typedef enum wait_state
+{
+ WAIT_STATE_GO = 0,
+ WAIT_STATE_ENTER_SEM,
+ WAIT_STATE_WAITING_ON_SEM,
+} wait_state;
+
typedef struct thread_data
{
SDL_Thread *thread;
+ SDL_Semaphore *suspend_sem;
+ SDL_AtomicInt suspended;
int done;
int index;
} thread_data;
@@ -56,6 +65,7 @@ typedef struct thread_data
static SDLTest_CommonState *state;
static SDL_GLContext *context = NULL;
static int depth = 16;
+static SDL_bool suspend_when_occluded;
static GLES2_Context ctx;
static int LoadContext(GLES2_Context *data)
@@ -557,6 +567,9 @@ render_thread_fn(void *render_ctx)
thread_data *thread = render_ctx;
while (!done && !thread->done && state->windows[thread->index]) {
+ if (SDL_AtomicCAS(&thread->suspended, WAIT_STATE_ENTER_SEM, WAIT_STATE_WAITING_ON_SEM)) {
+ SDL_WaitSemaphore(thread->suspend_sem);
+ }
render_window(thread->index);
}
@@ -564,28 +577,53 @@ render_thread_fn(void *render_ctx)
return 0;
}
+static thread_data *GetThreadDataForWindow(SDL_WindowID id)
+{
+ int i;
+ SDL_Window *window = SDL_GetWindowFromID(id);
+ if (window) {
+ for (i = 0; i < state->num_windows; ++i) {
+ if (window == state->windows[i]) {
+ return &threads[i];
+ }
+ }
+ }
+ return NULL;
+}
+
static void
loop_threaded(void)
{
SDL_Event event;
- int i;
+ thread_data *tdata;
/* Wait for events */
while (SDL_WaitEvent(&event) && !done) {
- if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED) {
- 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;
- }
+ if (suspend_when_occluded && event.type == SDL_EVENT_WINDOW_OCCLUDED) {
+ tdata = GetThreadDataForWindow(event.window.windowID);
+ if (tdata) {
+ SDL_AtomicCAS(&tdata->suspended, WAIT_STATE_GO, WAIT_STATE_ENTER_SEM);
+ }
+ } else if (suspend_when_occluded && event.type == SDL_EVENT_WINDOW_EXPOSED) {
+ tdata = GetThreadDataForWindow(event.window.windowID);
+ if (tdata) {
+ if (SDL_AtomicSet(&tdata->suspended, WAIT_STATE_GO) == WAIT_STATE_WAITING_ON_SEM) {
+ SDL_PostSemaphore(tdata->suspend_sem);
+ }
+ }
+ } else if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED) {
+ tdata = GetThreadDataForWindow(event.window.windowID);
+ if (tdata) {
+ /* Stop the render thread when the window is closed */
+ tdata->done = 1;
+ if (tdata->thread) {
+ SDL_AtomicSet(&tdata->suspended, WAIT_STATE_GO);
+ SDL_PostSemaphore(tdata->suspend_sem);
+ SDL_WaitThread(tdata->thread, NULL);
+ tdata->thread = NULL;
+ SDL_DestroySemaphore(tdata->suspend_sem);
}
+ break;
}
}
SDLTest_CommonEvent(state, &event, &done);
@@ -598,6 +636,7 @@ loop(void)
{
SDL_Event event;
int i;
+ int active_windows = 0;
/* Check for events */
while (SDL_PollEvent(&event) && !done) {
@@ -605,6 +644,11 @@ loop(void)
}
if (!done) {
for (i = 0; i < state->num_windows; ++i) {
+ if (state->windows[i] == NULL ||
+ (suspend_when_occluded && (SDL_GetWindowFlags(state->windows[i]) & SDL_WINDOW_OCCLUDED))) {
+ continue;
+ }
+ ++active_windows;
render_window(i);
}
}
@@ -613,6 +657,11 @@ loop(void)
emscripten_cancel_main_loop();
}
#endif
+
+ /* If all windows are occluded, throttle event polling to 15hz. */
+ if (!done && !active_windows) {
+ SDL_DelayNS(SDL_NS_PER_SECOND / 15);
+ }
}
int main(int argc, char *argv[])
@@ -649,6 +698,9 @@ int main(int argc, char *argv[])
} else if (SDL_strcasecmp(argv[i], "--threaded") == 0) {
++threaded;
consumed = 1;
+ } else if(SDL_strcasecmp(argv[i], "--suspend-when-occluded") == 0) {
+ suspend_when_occluded = SDL_TRUE;
+ consumed = 1;
} else if (SDL_strcasecmp(argv[i], "--zdepth") == 0) {
i++;
if (!argv[i]) {
@@ -667,7 +719,7 @@ int main(int argc, char *argv[])
}
}
if (consumed < 0) {
- static const char *options[] = { "[--fsaa]", "[--accel]", "[--zdepth %d]", "[--threaded]", NULL };
+ static const char *options[] = { "[--fsaa]", "[--accel]", "[--zdepth %d]", "[--threaded]", "[--suspend-when-occluded]",NULL };
SDLTest_CommonLogUsage(state, argv[0], options);
quit(1);
}
@@ -869,6 +921,8 @@ int main(int argc, char *argv[])
/* Start a render thread for each window */
for (i = 0; i < state->num_windows; ++i) {
threads[i].index = i;
+ SDL_AtomicSet(&threads[i].suspended, 0);
+ threads[i].suspend_sem = SDL_CreateSemaphore(0);
threads[i].thread = SDL_CreateThread(render_thread_fn, "RenderThread", &threads[i]);
}
diff --git a/test/testsprite.c b/test/testsprite.c
index 68b3b7b2db6f..9afa6f0dac3c 100644
--- a/test/testsprite.c
+++ b/test/testsprite.c
@@ -42,6 +42,7 @@ static Uint64 next_fps_check;
static Uint32 frames;
static const int fps_check_delay = 5000;
static int use_rendergeometry = 0;
+static SDL_bool suspend_when_occluded;
/* Number of iterations to move sprites - used for visual tests. */
/* -1: infinite random moves (default); >=0: enables N deterministic moves */
@@ -398,6 +399,7 @@ static void loop(void)
{
Uint64 now;
int i;
+ int active_windows = 0;
SDL_Event event;
/* Check for events */
@@ -405,9 +407,11 @@ static void loop(void)
SDLTest_CommonEvent(state, &event, &done);
}
for (i = 0; i < state->num_windows; ++i) {
- if (state->windows[i] == NULL) {
+ if (state->windows[i] == NULL ||
+ (suspend_when_occluded && (SDL_GetWindowFlags(state->windows[i]) & SDL_WINDOW_OCCLUDED))) {
continue;
}
+ ++active_windows;
MoveSprites(state->renderers[i], sprites[i]);
}
#ifdef __EMSCRIPTEN__
@@ -416,6 +420,11 @@ static void loop(void)
}
#endif
+ /* If all windows are occluded, throttle the event polling to 15hz. */
+ if (!done && !active_windows) {
+ SDL_DelayNS(SDL_NS_PER_SECOND / 15);
+ }
+
frames++;
now = SDL_GetTicks();
if (now >= next_fps_check) {
@@ -485,6 +494,9 @@ int main(int argc, char *argv[])
} else if (SDL_strcasecmp(argv[i], "--cyclealpha") == 0) {
cycle_alpha = SDL_TRUE;
consumed = 1;
+ } else if(SDL_strcasecmp(argv[i], "--suspend-when-occluded") == 0) {
+ suspend_when_occluded = SDL_TRUE;
+ consumed = 1;
} else if (SDL_strcasecmp(argv[i], "--use-rendergeometry") == 0) {
if (argv[i + 1]) {
if (SDL_strcasecmp(argv[i + 1], "mode1") == 0) {
@@ -512,6 +524,7 @@ int main(int argc, char *argv[])
"[--blend none|blend|add|mod|mul|sub]",
"[--cyclecolor]",
"[--cyclealpha]",
+ "[--suspend-when-occluded]",
"[--iterations N]",
"[--use-rendergeometry mode1|mode2]",
"[num_sprites]",