diff --git a/include/SDL3/SDL_stdinc.h b/include/SDL3/SDL_stdinc.h index e8f41543a0..49d424c0c1 100644 --- a/include/SDL3/SDL_stdinc.h +++ b/include/SDL3/SDL_stdinc.h @@ -1362,7 +1362,9 @@ extern SDL_DECLSPEC SDL_MALLOC void * SDLCALL SDL_malloc(size_t size); * * If the allocation is successful, the returned pointer is guaranteed to be * aligned to either the *fundamental alignment* (`alignof(max_align_t)` in - * C11 and later) or `2 * sizeof(void *)`, whichever is smaller. + * C11 and later) or `2 * sizeof(void *)`, whichever is smaller. Use + * SDL_aligned_alloc_zero() if you need to allocate memory aligned to an + * alignment greater than this guarantee. * * \param nmemb the number of elements in the array. * \param size the size of each element of the array. @@ -1616,6 +1618,30 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetMemoryFunctions(SDL_malloc_func malloc_f */ extern SDL_DECLSPEC SDL_MALLOC void * SDLCALL SDL_aligned_alloc(size_t alignment, size_t size); +/** + * Allocate zero-initialized memory aligned to a specific alignment. + * + * The memory returned by this function must be freed with SDL_aligned_free(), + * _not_ SDL_free(). + * + * If `alignment` is less than the size of `void *`, it will be increased to + * match that. + * + * The returned memory address will be a multiple of the alignment value, and + * the size of the memory allocated will be a multiple of the alignment value. + * + * \param alignment the alignment of the memory. + * \param size the size to allocate. + * \returns a pointer to the aligned memory, or NULL if allocation failed. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.6.0. + * + * \sa SDL_aligned_free + */ +extern SDL_DECLSPEC SDL_MALLOC void * SDLCALL SDL_aligned_alloc_zero(size_t alignment, size_t size); + /** * Free memory allocated by SDL_aligned_alloc(). * diff --git a/src/dynapi/SDL_dynapi.exports b/src/dynapi/SDL_dynapi.exports index 9864557071..4eb5b02e62 100644 --- a/src/dynapi/SDL_dynapi.exports +++ b/src/dynapi/SDL_dynapi.exports @@ -1290,3 +1290,4 @@ _SDL_LoadJPG _SDL_HasSVE2 _SDL_GamepadHasCapSense _SDL_GetGamepadCapSense +_SDL_aligned_alloc_zero diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index 3958a52aa6..de5e49896f 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -1291,6 +1291,7 @@ SDL3_0.0.0 { SDL_HasSVE2; SDL_GamepadHasCapSense; SDL_GetGamepadCapSense; + SDL_aligned_alloc_zero; # extra symbols go here (don't modify this line) local: *; }; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index b54d32ae6d..e471dac703 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -1317,3 +1317,4 @@ #define SDL_HasSVE2 SDL_HasSVE2_REAL #define SDL_GamepadHasCapSense SDL_GamepadHasCapSense_REAL #define SDL_GetGamepadCapSense SDL_GetGamepadCapSense_REAL +#define SDL_aligned_alloc_zero SDL_aligned_alloc_zero_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 4f8ac0ba0c..d2a28315ca 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -1325,3 +1325,4 @@ SDL_DYNAPI_PROC(SDL_Surface*,SDL_LoadJPG,(const char *a),(a),return) SDL_DYNAPI_PROC(bool,SDL_HasSVE2,(void),(),return) SDL_DYNAPI_PROC(bool,SDL_GamepadHasCapSense,(SDL_Gamepad *a,SDL_GamepadCapSenseType b),(a,b),return) SDL_DYNAPI_PROC(bool,SDL_GetGamepadCapSense,(SDL_Gamepad *a,SDL_GamepadCapSenseType b),(a,b),return) +SDL_DYNAPI_PROC(void*,SDL_aligned_alloc_zero,(size_t a,size_t b),(a,b),return) diff --git a/src/stdlib/SDL_stdlib.c b/src/stdlib/SDL_stdlib.c index 1c55dc984e..8c33006308 100644 --- a/src/stdlib/SDL_stdlib.c +++ b/src/stdlib/SDL_stdlib.c @@ -523,7 +523,7 @@ int SDL_toupper(int x) { return ((x) >= 'a') && ((x) <= 'z') ? ('A' + ((x) - 'a' int SDL_tolower(int x) { return ((x) >= 'A') && ((x) <= 'Z') ? ('a' + ((x) - 'A')) : (x); } int SDL_isblank(int x) { return ((x) == ' ') || ((x) == '\t'); } -void *SDL_aligned_alloc(size_t alignment, size_t size) +static void *SDL_aligned_alloc_internal(size_t alignment, size_t size, bool clear_memory) { size_t padding; Uint8 *result = NULL; @@ -537,7 +537,7 @@ void *SDL_aligned_alloc(size_t alignment, size_t size) if (SDL_size_add_check_overflow(size, alignment, &size) && SDL_size_add_check_overflow(size, sizeof(void *), &size) && SDL_size_add_check_overflow(size, padding, &size)) { - void *original = SDL_malloc(size); + void *original = clear_memory ? SDL_calloc(1, size) : SDL_malloc(size); if (original) { // Make sure we have enough space to store the original pointer result = (Uint8 *)original + sizeof(original); @@ -557,6 +557,16 @@ void *SDL_aligned_alloc(size_t alignment, size_t size) return result; } +void *SDL_aligned_alloc(size_t alignment, size_t size) +{ + return SDL_aligned_alloc_internal(alignment, size, false); +} + +void *SDL_aligned_alloc_zero(size_t alignment, size_t size) +{ + return SDL_aligned_alloc_internal(alignment, size, true); +} + void SDL_aligned_free(void *mem) { if (mem) { diff --git a/src/video/SDL_surface.c b/src/video/SDL_surface.c index 03e435c191..20bedee14e 100644 --- a/src/video/SDL_surface.c +++ b/src/video/SDL_surface.c @@ -230,19 +230,23 @@ static SDL_Surface *SDL_CreateSurfaceInternal(int width, int height, SDL_PixelFo if (surface->w && surface->h && format != SDL_PIXELFORMAT_MJPG) { surface->flags &= ~SDL_SURFACE_PREALLOCATED; if (SDL_GetHintBoolean("SDL_SURFACE_MALLOC", false)) { - surface->pixels = SDL_malloc(size); + if (clear_surface) { + surface->pixels = SDL_calloc(1, size); + } else { + surface->pixels = SDL_malloc(size); + } } else { surface->flags |= SDL_SURFACE_SIMD_ALIGNED; - surface->pixels = SDL_aligned_alloc(SDL_GetSIMDAlignment(), size); + if (clear_surface) { + surface->pixels = SDL_aligned_alloc_zero(SDL_GetSIMDAlignment(), size); + } else { + surface->pixels = SDL_aligned_alloc(SDL_GetSIMDAlignment(), size); + } } if (!surface->pixels) { SDL_DestroySurface(surface); return NULL; } - - if (clear_surface) { - SDL_memset(surface->pixels, 0, size); - } } return surface; }