From f7d5bb3c7a8be638512c1ee3c6541109b36e645e Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Fri, 10 Oct 2025 17:40:51 -0400
Subject: [PATCH] cpuinfo: Added SDL_GetSystemPageSize.
Fixes #14201.
---
include/SDL3/SDL_cpuinfo.h | 21 +++++++++++
src/cpuinfo/SDL_cpuinfo.c | 59 +++++++++++++++++++++++++++++++
src/dynapi/SDL_dynapi.sym | 1 +
src/dynapi/SDL_dynapi_overrides.h | 1 +
src/dynapi/SDL_dynapi_procs.h | 1 +
test/testplatform.c | 1 +
test/testsymbols.c | 1 +
7 files changed, 85 insertions(+)
diff --git a/include/SDL3/SDL_cpuinfo.h b/include/SDL3/SDL_cpuinfo.h
index 1745bd9349015..87432ed909c34 100644
--- a/include/SDL3/SDL_cpuinfo.h
+++ b/include/SDL3/SDL_cpuinfo.h
@@ -344,6 +344,27 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetSystemRAM(void);
*/
extern SDL_DECLSPEC size_t SDLCALL SDL_GetSIMDAlignment(void);
+/**
+ * Report the size of a page of memory.
+ *
+ * Different platforms might have different memory page sizes. In current
+ * times, 4 kilobytes is not unusual, but newer systems are moving to larger
+ * page sizes, and esoteric platforms might have any unexpected size.
+ *
+ * Note that this function can return 0, which means SDL can't determine
+ * the page size on this platform. It will _not_ set an error string to be
+ * retrieved with SDL_GetError() in this case! In this case, defaulting to
+ * 4096 is often a reasonable option.
+ *
+ * \returns the size of a single page of memory, in bytes, or 0 if SDL can't
+ * determine this information.
+ *
+ * \threadsafety It is safe to call this function from any thread.
+ *
+ * \since This function is available since SDL 3.4.0.
+ */
+extern SDL_DECLSPEC int SDLCALL SDL_GetSystemPageSize(void);
+
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
diff --git a/src/cpuinfo/SDL_cpuinfo.c b/src/cpuinfo/SDL_cpuinfo.c
index 1ec1655135bc5..a097170e118ea 100644
--- a/src/cpuinfo/SDL_cpuinfo.c
+++ b/src/cpuinfo/SDL_cpuinfo.c
@@ -1213,6 +1213,65 @@ int SDL_GetSystemRAM(void)
return SDL_SystemRAM;
}
+
+static int SDL_SystemPageSize = -1;
+
+int SDL_GetSystemPageSize(void)
+{
+ if (SDL_SystemPageSize == -1) {
+#ifdef SDL_PLATFORM_SYSTEM_PAGE_SIZE_PRIVATE // consoles will define this in a platform-specific internal header.
+ SDL_SystemPageSize = SDL_PLATFORM_SYSTEM_PAGE_SIZE_PRIVATE;
+#endif
+#ifdef SDL_PLATFORM_3DS
+ SDL_SystemPageSize = 4096; // It's an ARM11 CPU; I assume this is 4K.
+#endif
+#ifdef SDL_PLATFORM_VITA
+ SDL_SystemPageSize = 4096; // It's an ARMv7 CPU; I assume this is 4K.
+#endif
+#ifdef SDL_PLATFORM_PS2
+ SDL_SystemPageSize = 4096; // It's a MIPS R5900 CPU; I assume this is 4K.
+#endif
+#if defined(HAVE_SYSCONF) && (defined(_SC_PAGESIZE) || defined(_SC_PAGE_SIZE))
+ if (SDL_SystemPageSize <= 0) {
+ #if defined(_SC_PAGE_SIZE)
+ SDL_SystemPageSize = sysconf(_SC_PAGE_SIZE);
+ #else
+ SDL_SystemPageSize = sysconf(_SC_PAGESIZE);
+ #endif
+ }
+#endif
+#if defined(HAVE_SYSCTLBYNAME) && defined(HW_PAGESIZE)
+ if (SDL_SystemPageSize <= 0) {
+ // NetBSD, OpenBSD, FreeBSD, Darwin...everything agrees to use HW_PAGESIZE.
+ int mib[2] = { CTL_HW, HW_PAGESIZE };
+ int pagesize = 0;
+ size_t len = sizeof(pagesize);
+
+ if (sysctl(mib, 2, &pagesize, &len, NULL, 0) == 0) {
+ SDL_SystemPageSize = pagesize;
+ }
+ }
+#endif
+#ifdef HAVE_GETPAGESIZE
+ if (SDL_SystemPageSize <= 0) {
+ SDL_SystemPageSize = getpagesize();
+ }
+#endif
+#if defined(SDL_PLATFORM_WINDOWS)
+ if (SDL_SystemPageSize <= 0) {
+ SYSTEM_INFO sysinfo;
+ GetSystemInfo(&sysinfo);
+ SDL_SystemPageSize = (int) sysinfo.dwPageSize;
+ }
+#endif
+ if (SDL_SystemPageSize < 0) { // in case we got a weird result somewhere, or no better information, force it to 0.
+ SDL_SystemPageSize = 0; // unknown page size, sorry.
+ }
+ }
+ return SDL_SystemPageSize;
+}
+
+
size_t SDL_GetSIMDAlignment(void)
{
if (SDL_SIMDAlignment == 0xFFFFFFFF) {
diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym
index 3aa7a822e61cc..dce512ba9ba26 100644
--- a/src/dynapi/SDL_dynapi.sym
+++ b/src/dynapi/SDL_dynapi.sym
@@ -1264,6 +1264,7 @@ SDL3_0.0.0 {
SDL_LoadPNG;
SDL_SavePNG_IO;
SDL_SavePNG;
+ SDL_GetSystemPageSize;
# 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 f0693ad980589..c4fa08b353cb5 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -1290,3 +1290,4 @@
#define SDL_LoadPNG SDL_LoadPNG_REAL
#define SDL_SavePNG_IO SDL_SavePNG_IO_REAL
#define SDL_SavePNG SDL_SavePNG_REAL
+#define SDL_GetSystemPageSize SDL_GetSystemPageSize_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index 4e3ca27e3ed2f..7c6a6f83883eb 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -1298,3 +1298,4 @@ SDL_DYNAPI_PROC(SDL_Surface*,SDL_LoadPNG_IO,(SDL_IOStream *a,bool b),(a,b),retur
SDL_DYNAPI_PROC(SDL_Surface*,SDL_LoadPNG,(const char *a),(a),return)
SDL_DYNAPI_PROC(bool,SDL_SavePNG_IO,(SDL_Surface *a,SDL_IOStream *b,bool c),(a,b,c),return)
SDL_DYNAPI_PROC(bool,SDL_SavePNG,(SDL_Surface *a,const char *b),(a,b),return)
+SDL_DYNAPI_PROC(int,SDL_GetSystemPageSize,(void),(),return)
diff --git a/test/testplatform.c b/test/testplatform.c
index c1eb6aa62f30b..1b8945c49d225 100644
--- a/test/testplatform.c
+++ b/test/testplatform.c
@@ -412,6 +412,7 @@ static int TestCPUInfo(bool verbose)
SDL_Log("LSX %s", SDL_HasLSX() ? "detected" : "not detected");
SDL_Log("LASX %s", SDL_HasLASX() ? "detected" : "not detected");
SDL_Log("System RAM %d MB", SDL_GetSystemRAM());
+ SDL_Log("System memory page size %d bytes", SDL_GetSystemPageSize());
}
return 0;
}
diff --git a/test/testsymbols.c b/test/testsymbols.c
index 7b5a9df2ed997..f8655a8460385 100644
--- a/test/testsymbols.c
+++ b/test/testsymbols.c
@@ -1339,6 +1339,7 @@ const static struct {
SDL_SYMBOL_ITEM(SDL_LoadPNG),
SDL_SYMBOL_ITEM(SDL_SavePNG_IO),
SDL_SYMBOL_ITEM(SDL_SavePNG),
+ SDL_SYMBOL_ITEM(SDL_GetSystemPageSize),
/* extra symbols go here (don't modify this line) */
{ NULL, NULL }
};