From b64401cbdd8d09ce06cad69d1d4586364ccc1090 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 1 Dec 2015 08:04:01 -0800 Subject: [PATCH] VIDEO: Fix crash using libSDL on hosts which display using X11. --- sim_video.c | 75 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 21 deletions(-) diff --git a/sim_video.c b/sim_video.c index 2339acd9..ed6c5fd4 100644 --- a/sim_video.c +++ b/sim_video.c @@ -284,6 +284,37 @@ int32 vid_width; int32 vid_height; t_bool vid_ready; #if SDL_MAJOR_VERSION == 1 + +/* + Some platforms that use X11 display technology have libSDL + environments which need to call XInitThreads when libSDL is used + in multi-threaded programs. This routine attempts to locate + the X11 shareable library and if it is found loads it and calls + the XInitThreads routine to meet this requirement. + */ +#ifdef HAVE_DLOPEN +#include +#endif + +static void _XInitThreads (void) +{ +#ifdef HAVE_DLOPEN +static void *hLib = 0; /* handle to Library */ +#define __STR_QUOTE(tok) #tok +#define __STR(tok) __STR_QUOTE(tok) +static const char* lib_name = "libX11." __STR(HAVE_DLOPEN); +typedef int (*_func)(); +_func _func_ptr; + +if (!hLib) + hLib = dlopen(lib_name, RTLD_NOW); +if (hLib) + _func_ptr = (_func)((size_t)dlsym(hLib, "XInitThreads")); +if (_func_ptr) + _func_ptr(); +#endif +} + t_bool vid_key_state[SDLK_LAST]; SDL_Surface *vid_image; /* video buffer */ SDL_Surface *vid_window; /* window handle */ @@ -322,7 +353,8 @@ user_event.type = SDL_USEREVENT; user_event.user.code = EVENT_EXIT; user_event.user.data1 = NULL; user_event.user.data2 = NULL; -SDL_PushEvent (&user_event); +while (SDL_PushEvent (&user_event) < 0) + sim_os_ms_sleep (10); return stat; } @@ -335,6 +367,7 @@ main_argc = argc; main_argv = argv; #if SDL_MAJOR_VERSION == 1 +_XInitThreads(); SDL_Init (SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE); vid_main_thread_handle = SDL_CreateThread (main_thread , NULL); @@ -373,7 +406,7 @@ while (1) { } else { if (status < 0) - sim_printf ("main() - SDL_WaitEvent error: %s\n", SDL_GetError()); + sim_printf ("main() - ` error: %s\n", SDL_GetError()); } } SDL_WaitThread (vid_main_thread_handle, &status); @@ -474,7 +507,8 @@ if (vid_active) { user_event.user.data1 = NULL; user_event.user.data2 = NULL; - SDL_PushEvent (&user_event); + while (SDL_PushEvent (&user_event) < 0) + sim_os_ms_sleep (10); if (vid_thread_handle) { SDL_WaitThread (vid_thread_handle, &status); vid_thread_handle = NULL; @@ -545,17 +579,6 @@ return stat; void vid_draw (int32 x, int32 y, int32 w, int32 h, uint32 *buf) { -#if SDL_MAJOR_VERSION == 1 -int32 i; -uint32* pixels; - -sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "vid_draw(%d, %d, %d, %d)\n", x, y, w, h); - -pixels = (uint32 *)vid_image->pixels; - -for (i = 0; i < h; i++) - memcpy (pixels + ((i + y) * vid_width) + x, buf + w*i, w*sizeof(*pixels)); -#else SDL_Event user_event; SDL_Rect *vid_dst; uint32 *vid_data; @@ -578,7 +601,6 @@ if (SDL_PushEvent (&user_event) < 0) { free (vid_dst); free (vid_data); } -#endif } t_stat vid_set_cursor (t_bool visible, uint32 width, uint32 height, uint8 *data, uint8 *mask) @@ -1312,7 +1334,6 @@ SDL_WarpMouseInWindow (NULL, vid_cursor_x, vid_cursor_y); SDL_PumpEvents (); } -#if SDL_MAJOR_VERSION != 1 void vid_draw_region (SDL_UserEvent *event) { SDL_Rect *vid_dst = (SDL_Rect *)event->data1; @@ -1320,14 +1341,25 @@ uint32 *buf = (uint32 *)event->data2; sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "Draw Region Event: (%d,%d,%d,%d)\n", vid_dst->x, vid_dst->x, vid_dst->w, vid_dst->h); +#if SDL_MAJOR_VERSION == 1 +if (1) { + int32 i; + uint32* pixels; + + pixels = (uint32 *)vid_image->pixels; + + for (i = 0; i < vid_dst->h; i++) + memcpy (pixels + ((i + vid_dst->y) * vid_width) + vid_dst->x, buf + vid_dst->w*i, vid_dst->w*sizeof(*pixels)); + } +#else if (SDL_UpdateTexture(vid_texture, vid_dst, buf, vid_dst->w*sizeof(*buf))) sim_printf ("%s: vid_draw() - SDL_UpdateTexture error: %s\n", sim_dname(vid_dev), SDL_GetError()); +#endif free (vid_dst); free (buf); event->data1 = NULL; } -#endif int vid_video_events (void) { @@ -1634,12 +1666,10 @@ if (0) while (SDL_PeepEvents (&event, 1, SDL_GETEVENT, SD if (event.user.code == EVENT_CLOSE) { event.user.code = 0; /* Mark as done */ } -#if SDL_MAJOR_VERSION != 1 if (event.user.code == EVENT_DRAW) { vid_draw_region ((SDL_UserEvent*)&event); event.user.code = 0; /* Mark as done */ } -#endif if (event.user.code == EVENT_SHOW) { vid_show_video_event (); event.user.code = 0; /* Mark as done */ @@ -1684,6 +1714,7 @@ return 0; int vid_thread (void *arg) { #if SDL_MAJOR_VERSION == 1 +_XInitThreads(); SDL_Init (SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE); #else SDL_SetHint (SDL_HINT_RENDER_DRIVER, "software"); @@ -1998,7 +2029,8 @@ user_event.user.code = EVENT_SHOW; user_event.user.data1 = NULL; user_event.user.data2 = NULL; #if defined (SDL_MAIN_AVAILABLE) -SDL_PushEvent (&user_event); +while (SDL_PushEvent (&user_event) < 0) + sim_os_ms_sleep (10); #else vid_show_video_event (); #endif @@ -2073,7 +2105,8 @@ user_event.user.code = EVENT_SCREENSHOT; user_event.user.data1 = NULL; user_event.user.data2 = NULL; #if defined (SDL_MAIN_AVAILABLE) -SDL_PushEvent (&user_event); +while (SDL_PushEvent (&user_event) < 0) + sim_os_ms_sleep (10); #else vid_screenshot_event (); #endif