tomato-testing/docs/README-migration.md
Green Sky 644725478f Squashed 'external/sdl/SDL/' changes from ec0042081..399bc709b
399bc709b build-scripts.pl: Added add-source-to-projects.pl
ac6827187 Visual-WinRT: dos2unix the project files to match other Visual Studio targets.
34719cba9 Fixed crash in hid_init() if the HIDDeviceManager isn't available
2e92e94eb Make sure we update device->sample_frames in SDL_AudioDeviceFormatChangedAlreadyLocked()
9964e5c5b wayland: Don't retrieve the drag offer strings with every pointer motion event
bac7eeaaa Added missing include
a541e2ac1 audio: Change a few SDL_memcpy calls to SDL_copyp.
54125c140 audio: Only update bound audiostreams' formats when necessary.
e0b0f9a36 testaudio: Fix mouseover testing.
2f3deec24 wayland: Don't process drag & drop events from surfaces not owned by SDL
42bdced05 events: Log file drop position events and print the pointer coordinates
c10d93d3a wayland: Replace magic constant with define
500852153 emscripten: Restore compatibility with existing emsdk releases.
953b55dd6 Use EM_ASM_PTR when the return value is a pointer
a4541a255 audio: SDL_GetAudioStreamQueued now returns bytes, not frames.
703aefbce Sync SDL3 wiki -> header
99421b64d linux: Add portal drag and drop
952c5059b Remove stray Â
eebd5d18a linux: Handle upower's UP_DEVICE_STATE_PENDING_CHARGE, PENDING_DISCHARGE
f8fdb20d8 audio: Destroy all existing SDL_AudioStreams on shutdown.
62d445997 audio: Removed declarations of functions that don't exist anymore.
b656720bc loopwave: Use SDL_GetAudioStreamQueued() for more accurate results.
34b931f7e audio: Added SDL_GetAudioStreamQueued
23206b9e3 audio: Added SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED
c7e6d7a1f audio: Changed debug logging output.
87ec6acf2 audio: Added a FIXME
ac88ffb7e audio: don't allocate buffer in SDL_SetAudioPostmixCallback for NULL callback.
2a950f6ae audio: Replace some SDL_memcpy calls with SDL_copyp.
0dc0434a3 audio: Fixed race condition in subsystem shutdown.
23f60203a audio: precalculate if we can use simple copies instead of the full mixer.
36b0f1141 audio: Optimize setting device formats during audio thread iteration.
4c3e84897 testspriteminimal: make standalone by embedding icon.bmp
2a01f9dcb tests: plug leaks when running with --trackmem
f42bbeca2 SDL_test: track stack frames of allocations on Windows
12c0be028 SDL_test: clear text cache on exit event
b4bfb1831 SDL_test: free state before logging allocations
248b1edd3 SDL_test: destroy windows in SDL_CommonQuit
98da2dd30 SDL_test: don't warn about expected allocations when running with --trackmem
6a381567b Support audio rate conversion up to 384KHz
b2b548a1f Don't hang if IAudioRenderClient_GetBuffer() fails indefinitely
a3a5e1728 Fixed build warning '=': conversion from 'Uint32' to 'Uint16', possible loss of data
6d3e21c27 Fixed android build warnings
fca2f5318 Fixed warning: this function declaration is not a prototype
a72dfa6a5 Fixed sensor timestamp units for third-party PS5 controllers
f6756047a Fixed error: array subscript 2 is above array bounds of ‘const Uint8[2]’
7059a55cc Fixed sensor timestamp calculation for third-party PS5 controllers
c0443e5d1 Fixed crash in SDL_IMMDevice_FindByDevID()
fde8499f6 Use around 20ms for the audio buffer size
e5739d7d1 video: Remove SDL_GetFocusWindow()
39c2f9737 Fix NULL dereference in SDL_OpenAudio
9a23d0e3f Added new audio files to the Xcode project
a62e62f97 Refactored SDL_audiocvt.c
31229fd47 include: Added a note about SDL's iOS app delegate functions.
65aaf3a9a x11: Always update clipboard owner
f622f21e6 Fixed build
5774c9638 Prefer hidraw over libusb when libusb whitelisting is not enabled
9301f7ace hidapi/libusb: only enumerate each interface once
859dc14ad Replaced SDL_GetGamepadBindForAxis() and SDL_GetGamepadBindForButton() with SDL_GetGamepadBindings()
9e50048ab Revert "Removed SDL_GamepadBinding from the API"
9f17d1a9d Don't reference the same function in "see also"
86505ea63 fix SDL_AudioStreamCallback documentation
d885d5c31 Sync SDL3 wiki -> header
2f43f7bc5 audio: Allow querying of device buffer size.
cf9572113 audio: Added a hint to let apps force device buffer size.
47d8c77c6 audio: Choose better default sample frame counts.
8b26e95f9 audio: Change SDL_AudioStreamCallback
9da34e8fb docs: Updated README-emscripten.md.
fd1c54a00 detect fanatec steering wheels
cb4414608 docs: Whoops, this got added by the wiki bridge by accident!
cd633b9a8 Renamed SDL_IsAudioDevicePaused() to SDL_AudioDevicePaused()
c6cad07fa Sync SDL3 wiki -> header
a6e52f9e4 Sync SDL3 wiki -> header
2de2e9d03 Fix flickering of window when using desktop-fullscreen and borderless window on multiple monitors on Linux.  Closes #8186.
723835d16 Windows: fix for client rect resizing larger each time we came from exclusive fullscreen -> windowed on a monitor with HiDPI set.  The problem was we were using the monitor DPI rather than the window DPI so AdjustWindowRectExForDpi was giving us an incorrect size which would be too large for the client rect.  Closes #8237.
ce27363df wikiheaders: Sort undocumented functions.
e22282b09 Added README about transparent windows in Win32
1d1c6e630 Turn off COREAUDIO debug logging by default
52efefca0 wayland: Fix drag offer leak
3a992af44 audio: Added a postmix callback to logical devices.
7207bdce5 render: Enable clipping for zero-sized rectangles
22d81fb3e cmake: use MSVC_RUNTIME_LIBRARY to force MT
a2e17852d cmake: make sure SDL_GetPrefPath is run before testfilesystem
2fb266e0a ci: run tests in parallel
ad1313e75 testaudio: Patched to compile.
5747ddc01 testaudio: Clean up some messy memory management.
fafbea1ce audio: Move internal float32 mixing to a simplified function
116b0ec97 include: minor tweak to audio API documentation
fb1377035 include: Replaced old Bugzilla URL.
38c8fc05c audio: Remove ChooseMixStrategy.
b00cbd76a wikiheaders.pl: create Unsupported.md file with list of functions undocumented in either the headers or the wiki
37e1fc3b5 wayland: Ensure that the toplevel window is recreated when switching decoration modes
f2ca9a615 Added SDL_AUDIO_FRAMESIZE
53122593f Added SDL_AUDIO_BYTESIZE
544351c98 Sync SDL3 wiki -> header
2e7d2b94e Clarify that SDL_BlitSurface() ignores the width and height in dstrect
a2c1984d3 Detect Simagic wheel bases as wheels (#8198)
1d8dfbb22 avoid type redefinition errors after PR/8181
266b91d2f Detect Logitech G923 Playstation as wheel G923 have two different versions - Xbox version is already present in the wheel list, but not the PS version.
cde67ea49 Detect Logitech PRO Racing Wheel for Xbox (PC mode) as wheel Logitech PRO Racing Wheel have two different versions - for Playstation and Xbox. Vendor + Product ID for Playstation version already present in SDL sources, but not an Xbox version
3a932141e Restore audio format binary compatibility with SDL 2.0
e85206ffd wikiheaders.pl: add --rev= option to pass revision string
233789b0d Audio types have the same naming convention as other SDL endian types, e.g. [S|U][BITS][LE|BE]
36b5f3e35 Sync SDL3 wiki -> header
0e552761b Renamed AudioStreamSpeed to AudioStreamFrequencyRatio
47bcb078f Fixed some incorrect SDL_AUDIO_F32 uses
2833f2e7b Fixed OOB access in audio_convertAccuracy test
8387fae69 Sync SDL3 wiki -> header
832181345 docs: Add note about Wayland application icons
825d34475 Make sure that the same timestamp is used for all PS5 events from the same packet
9c1430324 Removed SDL_dataqueue
28b28bd8f Added audio_formatChange test
a59152688 Try and avoid overflow when handling very large audio streams
5394a805f Improved testaudiostreamdynamicresample
e55844274 Added SDL_(Get|Set)AudioStreamSpeed
43c3c5736 Track the formats of data in an SDL_AudioStream
337fed3df Tweaked ResampleFrame_SSE Use _mm_unpack(lo|hi)_ps instead of _mm_shuffle_ps
fd7cd91dc audio: Mix multiple streams in float32 to prevent clipping.
9097573e3 audio: Choose a mixing strategy on each iteration.
bbe2e012a Don't provide the SDL3 header path
c17a35f09 Fixed typo
4f72255eb Fixed README.md link
e0ab59754 Simplified SDL_main.h migration notes
d44bde61e Added SDL migration information to the top level README.md
6ff31e10c metal: Add hint to select low power device instead of the default one (#8182)
8a8aed477 Make sure that we process touch events that position the mouse
f84c87f20 Sync SDL3 wiki -> header
a7eea9997 macOS: Don't raise the parent top-level window when raising a child window, only raise the child window to the top of the parent
a5e721479 Add SDL_WINDOW_NOT_FOCUSABLE flag to set that the window should not be able to gain key focus
b385dc3b6 n3dsaudio: Patched to compile.
4e0c7c91f audio: PlayDevice() should return an error code.
a94d724f1 wayland: add SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL
da5d93d3d wayland: don't define SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_* macro's
f002f7d12 ci: build emscripten with Debug buid type
3699b12ed audio: Fixed some "is_*" variables to be cleaner and/or more specific.
2471d8cc2 audio: Fixed logic error in SDL_OpenAudioDeviceStream.
1b03a2430 testsurround: fix order of arguments of callback
82db2b58f Renamed audio stream callback and moved the userdata parameter first
5bdad5210 Sync SDL3 wiki -> header
58c859f64 audio: Rename SDL_GetAudioStreamBinding to SDL_GetAudioStreamDevice.
efd2023a7 audio: Fixed documentation.
1e775e0ee audio: Replace SDL_CreateAndBindAudioStream with SDL_OpenAudioDeviceStream.
bd088c2f9 Revert "Clarify whether an audio function expects a physical or logical device ID"
82e481b52 Added --randmem test parameter
ea68bb802 Add some additional checks to audio_convertAudio
f8286df16 Fixed ResampleFrame_SSE doing unnecessary work
b1d63be53 Fixed audio_resampleLoss test
c191d6c30 Better Win32 transparent window support
923d612ca hidapi: sync macOS code with mainstream.
363f4fa9c avoid type redefinition errors after commit ee806597b9.
615824a80 Updated documentation now that SDL_GetAudioDevices() has been split into separate functions for output and capture devices
506a133d8 Clarify whether an audio function expects a physical or logical device ID
3b1d1e4e3 hidapi: sync the hidraw changes with mainstream
f617918e0 cmake: check linkage to libusb too, instead of libusb.h presence only.
041dbd6b5 Fixed GetResamplerAvailableOutputFrames Non-euclidean division is a pain
b49d0a607 x11: Avoid including full Vulkan headers.
4d2f9f3a3 yuv_rgb: Comment out unused code.
3c3486e2a wayland: Don't include full Vulkan headers when not necessary.
f066bbe98 x11: Don't include system headers twice.
d86d02bbb updated dynapi after SDL_GDKGetDefaultUser addition
4355f9cec Fixed warning C4389: '!=': signed/unsigned mismatch
5755de07a Fixed build warnings
0f80d47bb Fixed thread-safety warning
ee806597b Removed SDL_vulkan_internal.h from SDL_sysvideo.h
34860b932 Fixed testautomation --filter pixels_allocFreeFormat
6f8a6a31c gdk: GetBasePath should be a UTF8 version of Win32 GetBasePath
e30e5c77e Sync SDL3 wiki -> header
c0cd8c814 gdk: Add SDL_GDKGetDefaultUser, SDL_GetPrefPath implementation
106abce69 Refactored GetAudioStreamDataInternal buffer handling The final conversion step should now always go straight into the output buffer.
e44f54ec5 Avoid using hex-floats
5b696996c Added ResampleFrame_SSE
958b3cfae Tweaked and enabled audio_convertAudio test
7dbb9b65b audio_convertAccuracy: Shuffle the data in case of a bad SIMD implementation
f6a4080ff audio_resampleLoss: Add support for multiple channels
4f894e748 audio_resampleLoss: SDL_GetAudioStreamData now returns the correct length
ab83f75bb Make sure GetAudioStreamDataInternal is called with a valid length
6a73f74b6 Rebuild full ResamplerFilter (left wing + right wing) at runtime
0c15ce006 Add a missing int cast
b74ee86b1 Optimized ResampleAudio, with special cases for 1 and 2 channels This would also benefit from some SIMD, since it's just a bunch of multiply-adds
fba6e1e3d Removed ResamplerFilterDifference It takes 1 extra multiply to calculate the correct interpolation, but I think the improvement in cache locality (and binary size) outweighs that.
9f7a22fa4 Removed 64-bit handling from AudioConvertByteswap
1f5327a9f Removed future_buffer, left_padding, and right_padding from SDL_AudioStream
71ad52d6d Lowered SDL_GetAudioStreamData to 32 KB No particular reason for this number, but 1 MB was a bit silly
69aec8c91 Fixed the report format for the Razer Wolverine V2 Pro
7c2669c9d Accept key events from any source
1e9d31448 Updated to Android minSdkVersion 19 and targetSdkVersion 34
8924d0d92 Added missing function prototype for SDL_WriteS64BE()
845f3c745 Fixed mismatch between stdlib calloc() and SDL free()
fb7921173 emscriptenaudio: Fire the capture silence_callback at an interval.
5191b2054 emscriptenaudio: Don't bother undefining things about to be unreachable.
fd75a4ca0 emscriptenaudio: Deal with blocked audio devices better.
981b8a337 emscriptenaudio: Remove unnecessary functions.
c7588e426 Transparent window for Win32 + OpenGL (#8143)
f9581178d cmake: fixed a typo.
e6c878824 Fixed ResampleAudio interpolation factor calculation
498363863 Misc audio tweaks/cleanup
72d9d53de Invert the inner ResampleAudio loops to avoid doing unnecessary work
88123a510 The history buffer should always have the maximum possible padding frames
96e47f165 Clamp results of GetResampler(AvailableOutput|NeededInput)Frames
d2b9c8b80 Fixed maths in testaudiostreamdynamicresample (and just show the actual scale)
14e38b17d Removed assertions from inner ResampleAudio loop
9d413dfdc The history buffer doesn't need to be so large
2788e848f Allow resampling less than 1 frame of input
383084e0a Pre-calculate resampling rate, and use it instead of .freq in most places
40a6a445c Update resample_offset inside ResampleAudio
47fea7f06 Used fixed-point arithmetic in ResampleAudio
7bb4e806e Clear resample_offset in SDL_ClearAudioStream, not SetAudioStreamFormat Not entirely sure if ClearAudioStream is the right place, but SetAudioStreamFormat was the wrong place
b9541b9ea Improved ResampleAudio * filterindex2 was off-by-one * Generate ResamplerFilter using doubles * Transpose ResamplerFilter to improve access patterns
cdaa19869 Track offset within the current sample when resampling
d60ebb06d mouse: Ensure that the dummy default cursor is removed from the cursor list
e58c2731f mouse: Free the default cursor when destroyed
789ce17e1 audio: Don't resample in chunks for now.
cbab33482 audio: Don't call SDL_AudioStream callbacks for empty data sets.
3e1ae0c86 Clearified the libusb whitelist default logic
f4520821e Removed some unnecessary integer casts
0989b7e86 Avoid using designated initializers
c6c1e673c Optimized SDL_Convert_*_to_*_Scalar
f97b920b3 Optimized SDL_Convert_*_to_*_SSE2 Some of the SDL_Convert_F32_to_*_SSE2 do not explicitly clamp the input, but instead rely on saturating casts. Inputs very far outside the valid [-1.0, 1.0] range may produce an incorrect result, but I believe that is an acceptable trade-off.
300d1ec3e Added audio_convertAccuracy test
32cecc2ea Fixed assertion in audio_convertAudio
33f11e21e Removed assertions in AudioConvert(To|From)Float
c2f388fd8 cmake: add SDL_HIDAPI_LIBUSB_SHARED option + test on ci
371cc2d17 wayland: Remove unnecessary flag and state settings
fe85e6e75 cocoa: Send a maximized event instead of restored if a deminiaturized window is zoomed
ddddcb78c cocoa: Use the close method to hide a miniaturized window
be8c42cfd Clarify that a window being 'hidden' means that it is unmapped/ordered out
a44338cbc Fix typo in SDL_audiocvt.c
f464eb2c5 SDL_hidapi.c: change 'use_libusb_whitelist_default' into a macro.
6607a3cfa Disable cache in python http server
181d5d285 hidapi: Enable libusb support by default.
f0f15e365 hidapi: Use a whitelist for libusb when other backends are available
c3f7a7dc4 Convert audio using SDL_AUDIO_F32SYS format instead of SDL_AUDIO_F32
796713b9d xxd.py: always write \n line endings
723bcd0a8 SDL_TriggerBreakppoint for riscv arch (both 32/64) version.

git-subtree-dir: external/sdl/SDL
git-subtree-split: 399bc709b7485bab57880f8261f826f29dc0d7b2
2023-09-23 18:45:49 +02:00

64 KiB

Migrating to SDL 3.0

This guide provides useful information for migrating applications from SDL 2.0 to SDL 3.0.

Details on API changes are organized by SDL 2.0 header below.

The file with your main() function should include <SDL3/SDL_main.h>, as that is no longer included in SDL.h.

Many functions and symbols have been renamed. We have provided a handy Python script rename_symbols.py to rename SDL2 functions to their SDL3 counterparts:

rename_symbols.py --all-symbols source_code_path

It's also possible to apply a semantic patch to migrate more easily to SDL3: SDL_migration.cocci

SDL headers should now be included as #include <SDL3/SDL.h>. Typically that's the only header you'll need in your application unless you are using OpenGL or Vulkan functionality. We have provided a handy Python script rename_headers.py to rename SDL2 headers to their SDL3 counterparts:

rename_headers.py source_code_path

CMake users should use this snippet to include SDL support in their project:

find_package(SDL3 REQUIRED CONFIG REQUIRED COMPONENTS SDL3)
target_link_libraries(mygame PRIVATE SDL3::SDL3)

Autotools users should use this snippet to include SDL support in their project:

PKG_CHECK_MODULES([SDL3], [sdl3])

and then add $SDL3_CFLAGS to their project CFLAGS and $SDL3_LIBS to their project LDFLAGS

Makefile users can use this snippet to include SDL support in their project:

CFLAGS += $(shell pkg-config sdl3 --cflags)
LDFLAGS += $(shell pkg-config sdl3 --libs)

The SDL3test library has been renamed SDL3_test.

The SDLmain library has been removed, it's been entirely replaced by SDL_main.h.

The vi format comments have been removed from source code. Vim users can use the editorconfig plugin to automatically set tab spacing for the SDL coding style.

SDL_atomic.h

The following structures have been renamed:

  • SDL_atomic_t => SDL_AtomicInt

SDL_audio.h

The audio subsystem in SDL3 is dramatically different than SDL2. The primary way to play audio is no longer an audio callback; instead you bind SDL_AudioStreams to devices; however, there is still a callback method available if needed.

The SDL 1.2 audio compatibility API has also been removed, as it was a simplified version of the audio callback interface.

SDL3 will not implicitly initialize the audio subsystem on your behalf if you open a device without doing so. Please explicitly call SDL_Init(SDL_INIT_AUDIO) at some point.

SDL3's audio subsystem offers an enormous amount of power over SDL2, but if you just want a simple migration of your existing code, you can ignore most of it. The simplest migration path from SDL2 looks something like this:

In SDL2, you might have done something like this to play audio...

    void SDLCALL MyAudioCallback(void *userdata, Uint8 * stream, int len)
    {
        /* calculate a little more audio here, maybe using `userdata`, write it to `stream` */
    }

    /* ...somewhere near startup... */
    SDL_AudioSpec my_desired_audio_format;
    SDL_zero(my_desired_audio_format);
    my_desired_audio_format.format = AUDIO_S16;
    my_desired_audio_format.channels = 2;
    my_desired_audio_format.freq = 44100;
    my_desired_audio_format.samples = 1024;
    my_desired_audio_format.callback = MyAudioCallback;
    my_desired_audio_format.userdata = &my_audio_callback_user_data;
    SDL_AudioDeviceID my_audio_device = SDL_OpenAudioDevice(NULL, 0, &my_desired_audio_format, NULL, 0);
    SDL_PauseAudioDevice(my_audio_device, 0);

...in SDL3, you can do this...

    void SDLCALL MyAudioCallback(SDL_AudioStream *stream, int len, void *userdata)
    {
        /* calculate a little more audio here, maybe using `userdata`, write it to `stream` */
        SDL_PutAudioStreamData(stream, newdata, len);
    }

    /* ...somewhere near startup... */
    const SDL_AudioSpec spec = { SDL_AUDIO_S16, 2, 44100 };
    SDL_AudioStream *stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_OUTPUT, &spec, MyAudioCallback, &my_audio_callback_user_data);
    SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(stream));

If you used SDL_QueueAudio instead of a callback in SDL2, this is also straightforward.

    /* ...somewhere near startup... */
    const SDL_AudioSpec spec = { SDL_AUDIO_S16, 2, 44100 };
    SDL_AudioStream *stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_OUTPUT, &spec, NULL, NULL);
    SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(stream));

    /* ...in your main loop... */
    /* calculate a little more audio into `buf`, add it to `stream` */
    SDL_PutAudioStreamData(stream, buf, buflen);

...these same migration examples apply to audio capture, just using SDL_GetAudioStreamData instead of SDL_PutAudioStreamData.

SDL_AudioInit() and SDL_AudioQuit() have been removed. Instead you can call SDL_InitSubSystem() and SDL_QuitSubSystem() with SDL_INIT_AUDIO, which will properly refcount the subsystems. You can choose a specific audio driver using SDL_AUDIO_DRIVER hint.

The SDL_AUDIO_ALLOW_* symbols have been removed; now one may request the format they desire from the audio device, but ultimately SDL_AudioStream will manage the difference. One can use SDL_GetAudioDeviceFormat() to see what the final format is, if any "allowed" changes should be accomodated by the app.

SDL_AudioDeviceID now represents both an open audio device's handle (a "logical" device) and the instance ID that the hardware owns as long as it exists on the system (a "physical" device). The separation between device instances and device indexes is gone, and logical and physical devices are almost entirely interchangeable at the API level.

Devices are opened by physical device instance ID, and a new logical instance ID is generated by the open operation; This allows any device to be opened multiple times, possibly by unrelated pieces of code. SDL will manage the logical devices to provide a single stream of audio to the physical device behind the scenes.

Devices are not opened by an arbitrary string name anymore, but by device instance ID (or magic numbers to request a reasonable default, like a NULL string in SDL2). In SDL2, the string was used to open both a standard list of system devices, but also allowed for arbitrary devices, such as hostnames of network sound servers. In SDL3, many of the backends that supported arbitrary device names are obsolete and have been removed; of those that remain, arbitrary devices will be opened with a default device ID and an SDL_hint, so specific end-users can set an environment variable to fit their needs and apps don't have to concern themselves with it.

Many functions that would accept a device index and an iscapture parameter now just take an SDL_AudioDeviceID, as they are unique across all devices, instead of separate indices into output and capture device lists.

Rather than iterating over audio devices using a device index, there are new functions, SDL_GetAudioOutputDevices() and SDL_GetAudioCaptureDevices(), to get the current list of devices, and new functions to get information about devices from their instance ID:

{
    if (SDL_InitSubSystem(SDL_INIT_AUDIO) == 0) {
        int i, num_devices;
        SDL_AudioDeviceID *devices = SDL_GetAudioOutputDevices(&num_devices);
        if (devices) {
            for (i = 0; i < num_devices; ++i) {
                SDL_AudioDeviceID instance_id = devices[i];
                char *name = SDL_GetAudioDeviceName(instance_id);
                SDL_Log("AudioDevice %" SDL_PRIu32 ": %s\n", instance_id, name);
                SDL_free(name);
            }
            SDL_free(devices);
        }
        SDL_QuitSubSystem(SDL_INIT_AUDIO);
    }
}

SDL_LockAudioDevice() and SDL_UnlockAudioDevice() have been removed, since there is no callback in another thread to protect. SDL's audio subsystem and SDL_AudioStream maintain their own locks internally, so audio streams are safe to use from any thread. If the app assigns a callback to a specific stream, it can use the stream's lock through SDL_LockAudioStream() if necessary.

SDL_PauseAudioDevice() no longer takes a second argument; it always pauses the device. To unpause, use SDL_ResumeAudioDevice().

Audio devices, opened by SDL_OpenAudioDevice(), no longer start in a paused state, as they don't begin processing audio until a stream is bound.

SDL_GetAudioDeviceStatus() has been removed; there is now SDL_AudioDevicePaused().

SDL_QueueAudio(), SDL_DequeueAudio, and SDL_ClearQueuedAudio and SDL_GetQueuedAudioSize() have been removed; an SDL_AudioStream bound to a device provides the exact same functionality.

APIs that use channel counts used to use a Uint8 for the channel; now they use int.

SDL_AudioSpec has been reduced; now it only holds format, channel, and sample rate. SDL_GetSilenceValueForFormat() can provide the information from the SDL_AudioSpec's silence field. The other SDL2 SDL_AudioSpec fields aren't relevant anymore.

SDL_GetAudioDeviceSpec() is removed; use SDL_GetAudioDeviceFormat() instead.

SDL_GetDefaultAudioInfo() is removed; SDL_GetAudioDeviceFormat() with SDL_AUDIO_DEVICE_DEFAULT_OUTPUT or SDL_AUDIO_DEVICE_DEFAULT_CAPTURE. There is no replacement for querying the default device name; the string is no longer used to open devices, and SDL3 will migrate between physical devices on the fly if the system default changes, so if you must show this to the user, a generic name like "System default" is recommended.

SDL_MixAudio() has been removed, as it relied on legacy SDL 1.2 quirks; SDL_MixAudioFormat() remains and offers the same functionality.

SDL_AudioInit() and SDL_AudioQuit() have been removed. Instead you can call SDL_InitSubSystem() and SDL_QuitSubSystem() with SDL_INIT_AUDIO, which will properly refcount the subsystems. You can choose a specific audio driver using SDL_AUDIO_DRIVER hint.

SDL_FreeWAV has been removed and calls can be replaced with SDL_free.

SDL_LoadWAV() is a proper function now and no longer a macro (but offers the same functionality otherwise).

SDL_LoadWAV_RW() and SDL_LoadWAV() return an int now: zero on success, -1 on error, like most of SDL. They no longer return a pointer to an SDL_AudioSpec.

SDL_AudioCVT interface has been removed, the SDL_AudioStream interface (for audio supplied in pieces) or the new SDL_ConvertAudioSamples() function (for converting a complete audio buffer in one call) can be used instead.

Code that used to look like this:

    SDL_AudioCVT cvt;
    SDL_BuildAudioCVT(&cvt, src_format, src_channels, src_rate, dst_format, dst_channels, dst_rate);
    cvt.len = src_len;
    cvt.buf = (Uint8 *) SDL_malloc(src_len * cvt.len_mult);
    SDL_memcpy(cvt.buf, src_data, src_len);
    SDL_ConvertAudio(&cvt);
    do_something(cvt.buf, cvt.len_cvt);

should be changed to:

    Uint8 *dst_data = NULL;
    int dst_len = 0;
    const SDL_AudioSpec src_spec = { src_format, src_channels, src_rate };
    const SDL_AudioSpec dst_spec = { dst_format, dst_channels, dst_rate };
    if (SDL_ConvertAudioSamples(&src_spec, src_data, src_len, &dst_spec, &dst_data, &dst_len) < 0) {
        /* error */
    }
    do_something(dst_data, dst_len);
    SDL_free(dst_data);

AUDIO_U16, AUDIO_U16LSB, AUDIO_U16MSB, and AUDIO_U16SYS have been removed. They were not heavily used, and one could not memset a buffer in this format to silence with a single byte value. Use a different audio format.

If you need to convert U16 audio data to a still-supported format at runtime, the fastest, lossless conversion is to SDL_AUDIO_S16:

    /* this converts the buffer in-place. The buffer size does not change. */
    Sint16 *audio_ui16_to_si16(Uint16 *buffer, const size_t num_samples)
    {
        size_t i;
        const Uint16 *src = buffer;
        Sint16 *dst = (Sint16 *) buffer;

        for (i = 0; i < num_samples; i++) {
            dst[i] = (Sint16) (src[i] ^ 0x8000);
        }

        return dst;
    }

All remaining AUDIO_* symbols have been renamed to SDL_AUDIO_* for API consistency, but othewise are identical in value and usage.

In SDL2, SDL_AudioStream would convert/resample audio data during input (via SDL_AudioStreamPut). In SDL3, it does this work when requesting audio (via SDL_GetAudioStreamData, which would have been SDL_AudioStreamGet in SDL2). The way you use an AudioStream is roughly the same, just be aware that the workload moved to a different phase.

In SDL2, SDL_AudioStreamAvailable() returns 0 if passed a NULL stream. In SDL3, the equivalent SDL_GetAudioStreamAvailable() call returns -1 and sets an error string, which matches other audiostream APIs' behavior.

In SDL2, SDL_AUDIODEVICEREMOVED events would fire for open devices with the which field set to the SDL_AudioDeviceID of the lost device, and in later SDL2 releases, would also fire this event with a which field of zero for unopened devices, to signify that the app might want to refresh the available device list. In SDL3, this event works the same, except it won't ever fire with a zero; in this case it'll return the physical device's SDL_AudioDeviceID. Any still-open SDL_AudioDeviceIDs generated from this device with SDL_OpenAudioDevice() will also fire a separate event.

The following functions have been renamed:

  • SDL_AudioStreamAvailable() => SDL_GetAudioStreamAvailable()
  • SDL_AudioStreamClear() => SDL_ClearAudioStream()
  • SDL_AudioStreamFlush() => SDL_FlushAudioStream()
  • SDL_AudioStreamGet() => SDL_GetAudioStreamData()
  • SDL_AudioStreamPut() => SDL_PutAudioStreamData()
  • SDL_FreeAudioStream() => SDL_DestroyAudioStream()
  • SDL_NewAudioStream() => SDL_CreateAudioStream()

The following functions have been removed:

  • SDL_GetNumAudioDevices()
  • SDL_GetAudioDeviceSpec()
  • SDL_ConvertAudio()
  • SDL_BuildAudioCVT()
  • SDL_OpenAudio()
  • SDL_CloseAudio()
  • SDL_PauseAudio()
  • SDL_GetAudioStatus()
  • SDL_GetAudioDeviceStatus()
  • SDL_GetDefaultAudioInfo()
  • SDL_LockAudio()
  • SDL_LockAudioDevice()
  • SDL_UnlockAudio()
  • SDL_UnlockAudioDevice()
  • SDL_MixAudio()
  • SDL_QueueAudio()
  • SDL_DequeueAudio()
  • SDL_ClearAudioQueue()
  • SDL_GetQueuedAudioSize()

The following symbols have been renamed:

  • AUDIO_F32 => SDL_AUDIO_F32LE
  • AUDIO_F32LSB => SDL_AUDIO_F32LE
  • AUDIO_F32MSB => SDL_AUDIO_F32BE
  • AUDIO_F32SYS => SDL_AUDIO_F32
  • AUDIO_S16 => SDL_AUDIO_S16LE
  • AUDIO_S16LSB => SDL_AUDIO_S16LE
  • AUDIO_S16MSB => SDL_AUDIO_S16BE
  • AUDIO_S16SYS => SDL_AUDIO_S16
  • AUDIO_S32 => SDL_AUDIO_S32LE
  • AUDIO_S32LSB => SDL_AUDIO_S32LE
  • AUDIO_S32MSB => SDL_AUDIO_S32BE
  • AUDIO_S32SYS => SDL_AUDIO_S32
  • AUDIO_S8 => SDL_AUDIO_S8
  • AUDIO_U8 => SDL_AUDIO_U8

SDL_cpuinfo.h

The intrinsics headers (mmintrin.h, etc.) have been moved to <SDL3/SDL_intrin.h> and are no longer automatically included in SDL.h.

SDL_Has3DNow() has been removed; there is no replacement.

SDL_SIMDAlloc(), SDL_SIMDRealloc(), and SDL_SIMDFree() have been removed. You can use SDL_aligned_alloc() and SDL_aligned_free() with SDL_SIMDGetAlignment() to get the same functionality.

SDL_events.h

The timestamp member of the SDL_Event structure now represents nanoseconds, and is populated with SDL_GetTicksNS()

The timestamp_us member of the sensor events has been renamed sensor_timestamp and now represents nanoseconds. This value is filled in from the hardware, if available, and may not be synchronized with values returned from SDL_GetTicksNS().

You should set the event.common.timestamp field before passing an event to SDL_PushEvent(). If the timestamp is 0 it will be filled in with SDL_GetTicksNS().

Mouse events use floating point values for mouse coordinates and relative motion values. You can get sub-pixel motion depending on the platform and display scaling.

The SDL_DISPLAYEVENT_* events have been moved to top level events, and SDL_DISPLAYEVENT has been removed. In general, handling this change just means checking for the individual events instead of first checking for SDL_DISPLAYEVENT and then checking for display events. You can compare the event >= SDL_EVENT_DISPLAY_FIRST and <= SDL_EVENT_DISPLAY_LAST if you need to see whether it's a display event.

The SDL_WINDOWEVENT_* events have been moved to top level events, and SDL_WINDOWEVENT has been removed. In general, handling this change just means checking for the individual events instead of first checking for SDL_WINDOWEVENT and then checking for window events. You can compare the event >= SDL_EVENT_WINDOW_FIRST and <= SDL_EVENT_WINDOW_LAST if you need to see whether it's a window event.

The SDL_EVENT_WINDOW_RESIZED event is always sent, even in response to SDL_SetWindowSize().

The SDL_EVENT_WINDOW_SIZE_CHANGED event has been removed, and you can use SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED to detect window backbuffer size changes.

The gamepad event structures caxis, cbutton, cdevice, ctouchpad, and csensor have been renamed gaxis, gbutton, gdevice, gtouchpad, and gsensor.

SDL_QUERY, SDL_IGNORE, SDL_ENABLE, and SDL_DISABLE have been removed. You can use the functions SDL_SetEventEnabled() and SDL_EventEnabled() to set and query event processing state.

The following symbols have been renamed:

  • SDL_APP_DIDENTERBACKGROUND => SDL_EVENT_DID_ENTER_BACKGROUND
  • SDL_APP_DIDENTERFOREGROUND => SDL_EVENT_DID_ENTER_FOREGROUND
  • SDL_APP_LOWMEMORY => SDL_EVENT_LOW_MEMORY
  • SDL_APP_TERMINATING => SDL_EVENT_TERMINATING
  • SDL_APP_WILLENTERBACKGROUND => SDL_EVENT_WILL_ENTER_BACKGROUND
  • SDL_APP_WILLENTERFOREGROUND => SDL_EVENT_WILL_ENTER_FOREGROUND
  • SDL_AUDIODEVICEADDED => SDL_EVENT_AUDIO_DEVICE_ADDED
  • SDL_AUDIODEVICEREMOVED => SDL_EVENT_AUDIO_DEVICE_REMOVED
  • SDL_CLIPBOARDUPDATE => SDL_EVENT_CLIPBOARD_UPDATE
  • SDL_CONTROLLERAXISMOTION => SDL_EVENT_GAMEPAD_AXIS_MOTION
  • SDL_CONTROLLERBUTTONDOWN => SDL_EVENT_GAMEPAD_BUTTON_DOWN
  • SDL_CONTROLLERBUTTONUP => SDL_EVENT_GAMEPAD_BUTTON_UP
  • SDL_CONTROLLERDEVICEADDED => SDL_EVENT_GAMEPAD_ADDED
  • SDL_CONTROLLERDEVICEREMAPPED => SDL_EVENT_GAMEPAD_REMAPPED
  • SDL_CONTROLLERDEVICEREMOVED => SDL_EVENT_GAMEPAD_REMOVED
  • SDL_CONTROLLERSENSORUPDATE => SDL_EVENT_GAMEPAD_SENSOR_UPDATE
  • SDL_CONTROLLERTOUCHPADDOWN => SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN
  • SDL_CONTROLLERTOUCHPADMOTION => SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION
  • SDL_CONTROLLERTOUCHPADUP => SDL_EVENT_GAMEPAD_TOUCHPAD_UP
  • SDL_DROPBEGIN => SDL_EVENT_DROP_BEGIN
  • SDL_DROPCOMPLETE => SDL_EVENT_DROP_COMPLETE
  • SDL_DROPFILE => SDL_EVENT_DROP_FILE
  • SDL_DROPTEXT => SDL_EVENT_DROP_TEXT
  • SDL_FINGERDOWN => SDL_EVENT_FINGER_DOWN
  • SDL_FINGERMOTION => SDL_EVENT_FINGER_MOTION
  • SDL_FINGERUP => SDL_EVENT_FINGER_UP
  • SDL_FIRSTEVENT => SDL_EVENT_FIRST
  • SDL_JOYAXISMOTION => SDL_EVENT_JOYSTICK_AXIS_MOTION
  • SDL_JOYBATTERYUPDATED => SDL_EVENT_JOYSTICK_BATTERY_UPDATED
  • SDL_JOYBUTTONDOWN => SDL_EVENT_JOYSTICK_BUTTON_DOWN
  • SDL_JOYBUTTONUP => SDL_EVENT_JOYSTICK_BUTTON_UP
  • SDL_JOYDEVICEADDED => SDL_EVENT_JOYSTICK_ADDED
  • SDL_JOYDEVICEREMOVED => SDL_EVENT_JOYSTICK_REMOVED
  • SDL_JOYHATMOTION => SDL_EVENT_JOYSTICK_HAT_MOTION
  • SDL_KEYDOWN => SDL_EVENT_KEY_DOWN
  • SDL_KEYMAPCHANGED => SDL_EVENT_KEYMAP_CHANGED
  • SDL_KEYUP => SDL_EVENT_KEY_UP
  • SDL_LASTEVENT => SDL_EVENT_LAST
  • SDL_LOCALECHANGED => SDL_EVENT_LOCALE_CHANGED
  • SDL_MOUSEBUTTONDOWN => SDL_EVENT_MOUSE_BUTTON_DOWN
  • SDL_MOUSEBUTTONUP => SDL_EVENT_MOUSE_BUTTON_UP
  • SDL_MOUSEMOTION => SDL_EVENT_MOUSE_MOTION
  • SDL_MOUSEWHEEL => SDL_EVENT_MOUSE_WHEEL
  • SDL_POLLSENTINEL => SDL_EVENT_POLL_SENTINEL
  • SDL_QUIT => SDL_EVENT_QUIT
  • SDL_RENDER_DEVICE_RESET => SDL_EVENT_RENDER_DEVICE_RESET
  • SDL_RENDER_TARGETS_RESET => SDL_EVENT_RENDER_TARGETS_RESET
  • SDL_SENSORUPDATE => SDL_EVENT_SENSOR_UPDATE
  • SDL_SYSWMEVENT => SDL_EVENT_SYSWM
  • SDL_TEXTEDITING => SDL_EVENT_TEXT_EDITING
  • SDL_TEXTEDITING_EXT => SDL_EVENT_TEXT_EDITING_EXT
  • SDL_TEXTINPUT => SDL_EVENT_TEXT_INPUT
  • SDL_USEREVENT => SDL_EVENT_USER

The following structures have been renamed:

  • SDL_ControllerAxisEvent => SDL_GamepadAxisEvent
  • SDL_ControllerButtonEvent => SDL_GamepadButtonEvent
  • SDL_ControllerDeviceEvent => SDL_GamepadDeviceEvent
  • SDL_ControllerSensorEvent => SDL_GamepadSensorEvent
  • SDL_ControllerTouchpadEvent => SDL_GamepadTouchpadEvent

The following functions have been removed:

  • SDL_EventState() - replaced with SDL_SetEventEnabled()
  • SDL_GetEventState() - replaced with SDL_EventEnabled()

SDL_gamecontroller.h

SDL_gamecontroller.h has been renamed SDL_gamepad.h, and all APIs have been renamed to match.

The SDL_EVENT_GAMEPAD_ADDED event now provides the joystick instance ID in the which member of the cdevice event structure.

The functions SDL_GetGamepads(), SDL_GetGamepadInstanceName(), SDL_GetGamepadInstancePath(), SDL_GetGamepadInstancePlayerIndex(), SDL_GetGamepadInstanceGUID(), SDL_GetGamepadInstanceVendor(), SDL_GetGamepadInstanceProduct(), SDL_GetGamepadInstanceProductVersion(), and SDL_GetGamepadInstanceType() have been added to directly query the list of available gamepads.

SDL_GameControllerGetSensorDataWithTimestamp() has been removed. If you want timestamps for the sensor data, you should use the sensor_timestamp member of SDL_EVENT_GAMEPAD_SENSOR_UPDATE events.

SDL_CONTROLLER_TYPE_VIRTUAL has been removed, so virtual controllers can emulate other gamepad types. If you need to know whether a controller is virtual, you can use SDL_IsJoystickVirtual().

SDL_CONTROLLER_TYPE_AMAZON_LUNA has been removed, and can be replaced with this code:

SDL_bool SDL_IsJoystickAmazonLunaController(Uint16 vendor_id, Uint16 product_id)
{
    return ((vendor_id == 0x1949 && product_id == 0x0419) ||
            (vendor_id == 0x0171 && product_id == 0x0419));
}

SDL_CONTROLLER_TYPE_GOOGLE_STADIA has been removed, and can be replaced with this code:

SDL_bool SDL_IsJoystickGoogleStadiaController(Uint16 vendor_id, Uint16 product_id)
{
    return (vendor_id == 0x18d1 && product_id == 0x9400);
}

SDL_CONTROLLER_TYPE_NVIDIA_SHIELD has been removed, and can be replaced with this code:

SDL_bool SDL_IsJoystickNVIDIASHIELDController(Uint16 vendor_id, Uint16 product_id)
{
    return (vendor_id == 0x0955 && (product_id == 0x7210 || product_id == 0x7214));
}

The following enums have been renamed:

  • SDL_GameControllerAxis => SDL_GamepadAxis
  • SDL_GameControllerBindType => SDL_GamepadBindingType
  • SDL_GameControllerButton => SDL_GamepadButton
  • SDL_GameControllerType => SDL_GamepadType

The following structures have been renamed:

  • SDL_GameController => SDL_Gamepad

The following functions have been renamed:

  • SDL_GameControllerAddMapping() => SDL_AddGamepadMapping()
  • SDL_GameControllerAddMappingsFromFile() => SDL_AddGamepadMappingsFromFile()
  • SDL_GameControllerAddMappingsFromRW() => SDL_AddGamepadMappingsFromRW()
  • SDL_GameControllerClose() => SDL_CloseGamepad()
  • SDL_GameControllerFromInstanceID() => SDL_GetGamepadFromInstanceID()
  • SDL_GameControllerFromPlayerIndex() => SDL_GetGamepadFromPlayerIndex()
  • SDL_GameControllerGetAppleSFSymbolsNameForAxis() => SDL_GetGamepadAppleSFSymbolsNameForAxis()
  • SDL_GameControllerGetAppleSFSymbolsNameForButton() => SDL_GetGamepadAppleSFSymbolsNameForButton()
  • SDL_GameControllerGetAttached() => SDL_GamepadConnected()
  • SDL_GameControllerGetAxis() => SDL_GetGamepadAxis()
  • SDL_GameControllerGetAxisFromString() => SDL_GetGamepadAxisFromString()
  • SDL_GameControllerGetButton() => SDL_GetGamepadButton()
  • SDL_GameControllerGetButtonFromString() => SDL_GetGamepadButtonFromString()
  • SDL_GameControllerGetFirmwareVersion() => SDL_GetGamepadFirmwareVersion()
  • SDL_GameControllerGetJoystick() => SDL_GetGamepadJoystick()
  • SDL_GameControllerGetNumTouchpadFingers() => SDL_GetNumGamepadTouchpadFingers()
  • SDL_GameControllerGetNumTouchpads() => SDL_GetNumGamepadTouchpads()
  • SDL_GameControllerGetPlayerIndex() => SDL_GetGamepadPlayerIndex()
  • SDL_GameControllerGetProduct() => SDL_GetGamepadProduct()
  • SDL_GameControllerGetProductVersion() => SDL_GetGamepadProductVersion()
  • SDL_GameControllerGetSensorData() => SDL_GetGamepadSensorData()
  • SDL_GameControllerGetSensorDataRate() => SDL_GetGamepadSensorDataRate()
  • SDL_GameControllerGetSerial() => SDL_GetGamepadSerial()
  • SDL_GameControllerGetStringForAxis() => SDL_GetGamepadStringForAxis()
  • SDL_GameControllerGetStringForButton() => SDL_GetGamepadStringForButton()
  • SDL_GameControllerGetTouchpadFinger() => SDL_GetGamepadTouchpadFinger()
  • SDL_GameControllerGetType() => SDL_GetGamepadType()
  • SDL_GameControllerGetVendor() => SDL_GetGamepadVendor()
  • SDL_GameControllerHasAxis() => SDL_GamepadHasAxis()
  • SDL_GameControllerHasButton() => SDL_GamepadHasButton()
  • SDL_GameControllerHasLED() => SDL_GamepadHasLED()
  • SDL_GameControllerHasRumble() => SDL_GamepadHasRumble()
  • SDL_GameControllerHasRumbleTriggers() => SDL_GamepadHasRumbleTriggers()
  • SDL_GameControllerHasSensor() => SDL_GamepadHasSensor()
  • SDL_GameControllerIsSensorEnabled() => SDL_GamepadSensorEnabled()
  • SDL_GameControllerMapping() => SDL_GetGamepadMapping()
  • SDL_GameControllerMappingForGUID() => SDL_GetGamepadMappingForGUID()
  • SDL_GameControllerMappingForIndex() => SDL_GetGamepadMappingForIndex()
  • SDL_GameControllerName() => SDL_GetGamepadName()
  • SDL_GameControllerNumMappings() => SDL_GetNumGamepadMappings()
  • SDL_GameControllerOpen() => SDL_OpenGamepad()
  • SDL_GameControllerPath() => SDL_GetGamepadPath()
  • SDL_GameControllerRumble() => SDL_RumbleGamepad()
  • SDL_GameControllerRumbleTriggers() => SDL_RumbleGamepadTriggers()
  • SDL_GameControllerSendEffect() => SDL_SendGamepadEffect()
  • SDL_GameControllerSetLED() => SDL_SetGamepadLED()
  • SDL_GameControllerSetPlayerIndex() => SDL_SetGamepadPlayerIndex()
  • SDL_GameControllerSetSensorEnabled() => SDL_SetGamepadSensorEnabled()
  • SDL_GameControllerUpdate() => SDL_UpdateGamepads()
  • SDL_IsGameController() => SDL_IsGamepad()

The following functions have been removed:

  • SDL_GameControllerEventState() - replaced with SDL_SetGamepadEventsEnabled() and SDL_GamepadEventsEnabled()
  • SDL_GameControllerGetBindForAxis() - replaced with SDL_GetGamepadBindings()
  • SDL_GameControllerGetBindForButton() - replaced with SDL_GetGamepadBindings()
  • SDL_GameControllerMappingForDeviceIndex() - replaced with SDL_GetGamepadInstanceMapping()
  • SDL_GameControllerNameForIndex() - replaced with SDL_GetGamepadInstanceName()
  • SDL_GameControllerPathForIndex() - replaced with SDL_GetGamepadInstancePath()
  • SDL_GameControllerTypeForIndex() - replaced with SDL_GetGamepadInstanceType()

The following symbols have been renamed:

  • SDL_CONTROLLER_AXIS_INVALID => SDL_GAMEPAD_AXIS_INVALID
  • SDL_CONTROLLER_AXIS_LEFTX => SDL_GAMEPAD_AXIS_LEFTX
  • SDL_CONTROLLER_AXIS_LEFTY => SDL_GAMEPAD_AXIS_LEFTY
  • SDL_CONTROLLER_AXIS_MAX => SDL_GAMEPAD_AXIS_MAX
  • SDL_CONTROLLER_AXIS_RIGHTX => SDL_GAMEPAD_AXIS_RIGHTX
  • SDL_CONTROLLER_AXIS_RIGHTY => SDL_GAMEPAD_AXIS_RIGHTY
  • SDL_CONTROLLER_AXIS_TRIGGERLEFT => SDL_GAMEPAD_AXIS_LEFT_TRIGGER
  • SDL_CONTROLLER_AXIS_TRIGGERRIGHT => SDL_GAMEPAD_AXIS_RIGHT_TRIGGER
  • SDL_CONTROLLER_BINDTYPE_AXIS => SDL_GAMEPAD_BINDTYPE_AXIS
  • SDL_CONTROLLER_BINDTYPE_BUTTON => SDL_GAMEPAD_BINDTYPE_BUTTON
  • SDL_CONTROLLER_BINDTYPE_HAT => SDL_GAMEPAD_BINDTYPE_HAT
  • SDL_CONTROLLER_BINDTYPE_NONE => SDL_GAMEPAD_BINDTYPE_NONE
  • SDL_CONTROLLER_BUTTON_A => SDL_GAMEPAD_BUTTON_A
  • SDL_CONTROLLER_BUTTON_B => SDL_GAMEPAD_BUTTON_B
  • SDL_CONTROLLER_BUTTON_BACK => SDL_GAMEPAD_BUTTON_BACK
  • SDL_CONTROLLER_BUTTON_DPAD_DOWN => SDL_GAMEPAD_BUTTON_DPAD_DOWN
  • SDL_CONTROLLER_BUTTON_DPAD_LEFT => SDL_GAMEPAD_BUTTON_DPAD_LEFT
  • SDL_CONTROLLER_BUTTON_DPAD_RIGHT => SDL_GAMEPAD_BUTTON_DPAD_RIGHT
  • SDL_CONTROLLER_BUTTON_DPAD_UP => SDL_GAMEPAD_BUTTON_DPAD_UP
  • SDL_CONTROLLER_BUTTON_GUIDE => SDL_GAMEPAD_BUTTON_GUIDE
  • SDL_CONTROLLER_BUTTON_INVALID => SDL_GAMEPAD_BUTTON_INVALID
  • SDL_CONTROLLER_BUTTON_LEFTSHOULDER => SDL_GAMEPAD_BUTTON_LEFT_SHOULDER
  • SDL_CONTROLLER_BUTTON_LEFTSTICK => SDL_GAMEPAD_BUTTON_LEFT_STICK
  • SDL_CONTROLLER_BUTTON_MAX => SDL_GAMEPAD_BUTTON_MAX
  • SDL_CONTROLLER_BUTTON_MISC1 => SDL_GAMEPAD_BUTTON_MISC1
  • SDL_CONTROLLER_BUTTON_PADDLE1 => SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1
  • SDL_CONTROLLER_BUTTON_PADDLE2 => SDL_GAMEPAD_BUTTON_LEFT_PADDLE1
  • SDL_CONTROLLER_BUTTON_PADDLE3 => SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2
  • SDL_CONTROLLER_BUTTON_PADDLE4 => SDL_GAMEPAD_BUTTON_LEFT_PADDLE2
  • SDL_CONTROLLER_BUTTON_RIGHTSHOULDER => SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER
  • SDL_CONTROLLER_BUTTON_RIGHTSTICK => SDL_GAMEPAD_BUTTON_RIGHT_STICK
  • SDL_CONTROLLER_BUTTON_START => SDL_GAMEPAD_BUTTON_START
  • SDL_CONTROLLER_BUTTON_TOUCHPAD => SDL_GAMEPAD_BUTTON_TOUCHPAD
  • SDL_CONTROLLER_BUTTON_X => SDL_GAMEPAD_BUTTON_X
  • SDL_CONTROLLER_BUTTON_Y => SDL_GAMEPAD_BUTTON_Y
  • SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT => SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT
  • SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR => SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_PAIR
  • SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT => SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT
  • SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO => SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO
  • SDL_CONTROLLER_TYPE_PS3 => SDL_GAMEPAD_TYPE_PS3
  • SDL_CONTROLLER_TYPE_PS4 => SDL_GAMEPAD_TYPE_PS4
  • SDL_CONTROLLER_TYPE_PS5 => SDL_GAMEPAD_TYPE_PS5
  • SDL_CONTROLLER_TYPE_UNKNOWN => SDL_GAMEPAD_TYPE_STANDARD
  • SDL_CONTROLLER_TYPE_VIRTUAL => SDL_GAMEPAD_TYPE_VIRTUAL
  • SDL_CONTROLLER_TYPE_XBOX360 => SDL_GAMEPAD_TYPE_XBOX360
  • SDL_CONTROLLER_TYPE_XBOXONE => SDL_GAMEPAD_TYPE_XBOXONE

SDL_gesture.h

The gesture API has been removed. There is no replacement planned in SDL3. However, the SDL2 code has been moved to a single-header library that can be dropped into an SDL3 or SDL2 program, to continue to provide this functionality to your app and aid migration. That is located in the SDL_gesture GitHub repository.

SDL_hints.h

SDL_AddHintCallback() now returns a standard int result instead of void, returning 0 if the function succeeds or a negative error code if there was an error.

Calling SDL_GetHint() with the name of the hint being changed from within a hint callback will now return the new value rather than the old value. The old value is still passed as a parameter to the hint callback.

The following hints have been removed:

  • SDL_HINT_VIDEO_HIGHDPI_DISABLED - high DPI support is always enabled

  • SDL_HINT_IDLE_TIMER_DISABLED - use SDL_DisableScreenSaver instead

  • SDL_HINT_MOUSE_RELATIVE_SCALING - mouse coordinates are no longer automatically scaled by the SDL renderer

  • SDL_HINT_RENDER_LOGICAL_SIZE_MODE - the logical size mode is explicitly set with SDL_SetRenderLogicalPresentation()

  • SDL_HINT_VIDEO_X11_FORCE_EGL - use SDL_HINT_VIDEO_FORCE_EGL instead

  • SDL_HINT_VIDEO_X11_XINERAMA - Xinerama no longer supported by the X11 backend

  • SDL_HINT_VIDEO_X11_XVIDMODE - Xvidmode no longer supported by the X11 backend

  • Renamed hints SDL_HINT_VIDEODRIVER and SDL_HINT_AUDIODRIVER to SDL_HINT_VIDEO_DRIVER and SDL_HINT_AUDIO_DRIVER

  • Renamed environment variables SDL_VIDEODRIVER and SDL_AUDIODRIVER to SDL_VIDEO_DRIVER and SDL_AUDIO_DRIVER

  • The environment variables SDL_VIDEO_X11_WMCLASS and SDL_VIDEO_WAYLAND_WMCLASS have been removed and replaced with the unified hint SDL_HINT_APP_ID

SDL_init.h

The following symbols have been renamed:

  • SDL_INIT_GAMECONTROLLER => SDL_INIT_GAMEPAD

The following symbols have been removed:

  • SDL_INIT_NOPARACHUTE

SDL_joystick.h

SDL_JoystickID has changed from Sint32 to Uint32, with an invalid ID being 0.

Rather than iterating over joysticks using device index, there is a new function SDL_GetJoysticks() to get the current list of joysticks, and new functions to get information about joysticks from their instance ID:

{
    if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == 0) {
        int i, num_joysticks;
        SDL_JoystickID *joysticks = SDL_GetJoysticks(&num_joysticks);
        if (joysticks) {
            for (i = 0; i < num_joysticks; ++i) {
                SDL_JoystickID instance_id = joysticks[i];
                const char *name = SDL_GetJoystickInstanceName(instance_id);
                const char *path = SDL_GetJoystickInstancePath(instance_id);

                SDL_Log("Joystick %" SDL_PRIu32 ": %s%s%s VID 0x%.4x, PID 0x%.4x\n",
                        instance_id, name ? name : "Unknown", path ? ", " : "", path ? path : "", SDL_GetJoystickInstanceVendor(instance_id), SDL_GetJoystickInstanceProduct(instance_id));
            }
            SDL_free(joysticks);
        }
        SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
    }
}

The SDL_EVENT_JOYSTICK_ADDED event now provides the joystick instance ID in the which member of the jdevice event structure.

The functions SDL_GetJoysticks(), SDL_GetJoystickInstanceName(), SDL_GetJoystickInstancePath(), SDL_GetJoystickInstancePlayerIndex(), SDL_GetJoystickInstanceGUID(), SDL_GetJoystickInstanceVendor(), SDL_GetJoystickInstanceProduct(), SDL_GetJoystickInstanceProductVersion(), and SDL_GetJoystickInstanceType() have been added to directly query the list of available joysticks.

SDL_AttachVirtualJoystick() and SDL_AttachVirtualJoystickEx() now return the joystick instance ID instead of a device index, and return 0 if there was an error.

The following functions have been renamed:

  • SDL_JoystickAttachVirtual() => SDL_AttachVirtualJoystick()
  • SDL_JoystickAttachVirtualEx() => SDL_AttachVirtualJoystickEx()
  • SDL_JoystickClose() => SDL_CloseJoystick()
  • SDL_JoystickCurrentPowerLevel() => SDL_GetJoystickPowerLevel()
  • SDL_JoystickDetachVirtual() => SDL_DetachVirtualJoystick()
  • SDL_JoystickFromInstanceID() => SDL_GetJoystickFromInstanceID()
  • SDL_JoystickFromPlayerIndex() => SDL_GetJoystickFromPlayerIndex()
  • SDL_JoystickGetAttached() => SDL_JoystickConnected()
  • SDL_JoystickGetAxis() => SDL_GetJoystickAxis()
  • SDL_JoystickGetAxisInitialState() => SDL_GetJoystickAxisInitialState()
  • SDL_JoystickGetButton() => SDL_GetJoystickButton()
  • SDL_JoystickGetFirmwareVersion() => SDL_GetJoystickFirmwareVersion()
  • SDL_JoystickGetGUID() => SDL_GetJoystickGUID()
  • SDL_JoystickGetGUIDFromString() => SDL_GetJoystickGUIDFromString()
  • SDL_JoystickGetGUIDString() => SDL_GetJoystickGUIDString()
  • SDL_JoystickGetHat() => SDL_GetJoystickHat()
  • SDL_JoystickGetPlayerIndex() => SDL_GetJoystickPlayerIndex()
  • SDL_JoystickGetProduct() => SDL_GetJoystickProduct()
  • SDL_JoystickGetProductVersion() => SDL_GetJoystickProductVersion()
  • SDL_JoystickGetSerial() => SDL_GetJoystickSerial()
  • SDL_JoystickGetType() => SDL_GetJoystickType()
  • SDL_JoystickGetVendor() => SDL_GetJoystickVendor()
  • SDL_JoystickInstanceID() => SDL_GetJoystickInstanceID()
  • SDL_JoystickIsVirtual() => SDL_IsJoystickVirtual()
  • SDL_JoystickName() => SDL_GetJoystickName()
  • SDL_JoystickNumAxes() => SDL_GetNumJoystickAxes()
  • SDL_JoystickNumButtons() => SDL_GetNumJoystickButtons()
  • SDL_JoystickNumHats() => SDL_GetNumJoystickHats()
  • SDL_JoystickOpen() => SDL_OpenJoystick()
  • SDL_JoystickPath() => SDL_GetJoystickPath()
  • SDL_JoystickRumble() => SDL_RumbleJoystick()
  • SDL_JoystickRumbleTriggers() => SDL_RumbleJoystickTriggers()
  • SDL_JoystickSendEffect() => SDL_SendJoystickEffect()
  • SDL_JoystickSetLED() => SDL_SetJoystickLED()
  • SDL_JoystickSetPlayerIndex() => SDL_SetJoystickPlayerIndex()
  • SDL_JoystickSetVirtualAxis() => SDL_SetJoystickVirtualAxis()
  • SDL_JoystickSetVirtualButton() => SDL_SetJoystickVirtualButton()
  • SDL_JoystickSetVirtualHat() => SDL_SetJoystickVirtualHat()
  • SDL_JoystickUpdate() => SDL_UpdateJoysticks()

The following symbols have been renamed:

  • SDL_JOYSTICK_TYPE_GAMECONTROLLER => SDL_JOYSTICK_TYPE_GAMEPAD

The following functions have been removed:

  • SDL_JoystickEventState() - replaced with SDL_SetJoystickEventsEnabled() and SDL_JoystickEventsEnabled()
  • SDL_JoystickGetDeviceGUID() - replaced with SDL_GetJoystickInstanceGUID()
  • SDL_JoystickGetDeviceInstanceID()
  • SDL_JoystickGetDevicePlayerIndex() - replaced with SDL_GetJoystickInstancePlayerIndex()
  • SDL_JoystickGetDeviceProduct() - replaced with SDL_GetJoystickInstanceProduct()
  • SDL_JoystickGetDeviceProductVersion() - replaced with SDL_GetJoystickInstanceProductVersion()
  • SDL_JoystickGetDeviceType() - replaced with SDL_GetJoystickInstanceType()
  • SDL_JoystickGetDeviceVendor() - replaced with SDL_GetJoystickInstanceVendor()
  • SDL_JoystickNameForIndex() - replaced with SDL_GetJoystickInstanceName()
  • SDL_JoystickNumBalls() - API has been removed, see https://github.com/libsdl-org/SDL/issues/6766
  • SDL_JoystickPathForIndex() - replaced with SDL_GetJoystickInstancePath()
  • SDL_NumJoysticks() - replaced with SDL_GetJoysticks()

The following symbols have been removed:

  • SDL_JOYBALLMOTION

SDL_keyboard.h

The following functions have been renamed:

  • SDL_IsScreenKeyboardShown() => SDL_ScreenKeyboardShown()
  • SDL_IsTextInputActive() => SDL_TextInputActive()
  • SDL_IsTextInputShown() => SDL_TextInputShown()

SDL_keycode.h

The following symbols have been renamed:

  • KMOD_ALT => SDL_KMOD_ALT
  • KMOD_CAPS => SDL_KMOD_CAPS
  • KMOD_CTRL => SDL_KMOD_CTRL
  • KMOD_GUI => SDL_KMOD_GUI
  • KMOD_LALT => SDL_KMOD_LALT
  • KMOD_LCTRL => SDL_KMOD_LCTRL
  • KMOD_LGUI => SDL_KMOD_LGUI
  • KMOD_LSHIFT => SDL_KMOD_LSHIFT
  • KMOD_MODE => SDL_KMOD_MODE
  • KMOD_NONE => SDL_KMOD_NONE
  • KMOD_NUM => SDL_KMOD_NUM
  • KMOD_RALT => SDL_KMOD_RALT
  • KMOD_RCTRL => SDL_KMOD_RCTRL
  • KMOD_RESERVED => SDL_KMOD_RESERVED
  • KMOD_RGUI => SDL_KMOD_RGUI
  • KMOD_RSHIFT => SDL_KMOD_RSHIFT
  • KMOD_SCROLL => SDL_KMOD_SCROLL
  • KMOD_SHIFT => SDL_KMOD_SHIFT

SDL_loadso.h

SDL_LoadFunction() now returns SDL_FunctionPointer instead of void *, and should be cast to the appropriate function type. You can define SDL_FUNCTION_POINTER_IS_VOID_POINTER in your project to restore the previous behavior.

SDL_main.h

SDL3 doesn't have a static libSDLmain to link against anymore. Instead SDL_main.h is now a header-only library and not included by SDL.h anymore.

Using it is really simple: Just #include <SDL3/SDL_main.h> in the source file with your standard int main(int argc, char* argv[]) function.

SDL_metal.h

SDL_Metal_GetDrawableSize() has been removed. SDL_GetWindowSizeInPixels() can be used in its place.

SDL_mouse.h

SDL_ShowCursor() has been split into three functions: SDL_ShowCursor(), SDL_HideCursor(), and SDL_CursorVisible()

SDL_GetMouseState(), SDL_GetGlobalMouseState(), SDL_GetRelativeMouseState(), SDL_WarpMouseInWindow(), and SDL_WarpMouseGlobal() all use floating point mouse positions, to provide sub-pixel precision on platforms that support it.

The following functions have been renamed:

  • SDL_FreeCursor() => SDL_DestroyCursor()

SDL_mutex.h

The following functions have been renamed:

  • SDL_CondBroadcast() => SDL_BroadcastCondition()
  • SDL_CondSignal() => SDL_SignalCondition()
  • SDL_CondWait() => SDL_WaitCondition()
  • SDL_CondWaitTimeout() => SDL_WaitConditionTimeout()
  • SDL_CreateCond() => SDL_CreateCondition()
  • SDL_DestroyCond() => SDL_DestroyCondition()
  • SDL_SemPost() => SDL_PostSemaphore()
  • SDL_SemTryWait() => SDL_TryWaitSemaphore()
  • SDL_SemValue() => SDL_GetSemaphoreValue()
  • SDL_SemWait() => SDL_WaitSemaphore()
  • SDL_SemWaitTimeout() => SDL_WaitSemaphoreTimeout()

The following symbols have been renamed:

  • SDL_cond => SDL_Condition
  • SDL_mutex => SDL_Mutex
  • SDL_sem => SDL_Semaphore

SDL_pixels.h

SDL_CalculateGammaRamp has been removed, because SDL_SetWindowGammaRamp has been removed as well due to poor support in modern operating systems (see SDL_video.h).

The following functions have been renamed:

  • SDL_AllocFormat() => SDL_CreatePixelFormat()
  • SDL_AllocPalette() => SDL_CreatePalette()
  • SDL_FreeFormat() => SDL_DestroyPixelFormat()
  • SDL_FreePalette() => SDL_DestroyPalette()
  • SDL_MasksToPixelFormatEnum() => SDL_GetPixelFormatEnumForMasks()
  • SDL_PixelFormatEnumToMasks() => SDL_GetMasksForPixelFormatEnum()

The following symbols have been renamed:

  • SDL_DISPLAYEVENT_DISCONNECTED => SDL_EVENT_DISPLAY_DISCONNECTED
  • SDL_DISPLAYEVENT_MOVED => SDL_EVENT_DISPLAY_MOVED
  • SDL_DISPLAYEVENT_ORIENTATION => SDL_EVENT_DISPLAY_ORIENTATION
  • SDL_WINDOWEVENT_CLOSE => SDL_EVENT_WINDOW_CLOSE_REQUESTED
  • SDL_WINDOWEVENT_DISPLAY_CHANGED => SDL_EVENT_WINDOW_DISPLAY_CHANGED
  • SDL_WINDOWEVENT_ENTER => SDL_EVENT_WINDOW_ENTER
  • SDL_WINDOWEVENT_EXPOSED => SDL_EVENT_WINDOW_EXPOSED
  • SDL_WINDOWEVENT_FOCUS_GAINED => SDL_EVENT_WINDOW_FOCUS_GAINED
  • SDL_WINDOWEVENT_FOCUS_LOST => SDL_EVENT_WINDOW_FOCUS_LOST
  • SDL_WINDOWEVENT_HIDDEN => SDL_EVENT_WINDOW_HIDDEN
  • SDL_WINDOWEVENT_HIT_TEST => SDL_EVENT_WINDOW_HIT_TEST
  • SDL_WINDOWEVENT_ICCPROF_CHANGED => SDL_EVENT_WINDOW_ICCPROF_CHANGED
  • SDL_WINDOWEVENT_LEAVE => SDL_EVENT_WINDOW_LEAVE
  • SDL_WINDOWEVENT_MAXIMIZED => SDL_EVENT_WINDOW_MAXIMIZED
  • SDL_WINDOWEVENT_MINIMIZED => SDL_EVENT_WINDOW_MINIMIZED
  • SDL_WINDOWEVENT_MOVED => SDL_EVENT_WINDOW_MOVED
  • SDL_WINDOWEVENT_RESIZED => SDL_EVENT_WINDOW_RESIZED
  • SDL_WINDOWEVENT_RESTORED => SDL_EVENT_WINDOW_RESTORED
  • SDL_WINDOWEVENT_SHOWN => SDL_EVENT_WINDOW_SHOWN
  • SDL_WINDOWEVENT_SIZE_CHANGED => SDL_EVENT_WINDOW_SIZE_CHANGED
  • SDL_WINDOWEVENT_TAKE_FOCUS => SDL_EVENT_WINDOW_TAKE_FOCUS

SDL_platform.h

The preprocessor symbol __MACOSX__ has been renamed __MACOS__, and __IPHONEOS__ has been renamed __IOS__

SDL_rect.h

The following functions have been renamed:

  • SDL_EncloseFPoints() => SDL_GetRectEnclosingPointsFloat()
  • SDL_EnclosePoints() => SDL_GetRectEnclosingPoints()
  • SDL_FRectEmpty() => SDL_RectEmptyFloat()
  • SDL_FRectEquals() => SDL_RectsEqualFloat()
  • SDL_FRectEqualsEpsilon() => SDL_RectsEqualEpsilon()
  • SDL_HasIntersection() => SDL_HasRectIntersection()
  • SDL_HasIntersectionF() => SDL_HasRectIntersectionFloat()
  • SDL_IntersectFRect() => SDL_GetRectIntersectionFloat()
  • SDL_IntersectFRectAndLine() => SDL_GetRectAndLineIntersectionFloat()
  • SDL_IntersectRect() => SDL_GetRectIntersection()
  • SDL_IntersectRectAndLine() => SDL_GetRectAndLineIntersection()
  • SDL_PointInFRect() => SDL_PointInRectFloat()
  • SDL_RectEquals() => SDL_RectsEqual()
  • SDL_UnionFRect() => SDL_GetRectUnionFloat()
  • SDL_UnionRect() => SDL_GetRectUnion()

SDL_render.h

SDL_GetRenderDriverInfo() has been removed, since most of the information it reported were estimates and could not be accurate before creating a renderer. Often times this function was used to figure out the index of a driver, so one would call it in a for-loop, looking for the driver named "opengl" or whatnot. SDL_GetRenderDriver() has been added for this functionality, which returns only the name of the driver.

Additionally, SDL_CreateRenderer()'s second argument is no longer an integer index, but a const char * representing a renderer's name; if you were just using a for-loop to find which index is the "opengl" or whatnot driver, you can just pass that string directly here, now. Passing NULL is the same as passing -1 here in SDL2, to signify you want SDL to decide for you.

The SDL_RENDERER_TARGETTEXTURE flag has been removed, all current renderers support target texture functionality.

When a renderer is created, it will automatically set the logical size to the size of the window in points. For high DPI displays, this will set up scaling from points to pixels. You can disable this scaling with:

    SDL_SetRenderLogicalPresentation(renderer, 0, 0, SDL_LOGICAL_PRESENTATION_DISABLED, SDL_SCALEMODE_NEAREST);

Mouse and touch events are no longer filtered to change their coordinates, instead you can call SDL_ConvertEventToRenderCoordinates() to explicitly map event coordinates into the rendering viewport.

SDL_RenderWindowToLogical() and SDL_RenderLogicalToWindow() have been renamed SDL_RenderCoordinatesFromWindow() and SDL_RenderCoordinatesToWindow() and take floating point coordinates in both directions.

The viewport, clipping state, and scale for render targets are now persistent and will remain set whenever they are active.

The following functions have been renamed:

  • SDL_GetRendererOutputSize() => SDL_GetCurrentRenderOutputSize()
  • SDL_RenderCopy() => SDL_RenderTexture()
  • SDL_RenderCopyEx() => SDL_RenderTextureRotated()
  • SDL_RenderCopyExF() => SDL_RenderTextureRotated()
  • SDL_RenderCopyF() => SDL_RenderTexture()
  • SDL_RenderDrawLine() => SDL_RenderLine()
  • SDL_RenderDrawLineF() => SDL_RenderLine()
  • SDL_RenderDrawLines() => SDL_RenderLines()
  • SDL_RenderDrawLinesF() => SDL_RenderLines()
  • SDL_RenderDrawPoint() => SDL_RenderPoint()
  • SDL_RenderDrawPointF() => SDL_RenderPoint()
  • SDL_RenderDrawPoints() => SDL_RenderPoints()
  • SDL_RenderDrawPointsF() => SDL_RenderPoints()
  • SDL_RenderDrawRect() => SDL_RenderRect()
  • SDL_RenderDrawRectF() => SDL_RenderRect()
  • SDL_RenderDrawRects() => SDL_RenderRects()
  • SDL_RenderDrawRectsF() => SDL_RenderRects()
  • SDL_RenderFillRectF() => SDL_RenderFillRect()
  • SDL_RenderFillRectsF() => SDL_RenderFillRects()
  • SDL_RenderGetClipRect() => SDL_GetRenderClipRect()
  • SDL_RenderGetIntegerScale() => SDL_GetRenderIntegerScale()
  • SDL_RenderGetLogicalSize() => SDL_GetRenderLogicalPresentation()
  • SDL_RenderGetMetalCommandEncoder() => SDL_GetRenderMetalCommandEncoder()
  • SDL_RenderGetMetalLayer() => SDL_GetRenderMetalLayer()
  • SDL_RenderGetScale() => SDL_GetRenderScale()
  • SDL_RenderGetViewport() => SDL_GetRenderViewport()
  • SDL_RenderGetWindow() => SDL_GetRenderWindow()
  • SDL_RenderIsClipEnabled() => SDL_RenderClipEnabled()
  • SDL_RenderLogicalToWindow() => SDL_RenderCoordinatesToWindow()
  • SDL_RenderSetClipRect() => SDL_SetRenderClipRect()
  • SDL_RenderSetIntegerScale() => SDL_SetRenderIntegerScale()
  • SDL_RenderSetLogicalSize() => SDL_SetRenderLogicalPresentation()
  • SDL_RenderSetScale() => SDL_SetRenderScale()
  • SDL_RenderSetVSync() => SDL_SetRenderVSync()
  • SDL_RenderSetViewport() => SDL_SetRenderViewport()
  • SDL_RenderWindowToLogical() => SDL_RenderCoordinatesFromWindow()

The following functions have been removed:

  • SDL_RenderGetIntegerScale()
  • SDL_RenderSetIntegerScale() - this is now explicit with SDL_LOGICAL_PRESENTATION_INTEGER_SCALE
  • SDL_RenderTargetSupported() - render targets are always supported

The following symbols have been renamed:

  • SDL_ScaleModeBest => SDL_SCALEMODE_BEST
  • SDL_ScaleModeLinear => SDL_SCALEMODE_LINEAR
  • SDL_ScaleModeNearest => SDL_SCALEMODE_NEAREST

SDL_rwops.h

The following symbols have been renamed:

  • RW_SEEK_CUR => SDL_RW_SEEK_CUR
  • RW_SEEK_END => SDL_RW_SEEK_END
  • RW_SEEK_SET => SDL_RW_SEEK_SET

SDL_RWread and SDL_RWwrite (and SDL_RWops::read, SDL_RWops::write) have a different function signature in SDL3.

Previously they looked more like stdio:

size_t SDL_RWread(SDL_RWops *context, void *ptr, size_t size, size_t maxnum);
size_t SDL_RWwrite(SDL_RWops *context, const void *ptr, size_t size, size_t maxnum);

But now they look more like POSIX:

size_t SDL_RWread(SDL_RWops *context, void *ptr, size_t size);
size_t SDL_RWwrite(SDL_RWops *context, const void *ptr, size_t size);

Code that used to look like this:

size_t custom_read(void *ptr, size_t size, size_t nitems, SDL_RWops *stream)
{
    return SDL_RWread(stream, ptr, size, nitems);
}

should be changed to:

size_t custom_read(void *ptr, size_t size, size_t nitems, SDL_RWops *stream)
{
    if (size > 0 && nitems > 0) {
        return SDL_RWread(stream, ptr, size * nitems) / size;
    }
    return 0;
}

SDL_RWFromFP has been removed from the API, due to issues when the SDL library uses a different C runtime from the application.

You can implement this in your own code easily:

#include <stdio.h>


static Sint64 SDLCALL stdio_seek(SDL_RWops *context, Sint64 offset, int whence)
{
    int stdiowhence;

    switch (whence) {
    case SDL_RW_SEEK_SET:
        stdiowhence = SEEK_SET;
        break;
    case SDL_RW_SEEK_CUR:
        stdiowhence = SEEK_CUR;
        break;
    case SDL_RW_SEEK_END:
        stdiowhence = SEEK_END;
        break;
    default:
        return SDL_SetError("Unknown value for 'whence'");
    }

    if (fseek((FILE *)context->hidden.stdio.fp, (fseek_off_t)offset, stdiowhence) == 0) {
        Sint64 pos = ftell((FILE *)context->hidden.stdio.fp);
        if (pos < 0) {
            return SDL_SetError("Couldn't get stream offset");
        }
        return pos;
    }
    return SDL_Error(SDL_EFSEEK);
}

static size_t SDLCALL stdio_read(SDL_RWops *context, void *ptr, size_t size)
{
    size_t bytes;

    bytes = fread(ptr, 1, size, (FILE *)context->hidden.stdio.fp);
    if (bytes == 0 && ferror((FILE *)context->hidden.stdio.fp)) {
        SDL_Error(SDL_EFREAD);
    }
    return bytes;
}

static size_t SDLCALL stdio_write(SDL_RWops *context, const void *ptr, size_t size)
{
    size_t bytes;

    bytes = fwrite(ptr, 1, size, (FILE *)context->hidden.stdio.fp);
    if (bytes == 0 && ferror((FILE *)context->hidden.stdio.fp)) {
        SDL_Error(SDL_EFWRITE);
    }
    return bytes;
}

static int SDLCALL stdio_close(SDL_RWops *context)
{
    int status = 0;
    if (context->hidden.stdio.autoclose) {
        if (fclose((FILE *)context->hidden.stdio.fp) != 0) {
            status = SDL_Error(SDL_EFWRITE);
        }
    }
    SDL_DestroyRW(context);
    return status;
}

SDL_RWops *SDL_RWFromFP(void *fp, SDL_bool autoclose)
{
    SDL_RWops *rwops = NULL;

    rwops = SDL_CreateRW();
    if (rwops != NULL) {
        rwops->seek = stdio_seek;
        rwops->read = stdio_read;
        rwops->write = stdio_write;
        rwops->close = stdio_close;
        rwops->hidden.stdio.fp = fp;
        rwops->hidden.stdio.autoclose = autoclose;
        rwops->type = SDL_RWOPS_STDFILE;
    }
    return rwops;
}

The functions SDL_ReadU8(), SDL_ReadU16LE(), SDL_ReadU16BE(), SDL_ReadU32LE(), SDL_ReadU32BE(), SDL_ReadU64LE(), and SDL_ReadU64BE() now return SDL_TRUE if the read succeeded and SDL_FALSE if it didn't, and store the data in a pointer passed in as a parameter.

The following functions have been renamed:

  • SDL_AllocRW() => SDL_CreateRW()
  • SDL_FreeRW() => SDL_DestroyRW()
  • SDL_ReadBE16() => SDL_ReadU16BE()
  • SDL_ReadBE32() => SDL_ReadU32BE()
  • SDL_ReadBE64() => SDL_ReadU64BE()
  • SDL_ReadLE16() => SDL_ReadU16LE()
  • SDL_ReadLE32() => SDL_ReadU32LE()
  • SDL_ReadLE64() => SDL_ReadU64LE()
  • SDL_WriteBE16() => SDL_WriteU16BE()
  • SDL_WriteBE32() => SDL_WriteU32BE()
  • SDL_WriteBE64() => SDL_WriteU64BE()
  • SDL_WriteLE16() => SDL_WriteU16LE()
  • SDL_WriteLE32() => SDL_WriteU32LE()
  • SDL_WriteLE64() => SDL_WriteU64LE()

SDL_sensor.h

SDL_SensorID has changed from Sint32 to Uint32, with an invalid ID being 0.

Rather than iterating over sensors using device index, there is a new function SDL_GetSensors() to get the current list of sensors, and new functions to get information about sensors from their instance ID:

{
    if (SDL_InitSubSystem(SDL_INIT_SENSOR) == 0) {
        int i, num_sensors;
        SDL_SensorID *sensors = SDL_GetSensors(&num_sensors);
        if (sensors) {
            for (i = 0; i < num_sensors; ++i) {
                SDL_Log("Sensor %" SDL_PRIu32 ": %s, type %d, platform type %d\n",
                        sensors[i],
                        SDL_GetSensorInstanceName(sensors[i]),
                        SDL_GetSensorInstanceType(sensors[i]),
                        SDL_GetSensorInstanceNonPortableType(sensors[i]));
            }
            SDL_free(sensors);
        }
        SDL_QuitSubSystem(SDL_INIT_SENSOR);
    }
}

Removed SDL_SensorGetDataWithTimestamp(), if you want timestamps for the sensor data, you should use the sensor_timestamp member of SDL_EVENT_SENSOR_UPDATE events.

The following functions have been renamed:

  • SDL_SensorClose() => SDL_CloseSensor()
  • SDL_SensorFromInstanceID() => SDL_GetSensorFromInstanceID()
  • SDL_SensorGetData() => SDL_GetSensorData()
  • SDL_SensorGetInstanceID() => SDL_GetSensorInstanceID()
  • SDL_SensorGetName() => SDL_GetSensorName()
  • SDL_SensorGetNonPortableType() => SDL_GetSensorNonPortableType()
  • SDL_SensorGetType() => SDL_GetSensorType()
  • SDL_SensorOpen() => SDL_OpenSensor()
  • SDL_SensorUpdate() => SDL_UpdateSensors()

The following functions have been removed:

  • SDL_LockSensors()
  • SDL_NumSensors() - replaced with SDL_GetSensors()
  • SDL_SensorGetDeviceInstanceID()
  • SDL_SensorGetDeviceName() - replaced with SDL_GetSensorInstanceName()
  • SDL_SensorGetDeviceNonPortableType() - replaced with SDL_GetSensorInstanceNonPortableType()
  • SDL_SensorGetDeviceType() - replaced with SDL_GetSensorInstanceType()
  • SDL_UnlockSensors()

SDL_stdinc.h

The standard C headers like stdio.h and stdlib.h are no longer included, you should include them directly in your project if you use non-SDL C runtime functions. M_PI is no longer defined in SDL_stdinc.h, you can use the new symbols SDL_PI_D (double) and SDL_PI_F (float) instead.

The following functions have been renamed:

  • SDL_strtokr() => SDL_strtok_r()

SDL_surface.h

Removed unused 'flags' parameter from SDL_ConvertSurface and SDL_ConvertSurfaceFormat.

SDL_CreateRGBSurface() and SDL_CreateRGBSurfaceWithFormat() have been combined into a new function SDL_CreateSurface(). SDL_CreateRGBSurfaceFrom() and SDL_CreateRGBSurfaceWithFormatFrom() have been combined into a new function SDL_CreateSurfaceFrom().

You can implement the old functions in your own code easily:

SDL_Surface *SDL_CreateRGBSurface(Uint32 flags, int width, int height, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
{
    return SDL_CreateSurface(width, height,
            SDL_GetPixelFormatEnumForMasks(depth, Rmask, Gmask, Bmask, Amask));
}

SDL_Surface *SDL_CreateRGBSurfaceWithFormat(Uint32 flags, int width, int height, int depth, Uint32 format)
{
    return SDL_CreateSurface(width, height, format);
}

SDL_Surface *SDL_CreateRGBSurfaceFrom(void *pixels, int width, int height, int depth, int pitch, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
{
    return SDL_CreateSurfaceFrom(pixels, width, height, pitch,
            SDL_GetPixelFormatEnumForMasks(depth, Rmask, Gmask, Bmask, Amask));
}

SDL_Surface *SDL_CreateRGBSurfaceWithFormatFrom(void *pixels, int width, int height, int depth, int pitch, Uint32 format)
{
    return SDL_CreateSurfaceFrom(pixels, width, height, pitch, format);
}

But if you're migrating your code which uses masks, you probably have a format in mind, possibly one of these:

// Various mask (R, G, B, A) and their corresponding format:
0xFF000000 0x00FF0000 0x0000FF00 0x000000FF => SDL_PIXELFORMAT_RGBA8888
0x00FF0000 0x0000FF00 0x000000FF 0xFF000000 => SDL_PIXELFORMAT_ARGB8888
0x0000FF00 0x00FF0000 0xFF000000 0x000000FF => SDL_PIXELFORMAT_BGRA8888
0x000000FF 0x0000FF00 0x00FF0000 0xFF000000 => SDL_PIXELFORMAT_ABGR8888
0x0000F800 0x000007E0 0x0000001F 0x00000000 => SDL_PIXELFORMAT_RGB565

The following functions have been renamed:

  • SDL_FillRect() => SDL_FillSurfaceRect()
  • SDL_FillRects() => SDL_FillSurfaceRects()
  • SDL_FreeSurface() => SDL_DestroySurface()
  • SDL_GetClipRect() => SDL_GetSurfaceClipRect()
  • SDL_GetColorKey() => SDL_GetSurfaceColorKey()
  • SDL_HasColorKey() => SDL_SurfaceHasColorKey()
  • SDL_HasSurfaceRLE() => SDL_SurfaceHasRLE()
  • SDL_LowerBlit() => SDL_BlitSurfaceUnchecked()
  • SDL_LowerBlitScaled() => SDL_BlitSurfaceUncheckedScaled()
  • SDL_SetClipRect() => SDL_SetSurfaceClipRect()
  • SDL_SetColorKey() => SDL_SetSurfaceColorKey()
  • SDL_UpperBlit() => SDL_BlitSurface()
  • SDL_UpperBlitScaled() => SDL_BlitSurfaceScaled()

SDL_system.h

SDL_AndroidGetExternalStorageState() takes the state as an output parameter and returns 0 if the function succeeds or a negative error code if there was an error.

The following functions have been renamed:

  • SDL_RenderGetD3D11Device() => SDL_GetRenderD3D11Device()
  • SDL_RenderGetD3D9Device() => SDL_GetRenderD3D9Device()

SDL_syswm.h

The structures in this file are versioned separately from the rest of SDL, allowing better backwards compatibility and limited forwards compatibility with your application. Instead of calling SDL_VERSION(&info.version) before calling SDL_GetWindowWMInfo(), you pass the version in explicitly as SDL_SYSWM_CURRENT_VERSION so SDL knows what fields you expect to be filled out.

SDL_GetWindowWMInfo

This function now returns a standard int result instead of SDL_bool, returning 0 if the function succeeds or a negative error code if there was an error. You should also pass SDL_SYSWM_CURRENT_VERSION as the new third version parameter. The version member of the info structure will be filled in with the version of data that is returned, the minimum of the version you requested and the version supported by the runtime SDL library.

SDL_thread.h

The following functions have been renamed:

  • SDL_TLSCleanup() => SDL_CleanupTLS()
  • SDL_TLSCreate() => SDL_CreateTLS()
  • SDL_TLSGet() => SDL_GetTLS()
  • SDL_TLSSet() => SDL_SetTLS()

SDL_timer.h

SDL_GetTicks() now returns a 64-bit value. Instead of using the SDL_TICKS_PASSED macro, you can directly compare tick values, e.g.

Uint32 deadline = SDL_GetTicks() + 1000;
...
if (SDL_TICKS_PASSED(SDL_GetTicks(), deadline)) {
    ...
}

becomes:

Uint64 deadline = SDL_GetTicks() + 1000
...
if (SDL_GetTicks() >= deadline) {
    ...
}

If you were using this macro for other things besides SDL ticks values, you can define it in your own code as:

#define SDL_TICKS_PASSED(A, B)  ((Sint32)((B) - (A)) <= 0)

SDL_touch.h

SDL_GetNumTouchFingers() returns a negative error code if there was an error.

SDL_version.h

SDL_GetRevisionNumber() has been removed from the API, it always returned 0 in SDL 2.0.

SDL_video.h

SDL_VideoInit() and SDL_VideoQuit() have been removed. Instead you can call SDL_InitSubSystem() and SDL_QuitSubSystem() with SDL_INIT_VIDEO, which will properly refcount the subsystems. You can choose a specific video driver using SDL_VIDEO_DRIVER hint.

Rather than iterating over displays using display index, there is a new function SDL_GetDisplays() to get the current list of displays, and functions which used to take a display index now take SDL_DisplayID, with an invalid ID being 0.

{
    if (SDL_InitSubSystem(SDL_INIT_VIDEO) == 0) {
        int i, num_displays = 0;
        SDL_DisplayID *displays = SDL_GetDisplays(&num_displays);
        if (displays) {
            for (i = 0; i < num_displays; ++i) {
                SDL_DisplayID instance_id = displays[i];
                const char *name = SDL_GetDisplayName(instance_id);

                SDL_Log("Display %" SDL_PRIu32 ": %s\n", instance_id, name ? name : "Unknown");
            }
            SDL_free(displays);
        }
        SDL_QuitSubSystem(SDL_INIT_VIDEO);
    }
}

SDL_CreateWindow() has been simplified and no longer takes a window position. You can use SDL_CreateWindowWithPosition() if you need to set the window position when creating it.

The SDL_WINDOWPOS_UNDEFINED_DISPLAY() and SDL_WINDOWPOS_CENTERED_DISPLAY() macros take a display ID instead of display index. The display ID 0 has a special meaning in this case, and is used to indicate the primary display.

The SDL_WINDOW_SHOWN flag has been removed. Windows are shown by default and can be created hidden by using the SDL_WINDOW_HIDDEN flag.

The SDL_WINDOW_SKIP_TASKBAR flag has been replaced by the SDL_WINDOW_UTILITY flag, which has the same functionality.

SDL_DisplayMode now includes the pixel density which can be greater than 1.0 for display modes that have a higher pixel size than the mode size. You should use SDL_GetWindowSizeInPixels() to get the actual pixel size of the window back buffer.

The refresh rate in SDL_DisplayMode is now a float.

Rather than iterating over display modes using an index, there is a new function SDL_GetFullscreenDisplayModes() to get the list of available fullscreen modes on a display.

{
    SDL_DisplayID display = SDL_GetPrimaryDisplay();
    int num_modes = 0;
    SDL_DisplayMode **modes = SDL_GetFullscreenDisplayModes(display, &num_modes);
    if (modes) {
        for (i = 0; i < num_modes; ++i) {
            SDL_DisplayMode *mode = modes[i];
            SDL_Log("Display %" SDL_PRIu32 " mode %d: %dx%d@%gx %gHz\n",
                    display, i, mode->w, mode->h, mode->pixel_density, mode->refresh_rate);
        }
        SDL_free(modes);
    }
}

SDL_GetDesktopDisplayMode() and SDL_GetCurrentDisplayMode() return pointers to display modes rather than filling in application memory.

Windows now have an explicit fullscreen mode that is set, using SDL_SetWindowFullscreenMode(). The fullscreen mode for a window can be queried with SDL_GetWindowFullscreenMode(), which returns a pointer to the mode, or NULL if the window will be fullscreen desktop. SDL_SetWindowFullscreen() just takes a boolean value, setting the correct fullscreen state based on the selected mode.

SDL_WINDOW_FULLSCREEN_DESKTOP has been removed, and you can call SDL_GetWindowFullscreenMode() to see whether an exclusive fullscreen mode will be used or the fullscreen desktop mode will be used when the window is fullscreen.

SDL_SetWindowBrightness and SDL_SetWindowGammaRamp have been removed from the API, because they interact poorly with modern operating systems and aren't able to limit their effects to the SDL window.

Programs which have access to shaders can implement more robust versions of those functions using custom shader code rendered as a post-process effect.

Removed SDL_GL_CONTEXT_EGL from OpenGL configuration attributes. You can instead use SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);

SDL_GL_GetProcAddress() and SDL_EGL_GetProcAddress() now return SDL_FunctionPointer instead of void *, and should be cast to the appropriate function type. You can define SDL_FUNCTION_POINTER_IS_VOID_POINTER in your project to restore the previous behavior.

SDL_GL_SwapWindow() returns 0 if the function succeeds or a negative error code if there was an error.

SDL_GL_GetSwapInterval() takes the interval as an output parameter and returns 0 if the function succeeds or a negative error code if there was an error.

SDL_GL_GetDrawableSize() has been removed. SDL_GetWindowSizeInPixels() can be used in its place.

The SDL_WINDOW_TOOLTIP and SDL_WINDOW_POPUP_MENU window flags are now supported on Windows, Mac (Cocoa), X11, and Wayland. Creating windows with these flags must happen via the SDL_CreatePopupWindow() function. This function requires passing in the handle to a valid parent window for the popup, and the popup window is positioned relative to the parent.

The following functions have been renamed:

  • SDL_GetClosestDisplayMode() => SDL_GetClosestFullscreenDisplayMode()
  • SDL_GetDisplayOrientation() => SDL_GetCurrentDisplayOrientation()
  • SDL_GetPointDisplayIndex() => SDL_GetDisplayForPoint()
  • SDL_GetRectDisplayIndex() => SDL_GetDisplayForRect()
  • SDL_GetWindowDisplayIndex() => SDL_GetDisplayForWindow()
  • SDL_GetWindowDisplayMode() => SDL_GetWindowFullscreenMode()
  • SDL_IsScreenSaverEnabled() => SDL_ScreenSaverEnabled()
  • SDL_SetWindowDisplayMode() => SDL_SetWindowFullscreenMode()

The following functions have been removed:

  • SDL_GetClosestFullscreenDisplayMode()
  • SDL_GetDisplayDPI() - not reliable across platforms, approximately replaced by multiplying display_scale in the structure returned by SDL_GetDesktopDisplayMode() times 160 on iPhone and Android, and 96 on other platforms.
  • SDL_GetDisplayMode()
  • SDL_GetNumDisplayModes() - replaced with SDL_GetFullscreenDisplayModes()
  • SDL_GetNumVideoDisplays() - replaced with SDL_GetDisplays()

SDL_Window id type is named SDL_WindowID

The following symbols have been renamed:

  • SDL_WINDOW_ALLOW_HIGHDPI => SDL_WINDOW_HIGH_PIXEL_DENSITY
  • SDL_WINDOW_INPUT_GRABBED => SDL_WINDOW_MOUSE_GRABBED

SDL_vulkan.h

SDL_Vulkan_GetInstanceExtensions() no longer takes a window parameter.

SDL_Vulkan_GetVkGetInstanceProcAddr() now returns SDL_FunctionPointer instead of void *, and should be cast to PFN_vkGetInstanceProcAddr.

SDL_Vulkan_GetDrawableSize() has been removed. SDL_GetWindowSizeInPixels() can be used in its place.