From 85b2733324a0afb40f0ccfb4256941069fde4a54 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Mon, 2 Sep 2024 08:40:53 -0700 Subject: [PATCH 01/20] Make newer DRM and GBM functions optional Fixes https://github.com/libsdl-org/SDL/issues/10675 (cherry picked from commit d501f6db07d4a067f7261d1ef51bec199f6d421f) (cherry picked from commit 10b4a79379d226041781d0a825da79a296af715f) --- src/video/kmsdrm/SDL_kmsdrmdyn.c | 14 ++++++---- src/video/kmsdrm/SDL_kmsdrmdyn.h | 3 +++ src/video/kmsdrm/SDL_kmsdrmsym.h | 19 ++++++++----- src/video/kmsdrm/SDL_kmsdrmvideo.c | 43 ++++++++++++++++++------------ 4 files changed, 50 insertions(+), 29 deletions(-) diff --git a/src/video/kmsdrm/SDL_kmsdrmdyn.c b/src/video/kmsdrm/SDL_kmsdrmdyn.c index 750babbcdeefc..f96d230904ef0 100644 --- a/src/video/kmsdrm/SDL_kmsdrmdyn.c +++ b/src/video/kmsdrm/SDL_kmsdrmdyn.c @@ -47,7 +47,7 @@ static kmsdrmdynlib kmsdrmlibs[] = { { NULL, SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC } }; -static void *KMSDRM_GetSym(const char *fnname, int *pHasModule) +static void *KMSDRM_GetSym(const char *fnname, int *pHasModule, SDL_bool required) { int i; void *fn = NULL; @@ -67,7 +67,7 @@ static void *KMSDRM_GetSym(const char *fnname, int *pHasModule) SDL_Log("KMSDRM: Symbol '%s' NOT FOUND!\n", fnname); #endif - if (!fn) { + if (!fn && required) { *pHasModule = 0; /* kill this module. */ } @@ -80,6 +80,7 @@ static void *KMSDRM_GetSym(const char *fnname, int *pHasModule) #define SDL_KMSDRM_MODULE(modname) int SDL_KMSDRM_HAVE_##modname = 0; #define SDL_KMSDRM_SYM(rc, fn, params) SDL_DYNKMSDRMFN_##fn KMSDRM_##fn = NULL; #define SDL_KMSDRM_SYM_CONST(type, name) SDL_DYNKMSDRMCONST_##name KMSDRM_##name = NULL; +#define SDL_KMSDRM_SYM_OPT(rc, fn, params) SDL_DYNKMSDRMFN_##fn KMSDRM_##fn = NULL; #include "SDL_kmsdrmsym.h" static int kmsdrm_load_refcount = 0; @@ -97,6 +98,7 @@ void SDL_KMSDRM_UnloadSymbols(void) #define SDL_KMSDRM_MODULE(modname) SDL_KMSDRM_HAVE_##modname = 0; #define SDL_KMSDRM_SYM(rc, fn, params) KMSDRM_##fn = NULL; #define SDL_KMSDRM_SYM_CONST(type, name) KMSDRM_##name = NULL; +#define SDL_KMSDRM_SYM_OPT(rc, fn, params) KMSDRM_##fn = NULL; #include "SDL_kmsdrmsym.h" #ifdef SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC @@ -130,9 +132,10 @@ int SDL_KMSDRM_LoadSymbols(void) #define SDL_KMSDRM_MODULE(modname) SDL_KMSDRM_HAVE_##modname = 1; /* default yes */ #include "SDL_kmsdrmsym.h" -#define SDL_KMSDRM_MODULE(modname) thismod = &SDL_KMSDRM_HAVE_##modname; -#define SDL_KMSDRM_SYM(rc, fn, params) KMSDRM_##fn = (SDL_DYNKMSDRMFN_##fn)KMSDRM_GetSym(#fn, thismod); -#define SDL_KMSDRM_SYM_CONST(type, name) KMSDRM_##name = *(SDL_DYNKMSDRMCONST_##name *)KMSDRM_GetSym(#name, thismod); +#define SDL_KMSDRM_MODULE(modname) thismod = &SDL_KMSDRM_HAVE_##modname; +#define SDL_KMSDRM_SYM(rc, fn, params) KMSDRM_##fn = (SDL_DYNKMSDRMFN_##fn)KMSDRM_GetSym(#fn, thismod, SDL_TRUE); +#define SDL_KMSDRM_SYM_CONST(type, name) KMSDRM_##name = *(SDL_DYNKMSDRMCONST_##name *)KMSDRM_GetSym(#name, thismod, SDL_TRUE); +#define SDL_KMSDRM_SYM_OPT(rc, fn, params) KMSDRM_##fn = (SDL_DYNKMSDRMFN_##fn)KMSDRM_GetSym(#fn, thismod, SDL_FALSE); #include "SDL_kmsdrmsym.h" if ((SDL_KMSDRM_HAVE_LIBDRM) && (SDL_KMSDRM_HAVE_GBM)) { @@ -149,6 +152,7 @@ int SDL_KMSDRM_LoadSymbols(void) #define SDL_KMSDRM_MODULE(modname) SDL_KMSDRM_HAVE_##modname = 1; /* default yes */ #define SDL_KMSDRM_SYM(rc, fn, params) KMSDRM_##fn = fn; #define SDL_KMSDRM_SYM_CONST(type, name) KMSDRM_##name = name; +#define SDL_KMSDRM_SYM_OPT(rc, fn, params) KMSDRM_##fn = fn; #include "SDL_kmsdrmsym.h" #endif diff --git a/src/video/kmsdrm/SDL_kmsdrmdyn.h b/src/video/kmsdrm/SDL_kmsdrmdyn.h index e6da337921ad2..633a20eea0686 100644 --- a/src/video/kmsdrm/SDL_kmsdrmdyn.h +++ b/src/video/kmsdrm/SDL_kmsdrmdyn.h @@ -42,6 +42,9 @@ void SDL_KMSDRM_UnloadSymbols(void); #define SDL_KMSDRM_SYM_CONST(type, name) \ typedef type SDL_DYNKMSDRMCONST_##name; \ extern SDL_DYNKMSDRMCONST_##name KMSDRM_##name; +#define SDL_KMSDRM_SYM_OPT(rc, fn, params) \ + typedef rc(*SDL_DYNKMSDRMFN_##fn) params; \ + extern SDL_DYNKMSDRMFN_##fn KMSDRM_##fn; #include "SDL_kmsdrmsym.h" #ifdef __cplusplus diff --git a/src/video/kmsdrm/SDL_kmsdrmsym.h b/src/video/kmsdrm/SDL_kmsdrmsym.h index 7a99e1b6a3302..df4621207ef3f 100644 --- a/src/video/kmsdrm/SDL_kmsdrmsym.h +++ b/src/video/kmsdrm/SDL_kmsdrmsym.h @@ -33,6 +33,10 @@ #define SDL_KMSDRM_SYM_CONST(type, name) #endif +#ifndef SDL_KMSDRM_SYM_OPT +#define SDL_KMSDRM_SYM_OPT(rc,fn,params) +#endif + SDL_KMSDRM_MODULE(LIBDRM) SDL_KMSDRM_SYM(void,drmModeFreeResources,(drmModeResPtr ptr)) @@ -49,12 +53,12 @@ SDL_KMSDRM_SYM(int,drmModeAddFB,(int fd, uint32_t width, uint32_t height, uint8_ uint8_t bpp, uint32_t pitch, uint32_t bo_handle, uint32_t *buf_id)) -SDL_KMSDRM_SYM(int,drmModeAddFB2,(int fd, uint32_t width, uint32_t height, +SDL_KMSDRM_SYM_OPT(int,drmModeAddFB2,(int fd, uint32_t width, uint32_t height, uint32_t pixel_format, const uint32_t bo_handles[4], const uint32_t pitches[4], const uint32_t offsets[4], uint32_t *buf_id, uint32_t flags)) -SDL_KMSDRM_SYM(int,drmModeAddFB2WithModifiers,(int fd, uint32_t width, +SDL_KMSDRM_SYM_OPT(int,drmModeAddFB2WithModifiers,(int fd, uint32_t width, uint32_t height, uint32_t pixel_format, const uint32_t bo_handles[4], const uint32_t pitches[4], const uint32_t offsets[4], const uint64_t modifier[4], uint32_t *buf_id, uint32_t flags)) @@ -129,15 +133,16 @@ SDL_KMSDRM_SYM(void,gbm_surface_destroy,(struct gbm_surface *surf)) SDL_KMSDRM_SYM(struct gbm_bo *,gbm_surface_lock_front_buffer,(struct gbm_surface *surf)) SDL_KMSDRM_SYM(void,gbm_surface_release_buffer,(struct gbm_surface *surf, struct gbm_bo *bo)) -SDL_KMSDRM_SYM(uint64_t,gbm_bo_get_modifier,(struct gbm_bo *bo)) -SDL_KMSDRM_SYM(int,gbm_bo_get_plane_count,(struct gbm_bo *bo)) -SDL_KMSDRM_SYM(uint32_t,gbm_bo_get_offset,(struct gbm_bo *bo, int plane)) -SDL_KMSDRM_SYM(uint32_t,gbm_bo_get_stride_for_plane,(struct gbm_bo *bo, int plane)) -SDL_KMSDRM_SYM(union gbm_bo_handle,gbm_bo_get_handle_for_plane,(struct gbm_bo *bo, int plane);) +SDL_KMSDRM_SYM_OPT(uint64_t,gbm_bo_get_modifier,(struct gbm_bo *bo)) +SDL_KMSDRM_SYM_OPT(int,gbm_bo_get_plane_count,(struct gbm_bo *bo)) +SDL_KMSDRM_SYM_OPT(uint32_t,gbm_bo_get_offset,(struct gbm_bo *bo, int plane)) +SDL_KMSDRM_SYM_OPT(uint32_t,gbm_bo_get_stride_for_plane,(struct gbm_bo *bo, int plane)) +SDL_KMSDRM_SYM_OPT(union gbm_bo_handle,gbm_bo_get_handle_for_plane,(struct gbm_bo *bo, int plane)) #undef SDL_KMSDRM_MODULE #undef SDL_KMSDRM_SYM #undef SDL_KMSDRM_SYM_CONST +#undef SDL_KMSDRM_SYM_OPT /* *INDENT-ON* */ /* clang-format on */ diff --git a/src/video/kmsdrm/SDL_kmsdrmvideo.c b/src/video/kmsdrm/SDL_kmsdrmvideo.c index b7abb4fc785f5..7cd538c942064 100644 --- a/src/video/kmsdrm/SDL_kmsdrmvideo.c +++ b/src/video/kmsdrm/SDL_kmsdrmvideo.c @@ -336,8 +336,9 @@ KMSDRM_FBInfo *KMSDRM_FBFromBO(_THIS, struct gbm_bo *bo) { SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata); unsigned w, h; - int ret, num_planes = 0; - Uint32 format, strides[4] = { 0 }, handles[4] = { 0 }, offsets[4] = { 0 }, flags = 0; + int rc = -1; + int num_planes = 0; + uint32_t format, strides[4] = { 0 }, handles[4] = { 0 }, offsets[4] = { 0 }, flags = 0; uint64_t modifiers[4] = { 0 }; /* Check for an existing framebuffer */ @@ -364,28 +365,36 @@ KMSDRM_FBInfo *KMSDRM_FBFromBO(_THIS, struct gbm_bo *bo) h = KMSDRM_gbm_bo_get_height(bo); format = KMSDRM_gbm_bo_get_format(bo); - modifiers[0] = KMSDRM_gbm_bo_get_modifier(bo); - num_planes = KMSDRM_gbm_bo_get_plane_count(bo); - for (int i = 0; i < num_planes; i++) { - strides[i] = KMSDRM_gbm_bo_get_stride_for_plane(bo, i); - handles[i] = KMSDRM_gbm_bo_get_handle_for_plane(bo, i).u32; - offsets[i] = KMSDRM_gbm_bo_get_offset(bo, i); - modifiers[i] = modifiers[0]; - } + if (KMSDRM_drmModeAddFB2WithModifiers && + KMSDRM_gbm_bo_get_modifier && + KMSDRM_gbm_bo_get_plane_count && + KMSDRM_gbm_bo_get_offset && + KMSDRM_gbm_bo_get_stride_for_plane && + KMSDRM_gbm_bo_get_handle_for_plane) { + + modifiers[0] = KMSDRM_gbm_bo_get_modifier(bo); + num_planes = KMSDRM_gbm_bo_get_plane_count(bo); + for (int i = 0; i < num_planes; i++) { + strides[i] = KMSDRM_gbm_bo_get_stride_for_plane(bo, i); + handles[i] = KMSDRM_gbm_bo_get_handle_for_plane(bo, i).u32; + offsets[i] = KMSDRM_gbm_bo_get_offset(bo, i); + modifiers[i] = modifiers[0]; + } - if (modifiers[0] && modifiers[0] != DRM_FORMAT_MOD_INVALID) { - flags = DRM_MODE_FB_MODIFIERS; - } + if (modifiers[0] && modifiers[0] != DRM_FORMAT_MOD_INVALID) { + flags = DRM_MODE_FB_MODIFIERS; + } - ret = KMSDRM_drmModeAddFB2WithModifiers(viddata->drm_fd, w, h, format, handles, strides, offsets, modifiers, &fb_info->fb_id, flags); + rc = KMSDRM_drmModeAddFB2WithModifiers(viddata->drm_fd, w, h, format, handles, strides, offsets, modifiers, &fb_info->fb_id, flags); + } - if (ret) { + if (rc < 0) { strides[0] = KMSDRM_gbm_bo_get_stride(bo); handles[0] = KMSDRM_gbm_bo_get_handle(bo).u32; - ret = KMSDRM_drmModeAddFB(viddata->drm_fd, w, h, 24, 32, strides[0], handles[0], &fb_info->fb_id); + rc = KMSDRM_drmModeAddFB(viddata->drm_fd, w, h, 24, 32, strides[0], handles[0], &fb_info->fb_id); } - if (ret) { + if (rc < 0) { SDL_free(fb_info); return NULL; } From ba9b075eba3ffa10586e7603ba5f180d54e7f055 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Thu, 5 Sep 2024 05:35:03 -0700 Subject: [PATCH 02/20] Use atomic variables for thread communication Fixes https://github.com/libsdl-org/SDL/issues/10711 (cherry picked from commit a0f36fb85b40338fb24e1f1479bdcc432c06aba6) (cherry picked from commit a75227aaebc5bc04ad5a9b3225c66db0a707951d) --- test/testthread.c | 12 ++++++------ test/torturethread.c | 11 ++++++----- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/test/testthread.c b/test/testthread.c index 5ceac05ffac38..b57dfde1856c2 100644 --- a/test/testthread.c +++ b/test/testthread.c @@ -19,7 +19,7 @@ #include "SDL.h" static SDL_TLSID tls; -static int alive = 0; +static SDL_atomic_t alive; static int testprio = 0; /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ @@ -55,7 +55,7 @@ ThreadFunc(void *data) SDL_TLSSet(tls, "baby thread", NULL); SDL_Log("Started thread %s: My thread id is %lu, thread data = %s\n", (char *)data, SDL_ThreadID(), (const char *)SDL_TLSGet(tls)); - while (alive) { + while (SDL_AtomicGet(&alive)) { SDL_Log("Thread '%s' is alive!\n", (char *)data); if (testprio) { @@ -76,7 +76,7 @@ killed(int sig) { SDL_Log("Killed with SIGTERM, waiting 5 seconds to exit\n"); SDL_Delay(5 * 1000); - alive = 0; + SDL_AtomicSet(&alive, 0); quit(0); } @@ -112,7 +112,7 @@ int main(int argc, char *argv[]) SDL_TLSSet(tls, "main thread", NULL); SDL_Log("Main thread data initially: %s\n", (const char *)SDL_TLSGet(tls)); - alive = 1; + SDL_AtomicSet(&alive, 1); thread = SDL_CreateThread(ThreadFunc, "One", "#1"); if (!thread) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create thread: %s\n", SDL_GetError()); @@ -120,12 +120,12 @@ int main(int argc, char *argv[]) } SDL_Delay(5 * 1000); SDL_Log("Waiting for thread #1\n"); - alive = 0; + SDL_AtomicSet(&alive, 0); SDL_WaitThread(thread, NULL); SDL_Log("Main thread data finally: %s\n", (const char *)SDL_TLSGet(tls)); - alive = 1; + SDL_AtomicSet(&alive, 1); (void)signal(SIGTERM, killed); thread = SDL_CreateThread(ThreadFunc, "Two", "#2"); if (!thread) { diff --git a/test/torturethread.c b/test/torturethread.c index b612cda497766..b91baa1347eb0 100644 --- a/test/torturethread.c +++ b/test/torturethread.c @@ -34,8 +34,9 @@ quit(int rc) int SDLCALL SubThreadFunc(void *data) { - while (!*(int volatile *)data) { - ; /* SDL_Delay(10); */ /* do nothing */ + SDL_atomic_t *flag = (SDL_atomic_t *)data; + while (!SDL_AtomicGet(flag)) { + SDL_Delay(10); } return 0; } @@ -44,7 +45,7 @@ int SDLCALL ThreadFunc(void *data) { SDL_Thread *sub_threads[NUMTHREADS]; - int flags[NUMTHREADS]; + SDL_atomic_t flags[NUMTHREADS]; int i; int tid = (int)(uintptr_t)data; @@ -53,7 +54,7 @@ ThreadFunc(void *data) for (i = 0; i < NUMTHREADS; i++) { char name[64]; (void)SDL_snprintf(name, sizeof(name), "Child%d_%d", tid, i); - flags[i] = 0; + SDL_AtomicSet(&flags[i], 0); sub_threads[i] = SDL_CreateThread(SubThreadFunc, name, &flags[i]); } @@ -64,7 +65,7 @@ ThreadFunc(void *data) SDL_Log("Thread '%d' sending signals to subthreads\n", tid); for (i = 0; i < NUMTHREADS; i++) { - flags[i] = 1; + SDL_AtomicSet(&flags[i], 1); SDL_WaitThread(sub_threads[i], NULL); } From e5bb4fa90fefa873671eb3456c4efb2075b202de Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sun, 28 Jul 2024 07:51:31 -0700 Subject: [PATCH 03/20] Fixed memory leak in testthread (cherry picked from commit dfe6efcd2df1b7781ce9bbcf86963bafda589b5e) (cherry picked from commit 224a37faabe3a074b7f0b1fd17848526961ca0a0) --- test/testthread.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/testthread.c b/test/testthread.c index b57dfde1856c2..188bc715f1913 100644 --- a/test/testthread.c +++ b/test/testthread.c @@ -19,6 +19,7 @@ #include "SDL.h" static SDL_TLSID tls; +static SDL_Thread *thread = NULL; static SDL_atomic_t alive; static int testprio = 0; @@ -77,13 +78,13 @@ killed(int sig) SDL_Log("Killed with SIGTERM, waiting 5 seconds to exit\n"); SDL_Delay(5 * 1000); SDL_AtomicSet(&alive, 0); + SDL_WaitThread(thread, NULL); quit(0); } int main(int argc, char *argv[]) { int arg = 1; - SDL_Thread *thread; /* Enable standard application logging */ SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); From d53b22e8f057136b7121cc6c2b660b34ea8b43a8 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Fri, 6 Sep 2024 10:15:16 -0700 Subject: [PATCH 04/20] Fixed race condition at startup that could cause a crash in the XInput driver (cherry picked from commit 6d7c211fafd5404e6d10a143ab4c443ed9e61b5a) (cherry picked from commit 5aadfd4eafc12036c4f8da4b925016c619f465af) --- src/joystick/windows/SDL_xinputjoystick.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/joystick/windows/SDL_xinputjoystick.c b/src/joystick/windows/SDL_xinputjoystick.c index ca6585312eb6c..59c60835335b9 100644 --- a/src/joystick/windows/SDL_xinputjoystick.c +++ b/src/joystick/windows/SDL_xinputjoystick.c @@ -65,11 +65,13 @@ SDL_bool SDL_XINPUT_Enabled(void) int SDL_XINPUT_JoystickInit(void) { - s_bXInputEnabled = SDL_GetHintBoolean(SDL_HINT_XINPUT_ENABLED, SDL_TRUE); + SDL_bool enabled = SDL_GetHintBoolean(SDL_HINT_XINPUT_ENABLED, SDL_TRUE); - if (s_bXInputEnabled && WIN_LoadXInputDLL() < 0) { - s_bXInputEnabled = SDL_FALSE; /* oh well. */ + if (enabled && WIN_LoadXInputDLL() < 0) { + enabled = SDL_FALSE; /* oh well. */ } + s_bXInputEnabled = enabled; + return 0; } From 00a7191f673bbb1a9eb7fb314cf1a4b600a42c96 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Fri, 6 Sep 2024 11:19:19 -0700 Subject: [PATCH 05/20] SDL_XINPUT_Enabled() returns false until XInput DLL is successfully loaded We make sure we initialize XInput first, so that anything checking whether it's enabled gets a valid result based on whether we were able to load it or not. (cherry picked from commit 8f46cb771c7c5e8aa4193b01f14f63e3ab7b4d8f) (cherry picked from commit f5ed158d1f59d0d3bfe65f6c3603c5082c560797) --- src/joystick/windows/SDL_windowsjoystick.c | 6 +++--- src/joystick/windows/SDL_xinputjoystick.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/joystick/windows/SDL_windowsjoystick.c b/src/joystick/windows/SDL_windowsjoystick.c index 49e4c59757ce0..634c81bb89389 100644 --- a/src/joystick/windows/SDL_windowsjoystick.c +++ b/src/joystick/windows/SDL_windowsjoystick.c @@ -377,7 +377,7 @@ static int SDLCALL SDL_JoystickThread(void *_data) #ifdef SDL_JOYSTICK_XINPUT /* WM_DEVICECHANGE not working, poll for new XINPUT controllers */ SDL_CondWaitTimeout(s_condJoystickThread, s_mutexJoyStickEnum, 1000); - if (SDL_XINPUT_Enabled() && XINPUTGETCAPABILITIES) { + if (SDL_XINPUT_Enabled()) { /* scan for any change in XInput devices */ Uint8 userId; for (userId = 0; userId < XUSER_MAX_COUNT; userId++) { @@ -473,12 +473,12 @@ void WINDOWS_JoystickQuit(void); */ static int WINDOWS_JoystickInit(void) { - if (SDL_DINPUT_JoystickInit() < 0) { + if (SDL_XINPUT_JoystickInit() < 0) { WINDOWS_JoystickQuit(); return -1; } - if (SDL_XINPUT_JoystickInit() < 0) { + if (SDL_DINPUT_JoystickInit() < 0) { WINDOWS_JoystickQuit(); return -1; } diff --git a/src/joystick/windows/SDL_xinputjoystick.c b/src/joystick/windows/SDL_xinputjoystick.c index 59c60835335b9..02cb445cc4109 100644 --- a/src/joystick/windows/SDL_xinputjoystick.c +++ b/src/joystick/windows/SDL_xinputjoystick.c @@ -39,7 +39,7 @@ extern "C" { /* * Internal stuff. */ -static SDL_bool s_bXInputEnabled = SDL_TRUE; +static SDL_bool s_bXInputEnabled = SDL_FALSE; static SDL_bool SDL_XInputUseOldJoystickMapping(void) { From 1df907b1ba3b206a5e336176cac4c78b4f58e4ea Mon Sep 17 00:00:00 2001 From: vanfanel Date: Wed, 17 Jul 2024 20:40:30 +0200 Subject: [PATCH 06/20] Add SDL_VIDEO_DOUBLE_BUFFER support to the Wayland backend. (cherry picked from commit 9e6b8d56e33f77dab507236d84a3f76b6fea7b2a) --- include/SDL_hints.h | 1 + src/video/wayland/SDL_waylandopengles.c | 26 ++++++++++++++++++++----- src/video/wayland/SDL_waylandwindow.c | 5 +++++ src/video/wayland/SDL_waylandwindow.h | 1 + 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/include/SDL_hints.h b/include/SDL_hints.h index a26ab60e869d4..8c38d86edd684 100644 --- a/include/SDL_hints.h +++ b/include/SDL_hints.h @@ -1912,6 +1912,7 @@ extern "C" { * Since it's driver-specific, it's only supported where possible and * implemented. Currently supported the following drivers: * + * - Wayland (wayland) * - KMSDRM (kmsdrm) * - Raspberry Pi (raspberrypi) */ diff --git a/src/video/wayland/SDL_waylandopengles.c b/src/video/wayland/SDL_waylandopengles.c index 22311a63e65fa..c107df9091b98 100644 --- a/src/video/wayland/SDL_waylandopengles.c +++ b/src/video/wayland/SDL_waylandopengles.c @@ -120,6 +120,20 @@ int Wayland_GLES_SwapWindow(_THIS, SDL_Window *window) return 0; } + /* By default, we wait for Wayland frame callback and then issue pageflip (eglSwapBuffers), + * but if we want low latency (double buffer scheme), we issue the pageflip + * and then wait immediately for Wayland frame callback. + */ + + if (data->double_buffer) { + /* Feed the frame to Wayland. This will set it so the wl_surface_frame callback can fire again. */ + if (!_this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, data->egl_surface)) { + return SDL_EGL_SetError("unable to show color buffer in an OS-native window", "eglSwapBuffers"); + } + + WAYLAND_wl_display_flush(data->waylandData->display); + } + /* Control swap interval ourselves. See comments on Wayland_GLES_SetSwapInterval */ if (swap_interval != 0) { SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata; @@ -162,12 +176,14 @@ int Wayland_GLES_SwapWindow(_THIS, SDL_Window *window) SDL_AtomicSet(&data->swap_interval_ready, 0); } - /* Feed the frame to Wayland. This will set it so the wl_surface_frame callback can fire again. */ - if (!_this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, data->egl_surface)) { - return SDL_EGL_SetError("unable to show color buffer in an OS-native window", "eglSwapBuffers"); - } + if (!data->double_buffer) { + /* Feed the frame to Wayland. This will set it so the wl_surface_frame callback can fire again. */ + if (!_this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, data->egl_surface)) { + return SDL_EGL_SetError("unable to show color buffer in an OS-native window", "eglSwapBuffers"); + } - WAYLAND_wl_display_flush(data->waylandData->display); + WAYLAND_wl_display_flush(data->waylandData->display); + } return 0; } diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c index c8d55def1754d..ad89748465f2a 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -2023,6 +2023,11 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window) } } + data->double_buffer = SDL_FALSE; + if (SDL_GetHintBoolean(SDL_HINT_VIDEO_DOUBLE_BUFFER, SDL_FALSE)) { + data->double_buffer = SDL_TRUE; + } + data->outputs = NULL; data->num_outputs = 0; diff --git a/src/video/wayland/SDL_waylandwindow.h b/src/video/wayland/SDL_waylandwindow.h index 36600a4d2783e..e22e6baa64dd4 100644 --- a/src/video/wayland/SDL_waylandwindow.h +++ b/src/video/wayland/SDL_waylandwindow.h @@ -116,6 +116,7 @@ typedef struct SDL_bool is_fullscreen; SDL_bool in_fullscreen_transition; Uint32 fullscreen_flags; + SDL_bool double_buffer; } SDL_WindowData; extern void Wayland_ShowWindow(_THIS, SDL_Window *window); From 38d3b1b6d6446b81a55926bd511b74295eb0ddfa Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Mon, 9 Sep 2024 19:56:25 +0100 Subject: [PATCH 07/20] x11vulkan: Use the correct SONAME of libX11-xcb.so.1 on Linux, etc. On most Unix platforms supported by SDL, the canonical name used to load a library at runtime includes its ABI major version, and the name without a version is not guaranteed to exist on non-developer systems. libX11-xcb.so.1 is correct on Linux, and probably on other Unix platforms like FreeBSD. A notable exception is OpenBSD, which apparently does not use ABI-suffixed names, so continue to use libX11-xcb.so there. Signed-off-by: Simon McVittie (cherry picked from commit 7713a7eec7d953be16c3f5beccb5a9f3bb6c24d2) (cherry picked from commit 54757c29dd4e8783d57e6b0d2261bd00f66c3f0d) --- src/video/x11/SDL_x11vulkan.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/video/x11/SDL_x11vulkan.c b/src/video/x11/SDL_x11vulkan.c index d9a0d2f35bf8a..71bb4b0d6bb8f 100644 --- a/src/video/x11/SDL_x11vulkan.c +++ b/src/video/x11/SDL_x11vulkan.c @@ -32,8 +32,10 @@ #if defined(__OpenBSD__) #define DEFAULT_VULKAN "libvulkan.so" +#define DEFAULT_X11_XCB "libX11-xcb.so" #else #define DEFAULT_VULKAN "libvulkan.so.1" +#define DEFAULT_X11_XCB "libX11-xcb.so.1" #endif /* @@ -108,7 +110,7 @@ int X11_Vulkan_LoadLibrary(_THIS, const char *path) } else { const char *libX11XCBLibraryName = SDL_getenv("SDL_X11_XCB_LIBRARY"); if (!libX11XCBLibraryName) { - libX11XCBLibraryName = "libX11-xcb.so"; + libX11XCBLibraryName = DEFAULT_X11_XCB; } videoData->vulkan_xlib_xcb_library = SDL_LoadObject(libX11XCBLibraryName); if (!videoData->vulkan_xlib_xcb_library) { From d32189918ba065b86ee5afec6b8bd217fdca7dc2 Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Tue, 10 Sep 2024 10:07:55 -0400 Subject: [PATCH 08/20] wayland: Send exposure events when showing or resizing the window Clients may rely on this event to signal when they should redraw themselves, so send it when appropriate. (cherry picked from commit 8fa99993af4e50d41a7c5f0927fd4a6d04639004) --- src/video/wayland/SDL_waylandwindow.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c index ad89748465f2a..cec81d00c9f4e 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -1481,6 +1481,9 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window) * HideWindow was called immediately before ShowWindow. */ WAYLAND_wl_display_roundtrip(c->display); + + /* Send an exposure event to signal that the client should draw. */ + SDL_SendWindowEvent(window, SDL_WINDOWEVENT_EXPOSED, 0, 0); } static void Wayland_ReleasePopup(_THIS, SDL_Window *popup) @@ -2147,6 +2150,7 @@ static void Wayland_HandleResize(SDL_Window *window, int width, int height, floa window->w = 0; window->h = 0; SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, width, height); + SDL_SendWindowEvent(window, SDL_WINDOWEVENT_EXPOSED, 0, 0); window->w = width; window->h = height; data->needs_resize_event = SDL_FALSE; From e9efcfb428c6cf4ee49b249fb099981445685e0d Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Thu, 12 Sep 2024 18:00:58 -0400 Subject: [PATCH 09/20] pulseaudio: Hotplug thread fixes. This used a tiny stack, which apparently upsets Blender for various technical reasons. Instead, just use the default stack size, which should give it plenty of space to work. If the thread failed to create, we would then wait on a semaphore that would never trigger, so don't do that anymore! Fixes #10806. (cherry-picked from commit b7dc30ca24650a22de61c0c4ab28f7cb5905dee9) (cherry picked from commit 58f2586b4463b5b7e637b9b54798b4d6f0375c51) --- src/audio/pulseaudio/SDL_pulseaudio.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/audio/pulseaudio/SDL_pulseaudio.c b/src/audio/pulseaudio/SDL_pulseaudio.c index 5039d0547a2ea..f34deb0ec1d05 100644 --- a/src/audio/pulseaudio/SDL_pulseaudio.c +++ b/src/audio/pulseaudio/SDL_pulseaudio.c @@ -897,8 +897,12 @@ static void PULSEAUDIO_DetectDevices(void) /* ok, we have a sane list, let's set up hotplug notifications now... */ SDL_AtomicSet(&pulseaudio_hotplug_thread_active, 1); - pulseaudio_hotplug_thread = SDL_CreateThreadInternal(HotplugThread, "PulseHotplug", 256 * 1024, ready_sem); /* !!! FIXME: this can probably survive in significantly less stack space. */ - SDL_SemWait(ready_sem); + pulseaudio_hotplug_thread = SDL_CreateThreadInternal(HotplugThread, "PulseHotplug", 0, ready_sem); + if (pulseaudio_hotplug_thread) { + SDL_SemWait(ready_sem); + } else { + SDL_AtomicSet(&pulseaudio_hotplug_thread_active, 0); // thread failed to start, we'll go on without hotplug. + } SDL_DestroySemaphore(ready_sem); } From 1c4dd015ac28fa634024545f94a114c49a8d4acb Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Fri, 13 Sep 2024 21:15:08 +0200 Subject: [PATCH 10/20] Spell "unknown" correctly (cherry picked from commit ee377793fe0e45014288cf6b46f2309aa5c55cf6) (cherry picked from commit d9b4b7d0e0a7f83167f099687fb2d94d07c6fb49) --- .../app/src/main/java/org/libsdl/app/SDLActivity.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java index 2114311f1ff7d..582157b0308e0 100644 --- a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java +++ b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java @@ -89,7 +89,7 @@ public static void debugSource(int sources, String prefix) { | InputDevice.SOURCE_CLASS_POSITION | InputDevice.SOURCE_CLASS_TRACKBALL); - if (s2 != 0) cls += "Some_Unkown"; + if (s2 != 0) cls += "Some_Unknown"; s2 = s_copy & InputDevice.SOURCE_ANY; // keep source only, no class; @@ -163,7 +163,7 @@ public static void debugSource(int sources, String prefix) { if (s == FLAG_TAINTED) src += " FLAG_TAINTED"; s2 &= ~FLAG_TAINTED; - if (s2 != 0) src += " Some_Unkown"; + if (s2 != 0) src += " Some_Unknown"; Log.v(TAG, prefix + "int=" + s_copy + " CLASS={" + cls + " } source(s):" + src); } From 6f0fae74321a6d72bbf6a0ec414031163199ed0c Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Wed, 18 Sep 2024 19:37:10 -0500 Subject: [PATCH 11/20] wayland: Fix memory leaks (cherry picked from commit e239295491abef326c2370cb9d680ae326d464de) --- src/video/wayland/SDL_waylandevents.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index 9e9c3934022b1..dc34cfeef3a0d 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -248,12 +248,25 @@ static SDL_bool keyboard_repeat_key_is_set(SDL_WaylandKeyboardRepeat *repeat_inf return repeat_info->is_initialized && repeat_info->is_key_down && key == repeat_info->key; } +static void sync_done_handler(void *data, struct wl_callback *callback, uint32_t callback_data) +{ + /* Nothing to do, just destroy the callback */ + wl_callback_destroy(callback); +} + +static struct wl_callback_listener sync_listener = { + sync_done_handler +}; + void Wayland_SendWakeupEvent(_THIS, SDL_Window *window) { SDL_VideoData *d = _this->driverdata; - /* TODO: Maybe use a pipe to avoid the compositor roundtrip? */ - wl_display_sync(d->display); + /* Queue a sync event to unblock the event queue fd if it's empty and being waited on. + * TODO: Maybe use a pipe to avoid the compositor roundtrip? + */ + struct wl_callback *cb = wl_display_sync(d->display); + wl_callback_add_listener(cb, &sync_listener, NULL); WAYLAND_wl_display_flush(d->display); } @@ -2522,6 +2535,9 @@ void Wayland_display_destroy_input(SDL_VideoData *d) if (input->primary_selection_device->selection_offer) { Wayland_primary_selection_offer_destroy(input->primary_selection_device->selection_offer); } + if (input->primary_selection_device->primary_selection_device) { + zwp_primary_selection_device_v1_destroy(input->primary_selection_device->primary_selection_device); + } SDL_free(input->primary_selection_device); } From 5669b97fd78642b9068d4efa3eeab84098ce8527 Mon Sep 17 00:00:00 2001 From: T3hD0gg <150945521+t3hd0gg@users.noreply.github.com> Date: Fri, 13 Sep 2024 19:53:32 -0400 Subject: [PATCH 12/20] Add Thrustmaster TMX VID & PID to wheel device list. (cherry picked from commit 594edb6bd2995a610c64fadd3f82d7ae4c33dd98) (cherry picked from commit ec9a9fee58aa9588eb9c83dc9bffa96322a1d7e6) --- src/joystick/SDL_joystick.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index dff447bd217ee..3b72fd3601328 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -370,6 +370,7 @@ static Uint32 initial_wheel_devices[] = { MAKE_VIDPID(0x044f, 0xb65e), /* Thrustmaster T500RS */ MAKE_VIDPID(0x044f, 0xb664), /* Thrustmaster TX (initial mode) */ MAKE_VIDPID(0x044f, 0xb669), /* Thrustmaster TX (active mode) */ + MAKE_VIDPID(0x044f, 0xb67f), /* Thrustmaster TMX */ MAKE_VIDPID(0x044f, 0xb691), /* Thrustmaster TS-XW (initial mode) */ MAKE_VIDPID(0x044f, 0xb692), /* Thrustmaster TS-XW (active mode) */ MAKE_VIDPID(0x0483, 0x0522), /* Simagic Wheelbase (including M10, Alpha Mini, Alpha, Alpha U) */ From d9139ff3de509cd6d7921fb1cd2c4b21f4c110f1 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 21 Sep 2024 14:20:08 -0500 Subject: [PATCH 13/20] kmsdrm: Keep fd around if we can drop master Modern kernels (v5.8+) allow non-root usage of drmDropMaster(), so we can hold on to our fd after dropping master on it. This fixes populating drm_fd in the KMSDRM SysWMinfo when using Vulkan. Also add a missing error check for open() while we're here. (cherry picked from commit dab4f856c1ec89e693b029c14751df5dc2376543) --- src/video/kmsdrm/SDL_kmsdrmvideo.c | 31 ++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/video/kmsdrm/SDL_kmsdrmvideo.c b/src/video/kmsdrm/SDL_kmsdrmvideo.c index 7cd538c942064..e17e9ce3bddf4 100644 --- a/src/video/kmsdrm/SDL_kmsdrmvideo.c +++ b/src/video/kmsdrm/SDL_kmsdrmvideo.c @@ -533,7 +533,7 @@ static drmModeModeInfo *KMSDRM_GetClosestDisplayMode(SDL_VideoDisplay *display, /* Deinitializes the driverdata of the SDL Displays in the SDL display list. */ static void KMSDRM_DeinitDisplays(_THIS) { - + SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata); SDL_DisplayData *dispdata; int num_displays, i; @@ -557,6 +557,11 @@ static void KMSDRM_DeinitDisplays(_THIS) dispdata->crtc = NULL; } } + + if (viddata->drm_fd >= 0) { + close(viddata->drm_fd); + viddata->drm_fd = -1; + } } static uint32_t KMSDRM_CrtcGetPropId(uint32_t drm_fd, @@ -912,8 +917,6 @@ static void KMSDRM_AddDisplay(_THIS, drmModeConnector *connector, drmModeRes *re /* Initializes the list of SDL displays: we build a new display for each connecter connector we find. - Inoffeensive for VK compatibility, except we must leave the drm_fd - closed when we get to the end of this function. This is to be called early, in VideoInit(), because it gets us the videomode information, which SDL needs immediately after VideoInit(). */ static int KMSDRM_InitDisplays(_THIS) @@ -986,10 +989,13 @@ static int KMSDRM_InitDisplays(_THIS) /* Block for Vulkan compatibility. */ /***********************************/ - /* THIS IS FOR VULKAN! Leave the FD closed, so VK can work. - Will reopen this in CreateWindow, but only if requested a non-VK window. */ - close(viddata->drm_fd); - viddata->drm_fd = -1; + /* Vulkan requires DRM master on its own FD to work, so try to drop master + on our FD. This will only work without root on kernels v5.8 and later. + If it doesn't work, just close the FD and we'll reopen it later. */ + if (KMSDRM_drmDropMaster(viddata->drm_fd) < 0) { + close(viddata->drm_fd); + viddata->drm_fd = -1; + } cleanup: if (resources) { @@ -1017,10 +1023,15 @@ static int KMSDRM_GBMInit(_THIS, SDL_DisplayData *dispdata) SDL_VideoData *viddata = (SDL_VideoData *)_this->driverdata; int ret = 0; - /* Reopen the FD! */ - viddata->drm_fd = open(viddata->devpath, O_RDWR | O_CLOEXEC); + /* Reopen the FD if we weren't able to drop master on the original one */ + if (viddata->drm_fd < 0) { + viddata->drm_fd = open(viddata->devpath, O_RDWR | O_CLOEXEC); + if (viddata->drm_fd < 0) { + return SDL_SetError("Could not reopen %s", viddata->devpath); + } + } - /* Set the FD we just opened as current DRM master. */ + /* Set the FD as current DRM master. */ KMSDRM_drmSetMaster(viddata->drm_fd); /* Create the GBM device. */ From 5e90dd350796a31266c778114ab3f538f8185b33 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Mon, 23 Sep 2024 18:59:54 -0500 Subject: [PATCH 14/20] kmsdrm: Fix one more place that doesn't try to drop master (cherry picked from commit 7eb85b07e0b76c7e8ae5bfdde5932af7249df395) --- src/video/kmsdrm/SDL_kmsdrmvideo.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/video/kmsdrm/SDL_kmsdrmvideo.c b/src/video/kmsdrm/SDL_kmsdrmvideo.c index e17e9ce3bddf4..dbcb05239b6b5 100644 --- a/src/video/kmsdrm/SDL_kmsdrmvideo.c +++ b/src/video/kmsdrm/SDL_kmsdrmvideo.c @@ -530,6 +530,19 @@ static drmModeModeInfo *KMSDRM_GetClosestDisplayMode(SDL_VideoDisplay *display, /* _this is a SDL_VideoDevice * */ /*****************************************************************************/ +static SDL_bool KMSDRM_DropMaster(_THIS) +{ + SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata); + + /* Check if we have DRM master to begin with */ + if (KMSDRM_drmAuthMagic(viddata->drm_fd, 0) == -EACCES) { + /* Nope, nothing to do then */ + return SDL_TRUE; + } + + return KMSDRM_drmDropMaster(viddata->drm_fd) < 0 ? SDL_FALSE : SDL_TRUE; +} + /* Deinitializes the driverdata of the SDL Displays in the SDL display list. */ static void KMSDRM_DeinitDisplays(_THIS) { @@ -992,7 +1005,7 @@ static int KMSDRM_InitDisplays(_THIS) /* Vulkan requires DRM master on its own FD to work, so try to drop master on our FD. This will only work without root on kernels v5.8 and later. If it doesn't work, just close the FD and we'll reopen it later. */ - if (KMSDRM_drmDropMaster(viddata->drm_fd) < 0) { + if (!KMSDRM_DropMaster(_this)) { close(viddata->drm_fd); viddata->drm_fd = -1; } @@ -1057,8 +1070,9 @@ static void KMSDRM_GBMDeinit(_THIS, SDL_DisplayData *dispdata) viddata->gbm_dev = NULL; } - /* Finally close DRM FD. May be reopen on next non-vulkan window creation. */ - if (viddata->drm_fd >= 0) { + /* Finally drop DRM master if possible, otherwise close DRM FD. + May be reopened on next non-vulkan window creation. */ + if (viddata->drm_fd >= 0 && !KMSDRM_DropMaster(_this)) { close(viddata->drm_fd); viddata->drm_fd = -1; } From b6535836aa5a9d1b7e959ce6b98fb47d997a0d54 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Tue, 24 Sep 2024 22:05:12 -0500 Subject: [PATCH 15/20] Throttle tickle reports to PS4/PS5 controllers UpdateDevice() can be called at an arbitrary rate, so we need to pace ourselves to avoid filling up the rumble queue with these. (cherry picked from commit 6ec8b1a1735b5177f75f67e2cca595e763425319) (cherry picked from commit 656b5998283d159b5fff5ca2f697c5d440136754) --- src/joystick/hidapi/SDL_hidapi_ps4.c | 1 + src/joystick/hidapi/SDL_hidapi_ps5.c | 1 + 2 files changed, 2 insertions(+) diff --git a/src/joystick/hidapi/SDL_hidapi_ps4.c b/src/joystick/hidapi/SDL_hidapi_ps4.c index 565431d838928..8af16671e1f05 100644 --- a/src/joystick/hidapi/SDL_hidapi_ps4.c +++ b/src/joystick/hidapi/SDL_hidapi_ps4.c @@ -1208,6 +1208,7 @@ static SDL_bool HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device) if (SDL_TICKS_PASSED(now, ctx->last_packet + BLUETOOTH_DISCONNECT_TIMEOUT_MS)) { /* Send an empty output report to tickle the Bluetooth stack */ HIDAPI_DriverPS4_TickleBluetooth(device); + ctx->last_packet = now; } } else { /* Reconnect the Bluetooth device once the USB device is gone */ diff --git a/src/joystick/hidapi/SDL_hidapi_ps5.c b/src/joystick/hidapi/SDL_hidapi_ps5.c index dfdbc81201d75..684f601bb8fe7 100644 --- a/src/joystick/hidapi/SDL_hidapi_ps5.c +++ b/src/joystick/hidapi/SDL_hidapi_ps5.c @@ -1500,6 +1500,7 @@ static SDL_bool HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device) if (SDL_TICKS_PASSED(now, ctx->last_packet + BLUETOOTH_DISCONNECT_TIMEOUT_MS)) { /* Send an empty output report to tickle the Bluetooth stack */ HIDAPI_DriverPS5_TickleBluetooth(device); + ctx->last_packet = now; } } else { /* Reconnect the Bluetooth device once the USB device is gone */ From 235c87dc92c9bc9a1b5c30a3a52b8ca17653b7dd Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Wed, 25 Sep 2024 21:54:05 -0700 Subject: [PATCH 16/20] Don't use BlitARGBto555PixelAlpha() for SDL_PIXELFORMAT_ARGB1555 This didn't properly take into account destination alpha. Fixes https://github.com/libsdl-org/SDL/issues/8401 (cherry picked from commit 1aea43846e0286d44d3249a02220dab222e38218) (cherry picked from commit c9f3cbe02f1b81f6591608f0f19b35c7d3a1347c) --- src/video/SDL_blit_A.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/video/SDL_blit_A.c b/src/video/SDL_blit_A.c index 2cf00e0a2c06b..96fec1b478fc8 100644 --- a/src/video/SDL_blit_A.c +++ b/src/video/SDL_blit_A.c @@ -1222,10 +1222,9 @@ static void BlitARGBto565PixelAlpha(SDL_BlitInfo *info) DUFFS_LOOP4({ Uint32 s = *srcp; unsigned alpha = s >> 27; /* downscale alpha to 5 bits */ - /* FIXME: Here we special-case opaque alpha since the + /* Here we special-case opaque alpha since the compositioning used (>>8 instead of /255) doesn't handle - it correctly. Also special-case alpha=0 for speed? - Benchmark this! */ + it correctly. */ if (alpha) { if (alpha == (SDL_ALPHA_OPAQUE >> 3)) { *dstp = (Uint16)((s >> 8 & 0xf800) + (s >> 5 & 0x7e0) + (s >> 3 & 0x1f)); @@ -1235,8 +1234,7 @@ static void BlitARGBto565PixelAlpha(SDL_BlitInfo *info) * convert source and destination to G0RAB65565 * and blend all components at the same time */ - s = ((s & 0xfc00) << 11) + (s >> 8 & 0xf800) - + (s >> 3 & 0x1f); + s = ((s & 0xfc00) << 11) + (s >> 8 & 0xf800) + (s >> 3 & 0x1f); d = (d | d << 16) & 0x07e0f81f; d += (s - d) * alpha >> 5; d &= 0x07e0f81f; @@ -1268,21 +1266,19 @@ static void BlitARGBto555PixelAlpha(SDL_BlitInfo *info) unsigned alpha; Uint32 s = *srcp; alpha = s >> 27; /* downscale alpha to 5 bits */ - /* FIXME: Here we special-case opaque alpha since the + /* Here we special-case opaque alpha since the compositioning used (>>8 instead of /255) doesn't handle - it correctly. Also special-case alpha=0 for speed? - Benchmark this! */ + it correctly. */ if (alpha) { if (alpha == (SDL_ALPHA_OPAQUE >> 3)) { *dstp = (Uint16)((s >> 9 & 0x7c00) + (s >> 6 & 0x3e0) + (s >> 3 & 0x1f)); } else { Uint32 d = *dstp; /* - * convert source and destination to G0RAB65565 + * convert source and destination to G0RAB55555 * and blend all components at the same time */ - s = ((s & 0xf800) << 10) + (s >> 9 & 0x7c00) - + (s >> 3 & 0x1f); + s = ((s & 0xf800) << 10) + (s >> 9 & 0x7c00) + (s >> 3 & 0x1f); d = (d | d << 16) & 0x03e07c1f; d += (s - d) * alpha >> 5; d &= 0x03e07c1f; @@ -1452,7 +1448,7 @@ SDL_BlitFunc SDL_CalculateBlitA(SDL_Surface *surface) if (sf->BytesPerPixel == 4 && sf->Amask == 0xff000000 && sf->Gmask == 0xff00 && ((sf->Rmask == 0xff && df->Rmask == 0x1f) || (sf->Bmask == 0xff && df->Bmask == 0x1f))) { if (df->Gmask == 0x7e0) { return BlitARGBto565PixelAlpha; - } else if (df->Gmask == 0x3e0) { + } else if (df->Gmask == 0x3e0 && !df->Amask) { return BlitARGBto555PixelAlpha; } } From e9f5f3ac1f3eb83bc417482f360f5f3b5f8758d5 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Tue, 1 Oct 2024 09:25:57 -0700 Subject: [PATCH 17/20] Updated to version 2.30.8 for release --- CMakeLists.txt | 2 +- Makefile.os2 | 2 +- Makefile.w32 | 2 +- Xcode/SDL/Info-Framework.plist | 4 ++-- Xcode/SDL/SDL.xcodeproj/project.pbxproj | 12 ++++++------ Xcode/SDL/pkg-support/SDL.info | 2 +- .../src/main/java/org/libsdl/app/SDLActivity.java | 2 +- configure | 2 +- configure.ac | 2 +- include/SDL_version.h | 2 +- src/main/windows/version.rc | 8 ++++---- 11 files changed, 20 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e135490ac1f7..c930eadf79a0d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,7 +87,7 @@ endif() # See docs/release_checklist.md set(SDL_MAJOR_VERSION 2) set(SDL_MINOR_VERSION 30) -set(SDL_MICRO_VERSION 7) +set(SDL_MICRO_VERSION 8) set(SDL_VERSION "${SDL_MAJOR_VERSION}.${SDL_MINOR_VERSION}.${SDL_MICRO_VERSION}") # Set defaults preventing destination file conflicts diff --git a/Makefile.os2 b/Makefile.os2 index ff95021bbd2a2..82160b9e76c1f 100644 --- a/Makefile.os2 +++ b/Makefile.os2 @@ -15,7 +15,7 @@ LIBNAME = SDL2 MAJOR_VERSION = 2 MINOR_VERSION = 30 -MICRO_VERSION = 7 +MICRO_VERSION = 8 VERSION = $(MAJOR_VERSION).$(MINOR_VERSION).$(MICRO_VERSION) DESCRIPTION = Simple DirectMedia Layer 2 diff --git a/Makefile.w32 b/Makefile.w32 index 076f7954cbeb5..9053fa30b929f 100644 --- a/Makefile.w32 +++ b/Makefile.w32 @@ -6,7 +6,7 @@ LIBNAME = SDL2 MAJOR_VERSION = 2 MINOR_VERSION = 30 -MICRO_VERSION = 7 +MICRO_VERSION = 8 VERSION = $(MAJOR_VERSION).$(MINOR_VERSION).$(MICRO_VERSION) LIBHOME = . diff --git a/Xcode/SDL/Info-Framework.plist b/Xcode/SDL/Info-Framework.plist index 342da0ec7c101..7e5c8d957adb6 100644 --- a/Xcode/SDL/Info-Framework.plist +++ b/Xcode/SDL/Info-Framework.plist @@ -19,10 +19,10 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.30.7 + 2.30.8 CFBundleSignature SDLX CFBundleVersion - 2.30.7 + 2.30.8 diff --git a/Xcode/SDL/SDL.xcodeproj/project.pbxproj b/Xcode/SDL/SDL.xcodeproj/project.pbxproj index 217add597ca59..2039e1aadd438 100644 --- a/Xcode/SDL/SDL.xcodeproj/project.pbxproj +++ b/Xcode/SDL/SDL.xcodeproj/project.pbxproj @@ -9729,7 +9729,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEPLOYMENT_POSTPROCESSING = YES; DYLIB_COMPATIBILITY_VERSION = 3001.0.0; - DYLIB_CURRENT_VERSION = 3001.7.0; + DYLIB_CURRENT_VERSION = 3001.8.0; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_ALTIVEC_EXTENSIONS = YES; @@ -9770,7 +9770,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_LINK_OBJC_RUNTIME = NO; - MARKETING_VERSION = 2.30.7; + MARKETING_VERSION = 2.30.8; OTHER_LDFLAGS = "-liconv"; }; name = Release; @@ -9814,7 +9814,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; DEBUG_INFORMATION_FORMAT = dwarf; DYLIB_COMPATIBILITY_VERSION = 3001.0.0; - DYLIB_CURRENT_VERSION = 3001.7.0; + DYLIB_CURRENT_VERSION = 3001.8.0; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -9856,7 +9856,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_LINK_OBJC_RUNTIME = NO; - MARKETING_VERSION = 2.30.7; + MARKETING_VERSION = 2.30.8; OTHER_LDFLAGS = "-liconv"; }; name = Debug; @@ -10063,7 +10063,7 @@ DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 3001.0.0; - DYLIB_CURRENT_VERSION = 3001.7.0; + DYLIB_CURRENT_VERSION = 3001.8.0; DYLIB_INSTALL_NAME_BASE = "@rpath"; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; @@ -10115,7 +10115,7 @@ DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 3001.0.0; - DYLIB_CURRENT_VERSION = 3001.7.0; + DYLIB_CURRENT_VERSION = 3001.8.0; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_NS_ASSERTIONS = NO; GCC_C_LANGUAGE_STANDARD = gnu11; diff --git a/Xcode/SDL/pkg-support/SDL.info b/Xcode/SDL/pkg-support/SDL.info index 0e289444dc1fe..fa5bc62d1caf5 100644 --- a/Xcode/SDL/pkg-support/SDL.info +++ b/Xcode/SDL/pkg-support/SDL.info @@ -1,4 +1,4 @@ -Title SDL 2.30.7 +Title SDL 2.30.8 Version 1 Description SDL Library for Mac OS X (http://www.libsdl.org) DefaultLocation /Library/Frameworks diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java index 582157b0308e0..05ed80bdfa466 100644 --- a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java +++ b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java @@ -61,7 +61,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh private static final String TAG = "SDL"; private static final int SDL_MAJOR_VERSION = 2; private static final int SDL_MINOR_VERSION = 30; - private static final int SDL_MICRO_VERSION = 7; + private static final int SDL_MICRO_VERSION = 8; /* // Display InputType.SOURCE/CLASS of events and devices // diff --git a/configure b/configure index 6d39b056a8869..124d9462334e9 100755 --- a/configure +++ b/configure @@ -3508,7 +3508,7 @@ orig_CFLAGS="$CFLAGS" # See docs/release_checklist.md SDL_MAJOR_VERSION=2 SDL_MINOR_VERSION=30 -SDL_MICRO_VERSION=7 +SDL_MICRO_VERSION=8 SDL_VERSION=$SDL_MAJOR_VERSION.$SDL_MINOR_VERSION.$SDL_MICRO_VERSION SDL_BINARY_AGE=`expr $SDL_MINOR_VERSION \* 100 + $SDL_MICRO_VERSION` diff --git a/configure.ac b/configure.ac index 7be3b5c3f9499..4e37d16a23145 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ dnl Set various version strings - taken gratefully from the GTk sources # See docs/release_checklist.md SDL_MAJOR_VERSION=2 SDL_MINOR_VERSION=30 -SDL_MICRO_VERSION=7 +SDL_MICRO_VERSION=8 SDL_VERSION=$SDL_MAJOR_VERSION.$SDL_MINOR_VERSION.$SDL_MICRO_VERSION SDL_BINARY_AGE=`expr $SDL_MINOR_VERSION \* 100 + $SDL_MICRO_VERSION` diff --git a/include/SDL_version.h b/include/SDL_version.h index 517811f32e3e6..dc8a254fa4c10 100644 --- a/include/SDL_version.h +++ b/include/SDL_version.h @@ -59,7 +59,7 @@ typedef struct SDL_version */ #define SDL_MAJOR_VERSION 2 #define SDL_MINOR_VERSION 30 -#define SDL_PATCHLEVEL 7 +#define SDL_PATCHLEVEL 8 /** * Macro to determine SDL version program was compiled against. diff --git a/src/main/windows/version.rc b/src/main/windows/version.rc index 455c254f62fab..b4898daf6338f 100644 --- a/src/main/windows/version.rc +++ b/src/main/windows/version.rc @@ -9,8 +9,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,30,7,0 - PRODUCTVERSION 2,30,7,0 + FILEVERSION 2,30,8,0 + PRODUCTVERSION 2,30,8,0 FILEFLAGSMASK 0x3fL FILEFLAGS 0x0L FILEOS 0x40004L @@ -23,12 +23,12 @@ BEGIN BEGIN VALUE "CompanyName", "\0" VALUE "FileDescription", "SDL\0" - VALUE "FileVersion", "2, 30, 7, 0\0" + VALUE "FileVersion", "2, 30, 8, 0\0" VALUE "InternalName", "SDL\0" VALUE "LegalCopyright", "Copyright (C) 2024 Sam Lantinga\0" VALUE "OriginalFilename", "SDL2.dll\0" VALUE "ProductName", "Simple DirectMedia Layer\0" - VALUE "ProductVersion", "2, 30, 7, 0\0" + VALUE "ProductVersion", "2, 30, 8, 0\0" END END BLOCK "VarFileInfo" From 025fc35c87f05a0e0d8e2e9e3d497f2d3cc17aef Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Mon, 16 Sep 2024 22:56:12 +0200 Subject: [PATCH 18/20] Port SDL3 release scripts to SDL2 [skip ci] (cherry picked from commit 8291b1be363ceada6ad64844a4467a5e09763fdf) --- .github/workflows/release.yml | 406 +++++++++++ .gitignore | 1 + VisualC/SDL/SDL.vcxproj | 16 - VisualC/pkg-support/cmake/sdl2-config.cmake | 4 +- build-scripts/build-release.py | 640 ++++++++++++++++++ .../cmake-toolchain-mingw64-i686.cmake | 18 + .../cmake-toolchain-mingw64-x86_64.cmake | 18 + build-scripts/create-release.py | 41 ++ cmake/test/CMakeLists.txt | 26 + cmake/test/sdltest.c | 9 + mingw/pkg-support/INSTALL.txt | 18 + mingw/pkg-support/Makefile | 30 + .../cmake/sdl2-config-version.cmake | 4 +- mingw/pkg-support/cmake/sdl2-config.cmake | 4 +- 14 files changed, 1214 insertions(+), 21 deletions(-) create mode 100644 .github/workflows/release.yml create mode 100755 build-scripts/build-release.py create mode 100644 build-scripts/cmake-toolchain-mingw64-i686.cmake create mode 100644 build-scripts/cmake-toolchain-mingw64-x86_64.cmake create mode 100755 build-scripts/create-release.py create mode 100644 cmake/test/sdltest.c create mode 100644 mingw/pkg-support/INSTALL.txt create mode 100644 mingw/pkg-support/Makefile diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000000..f6f0c56665a8d --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,406 @@ +name: 'release' +run-name: 'Create SDL release artifacts for ${{ inputs.commit }}' + +on: + workflow_dispatch: + inputs: + commit: + description: 'Commit of SDL' + required: true + +jobs: + + src: + runs-on: ubuntu-latest + outputs: + project: ${{ steps.releaser.outputs.project }} + version: ${{ steps.releaser.outputs.version }} + src-tar-gz: ${{ steps.releaser.outputs.src-tar-gz }} + src-tar-xz: ${{ steps.releaser.outputs.src-tar-xz }} + src-zip: ${{ steps.releaser.outputs.src-zip }} + steps: + - name: 'Set up Python' + uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: 'Fetch build-release.py' + uses: actions/checkout@v4 + with: + sparse-checkout: 'build-scripts/build-release.py' + - name: 'Set up SDL sources' + uses: actions/checkout@v4 + with: + path: 'SDL' + fetch-depth: 0 + - name: 'Build Source archive' + id: releaser + shell: bash + run: | + python build-scripts/build-release.py \ + --create source \ + --commit ${{ inputs.commit }} \ + --project SDL2 \ + --root "${{ github.workspace }}/SDL" \ + --github \ + --debug + - name: 'Store source archives' + uses: actions/upload-artifact@v4 + with: + name: sources + path: '${{ github.workspace}}/dist' + + linux-verify: + needs: [src] + runs-on: ubuntu-latest + steps: + - name: 'Download source archives' + uses: actions/download-artifact@v4 + with: + name: sources + path: '${{ github.workspace }}' + - name: 'Unzip ${{ needs.src.outputs.src-zip }}' + id: zip + run: | + mkdir /tmp/zipdir + cd /tmp/zipdir + unzip "${{ github.workspace }}/${{ needs.src.outputs.src-zip }}" + echo "path=/tmp/zipdir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT + - name: 'Untar ${{ needs.src.outputs.src-tar-gz }}' + id: tar + run: | + mkdir -p /tmp/tardir + tar -C /tmp/tardir -v -x -f "${{ github.workspace }}/${{ needs.src.outputs.src-tar-gz }}" + echo "path=/tmp/tardir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT + - name: 'Compare contents of ${{ needs.src.outputs.src-zip }} and ${{ needs.src.outputs.src-tar-gz }}' + run: | + diff /tmp/zipdir /tmp/tardir + - name: 'Test versioning' + shell: bash + run: | + ${{ steps.tar.outputs.path }}/build-scripts/test-versioning.sh + - name: 'CMake (configure + build + tests + examples)' + run: | + cmake -S ${{ steps.tar.outputs.path }} -B /tmp/build -DSDL_TEST_LIBRARY=TRUE -DSDL_TESTS=TRUE -DSDL_EXAMPLES=TRUE + cmake --build /tmp/build --verbose + ctest --test-dir /tmp/build --no-tests=error --output-on-failure + + dmg: + needs: [src] + runs-on: macos-latest + outputs: + dmg: ${{ steps.releaser.outputs.dmg }} + steps: + - name: 'Set up Python' + uses: actions/setup-python@v5 + with: + python-version: '3.10' + - name: 'Fetch build-release.py' + uses: actions/checkout@v4 + with: + sparse-checkout: 'build-scripts/build-release.py' + - name: 'Download source archives' + uses: actions/download-artifact@v4 + with: + name: sources + path: '${{ github.workspace }}' + - name: 'Untar ${{ needs.src.outputs.src-tar-gz }}' + id: tar + run: | + mkdir -p "${{ github.workspace }}/tardir" + tar -C "${{ github.workspace }}/tardir" -v -x -f "${{ github.workspace }}/${{ needs.src.outputs.src-tar-gz }}" + echo "path=${{ github.workspace }}/tardir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT + - name: 'Build SDL2.dmg' + id: releaser + shell: bash + run: | + python build-scripts/build-release.py \ + --create framework \ + --commit ${{ inputs.commit }} \ + --project SDL2 \ + --root "${{ steps.tar.outputs.path }}" \ + --github \ + --debug + - name: 'Store DMG image file' + uses: actions/upload-artifact@v4 + with: + name: dmg + path: '${{ github.workspace }}/dist' + + dmg-verify: + needs: [dmg, src] + runs-on: macos-latest + steps: + - name: 'Download source archives' + uses: actions/download-artifact@v4 + with: + name: sources + path: '${{ github.workspace }}' + - name: 'Download ${{ needs.dmg.outputs.dmg }}' + uses: actions/download-artifact@v4 + with: + name: dmg + path: '${{ github.workspace }}' + - name: 'Untar ${{ needs.src.outputs.src-tar-gz }}' + id: src + run: | + mkdir -p /tmp/tardir + tar -C /tmp/tardir -v -x -f "${{ github.workspace }}/${{ needs.src.outputs.src-tar-gz }}" + echo "path=/tmp/tardir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT + - name: 'Mount ${{ needs.dmg.outputs.dmg }}' + id: mount + run: | + hdiutil attach '${{ github.workspace }}/${{ needs.dmg.outputs.dmg }}' + mount_point="/Volumes/${{ needs.src.outputs.project }}" + if [ ! -d "$mount_point/${{ needs.src.outputs.project }}.framework" ]; then + echo "Cannot find ${{ needs.src.outputs.project }}.framework!" + exit 1 + fi + echo "mount_point=$mount_point">>$GITHUB_OUTPUT + - name: 'CMake (configure + build) Darwin' + run: | + set -e + cmake -S "${{ steps.src.outputs.path }}/cmake/test" \ + -DTEST_FULL=FALSE \ + -DTEST_STATIC=FALSE \ + -DTEST_TEST=FALSE \ + -DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount_point }}" \ + -DCMAKE_SYSTEM_NAME=Darwin \ + -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \ + -Werror=dev \ + -B build_darwin + cmake --build build_darwin --config Release --verbose + + cmake -S "${{ steps.src.outputs.path }}/cmake/test" \ + -DTEST_FULL=FALSE \ + -DTEST_STATIC=FALSE \ + -DTEST_TEST=FALSE \ + -DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount_point }}" \ + -DCMAKE_SYSTEM_NAME=Darwin \ + -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \ + -Werror=dev \ + -B build_darwin_2 + cmake --build build_darwin --config Release --verbose + + msvc: + needs: [src] + runs-on: windows-2019 + outputs: + VC-x86: ${{ steps.releaser.outputs.VC-x86 }} + VC-x64: ${{ steps.releaser.outputs.VC-x64 }} + VC-devel: ${{ steps.releaser.outputs.VC-devel }} + steps: + - name: 'Set up Python' + uses: actions/setup-python@v5 + with: + python-version: '3.10' + - name: 'Fetch build-release.py' + uses: actions/checkout@v4 + with: + sparse-checkout: 'build-scripts/build-release.py' + - name: 'Download source archives' + uses: actions/download-artifact@v4 + with: + name: sources + path: '${{ github.workspace }}' + - name: 'Unzip ${{ needs.src.outputs.src-zip }}' + id: zip + run: | + New-Item C:\temp -ItemType Directory -ErrorAction SilentlyContinue + cd C:\temp + unzip "${{ github.workspace }}/${{ needs.src.outputs.src-zip }}" + echo "path=C:\temp\${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$Env:GITHUB_OUTPUT + - name: 'Build MSVC binary archives' + id: releaser + run: | + python build-scripts/build-release.py ` + --create win32 ` + --commit ${{ inputs.commit }} ` + --project SDL2 ` + --root "${{ steps.zip.outputs.path }}" ` + --github ` + --debug + - name: 'Store MSVC archives' + uses: actions/upload-artifact@v4 + with: + name: win32 + path: '${{ github.workspace }}/dist' + + msvc-verify: + needs: [msvc, src] + runs-on: windows-latest + steps: + - name: 'Fetch .github/actions/setup-ninja/action.yml' + uses: actions/checkout@v4 + with: + sparse-checkout: '.github/actions/setup-ninja/action.yml' + - name: 'Download source archives' + uses: actions/download-artifact@v4 + with: + name: sources + path: '${{ github.workspace }}' + - name: 'Download MSVC binaries' + uses: actions/download-artifact@v4 + with: + name: win32 + path: '${{ github.workspace }}' + - name: 'Unzip ${{ needs.src.outputs.src-zip }}' + id: src + run: | + mkdir '${{ github.workspace }}/sources' + cd '${{ github.workspace }}/sources' + unzip "${{ github.workspace }}/${{ needs.src.outputs.src-zip }}" + echo "path=${{ github.workspace }}/sources/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$env:GITHUB_OUTPUT + - name: 'Unzip ${{ needs.msvc.outputs.VC-devel }}' + id: bin + run: | + mkdir '${{ github.workspace }}/vc' + cd '${{ github.workspace }}/vc' + unzip "${{ github.workspace }}/${{ needs.msvc.outputs.VC-devel }}" + echo "path=${{ github.workspace }}/vc/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$env:GITHUB_OUTPUT + - name: Set up ninja + uses: ./.github/actions/setup-ninja + - name: 'Configure vcvars x86' + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: x64_x86 + - name: 'CMake (configure + build + tests) x86' + run: | + cmake -S "${{ steps.src.outputs.path }}/cmake/test" ` + -B build_x86 ` + -GNinja ` + -DCMAKE_BUILD_TYPE=Debug ` + -Werror=dev ` + -DTEST_FULL=FALSE ` + -DTEST_STATIC=FALSE ` + -DTEST_SHARED=TRUE ` + -DTEST_TEST=TRUE ` + -DCMAKE_SUPPRESS_REGENERATION=TRUE ` + -DCMAKE_PREFIX_PATH="${{ steps.bin.outputs.path }}" + Start-Sleep -Seconds 2 + cmake --build build_x86 --config Release --verbose + #ctest --test-dir build_x86 --no-tests=error -C Release --output-on-failure + - name: 'Configure vcvars x64' + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: x64 + - name: 'CMake (configure + build + tests) x64' + run: | + cmake -S "${{ steps.src.outputs.path }}/cmake/test" ` + -B build_x64 ` + -GNinja ` + -DCMAKE_BUILD_TYPE=Debug ` + -Werror=dev ` + -DTEST_FULL=FALSE ` + -DTEST_STATIC=FALSE ` + -DTEST_SHARED=TRUE ` + -DTEST_TEST=TRUE ` + -DCMAKE_SUPPRESS_REGENERATION=TRUE ` + -DCMAKE_PREFIX_PATH="${{ steps.bin.outputs.path }}" + Start-Sleep -Seconds 2 + cmake --build build_x64 --config Release --verbose + #ctest --test-dir build_x64 --no-tests=error -C Release --output-on-failure + + mingw: + needs: [src] + runs-on: ubuntu-24.04 # FIXME: current ubuntu-latest ships an outdated mingw, replace with ubuntu-latest once 24.04 becomes the new default + outputs: + mingw-devel-tar-gz: ${{ steps.releaser.outputs.mingw-devel-tar-gz }} + mingw-devel-tar-xz: ${{ steps.releaser.outputs.mingw-devel-tar-xz }} + steps: + - name: 'Set up Python' + uses: actions/setup-python@v5 + with: + python-version: '3.10' + - name: 'Fetch build-release.py' + uses: actions/checkout@v4 + with: + sparse-checkout: 'build-scripts/build-release.py' + - name: 'Install Mingw toolchain' + run: | + sudo apt-get update -y + sudo apt-get install -y gcc-mingw-w64 g++-mingw-w64 ninja-build + - name: 'Download source archives' + uses: actions/download-artifact@v4 + with: + name: sources + path: '${{ github.workspace }}' + - name: 'Untar ${{ needs.src.outputs.src-tar-gz }}' + id: tar + run: | + mkdir -p /tmp/tardir + tar -C /tmp/tardir -v -x -f "${{ github.workspace }}/${{ needs.src.outputs.src-tar-gz }}" + echo "path=/tmp/tardir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT + - name: 'Build MinGW binary archives' + id: releaser + run: | + python build-scripts/build-release.py \ + --create mingw \ + --commit ${{ inputs.commit }} \ + --project SDL2 \ + --root "${{ steps.tar.outputs.path }}" \ + --github \ + --debug + - name: 'Store MinGW archives' + uses: actions/upload-artifact@v4 + with: + name: mingw + path: '${{ github.workspace }}/dist' + + mingw-verify: + needs: [mingw, src] + runs-on: ubuntu-latest + steps: + - name: 'Install Mingw toolchain' + run: | + sudo apt-get update -y + sudo apt-get install -y gcc-mingw-w64 g++-mingw-w64 ninja-build + - name: 'Download source archives' + uses: actions/download-artifact@v4 + with: + name: sources + path: '${{ github.workspace }}' + - name: 'Download MinGW binaries' + uses: actions/download-artifact@v4 + with: + name: mingw + path: '${{ github.workspace }}' + - name: 'Untar ${{ needs.src.outputs.src-tar-gz }}' + id: src + run: | + mkdir -p /tmp/tardir + tar -C /tmp/tardir -v -x -f "${{ github.workspace }}/${{ needs.src.outputs.src-tar-gz }}" + echo "path=/tmp/tardir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT + - name: 'Untar ${{ needs.mingw.outputs.mingw-devel-tar-gz }}' + id: bin + run: | + mkdir -p /tmp/mingw-tardir + tar -C /tmp/mingw-tardir -v -x -f "${{ github.workspace }}/${{ needs.mingw.outputs.mingw-devel-tar-gz }}" + echo "path=/tmp/mingw-tardir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT + - name: 'CMake (configure + build) i686' + run: | + set -e + cmake -S "${{ steps.src.outputs.path }}/cmake/test" \ + -DCMAKE_BUILD_TYPE="Release" \ + -DTEST_FULL=FALSE \ + -DTEST_STATIC=TRUE \ + -DTEST_TEST=TRUE \ + -DCMAKE_PREFIX_PATH="${{ steps.bin.outputs.path }}" \ + -DCMAKE_TOOLCHAIN_FILE="${{ steps.src.outputs.path }}/build-scripts/cmake-toolchain-mingw64-i686.cmake" \ + -DCMAKE_C_FLAGS="-DSDL_DISABLE_SSE4_2" \ + -Werror=dev \ + -B build_x86 + cmake --build build_x86 --config Release --verbose + - name: 'CMake (configure + build) x86_64' + run: | + set -e + cmake -S "${{ steps.src.outputs.path }}/cmake/test" \ + -DCMAKE_BUILD_TYPE="Release" \ + -DTEST_FULL=FALSE \ + -DTEST_STATIC=TRUE \ + -DTEST_TEST=TRUE \ + -DCMAKE_PREFIX_PATH="${{ steps.bin.outputs.path }}" \ + -DCMAKE_TOOLCHAIN_FILE="${{ steps.src.outputs.path }}/build-scripts/cmake-toolchain-mingw64-x86_64.cmake" \ + -DCMAKE_C_FLAGS="-DSDL_DISABLE_SSE4_2" \ + -Werror=dev \ + -B build_x64 + cmake --build build_x64 --config Release --verbose diff --git a/.gitignore b/.gitignore index cced2f8ed8b53..0af2680e36b56 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ gen Build buildbot /VERSION.txt +dist *.so *.so.* diff --git a/VisualC/SDL/SDL.vcxproj b/VisualC/SDL/SDL.vcxproj index a798514a1b5e0..b068b3330c326 100644 --- a/VisualC/SDL/SDL.vcxproj +++ b/VisualC/SDL/SDL.vcxproj @@ -44,22 +44,6 @@ - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.40219.1 diff --git a/VisualC/pkg-support/cmake/sdl2-config.cmake b/VisualC/pkg-support/cmake/sdl2-config.cmake index e54f470008e31..411b78a5152d0 100644 --- a/VisualC/pkg-support/cmake/sdl2-config.cmake +++ b/VisualC/pkg-support/cmake/sdl2-config.cmake @@ -79,6 +79,8 @@ endif() unset(_sdl2_library) unset(_sdl2_dll_library) +set(SDL2_SDL2-static_FOUND FALSE) + set(_sdl2main_library "${SDL2_LIBDIR}/SDL2main.lib") if(EXISTS "${_sdl2main_library}") if(NOT TARGET SDL2::SDL2main) @@ -110,7 +112,7 @@ if(EXISTS "${_sdl2test_library}") endif() set(SDL2_SDL2test_FOUND TRUE) else() - set(SDL2_SDL2_FOUND FALSE) + set(SDL2_SDL2test_FOUND FALSE) endif() unset(_sdl2test_library) diff --git a/build-scripts/build-release.py b/build-scripts/build-release.py new file mode 100755 index 0000000000000..3e94b66fc549a --- /dev/null +++ b/build-scripts/build-release.py @@ -0,0 +1,640 @@ +#!/usr/bin/env python + +import argparse +import collections +import contextlib +import datetime +import glob +import io +import json +import logging +import os +from pathlib import Path +import platform +import re +import shutil +import subprocess +import sys +import tarfile +import tempfile +import textwrap +import typing +import zipfile + +logger = logging.getLogger(__name__) + + +VcArchDevel = collections.namedtuple("VcArchDevel", ("dll", "pdb", "imp", "main", "test")) +GIT_HASH_FILENAME = ".git-hash" + +ANDROID_AVAILABLE_ABIS = [ + "armeabi-v7a", + "arm64-v8a", + "x86", + "x86_64", +] +ANDROID_MINIMUM_API = 19 +ANDROID_TARGET_API = 29 +ANDROID_MINIMUM_NDK = 21 + + +class Executer: + def __init__(self, root: Path, dry: bool=False): + self.root = root + self.dry = dry + + def run(self, cmd, stdout=False, dry_out=None, force=False): + sys.stdout.flush() + logger.info("Executing args=%r", cmd) + if self.dry and not force: + if stdout: + return subprocess.run(["echo", "-E", dry_out or ""], stdout=subprocess.PIPE if stdout else None, text=True, check=True, cwd=self.root) + else: + return subprocess.run(cmd, stdout=subprocess.PIPE if stdout else None, text=True, check=True, cwd=self.root) + + +class SectionPrinter: + @contextlib.contextmanager + def group(self, title: str): + print(f"{title}:") + yield + + +class GitHubSectionPrinter(SectionPrinter): + def __init__(self): + super().__init__() + self.in_group = False + + @contextlib.contextmanager + def group(self, title: str): + print(f"::group::{title}") + assert not self.in_group, "Can enter a group only once" + self.in_group = True + yield + self.in_group = False + print("::endgroup::") + + +class VisualStudio: + def __init__(self, executer: Executer, year: typing.Optional[str]=None): + self.executer = executer + self.vsdevcmd = self.find_vsdevcmd(year) + self.msbuild = self.find_msbuild() + + @property + def dry(self) -> bool: + return self.executer.dry + + VS_YEAR_TO_VERSION = { + "2022": 17, + "2019": 16, + "2017": 15, + "2015": 14, + "2013": 12, + } + + def find_vsdevcmd(self, year: typing.Optional[str]=None) -> typing.Optional[Path]: + vswhere_spec = ["-latest"] + if year is not None: + try: + version = self.VS_YEAR_TO_VERSION[year] + except KeyError: + logger.error("Invalid Visual Studio year") + return None + vswhere_spec.extend(["-version", f"[{version},{version+1})"]) + vswhere_cmd = ["vswhere"] + vswhere_spec + ["-property", "installationPath"] + vs_install_path = Path(self.executer.run(vswhere_cmd, stdout=True, dry_out="/tmp").stdout.strip()) + logger.info("VS install_path = %s", vs_install_path) + assert vs_install_path.is_dir(), "VS installation path does not exist" + vsdevcmd_path = vs_install_path / "Common7/Tools/vsdevcmd.bat" + logger.info("vsdevcmd path = %s", vsdevcmd_path) + if self.dry: + vsdevcmd_path.parent.mkdir(parents=True, exist_ok=True) + vsdevcmd_path.touch(exist_ok=True) + assert vsdevcmd_path.is_file(), "vsdevcmd.bat batch file does not exist" + return vsdevcmd_path + + def find_msbuild(self) -> typing.Optional[Path]: + vswhere_cmd = ["vswhere", "-latest", "-requires", "Microsoft.Component.MSBuild", "-find", r"MSBuild\**\Bin\MSBuild.exe"] + msbuild_path = Path(self.executer.run(vswhere_cmd, stdout=True, dry_out="/tmp/MSBuild.exe").stdout.strip()) + logger.info("MSBuild path = %s", msbuild_path) + if self.dry: + msbuild_path.parent.mkdir(parents=True, exist_ok=True) + msbuild_path.touch(exist_ok=True) + assert msbuild_path.is_file(), "MSBuild.exe does not exist" + return msbuild_path + + def build(self, arch: str, platform: str, configuration: str, projects: list[Path]): + assert projects, "Need at least one project to build" + + vsdev_cmd_str = f"\"{self.vsdevcmd}\" -arch={arch}" + msbuild_cmd_str = " && ".join([f"\"{self.msbuild}\" \"{project}\" /m /p:BuildInParallel=true /p:Platform={platform} /p:Configuration={configuration}" for project in projects]) + bat_contents = f"{vsdev_cmd_str} && {msbuild_cmd_str}\n" + bat_path = Path(tempfile.gettempdir()) / "cmd.bat" + with bat_path.open("w") as f: + f.write(bat_contents) + + logger.info("Running cmd.exe script (%s): %s", bat_path, bat_contents) + cmd = ["cmd.exe", "/D", "/E:ON", "/V:OFF", "/S", "/C", f"CALL {str(bat_path)}"] + self.executer.run(cmd) + + +class Releaser: + def __init__(self, project: str, commit: str, root: Path, dist_path: Path, section_printer: SectionPrinter, executer: Executer, cmake_generator: str): + self.project = project + self.version = self.extract_sdl_version(root=root, project=project) + self.root = root + self.commit = commit + self.dist_path = dist_path + self.section_printer = section_printer + self.executer = executer + self.cmake_generator = cmake_generator + + self.artifacts: dict[str, Path] = {} + + @property + def dry(self) -> bool: + return self.executer.dry + + def prepare(self): + logger.debug("Creating dist folder") + self.dist_path.mkdir(parents=True, exist_ok=True) + + TreeItem = collections.namedtuple("TreeItem", ("path", "mode", "data", "time")) + def _get_file_times(self, paths: tuple[str, ...]) -> dict[str, datetime.datetime]: + dry_out = textwrap.dedent("""\ + time=2024-03-14T15:40:25-07:00 + + M\tCMakeLists.txt + """) + git_log_out = self.executer.run(["git", "log", "--name-status", '--pretty=time=%cI', self.commit], stdout=True, dry_out=dry_out).stdout.splitlines(keepends=False) + current_time = None + set_paths = set(paths) + path_times: dict[str, datetime.datetime] = {} + for line in git_log_out: + if not line: + continue + if line.startswith("time="): + current_time = datetime.datetime.fromisoformat(line.removeprefix("time=")) + continue + mod_type, file_paths = line.split(maxsplit=1) + assert current_time is not None + for file_path in file_paths.split("\t"): + if file_path in set_paths and file_path not in path_times: + path_times[file_path] = current_time + assert set(path_times.keys()) == set_paths + return path_times + + @staticmethod + def _path_filter(path: str): + if path.startswith(".git"): + return False + return True + + def _get_git_contents(self) -> dict[str, TreeItem]: + contents_tgz = subprocess.check_output(["git", "archive", "--format=tar.gz", self.commit, "-o", "/dev/stdout"], text=False) + contents = tarfile.open(fileobj=io.BytesIO(contents_tgz), mode="r:gz") + filenames = tuple(m.name for m in contents if m.isfile()) + assert "src/SDL.c" in filenames + assert "include/SDL.h" in filenames + file_times = self._get_file_times(filenames) + git_contents = {} + for ti in contents: + if not ti.isfile(): + continue + if not self._path_filter(ti.name): + continue + contents_file = contents.extractfile(ti.name) + assert contents_file, f"{ti.name} is not a file" + git_contents[ti.name] = self.TreeItem(path=ti.name, mode=ti.mode, data=contents_file.read(), time=file_times[ti.name]) + return git_contents + + def create_source_archives(self) -> None: + archive_base = f"{self.project}-{self.version}" + + git_contents = self._get_git_contents() + git_files = list(git_contents.values()) + assert len(git_contents) == len(git_files) + + latest_mod_time = max(item.time for item in git_files) + + git_files.append(self.TreeItem(path="VERSION.txt", data=f"{self.version}\n".encode(), mode=0o100644, time=latest_mod_time)) + git_files.append(self.TreeItem(path=GIT_HASH_FILENAME, data=f"{self.commit}\n".encode(), mode=0o100644, time=latest_mod_time)) + + git_files.sort(key=lambda v: v.time) + + zip_path = self.dist_path / f"{archive_base}.zip" + logger.info("Creating .zip source archive (%s)...", zip_path) + if self.dry: + zip_path.touch() + else: + with zipfile.ZipFile(zip_path, "w", compression=zipfile.ZIP_DEFLATED) as zip_object: + for git_file in git_files: + file_data_time = (git_file.time.year, git_file.time.month, git_file.time.day, git_file.time.hour, git_file.time.minute, git_file.time.second) + zip_info = zipfile.ZipInfo(filename=f"{archive_base}/{git_file.path}", date_time=file_data_time) + zip_info.external_attr = git_file.mode << 16 + zip_info.compress_type = zipfile.ZIP_DEFLATED + zip_object.writestr(zip_info, data=git_file.data) + self.artifacts["src-zip"] = zip_path + + tar_types = ( + (".tar.gz", "gz"), + (".tar.xz", "xz"), + ) + for ext, comp in tar_types: + tar_path = self.dist_path / f"{archive_base}{ext}" + logger.info("Creating %s source archive (%s)...", ext, tar_path) + if self.dry: + tar_path.touch() + else: + with tarfile.open(tar_path, f"w:{comp}") as tar_object: + for git_file in git_files: + tar_info = tarfile.TarInfo(f"{archive_base}/{git_file.path}") + tar_info.mode = git_file.mode + tar_info.size = len(git_file.data) + tar_info.mtime = git_file.time.timestamp() + tar_object.addfile(tar_info, fileobj=io.BytesIO(git_file.data)) + + if tar_path.suffix == ".gz": + # Zero the embedded timestamp in the gzip'ed tarball + with open(tar_path, "r+b") as f: + f.seek(4, 0) + f.write(b"\x00\x00\x00\x00") + + self.artifacts[f"src-tar-{comp}"] = tar_path + + def create_framework(self, configuration: str="Release") -> None: + dmg_in = self.root / f"Xcode/SDL/build/{self.project}.dmg" + dmg_in.unlink(missing_ok=True) + self.executer.run(["xcodebuild", "-project", str(self.root / "Xcode/SDL/SDL.xcodeproj"), "-target", "Standard DMG", "-configuration", configuration]) + if self.dry: + dmg_in.parent.mkdir(parents=True, exist_ok=True) + dmg_in.touch() + + assert dmg_in.is_file(), f"{self.project}.dmg was not created by xcodebuild" + + dmg_out = self.dist_path / f"{self.project}-{self.version}.dmg" + shutil.copy(dmg_in, dmg_out) + self.artifacts["dmg"] = dmg_out + + @property + def git_hash_data(self) -> bytes: + return f"{self.commit}\n".encode() + + def _tar_add_git_hash(self, tar_object: tarfile.TarFile, root: typing.Optional[str]=None, time: typing.Optional[datetime.datetime]=None): + if not time: + time = datetime.datetime(year=2024, month=4, day=1) + path = GIT_HASH_FILENAME + if root: + path = f"{root}/{path}" + + tar_info = tarfile.TarInfo(path) + tar_info.mode = 0o100644 + tar_info.size = len(self.git_hash_data) + tar_info.mtime = int(time.timestamp()) + tar_object.addfile(tar_info, fileobj=io.BytesIO(self.git_hash_data)) + + def _zip_add_git_hash(self, zip_file: zipfile.ZipFile, root: typing.Optional[str]=None, time: typing.Optional[datetime.datetime]=None): + if not time: + time = datetime.datetime(year=2024, month=4, day=1) + path = GIT_HASH_FILENAME + if root: + path = f"{root}/{path}" + + file_data_time = (time.year, time.month, time.day, time.hour, time.minute, time.second) + zip_info = zipfile.ZipInfo(filename=path, date_time=file_data_time) + zip_info.external_attr = 0o100644 << 16 + zip_info.compress_type = zipfile.ZIP_DEFLATED + zip_file.writestr(zip_info, data=self.git_hash_data) + + def create_mingw_archives(self) -> None: + build_type = "Release" + mingw_archs = ("i686", "x86_64") + build_parent_dir = self.root / "build-mingw" + + zip_path = self.dist_path / f"{self.project}-devel-{self.version}-mingw.zip" + tar_exts = ("gz", "xz") + tar_paths = { ext: self.dist_path / f"{self.project}-devel-{self.version}-mingw.tar.{ext}" for ext in tar_exts} + + arch_install_paths = {} + arch_files = {} + + for arch in mingw_archs: + build_path = build_parent_dir / f"build-{arch}" + install_path = build_parent_dir / f"install-{arch}" + arch_install_paths[arch] = install_path + shutil.rmtree(install_path, ignore_errors=True) + build_path.mkdir(parents=True, exist_ok=True) + with self.section_printer.group(f"Configuring MinGW {arch}"): + self.executer.run([ + "cmake", "-S", str(self.root), "-B", str(build_path), + "--fresh", + f'''-DCMAKE_C_FLAGS="-ffile-prefix-map={self.root}=/src/{self.project}"''', + f'''-DCMAKE_CXX_FLAGS="-ffile-prefix-map={self.root}=/src/{self.project}"''', + "-DSDL_SHARED=ON", + "-DSDL_STATIC=ON", + "-DSDL_DISABLE_INSTALL_DOCS=ON", + "-DSDL_TEST_LIBRARY=ON", + "-DSDL_TESTS=OFF", + "-DCMAKE_INSTALL_BINDIR=bin", + "-DCMAKE_INSTALL_DATAROOTDIR=share", + "-DCMAKE_INSTALL_INCLUDEDIR=include", + "-DCMAKE_INSTALL_LIBDIR=lib", + f"-DCMAKE_BUILD_TYPE={build_type}", + f"-DCMAKE_TOOLCHAIN_FILE={self.root}/build-scripts/cmake-toolchain-mingw64-{arch}.cmake", + f"-G{self.cmake_generator}", + f"-DCMAKE_INSTALL_PREFIX={install_path}", + ]) + with self.section_printer.group(f"Build MinGW {arch}"): + self.executer.run(["cmake", "--build", str(build_path), "--verbose", "--config", build_type]) + with self.section_printer.group(f"Install MinGW {arch}"): + self.executer.run(["cmake", "--install", str(build_path), "--strip", "--config", build_type]) + arch_files[arch] = list(Path(r) / f for r, _, files in os.walk(install_path) for f in files) + + extra_files = ( + ("mingw/pkg-support/INSTALL.txt", ""), + ("mingw/pkg-support/Makefile", ""), + ("mingw/pkg-support/cmake/sdl2-config.cmake", "cmake/"), + ("mingw/pkg-support/cmake/sdl2-config-version.cmake", "cmake/"), + ("BUGS.txt", ""), + ("CREDITS.txt", ""), + ("README-SDL.txt", ""), + ("WhatsNew.txt", ""), + ("LICENSE.txt", ""), + ("README.md", ""), + ) + test_files = list(Path(r) / f for r, _, files in os.walk(self.root / "test") for f in files) + + # FIXME: split SDL2.dll debug information into debug library + # objcopy --only-keep-debug SDL2.dll SDL2.debug.dll + # objcopy --add-gnu-debuglink=SDL2.debug.dll SDL2.dll + # objcopy --strip-debug SDL2.dll + + for comp in tar_exts: + logger.info("Creating %s...", tar_paths[comp]) + with tarfile.open(tar_paths[comp], f"w:{comp}") as tar_object: + arc_root = f"{self.project}-{self.version}" + for file_path, arcdirname in extra_files: + assert not arcdirname or arcdirname[-1] == "/" + arcname = f"{arc_root}/{arcdirname}{Path(file_path).name}" + tar_object.add(self.root / file_path, arcname=arcname) + for arch in mingw_archs: + install_path = arch_install_paths[arch] + arcname_parent = f"{arc_root}/{arch}-w64-mingw32" + for file in arch_files[arch]: + arcname = os.path.join(arcname_parent, file.relative_to(install_path)) + tar_object.add(file, arcname=arcname) + for test_file in test_files: + arcname = f"{arc_root}/test/{test_file.relative_to(self.root/'test')}" + tar_object.add(test_file, arcname=arcname) + self._tar_add_git_hash(tar_object=tar_object, root=arc_root) + + self.artifacts[f"mingw-devel-tar-{comp}"] = tar_paths[comp] + + def build_vs(self, arch: str, platform: str, vs: VisualStudio, configuration: str="Release") -> VcArchDevel: + dll_path = self.root / f"VisualC/SDL/{platform}/{configuration}/{self.project}.dll" + pdb_path = self.root / f"VisualC/SDL/{platform}/{configuration}/{self.project}.pdb" + imp_path = self.root / f"VisualC/SDL/{platform}/{configuration}/{self.project}.lib" + test_path = self.root / f"VisualC/SDLtest/{platform}/{configuration}/{self.project}test.lib" + main_path = self.root / f"VisualC/SDLmain/{platform}/{configuration}/{self.project}main.lib" + + dll_path.unlink(missing_ok=True) + pdb_path.unlink(missing_ok=True) + imp_path.unlink(missing_ok=True) + test_path.unlink(missing_ok=True) + main_path.unlink(missing_ok=True) + + projects = [ + self.root / "VisualC/SDL/SDL.vcxproj", + self.root / "VisualC/SDLmain/SDLmain.vcxproj", + self.root / "VisualC/SDLtest/SDLtest.vcxproj", + ] + + with self.section_printer.group(f"Build {arch} VS binary"): + vs.build(arch=arch, platform=platform, configuration=configuration, projects=projects) + + if self.dry: + dll_path.parent.mkdir(parents=True, exist_ok=True) + dll_path.touch() + pdb_path.touch() + imp_path.touch() + main_path.parent.mkdir(parents=True, exist_ok=True) + main_path.touch() + test_path.parent.mkdir(parents=True, exist_ok=True) + test_path.touch() + + assert dll_path.is_file(), f"{self.project}.dll has not been created" + assert pdb_path.is_file(), f"{self.project}.pdb has not been created" + assert imp_path.is_file(), f"{self.project}.lib has not been created" + assert main_path.is_file(), f"{self.project}main.lib has not been created" + assert test_path.is_file(), f"{self.project}est.lib has not been created" + + zip_path = self.dist_path / f"{self.project}-{self.version}-win32-{arch}.zip" + zip_path.unlink(missing_ok=True) + logger.info("Creating %s", zip_path) + with zipfile.ZipFile(zip_path, mode="w", compression=zipfile.ZIP_DEFLATED) as zf: + logger.debug("Adding %s", dll_path.name) + zf.write(dll_path, arcname=dll_path.name) + logger.debug("Adding %s", "README-SDL.txt") + zf.write(self.root / "README-SDL.txt", arcname="README-SDL.txt") + self._zip_add_git_hash(zip_file=zf) + self.artifacts[f"VC-{arch}"] = zip_path + + return VcArchDevel(dll=dll_path, pdb=pdb_path, imp=imp_path, main=main_path, test=test_path) + + + def build_vs_devel(self, arch_vc: dict[str, VcArchDevel]) -> None: + zip_path = self.dist_path / f"{self.project}-devel-{self.version}-VC.zip" + archive_prefix = f"{self.project}-{self.version}" + + def zip_file(zf: zipfile.ZipFile, path: Path, arcrelpath: str): + arcname = f"{archive_prefix}/{arcrelpath}" + logger.debug("Adding %s to %s", path, arcname) + zf.write(path, arcname=arcname) + + def zip_directory(zf: zipfile.ZipFile, directory: Path, arcrelpath: str): + for f in directory.iterdir(): + if f.is_file(): + arcname = f"{archive_prefix}/{arcrelpath}/{f.name}" + logger.debug("Adding %s to %s", f, arcname) + zf.write(f, arcname=arcname) + + with zipfile.ZipFile(zip_path, mode="w", compression=zipfile.ZIP_DEFLATED) as zf: + for arch, binaries in arch_vc.items(): + zip_file(zf, path=binaries.dll, arcrelpath=f"lib/{arch}/{binaries.dll.name}") + zip_file(zf, path=binaries.imp, arcrelpath=f"lib/{arch}/{binaries.imp.name}") + zip_file(zf, path=binaries.pdb, arcrelpath=f"lib/{arch}/{binaries.pdb.name}") + zip_file(zf, path=binaries.main, arcrelpath=f"lib/{arch}/{binaries.main.name}") + zip_file(zf, path=binaries.test, arcrelpath=f"lib/{arch}/{binaries.test.name}") + + zip_directory(zf, directory=self.root / "include", arcrelpath="include") + zip_directory(zf, directory=self.root / "docs", arcrelpath="docs") + zip_directory(zf, directory=self.root / "VisualC/pkg-support/cmake", arcrelpath="cmake") + + for txt in ("BUGS.txt", "README-SDL.txt", "WhatsNew.txt"): + zip_file(zf, path=self.root / txt, arcrelpath=txt) + zip_file(zf, path=self.root / "LICENSE.txt", arcrelpath="COPYING.txt") + zip_file(zf, path=self.root / "README.md", arcrelpath="README.txt") + + self._zip_add_git_hash(zip_file=zf, root=archive_prefix) + self.artifacts["VC-devel"] = zip_path + + @classmethod + def extract_sdl_version(cls, root: Path, project: str) -> str: + with open(root / f"include/SDL_version.h", "r") as f: + text = f.read() + major = next(re.finditer(r"^#define SDL_MAJOR_VERSION\s+([0-9]+)$", text, flags=re.M)).group(1) + minor = next(re.finditer(r"^#define SDL_MINOR_VERSION\s+([0-9]+)$", text, flags=re.M)).group(1) + micro = next(re.finditer(r"^#define SDL_PATCHLEVEL\s+([0-9]+)$", text, flags=re.M)).group(1) + return f"{major}.{minor}.{micro}" + + +def main(argv=None) -> int: + parser = argparse.ArgumentParser(allow_abbrev=False, description="Create SDL release artifacts") + parser.add_argument("--root", metavar="DIR", type=Path, default=Path(__file__).absolute().parents[1], help="Root of SDL") + parser.add_argument("--out", "-o", metavar="DIR", dest="dist_path", type=Path, default="dist", help="Output directory") + parser.add_argument("--github", action="store_true", help="Script is running on a GitHub runner") + parser.add_argument("--commit", default="HEAD", help="Git commit/tag of which a release should be created") + parser.add_argument("--project", required=True, help="Name of the project (e.g. SDL2") + parser.add_argument("--create", choices=["source", "mingw", "win32", "framework", "android"], required=True, action="append", dest="actions", help="What to do") + parser.set_defaults(loglevel=logging.INFO) + parser.add_argument('--vs-year', dest="vs_year", help="Visual Studio year") + parser.add_argument('--android-api', type=int, dest="android_api", help="Android API version") + parser.add_argument('--android-home', dest="android_home", default=os.environ.get("ANDROID_HOME"), help="Android Home folder") + parser.add_argument('--android-ndk-home', dest="android_ndk_home", default=os.environ.get("ANDROID_NDK_HOME"), help="Android NDK Home folder") + parser.add_argument('--android-abis', dest="android_abis", nargs="*", choices=ANDROID_AVAILABLE_ABIS, default=list(ANDROID_AVAILABLE_ABIS), help="Android NDK Home folder") + parser.add_argument('--cmake-generator', dest="cmake_generator", default="Ninja", help="CMake Generator") + parser.add_argument('--debug', action='store_const', const=logging.DEBUG, dest="loglevel", help="Print script debug information") + parser.add_argument('--dry-run', action='store_true', dest="dry", help="Don't execute anything") + parser.add_argument('--force', action='store_true', dest="force", help="Ignore a non-clean git tree") + + args = parser.parse_args(argv) + logging.basicConfig(level=args.loglevel, format='[%(levelname)s] %(message)s') + args.actions = set(args.actions) + args.dist_path = args.dist_path.absolute() + args.root = args.root.absolute() + args.dist_path = args.dist_path.absolute() + if args.dry: + args.dist_path = args.dist_path / "dry" + + if args.github: + section_printer: SectionPrinter = GitHubSectionPrinter() + else: + section_printer = SectionPrinter() + + executer = Executer(root=args.root, dry=args.dry) + + root_git_hash_path = args.root / GIT_HASH_FILENAME + root_is_maybe_archive = root_git_hash_path.is_file() + if root_is_maybe_archive: + logger.warning("%s detected: Building from archive", GIT_HASH_FILENAME) + archive_commit = root_git_hash_path.read_text().strip() + if args.commit != archive_commit: + logger.warning("Commit argument is %s, but archive commit is %s. Using %s.", args.commit, archive_commit, archive_commit) + args.commit = archive_commit + else: + args.commit = executer.run(["git", "rev-parse", args.commit], stdout=True, dry_out="e5812a9fd2cda317b503325a702ba3c1c37861d9").stdout.strip() + logger.info("Using commit %s", args.commit) + + releaser = Releaser( + project=args.project, + commit=args.commit, + root=args.root, + dist_path=args.dist_path, + executer=executer, + section_printer=section_printer, + cmake_generator=args.cmake_generator, + ) + + if root_is_maybe_archive: + logger.warning("Building from archive. Skipping clean git tree check.") + else: + porcelain_status = executer.run(["git", "status", "--ignored", "--porcelain"], stdout=True, dry_out="\n").stdout.strip() + if porcelain_status: + print(porcelain_status) + logger.warning("The tree is dirty! Do not publish any generated artifacts!") + if not args.force: + raise Exception("The git repo contains modified and/or non-committed files. Run with --force to ignore.") + + with section_printer.group("Arguments"): + print(f"project = {args.project}") + print(f"version = {releaser.version}") + print(f"commit = {args.commit}") + print(f"out = {args.dist_path}") + print(f"actions = {args.actions}") + print(f"dry = {args.dry}") + print(f"force = {args.force}") + print(f"cmake_generator = {args.cmake_generator}") + + releaser.prepare() + + if "source" in args.actions: + if root_is_maybe_archive: + raise Exception("Cannot build source archive from source archive") + with section_printer.group("Create source archives"): + releaser.create_source_archives() + + if "framework" in args.actions: + if platform.system() != "Darwin" and not args.dry: + parser.error("framework artifact(s) can only be built on Darwin") + + releaser.create_framework() + + if "win32" in args.actions: + if platform.system() != "Windows" and not args.dry: + parser.error("win32 artifact(s) can only be built on Windows") + with section_printer.group("Find Visual Studio"): + vs = VisualStudio(executer=executer) + x86 = releaser.build_vs(arch="x86", platform="Win32", vs=vs) + x64 = releaser.build_vs(arch="x64", platform="x64", vs=vs) + with section_printer.group("Create SDL VC development zip"): + arch_vc = { + "x86": x86, + "x64": x64, + } + releaser.build_vs_devel(arch_vc) + + if "mingw" in args.actions: + releaser.create_mingw_archives() + + if "android" in args.actions: + if args.android_home is None or not Path(args.android_home).is_dir(): + parser.error("Invalid $ANDROID_HOME or --android-home: must be a directory containing the Android SDK") + if args.android_ndk_home is None or not Path(args.android_ndk_home).is_dir(): + parser.error("Invalid $ANDROID_NDK_HOME or --android_ndk_home: must be a directory containing the Android NDK") + if args.android_api is None: + with section_printer.group("Detect Android APIS"): + args.android_api = releaser.detect_android_api(android_home=args.android_home) + if args.android_api is None or not (Path(args.android_home) / f"platforms/android-{args.android_api}").is_dir(): + parser.error("Invalid --android-api, and/or could not be detected") + if not args.android_abis: + parser.error("Need at least one Android ABI") + with section_printer.group("Android arguments"): + print(f"android_home = {args.android_home}") + print(f"android_ndk_home = {args.android_ndk_home}") + print(f"android_api = {args.android_api}") + print(f"android_abis = {args.android_abis}") + releaser.create_android_archives( + android_api=args.android_api, + android_home=args.android_home, + android_ndk_home=args.android_ndk_home, + android_abis=args.android_abis, + ) + + + with section_printer.group("Summary"): + print(f"artifacts = {releaser.artifacts}") + + if args.github: + if args.dry: + os.environ["GITHUB_OUTPUT"] = "/tmp/github_output.txt" + with open(os.environ["GITHUB_OUTPUT"], "a") as f: + f.write(f"project={releaser.project}\n") + f.write(f"version={releaser.version}\n") + for k, v in releaser.artifacts.items(): + f.write(f"{k}={v.name}\n") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/build-scripts/cmake-toolchain-mingw64-i686.cmake b/build-scripts/cmake-toolchain-mingw64-i686.cmake new file mode 100644 index 0000000000000..8be7b3a80fe07 --- /dev/null +++ b/build-scripts/cmake-toolchain-mingw64-i686.cmake @@ -0,0 +1,18 @@ +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_SYSTEM_PROCESSOR x86) + +find_program(CMAKE_C_COMPILER NAMES i686-w64-mingw32-gcc) +find_program(CMAKE_CXX_COMPILER NAMES i686-w64-mingw32-g++) +find_program(CMAKE_RC_COMPILER NAMES i686-w64-mingw32-windres windres) + +if(NOT CMAKE_C_COMPILER) + message(FATAL_ERROR "Failed to find CMAKE_C_COMPILER.") +endif() + +if(NOT CMAKE_CXX_COMPILER) + message(FATAL_ERROR "Failed to find CMAKE_CXX_COMPILER.") +endif() + +if(NOT CMAKE_RC_COMPILER) + message(FATAL_ERROR "Failed to find CMAKE_RC_COMPILER.") +endif() diff --git a/build-scripts/cmake-toolchain-mingw64-x86_64.cmake b/build-scripts/cmake-toolchain-mingw64-x86_64.cmake new file mode 100644 index 0000000000000..8bf436695e1fd --- /dev/null +++ b/build-scripts/cmake-toolchain-mingw64-x86_64.cmake @@ -0,0 +1,18 @@ +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_SYSTEM_PROCESSOR x86_64) + +find_program(CMAKE_C_COMPILER NAMES x86_64-w64-mingw32-gcc) +find_program(CMAKE_CXX_COMPILER NAMES x86_64-w64-mingw32-g++) +find_program(CMAKE_RC_COMPILER NAMES x86_64-w64-mingw32-windres windres) + +if(NOT CMAKE_C_COMPILER) + message(FATAL_ERROR "Failed to find CMAKE_C_COMPILER.") +endif() + +if(NOT CMAKE_CXX_COMPILER) + message(FATAL_ERROR "Failed to find CMAKE_CXX_COMPILER.") +endif() + +if(NOT CMAKE_RC_COMPILER) + message(FATAL_ERROR "Failed to find CMAKE_RC_COMPILER.") +endif() diff --git a/build-scripts/create-release.py b/build-scripts/create-release.py new file mode 100755 index 0000000000000..b919c1050f762 --- /dev/null +++ b/build-scripts/create-release.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +import argparse +from pathlib import Path +import logging +import re +import subprocess + +ROOT = Path(__file__).resolve().parents[1] + + +def determine_project() -> str: + text = (ROOT / "CMakeLists.txt").read_text() + match = next(re.finditer(r"project\((?P[a-zA-Z0-9_]+)\s+", text, flags=re.M)) + project_with_version = match["project"] + project, _ = re.subn("([^a-zA-Z_])", "", project_with_version) + return project + + +def main(): + project = determine_project() + default_remote = f"libsdl-org/{project}" + + current_commit = subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=ROOT, text=True).strip() + + parser = argparse.ArgumentParser(allow_abbrev=False) + parser.add_argument("--ref", required=True, help=f"Name of branch or tag containing release.yml") + parser.add_argument("--remote", "-R", default=default_remote, help=f"Remote repo (default={default_remote})") + parser.add_argument("--commit", default=current_commit, help=f"Commit (default={current_commit})") + args = parser.parse_args() + + + print(f"Running release.yml workflow:") + print(f" commit = {args.commit}") + print(f" remote = {args.remote}") + + subprocess.check_call(["gh", "-R", args.remote, "workflow", "run", "release.yml", "--ref", args.ref, "-f", f"commit={args.commit}"], cwd=ROOT) + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/cmake/test/CMakeLists.txt b/cmake/test/CMakeLists.txt index 388e86c54ce42..a9c0c498a9716 100644 --- a/cmake/test/CMakeLists.txt +++ b/cmake/test/CMakeLists.txt @@ -27,6 +27,12 @@ add_feature_info("TEST_SHARED" TEST_SHARED "Test linking with shared library") option(TEST_STATIC "Test linking to static SDL2 library" ON) add_feature_info("TEST_STATIC" TEST_STATIC "Test linking with static library") +option(TEST_TEST "Test linking to SDL3_test library" ON) +add_feature_info("TEST_TEST" TEST_STATIC "Test linking to SDL test library") + +option(TEST_FULL "Run complete SDL test suite" OFF) +add_feature_info("TEST_FULL" TEST_FULL "Build full SDL testsuite") + if(TEST_SHARED) find_package(SDL2 REQUIRED CONFIG COMPONENTS SDL2) if(EMSCRIPTEN OR (WIN32 AND NOT WINDOWS_STORE)) @@ -75,6 +81,11 @@ if(TEST_SHARED) generate_export_header(sharedlib-shared-vars EXPORT_MACRO_NAME MYLIBRARY_EXPORT) target_compile_definitions(sharedlib-shared-vars PRIVATE "EXPORT_HEADER=\"${CMAKE_CURRENT_BINARY_DIR}/sharedlib-shared-vars_export.h\"") set_target_properties(sharedlib-shared-vars PROPERTIES C_VISIBILITY_PRESET "hidden") + + if(TEST_TEST) + add_executable(sdltest-shared sdltest.c) + target_link_libraries(sdltest-shared PRIVATE SDL2::SDL2main SDL2::SDL2test SDL2::SDL2) + endif() endif() if(TEST_STATIC) @@ -111,6 +122,21 @@ if(TEST_STATIC) target_link_libraries(cli-static-vars PRIVATE ${SDL2_STATIC_LIBRARIES}) target_include_directories(cli-static-vars PRIVATE ${SDL2_INCLUDE_DIRS}) endif() + + if(CMAKE_Swift_COMPILER) + add_executable(swift-static main.swift) + target_include_directories(swift-static PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/swift") + target_link_libraries(swift-static PRIVATE SDL2::SDL2-static) + endif() +endif() + +if(TEST_FULL) + enable_testing() + set(SDL_TESTS_TIMEOUT_MULTIPLIER "1" CACHE STRING "Test timeout multiplier") + set(SDL_TESTS_LINK_SHARED ${TEST_SHARED}) + + add_definitions(-DNO_BUILD_CONFIG) + add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/../../test" SDL_test) endif() message(STATUS "SDL2_PREFIX: ${SDL2_PREFIX}") diff --git a/cmake/test/sdltest.c b/cmake/test/sdltest.c new file mode 100644 index 0000000000000..5c6d6972f0093 --- /dev/null +++ b/cmake/test/sdltest.c @@ -0,0 +1,9 @@ +#include "SDL.h" +#include "SDL_test.h" + + +int main(int argc, char *argv[]) { + SDLTest_CommonState state; + SDLTest_CommonDefaultArgs(&state, argc, argv); + return 0; +} diff --git a/mingw/pkg-support/INSTALL.txt b/mingw/pkg-support/INSTALL.txt new file mode 100644 index 0000000000000..607dafd0ee0a7 --- /dev/null +++ b/mingw/pkg-support/INSTALL.txt @@ -0,0 +1,18 @@ + +The 32-bit files are in i686-w64-mingw32 +The 64-bit files are in x86_64-w64-mingw32 + +To install SDL for native development: + make native + +To install SDL for cross-compiling development: + make cross + +Look at the example programs in ./test, and check out online documentation: + http://wiki.libsdl.org/ + +Join the SDL developer mailing list if you want to join the community: + http://www.libsdl.org/mailing-list.php + +That's it! +Sam Lantinga diff --git a/mingw/pkg-support/Makefile b/mingw/pkg-support/Makefile new file mode 100644 index 0000000000000..9edfd003e83e0 --- /dev/null +++ b/mingw/pkg-support/Makefile @@ -0,0 +1,30 @@ +# +# Makefile for installing the mingw32 version of the SDL library + +CROSS_PATH := /usr/local +ARCHITECTURES := i686-w64-mingw32 x86_64-w64-mingw32 + +all install: + @echo "Type \"make native\" to install 32-bit to /usr" + @echo "Type \"make cross\" to install 32-bit and 64-bit to $(CROSS_PATH)" + +native: + make install-package arch=i686-w64-mingw32 prefix=/usr + +cross: + for arch in $(ARCHITECTURES); do \ + make install-package arch=$$arch prefix=$(CROSS_PATH)/$$arch; \ + done + +install-package: + @if test -d $(arch) && test -d $(prefix); then \ + (cd $(arch) && cp -rv bin include lib share $(prefix)/); \ + sed "s|^prefix=.*|prefix=$(prefix)|" <$(arch)/bin/sdl2-config >$(prefix)/bin/sdl2-config; \ + chmod 755 $(prefix)/bin/sdl2-config; \ + sed "s|^libdir=.*|libdir=\'$(prefix)/lib\'|" <$(arch)/lib/libSDL2.la >$(prefix)/lib/libSDL2.la; \ + sed "s|^libdir=.*|libdir=\'$(prefix)/lib\'|" <$(arch)/lib/libSDL2main.la >$(prefix)/lib/libSDL2main.la; \ + sed "s|^prefix=.*|prefix=$(prefix)|" <$(arch)/lib/pkgconfig/sdl2.pc >$(prefix)/lib/pkgconfig/sdl2.pc; \ + else \ + echo "*** ERROR: $(arch) or $(prefix) does not exist!"; \ + exit 1; \ + fi diff --git a/mingw/pkg-support/cmake/sdl2-config-version.cmake b/mingw/pkg-support/cmake/sdl2-config-version.cmake index 9f7a8b34dc724..307063048f993 100644 --- a/mingw/pkg-support/cmake/sdl2-config-version.cmake +++ b/mingw/pkg-support/cmake/sdl2-config-version.cmake @@ -2,9 +2,9 @@ # This file is meant to be placed in a cmake subfolder of SDL2-devel-2.x.y-mingw if(CMAKE_SIZEOF_VOID_P EQUAL 4) - set(sdl2_config_path "${CMAKE_CURRENT_LIST_DIR}/../i686-w64-mingw32/lib/cmake/SDL2/sdl2-config-version.cmake") + set(sdl2_config_path "${CMAKE_CURRENT_LIST_DIR}/../i686-w64-mingw32/lib/cmake/SDL2/SDL2ConfigVersion.cmake") elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(sdl2_config_path "${CMAKE_CURRENT_LIST_DIR}/../x86_64-w64-mingw32/lib/cmake/SDL2/sdl2-config-version.cmake") + set(sdl2_config_path "${CMAKE_CURRENT_LIST_DIR}/../x86_64-w64-mingw32/lib/cmake/SDL2/SDL2ConfigVersion.cmake") else() set(PACKAGE_VERSION_UNSUITABLE TRUE) return() diff --git a/mingw/pkg-support/cmake/sdl2-config.cmake b/mingw/pkg-support/cmake/sdl2-config.cmake index 3c0799fbcaf30..f512814d78200 100644 --- a/mingw/pkg-support/cmake/sdl2-config.cmake +++ b/mingw/pkg-support/cmake/sdl2-config.cmake @@ -2,9 +2,9 @@ # This file is meant to be placed in a cmake subfolder of SDL2-devel-2.x.y-mingw if(CMAKE_SIZEOF_VOID_P EQUAL 4) - set(sdl2_config_path "${CMAKE_CURRENT_LIST_DIR}/../i686-w64-mingw32/lib/cmake/SDL2/sdl2-config.cmake") + set(sdl2_config_path "${CMAKE_CURRENT_LIST_DIR}/../i686-w64-mingw32/lib/cmake/SDL2/SDL2Config.cmake") elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(sdl2_config_path "${CMAKE_CURRENT_LIST_DIR}/../x86_64-w64-mingw32/lib/cmake/SDL2/sdl2-config.cmake") + set(sdl2_config_path "${CMAKE_CURRENT_LIST_DIR}/../x86_64-w64-mingw32/lib/cmake/SDL2/SDL2Config.cmake") else() set(SDL2_FOUND FALSE) return() From 40a3a80d45a494d56286c5bd5708caa65bf23dcf Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Tue, 1 Oct 2024 21:37:42 +0200 Subject: [PATCH 19/20] release.yml needs setup-ninja --- .github/actions/setup-ninja/action.yml | 62 ++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 .github/actions/setup-ninja/action.yml diff --git a/.github/actions/setup-ninja/action.yml b/.github/actions/setup-ninja/action.yml new file mode 100644 index 0000000000000..b9283598d773d --- /dev/null +++ b/.github/actions/setup-ninja/action.yml @@ -0,0 +1,62 @@ +name: 'Setup ninja' +description: 'Download ninja and add it to the PATH environment variable' +inputs: + version: + description: 'Ninja version' + default: '1.12.1' +runs: + using: 'composite' + steps: + - name: 'Calculate variables' + id: calc + shell: sh + run: | + case "${{ runner.os }}-${{ runner.arch }}" in + "Linux-X86" | "Linux-X64") + archive="ninja-linux.zip" + ;; + "Linux-ARM64") + archive="ninja-linux-aarch64.zip" + ;; + "macOS-X86" | "macOS-X64" | "macOS-ARM64") + archive="ninja-mac.zip" + ;; + "Windows-X86" | "Windows-X64") + archive="ninja-win.zip" + ;; + "Windows-ARM64") + archive="ninja-winarm64.zip" + ;; + *) + echo "Unsupported ${{ runner.os }}-${{ runner.arch }}" + exit 1; + ;; + esac + echo "archive=${archive}" >> ${GITHUB_OUTPUT} + echo "cache-key=${archive}-${{ inputs.version }}-${{ runner.os }}-${{ runner.arch }}" >> ${GITHUB_OUTPUT} + - name: 'Restore cached ${{ steps.calc.outputs.archive }}' + id: cache-restore + uses: actions/cache/restore@v4 + with: + path: '${{ runner.temp }}/${{ steps.calc.outputs.archive }}' + key: ${{ steps.calc.outputs.cache-key }} + - name: 'Download ninja ${{ inputs.version }} for ${{ runner.os }} (${{ runner.arch }})' + if: ${{ !steps.cache-restore.outputs.cache-hit }} + shell: pwsh + run: | + Invoke-WebRequest "https://github.com/ninja-build/ninja/releases/download/v${{ inputs.version }}/${{ steps.calc.outputs.archive }}" -OutFile "${{ runner.temp }}/${{ steps.calc.outputs.archive }}" + - name: 'Cache ${{ steps.calc.outputs.archive }}' + if: ${{ !steps.cache-restore.outputs.cache-hit }} + uses: actions/cache/save@v4 + with: + path: '${{ runner.temp }}/${{ steps.calc.outputs.archive }}' + key: ${{ steps.calc.outputs.cache-key }} + - name: 'Extract libusb' + shell: pwsh + run: | + 7z "-o${{ runner.temp }}/ninja-${{ inputs.version }}-${{ runner.arch }}" x "${{ runner.temp }}/${{ steps.calc.outputs.archive }}" + - name: 'Set output variables' + id: final + shell: pwsh + run: | + echo "${{ runner.temp }}/ninja-${{ inputs.version }}-${{ runner.arch }}" >> $env:GITHUB_PATH From 79ec168f3c1e2fe27335cb8886439f7ef676fb49 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Tue, 1 Oct 2024 23:04:32 +0200 Subject: [PATCH 20/20] Add docs to mingw release and don't modify libtool files in mingw's Makefile (cherry picked from commit 2b2907db18484c4c41a6afa0972accd1c0e84237) --- build-scripts/build-release.py | 8 +++++--- mingw/pkg-support/Makefile | 2 -- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build-scripts/build-release.py b/build-scripts/build-release.py index 3e94b66fc549a..0da88a075bcb8 100755 --- a/build-scripts/build-release.py +++ b/build-scripts/build-release.py @@ -362,6 +362,7 @@ def create_mingw_archives(self) -> None: ("WhatsNew.txt", ""), ("LICENSE.txt", ""), ("README.md", ""), + ("docs/*.md", "docs/"), ) test_files = list(Path(r) / f for r, _, files in os.walk(self.root / "test") for f in files) @@ -374,10 +375,11 @@ def create_mingw_archives(self) -> None: logger.info("Creating %s...", tar_paths[comp]) with tarfile.open(tar_paths[comp], f"w:{comp}") as tar_object: arc_root = f"{self.project}-{self.version}" - for file_path, arcdirname in extra_files: + for file_path_glob, arcdirname in extra_files: assert not arcdirname or arcdirname[-1] == "/" - arcname = f"{arc_root}/{arcdirname}{Path(file_path).name}" - tar_object.add(self.root / file_path, arcname=arcname) + for file_path in glob.glob(file_path_glob, root_dir=self.root): + arcname = f"{arc_root}/{arcdirname}{Path(file_path).name}" + tar_object.add(self.root / file_path, arcname=arcname) for arch in mingw_archs: install_path = arch_install_paths[arch] arcname_parent = f"{arc_root}/{arch}-w64-mingw32" diff --git a/mingw/pkg-support/Makefile b/mingw/pkg-support/Makefile index 9edfd003e83e0..3d9bc47889a4c 100644 --- a/mingw/pkg-support/Makefile +++ b/mingw/pkg-support/Makefile @@ -21,8 +21,6 @@ install-package: (cd $(arch) && cp -rv bin include lib share $(prefix)/); \ sed "s|^prefix=.*|prefix=$(prefix)|" <$(arch)/bin/sdl2-config >$(prefix)/bin/sdl2-config; \ chmod 755 $(prefix)/bin/sdl2-config; \ - sed "s|^libdir=.*|libdir=\'$(prefix)/lib\'|" <$(arch)/lib/libSDL2.la >$(prefix)/lib/libSDL2.la; \ - sed "s|^libdir=.*|libdir=\'$(prefix)/lib\'|" <$(arch)/lib/libSDL2main.la >$(prefix)/lib/libSDL2main.la; \ sed "s|^prefix=.*|prefix=$(prefix)|" <$(arch)/lib/pkgconfig/sdl2.pc >$(prefix)/lib/pkgconfig/sdl2.pc; \ else \ echo "*** ERROR: $(arch) or $(prefix) does not exist!"; \