update sdl Merge commit '4d48f9d23713d94b861da7b5d41baf2a41334994'

This commit is contained in:
2023-08-12 20:17:29 +02:00
215 changed files with 12672 additions and 17114 deletions

View File

@ -35,6 +35,14 @@ cmake --install ~/build --prefix /usr/local # '--install' requires CMake
This will install SDL to /usr/local.
### Building SDL tests
You can build the SDL test programs by adding `-DSDL_TESTS=ON` to the first cmake command above:
```sh
cmake -S ~/sdl -B ~/build -DSDL_TEST_LIBRARY=ON -DSDL_TESTS=ON
```
and then building normally. In this example, the test programs will be built and can be run from `~/build/tests/`.
## Including SDL in your project
SDL can be included in your project in 2 major ways:
@ -197,6 +205,22 @@ To use, set the following CMake variables when running CMake's configuration sta
cmake ~/sdl -DCMAKE_TOOLCHAIN_FILE=~/sdl/build-scripts/cmake-toolchain-qnx-aarch64le.cmake -DSDL_X11=0
```
## SDL-specific CMake options
SDL can be customized through (platform-specific) CMake options.
The following table shows generic options that are available for most platforms.
At the end of SDL CMake configuration, a table shows all CMake options along with its detected value.
| CMake option | Valid values | Description |
|-------------------------------|--------------|-----------------------------------------------------------------------------------------------------|
| `-DSDL_SHARED=` | `ON`/`OFF` | Build SDL shared library (not all platforms support this) (`libSDL3.so`/`libSDL3.dylib`/`SDL3.dll`) |
| `-DSDL_STATIC=` | `ON`/`OFF` | Build SDL static library (`libSDL3.a`/`SDL3-static.lib`) |
| `-DSDL_TEST_LIBRARY=` | `ON`/`OFF` | Build SDL test library (`libSDL3_test.a`/`SDL3_test.lib`) |
| `-DSDL_TESTS=` | `ON`/`OFF` | Build SDL test programs (**requires `-DSDL_TEST_LIBRARY=ON`**) |
| `-DSDL_DISABLE_INSTALL=` | `ON`/`OFF` | Don't create a SDL install target |
| `-DSDL_DISABLE_INSTALL_DOCS=` | `ON`/`OFF` | Don't install the SDL documentation |
| `-DSDL_INSTALL_TESTS=` | `ON`/`OFF` | Install the SDL test programs |
## Help, it doesn't work!
Below, a SDL3 CMake project can be found that builds 99.9% of time (assuming you have internet connectivity).

View File

@ -53,13 +53,128 @@ The following structures have been renamed:
## 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.
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.
If your app depends on the callback method, there is a similar approach you can take. But first, this is the new approach:
In SDL2, you might have done something like this to play audio:
```c
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:
```c
/* ...somewhere near startup... */
SDL_AudioSpec spec = { SDL_AUDIO_S16, 2, 44100 };
SDL_AudioDeviceID my_audio_device = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_OUTPUT, &spec);
SDL_AudioSteam *stream = SDL_CreateAndBindAudioStream(my_audio_device, &spec);
/* ...in your main loop... */
/* calculate a little more audio into `buf`, add it to `stream` */
SDL_PutAudioStreamData(stream, buf, buflen);
```
If you absolutely require the callback method, SDL_AudioStreams can use a callback whenever more data is to be read from them, which can be used to simulate SDL2 semantics:
```c
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... */
SDL_AudioSpec spec = { SDL_AUDIO_S16, 2, 44100 };
SDL_AudioDeviceID my_audio_device = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_OUTPUT, &spec);
SDL_AudioSteam *stream = SDL_CreateAndBindAudioStream(my_audio_device, &spec);
SDL_SetAudioStreamGetCallback(stream, MyAudioCallback);
/* MyAudioCallback will be called whenever the device requests more audio data. */
```
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_PauseAudioDevice() is only used to pause audio playback. Use SDL_PlayAudioDevice() to start playing audio.
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.
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 is a new function, SDL_GetAudioDevices(), to get the current list of devices, and new functions to get information about devices from their instance ID:
```c
{
if (SDL_InitSubSystem(SDL_INIT_AUDIO) == 0) {
int i, num_devices;
SDL_AudioDeviceID *devices = SDL_GetAudioDevices(/*iscapture=*/SDL_FALSE, &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_IsAudioDevicePaused().
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_AudioCVT interface is removed, SDL_AudioStream interface or SDL_ConvertAudioSamples() helper function can be used.
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:
```c
@ -75,8 +190,9 @@ should be changed to:
```c
Uint8 *dst_data = NULL;
int dst_len = 0;
if (SDL_ConvertAudioSamples(src_format, src_channels, src_rate, src_data, src_len
dst_format, dst_channels, dst_rate, &dst_data, &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);
@ -103,9 +219,13 @@ If you need to convert U16 audio data to a still-supported format at runtime, th
}
```
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_AudioStreamPut in SDL2. The way you use an AudioStream is roughly the same, just be aware that the workload moved to a different phase.
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()
@ -118,17 +238,25 @@ The following functions have been renamed:
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()
Use the SDL_AudioDevice functions instead.
* SDL_QueueAudio()
* SDL_DequeueAudio()
* SDL_ClearAudioQueue()
* SDL_GetQueuedAudioSize()
The following symbols have been renamed:
* AUDIO_F32 => SDL_AUDIO_F32
@ -380,10 +508,10 @@ The following symbols have been renamed:
* 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_PADDLE1
* SDL_CONTROLLER_BUTTON_PADDLE2 => SDL_GAMEPAD_BUTTON_PADDLE2
* SDL_CONTROLLER_BUTTON_PADDLE3 => SDL_GAMEPAD_BUTTON_PADDLE3
* SDL_CONTROLLER_BUTTON_PADDLE4 => SDL_GAMEPAD_BUTTON_PADDLE4
* 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
@ -698,6 +826,8 @@ which index is the "opengl" or whatnot driver, you can just pass that string dir
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:
@ -780,33 +910,28 @@ size_t SDL_RWwrite(SDL_RWops *context, const void *ptr, size_t size, size_t maxn
But now they look more like POSIX:
```c
Sint64 SDL_RWread(SDL_RWops *context, void *ptr, Sint64 size);
Sint64 SDL_RWwrite(SDL_RWops *context, const void *ptr, Sint64 size);
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);
```
SDL_RWread() previously returned 0 at end of file or other error. Now it returns the number of bytes read, 0 for end of file, -1 for another error, or -2 for data not ready (in the case of a non-blocking context).
Code that used to look like this:
```
size_t custom_read(void *ptr, size_t size, size_t nitems, SDL_RWops *stream)
{
return (size_t)SDL_RWread(stream, ptr, size, nitems);
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)
{
Sint64 amount = SDL_RWread(stream, ptr, size * nitems);
if (amount <= 0) {
return 0;
if (size > 0 && nitems > 0) {
return SDL_RWread(stream, ptr, size * nitems) / size;
}
return (size_t)(amount / size);
return 0;
}
```
Similarly, SDL_RWwrite() can return -2 for data not ready in the case of a non-blocking context. There is currently no way to create a non-blocking context, we have simply defined the semantic for your own custom SDL_RWops object.
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:
@ -814,23 +939,7 @@ You can implement this in your own code easily:
#include <stdio.h>
static Sint64 SDLCALL
stdio_size(SDL_RWops * context)
{
Sint64 pos, size;
pos = SDL_RWseek(context, 0, SDL_RW_SEEK_CUR);
if (pos < 0) {
return -1;
}
size = SDL_RWseek(context, 0, SDL_RW_SEEK_END);
SDL_RWseek(context, pos, SDL_RW_SEEK_SET);
return size;
}
static Sint64 SDLCALL
stdio_seek(SDL_RWops * context, Sint64 offset, int whence)
static Sint64 SDLCALL stdio_seek(SDL_RWops *context, Sint64 offset, int whence)
{
int stdiowhence;
@ -858,54 +967,46 @@ stdio_seek(SDL_RWops * context, Sint64 offset, int whence)
return SDL_Error(SDL_EFSEEK);
}
static Sint64 SDLCALL
stdio_read(SDL_RWops * context, void *ptr, Sint64 size)
static size_t SDLCALL stdio_read(SDL_RWops *context, void *ptr, size_t size)
{
size_t nread;
size_t bytes;
nread = fread(ptr, 1, (size_t) size, (FILE *)context->hidden.stdio.fp);
if (nread == 0 && ferror((FILE *)context->hidden.stdio.fp)) {
return SDL_Error(SDL_EFREAD);
bytes = fread(ptr, 1, size, (FILE *)context->hidden.stdio.fp);
if (bytes == 0 && ferror((FILE *)context->hidden.stdio.fp)) {
SDL_Error(SDL_EFREAD);
}
return (Sint64) nread;
return bytes;
}
static Sint64 SDLCALL
stdio_write(SDL_RWops * context, const void *ptr, Sint64 size)
static size_t SDLCALL stdio_write(SDL_RWops *context, const void *ptr, size_t size)
{
size_t nwrote;
size_t bytes;
nwrote = fwrite(ptr, 1, (size_t) size, (FILE *)context->hidden.stdio.fp);
if (nwrote == 0 && ferror((FILE *)context->hidden.stdio.fp)) {
return SDL_Error(SDL_EFWRITE);
bytes = fwrite(ptr, 1, size, (FILE *)context->hidden.stdio.fp);
if (bytes == 0 && ferror((FILE *)context->hidden.stdio.fp)) {
SDL_Error(SDL_EFWRITE);
}
return (Sint64) nwrote;
return bytes;
}
static int SDLCALL
stdio_close(SDL_RWops * context)
static int SDLCALL stdio_close(SDL_RWops *context)
{
int status = 0;
if (context) {
if (context->hidden.stdio.autoclose) {
/* WARNING: Check the return value here! */
if (fclose((FILE *)context->hidden.stdio.fp) != 0) {
status = SDL_Error(SDL_EFWRITE);
}
if (context->hidden.stdio.autoclose) {
if (fclose((FILE *)context->hidden.stdio.fp) != 0) {
status = SDL_Error(SDL_EFWRITE);
}
SDL_DestroyRW(context);
}
SDL_DestroyRW(context);
return status;
}
SDL_RWops *
SDL_RWFromFP(void *fp, SDL_bool autoclose)
SDL_RWops *SDL_RWFromFP(void *fp, SDL_bool autoclose)
{
SDL_RWops *rwops = NULL;
rwops = SDL_CreateRW();
if (rwops != NULL) {
rwops->size = stdio_size;
rwops->seek = stdio_seek;
rwops->read = stdio_read;
rwops->write = stdio_write;
@ -918,10 +1019,23 @@ SDL_RWFromFP(void *fp, SDL_bool autoclose)
}
```
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