From aac2920f03ea7e559bb22a506024a65f71ceef05 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Wed, 1 Jan 2025 02:04:30 +0200 Subject: [PATCH] Update SDL3 --- Source/ThirdParty/SDL/SDL3/SDL_asyncio.h | 2 +- Source/ThirdParty/SDL/SDL3/SDL_events.h | 3 +- Source/ThirdParty/SDL/SDL3/SDL_gpu.h | 33 +++ Source/ThirdParty/SDL/SDL3/SDL_hints.h | 12 +- Source/ThirdParty/SDL/SDL3/SDL_revision.h | 4 +- Source/ThirdParty/SDL/SDL3/SDL_storage.h | 199 +++++++++++++++++- Source/ThirdParty/SDL/SDL3/SDL_thread.h | 2 +- .../Tools/Flax.Build/Deps/Dependencies/SDL.cs | 7 +- 8 files changed, 249 insertions(+), 13 deletions(-) diff --git a/Source/ThirdParty/SDL/SDL3/SDL_asyncio.h b/Source/ThirdParty/SDL/SDL3/SDL_asyncio.h index 3c983913d..a366cd937 100644 --- a/Source/ThirdParty/SDL/SDL3/SDL_asyncio.h +++ b/Source/ThirdParty/SDL/SDL3/SDL_asyncio.h @@ -144,7 +144,7 @@ typedef enum SDL_AsyncIOResult { SDL_ASYNCIO_COMPLETE, /**< request was completed without error */ SDL_ASYNCIO_FAILURE, /**< request failed for some reason; check SDL_GetError()! */ - SDL_ASYNCIO_CANCELLED /**< request was cancelled before completing. */ + SDL_ASYNCIO_CANCELED /**< request was canceled before completing. */ } SDL_AsyncIOResult; /** diff --git a/Source/ThirdParty/SDL/SDL3/SDL_events.h b/Source/ThirdParty/SDL/SDL3/SDL_events.h index 2850b7639..e67559437 100644 --- a/Source/ThirdParty/SDL/SDL3/SDL_events.h +++ b/Source/ThirdParty/SDL/SDL3/SDL_events.h @@ -212,6 +212,7 @@ typedef enum SDL_EventType SDL_EVENT_FINGER_DOWN = 0x700, SDL_EVENT_FINGER_UP, SDL_EVENT_FINGER_MOTION, + SDL_EVENT_FINGER_CANCELED, /* 0x800, 0x801, and 0x802 were the Gesture events from SDL2. Do not reuse these values! sdl2-compat needs them! */ @@ -764,7 +765,7 @@ typedef struct SDL_RenderEvent */ typedef struct SDL_TouchFingerEvent { - SDL_EventType type; /**< SDL_EVENT_FINGER_MOTION or SDL_EVENT_FINGER_DOWN or SDL_EVENT_FINGER_UP */ + SDL_EventType type; /**< SDL_EVENT_FINGER_DOWN, SDL_EVENT_FINGER_UP, SDL_EVENT_FINGER_MOTION, or SDL_EVENT_FINGER_CANCELED */ Uint32 reserved; Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */ SDL_TouchID touchID; /**< The touch device id */ diff --git a/Source/ThirdParty/SDL/SDL3/SDL_gpu.h b/Source/ThirdParty/SDL/SDL3/SDL_gpu.h index 257efbc58..305b1165b 100644 --- a/Source/ThirdParty/SDL/SDL3/SDL_gpu.h +++ b/Source/ThirdParty/SDL/SDL3/SDL_gpu.h @@ -149,6 +149,29 @@ * [here](https://github.com/TheSpydog/SDL_gpu_examples) * . * + * ## Performance considerations + * + * Here are some basic tips for maximizing your rendering performance. + * + * - Beginning a new render pass is relatively expensive. Use as few render + * passes as you can. + * - Minimize the amount of state changes. For example, binding a pipeline is + * relatively cheap, but doing it hundreds of times when you don't need to + * will slow the performance significantly. + * - Perform your data uploads as early as possible in the frame. + * - Don't churn resources. Creating and releasing resources is expensive. + * It's better to create what you need up front and cache it. + * - Don't use uniform buffers for large amounts of data (more than a matrix + * or so). Use a storage buffer instead. + * - Use cycling correctly. There is a detailed explanation of cycling further + * below. + * - Use culling techniques to minimize pixel writes. The less writing the GPU + * has to do the better. Culling can be a very advanced topic but even + * simple culling techniques can boost performance significantly. + * + * In general try to remember the golden rule of performance: doing things is + * more expensive than not doing things. Don't Touch The Driver! + * * ## FAQ * * **Question: When are you adding more advanced features, like ray tracing or @@ -174,6 +197,16 @@ * reflection to extract the required information from the shader * automatically instead of manually filling in the struct's values. * + * **Question: My application isn't performing very well. Is this the GPU + * API's fault?** + * + * Answer: No. Long answer: The GPU API is a relatively thin layer over the + * underlying graphics API. While it's possible that we have done something + * inefficiently, it's very unlikely especially if you are relatively + * inexperienced with GPU rendering. Please see the performance tips above and + * make sure you are following them. Additionally, tools like RenderDoc can be + * very helpful for diagnosing incorrect behavior and performance issues. + * * ## System Requirements * * **Vulkan:** Supported on Windows, Linux, Nintendo Switch, and certain diff --git a/Source/ThirdParty/SDL/SDL3/SDL_hints.h b/Source/ThirdParty/SDL/SDL3/SDL_hints.h index c380d26fd..6db10f913 100644 --- a/Source/ThirdParty/SDL/SDL3/SDL_hints.h +++ b/Source/ThirdParty/SDL/SDL3/SDL_hints.h @@ -2391,13 +2391,21 @@ extern "C" { /** * Request SDL_AppIterate() be called at a specific rate. * - * This number is in Hz, so "60" means try to iterate 60 times per second. + * If this is set to a number, it represents Hz, so "60" means try to iterate + * 60 times per second. "0" means to iterate as fast as possible. Negative + * values are illegal, but reserved, in case they are useful in a future + * revision of SDL. + * + * There are other strings that have special meaning. If set to "waitevent", + * SDL_AppIterate will not be called until new event(s) have arrived (and been + * processed by SDL_AppEvent). This can be useful for apps that are completely + * idle except in response to input. * * On some platforms, or if you are using SDL_main instead of SDL_AppIterate, * this hint is ignored. When the hint can be used, it is allowed to be * changed at any time. * - * This defaults to 60, and specifying NULL for the hint's value will restore + * This defaults to 0, and specifying NULL for the hint's value will restore * the default. * * This hint can be set anytime. diff --git a/Source/ThirdParty/SDL/SDL3/SDL_revision.h b/Source/ThirdParty/SDL/SDL3/SDL_revision.h index e7a87f3a8..93ab96352 100644 --- a/Source/ThirdParty/SDL/SDL3/SDL_revision.h +++ b/Source/ThirdParty/SDL/SDL3/SDL_revision.h @@ -31,9 +31,9 @@ /* #undef SDL_VENDOR_INFO */ #ifdef SDL_VENDOR_INFO -#define SDL_REVISION "SDL3-3.1.7-8cc4735 (" SDL_VENDOR_INFO ")" +#define SDL_REVISION "SDL3-3.1.7-release-2.0.14-11837-g4286c8328 (" SDL_VENDOR_INFO ")" #else -#define SDL_REVISION "SDL3-3.1.7-8cc4735" +#define SDL_REVISION "SDL3-3.1.7-release-2.0.14-11837-g4286c8328" #endif #endif /* SDL_revision_h_ */ diff --git a/Source/ThirdParty/SDL/SDL3/SDL_storage.h b/Source/ThirdParty/SDL/SDL3/SDL_storage.h index c408120a5..5f0e26e4d 100644 --- a/Source/ThirdParty/SDL/SDL3/SDL_storage.h +++ b/Source/ThirdParty/SDL/SDL3/SDL_storage.h @@ -22,7 +22,198 @@ /** * # CategoryStorage * - * SDL storage container management. + * The storage API is a high-level API designed to abstract away the + * portability issues that come up when using something lower-level (in SDL's + * case, this sits on top of SDL_filesystem). It is significantly more + * restrictive than a typical filesystem API, for a number of reasons: + * + * 1. **What to Access:** A common pitfall with existing filesystem APIs is + * the assumption that all storage is monolithic. However, many other + * platforms (game consoles in particular) are more strict about what _type_ + * of filesystem is being accessed; for example, game content and user data + * are usually two separate storage devices with entirely different + * characteristics (and possibly different low-level APIs altogether!). 2. + * **How to Access:** Another common mistake is applications assuming that all + * storage is universally writeable - again, many platforms treat game content + * and user data as two separate storage devices, and only user data is + * writeable while game content is read-only. 3. **When to Access:** The most + * common portability issue with filesystem access is _timing_ - you cannot + * always assume that the storage device is always accessible all of the time, + * nor can you assume that there are no limits to how long you have access to + * a particular device. + * + * Consider the following example: + * + * ``` + * void ReadGameData(void) + * { + * extern char** fileNames; + * extern size_t numFiles; + * for (size_t i = 0; i < numFiles; i += 1) { + * FILE *data = fopen(fileNames[i], "rwb"); + * if (data == NULL) { + * // Something bad happened! + * } else { + * // A bunch of stuff happens here + * fclose(data); + * } + * } + * } + * + * void ReadSave(void) + * { + * FILE *save = fopen("saves/save0.sav", "rb"); + * if (save == NULL) { + * // Something bad happened! + * } else { + * // A bunch of stuff happens here + * fclose(save); + * } + * } + * + * void WriteSave(void) + * { + * FILE *save = fopen("saves/save0.sav", "wb"); + * if (save == NULL) { + * // Something bad happened! + * } else { + * // A bunch of stuff happens here + * fclose(save); + * } + * } + * ``` + * + * Going over the bullet points again: + * + * 1. **What to Access:** This code accesses a global filesystem; game data + * and saves are all presumed to be in the current working directory (which + * may or may not be the game's installation folder!). 2. **How to Access:** + * This code assumes that content paths are writeable, and that save data is + * also writeable despite being in the same location as the game data. 3. + * **When to Access:** This code assumes that they can be called at any time, + * since the filesystem is always accessible and has no limits on how long the + * filesystem is being accessed. + * + * Due to these assumptions, the filesystem code is not portable and will fail + * under these common scenarios: + * + * - The game is installed on a device that is read-only, both content loading + * and game saves will fail or crash outright + * - Game/User storage is not implicitly mounted, so no files will be found + * for either scenario when a platform requires explicitly mounting + * filesystems + * - Save data may not be safe since the I/O is not being flushed or + * validated, so an error occurring elsewhere in the program may result in + * missing/corrupted save data + * + * When using, SDL_Storage, these types of problems are virtually impossible + * to trip over: + * + * ``` + * void ReadGameData(void) + * { + * extern char** fileNames; + * extern size_t numFiles; + * + * SDL_Storage *title = SDL_OpenTitleStorage(NULL, 0); + * if (title == NULL) { + * // Something bad happened! + * } + * while (!SDL_StorageReady(title)) { + * SDL_Delay(1); + * } + * + * for (size_t i = 0; i < numFiles; i += 1) { + * void* dst; + * Uint64 dstLen = 0; + * + * if (SDL_GetStorageFileSize(title, fileNames[i], &dstLen) && dstLen > 0) { + * dst = SDL_malloc(dstLen); + * if (SDL_ReadStorageFile(title, fileNames[i], dst, dstLen)) { + * // A bunch of stuff happens here + * } else { + * // Something bad happened! + * } + * SDL_free(dst); + * } else { + * // Something bad happened! + * } + * } + * + * SDL_CloseStorage(title); + * } + * + * void ReadSave(void) + * { + * SDL_Storage *user = SDL_OpenUserStorage("libsdl", "Storage Example", 0); + * if (user == NULL) { + * // Something bad happened! + * } + * while (!SDL_StorageReady(user)) { + * SDL_Delay(1); + * } + * + * Uint64 saveLen = 0; + * if (SDL_GetStorageFileSize(user, "save0.sav", &saveLen) && saveLen > 0) { + * void* dst = SDL_malloc(saveLen); + * if (SDL_ReadStorageFile(user, "save0.sav", dst, saveLen)) { + * // A bunch of stuff happens here + * } else { + * // Something bad happened! + * } + * SDL_free(dst); + * } else { + * // Something bad happened! + * } + * + * SDL_CloseStorage(user); + * } + * + * void WriteSave(void) + * { + * SDL_Storage *user = SDL_OpenUserStorage("libsdl", "Storage Example", 0); + * if (user == NULL) { + * // Something bad happened! + * } + * while (!SDL_StorageReady(user)) { + * SDL_Delay(1); + * } + * + * extern void *saveData; // A bunch of stuff happened here... + * extern Uint64 saveLen; + * if (!SDL_WriteStorageFile(user, "save0.sav", saveData, saveLen)) { + * // Something bad happened! + * } + * + * SDL_CloseStorage(user); + * } + * ``` + * + * Note the improvements that SDL_Storage makes: + * + * 1. **What to Access:** This code explicitly reads from a title or user + * storage device based on the context of the function. 2. **How to Access:** + * This code explicitly uses either a read or write function based on the + * context of the function. 3. **When to Access:** This code explicitly opens + * the device when it needs to, and closes it when it is finished working with + * the filesystem. + * + * The result is an application that is significantly more robust against the + * increasing demands of platforms and their filesystems! + * + * A publicly available example of an SDL_Storage backend is the + * [Steam Cloud](https://partner.steamgames.com/doc/features/cloud) + * backend - you can initialize Steamworks when starting the program, and then + * SDL will recognize that Steamworks is initialized and automatically use + * ISteamRemoteStorage when the application opens user storage. More + * importantly, when you _open_ storage it knows to begin a "batch" of + * filesystem operations, and when you _close_ storage it knows to end and + * flush the batch. This is used by Steam to support + * [Dynamic Cloud Sync](https://steamcommunity.com/groups/steamworks/announcements/detail/3142949576401813670) + * ; users can save data on one PC, put the device to sleep, and then continue + * playing on another PC (and vice versa) with the save data fully + * synchronized across all devices, allowing for a seamless experience without + * having to do full restarts of the program. */ #ifndef SDL_storage_h_ @@ -40,8 +231,6 @@ extern "C" { #endif -/* !!! FIXME: Don't let this ship without async R/W support!!! */ - /** * Function interface for SDL_Storage. * @@ -266,6 +455,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetStorageFileSize(SDL_Storage *storage, co * Synchronously read a file from a storage container into a client-provided * buffer. * + * The value of `length` must match the length of the file exactly; call + * SDL_GetStorageFileSize() to get this value. This behavior may be relaxed in + * a future release. + * * \param storage a storage container to read from. * \param path the relative path of the file to read. * \param destination a client-provided buffer to read the file into. diff --git a/Source/ThirdParty/SDL/SDL3/SDL_thread.h b/Source/ThirdParty/SDL/SDL3/SDL_thread.h index 1821d15c6..9c561efb2 100644 --- a/Source/ThirdParty/SDL/SDL3/SDL_thread.h +++ b/Source/ThirdParty/SDL/SDL3/SDL_thread.h @@ -116,7 +116,7 @@ typedef enum SDL_ThreadState SDL_THREAD_UNKNOWN, /**< The thread is not valid */ SDL_THREAD_ALIVE, /**< The thread is currently running */ SDL_THREAD_DETACHED, /**< The thread is detached and can't be waited on */ - SDL_THREAD_COMPLETE, /**< The thread has finished and should be cleaned up with SDL_WaitThread() */ + SDL_THREAD_COMPLETE /**< The thread has finished and should be cleaned up with SDL_WaitThread() */ } SDL_ThreadState; /** diff --git a/Source/Tools/Flax.Build/Deps/Dependencies/SDL.cs b/Source/Tools/Flax.Build/Deps/Dependencies/SDL.cs index 16a9dd397..15294578a 100644 --- a/Source/Tools/Flax.Build/Deps/Dependencies/SDL.cs +++ b/Source/Tools/Flax.Build/Deps/Dependencies/SDL.cs @@ -48,7 +48,7 @@ namespace Flax.Deps.Dependencies public override void Build(BuildOptions options) { string root = options.IntermediateFolder; - string configuration = "Release"; + string configuration = "Debug"; const bool buildStatic = true; var configs = new string[] { @@ -88,8 +88,9 @@ namespace Flax.Deps.Dependencies Path.Combine(root, "include", "SDL3"), }; - CloneGitRepoFastSince(root, "https://github.com/libsdl-org/SDL.git", new DateTime(2024, 12, 29)); - GitResetToCommit(root, "8cc4735d74a1ce89c5fceb48b021872c8c563174"); + //CloneGitRepoFastSince(root, "https://github.com/Kontrabant/SDL", new DateTime(2024, 12, 29)); + CloneGitRepo(root, "https://github.com/Kontrabant/SDL"); + GitResetToCommit(root, "0777bff39efaa197ded98b1b64e3dd5b3845a011"); foreach (var platform in options.Platforms) {