Skip to content

Commit 75a0440

Browse files
committed
Removed temporary memory from the API
It was intended to make the API easier to use, but various automatic garbage collection all had flaws, and making the application periodically clean up temporary memory added cognitive load to using the API, and in many cases was it was difficult to restructure threaded code to handle this. So, we're largely going back to the original system, where the API returns allocated results and you free them. In addition, to solve the problems we originally wanted temporary memory for: * Short strings with a finite count, like device names, get stored in a per-thread string pool. * Events continue to use temporary memory internally, which is cleaned up on the next event processing cycle.
1 parent 21411c6 commit 75a0440

File tree

100 files changed

+721
-837
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

100 files changed

+721
-837
lines changed

docs/README-migration.md

+13-25
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,9 @@ Rather than iterating over audio devices using a device index, there are new fun
158158
if (devices) {
159159
for (i = 0; i < num_devices; ++i) {
160160
SDL_AudioDeviceID instance_id = devices[i];
161-
const char *name = SDL_GetAudioDeviceName(instance_id);
162-
SDL_Log("AudioDevice %" SDL_PRIu32 ": %s\n", instance_id, name);
161+
SDL_Log("AudioDevice %" SDL_PRIu32 ": %s\n", instance_id, SDL_GetAudioDeviceName(instance_id));
163162
}
163+
SDL_free(devices);
164164
}
165165
SDL_QuitSubSystem(SDL_INIT_AUDIO);
166166
}
@@ -298,10 +298,6 @@ The following symbols have been renamed:
298298
The following symbols have been removed:
299299
* SDL_MIX_MAXVOLUME - mixer volume is now a float between 0.0 and 1.0
300300
301-
## SDL_clipboard.h
302-
303-
SDL_GetClipboardText() and SDL_GetPrimarySelectionText() return a const pointer to temporary memory, which does not need to be freed. You can use SDL_ClaimTemporaryMemory() to convert it to a non-const pointer that should be freed when you're done with it.
304-
305301
## SDL_cpuinfo.h
306302
307303
The intrinsics headers (mmintrin.h, etc.) have been moved to `<SDL3/SDL_intrin.h>` and are no longer automatically included in SDL.h.
@@ -458,10 +454,6 @@ The following functions have been removed:
458454
The following enums have been renamed:
459455
* SDL_eventaction => SDL_EventAction
460456

461-
## SDL_filesystem.h
462-
463-
SDL_GetBasePath() and SDL_GetPrefPath() return a const pointer to temporary memory, which does not need to be freed. You can use SDL_ClaimTemporaryMemory() to convert it to a non-const pointer that should be freed when you're done with it.
464-
465457
## SDL_gamecontroller.h
466458

467459
SDL_gamecontroller.h has been renamed SDL_gamepad.h, and all APIs have been renamed to match.
@@ -710,15 +702,13 @@ Rather than iterating over haptic devices using device index, there is a new fun
710702
{
711703
if (SDL_InitSubSystem(SDL_INIT_HAPTIC) == 0) {
712704
int i, num_haptics;
713-
const SDL_HapticID *haptics = SDL_GetHaptics(&num_haptics);
705+
SDL_HapticID *haptics = SDL_GetHaptics(&num_haptics);
714706
if (haptics) {
715707
for (i = 0; i < num_haptics; ++i) {
716708
SDL_HapticID instance_id = haptics[i];
717-
const char *name = SDL_GetHapticNameForID(instance_id);
718-
719-
SDL_Log("Haptic %" SDL_PRIu32 ": %s\n",
720-
instance_id, name ? name : "Unknown");
709+
SDL_Log("Haptic %" SDL_PRIu32 ": %s\n", instance_id, SDL_GetHapticNameForID(instance_id));
721710
}
711+
SDL_free(haptics);
722712
}
723713
SDL_QuitSubSystem(SDL_INIT_HAPTIC);
724714
}
@@ -840,7 +830,7 @@ Rather than iterating over joysticks using device index, there is a new function
840830
{
841831
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == 0) {
842832
int i, num_joysticks;
843-
const SDL_JoystickID *joysticks = SDL_GetJoysticks(&num_joysticks);
833+
SDL_JoystickID *joysticks = SDL_GetJoysticks(&num_joysticks);
844834
if (joysticks) {
845835
for (i = 0; i < num_joysticks; ++i) {
846836
SDL_JoystickID instance_id = joysticks[i];
@@ -850,6 +840,7 @@ Rather than iterating over joysticks using device index, there is a new function
850840
SDL_Log("Joystick %" SDL_PRIu32 ": %s%s%s VID 0x%.4x, PID 0x%.4x\n",
851841
instance_id, name ? name : "Unknown", path ? ", " : "", path ? path : "", SDL_GetJoystickVendorForID(instance_id), SDL_GetJoystickProductForID(instance_id));
852842
}
843+
SDL_free(joysticks);
853844
}
854845
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
855846
}
@@ -1034,10 +1025,6 @@ The following symbols have been renamed:
10341025

10351026
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.
10361027

1037-
## SDL_locale.h
1038-
1039-
SDL_GetPreferredLocales() returns a const array of locale pointers, which does not need to be freed. You can use SDL_ClaimTemporaryMemory() to convert it to a non-const pointer that should be freed when you're done with it.
1040-
10411028
## SDL_log.h
10421029

10431030
The following macros have been removed:
@@ -1588,7 +1575,7 @@ Rather than iterating over sensors using device index, there is a new function S
15881575
{
15891576
if (SDL_InitSubSystem(SDL_INIT_SENSOR) == 0) {
15901577
int i, num_sensors;
1591-
const SDL_SensorID *sensors = SDL_GetSensors(&num_sensors);
1578+
SDL_SensorID *sensors = SDL_GetSensors(&num_sensors);
15921579
if (sensors) {
15931580
for (i = 0; i < num_sensors; ++i) {
15941581
SDL_Log("Sensor %" SDL_PRIu32 ": %s, type %d, platform type %d\n",
@@ -1597,6 +1584,7 @@ Rather than iterating over sensors using device index, there is a new function S
15971584
SDL_GetSensorTypeForID(sensors[i]),
15981585
SDL_GetSensorNonPortableTypeForID(sensors[i]));
15991586
}
1587+
SDL_free(sensors);
16001588
}
16011589
SDL_QuitSubSystem(SDL_INIT_SENSOR);
16021590
}
@@ -1996,14 +1984,15 @@ Rather than iterating over displays using display index, there is a new function
19961984
{
19971985
if (SDL_InitSubSystem(SDL_INIT_VIDEO) == 0) {
19981986
int i, num_displays = 0;
1999-
const SDL_DisplayID *displays = SDL_GetDisplays(&num_displays);
1987+
SDL_DisplayID *displays = SDL_GetDisplays(&num_displays);
20001988
if (displays) {
20011989
for (i = 0; i < num_displays; ++i) {
20021990
SDL_DisplayID instance_id = displays[i];
20031991
const char *name = SDL_GetDisplayName(instance_id);
20041992
20051993
SDL_Log("Display %" SDL_PRIu32 ": %s\n", instance_id, name ? name : "Unknown");
20061994
}
1995+
SDL_free(displays);
20071996
}
20081997
SDL_QuitSubSystem(SDL_INIT_VIDEO);
20091998
}
@@ -2041,13 +2030,14 @@ Rather than iterating over display modes using an index, there is a new function
20412030
{
20422031
SDL_DisplayID display = SDL_GetPrimaryDisplay();
20432032
int num_modes = 0;
2044-
const SDL_DisplayMode * const *modes = SDL_GetFullscreenDisplayModes(display, &num_modes);
2033+
SDL_DisplayMode **modes = SDL_GetFullscreenDisplayModes(display, &num_modes);
20452034
if (modes) {
20462035
for (i = 0; i < num_modes; ++i) {
20472036
SDL_DisplayMode *mode = modes[i];
20482037
SDL_Log("Display %" SDL_PRIu32 " mode %d: %dx%d@%gx %gHz\n",
20492038
display, i, mode->w, mode->h, mode->pixel_density, mode->refresh_rate);
20502039
}
2040+
SDL_free(modes);
20512041
}
20522042
}
20532043
```
@@ -2080,8 +2070,6 @@ SDL_WindowFlags is used instead of Uint32 for API functions that refer to window
20802070

20812071
SDL_GetWindowOpacity() directly returns the opacity instead of using an out parameter.
20822072

2083-
SDL_GetWindowICCProfile() returns a const pointer to temporary memory, which does not need to be freed. You can use SDL_ClaimTemporaryMemory() to convert it to a non-const pointer that should be freed when you're done with it.
2084-
20852073
The following functions have been renamed:
20862074
* SDL_GL_DeleteContext() => SDL_GL_DestroyContext()
20872075
* SDL_GetClosestDisplayMode() => SDL_GetClosestFullscreenDisplayMode()

docs/README-strings.md

-52
Original file line numberDiff line numberDiff line change
@@ -5,55 +5,3 @@
55
Unless otherwise specified, all strings in SDL, across all platforms, are
66
UTF-8 encoded and can represent the full range of [Unicode](https://unicode.org).
77

8-
9-
## The SDL Get String Rule.
10-
11-
Did you see 'SDL_GetStringRule' in the wiki or headers? Here are the details
12-
that aren't worth copying across dozens of functions' documentation.
13-
14-
tl;dr: If an SDL function returns a `const char *` string, do not modify or
15-
free it, and if you need to save it, make a copy right away.
16-
17-
In several cases, SDL wants to return a string to the app, and the question
18-
in any library that does this is: _who owns this thing?_
19-
20-
The answer in almost all cases, is that SDL does, but not for long.
21-
22-
The pointer is only guaranteed to be valid until the next time the event
23-
queue is updated, or SDL_Quit is called.
24-
25-
The reason for this is memory safety.
26-
27-
There are several strings that SDL provides that could be freed at
28-
any moment. For example, an app calls SDL_GetAudioDeviceName(), which returns
29-
a string that is part of the internal audio device structure. But, while this
30-
function is returning, the user yanks the USB audio device out of the
31-
computer, and SDL decides to deallocate the structure...and the string!
32-
Now the app is holding a pointer that didn't live long enough to be useful,
33-
and could crash if accessed.
34-
35-
To avoid this, instead of calling SDL_free on a string as soon as it's done
36-
with it, SDL adds the pointer to a list. This list is freed at specific
37-
points: when the event queue is run (for ongoing cleanup) and when SDL_Quit
38-
is called (to catch things that are just hanging around). This allows the
39-
app to use a string without worrying about it becoming bogus in the middle
40-
of a printf() call. If the app needs it for longer, it should copy it.
41-
42-
When does "the event queue run"? There are several points:
43-
44-
- If the app calls SDL_PumpEvents() _from any thread_.
45-
- SDL_PumpEvents is also called by several other APIs internally:
46-
SDL_PollEvent(), SDL_PeepEvents(), SDL_WaitEvent(),
47-
SDL_WaitEventTimeout(), and maybe others.
48-
- If you are using [the main callbacks](main-functions#main-callbacks-in-sdl3),
49-
the event queue can run immediately after any of the callback functions
50-
return.
51-
52-
Note that these are just guaranteed minimum lifespans; any given string
53-
might live much longer--some might even be static memory that is _never_
54-
deallocated--but this rule promises that the app has a safe window.
55-
56-
Note that none of this applies if the return value is `char *` instead of
57-
`const char *`. Please see the specific function's documentation for how
58-
to handle those pointers.
59-

docs/README-winrt.md

-39
Original file line numberDiff line numberDiff line change
@@ -95,45 +95,6 @@ Here is a rough list of what works, and what doesn't:
9595

9696

9797

98-
Upgrade Notes
99-
-------------
100-
101-
#### SDL_GetPrefPath() usage when upgrading WinRT apps from SDL 2.0.3
102-
103-
SDL 2.0.4 fixes two bugs found in the WinRT version of SDL_GetPrefPath().
104-
The fixes may affect older, SDL 2.0.3-based apps' save data. Please note
105-
that these changes only apply to SDL-based WinRT apps, and not to apps for
106-
any other platform.
107-
108-
1. SDL_GetPrefPath() would return an invalid path, one in which the path's
109-
directory had not been created. Attempts to create files there
110-
(via fopen(), for example), would fail, unless that directory was
111-
explicitly created beforehand.
112-
113-
2. SDL_GetPrefPath(), for non-WinPhone-based apps, would return a path inside
114-
a WinRT 'Roaming' folder, the contents of which get automatically
115-
synchronized across multiple devices. This process can occur while an
116-
application runs, and can cause existing save-data to be overwritten
117-
at unexpected times, with data from other devices. (Windows Phone apps
118-
written with SDL 2.0.3 did not utilize a Roaming folder, due to API
119-
restrictions in Windows Phone 8.0).
120-
121-
122-
SDL_GetPrefPath(), starting with SDL 2.0.4, addresses these by:
123-
124-
1. making sure that SDL_GetPrefPath() returns a directory in which data
125-
can be written to immediately, without first needing to create directories.
126-
127-
2. basing SDL_GetPrefPath() off of a different, non-Roaming folder, the
128-
contents of which do not automatically get synchronized across devices
129-
(and which require less work to use safely, in terms of data integrity).
130-
131-
Apps that wish to get their Roaming folder's path can do so either by using
132-
SDL_GetWinRTFSPath(), or directly through the WinRT class,
133-
Windows.Storage.ApplicationData.
134-
135-
136-
13798
Setup, High-Level Steps
13899
-----------------------
139100

include/SDL3/SDL_audio.h

+13-13
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetNumAudioDrivers(void);
411411
*
412412
* \sa SDL_GetNumAudioDrivers
413413
*/
414-
extern SDL_DECLSPEC_TEMP const char * SDLCALL SDL_GetAudioDriver(int index);
414+
extern SDL_DECLSPEC const char * SDLCALL SDL_GetAudioDriver(int index);
415415
/* @} */
416416

417417
/**
@@ -428,7 +428,7 @@ extern SDL_DECLSPEC_TEMP const char * SDLCALL SDL_GetAudioDriver(int index);
428428
*
429429
* \since This function is available since SDL 3.0.0.
430430
*/
431-
extern SDL_DECLSPEC_TEMP const char * SDLCALL SDL_GetCurrentAudioDriver(void);
431+
extern SDL_DECLSPEC const char * SDLCALL SDL_GetCurrentAudioDriver(void);
432432

433433
/**
434434
* Get a list of currently-connected audio playback devices.
@@ -447,7 +447,7 @@ extern SDL_DECLSPEC_TEMP const char * SDLCALL SDL_GetCurrentAudioDriver(void);
447447
* \param count a pointer filled in with the number of devices returned, may
448448
* be NULL.
449449
* \returns a 0 terminated array of device instance IDs or NULL on error; call
450-
* SDL_GetError() for more information.
450+
* SDL_GetError() for more information. This should be freed with SDL_free() when it is no longer needed.
451451
*
452452
* \threadsafety It is safe to call this function from any thread.
453453
*
@@ -456,7 +456,7 @@ extern SDL_DECLSPEC_TEMP const char * SDLCALL SDL_GetCurrentAudioDriver(void);
456456
* \sa SDL_OpenAudioDevice
457457
* \sa SDL_GetAudioRecordingDevices
458458
*/
459-
extern SDL_DECLSPEC_TEMP const SDL_AudioDeviceID * SDLCALL SDL_GetAudioPlaybackDevices(int *count);
459+
extern SDL_DECLSPEC_FREE SDL_AudioDeviceID * SDLCALL SDL_GetAudioPlaybackDevices(int *count);
460460

461461
/**
462462
* Get a list of currently-connected audio recording devices.
@@ -475,7 +475,7 @@ extern SDL_DECLSPEC_TEMP const SDL_AudioDeviceID * SDLCALL SDL_GetAudioPlaybackD
475475
* \param count a pointer filled in with the number of devices returned, may
476476
* be NULL.
477477
* \returns a 0 terminated array of device instance IDs, or NULL on failure;
478-
* call SDL_GetError() for more information.
478+
* call SDL_GetError() for more information. This should be freed with SDL_free() when it is no longer needed.
479479
*
480480
* \threadsafety It is safe to call this function from any thread.
481481
*
@@ -484,7 +484,7 @@ extern SDL_DECLSPEC_TEMP const SDL_AudioDeviceID * SDLCALL SDL_GetAudioPlaybackD
484484
* \sa SDL_OpenAudioDevice
485485
* \sa SDL_GetAudioPlaybackDevices
486486
*/
487-
extern SDL_DECLSPEC_TEMP const SDL_AudioDeviceID * SDLCALL SDL_GetAudioRecordingDevices(int *count);
487+
extern SDL_DECLSPEC_FREE SDL_AudioDeviceID * SDLCALL SDL_GetAudioRecordingDevices(int *count);
488488

489489
/**
490490
* Get the human-readable name of a specific audio device.
@@ -501,7 +501,7 @@ extern SDL_DECLSPEC_TEMP const SDL_AudioDeviceID * SDLCALL SDL_GetAudioRecording
501501
* \sa SDL_GetAudioRecordingDevices
502502
* \sa SDL_GetDefaultAudioInfo
503503
*/
504-
extern SDL_DECLSPEC_TEMP const char * SDLCALL SDL_GetAudioDeviceName(SDL_AudioDeviceID devid);
504+
extern SDL_DECLSPEC const char * SDLCALL SDL_GetAudioDeviceName(SDL_AudioDeviceID devid);
505505

506506
/**
507507
* Get the current audio format of a specific audio device.
@@ -550,15 +550,15 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetAudioDeviceFormat(SDL_AudioDeviceID devid
550550
* \param devid the instance ID of the device to query.
551551
* \param count On output, set to number of channels in the map. Can be NULL.
552552
* \returns an array of the current channel mapping, with as many elements as
553-
* the current output spec's channels, or NULL if default.
553+
* the current output spec's channels, or NULL if default. This should be freed with SDL_free() when it is no longer needed.
554554
*
555555
* \threadsafety It is safe to call this function from any thread.
556556
*
557557
* \since This function is available since SDL 3.0.0.
558558
*
559559
* \sa SDL_SetAudioStreamInputChannelMap
560560
*/
561-
extern SDL_DECLSPEC_TEMP const int * SDLCALL SDL_GetAudioDeviceChannelMap(SDL_AudioDeviceID devid, int *count);
561+
extern SDL_DECLSPEC_FREE int * SDLCALL SDL_GetAudioDeviceChannelMap(SDL_AudioDeviceID devid, int *count);
562562

563563
/**
564564
* Open a specific audio device.
@@ -1098,7 +1098,7 @@ extern SDL_DECLSPEC int SDLCALL SDL_SetAudioStreamGain(SDL_AudioStream *stream,
10981098
* \param stream the SDL_AudioStream to query.
10991099
* \param count On output, set to number of channels in the map. Can be NULL.
11001100
* \returns an array of the current channel mapping, with as many elements as
1101-
* the current output spec's channels, or NULL if default.
1101+
* the current output spec's channels, or NULL if default. This should be freed with SDL_free() when it is no longer needed.
11021102
*
11031103
* \threadsafety It is safe to call this function from any thread, as it holds
11041104
* a stream-specific mutex while running.
@@ -1107,7 +1107,7 @@ extern SDL_DECLSPEC int SDLCALL SDL_SetAudioStreamGain(SDL_AudioStream *stream,
11071107
*
11081108
* \sa SDL_SetAudioStreamInputChannelMap
11091109
*/
1110-
extern SDL_DECLSPEC_TEMP const int * SDLCALL SDL_GetAudioStreamInputChannelMap(SDL_AudioStream *stream, int *count);
1110+
extern SDL_DECLSPEC_FREE int * SDLCALL SDL_GetAudioStreamInputChannelMap(SDL_AudioStream *stream, int *count);
11111111

11121112
/**
11131113
* Get the current output channel map of an audio stream.
@@ -1121,7 +1121,7 @@ extern SDL_DECLSPEC_TEMP const int * SDLCALL SDL_GetAudioStreamInputChannelMap(S
11211121
* \param stream the SDL_AudioStream to query.
11221122
* \param count On output, set to number of channels in the map. Can be NULL.
11231123
* \returns an array of the current channel mapping, with as many elements as
1124-
* the current output spec's channels, or NULL if default.
1124+
* the current output spec's channels, or NULL if default. This should be freed with SDL_free() when it is no longer needed.
11251125
*
11261126
* \threadsafety It is safe to call this function from any thread, as it holds
11271127
* a stream-specific mutex while running.
@@ -1130,7 +1130,7 @@ extern SDL_DECLSPEC_TEMP const int * SDLCALL SDL_GetAudioStreamInputChannelMap(S
11301130
*
11311131
* \sa SDL_SetAudioStreamInputChannelMap
11321132
*/
1133-
extern SDL_DECLSPEC_TEMP const int * SDLCALL SDL_GetAudioStreamOutputChannelMap(SDL_AudioStream *stream, int *count);
1133+
extern SDL_DECLSPEC_FREE int * SDLCALL SDL_GetAudioStreamOutputChannelMap(SDL_AudioStream *stream, int *count);
11341134

11351135
/**
11361136
* Set the current input channel map of an audio stream.

include/SDL3/SDL_begin_code.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,11 @@
6767
# endif
6868
# endif
6969
#endif
70-
/* This is used to mark functions that return temporary memory */
71-
#define SDL_DECLSPEC_TEMP SDL_DECLSPEC
70+
71+
/* This is used to mark functions that return memory that need to be freed with SDL_free() */
72+
#ifndef SDL_DECLSPEC_FREE
73+
#define SDL_DECLSPEC_FREE SDL_DECLSPEC
74+
#endif
7275

7376
/* By default SDL uses the C calling convention */
7477
#ifndef SDLCALL

0 commit comments

Comments
 (0)