Add SDL3 support

This commit is contained in:
Andy Vandijck
2026-08-02 14:45:12 +02:00
committed by Maarten Bent
parent adde4275d5
commit 100eb6efc5
8 changed files with 872 additions and 31 deletions
+12 -7
View File
@@ -436,9 +436,9 @@ if(wxUSE_GUI)
wx_option_force_value(wxUSE_GRAPHICS_DIRECT2D OFF) wx_option_force_value(wxUSE_GRAPHICS_DIRECT2D OFF)
endif() endif()
endif() endif()
if(MSVC) # match setup.h if(MSVC) # match setup.h
wx_option_force_value(wxUSE_GRAPHICS_DIRECT2D ${wxUSE_GRAPHICS_CONTEXT}) wx_option_force_value(wxUSE_GRAPHICS_DIRECT2D ${wxUSE_GRAPHICS_CONTEXT})
endif() endif()
# WXQT checks # WXQT checks
if(WXQT) if(WXQT)
@@ -691,12 +691,17 @@ if(wxUSE_GUI)
endif() endif()
if(wxUSE_SOUND AND wxUSE_LIBSDL AND UNIX AND NOT APPLE) if(wxUSE_SOUND AND wxUSE_LIBSDL AND UNIX AND NOT APPLE)
find_package(SDL2) find_package(SDL3)
if(NOT SDL2_FOUND) if(SDL3_FOUND)
find_package(SDL) set(wxUSE_LIBSDL3 ON)
mark_as_advanced(SDL_INCLUDE_DIR SDLMAIN_LIBRARY) else()
find_package(SDL2)
if(NOT SDL2_FOUND)
find_package(SDL)
mark_as_advanced(SDL_INCLUDE_DIR SDLMAIN_LIBRARY)
endif()
endif() endif()
if(NOT SDL2_FOUND AND NOT SDL_FOUND) if(NOT SDL3_FOUND AND NOT SDL2_FOUND AND NOT SDL_FOUND)
message(WARNING "SDL not found, SDL Audio back-end won't be available") message(WARNING "SDL not found, SDL Audio back-end won't be available")
wx_option_force_value(wxUSE_LIBSDL OFF) wx_option_force_value(wxUSE_LIBSDL OFF)
endif() endif()
+11 -1
View File
@@ -99,7 +99,17 @@ if(WXGTK AND wxUSE_PRIVATE_FONTS)
wx_lib_link_libraries(wxcore PUBLIC ${FONTCONFIG_LIBRARIES} ${PANGOFT2_LIBRARIES}) wx_lib_link_libraries(wxcore PUBLIC ${FONTCONFIG_LIBRARIES} ${PANGOFT2_LIBRARIES})
endif() endif()
if(wxUSE_LIBSDL) if(wxUSE_LIBSDL)
if(SDL2_FOUND) if(SDL3_FOUND)
# Upstream SDL3 ships an imported target; prefer it over raw vars.
if(TARGET SDL3::SDL3)
wx_lib_link_libraries(wxcore PUBLIC SDL3::SDL3)
elseif(TARGET SDL3::SDL3-shared)
wx_lib_link_libraries(wxcore PUBLIC SDL3::SDL3-shared)
else()
wx_lib_include_directories(wxcore ${SDL3_INCLUDE_DIRS})
wx_lib_link_libraries(wxcore PUBLIC ${SDL3_LIBRARIES})
endif()
elseif(SDL2_FOUND)
wx_lib_include_directories(wxcore ${SDL2_INCLUDE_DIR}) wx_lib_include_directories(wxcore ${SDL2_INCLUDE_DIR})
wx_lib_link_libraries(wxcore PUBLIC ${SDL2_LIBRARY}) wx_lib_link_libraries(wxcore PUBLIC ${SDL2_LIBRARY})
elseif(SDL_FOUND) elseif(SDL_FOUND)
+5
View File
@@ -735,6 +735,11 @@
*/ */
#cmakedefine01 wxUSE_LIBSDL #cmakedefine01 wxUSE_LIBSDL
/*
* Use SDL 3.x (rather than SDL 2.x or 1.x) for the SDL audio backend
*/
#cmakedefine01 wxUSE_LIBSDL3
/* /*
* Compile sound backends as plugins * Compile sound backends as plugins
*/ */
Vendored
+697 -10
View File
File diff suppressed because it is too large Load Diff
+15 -4
View File
@@ -5320,23 +5320,34 @@ WITH_PLUGIN_SDL=0
if test "$wxUSE_SOUND" = "yes"; then if test "$wxUSE_SOUND" = "yes"; then
if test "$USE_UNIX" = 1 -a "$USE_MAC" != 1 ; then if test "$USE_UNIX" = 1 -a "$USE_MAC" != 1 ; then
if test "$wxUSE_LIBSDL" != "no"; then if test "$wxUSE_LIBSDL" != "no"; then
PKG_CHECK_MODULES([SDL], [sdl2 >= 2.0.0], PKG_CHECK_MODULES([SDL], [sdl3 >= 3.0.0],
[ [
EXTRALIBS_SDL="$SDL_LIBS" EXTRALIBS_SDL="$SDL_LIBS"
CFLAGS="$SDL_CFLAGS $CFLAGS" CFLAGS="$SDL_CFLAGS $CFLAGS"
CXXFLAGS="$SDL_CFLAGS $CXXFLAGS" CXXFLAGS="$SDL_CFLAGS $CXXFLAGS"
AC_DEFINE(wxUSE_LIBSDL) AC_DEFINE(wxUSE_LIBSDL)
AC_DEFINE(wxUSE_LIBSDL3)
], ],
[ [
AC_MSG_NOTICE([SDL 2.0 not available. Falling back to 1.2.]) AC_MSG_NOTICE([SDL 3.0 not available. Falling back to SDL 2.0.])
AM_PATH_SDL([1.2.0], PKG_CHECK_MODULES([SDL], [sdl2 >= 2.0.0],
[ [
EXTRALIBS_SDL="$SDL_LIBS" EXTRALIBS_SDL="$SDL_LIBS"
CFLAGS="$SDL_CFLAGS $CFLAGS" CFLAGS="$SDL_CFLAGS $CFLAGS"
CXXFLAGS="$SDL_CFLAGS $CXXFLAGS" CXXFLAGS="$SDL_CFLAGS $CXXFLAGS"
AC_DEFINE(wxUSE_LIBSDL) AC_DEFINE(wxUSE_LIBSDL)
], ],
[wxUSE_LIBSDL="no"]) [
AC_MSG_NOTICE([SDL 2.0 not available. Falling back to 1.2.])
AM_PATH_SDL([1.2.0],
[
EXTRALIBS_SDL="$SDL_LIBS"
CFLAGS="$SDL_CFLAGS $CFLAGS"
CXXFLAGS="$SDL_CFLAGS $CXXFLAGS"
AC_DEFINE(wxUSE_LIBSDL)
],
[wxUSE_LIBSDL="no"])
])
]) ])
if test "$wxUSE_LIBSDL" = "yes" -a "$wxUSE_PLUGINS" = "yes" ; then if test "$wxUSE_LIBSDL" = "yes" -a "$wxUSE_PLUGINS" = "yes" ; then
WITH_PLUGIN_SDL=1 WITH_PLUGIN_SDL=1
+5
View File
@@ -734,6 +734,11 @@
*/ */
#define wxUSE_LIBSDL 0 #define wxUSE_LIBSDL 0
/*
* Use SDL 3.x (rather than SDL 2.x or 1.x) for the SDL audio backend
*/
#define wxUSE_LIBSDL3 0
/* /*
* Compile sound backends as plugins * Compile sound backends as plugins
*/ */
+7 -1
View File
@@ -88,7 +88,7 @@ typedef pid_t GPid;
#endif #endif
#endif #endif
#if defined( VMS_GTK2 ) || defined( __WXX11__ ) #if defined( VMS_GTK2 ) || defined( __WXX11__ )
#define wxUSE_CAIRO 1 #define wxUSE_CAIRO 1
#else #else
#define wxUSE_CAIRO 0 #define wxUSE_CAIRO 0
@@ -764,6 +764,12 @@ typedef pid_t GPid;
* Use SDL for audio (Unix) * Use SDL for audio (Unix)
*/ */
#define wxUSE_LIBSDL 0 #define wxUSE_LIBSDL 0
/*
* Use SDL 3.x (rather than SDL 2.x or 1.x) for the SDL audio backend
*/
#define wxUSE_LIBSDL3 0
/* /*
* Use GTK print for printing under GTK+ 2.10+ * Use GTK print for printing under GTK+ 2.10+
*/ */
+120 -8
View File
@@ -13,7 +13,24 @@
#if wxUSE_SOUND && wxUSE_LIBSDL #if wxUSE_SOUND && wxUSE_LIBSDL
#include <SDL.h> #if wxUSE_LIBSDL3
#include <SDL3/SDL.h>
#else
#include <SDL.h>
#endif
// Compatibility helpers so the rest of this file can be written once.
#if SDL_MAJOR_VERSION >= 3
typedef SDL_AudioFormat wxSDL_AudioFormat;
#define wxSDL_AUDIO_U8 SDL_AUDIO_U8
#define wxSDL_AUDIO_S16LSB SDL_AUDIO_S16LE
#define WX_SDL_USE_STREAM_API 1
#else
typedef int wxSDL_AudioFormat;
#define wxSDL_AUDIO_U8 AUDIO_U8
#define wxSDL_AUDIO_S16LSB AUDIO_S16LSB
#define WX_SDL_USE_STREAM_API 0
#endif
#ifndef WX_PRECOMP #ifndef WX_PRECOMP
#include "wx/event.h" #include "wx/event.h"
@@ -65,7 +82,11 @@ class wxSoundBackendSDL : public wxSoundBackend
public: public:
wxSoundBackendSDL() wxSoundBackendSDL()
: m_initialized(false), m_playing(false), m_audioOpen(false), : m_initialized(false), m_playing(false), m_audioOpen(false),
m_data(nullptr), m_evtHandler(nullptr) {} m_data(nullptr),
#if WX_SDL_USE_STREAM_API
m_stream(nullptr), m_silence(0),
#endif
m_evtHandler(nullptr) {}
virtual ~wxSoundBackendSDL(); virtual ~wxSoundBackendSDL();
wxString GetName() const override { return wxT("Simple DirectMedia Layer"); } wxString GetName() const override { return wxT("Simple DirectMedia Layer"); }
@@ -93,6 +114,13 @@ private:
SDL_AudioSpec m_spec; SDL_AudioSpec m_spec;
bool m_loop; bool m_loop;
#if WX_SDL_USE_STREAM_API
// SDL3 owns the device through the audio stream; silence sample is no
// longer part of SDL_AudioSpec, so we keep our own copy.
SDL_AudioStream *m_stream;
Uint8 m_silence;
#endif
wxSoundBackendSDLEvtHandler *m_evtHandler; wxSoundBackendSDLEvtHandler *m_evtHandler;
}; };
@@ -128,22 +156,45 @@ bool wxSoundBackendSDL::IsAvailable() const
{ {
if (m_initialized) if (m_initialized)
return true; return true;
if (SDL_WasInit(SDL_INIT_AUDIO) != SDL_INIT_AUDIO) if ((SDL_WasInit(SDL_INIT_AUDIO) & SDL_INIT_AUDIO) != SDL_INIT_AUDIO)
{ {
SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "1"); SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "1");
#if SDL_MAJOR_VERSION >= 3
// SDL3: SDL_Init returns bool, and SDL_INIT_NOPARACHUTE is gone.
if (!SDL_Init(SDL_INIT_AUDIO))
return false;
#else
if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE) == -1) if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE) == -1)
return false; return false;
#endif
} }
wxConstCast(this, wxSoundBackendSDL)->m_initialized = true; wxConstCast(this, wxSoundBackendSDL)->m_initialized = true;
wxLogTrace(wxT("sound"), wxT("initialized SDL audio subsystem")); wxLogTrace(wxT("sound"), wxT("initialized SDL audio subsystem"));
return true; return true;
} }
#if WX_SDL_USE_STREAM_API
extern "C" void SDLCALL
wx_sdl_audio_callback(void *userdata, SDL_AudioStream *stream,
int additional_amount, int /*total_amount*/)
{
if (additional_amount <= 0)
return;
wxSoundBackendSDL *bk = static_cast<wxSoundBackendSDL*>(userdata);
Uint8 *buf = static_cast<Uint8*>(SDL_malloc(additional_amount));
if (!buf)
return;
bk->FillAudioBuffer(buf, additional_amount);
SDL_PutAudioStreamData(stream, buf, additional_amount);
SDL_free(buf);
}
#else
extern "C" void wx_sdl_audio_callback(void *userdata, Uint8 *stream, int len) extern "C" void wx_sdl_audio_callback(void *userdata, Uint8 *stream, int len)
{ {
wxSoundBackendSDL *bk = (wxSoundBackendSDL*)userdata; wxSoundBackendSDL *bk = (wxSoundBackendSDL*)userdata;
bk->FillAudioBuffer(stream, len); bk->FillAudioBuffer(stream, len);
} }
#endif
void wxSoundBackendSDL::FillAudioBuffer(Uint8 *stream, int len) void wxSoundBackendSDL::FillAudioBuffer(Uint8 *stream, int len)
{ {
@@ -180,7 +231,11 @@ void wxSoundBackendSDL::FillAudioBuffer(Uint8 *stream, int len)
} }
else else
{ {
#if WX_SDL_USE_STREAM_API
memset(stream, m_silence, len);
#else
memset(stream, m_spec.silence, len); memset(stream, m_spec.silence, len);
#endif
} }
} }
} }
@@ -198,6 +253,33 @@ bool wxSoundBackendSDL::OpenAudio()
if (!m_evtHandler) if (!m_evtHandler)
m_evtHandler = new wxSoundBackendSDLEvtHandler(this); m_evtHandler = new wxSoundBackendSDLEvtHandler(this);
#if WX_SDL_USE_STREAM_API
// SDL3: silence and buffering are handled by the stream itself, and
// SDL_AudioSpec only carries format/channels/freq.
m_silence = (m_spec.format == wxSDL_AUDIO_U8) ? 128 : 0;
wxLogTrace(wxT("sound"), wxT("opening SDL audio..."));
m_stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK,
&m_spec,
wx_sdl_audio_callback,
this);
if (m_stream)
{
#if wxUSE_LOG_DEBUG
const char *drv = SDL_GetCurrentAudioDriver();
wxLogTrace(wxT("sound"), wxT("opened audio, driver '%s'"),
wxString(drv ? drv : "", wxConvLocal));
#endif
m_audioOpen = true;
return true;
}
else
{
wxString err(SDL_GetError(), wxConvLocal);
wxLogError(_("Couldn't open audio: %s"), err);
return false;
}
#else
m_spec.silence = 0; m_spec.silence = 0;
m_spec.samples = 4096; m_spec.samples = 4096;
m_spec.size = 0; m_spec.size = 0;
@@ -226,6 +308,7 @@ bool wxSoundBackendSDL::OpenAudio()
wxLogError(_("Couldn't open audio: %s"), err); wxLogError(_("Couldn't open audio: %s"), err);
return false; return false;
} }
#endif
} }
return true; return true;
} }
@@ -234,7 +317,12 @@ void wxSoundBackendSDL::CloseAudio()
{ {
if (m_audioOpen) if (m_audioOpen)
{ {
#if WX_SDL_USE_STREAM_API
SDL_DestroyAudioStream(m_stream);
m_stream = nullptr;
#else
SDL_CloseAudio(); SDL_CloseAudio();
#endif
wxLogTrace(wxT("sound"), wxT("closed audio")); wxLogTrace(wxT("sound"), wxT("closed audio"));
m_audioOpen = false; m_audioOpen = false;
} }
@@ -245,11 +333,11 @@ bool wxSoundBackendSDL::Play(wxSoundData *data, unsigned flags,
{ {
Stop(); Stop();
int format; wxSDL_AudioFormat format;
if (data->m_bitsPerSample == 8) if (data->m_bitsPerSample == 8)
format = AUDIO_U8; format = wxSDL_AUDIO_U8;
else if (data->m_bitsPerSample == 16) else if (data->m_bitsPerSample == 16)
format = AUDIO_S16LSB; format = wxSDL_AUDIO_S16LSB;
else else
return false; return false;
@@ -258,7 +346,7 @@ bool wxSoundBackendSDL::Play(wxSoundData *data, unsigned flags,
{ {
if (format == m_spec.format && if (format == m_spec.format &&
m_spec.freq == (int)data->m_samplingRate && m_spec.freq == (int)data->m_samplingRate &&
m_spec.channels == data->m_channels) (unsigned)m_spec.channels == data->m_channels)
{ {
needsOpen = false; needsOpen = false;
} }
@@ -277,16 +365,24 @@ bool wxSoundBackendSDL::Play(wxSoundData *data, unsigned flags,
return false; return false;
} }
#if WX_SDL_USE_STREAM_API
SDL_LockAudioStream(m_stream);
#else
SDL_LockAudio(); SDL_LockAudio();
#endif
wxLogTrace(wxT("sound"), wxT("playing new sound")); wxLogTrace(wxT("sound"), wxT("playing new sound"));
m_playing = true; m_playing = true;
m_pos = 0; m_pos = 0;
m_loop = (flags & wxSOUND_LOOP); m_loop = (flags & wxSOUND_LOOP);
m_data = data; m_data = data;
data->IncRef(); data->IncRef();
#if WX_SDL_USE_STREAM_API
SDL_UnlockAudioStream(m_stream);
SDL_ResumeAudioStreamDevice(m_stream);
#else
SDL_UnlockAudio(); SDL_UnlockAudio();
SDL_PauseAudio(0); SDL_PauseAudio(0);
#endif
// wait until playback finishes if called in sync mode: // wait until playback finishes if called in sync mode:
if (!(flags & wxSOUND_ASYNC)) if (!(flags & wxSOUND_ASYNC))
@@ -314,6 +410,21 @@ bool wxSoundBackendSDL::Play(wxSoundData *data, unsigned flags,
void wxSoundBackendSDL::Stop() void wxSoundBackendSDL::Stop()
{ {
#if WX_SDL_USE_STREAM_API
if (m_stream)
{
SDL_LockAudioStream(m_stream);
SDL_PauseAudioStreamDevice(m_stream);
}
m_playing = false;
if (m_data)
{
m_data->DecRef();
m_data = nullptr;
}
if (m_stream)
SDL_UnlockAudioStream(m_stream);
#else
SDL_LockAudio(); SDL_LockAudio();
SDL_PauseAudio(1); SDL_PauseAudio(1);
m_playing = false; m_playing = false;
@@ -323,6 +434,7 @@ void wxSoundBackendSDL::Stop()
m_data = nullptr; m_data = nullptr;
} }
SDL_UnlockAudio(); SDL_UnlockAudio();
#endif
} }
extern "C" wxSoundBackend *wxCreateSoundBackendSDL() extern "C" wxSoundBackend *wxCreateSoundBackendSDL()