diff --git a/external/SDL/VisualC-GDK/SDL/SDL.vcxproj b/external/SDL/VisualC-GDK/SDL/SDL.vcxproj index c6ab1416..d6f85d2c 100644 --- a/external/SDL/VisualC-GDK/SDL/SDL.vcxproj +++ b/external/SDL/VisualC-GDK/SDL/SDL.vcxproj @@ -1,4 +1,4 @@ - + @@ -691,6 +691,7 @@ + diff --git a/external/SDL/VisualC-GDK/SDL/SDL.vcxproj.filters b/external/SDL/VisualC-GDK/SDL/SDL.vcxproj.filters index 017b9baf..e697a3e9 100644 --- a/external/SDL/VisualC-GDK/SDL/SDL.vcxproj.filters +++ b/external/SDL/VisualC-GDK/SDL/SDL.vcxproj.filters @@ -80,6 +80,7 @@ + diff --git a/external/SDL/VisualC/SDL/SDL.vcxproj b/external/SDL/VisualC/SDL/SDL.vcxproj index 27883a0c..b53a6022 100644 --- a/external/SDL/VisualC/SDL/SDL.vcxproj +++ b/external/SDL/VisualC/SDL/SDL.vcxproj @@ -569,6 +569,7 @@ + diff --git a/external/SDL/VisualC/SDL/SDL.vcxproj.filters b/external/SDL/VisualC/SDL/SDL.vcxproj.filters index 34f05bb4..d62aa47b 100644 --- a/external/SDL/VisualC/SDL/SDL.vcxproj.filters +++ b/external/SDL/VisualC/SDL/SDL.vcxproj.filters @@ -1229,6 +1229,9 @@ joystick\hidapi + + joystick\hidapi + joystick\hidapi diff --git a/external/SDL/Xcode/SDL/SDL.xcodeproj/project.pbxproj b/external/SDL/Xcode/SDL/SDL.xcodeproj/project.pbxproj index 23cf854b..01d01422 100644 --- a/external/SDL/Xcode/SDL/SDL.xcodeproj/project.pbxproj +++ b/external/SDL/Xcode/SDL/SDL.xcodeproj/project.pbxproj @@ -379,7 +379,6 @@ E479118F2BA9555500CE3B7F /* SDL_genericstorage.c in Sources */ = {isa = PBXBuildFile; fileRef = E479118A2BA9555500CE3B7F /* SDL_genericstorage.c */; }; E4A568B62AF763940062EEC4 /* SDL_sysmain_callbacks.c in Sources */ = {isa = PBXBuildFile; fileRef = E4A568B52AF763940062EEC4 /* SDL_sysmain_callbacks.c */; }; E4F257712C818FE200FCEAFC /* SDL_gpu.h in Headers */ = {isa = PBXBuildFile; fileRef = E4F257702C818FE200FCEAFC /* SDL_gpu.h */; settings = {ATTRIBUTES = (Public, ); }; }; - E4F257902C81903800FCEAFC /* compile_shaders.sh in Resources */ = {isa = PBXBuildFile; fileRef = E4F2577D2C81903800FCEAFC /* compile_shaders.sh */; }; E4F257912C81903800FCEAFC /* Metal_Blit.h in Headers */ = {isa = PBXBuildFile; fileRef = E4F2577E2C81903800FCEAFC /* Metal_Blit.h */; }; E4F257922C81903800FCEAFC /* Metal_Blit.metal in Sources */ = {isa = PBXBuildFile; fileRef = E4F2577F2C81903800FCEAFC /* Metal_Blit.metal */; }; E4F257932C81903800FCEAFC /* SDL_gpu_metal.m in Sources */ = {isa = PBXBuildFile; fileRef = E4F257802C81903800FCEAFC /* SDL_gpu_metal.m */; }; @@ -544,6 +543,8 @@ F3FA5A232B59ACE000FEAD97 /* yuv_rgb_lsx.c in Sources */ = {isa = PBXBuildFile; fileRef = F3FA5A1A2B59ACE000FEAD97 /* yuv_rgb_lsx.c */; }; F3FA5A242B59ACE000FEAD97 /* yuv_rgb_lsx.h in Headers */ = {isa = PBXBuildFile; fileRef = F3FA5A1B2B59ACE000FEAD97 /* yuv_rgb_lsx.h */; }; F3FA5A252B59ACE000FEAD97 /* yuv_rgb_common.h in Headers */ = {isa = PBXBuildFile; fileRef = F3FA5A1C2B59ACE000FEAD97 /* yuv_rgb_common.h */; }; + F3FD042E2C9B755700824C4C /* SDL_hidapi_nintendo.h in Headers */ = {isa = PBXBuildFile; fileRef = F3FD042C2C9B755700824C4C /* SDL_hidapi_nintendo.h */; }; + F3FD042F2C9B755700824C4C /* SDL_hidapi_steam_hori.c in Sources */ = {isa = PBXBuildFile; fileRef = F3FD042D2C9B755700824C4C /* SDL_hidapi_steam_hori.c */; }; FA73671D19A540EF004122E4 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA73671C19A540EF004122E4 /* CoreVideo.framework */; platformFilters = (ios, maccatalyst, macos, tvos, watchos, ); }; /* End PBXBuildFile section */ @@ -937,7 +938,6 @@ E479118A2BA9555500CE3B7F /* SDL_genericstorage.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_genericstorage.c; sourceTree = ""; }; E4A568B52AF763940062EEC4 /* SDL_sysmain_callbacks.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_sysmain_callbacks.c; sourceTree = ""; }; E4F257702C818FE200FCEAFC /* SDL_gpu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDL_gpu.h; path = SDL3/SDL_gpu.h; sourceTree = ""; }; - E4F2577D2C81903800FCEAFC /* compile_shaders.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = compile_shaders.sh; sourceTree = ""; }; E4F2577E2C81903800FCEAFC /* Metal_Blit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Metal_Blit.h; sourceTree = ""; }; E4F2577F2C81903800FCEAFC /* Metal_Blit.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; path = Metal_Blit.metal; sourceTree = ""; }; E4F257802C81903800FCEAFC /* SDL_gpu_metal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDL_gpu_metal.m; sourceTree = ""; }; @@ -1115,6 +1115,8 @@ F3FA5A1A2B59ACE000FEAD97 /* yuv_rgb_lsx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = yuv_rgb_lsx.c; sourceTree = ""; }; F3FA5A1B2B59ACE000FEAD97 /* yuv_rgb_lsx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = yuv_rgb_lsx.h; sourceTree = ""; }; F3FA5A1C2B59ACE000FEAD97 /* yuv_rgb_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = yuv_rgb_common.h; sourceTree = ""; }; + F3FD042C2C9B755700824C4C /* SDL_hidapi_nintendo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_hidapi_nintendo.h; sourceTree = ""; }; + F3FD042D2C9B755700824C4C /* SDL_hidapi_steam_hori.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_steam_hori.c; sourceTree = ""; }; F59C710300D5CB5801000001 /* ReadMe.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = ReadMe.txt; sourceTree = ""; }; F59C710600D5CB5801000001 /* SDL.info */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = SDL.info; sourceTree = ""; }; F5A2EF3900C6A39A01000001 /* BUGS.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; name = BUGS.txt; path = ../../BUGS.txt; sourceTree = SOURCE_ROOT; }; @@ -1898,25 +1900,27 @@ A7D8A7BE23E2513E00DCD162 /* hidapi */ = { isa = PBXGroup; children = ( - A797456F2B2E9D39009D224A /* SDL_hidapi_steamdeck.c */, F32305FE28939F6400E66D30 /* SDL_hidapi_combined.c */, A7D8A7C923E2513E00DCD162 /* SDL_hidapi_gamecube.c */, F3F07D59269640160074468B /* SDL_hidapi_luna.c */, + F3FD042C2C9B755700824C4C /* SDL_hidapi_nintendo.h */, F388C95428B5F6F600661ECF /* SDL_hidapi_ps3.c */, A7D8A7C323E2513E00DCD162 /* SDL_hidapi_ps4.c */, F3A4909D2554D38500E92A8B /* SDL_hidapi_ps5.c */, - A75FDBC423EA380300529352 /* SDL_hidapi_rumble.c */, A75FDBC323EA380300529352 /* SDL_hidapi_rumble.h */, + A75FDBC423EA380300529352 /* SDL_hidapi_rumble.c */, 9846B07B287A9020000C35C8 /* SDL_hidapi_shield.c */, F3984CCF25BCC92800374F43 /* SDL_hidapi_stadia.c */, A75FDAAC23E2795C00529352 /* SDL_hidapi_steam.c */, + F3FD042D2C9B755700824C4C /* SDL_hidapi_steam_hori.c */, + A797456F2B2E9D39009D224A /* SDL_hidapi_steamdeck.c */, A7D8A7C623E2513E00DCD162 /* SDL_hidapi_switch.c */, F3D60A8228C16A1800788A3A /* SDL_hidapi_wii.c */, A7D8A7C223E2513E00DCD162 /* SDL_hidapi_xbox360.c */, A7D8A7C823E2513E00DCD162 /* SDL_hidapi_xbox360w.c */, A7D8A7C523E2513E00DCD162 /* SDL_hidapi_xboxone.c */, - A7D8A7C723E2513E00DCD162 /* SDL_hidapijoystick_c.h */, A7D8A7C423E2513E00DCD162 /* SDL_hidapijoystick.c */, + A7D8A7C723E2513E00DCD162 /* SDL_hidapijoystick_c.h */, ); path = hidapi; sourceTree = ""; @@ -2297,7 +2301,6 @@ E4F257812C81903800FCEAFC /* metal */ = { isa = PBXGroup; children = ( - E4F2577D2C81903800FCEAFC /* compile_shaders.sh */, E4F2577E2C81903800FCEAFC /* Metal_Blit.h */, E4F2577F2C81903800FCEAFC /* Metal_Blit.metal */, E4F257802C81903800FCEAFC /* SDL_gpu_metal.m */, @@ -2671,6 +2674,7 @@ A7D8B26023E2514200DCD162 /* vulkan.h in Headers */, A7D8B2B423E2514200DCD162 /* vulkan_android.h in Headers */, A7D8B2A823E2514200DCD162 /* vulkan_core.h in Headers */, + F3FD042E2C9B755700824C4C /* SDL_hidapi_nintendo.h in Headers */, F3A9AE9B2C8A13C100AAC390 /* SDL_pipeline_gpu.h in Headers */, E41D20152BA9577D003073FA /* SDL_storage.h in Headers */, F37E18522BA50E760098C111 /* SDL_dialog.h in Headers */, @@ -2763,7 +2767,6 @@ files = ( F37A8E1A28405AA100C38E95 /* CMake in Resources */, A75FDBB823E4CBC700529352 /* ReadMe.txt in Resources */, - E4F257902C81903800FCEAFC /* compile_shaders.sh in Resources */, A75FDBB723E4CBC700529352 /* License.txt in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -3003,6 +3006,7 @@ A7D8B42E23E2514300DCD162 /* SDL_syscond.c in Sources */, A7D8AADA23E2514100DCD162 /* SDL_syshaptic.c in Sources */, A7D8BAE523E2514500DCD162 /* e_exp.c in Sources */, + F3FD042F2C9B755700824C4C /* SDL_hidapi_steam_hori.c in Sources */, A7D8BB8123E2514500DCD162 /* SDL_quit.c in Sources */, F3FA5A232B59ACE000FEAD97 /* yuv_rgb_lsx.c in Sources */, A7D8AEA623E2514100DCD162 /* SDL_cocoawindow.m in Sources */, diff --git a/external/SDL/examples/CMakeLists.txt b/external/SDL/examples/CMakeLists.txt index e3527d08..e35e49da 100644 --- a/external/SDL/examples/CMakeLists.txt +++ b/external/SDL/examples/CMakeLists.txt @@ -120,8 +120,16 @@ macro(add_sdl_example_executable TARGET) target_include_directories(${TARGET} PRIVATE "$") endmacro() -add_sdl_example_executable(renderer-clear SOURCES renderer/01-clear/renderer-clear.c) -add_sdl_example_executable(renderer-primitives SOURCES renderer/02-primitives/renderer-primitives.c) +add_sdl_example_executable(renderer-clear SOURCES renderer/01-clear/clear.c) +add_sdl_example_executable(renderer-primitives SOURCES renderer/02-primitives/primitives.c) +add_sdl_example_executable(renderer-lines SOURCES renderer/03-lines/lines.c) +add_sdl_example_executable(renderer-points SOURCES renderer/04-points/points.c) +add_sdl_example_executable(renderer-rectangles SOURCES renderer/05-rectangles/rectangles.c) +add_sdl_example_executable(renderer-textures SOURCES renderer/06-textures/textures.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/../test/sample.bmp) +add_sdl_example_executable(renderer-streaming-textures SOURCES renderer/07-streaming-textures/streaming-textures.c) +add_sdl_example_executable(renderer-rotating-textures SOURCES renderer/08-rotating-textures/rotating-textures.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/../test/sample.bmp) +add_sdl_example_executable(renderer-scaling-textures SOURCES renderer/09-scaling-textures/scaling-textures.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/../test/sample.bmp) +add_sdl_example_executable(renderer-geometry SOURCES renderer/10-geometry/geometry.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/../test/sample.bmp) add_sdl_example_executable(audio-simple-playback SOURCES audio/01-simple-playback/simple-playback.c) add_sdl_example_executable(audio-simple-playback-callback SOURCES audio/02-simple-playback-callback/simple-playback-callback.c) add_sdl_example_executable(audio-load-wav SOURCES audio/03-load-wav/load-wav.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/../test/sample.wav) diff --git a/external/SDL/examples/renderer/01-clear/renderer-clear.c b/external/SDL/examples/renderer/01-clear/clear.c similarity index 100% rename from external/SDL/examples/renderer/01-clear/renderer-clear.c rename to external/SDL/examples/renderer/01-clear/clear.c diff --git a/external/SDL/examples/renderer/02-primitives/README.txt b/external/SDL/examples/renderer/02-primitives/README.txt index 1e2bfce8..82da8e52 100644 --- a/external/SDL/examples/renderer/02-primitives/README.txt +++ b/external/SDL/examples/renderer/02-primitives/README.txt @@ -1,3 +1,7 @@ This example creates an SDL window and renderer, and then draws some lines, rectangles and points to it every frame. +This is just a quick overview of simple drawing primitives; futher examples +will explore them in more detail. + + diff --git a/external/SDL/examples/renderer/02-primitives/renderer-primitives.c b/external/SDL/examples/renderer/02-primitives/primitives.c similarity index 100% rename from external/SDL/examples/renderer/02-primitives/renderer-primitives.c rename to external/SDL/examples/renderer/02-primitives/primitives.c diff --git a/external/SDL/examples/renderer/03-lines/README.txt b/external/SDL/examples/renderer/03-lines/README.txt new file mode 100644 index 00000000..4abeab61 --- /dev/null +++ b/external/SDL/examples/renderer/03-lines/README.txt @@ -0,0 +1,3 @@ +This example creates an SDL window and renderer, and then draws a something +roughly like a Christmas tree with nothing but lines, every frame. + diff --git a/external/SDL/examples/renderer/03-lines/lines.c b/external/SDL/examples/renderer/03-lines/lines.c new file mode 100644 index 00000000..459af73d --- /dev/null +++ b/external/SDL/examples/renderer/03-lines/lines.c @@ -0,0 +1,93 @@ +/* + * This example creates an SDL window and renderer, and then draws some lines + * to it every frame. + * + * This code is public domain. Feel free to use it for any purpose! + */ + +#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */ +#include +#include + +/* We will use this renderer to draw into this window every frame. */ +static SDL_Window *window = NULL; +static SDL_Renderer *renderer = NULL; + +/* This function runs once at startup. */ +SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) +{ + if (!SDL_Init(SDL_INIT_VIDEO)) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't initialize SDL!", SDL_GetError(), NULL); + return SDL_APP_FAILURE; + } + + if (!SDL_CreateWindowAndRenderer("examples/renderer/lines", 640, 480, 0, &window, &renderer)) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create window/renderer!", SDL_GetError(), NULL); + return SDL_APP_FAILURE; + } + + SDL_srand(0); /* seed the random number generator */ + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs when a new event (mouse input, keypresses, etc) occurs. */ +SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) +{ + if (event->type == SDL_EVENT_QUIT) { + return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */ + } + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs once per frame, and is the heart of the program. */ +SDL_AppResult SDL_AppIterate(void *appstate) +{ + int i; + + /* Lines (line segments, really) are drawn in terms of points: a set of + X and Y coordinates, one set for each end of the line. + (0, 0) is the top left of the window, and larger numbers go down + and to the right. This isn't how geometry works, but this is pretty + standard in 2D graphics. */ + static const SDL_FPoint line_points[] = { + { 100, 354 }, { 220, 230 }, { 140, 230 }, { 320, 100 }, { 500, 230 }, + { 420, 230 }, { 540, 354 }, { 400, 354 }, { 100, 354 } + }; + + /* as you can see from this, rendering draws over whatever was drawn before it. */ + SDL_SetRenderDrawColor(renderer, 100, 100, 100, 255); /* grey, full alpha */ + SDL_RenderClear(renderer); /* start with a blank canvas. */ + + /* You can draw lines, one at a time, like these brown ones... */ + SDL_SetRenderDrawColor(renderer, 127, 49, 32, 255); + SDL_RenderLine(renderer, 240, 450, 400, 450); + SDL_RenderLine(renderer, 240, 356, 400, 356); + SDL_RenderLine(renderer, 240, 356, 240, 450); + SDL_RenderLine(renderer, 400, 356, 400, 450); + + /* You can also draw a series of connected lines in a single batch... */ + SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255); + SDL_RenderLines(renderer, line_points, SDL_arraysize(line_points)); + + /* here's a bunch of lines drawn out from a center point in a circle. */ + /* we randomize the color of each line, so it functions as animation. */ + for (i = 0; i < 360; i++) { + const float size = 30.0f; + const float x = 320.0f; + const float y = 95.0f - (size / 2.0f); + SDL_SetRenderDrawColor(renderer, SDL_rand(256), SDL_rand(256), SDL_rand(256), 255); + SDL_RenderLine(renderer, x, y, x + SDL_sinf((float) i) * size, y + SDL_cosf((float) i) * size); + } + + SDL_RenderPresent(renderer); /* put it all on the screen! */ + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs once at shutdown. */ +void SDL_AppQuit(void *appstate) +{ + /* SDL will clean up the window/renderer for us. */ +} + diff --git a/external/SDL/examples/renderer/04-points/README.txt b/external/SDL/examples/renderer/04-points/README.txt new file mode 100644 index 00000000..00e94191 --- /dev/null +++ b/external/SDL/examples/renderer/04-points/README.txt @@ -0,0 +1,3 @@ +This example creates an SDL window and renderer, and then draws a bunch of +single points, moving across the screen. + diff --git a/external/SDL/examples/renderer/04-points/points.c b/external/SDL/examples/renderer/04-points/points.c new file mode 100644 index 00000000..468a30ab --- /dev/null +++ b/external/SDL/examples/renderer/04-points/points.c @@ -0,0 +1,118 @@ +/* + * This example creates an SDL window and renderer, and then draws some points + * to it every frame. + * + * This code is public domain. Feel free to use it for any purpose! + */ + +#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */ +#include +#include + +/* We will use this renderer to draw into this window every frame. */ +static SDL_Window *window = NULL; +static SDL_Renderer *renderer = NULL; +static Uint64 last_time = 0; + +#define WINDOW_WIDTH 640 +#define WINDOW_HEIGHT 480 + +#define NUM_POINTS 500 +#define MIN_PIXELS_PER_SECOND 30 /* move at least this many pixels per second. */ +#define MAX_PIXELS_PER_SECOND 60 /* move this many pixels per second at most. */ + +/* (track everything as parallel arrays instead of a array of structs, + so we can pass the coordinates to the renderer in a single function call.) */ + +/* Points are plotted as a set of X and Y coordinates. + (0, 0) is the top left of the window, and larger numbers go down + and to the right. This isn't how geometry works, but this is pretty + standard in 2D graphics. */ +static SDL_FPoint points[NUM_POINTS]; +static float point_speeds[NUM_POINTS]; + +/* This function runs once at startup. */ +SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) +{ + int i; + + if (!SDL_Init(SDL_INIT_VIDEO)) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't initialize SDL!", SDL_GetError(), NULL); + return SDL_APP_FAILURE; + } + + if (!SDL_CreateWindowAndRenderer("examples/renderer/points", WINDOW_WIDTH, WINDOW_HEIGHT, 0, &window, &renderer)) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create window/renderer!", SDL_GetError(), NULL); + return SDL_APP_FAILURE; + } + + SDL_srand(0); /* seed the random number generator */ + + /* set up the data for a bunch of points. */ + for (i = 0; i < SDL_arraysize(points); i++) { + points[i].x = SDL_randf() * ((float) WINDOW_WIDTH); + points[i].y = SDL_randf() * ((float) WINDOW_HEIGHT); + point_speeds[i] = MIN_PIXELS_PER_SECOND + (SDL_randf() * (MAX_PIXELS_PER_SECOND - MIN_PIXELS_PER_SECOND)); + } + + last_time = SDL_GetTicks(); + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs when a new event (mouse input, keypresses, etc) occurs. */ +SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) +{ + if (event->type == SDL_EVENT_QUIT) { + return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */ + } + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs once per frame, and is the heart of the program. */ +SDL_AppResult SDL_AppIterate(void *appstate) +{ + const Uint64 now = SDL_GetTicks(); + const float elapsed = ((float) (now - last_time)) / 1000.0f; /* seconds since last iteration */ + int i; + + /* let's move all our points a little for a new frame. */ + for (i = 0; i < SDL_arraysize(points); i++) { + const float distance = elapsed * point_speeds[i]; + points[i].x += distance; + points[i].y += distance; + if ((points[i].x >= WINDOW_WIDTH) || (points[i].y >= WINDOW_HEIGHT)) { + /* off the screen; restart it elsewhere! */ + if (SDL_rand(2)) { + points[i].x = SDL_randf() * ((float) WINDOW_WIDTH); + points[i].y = 0.0f; + } else { + points[i].x = 0.0f; + points[i].y = SDL_randf() * ((float) WINDOW_HEIGHT); + } + point_speeds[i] = MIN_PIXELS_PER_SECOND + (SDL_randf() * (MAX_PIXELS_PER_SECOND - MIN_PIXELS_PER_SECOND)); + } + } + + last_time = now; + + /* as you can see from this, rendering draws over whatever was drawn before it. */ + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); /* black, full alpha */ + SDL_RenderClear(renderer); /* start with a blank canvas. */ + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); /* white, full alpha */ + SDL_RenderPoints(renderer, points, SDL_arraysize(points)); /* draw all the points! */ + + /* You can also draw single points with SDL_RenderPoint(), but it's + cheaper (sometimes significantly so) to do them all at once. */ + + SDL_RenderPresent(renderer); /* put it all on the screen! */ + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs once at shutdown. */ +void SDL_AppQuit(void *appstate) +{ + /* SDL will clean up the window/renderer for us. */ +} + diff --git a/external/SDL/examples/renderer/05-rectangles/README.txt b/external/SDL/examples/renderer/05-rectangles/README.txt new file mode 100644 index 00000000..26613c70 --- /dev/null +++ b/external/SDL/examples/renderer/05-rectangles/README.txt @@ -0,0 +1,3 @@ +This example creates an SDL window and renderer, and then draws a few +rectangles that change size each frame. + diff --git a/external/SDL/examples/renderer/05-rectangles/rectangles.c b/external/SDL/examples/renderer/05-rectangles/rectangles.c new file mode 100644 index 00000000..2fd2ba80 --- /dev/null +++ b/external/SDL/examples/renderer/05-rectangles/rectangles.c @@ -0,0 +1,110 @@ +/* + * This example creates an SDL window and renderer, and then draws some + * rectangles to it every frame. + * + * This code is public domain. Feel free to use it for any purpose! + */ + +#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */ +#include +#include + +/* We will use this renderer to draw into this window every frame. */ +static SDL_Window *window = NULL; +static SDL_Renderer *renderer = NULL; + +#define WINDOW_WIDTH 640 +#define WINDOW_HEIGHT 480 + +/* This function runs once at startup. */ +SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) +{ + if (!SDL_Init(SDL_INIT_VIDEO)) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't initialize SDL!", SDL_GetError(), NULL); + return SDL_APP_FAILURE; + } + + if (!SDL_CreateWindowAndRenderer("examples/renderer/rectangles", WINDOW_WIDTH, WINDOW_HEIGHT, 0, &window, &renderer)) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create window/renderer!", SDL_GetError(), NULL); + return SDL_APP_FAILURE; + } + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs when a new event (mouse input, keypresses, etc) occurs. */ +SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) +{ + if (event->type == SDL_EVENT_QUIT) { + return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */ + } + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs once per frame, and is the heart of the program. */ +SDL_AppResult SDL_AppIterate(void *appstate) +{ + SDL_FRect rects[16]; + const Uint64 now = SDL_GetTicks(); + int i; + + /* we'll have the rectangles grow and shrink over a few seconds. */ + const float direction = ((now % 2000) >= 1000) ? 1.0f : -1.0f; + const float scale = ((float) (((int) (now % 1000)) - 500) / 500.0f) * direction; + + /* as you can see from this, rendering draws over whatever was drawn before it. */ + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); /* black, full alpha */ + SDL_RenderClear(renderer); /* start with a blank canvas. */ + + /* Rectangles are comprised of set of X and Y coordinates, plus width and + height. (0, 0) is the top left of the window, and larger numbers go + down and to the right. This isn't how geometry works, but this is + pretty standard in 2D graphics. */ + + /* Let's draw a single rectangle (square, really). */ + rects[0].x = rects[0].y = 100; + rects[0].w = rects[0].h = 100 + (100 * scale); + SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); /* red, full alpha */ + SDL_RenderRect(renderer, &rects[0]); + + /* Now let's draw several rectangles with one function call. */ + for (i = 0; i < 3; i++) { + const float size = (i+1) * 50.0f; + rects[i].w = rects[i].h = size + (size * scale); + rects[i].x = (WINDOW_WIDTH - rects[i].w) / 2; /* center it. */ + rects[i].y = (WINDOW_HEIGHT - rects[i].h) / 2; /* center it. */ + } + SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255); /* green, full alpha */ + SDL_RenderRects(renderer, rects, 3); /* draw three rectangles at once */ + + /* those were rectangle _outlines_, really. You can also draw _filled_ rectangles! */ + rects[0].x = 400; + rects[0].y = 50; + rects[0].w = 100 + (100 * scale); + rects[0].h = 50 + (50 * scale); + SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255); /* blue, full alpha */ + SDL_RenderFillRect(renderer, &rects[0]); + + /* ...and also fill a bunch of rectangles at once... */ + for (i = 0; i < SDL_arraysize(rects); i++) { + const float w = (float) (WINDOW_WIDTH / SDL_arraysize(rects)); + const float h = i * 8.0f; + rects[i].x = i * w; + rects[i].y = WINDOW_HEIGHT - h; + rects[i].w = w; + rects[i].h = h; + } + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); /* white, full alpha */ + SDL_RenderFillRects(renderer, rects, SDL_arraysize(rects)); + + SDL_RenderPresent(renderer); /* put it all on the screen! */ + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs once at shutdown. */ +void SDL_AppQuit(void *appstate) +{ + /* SDL will clean up the window/renderer for us. */ +} + diff --git a/external/SDL/examples/renderer/06-textures/README.txt b/external/SDL/examples/renderer/06-textures/README.txt new file mode 100644 index 00000000..21c3f0bc --- /dev/null +++ b/external/SDL/examples/renderer/06-textures/README.txt @@ -0,0 +1,3 @@ +This example creates an SDL window and renderer, loads a texture from a +.bmp file, and then draws it a few times each frame. + diff --git a/external/SDL/examples/renderer/06-textures/textures.c b/external/SDL/examples/renderer/06-textures/textures.c new file mode 100644 index 00000000..a0bdb6c1 --- /dev/null +++ b/external/SDL/examples/renderer/06-textures/textures.c @@ -0,0 +1,125 @@ +/* + * This example creates an SDL window and renderer, and then draws some + * textures to it every frame. + * + * This code is public domain. Feel free to use it for any purpose! + */ + +#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */ +#include +#include + +/* We will use this renderer to draw into this window every frame. */ +static SDL_Window *window = NULL; +static SDL_Renderer *renderer = NULL; +static SDL_Texture *texture = NULL; +static int texture_width = 0; +static int texture_height = 0; + +#define WINDOW_WIDTH 640 +#define WINDOW_HEIGHT 480 + +/* This function runs once at startup. */ +SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) +{ + SDL_Surface *surface = NULL; + char *bmp_path = NULL; + + if (!SDL_Init(SDL_INIT_VIDEO)) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't initialize SDL!", SDL_GetError(), NULL); + return SDL_APP_FAILURE; + } + + if (!SDL_CreateWindowAndRenderer("examples/renderer/textures", WINDOW_WIDTH, WINDOW_HEIGHT, 0, &window, &renderer)) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create window/renderer!", SDL_GetError(), NULL); + return SDL_APP_FAILURE; + } + + /* Textures are pixel data that we upload to the video hardware for fast drawing. Lots of 2D + engines refer to these as "sprites." We'll do a static texture (upload once, draw many + times) with data from a bitmap file. */ + + /* SDL_Surface is pixel data the CPU can access. SDL_Texture is pixel data the GPU can access. + Load a .bmp into a surface, move it to a texture from there. */ + SDL_asprintf(&bmp_path, "%ssample.bmp", SDL_GetBasePath()); /* allocate a string of the full file path */ + surface = SDL_LoadBMP(bmp_path); + if (!surface) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't load bitmap!", SDL_GetError(), NULL); + return SDL_APP_FAILURE; + } + + SDL_free(bmp_path); /* done with this, the file is loaded. */ + + texture_width = surface->w; + texture_height = surface->h; + + texture = SDL_CreateTextureFromSurface(renderer, surface); + if (!texture) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create static texture!", SDL_GetError(), NULL); + return SDL_APP_FAILURE; + } + + SDL_DestroySurface(surface); /* done with this, the texture has a copy of the pixels now. */ + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs when a new event (mouse input, keypresses, etc) occurs. */ +SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) +{ + if (event->type == SDL_EVENT_QUIT) { + return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */ + } + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs once per frame, and is the heart of the program. */ +SDL_AppResult SDL_AppIterate(void *appstate) +{ + SDL_FRect dst_rect; + const Uint64 now = SDL_GetTicks(); + + /* we'll have some textures move around over a few seconds. */ + const float direction = ((now % 2000) >= 1000) ? 1.0f : -1.0f; + const float scale = ((float) (((int) (now % 1000)) - 500) / 500.0f) * direction; + + /* as you can see from this, rendering draws over whatever was drawn before it. */ + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); /* black, full alpha */ + SDL_RenderClear(renderer); /* start with a blank canvas. */ + + /* Just draw the static texture a few times. You can think of it like a + stamp, there isn't a limit to the number of times you can draw with it. */ + + /* top left */ + dst_rect.x = (100.0f * scale); + dst_rect.y = 0.0f; + dst_rect.w = (float) texture_width; + dst_rect.h = (float) texture_height; + SDL_RenderTexture(renderer, texture, NULL, &dst_rect); + + /* center this one. */ + dst_rect.x = ((float) (WINDOW_WIDTH - texture_width)) / 2.0f; + dst_rect.y = ((float) (WINDOW_HEIGHT - texture_height)) / 2.0f; + dst_rect.w = (float) texture_width; + dst_rect.h = (float) texture_height; + SDL_RenderTexture(renderer, texture, NULL, &dst_rect); + + /* bottom right. */ + dst_rect.x = ((float) (WINDOW_WIDTH - texture_width)) - (100.0f * scale); + dst_rect.y = (float) (WINDOW_HEIGHT - texture_height); + dst_rect.w = (float) texture_width; + dst_rect.h = (float) texture_height; + SDL_RenderTexture(renderer, texture, NULL, &dst_rect); + + SDL_RenderPresent(renderer); /* put it all on the screen! */ + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs once at shutdown. */ +void SDL_AppQuit(void *appstate) +{ + SDL_DestroyTexture(texture); + /* SDL will clean up the window/renderer for us. */ +} + diff --git a/external/SDL/examples/renderer/07-streaming-textures/README.txt b/external/SDL/examples/renderer/07-streaming-textures/README.txt new file mode 100644 index 00000000..c2505719 --- /dev/null +++ b/external/SDL/examples/renderer/07-streaming-textures/README.txt @@ -0,0 +1,3 @@ +This example creates an SDL window and renderer, then a streaming texture that +it will update every frame before drawing it to the screen. + diff --git a/external/SDL/examples/renderer/07-streaming-textures/streaming-textures.c b/external/SDL/examples/renderer/07-streaming-textures/streaming-textures.c new file mode 100644 index 00000000..6b3a2d29 --- /dev/null +++ b/external/SDL/examples/renderer/07-streaming-textures/streaming-textures.c @@ -0,0 +1,107 @@ +/* + * This example creates an SDL window and renderer, and then draws a streaming + * texture to it every frame. + * + * This code is public domain. Feel free to use it for any purpose! + */ + +#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */ +#include +#include + +/* We will use this renderer to draw into this window every frame. */ +static SDL_Window *window = NULL; +static SDL_Renderer *renderer = NULL; +static SDL_Texture *texture = NULL; + +#define TEXTURE_SIZE 150 + +#define WINDOW_WIDTH 640 +#define WINDOW_HEIGHT 480 + +/* This function runs once at startup. */ +SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) +{ + if (!SDL_Init(SDL_INIT_VIDEO)) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't initialize SDL!", SDL_GetError(), NULL); + return SDL_APP_FAILURE; + } + + if (!SDL_CreateWindowAndRenderer("examples/renderer/streaming-textures", WINDOW_WIDTH, WINDOW_HEIGHT, 0, &window, &renderer)) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create window/renderer!", SDL_GetError(), NULL); + return SDL_APP_FAILURE; + } + + texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, TEXTURE_SIZE, TEXTURE_SIZE); + if (!texture) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create streaming texture!", SDL_GetError(), NULL); + return SDL_APP_FAILURE; + } + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs when a new event (mouse input, keypresses, etc) occurs. */ +SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) +{ + if (event->type == SDL_EVENT_QUIT) { + return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */ + } + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs once per frame, and is the heart of the program. */ +SDL_AppResult SDL_AppIterate(void *appstate) +{ + SDL_FRect dst_rect; + const Uint64 now = SDL_GetTicks(); + SDL_Surface *surface = NULL; + + /* we'll have some color move around over a few seconds. */ + const float direction = ((now % 2000) >= 1000) ? 1.0f : -1.0f; + const float scale = ((float) (((int) (now % 1000)) - 500) / 500.0f) * direction; + + /* To update a streaming texture, you need to lock it first. This gets you access to the pixels. + Note that this is considered a _write-only_ operation: the buffer you get from locking + might not acutally have the existing contents of the texture, and you have to write to every + locked pixel! */ + + /* You can use SDL_LockTexture() to get an array of raw pixels, but we're going to use + SDL_LockTextureToSurface() here, because it wraps that array in a temporary SDL_Surface, + letting us use the surface drawing functions instead of lighting up individual pixels. */ + if (SDL_LockTextureToSurface(texture, NULL, &surface)) { + SDL_Rect r; + SDL_FillSurfaceRect(surface, NULL, SDL_MapRGB(SDL_GetPixelFormatDetails(surface->format), NULL, 0, 0, 0)); /* make the whole surface black */ + r.w = TEXTURE_SIZE; + r.h = TEXTURE_SIZE / 10; + r.x = 0; + r.y = (int) (((float) (TEXTURE_SIZE - r.h)) * ((scale + 1.0f) / 2.0f)); + SDL_FillSurfaceRect(surface, &r, SDL_MapRGB(SDL_GetPixelFormatDetails(surface->format), NULL, 0, 255, 0)); /* make a strip of the surface green */ + SDL_UnlockTexture(texture); /* upload the changes (and frees the temporary surface)! */ + } + + /* as you can see from this, rendering draws over whatever was drawn before it. */ + SDL_SetRenderDrawColor(renderer, 66, 66, 66, 255); /* grey, full alpha */ + SDL_RenderClear(renderer); /* start with a blank canvas. */ + + /* Just draw the static texture a few times. You can think of it like a + stamp, there isn't a limit to the number of times you can draw with it. */ + + /* Center this one. It'll draw the latest version of the texture we drew while it was locked. */ + dst_rect.x = ((float) (WINDOW_WIDTH - TEXTURE_SIZE)) / 2.0f; + dst_rect.y = ((float) (WINDOW_HEIGHT - TEXTURE_SIZE)) / 2.0f; + dst_rect.w = dst_rect.h = (float) TEXTURE_SIZE; + SDL_RenderTexture(renderer, texture, NULL, &dst_rect); + + SDL_RenderPresent(renderer); /* put it all on the screen! */ + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs once at shutdown. */ +void SDL_AppQuit(void *appstate) +{ + SDL_DestroyTexture(texture); + /* SDL will clean up the window/renderer for us. */ +} + diff --git a/external/SDL/examples/renderer/08-rotating-textures/README.txt b/external/SDL/examples/renderer/08-rotating-textures/README.txt new file mode 100644 index 00000000..4ae46bc2 --- /dev/null +++ b/external/SDL/examples/renderer/08-rotating-textures/README.txt @@ -0,0 +1,3 @@ +This example creates an SDL window and renderer, loads a texture from a .bmp +file, and then draws it, rotating around the center of the screen. + diff --git a/external/SDL/examples/renderer/08-rotating-textures/rotating-textures.c b/external/SDL/examples/renderer/08-rotating-textures/rotating-textures.c new file mode 100644 index 00000000..b7121124 --- /dev/null +++ b/external/SDL/examples/renderer/08-rotating-textures/rotating-textures.c @@ -0,0 +1,111 @@ +/* + * This example creates an SDL window and renderer, and then draws some + * rotated textures to it every frame. + * + * This code is public domain. Feel free to use it for any purpose! + */ + +#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */ +#include +#include + +/* We will use this renderer to draw into this window every frame. */ +static SDL_Window *window = NULL; +static SDL_Renderer *renderer = NULL; +static SDL_Texture *texture = NULL; +static int texture_width = 0; +static int texture_height = 0; + +#define WINDOW_WIDTH 640 +#define WINDOW_HEIGHT 480 + +/* This function runs once at startup. */ +SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) +{ + SDL_Surface *surface = NULL; + char *bmp_path = NULL; + + if (!SDL_Init(SDL_INIT_VIDEO)) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't initialize SDL!", SDL_GetError(), NULL); + return SDL_APP_FAILURE; + } + + if (!SDL_CreateWindowAndRenderer("examples/renderer/rotating-textures", WINDOW_WIDTH, WINDOW_HEIGHT, 0, &window, &renderer)) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create window/renderer!", SDL_GetError(), NULL); + return SDL_APP_FAILURE; + } + + /* Textures are pixel data that we upload to the video hardware for fast drawing. Lots of 2D + engines refer to these as "sprites." We'll do a static texture (upload once, draw many + times) with data from a bitmap file. */ + + /* SDL_Surface is pixel data the CPU can access. SDL_Texture is pixel data the GPU can access. + Load a .bmp into a surface, move it to a texture from there. */ + SDL_asprintf(&bmp_path, "%ssample.bmp", SDL_GetBasePath()); /* allocate a string of the full file path */ + surface = SDL_LoadBMP(bmp_path); + if (!surface) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't load bitmap!", SDL_GetError(), NULL); + return SDL_APP_FAILURE; + } + + SDL_free(bmp_path); /* done with this, the file is loaded. */ + + texture_width = surface->w; + texture_height = surface->h; + + texture = SDL_CreateTextureFromSurface(renderer, surface); + if (!texture) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create static texture!", SDL_GetError(), NULL); + return SDL_APP_FAILURE; + } + + SDL_DestroySurface(surface); /* done with this, the texture has a copy of the pixels now. */ + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs when a new event (mouse input, keypresses, etc) occurs. */ +SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) +{ + if (event->type == SDL_EVENT_QUIT) { + return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */ + } + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs once per frame, and is the heart of the program. */ +SDL_AppResult SDL_AppIterate(void *appstate) +{ + SDL_FPoint center; + SDL_FRect dst_rect; + const Uint64 now = SDL_GetTicks(); + + /* we'll have a texture rotate around over 2 seconds (2000 milliseconds). 360 degrees in a circle! */ + const float rotation = (((float) ((int) (now % 2000))) / 2000.0f) * 360.0f; + + /* as you can see from this, rendering draws over whatever was drawn before it. */ + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); /* black, full alpha */ + SDL_RenderClear(renderer); /* start with a blank canvas. */ + + /* Center this one, and draw it with some rotation so it spins! */ + dst_rect.x = ((float) (WINDOW_WIDTH - texture_width)) / 2.0f; + dst_rect.y = ((float) (WINDOW_HEIGHT - texture_height)) / 2.0f; + dst_rect.w = (float) texture_width; + dst_rect.h = (float) texture_height; + /* rotate it around the center of the texture; you can rotate it from a different point, too! */ + center.x = texture_width / 2.0f; + center.y = texture_height / 2.0f; + SDL_RenderTextureRotated(renderer, texture, NULL, &dst_rect, rotation, ¢er, SDL_FLIP_NONE); + + SDL_RenderPresent(renderer); /* put it all on the screen! */ + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs once at shutdown. */ +void SDL_AppQuit(void *appstate) +{ + SDL_DestroyTexture(texture); + /* SDL will clean up the window/renderer for us. */ +} + diff --git a/external/SDL/examples/renderer/09-scaling-textures/README.txt b/external/SDL/examples/renderer/09-scaling-textures/README.txt new file mode 100644 index 00000000..e13a6ec2 --- /dev/null +++ b/external/SDL/examples/renderer/09-scaling-textures/README.txt @@ -0,0 +1,3 @@ +This example creates an SDL window and renderer, loads a texture from a .bmp +file, and then draws it, scaling it up and down. + diff --git a/external/SDL/examples/renderer/09-scaling-textures/scaling-textures.c b/external/SDL/examples/renderer/09-scaling-textures/scaling-textures.c new file mode 100644 index 00000000..bcb9845f --- /dev/null +++ b/external/SDL/examples/renderer/09-scaling-textures/scaling-textures.c @@ -0,0 +1,108 @@ +/* + * This example creates an SDL window and renderer, and then draws some + * textures to it every frame. + * + * This code is public domain. Feel free to use it for any purpose! + */ + +#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */ +#include +#include + +/* We will use this renderer to draw into this window every frame. */ +static SDL_Window *window = NULL; +static SDL_Renderer *renderer = NULL; +static SDL_Texture *texture = NULL; +static int texture_width = 0; +static int texture_height = 0; + +#define WINDOW_WIDTH 640 +#define WINDOW_HEIGHT 480 + +/* This function runs once at startup. */ +SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) +{ + SDL_Surface *surface = NULL; + char *bmp_path = NULL; + + if (!SDL_Init(SDL_INIT_VIDEO)) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't initialize SDL!", SDL_GetError(), NULL); + return SDL_APP_FAILURE; + } + + if (!SDL_CreateWindowAndRenderer("examples/renderer/scaling-textures", WINDOW_WIDTH, WINDOW_HEIGHT, 0, &window, &renderer)) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create window/renderer!", SDL_GetError(), NULL); + return SDL_APP_FAILURE; + } + + /* Textures are pixel data that we upload to the video hardware for fast drawing. Lots of 2D + engines refer to these as "sprites." We'll do a static texture (upload once, draw many + times) with data from a bitmap file. */ + + /* SDL_Surface is pixel data the CPU can access. SDL_Texture is pixel data the GPU can access. + Load a .bmp into a surface, move it to a texture from there. */ + SDL_asprintf(&bmp_path, "%ssample.bmp", SDL_GetBasePath()); /* allocate a string of the full file path */ + surface = SDL_LoadBMP(bmp_path); + if (!surface) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't load bitmap!", SDL_GetError(), NULL); + return SDL_APP_FAILURE; + } + + SDL_free(bmp_path); /* done with this, the file is loaded. */ + + texture_width = surface->w; + texture_height = surface->h; + + texture = SDL_CreateTextureFromSurface(renderer, surface); + if (!texture) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create static texture!", SDL_GetError(), NULL); + return SDL_APP_FAILURE; + } + + SDL_DestroySurface(surface); /* done with this, the texture has a copy of the pixels now. */ + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs when a new event (mouse input, keypresses, etc) occurs. */ +SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) +{ + if (event->type == SDL_EVENT_QUIT) { + return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */ + } + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs once per frame, and is the heart of the program. */ +SDL_AppResult SDL_AppIterate(void *appstate) +{ + SDL_FRect dst_rect; + const Uint64 now = SDL_GetTicks(); + + /* we'll have the texture grow and shrink over a few seconds. */ + const float direction = ((now % 2000) >= 1000) ? 1.0f : -1.0f; + const float scale = ((float) (((int) (now % 1000)) - 500) / 500.0f) * direction; + + /* as you can see from this, rendering draws over whatever was drawn before it. */ + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); /* black, full alpha */ + SDL_RenderClear(renderer); /* start with a blank canvas. */ + + /* center this one and make it grow and shrink. */ + dst_rect.w = (float) texture_width + (texture_width * scale); + dst_rect.h = (float) texture_height + (texture_height * scale); + dst_rect.x = ((float) (WINDOW_WIDTH - dst_rect.w)) / 2.0f; + dst_rect.y = ((float) (WINDOW_HEIGHT - dst_rect.h)) / 2.0f; + SDL_RenderTexture(renderer, texture, NULL, &dst_rect); + + SDL_RenderPresent(renderer); /* put it all on the screen! */ + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs once at shutdown. */ +void SDL_AppQuit(void *appstate) +{ + SDL_DestroyTexture(texture); + /* SDL will clean up the window/renderer for us. */ +} + diff --git a/external/SDL/examples/renderer/10-geometry/README.txt b/external/SDL/examples/renderer/10-geometry/README.txt new file mode 100644 index 00000000..d76d0cce --- /dev/null +++ b/external/SDL/examples/renderer/10-geometry/README.txt @@ -0,0 +1,3 @@ +This example creates an SDL window and renderer, loads a texture from a .bmp +file, and then draws geometry (arbitrary polygons) using it. + diff --git a/external/SDL/examples/renderer/10-geometry/geometry.c b/external/SDL/examples/renderer/10-geometry/geometry.c new file mode 100644 index 00000000..b5621f87 --- /dev/null +++ b/external/SDL/examples/renderer/10-geometry/geometry.c @@ -0,0 +1,164 @@ +/* + * This example creates an SDL window and renderer, and then draws some + * geometry (arbitrary polygons) to it every frame. + * + * This code is public domain. Feel free to use it for any purpose! + */ + +#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */ +#include +#include + +/* We will use this renderer to draw into this window every frame. */ +static SDL_Window *window = NULL; +static SDL_Renderer *renderer = NULL; +static SDL_Texture *texture = NULL; +static int texture_width = 0; +static int texture_height = 0; + +#define WINDOW_WIDTH 640 +#define WINDOW_HEIGHT 480 + +/* This function runs once at startup. */ +SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) +{ + SDL_Surface *surface = NULL; + char *bmp_path = NULL; + + if (!SDL_Init(SDL_INIT_VIDEO)) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't initialize SDL!", SDL_GetError(), NULL); + return SDL_APP_FAILURE; + } + + if (!SDL_CreateWindowAndRenderer("examples/renderer/geometry", WINDOW_WIDTH, WINDOW_HEIGHT, 0, &window, &renderer)) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create window/renderer!", SDL_GetError(), NULL); + return SDL_APP_FAILURE; + } + + /* Textures are pixel data that we upload to the video hardware for fast drawing. Lots of 2D + engines refer to these as "sprites." We'll do a static texture (upload once, draw many + times) with data from a bitmap file. */ + + /* SDL_Surface is pixel data the CPU can access. SDL_Texture is pixel data the GPU can access. + Load a .bmp into a surface, move it to a texture from there. */ + SDL_asprintf(&bmp_path, "%ssample.bmp", SDL_GetBasePath()); /* allocate a string of the full file path */ + surface = SDL_LoadBMP(bmp_path); + if (!surface) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't load bitmap!", SDL_GetError(), NULL); + return SDL_APP_FAILURE; + } + + SDL_free(bmp_path); /* done with this, the file is loaded. */ + + texture_width = surface->w; + texture_height = surface->h; + + texture = SDL_CreateTextureFromSurface(renderer, surface); + if (!texture) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create static texture!", SDL_GetError(), NULL); + return SDL_APP_FAILURE; + } + + SDL_DestroySurface(surface); /* done with this, the texture has a copy of the pixels now. */ + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs when a new event (mouse input, keypresses, etc) occurs. */ +SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) +{ + if (event->type == SDL_EVENT_QUIT) { + return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */ + } + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs once per frame, and is the heart of the program. */ +SDL_AppResult SDL_AppIterate(void *appstate) +{ + const Uint64 now = SDL_GetTicks(); + + /* we'll have the triangle grow and shrink over a few seconds. */ + const float direction = ((now % 2000) >= 1000) ? 1.0f : -1.0f; + const float scale = ((float) (((int) (now % 1000)) - 500) / 500.0f) * direction; + const float size = 200.0f + (200.0f * scale); + + SDL_Vertex vertices[4]; + int i; + + /* as you can see from this, rendering draws over whatever was drawn before it. */ + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); /* black, full alpha */ + SDL_RenderClear(renderer); /* start with a blank canvas. */ + + /* Draw a single triangle with a different color at each vertex. Center this one and make it grow and shrink. */ + /* You always draw triangles with this, but you can string triangles together to form polygons. */ + SDL_zeroa(vertices); + vertices[0].position.x = ((float) WINDOW_WIDTH) / 2.0f; + vertices[0].position.y = (((float) WINDOW_HEIGHT) - size) / 2.0f; + vertices[0].color.r = 1.0f; + vertices[0].color.a = 1.0f; + vertices[1].position.x = (((float) WINDOW_WIDTH) + size) / 2.0f; + vertices[1].position.y = (((float) WINDOW_HEIGHT) + size) / 2.0f; + vertices[1].color.g = 1.0f; + vertices[1].color.a = 1.0f; + vertices[2].position.x = (((float) WINDOW_WIDTH) - size) / 2.0f; + vertices[2].position.y = (((float) WINDOW_HEIGHT) + size) / 2.0f; + vertices[2].color.b = 1.0f; + vertices[2].color.a = 1.0f; + + SDL_RenderGeometry(renderer, NULL, vertices, 3, NULL, 0); + + /* you can also map a texture to the geometry! Texture coordinates go from 0.0f to 1.0f. That will be the location + in the texture bound to this vertex. */ + SDL_zeroa(vertices); + vertices[0].position.x = 10.0f; + vertices[0].position.y = 10.0f; + vertices[0].color.r = vertices[0].color.g = vertices[0].color.b = vertices[0].color.a = 1.0f; + vertices[0].tex_coord.x = 0.0f; + vertices[0].tex_coord.y = 0.0f; + vertices[1].position.x = 150.0f; + vertices[1].position.y = 10.0f; + vertices[1].color.r = vertices[1].color.g = vertices[1].color.b = vertices[1].color.a = 1.0f; + vertices[1].tex_coord.x = 1.0f; + vertices[1].tex_coord.y = 0.0f; + vertices[2].position.x = 10.0f; + vertices[2].position.y = 150.0f; + vertices[2].color.r = vertices[2].color.g = vertices[2].color.b = vertices[2].color.a = 1.0f; + vertices[2].tex_coord.x = 0.0f; + vertices[2].tex_coord.y = 1.0f; + SDL_RenderGeometry(renderer, texture, vertices, 3, NULL, 0); + + /* Did that only draw half of the texture? You can do multiple triangles sharing some vertices, + using indices, to get the whole thing on the screen: */ + + /* Let's just move this over so it doesn't overlap... */ + for (i = 0; i < 3; i++) { + vertices[i].position.x += 450; + } + + /* we need one more vertex, since the two triangles can share two of them. */ + vertices[3].position.x = 600.0f; + vertices[3].position.y = 150.0f; + vertices[3].color.r = vertices[0].color.g = vertices[0].color.b = vertices[0].color.a = 1.0f; + vertices[3].tex_coord.x = 1.0f; + vertices[3].tex_coord.y = 1.0f; + + /* And an index to tell it to reuse some of the vertices between triangles... */ + { + /* 4 vertices, but 6 actual places they used. Indices need less bandwidth to transfer and can reorder vertices easily! */ + const int indices[] = { 0, 1, 2, 1, 2, 3 }; + SDL_RenderGeometry(renderer, texture, vertices, 4, indices, SDL_arraysize(indices)); + } + + SDL_RenderPresent(renderer); /* put it all on the screen! */ + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs once at shutdown. */ +void SDL_AppQuit(void *appstate) +{ + SDL_DestroyTexture(texture); + /* SDL will clean up the window/renderer for us. */ +} + diff --git a/external/SDL/include/SDL3/SDL_atomic.h b/external/SDL/include/SDL3/SDL_atomic.h index 0a9fa045..e36436f9 100644 --- a/external/SDL/include/SDL3/SDL_atomic.h +++ b/external/SDL/include/SDL3/SDL_atomic.h @@ -224,8 +224,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_MemoryBarrierAcquireFunction(void); hard-coded at address 0xffff0fa0 */ typedef void (*SDL_KernelMemoryBarrierFunc)(); -#define SDL_MemoryBarrierRelease() ((SDL_KernelMemoryBarrierFunc)0xffff0fa0)() -#define SDL_MemoryBarrierAcquire() ((SDL_KernelMemoryBarrierFunc)0xffff0fa0)() +#define SDL_MemoryBarrierRelease() ((SDL_KernelMemoryBarrierFunc)0xffff0fa0)() +#define SDL_MemoryBarrierAcquire() ((SDL_KernelMemoryBarrierFunc)0xffff0fa0)() #else #if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) || defined(__ARM_ARCH_8A__) #define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("dmb ish" : : : "memory") diff --git a/external/SDL/include/SDL3/SDL_gpu.h b/external/SDL/include/SDL3/SDL_gpu.h index ad496855..04099f24 100644 --- a/external/SDL/include/SDL3/SDL_gpu.h +++ b/external/SDL/include/SDL3/SDL_gpu.h @@ -490,7 +490,7 @@ typedef enum SDL_GPUTextureType SDL_GPU_TEXTURETYPE_2D_ARRAY, /**< The texture is a 2-dimensional array image. */ SDL_GPU_TEXTURETYPE_3D, /**< The texture is a 3-dimensional image. */ SDL_GPU_TEXTURETYPE_CUBE, /**< The texture is a cube image. */ - SDL_GPU_TEXTURETYPE_CUBE_ARRAY /**< The texture is a cube array image. */ + SDL_GPU_TEXTURETYPE_CUBE_ARRAY /**< The texture is a cube array image. */ } SDL_GPUTextureType; /** diff --git a/external/SDL/include/SDL3/SDL_hints.h b/external/SDL/include/SDL3/SDL_hints.h index 20488592..88155b0c 100644 --- a/external/SDL/include/SDL3/SDL_hints.h +++ b/external/SDL/include/SDL3/SDL_hints.h @@ -1654,6 +1654,17 @@ extern "C" { */ #define SDL_HINT_JOYSTICK_HIDAPI_STEAMDECK "SDL_JOYSTICK_HIDAPI_STEAMDECK" +/** + * A variable controlling whether the HIDAPI driver for HORI licensed Steam + * controllers should be used. + * + * This variable can be set to the following values: "0" - HIDAPI driver is + * not used "1" - HIDAPI driver is used + * + * The default is the value of SDL_HINT_JOYSTICK_HIDAPI + */ +#define SDL_HINT_JOYSTICK_HIDAPI_STEAM_HORI "SDL_JOYSTICK_HIDAPI_STEAM_HORI" + /** * A variable controlling whether the HIDAPI driver for Nintendo Switch * controllers should be used. diff --git a/external/SDL/include/SDL3/SDL_keycode.h b/external/SDL/include/SDL3/SDL_keycode.h index 2d03a3d6..28e40a35 100644 --- a/external/SDL/include/SDL3/SDL_keycode.h +++ b/external/SDL/include/SDL3/SDL_keycode.h @@ -123,7 +123,7 @@ typedef Uint32 SDL_Keycode; #define SDLK_RIGHTBRACE 0x0000007du /* '}' */ #define SDLK_TILDE 0x0000007eu /* '~' */ #define SDLK_DELETE 0x0000007fu /* '\x7F' */ -#define SDLK_PLUSMINUS 0x000000b1u /* '±' */ +#define SDLK_PLUSMINUS 0x000000b1u /* '\xB1' */ #define SDLK_CAPSLOCK 0x40000039u /* SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CAPSLOCK) */ #define SDLK_F1 0x4000003au /* SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F1) */ #define SDLK_F2 0x4000003bu /* SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F2) */ diff --git a/external/SDL/include/SDL3/SDL_stdinc.h b/external/SDL/include/SDL3/SDL_stdinc.h index d958eb29..5326fd6b 100644 --- a/external/SDL/include/SDL3/SDL_stdinc.h +++ b/external/SDL/include/SDL3/SDL_stdinc.h @@ -38,6 +38,10 @@ #if defined(_MSC_VER) && (_MSC_VER < 1910) #define SDL_DEFINE_STDBOOL #endif +/* gcc-2.95 had non-standard stdbool.h */ +#if defined(__GNUC__) && (__GNUC__ < 3) +#define SDL_DEFINE_STDBOOL +#endif #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L #include @@ -47,7 +51,7 @@ #ifdef SDL_DEFINE_STDBOOL #ifndef __bool_true_false_are_defined #define __bool_true_false_are_defined 1 -#define bool int8_t +#define bool uint8_t #define false 0 #define true 1 #endif @@ -96,6 +100,25 @@ void *alloca(size_t); # define SDL_SIZE_MAX ((size_t) -1) #endif +#ifndef SDL_COMPILE_TIME_ASSERT +#if defined(__cplusplus) +/* Keep C++ case alone: Some versions of gcc will define __STDC_VERSION__ even when compiling in C++ mode. */ +#if (__cplusplus >= 201103L) +#define SDL_COMPILE_TIME_ASSERT(name, x) static_assert(x, #x) +#endif +#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 202311L) +#define SDL_COMPILE_TIME_ASSERT(name, x) static_assert(x, #x) +#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) +#define SDL_COMPILE_TIME_ASSERT(name, x) _Static_assert(x, #x) +#endif +#endif /* !SDL_COMPILE_TIME_ASSERT */ + +#ifndef SDL_COMPILE_TIME_ASSERT +/* universal, but may trigger -Wunused-local-typedefs */ +#define SDL_COMPILE_TIME_ASSERT(name, x) \ + typedef int SDL_compile_time_assert_ ## name[(x) * 2 - 1] +#endif + /** * Check if the compiler supports a given builtin. * Supported by virtually all clang versions and recent gcc. Use this @@ -404,7 +427,7 @@ typedef Sint64 SDL_Time; /* @} *//* Floating-point constants */ /* Make sure we have macros for printing width-based integers. - * should define these but this is not true all platforms. + * should define these but this is not true all platforms. * (for example win32) */ #ifndef SDL_PRIs64 #if defined(SDL_PLATFORM_WINDOWS) @@ -478,6 +501,25 @@ typedef Sint64 SDL_Time; #define SDL_PRIX32 "X" #endif #endif +/* Specifically for the `long long` -- SDL-specific. */ +#ifdef SDL_PLATFORM_WINDOWS +SDL_COMPILE_TIME_ASSERT(longlong_size64, sizeof(long long) == 8); /* using I64 for windows - make sure `long long` is 64 bits. */ +#define SDL_PRILL_PREFIX "I64" +#else +#define SDL_PRILL_PREFIX "ll" +#endif +#ifndef SDL_PRILLd +#define SDL_PRILLd SDL_PRILL_PREFIX "d" +#endif +#ifndef SDL_PRILLu +#define SDL_PRILLu SDL_PRILL_PREFIX "u" +#endif +#ifndef SDL_PRILLx +#define SDL_PRILLx SDL_PRILL_PREFIX "x" +#endif +#ifndef SDL_PRILLX +#define SDL_PRILLX SDL_PRILL_PREFIX "X" +#endif /* Annotations to help code analysis tools */ #ifdef SDL_DISABLE_ANALYZE_MACROS @@ -535,25 +577,6 @@ typedef Sint64 SDL_Time; #endif #endif /* SDL_DISABLE_ANALYZE_MACROS */ -#ifndef SDL_COMPILE_TIME_ASSERT -#if defined(__cplusplus) -/* Keep C++ case alone: Some versions of gcc will define __STDC_VERSION__ even when compiling in C++ mode. */ -#if (__cplusplus >= 201103L) -#define SDL_COMPILE_TIME_ASSERT(name, x) static_assert(x, #x) -#endif -#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 202311L) -#define SDL_COMPILE_TIME_ASSERT(name, x) static_assert(x, #x) -#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) -#define SDL_COMPILE_TIME_ASSERT(name, x) _Static_assert(x, #x) -#endif -#endif /* !SDL_COMPILE_TIME_ASSERT */ - -#ifndef SDL_COMPILE_TIME_ASSERT -/* universal, but may trigger -Wunused-local-typedefs */ -#define SDL_COMPILE_TIME_ASSERT(name, x) \ - typedef int SDL_compile_time_assert_ ## name[(x) * 2 - 1] -#endif - /** \cond */ #ifndef DOXYGEN_SHOULD_IGNORE_THIS SDL_COMPILE_TIME_ASSERT(bool_size, sizeof(bool) == 1); diff --git a/external/SDL/include/build_config/SDL_build_config_ios.h b/external/SDL/include/build_config/SDL_build_config_ios.h index 738a8175..2f40f664 100644 --- a/external/SDL/include/build_config/SDL_build_config_ios.h +++ b/external/SDL/include/build_config/SDL_build_config_ios.h @@ -190,9 +190,9 @@ Also supported in simulator from iOS 13.0 and tvOS 13.0 */ #if (TARGET_OS_SIMULATOR && ((__IPHONE_OS_VERSION_MIN_REQUIRED >= 130000) || (__TV_OS_VERSION_MIN_REQUIRED >= 130000))) || (!TARGET_CPU_ARM && ((__IPHONE_OS_VERSION_MIN_REQUIRED >= 80000) || (__TV_OS_VERSION_MIN_REQUIRED >= 90000))) -#define SDL_PLATFORM_SUPPORTS_METAL 1 +#define SDL_PLATFORM_SUPPORTS_METAL 1 #else -#define SDL_PLATFORM_SUPPORTS_METAL 0 +#define SDL_PLATFORM_SUPPORTS_METAL 0 #endif #if SDL_PLATFORM_SUPPORTS_METAL diff --git a/external/SDL/src/core/android/SDL_android.c b/external/SDL/src/core/android/SDL_android.c index 6f9db679..e1e18c3c 100644 --- a/external/SDL/src/core/android/SDL_android.c +++ b/external/SDL/src/core/android/SDL_android.c @@ -1525,7 +1525,8 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetenv)( const char *utfvalue = (*env)->GetStringUTFChars(env, value, NULL); // This is only called at startup, to initialize the environment - SDL_setenv_unsafe(utfname, utfvalue, 1); + // Note that we call setenv() directly to avoid affecting SDL environments + setenv(utfname, utfvalue, 1); (*env)->ReleaseStringUTFChars(env, name, utfname); (*env)->ReleaseStringUTFChars(env, value, utfvalue); diff --git a/external/SDL/src/file/SDL_iostream.c b/external/SDL/src/file/SDL_iostream.c index bb14e090..50f22dc3 100644 --- a/external/SDL/src/file/SDL_iostream.c +++ b/external/SDL/src/file/SDL_iostream.c @@ -33,6 +33,8 @@ #include #endif +#include "SDL_iostream_c.h" + /* This file provides a general interface for SDL to read and write data sources. It can easily be extended to files, memory, etc. */ diff --git a/external/SDL/src/gpu/SDL_gpu.c b/external/SDL/src/gpu/SDL_gpu.c index 935137fe..abc7f8ec 100644 --- a/external/SDL/src/gpu/SDL_gpu.c +++ b/external/SDL/src/gpu/SDL_gpu.c @@ -155,12 +155,12 @@ static const SDL_GPUBootstrap *backends[] = { #ifdef SDL_GPU_METAL &MetalDriver, #endif -#ifdef SDL_GPU_D3D12 - &D3D12Driver, -#endif #ifdef SDL_GPU_VULKAN &VulkanDriver, #endif +#ifdef SDL_GPU_D3D12 + &D3D12Driver, +#endif #ifdef SDL_GPU_D3D11 &D3D11Driver, #endif @@ -959,6 +959,10 @@ SDL_GPUTexture *SDL_CreateGPUTexture( SDL_assert_release(!"For array textures: usage must not contain DEPTH_STENCIL_TARGET"); failed = true; } + if (createinfo->sample_count > SDL_GPU_SAMPLECOUNT_1) { + SDL_assert_release(!"For array textures: sample_count must be SDL_GPU_SAMPLECOUNT_1"); + failed = true; + } } if (createinfo->sample_count > SDL_GPU_SAMPLECOUNT_1 && createinfo->num_levels > 1) { SDL_assert_release(!"For 2D multisample textures: num_levels must be 1"); @@ -1378,6 +1382,9 @@ SDL_GPURenderPass *SDL_BeginGPURenderPass( if (resolveTextureHeader->info.type == SDL_GPU_TEXTURETYPE_3D) { SDL_assert_release(!"Resolve texture must not be of TEXTURETYPE_3D!"); } + if (!(resolveTextureHeader->info.usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET)) { + SDL_assert_release(!"Resolve texture usage must include COLOR_TARGET!"); + } } } } diff --git a/external/SDL/src/gpu/d3d11/SDL_gpu_d3d11.c b/external/SDL/src/gpu/d3d11/SDL_gpu_d3d11.c index 25be9a19..ccd55d6b 100644 --- a/external/SDL/src/gpu/d3d11/SDL_gpu_d3d11.c +++ b/external/SDL/src/gpu/d3d11/SDL_gpu_d3d11.c @@ -2081,29 +2081,21 @@ static D3D11Texture *D3D11_INTERNAL_CreateTexture( D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; rtvDesc.Format = SDLToD3D11_TextureFormat[createInfo->format]; - if (isMultisample) { - if (createInfo->type == SDL_GPU_TEXTURETYPE_2D) { - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS; - } else if (createInfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY) { - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY; - rtvDesc.Texture2DMSArray.FirstArraySlice = layerIndex; - rtvDesc.Texture2DMSArray.ArraySize = 1; - } + if (createInfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY || createInfo->type == SDL_GPU_TEXTURETYPE_CUBE || createInfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) { + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = levelIndex; + rtvDesc.Texture2DArray.FirstArraySlice = layerIndex; + rtvDesc.Texture2DArray.ArraySize = 1; + } else if (createInfo->type == SDL_GPU_TEXTURETYPE_3D) { + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; + rtvDesc.Texture3D.MipSlice = levelIndex; + rtvDesc.Texture3D.FirstWSlice = depthIndex; + rtvDesc.Texture3D.WSize = 1; + } else if (isMultisample) { + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS; } else { - if (createInfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY || createInfo->type == SDL_GPU_TEXTURETYPE_CUBE || createInfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) { - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; - rtvDesc.Texture2DArray.MipSlice = levelIndex; - rtvDesc.Texture2DArray.FirstArraySlice = layerIndex; - rtvDesc.Texture2DArray.ArraySize = 1; - } else if (createInfo->type == SDL_GPU_TEXTURETYPE_3D) { - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; - rtvDesc.Texture3D.MipSlice = levelIndex; - rtvDesc.Texture3D.FirstWSlice = depthIndex; - rtvDesc.Texture3D.WSize = 1; - } else { - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - rtvDesc.Texture2D.MipSlice = levelIndex; - } + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Texture2D.MipSlice = levelIndex; } res = ID3D11Device_CreateRenderTargetView( diff --git a/external/SDL/src/gpu/d3d12/SDL_gpu_d3d12.c b/external/SDL/src/gpu/d3d12/SDL_gpu_d3d12.c index 10693c8f..90293014 100644 --- a/external/SDL/src/gpu/d3d12/SDL_gpu_d3d12.c +++ b/external/SDL/src/gpu/d3d12/SDL_gpu_d3d12.c @@ -2957,31 +2957,23 @@ static D3D12Texture *D3D12_INTERNAL_CreateTexture( rtvDesc.Format = SDLToD3D12_TextureFormat[createinfo->format]; - if (isMultisample) { - if (createinfo->type == SDL_GPU_TEXTURETYPE_2D) { - rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS; - } else if (createinfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY) { - rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY; - rtvDesc.Texture2DMSArray.FirstArraySlice = layerIndex; - rtvDesc.Texture2DMSArray.ArraySize = 1; - } + if (createinfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY || createinfo->type == SDL_GPU_TEXTURETYPE_CUBE || createinfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) { + rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = levelIndex; + rtvDesc.Texture2DArray.FirstArraySlice = layerIndex; + rtvDesc.Texture2DArray.ArraySize = 1; + rtvDesc.Texture2DArray.PlaneSlice = 0; + } else if (createinfo->type == SDL_GPU_TEXTURETYPE_3D) { + rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D; + rtvDesc.Texture3D.MipSlice = levelIndex; + rtvDesc.Texture3D.FirstWSlice = depthIndex; + rtvDesc.Texture3D.WSize = 1; + } else if (isMultisample) { + rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS; } else { - if (createinfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY || createinfo->type == SDL_GPU_TEXTURETYPE_CUBE || createinfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) { - rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY; - rtvDesc.Texture2DArray.MipSlice = levelIndex; - rtvDesc.Texture2DArray.FirstArraySlice = layerIndex; - rtvDesc.Texture2DArray.ArraySize = 1; - rtvDesc.Texture2DArray.PlaneSlice = 0; - } else if (createinfo->type == SDL_GPU_TEXTURETYPE_3D) { - rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D; - rtvDesc.Texture3D.MipSlice = levelIndex; - rtvDesc.Texture3D.FirstWSlice = depthIndex; - rtvDesc.Texture3D.WSize = 1; - } else { - rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; - rtvDesc.Texture2D.MipSlice = levelIndex; - rtvDesc.Texture2D.PlaneSlice = 0; - } + rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Texture2D.MipSlice = levelIndex; + rtvDesc.Texture2D.PlaneSlice = 0; } ID3D12Device_CreateRenderTargetView( diff --git a/external/SDL/src/gpu/metal/SDL_gpu_metal.m b/external/SDL/src/gpu/metal/SDL_gpu_metal.m index 95a400a7..7ea18b3c 100644 --- a/external/SDL/src/gpu/metal/SDL_gpu_metal.m +++ b/external/SDL/src/gpu/metal/SDL_gpu_metal.m @@ -313,14 +313,6 @@ static NSUInteger SDLToMetal_SampleCount[] = { 8 // SDL_GPU_SAMPLECOUNT_8 }; -static MTLTextureType SDLToMetal_TextureType[] = { - MTLTextureType2D, // SDL_GPU_TEXTURETYPE_2D - MTLTextureType2DArray, // SDL_GPU_TEXTURETYPE_2D_ARRAY - MTLTextureType3D, // SDL_GPU_TEXTURETYPE_3D - MTLTextureTypeCube, // SDL_GPU_TEXTURETYPE_CUBE - MTLTextureTypeCubeArray // SDL_GPU_TEXTURETYPE_CUBE_ARRAY -}; - static SDL_GPUTextureFormat SwapchainCompositionToFormat[] = { SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM, // SDR SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB, // SDR_LINEAR @@ -330,6 +322,24 @@ static SDL_GPUTextureFormat SwapchainCompositionToFormat[] = { static CFStringRef SwapchainCompositionToColorSpace[4]; // initialized on device creation +static MTLTextureType SDLToMetal_TextureType(SDL_GPUTextureType textureType, bool isMSAA) +{ + switch (textureType) { + case SDL_GPU_TEXTURETYPE_2D: + return isMSAA ? MTLTextureType2DMultisample : MTLTextureType2D; + case SDL_GPU_TEXTURETYPE_2D_ARRAY: + return MTLTextureType2DArray; + case SDL_GPU_TEXTURETYPE_3D: + return MTLTextureType3D; + case SDL_GPU_TEXTURETYPE_CUBE: + return MTLTextureTypeCube; + case SDL_GPU_TEXTURETYPE_CUBE_ARRAY: + return MTLTextureTypeCubeArray; + default: + return MTLTextureType2D; + } +} + static MTLColorWriteMask SDLToMetal_ColorWriteMask( SDL_GPUColorComponentFlags mask) { @@ -1198,8 +1208,10 @@ static void METAL_InsertDebugLabel( [metalCommandBuffer->computeEncoder insertDebugSignpost:label]; } else { // Metal doesn't have insertDebugSignpost for command buffers... - [metalCommandBuffer->handle pushDebugGroup:label]; - [metalCommandBuffer->handle popDebugGroup]; + if (@available(macOS 10.13, *)) { + [metalCommandBuffer->handle pushDebugGroup:label]; + [metalCommandBuffer->handle popDebugGroup]; + } } } } @@ -1219,7 +1231,9 @@ static void METAL_PushDebugGroup( } else if (metalCommandBuffer->computeEncoder) { [metalCommandBuffer->computeEncoder pushDebugGroup:label]; } else { - [metalCommandBuffer->handle pushDebugGroup:label]; + if (@available(macOS 10.13, *)) { + [metalCommandBuffer->handle pushDebugGroup:label]; + } } } } @@ -1237,7 +1251,9 @@ static void METAL_PopDebugGroup( } else if (metalCommandBuffer->computeEncoder) { [metalCommandBuffer->computeEncoder popDebugGroup]; } else { - [metalCommandBuffer->handle popDebugGroup]; + if (@available(macOS 10.13, *)) { + [metalCommandBuffer->handle popDebugGroup]; + } } } } @@ -1317,15 +1333,19 @@ static MetalTexture *METAL_INTERNAL_CreateTexture( id texture; MetalTexture *metalTexture; - textureDescriptor.textureType = SDLToMetal_TextureType[createinfo->type]; + textureDescriptor.textureType = SDLToMetal_TextureType(createinfo->type, createinfo->sample_count > SDL_GPU_SAMPLECOUNT_1); textureDescriptor.pixelFormat = SDLToMetal_SurfaceFormat[createinfo->format]; // This format isn't natively supported so let's swizzle! if (createinfo->format == SDL_GPU_TEXTUREFORMAT_B4G4R4A4_UNORM) { - textureDescriptor.swizzle = MTLTextureSwizzleChannelsMake( - MTLTextureSwizzleBlue, - MTLTextureSwizzleGreen, - MTLTextureSwizzleRed, - MTLTextureSwizzleAlpha); + if (@available(macOS 10.15, *)) { + textureDescriptor.swizzle = MTLTextureSwizzleChannelsMake(MTLTextureSwizzleBlue, + MTLTextureSwizzleGreen, + MTLTextureSwizzleRed, + MTLTextureSwizzleAlpha); + } else { + SDL_SetError("SDL_GPU_TEXTUREFORMAT_B4G4R4A4_UNORM is not supported"); + return NULL; + } } textureDescriptor.width = createinfo->width; @@ -2955,7 +2975,7 @@ static void METAL_BeginComputePass( METAL_INTERNAL_TrackTexture(metalCommandBuffer, texture); textureView = [texture->handle newTextureViewWithPixelFormat:SDLToMetal_SurfaceFormat[textureContainer->header.info.format] - textureType:SDLToMetal_TextureType[textureContainer->header.info.type] + textureType:SDLToMetal_TextureType(textureContainer->header.info.type, false) levels:NSMakeRange(storageTextureBindings[i].mip_level, 1) slices:NSMakeRange(storageTextureBindings[i].layer, 1)]; @@ -3409,7 +3429,9 @@ static Uint8 METAL_INTERNAL_CreateSwapchain( windowData->layer = (__bridge CAMetalLayer *)(SDL_Metal_GetLayer(windowData->view)); windowData->layer.device = renderer->device; #ifdef SDL_PLATFORM_MACOS - windowData->layer.displaySyncEnabled = (presentMode != SDL_GPU_PRESENTMODE_IMMEDIATE); + if (@available(macOS 10.13, *)) { + windowData->layer.displaySyncEnabled = (presentMode != SDL_GPU_PRESENTMODE_IMMEDIATE); + } #endif windowData->layer.pixelFormat = SDLToMetal_SurfaceFormat[SwapchainCompositionToFormat[swapchainComposition]]; #ifndef SDL_PLATFORM_TVOS @@ -3632,7 +3654,9 @@ static bool METAL_SetSwapchainParameters( METAL_Wait(driverData); #ifdef SDL_PLATFORM_MACOS - windowData->layer.displaySyncEnabled = (presentMode != SDL_GPU_PRESENTMODE_IMMEDIATE); + if (@available(macOS 10.13, *)) { + windowData->layer.displaySyncEnabled = (presentMode != SDL_GPU_PRESENTMODE_IMMEDIATE); + } #endif windowData->layer.pixelFormat = SDLToMetal_SurfaceFormat[SwapchainCompositionToFormat[swapchainComposition]]; #ifndef SDL_PLATFORM_TVOS @@ -3763,8 +3787,12 @@ static bool METAL_SupportsTextureFormat( // Cube arrays are not supported on older iOS devices if (type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) { - if (!([renderer->device supportsFamily:MTLGPUFamilyCommon2] || - [renderer->device supportsFamily:MTLGPUFamilyApple4])) { + if (@available(macOS 10.15, *)) { + if (!([renderer->device supportsFamily:MTLGPUFamilyCommon2] || + [renderer->device supportsFamily:MTLGPUFamilyApple4])) { + return false; + } + } else { return false; } } @@ -3774,7 +3802,11 @@ static bool METAL_SupportsTextureFormat( case SDL_GPU_TEXTUREFORMAT_B5G6R5_UNORM: case SDL_GPU_TEXTUREFORMAT_B5G5R5A1_UNORM: case SDL_GPU_TEXTUREFORMAT_B4G4R4A4_UNORM: - return [renderer->device supportsFamily:MTLGPUFamilyApple1]; + if (@available(macOS 10.15, *)) { + return [renderer->device supportsFamily:MTLGPUFamilyApple1]; + } else { + return false; + } // Requires BC compression support case SDL_GPU_TEXTUREFORMAT_BC1_RGBA_UNORM: diff --git a/external/SDL/src/gpu/vulkan/SDL_gpu_vulkan.c b/external/SDL/src/gpu/vulkan/SDL_gpu_vulkan.c index 6e215b90..38f94eaf 100644 --- a/external/SDL/src/gpu/vulkan/SDL_gpu_vulkan.c +++ b/external/SDL/src/gpu/vulkan/SDL_gpu_vulkan.c @@ -69,7 +69,7 @@ typedef struct VulkanExtensions #define SMALL_ALLOCATION_SIZE 16777216 // 16 MiB #define LARGE_ALLOCATION_INCREMENT 67108864 // 64 MiB #define MAX_UBO_SECTION_SIZE 4096 // 4 KiB -#define DESCRIPTOR_POOL_STARTING_SIZE 128 +#define DESCRIPTOR_POOL_SIZE 128 #define WINDOW_PROPERTY_DATA "SDL_GPUVulkanWindowPropertyData" #define IDENTITY_SWIZZLE \ @@ -723,23 +723,69 @@ typedef struct VulkanDescriptorInfo typedef struct DescriptorSetPool { - SDL_SpinLock lock; + // It's a pool... of pools!!! + Uint32 poolCount; + VkDescriptorPool *descriptorPools; + // We'll just manage the descriptor sets ourselves instead of freeing the sets + VkDescriptorSet *descriptorSets; + Uint32 descriptorSetCount; + Uint32 descriptorSetIndex; +} DescriptorSetPool; + +// A command buffer acquires a cache at command buffer acquisition time +typedef struct DescriptorSetCache +{ + // Pools are indexed by DescriptorSetLayoutID which increases monotonically + // There's only a certain number of maximum layouts possible since we de-duplicate them. + DescriptorSetPool *pools; + Uint32 poolCount; +} DescriptorSetCache; + +typedef struct DescriptorSetLayoutHashTableKey +{ + VkShaderStageFlagBits shaderStage; + // Category 1: read resources + Uint32 samplerCount; + Uint32 storageBufferCount; + Uint32 storageTextureCount; + // Category 2: write resources + Uint32 writeStorageBufferCount; + Uint32 writeStorageTextureCount; + // Category 3: uniform buffers + Uint32 uniformBufferCount; +} DescriptorSetLayoutHashTableKey; + +typedef uint32_t DescriptorSetLayoutID; + +typedef struct DescriptorSetLayout +{ + DescriptorSetLayoutID ID; VkDescriptorSetLayout descriptorSetLayout; - VulkanDescriptorInfo *descriptorInfos; - Uint32 descriptorInfoCount; + // Category 1: read resources + Uint32 samplerCount; + Uint32 storageBufferCount; + Uint32 storageTextureCount; + // Category 2: write resources + Uint32 writeStorageBufferCount; + Uint32 writeStorageTextureCount; + // Category 3: uniform buffers + Uint32 uniformBufferCount; +} DescriptorSetLayout; - // This is actually a descriptor set and descriptor pool simultaneously - VkDescriptorPool *descriptorPools; - Uint32 descriptorPoolCount; - Uint32 nextPoolSize; +typedef struct GraphicsPipelineResourceLayoutHashTableKey +{ + Uint32 vertexSamplerCount; + Uint32 vertexStorageBufferCount; + Uint32 vertexStorageTextureCount; + Uint32 vertexUniformBufferCount; - // We just manage a pool ourselves instead of freeing the sets - VkDescriptorSet *inactiveDescriptorSets; - Uint32 inactiveDescriptorSetCount; - Uint32 inactiveDescriptorSetCapacity; -} DescriptorSetPool; + Uint32 fragmentSamplerCount; + Uint32 fragmentStorageBufferCount; + Uint32 fragmentStorageTextureCount; + Uint32 fragmentUniformBufferCount; +} GraphicsPipelineResourceLayoutHashTableKey; typedef struct VulkanGraphicsPipelineResourceLayout { @@ -752,7 +798,7 @@ typedef struct VulkanGraphicsPipelineResourceLayout * 2: fragment resources * 3: fragment uniform buffers */ - DescriptorSetPool descriptorSetPools[4]; + DescriptorSetLayout *descriptorSetLayouts[4]; Uint32 vertexSamplerCount; Uint32 vertexStorageBufferCount; @@ -770,7 +816,7 @@ typedef struct VulkanGraphicsPipeline VkPipeline pipeline; SDL_GPUPrimitiveType primitiveType; - VulkanGraphicsPipelineResourceLayout resourceLayout; + VulkanGraphicsPipelineResourceLayout *resourceLayout; VulkanShader *vertexShader; VulkanShader *fragmentShader; @@ -778,6 +824,16 @@ typedef struct VulkanGraphicsPipeline SDL_AtomicInt referenceCount; } VulkanGraphicsPipeline; +typedef struct ComputePipelineResourceLayoutHashTableKey +{ + Uint32 samplerCount; + Uint32 readonlyStorageTextureCount; + Uint32 readonlyStorageBufferCount; + Uint32 writeonlyStorageTextureCount; + Uint32 writeonlyStorageBufferCount; + Uint32 uniformBufferCount; +} ComputePipelineResourceLayoutHashTableKey; + typedef struct VulkanComputePipelineResourceLayout { VkPipelineLayout pipelineLayout; @@ -788,7 +844,7 @@ typedef struct VulkanComputePipelineResourceLayout * 1: write-only textures, then write-only buffers * 2: uniform buffers */ - DescriptorSetPool descriptorSetPools[3]; + DescriptorSetLayout *descriptorSetLayouts[3]; Uint32 numSamplers; Uint32 numReadonlyStorageTextures; @@ -802,7 +858,7 @@ typedef struct VulkanComputePipeline { VkShaderModule shaderModule; VkPipeline pipeline; - VulkanComputePipelineResourceLayout resourceLayout; + VulkanComputePipelineResourceLayout *resourceLayout; SDL_AtomicInt referenceCount; } VulkanComputePipeline; @@ -851,12 +907,6 @@ typedef struct FramebufferHashTableKey // Command structures -typedef struct DescriptorSetData -{ - DescriptorSetPool *descriptorSetPool; - VkDescriptorSet descriptorSet; -} DescriptorSetData; - typedef struct VulkanFencePool { SDL_Mutex *lock; @@ -911,6 +961,8 @@ typedef struct VulkanCommandBuffer // Resource bind state + DescriptorSetCache *descriptorSetCache; // acquired when command buffer is acquired + bool needNewVertexResourceDescriptorSet; bool needNewVertexUniformDescriptorSet; bool needNewVertexUniformOffsets; @@ -932,10 +984,6 @@ typedef struct VulkanCommandBuffer VkDescriptorSet computeWriteOnlyDescriptorSet; VkDescriptorSet computeUniformDescriptorSet; - DescriptorSetData *boundDescriptorSetDatas; - Uint32 boundDescriptorSetDataCount; - Uint32 boundDescriptorSetDataCapacity; - VulkanTexture *vertexSamplerTextures[MAX_TEXTURE_SAMPLERS_PER_STAGE]; VulkanSampler *vertexSamplers[MAX_TEXTURE_SAMPLERS_PER_STAGE]; VulkanTexture *vertexStorageTextures[MAX_STORAGE_TEXTURES_PER_STAGE]; @@ -964,32 +1012,32 @@ typedef struct VulkanCommandBuffer // Track used resources VulkanBuffer **usedBuffers; - Uint32 usedBufferCount; - Uint32 usedBufferCapacity; + Sint32 usedBufferCount; + Sint32 usedBufferCapacity; VulkanTexture **usedTextures; - Uint32 usedTextureCount; - Uint32 usedTextureCapacity; + Sint32 usedTextureCount; + Sint32 usedTextureCapacity; VulkanSampler **usedSamplers; - Uint32 usedSamplerCount; - Uint32 usedSamplerCapacity; + Sint32 usedSamplerCount; + Sint32 usedSamplerCapacity; VulkanGraphicsPipeline **usedGraphicsPipelines; - Uint32 usedGraphicsPipelineCount; - Uint32 usedGraphicsPipelineCapacity; + Sint32 usedGraphicsPipelineCount; + Sint32 usedGraphicsPipelineCapacity; VulkanComputePipeline **usedComputePipelines; - Uint32 usedComputePipelineCount; - Uint32 usedComputePipelineCapacity; + Sint32 usedComputePipelineCount; + Sint32 usedComputePipelineCapacity; VulkanFramebuffer **usedFramebuffers; - Uint32 usedFramebufferCount; - Uint32 usedFramebufferCapacity; + Sint32 usedFramebufferCount; + Sint32 usedFramebufferCapacity; VulkanUniformBuffer **usedUniformBuffers; - Uint32 usedUniformBufferCount; - Uint32 usedUniformBufferCapacity; + Sint32 usedUniformBufferCount; + Sint32 usedUniformBufferCapacity; VulkanFenceHandle *inFlightFence; Uint8 autoReleaseFence; @@ -1048,11 +1096,20 @@ struct VulkanRenderer SDL_HashTable *commandPoolHashTable; SDL_HashTable *renderPassHashTable; SDL_HashTable *framebufferHashTable; + SDL_HashTable *graphicsPipelineResourceLayoutHashTable; + SDL_HashTable *computePipelineResourceLayoutHashTable; + SDL_HashTable *descriptorSetLayoutHashTable; VulkanUniformBuffer **uniformBufferPool; Uint32 uniformBufferPoolCount; Uint32 uniformBufferPoolCapacity; + DescriptorSetCache **descriptorSetCachePool; + Uint32 descriptorSetCachePoolCount; + Uint32 descriptorSetCachePoolCapacity; + + SDL_AtomicInt layoutResourceID; + Uint32 minUBOAlignment; // Deferred resource destruction @@ -2257,23 +2314,21 @@ static Uint8 VULKAN_INTERNAL_BindMemoryForBuffer( commandBuffer->array[commandBuffer->count] = resource; \ commandBuffer->count += 1; -#define TRACK_RESOURCE(resource, type, array, count, capacity) \ - Uint32 i; \ - \ - for (i = 0; i < commandBuffer->count; i += 1) { \ - if (commandBuffer->array[i] == resource) { \ - return; \ - } \ - } \ - \ - if (commandBuffer->count == commandBuffer->capacity) { \ - commandBuffer->capacity += 1; \ - commandBuffer->array = SDL_realloc( \ - commandBuffer->array, \ - commandBuffer->capacity * sizeof(type)); \ - } \ - commandBuffer->array[commandBuffer->count] = resource; \ - commandBuffer->count += 1; \ +#define TRACK_RESOURCE(resource, type, array, count, capacity) \ + for (Sint32 i = commandBuffer->count - 1; i >= 0; i -= 1) { \ + if (commandBuffer->array[i] == resource) { \ + return; \ + } \ + } \ + \ + if (commandBuffer->count == commandBuffer->capacity) { \ + commandBuffer->capacity += 1; \ + commandBuffer->array = SDL_realloc( \ + commandBuffer->array, \ + commandBuffer->capacity * sizeof(type)); \ + } \ + commandBuffer->array[commandBuffer->count] = resource; \ + commandBuffer->count += 1; \ SDL_AtomicIncRef(&resource->referenceCount); static void VULKAN_INTERNAL_TrackBuffer( @@ -2353,8 +2408,7 @@ static void VULKAN_INTERNAL_TrackUniformBuffer( VulkanCommandBuffer *commandBuffer, VulkanUniformBuffer *uniformBuffer) { - Uint32 i; - for (i = 0; i < commandBuffer->usedUniformBufferCount; i += 1) { + for (Sint32 i = commandBuffer->usedUniformBufferCount - 1; i >= 0; i -= 1) { if (commandBuffer->usedUniformBuffers[i] == uniformBuffer) { return; } @@ -2935,7 +2989,6 @@ static void VULKAN_INTERNAL_DestroyCommandPool( SDL_free(commandBuffer->presentDatas); SDL_free(commandBuffer->waitSemaphores); SDL_free(commandBuffer->signalSemaphores); - SDL_free(commandBuffer->boundDescriptorSetDatas); SDL_free(commandBuffer->usedBuffers); SDL_free(commandBuffer->usedTextures); SDL_free(commandBuffer->usedSamplers); @@ -2951,55 +3004,33 @@ static void VULKAN_INTERNAL_DestroyCommandPool( SDL_free(commandPool); } -static void VULKAN_INTERNAL_DestroyDescriptorSetPool( +static void VULKAN_INTERNAL_DestroyDescriptorSetLayout( VulkanRenderer *renderer, - DescriptorSetPool *pool) + DescriptorSetLayout *layout) { - Uint32 i; - - if (pool == NULL) { + if (layout == NULL) { return; } - for (i = 0; i < pool->descriptorPoolCount; i += 1) { - renderer->vkDestroyDescriptorPool( + if (layout->descriptorSetLayout != VK_NULL_HANDLE) { + renderer->vkDestroyDescriptorSetLayout( renderer->logicalDevice, - pool->descriptorPools[i], + layout->descriptorSetLayout, NULL); } - renderer->vkDestroyDescriptorSetLayout( - renderer->logicalDevice, - pool->descriptorSetLayout, - NULL); - - SDL_free(pool->descriptorInfos); - SDL_free(pool->descriptorPools); - SDL_free(pool->inactiveDescriptorSets); + SDL_free(layout); } static void VULKAN_INTERNAL_DestroyGraphicsPipeline( VulkanRenderer *renderer, VulkanGraphicsPipeline *graphicsPipeline) { - Uint32 i; - renderer->vkDestroyPipeline( renderer->logicalDevice, graphicsPipeline->pipeline, NULL); - renderer->vkDestroyPipelineLayout( - renderer->logicalDevice, - graphicsPipeline->resourceLayout.pipelineLayout, - NULL); - - for (i = 0; i < 4; i += 1) { - VULKAN_INTERNAL_DestroyDescriptorSetPool( - renderer, - &graphicsPipeline->resourceLayout.descriptorSetPools[i]); - } - (void)SDL_AtomicDecRef(&graphicsPipeline->vertexShader->referenceCount); (void)SDL_AtomicDecRef(&graphicsPipeline->fragmentShader->referenceCount); @@ -3010,28 +3041,19 @@ static void VULKAN_INTERNAL_DestroyComputePipeline( VulkanRenderer *renderer, VulkanComputePipeline *computePipeline) { - Uint32 i; - - renderer->vkDestroyPipeline( - renderer->logicalDevice, - computePipeline->pipeline, - NULL); - - renderer->vkDestroyPipelineLayout( - renderer->logicalDevice, - computePipeline->resourceLayout.pipelineLayout, - NULL); - - for (i = 0; i < 3; i += 1) { - VULKAN_INTERNAL_DestroyDescriptorSetPool( - renderer, - &computePipeline->resourceLayout.descriptorSetPools[i]); + if (computePipeline->pipeline != VK_NULL_HANDLE) { + renderer->vkDestroyPipeline( + renderer->logicalDevice, + computePipeline->pipeline, + NULL); } - renderer->vkDestroyShaderModule( - renderer->logicalDevice, - computePipeline->shaderModule, - NULL); + if (computePipeline->shaderModule != VK_NULL_HANDLE) { + renderer->vkDestroyShaderModule( + renderer->logicalDevice, + computePipeline->shaderModule, + NULL); + } SDL_free(computePipeline); } @@ -3119,8 +3141,148 @@ static void VULKAN_INTERNAL_DestroySwapchain( SDL_free(swapchainData); } +static void VULKAN_INTERNAL_DestroyGraphicsPipelineResourceLayout( + VulkanRenderer *renderer, + VulkanGraphicsPipelineResourceLayout *resourceLayout) +{ + if (resourceLayout->pipelineLayout != VK_NULL_HANDLE) { + renderer->vkDestroyPipelineLayout( + renderer->logicalDevice, + resourceLayout->pipelineLayout, + NULL); + } + + SDL_free(resourceLayout); +} + +static void VULKAN_INTERNAL_DestroyComputePipelineResourceLayout( + VulkanRenderer *renderer, + VulkanComputePipelineResourceLayout *resourceLayout) +{ + if (resourceLayout->pipelineLayout != VK_NULL_HANDLE) { + renderer->vkDestroyPipelineLayout( + renderer->logicalDevice, + resourceLayout->pipelineLayout, + NULL); + } + + SDL_free(resourceLayout); +} + +static void VULKAN_INTERNAL_DestroyDescriptorSetCache( + VulkanRenderer *renderer, + DescriptorSetCache *descriptorSetCache) +{ + for (Uint32 i = 0; i < descriptorSetCache->poolCount; i += 1) { + for (Uint32 j = 0; j < descriptorSetCache->pools[i].poolCount; j += 1) { + renderer->vkDestroyDescriptorPool( + renderer->logicalDevice, + descriptorSetCache->pools[i].descriptorPools[j], + NULL); + } + SDL_free(descriptorSetCache->pools[i].descriptorSets); + SDL_free(descriptorSetCache->pools[i].descriptorPools); + } + SDL_free(descriptorSetCache); +} + // Hashtable functions +static Uint32 VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashFunction(const void *key, void *data) +{ + GraphicsPipelineResourceLayoutHashTableKey *hashTableKey = (GraphicsPipelineResourceLayoutHashTableKey *)key; + /* The algorithm for this hashing function + * is taken from Josh Bloch's "Effective Java". + * (https://stackoverflow.com/a/113600/12492383) + */ + const Uint32 hashFactor = 31; + Uint32 result = 1; + result = result * hashFactor + hashTableKey->vertexSamplerCount; + result = result * hashFactor + hashTableKey->vertexStorageBufferCount; + result = result * hashFactor + hashTableKey->vertexStorageTextureCount; + result = result * hashFactor + hashTableKey->vertexUniformBufferCount; + result = result * hashFactor + hashTableKey->fragmentSamplerCount; + result = result * hashFactor + hashTableKey->fragmentStorageBufferCount; + result = result * hashFactor + hashTableKey->fragmentStorageTextureCount; + result = result * hashFactor + hashTableKey->fragmentUniformBufferCount; + return result; +} +static bool VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashKeyMatch(const void *aKey, const void *bKey, void *data) +{ + return SDL_memcmp(aKey, bKey, sizeof(GraphicsPipelineResourceLayoutHashTableKey)) == 0; +} +static void VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashNuke(const void *key, const void *value, void *data) +{ + VulkanRenderer *renderer = (VulkanRenderer *)data; + VulkanGraphicsPipelineResourceLayout *resourceLayout = (VulkanGraphicsPipelineResourceLayout *)value; + VULKAN_INTERNAL_DestroyGraphicsPipelineResourceLayout(renderer, resourceLayout); + SDL_free((void*)key); +} + +static Uint32 VULKAN_INTERNAL_ComputePipelineResourceLayoutHashFunction(const void *key, void *data) +{ + ComputePipelineResourceLayoutHashTableKey *hashTableKey = (ComputePipelineResourceLayoutHashTableKey *)key; + /* The algorithm for this hashing function + * is taken from Josh Bloch's "Effective Java". + * (https://stackoverflow.com/a/113600/12492383) + */ + const Uint32 hashFactor = 31; + Uint32 result = 1; + result = result * hashFactor + hashTableKey->samplerCount; + result = result * hashFactor + hashTableKey->readonlyStorageTextureCount; + result = result * hashFactor + hashTableKey->readonlyStorageBufferCount; + result = result * hashFactor + hashTableKey->writeonlyStorageTextureCount; + result = result * hashFactor + hashTableKey->writeonlyStorageBufferCount; + result = result * hashFactor + hashTableKey->uniformBufferCount; + return result; +} + +static bool VULKAN_INTERNAL_ComputePipelineResourceLayoutHashKeyMatch(const void *aKey, const void *bKey, void *data) +{ + return SDL_memcmp(aKey, bKey, sizeof(ComputePipelineResourceLayoutHashTableKey)) == 0; +} + +static void VULKAN_INTERNAL_ComputePipelineResourceLayoutHashNuke(const void *key, const void *value, void *data) +{ + VulkanRenderer *renderer = (VulkanRenderer *)data; + VulkanComputePipelineResourceLayout *resourceLayout = (VulkanComputePipelineResourceLayout *)value; + VULKAN_INTERNAL_DestroyComputePipelineResourceLayout(renderer, resourceLayout); + SDL_free((void*)key); +} + +static Uint32 VULKAN_INTERNAL_DescriptorSetLayoutHashFunction(const void *key, void *data) +{ + DescriptorSetLayoutHashTableKey *hashTableKey = (DescriptorSetLayoutHashTableKey *)key; + + /* The algorithm for this hashing function + * is taken from Josh Bloch's "Effective Java". + * (https://stackoverflow.com/a/113600/12492383) + */ + const Uint32 hashFactor = 31; + Uint32 result = 1; + result = result * hashFactor + hashTableKey->shaderStage; + result = result * hashFactor + hashTableKey->samplerCount; + result = result * hashFactor + hashTableKey->storageTextureCount; + result = result * hashFactor + hashTableKey->storageBufferCount; + result = result * hashFactor + hashTableKey->writeStorageTextureCount; + result = result * hashFactor + hashTableKey->writeStorageBufferCount; + result = result * hashFactor + hashTableKey->uniformBufferCount; + return result; +} + +static bool VULKAN_INTERNAL_DescriptorSetLayoutHashKeyMatch(const void *aKey, const void *bKey, void *data) +{ + return SDL_memcmp(aKey, bKey, sizeof(DescriptorSetLayoutHashTableKey)) == 0; +} + +static void VULKAN_INTERNAL_DescriptorSetLayoutHashNuke(const void *key, const void *value, void *data) +{ + VulkanRenderer *renderer = (VulkanRenderer *)data; + DescriptorSetLayout *layout = (DescriptorSetLayout *)value; + VULKAN_INTERNAL_DestroyDescriptorSetLayout(renderer, layout); + SDL_free((void*)key); +} + static Uint32 VULKAN_INTERNAL_CommandPoolHashFunction(const void *key, void *data) { return (Uint32)((CommandPoolHashTableKey *)key)->threadID; @@ -3301,53 +3463,7 @@ static void VULKAN_INTERNAL_FramebufferHashNuke(const void *key, const void *val SDL_free((void *)key); } -// Descriptor pool stuff - -static bool VULKAN_INTERNAL_CreateDescriptorPool( - VulkanRenderer *renderer, - VulkanDescriptorInfo *descriptorInfos, - Uint32 descriptorInfoCount, - Uint32 descriptorSetPoolSize, - VkDescriptorPool *pDescriptorPool) -{ - VkDescriptorPoolSize *descriptorPoolSizes; - VkDescriptorPoolCreateInfo descriptorPoolInfo; - VkResult vulkanResult; - Uint32 i; - - descriptorPoolSizes = NULL; - - if (descriptorInfoCount > 0) { - descriptorPoolSizes = SDL_stack_alloc(VkDescriptorPoolSize, descriptorInfoCount); - - for (i = 0; i < descriptorInfoCount; i += 1) { - descriptorPoolSizes[i].type = descriptorInfos[i].descriptorType; - descriptorPoolSizes[i].descriptorCount = descriptorSetPoolSize; - } - } - - descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - descriptorPoolInfo.pNext = NULL; - descriptorPoolInfo.flags = 0; - descriptorPoolInfo.maxSets = descriptorSetPoolSize; - descriptorPoolInfo.poolSizeCount = descriptorInfoCount; - descriptorPoolInfo.pPoolSizes = descriptorPoolSizes; - - vulkanResult = renderer->vkCreateDescriptorPool( - renderer->logicalDevice, - &descriptorPoolInfo, - NULL, - pDescriptorPool); - - SDL_stack_free(descriptorPoolSizes); - - if (vulkanResult != VK_SUCCESS) { - LogVulkanResultAsError("vkCreateDescriptorPool", vulkanResult); - return false; - } - - return true; -} +// Descriptor pools static bool VULKAN_INTERNAL_AllocateDescriptorSets( VulkanRenderer *renderer, @@ -3376,61 +3492,324 @@ static bool VULKAN_INTERNAL_AllocateDescriptorSets( &descriptorSetAllocateInfo, descriptorSetArray); + SDL_stack_free(descriptorSetLayouts); + if (vulkanResult != VK_SUCCESS) { LogVulkanResultAsError("vkAllocateDescriptorSets", vulkanResult); - SDL_stack_free(descriptorSetLayouts); return false; } - SDL_stack_free(descriptorSetLayouts); return true; } -static void VULKAN_INTERNAL_InitializeDescriptorSetPool( +static void VULKAN_INTERNAL_AllocateDescriptorsFromPool( VulkanRenderer *renderer, + DescriptorSetLayout *descriptorSetLayout, DescriptorSetPool *descriptorSetPool) { - descriptorSetPool->lock = 0; + VkDescriptorPoolSize descriptorPoolSizes[ + MAX_TEXTURE_SAMPLERS_PER_STAGE + + MAX_STORAGE_TEXTURES_PER_STAGE + + MAX_STORAGE_BUFFERS_PER_STAGE + + MAX_COMPUTE_WRITE_TEXTURES + + MAX_COMPUTE_WRITE_BUFFERS + + MAX_UNIFORM_BUFFERS_PER_STAGE]; + VkDescriptorPoolCreateInfo descriptorPoolInfo; + VkDescriptorPool pool; + VkResult vulkanResult; - // Descriptor set layout and descriptor infos are already set when this function is called + // Category 1 + for (Uint32 i = 0; i < descriptorSetLayout->samplerCount; i += 1) { + descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; + } - descriptorSetPool->descriptorPoolCount = 1; - descriptorSetPool->descriptorPools = SDL_malloc(sizeof(VkDescriptorPool)); - descriptorSetPool->nextPoolSize = DESCRIPTOR_POOL_STARTING_SIZE * 2; + for (Uint32 i = descriptorSetLayout->samplerCount; i < descriptorSetLayout->samplerCount + descriptorSetLayout->storageTextureCount; i += 1) { + descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; + } - VULKAN_INTERNAL_CreateDescriptorPool( - renderer, - descriptorSetPool->descriptorInfos, - descriptorSetPool->descriptorInfoCount, - DESCRIPTOR_POOL_STARTING_SIZE, - &descriptorSetPool->descriptorPools[0]); + for (Uint32 i = descriptorSetLayout->samplerCount + descriptorSetLayout->storageTextureCount; i < descriptorSetLayout->samplerCount + descriptorSetLayout->storageTextureCount + descriptorSetLayout->storageBufferCount; i += 1) { + descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; + } - descriptorSetPool->inactiveDescriptorSetCapacity = DESCRIPTOR_POOL_STARTING_SIZE; - descriptorSetPool->inactiveDescriptorSetCount = DESCRIPTOR_POOL_STARTING_SIZE; - descriptorSetPool->inactiveDescriptorSets = SDL_malloc( - sizeof(VkDescriptorSet) * DESCRIPTOR_POOL_STARTING_SIZE); + // Category 2 + for (Uint32 i = 0; i < descriptorSetLayout->writeStorageTextureCount; i += 1) { + descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; + } + + for (Uint32 i = descriptorSetLayout->writeStorageTextureCount; i < descriptorSetLayout->writeStorageTextureCount + descriptorSetLayout->writeStorageBufferCount; i += 1) { + descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; + } + + // Category 3 + for (Uint32 i = 0; i < descriptorSetLayout->uniformBufferCount; i += 1) { + descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; + descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; + } + + descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + descriptorPoolInfo.pNext = NULL; + descriptorPoolInfo.flags = 0; + descriptorPoolInfo.maxSets = DESCRIPTOR_POOL_SIZE; + descriptorPoolInfo.poolSizeCount = + descriptorSetLayout->samplerCount + + descriptorSetLayout->storageTextureCount + + descriptorSetLayout->storageBufferCount + + descriptorSetLayout->writeStorageTextureCount + + descriptorSetLayout->writeStorageBufferCount + + descriptorSetLayout->uniformBufferCount; + descriptorPoolInfo.pPoolSizes = descriptorPoolSizes; + + vulkanResult = renderer->vkCreateDescriptorPool( + renderer->logicalDevice, + &descriptorPoolInfo, + NULL, + &pool); + + if (vulkanResult != VK_SUCCESS) { + LogVulkanResultAsError("vkCreateDescriptorPool", vulkanResult); + return; + } + + descriptorSetPool->poolCount += 1; + descriptorSetPool->descriptorPools = SDL_realloc( + descriptorSetPool->descriptorPools, + sizeof(VkDescriptorPool) * descriptorSetPool->poolCount); + + descriptorSetPool->descriptorPools[descriptorSetPool->poolCount - 1] = pool; + + descriptorSetPool->descriptorSets = SDL_realloc( + descriptorSetPool->descriptorSets, + sizeof(VkDescriptorSet) * descriptorSetPool->poolCount * DESCRIPTOR_POOL_SIZE); VULKAN_INTERNAL_AllocateDescriptorSets( renderer, - descriptorSetPool->descriptorPools[0], - descriptorSetPool->descriptorSetLayout, - DESCRIPTOR_POOL_STARTING_SIZE, - descriptorSetPool->inactiveDescriptorSets); + pool, + descriptorSetLayout->descriptorSetLayout, + DESCRIPTOR_POOL_SIZE, + &descriptorSetPool->descriptorSets[descriptorSetPool->descriptorSetCount]); + + descriptorSetPool->descriptorSetCount += DESCRIPTOR_POOL_SIZE; } -static bool VULKAN_INTERNAL_InitializeGraphicsPipelineResourceLayout( +// NOTE: these categories should be mutually exclusive +static DescriptorSetLayout *VULKAN_INTERNAL_FetchDescriptorSetLayout( + VulkanRenderer *renderer, + VkShaderStageFlagBits shaderStage, + // Category 1: read resources + Uint32 samplerCount, + Uint32 storageTextureCount, + Uint32 storageBufferCount, + // Category 2: write resources + Uint32 writeStorageTextureCount, + Uint32 writeStorageBufferCount, + // Category 3: uniform buffers + Uint32 uniformBufferCount) +{ + DescriptorSetLayoutHashTableKey key; + SDL_zero(key); + DescriptorSetLayout *layout = NULL; + + key.shaderStage = shaderStage; + key.samplerCount = samplerCount; + key.storageTextureCount = storageTextureCount; + key.storageBufferCount = storageBufferCount; + key.writeStorageTextureCount = writeStorageTextureCount; + key.writeStorageBufferCount = writeStorageBufferCount; + key.uniformBufferCount = uniformBufferCount; + + if (SDL_FindInHashTable( + renderer->descriptorSetLayoutHashTable, + (const void *)&key, + (const void **)&layout)) { + return layout; + } + + VkDescriptorSetLayout descriptorSetLayout; + VkDescriptorSetLayoutBinding descriptorSetLayoutBindings[ + MAX_TEXTURE_SAMPLERS_PER_STAGE + + MAX_STORAGE_TEXTURES_PER_STAGE + + MAX_STORAGE_BUFFERS_PER_STAGE + + MAX_COMPUTE_WRITE_TEXTURES + + MAX_COMPUTE_WRITE_BUFFERS]; + + VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo; + descriptorSetLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + descriptorSetLayoutCreateInfo.pNext = NULL; + descriptorSetLayoutCreateInfo.flags = 0; + + // Category 1 + for (Uint32 i = 0; i < samplerCount; i += 1) { + descriptorSetLayoutBindings[i].binding = i; + descriptorSetLayoutBindings[i].descriptorCount = 1; + descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descriptorSetLayoutBindings[i].stageFlags = shaderStage; + descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; + } + + for (Uint32 i = samplerCount; i < samplerCount + storageTextureCount; i += 1) { + descriptorSetLayoutBindings[i].binding = i; + descriptorSetLayoutBindings[i].descriptorCount = 1; + descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + descriptorSetLayoutBindings[i].stageFlags = shaderStage; + descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; + } + + for (Uint32 i = samplerCount + storageTextureCount; i < samplerCount + storageTextureCount + storageBufferCount; i += 1) { + descriptorSetLayoutBindings[i].binding = i; + descriptorSetLayoutBindings[i].descriptorCount = 1; + descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptorSetLayoutBindings[i].stageFlags = shaderStage; + descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; + } + + // Category 2 + for (Uint32 i = 0; i < writeStorageTextureCount; i += 1) { + descriptorSetLayoutBindings[i].binding = i; + descriptorSetLayoutBindings[i].descriptorCount = 1; + descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + descriptorSetLayoutBindings[i].stageFlags = shaderStage; + descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; + } + + for (Uint32 i = writeStorageTextureCount; i < writeStorageTextureCount + writeStorageBufferCount; i += 1) { + descriptorSetLayoutBindings[i].binding = i; + descriptorSetLayoutBindings[i].descriptorCount = 1; + descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptorSetLayoutBindings[i].stageFlags = shaderStage; + descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; + } + + // Category 3 + for (Uint32 i = 0; i < uniformBufferCount; i += 1) { + descriptorSetLayoutBindings[i].binding = i; + descriptorSetLayoutBindings[i].descriptorCount = 1; + descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; + descriptorSetLayoutBindings[i].stageFlags = shaderStage; + descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; + } + + descriptorSetLayoutCreateInfo.pBindings = descriptorSetLayoutBindings; + descriptorSetLayoutCreateInfo.bindingCount = + samplerCount + + storageTextureCount + + storageBufferCount + + writeStorageTextureCount + + writeStorageBufferCount + + uniformBufferCount; + + VkResult vulkanResult = renderer->vkCreateDescriptorSetLayout( + renderer->logicalDevice, + &descriptorSetLayoutCreateInfo, + NULL, + &descriptorSetLayout); + + if (vulkanResult != VK_SUCCESS) { + LogVulkanResultAsError("vkCreateDescriptorSetLayout", vulkanResult); + return NULL; + } + + layout = SDL_malloc(sizeof(DescriptorSetLayout)); + layout->descriptorSetLayout = descriptorSetLayout; + + layout->samplerCount = samplerCount; + layout->storageBufferCount = storageBufferCount; + layout->storageTextureCount = storageTextureCount; + layout->writeStorageBufferCount = writeStorageBufferCount; + layout->writeStorageTextureCount = writeStorageTextureCount; + layout->uniformBufferCount = uniformBufferCount; + + layout->ID = SDL_AtomicIncRef(&renderer->layoutResourceID); + + DescriptorSetLayoutHashTableKey *allocedKey = SDL_malloc(sizeof(DescriptorSetLayoutHashTableKey)); + SDL_memcpy(allocedKey, &key, sizeof(DescriptorSetLayoutHashTableKey)); + + SDL_InsertIntoHashTable( + renderer->descriptorSetLayoutHashTable, + (const void *)allocedKey, + (const void *)layout); + + return layout; +} + +static VulkanGraphicsPipelineResourceLayout *VULKAN_INTERNAL_FetchGraphicsPipelineResourceLayout( VulkanRenderer *renderer, VulkanShader *vertexShader, - VulkanShader *fragmentShader, - VulkanGraphicsPipelineResourceLayout *pipelineResourceLayout) + VulkanShader *fragmentShader) { - VkDescriptorSetLayoutBinding descriptorSetLayoutBindings[MAX_TEXTURE_SAMPLERS_PER_STAGE + MAX_STORAGE_TEXTURES_PER_STAGE + MAX_STORAGE_BUFFERS_PER_STAGE]; - VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo; - VkDescriptorSetLayout descriptorSetLayouts[4]; + GraphicsPipelineResourceLayoutHashTableKey key; + SDL_zero(key); + VulkanGraphicsPipelineResourceLayout *pipelineResourceLayout = NULL; + + key.vertexSamplerCount = vertexShader->numSamplers; + key.vertexStorageTextureCount = vertexShader->numStorageTextures; + key.vertexStorageBufferCount = vertexShader->numStorageBuffers; + key.vertexUniformBufferCount = vertexShader->numUniformBuffers; + key.fragmentSamplerCount = fragmentShader->numSamplers; + key.fragmentStorageTextureCount = fragmentShader->numStorageTextures; + key.fragmentStorageBufferCount = fragmentShader->numStorageBuffers; + key.fragmentUniformBufferCount = fragmentShader->numUniformBuffers; + if (SDL_FindInHashTable( + renderer->graphicsPipelineResourceLayoutHashTable, + (const void *)&key, + (const void **)&pipelineResourceLayout)) { + return pipelineResourceLayout; + } + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo; - DescriptorSetPool *descriptorSetPool; + VkDescriptorSetLayout descriptorSetLayouts[4]; VkResult vulkanResult; - Uint32 i; + + pipelineResourceLayout = SDL_calloc(1, sizeof(VulkanGraphicsPipelineResourceLayout)); + + pipelineResourceLayout->descriptorSetLayouts[0] = VULKAN_INTERNAL_FetchDescriptorSetLayout( + renderer, + VK_SHADER_STAGE_VERTEX_BIT, + vertexShader->numSamplers, + vertexShader->numStorageTextures, + vertexShader->numStorageBuffers, + 0, + 0, + 0); + + pipelineResourceLayout->descriptorSetLayouts[1] = VULKAN_INTERNAL_FetchDescriptorSetLayout( + renderer, + VK_SHADER_STAGE_VERTEX_BIT, + 0, + 0, + 0, + 0, + 0, + vertexShader->numUniformBuffers); + + pipelineResourceLayout->descriptorSetLayouts[2] = VULKAN_INTERNAL_FetchDescriptorSetLayout( + renderer, + VK_SHADER_STAGE_FRAGMENT_BIT, + fragmentShader->numSamplers, + fragmentShader->numStorageTextures, + fragmentShader->numStorageBuffers, + 0, + 0, + 0); + + pipelineResourceLayout->descriptorSetLayouts[3] = VULKAN_INTERNAL_FetchDescriptorSetLayout( + renderer, + VK_SHADER_STAGE_FRAGMENT_BIT, + 0, + 0, + 0, + 0, + 0, + fragmentShader->numUniformBuffers); + + descriptorSetLayouts[0] = pipelineResourceLayout->descriptorSetLayouts[0]->descriptorSetLayout; + descriptorSetLayouts[1] = pipelineResourceLayout->descriptorSetLayouts[1]->descriptorSetLayout; + descriptorSetLayouts[2] = pipelineResourceLayout->descriptorSetLayouts[2]->descriptorSetLayout; + descriptorSetLayouts[3] = pipelineResourceLayout->descriptorSetLayouts[3]->descriptorSetLayout; pipelineResourceLayout->vertexSamplerCount = vertexShader->numSamplers; pipelineResourceLayout->vertexStorageTextureCount = vertexShader->numStorageTextures; @@ -3442,226 +3821,6 @@ static bool VULKAN_INTERNAL_InitializeGraphicsPipelineResourceLayout( pipelineResourceLayout->fragmentStorageBufferCount = fragmentShader->numStorageBuffers; pipelineResourceLayout->fragmentUniformBufferCount = fragmentShader->numUniformBuffers; - // Vertex Resources - - descriptorSetLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - descriptorSetLayoutCreateInfo.pNext = NULL; - descriptorSetLayoutCreateInfo.flags = 0; - descriptorSetLayoutCreateInfo.pBindings = NULL; - descriptorSetLayoutCreateInfo.bindingCount = - vertexShader->numSamplers + - vertexShader->numStorageTextures + - vertexShader->numStorageBuffers; - - descriptorSetPool = &pipelineResourceLayout->descriptorSetPools[0]; - - descriptorSetPool->descriptorInfoCount = descriptorSetLayoutCreateInfo.bindingCount; - descriptorSetPool->descriptorInfos = NULL; - - if (descriptorSetLayoutCreateInfo.bindingCount > 0) { - descriptorSetPool->descriptorInfos = SDL_malloc( - descriptorSetPool->descriptorInfoCount * sizeof(VulkanDescriptorInfo)); - - for (i = 0; i < vertexShader->numSamplers; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - descriptorSetLayoutBindings[i].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - - descriptorSetPool->descriptorInfos[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - descriptorSetPool->descriptorInfos[i].stageFlag = VK_SHADER_STAGE_VERTEX_BIT; - } - - for (i = vertexShader->numSamplers; i < vertexShader->numSamplers + vertexShader->numStorageTextures; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - descriptorSetLayoutBindings[i].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - - descriptorSetPool->descriptorInfos[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - descriptorSetPool->descriptorInfos[i].stageFlag = VK_SHADER_STAGE_VERTEX_BIT; - } - - for (i = vertexShader->numSamplers + vertexShader->numStorageTextures; i < descriptorSetLayoutCreateInfo.bindingCount; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - descriptorSetLayoutBindings[i].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - - descriptorSetPool->descriptorInfos[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - descriptorSetPool->descriptorInfos[i].stageFlag = VK_SHADER_STAGE_VERTEX_BIT; - } - - descriptorSetLayoutCreateInfo.pBindings = descriptorSetLayoutBindings; - } - - vulkanResult = renderer->vkCreateDescriptorSetLayout( - renderer->logicalDevice, - &descriptorSetLayoutCreateInfo, - NULL, - &descriptorSetPool->descriptorSetLayout); - - descriptorSetLayouts[0] = descriptorSetPool->descriptorSetLayout; - - if (vulkanResult != VK_SUCCESS) { - LogVulkanResultAsError("vkCreateDescriptorSetLayout", vulkanResult); - return false; - } - - // Vertex UBOs - - descriptorSetPool = &pipelineResourceLayout->descriptorSetPools[1]; - - descriptorSetLayoutCreateInfo.bindingCount = pipelineResourceLayout->vertexUniformBufferCount; - descriptorSetLayoutCreateInfo.pBindings = NULL; - - descriptorSetPool->descriptorInfoCount = descriptorSetLayoutCreateInfo.bindingCount; - descriptorSetPool->descriptorInfos = NULL; - - if (descriptorSetLayoutCreateInfo.bindingCount > 0) { - descriptorSetPool->descriptorInfos = SDL_malloc( - descriptorSetPool->descriptorInfoCount * sizeof(VulkanDescriptorInfo)); - - for (i = 0; i < vertexShader->numUniformBuffers; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - descriptorSetLayoutBindings[i].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - - descriptorSetPool->descriptorInfos[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - descriptorSetPool->descriptorInfos[i].stageFlag = VK_SHADER_STAGE_VERTEX_BIT; - } - - descriptorSetLayoutCreateInfo.pBindings = descriptorSetLayoutBindings; - } - - vulkanResult = renderer->vkCreateDescriptorSetLayout( - renderer->logicalDevice, - &descriptorSetLayoutCreateInfo, - NULL, - &descriptorSetPool->descriptorSetLayout); - - descriptorSetLayouts[1] = descriptorSetPool->descriptorSetLayout; - - if (vulkanResult != VK_SUCCESS) { - LogVulkanResultAsError("vkCreateDescriptorSetLayout", vulkanResult); - return false; - } - - // Fragment resources - - descriptorSetPool = &pipelineResourceLayout->descriptorSetPools[2]; - - descriptorSetLayoutCreateInfo.bindingCount = - fragmentShader->numSamplers + - fragmentShader->numStorageTextures + - fragmentShader->numStorageBuffers; - - descriptorSetLayoutCreateInfo.pBindings = NULL; - - descriptorSetPool->descriptorInfoCount = descriptorSetLayoutCreateInfo.bindingCount; - descriptorSetPool->descriptorInfos = NULL; - - if (descriptorSetLayoutCreateInfo.bindingCount > 0) { - descriptorSetPool->descriptorInfos = SDL_malloc( - descriptorSetPool->descriptorInfoCount * sizeof(VulkanDescriptorInfo)); - - for (i = 0; i < fragmentShader->numSamplers; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - descriptorSetLayoutBindings[i].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - - descriptorSetPool->descriptorInfos[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - descriptorSetPool->descriptorInfos[i].stageFlag = VK_SHADER_STAGE_FRAGMENT_BIT; - } - - for (i = fragmentShader->numSamplers; i < fragmentShader->numSamplers + fragmentShader->numStorageTextures; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - descriptorSetLayoutBindings[i].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - - descriptorSetPool->descriptorInfos[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - descriptorSetPool->descriptorInfos[i].stageFlag = VK_SHADER_STAGE_FRAGMENT_BIT; - } - - for (i = fragmentShader->numSamplers + fragmentShader->numStorageTextures; i < descriptorSetLayoutCreateInfo.bindingCount; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - descriptorSetLayoutBindings[i].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - - descriptorSetPool->descriptorInfos[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - descriptorSetPool->descriptorInfos[i].stageFlag = VK_SHADER_STAGE_FRAGMENT_BIT; - } - - descriptorSetLayoutCreateInfo.pBindings = descriptorSetLayoutBindings; - } - - vulkanResult = renderer->vkCreateDescriptorSetLayout( - renderer->logicalDevice, - &descriptorSetLayoutCreateInfo, - NULL, - &descriptorSetPool->descriptorSetLayout); - - descriptorSetLayouts[2] = descriptorSetPool->descriptorSetLayout; - - if (vulkanResult != VK_SUCCESS) { - LogVulkanResultAsError("vkCreateDescriptorSetLayout", vulkanResult); - return false; - } - - // Fragment UBOs - - descriptorSetPool = &pipelineResourceLayout->descriptorSetPools[3]; - - descriptorSetLayoutCreateInfo.bindingCount = - pipelineResourceLayout->fragmentUniformBufferCount; - - descriptorSetLayoutCreateInfo.pBindings = NULL; - - descriptorSetPool->descriptorInfoCount = descriptorSetLayoutCreateInfo.bindingCount; - descriptorSetPool->descriptorInfos = NULL; - - if (descriptorSetLayoutCreateInfo.bindingCount > 0) { - descriptorSetPool->descriptorInfos = SDL_malloc( - descriptorSetPool->descriptorInfoCount * sizeof(VulkanDescriptorInfo)); - - for (i = 0; i < fragmentShader->numUniformBuffers; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - descriptorSetLayoutBindings[i].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - - descriptorSetPool->descriptorInfos[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - descriptorSetPool->descriptorInfos[i].stageFlag = VK_SHADER_STAGE_FRAGMENT_BIT; - } - - descriptorSetLayoutCreateInfo.pBindings = descriptorSetLayoutBindings; - } - - vulkanResult = renderer->vkCreateDescriptorSetLayout( - renderer->logicalDevice, - &descriptorSetLayoutCreateInfo, - NULL, - &descriptorSetPool->descriptorSetLayout); - - descriptorSetLayouts[3] = descriptorSetPool->descriptorSetLayout; - - if (vulkanResult != VK_SUCCESS) { - LogVulkanResultAsError("vkCreateDescriptorSetLayout", vulkanResult); - return false; - } - // Create the pipeline layout pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; @@ -3680,30 +3839,82 @@ static bool VULKAN_INTERNAL_InitializeGraphicsPipelineResourceLayout( if (vulkanResult != VK_SUCCESS) { LogVulkanResultAsError("vkCreatePipelineLayout", vulkanResult); - return false; + VULKAN_INTERNAL_DestroyGraphicsPipelineResourceLayout(renderer, pipelineResourceLayout); + return NULL; } - for (i = 0; i < 4; i += 1) { - VULKAN_INTERNAL_InitializeDescriptorSetPool( - renderer, - &pipelineResourceLayout->descriptorSetPools[i]); - } + GraphicsPipelineResourceLayoutHashTableKey *allocedKey = SDL_malloc(sizeof(GraphicsPipelineResourceLayoutHashTableKey)); + SDL_memcpy(allocedKey, &key, sizeof(GraphicsPipelineResourceLayoutHashTableKey)); - return true; + SDL_InsertIntoHashTable( + renderer->graphicsPipelineResourceLayoutHashTable, + (const void *)allocedKey, + (const void *)pipelineResourceLayout); + + return pipelineResourceLayout; } -static bool VULKAN_INTERNAL_InitializeComputePipelineResourceLayout( +static VulkanComputePipelineResourceLayout *VULKAN_INTERNAL_FetchComputePipelineResourceLayout( VulkanRenderer *renderer, - const SDL_GPUComputePipelineCreateInfo *createinfo, - VulkanComputePipelineResourceLayout *pipelineResourceLayout) + const SDL_GPUComputePipelineCreateInfo *createinfo) { - VkDescriptorSetLayoutBinding descriptorSetLayoutBindings[MAX_UNIFORM_BUFFERS_PER_STAGE]; - VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo; + ComputePipelineResourceLayoutHashTableKey key; + SDL_zero(key); + VulkanComputePipelineResourceLayout *pipelineResourceLayout = NULL; + + key.samplerCount = createinfo->num_samplers; + key.readonlyStorageTextureCount = createinfo->num_readonly_storage_textures; + key.readonlyStorageBufferCount = createinfo->num_readonly_storage_buffers; + key.writeonlyStorageTextureCount = createinfo->num_writeonly_storage_textures; + key.writeonlyStorageBufferCount = createinfo->num_writeonly_storage_buffers; + key.uniformBufferCount = createinfo->num_uniform_buffers; + + if (SDL_FindInHashTable( + renderer->computePipelineResourceLayoutHashTable, + (const void *)&key, + (const void **)&pipelineResourceLayout)) { + return pipelineResourceLayout; + } + VkDescriptorSetLayout descriptorSetLayouts[3]; VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo; - DescriptorSetPool *descriptorSetPool; VkResult vulkanResult; - Uint32 i; + + pipelineResourceLayout = SDL_calloc(1, sizeof(VulkanComputePipelineResourceLayout)); + + pipelineResourceLayout->descriptorSetLayouts[0] = VULKAN_INTERNAL_FetchDescriptorSetLayout( + renderer, + VK_SHADER_STAGE_COMPUTE_BIT, + createinfo->num_samplers, + createinfo->num_readonly_storage_textures, + createinfo->num_readonly_storage_buffers, + 0, + 0, + 0); + + pipelineResourceLayout->descriptorSetLayouts[1] = VULKAN_INTERNAL_FetchDescriptorSetLayout( + renderer, + VK_SHADER_STAGE_COMPUTE_BIT, + 0, + 0, + 0, + createinfo->num_writeonly_storage_textures, + createinfo->num_writeonly_storage_buffers, + 0); + + pipelineResourceLayout->descriptorSetLayouts[2] = VULKAN_INTERNAL_FetchDescriptorSetLayout( + renderer, + VK_SHADER_STAGE_COMPUTE_BIT, + 0, + 0, + 0, + 0, + 0, + createinfo->num_uniform_buffers); + + descriptorSetLayouts[0] = pipelineResourceLayout->descriptorSetLayouts[0]->descriptorSetLayout; + descriptorSetLayouts[1] = pipelineResourceLayout->descriptorSetLayouts[1]->descriptorSetLayout; + descriptorSetLayouts[2] = pipelineResourceLayout->descriptorSetLayouts[2]->descriptorSetLayout; pipelineResourceLayout->numSamplers = createinfo->num_samplers; pipelineResourceLayout->numReadonlyStorageTextures = createinfo->num_readonly_storage_textures; @@ -3712,171 +3923,6 @@ static bool VULKAN_INTERNAL_InitializeComputePipelineResourceLayout( pipelineResourceLayout->numWriteonlyStorageBuffers = createinfo->num_writeonly_storage_buffers; pipelineResourceLayout->numUniformBuffers = createinfo->num_uniform_buffers; - // Read-only resources - - descriptorSetLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - descriptorSetLayoutCreateInfo.pNext = NULL; - descriptorSetLayoutCreateInfo.flags = 0; - descriptorSetLayoutCreateInfo.pBindings = NULL; - descriptorSetLayoutCreateInfo.bindingCount = - createinfo->num_samplers + - createinfo->num_readonly_storage_textures + - createinfo->num_readonly_storage_buffers; - - descriptorSetPool = &pipelineResourceLayout->descriptorSetPools[0]; - - descriptorSetPool->descriptorInfoCount = descriptorSetLayoutCreateInfo.bindingCount; - descriptorSetPool->descriptorInfos = NULL; - - if (descriptorSetLayoutCreateInfo.bindingCount > 0) { - descriptorSetPool->descriptorInfos = SDL_malloc( - descriptorSetPool->descriptorInfoCount * sizeof(VulkanDescriptorInfo)); - - for (i = 0; i < createinfo->num_samplers; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - descriptorSetLayoutBindings[i].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - - descriptorSetPool->descriptorInfos[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - descriptorSetPool->descriptorInfos[i].stageFlag = VK_SHADER_STAGE_COMPUTE_BIT; - } - - for (i = createinfo->num_samplers; i < createinfo->num_samplers + createinfo->num_readonly_storage_textures; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - descriptorSetLayoutBindings[i].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - - descriptorSetPool->descriptorInfos[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - descriptorSetPool->descriptorInfos[i].stageFlag = VK_SHADER_STAGE_COMPUTE_BIT; - } - - for (i = createinfo->num_samplers + createinfo->num_readonly_storage_textures; i < descriptorSetLayoutCreateInfo.bindingCount; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - descriptorSetLayoutBindings[i].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - - descriptorSetPool->descriptorInfos[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - descriptorSetPool->descriptorInfos[i].stageFlag = VK_SHADER_STAGE_COMPUTE_BIT; - } - - descriptorSetLayoutCreateInfo.pBindings = descriptorSetLayoutBindings; - } - - vulkanResult = renderer->vkCreateDescriptorSetLayout( - renderer->logicalDevice, - &descriptorSetLayoutCreateInfo, - NULL, - &descriptorSetPool->descriptorSetLayout); - - descriptorSetLayouts[0] = descriptorSetPool->descriptorSetLayout; - - if (vulkanResult != VK_SUCCESS) { - LogVulkanResultAsError("vkCreateDescriptorSetLayout", vulkanResult); - return false; - } - - // Write-only resources - - descriptorSetLayoutCreateInfo.bindingCount = - createinfo->num_writeonly_storage_textures + - createinfo->num_writeonly_storage_buffers; - - descriptorSetLayoutCreateInfo.pBindings = NULL; - - descriptorSetPool = &pipelineResourceLayout->descriptorSetPools[1]; - - descriptorSetPool->descriptorInfoCount = descriptorSetLayoutCreateInfo.bindingCount; - descriptorSetPool->descriptorInfos = NULL; - - if (descriptorSetLayoutCreateInfo.bindingCount > 0) { - descriptorSetPool->descriptorInfos = SDL_malloc( - descriptorSetPool->descriptorInfoCount * sizeof(VulkanDescriptorInfo)); - - for (i = 0; i < createinfo->num_writeonly_storage_textures; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - descriptorSetLayoutBindings[i].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - - descriptorSetPool->descriptorInfos[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - descriptorSetPool->descriptorInfos[i].stageFlag = VK_SHADER_STAGE_COMPUTE_BIT; - } - - for (i = createinfo->num_writeonly_storage_textures; i < descriptorSetLayoutCreateInfo.bindingCount; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - descriptorSetLayoutBindings[i].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - - descriptorSetPool->descriptorInfos[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - descriptorSetPool->descriptorInfos[i].stageFlag = VK_SHADER_STAGE_COMPUTE_BIT; - } - - descriptorSetLayoutCreateInfo.pBindings = descriptorSetLayoutBindings; - } - - vulkanResult = renderer->vkCreateDescriptorSetLayout( - renderer->logicalDevice, - &descriptorSetLayoutCreateInfo, - NULL, - &descriptorSetPool->descriptorSetLayout); - - descriptorSetLayouts[1] = descriptorSetPool->descriptorSetLayout; - - if (vulkanResult != VK_SUCCESS) { - LogVulkanResultAsError("vkCreateDescriptorSetLayout", vulkanResult); - return false; - } - - // Uniform buffers - - descriptorSetPool = &pipelineResourceLayout->descriptorSetPools[2]; - - descriptorSetLayoutCreateInfo.bindingCount = createinfo->num_uniform_buffers; - descriptorSetLayoutCreateInfo.pBindings = NULL; - - descriptorSetPool->descriptorInfoCount = descriptorSetLayoutCreateInfo.bindingCount; - descriptorSetPool->descriptorInfos = NULL; - - if (descriptorSetLayoutCreateInfo.bindingCount > 0) { - descriptorSetPool->descriptorInfos = SDL_malloc( - descriptorSetPool->descriptorInfoCount * sizeof(VulkanDescriptorInfo)); - - for (i = 0; i < createinfo->num_uniform_buffers; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - descriptorSetLayoutBindings[i].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - - descriptorSetPool->descriptorInfos[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - descriptorSetPool->descriptorInfos[i].stageFlag = VK_SHADER_STAGE_COMPUTE_BIT; - } - - descriptorSetLayoutCreateInfo.pBindings = descriptorSetLayoutBindings; - } - - vulkanResult = renderer->vkCreateDescriptorSetLayout( - renderer->logicalDevice, - &descriptorSetLayoutCreateInfo, - NULL, - &descriptorSetPool->descriptorSetLayout); - - descriptorSetLayouts[2] = descriptorSetPool->descriptorSetLayout; - - if (vulkanResult != VK_SUCCESS) { - LogVulkanResultAsError("vkCreateDescriptorSetLayout", vulkanResult); - return false; - } - // Create the pipeline layout pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; @@ -3895,16 +3941,19 @@ static bool VULKAN_INTERNAL_InitializeComputePipelineResourceLayout( if (vulkanResult != VK_SUCCESS) { LogVulkanResultAsError("vkCreatePipelineLayout", vulkanResult); - return false; + VULKAN_INTERNAL_DestroyComputePipelineResourceLayout(renderer, pipelineResourceLayout); + return NULL; } - for (i = 0; i < 3; i += 1) { - VULKAN_INTERNAL_InitializeDescriptorSetPool( - renderer, - &pipelineResourceLayout->descriptorSetPools[i]); - } + ComputePipelineResourceLayoutHashTableKey *allocedKey = SDL_malloc(sizeof(ComputePipelineResourceLayoutHashTableKey)); + SDL_memcpy(allocedKey, &key, sizeof(ComputePipelineResourceLayoutHashTableKey)); - return true; + SDL_InsertIntoHashTable( + renderer->computePipelineResourceLayoutHashTable, + (const void *)allocedKey, + (const void *)pipelineResourceLayout); + + return pipelineResourceLayout; } // Data Buffer @@ -4674,6 +4723,13 @@ static void VULKAN_DestroyDevice( } SDL_free(renderer->uniformBufferPool); + for (Uint32 i = 0; i < renderer->descriptorSetCachePoolCount; i += 1) { + VULKAN_INTERNAL_DestroyDescriptorSetCache( + renderer, + renderer->descriptorSetCachePool[i]); + } + SDL_free(renderer->descriptorSetCachePool); + for (Uint32 i = 0; i < renderer->fencePool.availableFenceCount; i += 1) { renderer->vkDestroyFence( renderer->logicalDevice, @@ -4689,6 +4745,9 @@ static void VULKAN_DestroyDevice( SDL_DestroyHashTable(renderer->commandPoolHashTable); SDL_DestroyHashTable(renderer->renderPassHashTable); SDL_DestroyHashTable(renderer->framebufferHashTable); + SDL_DestroyHashTable(renderer->graphicsPipelineResourceLayoutHashTable); + SDL_DestroyHashTable(renderer->computePipelineResourceLayoutHashTable); + SDL_DestroyHashTable(renderer->descriptorSetLayoutHashTable); for (Uint32 i = 0; i < VK_MAX_MEMORY_TYPES; i += 1) { allocator = &renderer->memoryAllocator->subAllocators[i]; @@ -4740,71 +4799,72 @@ static void VULKAN_DestroyDevice( SDL_Vulkan_UnloadLibrary(); } +static DescriptorSetCache *VULKAN_INTERNAL_AcquireDescriptorSetCache( + VulkanRenderer *renderer) +{ + DescriptorSetCache *cache; + + if (renderer->descriptorSetCachePoolCount == 0) { + cache = SDL_malloc(sizeof(DescriptorSetCache)); + cache->poolCount = 0; + cache->pools = NULL; + } else { + cache = renderer->descriptorSetCachePool[renderer->descriptorSetCachePoolCount - 1]; + renderer->descriptorSetCachePoolCount -= 1; + } + + return cache; +} + +static void VULKAN_INTERNAL_ReturnDescriptorSetCacheToPool( + VulkanRenderer *renderer, + DescriptorSetCache *descriptorSetCache) +{ + EXPAND_ARRAY_IF_NEEDED( + renderer->descriptorSetCachePool, + DescriptorSetCache *, + renderer->descriptorSetCachePoolCount + 1, + renderer->descriptorSetCachePoolCapacity, + renderer->descriptorSetCachePoolCapacity * 2) + + renderer->descriptorSetCachePool[renderer->descriptorSetCachePoolCount] = descriptorSetCache; + renderer->descriptorSetCachePoolCount += 1; + + for (Uint32 i = 0; i < descriptorSetCache->poolCount; i += 1) { + descriptorSetCache->pools[i].descriptorSetIndex = 0; + } +} + static VkDescriptorSet VULKAN_INTERNAL_FetchDescriptorSet( VulkanRenderer *renderer, VulkanCommandBuffer *vulkanCommandBuffer, - DescriptorSetPool *descriptorSetPool) + DescriptorSetLayout *descriptorSetLayout) { - VkDescriptorSet descriptorSet; + // Grow the pool to meet the descriptor set layout ID + if (descriptorSetLayout->ID >= vulkanCommandBuffer->descriptorSetCache->poolCount) { + vulkanCommandBuffer->descriptorSetCache->pools = SDL_realloc( + vulkanCommandBuffer->descriptorSetCache->pools, + sizeof(DescriptorSetPool) * (descriptorSetLayout->ID + 1)); - SDL_LockSpinlock(&descriptorSetPool->lock); - - // If no inactive descriptor sets remain, create a new pool and allocate new inactive sets - - if (descriptorSetPool->inactiveDescriptorSetCount == 0) { - descriptorSetPool->descriptorPoolCount += 1; - descriptorSetPool->descriptorPools = SDL_realloc( - descriptorSetPool->descriptorPools, - sizeof(VkDescriptorPool) * descriptorSetPool->descriptorPoolCount); - - if (!VULKAN_INTERNAL_CreateDescriptorPool( - renderer, - descriptorSetPool->descriptorInfos, - descriptorSetPool->descriptorInfoCount, - descriptorSetPool->nextPoolSize, - &descriptorSetPool->descriptorPools[descriptorSetPool->descriptorPoolCount - 1])) { - SDL_UnlockSpinlock(&descriptorSetPool->lock); - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create descriptor pool!"); - return VK_NULL_HANDLE; + for (Uint32 i = vulkanCommandBuffer->descriptorSetCache->poolCount; i < descriptorSetLayout->ID + 1; i += 1) { + SDL_zero(vulkanCommandBuffer->descriptorSetCache->pools[i]); } - descriptorSetPool->inactiveDescriptorSetCapacity += descriptorSetPool->nextPoolSize; - - descriptorSetPool->inactiveDescriptorSets = SDL_realloc( - descriptorSetPool->inactiveDescriptorSets, - sizeof(VkDescriptorSet) * descriptorSetPool->inactiveDescriptorSetCapacity); - - if (!VULKAN_INTERNAL_AllocateDescriptorSets( - renderer, - descriptorSetPool->descriptorPools[descriptorSetPool->descriptorPoolCount - 1], - descriptorSetPool->descriptorSetLayout, - descriptorSetPool->nextPoolSize, - descriptorSetPool->inactiveDescriptorSets)) { - SDL_UnlockSpinlock(&descriptorSetPool->lock); - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to allocate descriptor sets!"); - return VK_NULL_HANDLE; - } - - descriptorSetPool->inactiveDescriptorSetCount = descriptorSetPool->nextPoolSize; - - descriptorSetPool->nextPoolSize *= 2; + vulkanCommandBuffer->descriptorSetCache->poolCount = descriptorSetLayout->ID + 1; } - descriptorSet = descriptorSetPool->inactiveDescriptorSets[descriptorSetPool->inactiveDescriptorSetCount - 1]; - descriptorSetPool->inactiveDescriptorSetCount -= 1; + DescriptorSetPool *pool = + &vulkanCommandBuffer->descriptorSetCache->pools[descriptorSetLayout->ID]; - SDL_UnlockSpinlock(&descriptorSetPool->lock); - - if (vulkanCommandBuffer->boundDescriptorSetDataCount == vulkanCommandBuffer->boundDescriptorSetDataCapacity) { - vulkanCommandBuffer->boundDescriptorSetDataCapacity *= 2; - vulkanCommandBuffer->boundDescriptorSetDatas = SDL_realloc( - vulkanCommandBuffer->boundDescriptorSetDatas, - vulkanCommandBuffer->boundDescriptorSetDataCapacity * sizeof(DescriptorSetData)); + if (pool->descriptorSetIndex == pool->descriptorSetCount) { + VULKAN_INTERNAL_AllocateDescriptorsFromPool( + renderer, + descriptorSetLayout, + pool); } - vulkanCommandBuffer->boundDescriptorSetDatas[vulkanCommandBuffer->boundDescriptorSetDataCount].descriptorSet = descriptorSet; - vulkanCommandBuffer->boundDescriptorSetDatas[vulkanCommandBuffer->boundDescriptorSetDataCount].descriptorSetPool = descriptorSetPool; - vulkanCommandBuffer->boundDescriptorSetDataCount += 1; + VkDescriptorSet descriptorSet = pool->descriptorSets[pool->descriptorSetIndex]; + pool->descriptorSetIndex += 1; return descriptorSet; } @@ -4814,34 +4874,44 @@ static void VULKAN_INTERNAL_BindGraphicsDescriptorSets( VulkanCommandBuffer *commandBuffer) { VulkanGraphicsPipelineResourceLayout *resourceLayout; - VkWriteDescriptorSet *writeDescriptorSets; - VkWriteDescriptorSet *currentWriteDescriptorSet; - DescriptorSetPool *descriptorSetPool; - VkDescriptorBufferInfo bufferInfos[MAX_STORAGE_BUFFERS_PER_STAGE]; - VkDescriptorImageInfo imageInfos[MAX_TEXTURE_SAMPLERS_PER_STAGE + MAX_STORAGE_TEXTURES_PER_STAGE]; - Uint32 dynamicOffsets[MAX_UNIFORM_BUFFERS_PER_STAGE]; + DescriptorSetLayout *descriptorSetLayout; + VkWriteDescriptorSet writeDescriptorSets[ + (MAX_TEXTURE_SAMPLERS_PER_STAGE + + MAX_STORAGE_TEXTURES_PER_STAGE + + MAX_STORAGE_BUFFERS_PER_STAGE + + MAX_UNIFORM_BUFFERS_PER_STAGE) * 2]; + VkDescriptorBufferInfo bufferInfos[MAX_STORAGE_BUFFERS_PER_STAGE * 2]; + VkDescriptorImageInfo imageInfos[(MAX_TEXTURE_SAMPLERS_PER_STAGE + MAX_STORAGE_TEXTURES_PER_STAGE) * 2]; + Uint32 dynamicOffsets[MAX_UNIFORM_BUFFERS_PER_STAGE * 2]; + Uint32 writeCount = 0; Uint32 bufferInfoCount = 0; Uint32 imageInfoCount = 0; - Uint32 i; + Uint32 dynamicOffsetCount = 0; - resourceLayout = &commandBuffer->currentGraphicsPipeline->resourceLayout; + if ( + !commandBuffer->needNewVertexResourceDescriptorSet && + !commandBuffer->needNewVertexUniformDescriptorSet && + !commandBuffer->needNewVertexUniformOffsets && + !commandBuffer->needNewFragmentResourceDescriptorSet && + !commandBuffer->needNewFragmentUniformDescriptorSet && + !commandBuffer->needNewFragmentUniformOffsets + ) { + return; + } + + resourceLayout = commandBuffer->currentGraphicsPipeline->resourceLayout; if (commandBuffer->needNewVertexResourceDescriptorSet) { - descriptorSetPool = &resourceLayout->descriptorSetPools[0]; + descriptorSetLayout = resourceLayout->descriptorSetLayouts[0]; commandBuffer->vertexResourceDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( renderer, commandBuffer, - descriptorSetPool); + descriptorSetLayout); - writeDescriptorSets = SDL_stack_alloc( - VkWriteDescriptorSet, - resourceLayout->vertexSamplerCount + - resourceLayout->vertexStorageTextureCount + - resourceLayout->vertexStorageBufferCount); + for (Uint32 i = 0; i < resourceLayout->vertexSamplerCount; i += 1) { + VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; - for (i = 0; i < resourceLayout->vertexSamplerCount; i += 1) { - currentWriteDescriptorSet = &writeDescriptorSets[i]; currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; currentWriteDescriptorSet->descriptorCount = 1; @@ -4858,11 +4928,12 @@ static void VULKAN_INTERNAL_BindGraphicsDescriptorSets( currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; + writeCount += 1; imageInfoCount += 1; } - for (i = 0; i < resourceLayout->vertexStorageTextureCount; i += 1) { - currentWriteDescriptorSet = &writeDescriptorSets[resourceLayout->vertexSamplerCount + i]; + for (Uint32 i = 0; i < resourceLayout->vertexStorageTextureCount; i += 1) { + VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; @@ -4880,11 +4951,12 @@ static void VULKAN_INTERNAL_BindGraphicsDescriptorSets( currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; + writeCount += 1; imageInfoCount += 1; } - for (i = 0; i < resourceLayout->vertexStorageBufferCount; i += 1) { - currentWriteDescriptorSet = &writeDescriptorSets[resourceLayout->vertexSamplerCount + resourceLayout->vertexStorageTextureCount + i]; + for (Uint32 i = 0; i < resourceLayout->vertexStorageBufferCount; i += 1) { + VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; @@ -4902,47 +4974,23 @@ static void VULKAN_INTERNAL_BindGraphicsDescriptorSets( currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; + writeCount += 1; bufferInfoCount += 1; } - renderer->vkUpdateDescriptorSets( - renderer->logicalDevice, - resourceLayout->vertexSamplerCount + resourceLayout->vertexStorageTextureCount + resourceLayout->vertexStorageBufferCount, - writeDescriptorSets, - 0, - NULL); - - renderer->vkCmdBindDescriptorSets( - commandBuffer->commandBuffer, - VK_PIPELINE_BIND_POINT_GRAPHICS, - resourceLayout->pipelineLayout, - 0, - 1, - &commandBuffer->vertexResourceDescriptorSet, - 0, - NULL); - - SDL_stack_free(writeDescriptorSets); - bufferInfoCount = 0; - imageInfoCount = 0; - commandBuffer->needNewVertexResourceDescriptorSet = false; } if (commandBuffer->needNewVertexUniformDescriptorSet) { - descriptorSetPool = &resourceLayout->descriptorSetPools[1]; + descriptorSetLayout = resourceLayout->descriptorSetLayouts[1]; commandBuffer->vertexUniformDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( renderer, commandBuffer, - descriptorSetPool); + descriptorSetLayout); - writeDescriptorSets = SDL_stack_alloc( - VkWriteDescriptorSet, - resourceLayout->vertexUniformBufferCount); - - for (i = 0; i < resourceLayout->vertexUniformBufferCount; i += 1) { - currentWriteDescriptorSet = &writeDescriptorSets[i]; + for (Uint32 i = 0; i < resourceLayout->vertexUniformBufferCount; i += 1) { + VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; @@ -4960,58 +5008,29 @@ static void VULKAN_INTERNAL_BindGraphicsDescriptorSets( currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; + writeCount += 1; bufferInfoCount += 1; } - renderer->vkUpdateDescriptorSets( - renderer->logicalDevice, - resourceLayout->vertexUniformBufferCount, - writeDescriptorSets, - 0, - NULL); - - SDL_stack_free(writeDescriptorSets); - bufferInfoCount = 0; - imageInfoCount = 0; - commandBuffer->needNewVertexUniformDescriptorSet = false; - commandBuffer->needNewVertexUniformOffsets = true; } - if (commandBuffer->needNewVertexUniformOffsets) { - for (i = 0; i < resourceLayout->vertexUniformBufferCount; i += 1) { - dynamicOffsets[i] = commandBuffer->vertexUniformBuffers[i]->drawOffset; - } - - renderer->vkCmdBindDescriptorSets( - commandBuffer->commandBuffer, - VK_PIPELINE_BIND_POINT_GRAPHICS, - resourceLayout->pipelineLayout, - 1, - 1, - &commandBuffer->vertexUniformDescriptorSet, - resourceLayout->vertexUniformBufferCount, - dynamicOffsets); - - commandBuffer->needNewVertexUniformOffsets = false; + for (Uint32 i = 0; i < resourceLayout->vertexUniformBufferCount; i += 1) { + dynamicOffsets[dynamicOffsetCount] = commandBuffer->vertexUniformBuffers[i]->drawOffset; + dynamicOffsetCount += 1; } if (commandBuffer->needNewFragmentResourceDescriptorSet) { - descriptorSetPool = &resourceLayout->descriptorSetPools[2]; + descriptorSetLayout = resourceLayout->descriptorSetLayouts[2]; commandBuffer->fragmentResourceDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( renderer, commandBuffer, - descriptorSetPool); + descriptorSetLayout); - writeDescriptorSets = SDL_stack_alloc( - VkWriteDescriptorSet, - resourceLayout->fragmentSamplerCount + - resourceLayout->fragmentStorageTextureCount + - resourceLayout->fragmentStorageBufferCount); + for (Uint32 i = 0; i < resourceLayout->fragmentSamplerCount; i += 1) { + VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; - for (i = 0; i < resourceLayout->fragmentSamplerCount; i += 1) { - currentWriteDescriptorSet = &writeDescriptorSets[i]; currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; currentWriteDescriptorSet->descriptorCount = 1; @@ -5028,11 +5047,12 @@ static void VULKAN_INTERNAL_BindGraphicsDescriptorSets( currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; + writeCount += 1; imageInfoCount += 1; } - for (i = 0; i < resourceLayout->fragmentStorageTextureCount; i += 1) { - currentWriteDescriptorSet = &writeDescriptorSets[resourceLayout->fragmentSamplerCount + i]; + for (Uint32 i = 0; i < resourceLayout->fragmentStorageTextureCount; i += 1) { + VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; @@ -5050,11 +5070,12 @@ static void VULKAN_INTERNAL_BindGraphicsDescriptorSets( currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; + writeCount += 1; imageInfoCount += 1; } - for (i = 0; i < resourceLayout->fragmentStorageBufferCount; i += 1) { - currentWriteDescriptorSet = &writeDescriptorSets[resourceLayout->fragmentSamplerCount + resourceLayout->fragmentStorageTextureCount + i]; + for (Uint32 i = 0; i < resourceLayout->fragmentStorageBufferCount; i += 1) { + VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; @@ -5072,47 +5093,23 @@ static void VULKAN_INTERNAL_BindGraphicsDescriptorSets( currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; + writeCount += 1; bufferInfoCount += 1; } - renderer->vkUpdateDescriptorSets( - renderer->logicalDevice, - resourceLayout->fragmentSamplerCount + resourceLayout->fragmentStorageTextureCount + resourceLayout->fragmentStorageBufferCount, - writeDescriptorSets, - 0, - NULL); - - renderer->vkCmdBindDescriptorSets( - commandBuffer->commandBuffer, - VK_PIPELINE_BIND_POINT_GRAPHICS, - resourceLayout->pipelineLayout, - 2, - 1, - &commandBuffer->fragmentResourceDescriptorSet, - 0, - NULL); - - SDL_stack_free(writeDescriptorSets); - bufferInfoCount = 0; - imageInfoCount = 0; - commandBuffer->needNewFragmentResourceDescriptorSet = false; } if (commandBuffer->needNewFragmentUniformDescriptorSet) { - descriptorSetPool = &resourceLayout->descriptorSetPools[3]; + descriptorSetLayout = resourceLayout->descriptorSetLayouts[3]; commandBuffer->fragmentUniformDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( renderer, commandBuffer, - descriptorSetPool); + descriptorSetLayout); - writeDescriptorSets = SDL_stack_alloc( - VkWriteDescriptorSet, - resourceLayout->fragmentUniformBufferCount); - - for (i = 0; i < resourceLayout->fragmentUniformBufferCount; i += 1) { - currentWriteDescriptorSet = &writeDescriptorSets[i]; + for (Uint32 i = 0; i < resourceLayout->fragmentUniformBufferCount; i += 1) { + VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; @@ -5130,41 +5127,43 @@ static void VULKAN_INTERNAL_BindGraphicsDescriptorSets( currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; + writeCount += 1; bufferInfoCount += 1; } - renderer->vkUpdateDescriptorSets( - renderer->logicalDevice, - resourceLayout->fragmentUniformBufferCount, - writeDescriptorSets, - 0, - NULL); - - SDL_stack_free(writeDescriptorSets); - bufferInfoCount = 0; - imageInfoCount = 0; - commandBuffer->needNewFragmentUniformDescriptorSet = false; - commandBuffer->needNewFragmentUniformOffsets = true; } - if (commandBuffer->needNewFragmentUniformOffsets) { - for (i = 0; i < resourceLayout->fragmentUniformBufferCount; i += 1) { - dynamicOffsets[i] = commandBuffer->fragmentUniformBuffers[i]->drawOffset; - } - - renderer->vkCmdBindDescriptorSets( - commandBuffer->commandBuffer, - VK_PIPELINE_BIND_POINT_GRAPHICS, - resourceLayout->pipelineLayout, - 3, - 1, - &commandBuffer->fragmentUniformDescriptorSet, - resourceLayout->fragmentUniformBufferCount, - dynamicOffsets); - - commandBuffer->needNewFragmentUniformOffsets = false; + for (Uint32 i = 0; i < resourceLayout->fragmentUniformBufferCount; i += 1) { + dynamicOffsets[dynamicOffsetCount] = commandBuffer->fragmentUniformBuffers[i]->drawOffset; + dynamicOffsetCount += 1; } + + renderer->vkUpdateDescriptorSets( + renderer->logicalDevice, + writeCount, + writeDescriptorSets, + 0, + NULL); + + VkDescriptorSet sets[4]; + sets[0] = commandBuffer->vertexResourceDescriptorSet; + sets[1] = commandBuffer->vertexUniformDescriptorSet; + sets[2] = commandBuffer->fragmentResourceDescriptorSet; + sets[3] = commandBuffer->fragmentUniformDescriptorSet; + + renderer->vkCmdBindDescriptorSets( + commandBuffer->commandBuffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + resourceLayout->pipelineLayout, + 0, + 4, + sets, + dynamicOffsetCount, + dynamicOffsets); + + commandBuffer->needNewVertexUniformOffsets = false; + commandBuffer->needNewFragmentUniformOffsets = false; } static void VULKAN_DrawIndexedPrimitives( @@ -6283,11 +6282,13 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline( // Pipeline Layout - if (!VULKAN_INTERNAL_InitializeGraphicsPipelineResourceLayout( + graphicsPipeline->resourceLayout = + VULKAN_INTERNAL_FetchGraphicsPipelineResourceLayout( renderer, graphicsPipeline->vertexShader, - graphicsPipeline->fragmentShader, - &graphicsPipeline->resourceLayout)) { + graphicsPipeline->fragmentShader); + + if (graphicsPipeline->resourceLayout == NULL) { SDL_stack_free(vertexInputBindingDescriptions); SDL_stack_free(vertexInputAttributeDescriptions); SDL_stack_free(colorBlendAttachmentStates); @@ -6313,7 +6314,7 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline( vkPipelineCreateInfo.pDepthStencilState = &depthStencilStateCreateInfo; vkPipelineCreateInfo.pColorBlendState = &colorBlendStateCreateInfo; vkPipelineCreateInfo.pDynamicState = &dynamicStateCreateInfo; - vkPipelineCreateInfo.layout = graphicsPipeline->resourceLayout.pipelineLayout; + vkPipelineCreateInfo.layout = graphicsPipeline->resourceLayout->pipelineLayout; vkPipelineCreateInfo.renderPass = transientRenderPass; vkPipelineCreateInfo.subpass = 0; vkPipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE; @@ -6358,7 +6359,6 @@ static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline( VkComputePipelineCreateInfo vkShaderCreateInfo; VkPipelineShaderStageCreateInfo pipelineShaderStageCreateInfo; VkResult vulkanResult; - Uint32 i; VulkanRenderer *renderer = (VulkanRenderer *)driverData; VulkanComputePipeline *vulkanComputePipeline; @@ -6395,10 +6395,11 @@ static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline( pipelineShaderStageCreateInfo.pName = createinfo->entrypoint; pipelineShaderStageCreateInfo.pSpecializationInfo = NULL; - if (!VULKAN_INTERNAL_InitializeComputePipelineResourceLayout( - renderer, - createinfo, - &vulkanComputePipeline->resourceLayout)) { + vulkanComputePipeline->resourceLayout = VULKAN_INTERNAL_FetchComputePipelineResourceLayout( + renderer, + createinfo); + + if (vulkanComputePipeline->resourceLayout == NULL) { renderer->vkDestroyShaderModule( renderer->logicalDevice, vulkanComputePipeline->shaderModule, @@ -6411,8 +6412,7 @@ static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline( vkShaderCreateInfo.pNext = NULL; vkShaderCreateInfo.flags = 0; vkShaderCreateInfo.stage = pipelineShaderStageCreateInfo; - vkShaderCreateInfo.layout = - vulkanComputePipeline->resourceLayout.pipelineLayout; + vkShaderCreateInfo.layout = vulkanComputePipeline->resourceLayout->pipelineLayout; vkShaderCreateInfo.basePipelineHandle = (VkPipeline)VK_NULL_HANDLE; vkShaderCreateInfo.basePipelineIndex = 0; @@ -6425,24 +6425,9 @@ static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline( &vulkanComputePipeline->pipeline); if (vulkanResult != VK_SUCCESS) { - renderer->vkDestroyPipelineLayout( - renderer->logicalDevice, - vulkanComputePipeline->resourceLayout.pipelineLayout, - NULL); - - for (i = 0; i < 3; i += 1) { - VULKAN_INTERNAL_DestroyDescriptorSetPool( - renderer, - &vulkanComputePipeline->resourceLayout.descriptorSetPools[i]); - } - - renderer->vkDestroyShaderModule( - renderer->logicalDevice, - vulkanComputePipeline->shaderModule, - NULL); - LogVulkanResultAsError("vkCreateComputePipeline", vulkanResult); SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create compute pipeline!"); + VULKAN_INTERNAL_DestroyComputePipeline(renderer, vulkanComputePipeline); return NULL; } @@ -7667,14 +7652,14 @@ static void VULKAN_BindGraphicsPipeline( VULKAN_INTERNAL_TrackGraphicsPipeline(vulkanCommandBuffer, pipeline); // Acquire uniform buffers if necessary - for (Uint32 i = 0; i < pipeline->resourceLayout.vertexUniformBufferCount; i += 1) { + for (Uint32 i = 0; i < pipeline->resourceLayout->vertexUniformBufferCount; i += 1) { if (vulkanCommandBuffer->vertexUniformBuffers[i] == NULL) { vulkanCommandBuffer->vertexUniformBuffers[i] = VULKAN_INTERNAL_AcquireUniformBufferFromPool( vulkanCommandBuffer); } } - for (Uint32 i = 0; i < pipeline->resourceLayout.fragmentUniformBufferCount; i += 1) { + for (Uint32 i = 0; i < pipeline->resourceLayout->fragmentUniformBufferCount; i += 1) { if (vulkanCommandBuffer->fragmentUniformBuffers[i] == NULL) { vulkanCommandBuffer->fragmentUniformBuffers[i] = VULKAN_INTERNAL_AcquireUniformBufferFromPool( vulkanCommandBuffer); @@ -7899,7 +7884,7 @@ static void VULKAN_BindComputePipeline( VULKAN_INTERNAL_TrackComputePipeline(vulkanCommandBuffer, vulkanComputePipeline); // Acquire uniform buffers if necessary - for (Uint32 i = 0; i < vulkanComputePipeline->resourceLayout.numUniformBuffers; i += 1) { + for (Uint32 i = 0; i < vulkanComputePipeline->resourceLayout->numUniformBuffers; i += 1) { if (vulkanCommandBuffer->computeUniformBuffers[i] == NULL) { vulkanCommandBuffer->computeUniformBuffers[i] = VULKAN_INTERNAL_AcquireUniformBufferFromPool( vulkanCommandBuffer); @@ -8034,34 +8019,44 @@ static void VULKAN_INTERNAL_BindComputeDescriptorSets( VulkanCommandBuffer *commandBuffer) { VulkanComputePipelineResourceLayout *resourceLayout; - VkWriteDescriptorSet *writeDescriptorSets; - VkWriteDescriptorSet *currentWriteDescriptorSet; - DescriptorSetPool *descriptorSetPool; - VkDescriptorBufferInfo bufferInfos[MAX_STORAGE_BUFFERS_PER_STAGE]; // 8 is max for both read and write - VkDescriptorImageInfo imageInfos[MAX_TEXTURE_SAMPLERS_PER_STAGE + MAX_STORAGE_TEXTURES_PER_STAGE]; + DescriptorSetLayout *descriptorSetLayout; + VkWriteDescriptorSet writeDescriptorSets[ + MAX_TEXTURE_SAMPLERS_PER_STAGE + + MAX_STORAGE_TEXTURES_PER_STAGE + + MAX_STORAGE_BUFFERS_PER_STAGE + + MAX_COMPUTE_WRITE_TEXTURES + + MAX_COMPUTE_WRITE_BUFFERS + + MAX_UNIFORM_BUFFERS_PER_STAGE]; + VkDescriptorBufferInfo bufferInfos[MAX_STORAGE_BUFFERS_PER_STAGE + MAX_COMPUTE_WRITE_BUFFERS + MAX_UNIFORM_BUFFERS_PER_STAGE]; + VkDescriptorImageInfo imageInfos[MAX_TEXTURE_SAMPLERS_PER_STAGE + MAX_STORAGE_TEXTURES_PER_STAGE + MAX_COMPUTE_WRITE_TEXTURES]; Uint32 dynamicOffsets[MAX_UNIFORM_BUFFERS_PER_STAGE]; + Uint32 writeCount = 0; Uint32 bufferInfoCount = 0; Uint32 imageInfoCount = 0; - Uint32 i; + Uint32 dynamicOffsetCount = 0; - resourceLayout = &commandBuffer->currentComputePipeline->resourceLayout; + if ( + !commandBuffer->needNewComputeReadOnlyDescriptorSet && + !commandBuffer->needNewComputeWriteOnlyDescriptorSet && + !commandBuffer->needNewComputeUniformDescriptorSet && + !commandBuffer->needNewComputeUniformOffsets + ) { + return; + } + + resourceLayout = commandBuffer->currentComputePipeline->resourceLayout; if (commandBuffer->needNewComputeReadOnlyDescriptorSet) { - descriptorSetPool = &resourceLayout->descriptorSetPools[0]; + descriptorSetLayout = resourceLayout->descriptorSetLayouts[0]; commandBuffer->computeReadOnlyDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( renderer, commandBuffer, - descriptorSetPool); + descriptorSetLayout); - writeDescriptorSets = SDL_stack_alloc( - VkWriteDescriptorSet, - resourceLayout->numSamplers + - resourceLayout->numReadonlyStorageTextures + - resourceLayout->numReadonlyStorageBuffers); + for (Uint32 i = 0; i < resourceLayout->numSamplers; i += 1) { + VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; - for (i = 0; i < resourceLayout->numSamplers; i += 1) { - currentWriteDescriptorSet = &writeDescriptorSets[i]; currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; currentWriteDescriptorSet->descriptorCount = 1; @@ -8078,11 +8073,13 @@ static void VULKAN_INTERNAL_BindComputeDescriptorSets( currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; + writeCount += 1; imageInfoCount += 1; } - for (i = 0; i < resourceLayout->numReadonlyStorageTextures; i += 1) { - currentWriteDescriptorSet = &writeDescriptorSets[i]; + for (Uint32 i = 0; i < resourceLayout->numReadonlyStorageTextures; i += 1) { + VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; + currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; currentWriteDescriptorSet->descriptorCount = 1; @@ -8099,11 +8096,12 @@ static void VULKAN_INTERNAL_BindComputeDescriptorSets( currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; + writeCount += 1; imageInfoCount += 1; } - for (i = 0; i < resourceLayout->numReadonlyStorageBuffers; i += 1) { - currentWriteDescriptorSet = &writeDescriptorSets[resourceLayout->numReadonlyStorageTextures + i]; + for (Uint32 i = 0; i < resourceLayout->numReadonlyStorageBuffers; i += 1) { + VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; @@ -8121,48 +8119,23 @@ static void VULKAN_INTERNAL_BindComputeDescriptorSets( currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; + writeCount += 1; bufferInfoCount += 1; } - renderer->vkUpdateDescriptorSets( - renderer->logicalDevice, - resourceLayout->numSamplers + resourceLayout->numReadonlyStorageTextures + resourceLayout->numReadonlyStorageBuffers, - writeDescriptorSets, - 0, - NULL); - - renderer->vkCmdBindDescriptorSets( - commandBuffer->commandBuffer, - VK_PIPELINE_BIND_POINT_COMPUTE, - resourceLayout->pipelineLayout, - 0, - 1, - &commandBuffer->computeReadOnlyDescriptorSet, - 0, - NULL); - - SDL_stack_free(writeDescriptorSets); - bufferInfoCount = 0; - imageInfoCount = 0; - commandBuffer->needNewComputeReadOnlyDescriptorSet = false; } if (commandBuffer->needNewComputeWriteOnlyDescriptorSet) { - descriptorSetPool = &resourceLayout->descriptorSetPools[1]; + descriptorSetLayout = resourceLayout->descriptorSetLayouts[1]; commandBuffer->computeWriteOnlyDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( renderer, commandBuffer, - descriptorSetPool); + descriptorSetLayout); - writeDescriptorSets = SDL_stack_alloc( - VkWriteDescriptorSet, - resourceLayout->numWriteonlyStorageTextures + - resourceLayout->numWriteonlyStorageBuffers); - - for (i = 0; i < resourceLayout->numWriteonlyStorageTextures; i += 1) { - currentWriteDescriptorSet = &writeDescriptorSets[i]; + for (Uint32 i = 0; i < resourceLayout->numWriteonlyStorageTextures; i += 1) { + VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; @@ -8180,11 +8153,12 @@ static void VULKAN_INTERNAL_BindComputeDescriptorSets( currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; + writeCount += 1; imageInfoCount += 1; } - for (i = 0; i < resourceLayout->numWriteonlyStorageBuffers; i += 1) { - currentWriteDescriptorSet = &writeDescriptorSets[resourceLayout->numWriteonlyStorageTextures + i]; + for (Uint32 i = 0; i < resourceLayout->numWriteonlyStorageBuffers; i += 1) { + VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; @@ -8202,47 +8176,24 @@ static void VULKAN_INTERNAL_BindComputeDescriptorSets( currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; + writeCount += 1; bufferInfoCount += 1; } - renderer->vkUpdateDescriptorSets( - renderer->logicalDevice, - resourceLayout->numWriteonlyStorageTextures + resourceLayout->numWriteonlyStorageBuffers, - writeDescriptorSets, - 0, - NULL); - - renderer->vkCmdBindDescriptorSets( - commandBuffer->commandBuffer, - VK_PIPELINE_BIND_POINT_COMPUTE, - resourceLayout->pipelineLayout, - 1, - 1, - &commandBuffer->computeWriteOnlyDescriptorSet, - 0, - NULL); - - SDL_stack_free(writeDescriptorSets); - bufferInfoCount = 0; - imageInfoCount = 0; - commandBuffer->needNewComputeWriteOnlyDescriptorSet = false; } if (commandBuffer->needNewComputeUniformDescriptorSet) { - descriptorSetPool = &resourceLayout->descriptorSetPools[2]; + descriptorSetLayout = resourceLayout->descriptorSetLayouts[2]; commandBuffer->computeUniformDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( renderer, commandBuffer, - descriptorSetPool); + descriptorSetLayout); - writeDescriptorSets = SDL_stack_alloc( - VkWriteDescriptorSet, - resourceLayout->numUniformBuffers); - for (i = 0; i < resourceLayout->numUniformBuffers; i += 1) { - currentWriteDescriptorSet = &writeDescriptorSets[i]; + for (Uint32 i = 0; i < resourceLayout->numUniformBuffers; i += 1) { + VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; @@ -8260,41 +8211,41 @@ static void VULKAN_INTERNAL_BindComputeDescriptorSets( currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; + writeCount += 1; bufferInfoCount += 1; } - renderer->vkUpdateDescriptorSets( - renderer->logicalDevice, - resourceLayout->numUniformBuffers, - writeDescriptorSets, - 0, - NULL); - - SDL_stack_free(writeDescriptorSets); - bufferInfoCount = 0; - imageInfoCount = 0; - commandBuffer->needNewComputeUniformDescriptorSet = false; - commandBuffer->needNewComputeUniformOffsets = true; } - if (commandBuffer->needNewComputeUniformOffsets) { - for (i = 0; i < resourceLayout->numUniformBuffers; i += 1) { - dynamicOffsets[i] = commandBuffer->computeUniformBuffers[i]->drawOffset; - } - - renderer->vkCmdBindDescriptorSets( - commandBuffer->commandBuffer, - VK_PIPELINE_BIND_POINT_COMPUTE, - resourceLayout->pipelineLayout, - 2, - 1, - &commandBuffer->computeUniformDescriptorSet, - resourceLayout->numUniformBuffers, - dynamicOffsets); - - commandBuffer->needNewComputeUniformOffsets = false; + for (Uint32 i = 0; i < resourceLayout->numUniformBuffers; i += 1) { + dynamicOffsets[i] = commandBuffer->computeUniformBuffers[i]->drawOffset; + dynamicOffsetCount += 1; } + + renderer->vkUpdateDescriptorSets( + renderer->logicalDevice, + writeCount, + writeDescriptorSets, + 0, + NULL); + + VkDescriptorSet sets[3]; + sets[0] = commandBuffer->computeReadOnlyDescriptorSet; + sets[1] = commandBuffer->computeWriteOnlyDescriptorSet; + sets[2] = commandBuffer->computeUniformDescriptorSet; + + renderer->vkCmdBindDescriptorSets( + commandBuffer->commandBuffer, + VK_PIPELINE_BIND_POINT_COMPUTE, + resourceLayout->pipelineLayout, + 0, + 3, + sets, + dynamicOffsetCount, + dynamicOffsets); + + commandBuffer->needNewVertexUniformOffsets = false; } static void VULKAN_DispatchCompute( @@ -9039,13 +8990,6 @@ static void VULKAN_INTERNAL_AllocateCommandBuffers( commandBuffer->signalSemaphores = SDL_malloc( commandBuffer->signalSemaphoreCapacity * sizeof(VkSemaphore)); - // Descriptor set tracking - - commandBuffer->boundDescriptorSetDataCapacity = 16; - commandBuffer->boundDescriptorSetDataCount = 0; - commandBuffer->boundDescriptorSetDatas = SDL_malloc( - commandBuffer->boundDescriptorSetDataCapacity * sizeof(DescriptorSetData)); - // Resource bind tracking commandBuffer->needNewVertexResourceDescriptorSet = true; @@ -9215,6 +9159,8 @@ static SDL_GPUCommandBuffer *VULKAN_AcquireCommandBuffer( VulkanCommandBuffer *commandBuffer = VULKAN_INTERNAL_GetInactiveCommandBufferFromPool(renderer, threadID); + commandBuffer->descriptorSetCache = VULKAN_INTERNAL_AcquireDescriptorSetCache(renderer); + SDL_UnlockMutex(renderer->acquireCommandBufferLock); if (commandBuffer == NULL) { @@ -9933,9 +9879,6 @@ static void VULKAN_INTERNAL_CleanCommandBuffer( VulkanRenderer *renderer, VulkanCommandBuffer *commandBuffer) { - Uint32 i; - DescriptorSetData *descriptorSetData; - if (commandBuffer->autoReleaseFence) { VULKAN_ReleaseFence( (SDL_GPURenderer *)renderer, @@ -9944,33 +9887,11 @@ static void VULKAN_INTERNAL_CleanCommandBuffer( commandBuffer->inFlightFence = NULL; } - // Bound descriptor sets are now available - - for (i = 0; i < commandBuffer->boundDescriptorSetDataCount; i += 1) { - descriptorSetData = &commandBuffer->boundDescriptorSetDatas[i]; - - SDL_TryLockSpinlock(&descriptorSetData->descriptorSetPool->lock); - - if (descriptorSetData->descriptorSetPool->inactiveDescriptorSetCount == descriptorSetData->descriptorSetPool->inactiveDescriptorSetCapacity) { - descriptorSetData->descriptorSetPool->inactiveDescriptorSetCapacity *= 2; - descriptorSetData->descriptorSetPool->inactiveDescriptorSets = SDL_realloc( - descriptorSetData->descriptorSetPool->inactiveDescriptorSets, - descriptorSetData->descriptorSetPool->inactiveDescriptorSetCapacity * sizeof(VkDescriptorSet)); - } - - descriptorSetData->descriptorSetPool->inactiveDescriptorSets[descriptorSetData->descriptorSetPool->inactiveDescriptorSetCount] = descriptorSetData->descriptorSet; - descriptorSetData->descriptorSetPool->inactiveDescriptorSetCount += 1; - - SDL_UnlockSpinlock(&descriptorSetData->descriptorSetPool->lock); - } - - commandBuffer->boundDescriptorSetDataCount = 0; - // Uniform buffers are now available SDL_LockMutex(renderer->acquireUniformBufferLock); - for (i = 0; i < commandBuffer->usedUniformBufferCount; i += 1) { + for (Sint32 i = 0; i < commandBuffer->usedUniformBufferCount; i += 1) { VULKAN_INTERNAL_ReturnUniformBufferToPool( renderer, commandBuffer->usedUniformBuffers[i]); @@ -9981,32 +9902,32 @@ static void VULKAN_INTERNAL_CleanCommandBuffer( // Decrement reference counts - for (i = 0; i < commandBuffer->usedBufferCount; i += 1) { + for (Sint32 i = 0; i < commandBuffer->usedBufferCount; i += 1) { (void)SDL_AtomicDecRef(&commandBuffer->usedBuffers[i]->referenceCount); } commandBuffer->usedBufferCount = 0; - for (i = 0; i < commandBuffer->usedTextureCount; i += 1) { + for (Sint32 i = 0; i < commandBuffer->usedTextureCount; i += 1) { (void)SDL_AtomicDecRef(&commandBuffer->usedTextures[i]->referenceCount); } commandBuffer->usedTextureCount = 0; - for (i = 0; i < commandBuffer->usedSamplerCount; i += 1) { + for (Sint32 i = 0; i < commandBuffer->usedSamplerCount; i += 1) { (void)SDL_AtomicDecRef(&commandBuffer->usedSamplers[i]->referenceCount); } commandBuffer->usedSamplerCount = 0; - for (i = 0; i < commandBuffer->usedGraphicsPipelineCount; i += 1) { + for (Sint32 i = 0; i < commandBuffer->usedGraphicsPipelineCount; i += 1) { (void)SDL_AtomicDecRef(&commandBuffer->usedGraphicsPipelines[i]->referenceCount); } commandBuffer->usedGraphicsPipelineCount = 0; - for (i = 0; i < commandBuffer->usedComputePipelineCount; i += 1) { + for (Sint32 i = 0; i < commandBuffer->usedComputePipelineCount; i += 1) { (void)SDL_AtomicDecRef(&commandBuffer->usedComputePipelines[i]->referenceCount); } commandBuffer->usedComputePipelineCount = 0; - for (i = 0; i < commandBuffer->usedFramebufferCount; i += 1) { + for (Sint32 i = 0; i < commandBuffer->usedFramebufferCount; i += 1) { (void)SDL_AtomicDecRef(&commandBuffer->usedFramebuffers[i]->referenceCount); } commandBuffer->usedFramebufferCount = 0; @@ -10037,10 +9958,18 @@ static void VULKAN_INTERNAL_CleanCommandBuffer( commandBuffer->commandPool->inactiveCommandBuffers[commandBuffer->commandPool->inactiveCommandBufferCount] = commandBuffer; commandBuffer->commandPool->inactiveCommandBufferCount += 1; + // Release descriptor set cache + + VULKAN_INTERNAL_ReturnDescriptorSetCacheToPool( + renderer, + commandBuffer->descriptorSetCache); + + commandBuffer->descriptorSetCache = NULL; + SDL_UnlockMutex(renderer->acquireCommandBufferLock); // Remove this command buffer from the submitted list - for (i = 0; i < renderer->submittedCommandBufferCount; i += 1) { + for (Uint32 i = 0; i < renderer->submittedCommandBufferCount; i += 1) { if (renderer->submittedCommandBuffers[i] == commandBuffer) { renderer->submittedCommandBuffers[i] = renderer->submittedCommandBuffers[renderer->submittedCommandBufferCount - 1]; renderer->submittedCommandBufferCount -= 1; @@ -11397,6 +11326,12 @@ static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, S UNIFORM_BUFFER_SIZE); } + renderer->descriptorSetCachePoolCapacity = 8; + renderer->descriptorSetCachePoolCount = 0; + renderer->descriptorSetCachePool = SDL_calloc(renderer->descriptorSetCachePoolCapacity, sizeof(DescriptorSetCache *)); + + SDL_SetAtomicInt(&renderer->layoutResourceID, 0); + // Device limits renderer->minUBOAlignment = (Uint32)renderer->physicalDeviceProperties.properties.limits.minUniformBufferOffsetAlignment; @@ -11427,6 +11362,30 @@ static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, S VULKAN_INTERNAL_FramebufferHashNuke, false); + renderer->graphicsPipelineResourceLayoutHashTable = SDL_CreateHashTable( + (void *)renderer, + 64, + VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashFunction, + VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashKeyMatch, + VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashNuke, + false); + + renderer->computePipelineResourceLayoutHashTable = SDL_CreateHashTable( + (void *)renderer, + 64, + VULKAN_INTERNAL_ComputePipelineResourceLayoutHashFunction, + VULKAN_INTERNAL_ComputePipelineResourceLayoutHashKeyMatch, + VULKAN_INTERNAL_ComputePipelineResourceLayoutHashNuke, + false); + + renderer->descriptorSetLayoutHashTable = SDL_CreateHashTable( + (void *)renderer, + 64, + VULKAN_INTERNAL_DescriptorSetLayoutHashFunction, + VULKAN_INTERNAL_DescriptorSetLayoutHashKeyMatch, + VULKAN_INTERNAL_DescriptorSetLayoutHashNuke, + false); + // Initialize fence pool renderer->fencePool.lock = SDL_CreateMutex(); diff --git a/external/SDL/src/hidapi/mac/hid.c b/external/SDL/src/hidapi/mac/hid.c index db20b35c..8acb6da7 100644 --- a/external/SDL/src/hidapi/mac/hid.c +++ b/external/SDL/src/hidapi/mac/hid.c @@ -1572,7 +1572,7 @@ int HID_API_EXPORT_CALL hid_get_report_descriptor(hid_device *dev, unsigned char } memcpy(buf, descriptor_buf, copy_len); - return copy_len; + return (int)copy_len; } else { register_device_error(dev, "Failed to get kIOHIDReportDescriptorKey property"); diff --git a/external/SDL/src/joystick/SDL_gamepad.c b/external/SDL/src/joystick/SDL_gamepad.c index b6d4c16e..2997b9f7 100644 --- a/external/SDL/src/joystick/SDL_gamepad.c +++ b/external/SDL/src/joystick/SDL_gamepad.c @@ -806,6 +806,9 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid) // The original SHIELD controller has a touchpad and plus/minus buttons as well SDL_strlcat(mapping_string, "touchpad:b12,misc2:b13,misc3:b14", sizeof(mapping_string)); } + } else if (SDL_IsJoystickHoriSteamController(vendor, product)) { + /* The Wireless HORIPad for Steam has QAM, Steam, Capsense L/R Sticks, 2 rear buttons, and 2 misc buttons */ + SDL_strlcat(mapping_string, "paddle1:b13,paddle2:b12,paddle3:b15,paddle4:b14,misc2:b11,misc3:b16,misc4:b17", sizeof(mapping_string)); } else { switch (SDL_GetGamepadTypeFromGUID(guid, NULL)) { case SDL_GAMEPAD_TYPE_PS4: diff --git a/external/SDL/src/joystick/SDL_joystick.c b/external/SDL/src/joystick/SDL_joystick.c index 2d4177b6..53afe156 100644 --- a/external/SDL/src/joystick/SDL_joystick.c +++ b/external/SDL/src/joystick/SDL_joystick.c @@ -366,6 +366,7 @@ static Uint32 initial_wheel_devices[] = { MAKE_VIDPID(0x044f, 0xb65e), // Thrustmaster T500RS MAKE_VIDPID(0x044f, 0xb664), // Thrustmaster TX (initial mode) MAKE_VIDPID(0x044f, 0xb669), // Thrustmaster TX (active mode) + MAKE_VIDPID(0x044f, 0xb67f), // Thrustmaster TMX MAKE_VIDPID(0x044f, 0xb691), // Thrustmaster TS-XW (initial mode) MAKE_VIDPID(0x044f, 0xb692), // Thrustmaster TS-XW (active mode) MAKE_VIDPID(0x0483, 0x0522), // Simagic Wheelbase (including M10, Alpha Mini, Alpha, Alpha U) @@ -3099,6 +3100,11 @@ bool SDL_IsJoystickSteamController(Uint16 vendor_id, Uint16 product_id) return eType == k_eControllerType_SteamController || eType == k_eControllerType_SteamControllerV2; } +bool SDL_IsJoystickHoriSteamController(Uint16 vendor_id, Uint16 product_id) +{ + return vendor_id == USB_VENDOR_HORI && (product_id == USB_PRODUCT_HORI_STEAM_CONTROLLER || product_id == USB_PRODUCT_HORI_STEAM_CONTROLLER_BT); +} + bool SDL_IsJoystickSteamDeck(Uint16 vendor_id, Uint16 product_id) { EControllerType eType = GuessControllerType(vendor_id, product_id); diff --git a/external/SDL/src/joystick/SDL_joystick_c.h b/external/SDL/src/joystick/SDL_joystick_c.h index 5bd15aec..b31dcb18 100644 --- a/external/SDL/src/joystick/SDL_joystick_c.h +++ b/external/SDL/src/joystick/SDL_joystick_c.h @@ -129,6 +129,9 @@ extern bool SDL_IsJoystickNVIDIASHIELDController(Uint16 vendor_id, Uint16 produc // Function to return whether a joystick is a Steam Controller extern bool SDL_IsJoystickSteamController(Uint16 vendor_id, Uint16 product_id); +// Function to return whether a joystick is a HORI Steam controller +extern bool SDL_IsJoystickHoriSteamController(Uint16 vendor_id, Uint16 product_id); + // Function to return whether a joystick is a Steam Deck extern bool SDL_IsJoystickSteamDeck(Uint16 vendor_id, Uint16 product_id); diff --git a/external/SDL/src/joystick/hidapi/SDL_hidapi_steam_hori.c b/external/SDL/src/joystick/hidapi/SDL_hidapi_steam_hori.c new file mode 100644 index 00000000..75d786db --- /dev/null +++ b/external/SDL/src/joystick/hidapi/SDL_hidapi_steam_hori.c @@ -0,0 +1,415 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2024 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifdef SDL_JOYSTICK_HIDAPI + +#include "../SDL_sysjoystick.h" +#include "SDL_hidapijoystick_c.h" +#include "SDL_hidapi_rumble.h" +#include "../SDL_joystick_c.h" + +#ifdef SDL_JOYSTICK_HIDAPI_STEAM_HORI + +/* Define this if you want to log all packets from the controller */ +/*#define DEBUG_HORI_PROTOCOL*/ + +#define LOAD16(A, B) (Sint16)((Uint16)(A) | (((Uint16)(B)) << 8)) + +enum +{ + SDL_GAMEPAD_BUTTON_HORI_QAM = 11, + SDL_GAMEPAD_BUTTON_HORI_FR, + SDL_GAMEPAD_BUTTON_HORI_FL, + SDL_GAMEPAD_BUTTON_HORI_M1, + SDL_GAMEPAD_BUTTON_HORI_M2, + SDL_GAMEPAD_BUTTON_HORI_JOYSTICK_TOUCH_L, + SDL_GAMEPAD_BUTTON_HORI_JOYSTICK_TOUCH_R, + SDL_GAMEPAD_NUM_HORI_BUTTONS +}; + +typedef struct +{ + Uint8 last_state[USB_PACKET_LENGTH]; + Uint64 sensor_ticks; + Uint32 last_tick; + bool wireless; + bool serial_needs_init; +} SDL_DriverSteamHori_Context; + +static bool HIDAPI_DriverSteamHori_UpdateDevice(SDL_HIDAPI_Device *device); + +static void HIDAPI_DriverSteamHori_RegisterHints(SDL_HintCallback callback, void *userdata) +{ + SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_STEAM_HORI, callback, userdata); +} + +static void HIDAPI_DriverSteamHori_UnregisterHints(SDL_HintCallback callback, void *userdata) +{ + SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_STEAM_HORI, callback, userdata); +} + +static bool HIDAPI_DriverSteamHori_IsEnabled(void) +{ + return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_STEAM_HORI, SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI, SDL_HIDAPI_DEFAULT)); +} + +static bool HIDAPI_DriverSteamHori_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, SDL_GamepadType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol) +{ + return SDL_IsJoystickHoriSteamController(vendor_id, product_id); +} + +static bool HIDAPI_DriverSteamHori_InitDevice(SDL_HIDAPI_Device *device) +{ + SDL_DriverSteamHori_Context *ctx; + + ctx = (SDL_DriverSteamHori_Context *)SDL_calloc(1, sizeof(*ctx)); + if (!ctx) { + return false; + } + + device->context = ctx; + ctx->serial_needs_init = true; + + HIDAPI_SetDeviceName(device, "Wireless HORIPAD For Steam"); + + return HIDAPI_JoystickConnected(device, NULL); +} + +static int HIDAPI_DriverSteamHori_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id) +{ + return -1; +} + +static void HIDAPI_DriverSteamHori_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index) +{ +} + +static bool HIDAPI_DriverSteamHori_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) +{ + SDL_DriverSteamHori_Context *ctx = (SDL_DriverSteamHori_Context *)device->context; + + SDL_AssertJoysticksLocked(); + + SDL_zeroa(ctx->last_state); + + /* Initialize the joystick capabilities */ + joystick->nbuttons = SDL_GAMEPAD_NUM_HORI_BUTTONS; + joystick->naxes = SDL_GAMEPAD_AXIS_COUNT; + joystick->nhats = 1; + + ctx->wireless = device->product_id == USB_PRODUCT_HORI_STEAM_CONTROLLER_BT; + + if (ctx->wireless && device->serial) { + joystick->serial = SDL_strdup(device->serial); + ctx->serial_needs_init = false; + } else if (!ctx->wireless) { + // Need to actual read from the device to init the serial + HIDAPI_DriverSteamHori_UpdateDevice(device); + } + + SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 250.0f); + SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 250.0f); + + return true; +} + +static bool HIDAPI_DriverSteamHori_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) +{ + // Device doesn't support rumble + return SDL_Unsupported(); +} + +static bool HIDAPI_DriverSteamHori_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) +{ + return SDL_Unsupported(); +} + +static Uint32 HIDAPI_DriverSteamHori_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) +{ + return 0; +} + +static bool HIDAPI_DriverSteamHori_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) +{ + return SDL_Unsupported(); +} + +static bool HIDAPI_DriverSteamHori_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size) +{ + return SDL_Unsupported(); +} + +static bool HIDAPI_DriverSteamHori_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, bool enabled) +{ + return true; +} + +#undef clamp +#define clamp(val, min, max) (((val) > (max)) ? (max) : (((val) < (min)) ? (min) : (val))) + +#ifndef DEG2RAD +#define DEG2RAD(x) ((float)(x) * (float)(SDL_PI_F / 180.f)) +#endif + +//--------------------------------------------------------------------------- +// Scale and clamp values to a range +//--------------------------------------------------------------------------- +static float RemapValClamped(float val, float A, float B, float C, float D) +{ + if (A == B) { + return (val - B) >= 0.0f ? D : C; + } else { + float cVal = (val - A) / (B - A); + cVal = clamp(cVal, 0.0f, 1.0f); + + return C + (D - C) * cVal; + } +} + +#define REPORT_HEADER_USB 0x07 +#define REPORT_HEADER_BT 0x00 + +static void HIDAPI_DriverSteamHori_HandleStatePacket(SDL_Joystick *joystick, SDL_DriverSteamHori_Context *ctx, Uint8 *data, int size) +{ + Sint16 axis; + Uint64 timestamp = SDL_GetTicksNS(); + + // Make sure it's gamepad state and not OTA FW update info + if (data[0] != REPORT_HEADER_USB && data[0] != REPORT_HEADER_BT) { + /* We don't know how to handle this report */ + return; + } + + #define READ_STICK_AXIS(offset) \ + (data[offset] == 0x80 ? 0 : (Sint16)HIDAPI_RemapVal((float)((int)data[offset] - 0x80), -0x80, 0xff - 0x80, SDL_MIN_SINT16, SDL_MAX_SINT16)) + { + axis = READ_STICK_AXIS(1); + SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis); + axis = READ_STICK_AXIS(2); + SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis); + axis = READ_STICK_AXIS(3); + SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis); + axis = READ_STICK_AXIS(4); + SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis); + } +#undef READ_STICK_AXIS + + if (ctx->last_state[5] != data[5]) { + Uint8 hat; + + switch (data[5] & 0xF) { + case 0: + hat = SDL_HAT_UP; + break; + case 1: + hat = SDL_HAT_RIGHTUP; + break; + case 2: + hat = SDL_HAT_RIGHT; + break; + case 3: + hat = SDL_HAT_RIGHTDOWN; + break; + case 4: + hat = SDL_HAT_DOWN; + break; + case 5: + hat = SDL_HAT_LEFTDOWN; + break; + case 6: + hat = SDL_HAT_LEFT; + break; + case 7: + hat = SDL_HAT_LEFTUP; + break; + default: + hat = SDL_HAT_CENTERED; + break; + } + SDL_SendJoystickHat(timestamp, joystick, 0, hat); + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[5] & 0x10) != 0)); + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[5] & 0x20) != 0)); + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_HORI_QAM, ((data[5] & 0x40) != 0)); + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[5] & 0x80) != 0)); + + } + + if (ctx->last_state[6] != data[6]) { + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[6] & 0x01) != 0)); + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_HORI_M1 /* M1 */, ((data[6] & 0x02) != 0)); + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data[6] & 0x04) != 0)); + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data[6] & 0x08) != 0)); + + // TODO: can we handle the digital trigger mode? The data seems to come through analog regardless of the trigger state + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((data[6] & 0x40) != 0)); + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[6] & 0x80) != 0)); + } + + if (ctx->last_state[7] != data[7]) { + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[7] & 0x01) != 0)); + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[7] & 0x02) != 0)); + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[7] & 0x04) != 0)); + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_HORI_M2, ((data[7] & 0x08) != 0)); + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_HORI_JOYSTICK_TOUCH_L, ((data[7] & 0x10) != 0)); + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_HORI_JOYSTICK_TOUCH_R, ((data[7] & 0x20) != 0)); + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_HORI_FR, ((data[7] & 0x40) != 0)); + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_HORI_FL, ((data[7] & 0x80) != 0)); + } + + if (!ctx->wireless && ctx->serial_needs_init) { + char serial[18]; + (void)SDL_snprintf(serial, sizeof(serial), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x", + data[38], data[39], data[40], data[41], data[42], data[43]); + + joystick->serial = SDL_strdup(serial); + ctx->serial_needs_init = false; + } + +#define READ_TRIGGER_AXIS(offset) \ + (Sint16)(((int)data[offset] * 257) - 32768) + { + axis = READ_TRIGGER_AXIS(8); + SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis); + axis = READ_TRIGGER_AXIS(9); + SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis); + } +#undef READ_TRIGGER_AXIS + + if (1) { + Uint64 sensor_timestamp; + float imu_data[3]; + + /* 16-bit timestamp */ + Uint32 delta; + Uint16 tick = LOAD16(data[10], + data[11]); + if (ctx->last_tick < tick) { + delta = (tick - ctx->last_tick); + } else { + delta = (SDL_MAX_UINT16 - ctx->last_tick + tick + 1); + } + + ctx->last_tick = tick; + ctx->sensor_ticks += delta; + + /* Sensor timestamp is in 1us units, but there seems to be some issues with the values reported from the device */ + sensor_timestamp = timestamp; // if the values were good we woudl call SDL_US_TO_NS(ctx->sensor_ticks); + + const float accelScale = SDL_STANDARD_GRAVITY * 8 / 32768.0f; + const float gyroScale = DEG2RAD(2048); + + imu_data[1] = RemapValClamped(-1.0f * LOAD16(data[12], data[13]), INT16_MIN, INT16_MAX, -gyroScale, gyroScale); + imu_data[2] = RemapValClamped(-1.0f * LOAD16(data[14], data[15]), INT16_MIN, INT16_MAX, -gyroScale, gyroScale); + imu_data[0] = RemapValClamped(-1.0f * LOAD16(data[16], data[17]), INT16_MIN, INT16_MAX, -gyroScale, gyroScale); + + + SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_GYRO, sensor_timestamp, imu_data, 3); + + // SDL_Log("%u %f, %f, %f \n", data[0], imu_data[0], imu_data[1], imu_data[2] ); + imu_data[2] = LOAD16(data[18], data[19]) * accelScale; + imu_data[1] = -1 * LOAD16(data[20], data[21]) * accelScale; + imu_data[0] = LOAD16(data[22], data[23]) * accelScale; + SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, sensor_timestamp, imu_data, 3); + } + + if (ctx->last_state[24] != data[24]) { + bool bCharging = (data[24] & 0x10) != 0; + int percent = (data[24] & 0xF) * 10; + SDL_PowerState state; + if (bCharging) { + state = SDL_POWERSTATE_CHARGING; + } else if (ctx->wireless) { + state = SDL_POWERSTATE_ON_BATTERY; + } else { + state = SDL_POWERSTATE_CHARGED; + } + + SDL_SendJoystickPowerInfo(joystick, state, percent); + } + + SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state))); +} + +static bool HIDAPI_DriverSteamHori_UpdateDevice(SDL_HIDAPI_Device *device) +{ + SDL_DriverSteamHori_Context *ctx = (SDL_DriverSteamHori_Context *)device->context; + SDL_Joystick *joystick = NULL; + Uint8 data[USB_PACKET_LENGTH]; + int size = 0; + + if (device->num_joysticks > 0) { + joystick = SDL_GetJoystickFromID(device->joysticks[0]); + } else { + return false; + } + + while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) { +#ifdef DEBUG_HORI_PROTOCOL + HIDAPI_DumpPacket("Google Hori packet: size = %d", data, size); +#endif + if (!joystick) { + continue; + } + + HIDAPI_DriverSteamHori_HandleStatePacket(joystick, ctx, data, size); + } + + if (size < 0) { + /* Read error, device is disconnected */ + HIDAPI_JoystickDisconnected(device, device->joysticks[0]); + } + return (size >= 0); +} + +static void HIDAPI_DriverSteamHori_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) +{ +} + +static void HIDAPI_DriverSteamHori_FreeDevice(SDL_HIDAPI_Device *device) +{ +} + +SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSteamHori = { + SDL_HINT_JOYSTICK_HIDAPI_STEAM_HORI, + true, + HIDAPI_DriverSteamHori_RegisterHints, + HIDAPI_DriverSteamHori_UnregisterHints, + HIDAPI_DriverSteamHori_IsEnabled, + HIDAPI_DriverSteamHori_IsSupportedDevice, + HIDAPI_DriverSteamHori_InitDevice, + HIDAPI_DriverSteamHori_GetDevicePlayerIndex, + HIDAPI_DriverSteamHori_SetDevicePlayerIndex, + HIDAPI_DriverSteamHori_UpdateDevice, + HIDAPI_DriverSteamHori_OpenJoystick, + HIDAPI_DriverSteamHori_RumbleJoystick, + HIDAPI_DriverSteamHori_RumbleJoystickTriggers, + HIDAPI_DriverSteamHori_GetJoystickCapabilities, + HIDAPI_DriverSteamHori_SetJoystickLED, + HIDAPI_DriverSteamHori_SendJoystickEffect, + HIDAPI_DriverSteamHori_SetJoystickSensorsEnabled, + HIDAPI_DriverSteamHori_CloseJoystick, + HIDAPI_DriverSteamHori_FreeDevice, +}; + +#endif /* SDL_JOYSTICK_HIDAPI_STEAM_HORI */ + +#endif /* SDL_JOYSTICK_HIDAPI */ diff --git a/external/SDL/src/joystick/hidapi/SDL_hidapijoystick.c b/external/SDL/src/joystick/hidapi/SDL_hidapijoystick.c index 5b153e7e..27911a40 100644 --- a/external/SDL/src/joystick/hidapi/SDL_hidapijoystick.c +++ b/external/SDL/src/joystick/hidapi/SDL_hidapijoystick.c @@ -67,6 +67,9 @@ static SDL_HIDAPI_DeviceDriver *SDL_HIDAPI_drivers[] = { #ifdef SDL_JOYSTICK_HIDAPI_STEAM &SDL_HIDAPI_DriverSteam, #endif +#ifdef SDL_JOYSTICK_HIDAPI_STEAM_HORI + &SDL_HIDAPI_DriverSteamHori, +#endif #ifdef SDL_JOYSTICK_HIDAPI_STEAMDECK &SDL_HIDAPI_DriverSteamDeck, #endif diff --git a/external/SDL/src/joystick/hidapi/SDL_hidapijoystick_c.h b/external/SDL/src/joystick/hidapi/SDL_hidapijoystick_c.h index afa00296..8b97f762 100644 --- a/external/SDL/src/joystick/hidapi/SDL_hidapijoystick_c.h +++ b/external/SDL/src/joystick/hidapi/SDL_hidapijoystick_c.h @@ -39,6 +39,7 @@ #define SDL_JOYSTICK_HIDAPI_XBOX360 #define SDL_JOYSTICK_HIDAPI_XBOXONE #define SDL_JOYSTICK_HIDAPI_SHIELD +#define SDL_JOYSTICK_HIDAPI_STEAM_HORI // Joystick capability definitions #define SDL_JOYSTICK_CAP_MONO_LED 0x00000001 @@ -150,6 +151,7 @@ extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverWii; extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360; extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360W; extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne; +extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSteamHori; // Return true if a HID device is present and supported as a joystick of the given type extern bool HIDAPI_IsDeviceTypePresent(SDL_GamepadType type); diff --git a/external/SDL/src/joystick/usb_ids.h b/external/SDL/src/joystick/usb_ids.h index 3b03739a..202e3edd 100644 --- a/external/SDL/src/joystick/usb_ids.h +++ b/external/SDL/src/joystick/usb_ids.h @@ -74,6 +74,8 @@ #define USB_PRODUCT_HORI_FIGHTING_STICK_ALPHA_PS4 0x011c #define USB_PRODUCT_HORI_FIGHTING_STICK_ALPHA_PS5 0x0184 #define USB_PRODUCT_HORI_FIGHTING_STICK_ALPHA_PS5 0x0184 +#define USB_PRODUCT_HORI_STEAM_CONTROLLER 0x01AB +#define USB_PRODUCT_HORI_STEAM_CONTROLLER_BT 0x0196 #define USB_PRODUCT_LOGITECH_F310 0xc216 #define USB_PRODUCT_LOGITECH_CHILLSTREAM 0xcad1 #define USB_PRODUCT_MADCATZ_SAITEK_SIDE_PANEL_CONTROL_DECK 0x2218 diff --git a/external/SDL/src/process/posix/SDL_posixprocess.c b/external/SDL/src/process/posix/SDL_posixprocess.c index a3c3fb38..ce0d58ce 100644 --- a/external/SDL/src/process/posix/SDL_posixprocess.c +++ b/external/SDL/src/process/posix/SDL_posixprocess.c @@ -143,7 +143,7 @@ static bool AddFileDescriptorCloseActions(posix_spawn_file_actions_t *fa) } closedir(dir); } else { - for (int fd = sysconf(_SC_OPEN_MAX) - 1; fd > STDERR_FILENO; --fd) { + for (int fd = (int)(sysconf(_SC_OPEN_MAX) - 1); fd > STDERR_FILENO; --fd) { int flags = fcntl(fd, F_GETFD); if (flags < 0 || (flags & FD_CLOEXEC)) { continue; diff --git a/external/SDL/src/stdlib/SDL_getenv.c b/external/SDL/src/stdlib/SDL_getenv.c index 98dabe67..6b691e3d 100644 --- a/external/SDL/src/stdlib/SDL_getenv.c +++ b/external/SDL/src/stdlib/SDL_getenv.c @@ -21,6 +21,7 @@ #include "SDL_internal.h" #include "../SDL_hashtable.h" +#include "SDL_getenv_c.h" #if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) #include "../core/windows/SDL_windows.h" diff --git a/external/SDL/src/video/cocoa/SDL_cocoapen.m b/external/SDL/src/video/cocoa/SDL_cocoapen.m index 663472be..6a9ff9a1 100644 --- a/external/SDL/src/video/cocoa/SDL_cocoapen.m +++ b/external/SDL/src/video/cocoa/SDL_cocoapen.m @@ -115,7 +115,7 @@ static void Cocoa_HandlePenProximityEvent(SDL_CocoaWindowData *_data, NSEvent *e static void Cocoa_HandlePenPointEvent(SDL_CocoaWindowData *_data, NSEvent *event) { - const Uint32 timestamp = Cocoa_GetEventTimestamp([event timestamp]); + const Uint64 timestamp = Cocoa_GetEventTimestamp([event timestamp]); Cocoa_PenHandle *handle = Cocoa_FindPenByDeviceID([event deviceID], [event pointingDeviceID]); if (!handle) { return; diff --git a/external/SDL/src/video/uikit/SDL_uikitviewcontroller.m b/external/SDL/src/video/uikit/SDL_uikitviewcontroller.m index 41f88236..15efd373 100644 --- a/external/SDL/src/video/uikit/SDL_uikitviewcontroller.m +++ b/external/SDL/src/video/uikit/SDL_uikitviewcontroller.m @@ -404,7 +404,7 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char break; case SDL_TEXTINPUT_TYPE_TEXT_USERNAME: textField.keyboardType = UIKeyboardTypeDefault; - if (@available(iOS 11.0, *)) { + if (@available(iOS 11.0, tvOS 11.0, *)) { textField.textContentType = UITextContentTypeUsername; } else { textField.textContentType = nil; @@ -412,7 +412,7 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char break; case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_HIDDEN: textField.keyboardType = UIKeyboardTypeDefault; - if (@available(iOS 11.0, *)) { + if (@available(iOS 11.0, tvOS 11.0, *)) { textField.textContentType = UITextContentTypePassword; } else { textField.textContentType = nil; @@ -421,7 +421,7 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char break; case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_VISIBLE: textField.keyboardType = UIKeyboardTypeDefault; - if (@available(iOS 11.0, *)) { + if (@available(iOS 11.0, tvOS 11.0, *)) { textField.textContentType = UITextContentTypePassword; } else { textField.textContentType = nil; @@ -433,7 +433,7 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char break; case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_HIDDEN: textField.keyboardType = UIKeyboardTypeNumberPad; - if (@available(iOS 12.0, *)) { + if (@available(iOS 12.0, tvOS 12.0, *)) { textField.textContentType = UITextContentTypeOneTimeCode; } else { textField.textContentType = nil; @@ -442,7 +442,7 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char break; case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_VISIBLE: textField.keyboardType = UIKeyboardTypeNumberPad; - if (@available(iOS 12.0, *)) { + if (@available(iOS 12.0, tvOS 12.0, *)) { textField.textContentType = UITextContentTypeOneTimeCode; } else { textField.textContentType = nil; diff --git a/external/SDL/src/video/wayland/SDL_waylandmouse.c b/external/SDL/src/video/wayland/SDL_waylandmouse.c index 576e898a..7b21a254 100644 --- a/external/SDL/src/video/wayland/SDL_waylandmouse.c +++ b/external/SDL/src/video/wayland/SDL_waylandmouse.c @@ -72,7 +72,8 @@ typedef struct { Wayland_SystemCursorFrame *frames; struct wl_callback *frame_callback; - Uint64 last_frame_time_ms; + Uint64 last_frame_callback_time_ms; + Uint64 current_frame_time_ms; Uint32 total_duration; int num_frames; int current_frame; @@ -304,16 +305,20 @@ static void cursor_frame_done(void *data, struct wl_callback *cb, uint32_t time) SDL_CursorData *c = (SDL_CursorData *)data; const Uint64 now = SDL_GetTicks(); - const Uint64 elapsed = (now - c->cursor_data.system.last_frame_time_ms) % c->cursor_data.system.total_duration; + const Uint64 elapsed = (now - c->cursor_data.system.last_frame_callback_time_ms) % c->cursor_data.system.total_duration; + Uint64 advance = 0; int next = c->cursor_data.system.current_frame; wl_callback_destroy(cb); c->cursor_data.system.frame_callback = wl_surface_frame(c->surface); wl_callback_add_listener(c->cursor_data.system.frame_callback, &cursor_frame_listener, data); + c->cursor_data.system.current_frame_time_ms += elapsed; + // Calculate the next frame based on the elapsed duration. - for (Uint64 t = c->cursor_data.system.frames[next].duration; t <= elapsed; t += c->cursor_data.system.frames[next].duration) { + for (Uint64 t = c->cursor_data.system.frames[next].duration; t <= c->cursor_data.system.current_frame_time_ms; t += c->cursor_data.system.frames[next].duration) { next = (next + 1) % c->cursor_data.system.num_frames; + advance = t; // Make sure we don't end up in an infinite loop if a cursor has frame durations of 0. if (!c->cursor_data.system.frames[next].duration) { @@ -321,7 +326,8 @@ static void cursor_frame_done(void *data, struct wl_callback *cb, uint32_t time) } } - c->cursor_data.system.last_frame_time_ms = now; + c->cursor_data.system.current_frame_time_ms -= advance; + c->cursor_data.system.last_frame_callback_time_ms = now; c->cursor_data.system.current_frame = next; wl_surface_attach(c->surface, c->cursor_data.system.frames[next].wl_buffer, 0, 0); if (wl_surface_get_version(c->surface) >= WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION) { @@ -711,7 +717,8 @@ static bool Wayland_ShowCursor(SDL_Cursor *cursor) // If more than one frame is available, create a frame callback to run the animation. if (data->cursor_data.system.num_frames > 1) { - data->cursor_data.system.last_frame_time_ms = SDL_GetTicks(); + data->cursor_data.system.last_frame_callback_time_ms = SDL_GetTicks(); + data->cursor_data.system.current_frame_time_ms = 0; data->cursor_data.system.current_frame = 0; data->cursor_data.system.frame_callback = wl_surface_frame(data->surface); wl_callback_add_listener(data->cursor_data.system.frame_callback, &cursor_frame_listener, data); diff --git a/external/SDL/test/testaudio.c b/external/SDL/test/testaudio.c index 60089ad5..e4ccf18c 100644 --- a/external/SDL/test/testaudio.c +++ b/external/SDL/test/testaudio.c @@ -1119,6 +1119,7 @@ SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) Thing *thing = NULL; saw_event = true; + SDL_ConvertEventToRenderCoordinates(SDL_GetRenderer(SDL_GetWindowFromEvent(event)), event); switch (event->type) { case SDL_EVENT_MOUSE_MOTION: diff --git a/external/SDL/test/testaudiostreamdynamicresample.c b/external/SDL/test/testaudiostreamdynamicresample.c index 1e13fe1c..e0dbb909 100644 --- a/external/SDL/test/testaudiostreamdynamicresample.c +++ b/external/SDL/test/testaudiostreamdynamicresample.c @@ -184,6 +184,20 @@ static const char *AudioChansToStr(const int channels) return "?"; } +static void scale_mouse_coords(SDL_FPoint *p) +{ + SDL_Window *window = SDL_GetMouseFocus(); + if (window) { + int w, p_w; + float scale; + SDL_GetWindowSize(window, &w, NULL); + SDL_GetWindowSizeInPixels(window, &p_w, NULL); + scale = (float)p_w / (float)w; + p->x *= scale; + p->y *= scale; + } +} + static void loop(void) { int i, j; @@ -228,6 +242,7 @@ static void loop(void) } if (SDL_GetMouseState(&p.x, &p.y) & SDL_BUTTON_LMASK) { + scale_mouse_coords(&p); if (active_slider == -1) { for (i = 0; i < NUM_SLIDERS; ++i) { if (SDL_PointInRectFloat(&p, &sliders[i].area)) { diff --git a/external/SDL/test/testautomation_stdlib.c b/external/SDL/test/testautomation_stdlib.c index 2e0e509c..b3ed82ab 100644 --- a/external/SDL/test/testautomation_stdlib.c +++ b/external/SDL/test/testautomation_stdlib.c @@ -714,6 +714,9 @@ static int SDLCALL stdlib_getsetenv(void *arg) #endif #endif +#define FMT_PRILLd "%" SDL_PRILLd +#define FMT_PRILLu "%" SDL_PRILLu + /** * Call to SDL_sscanf */ @@ -781,7 +784,7 @@ static int SDLCALL stdlib_sscanf(void *arg) SIZED_TEST_CASE(short, short, "%hd") SIZED_TEST_CASE(long, long, "%ld") - SIZED_TEST_CASE(long long, long_long, "%lld") + SIZED_TEST_CASE(long long, long_long, FMT_PRILLd) size_output = 123; expected_size_output = ~((size_t)0); @@ -1301,26 +1304,26 @@ static int SDLCALL stdlib_strtox(void *arg) } while (0) // infer decimal - STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "\t 123abcxyz", 0, 123, 6); // skip leading space - STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "+123abcxyz", 0, 123, 4); - STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "+123abcxyz", 0, 123, 4); - STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "-123abcxyz", 0, -123, 4); - STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "9999999999999999999999999999999999999999abcxyz", 0, ullong_max, 40); + STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, FMT_PRILLu, "\t 123abcxyz", 0, 123, 6); // skip leading space + STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, FMT_PRILLu, "+123abcxyz", 0, 123, 4); + STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, FMT_PRILLu, "+123abcxyz", 0, 123, 4); + STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, FMT_PRILLu, "-123abcxyz", 0, -123, 4); + STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, FMT_PRILLu, "9999999999999999999999999999999999999999abcxyz", 0, ullong_max, 40); // infer hexadecimal - STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "0x123abcxyz", 0, 0x123abc, 8); - STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "0X123ABCXYZ", 0, 0x123abc, 8); // uppercase X + STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, FMT_PRILLu, "0x123abcxyz", 0, 0x123abc, 8); + STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, FMT_PRILLu, "0X123ABCXYZ", 0, 0x123abc, 8); // uppercase X // infer octal - STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "0123abcxyz", 0, 0123, 4); + STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, FMT_PRILLu, "0123abcxyz", 0, 0123, 4); // arbitrary bases - STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "00110011", 2, 51, 8); - STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "-uvwxyz", 32, -991, 3); - STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "ZzZzZzZzZzZzZzZzZzZzZzZzZ", 36, ullong_max, 25); + STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, FMT_PRILLu, "00110011", 2, 51, 8); + STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, FMT_PRILLu, "-uvwxyz", 32, -991, 3); + STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, FMT_PRILLu, "ZzZzZzZzZzZzZzZzZzZzZzZzZ", 36, ullong_max, 25); - STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "-0", 10, 0, 2); - STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", " - 1", 0, 0, 0); // invalid input + STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, FMT_PRILLu, "-0", 10, 0, 2); + STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, FMT_PRILLu, " - 1", 0, 0, 0); // invalid input // We know that SDL_strtol, SDL_strtoul and SDL_strtoll share the same code path as SDL_strtoull under the hood, // so the most interesting test cases are those close to the bounds of the integer type. @@ -1342,15 +1345,15 @@ static int SDLCALL stdlib_strtox(void *arg) } if (sizeof(long long) == 8) { - STRTOX_TEST_CASE(SDL_strtoll, long long, "%lld", "9223372036854775807", 10, 9223372036854775807LL, 19); - STRTOX_TEST_CASE(SDL_strtoll, long long, "%lld", "9223372036854775808", 10, 9223372036854775807LL, 19); - STRTOX_TEST_CASE(SDL_strtoll, long long, "%lld", "-9223372036854775808", 10, -9223372036854775807LL - 1, 20); - STRTOX_TEST_CASE(SDL_strtoll, long long, "%lld", "-9223372036854775809", 10, -9223372036854775807LL - 1, 20); - STRTOX_TEST_CASE(SDL_strtoll, long long, "%lld", "-9999999999999999999999999999999999999999", 10, -9223372036854775807LL - 1, 41); + STRTOX_TEST_CASE(SDL_strtoll, long long, FMT_PRILLd, "9223372036854775807", 10, 9223372036854775807LL, 19); + STRTOX_TEST_CASE(SDL_strtoll, long long, FMT_PRILLd, "9223372036854775808", 10, 9223372036854775807LL, 19); + STRTOX_TEST_CASE(SDL_strtoll, long long, FMT_PRILLd, "-9223372036854775808", 10, -9223372036854775807LL - 1, 20); + STRTOX_TEST_CASE(SDL_strtoll, long long, FMT_PRILLd, "-9223372036854775809", 10, -9223372036854775807LL - 1, 20); + STRTOX_TEST_CASE(SDL_strtoll, long long, FMT_PRILLd, "-9999999999999999999999999999999999999999", 10, -9223372036854775807LL - 1, 41); - STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "18446744073709551615", 10, 18446744073709551615ULL, 20); - STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "18446744073709551616", 10, 18446744073709551615ULL, 20); - STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "-18446744073709551615", 10, 1, 21); + STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, FMT_PRILLd, "18446744073709551615", 10, 18446744073709551615ULL, 20); + STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, FMT_PRILLd, "18446744073709551616", 10, 18446744073709551615ULL, 20); + STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, FMT_PRILLd, "-18446744073709551615", 10, 1, 21); } #undef STRTOX_TEST_CASE diff --git a/external/SDL/test/testcamera.c b/external/SDL/test/testcamera.c index 0df3d91e..d6045a0a 100644 --- a/external/SDL/test/testcamera.c +++ b/external/SDL/test/testcamera.c @@ -97,8 +97,6 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) return SDL_APP_FAILURE; } - SDL_SetLogPriorities(SDL_LOG_PRIORITY_VERBOSE); - renderer = state->renderers[0]; if (!renderer) { /* SDL_Log("Couldn't create renderer: %s", SDL_GetError()); */ diff --git a/external/SDL/test/testhittesting.c b/external/SDL/test/testhittesting.c index fcd92a7e..05d8362e 100644 --- a/external/SDL/test/testhittesting.c +++ b/external/SDL/test/testhittesting.c @@ -33,17 +33,25 @@ static SDL_HitTestResult SDLCALL hitTest(SDL_Window *window, const SDL_Point *pt, void *data) { int i; - int w, h; + int w, h, p_w; + SDL_Point adj_pt; + float scale; + + SDL_GetWindowSize(window, &w, &h); + SDL_GetWindowSizeInPixels(window, &p_w, NULL); + + scale = (float)p_w / (float)w; + + adj_pt.x = (int)SDL_floorf(pt->x * scale); + adj_pt.y = (int)SDL_floorf(pt->y * scale); for (i = 0; i < numareas; i++) { - if (SDL_PointInRect(pt, &areas[i])) { + if (SDL_PointInRect(&adj_pt, &areas[i])) { SDL_Log("HIT-TEST: DRAGGABLE\n"); return SDL_HITTEST_DRAGGABLE; } } - SDL_GetWindowSize(window, &w, &h); - #define REPORT_RESIZE_HIT(name) \ { \ SDL_Log("HIT-TEST: RESIZE_" #name "\n"); \ diff --git a/external/SDL/test/testintersections.c b/external/SDL/test/testintersections.c index 7838047b..5e04c6fb 100644 --- a/external/SDL/test/testintersections.c +++ b/external/SDL/test/testintersections.c @@ -211,6 +211,7 @@ static void loop(void *arg) /* Check for events */ while (SDL_PollEvent(&event)) { SDLTest_CommonEvent(state, &event, done); + SDL_ConvertEventToRenderCoordinates(SDL_GetRenderer(SDL_GetWindowFromEvent(&event)), &event); switch (event.type) { case SDL_EVENT_MOUSE_BUTTON_DOWN: mouse_begin_x = event.button.x; diff --git a/external/SDL/test/testmanymouse.c b/external/SDL/test/testmanymouse.c index 4f64536b..017fbb28 100644 --- a/external/SDL/test/testmanymouse.c +++ b/external/SDL/test/testmanymouse.c @@ -184,7 +184,7 @@ static void HandleMouseAdded(SDL_MouseID instance_id) SDL_Window *window = state->windows[0]; int i, w = 0, h = 0; - SDL_GetWindowSize(window, &w, &h); + SDL_GetWindowSizeInPixels(window, &w, &h); for (i = 0; i < SDL_arraysize(mice); ++i) { MouseState *mouse_state = &mice[i]; @@ -237,7 +237,7 @@ static void HandleMouseMotion(SDL_MouseMotionEvent *event) ActivateMouse(event->which); - SDL_GetWindowSize(window, &w, &h); + SDL_GetWindowSizeInPixels(window, &w, &h); for (i = 0; i < SDL_arraysize(mice); ++i) { MouseState *mouse_state = &mice[i]; diff --git a/external/SDL/test/testoverlay.c b/external/SDL/test/testoverlay.c index 0b3971f8..f4bf7f75 100644 --- a/external/SDL/test/testoverlay.c +++ b/external/SDL/test/testoverlay.c @@ -255,6 +255,7 @@ static void loop(void) /* Check for events */ while (SDL_PollEvent(&event)) { SDLTest_CommonEvent(state, &event, &done); + SDL_ConvertEventToRenderCoordinates(SDL_GetRenderer(SDL_GetWindowFromEvent(&event)), &event); switch (event.type) { case SDL_EVENT_WINDOW_RESIZED: diff --git a/external/SDL/test/testwm.c b/external/SDL/test/testwm.c index 068dbe42..c92cd98b 100644 --- a/external/SDL/test/testwm.c +++ b/external/SDL/test/testwm.c @@ -165,6 +165,7 @@ static void loop(void) while (SDL_PollEvent(&event)) { SDLTest_CommonEvent(state, &event, &done); + SDL_ConvertEventToRenderCoordinates(SDL_GetRenderer(SDL_GetWindowFromEvent(&event)), &event); if (event.type == SDL_EVENT_WINDOW_RESIZED) { SDL_Window *window = SDL_GetWindowFromEvent(&event);