From 30709de45068a2454c910e6626641c09afc609ff Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Sun, 2 Mar 2025 14:42:35 -0400 Subject: [PATCH] update SDL3 to 3.2.6. --- libs/SDL3/.git-hash | 1 - libs/SDL3/.github/PULL_REQUEST_TEMPLATE.md | 7 + .../actions/setup-gdk-desktop/action.yml | 82 + .../setup-loongarch64-toolchain/action.yml | 53 + .../actions/setup-msvc-libusb/action.yml | 71 + .../.github/actions/setup-ninja/action.yml | 62 + .../actions/setup-vita-gles/action.yml | 93 + libs/SDL3/.github/cmake/CMakeLists.txt | 16 + libs/SDL3/.github/workflows/build.yml | 48 + .../.github/workflows/create-test-plan.py | 863 ++ libs/SDL3/.github/workflows/generic.yml | 431 + libs/SDL3/.github/workflows/release.yml | 652 ++ libs/SDL3/.gitignore | 178 + libs/SDL3/.wikiheaders-options | 2 +- libs/SDL3/CMakeLists.txt | 33 +- libs/SDL3/REVISION.txt | 1 - libs/SDL3/VisualC-GDK/SDL/SDL.vcxproj | 13 + libs/SDL3/VisualC-GDK/SDL/SDL.vcxproj.filters | 6 + .../VisualC-GDK/SDL_test/SDL_test.vcxproj | 7 + .../testcontroller/testcontroller.vcxproj | 7 + .../VisualC-GDK/tests/testgdk/src/testgdk.cpp | 12 +- .../VisualC-GDK/tests/testgdk/testgdk.vcxproj | 7 + .../tests/testsprite/testsprite.vcxproj | 7 + libs/SDL3/VisualC/SDL/Directory.Build.props | 8 + libs/SDL3/VisualC/SDL/SDL.vcxproj | 11 + libs/SDL3/VisualC/SDL/SDL.vcxproj.filters | 21 + .../VisualC/SDL_test/Directory.Build.props | 8 + libs/SDL3/VisualC/SDL_test/SDL_test.vcxproj | 5 + .../VisualC/examples/Directory.Build.props | 1 + .../VisualC/tests/checkkeys/checkkeys.vcxproj | 5 + .../VisualC/tests/loopwave/loopwave.vcxproj | 5 + .../tests/testatomic/testatomic.vcxproj | 5 + .../testautomation/testautomation.vcxproj | 5 + .../testcontroller/testcontroller.vcxproj | 5 + .../tests/testdialog/testdialog.vcxproj | 5 + .../VisualC/tests/testdraw/testdraw.vcxproj | 5 + .../VisualC/tests/testfile/testfile.vcxproj | 5 + libs/SDL3/VisualC/tests/testgl/testgl.vcxproj | 5 + .../VisualC/tests/testgles2/testgles2.vcxproj | 5 + .../tests/testoverlay/testoverlay.vcxproj | 5 + .../VisualC/tests/testpen/testpen.vcxproj | 5 + .../tests/testplatform/testplatform.vcxproj | 5 + .../VisualC/tests/testpower/testpower.vcxproj | 5 + .../testrendertarget/testrendertarget.vcxproj | 5 + .../tests/testrumble/testrumble.vcxproj | 5 + .../VisualC/tests/testscale/testscale.vcxproj | 5 + .../tests/testsensor/testsensor.vcxproj | 5 + .../VisualC/tests/testshape/testshape.vcxproj | 5 + .../tests/testsprite/testsprite.vcxproj | 5 + .../tests/testsurround/testsurround.vcxproj | 5 + .../tests/testvulkan/testvulkan.vcxproj | 5 + libs/SDL3/VisualC/tests/testwm/testwm.vcxproj | 5 + .../VisualC/tests/testyuv/testyuv.vcxproj | 5 + libs/SDL3/Xcode/SDL/Info-Framework.plist | 4 +- .../Xcode/SDL/SDL.xcodeproj/project.pbxproj | 82 +- libs/SDL3/Xcode/SDL/pkg-support/SDL.info | 2 +- .../resources/cmake/SDL3Config.cmake | 2 +- .../share/cmake/SDL3/SDL3Config.cmake | 2 +- .../SDLTest/SDLTest.xcodeproj/project.pbxproj | 85 +- .../main/java/org/libsdl/app/SDLActivity.java | 2 +- .../org/libsdl/app/SDLControllerManager.java | 9 +- .../main/java/org/libsdl/app/SDLSurface.java | 2 +- libs/SDL3/build-scripts/SDL_migration.cocci | 99 +- libs/SDL3/build-scripts/check_stdlib_usage.py | 1 + .../pkg-support/android/INSTALL.md.in | 4 +- .../mingw/{INSTALL.md => INSTALL.md.in} | 10 +- .../msvc/{INSTALL.md => INSTALL.md.in} | 8 +- libs/SDL3/build-scripts/release-info.json | 8 +- libs/SDL3/cmake/SDL3Config.cmake.in | 5 +- libs/SDL3/cmake/test/main_cli.c | 2 +- libs/SDL3/cmake/test/main_gui.c | 4 +- libs/SDL3/cmake/test/main_lib.c | 2 +- libs/SDL3/docs/INTRO-emscripten.md | 48 +- libs/SDL3/docs/INTRO-visualstudio.md | 3 +- libs/SDL3/docs/README-linux.md | 8 +- libs/SDL3/docs/README-migration.md | 20 +- libs/SDL3/docs/hello.c | 2 +- .../audio/01-simple-playback/README.txt | 2 +- .../01-simple-playback/simple-playback.c | 4 +- .../02-simple-playback-callback/README.txt | 2 +- .../simple-playback-callback.c | 2 +- .../examples/audio/03-load-wav/README.txt | 2 +- .../examples/audio/03-load-wav/load-wav.c | 4 +- .../04-multiple-streams/multiple-streams.c | 2 +- libs/SDL3/examples/demo/01-snake/snake.c | 4 +- .../examples/demo/04-bytepusher/bytepusher.c | 4 +- .../01-joystick-polling/joystick-polling.c | 6 +- .../pen/01-drawing-lines/drawing-lines.c | 10 + .../09-scaling-textures/scaling-textures.c | 4 +- .../examples/renderer/10-geometry/geometry.c | 2 +- libs/SDL3/include/SDL3/SDL.h | 2 +- libs/SDL3/include/SDL3/SDL_assert.h | 2 + libs/SDL3/include/SDL3/SDL_atomic.h | 2 +- libs/SDL3/include/SDL3/SDL_audio.h | 15 +- libs/SDL3/include/SDL3/SDL_camera.h | 4 +- libs/SDL3/include/SDL3/SDL_dialog.h | 4 +- libs/SDL3/include/SDL3/SDL_events.h | 4 +- libs/SDL3/include/SDL3/SDL_gamepad.h | 2 +- libs/SDL3/include/SDL3/SDL_gpu.h | 149 +- libs/SDL3/include/SDL3/SDL_guid.h | 4 + libs/SDL3/include/SDL3/SDL_hints.h | 28 +- libs/SDL3/include/SDL3/SDL_log.h | 13 +- libs/SDL3/include/SDL3/SDL_main.h | 9 +- libs/SDL3/include/SDL3/SDL_mouse.h | 6 +- libs/SDL3/include/SDL3/SDL_pixels.h | 3 + libs/SDL3/include/SDL3/SDL_platform_defines.h | 2 - libs/SDL3/include/SDL3/SDL_process.h | 12 +- libs/SDL3/include/SDL3/SDL_rect.h | 2 +- libs/SDL3/include/SDL3/SDL_render.h | 87 +- libs/SDL3/include/SDL3/SDL_revision.h | 36 +- libs/SDL3/include/SDL3/SDL_stdinc.h | 35 +- libs/SDL3/include/SDL3/SDL_storage.h | 7 +- libs/SDL3/include/SDL3/SDL_surface.h | 34 +- libs/SDL3/include/SDL3/SDL_test_common.h | 2 +- libs/SDL3/include/SDL3/SDL_thread.h | 2 +- libs/SDL3/include/SDL3/SDL_tray.h | 26 +- libs/SDL3/include/SDL3/SDL_version.h | 2 +- libs/SDL3/include/SDL3/SDL_vulkan.h | 2 +- .../include/build_config/SDL_revision.h.cmake | 46 +- libs/SDL3/src/SDL_hashtable.c | 416 +- libs/SDL3/src/SDL_hashtable.h | 627 +- libs/SDL3/src/SDL_internal.h | 16 + libs/SDL3/src/SDL_properties.c | 259 +- libs/SDL3/src/SDL_utils.c | 277 +- libs/SDL3/src/SDL_utils_c.h | 2 + libs/SDL3/src/audio/SDL_audio.c | 187 +- libs/SDL3/src/audio/SDL_audiocvt.c | 20 +- libs/SDL3/src/audio/SDL_audioqueue.c | 2 +- libs/SDL3/src/audio/SDL_audioresample.c | 17 +- libs/SDL3/src/audio/SDL_sysaudio.h | 3 +- libs/SDL3/src/audio/aaudio/SDL_aaudio.c | 14 +- libs/SDL3/src/audio/alsa/SDL_alsa_audio.c | 20 +- libs/SDL3/src/audio/coreaudio/SDL_coreaudio.m | 8 +- .../src/audio/directsound/SDL_directsound.c | 2 +- libs/SDL3/src/audio/disk/SDL_diskaudio.c | 4 +- libs/SDL3/src/audio/dsp/SDL_dspaudio.c | 2 +- libs/SDL3/src/audio/dummy/SDL_dummyaudio.c | 2 +- .../audio/emscripten/SDL_emscriptenaudio.c | 10 +- libs/SDL3/src/audio/haiku/SDL_haikuaudio.cc | 2 +- libs/SDL3/src/audio/jack/SDL_jackaudio.c | 2 +- libs/SDL3/src/audio/n3ds/SDL_n3dsaudio.c | 3 +- libs/SDL3/src/audio/netbsd/SDL_netbsdaudio.c | 2 +- libs/SDL3/src/audio/openslES/SDL_openslES.c | 2 +- libs/SDL3/src/audio/pipewire/SDL_pipewire.c | 47 +- libs/SDL3/src/audio/ps2/SDL_ps2audio.c | 2 +- libs/SDL3/src/audio/psp/SDL_pspaudio.c | 2 +- .../src/audio/pulseaudio/SDL_pulseaudio.c | 19 +- libs/SDL3/src/audio/qnx/SDL_qsa_audio.c | 2 +- libs/SDL3/src/audio/sndio/SDL_sndioaudio.c | 2 +- libs/SDL3/src/audio/vita/SDL_vitaaudio.c | 2 +- libs/SDL3/src/audio/wasapi/SDL_wasapi.c | 2 +- libs/SDL3/src/camera/SDL_camera.c | 321 +- libs/SDL3/src/camera/SDL_syscamera.h | 6 +- .../camera/emscripten/SDL_camera_emscripten.c | 77 +- .../SDL_camera_mediafoundation.c | 109 +- .../src/camera/pipewire/SDL_camera_pipewire.c | 86 +- libs/SDL3/src/camera/v4l2/SDL_camera_v4l2.c | 32 +- libs/SDL3/src/core/SDL_core_unsupported.c | 12 +- libs/SDL3/src/core/haiku/SDL_BApp.h | 25 +- libs/SDL3/src/core/linux/SDL_dbus.c | 8 +- libs/SDL3/src/core/unix/SDL_poll.c | 4 +- libs/SDL3/src/core/windows/SDL_gameinput.c | 98 + libs/SDL3/src/core/windows/SDL_gameinput.h | 36 + libs/SDL3/src/core/windows/SDL_hid.c | 2 + libs/SDL3/src/core/windows/SDL_hid.h | 2 + libs/SDL3/src/core/windows/version.rc | 8 +- libs/SDL3/src/dialog/unix/SDL_portaldialog.c | 2 +- libs/SDL3/src/dynapi/SDL_dynapi.c | 49 +- libs/SDL3/src/dynapi/SDL_dynapi.sym | 1 + libs/SDL3/src/dynapi/SDL_dynapi_overrides.h | 1 + libs/SDL3/src/dynapi/SDL_dynapi_procs.h | 1 + libs/SDL3/src/events/SDL_clipboardevents.c | 13 +- libs/SDL3/src/events/SDL_events.c | 204 +- libs/SDL3/src/events/SDL_eventwatch.c | 143 + libs/SDL3/src/events/SDL_eventwatch_c.h | 45 + libs/SDL3/src/events/SDL_keyboard.c | 4 +- libs/SDL3/src/events/SDL_keymap.c | 76 +- libs/SDL3/src/events/SDL_mouse.c | 60 +- libs/SDL3/src/events/SDL_pen.c | 13 +- libs/SDL3/src/events/SDL_windowevents.c | 47 +- libs/SDL3/src/events/SDL_windowevents_c.h | 11 + libs/SDL3/src/events/scancodes_linux.h | 14 +- libs/SDL3/src/filesystem/SDL_filesystem.c | 12 +- .../src/filesystem/cocoa/SDL_sysfilesystem.m | 2 +- libs/SDL3/src/gpu/SDL_gpu.c | 32 +- libs/SDL3/src/gpu/SDL_sysgpu.h | 14 +- libs/SDL3/src/gpu/d3d12/SDL_gpu_d3d12.c | 227 +- libs/SDL3/src/gpu/metal/SDL_gpu_metal.m | 490 +- libs/SDL3/src/gpu/vulkan/SDL_gpu_vulkan.c | 638 +- libs/SDL3/src/haptic/SDL_haptic.c | 94 + libs/SDL3/src/hidapi/android/hid.cpp | 2 +- libs/SDL3/src/io/SDL_asyncio.c | 14 +- libs/SDL3/src/io/SDL_iostream.c | 7 +- libs/SDL3/src/joystick/SDL_gamepad.c | 80 +- libs/SDL3/src/joystick/SDL_gamepad_db.h | 10 +- libs/SDL3/src/joystick/SDL_joystick.c | 206 +- .../src/joystick/android/SDL_sysjoystick.c | 2 +- .../SDL3/src/joystick/apple/SDL_mfijoystick.m | 4 +- libs/SDL3/src/joystick/controller_list.h | 5 +- .../src/joystick/gdk/SDL_gameinputjoystick.c | 74 +- .../src/joystick/hidapi/SDL_hidapi_combined.c | 2 + .../SDL3/src/joystick/hidapi/SDL_hidapi_ps3.c | 6 +- .../SDL3/src/joystick/hidapi/SDL_hidapi_ps4.c | 16 +- .../SDL3/src/joystick/hidapi/SDL_hidapi_ps5.c | 12 +- .../joystick/hidapi/SDL_hidapi_steam_hori.c | 2 +- .../src/joystick/hidapi/SDL_hidapi_switch.c | 62 +- .../SDL3/src/joystick/hidapi/SDL_hidapi_wii.c | 8 +- .../src/joystick/hidapi/SDL_hidapi_xbox360w.c | 6 +- .../src/joystick/hidapi/SDL_hidapi_xboxone.c | 36 +- .../src/joystick/hidapi/SDL_hidapijoystick.c | 56 +- .../joystick/hidapi/SDL_hidapijoystick_c.h | 4 + .../SDL3/src/joystick/linux/SDL_sysjoystick.c | 59 +- libs/SDL3/src/joystick/usb_ids.h | 3 +- .../joystick/windows/SDL_rawinputjoystick.c | 18 +- libs/SDL3/src/render/SDL_render.c | 542 +- libs/SDL3/src/render/SDL_sysrender.h | 16 +- libs/SDL3/src/render/SDL_yuv_sw.c | 2 +- .../src/render/direct3d11/SDL_render_d3d11.c | 36 +- .../direct3d12/D3D12_PixelShader_Advanced.h | 34 +- .../direct3d12/D3D12_PixelShader_Colors.h | 18 +- .../direct3d12/D3D12_PixelShader_Textures.h | 26 +- .../direct3d12/D3D12_RootSig_Advanced.h | 6 +- .../render/direct3d12/D3D12_RootSig_Color.h | 6 +- .../render/direct3d12/D3D12_RootSig_Texture.h | 6 +- .../direct3d12/D3D12_VertexShader_Advanced.h | 6 +- .../direct3d12/D3D12_VertexShader_Color.h | 6 +- .../direct3d12/D3D12_VertexShader_Texture.h | 6 +- .../src/render/direct3d12/SDL_render_d3d12.c | 34 +- libs/SDL3/src/render/gpu/SDL_pipeline_gpu.c | 101 +- libs/SDL3/src/render/gpu/SDL_render_gpu.c | 4 +- libs/SDL3/src/render/metal/SDL_render_metal.m | 4 +- libs/SDL3/src/render/opengl/SDL_render_gl.c | 2 +- libs/SDL3/src/render/opengl/SDL_shaders_gl.c | 5 +- .../src/render/opengles2/SDL_render_gles2.c | 6 +- .../src/render/vitagxm/SDL_render_vita_gxm.c | 4 +- .../vitagxm/SDL_render_vita_gxm_tools.c | 62 +- .../src/render/vulkan/SDL_render_vulkan.c | 24 +- .../src/sensor/windows/SDL_windowssensor.c | 8 +- libs/SDL3/src/stdlib/SDL_getenv.c | 130 +- libs/SDL3/src/stdlib/SDL_malloc.c | 8 +- libs/SDL3/src/stdlib/SDL_qsort.c | 8 +- libs/SDL3/src/stdlib/SDL_string.c | 31 + libs/SDL3/src/test/SDL_test_common.c | 138 +- libs/SDL3/src/test/SDL_test_fuzzer.c | 2 +- libs/SDL3/src/test/SDL_test_harness.c | 3 + libs/SDL3/src/test/SDL_test_memory.c | 6 +- libs/SDL3/src/thread/SDL_thread.c | 8 +- libs/SDL3/src/thread/n3ds/SDL_syscond.c | 111 - libs/SDL3/src/thread/windows/SDL_systhread.c | 2 +- libs/SDL3/src/timer/windows/SDL_systimer.c | 39 +- libs/SDL3/src/tray/cocoa/SDL_tray.m | 6 +- libs/SDL3/src/tray/dummy/SDL_tray.c | 2 +- libs/SDL3/src/tray/unix/SDL_tray.c | 48 +- libs/SDL3/src/tray/windows/SDL_tray.c | 11 +- libs/SDL3/src/video/SDL_bmp.c | 126 +- libs/SDL3/src/video/SDL_egl.c | 2 +- libs/SDL3/src/video/SDL_pixels.c | 19 +- libs/SDL3/src/video/SDL_stb.c | 121 + libs/SDL3/src/video/SDL_stb_c.h | 31 + libs/SDL3/src/video/SDL_stretch.c | 18 +- libs/SDL3/src/video/SDL_surface.c | 31 +- libs/SDL3/src/video/SDL_surface_c.h | 1 - libs/SDL3/src/video/SDL_sysvideo.h | 4 + libs/SDL3/src/video/SDL_video.c | 49 +- libs/SDL3/src/video/SDL_video_c.h | 3 + libs/SDL3/src/video/SDL_yuv.c | 2 +- .../SDL3/src/video/android/SDL_androidvideo.c | 3 +- libs/SDL3/src/video/cocoa/SDL_cocoakeyboard.m | 13 +- .../SDL3/src/video/cocoa/SDL_cocoametalview.m | 6 +- libs/SDL3/src/video/cocoa/SDL_cocoamouse.m | 20 +- libs/SDL3/src/video/cocoa/SDL_cocoapen.m | 2 +- libs/SDL3/src/video/cocoa/SDL_cocoavideo.m | 3 +- libs/SDL3/src/video/cocoa/SDL_cocoawindow.m | 69 +- libs/SDL3/src/video/dummy/SDL_nullvideo.c | 6 +- .../video/emscripten/SDL_emscriptenevents.c | 4 +- .../video/emscripten/SDL_emscriptenvideo.c | 3 +- libs/SDL3/src/video/haiku/SDL_bvideo.cc | 6 +- libs/SDL3/src/video/kmsdrm/SDL_kmsdrmdyn.c | 4 +- libs/SDL3/src/video/kmsdrm/SDL_kmsdrmvideo.c | 5 +- libs/SDL3/src/video/kmsdrm/SDL_kmsdrmvulkan.c | 2 +- libs/SDL3/src/video/n3ds/SDL_n3dsvideo.c | 2 +- .../src/video/offscreen/SDL_offscreenvideo.c | 3 +- libs/SDL3/src/video/openvr/SDL_openvrvideo.c | 14 +- libs/SDL3/src/video/ps2/SDL_ps2video.c | 3 +- libs/SDL3/src/video/psp/SDL_pspvideo.c | 3 +- libs/SDL3/src/video/qnx/SDL_qnxvideo.c | 3 +- libs/SDL3/src/video/raspberry/SDL_rpivideo.c | 3 +- libs/SDL3/src/video/riscos/SDL_riscosvideo.c | 3 +- libs/SDL3/src/video/stb_image.h | 8252 +++++++++++++++++ libs/SDL3/src/video/uikit/SDL_uikitpen.m | 29 +- libs/SDL3/src/video/uikit/SDL_uikitvideo.m | 3 +- libs/SDL3/src/video/vita/SDL_vitavideo.c | 3 +- .../SDL3/src/video/vivante/SDL_vivantevideo.c | 3 +- .../SDL3/src/video/wayland/SDL_waylandcolor.c | 303 + .../SDL3/src/video/wayland/SDL_waylandcolor.h | 35 + .../video/wayland/SDL_waylanddatamanager.c | 6 +- libs/SDL3/src/video/wayland/SDL_waylanddyn.c | 4 +- .../src/video/wayland/SDL_waylandevents.c | 50 +- .../SDL3/src/video/wayland/SDL_waylandmouse.c | 7 + .../SDL3/src/video/wayland/SDL_waylandvideo.c | 91 +- .../SDL3/src/video/wayland/SDL_waylandvideo.h | 5 + .../src/video/wayland/SDL_waylandwindow.c | 118 +- .../src/video/wayland/SDL_waylandwindow.h | 9 +- .../src/video/windows/SDL_windowsclipboard.c | 2 +- .../src/video/windows/SDL_windowsevents.c | 210 +- .../src/video/windows/SDL_windowsgameinput.c | 52 +- .../src/video/windows/SDL_windowskeyboard.c | 38 +- .../SDL3/src/video/windows/SDL_windowsmodes.c | 2 +- .../SDL3/src/video/windows/SDL_windowsmouse.c | 50 +- .../SDL3/src/video/windows/SDL_windowsshape.c | 3 +- .../SDL3/src/video/windows/SDL_windowsvideo.c | 18 +- .../src/video/windows/SDL_windowswindow.c | 103 +- libs/SDL3/src/video/x11/SDL_x11events.c | 208 +- libs/SDL3/src/video/x11/SDL_x11keyboard.c | 19 +- libs/SDL3/src/video/x11/SDL_x11pen.c | 25 +- libs/SDL3/src/video/x11/SDL_x11shape.c | 4 +- libs/SDL3/src/video/x11/SDL_x11video.c | 3 +- libs/SDL3/src/video/x11/SDL_x11window.c | 150 +- libs/SDL3/src/video/x11/SDL_x11window.h | 7 +- libs/SDL3/src/video/x11/SDL_x11xinput2.c | 13 +- libs/SDL3/src/video/x11/SDL_x11xsync.c | 12 +- libs/SDL3/test/CMakeLists.txt | 6 +- .../android/cmake/AndroidManifest.xml.cmake | 4 +- libs/SDL3/test/android/res/values/styles.xml | 7 + libs/SDL3/test/checkkeys.c | 22 +- libs/SDL3/test/childprocess.c | 2 +- libs/SDL3/test/emscripten/driver.py | 9 +- libs/SDL3/test/loopwave.c | 10 +- libs/SDL3/test/testatomic.c | 84 +- libs/SDL3/test/testaudio.c | 1 + libs/SDL3/test/testaudiohotplug.c | 20 +- libs/SDL3/test/testaudioinfo.c | 60 +- libs/SDL3/test/testaudiorecording.c | 34 +- .../test/testaudiostreamdynamicresample.c | 2 +- libs/SDL3/test/testautomation_audio.c | 15 + libs/SDL3/test/testautomation_events.c | 69 +- libs/SDL3/test/testautomation_intrinsics.c | 12 + libs/SDL3/test/testautomation_render.c | 4 +- libs/SDL3/test/testautomation_stdlib.c | 50 +- libs/SDL3/test/testcamera.c | 6 +- libs/SDL3/test/testclipboard.c | 35 +- libs/SDL3/test/testcolorspace.c | 22 +- libs/SDL3/test/testcontroller.c | 89 +- libs/SDL3/test/testdialog.c | 12 +- libs/SDL3/test/testdisplayinfo.c | 16 +- libs/SDL3/test/testdraw.c | 6 +- libs/SDL3/test/testdrawchessboard.c | 10 +- libs/SDL3/test/testerror.c | 12 +- libs/SDL3/test/testffmpeg.c | 36 +- libs/SDL3/test/testffmpeg_vulkan.c | 4 +- libs/SDL3/test/testfile.c | 12 +- libs/SDL3/test/testfilesystem.c | 22 +- libs/SDL3/test/testgeometry.c | 6 +- libs/SDL3/test/testgl.c | 64 +- libs/SDL3/test/testgles.c | 56 +- libs/SDL3/test/testgles2.c | 60 +- libs/SDL3/test/testgles2_sdf.c | 785 -- libs/SDL3/test/testgles2_sdf_img_normal.bmp | Bin 68122 -> 0 bytes libs/SDL3/test/testgles2_sdf_img_sdf.bmp | Bin 72202 -> 0 bytes libs/SDL3/test/testgpu_simple_clear.c | 10 +- libs/SDL3/test/testgpu_spinning_cube.c | 10 +- libs/SDL3/test/testhaptic.c | 103 +- libs/SDL3/test/testhittesting.c | 12 +- libs/SDL3/test/testhotplug.c | 42 +- libs/SDL3/test/testiconv.c | 6 +- libs/SDL3/test/testime.c | 50 +- libs/SDL3/test/testintersections.c | 6 +- libs/SDL3/test/testkeys.c | 4 +- libs/SDL3/test/testloadso.c | 18 +- libs/SDL3/test/testlock.c | 22 +- libs/SDL3/test/testmessage.c | 24 +- libs/SDL3/test/testmodal.c | 6 +- libs/SDL3/test/testmouse.c | 6 +- libs/SDL3/test/testmultiaudio.c | 10 +- libs/SDL3/test/testnative.c | 14 +- libs/SDL3/test/testoffscreen.c | 10 +- libs/SDL3/test/testoverlay.c | 28 +- libs/SDL3/test/testplatform.c | 74 +- libs/SDL3/test/testpower.c | 14 +- libs/SDL3/test/testqsort.c | 4 +- libs/SDL3/test/testrendercopyex.c | 6 +- libs/SDL3/test/testrendertarget.c | 14 +- libs/SDL3/test/testresample.c | 10 +- libs/SDL3/test/testrumble.c | 30 +- libs/SDL3/test/testrwlock.c | 16 +- libs/SDL3/test/testscale.c | 6 +- libs/SDL3/test/testsem.c | 36 +- libs/SDL3/test/testsensor.c | 18 +- libs/SDL3/test/testshader.c | 23 +- libs/SDL3/test/testshape.c | 14 +- libs/SDL3/test/testsprite.c | 8 +- libs/SDL3/test/testspriteminimal.c | 2 +- libs/SDL3/test/testspritesurface.c | 2 +- libs/SDL3/test/teststreaming.c | 14 +- libs/SDL3/test/testsurround.c | 16 +- libs/SDL3/test/testthread.c | 22 +- libs/SDL3/test/testtimer.c | 44 +- libs/SDL3/test/testtray.c | 62 +- libs/SDL3/test/testurl.c | 2 +- libs/SDL3/test/testutils.c | 2 +- libs/SDL3/test/testver.c | 8 +- libs/SDL3/test/testviewport.c | 4 +- libs/SDL3/test/testvulkan.c | 108 +- libs/SDL3/test/testwm.c | 8 +- libs/SDL3/test/testyuv.c | 64 +- libs/SDL3/test/torturethread.c | 10 +- .../wayland-protocols/color-management-v1.xml | 1631 ++++ 407 files changed, 20390 insertions(+), 5388 deletions(-) delete mode 100644 libs/SDL3/.git-hash create mode 100644 libs/SDL3/.github/PULL_REQUEST_TEMPLATE.md create mode 100644 libs/SDL3/.github/actions/setup-gdk-desktop/action.yml create mode 100644 libs/SDL3/.github/actions/setup-loongarch64-toolchain/action.yml create mode 100644 libs/SDL3/.github/actions/setup-msvc-libusb/action.yml create mode 100644 libs/SDL3/.github/actions/setup-ninja/action.yml create mode 100644 libs/SDL3/.github/actions/setup-vita-gles/action.yml create mode 100644 libs/SDL3/.github/cmake/CMakeLists.txt create mode 100644 libs/SDL3/.github/workflows/build.yml create mode 100644 libs/SDL3/.github/workflows/create-test-plan.py create mode 100644 libs/SDL3/.github/workflows/generic.yml create mode 100644 libs/SDL3/.github/workflows/release.yml create mode 100644 libs/SDL3/.gitignore delete mode 100644 libs/SDL3/REVISION.txt create mode 100644 libs/SDL3/VisualC/SDL/Directory.Build.props create mode 100644 libs/SDL3/VisualC/SDL_test/Directory.Build.props rename libs/SDL3/build-scripts/pkg-support/mingw/{INSTALL.md => INSTALL.md.in} (74%) rename libs/SDL3/build-scripts/pkg-support/msvc/{INSTALL.md => INSTALL.md.in} (77%) create mode 100644 libs/SDL3/src/core/windows/SDL_gameinput.c create mode 100644 libs/SDL3/src/core/windows/SDL_gameinput.h create mode 100644 libs/SDL3/src/events/SDL_eventwatch.c create mode 100644 libs/SDL3/src/events/SDL_eventwatch_c.h delete mode 100644 libs/SDL3/src/thread/n3ds/SDL_syscond.c create mode 100644 libs/SDL3/src/video/SDL_stb.c create mode 100644 libs/SDL3/src/video/SDL_stb_c.h create mode 100644 libs/SDL3/src/video/stb_image.h create mode 100644 libs/SDL3/src/video/wayland/SDL_waylandcolor.c create mode 100644 libs/SDL3/src/video/wayland/SDL_waylandcolor.h create mode 100644 libs/SDL3/test/android/res/values/styles.xml delete mode 100644 libs/SDL3/test/testgles2_sdf.c delete mode 100644 libs/SDL3/test/testgles2_sdf_img_normal.bmp delete mode 100644 libs/SDL3/test/testgles2_sdf_img_sdf.bmp create mode 100644 libs/SDL3/wayland-protocols/color-management-v1.xml diff --git a/libs/SDL3/.git-hash b/libs/SDL3/.git-hash deleted file mode 100644 index ab09ea1e..00000000 --- a/libs/SDL3/.git-hash +++ /dev/null @@ -1 +0,0 @@ -535d80badefc83c5c527ec5748f2a20d6a9310fe diff --git a/libs/SDL3/.github/PULL_REQUEST_TEMPLATE.md b/libs/SDL3/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..533be857 --- /dev/null +++ b/libs/SDL3/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,7 @@ + + +## Description + + +## Existing Issue(s) + diff --git a/libs/SDL3/.github/actions/setup-gdk-desktop/action.yml b/libs/SDL3/.github/actions/setup-gdk-desktop/action.yml new file mode 100644 index 00000000..10427ace --- /dev/null +++ b/libs/SDL3/.github/actions/setup-gdk-desktop/action.yml @@ -0,0 +1,82 @@ +name: 'Setup GDK (Game Development Kit) for Windows Desktop' +description: 'Download GDK and install into MSBuild' +inputs: + # Keep edition and ref in sync! + edition: + description: 'GDK edition' + default: '240601' # YYMMUU (Year Month Update) + ref: + description: 'Git reference' + default: 'June_2024_Update_1' + folder: + description: 'Folder where to create Directory.Build.props' + required: true + default: '${{ github.workspace }}' +runs: + using: 'composite' + steps: + - uses: actions/setup-python@main + with: + python-version: 3.x + - name: 'Calculate variables' + id: calc + shell: pwsh + run: | + $vs_folder=@(vswhere -latest -property installationPath) + echo "vs-folder=${vs_folder}" >> $Env:GITHUB_OUTPUT + + echo "gdk-path=${{ runner.temp }}\GDK-${{ inputs.edition }}" >> $Env:GITHUB_OUTPUT + + echo "cache-key=gdk-${{ inputs.ref }}-${{ inputs.edition }}" >> $Env:GITHUB_OUTPUT + - name: 'Restore cached GDK' + id: cache-restore + uses: actions/cache/restore@v4 + with: + path: '${{ steps.calc.outputs.gdk-path }}' + key: ${{ steps.calc.outputs.cache-key }} + - name: 'Download GDK' + if: ${{ !steps.cache-restore.outputs.cache-hit }} + shell: pwsh + run: | + python build-scripts/setup-gdk-desktop.py ` + --download ` + --temp-folder "${{ runner.temp }}" ` + --gdk-path="${{ steps.calc.outputs.gdk-path }}" ` + --ref-edition "${{ inputs.ref }},${{ inputs.edition }}" ` + --vs-folder="${{ steps.calc.outputs.vs-folder }}" ` + --no-user-props + - name: 'Extract GDK' + if: ${{ !steps.cache-restore.outputs.cache-hit }} + shell: pwsh + run: | + python build-scripts/setup-gdk-desktop.py ` + --extract ` + --ref-edition "${{ inputs.ref }},${{ inputs.edition }}" ` + --temp-folder "${{ runner.temp }}" ` + --gdk-path="${{ steps.calc.outputs.gdk-path }}" ` + --vs-folder="${{ steps.calc.outputs.vs-folder }}" ` + --no-user-props + - name: 'Cache GDK' + if: ${{ !steps.cache-restore.outputs.cache-hit }} + uses: actions/cache/save@v4 + with: + path: '${{ steps.calc.outputs.gdk-path }}' + key: ${{ steps.calc.outputs.cache-key }} + - name: 'Copy MSBuild files into GDK' + shell: pwsh + run: | + python build-scripts/setup-gdk-desktop.py ` + --ref-edition "${{ inputs.ref }},${{ inputs.edition }}" ` + --gdk-path="${{ steps.calc.outputs.gdk-path }}" ` + --vs-folder="${{ steps.calc.outputs.vs-folder }}" ` + --copy-msbuild ` + --no-user-props + - name: 'Write user props' + shell: pwsh + run: | + python build-scripts/setup-gdk-desktop.py ` + --ref-edition "${{ inputs.ref }},${{ inputs.edition }}" ` + --temp-folder "${{ runner.temp }}" ` + --vs-folder="${{ steps.calc.outputs.vs-folder }}" ` + --gdk-path="${{ steps.calc.outputs.gdk-path }}" ` + "--props-folder=${{ inputs.folder }}" diff --git a/libs/SDL3/.github/actions/setup-loongarch64-toolchain/action.yml b/libs/SDL3/.github/actions/setup-loongarch64-toolchain/action.yml new file mode 100644 index 00000000..e7f9ddc7 --- /dev/null +++ b/libs/SDL3/.github/actions/setup-loongarch64-toolchain/action.yml @@ -0,0 +1,53 @@ +name: 'Setup LoongArch64 toolchain' +description: 'Download Linux LoongArch64 toolchain and set output variables' +inputs: + version: + description: 'LoongArch64 version' + default: '2023.08.08' +outputs: + prefix: + description: "LoongArch toolchain prefix" + value: ${{ steps.final.outputs.prefix }} + cc: + description: "LoongArch C compiler" + value: ${{ steps.final.outputs.cc }} + cxx: + description: "LoongArch C++ compiler" + value: ${{ steps.final.outputs.cxx }} +runs: + using: 'composite' + steps: + - uses: actions/cache/restore@v4 + id: restore-cache + with: + path: /opt/cross-tools + key: loongarch64-${{ inputs.version }} + + - name: 'Download LoongArch64 gcc+glibc toolchain' + if: ${{ !steps.restore-cache.outputs.cache-hit }} + shell: bash + run: | + url="https://github.com/loongson/build-tools/releases/download/${{ inputs.version }}/CLFS-loongarch64-8.1-x86_64-cross-tools-gcc-glibc.tar.xz" + + wget "$url" -O /tmp/toolchain.tar.xz + + mkdir -p /opt + tar -C /opt -x -f /tmp/toolchain.tar.xz + + - uses: actions/cache/save@v4 + if: ${{ !steps.restore-cache.outputs.cache-hit }} + with: + path: /opt/cross-tools + key: loongarch64-${{ inputs.version }} + - name: 'Set output vars' + id: final + shell: bash + run: | + prefix=/opt/cross-tools + echo "prefix=${prefix}" >> $GITHUB_OUTPUT + cc="${prefix}/bin/loongarch64-unknown-linux-gnu-gcc" + cxx="${prefix}/bin/loongarch64-unknown-linux-gnu-g++" + echo "cc=${cc}" >> $GITHUB_OUTPUT + echo "cxx=${cxx}" >> $GITHUB_OUTPUT + echo "LOONGARCH64_CC=${cc}" >>$GITHUB_ENV + echo "LOONGARCH64_CXX=${cxx}" >>$GITHUB_ENV diff --git a/libs/SDL3/.github/actions/setup-msvc-libusb/action.yml b/libs/SDL3/.github/actions/setup-msvc-libusb/action.yml new file mode 100644 index 00000000..b8732f9c --- /dev/null +++ b/libs/SDL3/.github/actions/setup-msvc-libusb/action.yml @@ -0,0 +1,71 @@ +name: 'Setup libusb for MSVC' +description: 'Download libusb sdk for MSVC, and set output/environment variables' +inputs: + version: + description: 'libusb version' + required: true + default: '1.0.27' + arch: + description: "libusb architecture (x86 or x64)" + rqeuired: true +outputs: + root: + description: "libusb root directory" + value: ${{ steps.final.outputs.root }} +runs: + using: 'composite' + steps: + - name: 'Restore cached libusb-${{ inputs.version }}.7z' + id: cache-restore + uses: actions/cache/restore@v4 + with: + path: 'C:\temp\libusb-${{ inputs.version }}.7z' + key: libusb-msvc-${{ inputs.version }} + - name: 'Download libusb ${{ inputs.version }}' + if: ${{ !steps.cache-restore.outputs.cache-hit }} + shell: pwsh + run: | + Invoke-WebRequest "https://github.com/libusb/libusb/releases/download/v${{ inputs.version }}/libusb-${{ inputs.version }}.7z" -OutFile "C:\temp\libusb-${{ inputs.version }}.7z" + - name: 'Cache libusb-${{ inputs.version }}.7z' + if: ${{ !steps.cache-restore.outputs.cache-hit }} + uses: actions/cache/save@v4 + with: + path: 'C:\temp\libusb-${{ inputs.version }}.7z' + key: libusb-msvc-${{ inputs.version }} + - name: 'Extract libusb' + shell: pwsh + run: | + 7z "-oC:\temp\libusb-${{ inputs.version }}" x "C:\temp\libusb-${{ inputs.version }}.7z" + - name: 'Set output vars' + id: final + shell: pwsh + run: | + if ('${{ inputs.arch }}' -eq 'x86') { + $archdir = "MS32"; + } elseif ('${{ inputs.arch }}' -eq 'x64') { + $archdir = "MS64"; + } else { + write-host "Invalid arch=${{ inputs.arch }}" + exit 1 + } + $libusb_incdir = "C:\temp\libusb-${{ inputs.version }}\include"; + $libusb_libdir = "C:\temp\libusb-${{ inputs.version }}\VS2022\${archdir}\dll"; + + $libusb_header = "${libusb_incdir}\libusb.h"; + $libusb_implib = "${libusb_libdir}\libusb-1.0.lib"; + $libusb_dll = "${libusb_libdir}\libusb-1.0.dll"; + + if (!(Test-Path "${libusb_header}")) { + write-host "${libusb_header} does not exist!" + exit 1 + } + if (!(Test-Path "${libusb_implib}")){ + write-host "${libusb_implib} does not exist!" + exit 1 + } + if (!(Test-Path "${libusb_dll}")) { + write-host "${libusb_dll} does not exist!" + exit 1 + } + echo "root=${libusb_incdir};${libusb_libdir}" >> $env:GITHUB_OUTPUT + echo "LibUSB_ROOT=${libusb_incdir};${libusb_libdir}" >> $env:GITHUB_ENV diff --git a/libs/SDL3/.github/actions/setup-ninja/action.yml b/libs/SDL3/.github/actions/setup-ninja/action.yml new file mode 100644 index 00000000..a1d3ad98 --- /dev/null +++ b/libs/SDL3/.github/actions/setup-ninja/action.yml @@ -0,0 +1,62 @@ +name: 'Setup ninja' +description: 'Download ninja and add it to the PATH environment variable' +inputs: + version: + description: 'Ninja version' + default: '1.12.1' +runs: + using: 'composite' + steps: + - name: 'Calculate variables' + id: calc + shell: sh + run: | + case "${{ runner.os }}-${{ runner.arch }}" in + "Linux-X86" | "Linux-X64") + archive="ninja-linux.zip" + ;; + "Linux-ARM64") + archive="ninja-linux-aarch64.zip" + ;; + "macOS-X86" | "macOS-X64" | "macOS-ARM64") + archive="ninja-mac.zip" + ;; + "Windows-X86" | "Windows-X64") + archive="ninja-win.zip" + ;; + "Windows-ARM64") + archive="ninja-winarm64.zip" + ;; + *) + echo "Unsupported ${{ runner.os }}-${{ runner.arch }}" + exit 1; + ;; + esac + echo "archive=${archive}" >> ${GITHUB_OUTPUT} + echo "cache-key=${archive}-${{ inputs.version }}-${{ runner.os }}-${{ runner.arch }}" >> ${GITHUB_OUTPUT} + - name: 'Restore cached ${{ steps.calc.outputs.archive }}' + id: cache-restore + uses: actions/cache/restore@v4 + with: + path: '${{ runner.temp }}/${{ steps.calc.outputs.archive }}' + key: ${{ steps.calc.outputs.cache-key }} + - name: 'Download ninja ${{ inputs.version }} for ${{ runner.os }} (${{ runner.arch }})' + if: ${{ !steps.cache-restore.outputs.cache-hit || steps.cache-restore.outputs.cache-hit == 'false' }} + shell: pwsh + run: | + Invoke-WebRequest "https://github.com/ninja-build/ninja/releases/download/v${{ inputs.version }}/${{ steps.calc.outputs.archive }}" -OutFile "${{ runner.temp }}/${{ steps.calc.outputs.archive }}" + - name: 'Cache ${{ steps.calc.outputs.archive }}' + if: ${{ !steps.cache-restore.outputs.cache-hit || steps.cache-restore.outputs.cache-hit == 'false' }} + uses: actions/cache/save@v4 + with: + path: '${{ runner.temp }}/${{ steps.calc.outputs.archive }}' + key: ${{ steps.calc.outputs.cache-key }} + - name: 'Extract ninja' + shell: pwsh + run: | + 7z "-o${{ runner.temp }}/ninja-${{ inputs.version }}-${{ runner.arch }}" x "${{ runner.temp }}/${{ steps.calc.outputs.archive }}" + - name: 'Set output variables' + id: final + shell: pwsh + run: | + echo "${{ runner.temp }}/ninja-${{ inputs.version }}-${{ runner.arch }}" >> $env:GITHUB_PATH diff --git a/libs/SDL3/.github/actions/setup-vita-gles/action.yml b/libs/SDL3/.github/actions/setup-vita-gles/action.yml new file mode 100644 index 00000000..e263737b --- /dev/null +++ b/libs/SDL3/.github/actions/setup-vita-gles/action.yml @@ -0,0 +1,93 @@ +name: 'Setup GLES for PlayStation Vita' +description: 'Download GLES for VITA (PVR or PIB), and copy it into the vita sdk' +inputs: + pib-version: + description: 'PIB version' + default: '1.1.4' + pvr-version: + description: 'PVR_PSP2 version' + default: '3.9' + type: + description: '"pib" or "pvr"' + default: '' +runs: + using: 'composite' + steps: + - name: 'Calculate variables' + id: calc + shell: sh + run: | + if test "x${VITASDK}" = "x"; then + echo "VITASDK must be defined" + exit 1; + fi + case "x${{ inputs.type }}" in + "xpvr") + echo "cache-key=SDL-vita-gles-pvr-${{ inputs.pvr-version}}" >> ${GITHUB_OUTPUT} + ;; + "xpib") + echo "cache-key=SDL-vita-gles-pib-${{ inputs.pib-version}}" >> ${GITHUB_OUTPUT} + ;; + *) + echo "Invalid type. Must be 'pib' or 'pvr'." + exit 1 + ;; + esac + - uses: actions/cache/restore@v4 + id: restore-cache + with: + path: /vita/dependencies + key: '${{ steps.calc.outputs.cache-key }}' + - name: 'Download PVR_PSP2 (GLES)' + if: ${{ !steps.restore-cache.outputs.cache-hit && inputs.type == 'pvr' }} + shell: sh + run: | + pvr_psp2_version=${{ inputs.pvr-version }} + + mkdir -p /vita/dependencies/include + mkdir -p /vita/dependencies/lib + + # Configure PVR_PSP2 headers + wget https://github.com/GrapheneCt/PVR_PSP2/archive/refs/tags/v$pvr_psp2_version.zip -P/tmp + unzip /tmp/v$pvr_psp2_version.zip -d/tmp + cp -r /tmp/PVR_PSP2-$pvr_psp2_version/include/* /vita/dependencies/include + rm /tmp/v$pvr_psp2_version.zip + + # include guard of PVR_PSP2's khrplatform.h does not match the usual one + sed -i -e s/__drvkhrplatform_h_/__khrplatform_h_/ /vita/dependencies/include/KHR/khrplatform.h + + # Configure PVR_PSP2 stub libraries + wget https://github.com/GrapheneCt/PVR_PSP2/releases/download/v$pvr_psp2_version/vitasdk_stubs.zip -P/tmp + unzip /tmp/vitasdk_stubs.zip -d/tmp/pvr_psp2_stubs + find /tmp/pvr_psp2_stubs -type f -name "*.a" -exec cp {} /vita/dependencies/lib \; + rm /tmp/vitasdk_stubs.zip + rm -rf /tmp/pvr_psp2_stubs + + - name: 'Download gl4es4vita (OpenGL)' + if: ${{ !steps.restore-cache.outputs.cache-hit && inputs.type == 'pib' }} + shell: sh + run: | + gl4es4vita_version=${{ inputs.pib-version }} + + mkdir -p /vita/dependencies/include + mkdir -p /vita/dependencies/lib + + # Configure gl4es4vita headers + wget https://github.com/SonicMastr/gl4es4vita/releases/download/v$gl4es4vita_version-vita/include.zip -P/tmp + unzip -o /tmp/include.zip -d/vita/dependencies/include + rm /tmp/include.zip + + # Configure gl4es4vita stub libraries + wget https://github.com/SonicMastr/gl4es4vita/releases/download/v$gl4es4vita_version-vita/vitasdk_stubs.zip -P/tmp + unzip /tmp/vitasdk_stubs.zip -d/vita/dependencies/lib + + - uses: actions/cache/save@v4 + if: ${{ !steps.restore-cache.outputs.cache-hit }} + with: + path: /vita/dependencies + key: '${{ steps.calc.outputs.cache-key }}' + + - name: Copy PVR_PSP2 (GLES) or gl4es4vita (OpenGL) to vita toolchain dir + shell: sh + run: | + cp -rv /vita/dependencies/* ${VITASDK}/arm-vita-eabi diff --git a/libs/SDL3/.github/cmake/CMakeLists.txt b/libs/SDL3/.github/cmake/CMakeLists.txt new file mode 100644 index 00000000..48757010 --- /dev/null +++ b/libs/SDL3/.github/cmake/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.0...3.5) +project(ci_utils C CXX) + +set(txt "CC=${CMAKE_C_COMPILER} +CXX=${CMAKE_CXX_COMPILER} +CFLAGS=${CMAKE_C_FLAGS} +CXXFLAGS=${CMAKE_CXX_FLAGS} +LDFLAGS=${CMAKE_EXE_LINKER_FLAGS} ${CMAKE_C_STANDARD_LIBRARIES} +") + +message("${txt}") + +set(VAR_PATH "/tmp/env.txt" CACHE PATH "Where to write environment file") +message(STATUS "Writing CC/CXX/CFLAGS/CXXFLAGS/LDFLAGS environment to ${VAR_PATH}") + +file(WRITE "${VAR_PATH}" "${txt}") diff --git a/libs/SDL3/.github/workflows/build.yml b/libs/SDL3/.github/workflows/build.yml new file mode 100644 index 00000000..09652e02 --- /dev/null +++ b/libs/SDL3/.github/workflows/build.yml @@ -0,0 +1,48 @@ +name: 'Build (All)' + +on: [push, pull_request] + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: true + +jobs: + controller: + name: 'Create test plan' + runs-on: 'ubuntu-latest' + outputs: + platforms-level1: ${{ steps.plan.outputs.platforms-level1 }} + platforms-others: ${{ steps.plan.outputs.platforms-others }} + steps: + - uses: actions/setup-python@main + with: + python-version: 3.x + - uses: actions/checkout@main + with: + sparse-checkout: '.github/workflows/create-test-plan.py' + - name: 'Create plan' + id: plan + run: | + # Adding [sdl-ci-filter GLOB] to the commit message will limit the jobs + # e.g. [sdl-ci-filter msvc-*] + EOF=$(openssl rand -hex 32) + cat >/tmp/commit_message.txt <<$EOF + ${{ github.event.head_commit.message }} + $EOF + + python .github/workflows/create-test-plan.py \ + --github-variable-prefix platforms \ + --github-ci \ + --verbose \ + ${{ (github.repository_owner != 'libsdl-org' && '--no-artifact') || '' }} \ + --commit-message-file /tmp/commit_message.txt + level1: + needs: [controller] + uses: './.github/workflows/generic.yml' + with: + platforms: ${{ needs.controller.outputs.platforms-level1 }} + level2: + needs: [controller, level1] + uses: './.github/workflows/generic.yml' + with: + platforms: ${{ needs.controller.outputs.platforms-others }} diff --git a/libs/SDL3/.github/workflows/create-test-plan.py b/libs/SDL3/.github/workflows/create-test-plan.py new file mode 100644 index 00000000..a137889c --- /dev/null +++ b/libs/SDL3/.github/workflows/create-test-plan.py @@ -0,0 +1,863 @@ +#!/usr/bin/env python +import argparse +import dataclasses +import fnmatch +from enum import Enum +import json +import logging +import os +import re +from typing import Optional + +logger = logging.getLogger(__name__) + + +class AppleArch(Enum): + Aarch64 = "aarch64" + X86_64 = "x86_64" + + +class MsvcArch(Enum): + X86 = "x86" + X64 = "x64" + Arm32 = "arm" + Arm64 = "arm64" + + +class JobOs(Enum): + WindowsLatest = "windows-latest" + UbuntuLatest = "ubuntu-latest" + MacosLatest = "macos-latest" + Ubuntu22_04 = "ubuntu-22.04" + Ubuntu24_04 = "ubuntu-24.04" + Ubuntu24_04_arm = "ubuntu-24.04-arm" + Macos13 = "macos-13" + + +class SdlPlatform(Enum): + Android = "android" + Emscripten = "emscripten" + Haiku = "haiku" + LoongArch64 = "loongarch64" + Msys2 = "msys2" + Linux = "linux" + MacOS = "macos" + Ios = "ios" + Tvos = "tvos" + Msvc = "msvc" + N3ds = "n3ds" + PowerPC = "powerpc" + PowerPC64 = "powerpc64" + Ps2 = "ps2" + Psp = "psp" + Vita = "vita" + Riscos = "riscos" + FreeBSD = "freebsd" + NetBSD = "netbsd" + + +class Msys2Platform(Enum): + Mingw32 = "mingw32" + Mingw64 = "mingw64" + Clang64 = "clang64" + Ucrt64 = "ucrt64" + + +class IntelCompiler(Enum): + Icc = "icc" + Icx = "icx" + + +class VitaGLES(Enum): + Pib = "pib" + Pvr = "pvr" + + +@dataclasses.dataclass(slots=True) +class JobSpec: + name: str + os: JobOs + platform: SdlPlatform + artifact: Optional[str] + container: Optional[str] = None + no_cmake: bool = False + xcode: bool = False + android_mk: bool = False + android_gradle: bool = False + lean: bool = False + android_arch: Optional[str] = None + android_abi: Optional[str] = None + android_platform: Optional[int] = None + msys2_platform: Optional[Msys2Platform] = None + intel: Optional[IntelCompiler] = None + apple_framework: Optional[bool] = None + apple_archs: Optional[set[AppleArch]] = None + msvc_project: Optional[str] = None + msvc_arch: Optional[MsvcArch] = None + clang_cl: bool = False + gdk: bool = False + vita_gles: Optional[VitaGLES] = None + + +JOB_SPECS = { + "msys2-mingw32": JobSpec(name="Windows (msys2, mingw32)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw32", msys2_platform=Msys2Platform.Mingw32, ), + "msys2-mingw64": JobSpec(name="Windows (msys2, mingw64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw64", msys2_platform=Msys2Platform.Mingw64, ), + "msys2-clang64": JobSpec(name="Windows (msys2, clang64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw64-clang", msys2_platform=Msys2Platform.Clang64, ), + "msys2-ucrt64": JobSpec(name="Windows (msys2, ucrt64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw64-ucrt", msys2_platform=Msys2Platform.Ucrt64, ), + "msvc-x64": JobSpec(name="Windows (MSVC, x64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-x64", msvc_arch=MsvcArch.X64, msvc_project="VisualC/SDL.sln", ), + "msvc-x86": JobSpec(name="Windows (MSVC, x86)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-x86", msvc_arch=MsvcArch.X86, msvc_project="VisualC/SDL.sln", ), + "msvc-clang-x64": JobSpec(name="Windows (MSVC, clang-cl x64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-clang-cl-x64", msvc_arch=MsvcArch.X64, clang_cl=True, ), + "msvc-clang-x86": JobSpec(name="Windows (MSVC, clang-cl x86)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-clang-cl-x86", msvc_arch=MsvcArch.X86, clang_cl=True, ), + "msvc-arm32": JobSpec(name="Windows (MSVC, ARM)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-arm32", msvc_arch=MsvcArch.Arm32, ), + "msvc-arm64": JobSpec(name="Windows (MSVC, ARM64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-arm64", msvc_arch=MsvcArch.Arm64, ), + "msvc-gdk-x64": JobSpec(name="GDK (MSVC, x64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-GDK", msvc_arch=MsvcArch.X64, msvc_project="VisualC-GDK/SDL.sln", gdk=True, no_cmake=True, ), + "ubuntu-22.04": JobSpec(name="Ubuntu 22.04", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04", ), + "ubuntu-24.04-arm64": JobSpec(name="Ubuntu 24.04 (ARM64)", os=JobOs.Ubuntu24_04_arm, platform=SdlPlatform.Linux, artifact="SDL-ubuntu24.04-arm64", ), + "steamrt-sniper": JobSpec(name="Steam Linux Runtime (Sniper)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Linux, artifact="SDL-slrsniper", container="registry.gitlab.steamos.cloud/steamrt/sniper/sdk:beta", ), + "ubuntu-intel-icx": JobSpec(name="Ubuntu 22.04 (Intel oneAPI)", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04-oneapi", intel=IntelCompiler.Icx, ), + "ubuntu-intel-icc": JobSpec(name="Ubuntu 22.04 (Intel Compiler)", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04-icc", intel=IntelCompiler.Icc, ), + "macos-framework-x64": JobSpec(name="MacOS (Framework) (x64)", os=JobOs.Macos13, platform=SdlPlatform.MacOS, artifact="SDL-macos-framework", apple_framework=True, apple_archs={AppleArch.Aarch64, AppleArch.X86_64, }, xcode=True, ), + "macos-framework-arm64": JobSpec(name="MacOS (Framework) (arm64)", os=JobOs.MacosLatest, platform=SdlPlatform.MacOS, artifact=None, apple_framework=True, apple_archs={AppleArch.Aarch64, AppleArch.X86_64, }, ), + "macos-gnu-arm64": JobSpec(name="MacOS (GNU prefix)", os=JobOs.MacosLatest, platform=SdlPlatform.MacOS, artifact="SDL-macos-arm64-gnu", apple_framework=False, apple_archs={AppleArch.Aarch64, }, ), + "ios": JobSpec(name="iOS (CMake & xcode)", os=JobOs.MacosLatest, platform=SdlPlatform.Ios, artifact="SDL-ios-arm64", xcode=True, ), + "tvos": JobSpec(name="tvOS (CMake & xcode)", os=JobOs.MacosLatest, platform=SdlPlatform.Tvos, artifact="SDL-tvos-arm64", xcode=True, ), + "android-cmake": JobSpec(name="Android (CMake)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Android, artifact="SDL-android-arm64", android_abi="arm64-v8a", android_arch="aarch64", android_platform=23, ), + "android-cmake-lean": JobSpec(name="Android (CMake, lean)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Android, artifact="SDL-lean-android-arm64", android_abi="arm64-v8a", android_arch="aarch64", android_platform=23, lean=True, ), + "android-mk": JobSpec(name="Android (Android.mk)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Android, artifact=None, no_cmake=True, android_mk=True, ), + "android-gradle": JobSpec(name="Android (Gradle)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Android, artifact=None, no_cmake=True, android_gradle=True, ), + "emscripten": JobSpec(name="Emscripten", os=JobOs.UbuntuLatest, platform=SdlPlatform.Emscripten, artifact="SDL-emscripten", ), + "haiku": JobSpec(name="Haiku", os=JobOs.UbuntuLatest, platform=SdlPlatform.Haiku, artifact="SDL-haiku-x64", container="ghcr.io/haiku/cross-compiler:x86_64-r1beta5", ), + "loongarch64": JobSpec(name="LoongArch64", os=JobOs.UbuntuLatest, platform=SdlPlatform.LoongArch64, artifact="SDL-loongarch64", ), + "n3ds": JobSpec(name="Nintendo 3DS", os=JobOs.UbuntuLatest, platform=SdlPlatform.N3ds, artifact="SDL-n3ds", container="devkitpro/devkitarm:latest", ), + "ppc": JobSpec(name="PowerPC", os=JobOs.UbuntuLatest, platform=SdlPlatform.PowerPC, artifact="SDL-ppc", container="dockcross/linux-ppc:latest", ), + "ppc64": JobSpec(name="PowerPC64", os=JobOs.UbuntuLatest, platform=SdlPlatform.PowerPC64, artifact="SDL-ppc64le", container="dockcross/linux-ppc64le:latest", ), + "ps2": JobSpec(name="Sony PlayStation 2", os=JobOs.UbuntuLatest, platform=SdlPlatform.Ps2, artifact="SDL-ps2", container="ps2dev/ps2dev:latest", ), + "psp": JobSpec(name="Sony PlayStation Portable", os=JobOs.UbuntuLatest, platform=SdlPlatform.Psp, artifact="SDL-psp", container="pspdev/pspdev:latest", ), + "vita-pib": JobSpec(name="Sony PlayStation Vita (GLES w/ pib)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Vita, artifact="SDL-vita-pib", container="vitasdk/vitasdk:latest", vita_gles=VitaGLES.Pib, ), + "vita-pvr": JobSpec(name="Sony PlayStation Vita (GLES w/ PVR_PSP2)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Vita, artifact="SDL-vita-pvr", container="vitasdk/vitasdk:latest", vita_gles=VitaGLES.Pvr, ), + "riscos": JobSpec(name="RISC OS", os=JobOs.UbuntuLatest, platform=SdlPlatform.Riscos, artifact="SDL-riscos", container="riscosdotinfo/riscos-gccsdk-4.7:latest", ), + "netbsd": JobSpec(name="NetBSD", os=JobOs.UbuntuLatest, platform=SdlPlatform.NetBSD, artifact="SDL-netbsd-x64", ), + "freebsd": JobSpec(name="FreeBSD", os=JobOs.UbuntuLatest, platform=SdlPlatform.FreeBSD, artifact="SDL-freebsd-x64", ), +} + + +class StaticLibType(Enum): + MSVC = "SDL3-static.lib" + A = "libSDL3.a" + + +class SharedLibType(Enum): + WIN32 = "SDL3.dll" + SO_0 = "libSDL3.so.0" + SO = "libSDL3.so" + DYLIB = "libSDL3.0.dylib" + FRAMEWORK = "SDL3.framework/Versions/A/SDL3" + + +@dataclasses.dataclass(slots=True) +class JobDetails: + name: str + key: str + os: str + platform: str + artifact: str + no_cmake: bool + ccache: bool = False + build_tests: bool = True + container: str = "" + cmake_build_type: str = "RelWithDebInfo" + shell: str = "sh" + sudo: str = "sudo" + cmake_config_emulator: str = "" + apk_packages: list[str] = dataclasses.field(default_factory=list) + apt_packages: list[str] = dataclasses.field(default_factory=list) + brew_packages: list[str] = dataclasses.field(default_factory=list) + cmake_toolchain_file: str = "" + cmake_arguments: list[str] = dataclasses.field(default_factory=list) + cmake_build_arguments: list[str] = dataclasses.field(default_factory=list) + clang_tidy: bool = True + cppflags: list[str] = dataclasses.field(default_factory=list) + cc: str = "" + cxx: str = "" + cflags: list[str] = dataclasses.field(default_factory=list) + cxxflags: list[str] = dataclasses.field(default_factory=list) + ldflags: list[str] = dataclasses.field(default_factory=list) + pollute_directories: list[str] = dataclasses.field(default_factory=list) + use_cmake: bool = True + shared: bool = True + static: bool = True + shared_lib: Optional[SharedLibType] = None + static_lib: Optional[StaticLibType] = None + run_tests: bool = True + test_pkg_config: bool = True + cc_from_cmake: bool = False + source_cmd: str = "" + pretest_cmd: str = "" + java: bool = False + android_apks: list[str] = dataclasses.field(default_factory=list) + android_ndk: bool = False + android_mk: bool = False + android_gradle: bool = False + minidump: bool = False + intel: bool = False + msys2_msystem: str = "" + msys2_env: str = "" + msys2_no_perl: bool = False + werror: bool = True + msvc_vcvars_arch: str = "" + msvc_vcvars_sdk: str = "" + msvc_project: str = "" + msvc_project_flags: list[str] = dataclasses.field(default_factory=list) + setup_ninja: bool = False + setup_libusb_arch: str = "" + xcode_sdk: str = "" + cpactions: bool = False + setup_gdk_folder: str = "" + cpactions_os: str = "" + cpactions_version: str = "" + cpactions_arch: str = "" + cpactions_setup_cmd: str = "" + cpactions_install_cmd: str = "" + setup_vita_gles_type: str = "" + check_sources: bool = False + setup_python: bool = False + pypi_packages: list[str] = dataclasses.field(default_factory=list) + + def to_workflow(self, enable_artifacts: bool) -> dict[str, str|bool]: + data = { + "name": self.name, + "key": self.key, + "os": self.os, + "ccache": self.ccache, + "container": self.container if self.container else "", + "platform": self.platform, + "artifact": self.artifact, + "enable-artifacts": enable_artifacts, + "shell": self.shell, + "msys2-msystem": self.msys2_msystem, + "msys2-env": self.msys2_env, + "msys2-no-perl": self.msys2_no_perl, + "android-ndk": self.android_ndk, + "java": self.java, + "intel": self.intel, + "apk-packages": my_shlex_join(self.apk_packages), + "apt-packages": my_shlex_join(self.apt_packages), + "test-pkg-config": self.test_pkg_config, + "brew-packages": my_shlex_join(self.brew_packages), + "pollute-directories": my_shlex_join(self.pollute_directories), + "no-cmake": self.no_cmake, + "build-tests": self.build_tests, + "source-cmd": self.source_cmd, + "pretest-cmd": self.pretest_cmd, + "cmake-config-emulator": self.cmake_config_emulator, + "cc": self.cc, + "cxx": self.cxx, + "cflags": my_shlex_join(self.cppflags + self.cflags), + "cxxflags": my_shlex_join(self.cppflags + self.cxxflags), + "ldflags": my_shlex_join(self.ldflags), + "cmake-toolchain-file": self.cmake_toolchain_file, + "clang-tidy": self.clang_tidy, + "cmake-arguments": my_shlex_join(self.cmake_arguments), + "cmake-build-arguments": my_shlex_join(self.cmake_build_arguments), + "shared": self.shared, + "static": self.static, + "shared-lib": self.shared_lib.value if self.shared_lib else None, + "static-lib": self.static_lib.value if self.static_lib else None, + "cmake-build-type": self.cmake_build_type, + "run-tests": self.run_tests, + "android-apks": my_shlex_join(self.android_apks), + "android-gradle": self.android_gradle, + "android-mk": self.android_mk, + "werror": self.werror, + "sudo": self.sudo, + "msvc-vcvars-arch": self.msvc_vcvars_arch, + "msvc-vcvars-sdk": self.msvc_vcvars_sdk, + "msvc-project": self.msvc_project, + "msvc-project-flags": my_shlex_join(self.msvc_project_flags), + "setup-ninja": self.setup_ninja, + "setup-libusb-arch": self.setup_libusb_arch, + "cc-from-cmake": self.cc_from_cmake, + "xcode-sdk": self.xcode_sdk, + "cpactions": self.cpactions, + "cpactions-os": self.cpactions_os, + "cpactions-version": self.cpactions_version, + "cpactions-arch": self.cpactions_arch, + "cpactions-setup-cmd": self.cpactions_setup_cmd, + "cpactions-install-cmd": self.cpactions_install_cmd, + "setup-vita-gles-type": self.setup_vita_gles_type, + "setup-gdk-folder": self.setup_gdk_folder, + "check-sources": self.check_sources, + "setup-python": self.setup_python, + "pypi-packages": my_shlex_join(self.pypi_packages), + } + return {k: v for k, v in data.items() if v != ""} + + +def my_shlex_join(s): + def escape(s): + if s[:1] == "'" and s[-1:] == "'": + return s + if set(s).intersection(set("; \t")): + return f'"{s}"' + return s + + return " ".join(escape(s)) + + +def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDetails: + job = JobDetails( + name=spec.name, + key=key, + os=spec.os.value, + artifact=spec.artifact or "", + container=spec.container or "", + platform=spec.platform.value, + sudo="sudo", + no_cmake=spec.no_cmake, + ) + if job.os.startswith("ubuntu"): + job.apt_packages.extend([ + "ninja-build", + "pkg-config", + ]) + pretest_cmd = [] + if trackmem_symbol_names: + pretest_cmd.append("export SDL_TRACKMEM_SYMBOL_NAMES=1") + else: + pretest_cmd.append("export SDL_TRACKMEM_SYMBOL_NAMES=0") + win32 = spec.platform in (SdlPlatform.Msys2, SdlPlatform.Msvc) + fpic = None + build_parallel = True + if spec.lean: + job.cppflags.append("-DSDL_LEAN_AND_MEAN=1") + if win32: + job.cmake_arguments.append("-DSDLTEST_PROCDUMP=ON") + job.minidump = True + if spec.intel is not None: + match spec.intel: + case IntelCompiler.Icx: + job.cc = "icx" + job.cxx = "icpx" + case IntelCompiler.Icc: + job.cc = "icc" + job.cxx = "icpc" + # Disable deprecation warning + job.cppflags.append("-diag-disable=10441") + # Avoid 'Catastrophic error: cannot open precompiled header file' + job.cmake_arguments.append("-DCMAKE_DISABLE_PRECOMPILE_HEADERS:BOOL=ON") + job.clang_tidy = False + case _: + raise ValueError(f"Invalid intel={spec.intel}") + job.source_cmd = f"source /opt/intel/oneapi/setvars.sh;" + job.intel = True + job.shell = "bash" + job.cmake_arguments.extend(( + f"-DCMAKE_C_COMPILER={job.cc}", + f"-DCMAKE_CXX_COMPILER={job.cxx}", + "-DCMAKE_SYSTEM_NAME=Linux", + )) + match spec.platform: + case SdlPlatform.Msvc: + job.setup_ninja = not spec.gdk + job.clang_tidy = False # complains about \threadsafety: "unknown command tag name [clang-diagnostic-documentation-unknown-command]" + job.msvc_project = spec.msvc_project if spec.msvc_project else "" + job.msvc_project_flags.append("-p:TreatWarningsAsError=true") + job.test_pkg_config = False + job.shared_lib = SharedLibType.WIN32 + job.static_lib = StaticLibType.MSVC + job.cmake_arguments.extend(( + "-DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT=ProgramDatabase", + "-DCMAKE_EXE_LINKER_FLAGS=-DEBUG", + "-DCMAKE_SHARED_LINKER_FLAGS=-DEBUG", + )) + + job.cmake_arguments.append("'-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded$<$:Debug>'") + + if spec.clang_cl: + job.cmake_arguments.extend(( + "-DCMAKE_C_COMPILER=clang-cl", + "-DCMAKE_CXX_COMPILER=clang-cl", + )) + match spec.msvc_arch: + case MsvcArch.X86: + job.cflags.append("/clang:-m32") + job.ldflags.append("/MACHINE:X86") + case MsvcArch.X64: + job.cflags.append("/clang:-m64") + job.ldflags.append("/MACHINE:X64") + case _: + raise ValueError(f"Unsupported clang-cl architecture (arch={spec.msvc_arch})") + if spec.msvc_project: + match spec.msvc_arch: + case MsvcArch.X86: + msvc_platform = "Win32" + case MsvcArch.X64: + msvc_platform = "x64" + case _: + raise ValueError(f"Unsupported vcxproj architecture (arch={spec.msvc_arch})") + if spec.gdk: + msvc_platform = f"Gaming.Desktop.{msvc_platform}" + job.msvc_project_flags.append(f"-p:Platform={msvc_platform}") + match spec.msvc_arch: + case MsvcArch.X86: + job.msvc_vcvars_arch = "x64_x86" + case MsvcArch.X64: + job.msvc_vcvars_arch = "x64" + case MsvcArch.Arm32: + job.msvc_vcvars_arch = "x64_arm" + job.msvc_vcvars_sdk = "10.0.22621.0" # 10.0.26100.0 dropped ARM32 um and ucrt libraries + job.run_tests = False + case MsvcArch.Arm64: + job.msvc_vcvars_arch = "x64_arm64" + job.run_tests = False + if spec.gdk: + job.setup_gdk_folder = "VisualC-GDK" + else: + match spec.msvc_arch: + case MsvcArch.X86: + job.setup_libusb_arch = "x86" + case MsvcArch.X64: + job.setup_libusb_arch = "x64" + case SdlPlatform.Linux: + if spec.name.startswith("Ubuntu"): + assert spec.os.value.startswith("ubuntu-") + job.apt_packages.extend(( + "ccache", + "gnome-desktop-testing", + "libasound2-dev", + "libpulse-dev", + "libaudio-dev", + "libjack-dev", + "libsndio-dev", + "libusb-1.0-0-dev", + "libx11-dev", + "libxext-dev", + "libxrandr-dev", + "libxcursor-dev", + "libxfixes-dev", + "libxi-dev", + "libxss-dev", + "libwayland-dev", + "libxkbcommon-dev", + "libdrm-dev", + "libgbm-dev", + "libgl1-mesa-dev", + "libgles2-mesa-dev", + "libegl1-mesa-dev", + "libdbus-1-dev", + "libibus-1.0-dev", + "libudev-dev", + "fcitx-libs-dev", + )) + match = re.match(r"ubuntu-(?P[0-9]+)\.(?P[0-9]+).*", spec.os.value) + ubuntu_year, ubuntu_month = [int(match["year"]), int(match["month"])] + if ubuntu_year >= 22: + job.apt_packages.extend(("libpipewire-0.3-dev", "libdecor-0-dev")) + job.apt_packages.extend(( + "libunwind-dev", # For SDL_test memory tracking + )) + job.ccache = True + if trackmem_symbol_names: + # older libunwind is slow + job.cmake_arguments.append("-DSDLTEST_TIMEOUT_MULTIPLIER=2") + job.shared_lib = SharedLibType.SO_0 + job.static_lib = StaticLibType.A + fpic = True + case SdlPlatform.Ios | SdlPlatform.Tvos: + job.brew_packages.extend([ + "ccache", + "ninja", + ]) + job.ccache = True + job.clang_tidy = False + job.run_tests = False + job.test_pkg_config = False + job.shared_lib = SharedLibType.DYLIB + job.static_lib = StaticLibType.A + match spec.platform: + case SdlPlatform.Ios: + if spec.xcode: + job.xcode_sdk = 'iphoneos' + job.cmake_arguments.extend([ + "-DCMAKE_SYSTEM_NAME=iOS", + "-DCMAKE_OSX_ARCHITECTURES=\"arm64\"", + "-DCMAKE_OSX_DEPLOYMENT_TARGET=11.0", + ]) + case SdlPlatform.Tvos: + if spec.xcode: + job.xcode_sdk = 'appletvos' + job.cmake_arguments.extend([ + "-DCMAKE_SYSTEM_NAME=tvOS", + "-DCMAKE_OSX_ARCHITECTURES=\"arm64\"", + "-DCMAKE_OSX_DEPLOYMENT_TARGET=11.0", + ]) + case SdlPlatform.MacOS: + if spec.apple_framework: + job.static = False + job.clang_tidy = False + job.test_pkg_config = False + job.cmake_arguments.extend(( + "'-DCMAKE_OSX_ARCHITECTURES=x86_64;arm64'", + "-DCMAKE_OSX_DEPLOYMENT_TARGET=10.13", + "-DSDL_FRAMEWORK=ON", + )) + job.shared_lib = SharedLibType.FRAMEWORK + else: + job.clang_tidy = True + job.cmake_arguments.extend(( + "-DCMAKE_OSX_ARCHITECTURES=arm64", + "-DCMAKE_OSX_DEPLOYMENT_TARGET=10.13", + "-DCLANG_TIDY_BINARY=$(brew --prefix llvm)/bin/clang-tidy", + )) + job.shared_lib = SharedLibType.DYLIB + job.static_lib = StaticLibType.A + job.ccache = True + job.apt_packages = [] + job.brew_packages.extend(( + "ccache", + "ninja", + )) + if job.clang_tidy: + job.brew_packages.append("llvm") + if spec.xcode: + job.xcode_sdk = "macosx" + case SdlPlatform.Android: + job.android_gradle = spec.android_gradle + job.android_mk = spec.android_mk + job.apt_packages.append("ccache") + job.run_tests = False + job.shared_lib = SharedLibType.SO + job.static_lib = StaticLibType.A + if spec.android_mk or not spec.no_cmake: + job.android_ndk = True + if spec.android_gradle or not spec.no_cmake: + job.java = True + if spec.android_mk or spec.android_gradle: + job.apt_packages = [] + if not spec.no_cmake: + job.ccache = True + job.cmake_arguments.extend(( + f"-DANDROID_PLATFORM={spec.android_platform}", + f"-DANDROID_ABI={spec.android_abi}", + )) + job.cmake_toolchain_file = "${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake" + job.cc = f"${{ANDROID_NDK_HOME}}/toolchains/llvm/prebuilt/linux-x86_64/bin/clang --target={spec.android_arch}-none-linux-androideabi{spec.android_platform}" + + job.android_apks = [ + "testaudiorecording-apk", + "testautomation-apk", + "testcontroller-apk", + "testmultiaudio-apk", + "testsprite-apk", + ] + case SdlPlatform.Emscripten: + job.clang_tidy = False # clang-tidy does not understand -gsource-map + job.shared = False + job.ccache = True + job.apt_packages.append("ccache") + job.cmake_config_emulator = "emcmake" + job.cmake_build_type = "Debug" + job.test_pkg_config = False + job.cmake_arguments.extend(( + "-DSDLTEST_BROWSER=chrome", + "-DSDLTEST_TIMEOUT_MULTIPLIER=4", + "-DSDLTEST_CHROME_BINARY=${CHROME_BINARY}", + )) + job.cflags.extend(( + "-gsource-map", + "-ffile-prefix-map=${PWD}=/SDL", + )) + job.ldflags.extend(( + "--source-map-base", "/", + )) + pretest_cmd.extend(( + "# Start local HTTP server", + "cmake --build build --target serve-sdl-tests --verbose &", + "chrome --version", + "chromedriver --version", + )) + job.static_lib = StaticLibType.A + job.setup_python = True + job.pypi_packages.append("selenium") + case SdlPlatform.Ps2: + job.ccache = False # actions/ccache does not work in psp container (incompatible tar of busybox) + build_parallel = False + job.shared = False + job.sudo = "" + job.apt_packages = [] + job.apk_packages = ["ccache", "cmake", "gmp", "mpc1", "mpfr4", "ninja", "pkgconf", "git", ] + job.cmake_toolchain_file = "${PS2DEV}/ps2sdk/ps2dev.cmake" + job.clang_tidy = False + job.run_tests = False + job.shared = False + job.cc = "mips64r5900el-ps2-elf-gcc" + job.ldflags = ["-L${PS2DEV}/ps2sdk/ee/lib", "-L${PS2DEV}/gsKit/lib", "-L${PS2DEV}/ps2sdk/ports/lib", ] + job.static_lib = StaticLibType.A + case SdlPlatform.Psp: + job.ccache = False # actions/ccache does not work in psp container (incompatible tar of busybox) + build_parallel = False + job.sudo = "" + job.apt_packages = [] + job.apk_packages = ["ccache", "cmake", "gmp", "mpc1", "mpfr4", "ninja", "pkgconf", ] + job.cmake_toolchain_file = "${PSPDEV}/psp/share/pspdev.cmake" + job.clang_tidy = False + job.run_tests = False + job.shared = False + job.cc = "psp-gcc" + job.ldflags = ["-L${PSPDEV}/lib", "-L${PSPDEV}/psp/lib", "-L${PSPDEV}/psp/sdk/lib", ] + job.pollute_directories = ["${PSPDEV}/include", "${PSPDEV}/psp/include", "${PSPDEV}/psp/sdk/include", ] + job.static_lib = StaticLibType.A + case SdlPlatform.Vita: + job.ccache = True + job.sudo = "" + job.apt_packages = [] + job.apk_packages = ["ccache", "cmake", "ninja", "pkgconf", "bash", "tar"] + job.cmake_toolchain_file = "${VITASDK}/share/vita.toolchain.cmake" + assert spec.vita_gles is not None + job.setup_vita_gles_type = { + VitaGLES.Pib: "pib", + VitaGLES.Pvr: "pvr", + }[spec.vita_gles] + job.cmake_arguments.extend(( + f"-DVIDEO_VITA_PIB={ 'true' if spec.vita_gles == VitaGLES.Pib else 'false' }", + f"-DVIDEO_VITA_PVR={ 'true' if spec.vita_gles == VitaGLES.Pvr else 'false' }", + "-DSDL_ARMNEON=ON", + "-DSDL_ARMSIMD=ON", + )) + # Fix vita.toolchain.cmake (https://github.com/vitasdk/vita-toolchain/pull/253) + job.source_cmd = r"""sed -i -E "s#set\\( PKG_CONFIG_EXECUTABLE \"\\$\\{VITASDK}/bin/arm-vita-eabi-pkg-config\" \\)#set\\( PKG_CONFIG_EXECUTABLE \"${VITASDK}/bin/arm-vita-eabi-pkg-config\" CACHE PATH \"Path of pkg-config executable\" \\)#" ${VITASDK}/share/vita.toolchain.cmake""" + job.clang_tidy = False + job.run_tests = False + job.shared = False + job.cc = "arm-vita-eabi-gcc" + job.static_lib = StaticLibType.A + case SdlPlatform.Haiku: + job.ccache = True + fpic = False + job.run_tests = False + job.apt_packages.append("ccache") + job.cc = "x86_64-unknown-haiku-gcc" + job.cxx = "x86_64-unknown-haiku-g++" + job.sudo = "" + job.cmake_arguments.extend(( + f"-DCMAKE_C_COMPILER={job.cc}", + f"-DCMAKE_CXX_COMPILER={job.cxx}", + "-DSDL_UNIX_CONSOLE_BUILD=ON", + )) + job.shared_lib = SharedLibType.SO_0 + job.static_lib = StaticLibType.A + case SdlPlatform.PowerPC64 | SdlPlatform.PowerPC: + job.ccache = True + # FIXME: Enable SDL_WERROR + job.werror = False + job.clang_tidy = False + job.run_tests = False + job.sudo = "" + job.apt_packages = ["ccache"] + job.shared_lib = SharedLibType.SO_0 + job.static_lib = StaticLibType.A + job.cmake_arguments.extend(( + "-DSDL_UNIX_CONSOLE_BUILD=ON", + )) + case SdlPlatform.LoongArch64: + job.ccache = True + fpic = True + job.run_tests = False + job.apt_packages.append("ccache") + job.cc = "${LOONGARCH64_CC}" + job.cxx = "${LOONGARCH64_CXX}" + job.cmake_arguments.extend(( + f"-DCMAKE_C_COMPILER={job.cc}", + f"-DCMAKE_CXX_COMPILER={job.cxx}", + "-DSDL_UNIX_CONSOLE_BUILD=ON", + "-DCMAKE_SYSTEM_NAME=Linux", + )) + job.shared_lib = SharedLibType.SO_0 + job.static_lib = StaticLibType.A + case SdlPlatform.N3ds: + job.ccache = True + job.shared = False + job.apt_packages = ["ccache", "ninja-build", "binutils"] + job.clang_tidy = False + job.run_tests = False + job.cc_from_cmake = True + job.cmake_toolchain_file = "${DEVKITPRO}/cmake/3DS.cmake" + job.static_lib = StaticLibType.A + case SdlPlatform.Msys2: + job.ccache = True + job.shell = "msys2 {0}" + assert spec.msys2_platform + job.msys2_msystem = spec.msys2_platform.value + job.msys2_env = { + "mingw32": "mingw-w64-i686", + "mingw64": "mingw-w64-x86_64", + "clang64": "mingw-w64-clang-x86_64", + "ucrt64": "mingw-w64-ucrt-x86_64", + }[spec.msys2_platform.value] + job.msys2_no_perl = spec.msys2_platform in (Msys2Platform.Mingw32, ) + job.shared_lib = SharedLibType.WIN32 + job.static_lib = StaticLibType.A + case SdlPlatform.Riscos: + job.ccache = False # FIXME: enable when container gets upgrade + # FIXME: Enable SDL_WERROR + job.werror = False + job.apt_packages = ["ccache", "cmake", "ninja-build"] + job.test_pkg_config = False + job.shared = False + job.run_tests = False + job.sudo = "" + job.cmake_arguments.extend(( + "-DRISCOS:BOOL=ON", + "-DCMAKE_DISABLE_PRECOMPILE_HEADERS:BOOL=ON", + "-DSDL_GCC_ATOMICS:BOOL=OFF", + )) + job.cmake_toolchain_file = "/home/riscos/env/toolchain-riscos.cmake" + job.static_lib = StaticLibType.A + case SdlPlatform.FreeBSD | SdlPlatform.NetBSD: + job.cpactions = True + job.no_cmake = True + job.run_tests = False + job.apt_packages = [] + job.shared_lib = SharedLibType.SO_0 + job.static_lib = StaticLibType.A + match spec.platform: + case SdlPlatform.FreeBSD: + job.cpactions_os = "freebsd" + job.cpactions_version = "14.2" + job.cpactions_arch = "x86-64" + job.cpactions_setup_cmd = "sudo pkg update" + job.cpactions_install_cmd = "sudo pkg install -y cmake ninja pkgconf libXcursor libXext libXinerama libXi libXfixes libXrandr libXScrnSaver libXxf86vm wayland wayland-protocols libxkbcommon mesa-libs libglvnd evdev-proto libinotify alsa-lib jackit pipewire pulseaudio sndio dbus zh-fcitx ibus libudev-devd" + job.cmake_arguments.extend(( + "-DSDL_CHECK_REQUIRED_INCLUDES=/usr/local/include", + "-DSDL_CHECK_REQUIRED_LINK_OPTIONS=-L/usr/local/lib", + )) + case SdlPlatform.NetBSD: + job.cpactions_os = "netbsd" + job.cpactions_version = "10.1" + job.cpactions_arch = "x86-64" + job.cpactions_setup_cmd = "export PATH=\"/usr/pkg/sbin:/usr/pkg/bin:/sbin:$PATH\"; export PKG_CONFIG_PATH=\"/usr/pkg/lib/pkgconfig\";export PKG_PATH=\"https://cdn.netBSD.org/pub/pkgsrc/packages/NetBSD/$(uname -p)/$(uname -r|cut -f \"1 2\" -d.)/All/\";echo \"PKG_PATH=$PKG_PATH\";echo \"uname -a -> \"$(uname -a)\"\";sudo -E sysctl -w security.pax.aslr.enabled=0;sudo -E sysctl -w security.pax.aslr.global=0;sudo -E pkgin clean;sudo -E pkgin update" + job.cpactions_install_cmd = "sudo -E pkgin -y install cmake dbus pkgconf ninja-build pulseaudio libxkbcommon wayland wayland-protocols libinotify libusb1" + case _: + raise ValueError(f"Unsupported platform={spec.platform}") + + if "ubuntu" in spec.name.lower(): + job.check_sources = True + job.setup_python = True + + if job.ccache: + job.cmake_arguments.extend(( + "-DCMAKE_C_COMPILER_LAUNCHER=ccache", + "-DCMAKE_CXX_COMPILER_LAUNCHER=ccache", + )) + if not build_parallel: + job.cmake_build_arguments.append("-j1") + if job.cflags or job.cppflags: + job.cmake_arguments.append(f"-DCMAKE_C_FLAGS=\"{my_shlex_join(job.cflags + job.cppflags)}\"") + if job.cxxflags or job.cppflags: + job.cmake_arguments.append(f"-DCMAKE_CXX_FLAGS=\"{my_shlex_join(job.cxxflags + job.cppflags)}\"") + if job.ldflags: + job.cmake_arguments.append(f"-DCMAKE_SHARED_LINKER_FLAGS=\"{my_shlex_join(job.ldflags)}\"") + job.cmake_arguments.append(f"-DCMAKE_EXE_LINKER_FLAGS=\"{my_shlex_join(job.ldflags)}\"") + job.pretest_cmd = "\n".join(pretest_cmd) + def tf(b): + return "ON" if b else "OFF" + + if fpic is not None: + job.cmake_arguments.append(f"-DCMAKE_POSITION_INDEPENDENT_CODE={tf(fpic)}") + + if job.no_cmake: + job.cmake_arguments = [] + + return job + + +def spec_to_platform(spec: JobSpec, key: str, enable_artifacts: bool, trackmem_symbol_names: bool) -> dict[str, str|bool]: + logger.info("spec=%r", spec) + job = spec_to_job(spec, key=key, trackmem_symbol_names=trackmem_symbol_names) + logger.info("job=%r", job) + platform = job.to_workflow(enable_artifacts=enable_artifacts) + logger.info("platform=%r", platform) + return platform + + +def main(): + parser = argparse.ArgumentParser(allow_abbrev=False) + parser.add_argument("--github-variable-prefix", default="platforms") + parser.add_argument("--github-ci", action="store_true") + parser.add_argument("--verbose", action="store_true") + parser.add_argument("--commit-message-file") + parser.add_argument("--no-artifact", dest="enable_artifacts", action="store_false") + parser.add_argument("--trackmem-symbol-names", dest="trackmem_symbol_names", action="store_true") + args = parser.parse_args() + + logging.basicConfig(level=logging.INFO if args.verbose else logging.WARNING) + + remaining_keys = set(JOB_SPECS.keys()) + + all_level_keys = ( + # Level 1 + ( + "haiku", + ), + ) + + filters = [] + if args.commit_message_file: + with open(args.commit_message_file, "r") as f: + commit_message = f.read() + for m in re.finditer(r"\[sdl-ci-filter (.*)]", commit_message, flags=re.M): + filters.append(m.group(1).strip(" \t\n\r\t'\"")) + + if re.search(r"\[sdl-ci-artifacts?]", commit_message, flags=re.M): + args.enable_artifacts = True + + if re.search(r"\[sdl-ci-(full-)?trackmem(-symbol-names)?]", commit_message, flags=re.M): + args.trackmem_symbol_names = True + + if not filters: + filters.append("*") + + logger.info("filters: %r", filters) + + all_level_platforms = {} + + all_platforms = {key: spec_to_platform(spec, key=key, enable_artifacts=args.enable_artifacts, trackmem_symbol_names=args.trackmem_symbol_names) for key, spec in JOB_SPECS.items()} + + for level_i, level_keys in enumerate(all_level_keys, 1): + level_key = f"level{level_i}" + logger.info("Level %d: keys=%r", level_i, level_keys) + assert all(k in remaining_keys for k in level_keys) + level_platforms = tuple(all_platforms[key] for key in level_keys) + remaining_keys.difference_update(level_keys) + all_level_platforms[level_key] = level_platforms + logger.info("=" * 80) + + logger.info("Keys before filter: %r", remaining_keys) + + filtered_remaining_keys = set() + for filter in filters: + filtered_remaining_keys.update(fnmatch.filter(remaining_keys, filter)) + + logger.info("Keys after filter: %r", filtered_remaining_keys) + + remaining_keys = filtered_remaining_keys + + logger.info("Remaining: %r", remaining_keys) + all_level_platforms["others"] = tuple(all_platforms[key] for key in remaining_keys) + + if args.github_ci: + for level, platforms in all_level_platforms.items(): + platforms_json = json.dumps(platforms) + txt = f"{args.github_variable_prefix}-{level}={platforms_json}" + logger.info("%s", txt) + if "GITHUB_OUTPUT" in os.environ: + with open(os.environ["GITHUB_OUTPUT"], "a") as f: + f.write(txt) + f.write("\n") + else: + logger.warning("GITHUB_OUTPUT not defined") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/libs/SDL3/.github/workflows/generic.yml b/libs/SDL3/.github/workflows/generic.yml new file mode 100644 index 00000000..9776431e --- /dev/null +++ b/libs/SDL3/.github/workflows/generic.yml @@ -0,0 +1,431 @@ +name: 'Build' +run-name: 'Configure, Build and Test SDL' + +on: + workflow_call: + inputs: + platforms: + description: 'JSON-encoded test properties' + type: string + required: true + +jobs: + build: + name: ${{ matrix.platform.name }} + runs-on: ${{ matrix.platform.os }} + container: ${{ matrix.platform.container }} + defaults: + run: + shell: ${{ matrix.platform.shell }} + strategy: + fail-fast: false + matrix: + platform: ${{ fromJSON(inputs.platforms) }} + steps: + - name: 'Set up MSYS2' + if: ${{ matrix.platform.platform == 'msys2' }} + uses: msys2/setup-msys2@v2 + with: + msystem: ${{ matrix.platform.msys2-msystem }} + install: >- + ${{ matrix.platform.msys2-env }}-cc + ${{ matrix.platform.msys2-env }}-cmake + ${{ matrix.platform.msys2-env }}-ninja + ${{ (!matrix.platform.msys2-no-perl && format('{0}-perl', matrix.platform.msys2-env)) || '' }} + ${{ matrix.platform.msys2-env }}-pkg-config + ${{ matrix.platform.msys2-env }}-clang-tools-extra + ${{ (matrix.platform.ccache && format('{0}-ccache', matrix.platform.msys2-env)) || '' }} + - name: 'About this job' + run: | + echo "key=${{ matrix.platform.key }}" + echo "name=${{ matrix.platform.name }}" + echo "os=${{ matrix.platform.os }}" + echo "" + echo "Add [sdl-ci-filter ${{ matrix.platform.key }}] to your commit message to reduce the number of jobs." + - uses: actions/checkout@v4 + - name: 'Set up ninja' + if: ${{ matrix.platform.setup-ninja }} + uses: ./.github/actions/setup-ninja + - name: 'Set up libusb for MSVC' + if: ${{ matrix.platform.setup-libusb-arch != '' }} + uses: ./.github/actions/setup-msvc-libusb + with: + arch: ${{ matrix.platform.setup-libusb-arch }} + - uses: mymindstorm/setup-emsdk@v14 + if: ${{ matrix.platform.platform == 'emscripten' }} + with: + version: 3.1.35 + - uses: browser-actions/setup-chrome@v1 + id: setup-chrome + if: ${{ matrix.platform.platform == 'emscripten' }} + with: + install-chromedriver: true + - name: 'Add chrome to PATH' + if: ${{ matrix.platform.platform == 'emscripten' }} + run: | + chrome_dir="$(dirname "${{ steps.setup-chrome.outputs.chrome-path }}")" + chromedriver_dir="$(dirname "${{ steps.setup-chrome.outputs.chromedriver-path }}")" + echo "CHROME_BINARY=${{ steps.setup-chrome.outputs.chrome-path }}" >>$GITHUB_ENV + echo "CHROMEDRIVER_BINARY=${{ steps.setup-chrome.outputs.chromedriver-path }}" >>$GITHUB_ENV + echo "chrome_dir=${chrome_dir}" + echo "chromedriver_dir=${chromedriver_dir}" + echo "${chrome_dir}" >>${GITHUB_PATH} + echo "${chromedriver_dir}" >>${GITHUB_PATH} + - uses: nttld/setup-ndk@v1 + if: ${{ matrix.platform.android-ndk }} + id: setup-ndk + with: + local-cache: true + ndk-version: r21e + - name: 'Configure Android NDK variables' + if: ${{ matrix.platform.android-ndk }} + shell: sh + run: | + # We cannot use GitHub expressions in the controller job + echo "ANDROID_NDK_HOME=${{ steps.setup-ndk.outputs.ndk-path }}" >>$GITHUB_ENV + - uses: actions/setup-java@v4 + if: ${{ matrix.platform.java }} + with: + distribution: 'temurin' + java-version: '17' + - uses: ilammy/msvc-dev-cmd@v1 + if: ${{ matrix.platform.platform == 'msvc' }} + with: + arch: ${{ matrix.platform.msvc-vcvars-arch }} + sdk: ${{ matrix.platform.msvc-vcvars-sdk }} + - name: 'Set up Windows GDK Desktop' + uses: ./.github/actions/setup-gdk-desktop + if: ${{ matrix.platform.setup-gdk-folder != '' }} + with: + folder: '${{ matrix.platform.setup-gdk-folder }}' + - name: 'Set up LoongArch64 toolchain' + uses: ./.github/actions/setup-loongarch64-toolchain + id: setup-loongarch64-toolchain + if: ${{ matrix.platform.platform == 'loongarch64' }} + - name: 'Setup Intel oneAPI toolchain' + id: intel + if: ${{ matrix.platform.intel }} + run: | + # Download the key to system keyring + wget -O- https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB \ + | gpg --dearmor | sudo tee /usr/share/keyrings/oneapi-archive-keyring.gpg > /dev/null + + # Add signed entry to apt sources and configure the APT client to use Intel repository: + echo "deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list + + # Update package list + sudo apt-get update -y + + # Install oneAPI + sudo apt-get install -y intel-oneapi-compiler-dpcpp-cpp-and-cpp-classic + - name: 'Install apk packages' + if: ${{ matrix.platform.apk-packages != '' }} + run: | + ${{ matrix.platform.sudo }} apk update + ${{ matrix.platform.sudo }} apk add ${{ matrix.platform.apk-packages }} + - name: 'Install apt packages' + if: ${{ matrix.platform.apt-packages != '' }} + run: | + ${{ matrix.platform.sudo }} apt-get update + ${{ matrix.platform.sudo }} apt-get install -y ${{ matrix.platform.apt-packages }} + - name: 'Install brew packages' + if: ${{ matrix.platform.brew-packages != '' }} + run: | + export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 + brew update + brew install ${{ matrix.platform.brew-packages }} + - name: 'Setup Python' + uses: 'actions/setup-python@main' + if: ${{ matrix.platform.setup-python }} + with: + python-version: '3.x' + - name: 'Install PyPI packages' + if: ${{ matrix.platform.pypi-packages != '' }} + run: | + python -m pip install --user ${{ matrix.platform.pypi-packages }} + - name: 'Set up GLES for VITA' # Must be after apk + if: ${{ matrix.platform.setup-vita-gles-type != '' }} + uses: ./.github/actions/setup-vita-gles + with: + type: ${{ matrix.platform.setup-vita-gles-type }} + + - name: 'Pollute toolchain with "bad" SDL headers' + if: ${{ matrix.platform.pollute-directories != '' }} + #shell: ${{ matrix.platform.shell }} + run: | + # Create "bad" SDL headers in the toolchain. + # SDL sources should not use these. + for include in ${{ matrix.platform.pollute-directories }}; do + toolchain_directory="${include}/SDL3" + echo "Creating directory ${toolchain_directory}" + mkdir -p "${toolchain_directory}/SDL3" + for header in include/SDL3/*.h; do + dest="${toolchain_directory}/SDL3/$(basename "${header}")" + echo "Creating ${dest}" + echo '#error "System SDL headers must not be used by build system"' >"$dest" + done + done + + - name: 'Calculate ccache key' + if: ${{ matrix.platform.ccache }} + id: prepare-restore-ccache + run: | + echo "timestamp=$(date -u "+%Y%m%d%H%M_%S")" >> "$GITHUB_OUTPUT" + - name: 'Restore ccache' + if: ${{ matrix.platform.ccache }} + uses: actions/cache/restore@v4 + id: restore-ccache + with: + path: ${{ runner.temp }}/ccache + key: ccache-${{ matrix.platform.key }}-${{ steps.prepare-restore-ccache.outputs.timestamp }} + restore-keys: | + ccache-${{matrix.platform.key}} + - name: 'Configure ccache' + if: ${{ matrix.platform.ccache }} + run: | + echo 'CCACHE_DIR=${{ runner.temp }}/ccache' >>${GITHUB_ENV} + - name: 'Prepare ccache' + if: ${{ matrix.platform.ccache && steps.restore-ccache.outputs.cache-hit }} + run: | + if [ "x${{ runner.os }}" = "xmacOS" ]; then + touch_date="2025-02-01T12:00:00Z" + else + touch_date="2025-02-01" + fi + find "${CCACHE_DIR}" -type f -exec touch -a -m -d "$touch_date" {} + + ccache -s + ccache -z + + - name: 'Configure (CMake)' + if: ${{ !matrix.platform.no-cmake }} + #shell: ${{ matrix.platform.shell }} + run: | + ${{ matrix.platform.source-cmd }} + ${{ matrix.platform.cmake-config-emulator }} cmake -S . -B build -GNinja \ + -Wdeprecated -Wdev -Werror \ + ${{ matrix.platform.cmake-toolchain-file != '' && format('-DCMAKE_TOOLCHAIN_FILE={0}', matrix.platform.cmake-toolchain-file) || '' }} \ + -DSDL_WERROR=${{ matrix.platform.werror }} \ + -DSDL_EXAMPLES=${{ matrix.platform.build-tests }} \ + -DSDL_TESTS=${{ matrix.platform.build-tests }} \ + -DSDLTEST_TRACKMEM=ON \ + -DSDL_INSTALL_TESTS=${{ matrix.platform.build-tests }} \ + -DSDL_CLANG_TIDY=${{ matrix.platform.clang-tidy }} \ + -DSDL_INSTALL_DOCS=ON \ + -DSDL_INSTALL_CPACK=ON \ + -DSDL_INSTALL_DOCS=ON \ + ${{ matrix.platform.cmake-arguments }} \ + -DSDL_SHARED=${{ matrix.platform.shared }} \ + -DSDL_STATIC=${{ matrix.platform.static }} \ + -DSDL_VENDOR_INFO="Github Workflow" \ + -DCMAKE_INSTALL_PREFIX=prefix \ + -DCMAKE_INSTALL_LIBDIR=lib \ + -DCMAKE_BUILD_TYPE=${{ matrix.platform.cmake-build-type }} + - name: 'Build (CMake)' + id: build + if: ${{ !matrix.platform.no-cmake }} +# shell: ${{ matrix.platform.shell }} + run: | + ${{ matrix.platform.source-cmd }} + cmake --build build --config ${{ matrix.platform.cmake-build-type }} --verbose -- ${{ matrix.platform.cmake-build-arguments }} + - name: 'Verify SDL_REVISION' + if: ${{ !matrix.platform.no-cmake }} + run: | + echo "This should show us the SDL_REVISION" + echo "Shared library:" + ${{ (matrix.platform.shared-lib && format('strings build/{0} | grep "Github Workflow"', matrix.platform.shared-lib)) || 'echo ""' }} + echo "Static library:" + ${{ (matrix.platform.static-lib && format('strings build/{0} | grep "Github Workflow"', matrix.platform.static-lib)) || 'echo ""' }} + - name: 'Run build-time tests (CMake)' + id: tests + if: ${{ !matrix.platform.no-cmake && matrix.platform.run-tests }} +# shell: ${{ matrix.platform.shell }} + run: | + ${{ matrix.platform.source-cmd }} + ${{ matrix.platform.pretest-cmd }} + set -eu + export SDL_TESTS_QUICK=1 + ctest -VV --test-dir build/ -j2 + - name: "Build test apk's (CMake)" + id: apks + if: ${{ always() && steps.build.outcome == 'success' && matrix.platform.android-apks != '' }} +# shell: ${{ matrix.platform.shell }} + run: | + ${{ matrix.platform.source-cmd }} + cmake --build build --config ${{ matrix.platform.cmake-build-type }} \ + --target \ + ${{ matrix.platform.android-apks }} \ + --verbose \ + -- ${{ matrix.platform.cmake-build-arguments }} + - name: 'Install (CMake)' + id: install + if: ${{ always() && steps.build.outcome == 'success' }} +# shell: ${{ matrix.platform.shell }} + run: | + ${{ matrix.platform.source-cmd }} + cmake --install build --config ${{ matrix.platform.cmake-build-type }} + echo "prefix=$(pwd)/prefix" >> $GITHUB_OUTPUT + ( cd prefix; find . ) | LC_ALL=C sort -u + - name: 'Package (CPack)' + id: package + if: ${{ always() && steps.build.outcome == 'success' }} +# shell: ${{ matrix.platform.shell }} + run: | + # DMG creation on macOS occasionally fails, so try multiple times + # https://gitlab.kitware.com/cmake/cmake/-/issues/25671 + success=0 + max_tries=10 + for i in $(seq $max_tries); do + cmake --build build/ --config ${{ matrix.platform.cmake-build-type }} --target package -- ${{ matrix.platform.cmake-build-arguments }} && success=1 + if test $success = 1; then + break + fi + echo "Package creation failed. Sleep 1 second and try again." + sleep 1 + done + if test $success = 0; then + echo "Package creation failed after $max_tries attempts." + exit 1 + fi + - name: 'Verify CMake configuration files' + if: ${{ steps.install.outcome == 'success' }} +# shell: ${{ matrix.platform.shell }} + run: | + ${{ matrix.platform.source-cmd }} + ${{ matrix.platform.cmake-config-emulator }} cmake -S cmake/test -B cmake_test_build -GNinja \ + ${{ matrix.platform.cmake-toolchain-file != '' && format('-DCMAKE_TOOLCHAIN_FILE={0}', matrix.platform.cmake-toolchain-file) || '' }} \ + -DTEST_SHARED=${{ matrix.platform.shared }} \ + -DTEST_STATIC=${{ matrix.platform.static }} \ + ${{ matrix.platform.cmake-arguments }} \ + -DCMAKE_BUILD_TYPE=${{ matrix.platform.cmake-build-type }} \ + -DCMAKE_PREFIX_PATH="${{ steps.install.outputs.prefix }}" + cmake --build cmake_test_build --verbose --config ${{ matrix.platform.cmake-build-type }} -- ${{ matrix.platform.cmake-build-arguments }} + - name: 'Extract CC/CXX/CFLAGS/CXXFLAGS from CMake toolchain' + if: ${{ steps.install.outcome == 'success' && matrix.platform.cc-from-cmake }} +# shell: ${{ matrix.platform.shell }} + run: | + cmake -S .github/cmake -B /tmp/cmake_extract \ + ${{ matrix.platform.cmake-toolchain-file != '' && format('-DCMAKE_TOOLCHAIN_FILE={0}', matrix.platform.cmake-toolchain-file) || '' }} \ + -DCMAKE_BUILD_TYPE=${{ matrix.platform.cmake-build-type }} \ + -DVAR_PATH=/tmp/env.txt + cat /tmp/env.txt >> $GITHUB_ENV + - name: 'Verify sdl3.pc' +# shell: ${{ matrix.platform.shell }} + if: ${{ steps.install.outcome == 'success' && matrix.platform.test-pkg-config }} + run: | + ${{ matrix.platform.source-cmd }} + ${{ matrix.platform.cc && format('export CC="{0}"', matrix.platform.cc) || '' }} + ${{ matrix.platform.cflags && format('export CFLAGS="{0}"', matrix.platform.cflags) || '' }} + ${{ matrix.platform.ldflags && format('export LDFLAGS="{0}"', matrix.platform.ldflags) || '' }} + export PKG_CONFIG_PATH=${{ steps.install.outputs.prefix }}/lib/pkgconfig + cmake/test/test_pkgconfig.sh + - name: 'Build (cross-platform-actions, BSD)' + id: cpactions + if: ${{ matrix.platform.cpactions }} + uses: cross-platform-actions/action@v0.27.0 + with: + operating_system: '${{ matrix.platform.cpactions-os }}' + architecture: '${{ matrix.platform.cpactions-arch }}' + version: '${{ matrix.platform.cpactions-version }}' + run: | + ${{ matrix.platform.cpactions-setup-cmd }} + ${{ matrix.platform.cpactions-install-cmd }} + cmake -S . -B build -GNinja \ + ${{ matrix.platform.cmake-toolchain-file != '' && format('-DCMAKE_TOOLCHAIN_FILE={0}', matrix.platform.cmake-toolchain-file) || '' }} \ + -Wdeprecated -Wdev -Werror \ + -DSDL_WERROR=${{ matrix.platform.werror }} \ + -DSDL_INSTALL_DOCS=ON \ + ${{ matrix.platform.cmake-arguments }} \ + -DSDL_SHARED=${{ matrix.platform.shared }} \ + -DSDL_STATIC=${{ matrix.platform.static }} \ + -DSDL_VENDOR_INFO="Github Workflow" \ + -DCMAKE_INSTALL_PREFIX=prefix \ + -DCMAKE_INSTALL_LIBDIR=lib \ + -DCMAKE_BUILD_TYPE=${{ matrix.platform.cmake-build-type }} + cmake --build build/ --config ${{ matrix.platform.cmake-build-type }} --verbose + cmake --build build/ --config ${{ matrix.platform.cmake-build-type }} --target package + + cmake --build build/ --config ${{ matrix.platform.cmake-build-type }} --target clean + rm -rf build/dist/_CPack_Packages + rm -rf build/CMakeFiles + rm -rf build/docs + - name: Add msbuild to PATH + id: setup-msbuild + if: ${{ matrix.platform.msvc-project != '' }} + uses: microsoft/setup-msbuild@v2 + - name: Build msbuild + if: ${{ matrix.platform.msvc-project != '' }} + run: | + "$(cygpath -u '${{ steps.setup-msbuild.outputs.msbuildPath }}\msbuild.exe')" ${{ matrix.platform.msvc-project }} -m -p:BuildInParallel=true -p:Configuration=Release ${{ matrix.platform.msvc-project-flags }} + - name: 'Build (Android.mk)' + if: ${{ matrix.platform.android-mk }} + run: | + ./build-scripts/androidbuildlibs.sh + - name: 'Create Gradle project (Android)' + if: ${{ matrix.platform.android-gradle }} + run: | + for folder in build-ndk-build build-cmake; do + python build-scripts/create-android-project.py \ + --output "${folder}" \ + --variant copy \ + org.libsdl.testspriteminimal \ + test/testspriteminimal.c test/icon.h + done + echo "" + echo "Project contents:" + echo "" + find "build-ndk-build/org.libsdl.testspriteminimal" + - name: 'Build Android app (Gradle & ndk-build)' + if: ${{ matrix.platform.android-gradle }} + run: | + cd build-ndk-build/org.libsdl.testspriteminimal + ./gradlew -i assembleRelease + - name: 'Build Android app (Gradle & CMake)' + if: ${{ matrix.platform.android-gradle }} + run: | + cd build-cmake/org.libsdl.testspriteminimal + ./gradlew -i assembleRelease -PBUILD_WITH_CMAKE=1 + - name: 'Build (xcode)' + if: ${{ matrix.platform.xcode-sdk != '' }} + run: | + xcodebuild -project Xcode/SDL/SDL.xcodeproj -target SDL3 -configuration Release -sdk ${{ matrix.platform.xcode-sdk }} clean build + - name: 'Prune old ccache files' + if: ${{ matrix.platform.ccache }} + run: | + ccache --evict-older-than=1d + ccache -s + - name: 'Save ccache' + if: ${{ matrix.platform.ccache }} + uses: actions/cache/save@v4 + with: + path: ${{ runner.temp }}/ccache + key: ${{ steps.restore-ccache.outputs.cache-primary-key }} + - name: 'Check Sources' + if: ${{ matrix.platform.check-sources }} + run: | + set -e + build-scripts/test-versioning.sh + python build-scripts/check_android_jni.py + python build-scripts/check_stdlib_usage.py + - name: 'Upload binary package' + uses: actions/upload-artifact@v4 + if: ${{ always() && matrix.platform.artifact != '' && (steps.package.outcome == 'success' || steps.cpactions.outcome == 'success') && (matrix.platform.enable-artifacts || steps.tests.outcome == 'failure') }} + with: + if-no-files-found: error + name: '${{ matrix.platform.artifact }}' + path: | + build/dist/SDL3* + build/include* + - name: 'Upload minidumps' + uses: actions/upload-artifact@v4 + if: ${{ always() && steps.tests.outcome == 'failure' && (matrix.platform.platform == 'msvc' || matrix.platform.platform == 'msys2') }} + with: + if-no-files-found: ignore + name: '${{ matrix.platform.artifact }}-minidumps' + path: build/**/*.dmp + - name: "Upload Android test apk's" + uses: actions/upload-artifact@v4 + if: ${{ matrix.platform.enable-artifacts && always() && matrix.platform.artifact != '' && steps.apks.outcome == 'success' }} + with: + if-no-files-found: error + name: '${{ matrix.platform.artifact }}-apks' + path: build/test/*.apk \ No newline at end of file diff --git a/libs/SDL3/.github/workflows/release.yml b/libs/SDL3/.github/workflows/release.yml new file mode 100644 index 00000000..4fbd5837 --- /dev/null +++ b/libs/SDL3/.github/workflows/release.yml @@ -0,0 +1,652 @@ +name: 'release' +run-name: 'Create SDL release artifacts for ${{ inputs.commit }}' + +on: + workflow_dispatch: + inputs: + commit: + description: 'Commit of SDL' + required: true + +jobs: + + src: + runs-on: ubuntu-latest + outputs: + project: ${{ steps.releaser.outputs.project }} + version: ${{ steps.releaser.outputs.version }} + src-tar-gz: ${{ steps.releaser.outputs.src-tar-gz }} + src-tar-xz: ${{ steps.releaser.outputs.src-tar-xz }} + src-zip: ${{ steps.releaser.outputs.src-zip }} + steps: + - name: 'Set up Python' + uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: 'Fetch build-release.py' + uses: actions/checkout@v4 + with: + sparse-checkout: 'build-scripts/build-release.py' + - name: 'Set up SDL sources' + uses: actions/checkout@v4 + with: + path: 'SDL' + fetch-depth: 0 + - name: 'Build Source archive' + id: releaser + shell: bash + run: | + python build-scripts/build-release.py \ + --actions source \ + --commit ${{ inputs.commit }} \ + --root "${{ github.workspace }}/SDL" \ + --github \ + --debug + - name: 'Store source archives' + uses: actions/upload-artifact@v4 + with: + name: sources + path: '${{ github.workspace}}/dist' + - name: 'Generate summary' + run: | + echo "Run the following commands to download all artifacts:" >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + echo "mkdir -p /tmp/${{ steps.releaser.outputs.project }}-${{ steps.releaser.outputs.version }}" >> $GITHUB_STEP_SUMMARY + echo "cd /tmp/${{ steps.releaser.outputs.project }}-${{ steps.releaser.outputs.version }}" >> $GITHUB_STEP_SUMMARY + echo "gh run -R ${{ github.repository }} download ${{ github.run_id }}" >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + + linux-verify: + needs: [src] + runs-on: ubuntu-latest + steps: + - name: 'Download source archives' + uses: actions/download-artifact@v4 + with: + name: sources + path: '${{ github.workspace }}' + - name: 'Unzip ${{ needs.src.outputs.src-zip }}' + id: zip + run: | + mkdir /tmp/zipdir + cd /tmp/zipdir + unzip "${{ github.workspace }}/${{ needs.src.outputs.src-zip }}" + echo "path=/tmp/zipdir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT + - name: 'Untar ${{ needs.src.outputs.src-tar-gz }}' + id: tar + run: | + mkdir -p /tmp/tardir + tar -C /tmp/tardir -v -x -f "${{ github.workspace }}/${{ needs.src.outputs.src-tar-gz }}" + echo "path=/tmp/tardir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT + - name: 'Compare contents of ${{ needs.src.outputs.src-zip }} and ${{ needs.src.outputs.src-tar-gz }}' + run: | + diff /tmp/zipdir /tmp/tardir + - name: 'Test versioning' + shell: bash + run: | + ${{ steps.tar.outputs.path }}/build-scripts/test-versioning.sh + - name: 'Install Linux dependencies' + run: | + sudo apt-get update -y + sudo apt-get install -y \ + gnome-desktop-testing libasound2-dev libpulse-dev libaudio-dev libjack-dev libsndio-dev \ + libusb-1.0-0-dev libx11-dev libxext-dev libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev \ + libxss-dev libwayland-dev libxkbcommon-dev libdrm-dev libgbm-dev libgl1-mesa-dev libgles2-mesa-dev \ + libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev fcitx-libs-dev + - name: 'CMake (configure + build + tests + examples)' + run: | + cmake -S ${{ steps.tar.outputs.path }} -B /tmp/build -DSDL_TEST_LIBRARY=TRUE -DSDL_TESTS=TRUE -DSDL_EXAMPLES=TRUE + cmake --build /tmp/build --verbose + ctest --test-dir /tmp/build --no-tests=error --output-on-failure + + dmg: + needs: [src] + runs-on: macos-latest + outputs: + dmg: ${{ steps.releaser.outputs.dmg }} + steps: + - name: 'Set up Python' + uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: 'Fetch build-release.py' + uses: actions/checkout@v4 + with: + sparse-checkout: 'build-scripts/build-release.py' + - name: 'Download source archives' + uses: actions/download-artifact@v4 + with: + name: sources + path: '${{ github.workspace }}' + - name: 'Untar ${{ needs.src.outputs.src-tar-gz }}' + id: tar + run: | + mkdir -p "${{ github.workspace }}/tardir" + tar -C "${{ github.workspace }}/tardir" -v -x -f "${{ github.workspace }}/${{ needs.src.outputs.src-tar-gz }}" + echo "path=${{ github.workspace }}/tardir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT + - name: 'Build SDL3.dmg' + id: releaser + shell: bash + run: | + python build-scripts/build-release.py \ + --actions dmg \ + --commit ${{ inputs.commit }} \ + --root "${{ steps.tar.outputs.path }}" \ + --github \ + --debug + - name: 'Store DMG image file' + uses: actions/upload-artifact@v4 + with: + name: dmg + path: '${{ github.workspace }}/dist' + + dmg-verify: + needs: [dmg, src] + runs-on: macos-latest + steps: + - name: 'Download source archives' + uses: actions/download-artifact@v4 + with: + name: sources + path: '${{ github.workspace }}' + - name: 'Download ${{ needs.dmg.outputs.dmg }}' + uses: actions/download-artifact@v4 + with: + name: dmg + path: '${{ github.workspace }}' + - name: 'Untar ${{ needs.src.outputs.src-tar-gz }}' + id: src + run: | + mkdir -p /tmp/tardir + tar -C /tmp/tardir -v -x -f "${{ github.workspace }}/${{ needs.src.outputs.src-tar-gz }}" + echo "path=/tmp/tardir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT + - name: 'Mount ${{ needs.dmg.outputs.dmg }}' + id: mount + run: | + hdiutil attach '${{ github.workspace }}/${{ needs.dmg.outputs.dmg }}' + mount_point="/Volumes/${{ needs.src.outputs.project }}" + if [ ! -d "$mount_point/${{ needs.src.outputs.project }}.xcframework" ]; then + echo "Cannot find ${{ needs.src.outputs.project }}.xcframework!" + exit 1 + fi + echo "mount_point=$mount_point">>$GITHUB_OUTPUT + - name: 'CMake (configure + build) Darwin' + run: | + cmake -S "${{ steps.src.outputs.path }}/cmake/test" \ + -DTEST_FULL=FALSE \ + -DTEST_STATIC=FALSE \ + -DTEST_TEST=FALSE \ + -DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount_point }}" \ + -DCMAKE_SYSTEM_NAME=Darwin \ + -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \ + -DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 \ + -Werror=dev \ + -B build_darwin + cmake --build build_darwin --config Release --verbose + + cmake -S "${{ steps.src.outputs.path }}/cmake/test" \ + -DTEST_FULL=FALSE \ + -DTEST_STATIC=FALSE \ + -DTEST_TEST=FALSE \ + -DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount_point }}/SDL3.xcframework/macos-arm64_x86_64" \ + -DCMAKE_SYSTEM_NAME=Darwin \ + -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \ + -DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 \ + -Werror=dev \ + -B build_darwin_2 + cmake --build build_darwin --config Release --verbose + - name: 'CMake (configure + build) iOS' + run: | + cmake -S "${{ steps.src.outputs.path }}/cmake/test" \ + -DTEST_FULL=FALSE \ + -DTEST_STATIC=FALSE \ + -DTEST_TEST=FALSE \ + -DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount_point }}" \ + -DCMAKE_SYSTEM_NAME=iOS \ + -DCMAKE_OSX_ARCHITECTURES="arm64" \ + -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 \ + -Werror=dev \ + -B build_ios + cmake --build build_ios --config Release --verbose + - name: 'CMake (configure + build) tvOS' + run: | + cmake -S "${{ steps.src.outputs.path }}/cmake/test" \ + -DTEST_FULL=FALSE \ + -DTEST_STATIC=FALSE \ + -DTEST_TEST=FALSE \ + -DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount_point }}" \ + -DCMAKE_SYSTEM_NAME=tvOS \ + -DCMAKE_OSX_ARCHITECTURES="arm64" \ + -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 \ + -Werror=dev \ + -B build_tvos + cmake --build build_tvos --config Release --verbose + - name: 'CMake (configure + build) iOS simulator' + run: | + sysroot=$(xcodebuild -version -sdk iphonesimulator Path) + echo "sysroot=$sysroot" + cmake -S "${{ steps.src.outputs.path }}/cmake/test" \ + -DTEST_FULL=FALSE \ + -DTEST_STATIC=FALSE \ + -DTEST_TEST=FALSE \ + -DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount_point }}" \ + -DCMAKE_SYSTEM_NAME=iOS \ + -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \ + -DCMAKE_OSX_SYSROOT="${sysroot}" \ + -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 \ + -Werror=dev \ + -B build_ios_simulator + cmake --build build_ios_simulator --config Release --verbose + - name: 'CMake (configure + build) tvOS simulator' + run: | + sysroot=$(xcodebuild -version -sdk appletvsimulator Path) + echo "sysroot=$sysroot" + cmake -S "${{ steps.src.outputs.path }}/cmake/test" \ + -DTEST_FULL=FALSE \ + -DTEST_STATIC=FALSE \ + -DTEST_TEST=FALSE \ + -DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount_point }}" \ + -DCMAKE_SYSTEM_NAME=tvOS \ + -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \ + -DCMAKE_OSX_SYSROOT="${sysroot}" \ + -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 \ + -Werror=dev \ + -B build_tvos_simulator + cmake --build build_tvos_simulator --config Release --verbose + + msvc: + needs: [src] + runs-on: windows-2019 + outputs: + VC-x86: ${{ steps.releaser.outputs.VC-x86 }} + VC-x64: ${{ steps.releaser.outputs.VC-x64 }} + VC-arm64: ${{ steps.releaser.outputs.VC-arm64 }} + VC-devel: ${{ steps.releaser.outputs.VC-devel }} + steps: + - name: 'Set up Python' + uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: 'Fetch build-release.py' + uses: actions/checkout@v4 + with: + sparse-checkout: 'build-scripts/build-release.py' + - name: 'Download source archives' + uses: actions/download-artifact@v4 + with: + name: sources + path: '${{ github.workspace }}' + - name: 'Unzip ${{ needs.src.outputs.src-zip }}' + id: zip + run: | + New-Item C:\temp -ItemType Directory -ErrorAction SilentlyContinue + cd C:\temp + unzip "${{ github.workspace }}/${{ needs.src.outputs.src-zip }}" + echo "path=C:\temp\${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$Env:GITHUB_OUTPUT + - name: 'Build MSVC binary archives' + id: releaser + run: | + python build-scripts/build-release.py ` + --actions msvc ` + --commit ${{ inputs.commit }} ` + --root "${{ steps.zip.outputs.path }}" ` + --github ` + --debug + - name: 'Store MSVC archives' + uses: actions/upload-artifact@v4 + with: + name: win32 + path: '${{ github.workspace }}/dist' + + msvc-verify: + needs: [msvc, src] + runs-on: windows-latest + steps: + - name: 'Fetch .github/actions/setup-ninja/action.yml' + uses: actions/checkout@v4 + with: + sparse-checkout: '.github/actions/setup-ninja/action.yml' + - name: 'Download source archives' + uses: actions/download-artifact@v4 + with: + name: sources + path: '${{ github.workspace }}' + - name: 'Download MSVC binaries' + uses: actions/download-artifact@v4 + with: + name: win32 + path: '${{ github.workspace }}' + - name: 'Unzip ${{ needs.src.outputs.src-zip }}' + id: src + run: | + mkdir '${{ github.workspace }}/sources' + cd '${{ github.workspace }}/sources' + unzip "${{ github.workspace }}/${{ needs.src.outputs.src-zip }}" + echo "path=${{ github.workspace }}/sources/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$env:GITHUB_OUTPUT + - name: 'Unzip ${{ needs.msvc.outputs.VC-devel }}' + id: bin + run: | + mkdir '${{ github.workspace }}/vc' + cd '${{ github.workspace }}/vc' + unzip "${{ github.workspace }}/${{ needs.msvc.outputs.VC-devel }}" + echo "path=${{ github.workspace }}/vc/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$env:GITHUB_OUTPUT + - name: Set up ninja + uses: ./.github/actions/setup-ninja + - name: 'Configure vcvars x86' + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: x64_x86 + - name: 'CMake (configure + build + tests) x86' + run: | + cmake -S "${{ steps.src.outputs.path }}/cmake/test" ` + -B build_x86 ` + -GNinja ` + -DCMAKE_BUILD_TYPE=Debug ` + -Werror=dev ` + -DTEST_FULL=TRUE ` + -DTEST_STATIC=FALSE ` + -DTEST_SHARED=TRUE ` + -DTEST_TEST=TRUE ` + -DCMAKE_SUPPRESS_REGENERATION=TRUE ` + -DCMAKE_PREFIX_PATH="${{ steps.bin.outputs.path }}" + Start-Sleep -Seconds 2 + cmake --build build_x86 --config Release --verbose + ctest --test-dir build_x86 --no-tests=error -C Release --output-on-failure + - name: 'Configure vcvars x64' + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: x64 + - name: 'CMake (configure + build + tests) x64' + run: | + cmake -S "${{ steps.src.outputs.path }}/cmake/test" ` + -B build_x64 ` + -GNinja ` + -DCMAKE_BUILD_TYPE=Debug ` + -Werror=dev ` + -DTEST_FULL=TRUE ` + -DTEST_STATIC=FALSE ` + -DTEST_SHARED=TRUE ` + -DTEST_TEST=TRUE ` + -DCMAKE_SUPPRESS_REGENERATION=TRUE ` + -DCMAKE_PREFIX_PATH="${{ steps.bin.outputs.path }}" + Start-Sleep -Seconds 2 + cmake --build build_x64 --config Release --verbose + ctest --test-dir build_x64 --no-tests=error -C Release --output-on-failure + - name: 'Configure vcvars arm64' + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: x64_arm64 + - name: 'CMake (configure + build) arm64' + run: | + cmake -S "${{ steps.src.outputs.path }}/cmake/test" ` + -B build_arm64 ` + -GNinja ` + -DCMAKE_BUILD_TYPE=Debug ` + -Werror=dev ` + -DTEST_FULL=TRUE ` + -DTEST_STATIC=FALSE ` + -DTEST_SHARED=TRUE ` + -DTEST_TEST=TRUE ` + -DCMAKE_SUPPRESS_REGENERATION=TRUE ` + -DCMAKE_PREFIX_PATH="${{ steps.bin.outputs.path }}" + Start-Sleep -Seconds 2 + cmake --build build_arm64 --config Release --verbose + - name: 'CMake (configure + build) arm64ec' + run: | + cmake -S "${{ steps.src.outputs.path }}/cmake/test" ` + -B build_arm64ec ` + -GNinja ` + -DCMAKE_BUILD_TYPE=Debug ` + -Werror=dev ` + -DTEST_FULL=TRUE ` + -DTEST_STATIC=FALSE ` + -DTEST_SHARED=TRUE ` + -DTEST_TEST=TRUE ` + -DSDL_DISABLE_AVX=TRUE ` + -DSDL_DISABLE_AVX2=TRUE ` + -DSDL_DISABLE_AVX512F=TRUE ` + -DCMAKE_SUPPRESS_REGENERATION=TRUE ` + -DCMAKE_C_FLAGS="/arm64EC" ` + -DCMAKE_CXX_FLAGS="/arm64EC" ` + -DCMAKE_EXE_LINKER_FLAGS="/MACHINE:ARM64EC" ` + -DCMAKE_SHARED_LINKER_FLAGS="/MACHINE:ARM64EC" ` + -DCMAKE_STATIC_LINKER_FLAGS="/MACHINE:ARM64EC" ` + -DCMAKE_PREFIX_PATH="${{ steps.bin.outputs.path }}" + Start-Sleep -Seconds 2 + cmake --build build_arm64ec --config Release --verbose + + mingw: + needs: [src] + runs-on: ubuntu-24.04 # FIXME: current ubuntu-latest ships an outdated mingw, replace with ubuntu-latest once 24.04 becomes the new default + outputs: + mingw-devel-tar-gz: ${{ steps.releaser.outputs.mingw-devel-tar-gz }} + mingw-devel-tar-xz: ${{ steps.releaser.outputs.mingw-devel-tar-xz }} + steps: + - name: 'Set up Python' + uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: 'Fetch build-release.py' + uses: actions/checkout@v4 + with: + sparse-checkout: 'build-scripts/build-release.py' + - name: 'Install Mingw toolchain' + run: | + sudo apt-get update -y + sudo apt-get install -y gcc-mingw-w64 g++-mingw-w64 ninja-build + - name: 'Download source archives' + uses: actions/download-artifact@v4 + with: + name: sources + path: '${{ github.workspace }}' + - name: 'Untar ${{ needs.src.outputs.src-tar-gz }}' + id: tar + run: | + mkdir -p /tmp/tardir + tar -C /tmp/tardir -v -x -f "${{ github.workspace }}/${{ needs.src.outputs.src-tar-gz }}" + echo "path=/tmp/tardir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT + - name: 'Build MinGW binary archives' + id: releaser + run: | + python build-scripts/build-release.py \ + --actions mingw \ + --commit ${{ inputs.commit }} \ + --root "${{ steps.tar.outputs.path }}" \ + --github \ + --debug + - name: 'Store MinGW archives' + uses: actions/upload-artifact@v4 + with: + name: mingw + path: '${{ github.workspace }}/dist' + + mingw-verify: + needs: [mingw, src] + runs-on: ubuntu-latest + steps: + - name: 'Install Mingw toolchain' + run: | + sudo apt-get update -y + sudo apt-get install -y gcc-mingw-w64 g++-mingw-w64 ninja-build + - name: 'Download source archives' + uses: actions/download-artifact@v4 + with: + name: sources + path: '${{ github.workspace }}' + - name: 'Download MinGW binaries' + uses: actions/download-artifact@v4 + with: + name: mingw + path: '${{ github.workspace }}' + - name: 'Untar ${{ needs.src.outputs.src-tar-gz }}' + id: src + run: | + mkdir -p /tmp/tardir + tar -C /tmp/tardir -v -x -f "${{ github.workspace }}/${{ needs.src.outputs.src-tar-gz }}" + echo "path=/tmp/tardir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT + - name: 'Untar ${{ needs.mingw.outputs.mingw-devel-tar-gz }}' + id: bin + run: | + mkdir -p /tmp/mingw-tardir + tar -C /tmp/mingw-tardir -v -x -f "${{ github.workspace }}/${{ needs.mingw.outputs.mingw-devel-tar-gz }}" + echo "path=/tmp/mingw-tardir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT + - name: 'CMake (configure + build) i686' + run: | + cmake -S "${{ steps.src.outputs.path }}/cmake/test" \ + -DCMAKE_BUILD_TYPE="Release" \ + -DTEST_FULL=TRUE \ + -DTEST_STATIC=FALSE \ + -DTEST_TEST=TRUE \ + -DCMAKE_PREFIX_PATH="${{ steps.bin.outputs.path }}" \ + -DCMAKE_TOOLCHAIN_FILE="${{ steps.src.outputs.path }}/build-scripts/cmake-toolchain-mingw64-i686.cmake" \ + -DCMAKE_C_FLAGS="-DSDL_DISABLE_SSE4_2" \ + -Werror=dev \ + -B build_x86 + cmake --build build_x86 --config Release --verbose + - name: 'CMake (configure + build) x86_64' + run: | + cmake -S "${{ steps.src.outputs.path }}/cmake/test" \ + -DCMAKE_BUILD_TYPE="Release" \ + -DTEST_FULL=TRUE \ + -DTEST_STATIC=false \ + -DTEST_TEST=TRUE \ + -DCMAKE_PREFIX_PATH="${{ steps.bin.outputs.path }}" \ + -DCMAKE_TOOLCHAIN_FILE="${{ steps.src.outputs.path }}/build-scripts/cmake-toolchain-mingw64-x86_64.cmake" \ + -DCMAKE_C_FLAGS="-DSDL_DISABLE_SSE4_2" \ + -Werror=dev \ + -B build_x64 + cmake --build build_x64 --config Release --verbose + + android: + needs: [src] + runs-on: ubuntu-latest + outputs: + android-aar: ${{ steps.releaser.outputs.android-aar }} + steps: + - name: 'Set up Python' + uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: 'Fetch build-release.py' + uses: actions/checkout@v4 + with: + sparse-checkout: 'build-scripts/build-release.py' + - name: 'Setup Android NDK' + uses: nttld/setup-ndk@v1 + with: + local-cache: true + ndk-version: r21e + - name: 'Setup Java JDK' + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '11' + - name: 'Install ninja' + run: | + sudo apt-get update -y + sudo apt-get install -y ninja-build + - name: 'Download source archives' + uses: actions/download-artifact@v4 + with: + name: sources + path: '${{ github.workspace }}' + - name: 'Untar ${{ needs.src.outputs.src-tar-gz }}' + id: tar + run: | + mkdir -p /tmp/tardir + tar -C /tmp/tardir -v -x -f "${{ github.workspace }}/${{ needs.src.outputs.src-tar-gz }}" + echo "path=/tmp/tardir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT + - name: 'Build Android prefab binary archive(s)' + id: releaser + run: | + python build-scripts/build-release.py \ + --actions android \ + --commit ${{ inputs.commit }} \ + --root "${{ steps.tar.outputs.path }}" \ + --github \ + --debug + - name: 'Store Android archive(s)' + uses: actions/upload-artifact@v4 + with: + name: android + path: '${{ github.workspace }}/dist' + + android-verify: + needs: [android, src] + runs-on: ubuntu-latest + steps: + - name: 'Set up Python' + uses: actions/setup-python@v5 + with: + python-version: '3.11' + - uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' + - name: 'Download source archives' + uses: actions/download-artifact@v4 + with: + name: sources + path: '${{ github.workspace }}' + - name: 'Download Android .aar archive' + uses: actions/download-artifact@v4 + with: + name: android + path: '${{ github.workspace }}' + - name: 'Untar ${{ needs.src.outputs.src-tar-gz }}' + id: src + run: | + mkdir -p /tmp/tardir + tar -C /tmp/tardir -v -x -f "${{ github.workspace }}/${{ needs.src.outputs.src-tar-gz }}" + echo "path=/tmp/tardir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT + - name: 'Extract Android SDK from AAR' + id: sdk + run: | + cd /tmp + unzip "${{ github.workspace }}/${{ needs.android.outputs.android-aar }}" + python "${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}.aar" -o /tmp/SDL3-android + echo "prefix=/tmp/SDL3-android" >>$GITHUB_OUTPUT + echo "sdl3-aar=/tmp/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}.aar" >>$GITHUB_OUTPUT + - name: 'CMake (configure + build) x86, x64, arm32, arm64' + run: | + android_abis="x86 x86_64 armeabi-v7a arm64-v8a" + for android_abi in ${android_abis}; do + echo "Configuring ${android_abi}..." + cmake -S "${{ steps.src.outputs.path }}/cmake/test" \ + -DTEST_FULL=TRUE \ + -DTEST_STATIC=FALSE \ + -DTEST_TEST=TRUE \ + -DCMAKE_PREFIX_PATH="${{ steps.sdk.outputs.prefix }}" \ + -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake \ + -DANDROID_ABI=${android_abi} \ + -DCMAKE_BUILD_TYPE=Release \ + -B "${android_abi}" + echo "Building ${android_abi}..." + cmake --build "${android_abi}" --config Release --verbose + done + - name: 'Create gradle project' + id: create-gradle-project + run: | + python ${{ steps.src.outputs.path }}/build-scripts/create-android-project.py \ + org.libsdl.testspriteminimal \ + ${{ steps.src.outputs.path }}/test/testspriteminimal.c \ + ${{ steps.src.outputs.path }}/test/icon.h \ + --variant aar \ + --output "/tmp/projects" + echo "path=/tmp/projects/org.libsdl.testspriteminimal" >>$GITHUB_OUTPUT + - name: 'Copy SDL3 aar into Gradle project' + run: | + cp "${{ steps.sdk.outputs.sdl3-aar }}" "${{ steps.create-gradle-project.outputs.path }}/app/libs" + + echo "" + echo "Project contents:" + echo "" + find "${{ steps.create-gradle-project.outputs.path }}" + - name: 'Build app (Gradle & CMake)' + run: | + cd "${{ steps.create-gradle-project.outputs.path }}" + ./gradlew -i assembleRelease -Pandroid.native.buildOutput=verbose -PBUILD_WITH_CMAKE=1 + - name: 'Build app (Gradle & ndk-build)' + run: | + cd "${{ steps.create-gradle-project.outputs.path }}" + ./gradlew -i assembleRelease -Pandroid.native.buildOutput=verbose diff --git a/libs/SDL3/.gitignore b/libs/SDL3/.gitignore new file mode 100644 index 00000000..394f4b84 --- /dev/null +++ b/libs/SDL3/.gitignore @@ -0,0 +1,178 @@ +build/ +build-*/ +!build-scripts/ +buildbot/ +/VERSION.txt +__pycache__ + +*.so +*.so.* +*.dll +*.exe +*.o +*.obj +*.res +*.lib +*.a +*.la +*.dSYM +*,e1f +*,ff8 +*.lnk +*.err +*.exp +*.map +*.orig +*~ +*.swp +*.tmp +*.rej + +# for CMake +.cmake +CMakeFiles/ +CMakeCache.txt +cmake_install.cmake +cmake_uninstall.cmake +install_manifest.txt +*Targets.cmake +*Config.cmake +*ConfigVersion.cmake +CTestTestfile.cmake +Testing +compile_commands.json +.cache/ +/include-config-* +/include-revision +/Makefile +.ninja_* +*.ninja +*.pc +test/*.test +wayland-generated-protocols + +# for CLion +.idea +cmake-build-* + +# for Xcode +*.mode1* +*.perspective* +*.pbxuser +(^|/)build($|/) +.DS_Store +xcuserdata +*.xcworkspace +Xcode/build.xcconfig + +# for Visual Studio Code +.vscode/ + +# for Visual C++ +.vs +Debug +Release +*.user +*.ncb +*.suo +*.sdf +VisualC/tests/gamepadmap/axis.bmp +VisualC/tests/gamepadmap/button.bmp +VisualC/tests/gamepadmap/gamepadmap.bmp +VisualC/tests/gamepadmap/gamepadmap_back.bmp +VisualC/tests/loopwave/sample.wav +VisualC/tests/testautomation/*.bmp +VisualC/tests/testgamepad/axis.bmp +VisualC/tests/testgamepad/button.bmp +VisualC/tests/testgamepad/gamepadmap.bmp +VisualC/tests/testgamepad/gamepadmap_back.bmp +VisualC/tests/testoverlay/moose.dat +VisualC/tests/testrendertarget/icon.bmp +VisualC/tests/testrendertarget/sample.bmp +VisualC/tests/testscale/icon.bmp +VisualC/tests/testscale/sample.bmp +VisualC/tests/testsprite/icon.bmp +VisualC/tests/testyuv/testyuv.bmp +VisualC-GDK/**/Layout +src/render/direct3d12/D3D12_*_One.h +src/render/direct3d12/D3D12_*_Series.h +src/gpu/d3d12/D3D12_*_One.h +src/gpu/d3d12/D3D12_*_Series.h + +# for Android +android-project/local.properties +android-project/.gradle/ + +test/checkkeys +test/checkkeysthreads +test/gamepadmap +test/loopwave +test/loopwavequeue +test/testatomic +test/testaudiorecording +test/testaudiohotplug +test/testaudioinfo +test/testautomation +test/testbounds +test/testcustomcursor +test/testdisplayinfo +test/testdraw +test/testdrawchessboard +test/testdropfile +test/testerror +test/testevdev +test/testfile +test/testfilesystem +test/testgamepad +test/testgeometry +test/testgesture +test/testgl +test/testgles +test/testgles2 +test/testhaptic +test/testhittesting +test/testhotplug +test/testiconv +test/testime +test/testintersections +test/testjoystick +test/testkeys +test/testloadso +test/testlocale +test/testlock +test/testmessage +test/testmouse +test/testmultiaudio +test/testnative +test/testoverlay +test/testplatform +test/testpower +test/testqsort +test/testrelative +test/testrendercopyex +test/testrendertarget +test/testresample +test/testrumble +test/testscale +test/testsem +test/testsensor +test/testshader +test/testshape +test/testsprite +test/testspriteminimal +test/teststreaming +test/testsurround +test/testthread +test/testtimer +test/testurl +test/testver +test/testviewport +test/testvulkan +test/testwm +test/testyuv +test/torturethread + +# for Doxygen +docs/output +SDL.tag +doxygen_warn.txt diff --git a/libs/SDL3/.wikiheaders-options b/libs/SDL3/.wikiheaders-options index 11f66687..9c2b5bb9 100644 --- a/libs/SDL3/.wikiheaders-options +++ b/libs/SDL3/.wikiheaders-options @@ -14,7 +14,7 @@ projecturl = https://libsdl.org/ wikiurl = https://wiki.libsdl.org bugreporturl = https://github.com/libsdl-org/sdlwiki/issues/new warn_about_missing = 0 -wikipreamble = (This is the documentation for SDL3, which is the current stable version. [SDL2](https://wiki.libsdl.org/SDL2/) was the previous version!) +#wikipreamble = (This is the documentation for SDL3, which is the current stable version. [SDL2](https://wiki.libsdl.org/SDL2/) was the previous version!) wikiheaderfiletext = Defined in [](https://github.com/libsdl-org/SDL/blob/main/include/SDL3/%fname%) manpageheaderfiletext = Defined in SDL3/%fname% diff --git a/libs/SDL3/CMakeLists.txt b/libs/SDL3/CMakeLists.txt index ef42f644..62a6e460 100644 --- a/libs/SDL3/CMakeLists.txt +++ b/libs/SDL3/CMakeLists.txt @@ -5,7 +5,7 @@ if(NOT DEFINED CMAKE_BUILD_TYPE) endif() # See docs/release_checklist.md -project(SDL3 LANGUAGES C VERSION "3.2.0") +project(SDL3 LANGUAGES C VERSION "3.2.6") if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) set(SDL3_MAINPROJECT ON) @@ -13,6 +13,12 @@ else() set(SDL3_MAINPROJECT OFF) endif() +# Add UTF-8 encoding support for MSVC compiler. +# This ensures that the MSVC compiler interprets source files as UTF-8 encoded, +# which is useful for projects containing non-ASCII characters in source files. +add_compile_options("$<$:/utf-8>") +add_compile_options("$<$:/utf-8>") + # By default, configure SDL3 in RelWithDebInfo configuration if(SDL3_MAINPROJECT) get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) @@ -237,6 +243,8 @@ if(SDL_SHARED_DEFAULT AND SDL_STATIC_DEFAULT AND SDL_SHARED_AVAILABLE) endif() endif() +dep_option(SDL_DEPS_SHARED "Load dependencies dynamically" ON SDL_SHARED_AVAILABLE OFF) + set(SDL_SUBSYSTEMS ) macro(define_sdl_subsystem _name) @@ -328,19 +336,19 @@ set_option(SDL_PTHREADS "Use POSIX threads for multi-threading" ${SDL dep_option(SDL_PTHREADS_SEM "Use pthread semaphores" ON "SDL_PTHREADS" OFF) dep_option(SDL_OSS "Support the OSS audio API" ${SDL_OSS_DEFAULT} "UNIX_SYS OR RISCOS;SDL_AUDIO" OFF) dep_option(SDL_ALSA "Support the ALSA audio API" ${UNIX_SYS} "SDL_AUDIO" OFF) -dep_option(SDL_ALSA_SHARED "Dynamically load ALSA audio support" ON "SDL_ALSA" OFF) +dep_option(SDL_ALSA_SHARED "Dynamically load ALSA audio support" ON "SDL_ALSA;SDL_DEPS_SHARED" OFF) dep_option(SDL_JACK "Support the JACK audio API" ${UNIX_SYS} "SDL_AUDIO" OFF) -dep_option(SDL_JACK_SHARED "Dynamically load JACK audio support" ON "SDL_JACK" OFF) +dep_option(SDL_JACK_SHARED "Dynamically load JACK audio support" ON "SDL_JACK;SDL_DEPS_SHARED" OFF) set_option(SDL_PIPEWIRE "Use Pipewire audio" ${UNIX_SYS}) -dep_option(SDL_PIPEWIRE_SHARED "Dynamically load Pipewire support" ON "SDL_PIPEWIRE" OFF) +dep_option(SDL_PIPEWIRE_SHARED "Dynamically load Pipewire support" ON "SDL_PIPEWIRE;SDL_DEPS_SHARED" OFF) dep_option(SDL_PULSEAUDIO "Use PulseAudio" ${UNIX_SYS} "SDL_AUDIO" OFF) -dep_option(SDL_PULSEAUDIO_SHARED "Dynamically load PulseAudio support" ON "SDL_PULSEAUDIO" OFF) +dep_option(SDL_PULSEAUDIO_SHARED "Dynamically load PulseAudio support" ON "SDL_PULSEAUDIO;SDL_DEPS_SHARED" OFF) dep_option(SDL_SNDIO "Support the sndio audio API" ${UNIX_SYS} "SDL_AUDIO" OFF) -dep_option(SDL_SNDIO_SHARED "Dynamically load the sndio audio API" ON "SDL_SNDIO" OFF) +dep_option(SDL_SNDIO_SHARED "Dynamically load the sndio audio API" ON "SDL_SNDIO;SDL_DEPS_SHARED" OFF) set_option(SDL_RPATH "Use an rpath when linking SDL" ${SDL_RPATH_DEFAULT}) set_option(SDL_CLOCK_GETTIME "Use clock_gettime() instead of gettimeofday()" ${SDL_CLOCK_GETTIME_DEFAULT}) dep_option(SDL_X11 "Use X11 video driver" ${UNIX_SYS} "SDL_VIDEO" OFF) -dep_option(SDL_X11_SHARED "Dynamically load X11 support" ON "SDL_X11" OFF) +dep_option(SDL_X11_SHARED "Dynamically load X11 support" ON "SDL_X11;SDL_DEPS_SHARED" OFF) dep_option(SDL_X11_XCURSOR "Enable Xcursor support" ON SDL_X11 OFF) dep_option(SDL_X11_XDBE "Enable Xdbe support" ON SDL_X11 OFF) dep_option(SDL_X11_XINPUT "Enable XInput support" ON SDL_X11 OFF) @@ -350,9 +358,9 @@ dep_option(SDL_X11_XSCRNSAVER "Enable Xscrnsaver support" ON SDL_X11 OFF) dep_option(SDL_X11_XSHAPE "Enable XShape support" ON SDL_X11 OFF) dep_option(SDL_X11_XSYNC "Enable Xsync support" ON SDL_X11 OFF) dep_option(SDL_WAYLAND "Use Wayland video driver" ${UNIX_SYS} "SDL_VIDEO" OFF) -dep_option(SDL_WAYLAND_SHARED "Dynamically load Wayland support" ON "SDL_WAYLAND" OFF) +dep_option(SDL_WAYLAND_SHARED "Dynamically load Wayland support" ON "SDL_WAYLAND;SDL_DEPS_SHARED" OFF) dep_option(SDL_WAYLAND_LIBDECOR "Use client-side window decorations on Wayland" ON "SDL_WAYLAND" OFF) -dep_option(SDL_WAYLAND_LIBDECOR_SHARED "Dynamically load libdecor support" ON "SDL_WAYLAND_LIBDECOR;SDL_WAYLAND_SHARED" OFF) +dep_option(SDL_WAYLAND_LIBDECOR_SHARED "Dynamically load libdecor support" ON "SDL_WAYLAND_LIBDECOR;SDL_WAYLAND_SHARED;SDL_DEPS_SHARED" OFF) dep_option(SDL_RPI "Use Raspberry Pi video driver" ON "SDL_VIDEO;UNIX_SYS;SDL_CPU_ARM32 OR SDL_CPU_ARM64" OFF) dep_option(SDL_ROCKCHIP "Use ROCKCHIP Hardware Acceleration video driver" ON "SDL_VIDEO;UNIX_SYS;SDL_CPU_ARM32 OR SDL_CPU_ARM64" OFF) dep_option(SDL_COCOA "Use Cocoa video driver" ON "APPLE" OFF) @@ -370,14 +378,14 @@ dep_option(SDL_RENDER_VULKAN "Enable the Vulkan render driver" ON "SDL_REN dep_option(SDL_METAL "Enable Metal support" ON "APPLE" OFF) set_option(SDL_OPENVR "Use OpenVR video driver" OFF) dep_option(SDL_KMSDRM "Use KMS DRM video driver" ${UNIX_SYS} "SDL_VIDEO" OFF) -dep_option(SDL_KMSDRM_SHARED "Dynamically load KMS DRM support" ON "SDL_KMSDRM" OFF) +dep_option(SDL_KMSDRM_SHARED "Dynamically load KMS DRM support" ON "SDL_KMSDRM;SDL_DEPS_SHARED" OFF) set_option(SDL_OFFSCREEN "Use offscreen video driver" ON) dep_option(SDL_DUMMYCAMERA "Support the dummy camera driver" ON SDL_CAMERA OFF) option_string(SDL_BACKGROUNDING_SIGNAL "number to use for magic backgrounding signal or 'OFF'" OFF) option_string(SDL_FOREGROUNDING_SIGNAL "number to use for magic foregrounding signal or 'OFF'" OFF) dep_option(SDL_HIDAPI "Enable the HIDAPI subsystem" ON "NOT VISIONOS" OFF) dep_option(SDL_HIDAPI_LIBUSB "Use libusb for low level joystick drivers" ON SDL_HIDAPI_LIBUSB_AVAILABLE OFF) -dep_option(SDL_HIDAPI_LIBUSB_SHARED "Dynamically load libusb support" ON SDL_HIDAPI_LIBUSB OFF) +dep_option(SDL_HIDAPI_LIBUSB_SHARED "Dynamically load libusb support" ON "SDL_HIDAPI_LIBUSB;SDL_DEPS_SHARED" OFF) dep_option(SDL_HIDAPI_JOYSTICK "Use HIDAPI for low level joystick drivers" ON SDL_HIDAPI OFF) dep_option(SDL_VIRTUAL_JOYSTICK "Enable the virtual-joystick driver" ON SDL_HIDAPI OFF) set_option(SDL_LIBUDEV "Enable libudev support" ON) @@ -745,7 +753,7 @@ if(SDL_ASSEMBLY) if(SDL_SSE4_2) cmake_push_check_state() if(USE_GCC OR USE_CLANG OR USE_INTELCC) - string(APPEND CMAKE_REQUIRED_FLAGS " -msse4.2") + string(APPEND CMAKE_REQUIRED_FLAGS " -msse4.2 -mcrc32") endif() check_c_source_compiles(" #include @@ -2881,6 +2889,7 @@ elseif(N3DS) set(SDL_THREAD_N3DS 1) sdl_glob_sources("${SDL3_SOURCE_DIR}/src/thread/n3ds/*.c") sdl_sources( + "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_syscond.c" "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_systls.c" "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_sysrwlock.c" ) diff --git a/libs/SDL3/REVISION.txt b/libs/SDL3/REVISION.txt deleted file mode 100644 index dd04808f..00000000 --- a/libs/SDL3/REVISION.txt +++ /dev/null @@ -1 +0,0 @@ -release-3.2.0-0-g535d80bad diff --git a/libs/SDL3/VisualC-GDK/SDL/SDL.vcxproj b/libs/SDL3/VisualC-GDK/SDL/SDL.vcxproj index 07a9b3be..5bf00043 100644 --- a/libs/SDL3/VisualC-GDK/SDL/SDL.vcxproj +++ b/libs/SDL3/VisualC-GDK/SDL/SDL.vcxproj @@ -115,6 +115,7 @@ .\Debug/SDL.tlb + %(AdditionalOptions) /utf-8 Disabled $(ProjectDir)\..\..\include;$(ProjectDir)\..\..\include\build_config;$(ProjectDir)\..\..\src;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -145,6 +146,7 @@ .\Debug/SDL.tlb + %(AdditionalOptions) /utf-8 Disabled $(ProjectDir)\..\..\include;$(ProjectDir)\..\..\include\build_config;$(ProjectDir)\..\..\src;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -182,6 +184,7 @@ .\Debug/SDL.tlb + %(AdditionalOptions) /utf-8 Disabled $(ProjectDir)\..\..\include;$(ProjectDir)\..\..\include\build_config;$(ProjectDir)\..\..\src;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -219,6 +222,7 @@ .\Release/SDL.tlb + %(AdditionalOptions) /utf-8 $(ProjectDir)\..\..\include;$(ProjectDir)\..\..\include\build_config;$(ProjectDir)\..\..\src;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) DLL_EXPORT;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -250,6 +254,7 @@ .\Release/SDL.tlb + %(AdditionalOptions) /utf-8 $(ProjectDir)\..\..\include;$(ProjectDir)\..\..\include\build_config;$(ProjectDir)\..\..\src;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) DLL_EXPORT;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -288,6 +293,7 @@ .\Release/SDL.tlb + %(AdditionalOptions) /utf-8 $(ProjectDir)\..\..\include;$(ProjectDir)\..\..\include\build_config;$(ProjectDir)\..\..\src;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) DLL_EXPORT;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -320,6 +326,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) @@ -418,6 +425,7 @@ + @@ -434,6 +442,7 @@ + @@ -587,6 +596,7 @@ + @@ -633,6 +643,7 @@ + @@ -666,6 +677,7 @@ + @@ -861,6 +873,7 @@ + diff --git a/libs/SDL3/VisualC-GDK/SDL/SDL.vcxproj.filters b/libs/SDL3/VisualC-GDK/SDL/SDL.vcxproj.filters index 247bbdc0..f760877e 100644 --- a/libs/SDL3/VisualC-GDK/SDL/SDL.vcxproj.filters +++ b/libs/SDL3/VisualC-GDK/SDL/SDL.vcxproj.filters @@ -27,6 +27,7 @@ + @@ -38,6 +39,7 @@ + @@ -175,6 +177,7 @@ + @@ -314,6 +317,7 @@ + @@ -330,6 +334,7 @@ + @@ -434,6 +439,7 @@ + diff --git a/libs/SDL3/VisualC-GDK/SDL_test/SDL_test.vcxproj b/libs/SDL3/VisualC-GDK/SDL_test/SDL_test.vcxproj index 7505baf8..8d5106cb 100644 --- a/libs/SDL3/VisualC-GDK/SDL_test/SDL_test.vcxproj +++ b/libs/SDL3/VisualC-GDK/SDL_test/SDL_test.vcxproj @@ -103,6 +103,7 @@ + %(AdditionalOptions) /utf-8 $(ProjectDir)/../../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -117,6 +118,7 @@ + %(AdditionalOptions) /utf-8 $(ProjectDir)/../../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -131,6 +133,7 @@ + %(AdditionalOptions) /utf-8 $(ProjectDir)/../../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -145,6 +148,7 @@ + %(AdditionalOptions) /utf-8 Disabled $(ProjectDir)/../../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -159,6 +163,7 @@ + %(AdditionalOptions) /utf-8 Disabled $(ProjectDir)/../../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -173,6 +178,7 @@ + %(AdditionalOptions) /utf-8 Disabled $(ProjectDir)/../../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -186,6 +192,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/VisualC-GDK/tests/testcontroller/testcontroller.vcxproj b/libs/SDL3/VisualC-GDK/tests/testcontroller/testcontroller.vcxproj index d7ad95cf..f600ce20 100644 --- a/libs/SDL3/VisualC-GDK/tests/testcontroller/testcontroller.vcxproj +++ b/libs/SDL3/VisualC-GDK/tests/testcontroller/testcontroller.vcxproj @@ -121,6 +121,7 @@ .\Release/testcontroller.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -144,6 +145,7 @@ .\Release/testcontroller.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -167,6 +169,7 @@ .\Release/testcontroller.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -190,6 +193,7 @@ .\Debug/testcontroller.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -216,6 +220,7 @@ .\Debug/testcontroller.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -242,6 +247,7 @@ .\Debug/testcontroller.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -262,6 +268,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/VisualC-GDK/tests/testgdk/src/testgdk.cpp b/libs/SDL3/VisualC-GDK/tests/testgdk/src/testgdk.cpp index d2a92091..51fc75bc 100644 --- a/libs/SDL3/VisualC-GDK/tests/testgdk/src/testgdk.cpp +++ b/libs/SDL3/VisualC-GDK/tests/testgdk/src/testgdk.cpp @@ -198,7 +198,7 @@ LoadSprite(const char *file) return -1; } if (!SDL_SetTextureBlendMode(sprites[i], blendMode)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set blend mode: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set blend mode: %s", SDL_GetError()); SDL_DestroyTexture(sprites[i]); return -1; } @@ -405,7 +405,7 @@ main(int argc, char *argv[]) sprites = (SDL_Texture **) SDL_malloc(state->num_windows * sizeof(*sprites)); if (!sprites) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!"); quit(2); } for (i = 0; i < state->num_windows; ++i) { @@ -420,13 +420,13 @@ main(int argc, char *argv[]) soundname = GetResourceFilename(argc > 1 ? argv[1] : NULL, "sample.wav"); if (!soundname) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s", SDL_GetError()); quit(1); } /* Load the wave file into memory */ if (!SDL_LoadWAV(soundname, &wave.spec, &wave.sound, &wave.soundlen)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s\n", soundname, SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s", soundname, SDL_GetError()); quit(1); } @@ -436,11 +436,11 @@ main(int argc, char *argv[]) SDL_Log("%i: %s", i, SDL_GetAudioDriver(i)); } - SDL_Log("Using audio driver: %s\n", SDL_GetCurrentAudioDriver()); + SDL_Log("Using audio driver: %s", SDL_GetCurrentAudioDriver()); stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &wave.spec, NULL, NULL); if (!stream) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create audio stream: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create audio stream: %s", SDL_GetError()); return -1; } SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(stream)); diff --git a/libs/SDL3/VisualC-GDK/tests/testgdk/testgdk.vcxproj b/libs/SDL3/VisualC-GDK/tests/testgdk/testgdk.vcxproj index 41293cad..c16fadef 100644 --- a/libs/SDL3/VisualC-GDK/tests/testgdk/testgdk.vcxproj +++ b/libs/SDL3/VisualC-GDK/tests/testgdk/testgdk.vcxproj @@ -121,6 +121,7 @@ .\Release/testsprite.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -148,6 +149,7 @@ .\Release/testsprite.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -175,6 +177,7 @@ .\Release/testsprite.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -202,6 +205,7 @@ .\Debug/testsprite.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -232,6 +236,7 @@ .\Debug/testsprite.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -262,6 +267,7 @@ .\Debug/testsprite.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -286,6 +292,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/VisualC-GDK/tests/testsprite/testsprite.vcxproj b/libs/SDL3/VisualC-GDK/tests/testsprite/testsprite.vcxproj index 3885aec2..15ea690a 100644 --- a/libs/SDL3/VisualC-GDK/tests/testsprite/testsprite.vcxproj +++ b/libs/SDL3/VisualC-GDK/tests/testsprite/testsprite.vcxproj @@ -121,6 +121,7 @@ .\Release/testsprite.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -148,6 +149,7 @@ .\Release/testsprite.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -175,6 +177,7 @@ .\Release/testsprite.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -202,6 +205,7 @@ .\Debug/testsprite.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -232,6 +236,7 @@ .\Debug/testsprite.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -262,6 +267,7 @@ .\Debug/testsprite.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -286,6 +292,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/VisualC/SDL/Directory.Build.props b/libs/SDL3/VisualC/SDL/Directory.Build.props new file mode 100644 index 00000000..24033f43 --- /dev/null +++ b/libs/SDL3/VisualC/SDL/Directory.Build.props @@ -0,0 +1,8 @@ + + + + + SDL_VENDOR_INFO="libsdl.org";%(PreprocessorDefinitions) + + + diff --git a/libs/SDL3/VisualC/SDL/SDL.vcxproj b/libs/SDL3/VisualC/SDL/SDL.vcxproj index 134c730c..a15978a2 100644 --- a/libs/SDL3/VisualC/SDL/SDL.vcxproj +++ b/libs/SDL3/VisualC/SDL/SDL.vcxproj @@ -106,6 +106,7 @@ .\Debug/SDL.tlb + %(AdditionalOptions) /utf-8 Disabled $(ProjectDir)/../../include;$(ProjectDir)/../../include/build_config;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -139,6 +140,7 @@ .\Debug/SDL.tlb + %(AdditionalOptions) /utf-8 Disabled $(ProjectDir)/../../include;$(ProjectDir)/../../include/build_config;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -175,6 +177,7 @@ .\Release/SDL.tlb + %(AdditionalOptions) /utf-8 $(ProjectDir)/../../include;$(ProjectDir)/../../include/build_config;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) DLL_EXPORT;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -209,6 +212,7 @@ .\Release/SDL.tlb + %(AdditionalOptions) /utf-8 $(ProjectDir)/../../include;$(ProjectDir)/../../include/build_config;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) DLL_EXPORT;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -235,6 +239,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) @@ -331,6 +336,7 @@ + @@ -348,6 +354,7 @@ + @@ -487,6 +494,7 @@ + @@ -533,6 +541,7 @@ + @@ -550,6 +559,7 @@ + @@ -698,6 +708,7 @@ + diff --git a/libs/SDL3/VisualC/SDL/SDL.vcxproj.filters b/libs/SDL3/VisualC/SDL/SDL.vcxproj.filters index 176bea64..d653ee05 100644 --- a/libs/SDL3/VisualC/SDL/SDL.vcxproj.filters +++ b/libs/SDL3/VisualC/SDL/SDL.vcxproj.filters @@ -486,6 +486,12 @@ audio + + core\windows + + + core\windows + core\windows @@ -528,6 +534,9 @@ events + + events + events @@ -666,6 +675,9 @@ video + + video + video @@ -1028,6 +1040,9 @@ core + + core\windows + core\windows @@ -1064,6 +1079,9 @@ events + + events + events @@ -1283,6 +1301,9 @@ video + + video + video diff --git a/libs/SDL3/VisualC/SDL_test/Directory.Build.props b/libs/SDL3/VisualC/SDL_test/Directory.Build.props new file mode 100644 index 00000000..24033f43 --- /dev/null +++ b/libs/SDL3/VisualC/SDL_test/Directory.Build.props @@ -0,0 +1,8 @@ + + + + + SDL_VENDOR_INFO="libsdl.org";%(PreprocessorDefinitions) + + + diff --git a/libs/SDL3/VisualC/SDL_test/SDL_test.vcxproj b/libs/SDL3/VisualC/SDL_test/SDL_test.vcxproj index 541f7cb0..4313bbe1 100644 --- a/libs/SDL3/VisualC/SDL_test/SDL_test.vcxproj +++ b/libs/SDL3/VisualC/SDL_test/SDL_test.vcxproj @@ -86,6 +86,7 @@ + %(AdditionalOptions) /utf-8 $(ProjectDir)/../../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -104,6 +105,7 @@ X64 + %(AdditionalOptions) /utf-8 $(ProjectDir)/../../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -122,6 +124,7 @@ + %(AdditionalOptions) /utf-8 Disabled $(ProjectDir)/../../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -140,6 +143,7 @@ X64 + %(AdditionalOptions) /utf-8 Disabled $(ProjectDir)/../../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -154,6 +158,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/VisualC/examples/Directory.Build.props b/libs/SDL3/VisualC/examples/Directory.Build.props index fea48e06..4833d3e7 100644 --- a/libs/SDL3/VisualC/examples/Directory.Build.props +++ b/libs/SDL3/VisualC/examples/Directory.Build.props @@ -161,6 +161,7 @@ + %(AdditionalOptions) /utf-8 $(SolutionDir)\..\include;%(AdditionalIncludeDirectories) diff --git a/libs/SDL3/VisualC/tests/checkkeys/checkkeys.vcxproj b/libs/SDL3/VisualC/tests/checkkeys/checkkeys.vcxproj index cc263df0..901cdbbd 100644 --- a/libs/SDL3/VisualC/tests/checkkeys/checkkeys.vcxproj +++ b/libs/SDL3/VisualC/tests/checkkeys/checkkeys.vcxproj @@ -88,6 +88,7 @@ .\Debug/checkkeys.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -114,6 +115,7 @@ .\Debug/checkkeys.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -140,6 +142,7 @@ .\Release/checkkeys.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -166,6 +169,7 @@ .\Release/checkkeys.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -185,6 +189,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/VisualC/tests/loopwave/loopwave.vcxproj b/libs/SDL3/VisualC/tests/loopwave/loopwave.vcxproj index a5912a9a..6ab91a82 100644 --- a/libs/SDL3/VisualC/tests/loopwave/loopwave.vcxproj +++ b/libs/SDL3/VisualC/tests/loopwave/loopwave.vcxproj @@ -88,6 +88,7 @@ .\Release/loopwave.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -114,6 +115,7 @@ .\Release/loopwave.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -140,6 +142,7 @@ .\Debug/loopwave.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -166,6 +169,7 @@ .\Debug/loopwave.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -185,6 +189,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/VisualC/tests/testatomic/testatomic.vcxproj b/libs/SDL3/VisualC/tests/testatomic/testatomic.vcxproj index 5a1efef2..abe71ff9 100644 --- a/libs/SDL3/VisualC/tests/testatomic/testatomic.vcxproj +++ b/libs/SDL3/VisualC/tests/testatomic/testatomic.vcxproj @@ -88,6 +88,7 @@ .\Debug/testatomic.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -114,6 +115,7 @@ .\Debug/testatomic.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -140,6 +142,7 @@ .\Release/testatomic.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -163,6 +166,7 @@ .\Release/testatomic.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -179,6 +183,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/VisualC/tests/testautomation/testautomation.vcxproj b/libs/SDL3/VisualC/tests/testautomation/testautomation.vcxproj index ba737643..d973c8dc 100644 --- a/libs/SDL3/VisualC/tests/testautomation/testautomation.vcxproj +++ b/libs/SDL3/VisualC/tests/testautomation/testautomation.vcxproj @@ -88,6 +88,7 @@ .\Debug/testautomation.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;$(SolutionDir)/../include/build_config;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -114,6 +115,7 @@ .\Debug/testautomation.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;$(SolutionDir)/../include/build_config;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -140,6 +142,7 @@ .\Release/testautomation.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;$(SolutionDir)/../include/build_config;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -163,6 +166,7 @@ .\Release/testautomation.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;$(SolutionDir)/../include/build_config;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -179,6 +183,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/VisualC/tests/testcontroller/testcontroller.vcxproj b/libs/SDL3/VisualC/tests/testcontroller/testcontroller.vcxproj index 94c8629a..fbcadfcb 100644 --- a/libs/SDL3/VisualC/tests/testcontroller/testcontroller.vcxproj +++ b/libs/SDL3/VisualC/tests/testcontroller/testcontroller.vcxproj @@ -88,6 +88,7 @@ .\Release/testcontroller.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -111,6 +112,7 @@ .\Release/testcontroller.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -134,6 +136,7 @@ .\Debug/testcontroller.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -160,6 +163,7 @@ .\Debug/testcontroller.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -179,6 +183,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/VisualC/tests/testdialog/testdialog.vcxproj b/libs/SDL3/VisualC/tests/testdialog/testdialog.vcxproj index 9961cf25..29ae4469 100644 --- a/libs/SDL3/VisualC/tests/testdialog/testdialog.vcxproj +++ b/libs/SDL3/VisualC/tests/testdialog/testdialog.vcxproj @@ -88,6 +88,7 @@ .\Debug/testdialog.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -114,6 +115,7 @@ .\Debug/testdialog.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -140,6 +142,7 @@ .\Release/testdialog.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -163,6 +166,7 @@ .\Release/testdialog.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -179,6 +183,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/VisualC/tests/testdraw/testdraw.vcxproj b/libs/SDL3/VisualC/tests/testdraw/testdraw.vcxproj index 5ca57bf0..de8a31e2 100644 --- a/libs/SDL3/VisualC/tests/testdraw/testdraw.vcxproj +++ b/libs/SDL3/VisualC/tests/testdraw/testdraw.vcxproj @@ -88,6 +88,7 @@ .\Release/testdraw.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -111,6 +112,7 @@ .\Release/testdraw.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -134,6 +136,7 @@ .\Debug/testdraw.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -160,6 +163,7 @@ .\Debug/testdraw.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -179,6 +183,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/VisualC/tests/testfile/testfile.vcxproj b/libs/SDL3/VisualC/tests/testfile/testfile.vcxproj index a38880d5..dfcd4312 100644 --- a/libs/SDL3/VisualC/tests/testfile/testfile.vcxproj +++ b/libs/SDL3/VisualC/tests/testfile/testfile.vcxproj @@ -88,6 +88,7 @@ .\Debug/testfile.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -114,6 +115,7 @@ .\Debug/testfile.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -140,6 +142,7 @@ .\Release/testfile.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -163,6 +166,7 @@ .\Release/testfile.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -179,6 +183,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/VisualC/tests/testgl/testgl.vcxproj b/libs/SDL3/VisualC/tests/testgl/testgl.vcxproj index b8bc234e..6c521252 100644 --- a/libs/SDL3/VisualC/tests/testgl/testgl.vcxproj +++ b/libs/SDL3/VisualC/tests/testgl/testgl.vcxproj @@ -88,6 +88,7 @@ .\Debug/testgl.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -115,6 +116,7 @@ .\Debug/testgl.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -142,6 +144,7 @@ .\Release/testgl.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) NDEBUG;WIN32;_WINDOWS;HAVE_OPENGL;%(PreprocessorDefinitions) @@ -166,6 +169,7 @@ .\Release/testgl.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) NDEBUG;WIN32;_WINDOWS;HAVE_OPENGL;%(PreprocessorDefinitions) @@ -183,6 +187,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/VisualC/tests/testgles2/testgles2.vcxproj b/libs/SDL3/VisualC/tests/testgles2/testgles2.vcxproj index 13d0df29..728bb2cc 100644 --- a/libs/SDL3/VisualC/tests/testgles2/testgles2.vcxproj +++ b/libs/SDL3/VisualC/tests/testgles2/testgles2.vcxproj @@ -88,6 +88,7 @@ .\Debug/testgles2.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_WINDOWS;HAVE_OPENGL;%(PreprocessorDefinitions) @@ -114,6 +115,7 @@ .\Debug/testgles2.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_WINDOWS;HAVE_OPENGL;%(PreprocessorDefinitions) @@ -140,6 +142,7 @@ .\Release/testgles2.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_WINDOWS;HAVE_OPENGL;%(PreprocessorDefinitions) MultiThreadedDLL @@ -163,6 +166,7 @@ .\Release/testgles2.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_WINDOWS;HAVE_OPENGL;%(PreprocessorDefinitions) MultiThreadedDLL @@ -179,6 +183,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/VisualC/tests/testoverlay/testoverlay.vcxproj b/libs/SDL3/VisualC/tests/testoverlay/testoverlay.vcxproj index 80c8b030..6d7e2ccb 100644 --- a/libs/SDL3/VisualC/tests/testoverlay/testoverlay.vcxproj +++ b/libs/SDL3/VisualC/tests/testoverlay/testoverlay.vcxproj @@ -88,6 +88,7 @@ .\Release/testoverlay.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -111,6 +112,7 @@ .\Release/testoverlay.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -134,6 +136,7 @@ .\Debug/testoverlay.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -160,6 +163,7 @@ .\Debug/testoverlay.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -179,6 +183,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/VisualC/tests/testpen/testpen.vcxproj b/libs/SDL3/VisualC/tests/testpen/testpen.vcxproj index fdef64f2..65888443 100644 --- a/libs/SDL3/VisualC/tests/testpen/testpen.vcxproj +++ b/libs/SDL3/VisualC/tests/testpen/testpen.vcxproj @@ -88,6 +88,7 @@ .\Debug/testpower.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -114,6 +115,7 @@ .\Debug/testpower.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -140,6 +142,7 @@ .\Release/testpower.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -163,6 +166,7 @@ .\Release/testpower.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -179,6 +183,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/VisualC/tests/testplatform/testplatform.vcxproj b/libs/SDL3/VisualC/tests/testplatform/testplatform.vcxproj index 7752f733..af8ae0cd 100644 --- a/libs/SDL3/VisualC/tests/testplatform/testplatform.vcxproj +++ b/libs/SDL3/VisualC/tests/testplatform/testplatform.vcxproj @@ -90,6 +90,7 @@ + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -119,6 +120,7 @@ + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -148,6 +150,7 @@ + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -174,6 +177,7 @@ + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -191,6 +195,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/VisualC/tests/testpower/testpower.vcxproj b/libs/SDL3/VisualC/tests/testpower/testpower.vcxproj index 98ca2b53..cacf3621 100644 --- a/libs/SDL3/VisualC/tests/testpower/testpower.vcxproj +++ b/libs/SDL3/VisualC/tests/testpower/testpower.vcxproj @@ -88,6 +88,7 @@ .\Debug/testpower.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -114,6 +115,7 @@ .\Debug/testpower.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -140,6 +142,7 @@ .\Release/testpower.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -163,6 +166,7 @@ .\Release/testpower.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -179,6 +183,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/VisualC/tests/testrendertarget/testrendertarget.vcxproj b/libs/SDL3/VisualC/tests/testrendertarget/testrendertarget.vcxproj index eaf719bb..e59bb6ba 100644 --- a/libs/SDL3/VisualC/tests/testrendertarget/testrendertarget.vcxproj +++ b/libs/SDL3/VisualC/tests/testrendertarget/testrendertarget.vcxproj @@ -88,6 +88,7 @@ .\Release/testrendertarget.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -111,6 +112,7 @@ .\Release/testrendertarget.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -134,6 +136,7 @@ .\Debug/testrendertarget.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -160,6 +163,7 @@ .\Debug/testrendertarget.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -179,6 +183,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/VisualC/tests/testrumble/testrumble.vcxproj b/libs/SDL3/VisualC/tests/testrumble/testrumble.vcxproj index c0cb1090..0ae100dc 100644 --- a/libs/SDL3/VisualC/tests/testrumble/testrumble.vcxproj +++ b/libs/SDL3/VisualC/tests/testrumble/testrumble.vcxproj @@ -88,6 +88,7 @@ .\Debug/testrumble.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -114,6 +115,7 @@ .\Debug/testrumble.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -140,6 +142,7 @@ .\Release/testrumble.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -163,6 +166,7 @@ .\Release/testrumble.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -179,6 +183,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/VisualC/tests/testscale/testscale.vcxproj b/libs/SDL3/VisualC/tests/testscale/testscale.vcxproj index 3843e57a..c8900f36 100644 --- a/libs/SDL3/VisualC/tests/testscale/testscale.vcxproj +++ b/libs/SDL3/VisualC/tests/testscale/testscale.vcxproj @@ -88,6 +88,7 @@ .\Release/testscale.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -111,6 +112,7 @@ .\Release/testscale.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -134,6 +136,7 @@ .\Debug/testscale.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -160,6 +163,7 @@ .\Debug/testscale.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -179,6 +183,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/VisualC/tests/testsensor/testsensor.vcxproj b/libs/SDL3/VisualC/tests/testsensor/testsensor.vcxproj index 3f034ad3..f0a9af8a 100644 --- a/libs/SDL3/VisualC/tests/testsensor/testsensor.vcxproj +++ b/libs/SDL3/VisualC/tests/testsensor/testsensor.vcxproj @@ -88,6 +88,7 @@ .\Debug/testsensor.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -114,6 +115,7 @@ .\Debug/testsensor.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -140,6 +142,7 @@ .\Release/testsensor.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -163,6 +166,7 @@ .\Release/testsensor.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -179,6 +183,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/VisualC/tests/testshape/testshape.vcxproj b/libs/SDL3/VisualC/tests/testshape/testshape.vcxproj index 33521f68..14904837 100644 --- a/libs/SDL3/VisualC/tests/testshape/testshape.vcxproj +++ b/libs/SDL3/VisualC/tests/testshape/testshape.vcxproj @@ -88,6 +88,7 @@ .\Release/testshape.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -111,6 +112,7 @@ .\Release/testshape.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -134,6 +136,7 @@ .\Debug/testshape.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -160,6 +163,7 @@ .\Debug/testshape.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -179,6 +183,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/VisualC/tests/testsprite/testsprite.vcxproj b/libs/SDL3/VisualC/tests/testsprite/testsprite.vcxproj index f53408ff..46473ccc 100644 --- a/libs/SDL3/VisualC/tests/testsprite/testsprite.vcxproj +++ b/libs/SDL3/VisualC/tests/testsprite/testsprite.vcxproj @@ -88,6 +88,7 @@ .\Release/testsprite.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -111,6 +112,7 @@ .\Release/testsprite.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -134,6 +136,7 @@ .\Debug/testsprite.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -160,6 +163,7 @@ .\Debug/testsprite.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -179,6 +183,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/VisualC/tests/testsurround/testsurround.vcxproj b/libs/SDL3/VisualC/tests/testsurround/testsurround.vcxproj index 657dd1f3..13ded82f 100644 --- a/libs/SDL3/VisualC/tests/testsurround/testsurround.vcxproj +++ b/libs/SDL3/VisualC/tests/testsurround/testsurround.vcxproj @@ -88,6 +88,7 @@ .\Release/testsurround.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -114,6 +115,7 @@ .\Release/testsurround.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -140,6 +142,7 @@ .\Debug/testsurround.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -166,6 +169,7 @@ .\Debug/testsurround.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -185,6 +189,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/VisualC/tests/testvulkan/testvulkan.vcxproj b/libs/SDL3/VisualC/tests/testvulkan/testvulkan.vcxproj index 800aa50f..0e6645b4 100644 --- a/libs/SDL3/VisualC/tests/testvulkan/testvulkan.vcxproj +++ b/libs/SDL3/VisualC/tests/testvulkan/testvulkan.vcxproj @@ -88,6 +88,7 @@ .\Debug/testvulkan.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -114,6 +115,7 @@ .\Debug/testvulkan.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -140,6 +142,7 @@ .\Release/testvulkan.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) NDEBUG;WIN32;_WINDOWS;HAVE_OPENGL;%(PreprocessorDefinitions) @@ -163,6 +166,7 @@ .\Release/testvulkan.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) NDEBUG;WIN32;_WINDOWS;HAVE_OPENGL;%(PreprocessorDefinitions) @@ -179,6 +183,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/VisualC/tests/testwm/testwm.vcxproj b/libs/SDL3/VisualC/tests/testwm/testwm.vcxproj index b16df243..48786d34 100644 --- a/libs/SDL3/VisualC/tests/testwm/testwm.vcxproj +++ b/libs/SDL3/VisualC/tests/testwm/testwm.vcxproj @@ -88,6 +88,7 @@ .\Debug/testwm.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -114,6 +115,7 @@ .\Debug/testwm.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -140,6 +142,7 @@ .\Release/testwm.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -163,6 +166,7 @@ .\Release/testwm.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -179,6 +183,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/VisualC/tests/testyuv/testyuv.vcxproj b/libs/SDL3/VisualC/tests/testyuv/testyuv.vcxproj index e0eefbd7..5adf0eee 100644 --- a/libs/SDL3/VisualC/tests/testyuv/testyuv.vcxproj +++ b/libs/SDL3/VisualC/tests/testyuv/testyuv.vcxproj @@ -88,6 +88,7 @@ .\Release/testyuv.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -111,6 +112,7 @@ .\Release/testyuv.tlb + %(AdditionalOptions) /utf-8 $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) @@ -134,6 +136,7 @@ .\Debug/testyuv.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -160,6 +163,7 @@ .\Debug/testyuv.tlb + %(AdditionalOptions) /utf-8 Disabled $(SolutionDir)/../include;%(AdditionalIncludeDirectories) %(AdditionalUsingDirectories) @@ -179,6 +183,7 @@ + %(AdditionalOptions) /utf-8 $(TreatWarningsAsError) diff --git a/libs/SDL3/Xcode/SDL/Info-Framework.plist b/libs/SDL3/Xcode/SDL/Info-Framework.plist index c9cb1e5c..02a79b59 100644 --- a/libs/SDL3/Xcode/SDL/Info-Framework.plist +++ b/libs/SDL3/Xcode/SDL/Info-Framework.plist @@ -19,10 +19,10 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 3.2.0 + 3.2.6 CFBundleSignature SDLX CFBundleVersion - 3.2.0 + 3.2.6 diff --git a/libs/SDL3/Xcode/SDL/SDL.xcodeproj/project.pbxproj b/libs/SDL3/Xcode/SDL/SDL.xcodeproj/project.pbxproj index bb655606..d5177a1c 100644 --- a/libs/SDL3/Xcode/SDL/SDL.xcodeproj/project.pbxproj +++ b/libs/SDL3/Xcode/SDL/SDL.xcodeproj/project.pbxproj @@ -512,10 +512,16 @@ F3D46B122D20625800D9CBDF /* SDL_egl.h in Headers */ = {isa = PBXBuildFile; fileRef = F3D46A8E2D20625800D9CBDF /* SDL_egl.h */; settings = {ATTRIBUTES = (Public, ); }; }; F3D46B132D20625800D9CBDF /* SDL_filesystem.h in Headers */ = {isa = PBXBuildFile; fileRef = F3D46A922D20625800D9CBDF /* SDL_filesystem.h */; settings = {ATTRIBUTES = (Public, ); }; }; F3D60A8328C16A1900788A3A /* SDL_hidapi_wii.c in Sources */ = {isa = PBXBuildFile; fileRef = F3D60A8228C16A1800788A3A /* SDL_hidapi_wii.c */; }; + F3D8BDFC2D6D2C7000B22FA1 /* SDL_eventwatch_c.h in Headers */ = {isa = PBXBuildFile; fileRef = F3D8BDFB2D6D2C7000B22FA1 /* SDL_eventwatch_c.h */; }; + F3D8BDFD2D6D2C7000B22FA1 /* SDL_eventwatch.c in Sources */ = {isa = PBXBuildFile; fileRef = F3D8BDFA2D6D2C7000B22FA1 /* SDL_eventwatch.c */; }; F3DDCC562AFD42B600B0842B /* SDL_clipboard_c.h in Headers */ = {isa = PBXBuildFile; fileRef = F3DDCC4D2AFD42B500B0842B /* SDL_clipboard_c.h */; }; F3DDCC5B2AFD42B600B0842B /* SDL_video_c.h in Headers */ = {isa = PBXBuildFile; fileRef = F3DDCC522AFD42B600B0842B /* SDL_video_c.h */; }; F3DDCC5D2AFD42B600B0842B /* SDL_rect_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = F3DDCC542AFD42B600B0842B /* SDL_rect_impl.h */; }; F3E5A6EB2AD5E0E600293D83 /* SDL_properties.c in Sources */ = {isa = PBXBuildFile; fileRef = F3E5A6EA2AD5E0E600293D83 /* SDL_properties.c */; }; + F3EFA5ED2D5AB97300BCF22F /* SDL_stb_c.h in Headers */ = {isa = PBXBuildFile; fileRef = F3EFA5EA2D5AB97300BCF22F /* SDL_stb_c.h */; }; + F3EFA5EE2D5AB97300BCF22F /* stb_image.h in Headers */ = {isa = PBXBuildFile; fileRef = F3EFA5EC2D5AB97300BCF22F /* stb_image.h */; }; + F3EFA5EF2D5AB97300BCF22F /* SDL_surface_c.h in Headers */ = {isa = PBXBuildFile; fileRef = F3EFA5EB2D5AB97300BCF22F /* SDL_surface_c.h */; }; + F3EFA5F02D5AB97300BCF22F /* SDL_stb.c in Sources */ = {isa = PBXBuildFile; fileRef = F3EFA5E92D5AB97300BCF22F /* SDL_stb.c */; }; F3F07D5A269640160074468B /* SDL_hidapi_luna.c in Sources */ = {isa = PBXBuildFile; fileRef = F3F07D59269640160074468B /* SDL_hidapi_luna.c */; }; F3F15D7F2D011912007AE210 /* SDL_dialog.c in Sources */ = {isa = PBXBuildFile; fileRef = F3F15D7D2D011912007AE210 /* SDL_dialog.c */; }; F3F15D802D011912007AE210 /* SDL_dialog_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = F3F15D7E2D011912007AE210 /* SDL_dialog_utils.h */; }; @@ -1075,10 +1081,16 @@ F3D46AC82D20625800D9CBDF /* SDL_video.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_video.h; sourceTree = ""; }; F3D46AC92D20625800D9CBDF /* SDL_vulkan.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_vulkan.h; sourceTree = ""; }; F3D60A8228C16A1800788A3A /* SDL_hidapi_wii.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_wii.c; sourceTree = ""; }; + F3D8BDFA2D6D2C7000B22FA1 /* SDL_eventwatch.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_eventwatch.c; sourceTree = ""; }; + F3D8BDFB2D6D2C7000B22FA1 /* SDL_eventwatch_c.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_eventwatch_c.h; sourceTree = ""; }; F3DDCC4D2AFD42B500B0842B /* SDL_clipboard_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_clipboard_c.h; sourceTree = ""; }; F3DDCC522AFD42B600B0842B /* SDL_video_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_video_c.h; sourceTree = ""; }; F3DDCC542AFD42B600B0842B /* SDL_rect_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_rect_impl.h; sourceTree = ""; }; F3E5A6EA2AD5E0E600293D83 /* SDL_properties.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_properties.c; sourceTree = ""; }; + F3EFA5E92D5AB97300BCF22F /* SDL_stb.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_stb.c; sourceTree = ""; }; + F3EFA5EA2D5AB97300BCF22F /* SDL_stb_c.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_stb_c.h; sourceTree = ""; }; + F3EFA5EB2D5AB97300BCF22F /* SDL_surface_c.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_surface_c.h; sourceTree = ""; }; + F3EFA5EC2D5AB97300BCF22F /* stb_image.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = stb_image.h; sourceTree = ""; }; F3F07D59269640160074468B /* SDL_hidapi_luna.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_luna.c; sourceTree = ""; }; F3F15D7C2D011912007AE210 /* SDL_dialog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_dialog.h; sourceTree = ""; }; F3F15D7D2D011912007AE210 /* SDL_dialog.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_dialog.c; sourceTree = ""; }; @@ -1586,43 +1598,47 @@ A7D8A60523E2513D00DCD162 /* dummy */, A7D8A72123E2513E00DCD162 /* khronos */, A7D8A5EC23E2513D00DCD162 /* offscreen */, - A7D8A61823E2513D00DCD162 /* uikit */, - A7D8A76C23E2513E00DCD162 /* yuv2rgb */, + A7D8A76B23E2513E00DCD162 /* SDL_blit.h */, + A7D8A64C23E2513D00DCD162 /* SDL_blit.c */, A7D8A66223E2513E00DCD162 /* SDL_blit_0.c */, A7D8A6FA23E2513E00DCD162 /* SDL_blit_1.c */, A7D8A66423E2513E00DCD162 /* SDL_blit_A.c */, - A7D8A63F23E2513D00DCD162 /* SDL_blit_auto.c */, A7D8A73F23E2513E00DCD162 /* SDL_blit_auto.h */, - A7D8A61623E2513D00DCD162 /* SDL_blit_copy.c */, + A7D8A63F23E2513D00DCD162 /* SDL_blit_auto.c */, A7D8A76623E2513E00DCD162 /* SDL_blit_copy.h */, + A7D8A61623E2513D00DCD162 /* SDL_blit_copy.c */, A7D8A64223E2513D00DCD162 /* SDL_blit_N.c */, - A7D8A60223E2513D00DCD162 /* SDL_blit_slow.c */, A7D8A66323E2513E00DCD162 /* SDL_blit_slow.h */, - A7D8A64C23E2513D00DCD162 /* SDL_blit.c */, - A7D8A76B23E2513E00DCD162 /* SDL_blit.h */, + A7D8A60223E2513D00DCD162 /* SDL_blit_slow.c */, A7D8A77323E2513E00DCD162 /* SDL_bmp.c */, - F3DDCC4D2AFD42B500B0842B /* SDL_clipboard_c.h */, A7D8A67B23E2513E00DCD162 /* SDL_clipboard.c */, - A7D8A60423E2513D00DCD162 /* SDL_egl_c.h */, + F3DDCC4D2AFD42B500B0842B /* SDL_clipboard_c.h */, A7D8A6B623E2513E00DCD162 /* SDL_egl.c */, + A7D8A60423E2513D00DCD162 /* SDL_egl_c.h */, A7D8A76823E2513E00DCD162 /* SDL_fillrect.c */, - A7D8A74023E2513E00DCD162 /* SDL_pixels_c.h */, A7D8A64D23E2513D00DCD162 /* SDL_pixels.c */, + A7D8A74023E2513E00DCD162 /* SDL_pixels_c.h */, + A7D8A63423E2513D00DCD162 /* SDL_rect.c */, A7D8A60C23E2513D00DCD162 /* SDL_rect_c.h */, F3DDCC542AFD42B600B0842B /* SDL_rect_impl.h */, - A7D8A63423E2513D00DCD162 /* SDL_rect.c */, - A7D8A76723E2513E00DCD162 /* SDL_RLEaccel_c.h */, A7D8A61523E2513D00DCD162 /* SDL_RLEaccel.c */, + A7D8A76723E2513E00DCD162 /* SDL_RLEaccel_c.h */, + F3EFA5E92D5AB97300BCF22F /* SDL_stb.c */, + F3EFA5EA2D5AB97300BCF22F /* SDL_stb_c.h */, A7D8A60323E2513D00DCD162 /* SDL_stretch.c */, A7D8A61423E2513D00DCD162 /* SDL_surface.c */, + F3EFA5EB2D5AB97300BCF22F /* SDL_surface_c.h */, A7D8A61723E2513D00DCD162 /* SDL_sysvideo.h */, + A7D8A60E23E2513D00DCD162 /* SDL_video.c */, F3DDCC522AFD42B600B0842B /* SDL_video_c.h */, E4F7981F2AD8D87F00669F54 /* SDL_video_unsupported.c */, - A7D8A60E23E2513D00DCD162 /* SDL_video.c */, A7D8A63E23E2513D00DCD162 /* SDL_vulkan_internal.h */, A7D8A64023E2513D00DCD162 /* SDL_vulkan_utils.c */, - A7D8A76A23E2513E00DCD162 /* SDL_yuv_c.h */, A7D8A67C23E2513E00DCD162 /* SDL_yuv.c */, + A7D8A76A23E2513E00DCD162 /* SDL_yuv_c.h */, + F3EFA5EC2D5AB97300BCF22F /* stb_image.h */, + A7D8A61823E2513D00DCD162 /* uikit */, + A7D8A76C23E2513E00DCD162 /* yuv2rgb */, ); path = video; sourceTree = ""; @@ -2197,29 +2213,31 @@ A7D8A93623E2514000DCD162 /* scancodes_linux.h */, A7D8A92C23E2514000DCD162 /* scancodes_windows.h */, A7D8A94123E2514000DCD162 /* scancodes_xfree86.h */, - F3C2CB202C5DDDB2004D7998 /* SDL_categories_c.h */, F3C2CB212C5DDDB2004D7998 /* SDL_categories.c */, - A7D8A93923E2514000DCD162 /* SDL_clipboardevents_c.h */, + F3C2CB202C5DDDB2004D7998 /* SDL_categories_c.h */, A7D8A93A23E2514000DCD162 /* SDL_clipboardevents.c */, - A7D8A93123E2514000DCD162 /* SDL_displayevents_c.h */, + A7D8A93923E2514000DCD162 /* SDL_clipboardevents_c.h */, A7D8A92D23E2514000DCD162 /* SDL_displayevents.c */, - A7D8A92E23E2514000DCD162 /* SDL_dropevents_c.h */, + A7D8A93123E2514000DCD162 /* SDL_displayevents_c.h */, A7D8A93B23E2514000DCD162 /* SDL_dropevents.c */, - A7D8A94223E2514000DCD162 /* SDL_events_c.h */, + A7D8A92E23E2514000DCD162 /* SDL_dropevents_c.h */, A7D8A93523E2514000DCD162 /* SDL_events.c */, - A7D8A93D23E2514000DCD162 /* SDL_keyboard_c.h */, + A7D8A94223E2514000DCD162 /* SDL_events_c.h */, + F3D8BDFA2D6D2C7000B22FA1 /* SDL_eventwatch.c */, + F3D8BDFB2D6D2C7000B22FA1 /* SDL_eventwatch_c.h */, A7D8A93823E2514000DCD162 /* SDL_keyboard.c */, - F31013C62C24E98200FBE946 /* SDL_keymap_c.h */, + A7D8A93D23E2514000DCD162 /* SDL_keyboard_c.h */, F31013C52C24E98200FBE946 /* SDL_keymap.c */, - A7D8A92B23E2514000DCD162 /* SDL_mouse_c.h */, + F31013C62C24E98200FBE946 /* SDL_keymap_c.h */, A7D8A92A23E2514000DCD162 /* SDL_mouse.c */, - 63134A232A7902FD0021E9A6 /* SDL_pen_c.h */, + A7D8A92B23E2514000DCD162 /* SDL_mouse_c.h */, 63134A242A7902FD0021E9A6 /* SDL_pen.c */, + 63134A232A7902FD0021E9A6 /* SDL_pen_c.h */, A7D8A93C23E2514000DCD162 /* SDL_quit.c */, - A7D8A93723E2514000DCD162 /* SDL_touch_c.h */, A7D8A93E23E2514000DCD162 /* SDL_touch.c */, - A7D8A94323E2514000DCD162 /* SDL_windowevents_c.h */, + A7D8A93723E2514000DCD162 /* SDL_touch_c.h */, A7D8A92F23E2514000DCD162 /* SDL_windowevents.c */, + A7D8A94323E2514000DCD162 /* SDL_windowevents_c.h */, ); path = events; sourceTree = ""; @@ -2458,6 +2476,9 @@ A7D8BB6F23E2514500DCD162 /* SDL_clipboardevents_c.h in Headers */, A7D8AECA23E2514100DCD162 /* SDL_cocoaclipboard.h in Headers */, A7D8AF1223E2514100DCD162 /* SDL_cocoaevents.h in Headers */, + F3EFA5ED2D5AB97300BCF22F /* SDL_stb_c.h in Headers */, + F3EFA5EE2D5AB97300BCF22F /* stb_image.h in Headers */, + F3EFA5EF2D5AB97300BCF22F /* SDL_surface_c.h in Headers */, A7D8AE8E23E2514100DCD162 /* SDL_cocoakeyboard.h in Headers */, A7D8AF0623E2514100DCD162 /* SDL_cocoamessagebox.h in Headers */, A7D8AEB223E2514100DCD162 /* SDL_cocoametalview.h in Headers */, @@ -2692,6 +2713,7 @@ A7D8B3D423E2514300DCD162 /* yuv_rgb.h in Headers */, F3FA5A252B59ACE000FEAD97 /* yuv_rgb_common.h in Headers */, F3FA5A1D2B59ACE000FEAD97 /* yuv_rgb_internal.h in Headers */, + F3D8BDFC2D6D2C7000B22FA1 /* SDL_eventwatch_c.h in Headers */, F3FA5A242B59ACE000FEAD97 /* yuv_rgb_lsx.h in Headers */, F3FA5A1E2B59ACE000FEAD97 /* yuv_rgb_lsx_func.h in Headers */, F3FA5A1F2B59ACE000FEAD97 /* yuv_rgb_sse.h in Headers */, @@ -2950,6 +2972,8 @@ 566E26CF246274CC00718109 /* SDL_syslocale.m in Sources */, A7D8AFC023E2514200DCD162 /* SDL_egl.c in Sources */, A7D8AC3323E2514100DCD162 /* SDL_RLEaccel.c in Sources */, + F3D8BDFD2D6D2C7000B22FA1 /* SDL_eventwatch.c in Sources */, + F3EFA5F02D5AB97300BCF22F /* SDL_stb.c in Sources */, A7D8BBB123E2514500DCD162 /* SDL_assert.c in Sources */, A7D8B3DA23E2514300DCD162 /* SDL_bmp.c in Sources */, A7D8B96E23E2514400DCD162 /* SDL_stdlib.c in Sources */, @@ -3062,7 +3086,7 @@ CLANG_ENABLE_OBJC_ARC = YES; DEPLOYMENT_POSTPROCESSING = YES; DYLIB_COMPATIBILITY_VERSION = 201.0.0; - DYLIB_CURRENT_VERSION = 201.0.0; + DYLIB_CURRENT_VERSION = 201.6.0; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_ALTIVEC_EXTENSIONS = YES; @@ -3097,7 +3121,7 @@ "@loader_path/Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.13; - MARKETING_VERSION = 3.2.0; + MARKETING_VERSION = 3.2.6; OTHER_LDFLAGS = "$(CONFIG_FRAMEWORK_LDFLAGS)"; PRODUCT_BUNDLE_IDENTIFIER = org.libsdl.SDL3; PRODUCT_NAME = SDL3; @@ -3126,7 +3150,7 @@ CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; DYLIB_COMPATIBILITY_VERSION = 201.0.0; - DYLIB_CURRENT_VERSION = 201.0.0; + DYLIB_CURRENT_VERSION = 201.6.0; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -3158,7 +3182,7 @@ "@loader_path/Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.13; - MARKETING_VERSION = 3.2.0; + MARKETING_VERSION = 3.2.6; ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = "$(CONFIG_FRAMEWORK_LDFLAGS)"; PRODUCT_BUNDLE_IDENTIFIER = org.libsdl.SDL3; diff --git a/libs/SDL3/Xcode/SDL/pkg-support/SDL.info b/libs/SDL3/Xcode/SDL/pkg-support/SDL.info index b80d1f58..cb68cd8d 100644 --- a/libs/SDL3/Xcode/SDL/pkg-support/SDL.info +++ b/libs/SDL3/Xcode/SDL/pkg-support/SDL.info @@ -1,4 +1,4 @@ -Title SDL 3.2.0 +Title SDL 3.2.6 Version 1 Description SDL Library for macOS (http://www.libsdl.org) DefaultLocation /Library/Frameworks diff --git a/libs/SDL3/Xcode/SDL/pkg-support/resources/cmake/SDL3Config.cmake b/libs/SDL3/Xcode/SDL/pkg-support/resources/cmake/SDL3Config.cmake index 03673f3f..784d27db 100644 --- a/libs/SDL3/Xcode/SDL/pkg-support/resources/cmake/SDL3Config.cmake +++ b/libs/SDL3/Xcode/SDL/pkg-support/resources/cmake/SDL3Config.cmake @@ -59,7 +59,7 @@ if(NOT TARGET SDL3::SDL3-shared) set_target_properties(SDL3::SDL3-shared PROPERTIES FRAMEWORK "TRUE" - IMPORTED_LOCATION "${_sdl3_framework_path}" + IMPORTED_LOCATION "${_sdl3_framework_path}/SDL3" INTERFACE_LINK_LIBRARIES "SDL3::Headers" COMPATIBLE_INTERFACE_BOOL "SDL3_SHARED" INTERFACE_SDL3_SHARED "ON" diff --git a/libs/SDL3/Xcode/SDL/pkg-support/share/cmake/SDL3/SDL3Config.cmake b/libs/SDL3/Xcode/SDL/pkg-support/share/cmake/SDL3/SDL3Config.cmake index f1585814..9d29aae9 100644 --- a/libs/SDL3/Xcode/SDL/pkg-support/share/cmake/SDL3/SDL3Config.cmake +++ b/libs/SDL3/Xcode/SDL/pkg-support/share/cmake/SDL3/SDL3Config.cmake @@ -112,7 +112,7 @@ if(NOT TARGET SDL3::SDL3-shared) set_target_properties(SDL3::SDL3-shared PROPERTIES FRAMEWORK "TRUE" - IMPORTED_LOCATION "${_sdl3_framework_path}" + IMPORTED_LOCATION "${_sdl3_framework_path}/SDL3" INTERFACE_LINK_LIBRARIES "SDL3::Headers" ) endif() diff --git a/libs/SDL3/Xcode/SDLTest/SDLTest.xcodeproj/project.pbxproj b/libs/SDL3/Xcode/SDLTest/SDLTest.xcodeproj/project.pbxproj index bfeae4e5..3a2e59d0 100644 --- a/libs/SDL3/Xcode/SDLTest/SDLTest.xcodeproj/project.pbxproj +++ b/libs/SDL3/Xcode/SDLTest/SDLTest.xcodeproj/project.pbxproj @@ -167,6 +167,9 @@ F399C6512A7892D800C86979 /* testautomation_intrinsics.c in Sources */ = {isa = PBXBuildFile; fileRef = F399C6502A7892D800C86979 /* testautomation_intrinsics.c */; }; F399C6522A7892D800C86979 /* testautomation_intrinsics.c in Sources */ = {isa = PBXBuildFile; fileRef = F399C6502A7892D800C86979 /* testautomation_intrinsics.c */; }; F399C6552A78933100C86979 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F399C6542A78933000C86979 /* Cocoa.framework */; }; + F3B7FD642D73FC630086D1D0 /* SDL3.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 003FA643093FFD41000C53B3 /* SDL3.framework */; }; + F3B7FD662D73FC630086D1D0 /* SDL3.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 003FA643093FFD41000C53B3 /* SDL3.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + F3B7FD6C2D73FC9E0086D1D0 /* testpen.c in Sources */ = {isa = PBXBuildFile; fileRef = F3B7FD6B2D73FC9E0086D1D0 /* testpen.c */; }; F3C17C7728E40BC800E1A26D /* testutils.c in Sources */ = {isa = PBXBuildFile; fileRef = F3C17C7328E40ADE00E1A26D /* testutils.c */; }; F3C17C7928E40C6E00E1A26D /* testutils.c in Sources */ = {isa = PBXBuildFile; fileRef = F3C17C7328E40ADE00E1A26D /* testutils.c */; }; F3C17C7B28E40D4E00E1A26D /* testutils.c in Sources */ = {isa = PBXBuildFile; fileRef = F3C17C7328E40ADE00E1A26D /* testutils.c */; }; @@ -717,6 +720,17 @@ name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; + F3B7FD652D73FC630086D1D0 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + F3B7FD662D73FC630086D1D0 /* SDL3.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; F3CB568B2A7895F800766177 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -1356,6 +1370,8 @@ F399C6492A78929400C86979 /* gamepadutils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gamepadutils.c; sourceTree = ""; }; F399C6502A7892D800C86979 /* testautomation_intrinsics.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = testautomation_intrinsics.c; sourceTree = ""; }; F399C6542A78933000C86979 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + F3B7FD6A2D73FC630086D1D0 /* testpen.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = testpen.app; sourceTree = BUILT_PRODUCTS_DIR; }; + F3B7FD6B2D73FC9E0086D1D0 /* testpen.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = testpen.c; sourceTree = ""; }; F3C17C6A28E3FD4400E1A26D /* config.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = config.xcconfig; sourceTree = ""; }; F3C17C7328E40ADE00E1A26D /* testutils.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = testutils.c; sourceTree = ""; }; F3C17CD628E416AC00E1A26D /* testgeometry.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = testgeometry.c; sourceTree = ""; }; @@ -1732,6 +1748,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + F3B7FD632D73FC630086D1D0 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + F3B7FD642D73FC630086D1D0 /* SDL3.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; F3C17CD928E416CF00E1A26D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -1789,6 +1813,7 @@ 083E4872006D84C97F000001 /* loopwave.c */, 0017958F1074216E00F5D044 /* testatomic.c */, 001795B01074222D00F5D044 /* testaudioinfo.c */, + F35E56CC2983130F00A43A5F /* testautomation.c */, F35E56C42983130D00A43A5F /* testautomation_audio.c */, F35E56BC2983130B00A43A5F /* testautomation_clipboard.c */, F35E56BB2983130B00A43A5F /* testautomation_events.c */, @@ -1815,7 +1840,6 @@ A1A8594B2BC72FC20045DD6C /* testautomation_time.c */, F35E56BD2983130B00A43A5F /* testautomation_timer.c */, F35E56C12983130C00A43A5F /* testautomation_video.c */, - F35E56CC2983130F00A43A5F /* testautomation.c */, F36C342C2C0F869B00991150 /* testcamera.c */, BBFC088E164C6820003E6A99 /* testcontroller.c */, 001797711074320D00F5D044 /* testdraw.c */, @@ -1837,11 +1861,12 @@ 092D6D75FFB313BB7F000001 /* testlock.c */, DB166CBD16A1C74100A1396C /* testmessage.c */, 001798151074359B00F5D044 /* testmultiaudio.c */, - 0017985A107436ED00F5D044 /* testnative.c */, 0017985B107436ED00F5D044 /* testnative.h */, + 0017985A107436ED00F5D044 /* testnative.c */, 0017985C107436ED00F5D044 /* testnativecocoa.m */, 00179872107438D000F5D044 /* testnativex11.c */, 002F345209CA201C00EBEB88 /* testoverlay.c */, + F3B7FD6B2D73FC9E0086D1D0 /* testpen.c */, 002F346F09CA20A600EBEB88 /* testplatform.c */, 001798B910743A4900F5D044 /* testpower.c */, DB166CBF16A1C74100A1396C /* testrelative.c */, @@ -1918,6 +1943,7 @@ F3C17CDC28E416CF00E1A26D /* testgeometry.app */, F35E56AA298312CB00A43A5F /* testautomation.app */, F36C34272C0F85DB00991150 /* testcamera.app */, + F3B7FD6A2D73FC630086D1D0 /* testpen.app */, ); name = Products; sourceTree = ""; @@ -2756,6 +2782,23 @@ productReference = F36C34272C0F85DB00991150 /* testcamera.app */; productType = "com.apple.product-type.application"; }; + F3B7FD602D73FC630086D1D0 /* testpen */ = { + isa = PBXNativeTarget; + buildConfigurationList = F3B7FD672D73FC630086D1D0 /* Build configuration list for PBXNativeTarget "testpen" */; + buildPhases = ( + F3B7FD612D73FC630086D1D0 /* Sources */, + F3B7FD632D73FC630086D1D0 /* Frameworks */, + F3B7FD652D73FC630086D1D0 /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = testpen; + productName = testalpha; + productReference = F3B7FD6A2D73FC630086D1D0 /* testpen.app */; + productType = "com.apple.product-type.application"; + }; F3C17CDB28E416CF00E1A26D /* testgeometry */ = { isa = PBXNativeTarget; buildConfigurationList = F3C17CE828E416D000E1A26D /* Build configuration list for PBXNativeTarget "testgeometry" */; @@ -2972,6 +3015,7 @@ 001798781074392D00F5D044 /* testnative */, 002F343C09CA1FB300EBEB88 /* testoverlay */, 002F345909CA204F00EBEB88 /* testplatform */, + F3B7FD602D73FC630086D1D0 /* testpen */, 0017989D107439DF00F5D044 /* testpower */, DB166DDC16A1D50C00A1396C /* testrelative */, DB166DF316A1D57C00A1396C /* testrendercopyex */, @@ -3455,6 +3499,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + F3B7FD612D73FC630086D1D0 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F3B7FD6C2D73FC9E0086D1D0 /* testpen.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; F3C17CD828E416CF00E1A26D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -4704,6 +4756,26 @@ }; name = Release; }; + F3B7FD682D73FC630086D1D0 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + }; + name = Debug; + }; + F3B7FD692D73FC630086D1D0 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + }; + name = Release; + }; F3C17CE928E416D000E1A26D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -5159,6 +5231,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; + F3B7FD672D73FC630086D1D0 /* Build configuration list for PBXNativeTarget "testpen" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F3B7FD682D73FC630086D1D0 /* Debug */, + F3B7FD692D73FC630086D1D0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; F3C17CE828E416D000E1A26D /* Build configuration list for PBXNativeTarget "testgeometry" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/libs/SDL3/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java b/libs/SDL3/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java index 47bf3b31..648db8be 100644 --- a/libs/SDL3/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java +++ b/libs/SDL3/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java @@ -60,7 +60,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh private static final String TAG = "SDL"; private static final int SDL_MAJOR_VERSION = 3; private static final int SDL_MINOR_VERSION = 2; - private static final int SDL_MICRO_VERSION = 0; + private static final int SDL_MICRO_VERSION = 6; /* // Display InputType.SOURCE/CLASS of events and devices // diff --git a/libs/SDL3/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java b/libs/SDL3/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java index dc6fb9d1..e1c892e7 100644 --- a/libs/SDL3/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java +++ b/libs/SDL3/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java @@ -705,9 +705,14 @@ class SDLGenericMotionListener_API14 implements View.OnGenericMotionListener { x = event.getX(i); y = event.getY(i); float p = event.getPressure(i); + if (p > 1.0f) { + // may be larger than 1.0f on some devices + // see the documentation of getPressure(i) + p = 1.0f; + } - // BUTTON_STYLUS_PRIMARY is 2^5, so shift by 4 - int buttons = event.getButtonState() >> 4; + // BUTTON_STYLUS_PRIMARY is 2^5, so shift by 4, and apply SDL_PEN_INPUT_DOWN/SDL_PEN_INPUT_ERASER_TIP + int buttons = (event.getButtonState() >> 4) | (1 << (toolType == MotionEvent.TOOL_TYPE_STYLUS ? 0 : 30)); SDLActivity.onNativePen(event.getPointerId(i), buttons, action, x, y, p); consumed = true; diff --git a/libs/SDL3/android-project/app/src/main/java/org/libsdl/app/SDLSurface.java b/libs/SDL3/android-project/app/src/main/java/org/libsdl/app/SDLSurface.java index 16588213..080501c9 100644 --- a/libs/SDL3/android-project/app/src/main/java/org/libsdl/app/SDLSurface.java +++ b/libs/SDL3/android-project/app/src/main/java/org/libsdl/app/SDLSurface.java @@ -276,7 +276,7 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, int buttonState = (event.getButtonState() >> 4) | (1 << (toolType == MotionEvent.TOOL_TYPE_STYLUS ? 0 : 30)); SDLActivity.onNativePen(pointerId, buttonState, action, x, y, p); - } else if (toolType == MotionEvent.TOOL_TYPE_FINGER) { + } else { // MotionEvent.TOOL_TYPE_FINGER or MotionEvent.TOOL_TYPE_UNKNOWN pointerId = event.getPointerId(i); x = getNormalizedX(event.getX(i)); y = getNormalizedY(event.getY(i)); diff --git a/libs/SDL3/build-scripts/SDL_migration.cocci b/libs/SDL3/build-scripts/SDL_migration.cocci index dac94493..38655aff 100644 --- a/libs/SDL3/build-scripts/SDL_migration.cocci +++ b/libs/SDL3/build-scripts/SDL_migration.cocci @@ -1136,12 +1136,12 @@ typedef SDL_GameControllerButton, SDL_GamepadButton; @@ @@ - SDL_GameControllerGetNumTouchpadFingers -+ SDL_GetGamepadNumTouchpadFingers ++ SDL_GetNumGamepadTouchpadFingers (...) @@ @@ - SDL_GameControllerGetNumTouchpads -+ SDL_GetGamepadNumTouchpads ++ SDL_GetNumGamepadTouchpads (...) @@ @@ @@ -1491,6 +1491,51 @@ typedef SDL_GameControllerButton, SDL_GamepadButton; + SDL_TextInputShown (...) @@ +SDL_Event e1; +@@ +- e1.key.keysym.mod ++ e1.key.mod +@@ +SDL_Event *e1; +@@ +- e1->key.keysym.mod ++ e1->key.mod +@@ +SDL_KeyboardEvent *e1; +@@ +- e1->keysym.mod ++ e1->mod +@@ +SDL_Event e1; +@@ +- e1.key.keysym.sym ++ e1.key.key +@@ +SDL_Event *e1; +@@ +- e1->key.keysym.sym ++ e1->key.key +@@ +SDL_KeyboardEvent *e1; +@@ +- e1->keysym.sym ++ e1->key +@@ +SDL_Event e1; +@@ +- e1.key.keysym.scancode ++ e1.key.scancode +@@ +SDL_Event *e1; +@@ +- e1->key.keysym.scancode ++ e1->key.scancode +@@ +SDL_KeyboardEvent *e1; +@@ +- e1->keysym.scancode ++ e1->scancode +@@ @@ - KMOD_ALT + SDL_KMOD_ALT @@ -2443,6 +2488,11 @@ SDL_Event *e1; - e1->wheel.mouseX + e1->wheel.mouse_x @@ +SDL_MouseWheelEvent *e1; +@@ +- e1->mouseX ++ e1->mouse_x +@@ SDL_Event e1; @@ - e1.wheel.mouseY @@ -2453,6 +2503,41 @@ SDL_Event *e1; - e1->wheel.mouseY + e1->wheel.mouse_y @@ +SDL_MouseWheelEvent *e1; +@@ +- e1->mouseY ++ e1->mouse_y +@@ +SDL_Event e1; +@@ +- e1.wheel.preciseX ++ e1.wheel.x +@@ +SDL_Event *e1; +@@ +- e1->wheel.preciseX ++ e1->wheel.x +@@ +SDL_MouseWheelEvent *e1; +@@ +- e1->preciseX ++ e1->x +@@ +SDL_Event e1; +@@ +- e1.wheel.preciseY ++ e1.wheel.y +@@ +SDL_Event *e1; +@@ +- e1->wheel.preciseY ++ e1->wheel.y +@@ +SDL_MouseWheelEvent *e1; +@@ +- e1->preciseY ++ e1->y +@@ SDL_Event e1; @@ - e1.tfinger.touchId @@ -2463,6 +2548,11 @@ SDL_Event *e1; - e1->tfinger.touchId + e1->tfinger.touchID @@ +SDL_TouchFingerEvent *e1; +@@ +- e1->touchId ++ e1->touchID +@@ SDL_Event e1; @@ - e1.tfinger.fingerId @@ -2473,6 +2563,11 @@ SDL_Event *e1; - e1->tfinger.fingerId + e1->tfinger.fingerID @@ +SDL_TouchFingerEvent *e1; +@@ +- e1->fingerId ++ e1->fingerID +@@ expression e1, e2, e3, e4; @@ - SDL_CreateWindow(e1, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, e2, e3, e4) diff --git a/libs/SDL3/build-scripts/check_stdlib_usage.py b/libs/SDL3/build-scripts/check_stdlib_usage.py index 9ab65e09..09941306 100644 --- a/libs/SDL3/build-scripts/check_stdlib_usage.py +++ b/libs/SDL3/build-scripts/check_stdlib_usage.py @@ -161,6 +161,7 @@ def find_symbols_in_file(file: pathlib.Path) -> int: "src/libm", "src/hidapi", "src/video/khronos", + "src/video/stb_image.h", "include/SDL3", "build-scripts/gen_audio_resampler_filter.c", "build-scripts/gen_audio_channel_conversion.c", diff --git a/libs/SDL3/build-scripts/pkg-support/android/INSTALL.md.in b/libs/SDL3/build-scripts/pkg-support/android/INSTALL.md.in index 60267733..80321c2e 100644 --- a/libs/SDL3/build-scripts/pkg-support/android/INSTALL.md.in +++ b/libs/SDL3/build-scripts/pkg-support/android/INSTALL.md.in @@ -1,7 +1,7 @@ # Using this package -This package contains SDL built for the Android platform. +This package contains @<@PROJECT_NAME@>@ built for the Android platform. ## Gradle integration @@ -59,7 +59,7 @@ Add `--help` for a list of all available options. An API reference, tutorials, and additional documentation is available at: -https://wiki.libsdl.org/SDL3 +https://wiki.libsdl.org/@<@PROJECT_NAME@>@ # Example code diff --git a/libs/SDL3/build-scripts/pkg-support/mingw/INSTALL.md b/libs/SDL3/build-scripts/pkg-support/mingw/INSTALL.md.in similarity index 74% rename from libs/SDL3/build-scripts/pkg-support/mingw/INSTALL.md rename to libs/SDL3/build-scripts/pkg-support/mingw/INSTALL.md.in index 83ea472e..f1a6a789 100644 --- a/libs/SDL3/build-scripts/pkg-support/mingw/INSTALL.md +++ b/libs/SDL3/build-scripts/pkg-support/mingw/INSTALL.md.in @@ -1,19 +1,19 @@ # Using this package -This package contains SDL built for the mingw-w64 toolchain. +This package contains @<@PROJECT_NAME@>@ built for the mingw-w64 toolchain. The files for 32-bit architecture are in i686-w64-mingw32 The files for 64-bit architecture are in x86_64-w64-mingw32 You can install them to another location, just type `make` for help. -To use this package, point your include path at _arch_/include and your library path at _arch_/lib, link with the SDL3 library and copy _arch_/bin/SDL3.dll next to your executable. +To use this package, point your include path at _arch_/include and your library path at _arch_/lib, link with the @<@PROJECT_NAME@>@ library and copy _arch_/bin/@<@PROJECT_NAME@>@.dll next to your executable. e.g. ```sh -gcc -o hello.exe hello.c -Ix86_64-w64-mingw32/include -Lx86_64-w64-mingw32/lib -lSDL3 -cp x86_64-w64-mingw32/bin/SDL3.dll . +gcc -o hello.exe hello.c -Ix86_64-w64-mingw32/include -Lx86_64-w64-mingw32/lib -l@<@PROJECT_NAME@>@ +cp x86_64-w64-mingw32/bin/@<@PROJECT_NAME@>@.dll . ./hello.exe ``` @@ -21,7 +21,7 @@ cp x86_64-w64-mingw32/bin/SDL3.dll . An API reference, tutorials, and additional documentation is available at: -https://wiki.libsdl.org/SDL3 +https://wiki.libsdl.org/@<@PROJECT_NAME@>@ # Example code diff --git a/libs/SDL3/build-scripts/pkg-support/msvc/INSTALL.md b/libs/SDL3/build-scripts/pkg-support/msvc/INSTALL.md.in similarity index 77% rename from libs/SDL3/build-scripts/pkg-support/msvc/INSTALL.md rename to libs/SDL3/build-scripts/pkg-support/msvc/INSTALL.md.in index 82f812f3..671f5243 100644 --- a/libs/SDL3/build-scripts/pkg-support/msvc/INSTALL.md +++ b/libs/SDL3/build-scripts/pkg-support/msvc/INSTALL.md.in @@ -1,19 +1,19 @@ # Using this package -This package contains SDL built for Visual Studio. +This package contains @<@PROJECT_NAME@>@ built for Visual Studio. To use this package, edit your project properties: - Add the include directory to "VC++ Directories" -> "Include Directories" - Add the lib/_arch_ directory to "VC++ Directories" -> "Library Directories" -- Add SDL3.lib to Linker -> Input -> "Additional Dependencies" -- Copy lib/_arch_/SDL3.dll to your project directory. +- Add @<@PROJECT_NAME@>@.lib to Linker -> Input -> "Additional Dependencies" +- Copy lib/_arch_/@<@PROJECT_NAME@>@.dll to your project directory. # Documentation An API reference, tutorials, and additional documentation is available at: -https://wiki.libsdl.org/SDL3 +https://wiki.libsdl.org/@<@PROJECT_NAME@>@ # Example code diff --git a/libs/SDL3/build-scripts/release-info.json b/libs/SDL3/build-scripts/release-info.json index dc0bd31b..8ba213ae 100644 --- a/libs/SDL3/build-scripts/release-info.json +++ b/libs/SDL3/build-scripts/release-info.json @@ -45,7 +45,7 @@ }, "files": { "": [ - "build-scripts/pkg-support/mingw/INSTALL.md", + "build-scripts/pkg-support/mingw/INSTALL.md.in:INSTALL.md", "build-scripts/pkg-support/mingw/Makefile", "LICENSE.txt", "README.md" @@ -117,7 +117,7 @@ }, "files-devel": { "": [ - "build-scripts/pkg-support/msvc/INSTALL.md", + "build-scripts/pkg-support/msvc/INSTALL.md.in:INSTALL.md", "LICENSE.txt", "README.md" ], @@ -181,8 +181,8 @@ "x86", "x86_64" ], - "api-minimum": 19, - "api-target": 29, + "api-minimum": 21, + "api-target": 35, "ndk-minimum": 21, "aar-files": { "": [ diff --git a/libs/SDL3/cmake/SDL3Config.cmake.in b/libs/SDL3/cmake/SDL3Config.cmake.in index e2ca50ed..4c6f1b69 100644 --- a/libs/SDL3/cmake/SDL3Config.cmake.in +++ b/libs/SDL3/cmake/SDL3Config.cmake.in @@ -77,6 +77,9 @@ else() endif() endif() +if(NOT SDL3_COMPONENTS AND NOT TARGET SDL3::Headers AND NOT TARGET SDL3::SDL3-shared AND NOT TARGET SDL3::SDL3-static) + set(SDL3_FOUND FALSE) +endif() check_required_components(SDL3) function(_sdl_create_target_alias_compat NEW_TARGET TARGET) @@ -93,7 +96,7 @@ endfunction() if(NOT TARGET SDL3::SDL3) if(TARGET SDL3::SDL3-shared) _sdl_create_target_alias_compat(SDL3::SDL3 SDL3::SDL3-shared) - else() + elseif(TARGET SDL3::SDL3-static) _sdl_create_target_alias_compat(SDL3::SDL3 SDL3::SDL3-static) endif() endif() diff --git a/libs/SDL3/cmake/test/main_cli.c b/libs/SDL3/cmake/test/main_cli.c index 5a1c0c62..39c5ce27 100644 --- a/libs/SDL3/cmake/test/main_cli.c +++ b/libs/SDL3/cmake/test/main_cli.c @@ -6,7 +6,7 @@ int main(int argc, char *argv[]) { SDL_SetMainReady(); if (!SDL_Init(0)) { - SDL_Log("Could not initialize SDL: %s\n", SDL_GetError()); + SDL_Log("Could not initialize SDL: %s", SDL_GetError()); return 1; } SDL_Delay(100); diff --git a/libs/SDL3/cmake/test/main_gui.c b/libs/SDL3/cmake/test/main_gui.c index 3df64e5f..18ed1010 100644 --- a/libs/SDL3/cmake/test/main_gui.c +++ b/libs/SDL3/cmake/test/main_gui.c @@ -6,12 +6,12 @@ int main(int argc, char *argv[]) SDL_Window *window = NULL; SDL_Surface *screenSurface = NULL; if (!SDL_Init(SDL_INIT_VIDEO)) { - SDL_Log("Could not initialize SDL: %s\n", SDL_GetError()); + SDL_Log("Could not initialize SDL: %s", SDL_GetError()); return 1; } window = SDL_CreateWindow("Hello SDL", 640, 480, 0); if (!window) { - SDL_Log("could not create window: %s\n", SDL_GetError()); + SDL_Log("could not create window: %s", SDL_GetError()); return 1; } screenSurface = SDL_GetWindowSurface(window); diff --git a/libs/SDL3/cmake/test/main_lib.c b/libs/SDL3/cmake/test/main_lib.c index a59150b4..6aec1f63 100644 --- a/libs/SDL3/cmake/test/main_lib.c +++ b/libs/SDL3/cmake/test/main_lib.c @@ -18,7 +18,7 @@ int MYLIBRARY_EXPORT mylibrary_work(void); int mylibrary_init(void) { SDL_SetMainReady(); if (!SDL_Init(0)) { - SDL_Log("Could not initialize SDL: %s\n", SDL_GetError()); + SDL_Log("Could not initialize SDL: %s", SDL_GetError()); return 1; } return 0; diff --git a/libs/SDL3/docs/INTRO-emscripten.md b/libs/SDL3/docs/INTRO-emscripten.md index 89831248..a0541c83 100644 --- a/libs/SDL3/docs/INTRO-emscripten.md +++ b/libs/SDL3/docs/INTRO-emscripten.md @@ -1,35 +1,47 @@ # Introduction to SDL with Emscripten +The easiest way to use SDL is to include it as a subproject in your project. + +We'll start by creating a simple project to build and run [hello.c](hello.c) + First, you should have the Emscripten SDK installed from: https://emscripten.org/docs/getting_started/downloads.html -We'll start by creating a simple project to build and run [hello.c](hello.c) +Create the file CMakeLists.txt +```cmake +cmake_minimum_required(VERSION 3.16) +project(hello) -## Building SDL +# set the output directory for built objects. +# This makes sure that the dynamic library goes into the build directory automatically. +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/$") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/$") -Once you have a command line interface with the Emscripten SDK set up and you've changed directory to the SDL directory, you can build SDL like this: +# This assumes the SDL source is available in vendored/SDL +add_subdirectory(vendored/SDL EXCLUDE_FROM_ALL) +# on Web targets, we need CMake to generate a HTML webpage. +if(EMSCRIPTEN) + set(CMAKE_EXECUTABLE_SUFFIX ".html" CACHE INTERNAL "") +endif() + +# Create your game executable target as usual +add_executable(hello WIN32 hello.c) + +# Link to the actual SDL3 library. +target_link_libraries(hello PRIVATE SDL3::SDL3) +``` + +Build: ```sh -mkdir hello -cd hello -emcmake cmake .. +emcmake cmake -S . -B build +cd build emmake make ``` -## Building your app - -In this case we'll just run a simple command to compile our source with the SDL library we just built: -```sh -emcc -o index.html ../docs/hello.c -I../include -L. -lSDL3 -``` - -## Running your app - -You can now run your app by pointing a webserver at your build directory and connecting a web browser to it. - -## More information +You can now run your app by pointing a webserver at your build directory and connecting a web browser to it, opening hello.html A more complete example is available at: diff --git a/libs/SDL3/docs/INTRO-visualstudio.md b/libs/SDL3/docs/INTRO-visualstudio.md index 31a16e0a..2cc6100c 100644 --- a/libs/SDL3/docs/INTRO-visualstudio.md +++ b/libs/SDL3/docs/INTRO-visualstudio.md @@ -8,8 +8,7 @@ We'll start by creating a simple project to build and run [hello.c](hello.c) - Create a new project in Visual Studio, using the C++ Empty Project template - Add hello.c to the Source Files - Right click the solution, select add an existing project, navigate to VisualC/SDL and add SDL.vcxproj -- Select your main project and go to Project -> Project Dependencies and select SDL3 -- Select your main project and go to Project -> Properties, set the filter at the top to "All Configurations" and "All Platforms", select VC++ Directories and add the SDL include directory to "Include Directories" - Select your main project and go to Project -> Add Reference and select SDL3 +- Select your main project and go to Project -> Properties, set the filter at the top to "All Configurations" and "All Platforms", select VC++ Directories and add the SDL include directory to "Include Directories" - Build and run! diff --git a/libs/SDL3/docs/README-linux.md b/libs/SDL3/docs/README-linux.md index ce740ea8..3f2d2c05 100644 --- a/libs/SDL3/docs/README-linux.md +++ b/libs/SDL3/docs/README-linux.md @@ -19,7 +19,7 @@ Ubuntu 18.04, all available features enabled: libaudio-dev libjack-dev libsndio-dev libx11-dev libxext-dev \ libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev \ libxkbcommon-dev libdrm-dev libgbm-dev libgl1-mesa-dev libgles2-mesa-dev \ - libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev fcitx-libs-dev + libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev Ubuntu 22.04+ can also add `libpipewire-0.3-dev libwayland-dev libdecor-0-dev liburing-dev` to that command line. @@ -28,7 +28,7 @@ Fedora 35, all available features enabled: sudo yum install gcc git-core make cmake \ alsa-lib-devel pulseaudio-libs-devel nas-devel pipewire-devel \ libX11-devel libXext-devel libXrandr-devel libXcursor-devel libXfixes-devel \ - libXi-devel libXScrnSaver-devel dbus-devel ibus-devel fcitx-devel \ + libXi-devel libXScrnSaver-devel dbus-devel ibus-devel \ systemd-devel mesa-libGL-devel libxkbcommon-devel mesa-libGLES-devel \ mesa-libEGL-devel vulkan-devel wayland-devel wayland-protocols-devel \ libdrm-devel mesa-libgbm-devel libusb-devel libdecor-devel \ @@ -45,6 +45,10 @@ openSUSE Tumbleweed: sudo zypper in libunwind-devel libusb-1_0-devel Mesa-libGL-devel libxkbcommon-devel libdrm-devel \ libgbm-devel pipewire-devel libpulse-devel sndio-devel Mesa-libEGL-devel +Arch: + sudo pacman -S alsa-lib cmake hidapi ibus jack libdecor libgl libpulse libusb libx11 libxcursor libxext libxinerama libxkbcommon libxrandr libxrender libxss mesa ninja pipewire sndio vulkan-driver vulkan-headers wayland wayland-protocols + + Joystick does not work -------------------------------------------------------------------------------- diff --git a/libs/SDL3/docs/README-migration.md b/libs/SDL3/docs/README-migration.md index 84bf315b..deca6d0c 100644 --- a/libs/SDL3/docs/README-migration.md +++ b/libs/SDL3/docs/README-migration.md @@ -193,7 +193,7 @@ Rather than iterating over audio devices using a device index, there are new fun if (devices) { for (i = 0; i < num_devices; ++i) { SDL_AudioDeviceID instance_id = devices[i]; - SDL_Log("AudioDevice %" SDL_PRIu32 ": %s\n", instance_id, SDL_GetAudioDeviceName(instance_id)); + SDL_Log("AudioDevice %" SDL_PRIu32 ": %s", instance_id, SDL_GetAudioDeviceName(instance_id)); } SDL_free(devices); } @@ -411,7 +411,7 @@ The iscapture field of SDL_AudioDeviceEvent has been renamed recording. SDL_QUERY, SDL_IGNORE, SDL_ENABLE, and SDL_DISABLE have been removed. You can use the functions SDL_SetEventEnabled() and SDL_EventEnabled() to set and query event processing state. -SDL_AddEventWatch() now returns SDL_FALSE_ if it fails because it ran out of memory and couldn't add the event watch callback. +SDL_AddEventWatch() now returns false if it fails because it ran out of memory and couldn't add the event watch callback. SDL_RegisterEvents() now returns 0 if it couldn't allocate any user events. @@ -749,7 +749,7 @@ Rather than iterating over haptic devices using device index, there is a new fun if (haptics) { for (i = 0; i < num_haptics; ++i) { SDL_HapticID instance_id = haptics[i]; - SDL_Log("Haptic %" SDL_PRIu32 ": %s\n", instance_id, SDL_GetHapticNameForID(instance_id)); + SDL_Log("Haptic %" SDL_PRIu32 ": %s", instance_id, SDL_GetHapticNameForID(instance_id)); } SDL_free(haptics); } @@ -917,7 +917,7 @@ Rather than iterating over joysticks using device index, there is a new function const char *name = SDL_GetJoystickNameForID(instance_id); const char *path = SDL_GetJoystickPathForID(instance_id); - SDL_Log("Joystick %" SDL_PRIu32 ": %s%s%s VID 0x%.4x, PID 0x%.4x\n", + SDL_Log("Joystick %" SDL_PRIu32 ": %s%s%s VID 0x%.4x, PID 0x%.4x", instance_id, name ? name : "Unknown", path ? ", " : "", path ? path : "", SDL_GetJoystickVendorForID(instance_id), SDL_GetJoystickProductForID(instance_id)); } SDL_free(joysticks); @@ -1696,7 +1696,7 @@ Rather than iterating over sensors using device index, there is a new function S SDL_SensorID *sensors = SDL_GetSensors(&num_sensors); if (sensors) { for (i = 0; i < num_sensors; ++i) { - SDL_Log("Sensor %" SDL_PRIu32 ": %s, type %d, platform type %d\n", + SDL_Log("Sensor %" SDL_PRIu32 ": %s, type %d, platform type %d", sensors[i], SDL_GetSensorNameForID(sensors[i]), SDL_GetSensorTypeForID(sensors[i]), @@ -1845,8 +1845,6 @@ SDL_BlitSurface() and SDL_BlitSurfaceScaled() now have a const `dstrect` paramet SDL_BlitSurfaceScaled() and SDL_BlitSurfaceUncheckedScaled() now take a scale parameter. -SDL_SoftStretch() now takes a scale parameter. - SDL_PixelFormat is used instead of Uint32 for API functions that refer to pixel format by enumerated value. SDL_SetSurfaceColorKey() takes an bool to enable and disable colorkey. RLE acceleration isn't controlled by the parameter, you should use SDL_SetSurfaceRLE() to change that separately. @@ -1880,8 +1878,8 @@ The following functions have been removed: * SDL_GetYUVConversionMode() * SDL_GetYUVConversionModeForResolution() * SDL_SetYUVConversionMode() - use SDL_SetSurfaceColorspace() to set the surface colorspace and SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER with SDL_CreateTextureWithProperties() to set the texture colorspace. The default colorspace for YUV pixel formats is SDL_COLORSPACE_JPEG. -* SDL_SoftStretch() - use SDL_BlitSurfaceScaled() with SDL_SCALEMODE_NEAREST -* SDL_SoftStretchLinear() - use SDL_BlitSurfaceScaled() with SDL_SCALEMODE_LINEAR +* SDL_SoftStretch() - use SDL_StretchSurface() with SDL_SCALEMODE_NEAREST +* SDL_SoftStretchLinear() - use SDL_StretchSurface() with SDL_SCALEMODE_LINEAR The following symbols have been renamed: * SDL_PREALLOC => SDL_SURFACE_PREALLOCATED @@ -2121,7 +2119,7 @@ Rather than iterating over displays using display index, there is a new function SDL_DisplayID instance_id = displays[i]; const char *name = SDL_GetDisplayName(instance_id); - SDL_Log("Display %" SDL_PRIu32 ": %s\n", instance_id, name ? name : "Unknown"); + SDL_Log("Display %" SDL_PRIu32 ": %s", instance_id, name ? name : "Unknown"); } SDL_free(displays); } @@ -2167,7 +2165,7 @@ Rather than iterating over display modes using an index, there is a new function if (modes) { for (i = 0; i < num_modes; ++i) { SDL_DisplayMode *mode = modes[i]; - SDL_Log("Display %" SDL_PRIu32 " mode %d: %dx%d@%gx %gHz\n", + SDL_Log("Display %" SDL_PRIu32 " mode %d: %dx%d@%gx %gHz", display, i, mode->w, mode->h, mode->pixel_density, mode->refresh_rate); } SDL_free(modes); diff --git a/libs/SDL3/docs/hello.c b/libs/SDL3/docs/hello.c index 74a04bc2..a825ea1c 100644 --- a/libs/SDL3/docs/hello.c +++ b/libs/SDL3/docs/hello.c @@ -21,7 +21,7 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) { /* Create the window */ if (!SDL_CreateWindowAndRenderer("Hello World", 800, 600, SDL_WINDOW_FULLSCREEN, &window, &renderer)) { - SDL_Log("Couldn't create window and renderer: %s\n", SDL_GetError()); + SDL_Log("Couldn't create window and renderer: %s", SDL_GetError()); return SDL_APP_FAILURE; } return SDL_APP_CONTINUE; diff --git a/libs/SDL3/examples/audio/01-simple-playback/README.txt b/libs/SDL3/examples/audio/01-simple-playback/README.txt index 9b3c07dd..20ad0598 100644 --- a/libs/SDL3/examples/audio/01-simple-playback/README.txt +++ b/libs/SDL3/examples/audio/01-simple-playback/README.txt @@ -1,5 +1,5 @@ If you're running this in a web browser, you need to click the window before you'll hear anything! -This example code creates an simple audio stream for playing sound, and +This example code creates a simple audio stream for playing sound, and generates a sine wave sound effect for it to play as time goes on. This is the simplest way to get up and running with procedural sound. diff --git a/libs/SDL3/examples/audio/01-simple-playback/simple-playback.c b/libs/SDL3/examples/audio/01-simple-playback/simple-playback.c index 35ddf8a8..15126e56 100644 --- a/libs/SDL3/examples/audio/01-simple-playback/simple-playback.c +++ b/libs/SDL3/examples/audio/01-simple-playback/simple-playback.c @@ -1,5 +1,5 @@ /* - * This example code creates an simple audio stream for playing sound, and + * This example code creates a simple audio stream for playing sound, and * generates a sine wave sound effect for it to play as time goes on. This * is the simplest way to get up and running with procedural sound. * @@ -69,7 +69,7 @@ SDL_AppResult SDL_AppIterate(void *appstate) A sine wave is unchanging audio--easy to stream--but for video games, you'll want to generate significantly _less_ audio ahead of time! */ const int minimum_audio = (8000 * sizeof (float)) / 2; /* 8000 float samples per second. Half of that. */ - if (SDL_GetAudioStreamAvailable(stream) < minimum_audio) { + if (SDL_GetAudioStreamQueued(stream) < minimum_audio) { static float samples[512]; /* this will feed 512 samples each frame until we get to our maximum. */ int i; diff --git a/libs/SDL3/examples/audio/02-simple-playback-callback/README.txt b/libs/SDL3/examples/audio/02-simple-playback-callback/README.txt index e719256d..888ae349 100644 --- a/libs/SDL3/examples/audio/02-simple-playback-callback/README.txt +++ b/libs/SDL3/examples/audio/02-simple-playback-callback/README.txt @@ -1,5 +1,5 @@ If you're running this in a web browser, you need to click the window before you'll hear anything! -This example code creates an simple audio stream for playing sound, and +This example code creates a simple audio stream for playing sound, and generates a sine wave sound effect for it to play as time goes on. Unlike the previous example, this uses a callback to generate sound. diff --git a/libs/SDL3/examples/audio/02-simple-playback-callback/simple-playback-callback.c b/libs/SDL3/examples/audio/02-simple-playback-callback/simple-playback-callback.c index 5a783619..c011c727 100644 --- a/libs/SDL3/examples/audio/02-simple-playback-callback/simple-playback-callback.c +++ b/libs/SDL3/examples/audio/02-simple-playback-callback/simple-playback-callback.c @@ -1,5 +1,5 @@ /* - * This example code creates an simple audio stream for playing sound, and + * This example code creates a simple audio stream for playing sound, and * generates a sine wave sound effect for it to play as time goes on. Unlike * the previous example, this uses a callback to generate sound. * diff --git a/libs/SDL3/examples/audio/03-load-wav/README.txt b/libs/SDL3/examples/audio/03-load-wav/README.txt index 5a6894c7..57eb90ce 100644 --- a/libs/SDL3/examples/audio/03-load-wav/README.txt +++ b/libs/SDL3/examples/audio/03-load-wav/README.txt @@ -1,5 +1,5 @@ If you're running this in a web browser, you need to click the window before you'll hear anything! -This example code creates an simple audio stream for playing sound, and +This example code creates a simple audio stream for playing sound, and loads a .wav file that is pushed through the stream in a loop. diff --git a/libs/SDL3/examples/audio/03-load-wav/load-wav.c b/libs/SDL3/examples/audio/03-load-wav/load-wav.c index 7a4adf0c..c517e5d6 100644 --- a/libs/SDL3/examples/audio/03-load-wav/load-wav.c +++ b/libs/SDL3/examples/audio/03-load-wav/load-wav.c @@ -1,5 +1,5 @@ /* - * This example code creates an simple audio stream for playing sound, and + * This example code creates a simple audio stream for playing sound, and * loads a .wav file that is pushed through the stream in a loop. * * This code is public domain. Feel free to use it for any purpose! @@ -82,7 +82,7 @@ SDL_AppResult SDL_AppIterate(void *appstate) We're being lazy here, but if there's less than the entire wav file left to play, just shove a whole copy of it into the queue, so we always have _tons_ of data queued for playback. */ - if (SDL_GetAudioStreamAvailable(stream) < (int)wav_data_len) { + if (SDL_GetAudioStreamQueued(stream) < (int)wav_data_len) { /* feed more data to the stream. It will queue at the end, and trickle out as the hardware needs more data. */ SDL_PutAudioStreamData(stream, wav_data, wav_data_len); } diff --git a/libs/SDL3/examples/audio/04-multiple-streams/multiple-streams.c b/libs/SDL3/examples/audio/04-multiple-streams/multiple-streams.c index 57f3cd0e..8d3bfaa0 100644 --- a/libs/SDL3/examples/audio/04-multiple-streams/multiple-streams.c +++ b/libs/SDL3/examples/audio/04-multiple-streams/multiple-streams.c @@ -104,7 +104,7 @@ SDL_AppResult SDL_AppIterate(void *appstate) /* If less than a full copy of the audio is queued for playback, put another copy in there. This is overkill, but easy when lots of RAM is cheap. One could be more careful and queue less at a time, as long as the stream doesn't run dry. */ - if (SDL_GetAudioStreamAvailable(sounds[i].stream) < ((int) sounds[i].wav_data_len)) { + if (SDL_GetAudioStreamQueued(sounds[i].stream) < ((int) sounds[i].wav_data_len)) { SDL_PutAudioStreamData(sounds[i].stream, sounds[i].wav_data, (int) sounds[i].wav_data_len); } } diff --git a/libs/SDL3/examples/demo/01-snake/snake.c b/libs/SDL3/examples/demo/01-snake/snake.c index a7f667d5..0aca862d 100644 --- a/libs/SDL3/examples/demo/01-snake/snake.c +++ b/libs/SDL3/examples/demo/01-snake/snake.c @@ -208,7 +208,7 @@ void snake_step(SnakeContext *ctx) } } -static int handle_key_event_(SnakeContext *ctx, SDL_Scancode key_code) +static SDL_AppResult handle_key_event_(SnakeContext *ctx, SDL_Scancode key_code) { switch (key_code) { /* Quit. */ @@ -309,7 +309,7 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) return SDL_APP_FAILURE; } - AppState *as = SDL_calloc(1, sizeof(AppState)); + AppState *as = (AppState *)SDL_calloc(1, sizeof(AppState)); if (!as) { return SDL_APP_FAILURE; } diff --git a/libs/SDL3/examples/demo/04-bytepusher/bytepusher.c b/libs/SDL3/examples/demo/04-bytepusher/bytepusher.c index 01b0e1a4..acb2ea48 100644 --- a/libs/SDL3/examples/demo/04-bytepusher/bytepusher.c +++ b/libs/SDL3/examples/demo/04-bytepusher/bytepusher.c @@ -156,7 +156,7 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) { return SDL_APP_FAILURE; } - if (!(vm = SDL_calloc(1, sizeof(*vm)))) { + if (!(vm = (BytePusher *)SDL_calloc(1, sizeof(*vm)))) { return SDL_APP_FAILURE; } *(BytePusher**)appstate = vm; @@ -199,7 +199,7 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) { for (r = 0; r < 6; ++r) { for (g = 0; g < 6; ++g) { for (b = 0; b < 6; ++b, ++i) { - SDL_Color color = { r * 0x33, g * 0x33, b * 0x33, SDL_ALPHA_OPAQUE }; + SDL_Color color = { (Uint8)(r * 0x33), (Uint8)(g * 0x33), (Uint8)(b * 0x33), SDL_ALPHA_OPAQUE }; palette->colors[i] = color; } } diff --git a/libs/SDL3/examples/input/01-joystick-polling/joystick-polling.c b/libs/SDL3/examples/input/01-joystick-polling/joystick-polling.c index 8f7a3156..6eb23b83 100644 --- a/libs/SDL3/examples/input/01-joystick-polling/joystick-polling.c +++ b/libs/SDL3/examples/input/01-joystick-polling/joystick-polling.c @@ -105,7 +105,7 @@ SDL_AppResult SDL_AppIterate(void *appstate) /* draw axes as bars going across middle of screen. We don't know if it's an X or Y or whatever axis, so we can't do more than this. */ total = SDL_GetNumJoystickAxes(joystick); - y = (float) ((winh - (total * size)) / 2); + y = (winh - (total * size)) / 2; x = ((float) winw) / 2.0f; for (i = 0; i < total; i++) { const SDL_Color *color = &colors[i % SDL_arraysize(colors)]; @@ -119,7 +119,7 @@ SDL_AppResult SDL_AppIterate(void *appstate) /* draw buttons as blocks across top of window. We only know the button numbers, but not where they are on the device. */ total = SDL_GetNumJoystickButtons(joystick); - x = (float) ((winw - (total * size)) / 2); + x = (winw - (total * size)) / 2; for (i = 0; i < total; i++) { const SDL_Color *color = &colors[i % SDL_arraysize(colors)]; const SDL_FRect dst = { x, 0.0f, size, size }; @@ -136,7 +136,7 @@ SDL_AppResult SDL_AppIterate(void *appstate) /* draw hats across the bottom of the screen. */ total = SDL_GetNumJoystickHats(joystick); - x = ((float) ((winw - (total * (size * 2.0f))) / 2.0f)) + (size / 2.0f); + x = ((winw - (total * (size * 2.0f))) / 2.0f) + (size / 2.0f); y = ((float) winh) - size; for (i = 0; i < total; i++) { const SDL_Color *color = &colors[i % SDL_arraysize(colors)]; diff --git a/libs/SDL3/examples/pen/01-drawing-lines/drawing-lines.c b/libs/SDL3/examples/pen/01-drawing-lines/drawing-lines.c index a530ab60..d0d78eaf 100644 --- a/libs/SDL3/examples/pen/01-drawing-lines/drawing-lines.c +++ b/libs/SDL3/examples/pen/01-drawing-lines/drawing-lines.c @@ -19,6 +19,8 @@ static SDL_Texture *render_target = NULL; static float pressure = 0.0f; static float previous_touch_x = -1.0f; static float previous_touch_y = -1.0f; +static float tilt_x = 0.0f; +static float tilt_y = 0.0f; /* This function runs once at startup. */ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) @@ -84,6 +86,10 @@ SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) } else if (event->type == SDL_EVENT_PEN_AXIS) { if (event->paxis.axis == SDL_PEN_AXIS_PRESSURE) { pressure = event->paxis.value; /* remember new pressure for later draws. */ + } else if(event->paxis.axis == SDL_PEN_AXIS_XTILT) { + tilt_x = event->paxis.value; + } else if(event->paxis.axis == SDL_PEN_AXIS_YTILT) { + tilt_y = event->paxis.value; } } @@ -93,11 +99,15 @@ SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) /* This function runs once per frame, and is the heart of the program. */ SDL_AppResult SDL_AppIterate(void *appstate) { + char debug_text[1024]; + /* make sure we're drawing to the window and not the render target */ SDL_SetRenderTarget(renderer, NULL); SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); SDL_RenderClear(renderer); /* just in case. */ SDL_RenderTexture(renderer, render_target, NULL, NULL); + SDL_snprintf(debug_text, sizeof(debug_text), "Tilt: %f %f", tilt_x, tilt_y); + SDL_RenderDebugText(renderer, 0, 8, debug_text); SDL_RenderPresent(renderer); return SDL_APP_CONTINUE; /* carry on with the program! */ } diff --git a/libs/SDL3/examples/renderer/09-scaling-textures/scaling-textures.c b/libs/SDL3/examples/renderer/09-scaling-textures/scaling-textures.c index 71a94c65..66060ed7 100644 --- a/libs/SDL3/examples/renderer/09-scaling-textures/scaling-textures.c +++ b/libs/SDL3/examples/renderer/09-scaling-textures/scaling-textures.c @@ -92,8 +92,8 @@ SDL_AppResult SDL_AppIterate(void *appstate) /* 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; + dst_rect.x = (WINDOW_WIDTH - dst_rect.w) / 2.0f; + dst_rect.y = (WINDOW_HEIGHT - dst_rect.h) / 2.0f; SDL_RenderTexture(renderer, texture, NULL, &dst_rect); SDL_RenderPresent(renderer); /* put it all on the screen! */ diff --git a/libs/SDL3/examples/renderer/10-geometry/geometry.c b/libs/SDL3/examples/renderer/10-geometry/geometry.c index ffe71115..77ff863c 100644 --- a/libs/SDL3/examples/renderer/10-geometry/geometry.c +++ b/libs/SDL3/examples/renderer/10-geometry/geometry.c @@ -141,7 +141,7 @@ SDL_AppResult SDL_AppIterate(void *appstate) /* 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].color.r = vertices[3].color.g = vertices[3].color.b = vertices[3].color.a = 1.0f; vertices[3].tex_coord.x = 1.0f; vertices[3].tex_coord.y = 1.0f; diff --git a/libs/SDL3/include/SDL3/SDL.h b/libs/SDL3/include/SDL3/SDL.h index 861c404f..f8586ad4 100644 --- a/libs/SDL3/include/SDL3/SDL.h +++ b/libs/SDL3/include/SDL3/SDL.h @@ -20,7 +20,7 @@ */ /** - * Main include header for the SDL library, version 3.2.0 + * Main include header for the SDL library, version 3.2.6 * * It is almost always best to include just this one header instead of * picking out individual headers included here. There are exceptions to diff --git a/libs/SDL3/include/SDL3/SDL_assert.h b/libs/SDL3/include/SDL3/SDL_assert.h index 09b3b478..6c90acc0 100644 --- a/libs/SDL3/include/SDL3/SDL_assert.h +++ b/libs/SDL3/include/SDL3/SDL_assert.h @@ -149,6 +149,8 @@ extern "C" { #define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "bkpt #22\n\t" ) #elif defined(_WIN32) && ((defined(__GNUC__) || defined(__clang__)) && (defined(__arm64__) || defined(__aarch64__)) ) #define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "brk #0xF000\n\t" ) +#elif defined(__GNUC__) || defined(__clang__) + #define SDL_TriggerBreakpoint() __builtin_trap() /* older gcc may not support SDL_HAS_BUILTIN(__builtin_trap) above */ #elif defined(__386__) && defined(__WATCOMC__) #define SDL_TriggerBreakpoint() { _asm { int 0x03 } } #elif defined(HAVE_SIGNAL_H) && !defined(__WATCOMC__) diff --git a/libs/SDL3/include/SDL3/SDL_atomic.h b/libs/SDL3/include/SDL3/SDL_atomic.h index 03e3fb13..78b5e0fa 100644 --- a/libs/SDL3/include/SDL3/SDL_atomic.h +++ b/libs/SDL3/include/SDL3/SDL_atomic.h @@ -498,7 +498,7 @@ extern SDL_DECLSPEC int SDLCALL SDL_AddAtomicInt(SDL_AtomicInt *a, int v); * * ***Note: If you don't know what this macro is for, you shouldn't use it!*** * - * \param a a pointer to an SDL_AtomicInt to increment. + * \param a a pointer to an SDL_AtomicInt to decrement. * \returns true if the variable reached zero after decrementing, false * otherwise. * diff --git a/libs/SDL3/include/SDL3/SDL_audio.h b/libs/SDL3/include/SDL3/SDL_audio.h index 95693821..541c5dfb 100644 --- a/libs/SDL3/include/SDL3/SDL_audio.h +++ b/libs/SDL3/include/SDL3/SDL_audio.h @@ -781,7 +781,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_IsAudioDevicePlayback(SDL_AudioDeviceID dev * Physical devices can not be paused or unpaused, only logical devices * created through SDL_OpenAudioDevice() can be. * - * \param dev a device opened by SDL_OpenAudioDevice(). + * \param devid a device opened by SDL_OpenAudioDevice(). * \returns true on success or false on failure; call SDL_GetError() for more * information. * @@ -792,7 +792,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_IsAudioDevicePlayback(SDL_AudioDeviceID dev * \sa SDL_ResumeAudioDevice * \sa SDL_AudioDevicePaused */ -extern SDL_DECLSPEC bool SDLCALL SDL_PauseAudioDevice(SDL_AudioDeviceID dev); +extern SDL_DECLSPEC bool SDLCALL SDL_PauseAudioDevice(SDL_AudioDeviceID devid); /** * Use this function to unpause audio playback on a specified device. @@ -809,7 +809,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_PauseAudioDevice(SDL_AudioDeviceID dev); * Physical devices can not be paused or unpaused, only logical devices * created through SDL_OpenAudioDevice() can be. * - * \param dev a device opened by SDL_OpenAudioDevice(). + * \param devid a device opened by SDL_OpenAudioDevice(). * \returns true on success or false on failure; call SDL_GetError() for more * information. * @@ -820,7 +820,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_PauseAudioDevice(SDL_AudioDeviceID dev); * \sa SDL_AudioDevicePaused * \sa SDL_PauseAudioDevice */ -extern SDL_DECLSPEC bool SDLCALL SDL_ResumeAudioDevice(SDL_AudioDeviceID dev); +extern SDL_DECLSPEC bool SDLCALL SDL_ResumeAudioDevice(SDL_AudioDeviceID devid); /** * Use this function to query if an audio device is paused. @@ -832,7 +832,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ResumeAudioDevice(SDL_AudioDeviceID dev); * created through SDL_OpenAudioDevice() can be. Physical and invalid device * IDs will report themselves as unpaused here. * - * \param dev a device opened by SDL_OpenAudioDevice(). + * \param devid a device opened by SDL_OpenAudioDevice(). * \returns true if device is valid and paused, false otherwise. * * \threadsafety It is safe to call this function from any thread. @@ -842,7 +842,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ResumeAudioDevice(SDL_AudioDeviceID dev); * \sa SDL_PauseAudioDevice * \sa SDL_ResumeAudioDevice */ -extern SDL_DECLSPEC bool SDLCALL SDL_AudioDevicePaused(SDL_AudioDeviceID dev); +extern SDL_DECLSPEC bool SDLCALL SDL_AudioDevicePaused(SDL_AudioDeviceID devid); /** * Get the gain of an audio device. @@ -1583,6 +1583,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_PauseAudioStreamDevice(SDL_AudioStream *str * previously been paused. Once unpaused, any bound audio streams will begin * to progress again, and audio can be generated. * + * Remember, SDL_OpenAudioDeviceStream opens device in a paused state, so this + * function call is required for audio playback to begin on such device. + * * \param stream the audio stream associated with the audio device to resume. * \returns true on success or false on failure; call SDL_GetError() for more * information. diff --git a/libs/SDL3/include/SDL3/SDL_camera.h b/libs/SDL3/include/SDL3/SDL_camera.h index c4d05962..5f3911fd 100644 --- a/libs/SDL3/include/SDL3/SDL_camera.h +++ b/libs/SDL3/include/SDL3/SDL_camera.h @@ -239,7 +239,7 @@ extern SDL_DECLSPEC SDL_CameraID * SDLCALL SDL_GetCameras(int *count); * there _is_ a camera until the user has given you permission to check * through a scary warning popup. * - * \param devid the camera device instance ID to query. + * \param instance_id the camera device instance ID. * \param count a pointer filled in with the number of elements in the list, * may be NULL. * \returns a NULL terminated array of pointers to SDL_CameraSpec or NULL on @@ -254,7 +254,7 @@ extern SDL_DECLSPEC SDL_CameraID * SDLCALL SDL_GetCameras(int *count); * \sa SDL_GetCameras * \sa SDL_OpenCamera */ -extern SDL_DECLSPEC SDL_CameraSpec ** SDLCALL SDL_GetCameraSupportedFormats(SDL_CameraID devid, int *count); +extern SDL_DECLSPEC SDL_CameraSpec ** SDLCALL SDL_GetCameraSupportedFormats(SDL_CameraID instance_id, int *count); /** * Get the human-readable device name for a camera. diff --git a/libs/SDL3/include/SDL3/SDL_dialog.h b/libs/SDL3/include/SDL3/SDL_dialog.h index 460038ff..ddb9e24d 100644 --- a/libs/SDL3/include/SDL3/SDL_dialog.h +++ b/libs/SDL3/include/SDL3/SDL_dialog.h @@ -84,8 +84,8 @@ typedef struct SDL_DialogFileFilter * - A pointer to NULL, the user either didn't choose any file or canceled the * dialog. * - A pointer to non-`NULL`, the user chose one or more files. The argument - * is a null-terminated list of pointers to C strings, each containing a - * path. + * is a null-terminated array of pointers to UTF-8 encoded strings, each + * containing a path. * * The filelist argument should not be freed; it will automatically be freed * when the callback returns. diff --git a/libs/SDL3/include/SDL3/SDL_events.h b/libs/SDL3/include/SDL3/SDL_events.h index 1323e9f0..56a2194b 100644 --- a/libs/SDL3/include/SDL3/SDL_events.h +++ b/libs/SDL3/include/SDL3/SDL_events.h @@ -132,7 +132,7 @@ typedef enum SDL_EventType /* Window events */ /* 0x200 was SDL_WINDOWEVENT, reserve the number for sdl2-compat */ - /* 0x201 was SDL_EVENT_SYSWM, reserve the number for sdl2-compat */ + /* 0x201 was SDL_SYSWMEVENT, reserve the number for sdl2-compat */ SDL_EVENT_WINDOW_SHOWN = 0x202, /**< Window has been shown */ SDL_EVENT_WINDOW_HIDDEN, /**< Window has been hidden */ SDL_EVENT_WINDOW_EXPOSED, /**< Window has been exposed and should be redrawn, and can be redrawn directly from event watchers for this event */ @@ -1108,7 +1108,7 @@ typedef enum SDL_EventAction * \param numevents if action is SDL_ADDEVENT, the number of events to add * back to the event queue; if action is SDL_PEEKEVENT or * SDL_GETEVENT, the maximum number of events to retrieve. - * \param action action to take; see [[#action|Remarks]] for details. + * \param action action to take; see [Remarks](#remarks) for details. * \param minType minimum value of the event type to be considered; * SDL_EVENT_FIRST is a safe choice. * \param maxType maximum value of the event type to be considered; diff --git a/libs/SDL3/include/SDL3/SDL_gamepad.h b/libs/SDL3/include/SDL3/SDL_gamepad.h index 264f763b..99f8b659 100644 --- a/libs/SDL3/include/SDL3/SDL_gamepad.h +++ b/libs/SDL3/include/SDL3/SDL_gamepad.h @@ -29,7 +29,7 @@ * "joysticks" now are actually console-style gamepads. So SDL provides the * gamepad API on top of the lower-level joystick functionality. * - * The difference betweena joystick and a gamepad is that a gamepad tells you + * The difference between a joystick and a gamepad is that a gamepad tells you * _where_ a button or axis is on the device. You don't speak to gamepads in * terms of arbitrary numbers like "button 3" or "axis 2" but in standard * locations: the d-pad, the shoulder buttons, triggers, A/B/X/Y (or diff --git a/libs/SDL3/include/SDL3/SDL_gpu.h b/libs/SDL3/include/SDL3/SDL_gpu.h index fa870a57..818ca7e7 100644 --- a/libs/SDL3/include/SDL3/SDL_gpu.h +++ b/libs/SDL3/include/SDL3/SDL_gpu.h @@ -35,13 +35,14 @@ * can render offscreen entirely, perhaps for image processing, and not use a * window at all. * - * Next the app prepares static data (things that are created once and used + * Next, the app prepares static data (things that are created once and used * over and over). For example: * * - Shaders (programs that run on the GPU): use SDL_CreateGPUShader(). - * - Vertex buffers (arrays of geometry data) and other data rendering will - * need: use SDL_UploadToGPUBuffer(). - * - Textures (images): use SDL_UploadToGPUTexture(). + * - Vertex buffers (arrays of geometry data) and other rendering data: use + * SDL_CreateGPUBuffer() and SDL_UploadToGPUBuffer(). + * - Textures (images): use SDL_CreateGPUTexture() and + * SDL_UploadToGPUTexture(). * - Samplers (how textures should be read from): use SDL_CreateGPUSampler(). * - Render pipelines (precalculated rendering state): use * SDL_CreateGPUGraphicsPipeline() @@ -130,7 +131,8 @@ * It is optimal for apps to pre-compile the shader formats they might use, * but for ease of use SDL provides a separate project, * [SDL_shadercross](https://github.com/libsdl-org/SDL_shadercross) - * , for performing runtime shader cross-compilation. + * , for performing runtime shader cross-compilation. It also has a CLI + * interface for offline precompilation as well. * * This is an extremely quick overview that leaves out several important * details. Already, though, one can see that GPU programming can be quite @@ -888,6 +890,10 @@ typedef enum SDL_GPUCubeMapFace * Unlike textures, READ | WRITE can be used for simultaneous read-write * usage. The same data synchronization concerns as textures apply. * + * If you use a STORAGE flag, the data in the buffer must respect std140 + * layout conventions. In practical terms this means you must ensure that vec3 + * and vec4 fields are 16-byte aligned. + * * \since This datatype is available since SDL 3.2.0. * * \sa SDL_CreateGPUBuffer @@ -1361,6 +1367,7 @@ typedef struct SDL_GPUTextureLocation * * \sa SDL_UploadToGPUTexture * \sa SDL_DownloadFromGPUTexture + * \sa SDL_CreateGPUTexture */ typedef struct SDL_GPUTextureRegion { @@ -1489,9 +1496,16 @@ typedef struct SDL_GPUIndirectDispatchCommand /** * A structure specifying the parameters of a sampler. * + * Note that mip_lod_bias is a no-op for the Metal driver. For Metal, LOD bias + * must be applied via shader instead. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_CreateGPUSampler + * \sa SDL_GPUFilter + * \sa SDL_GPUSamplerMipmapMode + * \sa SDL_GPUSamplerAddressMode + * \sa SDL_GPUCompareOp */ typedef struct SDL_GPUSamplerCreateInfo { @@ -1530,14 +1544,14 @@ typedef struct SDL_GPUSamplerCreateInfo * \since This struct is available since SDL 3.2.0. * * \sa SDL_GPUVertexAttribute - * \sa SDL_GPUVertexInputState + * \sa SDL_GPUVertexInputRate */ typedef struct SDL_GPUVertexBufferDescription { Uint32 slot; /**< The binding slot of the vertex buffer. */ Uint32 pitch; /**< The byte pitch between consecutive elements of the vertex buffer. */ SDL_GPUVertexInputRate input_rate; /**< Whether attribute addressing is a function of the vertex index or instance index. */ - Uint32 instance_step_rate; /**< The number of instances to draw using the same per-instance data before advancing in the instance buffer by one element. Ignored unless input_rate is SDL_GPU_VERTEXINPUTRATE_INSTANCE */ + Uint32 instance_step_rate; /**< Reserved for future use. Must be set to 0. */ } SDL_GPUVertexBufferDescription; /** @@ -1550,6 +1564,7 @@ typedef struct SDL_GPUVertexBufferDescription * * \sa SDL_GPUVertexBufferDescription * \sa SDL_GPUVertexInputState + * \sa SDL_GPUVertexElementFormat */ typedef struct SDL_GPUVertexAttribute { @@ -1706,10 +1721,13 @@ typedef struct SDL_GPUTransferBufferCreateInfo * A structure specifying the parameters of the graphics pipeline rasterizer * state. * - * NOTE: Some backend APIs (D3D11/12) will enable depth clamping even if - * enable_depth_clip is true. If you rely on this clamp+clip behavior, - * consider enabling depth clip and then manually clamping depth in your - * fragment shaders on Metal and Vulkan. + * Note that SDL_GPU_FILLMODE_LINE is not supported on many Android devices. + * For those devices, the fill mode will automatically fall back to FILL. + * + * Also note that the D3D12 driver will enable depth clamping even if + * enable_depth_clip is true. If you need this clamp+clip behavior, consider + * enabling depth clip and then manually clamping depth in your fragment + * shaders on Metal and Vulkan. * * \since This struct is available since SDL 3.2.0. * @@ -1740,8 +1758,8 @@ typedef struct SDL_GPURasterizerState typedef struct SDL_GPUMultisampleState { SDL_GPUSampleCount sample_count; /**< The number of samples to be used in rasterization. */ - Uint32 sample_mask; /**< Determines which samples get updated in the render targets. Treated as 0xFFFFFFFF if enable_mask is false. */ - bool enable_mask; /**< Enables sample masking. */ + Uint32 sample_mask; /**< Reserved for future use. Must be set to 0. */ + bool enable_mask; /**< Reserved for future use. Must be set to false. */ Uint8 padding1; Uint8 padding2; Uint8 padding3; @@ -1791,6 +1809,8 @@ typedef struct SDL_GPUColorTargetDescription * \since This struct is available since SDL 3.2.0. * * \sa SDL_GPUGraphicsPipelineCreateInfo + * \sa SDL_GPUColorTargetDescription + * \sa SDL_GPUTextureFormat */ typedef struct SDL_GPUGraphicsPipelineTargetInfo { @@ -1809,6 +1829,7 @@ typedef struct SDL_GPUGraphicsPipelineTargetInfo * \since This struct is available since SDL 3.2.0. * * \sa SDL_CreateGPUGraphicsPipeline + * \sa SDL_GPUShader * \sa SDL_GPUVertexInputState * \sa SDL_GPUPrimitiveType * \sa SDL_GPURasterizerState @@ -1836,6 +1857,7 @@ typedef struct SDL_GPUGraphicsPipelineCreateInfo * \since This struct is available since SDL 3.2.0. * * \sa SDL_CreateGPUComputePipeline + * \sa SDL_GPUShaderFormat */ typedef struct SDL_GPUComputePipelineCreateInfo { @@ -2104,7 +2126,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GPUSupportsProperties( * \sa SDL_DestroyGPUDevice * \sa SDL_GPUSupportsShaderFormats */ -extern SDL_DECLSPEC SDL_GPUDevice *SDLCALL SDL_CreateGPUDevice( +extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDevice( SDL_GPUShaderFormat format_flags, bool debug_mode, const char *name); @@ -2152,7 +2174,7 @@ extern SDL_DECLSPEC SDL_GPUDevice *SDLCALL SDL_CreateGPUDevice( * \sa SDL_DestroyGPUDevice * \sa SDL_GPUSupportsProperties */ -extern SDL_DECLSPEC SDL_GPUDevice *SDLCALL SDL_CreateGPUDeviceWithProperties( +extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDeviceWithProperties( SDL_PropertiesID props); #define SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN "SDL.gpu.device.create.debugmode" @@ -2275,7 +2297,7 @@ extern SDL_DECLSPEC SDL_GPUShaderFormat SDLCALL SDL_GetGPUShaderFormats(SDL_GPUD * \sa SDL_BindGPUComputePipeline * \sa SDL_ReleaseGPUComputePipeline */ -extern SDL_DECLSPEC SDL_GPUComputePipeline *SDLCALL SDL_CreateGPUComputePipeline( +extern SDL_DECLSPEC SDL_GPUComputePipeline * SDLCALL SDL_CreateGPUComputePipeline( SDL_GPUDevice *device, const SDL_GPUComputePipelineCreateInfo *createinfo); @@ -2302,7 +2324,7 @@ extern SDL_DECLSPEC SDL_GPUComputePipeline *SDLCALL SDL_CreateGPUComputePipeline * \sa SDL_BindGPUGraphicsPipeline * \sa SDL_ReleaseGPUGraphicsPipeline */ -extern SDL_DECLSPEC SDL_GPUGraphicsPipeline *SDLCALL SDL_CreateGPUGraphicsPipeline( +extern SDL_DECLSPEC SDL_GPUGraphicsPipeline * SDLCALL SDL_CreateGPUGraphicsPipeline( SDL_GPUDevice *device, const SDL_GPUGraphicsPipelineCreateInfo *createinfo); @@ -2329,7 +2351,7 @@ extern SDL_DECLSPEC SDL_GPUGraphicsPipeline *SDLCALL SDL_CreateGPUGraphicsPipeli * \sa SDL_BindGPUFragmentSamplers * \sa SDL_ReleaseGPUSampler */ -extern SDL_DECLSPEC SDL_GPUSampler *SDLCALL SDL_CreateGPUSampler( +extern SDL_DECLSPEC SDL_GPUSampler * SDLCALL SDL_CreateGPUSampler( SDL_GPUDevice *device, const SDL_GPUSamplerCreateInfo *createinfo); @@ -2408,7 +2430,7 @@ extern SDL_DECLSPEC SDL_GPUSampler *SDLCALL SDL_CreateGPUSampler( * \sa SDL_CreateGPUGraphicsPipeline * \sa SDL_ReleaseGPUShader */ -extern SDL_DECLSPEC SDL_GPUShader *SDLCALL SDL_CreateGPUShader( +extern SDL_DECLSPEC SDL_GPUShader * SDLCALL SDL_CreateGPUShader( SDL_GPUDevice *device, const SDL_GPUShaderCreateInfo *createinfo); @@ -2469,7 +2491,7 @@ extern SDL_DECLSPEC SDL_GPUShader *SDLCALL SDL_CreateGPUShader( * \sa SDL_ReleaseGPUTexture * \sa SDL_GPUTextureSupportsFormat */ -extern SDL_DECLSPEC SDL_GPUTexture *SDLCALL SDL_CreateGPUTexture( +extern SDL_DECLSPEC SDL_GPUTexture * SDLCALL SDL_CreateGPUTexture( SDL_GPUDevice *device, const SDL_GPUTextureCreateInfo *createinfo); @@ -2490,6 +2512,10 @@ extern SDL_DECLSPEC SDL_GPUTexture *SDLCALL SDL_CreateGPUTexture( * Note that certain combinations of usage flags are invalid. For example, a * buffer cannot have both the VERTEX and INDEX flags. * + * If you use a STORAGE flag, the data in the buffer must respect std140 + * layout conventions. In practical terms this means you must ensure that vec3 + * and vec4 fields are 16-byte aligned. + * * For better understanding of underlying concepts and memory management with * SDL GPU API, you may refer * [this blog post](https://moonside.games/posts/sdl-gpu-concepts-cycling/) @@ -2521,7 +2547,7 @@ extern SDL_DECLSPEC SDL_GPUTexture *SDLCALL SDL_CreateGPUTexture( * \sa SDL_DispatchGPUComputeIndirect * \sa SDL_ReleaseGPUBuffer */ -extern SDL_DECLSPEC SDL_GPUBuffer *SDLCALL SDL_CreateGPUBuffer( +extern SDL_DECLSPEC SDL_GPUBuffer * SDLCALL SDL_CreateGPUBuffer( SDL_GPUDevice *device, const SDL_GPUBufferCreateInfo *createinfo); @@ -2554,7 +2580,7 @@ extern SDL_DECLSPEC SDL_GPUBuffer *SDLCALL SDL_CreateGPUBuffer( * \sa SDL_DownloadFromGPUTexture * \sa SDL_ReleaseGPUTransferBuffer */ -extern SDL_DECLSPEC SDL_GPUTransferBuffer *SDLCALL SDL_CreateGPUTransferBuffer( +extern SDL_DECLSPEC SDL_GPUTransferBuffer * SDLCALL SDL_CreateGPUTransferBuffer( SDL_GPUDevice *device, const SDL_GPUTransferBufferCreateInfo *createinfo); @@ -2782,7 +2808,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_ReleaseGPUGraphicsPipeline( * \sa SDL_SubmitGPUCommandBuffer * \sa SDL_SubmitGPUCommandBufferAndAcquireFence */ -extern SDL_DECLSPEC SDL_GPUCommandBuffer *SDLCALL SDL_AcquireGPUCommandBuffer( +extern SDL_DECLSPEC SDL_GPUCommandBuffer * SDLCALL SDL_AcquireGPUCommandBuffer( SDL_GPUDevice *device); /* Uniform Data */ @@ -2792,6 +2818,10 @@ extern SDL_DECLSPEC SDL_GPUCommandBuffer *SDLCALL SDL_AcquireGPUCommandBuffer( * * Subsequent draw calls will use this uniform data. * + * The data being pushed must respect std140 layout conventions. In practical + * terms this means you must ensure that vec3 and vec4 fields are 16-byte + * aligned. + * * \param command_buffer a command buffer. * \param slot_index the vertex uniform slot to push data to. * \param data client data to write. @@ -2810,6 +2840,10 @@ extern SDL_DECLSPEC void SDLCALL SDL_PushGPUVertexUniformData( * * Subsequent draw calls will use this uniform data. * + * The data being pushed must respect std140 layout conventions. In practical + * terms this means you must ensure that vec3 and vec4 fields are 16-byte + * aligned. + * * \param command_buffer a command buffer. * \param slot_index the fragment uniform slot to push data to. * \param data client data to write. @@ -2828,6 +2862,10 @@ extern SDL_DECLSPEC void SDLCALL SDL_PushGPUFragmentUniformData( * * Subsequent draw calls will use this uniform data. * + * The data being pushed must respect std140 layout conventions. In practical + * terms this means you must ensure that vec3 and vec4 fields are 16-byte + * aligned. + * * \param command_buffer a command buffer. * \param slot_index the uniform slot to push data to. * \param data client data to write. @@ -2868,7 +2906,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_PushGPUComputeUniformData( * * \sa SDL_EndGPURenderPass */ -extern SDL_DECLSPEC SDL_GPURenderPass *SDLCALL SDL_BeginGPURenderPass( +extern SDL_DECLSPEC SDL_GPURenderPass * SDLCALL SDL_BeginGPURenderPass( SDL_GPUCommandBuffer *command_buffer, const SDL_GPUColorTargetInfo *color_target_infos, Uint32 num_color_targets, @@ -2978,6 +3016,9 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUIndexBuffer( * * The textures must have been created with SDL_GPU_TEXTUREUSAGE_SAMPLER. * + * Be sure your shader is set up according to the requirements documented in + * SDL_CreateGPUShader(). + * * \param render_pass a render pass handle. * \param first_slot the vertex sampler slot to begin binding from. * \param texture_sampler_bindings an array of texture-sampler binding @@ -2986,6 +3027,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUIndexBuffer( * array. * * \since This function is available since SDL 3.2.0. + * + * \sa SDL_CreateGPUShader */ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUVertexSamplers( SDL_GPURenderPass *render_pass, @@ -2999,12 +3042,17 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUVertexSamplers( * These textures must have been created with * SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ. * + * Be sure your shader is set up according to the requirements documented in + * SDL_CreateGPUShader(). + * * \param render_pass a render pass handle. * \param first_slot the vertex storage texture slot to begin binding from. * \param storage_textures an array of storage textures. * \param num_bindings the number of storage texture to bind from the array. * * \since This function is available since SDL 3.2.0. + * + * \sa SDL_CreateGPUShader */ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUVertexStorageTextures( SDL_GPURenderPass *render_pass, @@ -3018,12 +3066,17 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUVertexStorageTextures( * These buffers must have been created with * SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ. * + * Be sure your shader is set up according to the requirements documented in + * SDL_CreateGPUShader(). + * * \param render_pass a render pass handle. * \param first_slot the vertex storage buffer slot to begin binding from. * \param storage_buffers an array of buffers. * \param num_bindings the number of buffers to bind from the array. * * \since This function is available since SDL 3.2.0. + * + * \sa SDL_CreateGPUShader */ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUVertexStorageBuffers( SDL_GPURenderPass *render_pass, @@ -3036,6 +3089,9 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUVertexStorageBuffers( * * The textures must have been created with SDL_GPU_TEXTUREUSAGE_SAMPLER. * + * Be sure your shader is set up according to the requirements documented in + * SDL_CreateGPUShader(). + * * \param render_pass a render pass handle. * \param first_slot the fragment sampler slot to begin binding from. * \param texture_sampler_bindings an array of texture-sampler binding @@ -3044,6 +3100,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUVertexStorageBuffers( * array. * * \since This function is available since SDL 3.2.0. + * + * \sa SDL_CreateGPUShader */ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUFragmentSamplers( SDL_GPURenderPass *render_pass, @@ -3057,12 +3115,17 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUFragmentSamplers( * These textures must have been created with * SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ. * + * Be sure your shader is set up according to the requirements documented in + * SDL_CreateGPUShader(). + * * \param render_pass a render pass handle. * \param first_slot the fragment storage texture slot to begin binding from. * \param storage_textures an array of storage textures. * \param num_bindings the number of storage textures to bind from the array. * * \since This function is available since SDL 3.2.0. + * + * \sa SDL_CreateGPUShader */ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUFragmentStorageTextures( SDL_GPURenderPass *render_pass, @@ -3076,12 +3139,17 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUFragmentStorageTextures( * These buffers must have been created with * SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ. * + * Be sure your shader is set up according to the requirements documented in + * SDL_CreateGPUShader(). + * * \param render_pass a render pass handle. * \param first_slot the fragment storage buffer slot to begin binding from. * \param storage_buffers an array of storage buffers. * \param num_bindings the number of storage buffers to bind from the array. * * \since This function is available since SDL 3.2.0. + * + * \sa SDL_CreateGPUShader */ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUFragmentStorageBuffers( SDL_GPURenderPass *render_pass, @@ -3245,7 +3313,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_EndGPURenderPass( * * \sa SDL_EndGPUComputePass */ -extern SDL_DECLSPEC SDL_GPUComputePass *SDLCALL SDL_BeginGPUComputePass( +extern SDL_DECLSPEC SDL_GPUComputePass * SDLCALL SDL_BeginGPUComputePass( SDL_GPUCommandBuffer *command_buffer, const SDL_GPUStorageTextureReadWriteBinding *storage_texture_bindings, Uint32 num_storage_texture_bindings, @@ -3269,6 +3337,9 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUComputePipeline( * * The textures must have been created with SDL_GPU_TEXTUREUSAGE_SAMPLER. * + * Be sure your shader is set up according to the requirements documented in + * SDL_CreateGPUShader(). + * * \param compute_pass a compute pass handle. * \param first_slot the compute sampler slot to begin binding from. * \param texture_sampler_bindings an array of texture-sampler binding @@ -3277,6 +3348,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUComputePipeline( * array. * * \since This function is available since SDL 3.2.0. + * + * \sa SDL_CreateGPUShader */ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUComputeSamplers( SDL_GPUComputePass *compute_pass, @@ -3290,12 +3363,17 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUComputeSamplers( * These textures must have been created with * SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ. * + * Be sure your shader is set up according to the requirements documented in + * SDL_CreateGPUShader(). + * * \param compute_pass a compute pass handle. * \param first_slot the compute storage texture slot to begin binding from. * \param storage_textures an array of storage textures. * \param num_bindings the number of storage textures to bind from the array. * * \since This function is available since SDL 3.2.0. + * + * \sa SDL_CreateGPUShader */ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUComputeStorageTextures( SDL_GPUComputePass *compute_pass, @@ -3309,12 +3387,17 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUComputeStorageTextures( * These buffers must have been created with * SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_READ. * + * Be sure your shader is set up according to the requirements documented in + * SDL_CreateGPUShader(). + * * \param compute_pass a compute pass handle. * \param first_slot the compute storage buffer slot to begin binding from. * \param storage_buffers an array of storage buffer binding structs. * \param num_bindings the number of storage buffers to bind from the array. * * \since This function is available since SDL 3.2.0. + * + * \sa SDL_CreateGPUShader */ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUComputeStorageBuffers( SDL_GPUComputePass *compute_pass, @@ -3389,7 +3472,9 @@ extern SDL_DECLSPEC void SDLCALL SDL_EndGPUComputePass( /** * Maps a transfer buffer into application address space. * - * You must unmap the transfer buffer before encoding upload commands. + * You must unmap the transfer buffer before encoding upload commands. The + * memory is owned by the graphics driver - do NOT call SDL_free() on the + * returned pointer. * * \param device a GPU context. * \param transfer_buffer a transfer buffer. @@ -3399,7 +3484,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_EndGPUComputePass( * * \since This function is available since SDL 3.2.0. */ -extern SDL_DECLSPEC void *SDLCALL SDL_MapGPUTransferBuffer( +extern SDL_DECLSPEC void * SDLCALL SDL_MapGPUTransferBuffer( SDL_GPUDevice *device, SDL_GPUTransferBuffer *transfer_buffer, bool cycle); @@ -3430,7 +3515,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_UnmapGPUTransferBuffer( * * \since This function is available since SDL 3.2.0. */ -extern SDL_DECLSPEC SDL_GPUCopyPass *SDLCALL SDL_BeginGPUCopyPass( +extern SDL_DECLSPEC SDL_GPUCopyPass * SDLCALL SDL_BeginGPUCopyPass( SDL_GPUCommandBuffer *command_buffer); /** @@ -3848,6 +3933,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WaitForGPUSwapchain( * freed by the user. You MUST NOT call this function from any thread other * than the one that created the window. * + * The swapchain texture is write-only and cannot be used as a sampler or for + * another reading operation. + * * \param command_buffer a command buffer. * \param window a window that has been claimed. * \param swapchain_texture a pointer filled in with a swapchain texture @@ -3866,6 +3954,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WaitForGPUSwapchain( * * \sa SDL_SubmitGPUCommandBuffer * \sa SDL_SubmitGPUCommandBufferAndAcquireFence + * \sa SDL_AcquireGPUSwapchainTexture */ extern SDL_DECLSPEC bool SDLCALL SDL_WaitAndAcquireGPUSwapchainTexture( SDL_GPUCommandBuffer *command_buffer, @@ -3922,7 +4011,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SubmitGPUCommandBuffer( * \sa SDL_SubmitGPUCommandBuffer * \sa SDL_ReleaseGPUFence */ -extern SDL_DECLSPEC SDL_GPUFence *SDLCALL SDL_SubmitGPUCommandBufferAndAcquireFence( +extern SDL_DECLSPEC SDL_GPUFence * SDLCALL SDL_SubmitGPUCommandBufferAndAcquireFence( SDL_GPUCommandBuffer *command_buffer); /** @@ -4004,6 +4093,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_QueryGPUFence( /** * Releases a fence obtained from SDL_SubmitGPUCommandBufferAndAcquireFence. * + * You must not reference the fence after calling this function. + * * \param device a GPU context. * \param fence a fence. * diff --git a/libs/SDL3/include/SDL3/SDL_guid.h b/libs/SDL3/include/SDL3/SDL_guid.h index e2f32ffc..312c42c0 100644 --- a/libs/SDL3/include/SDL3/SDL_guid.h +++ b/libs/SDL3/include/SDL3/SDL_guid.h @@ -71,6 +71,8 @@ typedef struct SDL_GUID { * \param pszGUID buffer in which to write the ASCII string. * \param cbGUID the size of pszGUID, should be at least 33 bytes. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_StringToGUID @@ -87,6 +89,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_GUIDToString(SDL_GUID guid, char *pszGUID, * \param pchGUID string containing an ASCII representation of a GUID. * \returns a SDL_GUID structure. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GUIDToString diff --git a/libs/SDL3/include/SDL3/SDL_hints.h b/libs/SDL3/include/SDL3/SDL_hints.h index 8f2d074d..3206dc13 100644 --- a/libs/SDL3/include/SDL3/SDL_hints.h +++ b/libs/SDL3/include/SDL3/SDL_hints.h @@ -2191,6 +2191,28 @@ extern "C" { */ #define SDL_HINT_JOYSTICK_ZERO_CENTERED_DEVICES "SDL_JOYSTICK_ZERO_CENTERED_DEVICES" +/** + * A variable containing a list of devices and their desired number of haptic + * (force feedback) enabled axis. + * + * The format of the string is a comma separated list of USB VID/PID pairs in + * hexadecimal form plus the number of desired axes, e.g. + * + * `0xAAAA/0xBBBB/1,0xCCCC/0xDDDD/3` + * + * This hint supports a "wildcard" device that will set the number of haptic + * axes on all initialized haptic devices which were not defined explicitly in + * this hint. + * + * `0xFFFF/0xFFFF/1` + * + * This hint should be set before a controller is opened. The number of haptic + * axes won't exceed the number of real axes found on the device. + * + * \since This hint is available since SDL 3.2.5. + */ +#define SDL_HINT_JOYSTICK_HAPTIC_AXES "SDL_JOYSTICK_HAPTIC_AXES" + /** * A variable that controls keycode representation in keyboard events. * @@ -2349,8 +2371,8 @@ extern "C" { #define SDL_HINT_MAC_OPENGL_ASYNC_DISPATCH "SDL_MAC_OPENGL_ASYNC_DISPATCH" /** - * A variable controlling whether the Option (⌥) key on macOS should be - * remapped to act as the Alt key. + * A variable controlling whether the Option key on macOS should be remapped + * to act as the Alt key. * * The variable can be set to the following values: * @@ -4360,7 +4382,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_ResetHints(void); * \sa SDL_SetHint * \sa SDL_SetHintWithPriority */ -extern SDL_DECLSPEC const char *SDLCALL SDL_GetHint(const char *name); +extern SDL_DECLSPEC const char * SDLCALL SDL_GetHint(const char *name); /** * Get the boolean value of a hint variable. diff --git a/libs/SDL3/include/SDL3/SDL_log.h b/libs/SDL3/include/SDL3/SDL_log.h index a56476c6..3fd7ec2e 100644 --- a/libs/SDL3/include/SDL3/SDL_log.h +++ b/libs/SDL3/include/SDL3/SDL_log.h @@ -41,8 +41,8 @@ * "system", "audio", "video", "render", "input", "test", or `*` for any * unspecified category. * - * The level can be a numeric level, one of "verbose", "debug", "info", - * "warn", "error", "critical", or "quiet" to disable that category. + * The level can be a numeric level, one of "trace", "verbose", "debug", + * "info", "warn", "error", "critical", or "quiet" to disable that category. * * You can omit the category if you want to set the logging level for all * categories. @@ -56,6 +56,15 @@ * - Windows: debug output stream * - Android: log output * - Others: standard error output (stderr) + * + * You don't need to have a newline (`\n`) on the end of messages, the + * functions will do that for you. For consistent behavior cross-platform, you + * shouldn't have any newlines in messages, such as to log multiple lines in + * one call; unusual platform-specific behavior can be observed in such usage. + * Do one log call per line instead, with no newlines in messages. + * + * Each log call is atomic, so you won't see log messages cut off one another + * when logging from multiple threads. */ #ifndef SDL_log_h_ diff --git a/libs/SDL3/include/SDL3/SDL_main.h b/libs/SDL3/include/SDL3/SDL_main.h index 2e7a2ebb..905d78e9 100644 --- a/libs/SDL3/include/SDL3/SDL_main.h +++ b/libs/SDL3/include/SDL3/SDL_main.h @@ -28,6 +28,9 @@ * should look like this: * * ```c + * #include + * #include + * * int main(int argc, char *argv[]) * { * } @@ -38,9 +41,9 @@ * This is also where an app can be configured to use the main callbacks, via * the SDL_MAIN_USE_CALLBACKS macro. * - * This is a "single-header library," which is to say that including this - * header inserts code into your program, and you should only include it once - * in most cases. SDL.h does not include this header automatically. + * SDL_main.h is a "single-header library," which is to say that including + * this header inserts code into your program, and you should only include it + * once in most cases. SDL.h does not include this header automatically. * * For more information, see: * diff --git a/libs/SDL3/include/SDL3/SDL_mouse.h b/libs/SDL3/include/SDL3/SDL_mouse.h index 18856e20..864135d2 100644 --- a/libs/SDL3/include/SDL3/SDL_mouse.h +++ b/libs/SDL3/include/SDL3/SDL_mouse.h @@ -353,7 +353,7 @@ extern SDL_DECLSPEC SDL_MouseButtonFlags SDLCALL SDL_GetRelativeMouseState(float * * \sa SDL_WarpMouseGlobal */ -extern SDL_DECLSPEC void SDLCALL SDL_WarpMouseInWindow(SDL_Window * window, +extern SDL_DECLSPEC void SDLCALL SDL_WarpMouseInWindow(SDL_Window *window, float x, float y); /** @@ -514,8 +514,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_CaptureMouse(bool enabled); * \sa SDL_DestroyCursor * \sa SDL_SetCursor */ -extern SDL_DECLSPEC SDL_Cursor * SDLCALL SDL_CreateCursor(const Uint8 * data, - const Uint8 * mask, +extern SDL_DECLSPEC SDL_Cursor * SDLCALL SDL_CreateCursor(const Uint8 *data, + const Uint8 *mask, int w, int h, int hot_x, int hot_y); diff --git a/libs/SDL3/include/SDL3/SDL_pixels.h b/libs/SDL3/include/SDL3/SDL_pixels.h index b6f38acb..4127ac06 100644 --- a/libs/SDL3/include/SDL3/SDL_pixels.h +++ b/libs/SDL3/include/SDL3/SDL_pixels.h @@ -676,6 +676,9 @@ typedef enum SDL_PixelFormat SDL_PIXELFORMAT_EXTERNAL_OES = 0x2053454fu, /**< Android video texture format */ /* SDL_DEFINE_PIXELFOURCC('O', 'E', 'S', ' ') */ + SDL_PIXELFORMAT_MJPG = 0x47504a4du, /**< Motion JPEG */ + /* SDL_DEFINE_PIXELFOURCC('M', 'J', 'P', 'G') */ + /* Aliases for RGBA byte arrays of color data, for the current platform */ #if SDL_BYTEORDER == SDL_BIG_ENDIAN SDL_PIXELFORMAT_RGBA32 = SDL_PIXELFORMAT_RGBA8888, diff --git a/libs/SDL3/include/SDL3/SDL_platform_defines.h b/libs/SDL3/include/SDL3/SDL_platform_defines.h index 7e9a0a92..6b240a8b 100644 --- a/libs/SDL3/include/SDL3/SDL_platform_defines.h +++ b/libs/SDL3/include/SDL3/SDL_platform_defines.h @@ -471,8 +471,6 @@ * \since This macro is available since SDL 3.2.0. */ #define SDL_PLATFORM_3DS 1 - -#undef __3DS__ #endif #endif /* SDL_platform_defines_h_ */ diff --git a/libs/SDL3/include/SDL3/SDL_process.h b/libs/SDL3/include/SDL3/SDL_process.h index 2cc77395..511b2f9c 100644 --- a/libs/SDL3/include/SDL3/SDL_process.h +++ b/libs/SDL3/include/SDL3/SDL_process.h @@ -103,7 +103,7 @@ typedef struct SDL_Process SDL_Process; * \sa SDL_WaitProcess * \sa SDL_DestroyProcess */ -extern SDL_DECLSPEC SDL_Process *SDLCALL SDL_CreateProcess(const char * const *args, bool pipe_stdio); +extern SDL_DECLSPEC SDL_Process * SDLCALL SDL_CreateProcess(const char * const *args, bool pipe_stdio); /** * Description of where standard I/O should be directed when creating a @@ -173,13 +173,13 @@ typedef enum SDL_ProcessIO * standard input when `SDL_PROP_PROCESS_CREATE_STDIN_NUMBER` is set to * `SDL_PROCESS_STDIO_REDIRECT`. * - `SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER`: an SDL_ProcessIO value - * describing where standard output for the process goes go, defaults to + * describing where standard output for the process goes to, defaults to * `SDL_PROCESS_STDIO_INHERITED`. * - `SDL_PROP_PROCESS_CREATE_STDOUT_POINTER`: an SDL_IOStream pointer used * for standard output when `SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER` is set * to `SDL_PROCESS_STDIO_REDIRECT`. * - `SDL_PROP_PROCESS_CREATE_STDERR_NUMBER`: an SDL_ProcessIO value - * describing where standard error for the process goes go, defaults to + * describing where standard error for the process goes to, defaults to * `SDL_PROCESS_STDIO_INHERITED`. * - `SDL_PROP_PROCESS_CREATE_STDERR_POINTER`: an SDL_IOStream pointer used * for standard error when `SDL_PROP_PROCESS_CREATE_STDERR_NUMBER` is set to @@ -215,7 +215,7 @@ typedef enum SDL_ProcessIO * \sa SDL_WaitProcess * \sa SDL_DestroyProcess */ -extern SDL_DECLSPEC SDL_Process *SDLCALL SDL_CreateProcessWithProperties(SDL_PropertiesID props); +extern SDL_DECLSPEC SDL_Process * SDLCALL SDL_CreateProcessWithProperties(SDL_PropertiesID props); #define SDL_PROP_PROCESS_CREATE_ARGS_POINTER "SDL.process.create.args" #define SDL_PROP_PROCESS_CREATE_ENVIRONMENT_POINTER "SDL.process.create.environment" @@ -320,7 +320,7 @@ extern SDL_DECLSPEC void * SDLCALL SDL_ReadProcess(SDL_Process *process, size_t * \sa SDL_CreateProcessWithProperties * \sa SDL_GetProcessOutput */ -extern SDL_DECLSPEC SDL_IOStream *SDLCALL SDL_GetProcessInput(SDL_Process *process); +extern SDL_DECLSPEC SDL_IOStream * SDLCALL SDL_GetProcessInput(SDL_Process *process); /** * Get the SDL_IOStream associated with process standard output. @@ -344,7 +344,7 @@ extern SDL_DECLSPEC SDL_IOStream *SDLCALL SDL_GetProcessInput(SDL_Process *proce * \sa SDL_CreateProcessWithProperties * \sa SDL_GetProcessInput */ -extern SDL_DECLSPEC SDL_IOStream *SDLCALL SDL_GetProcessOutput(SDL_Process *process); +extern SDL_DECLSPEC SDL_IOStream * SDLCALL SDL_GetProcessOutput(SDL_Process *process); /** * Stop a process. diff --git a/libs/SDL3/include/SDL3/SDL_rect.h b/libs/SDL3/include/SDL3/SDL_rect.h index 8998de6f..eb2d34a6 100644 --- a/libs/SDL3/include/SDL3/SDL_rect.h +++ b/libs/SDL3/include/SDL3/SDL_rect.h @@ -371,7 +371,7 @@ SDL_FORCE_INLINE bool SDL_RectEmptyFloat(const SDL_FRect *r) * * \sa SDL_RectsEqualFloat */ -SDL_FORCE_INLINE bool SDL_RectsEqualEpsilon(const SDL_FRect *a, const SDL_FRect *b, const float epsilon) +SDL_FORCE_INLINE bool SDL_RectsEqualEpsilon(const SDL_FRect *a, const SDL_FRect *b, float epsilon) { return (a && b && ((a == b) || ((SDL_fabsf(a->x - b->x) <= epsilon) && diff --git a/libs/SDL3/include/SDL3/SDL_render.h b/libs/SDL3/include/SDL3/SDL_render.h index 891e9945..3352545d 100644 --- a/libs/SDL3/include/SDL3/SDL_render.h +++ b/libs/SDL3/include/SDL3/SDL_render.h @@ -490,6 +490,9 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetRendererProperties(SDL_Rende * This returns the true output size in pixels, ignoring any render targets or * logical size and presentation. * + * For the output size of the current rendering target, with logical size + * adjustments, use SDL_GetCurrentRenderOutputSize() instead. + * * \param renderer the rendering context. * \param w a pointer filled in with the width in pixels. * \param h a pointer filled in with the height in pixels. @@ -508,9 +511,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderOutputSize(SDL_Renderer *renderer, * Get the current output size in pixels of a rendering context. * * If a rendering target is active, this will return the size of the rendering - * target in pixels, otherwise if a logical size is set, it will return the - * logical size, otherwise it will return the value of - * SDL_GetRenderOutputSize(). + * target in pixels, otherwise return the value of SDL_GetRenderOutputSize(). + * + * Rendering target or not, the output will be adjusted by the current logical + * presentation state, dictated by SDL_SetRenderLogicalPresentation(). * * \param renderer the rendering context. * \param w a pointer filled in with the current width. @@ -1318,6 +1322,11 @@ extern SDL_DECLSPEC void SDLCALL SDL_UnlockTexture(SDL_Texture *texture); * To stop rendering to a texture and render to the window again, call this * function with a NULL `texture`. * + * Viewport, cliprect, scale, and logical presentation are unique to each + * render target. Get and set functions for these states apply to the current + * render target set by this function, and those states persist on each target + * when the current render target changes. + * * \param renderer the rendering context. * \param texture the targeted texture, which must be created with the * `SDL_TEXTUREACCESS_TARGET` flag, or NULL to render to the @@ -1351,25 +1360,39 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderTarget(SDL_Renderer *renderer, SDL extern SDL_DECLSPEC SDL_Texture * SDLCALL SDL_GetRenderTarget(SDL_Renderer *renderer); /** - * Set a device independent resolution and presentation mode for rendering. + * Set a device-independent resolution and presentation mode for rendering. * * This function sets the width and height of the logical rendering output. - * The renderer will act as if the window is always the requested dimensions, - * scaling to the actual window resolution as necessary. + * The renderer will act as if the current render target is always the + * requested dimensions, scaling to the actual resolution as necessary. * * This can be useful for games that expect a fixed size, but would like to * scale the output to whatever is available, regardless of how a user resizes * a window, or if the display is high DPI. * + * Logical presentation can be used with both render target textures and the + * renderer's window; the state is unique to each render target, and this + * function sets the state for the current render target. It might be useful + * to draw to a texture that matches the window dimensions with logical + * presentation enabled, and then draw that texture across the entire window + * with logical presentation disabled. Be careful not to render both with + * logical presentation enabled, however, as this could produce + * double-letterboxing, etc. + * * You can disable logical coordinates by setting the mode to * SDL_LOGICAL_PRESENTATION_DISABLED, and in that case you get the full pixel - * resolution of the output window; it is safe to toggle logical presentation + * resolution of the render target; it is safe to toggle logical presentation * during the rendering of a frame: perhaps most of the rendering is done to * specific dimensions but to make fonts look sharp, the app turns off logical - * presentation while drawing text. + * presentation while drawing text, for example. * - * Letterboxing will only happen if logical presentation is enabled during - * SDL_RenderPresent; be sure to reenable it first if you were using it. + * For the renderer's window, letterboxing is drawn into the framebuffer if + * logical presentation is enabled during SDL_RenderPresent; be sure to + * reenable it before presenting if you were toggling it, otherwise the + * letterbox areas might have artifacts from previous frames (or artifacts + * from external overlays, etc). Letterboxing is never drawn into texture + * render targets; be sure to call SDL_RenderClear() before drawing into the + * texture so the letterboxing areas are cleared, if appropriate. * * You can convert coordinates in an event into rendering coordinates using * SDL_ConvertEventToRenderCoordinates(). @@ -1397,6 +1420,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderLogicalPresentation(SDL_Renderer * * This function gets the width and height of the logical rendering output, or * the output size in pixels if a logical resolution is not enabled. * + * Each render target has its own logical presentation state. This function + * gets the state for the current render target. + * * \param renderer the rendering context. * \param w an int to be filled with the width. * \param h an int to be filled with the height. @@ -1420,6 +1446,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderLogicalPresentation(SDL_Renderer * * presentation is disabled, it will fill the rectangle with the output size, * in pixels. * + * Each render target has its own logical presentation state. This function + * gets the rectangle for the current render target. + * * \param renderer the rendering context. * \param rect a pointer filled in with the final presentation rectangle, may * be NULL. @@ -1536,6 +1565,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ConvertEventToRenderCoordinates(SDL_Rendere * * The area's width and height must be >= 0. * + * Each render target has its own viewport. This function sets the viewport + * for the current render target. + * * \param renderer the rendering context. * \param rect the SDL_Rect structure representing the drawing area, or NULL * to set the viewport to the entire target. @@ -1554,6 +1586,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderViewport(SDL_Renderer *renderer, c /** * Get the drawing area for the current target. * + * Each render target has its own viewport. This function gets the viewport + * for the current render target. + * * \param renderer the rendering context. * \param rect an SDL_Rect structure filled in with the current drawing area. * \returns true on success or false on failure; call SDL_GetError() for more @@ -1575,6 +1610,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderViewport(SDL_Renderer *renderer, S * whether you should restore a specific rectangle or NULL. Note that the * viewport is always reset when changing rendering targets. * + * Each render target has its own viewport. This function checks the viewport + * for the current render target. + * * \param renderer the rendering context. * \returns true if the viewport was set to a specific rectangle, or false if * it was set to NULL (the entire target). @@ -1613,6 +1651,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderSafeArea(SDL_Renderer *renderer, S /** * Set the clip rectangle for rendering on the specified target. * + * Each render target has its own clip rectangle. This function sets the + * cliprect for the current render target. + * * \param renderer the rendering context. * \param rect an SDL_Rect structure representing the clip area, relative to * the viewport, or NULL to disable clipping. @@ -1631,6 +1672,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderClipRect(SDL_Renderer *renderer, c /** * Get the clip rectangle for the current target. * + * Each render target has its own clip rectangle. This function gets the + * cliprect for the current render target. + * * \param renderer the rendering context. * \param rect an SDL_Rect structure filled in with the current clipping area * or an empty rectangle if clipping is disabled. @@ -1647,7 +1691,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderClipRect(SDL_Renderer *renderer, c extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderClipRect(SDL_Renderer *renderer, SDL_Rect *rect); /** - * Get whether clipping is enabled on the given renderer. + * Get whether clipping is enabled on the given render target. + * + * Each render target has its own clip rectangle. This function checks the + * cliprect for the current render target. * * \param renderer the rendering context. * \returns true if clipping is enabled or false if not; call SDL_GetError() @@ -1673,6 +1720,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderClipEnabled(SDL_Renderer *renderer); * will be handled using the appropriate quality hints. For best results use * integer scaling factors. * + * Each render target has its own scale. This function sets the scale for the + * current render target. + * * \param renderer the rendering context. * \param scaleX the horizontal scaling factor. * \param scaleY the vertical scaling factor. @@ -1690,6 +1740,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderScale(SDL_Renderer *renderer, floa /** * Get the drawing scale for the current target. * + * Each render target has its own scale. This function gets the scale for the + * current render target. + * * \param renderer the rendering context. * \param scaleX a pointer filled in with the horizontal scaling factor. * \param scaleY a pointer filled in with the vertical scaling factor. @@ -2247,15 +2300,21 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderGeometryRaw(SDL_Renderer *renderer, /** * Read pixels from the current rendering target. * - * The returned surface should be freed with SDL_DestroySurface() + * The returned surface contains pixels inside the desired area clipped to the + * current viewport, and should be freed with SDL_DestroySurface(). + * + * Note that this returns the actual pixels on the screen, so if you are using + * logical presentation you should use SDL_GetRenderLogicalPresentationRect() + * to get the area containing your content. * * **WARNING**: This is a very slow operation, and should not be used * frequently. If you're using this on the main rendering target, it should be * called after rendering and before SDL_RenderPresent(). * * \param renderer the rendering context. - * \param rect an SDL_Rect structure representing the area in pixels relative - * to the to current viewport, or NULL for the entire viewport. + * \param rect an SDL_Rect structure representing the area to read, which will + * be clipped to the current viewport, or NULL for the entire + * viewport. * \returns a new SDL_Surface on success or NULL on failure; call * SDL_GetError() for more information. * diff --git a/libs/SDL3/include/SDL3/SDL_revision.h b/libs/SDL3/include/SDL3/SDL_revision.h index 18f7c4d6..f0f57cd5 100644 --- a/libs/SDL3/include/SDL3/SDL_revision.h +++ b/libs/SDL3/include/SDL3/SDL_revision.h @@ -1,22 +1,22 @@ /* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Simple DirectMedia Layer + Copyright (C) 1997-2025 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. + 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: + 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. + 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. */ /* WIKI CATEGORY: Version */ @@ -44,13 +44,13 @@ * clue in debugging forensics and not something the app will parse in any * way. * - * \since This macro is available since SDL 3.0.0. + * \since This macro is available since SDL 3.2.0. */ #define SDL_REVISION "Some arbitrary string decided at SDL build time" #elif defined(SDL_VENDOR_INFO) -#define SDL_REVISION "release-3.2.0-0-g535d80bad (" SDL_VENDOR_INFO ")" +#define SDL_REVISION SDL_VENDOR_INFO #else -#define SDL_REVISION "release-3.2.0-0-g535d80bad" +#define SDL_REVISION "" #endif #endif /* SDL_revision_h_ */ diff --git a/libs/SDL3/include/SDL3/SDL_stdinc.h b/libs/SDL3/include/SDL3/SDL_stdinc.h index 4e15a3c6..9903a0b0 100644 --- a/libs/SDL3/include/SDL3/SDL_stdinc.h +++ b/libs/SDL3/include/SDL3/SDL_stdinc.h @@ -4243,14 +4243,14 @@ extern SDL_DECLSPEC int SDLCALL SDL_vasprintf(char **strp, SDL_PRINTF_FORMAT_STR /** * Seeds the pseudo-random number generator. * - * Reusing the seed number will cause SDL_rand_*() to repeat the same stream - * of 'random' numbers. + * Reusing the seed number will cause SDL_rand() to repeat the same stream of + * 'random' numbers. * * \param seed the value to use as a random number seed, or 0 to use * SDL_GetPerformanceCounter(). * * \threadsafety This should be called on the same thread that calls - * SDL_rand*() + * SDL_rand() * * \since This function is available since SDL 3.2.0. * @@ -4701,7 +4701,7 @@ extern SDL_DECLSPEC double SDLCALL SDL_atan2(double y, double x); * * \since This function is available since SDL 3.2.0. * - * \sa SDL_atan2f + * \sa SDL_atan2 * \sa SDL_atan * \sa SDL_tan */ @@ -4810,7 +4810,7 @@ extern SDL_DECLSPEC double SDLCALL SDL_copysign(double x, double y); * * \since This function is available since SDL 3.2.0. * - * \sa SDL_copysignf + * \sa SDL_copysign * \sa SDL_fabsf */ extern SDL_DECLSPEC float SDLCALL SDL_copysignf(float x, float y); @@ -4943,7 +4943,7 @@ extern SDL_DECLSPEC float SDLCALL SDL_expf(float x); * Range: `0 <= y <= INF` * * This function operates on double-precision floating point values, use - * SDL_copysignf for single-precision floats. + * SDL_fabsf for single-precision floats. * * \param x floating point value to use as the magnitude. * \returns the absolute value of `x`. @@ -4964,7 +4964,7 @@ extern SDL_DECLSPEC double SDLCALL SDL_fabs(double x); * Range: `0 <= y <= INF` * * This function operates on single-precision floating point values, use - * SDL_copysignf for double-precision floats. + * SDL_fabs for double-precision floats. * * \param x floating point value to use as the magnitude. * \returns the absolute value of `x`. @@ -5016,7 +5016,7 @@ extern SDL_DECLSPEC double SDLCALL SDL_floor(double x); * Range: `-INF <= y <= INF`, y integer * * This function operates on single-precision floating point values, use - * SDL_floorf for double-precision floats. + * SDL_floor for double-precision floats. * * \param x floating point value. * \returns the floor of `x`. @@ -5073,7 +5073,7 @@ extern SDL_DECLSPEC double SDLCALL SDL_trunc(double x); * Range: `-INF <= y <= INF`, y integer * * This function operates on single-precision floating point values, use - * SDL_truncf for double-precision floats. + * SDL_trunc for double-precision floats. * * \param x floating point value. * \returns `x` truncated to an integer. @@ -5131,7 +5131,7 @@ extern SDL_DECLSPEC double SDLCALL SDL_fmod(double x, double y); * Range: `-y <= z <= y` * * This function operates on single-precision floating point values, use - * SDL_fmod for single-precision floats. + * SDL_fmod for double-precision floats. * * \param x the numerator. * \param y the denominator. Must not be 0. @@ -5409,7 +5409,7 @@ extern SDL_DECLSPEC double SDLCALL SDL_pow(double x, double y); * instead. * * This function operates on single-precision floating point values, use - * SDL_powf for double-precision floats. + * SDL_pow for double-precision floats. * * This function may use a different approximation across different versions, * platforms and configurations. i.e, it can return a different value given @@ -5469,8 +5469,8 @@ extern SDL_DECLSPEC double SDLCALL SDL_round(double x); * * Range: `-INF <= y <= INF`, y integer * - * This function operates on double-precision floating point values, use - * SDL_roundf for single-precision floats. To get the result as an integer + * This function operates on single-precision floating point values, use + * SDL_round for double-precision floats. To get the result as an integer * type, use SDL_lroundf. * * \param x floating point value. @@ -5499,7 +5499,7 @@ extern SDL_DECLSPEC float SDLCALL SDL_roundf(float x); * Range: `MIN_LONG <= y <= MAX_LONG` * * This function operates on double-precision floating point values, use - * SDL_lround for single-precision floats. To get the result as a + * SDL_lroundf for single-precision floats. To get the result as a * floating-point type, use SDL_round. * * \param x floating point value. @@ -5528,8 +5528,8 @@ extern SDL_DECLSPEC long SDLCALL SDL_lround(double x); * Range: `MIN_LONG <= y <= MAX_LONG` * * This function operates on single-precision floating point values, use - * SDL_lroundf for double-precision floats. To get the result as a - * floating-point type, use SDL_roundf, + * SDL_lround for double-precision floats. To get the result as a + * floating-point type, use SDL_roundf. * * \param x floating point value. * \returns the nearest integer to `x`. @@ -5742,7 +5742,7 @@ extern SDL_DECLSPEC double SDLCALL SDL_tan(double x); * Range: `-INF <= y <= INF` * * This function operates on single-precision floating point values, use - * SDL_tanf for double-precision floats. + * SDL_tan for double-precision floats. * * This function may use a different approximation across different versions, * platforms and configurations. i.e, it can return a different value given @@ -5969,7 +5969,6 @@ char *strdup(const char *str); their prototype defined (clang-diagnostic-implicit-function-declaration) */ #include #include -#include #define SDL_malloc malloc #define SDL_calloc calloc diff --git a/libs/SDL3/include/SDL3/SDL_storage.h b/libs/SDL3/include/SDL3/SDL_storage.h index 8b89ace1..6837ebaa 100644 --- a/libs/SDL3/include/SDL3/SDL_storage.h +++ b/libs/SDL3/include/SDL3/SDL_storage.h @@ -450,7 +450,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_CloseStorage(SDL_Storage *storage); * * This function should be called in regular intervals until it returns true - * however, it is not recommended to spinwait on this call, as the backend may - * depend on a synchronous message loop. + * depend on a synchronous message loop. You might instead poll this in your + * game's main loop while processing events and drawing a loading screen. * * \param storage a storage container to query. * \returns true if the container is ready, false otherwise. @@ -636,10 +637,10 @@ extern SDL_DECLSPEC Uint64 SDLCALL SDL_GetStorageSpaceRemaining(SDL_Storage *sto * Enumerate a directory tree, filtered by pattern, and return a list. * * Files are filtered out if they don't match the string in `pattern`, which - * may contain wildcard characters '*' (match everything) and '?' (match one + * may contain wildcard characters `*` (match everything) and `?` (match one * character). If pattern is NULL, no filtering is done and all results are * returned. Subdirectories are permitted, and are specified with a path - * separator of '/'. Wildcard characters '*' and '?' never match a path + * separator of '/'. Wildcard characters `*` and `?` never match a path * separator. * * `flags` may be set to SDL_GLOB_CASEINSENSITIVE to make the pattern matching diff --git a/libs/SDL3/include/SDL3/SDL_surface.h b/libs/SDL3/include/SDL3/SDL_surface.h index 0752f530..415da1b7 100644 --- a/libs/SDL3/include/SDL3/SDL_surface.h +++ b/libs/SDL3/include/SDL3/SDL_surface.h @@ -73,7 +73,7 @@ typedef Uint32 SDL_SurfaceFlags; * * \since This macro is available since SDL 3.2.0. */ -#define SDL_MUSTLOCK(S) ((((S)->flags & SDL_SURFACE_LOCK_NEEDED)) == SDL_SURFACE_LOCK_NEEDED) +#define SDL_MUSTLOCK(S) (((S)->flags & SDL_SURFACE_LOCK_NEEDED) == SDL_SURFACE_LOCK_NEEDED) /** * The scaling mode. @@ -120,6 +120,9 @@ typedef enum SDL_FlipMode * format with a pitch of 32 would consist of 32x32 bytes of Y plane followed * by 32x16 bytes of UV plane. * + * When a surface holds MJPG format data, pixels points at the compressed JPEG + * image and pitch is the length of that data. + * * \since This struct is available since SDL 3.2.0. * * \sa SDL_CreateSurface @@ -221,6 +224,10 @@ extern SDL_DECLSPEC void SDLCALL SDL_DestroySurface(SDL_Surface *surface); * the same tone mapping that Chrome uses for HDR content, the form "*=N", * where N is a floating point scale factor applied in linear space, and * "none", which disables tone mapping. This defaults to "chrome". + * - `SDL_PROP_SURFACE_HOTSPOT_X_NUMBER`: the hotspot pixel offset from the + * left edge of the image, if this surface is being used as a cursor. + * - `SDL_PROP_SURFACE_HOTSPOT_Y_NUMBER`: the hotspot pixel offset from the + * top edge of the image, if this surface is being used as a cursor. * * \param surface the SDL_Surface structure to query. * \returns a valid property ID on success or 0 on failure; call @@ -233,6 +240,8 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetSurfaceProperties(SDL_Surfac #define SDL_PROP_SURFACE_SDR_WHITE_POINT_FLOAT "SDL.surface.SDR_white_point" #define SDL_PROP_SURFACE_HDR_HEADROOM_FLOAT "SDL.surface.HDR_headroom" #define SDL_PROP_SURFACE_TONEMAP_OPERATOR_STRING "SDL.surface.tonemap" +#define SDL_PROP_SURFACE_HOTSPOT_X_NUMBER "SDL.surface.hotspot.x" +#define SDL_PROP_SURFACE_HOTSPOT_Y_NUMBER "SDL.surface.hotspot.y" /** * Set the colorspace used by a surface. @@ -1173,6 +1182,29 @@ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurfaceScaled(SDL_Surface *src, const S */ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurfaceUncheckedScaled(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect, SDL_ScaleMode scaleMode); +/** + * Perform a stretched pixel copy from one surface to another. + * + * \param src the SDL_Surface structure to be copied from. + * \param srcrect the SDL_Rect structure representing the rectangle to be + * copied, may not be NULL. + * \param dst the SDL_Surface structure that is the blit target. + * \param dstrect the SDL_Rect structure representing the target rectangle in + * the destination surface, may not be NULL. + * \param scaleMode the SDL_ScaleMode to be used. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety The same destination surface should not be used from two + * threads at once. It is safe to use the same source surface + * from multiple threads. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_BlitSurfaceScaled + */ +extern SDL_DECLSPEC bool SDLCALL SDL_StretchSurface(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect, SDL_ScaleMode scaleMode); + /** * Perform a tiled blit to a destination surface, which may be of a different * format. diff --git a/libs/SDL3/include/SDL3/SDL_test_common.h b/libs/SDL3/include/SDL3/SDL_test_common.h index 3ab1ad01..91efe8ac 100644 --- a/libs/SDL3/include/SDL3/SDL_test_common.h +++ b/libs/SDL3/include/SDL3/SDL_test_common.h @@ -177,7 +177,7 @@ extern "C" { * * \returns a newly allocated common state object. */ -SDLTest_CommonState *SDLCALL SDLTest_CommonCreateState(char **argv, SDL_InitFlags flags); +SDLTest_CommonState * SDLCALL SDLTest_CommonCreateState(char **argv, SDL_InitFlags flags); /** * Free the common state object. diff --git a/libs/SDL3/include/SDL3/SDL_thread.h b/libs/SDL3/include/SDL3/SDL_thread.h index 277535fc..e981b542 100644 --- a/libs/SDL3/include/SDL3/SDL_thread.h +++ b/libs/SDL3/include/SDL3/SDL_thread.h @@ -139,7 +139,7 @@ typedef enum SDL_ThreadState * * \since This datatype is available since SDL 3.2.0. */ -typedef int (SDLCALL * SDL_ThreadFunction) (void *data); +typedef int (SDLCALL *SDL_ThreadFunction) (void *data); #ifdef SDL_WIKI_DOCUMENTATION_SECTION diff --git a/libs/SDL3/include/SDL3/SDL_tray.h b/libs/SDL3/include/SDL3/SDL_tray.h index 0b05db25..1780b0ba 100644 --- a/libs/SDL3/include/SDL3/SDL_tray.h +++ b/libs/SDL3/include/SDL3/SDL_tray.h @@ -118,7 +118,7 @@ typedef void (SDLCALL *SDL_TrayCallback)(void *userdata, SDL_TrayEntry *entry); * \sa SDL_GetTrayMenu * \sa SDL_DestroyTray */ -extern SDL_DECLSPEC SDL_Tray *SDLCALL SDL_CreateTray(SDL_Surface *icon, const char *tooltip); +extern SDL_DECLSPEC SDL_Tray * SDLCALL SDL_CreateTray(SDL_Surface *icon, const char *tooltip); /** * Updates the system tray icon's icon. @@ -172,7 +172,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_SetTrayTooltip(SDL_Tray *tray, const char * * \sa SDL_GetTrayMenu * \sa SDL_GetTrayMenuParentTray */ -extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_CreateTrayMenu(SDL_Tray *tray); +extern SDL_DECLSPEC SDL_TrayMenu * SDLCALL SDL_CreateTrayMenu(SDL_Tray *tray); /** * Create a submenu for a system tray entry. @@ -196,7 +196,7 @@ extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_CreateTrayMenu(SDL_Tray *tray); * \sa SDL_GetTraySubmenu * \sa SDL_GetTrayMenuParentEntry */ -extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_CreateTraySubmenu(SDL_TrayEntry *entry); +extern SDL_DECLSPEC SDL_TrayMenu * SDLCALL SDL_CreateTraySubmenu(SDL_TrayEntry *entry); /** * Gets a previously created tray menu. @@ -220,7 +220,7 @@ extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_CreateTraySubmenu(SDL_TrayEntry *e * \sa SDL_CreateTray * \sa SDL_CreateTrayMenu */ -extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_GetTrayMenu(SDL_Tray *tray); +extern SDL_DECLSPEC SDL_TrayMenu * SDLCALL SDL_GetTrayMenu(SDL_Tray *tray); /** * Gets a previously created tray entry submenu. @@ -244,14 +244,14 @@ extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_GetTrayMenu(SDL_Tray *tray); * \sa SDL_InsertTrayEntryAt * \sa SDL_CreateTraySubmenu */ -extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_GetTraySubmenu(SDL_TrayEntry *entry); +extern SDL_DECLSPEC SDL_TrayMenu * SDLCALL SDL_GetTraySubmenu(SDL_TrayEntry *entry); /** * Returns a list of entries in the menu, in order. * * \param menu The menu to get entries from. - * \param size An optional pointer to obtain the number of entries in the - * menu. + * \param count An optional pointer to obtain the number of entries in the + * menu. * \returns a NULL-terminated list of entries within the given menu. The * pointer becomes invalid when any function that inserts or deletes * entries in the menu is called. @@ -264,7 +264,7 @@ extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_GetTraySubmenu(SDL_TrayEntry *entr * \sa SDL_RemoveTrayEntry * \sa SDL_InsertTrayEntryAt */ -extern SDL_DECLSPEC const SDL_TrayEntry **SDLCALL SDL_GetTrayEntries(SDL_TrayMenu *menu, int *size); +extern SDL_DECLSPEC const SDL_TrayEntry ** SDLCALL SDL_GetTrayEntries(SDL_TrayMenu *menu, int *count); /** * Removes a tray entry. @@ -307,7 +307,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_RemoveTrayEntry(SDL_TrayEntry *entry); * \sa SDL_RemoveTrayEntry * \sa SDL_GetTrayEntryParent */ -extern SDL_DECLSPEC SDL_TrayEntry *SDLCALL SDL_InsertTrayEntryAt(SDL_TrayMenu *menu, int pos, const char *label, SDL_TrayEntryFlags flags); +extern SDL_DECLSPEC SDL_TrayEntry * SDLCALL SDL_InsertTrayEntryAt(SDL_TrayMenu *menu, int pos, const char *label, SDL_TrayEntryFlags flags); /** * Sets the label of an entry. @@ -348,7 +348,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_SetTrayEntryLabel(SDL_TrayEntry *entry, con * \sa SDL_InsertTrayEntryAt * \sa SDL_SetTrayEntryLabel */ -extern SDL_DECLSPEC const char *SDLCALL SDL_GetTrayEntryLabel(SDL_TrayEntry *entry); +extern SDL_DECLSPEC const char * SDLCALL SDL_GetTrayEntryLabel(SDL_TrayEntry *entry); /** * Sets whether or not an entry is checked. @@ -481,7 +481,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_DestroyTray(SDL_Tray *tray); * * \sa SDL_InsertTrayEntryAt */ -extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_GetTrayEntryParent(SDL_TrayEntry *entry); +extern SDL_DECLSPEC SDL_TrayMenu * SDLCALL SDL_GetTrayEntryParent(SDL_TrayEntry *entry); /** * Gets the entry for which the menu is a submenu, if the current menu is a @@ -501,7 +501,7 @@ extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_GetTrayEntryParent(SDL_TrayEntry * * \sa SDL_CreateTraySubmenu * \sa SDL_GetTrayMenuParentTray */ -extern SDL_DECLSPEC SDL_TrayEntry *SDLCALL SDL_GetTrayMenuParentEntry(SDL_TrayMenu *menu); +extern SDL_DECLSPEC SDL_TrayEntry * SDLCALL SDL_GetTrayMenuParentEntry(SDL_TrayMenu *menu); /** * Gets the tray for which this menu is the first-level menu, if the current @@ -521,7 +521,7 @@ extern SDL_DECLSPEC SDL_TrayEntry *SDLCALL SDL_GetTrayMenuParentEntry(SDL_TrayMe * \sa SDL_CreateTrayMenu * \sa SDL_GetTrayMenuParentEntry */ -extern SDL_DECLSPEC SDL_Tray *SDLCALL SDL_GetTrayMenuParentTray(SDL_TrayMenu *menu); +extern SDL_DECLSPEC SDL_Tray * SDLCALL SDL_GetTrayMenuParentTray(SDL_TrayMenu *menu); /** * Update the trays. diff --git a/libs/SDL3/include/SDL3/SDL_version.h b/libs/SDL3/include/SDL3/SDL_version.h index 55014e3c..8b8dca6d 100644 --- a/libs/SDL3/include/SDL3/SDL_version.h +++ b/libs/SDL3/include/SDL3/SDL_version.h @@ -62,7 +62,7 @@ extern "C" { * * \since This macro is available since SDL 3.2.0. */ -#define SDL_MICRO_VERSION 0 +#define SDL_MICRO_VERSION 6 /** * This macro turns the version numbers into a numeric value. diff --git a/libs/SDL3/include/SDL3/SDL_vulkan.h b/libs/SDL3/include/SDL3/SDL_vulkan.h index 5a487561..710afbe6 100644 --- a/libs/SDL3/include/SDL3/SDL_vulkan.h +++ b/libs/SDL3/include/SDL3/SDL_vulkan.h @@ -226,7 +226,7 @@ extern SDL_DECLSPEC char const * const * SDLCALL SDL_Vulkan_GetInstanceExtension extern SDL_DECLSPEC bool SDLCALL SDL_Vulkan_CreateSurface(SDL_Window *window, VkInstance instance, const struct VkAllocationCallbacks *allocator, - VkSurfaceKHR* surface); + VkSurfaceKHR *surface); /** * Destroy the Vulkan rendering surface of a window. diff --git a/libs/SDL3/include/build_config/SDL_revision.h.cmake b/libs/SDL3/include/build_config/SDL_revision.h.cmake index 28144ade..32b95bf9 100644 --- a/libs/SDL3/include/build_config/SDL_revision.h.cmake +++ b/libs/SDL3/include/build_config/SDL_revision.h.cmake @@ -1,30 +1,28 @@ /* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Simple DirectMedia Layer + Copyright (C) 1997-2025 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. + 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: + 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. + 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. */ -/* WIKI CATEGORY: Version */ - -/* - * SDL_revision.h contains the SDL revision, which might be defined on the - * compiler command line, or generated right into the header itself by the - * build system. +/** + * \file SDL_revision.h + * + * Header file containing the SDL revision. */ #ifndef SDL_revision_h_ @@ -32,10 +30,10 @@ #cmakedefine SDL_VENDOR_INFO "@SDL_VENDOR_INFO@" -#if defined(SDL_VENDOR_INFO) -#define SDL_REVISION "release-3.2.0-0-g535d80bad (" SDL_VENDOR_INFO ")" +#ifdef SDL_VENDOR_INFO +#define SDL_REVISION "@SDL_REVISION@ (" SDL_VENDOR_INFO ")" #else -#define SDL_REVISION "release-3.2.0-0-g535d80bad" +#define SDL_REVISION "@SDL_REVISION@" #endif #endif /* SDL_revision_h_ */ diff --git a/libs/SDL3/src/SDL_hashtable.c b/libs/SDL3/src/SDL_hashtable.c index 571e3769..3124b41a 100644 --- a/libs/SDL3/src/SDL_hashtable.c +++ b/libs/SDL3/src/SDL_hashtable.c @@ -19,34 +19,6 @@ 3. This notice may not be removed or altered from any source distribution. */ #include "SDL_internal.h" -#include "SDL_hashtable.h" - -// XXX: We can't use SDL_assert here because it's going to call into hashtable code -#ifdef NDEBUG -#define HT_ASSERT(x) (void)(0) -#else -#if (defined(_WIN32) || defined(SDL_PLATFORM_CYGWIN)) && !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) -#include -#endif -/* This is not declared in any header, although it is shared between some - parts of SDL, because we don't want anything calling it without an - extremely good reason. */ -extern SDL_NORETURN void SDL_ExitProcess(int exitcode); -static void HT_ASSERT_FAIL(const char *msg) -{ - const char *caption = "SDL_HashTable Assertion Failure!"; - (void)caption; -#if (defined(_WIN32) || defined(SDL_PLATFORM_CYGWIN)) && !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) - MessageBoxA(NULL, msg, caption, MB_OK | MB_ICONERROR); -#elif defined(HAVE_STDIO_H) - fprintf(stderr, "\n\n%s\n%s\n\n", caption, msg); - fflush(stderr); -#endif - SDL_TriggerBreakpoint(); - SDL_ExitProcess(-1); -} -#define HT_ASSERT(x) if (!(x)) HT_ASSERT_FAIL("SDL_HashTable Assertion Failure: " #x) -#endif typedef struct SDL_HashItem { @@ -67,47 +39,49 @@ SDL_COMPILE_TIME_ASSERT(sizeof_SDL_HashItem, sizeof(SDL_HashItem) <= MAX_HASHITE struct SDL_HashTable { - SDL_RWLock *lock; + SDL_RWLock *lock; // NULL if not created threadsafe SDL_HashItem *table; - SDL_HashTable_HashFn hash; - SDL_HashTable_KeyMatchFn keymatch; - SDL_HashTable_NukeFn nuke; - void *data; + SDL_HashCallback hash; + SDL_HashKeyMatchCallback keymatch; + SDL_HashDestroyCallback destroy; + void *userdata; Uint32 hash_mask; Uint32 max_probe_len; Uint32 num_occupied_slots; - bool stackable; }; -SDL_HashTable *SDL_CreateHashTable(void *data, - Uint32 num_buckets, - SDL_HashTable_HashFn hashfn, - SDL_HashTable_KeyMatchFn keymatchfn, - SDL_HashTable_NukeFn nukefn, - bool threadsafe, - bool stackable) + +static Uint32 CalculateHashBucketsFromEstimate(int estimated_capacity) { - SDL_HashTable *table; - - // num_buckets must be a power of two so we can derive the bucket index with just a bit-and. - if ((num_buckets < 1) || !SDL_HasExactlyOneBitSet32(num_buckets)) { - SDL_SetError("num_buckets must be a power of two"); - return NULL; + if (estimated_capacity <= 0) { + return 4; // start small, grow as necessary. } - if (num_buckets > MAX_HASHTABLE_SIZE) { - SDL_SetError("num_buckets is too large"); - return NULL; + const Uint32 estimated32 = (Uint32) estimated_capacity; + Uint32 buckets = ((Uint32) 1) << SDL_MostSignificantBitIndex32(estimated32); + if (!SDL_HasExactlyOneBitSet32(estimated32)) { + buckets <<= 1; // need next power of two up to fit overflow capacity bits. } - table = (SDL_HashTable *)SDL_calloc(1, sizeof(SDL_HashTable)); + return SDL_min(buckets, MAX_HASHTABLE_SIZE); +} + +SDL_HashTable *SDL_CreateHashTable(int estimated_capacity, bool threadsafe, SDL_HashCallback hash, + SDL_HashKeyMatchCallback keymatch, + SDL_HashDestroyCallback destroy, void *userdata) +{ + const Uint32 num_buckets = CalculateHashBucketsFromEstimate(estimated_capacity); + SDL_HashTable *table = (SDL_HashTable *)SDL_calloc(1, sizeof(SDL_HashTable)); if (!table) { return NULL; } if (threadsafe) { - // Don't fail if we can't create a lock (single threaded environment?) table->lock = SDL_CreateRWLock(); + if (!table->lock) { + SDL_DestroyHashTable(table); + return NULL; + } } table->table = (SDL_HashItem *)SDL_calloc(num_buckets, sizeof(SDL_HashItem)); @@ -117,24 +91,22 @@ SDL_HashTable *SDL_CreateHashTable(void *data, } table->hash_mask = num_buckets - 1; - table->stackable = stackable; - table->data = data; - table->hash = hashfn; - table->keymatch = keymatchfn; - table->nuke = nukefn; + table->userdata = userdata; + table->hash = hash; + table->keymatch = keymatch; + table->destroy = destroy; return table; } static SDL_INLINE Uint32 calc_hash(const SDL_HashTable *table, const void *key) { const Uint32 BitMixer = 0x9E3779B1u; - return table->hash(key, table->data) * BitMixer; + return table->hash(table->userdata, key) * BitMixer; } static SDL_INLINE Uint32 get_probe_length(Uint32 zero_idx, Uint32 actual_idx, Uint32 num_buckets) { // returns the probe sequence length from zero_idx to actual_idx - if (actual_idx < zero_idx) { return num_buckets - zero_idx + actual_idx; } @@ -149,7 +121,7 @@ static SDL_HashItem *find_item(const SDL_HashTable *ht, const void *key, Uint32 SDL_HashItem *table = ht->table; - for (;;) { + while (true) { SDL_HashItem *item = table + *i; Uint32 item_hash = item->hash; @@ -157,12 +129,12 @@ static SDL_HashItem *find_item(const SDL_HashTable *ht, const void *key, Uint32 return NULL; } - if (item_hash == hash && ht->keymatch(item->key, key, ht->data)) { + if (item_hash == hash && ht->keymatch(ht->userdata, item->key, key)) { return item; } Uint32 item_probe_len = item->probe_len; - HT_ASSERT(item_probe_len == get_probe_length(item_hash & hash_mask, (Uint32)(item - table), hash_mask + 1)); + SDL_assert(item_probe_len == get_probe_length(item_hash & hash_mask, (Uint32)(item - table), hash_mask + 1)); if (*probe_len > item_probe_len) { return NULL; @@ -185,23 +157,23 @@ static SDL_HashItem *find_first_item(const SDL_HashTable *ht, const void *key, U static SDL_HashItem *insert_item(SDL_HashItem *item_to_insert, SDL_HashItem *table, Uint32 hash_mask, Uint32 *max_probe_len_ptr) { + const Uint32 num_buckets = hash_mask + 1; Uint32 idx = item_to_insert->hash & hash_mask; - SDL_HashItem temp_item, *target = NULL; - Uint32 num_buckets = hash_mask + 1; + SDL_HashItem *target = NULL; + SDL_HashItem temp_item; - for (;;) { + while (true) { SDL_HashItem *candidate = table + idx; if (!candidate->live) { // Found an empty slot. Put it here and we're done. - *candidate = *item_to_insert; if (target == NULL) { target = candidate; } - Uint32 probe_len = get_probe_length(candidate->hash & hash_mask, idx, num_buckets); + const Uint32 probe_len = get_probe_length(candidate->hash & hash_mask, idx, num_buckets); candidate->probe_len = probe_len; if (*max_probe_len_ptr < probe_len) { @@ -211,9 +183,9 @@ static SDL_HashItem *insert_item(SDL_HashItem *item_to_insert, SDL_HashItem *tab break; } - Uint32 candidate_probe_len = candidate->probe_len; - HT_ASSERT(candidate_probe_len == get_probe_length(candidate->hash & hash_mask, idx, num_buckets)); - Uint32 new_probe_len = get_probe_length(item_to_insert->hash & hash_mask, idx, num_buckets); + const Uint32 candidate_probe_len = candidate->probe_len; + SDL_assert(candidate_probe_len == get_probe_length(candidate->hash & hash_mask, idx, num_buckets)); + const Uint32 new_probe_len = get_probe_length(item_to_insert->hash & hash_mask, idx, num_buckets); if (candidate_probe_len < new_probe_len) { // Robin Hood hashing: the item at idx has a better probe length than our item would at this position. @@ -229,7 +201,7 @@ static SDL_HashItem *insert_item(SDL_HashItem *item_to_insert, SDL_HashItem *tab *item_to_insert = temp_item; - HT_ASSERT(new_probe_len == get_probe_length(candidate->hash & hash_mask, idx, num_buckets)); + SDL_assert(new_probe_len == get_probe_length(candidate->hash & hash_mask, idx, num_buckets)); candidate->probe_len = new_probe_len; if (*max_probe_len_ptr < new_probe_len) { @@ -245,17 +217,19 @@ static SDL_HashItem *insert_item(SDL_HashItem *item_to_insert, SDL_HashItem *tab static void delete_item(SDL_HashTable *ht, SDL_HashItem *item) { - Uint32 hash_mask = ht->hash_mask; + const Uint32 hash_mask = ht->hash_mask; SDL_HashItem *table = ht->table; - if (ht->nuke) { - ht->nuke(item->key, item->value, ht->data); + if (ht->destroy) { + ht->destroy(ht->userdata, item->key, item->value); } + + SDL_assert(ht->num_occupied_slots > 0); ht->num_occupied_slots--; Uint32 idx = (Uint32)(item - ht->table); - for (;;) { + while (true) { idx = (idx + 1) & hash_mask; SDL_HashItem *next_item = table + idx; @@ -266,22 +240,23 @@ static void delete_item(SDL_HashTable *ht, SDL_HashItem *item) *item = *next_item; item->probe_len -= 1; - HT_ASSERT(item->probe_len < ht->max_probe_len); + SDL_assert(item->probe_len < ht->max_probe_len); item = next_item; } } static bool resize(SDL_HashTable *ht, Uint32 new_size) { - SDL_HashItem *old_table = ht->table; - Uint32 old_size = ht->hash_mask + 1; - Uint32 new_hash_mask = new_size - 1; + const Uint32 new_hash_mask = new_size - 1; SDL_HashItem *new_table = SDL_calloc(new_size, sizeof(*new_table)); if (!new_table) { return false; } + SDL_HashItem *old_table = ht->table; + const Uint32 old_size = ht->hash_mask + 1; + ht->max_probe_len = 0; ht->hash_mask = new_hash_mask; ht->table = new_table; @@ -299,14 +274,14 @@ static bool resize(SDL_HashTable *ht, Uint32 new_size) static bool maybe_resize(SDL_HashTable *ht) { - Uint32 capacity = ht->hash_mask + 1; + const Uint32 capacity = ht->hash_mask + 1; if (capacity >= MAX_HASHTABLE_SIZE) { return false; } - Uint32 max_load_factor = 217; // range: 0-255; 217 is roughly 85% - Uint32 resize_threshold = (Uint32)((max_load_factor * (Uint64)capacity) >> 8); + const Uint32 max_load_factor = 217; // range: 0-255; 217 is roughly 85% + const Uint32 resize_threshold = (Uint32)((max_load_factor * (Uint64)capacity) >> 8); if (ht->num_occupied_slots > resize_threshold) { return resize(ht, capacity * 2); @@ -315,72 +290,66 @@ static bool maybe_resize(SDL_HashTable *ht) return true; } -bool SDL_InsertIntoHashTable(SDL_HashTable *table, const void *key, const void *value) +bool SDL_InsertIntoHashTable(SDL_HashTable *table, const void *key, const void *value, bool replace) { - SDL_HashItem *item; - Uint32 hash; + if (!table) { + return SDL_InvalidParamError("table"); + } + bool result = false; - if (!table) { - return false; + SDL_LockRWLockForWriting(table->lock); + + const Uint32 hash = calc_hash(table, key); + SDL_HashItem *item = find_first_item(table, key, hash); + bool do_insert = true; + + if (item) { + if (replace) { + delete_item(table, item); + } else { + SDL_SetError("key already exists and replace is disabled"); + do_insert = false; + } } - if (table->lock) { - SDL_LockRWLockForWriting(table->lock); + if (do_insert) { + SDL_HashItem new_item; + new_item.key = key; + new_item.value = value; + new_item.hash = hash; + new_item.live = true; + new_item.probe_len = 0; + + table->num_occupied_slots++; + + if (!maybe_resize(table)) { + table->num_occupied_slots--; + } else { + // This never returns NULL + insert_item(&new_item, table->table, table->hash_mask, &table->max_probe_len); + result = true; + } } - hash = calc_hash(table, key); - item = find_first_item(table, key, hash); - - if (item && !table->stackable) { - // Allow overwrites, this might have been inserted on another thread - delete_item(table, item); - } - - SDL_HashItem new_item; - new_item.key = key; - new_item.value = value; - new_item.hash = hash; - new_item.live = true; - new_item.probe_len = 0; - - table->num_occupied_slots++; - - if (!maybe_resize(table)) { - table->num_occupied_slots--; - goto done; - } - - // This never returns NULL - insert_item(&new_item, table->table, table->hash_mask, &table->max_probe_len); - result = true; - -done: - if (table->lock) { - SDL_UnlockRWLock(table->lock); - } + SDL_UnlockRWLock(table->lock); return result; } bool SDL_FindInHashTable(const SDL_HashTable *table, const void *key, const void **value) { - Uint32 hash; - SDL_HashItem *i; - bool result = false; - if (!table) { if (value) { *value = NULL; } - return false; + return SDL_InvalidParamError("table"); } - if (table->lock) { - SDL_LockRWLockForReading(table->lock); - } + SDL_LockRWLockForReading(table->lock); - hash = calc_hash(table, key); - i = find_first_item(table, key, hash); + bool result = false; + const Uint32 hash = calc_hash(table, key); + SDL_HashItem *i = find_first_item(table, key, hash); if (i) { if (value) { *value = i->value; @@ -388,156 +357,91 @@ bool SDL_FindInHashTable(const SDL_HashTable *table, const void *key, const void result = true; } - if (table->lock) { - SDL_UnlockRWLock(table->lock); - } + SDL_UnlockRWLock(table->lock); + return result; } bool SDL_RemoveFromHashTable(SDL_HashTable *table, const void *key) { - Uint32 hash; - SDL_HashItem *item; - bool result = false; - if (!table) { - return false; + return SDL_InvalidParamError("table"); } - if (table->lock) { - SDL_LockRWLockForWriting(table->lock); + SDL_LockRWLockForWriting(table->lock); + + bool result = false; + const Uint32 hash = calc_hash(table, key); + SDL_HashItem *item = find_first_item(table, key, hash); + if (item) { + delete_item(table, item); + result = true; } - // FIXME: what to do for stacking hashtables? - // The original code removes just one item. - // This hashtable happens to preserve the insertion order of multi-value keys, - // so deleting the first one will always delete the least-recently inserted one. - // But maybe it makes more sense to remove all matching items? - - hash = calc_hash(table, key); - item = find_first_item(table, key, hash); - if (!item) { - goto done; - } - - delete_item(table, item); - result = true; - -done: - if (table->lock) { - SDL_UnlockRWLock(table->lock); - } + SDL_UnlockRWLock(table->lock); return result; } -bool SDL_IterateHashTableKey(const SDL_HashTable *table, const void *key, const void **_value, void **iter) +bool SDL_IterateHashTable(const SDL_HashTable *table, SDL_HashTableIterateCallback callback, void *userdata) { - SDL_HashItem *item = (SDL_HashItem *)*iter; - if (!table) { - return false; + return SDL_InvalidParamError("table"); + } else if (!callback) { + return SDL_InvalidParamError("callback"); } - Uint32 i, probe_len, hash; - - if (item) { - HT_ASSERT(item >= table->table); - HT_ASSERT(item < table->table + (table->hash_mask + 1)); - - hash = item->hash; - probe_len = item->probe_len + 1; - i = ((Uint32)(item - table->table) + 1) & table->hash_mask; - item = table->table + i; - } else { - hash = calc_hash(table, key); - i = hash & table->hash_mask; - probe_len = 0; - } - - item = find_item(table, key, hash, &i, &probe_len); - - if (!item) { - *_value = NULL; - return false; - } - - *_value = item->value; - *iter = item; - - return true; -} - -bool SDL_IterateHashTable(const SDL_HashTable *table, const void **_key, const void **_value, void **iter) -{ - SDL_HashItem *item = (SDL_HashItem *)*iter; - - if (!table) { - return false; - } - - if (!item) { - item = table->table; - } else { - item++; - } - - HT_ASSERT(item >= table->table); + SDL_LockRWLockForReading(table->lock); SDL_HashItem *end = table->table + (table->hash_mask + 1); + Uint32 num_iterated = 0; - while (item < end && !item->live) { - ++item; - } - - HT_ASSERT(item <= end); - - if (item == end) { - if (_key) { - *_key = NULL; + for (SDL_HashItem *item = table->table; item < end; item++) { + if (item->live) { + if (!callback(userdata, table, item->key, item->value)) { + break; // callback requested iteration stop. + } else if (++num_iterated >= table->num_occupied_slots) { + break; // we can drop out early because we've seen all the live items. + } } - if (_value) { - *_value = NULL; - } - return false; } - if (_key) { - *_key = item->key; - } - if (_value) { - *_value = item->value; - } - *iter = item; - + SDL_UnlockRWLock(table->lock); return true; } bool SDL_HashTableEmpty(SDL_HashTable *table) { - return !(table && table->num_occupied_slots); + if (!table) { + return SDL_InvalidParamError("table"); + } + + SDL_LockRWLockForReading(table->lock); + const bool retval = (table->num_occupied_slots == 0); + SDL_UnlockRWLock(table->lock); + return retval; } -static void nuke_all(SDL_HashTable *table) -{ - void *data = table->data; - SDL_HashItem *end = table->table + (table->hash_mask + 1); - SDL_HashItem *i; - for (i = table->table; i < end; ++i) { - if (i->live) { - table->nuke(i->key, i->value, data); +static void destroy_all(SDL_HashTable *table) +{ + SDL_HashDestroyCallback destroy = table->destroy; + if (destroy) { + void *userdata = table->userdata; + SDL_HashItem *end = table->table + (table->hash_mask + 1); + for (SDL_HashItem *i = table->table; i < end; ++i) { + if (i->live) { + i->live = false; + destroy(userdata, i->key, i->value); + } } } } -void SDL_EmptyHashTable(SDL_HashTable *table) +void SDL_ClearHashTable(SDL_HashTable *table) { if (table) { SDL_LockRWLockForWriting(table->lock); { - if (table->nuke) { - nuke_all(table); - } - + destroy_all(table); SDL_memset(table->table, 0, sizeof(*table->table) * (table->hash_mask + 1)); table->num_occupied_slots = 0; } @@ -548,9 +452,10 @@ void SDL_EmptyHashTable(SDL_HashTable *table) void SDL_DestroyHashTable(SDL_HashTable *table) { if (table) { - SDL_EmptyHashTable(table); - - SDL_DestroyRWLock(table->lock); + destroy_all(table); + if (table->lock) { + SDL_DestroyRWLock(table->lock); + } SDL_free(table->table); SDL_free(table); } @@ -566,26 +471,26 @@ static SDL_INLINE Uint32 hash_string_djbxor(const char *str, size_t len) return hash; } -Uint32 SDL_HashPointer(const void *key, void *unused) +Uint32 SDL_HashPointer(void *unused, const void *key) { (void)unused; return SDL_murmur3_32(&key, sizeof(key), 0); } -bool SDL_KeyMatchPointer(const void *a, const void *b, void *unused) +bool SDL_KeyMatchPointer(void *unused, const void *a, const void *b) { (void)unused; return (a == b); } -Uint32 SDL_HashString(const void *key, void *unused) +Uint32 SDL_HashString(void *unused, const void *key) { (void)unused; const char *str = (const char *)key; return hash_string_djbxor(str, SDL_strlen(str)); } -bool SDL_KeyMatchString(const void *a, const void *b, void *unused) +bool SDL_KeyMatchString(void *unused, const void *a, const void *b) { const char *a_string = (const char *)a; const char *b_string = (const char *)b; @@ -604,26 +509,33 @@ bool SDL_KeyMatchString(const void *a, const void *b, void *unused) // We assume we can fit the ID in the key directly SDL_COMPILE_TIME_ASSERT(SDL_HashID_KeySize, sizeof(Uint32) <= sizeof(const void *)); -Uint32 SDL_HashID(const void *key, void *unused) +Uint32 SDL_HashID(void *unused, const void *key) { (void)unused; return (Uint32)(uintptr_t)key; } -bool SDL_KeyMatchID(const void *a, const void *b, void *unused) +bool SDL_KeyMatchID(void *unused, const void *a, const void *b) { (void)unused; return (a == b); } -void SDL_NukeFreeKey(const void *key, const void *value, void *unused) +void SDL_DestroyHashKeyAndValue(void *unused, const void *key, const void *value) +{ + (void)unused; + SDL_free((void *)key); + SDL_free((void *)value); +} + +void SDL_DestroyHashKey(void *unused, const void *key, const void *value) { (void)value; (void)unused; SDL_free((void *)key); } -void SDL_NukeFreeValue(const void *key, const void *value, void *unused) +void SDL_DestroyHashValue(void *unused, const void *key, const void *value) { (void)key; (void)unused; diff --git a/libs/SDL3/src/SDL_hashtable.h b/libs/SDL3/src/SDL_hashtable.h index 5983b8d3..598a6d6b 100644 --- a/libs/SDL3/src/SDL_hashtable.h +++ b/libs/SDL3/src/SDL_hashtable.h @@ -18,61 +18,616 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ + +/* this is over-documented because it was almost a public API. Leaving the + full docs here in case it _does_ become public some day. */ + +/* WIKI CATEGORY: HashTable */ + +/** + * # CategoryHashTable + * + * SDL offers a hash table implementation, as a convenience for C code that + * needs efficient organization and access of arbitrary data. + * + * Hash tables are a popular data structure, designed to make it quick to + * store and look up arbitrary data. Data is stored with an associated "key." + * While one would look up an element of an array with an index, a hash table + * uses a unique key to find an element later. + * + * A key can be anything, as long as its unique and in a format that the table + * understands. For example, it's popular to use strings as keys: the key + * might be a username, and it is used to lookup account information for that + * user, etc. + * + * Hash tables are named because they "hash" their keys down into simple + * integers that can be used to efficiently organize and access the associated + * data. + * + * As this is a C API, there is one generic interface that is intended to work + * with different data types. This can be a little awkward to set up, but is + * easy to use after that. + * + * Hashtables are generated by a call to SDL_CreateHashTable(). This function + * requires several callbacks to be provided (for hashing keys, comparing + * entries, and cleaning up entries when removed). These are necessary to + * allow the hash to manage any arbitrary data type. + * + * Once a hash table is created, the common tasks are inserting data into the + * table, (SDL_InsertIntoHashTable), looking up previously inserted data + * (SDL_FindInHashTable), and removing data (SDL_RemoveFromHashTable and + * SDL_ClearHashTable). Less common but still useful is the ability to + * iterate through all the items in the table (SDL_IterateHashTable). + * + * The underlying hash table implementation is always subject to change, but + * at the time of writing, it uses open addressing and Robin Hood hashing. + * The technical details are explained [here](https://github.com/libsdl-org/SDL/pull/10897). + * + * Hashtables keep an SDL_RWLock internally, so multiple threads can perform + * hash lookups in parallel, while changes to the table will safely serialize + * access between threads. + * + * SDL provides a layer on top of this hash table implementation that might be + * more pleasant to use. SDL_PropertiesID maps a string to arbitrary data of + * various types in the same table, which could be both easier to use and more + * flexible. Refer to [CategoryProperties](CategoryProperties) for details. + */ + #ifndef SDL_hashtable_h_ #define SDL_hashtable_h_ -// this is not (currently) a public API. But maybe it should be! +#include -struct SDL_HashTable; +#include +/* Set up for C function definitions, even when using C++ */ +#ifdef __cplusplus +extern "C" { +#endif + +/** + * The opaque type that represents a hash table. + * + * This is hidden behind an opaque pointer because not only does the table + * need to store arbitrary data types, but the hash table implementation may + * change in the future. + * + * \since This struct is available since SDL 3.4.0. + * + * \sa SDL_CreateHashTable + */ typedef struct SDL_HashTable SDL_HashTable; -typedef Uint32 (*SDL_HashTable_HashFn)(const void *key, void *data); -typedef bool (*SDL_HashTable_KeyMatchFn)(const void *a, const void *b, void *data); -typedef void (*SDL_HashTable_NukeFn)(const void *key, const void *value, void *data); -extern SDL_HashTable *SDL_CreateHashTable(void *data, - Uint32 num_buckets, - SDL_HashTable_HashFn hashfn, - SDL_HashTable_KeyMatchFn keymatchfn, - SDL_HashTable_NukeFn nukefn, - bool threadsafe, - bool stackable); +/** + * A function pointer representing a hash table hashing callback. + * + * This is called by SDL_HashTable when it needs to look up a key in + * its dataset. It generates a hash value from that key, and then uses that + * value as a basis for an index into an internal array. + * + * There are no rules on what hashing algorithm is used, so long as it + * can produce a reliable 32-bit value from `key`, and ideally distributes + * those values well across the 32-bit value space. The quality of a + * hashing algorithm is directly related to how well a hash table performs. + * + * Hashing can be a complicated subject, and often times what works best + * for one dataset will be suboptimal for another. There is a good discussion + * of the field [on Wikipedia](https://en.wikipedia.org/wiki/Hash_function). + * + * Also: do you _need_ to write a hashing function? SDL provides generic + * functions for strings (SDL_HashString), generic integer IDs (SDL_HashID), + * and generic pointers (SDL_HashPointer). Often you should use one of these + * before writing your own. + * + * \param userdata what was passed as `userdata` to SDL_CreateHashTable(). + * \param key the key to be hashed. + * \returns a 32-bit value that represents a hash of `key`. + * + * \threadsafety This function must be thread safe if the hash table is used + * from multiple threads at the same time. + * + * \since This datatype is available since SDL 3.4.0. + * + * \sa SDL_CreateHashTable + * \sa SDL_HashString + * \sa SDL_HashID + * \sa SDL_HashPointer + */ +typedef Uint32 (SDLCALL *SDL_HashCallback)(void *userdata, const void *key); -// This function is thread-safe if the hashtable was created with threadsafe = true -extern void SDL_EmptyHashTable(SDL_HashTable *table); -// This function is not thread-safe. +/** + * A function pointer representing a hash table matching callback. + * + * This is called by SDL_HashTable when it needs to look up a key in its + * dataset. After hashing the key, it looks for items stored in relation to + * that hash value. Since there can be more than one item found through the + * same hash value, this function verifies a specific value is actually + * correct before choosing it. + * + * So this function needs to compare the keys at `a` and `b` and decide if + * they are actually the same. + * + * For example, if the keys are C strings, this function might just be: + * + * ```c + * return (SDL_strcmp((const char *) a, const char *b) == 0);` + * ``` + * + * Also: do you _need_ to write a matching function? SDL provides generic + * functions for strings (SDL_KeyMatchString), generic integer IDs + * (SDL_KeyMatchID), and generic pointers (SDL_KeyMatchPointer). Often you + * should use one of these before writing your own. + * + * \param userdata what was passed as `userdata` to SDL_CreateHashTable(). + * \param a the first key to be compared. + * \param b the second key to be compared. + * \returns true if two keys are identical, false otherwise. + * + * \threadsafety This function must be thread safe if the hash table is used + * from multiple threads at the same time. + * + * \since This datatype is available since SDL 3.4.0. + * + * \sa SDL_CreateHashTable + */ +typedef bool (SDLCALL *SDL_HashKeyMatchCallback)(void *userdata, const void *a, const void *b); + + +/** + * A function pointer representing a hash table cleanup callback. + * + * This is called by SDL_HashTable when removing items from the hash, or + * destroying the hash table. It is used to optionally deallocate the + * key/value pairs. + * + * This is not required to do anything, if all the data in the table is + * static or POD data, but it can also do more than a simple free: for + * example, if the hash table is storing open files, it can close them here. + * It can also free only the key or only the value; it depends on what the + * hash table contains. + * + * \param userdata what was passed as `userdata` to SDL_CreateHashTable(). + * \param key the key to deallocate. + * \param value the value to deallocate. + * + * \threadsafety This function must be thread safe if the hash table is used + * from multiple threads at the same time. + * + * \since This datatype is available since SDL 3.4.0. + * + * \sa SDL_CreateHashTable + */ +typedef void (SDLCALL *SDL_HashDestroyCallback)(void *userdata, const void *key, const void *value); + + +/** + * A function pointer representing a hash table iterator callback. + * + * This function is called once for each key/value pair to be considered + * when iterating a hash table. + * + * Iteration continues as long as there are more items to examine and this + * callback continues to return true. + * + * Do not attempt to modify the hash table during this callback, as it will + * cause incorrect behavior and possibly crashes. + * + * \param userdata what was passed as `userdata` to an iterator function. + * \param table the hash table being iterated. + * \param key the current key being iterated. + * \param value the current value being iterated. + * \returns true to keep iterating, false to stop iteration. + * + * \threadsafety A read lock is held during iteration, so other threads can + * still access the the hash table, but threads attempting to + * make changes will be blocked until iteration completes. If + * this is a concern, do as little in the callback as possible + * and finish iteration quickly. + * + * \since This datatype is available since SDL 3.4.0. + * + * \sa SDL_IterateHashTable + */ +typedef bool (SDLCALL *SDL_HashTableIterateCallback)(void *userdata, const SDL_HashTable *table, const void *key, const void *value); + + +/** + * Create a new hash table. + * + * To deal with different datatypes and needs of the caller, hash tables + * require several callbacks that deal with some specifics: how to hash a key, + * how to compare a key for equality, and how to clean up keys and values. + * SDL provides a few generic functions that can be used for these callbacks: + * + * - SDL_HashString and SDL_KeyMatchString for C strings. + * - SDL_HashPointer and SDL_KeyMatchPointer for generic pointers. + * - SDL_HashID and SDL_KeyMatchID for generic (possibly small) integers. + * + * Oftentimes, these are all you need for any hash table, but depending on + * your dataset, custom implementations might make more sense. + * + * You can specify an estimate of the number of items expected to be stored + * in the table, which can help make the table run more efficiently. The table + * will preallocate resources to accomodate this number of items, which is + * most useful if you intend to fill the table with a lot of data right after + * creating it. Otherwise, it might make more sense to specify the _minimum_ + * you expect the table to hold and let it grow as necessary from there. This + * number is only a hint, and the table will be able to handle any amount of + * data--as long as the system doesn't run out of resources--so a perfect + * answer is not required. A value of 0 signifies no guess at all, and the + * table will start small and reallocate as necessary; often this is the + * correct thing to do. + * + * !!! FIXME: add note about `threadsafe` here. And update `threadsafety` tags. + * !!! FIXME: note that `threadsafe` tables can't be recursively locked, so + * !!! FIXME: you can't use `destroy` callbacks that might end up relocking. + * + * Note that SDL provides a higher-level option built on its hash tables: + * SDL_PropertiesID lets you map strings to various datatypes, and this + * might be easier to use. It only allows strings for keys, however. Those are + * created with SDL_CreateProperties(). + * + * The returned hash table should be destroyed with SDL_DestroyHashTable() + * when no longer needed. + * + * \param estimated_capacity the approximate maximum number of items to be held + * in the hash table, or 0 for no estimate. + * \param threadsafe true to create an internal rwlock for this table. + * \param hash the function to use to hash keys. + * \param keymatch the function to use to compare keys. + * \param destroy the function to use to clean up keys and values, may be NULL. + * \param userdata a pointer that is passed to the callbacks. + * \returns a newly-created hash table, or NULL if there was an error; call + * SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_DestroyHashTable + */ +extern SDL_HashTable * SDL_CreateHashTable(int estimated_capacity, + bool threadsafe, + SDL_HashCallback hash, + SDL_HashKeyMatchCallback keymatch, + SDL_HashDestroyCallback destroy, + void *userdata); + + +/** + * Destroy a hash table. + * + * This will call the hash table's SDL_HashDestroyCallback for each item in + * the table, removing all inserted items, before deallocating the table + * itself. + * + * The table becomes invalid once this function is called, and no other thread + * should be accessing this table once this function has started. + * + * \param table the hash table to destroy. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + */ extern void SDL_DestroyHashTable(SDL_HashTable *table); -// This function is thread-safe if the hashtable was created with threadsafe = true -extern bool SDL_InsertIntoHashTable(SDL_HashTable *table, const void *key, const void *value); +/** + * Add an item to a hash table. + * + * All keys in the table must be unique. If attempting to insert a key that + * already exists in the hash table, what will be done depends on the + * `replace` value: + * + * - If `replace` is false, this function will return false without modifying + * the table. + * - If `replace` is true, SDL will remove the previous item first, so the new + * value is the only one associated with that key. This will call the hash + * table's SDL_HashDestroyCallback for the previous item. + * + * \param table the hash table to insert into. + * \param key the key of the new item to insert. + * \param value the value of the new item to insert. + * \param replace true if a duplicate key should replace the previous value. + * \returns true if the new item was inserted, false otherwise. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + */ +extern bool SDL_InsertIntoHashTable(SDL_HashTable *table, const void *key, const void *value, bool replace); -// This function is thread-safe if the hashtable was created with threadsafe = true +/** + * Look up an item in a hash table. + * + * On return, the value associated with `key` is stored to `*value`. + * If the key does not exist in the table, `*value` will be set to NULL. + * + * It is legal for `value` to be NULL, to not retrieve the key's value. In + * this case, the return value is still useful for reporting if the key exists + * in the table at all. + * + * \param table the hash table to search. + * \param key the key to search for in the table. + * \param value the found value will be stored here. Can be NULL. + * \returns true if key exists in the table, false otherwise. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_InsertIntoHashTable + */ +extern bool SDL_FindInHashTable(const SDL_HashTable *table, const void *key, const void **value); + +/** + * Remove an item from a hash table. + * + * If there is an item that matches `key`, it is removed from the table. This + * will call the hash table's SDL_HashDestroyCallback for the item to be + * removed. + * + * \param table the hash table to remove from. + * \param key the key of the item to remove from the table. + * \returns true if a key was removed, false if the key was not found. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + */ extern bool SDL_RemoveFromHashTable(SDL_HashTable *table, const void *key); -// This function is thread-safe if the hashtable was created with threadsafe = true -extern bool SDL_FindInHashTable(const SDL_HashTable *table, const void *key, const void **_value); +/** + * Remove all items in a hash table. + * + * This will call the hash table's SDL_HashDestroyCallback for each item in + * the table, removing all inserted items. + * + * When this function returns, the hash table will be empty. + * + * \param table the hash table to clear. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + */ +extern void SDL_ClearHashTable(SDL_HashTable *table); -// This function is thread-safe if the hashtable was created with threadsafe = true +/** + * Check if any items are currently stored in a hash table. + * + * If there are no items stored (the table is completely empty), this will + * return true. + * + * \param table the hash table to check. + * \returns true if the table is completely empty, false otherwise. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_ClearHashTable + */ extern bool SDL_HashTableEmpty(SDL_HashTable *table); -// iterate all values for a specific key. This only makes sense if the hash is stackable. If not-stackable, just use SDL_FindInHashTable(). -// This function is not thread-safe, you should use external locking if you use this function -extern bool SDL_IterateHashTableKey(const SDL_HashTable *table, const void *key, const void **_value, void **iter); +/** + * Iterate all key/value pairs in a hash table. + * + * This function will call `callback` once for each key/value pair in the + * table, until either all pairs have been presented to the callback, or the + * callback has returned false to signal it is done. + * + * There is no guarantee what order results will be returned in. + * + * \param table the hash table to iterate. + * \param callback the function pointer to call for each value. + * \param userdata a pointer that is passed to `callback`. + * \returns true if iteration happened, false if not (bogus parameter, etc). + * + * \since This function is available since SDL 3.4.0. + */ +extern bool SDL_IterateHashTable(const SDL_HashTable *table, SDL_HashTableIterateCallback callback, void *userdata); -// iterate all key/value pairs in a hash (stackable hashes can have duplicate keys with multiple values). -// This function is not thread-safe, you should use external locking if you use this function -extern bool SDL_IterateHashTable(const SDL_HashTable *table, const void **_key, const void **_value, void **iter); -extern Uint32 SDL_HashPointer(const void *key, void *unused); -extern bool SDL_KeyMatchPointer(const void *a, const void *b, void *unused); +/* Helper functions for SDL_CreateHashTable callbacks... */ -extern Uint32 SDL_HashString(const void *key, void *unused); -extern bool SDL_KeyMatchString(const void *a, const void *b, void *unused); +/** + * Generate a hash from a generic pointer. + * + * The key is intended to be a unique pointer to any datatype. + * + * This is intended to be used as one of the callbacks to SDL_CreateHashTable, + * if this is useful to the type of keys to be used with the hash table. + * + * Note that the implementation may change in the future; do not expect + * the results to be stable vs future SDL releases. Use this in a hash table + * in the current process and don't store them to disk for the future. + * + * \param unused this parameter is ignored. + * \param key the key to hash as a generic pointer. + * \returns a 32-bit hash of the key. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_CreateHashTable + */ +extern Uint32 SDL_HashPointer(void *unused, const void *key); -extern Uint32 SDL_HashID(const void *key, void *unused); -extern bool SDL_KeyMatchID(const void *a, const void *b, void *unused); +/** + * Compare two generic pointers as hash table keys. + * + * This is intended to be used as one of the callbacks to SDL_CreateHashTable, + * if this is useful to the type of keys to be used with the hash table. + * + * \param unused this parameter is ignored. + * \param a the first generic pointer to compare. + * \param b the second generic pointer to compare. + * \returns true if the pointers are the same, false otherwise. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_CreateHashTable + */ +extern bool SDL_KeyMatchPointer(void *unused, const void *a, const void *b); -extern void SDL_NukeFreeKey(const void *key, const void *value, void *unused); -extern void SDL_NukeFreeValue(const void *key, const void *value, void *unused); +/** + * Generate a hash from a C string. + * + * The key is intended to be a NULL-terminated string, in UTF-8 format. + * + * This is intended to be used as one of the callbacks to SDL_CreateHashTable, + * if this is useful to the type of keys to be used with the hash table. + * + * Note that the implementation may change in the future; do not expect + * the results to be stable vs future SDL releases. Use this in a hash table + * in the current process and don't store them to disk for the future. + * + * \param unused this parameter is ignored. + * \param key the key to hash as a generic pointer. + * \returns a 32-bit hash of the key. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_CreateHashTable + */ +extern Uint32 SDL_HashString(void *unused, const void *key); -#endif // SDL_hashtable_h_ +/** + * Compare two C strings as hash table keys. + * + * Strings will be compared in a case-sensitive manner. More specifically, + * they'll be compared as NULL-terminated arrays of bytes. + * + * This is intended to be used as one of the callbacks to SDL_CreateHashTable, + * if this is useful to the type of keys to be used with the hash table. + * + * \param unused this parameter is ignored. + * \param a the first string to compare. + * \param b the second string to compare. + * \returns true if the strings are the same, false otherwise. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_CreateHashTable + */ +extern bool SDL_KeyMatchString(void *unused, const void *a, const void *b); + +/** + * Generate a hash from an integer ID. + * + * The key is intended to a unique integer, possibly within a small range. + * + * This is intended to be used as one of the callbacks to SDL_CreateHashTable, + * if this is useful to the type of keys to be used with the hash table. + * + * Note that the implementation may change in the future; do not expect + * the results to be stable vs future SDL releases. Use this in a hash table + * in the current process and don't store them to disk for the future. + * + * \param unused this parameter is ignored. + * \param key the key to hash as a generic pointer. + * \returns a 32-bit hash of the key. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_CreateHashTable + */ +extern Uint32 SDL_HashID(void *unused, const void *key); + +/** + * Compare two integer IDs as hash table keys. + * + * This is intended to be used as one of the callbacks to SDL_CreateHashTable, + * if this is useful to the type of keys to be used with the hash table. + * + * \param unused this parameter is ignored. + * \param a the first ID to compare. + * \param b the second ID to compare. + * \returns true if the IDs are the same, false otherwise. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_CreateHashTable + */ +extern bool SDL_KeyMatchID(void *unused, const void *a, const void *b); + +/** + * Free both the key and value pointers of a hash table item. + * + * This is intended to be used as one of the callbacks to SDL_CreateHashTable, + * if this is useful to the type of data to be used with the hash table. + * + * This literally calls `SDL_free(key);` and `SDL_free(value);`. + * + * \param unused this parameter is ignored. + * \param key the key to be destroyed. + * \param value the value to be destroyed. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_CreateHashTable + */ +extern void SDL_DestroyHashKeyAndValue(void *unused, const void *key, const void *value); + +/** + * Free just the value pointer of a hash table item. + * + * This is intended to be used as one of the callbacks to SDL_CreateHashTable, + * if this is useful to the type of data to be used with the hash table. + * + * This literally calls `SDL_free(key);` and leaves `value` alone. + * + * \param unused this parameter is ignored. + * \param key the key to be destroyed. + * \param value the value to be destroyed. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_CreateHashTable + */ +extern void SDL_DestroyHashKey(void *unused, const void *key, const void *value); + +/** + * Free just the value pointer of a hash table item. + * + * This is intended to be used as one of the callbacks to SDL_CreateHashTable, + * if this is useful to the type of data to be used with the hash table. + * + * This literally calls `SDL_free(value);` and leaves `key` alone. + * + * \param unused this parameter is ignored. + * \param key the key to be destroyed. + * \param value the value to be destroyed. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_CreateHashTable + */ +extern void SDL_DestroyHashValue(void *unused, const void *key, const void *value); + + +/* Ends C function definitions when using C++ */ +#ifdef __cplusplus +} +#endif +#include + +#endif /* SDL_hashtable_h_ */ diff --git a/libs/SDL3/src/SDL_internal.h b/libs/SDL3/src/SDL_internal.h index ac018f9b..a345252f 100644 --- a/libs/SDL3/src/SDL_internal.h +++ b/libs/SDL3/src/SDL_internal.h @@ -191,6 +191,11 @@ #define SDL_VIDEO_RENDER_SW 1 #endif +/* STB image conversion */ +#if !defined(SDL_HAVE_STB) && !defined(SDL_LEAN_AND_MEAN) +#define SDL_HAVE_STB 1 +#endif + /* YUV formats - handling of YUV surfaces - blitting and conversion functions */ @@ -198,6 +203,17 @@ #define SDL_HAVE_YUV 1 #endif +#ifdef SDL_CAMERA_DISABLED +#undef SDL_CAMERA_DRIVER_ANDROID +#undef SDL_CAMERA_DRIVER_COREMEDIA +#undef SDL_CAMERA_DRIVER_DUMMY +#undef SDL_CAMERA_DRIVER_EMSCRIPTEN +#undef SDL_CAMERA_DRIVER_MEDIAFOUNDATION +#undef SDL_CAMERA_DRIVER_PIPEWIRE +#undef SDL_CAMERA_DRIVER_V4L2 +#undef SDL_CAMERA_DRIVER_VITA +#endif + #ifdef SDL_RENDER_DISABLED #undef SDL_VIDEO_RENDER_SW #undef SDL_VIDEO_RENDER_D3D diff --git a/libs/SDL3/src/SDL_properties.c b/libs/SDL3/src/SDL_properties.c index 9dc10a67..166ea0f9 100644 --- a/libs/SDL3/src/SDL_properties.c +++ b/libs/SDL3/src/SDL_properties.c @@ -76,7 +76,7 @@ static void SDL_FreePropertyWithCleanup(const void *key, const void *value, void SDL_free((void *)value); } -static void SDL_FreeProperty(const void *key, const void *value, void *data) +static void SDLCALL SDL_FreeProperty(void *data, const void *key, const void *value) { SDL_FreePropertyWithCleanup(key, value, data, true); } @@ -84,14 +84,8 @@ static void SDL_FreeProperty(const void *key, const void *value, void *data) static void SDL_FreeProperties(SDL_Properties *properties) { if (properties) { - if (properties->props) { - SDL_DestroyHashTable(properties->props); - properties->props = NULL; - } - if (properties->lock) { - SDL_DestroyMutex(properties->lock); - properties->lock = NULL; - } + SDL_DestroyHashTable(properties->props); + SDL_DestroyMutex(properties->lock); SDL_free(properties); } } @@ -102,18 +96,16 @@ bool SDL_InitProperties(void) return true; } - SDL_properties = SDL_CreateHashTable(NULL, 16, SDL_HashID, SDL_KeyMatchID, NULL, true, false); - if (!SDL_properties) { - goto error; - } + SDL_properties = SDL_CreateHashTable(0, true, SDL_HashID, SDL_KeyMatchID, NULL, NULL); + const bool initialized = (SDL_properties != NULL); + SDL_SetInitialized(&SDL_properties_init, initialized); + return initialized; +} - SDL_SetInitialized(&SDL_properties_init, true); - return true; - -error: - SDL_SetInitialized(&SDL_properties_init, true); - SDL_QuitProperties(); - return false; +static bool SDLCALL FreeOneProperties(void *userdata, const SDL_HashTable *table, const void *key, const void *value) +{ + SDL_FreeProperties((SDL_Properties *)value); + return true; // keep iterating. } void SDL_QuitProperties(void) @@ -131,17 +123,13 @@ void SDL_QuitProperties(void) SDL_DestroyProperties(props); } - if (SDL_properties) { - void *iter; - const void *key, *value; - - iter = NULL; - while (SDL_IterateHashTable(SDL_properties, &key, &value, &iter)) { - SDL_FreeProperties((SDL_Properties *)value); - } - SDL_DestroyHashTable(SDL_properties); - SDL_properties = NULL; - } + // this can't just DestroyHashTable with SDL_FreeProperties as the destructor, because + // other destructors under this might cause use to attempt a recursive lock on SDL_properties, + // which isn't allowed with rwlocks. So manually iterate and free everything. + SDL_HashTable *properties = SDL_properties; + SDL_properties = NULL; + SDL_IterateHashTable(properties, FreeOneProperties, NULL); + SDL_DestroyHashTable(properties); SDL_SetInitialized(&SDL_properties_init, false); } @@ -167,55 +155,101 @@ SDL_PropertiesID SDL_GetGlobalProperties(void) SDL_PropertiesID SDL_CreateProperties(void) { - SDL_PropertiesID props = 0; - SDL_Properties *properties = NULL; - bool inserted = false; - if (!SDL_CheckInitProperties()) { return 0; } - properties = (SDL_Properties *)SDL_calloc(1, sizeof(*properties)); + SDL_Properties *properties = (SDL_Properties *)SDL_calloc(1, sizeof(*properties)); if (!properties) { - goto error; - } - properties->props = SDL_CreateHashTable(NULL, 4, SDL_HashString, SDL_KeyMatchString, SDL_FreeProperty, false, false); - if (!properties->props) { - goto error; + return 0; } - // If this fails we'll continue without it. properties->lock = SDL_CreateMutex(); + if (!properties->lock) { + SDL_free(properties); + return 0; + } - for ( ; ; ) { + properties->props = SDL_CreateHashTable(0, false, SDL_HashString, SDL_KeyMatchString, SDL_FreeProperty, NULL); + if (!properties->props) { + SDL_DestroyMutex(properties->lock); + SDL_free(properties); + return 0; + } + + SDL_PropertiesID props = 0; + while (true) { props = (SDL_GetAtomicU32(&SDL_last_properties_id) + 1); if (props == 0) { continue; - } - if (SDL_CompareAndSwapAtomicU32(&SDL_last_properties_id, props - 1, props)) { + } else if (SDL_CompareAndSwapAtomicU32(&SDL_last_properties_id, props - 1, props)) { break; } } - if (SDL_InsertIntoHashTable(SDL_properties, (const void *)(uintptr_t)props, properties)) { - inserted = true; + + SDL_assert(!SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, NULL)); // should NOT be in the hash table already. + + if (!SDL_InsertIntoHashTable(SDL_properties, (const void *)(uintptr_t)props, properties, false)) { + SDL_FreeProperties(properties); + return 0; } - if (inserted) { - // All done! - return props; + return props; // All done! +} + +typedef struct CopyOnePropertyData +{ + SDL_Properties *dst_properties; + bool result; +} CopyOnePropertyData; + +static bool SDLCALL CopyOneProperty(void *userdata, const SDL_HashTable *table, const void *key, const void *value) +{ + const SDL_Property *src_property = (const SDL_Property *)value; + if (src_property->cleanup) { + // Can't copy properties with cleanup functions, we don't know how to duplicate the data + return true; // keep iterating. } -error: - SDL_FreeProperties(properties); - return 0; + CopyOnePropertyData *data = (CopyOnePropertyData *) userdata; + SDL_Properties *dst_properties = data->dst_properties; + const char *src_name = (const char *)key; + SDL_Property *dst_property; + + char *dst_name = SDL_strdup(src_name); + if (!dst_name) { + data->result = false; + return true; // keep iterating (I guess...?) + } + + dst_property = (SDL_Property *)SDL_malloc(sizeof(*dst_property)); + if (!dst_property) { + SDL_free(dst_name); + data->result = false; + return true; // keep iterating (I guess...?) + } + + SDL_copyp(dst_property, src_property); + if (src_property->type == SDL_PROPERTY_TYPE_STRING) { + dst_property->value.string_value = SDL_strdup(src_property->value.string_value); + if (!dst_property->value.string_value) { + SDL_free(dst_name); + SDL_free(dst_property); + data->result = false; + return true; // keep iterating (I guess...?) + } + } + + if (!SDL_InsertIntoHashTable(dst_properties->props, dst_name, dst_property, true)) { + SDL_FreePropertyWithCleanup(dst_name, dst_property, NULL, false); + data->result = false; + } + + return true; // keep iterating. } bool SDL_CopyProperties(SDL_PropertiesID src, SDL_PropertiesID dst) { - SDL_Properties *src_properties = NULL; - SDL_Properties *dst_properties = NULL; - bool result = true; - if (!src) { return SDL_InvalidParamError("src"); } @@ -223,55 +257,25 @@ bool SDL_CopyProperties(SDL_PropertiesID src, SDL_PropertiesID dst) return SDL_InvalidParamError("dst"); } + SDL_Properties *src_properties = NULL; + SDL_Properties *dst_properties = NULL; + SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)src, (const void **)&src_properties); - SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)dst, (const void **)&dst_properties); if (!src_properties) { return SDL_InvalidParamError("src"); } + SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)dst, (const void **)&dst_properties); if (!dst_properties) { return SDL_InvalidParamError("dst"); } + bool result = true; SDL_LockMutex(src_properties->lock); SDL_LockMutex(dst_properties->lock); { - void *iter; - const void *key, *value; - - iter = NULL; - while (SDL_IterateHashTable(src_properties->props, &key, &value, &iter)) { - const char *src_name = (const char *)key; - const SDL_Property *src_property = (const SDL_Property *)value; - char *dst_name; - SDL_Property *dst_property; - - if (src_property->cleanup) { - // Can't copy properties with cleanup functions, we don't know how to duplicate the data - continue; - } - - SDL_RemoveFromHashTable(dst_properties->props, src_name); - - dst_name = SDL_strdup(src_name); - if (!dst_name) { - result = false; - continue; - } - dst_property = (SDL_Property *)SDL_malloc(sizeof(*dst_property)); - if (!dst_property) { - SDL_free(dst_name); - result = false; - continue; - } - SDL_copyp(dst_property, src_property); - if (src_property->type == SDL_PROPERTY_TYPE_STRING) { - dst_property->value.string_value = SDL_strdup(src_property->value.string_value); - } - if (!SDL_InsertIntoHashTable(dst_properties->props, dst_name, dst_property)) { - SDL_FreePropertyWithCleanup(dst_name, dst_property, NULL, false); - result = false; - } - } + CopyOnePropertyData data = { dst_properties, true }; + SDL_IterateHashTable(src_properties->props, CopyOneProperty, &data); + result = data.result; } SDL_UnlockMutex(dst_properties->lock); SDL_UnlockMutex(src_properties->lock); @@ -337,7 +341,7 @@ static bool SDL_PrivateSetProperty(SDL_PropertiesID props, const char *name, SDL SDL_RemoveFromHashTable(properties->props, name); if (property) { char *key = SDL_strdup(name); - if (!SDL_InsertIntoHashTable(properties->props, key, property)) { + if (!key || !SDL_InsertIntoHashTable(properties->props, key, property, false)) { SDL_FreePropertyWithCleanup(key, property, NULL, true); result = false; } @@ -518,10 +522,9 @@ void *SDL_GetPointerProperty(SDL_PropertiesID props, const char *name, void *def return value; } - /* Note that taking the lock here only guarantees that we won't read the - * hashtable while it's being modified. The value itself can easily be - * freed from another thread after it is returned here. - */ + // Note that taking the lock here only guarantees that we won't read the + // hashtable while it's being modified. The value itself can easily be + // freed from another thread after it is returned here. SDL_LockMutex(properties->lock); { SDL_Property *property = NULL; @@ -731,6 +734,23 @@ bool SDL_ClearProperty(SDL_PropertiesID props, const char *name) return SDL_PrivateSetProperty(props, name, NULL); } +typedef struct EnumerateOnePropertyData +{ + SDL_EnumeratePropertiesCallback callback; + void *userdata; + SDL_PropertiesID props; +} EnumerateOnePropertyData; + + +static bool SDLCALL EnumerateOneProperty(void *userdata, const SDL_HashTable *table, const void *key, const void *value) +{ + (void) table; + (void) value; + const EnumerateOnePropertyData *data = (const EnumerateOnePropertyData *) userdata; + data->callback(data->userdata, data->props, (const char *)key); + return true; // keep iterating. +} + bool SDL_EnumerateProperties(SDL_PropertiesID props, SDL_EnumeratePropertiesCallback callback, void *userdata) { SDL_Properties *properties = NULL; @@ -749,13 +769,8 @@ bool SDL_EnumerateProperties(SDL_PropertiesID props, SDL_EnumeratePropertiesCall SDL_LockMutex(properties->lock); { - void *iter; - const void *key, *value; - - iter = NULL; - while (SDL_IterateHashTable(properties->props, &key, &value, &iter)) { - callback(userdata, props, (const char *)key); - } + EnumerateOnePropertyData data = { callback, userdata, props }; + SDL_IterateHashTable(properties->props, EnumerateOneProperty, &data); } SDL_UnlockMutex(properties->lock); @@ -766,25 +781,25 @@ static void SDLCALL SDL_DumpPropertiesCallback(void *userdata, SDL_PropertiesID { switch (SDL_GetPropertyType(props, name)) { case SDL_PROPERTY_TYPE_POINTER: - SDL_Log("%s: %p\n", name, SDL_GetPointerProperty(props, name, NULL)); + SDL_Log("%s: %p", name, SDL_GetPointerProperty(props, name, NULL)); break; case SDL_PROPERTY_TYPE_STRING: - SDL_Log("%s: \"%s\"\n", name, SDL_GetStringProperty(props, name, "")); + SDL_Log("%s: \"%s\"", name, SDL_GetStringProperty(props, name, "")); break; case SDL_PROPERTY_TYPE_NUMBER: { Sint64 value = SDL_GetNumberProperty(props, name, 0); - SDL_Log("%s: %" SDL_PRIs64 " (%" SDL_PRIx64 ")\n", name, value, value); + SDL_Log("%s: %" SDL_PRIs64 " (%" SDL_PRIx64 ")", name, value, value); } break; case SDL_PROPERTY_TYPE_FLOAT: - SDL_Log("%s: %g\n", name, SDL_GetFloatProperty(props, name, 0.0f)); + SDL_Log("%s: %g", name, SDL_GetFloatProperty(props, name, 0.0f)); break; case SDL_PROPERTY_TYPE_BOOLEAN: - SDL_Log("%s: %s\n", name, SDL_GetBooleanProperty(props, name, false) ? "true" : "false"); + SDL_Log("%s: %s", name, SDL_GetBooleanProperty(props, name, false) ? "true" : "false"); break; default: - SDL_Log("%s UNKNOWN TYPE\n", name); + SDL_Log("%s UNKNOWN TYPE", name); break; } } @@ -796,14 +811,14 @@ bool SDL_DumpProperties(SDL_PropertiesID props) void SDL_DestroyProperties(SDL_PropertiesID props) { - SDL_Properties *properties = NULL; - - if (!props) { - return; - } - - if (SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties)) { - SDL_FreeProperties(properties); - SDL_RemoveFromHashTable(SDL_properties, (const void *)(uintptr_t)props); + if (props) { + // this can't just use RemoveFromHashTable with SDL_FreeProperties as the destructor, because + // other destructors under this might cause use to attempt a recursive lock on SDL_properties, + // which isn't allowed with rwlocks. So manually look it up and remove/free it. + SDL_Properties *properties = NULL; + if (SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties)) { + SDL_FreeProperties(properties); + SDL_RemoveFromHashTable(SDL_properties, (const void *)(uintptr_t)props); + } } } diff --git a/libs/SDL3/src/SDL_utils.c b/libs/SDL3/src/SDL_utils.c index a877360f..8d321430 100644 --- a/libs/SDL3/src/SDL_utils.c +++ b/libs/SDL3/src/SDL_utils.c @@ -24,6 +24,9 @@ #include #endif +#include "joystick/SDL_joystick_c.h" // For SDL_GetGamepadTypeFromVIDPID() + + // Common utility functions that aren't in the public API int SDL_powerof2(int x) @@ -135,12 +138,12 @@ Uint32 SDL_GetNextObjectID(void) static SDL_InitState SDL_objects_init; static SDL_HashTable *SDL_objects; -static Uint32 SDL_HashObject(const void *key, void *unused) +static Uint32 SDLCALL SDL_HashObject(void *unused, const void *key) { return (Uint32)(uintptr_t)key; } -static bool SDL_KeyMatchObject(const void *a, const void *b, void *unused) +static bool SDL_KeyMatchObject(void *unused, const void *a, const void *b) { return (a == b); } @@ -149,16 +152,17 @@ void SDL_SetObjectValid(void *object, SDL_ObjectType type, bool valid) { SDL_assert(object != NULL); - if (valid && SDL_ShouldInit(&SDL_objects_init)) { - SDL_objects = SDL_CreateHashTable(NULL, 32, SDL_HashObject, SDL_KeyMatchObject, NULL, true, false); - if (!SDL_objects) { - SDL_SetInitialized(&SDL_objects_init, false); + if (SDL_ShouldInit(&SDL_objects_init)) { + SDL_objects = SDL_CreateHashTable(0, true, SDL_HashObject, SDL_KeyMatchObject, NULL, NULL); + const bool initialized = (SDL_objects != NULL); + SDL_SetInitialized(&SDL_objects_init, initialized); + if (!initialized) { + return; } - SDL_SetInitialized(&SDL_objects_init, true); } if (valid) { - SDL_InsertIntoHashTable(SDL_objects, object, (void *)(uintptr_t)type); + SDL_InsertIntoHashTable(SDL_objects, object, (void *)(uintptr_t)type, true); } else { SDL_RemoveFromHashTable(SDL_objects, object); } @@ -178,75 +182,65 @@ bool SDL_ObjectValid(void *object, SDL_ObjectType type) return (((SDL_ObjectType)(uintptr_t)object_type) == type); } +typedef struct GetOneObjectData +{ + const SDL_ObjectType type; + void **objects; + const int count; + int num_objects; +} GetOneObjectData; + +static bool SDLCALL GetOneObject(void *userdata, const SDL_HashTable *table, const void *object, const void *object_type) +{ + GetOneObjectData *data = (GetOneObjectData *) userdata; + if ((SDL_ObjectType)(uintptr_t)object_type == data->type) { + if (data->num_objects < data->count) { + data->objects[data->num_objects] = (void *)object; + } + ++data->num_objects; + } + return true; // keep iterating. +} + + int SDL_GetObjects(SDL_ObjectType type, void **objects, int count) { - const void *object, *object_type; - void *iter = NULL; - int num_objects = 0; - while (SDL_IterateHashTable(SDL_objects, &object, &object_type, &iter)) { - if ((SDL_ObjectType)(uintptr_t)object_type == type) { - if (num_objects < count) { - objects[num_objects] = (void *)object; - } - ++num_objects; - } + GetOneObjectData data = { type, objects, count, 0 }; + SDL_IterateHashTable(SDL_objects, GetOneObject, &data); + return data.num_objects; +} + +static bool SDLCALL LogOneLeakedObject(void *userdata, const SDL_HashTable *table, const void *object, const void *object_type) +{ + const char *type = "unknown object"; + switch ((SDL_ObjectType)(uintptr_t)object_type) { + #define SDLOBJTYPECASE(typ, name) case SDL_OBJECT_TYPE_##typ: type = name; break + SDLOBJTYPECASE(WINDOW, "SDL_Window"); + SDLOBJTYPECASE(RENDERER, "SDL_Renderer"); + SDLOBJTYPECASE(TEXTURE, "SDL_Texture"); + SDLOBJTYPECASE(JOYSTICK, "SDL_Joystick"); + SDLOBJTYPECASE(GAMEPAD, "SDL_Gamepad"); + SDLOBJTYPECASE(HAPTIC, "SDL_Haptic"); + SDLOBJTYPECASE(SENSOR, "SDL_Sensor"); + SDLOBJTYPECASE(HIDAPI_DEVICE, "hidapi device"); + SDLOBJTYPECASE(HIDAPI_JOYSTICK, "hidapi joystick"); + SDLOBJTYPECASE(THREAD, "thread"); + SDLOBJTYPECASE(TRAY, "SDL_Tray"); + #undef SDLOBJTYPECASE + default: break; } - return num_objects; + SDL_Log("Leaked %s (%p)", type, object); + return true; // keep iterating. } void SDL_SetObjectsInvalid(void) { if (SDL_ShouldQuit(&SDL_objects_init)) { // Log any leaked objects - const void *object, *object_type; - void *iter = NULL; - while (SDL_IterateHashTable(SDL_objects, &object, &object_type, &iter)) { - const char *type; - switch ((SDL_ObjectType)(uintptr_t)object_type) { - case SDL_OBJECT_TYPE_WINDOW: - type = "SDL_Window"; - break; - case SDL_OBJECT_TYPE_RENDERER: - type = "SDL_Renderer"; - break; - case SDL_OBJECT_TYPE_TEXTURE: - type = "SDL_Texture"; - break; - case SDL_OBJECT_TYPE_JOYSTICK: - type = "SDL_Joystick"; - break; - case SDL_OBJECT_TYPE_GAMEPAD: - type = "SDL_Gamepad"; - break; - case SDL_OBJECT_TYPE_HAPTIC: - type = "SDL_Haptic"; - break; - case SDL_OBJECT_TYPE_SENSOR: - type = "SDL_Sensor"; - break; - case SDL_OBJECT_TYPE_HIDAPI_DEVICE: - type = "hidapi device"; - break; - case SDL_OBJECT_TYPE_HIDAPI_JOYSTICK: - type = "hidapi joystick"; - break; - case SDL_OBJECT_TYPE_THREAD: - type = "thread"; - break; - case SDL_OBJECT_TYPE_TRAY: - type = "SDL_Tray"; - break; - default: - type = "unknown object"; - break; - } - SDL_Log("Leaked %s (%p)\n", type, object); - } + SDL_IterateHashTable(SDL_objects, LogOneLeakedObject, NULL); SDL_assert(SDL_HashTableEmpty(SDL_objects)); - SDL_DestroyHashTable(SDL_objects); SDL_objects = NULL; - SDL_SetInitialized(&SDL_objects_init, false); } } @@ -384,7 +378,7 @@ const char *SDL_GetPersistentString(const char *string) SDL_HashTable *strings = (SDL_HashTable *)SDL_GetTLS(&SDL_string_storage); if (!strings) { - strings = SDL_CreateHashTable(NULL, 32, SDL_HashString, SDL_KeyMatchString, SDL_NukeFreeValue, false, false); + strings = SDL_CreateHashTable(0, false, SDL_HashString, SDL_KeyMatchString, SDL_DestroyHashValue, NULL); if (!strings) { return NULL; } @@ -400,8 +394,157 @@ const char *SDL_GetPersistentString(const char *string) } // If the hash table insert fails, at least we can return the string we allocated - SDL_InsertIntoHashTable(strings, new_string, new_string); + SDL_InsertIntoHashTable(strings, new_string, new_string, false); result = new_string; } return result; } + +static int PrefixMatch(const char *a, const char *b) +{ + int matchlen = 0; + while (*a && *b) { + if (SDL_tolower((unsigned char)*a++) == SDL_tolower((unsigned char)*b++)) { + ++matchlen; + } else { + break; + } + } + return matchlen; +} + +char *SDL_CreateDeviceName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name, const char *default_name) +{ + static struct + { + const char *prefix; + const char *replacement; + } replacements[] = { + { "8BitDo Tech Ltd", "8BitDo" }, + { "ASTRO Gaming", "ASTRO" }, + { "Bensussen Deutsch & Associates,Inc.(BDA)", "BDA" }, + { "Guangzhou Chicken Run Network Technology Co., Ltd.", "GameSir" }, + { "HORI CO.,LTD", "HORI" }, + { "HORI CO.,LTD.", "HORI" }, + { "Mad Catz Inc.", "Mad Catz" }, + { "Nintendo Co., Ltd.", "Nintendo" }, + { "NVIDIA Corporation ", "" }, + { "Performance Designed Products", "PDP" }, + { "QANBA USA, LLC", "Qanba" }, + { "QANBA USA,LLC", "Qanba" }, + { "Unknown ", "" }, + }; + char *name = NULL; + size_t i, len; + + if (!vendor_name) { + vendor_name = ""; + } + if (!product_name) { + product_name = ""; + } + + while (*vendor_name == ' ') { + ++vendor_name; + } + while (*product_name == ' ') { + ++product_name; + } + + if (*vendor_name && *product_name) { + len = (SDL_strlen(vendor_name) + 1 + SDL_strlen(product_name) + 1); + name = (char *)SDL_malloc(len); + if (name) { + (void)SDL_snprintf(name, len, "%s %s", vendor_name, product_name); + } + } else if (*product_name) { + name = SDL_strdup(product_name); + } else if (vendor || product) { + // Couldn't find a controller name, try to give it one based on device type + switch (SDL_GetGamepadTypeFromVIDPID(vendor, product, NULL, true)) { + case SDL_GAMEPAD_TYPE_XBOX360: + name = SDL_strdup("Xbox 360 Controller"); + break; + case SDL_GAMEPAD_TYPE_XBOXONE: + name = SDL_strdup("Xbox One Controller"); + break; + case SDL_GAMEPAD_TYPE_PS3: + name = SDL_strdup("PS3 Controller"); + break; + case SDL_GAMEPAD_TYPE_PS4: + name = SDL_strdup("PS4 Controller"); + break; + case SDL_GAMEPAD_TYPE_PS5: + name = SDL_strdup("DualSense Wireless Controller"); + break; + case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO: + name = SDL_strdup("Nintendo Switch Pro Controller"); + break; + default: + len = (6 + 1 + 6 + 1); + name = (char *)SDL_malloc(len); + if (name) { + (void)SDL_snprintf(name, len, "0x%.4x/0x%.4x", vendor, product); + } + break; + } + } else if (default_name) { + name = SDL_strdup(default_name); + } + + if (!name) { + return NULL; + } + + // Trim trailing whitespace + for (len = SDL_strlen(name); (len > 0 && name[len - 1] == ' '); --len) { + // continue + } + name[len] = '\0'; + + // Compress duplicate spaces + for (i = 0; i < (len - 1);) { + if (name[i] == ' ' && name[i + 1] == ' ') { + SDL_memmove(&name[i], &name[i + 1], (len - i)); + --len; + } else { + ++i; + } + } + + // Perform any manufacturer replacements + for (i = 0; i < SDL_arraysize(replacements); ++i) { + size_t prefixlen = SDL_strlen(replacements[i].prefix); + if (SDL_strncasecmp(name, replacements[i].prefix, prefixlen) == 0) { + size_t replacementlen = SDL_strlen(replacements[i].replacement); + if (replacementlen <= prefixlen) { + SDL_memcpy(name, replacements[i].replacement, replacementlen); + SDL_memmove(name + replacementlen, name + prefixlen, (len - prefixlen) + 1); + len -= (prefixlen - replacementlen); + } else { + // FIXME: Need to handle the expand case by reallocating the string + } + break; + } + } + + /* Remove duplicate manufacturer or product in the name + * e.g. Razer Razer Raiju Tournament Edition Wired + */ + for (i = 1; i < (len - 1); ++i) { + int matchlen = PrefixMatch(name, &name[i]); + while (matchlen > 0) { + if (name[matchlen] == ' ' || name[matchlen] == '-') { + SDL_memmove(name, name + matchlen + 1, len - matchlen); + break; + } + --matchlen; + } + if (matchlen > 0) { + // We matched the manufacturer's name and removed it + break; + } + } + + return name; +} diff --git a/libs/SDL3/src/SDL_utils_c.h b/libs/SDL3/src/SDL_utils_c.h index 557dad49..5e0e8f51 100644 --- a/libs/SDL3/src/SDL_utils_c.h +++ b/libs/SDL3/src/SDL_utils_c.h @@ -73,4 +73,6 @@ extern void SDL_SetObjectsInvalid(void); extern const char *SDL_GetPersistentString(const char *string); +extern char *SDL_CreateDeviceName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name, const char *default_name); + #endif // SDL_utils_h_ diff --git a/libs/SDL3/src/audio/SDL_audio.c b/libs/SDL3/src/audio/SDL_audio.c index db4c55f3..583a1591 100644 --- a/libs/SDL3/src/audio/SDL_audio.c +++ b/libs/SDL3/src/audio/SDL_audio.c @@ -136,6 +136,7 @@ const char *SDL_GetAudioDriver(int index) if (index >= 0 && index < SDL_GetNumAudioDrivers()) { return deduped_bootstrap[index]->name; } + SDL_InvalidParamError("index"); return NULL; } @@ -650,7 +651,7 @@ static SDL_AudioDevice *CreatePhysicalAudioDevice(const char *name, bool recordi device->instance_id = AssignAudioDeviceInstanceId(recording, /*islogical=*/false); SDL_LockRWLockForWriting(current_audio.device_hash_lock); - if (SDL_InsertIntoHashTable(current_audio.device_hash, (const void *) (uintptr_t) device->instance_id, device)) { + if (SDL_InsertIntoHashTable(current_audio.device_hash, (const void *) (uintptr_t) device->instance_id, device, false)) { SDL_AddAtomicInt(device_count, 1); } else { SDL_DestroyCondition(device->close_cond); @@ -864,50 +865,47 @@ static void CompleteAudioEntryPoints(void) #undef FILL_STUB } -static SDL_AudioDevice *GetFirstAddedAudioDevice(const bool recording) +typedef struct FindLowestDeviceIDData { - SDL_AudioDeviceID highest = (SDL_AudioDeviceID) SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK; // According to AssignAudioDeviceInstanceId, nothing can have a value this large. - SDL_AudioDevice *result = NULL; + const bool recording; + SDL_AudioDeviceID highest; + SDL_AudioDevice *result; +} FindLowestDeviceIDData; - // (Device IDs increase as new devices are added, so the first device added has the lowest SDL_AudioDeviceID value.) - SDL_LockRWLockForReading(current_audio.device_hash_lock); - - const void *key; - const void *value; - void *iter = NULL; - while (SDL_IterateHashTable(current_audio.device_hash, &key, &value, &iter)) { - const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key; - // bit #0 of devid is set for playback devices and unset for recording. - // bit #1 of devid is set for physical devices and unset for logical. - const bool devid_recording = !(devid & (1 << 0)); - const bool isphysical = !!(devid & (1 << 1)); - if (isphysical && (devid_recording == recording) && (devid < highest)) { - highest = devid; - result = (SDL_AudioDevice *) value; - } +static bool SDLCALL FindLowestDeviceID(void *userdata, const SDL_HashTable *table, const void *key, const void *value) +{ + FindLowestDeviceIDData *data = (FindLowestDeviceIDData *) userdata; + const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key; + // bit #0 of devid is set for playback devices and unset for recording. + // bit #1 of devid is set for physical devices and unset for logical. + const bool devid_recording = !(devid & (1 << 0)); + const bool isphysical = !!(devid & (1 << 1)); + if (isphysical && (devid_recording == data->recording) && (devid < data->highest)) { + data->highest = devid; + data->result = (SDL_AudioDevice *) value; } - - SDL_UnlockRWLock(current_audio.device_hash_lock); - return result; + return true; // keep iterating. } -static Uint32 HashAudioDeviceID(const void *key, void *data) +static SDL_AudioDevice *GetFirstAddedAudioDevice(const bool recording) +{ + const SDL_AudioDeviceID highest = SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK; // According to AssignAudioDeviceInstanceId, nothing can have a value this large. + + // (Device IDs increase as new devices are added, so the first device added has the lowest SDL_AudioDeviceID value.) + FindLowestDeviceIDData data = { recording, highest, NULL }; + SDL_LockRWLockForReading(current_audio.device_hash_lock); + SDL_IterateHashTable(current_audio.device_hash, FindLowestDeviceID, &data); + SDL_UnlockRWLock(current_audio.device_hash_lock); + return data.result; +} + +static Uint32 SDLCALL HashAudioDeviceID(void *userdata, const void *key) { // shift right 2, to dump the first two bits, since these are flags // (recording vs playback, logical vs physical) and the rest are unique incrementing integers. return ((Uint32) ((uintptr_t) key)) >> 2; } -static bool MatchAudioDeviceID(const void *a, const void *b, void *data) -{ - return (a == b); -} - -static void NukeAudioDeviceHashItem(const void *key, const void *value, void *data) -{ - // no-op, keys and values in this hashtable are treated as Plain Old Data and don't get freed here. -} - // !!! FIXME: the video subsystem does SDL_VideoInit, not SDL_InitVideo. Make this match. bool SDL_InitAudio(const char *driver_name) { @@ -926,7 +924,7 @@ bool SDL_InitAudio(const char *driver_name) return false; } - SDL_HashTable *device_hash = SDL_CreateHashTable(NULL, 8, HashAudioDeviceID, MatchAudioDeviceID, NukeAudioDeviceHashItem, false, false); + SDL_HashTable *device_hash = SDL_CreateHashTable(0, false, HashAudioDeviceID, SDL_KeyMatchID, NULL, NULL); if (!device_hash) { SDL_DestroyRWLock(device_hash_lock); return false; @@ -964,7 +962,7 @@ bool SDL_InitAudio(const char *driver_name) } for (int i = 0; bootstrap[i]; ++i) { - if (SDL_strcasecmp(bootstrap[i]->name, driver_attempt) == 0) { + if (!bootstrap[i]->is_preferred && SDL_strcasecmp(bootstrap[i]->name, driver_attempt) == 0) { tried_to_init = true; SDL_zero(current_audio); current_audio.pending_events_tail = ¤t_audio.pending_events; @@ -1047,6 +1045,17 @@ bool SDL_InitAudio(const char *driver_name) return true; } +static bool SDLCALL DestroyOnePhysicalAudioDevice(void *userdata, const SDL_HashTable *table, const void *key, const void *value) +{ + // bit #1 of devid is set for physical devices and unset for logical. + const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key; + const bool isphysical = !!(devid & (1<<1)); + if (isphysical) { + DestroyPhysicalAudioDevice((SDL_AudioDevice *) value); + } + return true; // keep iterating. +} + void SDL_QuitAudio(void) { if (!current_audio.name) { // not initialized?! @@ -1076,17 +1085,7 @@ void SDL_QuitAudio(void) SDL_free(i); } - const void *key; - const void *value; - void *iter = NULL; - while (SDL_IterateHashTable(device_hash, &key, &value, &iter)) { - // bit #1 of devid is set for physical devices and unset for logical. - const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key; - const bool isphysical = !!(devid & (1<<1)); - if (isphysical) { - DestroyPhysicalAudioDevice((SDL_AudioDevice *) value); - } - } + SDL_IterateHashTable(device_hash, DestroyOnePhysicalAudioDevice, NULL); // Free the driver data current_audio.impl.Deinitialize(); @@ -1383,6 +1382,28 @@ static int SDLCALL RecordingAudioThread(void *devicep) // thread entry point return 0; } +typedef struct CountAudioDevicesData +{ + int devs_seen; + const int num_devices; + SDL_AudioDeviceID *result; + const bool recording; +} CountAudioDevicesData; + +static bool SDLCALL CountAudioDevices(void *userdata, const SDL_HashTable *table, const void *key, const void *value) +{ + CountAudioDevicesData *data = (CountAudioDevicesData *) userdata; + const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key; + // bit #0 of devid is set for playback devices and unset for recording. + // bit #1 of devid is set for physical devices and unset for logical. + const bool devid_recording = !(devid & (1<<0)); + const bool isphysical = !!(devid & (1<<1)); + if (isphysical && (devid_recording == data->recording)) { + SDL_assert(data->devs_seen < data->num_devices); + data->result[data->devs_seen++] = devid; + } + return true; // keep iterating. +} static SDL_AudioDeviceID *GetAudioDevices(int *count, bool recording) { @@ -1395,24 +1416,10 @@ static SDL_AudioDeviceID *GetAudioDevices(int *count, bool recording) num_devices = SDL_GetAtomicInt(recording ? ¤t_audio.recording_device_count : ¤t_audio.playback_device_count); result = (SDL_AudioDeviceID *) SDL_malloc((num_devices + 1) * sizeof (SDL_AudioDeviceID)); if (result) { - int devs_seen = 0; - const void *key; - const void *value; - void *iter = NULL; - while (SDL_IterateHashTable(current_audio.device_hash, &key, &value, &iter)) { - const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key; - // bit #0 of devid is set for playback devices and unset for recording. - // bit #1 of devid is set for physical devices and unset for logical. - const bool devid_recording = !(devid & (1<<0)); - const bool isphysical = !!(devid & (1<<1)); - if (isphysical && (devid_recording == recording)) { - SDL_assert(devs_seen < num_devices); - result[devs_seen++] = devid; - } - } - - SDL_assert(devs_seen == num_devices); - result[devs_seen] = 0; // null-terminated. + CountAudioDevicesData data = { 0, num_devices, result, recording }; + SDL_IterateHashTable(current_audio.device_hash, CountAudioDevices, &data); + SDL_assert(data.devs_seen == num_devices); + result[data.devs_seen] = 0; // null-terminated. } } SDL_UnlockRWLock(current_audio.device_hash_lock); @@ -1440,7 +1447,30 @@ SDL_AudioDeviceID *SDL_GetAudioRecordingDevices(int *count) return GetAudioDevices(count, true); } +typedef struct FindAudioDeviceByCallbackData +{ + bool (*callback)(SDL_AudioDevice *device, void *userdata); + void *userdata; + SDL_AudioDevice *retval; +} FindAudioDeviceByCallbackData; +static bool SDLCALL FindAudioDeviceByCallback(void *userdata, const SDL_HashTable *table, const void *key, const void *value) +{ + FindAudioDeviceByCallbackData *data = (FindAudioDeviceByCallbackData *) userdata; + const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key; + // bit #1 of devid is set for physical devices and unset for logical. + const bool isphysical = !!(devid & (1<<1)); + if (isphysical) { + SDL_AudioDevice *device = (SDL_AudioDevice *) value; + if (data->callback(device, data->userdata)) { // found it? + data->retval = device; + return false; // stop iterating, we found it. + } + } + return true; // keep iterating. +} + +// !!! FIXME: SDL convention is for userdata to come first in the callback's params. Fix this at some point. SDL_AudioDevice *SDL_FindPhysicalAudioDeviceByCallback(bool (*callback)(SDL_AudioDevice *device, void *userdata), void *userdata) { if (!SDL_GetCurrentAudioDriver()) { @@ -1448,27 +1478,16 @@ SDL_AudioDevice *SDL_FindPhysicalAudioDeviceByCallback(bool (*callback)(SDL_Audi return NULL; } - const void *key; - const void *value; - void *iter = NULL; - + FindAudioDeviceByCallbackData data = { callback, userdata, NULL }; SDL_LockRWLockForReading(current_audio.device_hash_lock); - while (SDL_IterateHashTable(current_audio.device_hash, &key, &value, &iter)) { - const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key; - // bit #1 of devid is set for physical devices and unset for logical. - const bool isphysical = !!(devid & (1<<1)); - if (isphysical) { - SDL_AudioDevice *device = (SDL_AudioDevice *) value; - if (callback(device, userdata)) { // found it? - SDL_UnlockRWLock(current_audio.device_hash_lock); - return device; - } - } - } + SDL_IterateHashTable(current_audio.device_hash, FindAudioDeviceByCallback, &data); SDL_UnlockRWLock(current_audio.device_hash_lock); - SDL_SetError("Device not found"); - return NULL; + if (!data.retval) { + SDL_SetError("Device not found"); + } + + return data.retval; } static bool TestDeviceHandleCallback(SDL_AudioDevice *device, void *handle) @@ -1794,7 +1813,7 @@ SDL_AudioDeviceID SDL_OpenAudioDevice(SDL_AudioDeviceID devid, const SDL_AudioSp if (result) { SDL_LockRWLockForWriting(current_audio.device_hash_lock); - const bool inserted = SDL_InsertIntoHashTable(current_audio.device_hash, (const void *) (uintptr_t) result, logdev); + const bool inserted = SDL_InsertIntoHashTable(current_audio.device_hash, (const void *) (uintptr_t) result, logdev, false); SDL_UnlockRWLock(current_audio.device_hash_lock); if (!inserted) { SDL_CloseAudioDevice(result); diff --git a/libs/SDL3/src/audio/SDL_audiocvt.c b/libs/SDL3/src/audio/SDL_audiocvt.c index daf44da0..f751b0e5 100644 --- a/libs/SDL3/src/audio/SDL_audiocvt.c +++ b/libs/SDL3/src/audio/SDL_audiocvt.c @@ -237,7 +237,7 @@ static void SwizzleAudio(const int num_frames, void *dst, const void *src, int c void ConvertAudio(int num_frames, const void *src, SDL_AudioFormat src_format, int src_channels, const int *src_map, void *dst, SDL_AudioFormat dst_format, int dst_channels, const int *dst_map, - void* scratch, float gain) + void *scratch, float gain) { SDL_assert(src != NULL); SDL_assert(dst != NULL); @@ -325,7 +325,7 @@ void ConvertAudio(int num_frames, // Gain adjustment if (gain != 1.0f) { - float *buf = (float *)(dstconvert ? scratch : dst); + float *buf = (float *)((channelconvert || dstconvert) ? scratch : dst); const int total_samples = num_frames * src_channels; if (src == buf) { for (int i = 0; i < total_samples; i++) { @@ -558,9 +558,9 @@ bool SDL_SetAudioStreamFormat(SDL_AudioStream *stream, const SDL_AudioSpec *src_ return SDL_InvalidParamError("stream"); } - // Picked mostly arbitrarily. - static const int min_freq = 4000; - static const int max_freq = 384000; + // note that while we've removed the maximum frequency checks, SDL _will_ + // fail to resample to extremely high sample rates correctly. Really high, + // like 196608000Hz. File a bug. :P if (src_spec) { if (!SDL_IsSupportedAudioFormat(src_spec->format)) { @@ -569,10 +569,6 @@ bool SDL_SetAudioStreamFormat(SDL_AudioStream *stream, const SDL_AudioSpec *src_ return SDL_InvalidParamError("src_spec->channels"); } else if (src_spec->freq <= 0) { return SDL_InvalidParamError("src_spec->freq"); - } else if (src_spec->freq < min_freq) { - return SDL_SetError("Source rate is too low"); - } else if (src_spec->freq > max_freq) { - return SDL_SetError("Source rate is too high"); } } @@ -583,10 +579,6 @@ bool SDL_SetAudioStreamFormat(SDL_AudioStream *stream, const SDL_AudioSpec *src_ return SDL_InvalidParamError("dst_spec->channels"); } else if (dst_spec->freq <= 0) { return SDL_InvalidParamError("dst_spec->freq"); - } else if (dst_spec->freq < min_freq) { - return SDL_SetError("Destination rate is too low"); - } else if (dst_spec->freq > max_freq) { - return SDL_SetError("Destination rate is too high"); } } @@ -1030,7 +1022,7 @@ static bool GetAudioStreamDataInternal(SDL_AudioStream *stream, void *buf, int o Uint8* work_buffer = NULL; // Ensure we have enough scratch space for any conversions - if ((src_format != dst_format) || (src_channels != dst_channels)) { + if ((src_format != dst_format) || (src_channels != dst_channels) || (gain != 1.0f)) { work_buffer = EnsureAudioStreamWorkBufferSize(stream, output_frames * max_frame_size); if (!work_buffer) { diff --git a/libs/SDL3/src/audio/SDL_audioqueue.c b/libs/SDL3/src/audio/SDL_audioqueue.c index 18ed346f..df7cac88 100644 --- a/libs/SDL3/src/audio/SDL_audioqueue.c +++ b/libs/SDL3/src/audio/SDL_audioqueue.c @@ -548,7 +548,7 @@ const Uint8 *SDL_ReadFromAudioQueue(SDL_AudioQueue *queue, size_t dst_present_bytes = present_frames * dst_frame_size; size_t dst_future_bytes = future_frames * dst_frame_size; - bool convert = (src_format != dst_format) || (src_channels != dst_channels); + const bool convert = (src_format != dst_format) || (src_channels != dst_channels) || (gain != 1.0f); if (convert && !dst) { // The user didn't ask for the data to be copied, but we need to convert it, so store it in the scratch buffer diff --git a/libs/SDL3/src/audio/SDL_audioresample.c b/libs/SDL3/src/audio/SDL_audioresample.c index dd2451bf..371002e3 100644 --- a/libs/SDL3/src/audio/SDL_audioresample.c +++ b/libs/SDL3/src/audio/SDL_audioresample.c @@ -444,7 +444,7 @@ static void SincTable(float *table, int len) } // Calculate Sinc(x/y), using a lookup table -static float Sinc(float *table, int x, int y) +static float Sinc(const float *table, int x, int y) { float s = table[x % y]; s = ((x / y) & 1) ? -s : s; @@ -587,7 +587,18 @@ Sint64 SDL_GetResampleRate(int src_rate, int dst_rate) SDL_assert(src_rate > 0); SDL_assert(dst_rate > 0); - Sint64 sample_rate = ((Sint64)src_rate << 32) / (Sint64)dst_rate; + Sint64 numerator = (Sint64)src_rate << 32; + Sint64 denominator = (Sint64)dst_rate; + + // Generally it's expected that `dst_frames = (src_frames * dst_rate) / src_rate` + // To match this as closely as possible without infinite precision, always round up the resample rate. + // For example, without rounding up, a sample ratio of 2:3 would have `sample_rate = 0xAAAAAAAA` + // After 3 frames, the position would be 0x1.FFFFFFFE, meaning we haven't fully consumed the second input frame. + // By rounding up to 0xAAAAAAAB, we would instead reach 0x2.00000001, fulling consuming the second frame. + // Technically you could say this is kicking the can 0x100000000 steps down the road, but I'm fine with that :) + // sample_rate = div_ceil(numerator, denominator) + Sint64 sample_rate = ((numerator - 1) / denominator) + 1; + SDL_assert(sample_rate > 0); return sample_rate; @@ -657,7 +668,7 @@ Sint64 SDL_GetResamplerOutputFrames(Sint64 input_frames, Sint64 resample_rate, S } // output_frames = div_ceil(input_offset, resample_rate) - Sint64 output_frames = (input_offset > 0) ? ((input_offset + resample_rate * 3 / 4) / resample_rate) : 0; + Sint64 output_frames = (input_offset > 0) ? ((input_offset - 1) / resample_rate) + 1 : 0; *inout_resample_offset = (output_frames * resample_rate) - input_offset; diff --git a/libs/SDL3/src/audio/SDL_sysaudio.h b/libs/SDL3/src/audio/SDL_sysaudio.h index c5cce0e4..4a88bd23 100644 --- a/libs/SDL3/src/audio/SDL_sysaudio.h +++ b/libs/SDL3/src/audio/SDL_sysaudio.h @@ -28,7 +28,7 @@ #define DEBUG_AUDIO_CONVERT 0 #if DEBUG_AUDIO_CONVERT -#define LOG_DEBUG_AUDIO_CONVERT(from, to) SDL_Log("SDL_AUDIO_CONVERT: Converting %s to %s.\n", from, to); +#define LOG_DEBUG_AUDIO_CONVERT(from, to) SDL_Log("SDL_AUDIO_CONVERT: Converting %s to %s.", from, to); #else #define LOG_DEBUG_AUDIO_CONVERT(from, to) #endif @@ -360,6 +360,7 @@ typedef struct AudioBootStrap const char *desc; bool (*init)(SDL_AudioDriverImpl *impl); bool demand_only; // if true: request explicitly, or it won't be available. + bool is_preferred; } AudioBootStrap; // Not all of these are available in a given build. Use #ifdefs, etc. diff --git a/libs/SDL3/src/audio/aaudio/SDL_aaudio.c b/libs/SDL3/src/audio/aaudio/SDL_aaudio.c index fd075b53..3360bec9 100644 --- a/libs/SDL3/src/audio/aaudio/SDL_aaudio.c +++ b/libs/SDL3/src/audio/aaudio/SDL_aaudio.c @@ -102,7 +102,7 @@ static aaudio_data_callback_result_t AAUDIO_dataCallback(AAudioStream *stream, v size_t end = (offset + size) % hidden->mixbuf_bytes; SDL_assert(size <= hidden->mixbuf_bytes); -//LOGI("Recorded %zu frames, %zu available, %zu max (%zu written, %zu read)\n", callback_bytes / framesize, available_bytes / framesize, hidden->mixbuf_bytes / framesize, hidden->callback_bytes / framesize, hidden->processed_bytes / framesize); +//LOGI("Recorded %zu frames, %zu available, %zu max (%zu written, %zu read)", callback_bytes / framesize, available_bytes / framesize, hidden->mixbuf_bytes / framesize, hidden->callback_bytes / framesize, hidden->processed_bytes / framesize); if (offset <= end) { SDL_memcpy(&hidden->mixbuf[offset], input, size); @@ -116,7 +116,7 @@ static aaudio_data_callback_result_t AAUDIO_dataCallback(AAudioStream *stream, v hidden->callback_bytes += size; if (size < callback_bytes) { - LOGI("Audio recording overflow, dropped %zu frames\n", (callback_bytes - size) / framesize); + LOGI("Audio recording overflow, dropped %zu frames", (callback_bytes - size) / framesize); } } else { Uint8 *output = (Uint8 *)audioData; @@ -126,7 +126,7 @@ static aaudio_data_callback_result_t AAUDIO_dataCallback(AAudioStream *stream, v size_t end = (offset + size) % hidden->mixbuf_bytes; SDL_assert(size <= hidden->mixbuf_bytes); -//LOGI("Playing %zu frames, %zu available, %zu max (%zu written, %zu read)\n", callback_bytes / framesize, available_bytes / framesize, hidden->mixbuf_bytes / framesize, hidden->processed_bytes / framesize, hidden->callback_bytes / framesize); +//LOGI("Playing %zu frames, %zu available, %zu max (%zu written, %zu read)", callback_bytes / framesize, available_bytes / framesize, hidden->mixbuf_bytes / framesize, hidden->processed_bytes / framesize, hidden->callback_bytes / framesize); SDL_MemoryBarrierAcquire(); if (offset <= end) { @@ -139,7 +139,7 @@ static aaudio_data_callback_result_t AAUDIO_dataCallback(AAudioStream *stream, v hidden->callback_bytes += size; if (size < callback_bytes) { - LOGI("Audio playback underflow, missed %zu frames\n", (callback_bytes - size) / framesize); + LOGI("Audio playback underflow, missed %zu frames", (callback_bytes - size) / framesize); SDL_memset(&output[size], device->silence_value, (callback_bytes - size)); } } @@ -315,10 +315,10 @@ static bool BuildAAudioStream(SDL_AudioDevice *device) ctx.AAudioStreamBuilder_setDataCallback(builder, AAUDIO_dataCallback, device); // Some devices have flat sounding audio when low latency mode is enabled, but this is a better experience for most people if (SDL_GetHintBoolean(SDL_HINT_ANDROID_LOW_LATENCY_AUDIO, true)) { - SDL_Log("Low latency audio enabled\n"); + SDL_Log("Low latency audio enabled"); ctx.AAudioStreamBuilder_setPerformanceMode(builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY); } else { - SDL_Log("Low latency audio disabled\n"); + SDL_Log("Low latency audio disabled"); } LOGI("AAudio Try to open %u hz %s %u channels samples %u", @@ -545,7 +545,7 @@ static bool AAUDIO_Init(SDL_AudioDriverImpl *impl) } AudioBootStrap AAUDIO_bootstrap = { - "AAudio", "AAudio audio driver", AAUDIO_Init, false + "AAudio", "AAudio audio driver", AAUDIO_Init, false, false }; #endif // SDL_AUDIO_DRIVER_AAUDIO diff --git a/libs/SDL3/src/audio/alsa/SDL_alsa_audio.c b/libs/SDL3/src/audio/alsa/SDL_alsa_audio.c index 652a1a5c..308eb235 100644 --- a/libs/SDL3/src/audio/alsa/SDL_alsa_audio.c +++ b/libs/SDL3/src/audio/alsa/SDL_alsa_audio.c @@ -566,7 +566,7 @@ static enum snd_pcm_chmap_position sdl_channel_maps[SDL_AUDIO_ALSA__SDL_CHMAPS_N }; // Helper for the function right below. -static bool has_pos(unsigned int *chmap, unsigned int pos) +static bool has_pos(const unsigned int *chmap, unsigned int pos) { for (unsigned int chan_idx = 0; ; chan_idx++) { if (chan_idx == 6) { @@ -586,7 +586,7 @@ static bool has_pos(unsigned int *chmap, unsigned int pos) #define HAVE_REAR 1 #define HAVE_SIDE 2 #define HAVE_BOTH 3 -static void sdl_6chans_set_rear_or_side_channels_from_alsa_6chans(unsigned int *sdl_6chans, unsigned int *alsa_6chans) +static void sdl_6chans_set_rear_or_side_channels_from_alsa_6chans(unsigned int *sdl_6chans, const unsigned int *alsa_6chans) { // For alsa channel maps with 6 channels and with SND_CHMAP_FL,SND_CHMAP_FR,SND_CHMAP_FC, // SND_CHMAP_LFE, reduce our 6 channels maps to a uniq one. @@ -638,7 +638,7 @@ static void sdl_6chans_set_rear_or_side_channels_from_alsa_6chans(unsigned int * #undef HAVE_SIDE #undef HAVE_BOTH -static void swizzle_map_compute_alsa_subscan(struct ALSA_pcm_cfg_ctx *ctx, int *swizzle_map, unsigned int sdl_pos_idx) +static void swizzle_map_compute_alsa_subscan(const struct ALSA_pcm_cfg_ctx *ctx, int *swizzle_map, unsigned int sdl_pos_idx) { swizzle_map[sdl_pos_idx] = -1; for (unsigned int alsa_pos_idx = 0; ; alsa_pos_idx++) { @@ -652,7 +652,7 @@ static void swizzle_map_compute_alsa_subscan(struct ALSA_pcm_cfg_ctx *ctx, int * } // XXX: this must stay playback/recording symetric. -static void swizzle_map_compute(struct ALSA_pcm_cfg_ctx *ctx, int *swizzle_map, bool *needs_swizzle) +static void swizzle_map_compute(const struct ALSA_pcm_cfg_ctx *ctx, int *swizzle_map, bool *needs_swizzle) { *needs_swizzle = false; for (unsigned int sdl_pos_idx = 0; sdl_pos_idx != ctx->chans_n; sdl_pos_idx++) { @@ -668,7 +668,7 @@ static void swizzle_map_compute(struct ALSA_pcm_cfg_ctx *ctx, int *swizzle_map, #define CHMAP_NOT_FOUND 2 // Should always be a queried alsa channel map unless the queried alsa channel map was of type VAR, // namely we can program the channel positions directly from the SDL channel map. -static int alsa_chmap_install(struct ALSA_pcm_cfg_ctx *ctx, unsigned int *chmap) +static int alsa_chmap_install(struct ALSA_pcm_cfg_ctx *ctx, const unsigned int *chmap) { bool isstack; snd_pcm_chmap_t *chmap_to_install = (snd_pcm_chmap_t*)SDL_small_alloc(unsigned int, 1 + ctx->chans_n, &isstack); @@ -698,7 +698,7 @@ static int alsa_chmap_install(struct ALSA_pcm_cfg_ctx *ctx, unsigned int *chmap) // We restrict the alsa channel maps because in the unordered matches we do only simple accounting. // In the end, this will handle mostly alsa channel maps with more than one SND_CHMAP_NA position fillers. -static bool alsa_chmap_has_duplicate_position(struct ALSA_pcm_cfg_ctx *ctx, unsigned int *pos) +static bool alsa_chmap_has_duplicate_position(const struct ALSA_pcm_cfg_ctx *ctx, const unsigned int *pos) { if (ctx->chans_n < 2) {// we need at least 2 positions LOGDEBUG("channel map:no duplicate"); @@ -923,7 +923,7 @@ static int ALSA_pcm_cfg_hw_chans_n_scan(struct ALSA_pcm_cfg_ctx *ctx, unsigned i return CHANS_N_NOT_CONFIGURED; } - LOGDEBUG("target chans_n is %u\n", target_chans_n); + LOGDEBUG("target chans_n is %u", target_chans_n); int status = ALSA_snd_pcm_hw_params_any(ctx->device->hidden->pcm, ctx->hwparams); if (status < 0) { @@ -1050,7 +1050,7 @@ static int ALSA_pcm_cfg_hw_chans_n_scan(struct ALSA_pcm_cfg_ctx *ctx, unsigned i static bool ALSA_pcm_cfg_hw(struct ALSA_pcm_cfg_ctx *ctx) { - LOGDEBUG("target chans_n, equal or above requested chans_n mode\n"); + LOGDEBUG("target chans_n, equal or above requested chans_n mode"); int status = ALSA_pcm_cfg_hw_chans_n_scan(ctx, CHANS_N_SCAN_MODE__EQUAL_OR_ABOVE_REQUESTED_CHANS_N); if (status < 0) { // something went too wrong return false; @@ -1059,7 +1059,7 @@ static bool ALSA_pcm_cfg_hw(struct ALSA_pcm_cfg_ctx *ctx) } // Here, status == CHANS_N_NOT_CONFIGURED - LOGDEBUG("target chans_n, below requested chans_n mode\n"); + LOGDEBUG("target chans_n, below requested chans_n mode"); status = ALSA_pcm_cfg_hw_chans_n_scan(ctx, CHANS_N_SCAN_MODE__BELOW_REQUESTED_CHANS_N); if (status < 0) { // something went too wrong return false; @@ -1513,7 +1513,7 @@ static bool ALSA_Init(SDL_AudioDriverImpl *impl) } AudioBootStrap ALSA_bootstrap = { - "alsa", "ALSA PCM audio", ALSA_Init, false + "alsa", "ALSA PCM audio", ALSA_Init, false, false }; #endif // SDL_AUDIO_DRIVER_ALSA diff --git a/libs/SDL3/src/audio/coreaudio/SDL_coreaudio.m b/libs/SDL3/src/audio/coreaudio/SDL_coreaudio.m index cfa0616d..57b19c72 100644 --- a/libs/SDL3/src/audio/coreaudio/SDL_coreaudio.m +++ b/libs/SDL3/src/audio/coreaudio/SDL_coreaudio.m @@ -31,7 +31,7 @@ #if DEBUG_COREAUDIO #define CHECK_RESULT(msg) \ if (result != noErr) { \ - SDL_Log("COREAUDIO: Got error %d from '%s'!\n", (int)result, msg); \ + SDL_Log("COREAUDIO: Got error %d from '%s'!", (int)result, msg); \ return SDL_SetError("CoreAudio error (%s): %d", msg, (int)result); \ } #else @@ -224,7 +224,7 @@ static void RefreshPhysicalDevices(void) name[len] = '\0'; #if DEBUG_COREAUDIO - SDL_Log("COREAUDIO: Found %s device #%d: '%s' (devid %d)\n", ((recording) ? "recording" : "playback"), (int)i, name, (int)dev); + SDL_Log("COREAUDIO: Found %s device #%d: '%s' (devid %d)", ((recording) ? "recording" : "playback"), (int)i, name, (int)dev); #endif SDLCoreAudioHandle *newhandle = (SDLCoreAudioHandle *) SDL_calloc(1, sizeof (*newhandle)); if (newhandle) { @@ -834,7 +834,7 @@ static bool PrepareAudioQueue(SDL_AudioDevice *device) } #if DEBUG_COREAUDIO - SDL_Log("COREAUDIO: numAudioBuffers == %d\n", numAudioBuffers); + SDL_Log("COREAUDIO: numAudioBuffers == %d", numAudioBuffers); #endif for (int i = 0; i < numAudioBuffers; i++) { @@ -1034,7 +1034,7 @@ static bool COREAUDIO_Init(SDL_AudioDriverImpl *impl) } AudioBootStrap COREAUDIO_bootstrap = { - "coreaudio", "CoreAudio", COREAUDIO_Init, false + "coreaudio", "CoreAudio", COREAUDIO_Init, false, false }; #endif // SDL_AUDIO_DRIVER_COREAUDIO diff --git a/libs/SDL3/src/audio/directsound/SDL_directsound.c b/libs/SDL3/src/audio/directsound/SDL_directsound.c index da4390df..7b5cb11e 100644 --- a/libs/SDL3/src/audio/directsound/SDL_directsound.c +++ b/libs/SDL3/src/audio/directsound/SDL_directsound.c @@ -674,7 +674,7 @@ static bool DSOUND_Init(SDL_AudioDriverImpl *impl) } AudioBootStrap DSOUND_bootstrap = { - "directsound", "DirectSound", DSOUND_Init, false + "directsound", "DirectSound", DSOUND_Init, false, false }; #endif // SDL_AUDIO_DRIVER_DSOUND diff --git a/libs/SDL3/src/audio/disk/SDL_diskaudio.c b/libs/SDL3/src/audio/disk/SDL_diskaudio.c index c59bd2ec..9e05478c 100644 --- a/libs/SDL3/src/audio/disk/SDL_diskaudio.c +++ b/libs/SDL3/src/audio/disk/SDL_diskaudio.c @@ -136,7 +136,7 @@ static bool DISKAUDIO_OpenDevice(SDL_AudioDevice *device) } SDL_LogCritical(SDL_LOG_CATEGORY_AUDIO, "You are using the SDL disk i/o audio driver!"); - SDL_LogCritical(SDL_LOG_CATEGORY_AUDIO, " %s file [%s].\n", recording ? "Reading from" : "Writing to", fname); + SDL_LogCritical(SDL_LOG_CATEGORY_AUDIO, " %s file [%s].", recording ? "Reading from" : "Writing to", fname); return true; // We're ready to rock and roll. :-) } @@ -165,7 +165,7 @@ static bool DISKAUDIO_Init(SDL_AudioDriverImpl *impl) } AudioBootStrap DISKAUDIO_bootstrap = { - "disk", "direct-to-disk audio", DISKAUDIO_Init, true + "disk", "direct-to-disk audio", DISKAUDIO_Init, true, false }; #endif // SDL_AUDIO_DRIVER_DISK diff --git a/libs/SDL3/src/audio/dsp/SDL_dspaudio.c b/libs/SDL3/src/audio/dsp/SDL_dspaudio.c index 111caeb5..62b8990a 100644 --- a/libs/SDL3/src/audio/dsp/SDL_dspaudio.c +++ b/libs/SDL3/src/audio/dsp/SDL_dspaudio.c @@ -297,7 +297,7 @@ static bool DSP_Init(SDL_AudioDriverImpl *impl) } AudioBootStrap DSP_bootstrap = { - "dsp", "Open Sound System (/dev/dsp)", DSP_Init, false + "dsp", "Open Sound System (/dev/dsp)", DSP_Init, false, false }; #endif // SDL_AUDIO_DRIVER_OSS diff --git a/libs/SDL3/src/audio/dummy/SDL_dummyaudio.c b/libs/SDL3/src/audio/dummy/SDL_dummyaudio.c index c5999fbd..d0f1a1a6 100644 --- a/libs/SDL3/src/audio/dummy/SDL_dummyaudio.c +++ b/libs/SDL3/src/audio/dummy/SDL_dummyaudio.c @@ -131,5 +131,5 @@ static bool DUMMYAUDIO_Init(SDL_AudioDriverImpl *impl) } AudioBootStrap DUMMYAUDIO_bootstrap = { - "dummy", "SDL dummy audio driver", DUMMYAUDIO_Init, true + "dummy", "SDL dummy audio driver", DUMMYAUDIO_Init, true, false }; diff --git a/libs/SDL3/src/audio/emscripten/SDL_emscriptenaudio.c b/libs/SDL3/src/audio/emscripten/SDL_emscriptenaudio.c index 84ba63b0..55fb5b49 100644 --- a/libs/SDL3/src/audio/emscripten/SDL_emscriptenaudio.c +++ b/libs/SDL3/src/audio/emscripten/SDL_emscriptenaudio.c @@ -234,7 +234,7 @@ static bool EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device) if ((SDL3 === undefined) || (SDL3.audio_recording === undefined)) { return; } audioProcessingEvent.outputBuffer.getChannelData(0).fill(0.0); SDL3.audio_recording.currentRecordingBuffer = audioProcessingEvent.inputBuffer; - dynCall('ii', $2, [$3]); + dynCall('ip', $2, [$3]); }; SDL3.audio_recording.mediaStreamNode.connect(SDL3.audio_recording.scriptProcessorNode); SDL3.audio_recording.scriptProcessorNode.connect(SDL3.audioContext.destination); @@ -250,7 +250,7 @@ static bool EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device) SDL3.audio_recording.silenceBuffer.getChannelData(0).fill(0.0); var silence_callback = function() { SDL3.audio_recording.currentRecordingBuffer = SDL3.audio_recording.silenceBuffer; - dynCall('ii', $2, [$3]); + dynCall('ip', $2, [$3]); }; SDL3.audio_recording.silenceTimer = setInterval(silence_callback, ($1 / SDL3.audioContext.sampleRate) * 1000); @@ -275,7 +275,7 @@ static bool EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device) SDL3.audio_playback.silenceBuffer = undefined; } SDL3.audio_playback.currentPlaybackBuffer = e['outputBuffer']; - dynCall('ii', $2, [$3]); + dynCall('ip', $2, [$3]); }; SDL3.audio_playback.scriptProcessorNode['connect'](SDL3.audioContext['destination']); @@ -293,7 +293,7 @@ static bool EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device) // the buffer that gets filled here just gets ignored, so the app can make progress // and/or avoid flooding audio queues until we can actually play audio. SDL3.audio_playback.currentPlaybackBuffer = SDL3.audio_playback.silenceBuffer; - dynCall('ii', $2, [$3]); + dynCall('ip', $2, [$3]); SDL3.audio_playback.currentPlaybackBuffer = undefined; }; @@ -351,7 +351,7 @@ static bool EMSCRIPTENAUDIO_Init(SDL_AudioDriverImpl *impl) } AudioBootStrap EMSCRIPTENAUDIO_bootstrap = { - "emscripten", "SDL emscripten audio driver", EMSCRIPTENAUDIO_Init, false + "emscripten", "SDL emscripten audio driver", EMSCRIPTENAUDIO_Init, false, false }; /* *INDENT-ON* */ // clang-format on diff --git a/libs/SDL3/src/audio/haiku/SDL_haikuaudio.cc b/libs/SDL3/src/audio/haiku/SDL_haikuaudio.cc index 9401d88a..730b107d 100644 --- a/libs/SDL3/src/audio/haiku/SDL_haikuaudio.cc +++ b/libs/SDL3/src/audio/haiku/SDL_haikuaudio.cc @@ -216,7 +216,7 @@ static bool HAIKUAUDIO_Init(SDL_AudioDriverImpl *impl) extern "C" { extern AudioBootStrap HAIKUAUDIO_bootstrap; } AudioBootStrap HAIKUAUDIO_bootstrap = { - "haiku", "Haiku BSoundPlayer", HAIKUAUDIO_Init, false + "haiku", "Haiku BSoundPlayer", HAIKUAUDIO_Init, false, false }; #endif // SDL_AUDIO_DRIVER_HAIKU diff --git a/libs/SDL3/src/audio/jack/SDL_jackaudio.c b/libs/SDL3/src/audio/jack/SDL_jackaudio.c index 0ed79f53..3ae5137a 100644 --- a/libs/SDL3/src/audio/jack/SDL_jackaudio.c +++ b/libs/SDL3/src/audio/jack/SDL_jackaudio.c @@ -429,7 +429,7 @@ static bool JACK_Init(SDL_AudioDriverImpl *impl) } AudioBootStrap JACK_bootstrap = { - "jack", "JACK Audio Connection Kit", JACK_Init, false + "jack", "JACK Audio Connection Kit", JACK_Init, false, false }; #endif // SDL_AUDIO_DRIVER_JACK diff --git a/libs/SDL3/src/audio/n3ds/SDL_n3dsaudio.c b/libs/SDL3/src/audio/n3ds/SDL_n3dsaudio.c index 8144d907..780b06c4 100644 --- a/libs/SDL3/src/audio/n3ds/SDL_n3dsaudio.c +++ b/libs/SDL3/src/audio/n3ds/SDL_n3dsaudio.c @@ -280,7 +280,8 @@ AudioBootStrap N3DSAUDIO_bootstrap = { N3DSAUDIO_DRIVER_NAME, "SDL N3DS audio driver", N3DSAUDIO_Init, - 0 + false, + false }; #endif // SDL_AUDIO_DRIVER_N3DS diff --git a/libs/SDL3/src/audio/netbsd/SDL_netbsdaudio.c b/libs/SDL3/src/audio/netbsd/SDL_netbsdaudio.c index cc0840b7..26060d37 100644 --- a/libs/SDL3/src/audio/netbsd/SDL_netbsdaudio.c +++ b/libs/SDL3/src/audio/netbsd/SDL_netbsdaudio.c @@ -322,7 +322,7 @@ static bool NETBSDAUDIO_Init(SDL_AudioDriverImpl *impl) } AudioBootStrap NETBSDAUDIO_bootstrap = { - "netbsd", "NetBSD audio", NETBSDAUDIO_Init, false + "netbsd", "NetBSD audio", NETBSDAUDIO_Init, false, false }; #endif // SDL_AUDIO_DRIVER_NETBSD diff --git a/libs/SDL3/src/audio/openslES/SDL_openslES.c b/libs/SDL3/src/audio/openslES/SDL_openslES.c index 08fd6783..4d5b3bdf 100644 --- a/libs/SDL3/src/audio/openslES/SDL_openslES.c +++ b/libs/SDL3/src/audio/openslES/SDL_openslES.c @@ -779,7 +779,7 @@ static bool OPENSLES_Init(SDL_AudioDriverImpl *impl) } AudioBootStrap OPENSLES_bootstrap = { - "openslES", "OpenSL ES audio driver", OPENSLES_Init, false + "openslES", "OpenSL ES audio driver", OPENSLES_Init, false, false }; void OPENSLES_ResumeDevices(void) diff --git a/libs/SDL3/src/audio/pipewire/SDL_pipewire.c b/libs/SDL3/src/audio/pipewire/SDL_pipewire.c index 08f0db6c..e3f9439f 100644 --- a/libs/SDL3/src/audio/pipewire/SDL_pipewire.c +++ b/libs/SDL3/src/audio/pipewire/SDL_pipewire.c @@ -44,7 +44,9 @@ enum PW_READY_FLAGS { PW_READY_FLAG_BUFFER_ADDED = 0x1, PW_READY_FLAG_STREAM_READY = 0x2, - PW_READY_FLAG_ALL_BITS = 0x3 + PW_READY_FLAG_ALL_PREOPEN_BITS = 0x3, + PW_READY_FLAG_OPEN_COMPLETE = 0x4, + PW_READY_FLAG_ALL_BITS = 0x7 }; #define PW_ID_TO_HANDLE(x) (void *)((uintptr_t)x) @@ -513,6 +515,25 @@ static bool get_int_param(const struct spa_pod *param, Uint32 key, int *val) return false; } +static SDL_AudioFormat SPAFormatToSDL(enum spa_audio_format spafmt) +{ + switch (spafmt) { + #define CHECKFMT(spa,sdl) case SPA_AUDIO_FORMAT_##spa: return SDL_AUDIO_##sdl + CHECKFMT(U8, U8); + CHECKFMT(S8, S8); + CHECKFMT(S16_LE, S16LE); + CHECKFMT(S16_BE, S16BE); + CHECKFMT(S32_LE, S32LE); + CHECKFMT(S32_BE, S32BE); + CHECKFMT(F32_LE, F32LE); + CHECKFMT(F32_BE, F32BE); + #undef CHECKFMT + default: break; + } + + return SDL_AUDIO_UNKNOWN; +} + // Interface node callbacks static void node_event_info(void *object, const struct pw_node_info *info) { @@ -529,7 +550,7 @@ static void node_event_info(void *object, const struct pw_node_info *info) // Need to parse the parameters to get the sample rate for (i = 0; i < info->n_params; ++i) { - pw_node_enum_params(node->proxy, 0, info->params[i].id, 0, 0, NULL); + pw_node_enum_params((struct pw_node*)node->proxy, 0, info->params[i].id, 0, 0, NULL); } hotplug_core_sync(node); @@ -541,6 +562,15 @@ static void node_event_param(void *object, int seq, uint32_t id, uint32_t index, struct node_object *node = object; struct io_node *io = node->userdata; + if ((id == SPA_PARAM_Format) && (io->spec.format == SDL_AUDIO_UNKNOWN)) { + struct spa_audio_info_raw info; + SDL_zero(info); + if (spa_format_audio_raw_parse(param, &info) == 0) { + //SDL_Log("Sink Format: %d, Rate: %d Hz, Channels: %d", info.format, info.rate, info.channels); + io->spec.format = SPAFormatToSDL(info.format); + } + } + // Get the default frequency if (io->spec.freq == 0) { get_range_param(param, SPA_FORMAT_AUDIO_rate, &io->spec.freq, NULL, NULL); @@ -672,7 +702,9 @@ static void registry_event_global_callback(void *object, uint32_t id, uint32_t p // Begin setting the node properties io->id = id; io->recording = recording; - io->spec.format = SDL_AUDIO_F32; // Pipewire uses floats internally, other formats require conversion. + if (io->spec.format == SDL_AUDIO_UNKNOWN) { + io->spec.format = SDL_AUDIO_S16; // we'll go conservative here if for some reason the format isn't known. + } io->name = io->buf; io->path = io->buf + desc_buffer_len; SDL_strlcpy(io->buf, node_desc, desc_buffer_len); @@ -1185,12 +1217,13 @@ static bool PIPEWIRE_OpenDevice(SDL_AudioDevice *device) return SDL_SetError("Pipewire: Failed to start stream loop"); } - // Wait until all init flags are set or the stream has failed. + // Wait until all pre-open init flags are set or the stream has failed. PIPEWIRE_pw_thread_loop_lock(priv->loop); - while (priv->stream_init_status != PW_READY_FLAG_ALL_BITS && + while (priv->stream_init_status != PW_READY_FLAG_ALL_PREOPEN_BITS && PIPEWIRE_pw_stream_get_state(priv->stream, NULL) != PW_STREAM_STATE_ERROR) { PIPEWIRE_pw_thread_loop_wait(priv->loop); } + priv->stream_init_status |= PW_READY_FLAG_OPEN_COMPLETE; PIPEWIRE_pw_thread_loop_unlock(priv->loop); if (PIPEWIRE_pw_stream_get_state(priv->stream, &error) == PW_STREAM_STATE_ERROR) { @@ -1307,10 +1340,10 @@ static bool PIPEWIRE_Init(SDL_AudioDriverImpl *impl) } AudioBootStrap PIPEWIRE_PREFERRED_bootstrap = { - "pipewire", "Pipewire", PIPEWIRE_PREFERRED_Init, false + "pipewire", "Pipewire", PIPEWIRE_PREFERRED_Init, false, true }; AudioBootStrap PIPEWIRE_bootstrap = { - "pipewire", "Pipewire", PIPEWIRE_Init, false + "pipewire", "Pipewire", PIPEWIRE_Init, false, false }; #endif // SDL_AUDIO_DRIVER_PIPEWIRE diff --git a/libs/SDL3/src/audio/ps2/SDL_ps2audio.c b/libs/SDL3/src/audio/ps2/SDL_ps2audio.c index 2995eed1..6579f1bd 100644 --- a/libs/SDL3/src/audio/ps2/SDL_ps2audio.c +++ b/libs/SDL3/src/audio/ps2/SDL_ps2audio.c @@ -155,5 +155,5 @@ static bool PS2AUDIO_Init(SDL_AudioDriverImpl *impl) } AudioBootStrap PS2AUDIO_bootstrap = { - "ps2", "PS2 audio driver", PS2AUDIO_Init, false + "ps2", "PS2 audio driver", PS2AUDIO_Init, false, false }; diff --git a/libs/SDL3/src/audio/psp/SDL_pspaudio.c b/libs/SDL3/src/audio/psp/SDL_pspaudio.c index 328387e8..18546e88 100644 --- a/libs/SDL3/src/audio/psp/SDL_pspaudio.c +++ b/libs/SDL3/src/audio/psp/SDL_pspaudio.c @@ -177,7 +177,7 @@ static bool PSPAUDIO_Init(SDL_AudioDriverImpl *impl) } AudioBootStrap PSPAUDIO_bootstrap = { - "psp", "PSP audio driver", PSPAUDIO_Init, false + "psp", "PSP audio driver", PSPAUDIO_Init, false, false }; #endif // SDL_AUDIO_DRIVER_PSP diff --git a/libs/SDL3/src/audio/pulseaudio/SDL_pulseaudio.c b/libs/SDL3/src/audio/pulseaudio/SDL_pulseaudio.c index 75365147..049a5ec6 100644 --- a/libs/SDL3/src/audio/pulseaudio/SDL_pulseaudio.c +++ b/libs/SDL3/src/audio/pulseaudio/SDL_pulseaudio.c @@ -543,7 +543,7 @@ static void PULSEAUDIO_FlushRecording(SDL_AudioDevice *device) { struct SDL_PrivateAudioData *h = device->hidden; const void *data = NULL; - size_t nbytes = 0; + size_t nbytes = 0, buflen = 0; PULSEAUDIO_pa_threaded_mainloop_lock(pulseaudio_threaded_mainloop); @@ -553,7 +553,8 @@ static void PULSEAUDIO_FlushRecording(SDL_AudioDevice *device) h->recordinglen = 0; } - while (!SDL_GetAtomicInt(&device->shutdown) && (PULSEAUDIO_pa_stream_readable_size(h->stream) > 0)) { + buflen = PULSEAUDIO_pa_stream_readable_size(h->stream); + while (!SDL_GetAtomicInt(&device->shutdown) && (buflen > 0)) { PULSEAUDIO_pa_threaded_mainloop_wait(pulseaudio_threaded_mainloop); if ((PULSEAUDIO_pa_context_get_state(pulseaudio_context) != PA_CONTEXT_READY) || (PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY)) { //SDL_Log("PULSEAUDIO DEVICE FAILURE IN FLUSHRECORDING!"); @@ -561,11 +562,11 @@ static void PULSEAUDIO_FlushRecording(SDL_AudioDevice *device) break; } - if (PULSEAUDIO_pa_stream_readable_size(h->stream) > 0) { - // a new fragment is available! Just dump it. - PULSEAUDIO_pa_stream_peek(h->stream, &data, &nbytes); - PULSEAUDIO_pa_stream_drop(h->stream); // drop this fragment. - } + // a fragment of audio present before FlushCapture was call is + // still available! Just drop it. + PULSEAUDIO_pa_stream_peek(h->stream, &data, &nbytes); + PULSEAUDIO_pa_stream_drop(h->stream); + buflen -= nbytes; } PULSEAUDIO_pa_threaded_mainloop_unlock(pulseaudio_threaded_mainloop); @@ -778,8 +779,8 @@ static void AddPulseAudioDevice(const bool recording, const char *description, c SDL_free(handle); } else { handle->device_index = index; + SDL_AddAudioDevice(recording, description, &spec, handle); } - SDL_AddAudioDevice(recording, description, &spec, handle); } } @@ -1030,7 +1031,7 @@ static bool PULSEAUDIO_Init(SDL_AudioDriverImpl *impl) } AudioBootStrap PULSEAUDIO_bootstrap = { - "pulseaudio", "PulseAudio", PULSEAUDIO_Init, false + "pulseaudio", "PulseAudio", PULSEAUDIO_Init, false, false }; #endif // SDL_AUDIO_DRIVER_PULSEAUDIO diff --git a/libs/SDL3/src/audio/qnx/SDL_qsa_audio.c b/libs/SDL3/src/audio/qnx/SDL_qsa_audio.c index 715ee328..a31bea4b 100644 --- a/libs/SDL3/src/audio/qnx/SDL_qsa_audio.c +++ b/libs/SDL3/src/audio/qnx/SDL_qsa_audio.c @@ -444,7 +444,7 @@ static bool QSA_Init(SDL_AudioDriverImpl * impl) } AudioBootStrap QSAAUDIO_bootstrap = { - "qsa", "QNX QSA Audio", QSA_Init, 0 + "qsa", "QNX QSA Audio", QSA_Init, false, false }; #endif // SDL_AUDIO_DRIVER_QNX diff --git a/libs/SDL3/src/audio/sndio/SDL_sndioaudio.c b/libs/SDL3/src/audio/sndio/SDL_sndioaudio.c index 00562916..a0d20209 100644 --- a/libs/SDL3/src/audio/sndio/SDL_sndioaudio.c +++ b/libs/SDL3/src/audio/sndio/SDL_sndioaudio.c @@ -350,7 +350,7 @@ static bool SNDIO_Init(SDL_AudioDriverImpl *impl) } AudioBootStrap SNDIO_bootstrap = { - "sndio", "OpenBSD sndio", SNDIO_Init, false + "sndio", "OpenBSD sndio", SNDIO_Init, false, false }; #endif // SDL_AUDIO_DRIVER_SNDIO diff --git a/libs/SDL3/src/audio/vita/SDL_vitaaudio.c b/libs/SDL3/src/audio/vita/SDL_vitaaudio.c index c02c9fa6..e194f212 100644 --- a/libs/SDL3/src/audio/vita/SDL_vitaaudio.c +++ b/libs/SDL3/src/audio/vita/SDL_vitaaudio.c @@ -232,7 +232,7 @@ static bool VITAAUD_Init(SDL_AudioDriverImpl *impl) } AudioBootStrap VITAAUD_bootstrap = { - "vita", "VITA audio driver", VITAAUD_Init, false + "vita", "VITA audio driver", VITAAUD_Init, false, false }; #endif // SDL_AUDIO_DRIVER_VITA diff --git a/libs/SDL3/src/audio/wasapi/SDL_wasapi.c b/libs/SDL3/src/audio/wasapi/SDL_wasapi.c index 71eb3291..db0974b0 100644 --- a/libs/SDL3/src/audio/wasapi/SDL_wasapi.c +++ b/libs/SDL3/src/audio/wasapi/SDL_wasapi.c @@ -957,7 +957,7 @@ static bool WASAPI_Init(SDL_AudioDriverImpl *impl) } AudioBootStrap WASAPI_bootstrap = { - "wasapi", "WASAPI", WASAPI_Init, false + "wasapi", "WASAPI", WASAPI_Init, false, false }; #endif // SDL_AUDIO_DRIVER_WASAPI diff --git a/libs/SDL3/src/camera/SDL_camera.c b/libs/SDL3/src/camera/SDL_camera.c index fdd90904..9f71cea0 100644 --- a/libs/SDL3/src/camera/SDL_camera.c +++ b/libs/SDL3/src/camera/SDL_camera.c @@ -72,6 +72,7 @@ const char *SDL_GetCameraDriver(int index) if (index >= 0 && index < SDL_GetNumCameraDrivers()) { return bootstrap[index]->name; } + SDL_InvalidParamError("index"); return NULL; } @@ -277,23 +278,10 @@ static void ClosePhysicalCamera(SDL_Camera *device) device->base_timestamp = 0; device->adjust_timestamp = 0; -} -// this must not be called while `device` is still in a device list, or while a device's camera thread is still running. -static void DestroyPhysicalCamera(SDL_Camera *device) -{ - if (device) { - // Destroy any logical devices that still exist... - ClosePhysicalCamera(device); - camera_driver.impl.FreeDeviceHandle(device); - SDL_DestroyMutex(device->lock); - SDL_free(device->all_specs); - SDL_free(device->name); - SDL_free(device); - } + SDL_zero(device->spec); } - // Don't hold the device lock when calling this, as we may destroy the device! void UnrefPhysicalCamera(SDL_Camera *device) { @@ -304,7 +292,6 @@ void UnrefPhysicalCamera(SDL_Camera *device) SDL_AddAtomicInt(&camera_driver.device_count, -1); } SDL_UnlockRWLock(camera_driver.device_hash_lock); - DestroyPhysicalCamera(device); // ...and nuke it. } } @@ -497,7 +484,7 @@ SDL_Camera *SDL_AddCamera(const char *name, SDL_CameraPosition position, int num RefPhysicalCamera(device); SDL_LockRWLockForWriting(camera_driver.device_hash_lock); - if (SDL_InsertIntoHashTable(camera_driver.device_hash, (const void *) (uintptr_t) device->instance_id, device)) { + if (SDL_InsertIntoHashTable(camera_driver.device_hash, (const void *) (uintptr_t) device->instance_id, device, false)) { SDL_AddAtomicInt(&camera_driver.device_count, 1); } else { SDL_DestroyMutex(device->lock); @@ -621,7 +608,25 @@ void SDL_CameraPermissionOutcome(SDL_Camera *device, bool approved) } } +typedef struct FindOnePhysicalCameraByCallbackData +{ + bool (*callback)(SDL_Camera *device, void *userdata); + void *userdata; + SDL_Camera *device; +} FindOnePhysicalCameraByCallbackData; +static bool SDLCALL FindOnePhysicalCameraByCallback(void *userdata, const SDL_HashTable *table, const void *key, const void *value) +{ + FindOnePhysicalCameraByCallbackData *data = (FindOnePhysicalCameraByCallbackData *) userdata; + SDL_Camera *device = (SDL_Camera *) value; + if (data->callback(device, data->userdata)) { + data->device = device; + return false; // stop iterating. + } + return true; // keep iterating. +} + +// !!! FIXME: this doesn't follow SDL convention of `userdata` being the first param of the callback. SDL_Camera *SDL_FindPhysicalCameraByCallback(bool (*callback)(SDL_Camera *device, void *userdata), void *userdata) { if (!SDL_GetCurrentCameraDriver()) { @@ -629,28 +634,22 @@ SDL_Camera *SDL_FindPhysicalCameraByCallback(bool (*callback)(SDL_Camera *device return NULL; } - const void *key; - const void *value; - void *iter = NULL; + FindOnePhysicalCameraByCallbackData data = { callback, userdata, NULL }; SDL_LockRWLockForReading(camera_driver.device_hash_lock); - while (SDL_IterateHashTable(camera_driver.device_hash, &key, &value, &iter)) { - SDL_Camera *device = (SDL_Camera *) value; - if (callback(device, userdata)) { // found it? - SDL_UnlockRWLock(camera_driver.device_hash_lock); - return device; - } - } - + SDL_IterateHashTable(camera_driver.device_hash, FindOnePhysicalCameraByCallback, &data); SDL_UnlockRWLock(camera_driver.device_hash_lock); - SDL_SetError("Device not found"); - return NULL; + if (!data.device) { + SDL_SetError("Device not found"); + } + + return data.device; } void SDL_CloseCamera(SDL_Camera *camera) { - SDL_Camera *device = (SDL_Camera *) camera; // currently there's no separation between physical and logical device. + SDL_Camera *device = camera; // currently there's no separation between physical and logical device. ClosePhysicalCamera(device); } @@ -664,7 +663,7 @@ bool SDL_GetCameraFormat(SDL_Camera *camera, SDL_CameraSpec *spec) return SDL_InvalidParamError("spec"); } - SDL_Camera *device = (SDL_Camera *) camera; // currently there's no separation between physical and logical device. + SDL_Camera *device = camera; // currently there's no separation between physical and logical device. ObtainPhysicalCameraObj(device); if (device->permission > 0) { SDL_copyp(spec, &device->spec); @@ -701,6 +700,19 @@ SDL_CameraPosition SDL_GetCameraPosition(SDL_CameraID instance_id) } +typedef struct GetOneCameraData +{ + SDL_CameraID *result; + int devs_seen; +} GetOneCameraData; + +static bool SDLCALL GetOneCamera(void *userdata, const SDL_HashTable *table, const void *key, const void *value) +{ + GetOneCameraData *data = (GetOneCameraData *) userdata; + data->result[data->devs_seen++] = (SDL_CameraID) (uintptr_t) key; + return true; // keep iterating. +} + SDL_CameraID *SDL_GetCameras(int *count) { int dummy_count; @@ -722,16 +734,10 @@ SDL_CameraID *SDL_GetCameras(int *count) if (!result) { num_devices = 0; } else { - int devs_seen = 0; - const void *key; - const void *value; - void *iter = NULL; - while (SDL_IterateHashTable(camera_driver.device_hash, &key, &value, &iter)) { - result[devs_seen++] = (SDL_CameraID) (uintptr_t) key; - } - - SDL_assert(devs_seen == num_devices); - result[devs_seen] = 0; // null-terminated. + GetOneCameraData data = { result, 0 }; + SDL_IterateHashTable(camera_driver.device_hash, GetOneCamera, &data); + SDL_assert(data.devs_seen == num_devices); + result[num_devices] = 0; // null-terminated. } SDL_UnlockRWLock(camera_driver.device_hash_lock); @@ -886,7 +892,7 @@ bool SDL_CameraThreadIterate(SDL_Camera *device) SDL_Surface *srcsurf = acquired; if (device->needs_scaling == -1) { // downscaling? Do it first. -1: downscale, 0: no scaling, 1: upscale SDL_Surface *dstsurf = device->needs_conversion ? device->conversion_surface : output_surface; - SDL_SoftStretch(srcsurf, NULL, dstsurf, NULL, SDL_SCALEMODE_NEAREST); // !!! FIXME: linear scale? letterboxing? + SDL_StretchSurface(srcsurf, NULL, dstsurf, NULL, SDL_SCALEMODE_NEAREST); // !!! FIXME: linear scale? letterboxing? srcsurf = dstsurf; } if (device->needs_conversion) { @@ -897,7 +903,7 @@ bool SDL_CameraThreadIterate(SDL_Camera *device) srcsurf = dstsurf; } if (device->needs_scaling == 1) { // upscaling? Do it last. -1: downscale, 0: no scaling, 1: upscale - SDL_SoftStretch(srcsurf, NULL, output_surface, NULL, SDL_SCALEMODE_NEAREST); // !!! FIXME: linear scale? letterboxing? + SDL_StretchSurface(srcsurf, NULL, output_surface, NULL, SDL_SCALEMODE_NEAREST); // !!! FIXME: linear scale? letterboxing? } // we made a copy, so we can give the driver back its resources. @@ -952,6 +958,110 @@ static int SDLCALL CameraThread(void *devicep) return 0; } +bool SDL_PrepareCameraSurfaces(SDL_Camera *device) +{ + SDL_CameraSpec *appspec = &device->spec; // the app wants this format. + const SDL_CameraSpec *devspec = &device->actual_spec; // the hardware is set to this format. + + SDL_assert(device->acquire_surface == NULL); // shouldn't call this function twice on an opened camera! + SDL_assert(devspec->format != SDL_PIXELFORMAT_UNKNOWN); // fix the backend, it should have an actual format by now. + SDL_assert(devspec->width >= 0); // fix the backend, it should have an actual format by now. + SDL_assert(devspec->height >= 0); // fix the backend, it should have an actual format by now. + + if (appspec->width <= 0 || appspec->height <= 0) { + appspec->width = devspec->width; + appspec->height = devspec->height; + } + + if (appspec->format == SDL_PIXELFORMAT_UNKNOWN) { + appspec->format = devspec->format; + } + + if (appspec->framerate_denominator == 0) { + appspec->framerate_numerator = devspec->framerate_numerator; + appspec->framerate_denominator = devspec->framerate_denominator; + } + + if ((devspec->width == appspec->width) && (devspec->height == appspec->height)) { + device->needs_scaling = 0; + } else { + const Uint64 srcarea = ((Uint64) devspec->width) * ((Uint64) devspec->height); + const Uint64 dstarea = ((Uint64) appspec->width) * ((Uint64) appspec->height); + if (dstarea <= srcarea) { + device->needs_scaling = -1; // downscaling (or changing to new aspect ratio with same area) + } else { + device->needs_scaling = 1; // upscaling + } + } + + device->needs_conversion = (devspec->format != appspec->format); + + device->acquire_surface = SDL_CreateSurfaceFrom(devspec->width, devspec->height, devspec->format, NULL, 0); + if (!device->acquire_surface) { + goto failed; + } + SDL_SetSurfaceColorspace(device->acquire_surface, devspec->colorspace); + + // if we have to scale _and_ convert, we need a middleman surface, since we can't do both changes at once. + if (device->needs_scaling && device->needs_conversion) { + const bool downscaling_first = (device->needs_scaling < 0); + const SDL_CameraSpec *s = downscaling_first ? appspec : devspec; + const SDL_PixelFormat fmt = downscaling_first ? devspec->format : appspec->format; + device->conversion_surface = SDL_CreateSurface(s->width, s->height, fmt); + if (!device->conversion_surface) { + goto failed; + } + SDL_SetSurfaceColorspace(device->conversion_surface, devspec->colorspace); + } + + // output surfaces are in the app-requested format. If no conversion is necessary, we'll just use the pointers + // the backend fills into acquired_surface, and you can get all the way from DMA access in the camera hardware + // to the app without a single copy. Otherwise, these will be full surfaces that hold converted/scaled copies. + + for (int i = 0; i < (SDL_arraysize(device->output_surfaces) - 1); i++) { + device->output_surfaces[i].next = &device->output_surfaces[i + 1]; + } + device->empty_output_surfaces.next = device->output_surfaces; + + for (int i = 0; i < SDL_arraysize(device->output_surfaces); i++) { + SDL_Surface *surf; + if (device->needs_scaling || device->needs_conversion) { + surf = SDL_CreateSurface(appspec->width, appspec->height, appspec->format); + } else { + surf = SDL_CreateSurfaceFrom(appspec->width, appspec->height, appspec->format, NULL, 0); + } + if (!surf) { + goto failed; + } + SDL_SetSurfaceColorspace(surf, devspec->colorspace); + + device->output_surfaces[i].surface = surf; + } + + return true; + +failed: + if (device->acquire_surface) { + SDL_DestroySurface(device->acquire_surface); + device->acquire_surface = NULL; + } + + if (device->conversion_surface) { + SDL_DestroySurface(device->conversion_surface); + device->conversion_surface = NULL; + } + + for (int i = 0; i < SDL_arraysize(device->output_surfaces); i++) { + SDL_Surface *surf = device->output_surfaces[i].surface; + if (surf) { + SDL_DestroySurface(surf); + } + } + SDL_zeroa(device->output_surfaces); + + return false; +} + static void ChooseBestCameraSpec(SDL_Camera *device, const SDL_CameraSpec *spec, SDL_CameraSpec *closest) { // Find the closest available native format/size... @@ -1104,85 +1214,19 @@ SDL_Camera *SDL_OpenCamera(SDL_CameraID instance_id, const SDL_CameraSpec *spec) return NULL; } - if (spec) { - SDL_copyp(&device->spec, spec); - if (spec->width <= 0 || spec->height <= 0) { - device->spec.width = closest.width; - device->spec.height = closest.height; - } - if (spec->format == SDL_PIXELFORMAT_UNKNOWN) { - device->spec.format = closest.format; - } - if (spec->framerate_denominator == 0) { - device->spec.framerate_numerator = closest.framerate_numerator; - device->spec.framerate_denominator = closest.framerate_denominator; - } - } else { - SDL_copyp(&device->spec, &closest); - } - + SDL_copyp(&device->spec, spec ? spec : &closest); SDL_copyp(&device->actual_spec, &closest); - if ((closest.width == device->spec.width) && (closest.height == device->spec.height)) { - device->needs_scaling = 0; - } else { - const Uint64 srcarea = ((Uint64) closest.width) * ((Uint64) closest.height); - const Uint64 dstarea = ((Uint64) device->spec.width) * ((Uint64) device->spec.height); - if (dstarea <= srcarea) { - device->needs_scaling = -1; // downscaling (or changing to new aspect ratio with same area) - } else { - device->needs_scaling = 1; // upscaling - } - } - - device->needs_conversion = (closest.format != device->spec.format); - - device->acquire_surface = SDL_CreateSurfaceFrom(closest.width, closest.height, closest.format, NULL, 0); - if (!device->acquire_surface) { - ClosePhysicalCamera(device); - ReleaseCamera(device); - return NULL; - } - SDL_SetSurfaceColorspace(device->acquire_surface, closest.colorspace); - - // if we have to scale _and_ convert, we need a middleman surface, since we can't do both changes at once. - if (device->needs_scaling && device->needs_conversion) { - const bool downsampling_first = (device->needs_scaling < 0); - const SDL_CameraSpec *s = downsampling_first ? &device->spec : &closest; - const SDL_PixelFormat fmt = downsampling_first ? closest.format : device->spec.format; - device->conversion_surface = SDL_CreateSurface(s->width, s->height, fmt); - if (!device->conversion_surface) { + // SDL_PIXELFORMAT_UNKNOWN here is taken as a signal that the backend + // doesn't know its format yet (Emscripten waiting for user permission, + // in this case), and the backend will call SDL_PrepareCameraSurfaces() + // itself, later but before the app is allowed to acquire images. + if (closest.format != SDL_PIXELFORMAT_UNKNOWN) { + if (!SDL_PrepareCameraSurfaces(device)) { ClosePhysicalCamera(device); ReleaseCamera(device); return NULL; } - SDL_SetSurfaceColorspace(device->conversion_surface, closest.colorspace); - } - - // output surfaces are in the app-requested format. If no conversion is necessary, we'll just use the pointers - // the backend fills into acquired_surface, and you can get all the way from DMA access in the camera hardware - // to the app without a single copy. Otherwise, these will be full surfaces that hold converted/scaled copies. - - for (int i = 0; i < (SDL_arraysize(device->output_surfaces) - 1); i++) { - device->output_surfaces[i].next = &device->output_surfaces[i + 1]; - } - device->empty_output_surfaces.next = device->output_surfaces; - - for (int i = 0; i < SDL_arraysize(device->output_surfaces); i++) { - SDL_Surface *surf; - if (device->needs_scaling || device->needs_conversion) { - surf = SDL_CreateSurface(device->spec.width, device->spec.height, device->spec.format); - } else { - surf = SDL_CreateSurfaceFrom(device->spec.width, device->spec.height, device->spec.format, NULL, 0); - } - if (!surf) { - ClosePhysicalCamera(device); - ReleaseCamera(device); - return NULL; - } - SDL_SetSurfaceColorspace(surf, closest.colorspace); - - device->output_surfaces[i].surface = surf; } device->drop_frames = 1; @@ -1202,7 +1246,7 @@ SDL_Camera *SDL_OpenCamera(SDL_CameraID instance_id, const SDL_CameraSpec *spec) ReleaseCamera(device); // unlock, we're good to go! - return (SDL_Camera *) device; // currently there's no separation between physical and logical device. + return device; // currently there's no separation between physical and logical device. } SDL_Surface *SDL_AcquireCameraFrame(SDL_Camera *camera, Uint64 *timestampNS) @@ -1216,7 +1260,7 @@ SDL_Surface *SDL_AcquireCameraFrame(SDL_Camera *camera, Uint64 *timestampNS) return NULL; } - SDL_Camera *device = (SDL_Camera *) camera; // currently there's no separation between physical and logical device. + SDL_Camera *device = camera; // currently there's no separation between physical and logical device. ObtainPhysicalCameraObj(device); @@ -1258,7 +1302,7 @@ void SDL_ReleaseCameraFrame(SDL_Camera *camera, SDL_Surface *frame) return; } - SDL_Camera *device = (SDL_Camera *) camera; // currently there's no separation between physical and logical device. + SDL_Camera *device = camera; // currently there's no separation between physical and logical device. ObtainPhysicalCameraObj(device); SurfaceList *slistprev = &device->app_held_output_surfaces; @@ -1300,7 +1344,7 @@ SDL_CameraID SDL_GetCameraID(SDL_Camera *camera) if (!camera) { SDL_InvalidParamError("camera"); } else { - SDL_Camera *device = (SDL_Camera *) camera; // currently there's no separation between physical and logical device. + SDL_Camera *device = camera; // currently there's no separation between physical and logical device. ObtainPhysicalCameraObj(device); result = device->instance_id; ReleaseCamera(device); @@ -1315,7 +1359,7 @@ SDL_PropertiesID SDL_GetCameraProperties(SDL_Camera *camera) if (!camera) { SDL_InvalidParamError("camera"); } else { - SDL_Camera *device = (SDL_Camera *) camera; // currently there's no separation between physical and logical device. + SDL_Camera *device = camera; // currently there's no separation between physical and logical device. ObtainPhysicalCameraObj(device); if (device->props == 0) { device->props = SDL_CreateProperties(); @@ -1334,7 +1378,7 @@ int SDL_GetCameraPermissionState(SDL_Camera *camera) SDL_InvalidParamError("camera"); result = -1; } else { - SDL_Camera *device = (SDL_Camera *) camera; // currently there's no separation between physical and logical device. + SDL_Camera *device = camera; // currently there's no separation between physical and logical device. ObtainPhysicalCameraObj(device); result = device->permission; ReleaseCamera(device); @@ -1378,37 +1422,26 @@ void SDL_QuitCamera(void) SDL_free(i); } - const void *key; - const void *value; - void *iter = NULL; - while (SDL_IterateHashTable(device_hash, &key, &value, &iter)) { - DestroyPhysicalCamera((SDL_Camera *) value); - } + SDL_DestroyHashTable(device_hash); // Free the driver data camera_driver.impl.Deinitialize(); SDL_DestroyRWLock(camera_driver.device_hash_lock); - SDL_DestroyHashTable(device_hash); SDL_zero(camera_driver); } - -static Uint32 HashCameraID(const void *key, void *data) +// Physical camera objects are only destroyed when removed from the device hash. +static void SDLCALL DestroyCameraHashItem(void *userdata, const void *key, const void *value) { - // The values are unique incrementing integers, starting at 1, so just return minus 1 to start with bucket zero. - return ((Uint32) ((uintptr_t) key)) - 1; -} - -static bool MatchCameraID(const void *a, const void *b, void *data) -{ - return (a == b); // simple integers, just compare them as pointer values. -} - -static void NukeCameraHashItem(const void *key, const void *value, void *data) -{ - // no-op, keys and values in this hashtable are treated as Plain Old Data and don't get freed here. + SDL_Camera *device = (SDL_Camera *) value; + ClosePhysicalCamera(device); + camera_driver.impl.FreeDeviceHandle(device); + SDL_DestroyMutex(device->lock); + SDL_free(device->all_specs); + SDL_free(device->name); + SDL_free(device); } bool SDL_CameraInit(const char *driver_name) @@ -1422,7 +1455,7 @@ bool SDL_CameraInit(const char *driver_name) return false; } - SDL_HashTable *device_hash = SDL_CreateHashTable(NULL, 8, HashCameraID, MatchCameraID, NukeCameraHashItem, false, false); + SDL_HashTable *device_hash = SDL_CreateHashTable(0, false, SDL_HashID, SDL_KeyMatchID, DestroyCameraHashItem, NULL); if (!device_hash) { SDL_DestroyRWLock(device_hash_lock); return false; diff --git a/libs/SDL3/src/camera/SDL_syscamera.h b/libs/SDL3/src/camera/SDL_syscamera.h index 7af115ad..30a02f39 100644 --- a/libs/SDL3/src/camera/SDL_syscamera.h +++ b/libs/SDL3/src/camera/SDL_syscamera.h @@ -54,6 +54,10 @@ extern void SDL_CameraThreadSetup(SDL_Camera *device); extern bool SDL_CameraThreadIterate(SDL_Camera *device); extern void SDL_CameraThreadShutdown(SDL_Camera *device); +// Backends can call this if they have to finish initializing later, like Emscripten. Most backends should _not_ call this directly! +extern bool SDL_PrepareCameraSurfaces(SDL_Camera *device); + + // common utility functionality to gather up camera specs. Not required! typedef struct CameraFormatAddData { @@ -190,7 +194,7 @@ typedef struct SDL_CameraDriver const char *desc; // The description of this camera driver SDL_CameraDriverImpl impl; // the backend's interface - SDL_RWLock *device_hash_lock; // A rwlock that protects `device_hash` + SDL_RWLock *device_hash_lock; // A rwlock that protects `device_hash` // !!! FIXME: device_hash _also_ has a rwlock, see if we still need this one. SDL_HashTable *device_hash; // the collection of currently-available camera devices SDL_PendingCameraEvent pending_events; SDL_PendingCameraEvent *pending_events_tail; diff --git a/libs/SDL3/src/camera/emscripten/SDL_camera_emscripten.c b/libs/SDL3/src/camera/emscripten/SDL_camera_emscripten.c index 986c899c..fa2a5114 100644 --- a/libs/SDL3/src/camera/emscripten/SDL_camera_emscripten.c +++ b/libs/SDL3/src/camera/emscripten/SDL_camera_emscripten.c @@ -98,17 +98,24 @@ static void EMSCRIPTENCAMERA_CloseDevice(SDL_Camera *device) } } -static void SDLEmscriptenCameraPermissionOutcome(SDL_Camera *device, int approved, int w, int h, int fps) +static int SDLEmscriptenCameraPermissionOutcome(SDL_Camera *device, int approved, int w, int h, int fps) { - device->spec.width = device->actual_spec.width = w; - device->spec.height = device->actual_spec.height = h; - device->spec.framerate_numerator = device->actual_spec.framerate_numerator = fps; - device->spec.framerate_denominator = device->actual_spec.framerate_denominator = 1; - if (device->acquire_surface) { - device->acquire_surface->w = w; - device->acquire_surface->h = h; + if (approved) { + device->actual_spec.format = SDL_PIXELFORMAT_RGBA32; + device->actual_spec.width = w; + device->actual_spec.height = h; + device->actual_spec.framerate_numerator = fps; + device->actual_spec.framerate_denominator = 1; + + if (!SDL_PrepareCameraSurfaces(device)) { + // uhoh, we're in trouble. Probably ran out of memory. + SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Camera could not prepare surfaces: %s ... revoking approval!", SDL_GetError()); + approved = 0; // disconnecting the SDL camera might not be safe here, just mark it as denied by user. + } } + SDL_CameraPermissionOutcome(device, approved ? true : false); + return approved; } static bool EMSCRIPTENCAMERA_OpenDevice(SDL_Camera *device, const SDL_CameraSpec *spec) @@ -167,40 +174,40 @@ static bool EMSCRIPTENCAMERA_OpenDevice(SDL_Camera *device, const SDL_CameraSpec const actualfps = settings.frameRate; console.log("Camera is opened! Actual spec: (" + actualw + "x" + actualh + "), fps=" + actualfps); - dynCall('viiiii', outcome, [device, 1, actualw, actualh, actualfps]); + if (dynCall('iiiiii', outcome, [device, 1, actualw, actualh, actualfps])) { + const video = document.createElement("video"); + video.width = actualw; + video.height = actualh; + video.style.display = 'none'; // we need to attach this to a hidden video node so we can read it as pixels. + video.srcObject = stream; - const video = document.createElement("video"); - video.width = actualw; - video.height = actualh; - video.style.display = 'none'; // we need to attach this to a hidden video node so we can read it as pixels. - video.srcObject = stream; + const canvas = document.createElement("canvas"); + canvas.width = actualw; + canvas.height = actualh; + canvas.style.display = 'none'; // we need to attach this to a hidden video node so we can read it as pixels. - const canvas = document.createElement("canvas"); - canvas.width = actualw; - canvas.height = actualh; - canvas.style.display = 'none'; // we need to attach this to a hidden video node so we can read it as pixels. + const ctx2d = canvas.getContext('2d'); - const ctx2d = canvas.getContext('2d'); + const SDL3 = Module['SDL3']; + SDL3.camera.width = actualw; + SDL3.camera.height = actualh; + SDL3.camera.fps = actualfps; + SDL3.camera.fpsincrms = 1000.0 / actualfps; + SDL3.camera.stream = stream; + SDL3.camera.video = video; + SDL3.camera.canvas = canvas; + SDL3.camera.ctx2d = ctx2d; + SDL3.camera.next_frame_time = performance.now(); - const SDL3 = Module['SDL3']; - SDL3.camera.width = actualw; - SDL3.camera.height = actualh; - SDL3.camera.fps = actualfps; - SDL3.camera.fpsincrms = 1000.0 / actualfps; - SDL3.camera.stream = stream; - SDL3.camera.video = video; - SDL3.camera.canvas = canvas; - SDL3.camera.ctx2d = ctx2d; - SDL3.camera.next_frame_time = performance.now(); - - video.play(); - video.addEventListener('loadedmetadata', () => { - grabNextCameraFrame(); // start this loop going. - }); + video.play(); + video.addEventListener('loadedmetadata', () => { + grabNextCameraFrame(); // start this loop going. + }); + } }) .catch((err) => { console.error("Tried to open camera but it threw an error! " + err.name + ": " + err.message); - dynCall('viiiii', outcome, [device, 0, 0, 0, 0]); // we call this a permission error, because it probably is. + dynCall('iiiiii', outcome, [device, 0, 0, 0, 0]); // we call this a permission error, because it probably is. }); }, device, spec->width, spec->height, spec->framerate_numerator, spec->framerate_denominator, SDLEmscriptenCameraPermissionOutcome, SDL_CameraThreadIterate); diff --git a/libs/SDL3/src/camera/mediafoundation/SDL_camera_mediafoundation.c b/libs/SDL3/src/camera/mediafoundation/SDL_camera_mediafoundation.c index 086868f8..d9d627d0 100644 --- a/libs/SDL3/src/camera/mediafoundation/SDL_camera_mediafoundation.c +++ b/libs/SDL3/src/camera/mediafoundation/SDL_camera_mediafoundation.c @@ -76,6 +76,7 @@ SDL_DEFINE_MEDIATYPE_GUID(MFVideoFormat_UYVY, FCC('UYVY')); SDL_DEFINE_MEDIATYPE_GUID(MFVideoFormat_YVYU, FCC('YVYU')); SDL_DEFINE_MEDIATYPE_GUID(MFVideoFormat_NV12, FCC('NV12')); SDL_DEFINE_MEDIATYPE_GUID(MFVideoFormat_NV21, FCC('NV21')); +SDL_DEFINE_MEDIATYPE_GUID(MFVideoFormat_MJPG, FCC('MJPG')); #undef SDL_DEFINE_MEDIATYPE_GUID #ifdef __GNUC__ @@ -102,7 +103,8 @@ static const struct { &SDL_MFVideoFormat_UYVY, SDL_PIXELFORMAT_UYVY, SDL_COLORSPACE_BT709_LIMITED }, { &SDL_MFVideoFormat_YVYU, SDL_PIXELFORMAT_YVYU, SDL_COLORSPACE_BT709_LIMITED }, { &SDL_MFVideoFormat_NV12, SDL_PIXELFORMAT_NV12, SDL_COLORSPACE_BT709_LIMITED }, - { &SDL_MFVideoFormat_NV21, SDL_PIXELFORMAT_NV21, SDL_COLORSPACE_BT709_LIMITED } + { &SDL_MFVideoFormat_NV21, SDL_PIXELFORMAT_NV21, SDL_COLORSPACE_BT709_LIMITED }, + { &SDL_MFVideoFormat_MJPG, SDL_PIXELFORMAT_MJPG, SDL_COLORSPACE_SRGB } }; static SDL_Colorspace GetMediaTypeColorspace(IMFMediaType *mediatype, SDL_Colorspace default_colorspace) @@ -296,6 +298,13 @@ static void MediaTypeToSDLFmt(IMFMediaType *mediatype, SDL_PixelFormat *format, } } } +#if DEBUG_CAMERA + SDL_Log("Unknown media type: 0x%x (%c%c%c%c)", type.Data1, + (char)(Uint8)(type.Data1 >> 0), + (char)(Uint8)(type.Data1 >> 8), + (char)(Uint8)(type.Data1 >> 16), + (char)(Uint8)(type.Data1 >> 24)); +#endif *format = SDL_PIXELFORMAT_UNKNOWN; *colorspace = SDL_COLORSPACE_UNKNOWN; } @@ -424,7 +433,7 @@ static void SDLCALL CleanupIMFMediaBuffer(void *userdata, void *value) static SDL_CameraFrameResult MEDIAFOUNDATION_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS) { SDL_assert(device->hidden->current_sample != NULL); - + SDL_CameraFrameResult result = SDL_CAMERA_FRAME_READY; HRESULT ret; LONGLONG timestamp100NS = 0; @@ -457,46 +466,60 @@ static SDL_CameraFrameResult MEDIAFOUNDATION_AcquireFrame(SDL_Camera *device, SD } else { BYTE *pixels = NULL; LONG pitch = 0; + DWORD buflen = 0; if (SUCCEEDED(IMFMediaBuffer_QueryInterface(objs->buffer, &SDL_IID_IMF2DBuffer2, (void **)&objs->buffer2d2))) { BYTE *bufstart = NULL; - DWORD buflen = 0; ret = IMF2DBuffer2_Lock2DSize(objs->buffer2d2, MF2DBuffer_LockFlags_Read, &pixels, &pitch, &bufstart, &buflen); if (FAILED(ret)) { result = SDL_CAMERA_FRAME_ERROR; CleanupIMF2DBuffer2(NULL, objs); } else { + if (frame->format == SDL_PIXELFORMAT_MJPG) { + pitch = (LONG)buflen; + } + if (pitch < 0) { // image rows are reversed. + pixels += -pitch * (frame->h - 1); + } frame->pixels = pixels; - frame->pitch = (int) pitch; + frame->pitch = (int)pitch; if (!SDL_SetPointerPropertyWithCleanup(surfprops, PROP_SURFACE_IMFOBJS_POINTER, objs, CleanupIMF2DBuffer2, NULL)) { result = SDL_CAMERA_FRAME_ERROR; } } - } else if (SUCCEEDED(IMFMediaBuffer_QueryInterface(objs->buffer, &SDL_IID_IMF2DBuffer, (void **)&objs->buffer2d))) { + } else if (frame->format != SDL_PIXELFORMAT_MJPG && + SUCCEEDED(IMFMediaBuffer_QueryInterface(objs->buffer, &SDL_IID_IMF2DBuffer, (void **)&objs->buffer2d))) { ret = IMF2DBuffer_Lock2D(objs->buffer2d, &pixels, &pitch); if (FAILED(ret)) { CleanupIMF2DBuffer(NULL, objs); result = SDL_CAMERA_FRAME_ERROR; } else { + if (pitch < 0) { // image rows are reversed. + pixels += -pitch * (frame->h - 1); + } frame->pixels = pixels; - frame->pitch = (int) pitch; + frame->pitch = (int)pitch; if (!SDL_SetPointerPropertyWithCleanup(surfprops, PROP_SURFACE_IMFOBJS_POINTER, objs, CleanupIMF2DBuffer, NULL)) { result = SDL_CAMERA_FRAME_ERROR; } } } else { - DWORD maxlen = 0, currentlen = 0; - ret = IMFMediaBuffer_Lock(objs->buffer, &pixels, &maxlen, ¤tlen); + DWORD maxlen = 0; + ret = IMFMediaBuffer_Lock(objs->buffer, &pixels, &maxlen, &buflen); if (FAILED(ret)) { CleanupIMFMediaBuffer(NULL, objs); result = SDL_CAMERA_FRAME_ERROR; } else { - pitch = (LONG) device->hidden->pitch; - if (pitch < 0) { // image rows are reversed. + if (frame->format == SDL_PIXELFORMAT_MJPG) { + pitch = (LONG)buflen; + } else { + pitch = (LONG)device->hidden->pitch; + } + if (pitch < 0) { // image rows are reversed. pixels += -pitch * (frame->h - 1); } frame->pixels = pixels; - frame->pitch = (int) pitch; + frame->pitch = (int)pitch; if (!SDL_SetPointerPropertyWithCleanup(surfprops, PROP_SURFACE_IMFOBJS_POINTER, objs, CleanupIMFMediaBuffer, NULL)) { result = SDL_CAMERA_FRAME_ERROR; } @@ -522,6 +545,23 @@ static void MEDIAFOUNDATION_ReleaseFrame(SDL_Camera *device, SDL_Surface *frame) #else +static SDL_CameraFrameResult MEDIAFOUNDATION_CopyFrame(SDL_Surface *frame, const BYTE *pixels, LONG pitch, DWORD buflen) +{ + frame->pixels = SDL_aligned_alloc(SDL_GetSIMDAlignment(), buflen); + if (!frame->pixels) { + return SDL_CAMERA_FRAME_ERROR; + } + + const BYTE *start = pixels; + if (pitch < 0) { // image rows are reversed. + start += -pitch * (frame->h - 1); + } + SDL_memcpy(frame->pixels, start, buflen); + frame->pitch = (int)pitch; + + return SDL_CAMERA_FRAME_READY; +} + static SDL_CameraFrameResult MEDIAFOUNDATION_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS) { SDL_assert(device->hidden->current_sample != NULL); @@ -555,63 +595,44 @@ static SDL_CameraFrameResult MEDIAFOUNDATION_AcquireFrame(SDL_Camera *device, SD IMF2DBuffer2 *buffer2d2 = NULL; BYTE *pixels = NULL; LONG pitch = 0; + DWORD buflen = 0; if (SUCCEEDED(IMFMediaBuffer_QueryInterface(buffer, &SDL_IID_IMF2DBuffer2, (void **)&buffer2d2))) { BYTE *bufstart = NULL; - DWORD buflen = 0; ret = IMF2DBuffer2_Lock2DSize(buffer2d2, MF2DBuffer_LockFlags_Read, &pixels, &pitch, &bufstart, &buflen); if (FAILED(ret)) { result = SDL_CAMERA_FRAME_ERROR; } else { - frame->pixels = SDL_aligned_alloc(SDL_GetSIMDAlignment(), buflen); - if (frame->pixels == NULL) { - result = SDL_CAMERA_FRAME_ERROR; - } else { - SDL_memcpy(frame->pixels, pixels, buflen); - frame->pitch = (int)pitch; + if (frame->format == SDL_PIXELFORMAT_MJPG) { + pitch = (LONG)buflen; } + result = MEDIAFOUNDATION_CopyFrame(frame, pixels, pitch, buflen); IMF2DBuffer2_Unlock2D(buffer2d2); } IMF2DBuffer2_Release(buffer2d2); - } else if (SUCCEEDED(IMFMediaBuffer_QueryInterface(buffer, &SDL_IID_IMF2DBuffer, (void **)&buffer2d))) { + } else if (frame->format != SDL_PIXELFORMAT_MJPG && + SUCCEEDED(IMFMediaBuffer_QueryInterface(buffer, &SDL_IID_IMF2DBuffer, (void **)&buffer2d))) { ret = IMF2DBuffer_Lock2D(buffer2d, &pixels, &pitch); if (FAILED(ret)) { result = SDL_CAMERA_FRAME_ERROR; } else { - BYTE *bufstart = pixels; - const DWORD buflen = (SDL_abs((int)pitch) * frame->w) * frame->h; - if (pitch < 0) { // image rows are reversed. - bufstart += -pitch * (frame->h - 1); - } - frame->pixels = SDL_aligned_alloc(SDL_GetSIMDAlignment(), buflen); - if (frame->pixels == NULL) { - result = SDL_CAMERA_FRAME_ERROR; - } else { - SDL_memcpy(frame->pixels, bufstart, buflen); - frame->pitch = (int)pitch; - } + buflen = SDL_abs((int)pitch) * frame->h; + result = MEDIAFOUNDATION_CopyFrame(frame, pixels, pitch, buflen); IMF2DBuffer_Unlock2D(buffer2d); } IMF2DBuffer_Release(buffer2d); } else { - DWORD maxlen = 0, currentlen = 0; - ret = IMFMediaBuffer_Lock(buffer, &pixels, &maxlen, ¤tlen); + DWORD maxlen = 0; + ret = IMFMediaBuffer_Lock(buffer, &pixels, &maxlen, &buflen); if (FAILED(ret)) { result = SDL_CAMERA_FRAME_ERROR; } else { - BYTE *bufstart = pixels; - pitch = (LONG)device->hidden->pitch; - const DWORD buflen = (SDL_abs((int)pitch) * frame->w) * frame->h; - if (pitch < 0) { // image rows are reversed. - bufstart += -pitch * (frame->h - 1); - } - frame->pixels = SDL_aligned_alloc(SDL_GetSIMDAlignment(), buflen); - if (frame->pixels == NULL) { - result = SDL_CAMERA_FRAME_ERROR; + if (frame->format == SDL_PIXELFORMAT_MJPG) { + pitch = (LONG)buflen; } else { - SDL_memcpy(frame->pixels, bufstart, buflen); - frame->pitch = (int)pitch; + pitch = (LONG)device->hidden->pitch; } + result = MEDIAFOUNDATION_CopyFrame(frame, pixels, pitch, buflen); IMFMediaBuffer_Unlock(buffer); } } diff --git a/libs/SDL3/src/camera/pipewire/SDL_camera_pipewire.c b/libs/SDL3/src/camera/pipewire/SDL_camera_pipewire.c index 43e54d26..4de2f234 100644 --- a/libs/SDL3/src/camera/pipewire/SDL_camera_pipewire.c +++ b/libs/SDL3/src/camera/pipewire/SDL_camera_pipewire.c @@ -374,10 +374,8 @@ static struct sdl_video_format { { SDL_PIXELFORMAT_YUY2, SDL_COLORSPACE_BT709_LIMITED, SPA_VIDEO_FORMAT_YUY2 }, { SDL_PIXELFORMAT_UYVY, SDL_COLORSPACE_BT709_LIMITED, SPA_VIDEO_FORMAT_UYVY }, { SDL_PIXELFORMAT_YVYU, SDL_COLORSPACE_BT709_LIMITED, SPA_VIDEO_FORMAT_YVYU }, -#if SDL_VERSION_ATLEAST(2,0,4) { SDL_PIXELFORMAT_NV12, SDL_COLORSPACE_BT709_LIMITED, SPA_VIDEO_FORMAT_NV12 }, - { SDL_PIXELFORMAT_NV21, SDL_COLORSPACE_BT709_LIMITED, SPA_VIDEO_FORMAT_NV21 }, -#endif + { SDL_PIXELFORMAT_NV21, SDL_COLORSPACE_BT709_LIMITED, SPA_VIDEO_FORMAT_NV21 } }; static uint32_t sdl_format_to_id(SDL_PixelFormat format) @@ -500,14 +498,24 @@ static bool PIPEWIRECAMERA_OpenDevice(SDL_Camera *device, const SDL_CameraSpec * &device->hidden->stream_listener, &stream_events, device); - params[n_params++] = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, - SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video), - SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), - SPA_FORMAT_VIDEO_format, SPA_POD_Id(sdl_format_to_id(spec->format)), - SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle(&SPA_RECTANGLE(spec->width, spec->height)), - SPA_FORMAT_VIDEO_framerate, - SPA_POD_Fraction(&SPA_FRACTION(spec->framerate_numerator, spec->framerate_denominator))); + if (spec->format == SDL_PIXELFORMAT_MJPG) { + params[n_params++] = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, + SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video), + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_mjpg), + SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle(&SPA_RECTANGLE(spec->width, spec->height)), + SPA_FORMAT_VIDEO_framerate, + SPA_POD_Fraction(&SPA_FRACTION(spec->framerate_numerator, spec->framerate_denominator))); + } else { + params[n_params++] = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, + SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video), + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), + SPA_FORMAT_VIDEO_format, SPA_POD_Id(sdl_format_to_id(spec->format)), + SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle(&SPA_RECTANGLE(spec->width, spec->height)), + SPA_FORMAT_VIDEO_framerate, + SPA_POD_Fraction(&SPA_FRACTION(spec->framerate_numerator, spec->framerate_denominator))); + } if ((res = PIPEWIRE_pw_stream_connect(device->hidden->stream, PW_DIRECTION_INPUT, @@ -573,7 +581,11 @@ static SDL_CameraFrameResult PIPEWIRECAMERA_AcquireFrame(SDL_Camera *device, SDL *timestampNS = SDL_GetTicksNS(); #endif frame->pixels = b->buffer->datas[0].data; - frame->pitch = b->buffer->datas[0].chunk->stride; + if (frame->format == SDL_PIXELFORMAT_MJPG) { + frame->pitch = b->buffer->datas[0].chunk->size; + } else { + frame->pitch = b->buffer->datas[0].chunk->stride; + } PIPEWIRE_pw_thread_loop_unlock(hotplug.loop); @@ -612,7 +624,7 @@ static void collect_rates(CameraFormatAddData *data, struct param *p, SDL_PixelF switch (choice) { case SPA_CHOICE_None: n_vals = 1; - SPA_FALLTHROUGH; + SDL_FALLTHROUGH; case SPA_CHOICE_Enum: for (i = 0; i < n_vals; i++) { if (!SDL_AddCameraFormat(data, sdlfmt, colorspace, size->width, size->height, rates[i].num, rates[i].denom)) { @@ -645,7 +657,7 @@ static void collect_size(CameraFormatAddData *data, struct param *p, SDL_PixelFo switch (choice) { case SPA_CHOICE_None: n_vals = 1; - SPA_FALLTHROUGH; + SDL_FALLTHROUGH; case SPA_CHOICE_Enum: for (i = 0; i < n_vals; i++) { collect_rates(data, p, sdlfmt, colorspace, &rectangles[i]); @@ -657,7 +669,7 @@ static void collect_size(CameraFormatAddData *data, struct param *p, SDL_PixelFo } } -static void collect_format(CameraFormatAddData *data, struct param *p) +static void collect_raw(CameraFormatAddData *data, struct param *p) { const struct spa_pod_prop *prop; SDL_PixelFormat sdlfmt; @@ -677,7 +689,7 @@ static void collect_format(CameraFormatAddData *data, struct param *p) switch (choice) { case SPA_CHOICE_None: n_vals = 1; - SPA_FALLTHROUGH; + SDL_FALLTHROUGH; case SPA_CHOICE_Enum: for (i = 0; i < n_vals; i++) { id_to_sdl_format(ids[i], &sdlfmt, &colorspace); @@ -688,7 +700,47 @@ static void collect_format(CameraFormatAddData *data, struct param *p) } break; default: - SDL_Log("CAMERA: unimplemented choice:%d", choice); + SDL_Log("CAMERA: unimplemented choice: %d", choice); + break; + } +} + +static void collect_format(CameraFormatAddData *data, struct param *p) +{ + const struct spa_pod_prop *prop; + struct spa_pod * values; + uint32_t i, n_vals, choice, *ids; + + prop = spa_pod_find_prop(p->param, NULL, SPA_FORMAT_mediaSubtype); + if (prop == NULL) + return; + + values = spa_pod_get_values(&prop->value, &n_vals, &choice); + if (values->type != SPA_TYPE_Id || n_vals == 0) + return; + + ids = SPA_POD_BODY(values); + switch (choice) { + case SPA_CHOICE_None: + n_vals = 1; + SDL_FALLTHROUGH; + case SPA_CHOICE_Enum: + for (i = 0; i < n_vals; i++) { + switch (ids[i]) { + case SPA_MEDIA_SUBTYPE_raw: + collect_raw(data, p); + break; + case SPA_MEDIA_SUBTYPE_mjpg: + collect_size(data, p, SDL_PIXELFORMAT_MJPG, SDL_COLORSPACE_JPEG); + break; + default: + // Unsupported format + break; + } + } + break; + default: + SDL_Log("CAMERA: unimplemented choice: %d", choice); break; } } diff --git a/libs/SDL3/src/camera/v4l2/SDL_camera_v4l2.c b/libs/SDL3/src/camera/v4l2/SDL_camera_v4l2.c index a4d4df63..9cdb54b0 100644 --- a/libs/SDL3/src/camera/v4l2/SDL_camera_v4l2.c +++ b/libs/SDL3/src/camera/v4l2/SDL_camera_v4l2.c @@ -128,10 +128,11 @@ static SDL_CameraFrameResult V4L2_AcquireFrame(SDL_Camera *device, SDL_Surface * const io_method io = device->hidden->io; size_t size = device->hidden->buffers[0].length; struct v4l2_buffer buf; + ssize_t amount; switch (io) { case IO_METHOD_READ: - if (read(fd, device->hidden->buffers[0].start, size) == -1) { + if ((amount = read(fd, device->hidden->buffers[0].start, size)) == -1) { switch (errno) { case EAGAIN: return SDL_CAMERA_FRAME_SKIP; @@ -148,7 +149,11 @@ static SDL_CameraFrameResult V4L2_AcquireFrame(SDL_Camera *device, SDL_Surface * *timestampNS = SDL_GetTicksNS(); // oh well, close enough. frame->pixels = device->hidden->buffers[0].start; - frame->pitch = device->hidden->driver_pitch; + if (device->hidden->driver_pitch) { + frame->pitch = device->hidden->driver_pitch; + } else { + frame->pitch = (int)amount; + } break; case IO_METHOD_MMAP: @@ -178,7 +183,11 @@ static SDL_CameraFrameResult V4L2_AcquireFrame(SDL_Camera *device, SDL_Surface * } frame->pixels = device->hidden->buffers[buf.index].start; - frame->pitch = device->hidden->driver_pitch; + if (device->hidden->driver_pitch) { + frame->pitch = device->hidden->driver_pitch; + } else { + frame->pitch = buf.bytesused; + } device->hidden->buffers[buf.index].available = 1; *timestampNS = (((Uint64) buf.timestamp.tv_sec) * SDL_NS_PER_SECOND) + SDL_US_TO_NS(buf.timestamp.tv_usec); @@ -222,7 +231,11 @@ static SDL_CameraFrameResult V4L2_AcquireFrame(SDL_Camera *device, SDL_Surface * } frame->pixels = (void*)buf.m.userptr; - frame->pitch = device->hidden->driver_pitch; + if (device->hidden->driver_pitch) { + frame->pitch = device->hidden->driver_pitch; + } else { + frame->pitch = buf.bytesused; + } device->hidden->buffers[i].available = 1; *timestampNS = (((Uint64) buf.timestamp.tv_sec) * SDL_NS_PER_SECOND) + SDL_US_TO_NS(buf.timestamp.tv_usec); @@ -404,10 +417,15 @@ static void format_v4l2_to_sdl(Uint32 fmt, SDL_PixelFormat *format, SDL_Colorspa switch (fmt) { #define CASE(x, y, z) case x: *format = y; *colorspace = z; return CASE(V4L2_PIX_FMT_YUYV, SDL_PIXELFORMAT_YUY2, SDL_COLORSPACE_BT709_LIMITED); + CASE(V4L2_PIX_FMT_MJPEG, SDL_PIXELFORMAT_MJPG, SDL_COLORSPACE_SRGB); #undef CASE default: #if DEBUG_CAMERA - SDL_Log("CAMERA: Unknown format V4L2_PIX_FORMAT '%d'", fmt); + SDL_Log("CAMERA: Unknown format V4L2_PIX_FORMAT '%c%c%c%c' (0x%x)", + (char)(Uint8)(fmt >> 0), + (char)(Uint8)(fmt >> 8), + (char)(Uint8)(fmt >> 16), + (char)(Uint8)(fmt >> 24), fmt); #endif break; } @@ -420,10 +438,10 @@ static Uint32 format_sdl_to_v4l2(SDL_PixelFormat fmt) switch (fmt) { #define CASE(y, x) case x: return y CASE(V4L2_PIX_FMT_YUYV, SDL_PIXELFORMAT_YUY2); - CASE(V4L2_PIX_FMT_MJPEG, SDL_PIXELFORMAT_UNKNOWN); + CASE(V4L2_PIX_FMT_MJPEG, SDL_PIXELFORMAT_MJPG); #undef CASE default: - return true; + return 0; } } diff --git a/libs/SDL3/src/core/SDL_core_unsupported.c b/libs/SDL3/src/core/SDL_core_unsupported.c index 9a6b98f5..af963ed8 100644 --- a/libs/SDL3/src/core/SDL_core_unsupported.c +++ b/libs/SDL3/src/core/SDL_core_unsupported.c @@ -111,14 +111,14 @@ void SDL_SendAndroidBackButton(void) SDL_Unsupported(); } -SDL_DECLSPEC void *SDLCALL SDL_GetAndroidActivity(void); +SDL_DECLSPEC void * SDLCALL SDL_GetAndroidActivity(void); void *SDL_GetAndroidActivity(void) { SDL_Unsupported(); return NULL; } -SDL_DECLSPEC const char *SDLCALL SDL_GetAndroidCachePath(void); +SDL_DECLSPEC const char * SDLCALL SDL_GetAndroidCachePath(void); const char* SDL_GetAndroidCachePath(void) { SDL_Unsupported(); @@ -126,7 +126,7 @@ const char* SDL_GetAndroidCachePath(void) } -SDL_DECLSPEC const char *SDLCALL SDL_GetAndroidExternalStoragePath(void); +SDL_DECLSPEC const char * SDLCALL SDL_GetAndroidExternalStoragePath(void); const char* SDL_GetAndroidExternalStoragePath(void) { SDL_Unsupported(); @@ -139,14 +139,14 @@ Uint32 SDL_GetAndroidExternalStorageState(void) SDL_Unsupported(); return 0; } -SDL_DECLSPEC const char *SDLCALL SDL_GetAndroidInternalStoragePath(void); +SDL_DECLSPEC const char * SDLCALL SDL_GetAndroidInternalStoragePath(void); const char *SDL_GetAndroidInternalStoragePath(void) { SDL_Unsupported(); return NULL; } -SDL_DECLSPEC void *SDLCALL SDL_GetAndroidJNIEnv(void); +SDL_DECLSPEC void * SDLCALL SDL_GetAndroidJNIEnv(void); void *SDL_GetAndroidJNIEnv(void) { SDL_Unsupported(); @@ -171,7 +171,7 @@ bool SDL_SendAndroidMessage(Uint32 command, int param) return SDL_Unsupported(); } -SDL_DECLSPEC bool SDLCALL SDL_ShowAndroidToast(const char* message, int duration, int gravity, int xoffset, int yoffset); +SDL_DECLSPEC bool SDLCALL SDL_ShowAndroidToast(const char *message, int duration, int gravity, int xoffset, int yoffset); bool SDL_ShowAndroidToast(const char* message, int duration, int gravity, int xoffset, int yoffset) { (void)message; diff --git a/libs/SDL3/src/core/haiku/SDL_BApp.h b/libs/SDL3/src/core/haiku/SDL_BApp.h index b13b9e6d..cbd3e3a0 100644 --- a/libs/SDL3/src/core/haiku/SDL_BApp.h +++ b/libs/SDL3/src/core/haiku/SDL_BApp.h @@ -293,12 +293,9 @@ class SDL_BLooper : public BLooper void _HandleKey(BMessage *msg) { - SDL_Window *win; - int32 winID; int32 scancode; - bool down; + bool down; if ( - !_GetWinID(msg, &winID) || msg->FindInt32("key-scancode", &scancode) != B_OK || msg->FindBool("key-down", &down) != B_OK) { return; @@ -306,15 +303,17 @@ class SDL_BLooper : public BLooper SDL_SendKeyboardKey(0, SDL_DEFAULT_KEYBOARD_ID, scancode, HAIKU_GetScancodeFromBeKey(scancode), down); - win = GetSDLWindow(winID); - if (down && SDL_TextInputActive(win)) { - const int8 *keyUtf8; - ssize_t count; - if (msg->FindData("key-utf8", B_INT8_TYPE, (const void **)&keyUtf8, &count) == B_OK) { - char text[64]; - SDL_zeroa(text); - SDL_memcpy(text, keyUtf8, count); - SDL_SendKeyboardText(text); + if (down) { + SDL_Window *win = SDL_GetKeyboardFocus(); + if (win && SDL_TextInputActive(win)) { + const int8 *keyUtf8; + ssize_t count; + if (msg->FindData("key-utf8", B_INT8_TYPE, (const void **)&keyUtf8, &count) == B_OK) { + char text[64]; + SDL_zeroa(text); + SDL_memcpy(text, keyUtf8, count); + SDL_SendKeyboardText(text); + } } } } diff --git a/libs/SDL3/src/core/linux/SDL_dbus.c b/libs/SDL3/src/core/linux/SDL_dbus.c index e0ffea3c..9a2fc1ea 100644 --- a/libs/SDL3/src/core/linux/SDL_dbus.c +++ b/libs/SDL3/src/core/linux/SDL_dbus.c @@ -189,10 +189,16 @@ void SDL_DBus_Quit(void) if (dbus.shutdown) { dbus.shutdown(); } + + UnloadDBUSLibrary(); + } else { + /* Leaving libdbus loaded when skipping dbus_shutdown() avoids + * spurious leak warnings from LeakSanitizer on internal D-Bus + * allocations that would be freed by dbus_shutdown(). */ + dbus_handle = NULL; } SDL_zero(dbus); - UnloadDBUSLibrary(); if (inhibit_handle) { SDL_free(inhibit_handle); inhibit_handle = NULL; diff --git a/libs/SDL3/src/core/unix/SDL_poll.c b/libs/SDL3/src/core/unix/SDL_poll.c index 9440bff9..572ed5a6 100644 --- a/libs/SDL3/src/core/unix/SDL_poll.c +++ b/libs/SDL3/src/core/unix/SDL_poll.c @@ -54,7 +54,7 @@ int SDL_IOReady(int fd, int flags, Sint64 timeoutNS) } // FIXME: Add support for ppoll() for nanosecond precision if (timeoutNS > 0) { - timeoutMS = (int)SDL_NS_TO_MS(timeoutNS); + timeoutMS = (int)SDL_NS_TO_MS(timeoutNS + (SDL_NS_PER_MS - 1)); } else if (timeoutNS == 0) { timeoutMS = 0; } else { @@ -82,7 +82,7 @@ int SDL_IOReady(int fd, int flags, Sint64 timeoutNS) if (timeoutNS >= 0) { tv.tv_sec = (timeoutNS / SDL_NS_PER_SECOND); - tv.tv_usec = SDL_NS_TO_US(timeoutNS % SDL_NS_PER_SECOND); + tv.tv_usec = SDL_NS_TO_US((timeoutNS % SDL_NS_PER_SECOND) + (SDL_NS_PER_US - 1)); tvp = &tv; } diff --git a/libs/SDL3/src/core/windows/SDL_gameinput.c b/libs/SDL3/src/core/windows/SDL_gameinput.c new file mode 100644 index 00000000..9ac5912d --- /dev/null +++ b/libs/SDL3/src/core/windows/SDL_gameinput.c @@ -0,0 +1,98 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 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 HAVE_GAMEINPUT_H + +#include "SDL_windows.h" +#include "SDL_gameinput.h" + +#ifdef SDL_PLATFORM_WIN32 +#include +// {11BE2A7E-4254-445A-9C09-FFC40F006918} +DEFINE_GUID(SDL_IID_GameInput, 0x11BE2A7E, 0x4254, 0x445A, 0x9C, 0x09, 0xFF, 0xC4, 0x0F, 0x00, 0x69, 0x18); +#endif + +static SDL_SharedObject *g_hGameInputDLL; +static IGameInput *g_pGameInput; +static int g_nGameInputRefCount; + +bool SDL_InitGameInput(IGameInput **ppGameInput) +{ + if (g_nGameInputRefCount == 0) { + g_hGameInputDLL = SDL_LoadObject("gameinput.dll"); + if (!g_hGameInputDLL) { + return false; + } + + typedef HRESULT (WINAPI *GameInputCreate_t)(IGameInput * *gameInput); + GameInputCreate_t GameInputCreateFunc = (GameInputCreate_t)SDL_LoadFunction(g_hGameInputDLL, "GameInputCreate"); + if (!GameInputCreateFunc) { + SDL_UnloadObject(g_hGameInputDLL); + return false; + } + + IGameInput *pGameInput = NULL; + HRESULT hr = GameInputCreateFunc(&pGameInput); + if (FAILED(hr)) { + SDL_UnloadObject(g_hGameInputDLL); + return WIN_SetErrorFromHRESULT("GameInputCreate failed", hr); + } + +#ifdef SDL_PLATFORM_WIN32 + hr = IGameInput_QueryInterface(pGameInput, &SDL_IID_GameInput, (void **)&g_pGameInput); + IGameInput_Release(pGameInput); + if (FAILED(hr)) { + SDL_UnloadObject(g_hGameInputDLL); + return WIN_SetErrorFromHRESULT("GameInput QueryInterface failed", hr); + } +#else + // Assume that the version we get is compatible with the current SDK + // If that isn't the case, define the correct GUID for SDL_IID_GameInput above + g_pGameInput = pGameInput; +#endif + } + ++g_nGameInputRefCount; + + if (ppGameInput) { + *ppGameInput = g_pGameInput; + } + return true; +} + +void SDL_QuitGameInput(void) +{ + SDL_assert(g_nGameInputRefCount > 0); + + --g_nGameInputRefCount; + if (g_nGameInputRefCount == 0) { + if (g_pGameInput) { + IGameInput_Release(g_pGameInput); + g_pGameInput = NULL; + } + if (g_hGameInputDLL) { + SDL_UnloadObject(g_hGameInputDLL); + g_hGameInputDLL = NULL; + } + } +} + +#endif // HAVE_GAMEINPUT_H diff --git a/libs/SDL3/src/core/windows/SDL_gameinput.h b/libs/SDL3/src/core/windows/SDL_gameinput.h new file mode 100644 index 00000000..0022c0bd --- /dev/null +++ b/libs/SDL3/src/core/windows/SDL_gameinput.h @@ -0,0 +1,36 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 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" + +#ifndef SDL_gameinput_h_ +#define SDL_gameinput_h_ + +#ifdef HAVE_GAMEINPUT_H + +#define COBJMACROS +#include + +extern bool SDL_InitGameInput(IGameInput **ppGameInput); +extern void SDL_QuitGameInput(void); + +#endif // HAVE_GAMEINPUT_H + +#endif // SDL_gameinput_h_ diff --git a/libs/SDL3/src/core/windows/SDL_hid.c b/libs/SDL3/src/core/windows/SDL_hid.c index 98748154..87e87354 100644 --- a/libs/SDL3/src/core/windows/SDL_hid.c +++ b/libs/SDL3/src/core/windows/SDL_hid.c @@ -22,6 +22,7 @@ #include "SDL_hid.h" +HidD_GetAttributes_t SDL_HidD_GetAttributes; HidD_GetString_t SDL_HidD_GetManufacturerString; HidD_GetString_t SDL_HidD_GetProductString; HidP_GetCaps_t SDL_HidP_GetCaps; @@ -50,6 +51,7 @@ bool WIN_LoadHIDDLL(void) SDL_assert(s_HIDDLLRefCount == 0); s_HIDDLLRefCount = 1; + SDL_HidD_GetAttributes = (HidD_GetAttributes_t)GetProcAddress(s_pHIDDLL, "HidD_GetAttributes"); SDL_HidD_GetManufacturerString = (HidD_GetString_t)GetProcAddress(s_pHIDDLL, "HidD_GetManufacturerString"); SDL_HidD_GetProductString = (HidD_GetString_t)GetProcAddress(s_pHIDDLL, "HidD_GetProductString"); SDL_HidP_GetCaps = (HidP_GetCaps_t)GetProcAddress(s_pHIDDLL, "HidP_GetCaps"); diff --git a/libs/SDL3/src/core/windows/SDL_hid.h b/libs/SDL3/src/core/windows/SDL_hid.h index 8b20df11..46c22f24 100644 --- a/libs/SDL3/src/core/windows/SDL_hid.h +++ b/libs/SDL3/src/core/windows/SDL_hid.h @@ -191,6 +191,7 @@ typedef struct extern bool WIN_LoadHIDDLL(void); extern void WIN_UnloadHIDDLL(void); +typedef BOOLEAN (WINAPI *HidD_GetAttributes_t)(HANDLE HidDeviceObject, PHIDD_ATTRIBUTES Attributes); typedef BOOLEAN (WINAPI *HidD_GetString_t)(HANDLE HidDeviceObject, PVOID Buffer, ULONG BufferLength); typedef NTSTATUS (WINAPI *HidP_GetCaps_t)(PHIDP_PREPARSED_DATA PreparsedData, PHIDP_CAPS Capabilities); typedef NTSTATUS (WINAPI *HidP_GetButtonCaps_t)(HIDP_REPORT_TYPE ReportType, PHIDP_BUTTON_CAPS ButtonCaps, PUSHORT ButtonCapsLength, PHIDP_PREPARSED_DATA PreparsedData); @@ -198,6 +199,7 @@ typedef NTSTATUS (WINAPI *HidP_GetValueCaps_t)(HIDP_REPORT_TYPE ReportType, PHID typedef ULONG (WINAPI *HidP_MaxDataListLength_t)(HIDP_REPORT_TYPE ReportType, PHIDP_PREPARSED_DATA PreparsedData); typedef NTSTATUS (WINAPI *HidP_GetData_t)(HIDP_REPORT_TYPE ReportType, PHIDP_DATA DataList, PULONG DataLength, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength); +extern HidD_GetAttributes_t SDL_HidD_GetAttributes; extern HidD_GetString_t SDL_HidD_GetManufacturerString; extern HidD_GetString_t SDL_HidD_GetProductString; extern HidP_GetCaps_t SDL_HidP_GetCaps; diff --git a/libs/SDL3/src/core/windows/version.rc b/libs/SDL3/src/core/windows/version.rc index 83c5f637..cbe3a938 100644 --- a/libs/SDL3/src/core/windows/version.rc +++ b/libs/SDL3/src/core/windows/version.rc @@ -9,8 +9,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 3,2,0,0 - PRODUCTVERSION 3,2,0,0 + FILEVERSION 3,2,6,0 + PRODUCTVERSION 3,2,6,0 FILEFLAGSMASK 0x3fL FILEFLAGS 0x0L FILEOS 0x40004L @@ -23,12 +23,12 @@ BEGIN BEGIN VALUE "CompanyName", "\0" VALUE "FileDescription", "SDL\0" - VALUE "FileVersion", "3, 2, 0, 0\0" + VALUE "FileVersion", "3, 2, 6, 0\0" VALUE "InternalName", "SDL\0" VALUE "LegalCopyright", "Copyright (C) 2025 Sam Lantinga\0" VALUE "OriginalFilename", "SDL3.dll\0" VALUE "ProductName", "Simple DirectMedia Layer\0" - VALUE "ProductVersion", "3, 2, 0, 0\0" + VALUE "ProductVersion", "3, 2, 6, 0\0" END END BLOCK "VarFileInfo" diff --git a/libs/SDL3/src/dialog/unix/SDL_portaldialog.c b/libs/SDL3/src/dialog/unix/SDL_portaldialog.c index 1d068ff2..efecd124 100644 --- a/libs/SDL3/src/dialog/unix/SDL_portaldialog.c +++ b/libs/SDL3/src/dialog/unix/SDL_portaldialog.c @@ -497,7 +497,7 @@ bool SDL_Portal_detect(void) goto done; } - reply = dbus->connection_send_with_reply_and_block(dbus->session_conn, msg, DBUS_TIMEOUT_INFINITE, NULL); + reply = dbus->connection_send_with_reply_and_block(dbus->session_conn, msg, DBUS_TIMEOUT_USE_DEFAULT, NULL); dbus->message_unref(msg); if (!reply) { goto done; diff --git a/libs/SDL3/src/dynapi/SDL_dynapi.c b/libs/SDL3/src/dynapi/SDL_dynapi.c index f35f3e8b..a7b51af6 100644 --- a/libs/SDL3/src/dynapi/SDL_dynapi.c +++ b/libs/SDL3/src/dynapi/SDL_dynapi.c @@ -33,6 +33,9 @@ #ifdef HAVE_STDIO_H #include #endif +#ifdef HAVE_STDLIB_H +#include +#endif #include #define SDL_MAIN_NOIMPL // don't drag in header-only implementation of SDL_main @@ -42,6 +45,13 @@ // These headers have system specific definitions, so aren't included above #include +#if defined(WIN32) || defined(_WIN32) || defined(SDL_PLATFORM_CYGWIN) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif +#include +#endif + /* This is the version of the dynamic API. This doesn't match the SDL version and should not change until there's been a major revamp in API/ABI. So 2.0.5 adds functions over 2.0.4? This number doesn't change; @@ -309,6 +319,30 @@ static size_t SDLCALL SDL_IOprintf_LOGSDLCALLS(SDL_IOStream *context, SDL_PRINTF va_end(ap); return result; } +static bool SDLCALL SDL_RenderDebugTextFormat_LOGSDLCALLS(SDL_Renderer *renderer, float x, float y, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) +{ + char buf[128], *str = buf; + int result; + va_list ap; + SDL_Log_REAL("SDL3CALL SDL_RenderDebugTextFormat"); + va_start(ap, fmt); + result = jump_table.SDL_vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + if (result >= 0 && (size_t)result >= sizeof(buf)) { + str = NULL; + va_start(ap, fmt); + result = SDL_vasprintf_REAL(&str, fmt, ap); + va_end(ap); + } + bool retval = false; + if (result >= 0) { + retval = SDL_RenderDebugTextFormat_REAL(renderer, x, y, "%s", str); + } + if (str != buf) { + jump_table.SDL_free(str); + } + return retval; +} static void SDLCALL SDL_Log_LOGSDLCALLS(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) { va_list ap; @@ -414,10 +448,6 @@ Sint32 SDL_DYNAPI_entry(Uint32 apiver, void *table, Uint32 tablesize) // Obviously we can't use SDL_LoadObject() to load SDL. :) // Also obviously, we never close the loaded library. #if defined(WIN32) || defined(_WIN32) || defined(SDL_PLATFORM_CYGWIN) -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN 1 -#endif -#include static SDL_INLINE void *get_sdlapi_entry(const char *fname, const char *sym) { HMODULE lib = LoadLibraryA(fname); @@ -479,7 +509,16 @@ extern SDL_NORETURN void SDL_ExitProcess(int exitcode); static void SDL_InitDynamicAPILocked(void) { - const char *libname = SDL_getenv_unsafe_REAL(SDL_DYNAMIC_API_ENVVAR); + // this can't use SDL_getenv_unsafe_REAL, because it might allocate memory before the app can set their allocator. +#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) + // We've always used LoadLibraryA for this, so this has never worked with Unicode paths on Windows. Sorry. + char envbuf[512]; // overflows will just report as environment variable being unset, but LoadLibraryA has a MAX_PATH of 260 anyhow, apparently. + const DWORD rc = GetEnvironmentVariableA(SDL_DYNAMIC_API_ENVVAR, envbuf, (DWORD) sizeof (envbuf)); + char *libname = ((rc != 0) && (rc < sizeof (envbuf))) ? envbuf : NULL; +#else + char *libname = getenv(SDL_DYNAMIC_API_ENVVAR); +#endif + SDL_DYNAPI_ENTRYFN entry = NULL; // funcs from here by default. bool use_internal = true; diff --git a/libs/SDL3/src/dynapi/SDL_dynapi.sym b/libs/SDL3/src/dynapi/SDL_dynapi.sym index b4dcc383..73f34843 100644 --- a/libs/SDL3/src/dynapi/SDL_dynapi.sym +++ b/libs/SDL3/src/dynapi/SDL_dynapi.sym @@ -1233,6 +1233,7 @@ SDL3_0.0.0 { SDL_AudioStreamDevicePaused; SDL_ClickTrayEntry; SDL_UpdateTrays; + SDL_StretchSurface; # extra symbols go here (don't modify this line) local: *; }; diff --git a/libs/SDL3/src/dynapi/SDL_dynapi_overrides.h b/libs/SDL3/src/dynapi/SDL_dynapi_overrides.h index d90b6fd0..77fd553c 100644 --- a/libs/SDL3/src/dynapi/SDL_dynapi_overrides.h +++ b/libs/SDL3/src/dynapi/SDL_dynapi_overrides.h @@ -1258,3 +1258,4 @@ #define SDL_AudioStreamDevicePaused SDL_AudioStreamDevicePaused_REAL #define SDL_ClickTrayEntry SDL_ClickTrayEntry_REAL #define SDL_UpdateTrays SDL_UpdateTrays_REAL +#define SDL_StretchSurface SDL_StretchSurface_REAL diff --git a/libs/SDL3/src/dynapi/SDL_dynapi_procs.h b/libs/SDL3/src/dynapi/SDL_dynapi_procs.h index e57603d1..e86ac2a3 100644 --- a/libs/SDL3/src/dynapi/SDL_dynapi_procs.h +++ b/libs/SDL3/src/dynapi/SDL_dynapi_procs.h @@ -1266,3 +1266,4 @@ SDL_DYNAPI_PROC(SDL_ThreadState,SDL_GetThreadState,(SDL_Thread *a),(a),return) SDL_DYNAPI_PROC(bool,SDL_AudioStreamDevicePaused,(SDL_AudioStream *a),(a),return) SDL_DYNAPI_PROC(void,SDL_ClickTrayEntry,(SDL_TrayEntry *a),(a),) SDL_DYNAPI_PROC(void,SDL_UpdateTrays,(void),(),) +SDL_DYNAPI_PROC(bool,SDL_StretchSurface,(SDL_Surface *a,const SDL_Rect *b,SDL_Surface *c,const SDL_Rect *d,SDL_ScaleMode e),(a,b,c,d,e),return) diff --git a/libs/SDL3/src/events/SDL_clipboardevents.c b/libs/SDL3/src/events/SDL_clipboardevents.c index 96bfd041..d5cf8ad7 100644 --- a/libs/SDL3/src/events/SDL_clipboardevents.c +++ b/libs/SDL3/src/events/SDL_clipboardevents.c @@ -29,8 +29,17 @@ void SDL_SendClipboardUpdate(bool owner, char **mime_types, size_t num_mime_types) { if (!owner) { - // Clear our internal clipboard contents when external clipboard is set - SDL_CancelClipboardData(0); + /* Clear our internal clipboard contents when external clipboard is set. + * + * Wayland recursively sends a data offer to the client from which the clipboard data originated, + * and as the client can't determine the origin of the offer, the clipboard must not be cleared, + * or the original data may be destroyed. Cleanup will be done in the backend when an offer + * cancellation event arrives. + */ + if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "wayland") != 0) { + SDL_CancelClipboardData(0); + } + SDL_SaveClipboardMimeTypes((const char **)mime_types, num_mime_types); } diff --git a/libs/SDL3/src/events/SDL_events.c b/libs/SDL3/src/events/SDL_events.c index ca11afff..157f0180 100644 --- a/libs/SDL3/src/events/SDL_events.c +++ b/libs/SDL3/src/events/SDL_events.c @@ -23,6 +23,8 @@ // General event handling code for SDL #include "SDL_events_c.h" +#include "SDL_eventwatch_c.h" +#include "SDL_windowevents_c.h" #include "../SDL_hints_c.h" #include "../audio/SDL_audio_c.h" #include "../camera/SDL_camera_c.h" @@ -52,19 +54,53 @@ // Make sure the type in the SDL_Event aligns properly across the union SDL_COMPILE_TIME_ASSERT(SDL_Event_type, sizeof(Uint32) == sizeof(SDL_EventType)); -typedef struct SDL_EventWatcher -{ - SDL_EventFilter callback; - void *userdata; - bool removed; -} SDL_EventWatcher; +#define SDL2_SYSWMEVENT 0x201 -static SDL_Mutex *SDL_event_watchers_lock; -static SDL_EventWatcher SDL_EventOK; -static SDL_EventWatcher *SDL_event_watchers = NULL; -static int SDL_event_watchers_count = 0; -static bool SDL_event_watchers_dispatching = false; -static bool SDL_event_watchers_removed = false; +#ifdef SDL_VIDEO_DRIVER_WINDOWS +#include "../core/windows/SDL_windows.h" +#endif + +#ifdef SDL_VIDEO_DRIVER_X11 +#include +#endif + +typedef struct SDL2_version +{ + Uint8 major; + Uint8 minor; + Uint8 patch; +} SDL2_version; + +typedef enum +{ + SDL2_SYSWM_UNKNOWN +} SDL2_SYSWM_TYPE; + +typedef struct SDL2_SysWMmsg +{ + SDL2_version version; + SDL2_SYSWM_TYPE subsystem; + union + { +#ifdef SDL_VIDEO_DRIVER_WINDOWS + struct { + HWND hwnd; /**< The window for the message */ + UINT msg; /**< The type of message */ + WPARAM wParam; /**< WORD message parameter */ + LPARAM lParam; /**< LONG message parameter */ + } win; +#endif +#ifdef SDL_VIDEO_DRIVER_X11 + struct { + XEvent event; + } x11; +#endif + /* Can't have an empty union */ + int dummy; + } msg; +} SDL2_SysWMmsg; + +static SDL_EventWatchList SDL_event_watchers; static SDL_AtomicInt SDL_sentinel_pending; static Uint32 SDL_last_event_id = 0; @@ -214,6 +250,17 @@ static void SDL_LinkTemporaryMemoryToEvent(SDL_EventEntry *event, const void *me } } +static void SDL_TransferSysWMMemoryToEvent(SDL_EventEntry *event) +{ + SDL2_SysWMmsg **wmmsg = (SDL2_SysWMmsg **)((&event->event.common)+1); + SDL2_SysWMmsg *mem = SDL_AllocateTemporaryMemory(sizeof(*mem)); + if (mem) { + SDL_copyp(mem, *wmmsg); + *wmmsg = mem; + SDL_LinkTemporaryMemoryToEvent(event, mem); + } +} + // Transfer the event memory from the thread-local event memory list to the event static void SDL_TransferTemporaryMemoryToEvent(SDL_EventEntry *event) { @@ -238,6 +285,10 @@ static void SDL_TransferTemporaryMemoryToEvent(SDL_EventEntry *event) case SDL_EVENT_CLIPBOARD_UPDATE: SDL_LinkTemporaryMemoryToEvent(event, event->event.clipboard.mime_types); break; + case SDL2_SYSWMEVENT: + // We need to copy the stack pointer into temporary memory + SDL_TransferSysWMMemoryToEvent(event); + break; default: break; } @@ -847,7 +898,7 @@ void SDL_StopEventLoop(void) SDL_EventQ.active = false; if (report && SDL_atoi(report)) { - SDL_Log("SDL EVENT QUEUE: Maximum events in-flight: %d\n", + SDL_Log("SDL EVENT QUEUE: Maximum events in-flight: %d", SDL_EventQ.max_events_seen); } @@ -877,16 +928,8 @@ void SDL_StopEventLoop(void) SDL_disabled_events[i] = NULL; } - if (SDL_event_watchers_lock) { - SDL_DestroyMutex(SDL_event_watchers_lock); - SDL_event_watchers_lock = NULL; - } - if (SDL_event_watchers) { - SDL_free(SDL_event_watchers); - SDL_event_watchers = NULL; - SDL_event_watchers_count = 0; - } - SDL_zero(SDL_EventOK); + SDL_QuitEventWatchList(&SDL_event_watchers); + SDL_QuitWindowEventWatch(); SDL_Mutex *lock = NULL; if (SDL_EventQ.lock) { @@ -920,17 +963,19 @@ bool SDL_StartEventLoop(void) } SDL_LockMutex(SDL_EventQ.lock); - if (SDL_event_watchers_lock == NULL) { - SDL_event_watchers_lock = SDL_CreateMutex(); - if (SDL_event_watchers_lock == NULL) { - SDL_UnlockMutex(SDL_EventQ.lock); - return false; - } + if (!SDL_InitEventWatchList(&SDL_event_watchers)) { + SDL_UnlockMutex(SDL_EventQ.lock); + return false; } #endif // !SDL_THREADS_DISABLED + SDL_InitWindowEventWatch(); + SDL_EventQ.active = true; + +#ifndef SDL_THREADS_DISABLED SDL_UnlockMutex(SDL_EventQ.lock); +#endif return true; } @@ -1326,6 +1371,9 @@ bool SDL_RunOnMainThread(SDL_MainThreadCallback callback, void *userdata, bool w } SDL_UnlockMutex(SDL_main_callbacks_lock); + // If the main thread is waiting for events, wake it up + SDL_SendWakeupEvent(); + if (!wait_complete) { // Queued for execution, wait not requested return true; @@ -1674,44 +1722,11 @@ bool SDL_WaitEventTimeoutNS(SDL_Event *event, Sint64 timeoutNS) static bool SDL_CallEventWatchers(SDL_Event *event) { - if ((SDL_EventOK.callback || SDL_event_watchers_count > 0) && - (event->common.type != SDL_EVENT_POLL_SENTINEL)) { - SDL_LockMutex(SDL_event_watchers_lock); - { - if (SDL_EventOK.callback && !SDL_EventOK.callback(SDL_EventOK.userdata, event)) { - SDL_UnlockMutex(SDL_event_watchers_lock); - return false; - } - - if (SDL_event_watchers_count > 0) { - // Make sure we only dispatch the current watcher list - int i, event_watchers_count = SDL_event_watchers_count; - - SDL_event_watchers_dispatching = true; - for (i = 0; i < event_watchers_count; ++i) { - if (!SDL_event_watchers[i].removed) { - SDL_event_watchers[i].callback(SDL_event_watchers[i].userdata, event); - } - } - SDL_event_watchers_dispatching = false; - - if (SDL_event_watchers_removed) { - for (i = SDL_event_watchers_count; i--;) { - if (SDL_event_watchers[i].removed) { - --SDL_event_watchers_count; - if (i < SDL_event_watchers_count) { - SDL_memmove(&SDL_event_watchers[i], &SDL_event_watchers[i + 1], (SDL_event_watchers_count - i) * sizeof(SDL_event_watchers[i])); - } - } - } - SDL_event_watchers_removed = false; - } - } - } - SDL_UnlockMutex(SDL_event_watchers_lock); + if (event->common.type == SDL_EVENT_POLL_SENTINEL) { + return true; } - return true; + return SDL_DispatchEventWatchList(&SDL_event_watchers, event); } bool SDL_PushEvent(SDL_Event *event) @@ -1735,11 +1750,11 @@ bool SDL_PushEvent(SDL_Event *event) void SDL_SetEventFilter(SDL_EventFilter filter, void *userdata) { SDL_EventEntry *event, *next; - SDL_LockMutex(SDL_event_watchers_lock); + SDL_LockMutex(SDL_event_watchers.lock); { // Set filter and discard pending events - SDL_EventOK.callback = filter; - SDL_EventOK.userdata = userdata; + SDL_event_watchers.filter.callback = filter; + SDL_event_watchers.filter.userdata = userdata; if (filter) { // Cut all events not accepted by the filter SDL_LockMutex(SDL_EventQ.lock); @@ -1754,18 +1769,18 @@ void SDL_SetEventFilter(SDL_EventFilter filter, void *userdata) SDL_UnlockMutex(SDL_EventQ.lock); } } - SDL_UnlockMutex(SDL_event_watchers_lock); + SDL_UnlockMutex(SDL_event_watchers.lock); } bool SDL_GetEventFilter(SDL_EventFilter *filter, void **userdata) { SDL_EventWatcher event_ok; - SDL_LockMutex(SDL_event_watchers_lock); + SDL_LockMutex(SDL_event_watchers.lock); { - event_ok = SDL_EventOK; + event_ok = SDL_event_watchers.filter; } - SDL_UnlockMutex(SDL_event_watchers_lock); + SDL_UnlockMutex(SDL_event_watchers.lock); if (filter) { *filter = event_ok.callback; @@ -1778,53 +1793,12 @@ bool SDL_GetEventFilter(SDL_EventFilter *filter, void **userdata) bool SDL_AddEventWatch(SDL_EventFilter filter, void *userdata) { - bool result = true; - - SDL_LockMutex(SDL_event_watchers_lock); - { - SDL_EventWatcher *event_watchers; - - event_watchers = (SDL_EventWatcher *)SDL_realloc(SDL_event_watchers, (SDL_event_watchers_count + 1) * sizeof(*event_watchers)); - if (event_watchers) { - SDL_EventWatcher *watcher; - - SDL_event_watchers = event_watchers; - watcher = &SDL_event_watchers[SDL_event_watchers_count]; - watcher->callback = filter; - watcher->userdata = userdata; - watcher->removed = false; - ++SDL_event_watchers_count; - } else { - result = false; - } - } - SDL_UnlockMutex(SDL_event_watchers_lock); - - return result; + return SDL_AddEventWatchList(&SDL_event_watchers, filter, userdata); } void SDL_RemoveEventWatch(SDL_EventFilter filter, void *userdata) { - SDL_LockMutex(SDL_event_watchers_lock); - { - int i; - - for (i = 0; i < SDL_event_watchers_count; ++i) { - if (SDL_event_watchers[i].callback == filter && SDL_event_watchers[i].userdata == userdata) { - if (SDL_event_watchers_dispatching) { - SDL_event_watchers[i].removed = true; - SDL_event_watchers_removed = true; - } else { - --SDL_event_watchers_count; - if (i < SDL_event_watchers_count) { - SDL_memmove(&SDL_event_watchers[i], &SDL_event_watchers[i + 1], (SDL_event_watchers_count - i) * sizeof(SDL_event_watchers[i])); - } - } - break; - } - } - } - SDL_UnlockMutex(SDL_event_watchers_lock); + SDL_RemoveEventWatchList(&SDL_event_watchers, filter, userdata); } void SDL_FilterEvents(SDL_EventFilter filter, void *userdata) diff --git a/libs/SDL3/src/events/SDL_eventwatch.c b/libs/SDL3/src/events/SDL_eventwatch.c new file mode 100644 index 00000000..08e7248c --- /dev/null +++ b/libs/SDL3/src/events/SDL_eventwatch.c @@ -0,0 +1,143 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 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" + +#include "SDL_eventwatch_c.h" + + +bool SDL_InitEventWatchList(SDL_EventWatchList *list) +{ + if (list->lock == NULL) { + list->lock = SDL_CreateMutex(); + if (list->lock == NULL) { + return false; + } + } + return true; +} + +void SDL_QuitEventWatchList(SDL_EventWatchList *list) +{ + if (list->lock) { + SDL_DestroyMutex(list->lock); + list->lock = NULL; + } + if (list->watchers) { + SDL_free(list->watchers); + list->watchers = NULL; + list->count = 0; + } + SDL_zero(list->filter); +} + +bool SDL_DispatchEventWatchList(SDL_EventWatchList *list, SDL_Event *event) +{ + SDL_EventWatcher *filter = &list->filter; + + if (!filter->callback && list->count == 0) { + return true; + } + + SDL_LockMutex(list->lock); + { + // Make sure we only dispatch the current watcher list + int i, count = list->count; + + if (filter->callback && !filter->callback(filter->userdata, event)) { + SDL_UnlockMutex(list->lock); + return false; + } + + list->dispatching = true; + for (i = 0; i < count; ++i) { + if (!list->watchers[i].removed) { + list->watchers[i].callback(list->watchers[i].userdata, event); + } + } + list->dispatching = false; + + if (list->removed) { + for (i = list->count; i--;) { + if (list->watchers[i].removed) { + --list->count; + if (i < list->count) { + SDL_memmove(&list->watchers[i], &list->watchers[i + 1], (list->count - i) * sizeof(list->watchers[i])); + } + } + } + list->removed = false; + } + } + SDL_UnlockMutex(list->lock); + + return true; +} + +bool SDL_AddEventWatchList(SDL_EventWatchList *list, SDL_EventFilter filter, void *userdata) +{ + bool result = true; + + SDL_LockMutex(list->lock); + { + SDL_EventWatcher *watchers; + + watchers = (SDL_EventWatcher *)SDL_realloc(list->watchers, (list->count + 1) * sizeof(*watchers)); + if (watchers) { + SDL_EventWatcher *watcher; + + list->watchers = watchers; + watcher = &list->watchers[list->count]; + watcher->callback = filter; + watcher->userdata = userdata; + watcher->removed = false; + ++list->count; + } else { + result = false; + } + } + SDL_UnlockMutex(list->lock); + + return result; +} + +void SDL_RemoveEventWatchList(SDL_EventWatchList *list, SDL_EventFilter filter, void *userdata) +{ + SDL_LockMutex(list->lock); + { + int i; + + for (i = 0; i < list->count; ++i) { + if (list->watchers[i].callback == filter && list->watchers[i].userdata == userdata) { + if (list->dispatching) { + list->watchers[i].removed = true; + list->removed = true; + } else { + --list->count; + if (i < list->count) { + SDL_memmove(&list->watchers[i], &list->watchers[i + 1], (list->count - i) * sizeof(list->watchers[i])); + } + } + break; + } + } + } + SDL_UnlockMutex(list->lock); +} diff --git a/libs/SDL3/src/events/SDL_eventwatch_c.h b/libs/SDL3/src/events/SDL_eventwatch_c.h new file mode 100644 index 00000000..c9aea38c --- /dev/null +++ b/libs/SDL3/src/events/SDL_eventwatch_c.h @@ -0,0 +1,45 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 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" + +typedef struct SDL_EventWatcher +{ + SDL_EventFilter callback; + void *userdata; + bool removed; +} SDL_EventWatcher; + +typedef struct SDL_EventWatchList +{ + SDL_Mutex *lock; + SDL_EventWatcher filter; + SDL_EventWatcher *watchers; + int count; + bool dispatching; + bool removed; +} SDL_EventWatchList; + + +extern bool SDL_InitEventWatchList(SDL_EventWatchList *list); +extern void SDL_QuitEventWatchList(SDL_EventWatchList *list); +extern bool SDL_DispatchEventWatchList(SDL_EventWatchList *list, SDL_Event *event); +extern bool SDL_AddEventWatchList(SDL_EventWatchList *list, SDL_EventFilter filter, void *userdata); +extern void SDL_RemoveEventWatchList(SDL_EventWatchList *list, SDL_EventFilter filter, void *userdata); diff --git a/libs/SDL3/src/events/SDL_keyboard.c b/libs/SDL3/src/events/SDL_keyboard.c index e4664fba..066c6e6a 100644 --- a/libs/SDL3/src/events/SDL_keyboard.c +++ b/libs/SDL3/src/events/SDL_keyboard.c @@ -220,7 +220,7 @@ void SDL_ResetKeyboard(void) int scancode; #ifdef DEBUG_KEYBOARD - SDL_Log("Resetting keyboard\n"); + SDL_Log("Resetting keyboard"); #endif for (scancode = SDL_SCANCODE_UNKNOWN; scancode < SDL_SCANCODE_COUNT; ++scancode) { if (keyboard->keystate[scancode]) { @@ -517,7 +517,7 @@ static bool SDL_SendKeyboardKeyInternal(Uint64 timestamp, Uint32 flags, SDL_Keyb const Uint8 source = flags & KEYBOARD_SOURCE_MASK; #ifdef DEBUG_KEYBOARD - SDL_Log("The '%s' key has been %s\n", SDL_GetScancodeName(scancode), down ? "pressed" : "released"); + SDL_Log("The '%s' key has been %s", SDL_GetScancodeName(scancode), down ? "pressed" : "released"); #endif // Figure out what type of event this is diff --git a/libs/SDL3/src/events/SDL_keymap.c b/libs/SDL3/src/events/SDL_keymap.c index 5c3f784c..bd087860 100644 --- a/libs/SDL3/src/events/SDL_keymap.c +++ b/libs/SDL3/src/events/SDL_keymap.c @@ -39,8 +39,8 @@ SDL_Keymap *SDL_CreateKeymap(void) return NULL; } - keymap->scancode_to_keycode = SDL_CreateHashTable(NULL, 64, SDL_HashID, SDL_KeyMatchID, NULL, false, false); - keymap->keycode_to_scancode = SDL_CreateHashTable(NULL, 64, SDL_HashID, SDL_KeyMatchID, NULL, false, false); + keymap->scancode_to_keycode = SDL_CreateHashTable(256, false, SDL_HashID, SDL_KeyMatchID, NULL, NULL); + keymap->keycode_to_scancode = SDL_CreateHashTable(256, false, SDL_HashID, SDL_KeyMatchID, NULL, NULL); if (!keymap->scancode_to_keycode || !keymap->keycode_to_scancode) { SDL_DestroyKeymap(keymap); return NULL; @@ -72,27 +72,39 @@ void SDL_SetKeymapEntry(SDL_Keymap *keymap, SDL_Scancode scancode, SDL_Keymod mo return; } - if (keycode == SDL_GetKeymapKeycode(keymap, scancode, modstate)) { - return; - } - - Uint32 key = ((Uint32)NormalizeModifierStateForKeymap(modstate) << 16) | scancode; + modstate = NormalizeModifierStateForKeymap(modstate); + Uint32 key = ((Uint32)modstate << 16) | scancode; const void *value; if (SDL_FindInHashTable(keymap->scancode_to_keycode, (void *)(uintptr_t)key, &value)) { - // Changing the mapping, need to remove the existing entry from the keymap - SDL_RemoveFromHashTable(keymap->scancode_to_keycode, (void *)(uintptr_t)key); - SDL_RemoveFromHashTable(keymap->keycode_to_scancode, value); + const SDL_Keycode existing_keycode = (SDL_Keycode)(uintptr_t)value; + if (existing_keycode == keycode) { + // We already have this mapping + return; + } + // InsertIntoHashTable will replace the existing entry in the keymap atomically. } + SDL_InsertIntoHashTable(keymap->scancode_to_keycode, (void *)(uintptr_t)key, (void *)(uintptr_t)keycode, true); - SDL_InsertIntoHashTable(keymap->scancode_to_keycode, (void *)(uintptr_t)key, (void *)(uintptr_t)keycode); - SDL_InsertIntoHashTable(keymap->keycode_to_scancode, (void *)(uintptr_t)keycode, (void *)(uintptr_t)key); + bool update_keycode = true; + if (SDL_FindInHashTable(keymap->keycode_to_scancode, (void *)(uintptr_t)keycode, &value)) { + const Uint32 existing_value = (Uint32)(uintptr_t)value; + const SDL_Keymod existing_modstate = (SDL_Keymod)(existing_value >> 16); + + // Keep the simplest combination of scancode and modifiers to generate this keycode + if (existing_modstate <= modstate) { + update_keycode = false; + } + } + if (update_keycode) { + SDL_InsertIntoHashTable(keymap->keycode_to_scancode, (void *)(uintptr_t)keycode, (void *)(uintptr_t)key, true); + } } SDL_Keycode SDL_GetKeymapKeycode(SDL_Keymap *keymap, SDL_Scancode scancode, SDL_Keymod modstate) { SDL_Keycode keycode; - Uint32 key = ((Uint32)NormalizeModifierStateForKeymap(modstate) << 16) | scancode; + const Uint32 key = ((Uint32)NormalizeModifierStateForKeymap(modstate) << 16) | scancode; const void *value; if (keymap && SDL_FindInHashTable(keymap->scancode_to_keycode, (void *)(uintptr_t)key, &value)) { keycode = (SDL_Keycode)(uintptr_t)value; @@ -761,7 +773,7 @@ static const char *SDL_scancode_names[SDL_SCANCODE_COUNT] = /* 97 */ "Keypad 9", /* 98 */ "Keypad 0", /* 99 */ "Keypad .", - /* 100 */ NULL, + /* 100 */ "NonUSBackslash", /* 101 */ "Application", /* 102 */ "Power", /* 103 */ "Keypad =", @@ -796,24 +808,24 @@ static const char *SDL_scancode_names[SDL_SCANCODE_COUNT] = /* 132 */ NULL, /* 133 */ "Keypad ,", /* 134 */ "Keypad = (AS400)", - /* 135 */ NULL, - /* 136 */ NULL, - /* 137 */ NULL, - /* 138 */ NULL, - /* 139 */ NULL, - /* 140 */ NULL, - /* 141 */ NULL, - /* 142 */ NULL, - /* 143 */ NULL, - /* 144 */ NULL, - /* 145 */ NULL, - /* 146 */ NULL, - /* 147 */ NULL, - /* 148 */ NULL, - /* 149 */ NULL, - /* 150 */ NULL, - /* 151 */ NULL, - /* 152 */ NULL, + /* 135 */ "International 1", + /* 136 */ "International 2", + /* 137 */ "International 3", + /* 138 */ "International 4", + /* 139 */ "International 5", + /* 140 */ "International 6", + /* 141 */ "International 7", + /* 142 */ "International 8", + /* 143 */ "International 9", + /* 144 */ "Language 1", + /* 145 */ "Language 2", + /* 146 */ "Language 3", + /* 147 */ "Language 4", + /* 148 */ "Language 5", + /* 149 */ "Language 6", + /* 150 */ "Language 7", + /* 151 */ "Language 8", + /* 152 */ "Language 9", /* 153 */ "AltErase", /* 154 */ "SysReq", /* 155 */ "Cancel", diff --git a/libs/SDL3/src/events/SDL_mouse.c b/libs/SDL3/src/events/SDL_mouse.c index df892715..2ea5995d 100644 --- a/libs/SDL3/src/events/SDL_mouse.c +++ b/libs/SDL3/src/events/SDL_mouse.c @@ -484,7 +484,7 @@ SDL_SystemCursor SDL_GetDefaultSystemCursor(void) const char *value = SDL_GetHint(SDL_HINT_MOUSE_DEFAULT_SYSTEM_CURSOR); if (value) { int index = SDL_atoi(value); - if (0 <= index && index < (int)SDL_SYSTEM_CURSOR_COUNT) { + if (0 <= index && index < SDL_SYSTEM_CURSOR_COUNT) { id = (SDL_SystemCursor)index; } } @@ -605,7 +605,7 @@ static bool SDL_UpdateMouseFocus(SDL_Window *window, float x, float y, Uint32 bu if (!inWindow) { if (window == mouse->focus) { #ifdef DEBUG_MOUSE - SDL_Log("Mouse left window, synthesizing move & focus lost event\n"); + SDL_Log("Mouse left window, synthesizing move & focus lost event"); #endif if (send_mouse_motion) { SDL_PrivateSendMouseMotion(0, window, SDL_GLOBAL_MOUSE_ID, false, x, y); @@ -617,7 +617,7 @@ static bool SDL_UpdateMouseFocus(SDL_Window *window, float x, float y, Uint32 bu if (window != mouse->focus) { #ifdef DEBUG_MOUSE - SDL_Log("Mouse entered window, synthesizing focus gain & move event\n"); + SDL_Log("Mouse entered window, synthesizing focus gain & move event"); #endif SDL_SetMouseFocus(window); if (send_mouse_motion) { @@ -631,7 +631,7 @@ void SDL_SendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouse { if (window && !relative) { SDL_Mouse *mouse = SDL_GetMouse(); - if (!SDL_UpdateMouseFocus(window, x, y, SDL_GetMouseButtonState(mouse, mouseID, true), (mouseID != SDL_TOUCH_MOUSEID))) { + if (!SDL_UpdateMouseFocus(window, x, y, SDL_GetMouseButtonState(mouse, mouseID, true), (mouseID != SDL_TOUCH_MOUSEID && mouseID != SDL_PEN_MOUSEID))) { return; } } @@ -687,14 +687,9 @@ static void SDL_PrivateSendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL float yrel = 0.0f; bool window_is_relative = mouse->focus && (mouse->focus->flags & SDL_WINDOW_MOUSE_RELATIVE_MODE); - if ((!mouse->relative_mode || mouse->warp_emulation_active) && mouseID != SDL_TOUCH_MOUSEID) { - // We're not in relative mode, so all mouse events are global mouse events - mouseID = SDL_GLOBAL_MOUSE_ID; - } - // SDL_HINT_MOUSE_TOUCH_EVENTS: controlling whether mouse events should generate synthetic touch events if (mouse->mouse_touch_events) { - if (mouseID != SDL_TOUCH_MOUSEID && !relative && track_mouse_down) { + if (mouseID != SDL_TOUCH_MOUSEID && mouseID != SDL_PEN_MOUSEID && !relative && track_mouse_down) { if (window) { float normalized_x = x / (float)window->w; float normalized_y = y / (float)window->h; @@ -740,7 +735,7 @@ static void SDL_PrivateSendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL if (mouse->has_position && xrel == 0.0f && yrel == 0.0f) { // Drop events that don't change state #ifdef DEBUG_MOUSE - SDL_Log("Mouse event didn't change state - dropped!\n"); + SDL_Log("Mouse event didn't change state - dropped!"); #endif return; } @@ -753,10 +748,8 @@ static void SDL_PrivateSendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL // modify internal state { - if (relative) { - mouse->x_accu += xrel; - mouse->y_accu += yrel; - } + mouse->x_accu += xrel; + mouse->y_accu += yrel; if (relative && mouse->has_position) { mouse->x += xrel; @@ -784,6 +777,11 @@ static void SDL_PrivateSendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL // Post the event, if desired if (SDL_EventEnabled(SDL_EVENT_MOUSE_MOTION)) { + if ((!mouse->relative_mode || mouse->warp_emulation_active) && mouseID != SDL_TOUCH_MOUSEID && mouseID != SDL_PEN_MOUSEID) { + // We're not in relative mode, so all mouse events are global mouse events + mouseID = SDL_GLOBAL_MOUSE_ID; + } + if (!relative && window_is_relative) { if (!mouse->relative_mode_warp_motion) { return; @@ -791,6 +789,7 @@ static void SDL_PrivateSendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL xrel = 0.0f; yrel = 0.0f; } + SDL_Event event; event.type = SDL_EVENT_MOUSE_MOTION; event.common.timestamp = timestamp; @@ -873,11 +872,6 @@ static void SDL_PrivateSendMouseButton(Uint64 timestamp, SDL_Window *window, SDL Uint32 buttonstate; SDL_MouseInputSource *source; - if (!mouse->relative_mode && mouseID != SDL_TOUCH_MOUSEID) { - // We're not in relative mode, so all mouse events are global mouse events - mouseID = SDL_GLOBAL_MOUSE_ID; - } - source = GetMouseInputSource(mouse, mouseID, down, button); if (!source) { return; @@ -886,7 +880,7 @@ static void SDL_PrivateSendMouseButton(Uint64 timestamp, SDL_Window *window, SDL // SDL_HINT_MOUSE_TOUCH_EVENTS: controlling whether mouse events should generate synthetic touch events if (mouse->mouse_touch_events) { - if (mouseID != SDL_TOUCH_MOUSEID && button == SDL_BUTTON_LEFT) { + if (mouseID != SDL_TOUCH_MOUSEID && mouseID != SDL_PEN_MOUSEID && button == SDL_BUTTON_LEFT) { if (down) { track_mouse_down = true; } else { @@ -954,11 +948,18 @@ static void SDL_PrivateSendMouseButton(Uint64 timestamp, SDL_Window *window, SDL // Post the event, if desired if (SDL_EventEnabled(type)) { + if ((!mouse->relative_mode || mouse->warp_emulation_active) && mouseID != SDL_TOUCH_MOUSEID && mouseID != SDL_PEN_MOUSEID) { + // We're not in relative mode, so all mouse events are global mouse events + mouseID = SDL_GLOBAL_MOUSE_ID; + } else { + mouseID = source->mouseID; + } + SDL_Event event; event.type = type; event.common.timestamp = timestamp; event.button.windowID = mouse->focus ? mouse->focus->id : 0; - event.button.which = source->mouseID; + event.button.which = mouseID; event.button.down = down; event.button.button = button; event.button.clicks = (Uint8)SDL_min(clicks, 255); @@ -1001,13 +1002,13 @@ void SDL_SendMouseWheel(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseI return; } - if (!mouse->relative_mode || mouse->warp_emulation_active) { - // We're not in relative mode, so all mouse events are global mouse events - mouseID = SDL_GLOBAL_MOUSE_ID; - } - // Post the event, if desired if (SDL_EventEnabled(SDL_EVENT_MOUSE_WHEEL)) { + if (!mouse->relative_mode || mouse->warp_emulation_active) { + // We're not in relative mode, so all mouse events are global mouse events + mouseID = SDL_GLOBAL_MOUSE_ID; + } + SDL_Event event; event.type = SDL_EVENT_MOUSE_WHEEL; event.common.timestamp = timestamp; @@ -1480,6 +1481,11 @@ SDL_Cursor *SDL_CreateColorCursor(SDL_Surface *surface, int hot_x, int hot_y) return NULL; } + // Allow specifying the hot spot via properties on the surface + SDL_PropertiesID props = SDL_GetSurfaceProperties(surface); + hot_x = (int)SDL_GetNumberProperty(props, SDL_PROP_SURFACE_HOTSPOT_X_NUMBER, hot_x); + hot_y = (int)SDL_GetNumberProperty(props, SDL_PROP_SURFACE_HOTSPOT_Y_NUMBER, hot_y); + // Sanity check the hot spot if ((hot_x < 0) || (hot_y < 0) || (hot_x >= surface->w) || (hot_y >= surface->h)) { diff --git a/libs/SDL3/src/events/SDL_pen.c b/libs/SDL3/src/events/SDL_pen.c index afc2ea03..1ef7062a 100644 --- a/libs/SDL3/src/events/SDL_pen.c +++ b/libs/SDL3/src/events/SDL_pen.c @@ -109,9 +109,14 @@ bool SDL_InitPen(void) void SDL_QuitPen(void) { SDL_DestroyRWLock(pen_device_rwlock); - pen_device_rwlock = 0; - SDL_free(pen_devices); - pen_devices = NULL; + pen_device_rwlock = NULL; + if (pen_devices) { + for (int i = pen_device_count; i--; ) { + SDL_free(pen_devices[i].name); + } + SDL_free(pen_devices); + pen_devices = NULL; + } pen_device_count = 0; pen_touching = 0; } @@ -341,7 +346,7 @@ void SDL_SendPenTouch(Uint64 timestamp, SDL_PenID instance_id, SDL_Window *windo if (eraser && ((input_state & SDL_PEN_INPUT_ERASER_TIP) == 0)) { input_state |= SDL_PEN_INPUT_ERASER_TIP; send_event = true; - } else if (!down && (input_state & SDL_PEN_INPUT_ERASER_TIP)) { + } else if (!eraser && (input_state & SDL_PEN_INPUT_ERASER_TIP)) { input_state &= ~SDL_PEN_INPUT_ERASER_TIP; send_event = true; } diff --git a/libs/SDL3/src/events/SDL_windowevents.c b/libs/SDL3/src/events/SDL_windowevents.c index 2258ce79..e20cd3ab 100644 --- a/libs/SDL3/src/events/SDL_windowevents.c +++ b/libs/SDL3/src/events/SDL_windowevents.c @@ -23,9 +23,39 @@ // Window event handling code for SDL #include "SDL_events_c.h" +#include "SDL_eventwatch_c.h" #include "SDL_mouse_c.h" #include "../tray/SDL_tray_utils.h" + +#define NUM_WINDOW_EVENT_WATCH_PRIORITIES (SDL_WINDOW_EVENT_WATCH_NORMAL + 1) + +static SDL_EventWatchList SDL_window_event_watchers[NUM_WINDOW_EVENT_WATCH_PRIORITIES]; + +void SDL_InitWindowEventWatch(void) +{ + for (int i = 0; i < SDL_arraysize(SDL_window_event_watchers); ++i) { + SDL_InitEventWatchList(&SDL_window_event_watchers[i]); + } +} + +void SDL_QuitWindowEventWatch(void) +{ + for (int i = 0; i < SDL_arraysize(SDL_window_event_watchers); ++i) { + SDL_QuitEventWatchList(&SDL_window_event_watchers[i]); + } +} + +void SDL_AddWindowEventWatch(SDL_WindowEventWatchPriority priority, SDL_EventFilter filter, void *userdata) +{ + SDL_AddEventWatchList(&SDL_window_event_watchers[priority], filter, userdata); +} + +void SDL_RemoveWindowEventWatch(SDL_WindowEventWatchPriority priority, SDL_EventFilter filter, void *userdata) +{ + SDL_RemoveEventWatchList(&SDL_window_event_watchers[priority], filter, userdata); +} + static bool SDLCALL RemoveSupercededWindowEvents(void *userdata, SDL_Event *event) { SDL_Event *new_event = (SDL_Event *)userdata; @@ -183,14 +213,17 @@ bool SDL_SendWindowEvent(SDL_Window *window, SDL_EventType windowevent, int data } // Post the event, if desired - if (SDL_EventEnabled(windowevent)) { - SDL_Event event; - event.type = windowevent; - event.common.timestamp = 0; - event.window.data1 = data1; - event.window.data2 = data2; - event.window.windowID = window->id; + SDL_Event event; + event.type = windowevent; + event.common.timestamp = 0; + event.window.data1 = data1; + event.window.data2 = data2; + event.window.windowID = window->id; + SDL_DispatchEventWatchList(&SDL_window_event_watchers[SDL_WINDOW_EVENT_WATCH_EARLY], &event); + SDL_DispatchEventWatchList(&SDL_window_event_watchers[SDL_WINDOW_EVENT_WATCH_NORMAL], &event); + + if (SDL_EventEnabled(windowevent)) { // Fixes queue overflow with move/resize events that aren't processed if (windowevent == SDL_EVENT_WINDOW_MOVED || windowevent == SDL_EVENT_WINDOW_RESIZED || diff --git a/libs/SDL3/src/events/SDL_windowevents_c.h b/libs/SDL3/src/events/SDL_windowevents_c.h index b7f0681e..72043054 100644 --- a/libs/SDL3/src/events/SDL_windowevents_c.h +++ b/libs/SDL3/src/events/SDL_windowevents_c.h @@ -23,6 +23,17 @@ #ifndef SDL_windowevents_c_h_ #define SDL_windowevents_c_h_ +typedef enum +{ + SDL_WINDOW_EVENT_WATCH_EARLY, + SDL_WINDOW_EVENT_WATCH_NORMAL +} SDL_WindowEventWatchPriority; + +extern void SDL_InitWindowEventWatch(void); +extern void SDL_QuitWindowEventWatch(void); +extern void SDL_AddWindowEventWatch(SDL_WindowEventWatchPriority priority, SDL_EventFilter filter, void *userdata); +extern void SDL_RemoveWindowEventWatch(SDL_WindowEventWatchPriority priority, SDL_EventFilter filter, void *userdata); + extern bool SDL_SendWindowEvent(SDL_Window *window, SDL_EventType windowevent, int data1, int data2); #endif // SDL_windowevents_c_h_ diff --git a/libs/SDL3/src/events/scancodes_linux.h b/libs/SDL3/src/events/scancodes_linux.h index fc26e494..2deeb9af 100644 --- a/libs/SDL3/src/events/scancodes_linux.h +++ b/libs/SDL3/src/events/scancodes_linux.h @@ -169,7 +169,7 @@ static SDL_Scancode const linux_scancode_table[] = { /* 140, 0x08c */ SDL_SCANCODE_UNKNOWN, // KEY_CALC /* 141, 0x08d */ SDL_SCANCODE_UNKNOWN, // KEY_SETUP /* 142, 0x08e */ SDL_SCANCODE_SLEEP, // KEY_SLEEP - /* 143, 0x08f */ SDL_SCANCODE_UNKNOWN, // KEY_WAKEUP + /* 143, 0x08f */ SDL_SCANCODE_WAKE, // KEY_WAKEUP /* 144, 0x090 */ SDL_SCANCODE_UNKNOWN, // KEY_FILE /* 145, 0x091 */ SDL_SCANCODE_UNKNOWN, // KEY_SENDFILE /* 146, 0x092 */ SDL_SCANCODE_UNKNOWN, // KEY_DELETEFILE @@ -282,7 +282,6 @@ static SDL_Scancode const linux_scancode_table[] = { /* 253, 0x0fd */ SDL_SCANCODE_UNKNOWN, /* 254, 0x0fe */ SDL_SCANCODE_UNKNOWN, /* 255, 0x0ff */ SDL_SCANCODE_UNKNOWN, -#if 0 // We don't have any mapped scancodes after this point (yet) /* 256, 0x100 */ SDL_SCANCODE_UNKNOWN, /* 257, 0x101 */ SDL_SCANCODE_UNKNOWN, /* 258, 0x102 */ SDL_SCANCODE_UNKNOWN, @@ -380,9 +379,9 @@ static SDL_Scancode const linux_scancode_table[] = { /* 350, 0x15e */ SDL_SCANCODE_UNKNOWN, /* 351, 0x15f */ SDL_SCANCODE_UNKNOWN, /* 352, 0x160 */ SDL_SCANCODE_UNKNOWN, // KEY_OK - /* 353, 0x161 */ SDL_SCANCODE_UNKNOWN, // KEY_SELECT + /* 353, 0x161 */ SDL_SCANCODE_SELECT, // KEY_SELECT /* 354, 0x162 */ SDL_SCANCODE_UNKNOWN, // KEY_GOTO - /* 355, 0x163 */ SDL_SCANCODE_UNKNOWN, // KEY_CLEAR + /* 355, 0x163 */ SDL_SCANCODE_CLEAR, // KEY_CLEAR /* 356, 0x164 */ SDL_SCANCODE_UNKNOWN, // KEY_POWER2 /* 357, 0x165 */ SDL_SCANCODE_UNKNOWN, // KEY_OPTION /* 358, 0x166 */ SDL_SCANCODE_UNKNOWN, // KEY_INFO @@ -400,7 +399,7 @@ static SDL_Scancode const linux_scancode_table[] = { /* 370, 0x172 */ SDL_SCANCODE_UNKNOWN, // KEY_SUBTITLE /* 371, 0x173 */ SDL_SCANCODE_UNKNOWN, // KEY_ANGLE /* 372, 0x174 */ SDL_SCANCODE_UNKNOWN, // KEY_FULL_SCREEN - /* 373, 0x175 */ SDL_SCANCODE_UNKNOWN, // KEY_MODE + /* 373, 0x175 */ SDL_SCANCODE_MODE, // KEY_MODE /* 374, 0x176 */ SDL_SCANCODE_UNKNOWN, // KEY_KEYBOARD /* 375, 0x177 */ SDL_SCANCODE_UNKNOWN, // KEY_ASPECT_RATIO /* 376, 0x178 */ SDL_SCANCODE_UNKNOWN, // KEY_PC @@ -429,8 +428,9 @@ static SDL_Scancode const linux_scancode_table[] = { /* 399, 0x18f */ SDL_SCANCODE_UNKNOWN, // KEY_GREEN /* 400, 0x190 */ SDL_SCANCODE_UNKNOWN, // KEY_YELLOW /* 401, 0x191 */ SDL_SCANCODE_UNKNOWN, // KEY_BLUE - /* 402, 0x192 */ SDL_SCANCODE_UNKNOWN, // KEY_CHANNELUP - /* 403, 0x193 */ SDL_SCANCODE_UNKNOWN, // KEY_CHANNELDOWN + /* 402, 0x192 */ SDL_SCANCODE_CHANNEL_INCREMENT, // KEY_CHANNELUP + /* 403, 0x193 */ SDL_SCANCODE_CHANNEL_DECREMENT, // KEY_CHANNELDOWN +#if 0 // We don't have any mapped scancodes after this point (yet) /* 404, 0x194 */ SDL_SCANCODE_UNKNOWN, // KEY_FIRST /* 405, 0x195 */ SDL_SCANCODE_UNKNOWN, // KEY_LAST /* 406, 0x196 */ SDL_SCANCODE_UNKNOWN, // KEY_AB diff --git a/libs/SDL3/src/filesystem/SDL_filesystem.c b/libs/SDL3/src/filesystem/SDL_filesystem.c index 28388517..b115019b 100644 --- a/libs/SDL3/src/filesystem/SDL_filesystem.c +++ b/libs/SDL3/src/filesystem/SDL_filesystem.c @@ -188,6 +188,12 @@ static bool WildcardMatch(const char *pattern, const char *str, bool *matched_to sch = *str; pch = *pattern; } + + #ifdef SDL_PLATFORM_WINDOWS + if (sch == '\\') { + sch = '/'; + } + #endif } // '*' at the end can be ignored, they are allowed to match nothing. @@ -363,16 +369,16 @@ char **SDL_InternalGlobDirectory(const char *path, const char *pattern, SDL_Glob return NULL; } - // if path ends with any '/', chop them off, so we don't confuse the pattern matcher later. + // if path ends with any slash, chop them off, so we don't confuse the pattern matcher later. char *pathcpy = NULL; size_t pathlen = SDL_strlen(path); - if ((pathlen > 1) && (path[pathlen-1] == '/')) { + if ((pathlen > 1) && ((path[pathlen-1] == '/') || (path[pathlen-1] == '\\'))) { pathcpy = SDL_strdup(path); if (!pathcpy) { return NULL; } char *ptr = &pathcpy[pathlen-1]; - while ((ptr >= pathcpy) && (*ptr == '/')) { + while ((ptr >= pathcpy) && ((*ptr == '/') || (*ptr == '\\'))) { *(ptr--) = '\0'; } path = pathcpy; diff --git a/libs/SDL3/src/filesystem/cocoa/SDL_sysfilesystem.m b/libs/SDL3/src/filesystem/cocoa/SDL_sysfilesystem.m index a5fa67bc..5818764e 100644 --- a/libs/SDL3/src/filesystem/cocoa/SDL_sysfilesystem.m +++ b/libs/SDL3/src/filesystem/cocoa/SDL_sysfilesystem.m @@ -92,7 +92,7 @@ char *SDL_SYS_GetPrefPath(const char *org, const char *app) static bool shown = false; if (!shown) { shown = true; - SDL_LogCritical(SDL_LOG_CATEGORY_SYSTEM, "tvOS does not have persistent local storage! Use iCloud storage if you want your data to persist between sessions.\n"); + SDL_LogCritical(SDL_LOG_CATEGORY_SYSTEM, "tvOS does not have persistent local storage! Use iCloud storage if you want your data to persist between sessions."); } } diff --git a/libs/SDL3/src/gpu/SDL_gpu.c b/libs/SDL3/src/gpu/SDL_gpu.c index b3148c27..0897d1c9 100644 --- a/libs/SDL3/src/gpu/SDL_gpu.c +++ b/libs/SDL3/src/gpu/SDL_gpu.c @@ -158,6 +158,9 @@ #ifndef SDL_GPU_DISABLED static const SDL_GPUBootstrap *backends[] = { +#ifdef SDL_GPU_PRIVATE + &PrivateGPUDriver, +#endif #ifdef SDL_GPU_METAL &MetalDriver, #endif @@ -605,6 +608,7 @@ Uint32 SDL_GPUTextureFormatTexelBlockSize( case SDL_GPU_TEXTUREFORMAT_R8_SNORM: case SDL_GPU_TEXTUREFORMAT_A8_UNORM: case SDL_GPU_TEXTUREFORMAT_R8_UINT: + case SDL_GPU_TEXTUREFORMAT_R8_INT: return 1; case SDL_GPU_TEXTUREFORMAT_B5G6R5_UNORM: case SDL_GPU_TEXTUREFORMAT_B4G4R4A4_UNORM: @@ -613,9 +617,11 @@ Uint32 SDL_GPUTextureFormatTexelBlockSize( case SDL_GPU_TEXTUREFORMAT_R8G8_SNORM: case SDL_GPU_TEXTUREFORMAT_R8G8_UNORM: case SDL_GPU_TEXTUREFORMAT_R8G8_UINT: + case SDL_GPU_TEXTUREFORMAT_R8G8_INT: case SDL_GPU_TEXTUREFORMAT_R16_UNORM: case SDL_GPU_TEXTUREFORMAT_R16_SNORM: case SDL_GPU_TEXTUREFORMAT_R16_UINT: + case SDL_GPU_TEXTUREFORMAT_R16_INT: case SDL_GPU_TEXTUREFORMAT_D16_UNORM: return 2; case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM: @@ -628,11 +634,15 @@ Uint32 SDL_GPUTextureFormatTexelBlockSize( case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_SNORM: case SDL_GPU_TEXTUREFORMAT_R10G10B10A2_UNORM: case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UINT: + case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_INT: case SDL_GPU_TEXTUREFORMAT_R16G16_UINT: + case SDL_GPU_TEXTUREFORMAT_R16G16_INT: case SDL_GPU_TEXTUREFORMAT_R16G16_UNORM: case SDL_GPU_TEXTUREFORMAT_R16G16_SNORM: case SDL_GPU_TEXTUREFORMAT_D24_UNORM: case SDL_GPU_TEXTUREFORMAT_D32_FLOAT: + case SDL_GPU_TEXTUREFORMAT_R32_UINT: + case SDL_GPU_TEXTUREFORMAT_R32_INT: case SDL_GPU_TEXTUREFORMAT_D24_UNORM_S8_UINT: return 4; case SDL_GPU_TEXTUREFORMAT_D32_FLOAT_S8_UINT: @@ -640,10 +650,15 @@ Uint32 SDL_GPUTextureFormatTexelBlockSize( case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_FLOAT: case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UNORM: case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_SNORM: - case SDL_GPU_TEXTUREFORMAT_R32G32_FLOAT: case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UINT: + case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_INT: + case SDL_GPU_TEXTUREFORMAT_R32G32_FLOAT: + case SDL_GPU_TEXTUREFORMAT_R32G32_UINT: + case SDL_GPU_TEXTUREFORMAT_R32G32_INT: return 8; case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_FLOAT: + case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_INT: + case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_UINT: return 16; case SDL_GPU_TEXTUREFORMAT_ASTC_4x4_UNORM: case SDL_GPU_TEXTUREFORMAT_ASTC_5x4_UNORM: @@ -842,6 +857,12 @@ SDL_GPUGraphicsPipeline *SDL_CreateGPUGraphicsPipeline( SDL_assert_release(!"The number of vertex attributes in a vertex input state must not exceed 16!"); return NULL; } + for (Uint32 i = 0; i < graphicsPipelineCreateInfo->vertex_input_state.num_vertex_buffers; i += 1) { + if (graphicsPipelineCreateInfo->vertex_input_state.vertex_buffer_descriptions[i].instance_step_rate != 0) { + SDL_assert_release(!"For all vertex buffer descriptions, instance_step_rate must be 0!"); + return NULL; + } + } Uint32 locations[MAX_VERTEX_ATTRIBUTES]; for (Uint32 i = 0; i < graphicsPipelineCreateInfo->vertex_input_state.num_vertex_attributes; i += 1) { CHECK_VERTEXELEMENTFORMAT_ENUM_INVALID(graphicsPipelineCreateInfo->vertex_input_state.vertex_attributes[i].format, NULL); @@ -850,9 +871,18 @@ SDL_GPUGraphicsPipeline *SDL_CreateGPUGraphicsPipeline( for (Uint32 j = 0; j < i; j += 1) { if (locations[j] == locations[i]) { SDL_assert_release(!"Each vertex attribute location in a vertex input state must be unique!"); + return NULL; } } } + if (graphicsPipelineCreateInfo->multisample_state.enable_mask) { + SDL_assert_release(!"For multisample states, enable_mask must be false!"); + return NULL; + } + if (graphicsPipelineCreateInfo->multisample_state.sample_mask != 0) { + SDL_assert_release(!"For multisample states, sample_mask must be 0!"); + return NULL; + } if (graphicsPipelineCreateInfo->depth_stencil_state.enable_depth_test) { CHECK_COMPAREOP_ENUM_INVALID(graphicsPipelineCreateInfo->depth_stencil_state.compare_op, NULL) } diff --git a/libs/SDL3/src/gpu/SDL_sysgpu.h b/libs/SDL3/src/gpu/SDL_sysgpu.h index 98f4be9f..6de1765f 100644 --- a/libs/SDL3/src/gpu/SDL_sysgpu.h +++ b/libs/SDL3/src/gpu/SDL_sysgpu.h @@ -173,12 +173,18 @@ static inline Sint32 Texture_GetBlockWidth( case SDL_GPU_TEXTUREFORMAT_R16_UINT: case SDL_GPU_TEXTUREFORMAT_R16G16_UINT: case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UINT: + case SDL_GPU_TEXTUREFORMAT_R32_UINT: + case SDL_GPU_TEXTUREFORMAT_R32G32_UINT: + case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_UINT: case SDL_GPU_TEXTUREFORMAT_R8_INT: case SDL_GPU_TEXTUREFORMAT_R8G8_INT: case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_INT: case SDL_GPU_TEXTUREFORMAT_R16_INT: case SDL_GPU_TEXTUREFORMAT_R16G16_INT: case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_INT: + case SDL_GPU_TEXTUREFORMAT_R32_INT: + case SDL_GPU_TEXTUREFORMAT_R32G32_INT: + case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_INT: case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB: case SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB: case SDL_GPU_TEXTUREFORMAT_D16_UNORM: @@ -287,12 +293,18 @@ static inline Sint32 Texture_GetBlockHeight( case SDL_GPU_TEXTUREFORMAT_R16_UINT: case SDL_GPU_TEXTUREFORMAT_R16G16_UINT: case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UINT: + case SDL_GPU_TEXTUREFORMAT_R32_UINT: + case SDL_GPU_TEXTUREFORMAT_R32G32_UINT: + case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_UINT: case SDL_GPU_TEXTUREFORMAT_R8_INT: case SDL_GPU_TEXTUREFORMAT_R8G8_INT: case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_INT: case SDL_GPU_TEXTUREFORMAT_R16_INT: case SDL_GPU_TEXTUREFORMAT_R16G16_INT: case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_INT: + case SDL_GPU_TEXTUREFORMAT_R32_INT: + case SDL_GPU_TEXTUREFORMAT_R32G32_INT: + case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_INT: case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB: case SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB: case SDL_GPU_TEXTUREFORMAT_D16_UNORM: @@ -977,7 +989,7 @@ extern "C" { extern SDL_GPUBootstrap VulkanDriver; extern SDL_GPUBootstrap D3D12Driver; extern SDL_GPUBootstrap MetalDriver; -extern SDL_GPUBootstrap PS5Driver; +extern SDL_GPUBootstrap PrivateGPUDriver; #ifdef __cplusplus } diff --git a/libs/SDL3/src/gpu/d3d12/SDL_gpu_d3d12.c b/libs/SDL3/src/gpu/d3d12/SDL_gpu_d3d12.c index c142bae4..be13d8da 100644 --- a/libs/SDL3/src/gpu/d3d12/SDL_gpu_d3d12.c +++ b/libs/SDL3/src/gpu/d3d12/SDL_gpu_d3d12.c @@ -2028,7 +2028,7 @@ static void D3D12_InsertDebugLabel( d3d12CommandBuffer->graphicsCommandList, 0, wchar_text, - (UINT)SDL_wcslen(wchar_text)); + (UINT)SDL_wcslen(wchar_text) * sizeof(WCHAR)); SDL_free(wchar_text); } @@ -2044,7 +2044,7 @@ static void D3D12_PushDebugGroup( d3d12CommandBuffer->graphicsCommandList, 0, wchar_text, - (UINT)SDL_wcslen(wchar_text)); + (UINT)SDL_wcslen(wchar_text) * sizeof(WCHAR)); SDL_free(wchar_text); } @@ -2928,7 +2928,7 @@ static bool D3D12_INTERNAL_ConvertVertexInputState(SDL_GPUVertexInputState verte desc[i].AlignedByteOffset = attribute.offset; desc[i].InputSlotClass = SDLToD3D12_InputRate[vertexInputState.vertex_buffer_descriptions[attribute.buffer_slot].input_rate]; desc[i].InstanceDataStepRate = (vertexInputState.vertex_buffer_descriptions[attribute.buffer_slot].input_rate == SDL_GPU_VERTEXINPUTRATE_INSTANCE) - ? vertexInputState.vertex_buffer_descriptions[attribute.buffer_slot].instance_step_rate + ? 1 : 0; } @@ -3010,15 +3010,13 @@ static SDL_GPUGraphicsPipeline *D3D12_CreateGraphicsPipeline( return NULL; } - Uint32 sampleMask = createinfo->multisample_state.enable_mask ? - createinfo->multisample_state.sample_mask : - 0xFFFFFFFF; - - psoDesc.SampleMask = sampleMask; + psoDesc.SampleMask = 0xFFFFFFFF; psoDesc.SampleDesc.Count = SDLToD3D12_SampleCount[createinfo->multisample_state.sample_count]; psoDesc.SampleDesc.Quality = (createinfo->multisample_state.sample_count > SDL_GPU_SAMPLECOUNT_1) ? D3D12_STANDARD_MULTISAMPLE_PATTERN : 0; - psoDesc.DSVFormat = SDLToD3D12_DepthFormat[createinfo->target_info.depth_stencil_format]; + if (createinfo->target_info.has_depth_stencil_target) { + psoDesc.DSVFormat = SDLToD3D12_DepthFormat[createinfo->target_info.depth_stencil_format]; + } psoDesc.NumRenderTargets = createinfo->target_info.num_color_targets; for (uint32_t i = 0; i < createinfo->target_info.num_color_targets; i += 1) { psoDesc.RTVFormats[i] = SDLToD3D12_TextureFormat[createinfo->target_info.color_target_descriptions[i].format]; @@ -4552,15 +4550,18 @@ static void D3D12_BindVertexBuffers( for (Uint32 i = 0; i < numBindings; i += 1) { D3D12Buffer *currentBuffer = ((D3D12BufferContainer *)bindings[i].buffer)->activeBuffer; - d3d12CommandBuffer->vertexBuffers[firstSlot + i] = currentBuffer; - d3d12CommandBuffer->vertexBufferOffsets[firstSlot + i] = bindings[i].offset; - D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, currentBuffer); + + if (d3d12CommandBuffer->vertexBuffers[firstSlot + i] != currentBuffer || d3d12CommandBuffer->vertexBufferOffsets[firstSlot + i] != bindings[i].offset) { + D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, currentBuffer); + + d3d12CommandBuffer->vertexBuffers[firstSlot + i] = currentBuffer; + d3d12CommandBuffer->vertexBufferOffsets[firstSlot + i] = bindings[i].offset; + d3d12CommandBuffer->needVertexBufferBind = true; + } } d3d12CommandBuffer->vertexBufferCount = SDL_max(d3d12CommandBuffer->vertexBufferCount, firstSlot + numBindings); - - d3d12CommandBuffer->needVertexBufferBind = true; } static void D3D12_BindIndexBuffer( @@ -4596,19 +4597,24 @@ static void D3D12_BindVertexSamplers( D3D12TextureContainer *container = (D3D12TextureContainer *)textureSamplerBindings[i].texture; D3D12Sampler *sampler = (D3D12Sampler *)textureSamplerBindings[i].sampler; - D3D12_INTERNAL_TrackTexture( - d3d12CommandBuffer, - container->activeTexture); + if (d3d12CommandBuffer->vertexSamplers[firstSlot + i] != sampler) { + D3D12_INTERNAL_TrackSampler( + d3d12CommandBuffer, + sampler); - D3D12_INTERNAL_TrackSampler( - d3d12CommandBuffer, - sampler); + d3d12CommandBuffer->vertexSamplers[firstSlot + i] = sampler; + d3d12CommandBuffer->needVertexSamplerBind = true; + } - d3d12CommandBuffer->vertexSamplers[firstSlot + i] = sampler; - d3d12CommandBuffer->vertexSamplerTextures[firstSlot + i] = container->activeTexture; + if (d3d12CommandBuffer->vertexSamplerTextures[firstSlot + i] != container->activeTexture) { + D3D12_INTERNAL_TrackTexture( + d3d12CommandBuffer, + container->activeTexture); + + d3d12CommandBuffer->vertexSamplerTextures[firstSlot + i] = container->activeTexture; + d3d12CommandBuffer->needVertexSamplerBind = true; + } } - - d3d12CommandBuffer->needVertexSamplerBind = true; } static void D3D12_BindVertexStorageTextures( @@ -4623,12 +4629,13 @@ static void D3D12_BindVertexStorageTextures( D3D12TextureContainer *container = (D3D12TextureContainer *)storageTextures[i]; D3D12Texture *texture = container->activeTexture; - D3D12_INTERNAL_TrackTexture(d3d12CommandBuffer, texture); + if (d3d12CommandBuffer->vertexStorageTextures[firstSlot + i] != texture) { + D3D12_INTERNAL_TrackTexture(d3d12CommandBuffer, texture); - d3d12CommandBuffer->vertexStorageTextures[firstSlot + i] = texture; + d3d12CommandBuffer->vertexStorageTextures[firstSlot + i] = texture; + d3d12CommandBuffer->needVertexStorageTextureBind = true; + } } - - d3d12CommandBuffer->needVertexStorageTextureBind = true; } static void D3D12_BindVertexStorageBuffers( @@ -4641,15 +4648,15 @@ static void D3D12_BindVertexStorageBuffers( for (Uint32 i = 0; i < numBindings; i += 1) { D3D12BufferContainer *container = (D3D12BufferContainer *)storageBuffers[i]; + if (d3d12CommandBuffer->vertexStorageBuffers[firstSlot + i] != container->activeBuffer) { + D3D12_INTERNAL_TrackBuffer( + d3d12CommandBuffer, + container->activeBuffer); - D3D12_INTERNAL_TrackBuffer( - d3d12CommandBuffer, - container->activeBuffer); - - d3d12CommandBuffer->vertexStorageBuffers[firstSlot + i] = container->activeBuffer; + d3d12CommandBuffer->vertexStorageBuffers[firstSlot + i] = container->activeBuffer; + d3d12CommandBuffer->needVertexStorageBufferBind = true; + } } - - d3d12CommandBuffer->needVertexStorageBufferBind = true; } static void D3D12_BindFragmentSamplers( @@ -4664,19 +4671,24 @@ static void D3D12_BindFragmentSamplers( D3D12TextureContainer *container = (D3D12TextureContainer *)textureSamplerBindings[i].texture; D3D12Sampler *sampler = (D3D12Sampler *)textureSamplerBindings[i].sampler; - D3D12_INTERNAL_TrackTexture( - d3d12CommandBuffer, - container->activeTexture); + if (d3d12CommandBuffer->fragmentSamplers[firstSlot + i] != sampler) { + D3D12_INTERNAL_TrackSampler( + d3d12CommandBuffer, + sampler); - D3D12_INTERNAL_TrackSampler( - d3d12CommandBuffer, - sampler); + d3d12CommandBuffer->fragmentSamplers[firstSlot + i] = sampler; + d3d12CommandBuffer->needFragmentSamplerBind = true; + } - d3d12CommandBuffer->fragmentSamplers[firstSlot + i] = sampler; - d3d12CommandBuffer->fragmentSamplerTextures[firstSlot + i] = container->activeTexture; + if (d3d12CommandBuffer->fragmentSamplerTextures[firstSlot + i] != container->activeTexture) { + D3D12_INTERNAL_TrackTexture( + d3d12CommandBuffer, + container->activeTexture); + + d3d12CommandBuffer->fragmentSamplerTextures[firstSlot + i] = container->activeTexture; + d3d12CommandBuffer->needFragmentSamplerBind = true; + } } - - d3d12CommandBuffer->needFragmentSamplerBind = true; } static void D3D12_BindFragmentStorageTextures( @@ -4691,12 +4703,13 @@ static void D3D12_BindFragmentStorageTextures( D3D12TextureContainer *container = (D3D12TextureContainer *)storageTextures[i]; D3D12Texture *texture = container->activeTexture; - D3D12_INTERNAL_TrackTexture(d3d12CommandBuffer, texture); + if (d3d12CommandBuffer->fragmentStorageTextures[firstSlot + i] != texture) { + D3D12_INTERNAL_TrackTexture(d3d12CommandBuffer, texture); - d3d12CommandBuffer->fragmentStorageTextures[firstSlot + i] = texture; + d3d12CommandBuffer->fragmentStorageTextures[firstSlot + i] = texture; + d3d12CommandBuffer->needFragmentStorageTextureBind = true; + } } - - d3d12CommandBuffer->needFragmentStorageTextureBind = true; } static void D3D12_BindFragmentStorageBuffers( @@ -4710,14 +4723,15 @@ static void D3D12_BindFragmentStorageBuffers( for (Uint32 i = 0; i < numBindings; i += 1) { D3D12BufferContainer *container = (D3D12BufferContainer *)storageBuffers[i]; - D3D12_INTERNAL_TrackBuffer( - d3d12CommandBuffer, - container->activeBuffer); + if (d3d12CommandBuffer->fragmentStorageBuffers[firstSlot + i] != container->activeBuffer) { + D3D12_INTERNAL_TrackBuffer( + d3d12CommandBuffer, + container->activeBuffer); - d3d12CommandBuffer->fragmentStorageBuffers[firstSlot + i] = container->activeBuffer; + d3d12CommandBuffer->fragmentStorageBuffers[firstSlot + i] = container->activeBuffer; + d3d12CommandBuffer->needFragmentStorageBufferBind = true; + } } - - d3d12CommandBuffer->needFragmentStorageBufferBind = true; } static void D3D12_PushVertexUniformData( @@ -5330,20 +5344,26 @@ static void D3D12_BindComputeSamplers( for (Uint32 i = 0; i < numBindings; i += 1) { D3D12TextureContainer *container = (D3D12TextureContainer *)textureSamplerBindings[i].texture; + D3D12Sampler *sampler = (D3D12Sampler *)textureSamplerBindings[i].sampler; - D3D12_INTERNAL_TrackSampler( - d3d12CommandBuffer, - (D3D12Sampler *)textureSamplerBindings[i].sampler); + if (d3d12CommandBuffer->computeSamplers[firstSlot + i] != sampler) { + D3D12_INTERNAL_TrackSampler( + d3d12CommandBuffer, + (D3D12Sampler *)textureSamplerBindings[i].sampler); - D3D12_INTERNAL_TrackTexture( - d3d12CommandBuffer, - container->activeTexture); + d3d12CommandBuffer->computeSamplers[firstSlot + i] = (D3D12Sampler *)textureSamplerBindings[i].sampler; + d3d12CommandBuffer->needComputeSamplerBind = true; + } - d3d12CommandBuffer->computeSamplerTextures[firstSlot + i] = container->activeTexture; - d3d12CommandBuffer->computeSamplers[firstSlot + i] = (D3D12Sampler *)textureSamplerBindings[i].sampler; + if (d3d12CommandBuffer->computeSamplerTextures[firstSlot + i] != container->activeTexture) { + D3D12_INTERNAL_TrackTexture( + d3d12CommandBuffer, + container->activeTexture); + + d3d12CommandBuffer->computeSamplerTextures[firstSlot + i] = container->activeTexture; + d3d12CommandBuffer->needComputeSamplerBind = true; + } } - - d3d12CommandBuffer->needComputeSamplerBind = true; } static void D3D12_BindComputeStorageTextures( @@ -5355,27 +5375,31 @@ static void D3D12_BindComputeStorageTextures( D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; for (Uint32 i = 0; i < numBindings; i += 1) { - if (d3d12CommandBuffer->computeReadOnlyStorageTextures[firstSlot + i] != NULL) { - D3D12_INTERNAL_TextureTransitionToDefaultUsage( + D3D12TextureContainer *container = (D3D12TextureContainer *)storageTextures[i]; + + if (d3d12CommandBuffer->computeReadOnlyStorageTextures[firstSlot + i] != container->activeTexture) { + /* If a different texture was in this slot, transition it back to its default usage */ + if (d3d12CommandBuffer->computeReadOnlyStorageTextures[firstSlot + i] != NULL) { + D3D12_INTERNAL_TextureTransitionToDefaultUsage( + d3d12CommandBuffer, + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, + d3d12CommandBuffer->computeReadOnlyStorageTextures[firstSlot + i]); + } + + /* Then transition the new texture and prepare it for binding */ + D3D12_INTERNAL_TextureTransitionFromDefaultUsage( d3d12CommandBuffer, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, - d3d12CommandBuffer->computeReadOnlyStorageTextures[firstSlot + i]); + container->activeTexture); + + D3D12_INTERNAL_TrackTexture( + d3d12CommandBuffer, + container->activeTexture); + + d3d12CommandBuffer->computeReadOnlyStorageTextures[firstSlot + i] = container->activeTexture; + d3d12CommandBuffer->needComputeReadOnlyStorageTextureBind = true; } - - D3D12TextureContainer *container = (D3D12TextureContainer *)storageTextures[i]; - d3d12CommandBuffer->computeReadOnlyStorageTextures[firstSlot + i] = container->activeTexture; - - D3D12_INTERNAL_TextureTransitionFromDefaultUsage( - d3d12CommandBuffer, - D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, - container->activeTexture); - - D3D12_INTERNAL_TrackTexture( - d3d12CommandBuffer, - container->activeTexture); } - - d3d12CommandBuffer->needComputeReadOnlyStorageTextureBind = true; } static void D3D12_BindComputeStorageBuffers( @@ -5387,29 +5411,32 @@ static void D3D12_BindComputeStorageBuffers( D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; for (Uint32 i = 0; i < numBindings; i += 1) { - if (d3d12CommandBuffer->computeReadOnlyStorageBuffers[firstSlot + i] != NULL) { - D3D12_INTERNAL_BufferTransitionToDefaultUsage( - d3d12CommandBuffer, - D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, - d3d12CommandBuffer->computeReadOnlyStorageBuffers[firstSlot + i]); - } - D3D12BufferContainer *container = (D3D12BufferContainer *)storageBuffers[i]; D3D12Buffer *buffer = container->activeBuffer; - d3d12CommandBuffer->computeReadOnlyStorageBuffers[firstSlot + i] = buffer; + if (d3d12CommandBuffer->computeReadOnlyStorageBuffers[firstSlot + i] != buffer) { + /* If a different buffer was in this slot, transition it back to its default usage */ + if (d3d12CommandBuffer->computeReadOnlyStorageBuffers[firstSlot + i] != NULL) { + D3D12_INTERNAL_BufferTransitionToDefaultUsage( + d3d12CommandBuffer, + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, + d3d12CommandBuffer->computeReadOnlyStorageBuffers[firstSlot + i]); + } - D3D12_INTERNAL_BufferTransitionFromDefaultUsage( - d3d12CommandBuffer, - D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, - buffer); + /* Then transition the new buffer and prepare it for binding */ + D3D12_INTERNAL_BufferTransitionFromDefaultUsage( + d3d12CommandBuffer, + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, + buffer); - D3D12_INTERNAL_TrackBuffer( - d3d12CommandBuffer, - buffer); + D3D12_INTERNAL_TrackBuffer( + d3d12CommandBuffer, + buffer); + + d3d12CommandBuffer->computeReadOnlyStorageBuffers[firstSlot + i] = buffer; + d3d12CommandBuffer->needComputeReadOnlyStorageBufferBind = true; + } } - - d3d12CommandBuffer->needComputeReadOnlyStorageBufferBind = true; } static void D3D12_PushComputeUniformData( @@ -6708,7 +6735,7 @@ static bool D3D12_INTERNAL_CreateSwapchain( swapchainDesc.SampleDesc.Quality = 0; swapchainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapchainDesc.BufferCount = windowData->swapchainTextureCount; - swapchainDesc.Scaling = DXGI_SCALING_STRETCH; + swapchainDesc.Scaling = DXGI_SCALING_NONE; swapchainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; swapchainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; swapchainDesc.Flags = 0; diff --git a/libs/SDL3/src/gpu/metal/SDL_gpu_metal.m b/libs/SDL3/src/gpu/metal/SDL_gpu_metal.m index ac712d52..365b3448 100644 --- a/libs/SDL3/src/gpu/metal/SDL_gpu_metal.m +++ b/libs/SDL3/src/gpu/metal/SDL_gpu_metal.m @@ -478,8 +478,6 @@ typedef struct MetalGraphicsPipeline { id handle; - Uint32 sample_mask; - SDL_GPURasterizerState rasterizerState; SDL_GPUPrimitiveType primitiveType; @@ -567,30 +565,37 @@ typedef struct MetalCommandBuffer MetalComputePipeline *compute_pipeline; // Resource slot state + bool needVertexBufferBind; bool needVertexSamplerBind; bool needVertexStorageTextureBind; bool needVertexStorageBufferBind; - bool needVertexUniformBind; + bool needVertexUniformBufferBind[MAX_UNIFORM_BUFFERS_PER_STAGE]; bool needFragmentSamplerBind; bool needFragmentStorageTextureBind; bool needFragmentStorageBufferBind; - bool needFragmentUniformBind; + bool needFragmentUniformBufferBind[MAX_UNIFORM_BUFFERS_PER_STAGE]; bool needComputeSamplerBind; - bool needComputeTextureBind; - bool needComputeBufferBind; - bool needComputeUniformBind; + bool needComputeReadOnlyStorageTextureBind; + bool needComputeReadOnlyStorageBufferBind; + bool needComputeUniformBufferBind[MAX_UNIFORM_BUFFERS_PER_STAGE]; + + id vertexBuffers[MAX_VERTEX_BUFFERS]; + Uint32 vertexBufferOffsets[MAX_VERTEX_BUFFERS]; + Uint32 vertexBufferCount; id vertexSamplers[MAX_TEXTURE_SAMPLERS_PER_STAGE]; id vertexTextures[MAX_TEXTURE_SAMPLERS_PER_STAGE]; id vertexStorageTextures[MAX_STORAGE_TEXTURES_PER_STAGE]; id vertexStorageBuffers[MAX_STORAGE_BUFFERS_PER_STAGE]; + MetalUniformBuffer *vertexUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE]; id fragmentSamplers[MAX_TEXTURE_SAMPLERS_PER_STAGE]; id fragmentTextures[MAX_TEXTURE_SAMPLERS_PER_STAGE]; id fragmentStorageTextures[MAX_STORAGE_TEXTURES_PER_STAGE]; id fragmentStorageBuffers[MAX_STORAGE_BUFFERS_PER_STAGE]; + MetalUniformBuffer *fragmentUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE]; id computeSamplerTextures[MAX_TEXTURE_SAMPLERS_PER_STAGE]; id computeSamplers[MAX_TEXTURE_SAMPLERS_PER_STAGE]; @@ -598,10 +603,6 @@ typedef struct MetalCommandBuffer id computeReadOnlyBuffers[MAX_STORAGE_BUFFERS_PER_STAGE]; id computeReadWriteTextures[MAX_COMPUTE_WRITE_TEXTURES]; id computeReadWriteBuffers[MAX_COMPUTE_WRITE_BUFFERS]; - - // Uniform buffers - MetalUniformBuffer *vertexUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE]; - MetalUniformBuffer *fragmentUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE]; MetalUniformBuffer *computeUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE]; MetalUniformBuffer **usedUniformBuffers; @@ -1178,9 +1179,7 @@ static SDL_GPUGraphicsPipeline *METAL_CreateGraphicsPipeline( for (Uint32 i = 0; i < createinfo->vertex_input_state.num_vertex_buffers; i += 1) { binding = METAL_FIRST_VERTEX_BUFFER_SLOT + createinfo->vertex_input_state.vertex_buffer_descriptions[i].slot; vertexDescriptor.layouts[binding].stepFunction = SDLToMetal_StepFunction[createinfo->vertex_input_state.vertex_buffer_descriptions[i].input_rate]; - vertexDescriptor.layouts[binding].stepRate = (createinfo->vertex_input_state.vertex_buffer_descriptions[i].input_rate == SDL_GPU_VERTEXINPUTRATE_INSTANCE) - ? createinfo->vertex_input_state.vertex_buffer_descriptions[i].instance_step_rate - : 1; + vertexDescriptor.layouts[binding].stepRate = 1; vertexDescriptor.layouts[binding].stride = createinfo->vertex_input_state.vertex_buffer_descriptions[i].pitch; } @@ -1199,13 +1198,8 @@ static SDL_GPUGraphicsPipeline *METAL_CreateGraphicsPipeline( SET_ERROR_AND_RETURN("Creating render pipeline failed: %s", [[error description] UTF8String], NULL); } - Uint32 sampleMask = createinfo->multisample_state.enable_mask ? - createinfo->multisample_state.sample_mask : - 0xFFFFFFFF; - result = SDL_calloc(1, sizeof(MetalGraphicsPipeline)); result->handle = pipelineState; - result->sample_mask = sampleMask; result->depth_stencil_state = depthStencilState; result->rasterizerState = createinfo->rasterizer_state; result->primitiveType = createinfo->primitive_type; @@ -2130,20 +2124,6 @@ static SDL_GPUCommandBuffer *METAL_AcquireCommandBuffer( commandBuffer->computeUniformBuffers[i] = NULL; } - // FIXME: Do we actually need to set this? - commandBuffer->needVertexSamplerBind = true; - commandBuffer->needVertexStorageTextureBind = true; - commandBuffer->needVertexStorageBufferBind = true; - commandBuffer->needVertexUniformBind = true; - commandBuffer->needFragmentSamplerBind = true; - commandBuffer->needFragmentStorageTextureBind = true; - commandBuffer->needFragmentStorageBufferBind = true; - commandBuffer->needFragmentUniformBind = true; - commandBuffer->needComputeSamplerBind = true; - commandBuffer->needComputeBufferBind = true; - commandBuffer->needComputeTextureBind = true; - commandBuffer->needComputeUniformBind = true; - commandBuffer->autoReleaseFence = true; SDL_UnlockMutex(renderer->acquireCommandBufferLock); @@ -2397,73 +2377,71 @@ static void METAL_BindGraphicsPipeline( { @autoreleasepool { MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer; - MetalGraphicsPipeline *metalGraphicsPipeline = (MetalGraphicsPipeline *)graphicsPipeline; - SDL_GPURasterizerState *rast = &metalGraphicsPipeline->rasterizerState; + MetalGraphicsPipeline *pipeline = (MetalGraphicsPipeline *)graphicsPipeline; + SDL_GPURasterizerState *rast = &pipeline->rasterizerState; + Uint32 i; - metalCommandBuffer->graphics_pipeline = metalGraphicsPipeline; + metalCommandBuffer->graphics_pipeline = pipeline; - [metalCommandBuffer->renderEncoder setRenderPipelineState:metalGraphicsPipeline->handle]; + [metalCommandBuffer->renderEncoder setRenderPipelineState:pipeline->handle]; // Apply rasterizer state - [metalCommandBuffer->renderEncoder setTriangleFillMode:SDLToMetal_PolygonMode[metalGraphicsPipeline->rasterizerState.fill_mode]]; - [metalCommandBuffer->renderEncoder setCullMode:SDLToMetal_CullMode[metalGraphicsPipeline->rasterizerState.cull_mode]]; - [metalCommandBuffer->renderEncoder setFrontFacingWinding:SDLToMetal_FrontFace[metalGraphicsPipeline->rasterizerState.front_face]]; - [metalCommandBuffer->renderEncoder setDepthClipMode:SDLToMetal_DepthClipMode(metalGraphicsPipeline->rasterizerState.enable_depth_clip)]; + [metalCommandBuffer->renderEncoder setTriangleFillMode:SDLToMetal_PolygonMode[pipeline->rasterizerState.fill_mode]]; + [metalCommandBuffer->renderEncoder setCullMode:SDLToMetal_CullMode[pipeline->rasterizerState.cull_mode]]; + [metalCommandBuffer->renderEncoder setFrontFacingWinding:SDLToMetal_FrontFace[pipeline->rasterizerState.front_face]]; + [metalCommandBuffer->renderEncoder setDepthClipMode:SDLToMetal_DepthClipMode(pipeline->rasterizerState.enable_depth_clip)]; [metalCommandBuffer->renderEncoder setDepthBias:((rast->enable_depth_bias) ? rast->depth_bias_constant_factor : 0) slopeScale:((rast->enable_depth_bias) ? rast->depth_bias_slope_factor : 0) clamp:((rast->enable_depth_bias) ? rast->depth_bias_clamp : 0)]; // Apply depth-stencil state - if (metalGraphicsPipeline->depth_stencil_state != NULL) { + if (pipeline->depth_stencil_state != NULL) { [metalCommandBuffer->renderEncoder - setDepthStencilState:metalGraphicsPipeline->depth_stencil_state]; + setDepthStencilState:pipeline->depth_stencil_state]; } - for (Uint32 i = 0; i < metalGraphicsPipeline->vertexUniformBufferCount; i += 1) { + for (i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) { + metalCommandBuffer->needVertexUniformBufferBind[i] = true; + metalCommandBuffer->needFragmentUniformBufferBind[i] = true; + } + + for (i = 0; i < pipeline->vertexUniformBufferCount; i += 1) { if (metalCommandBuffer->vertexUniformBuffers[i] == NULL) { metalCommandBuffer->vertexUniformBuffers[i] = METAL_INTERNAL_AcquireUniformBufferFromPool( metalCommandBuffer); } } - for (Uint32 i = 0; i < metalGraphicsPipeline->fragmentUniformBufferCount; i += 1) { + for (i = 0; i < pipeline->fragmentUniformBufferCount; i += 1) { if (metalCommandBuffer->fragmentUniformBuffers[i] == NULL) { metalCommandBuffer->fragmentUniformBuffers[i] = METAL_INTERNAL_AcquireUniformBufferFromPool( metalCommandBuffer); } } - - metalCommandBuffer->needVertexUniformBind = true; - metalCommandBuffer->needFragmentUniformBind = true; } } static void METAL_BindVertexBuffers( SDL_GPUCommandBuffer *commandBuffer, - Uint32 firstBinding, + Uint32 firstSlot, const SDL_GPUBufferBinding *bindings, Uint32 numBindings) { - @autoreleasepool { - MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer; - id metalBuffers[MAX_VERTEX_BUFFERS]; - NSUInteger bufferOffsets[MAX_VERTEX_BUFFERS]; - NSRange range = NSMakeRange(METAL_FIRST_VERTEX_BUFFER_SLOT + firstBinding, numBindings); + MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer; - if (range.length == 0) { - return; - } - - for (Uint32 i = 0; i < numBindings; i += 1) { - MetalBuffer *currentBuffer = ((MetalBufferContainer *)bindings[i].buffer)->activeBuffer; - metalBuffers[firstBinding + i] = currentBuffer->handle; - bufferOffsets[firstBinding + i] = bindings[i].offset; + for (Uint32 i = 0; i < numBindings; i += 1) { + MetalBuffer *currentBuffer = ((MetalBufferContainer *)bindings[i].buffer)->activeBuffer; + if (metalCommandBuffer->vertexBuffers[firstSlot + i] != currentBuffer->handle || metalCommandBuffer->vertexBufferOffsets[firstSlot + i] != bindings[i].offset) { + metalCommandBuffer->vertexBuffers[firstSlot + i] = currentBuffer->handle; + metalCommandBuffer->vertexBufferOffsets[firstSlot + i] = bindings[i].offset; + metalCommandBuffer->needVertexBufferBind = true; METAL_INTERNAL_TrackBuffer(metalCommandBuffer, currentBuffer); } - - [metalCommandBuffer->renderEncoder setVertexBuffers:metalBuffers offsets:bufferOffsets withRange:range]; } + + metalCommandBuffer->vertexBufferCount = + SDL_max(metalCommandBuffer->vertexBufferCount, firstSlot + numBindings); } static void METAL_BindIndexBuffer( @@ -2487,22 +2465,28 @@ static void METAL_BindVertexSamplers( { MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer; MetalTextureContainer *textureContainer; + MetalSampler *sampler; for (Uint32 i = 0; i < numBindings; i += 1) { textureContainer = (MetalTextureContainer *)textureSamplerBindings[i].texture; + sampler = (MetalSampler *)textureSamplerBindings[i].sampler; - METAL_INTERNAL_TrackTexture( - metalCommandBuffer, - textureContainer->activeTexture); + if (metalCommandBuffer->vertexSamplers[firstSlot + i] != sampler->handle) { + metalCommandBuffer->vertexSamplers[firstSlot + i] = sampler->handle; + metalCommandBuffer->needVertexSamplerBind = true; + } - metalCommandBuffer->vertexSamplers[firstSlot + i] = - ((MetalSampler *)textureSamplerBindings[i].sampler)->handle; + if (metalCommandBuffer->vertexTextures[firstSlot + i] != textureContainer->activeTexture->handle) { + METAL_INTERNAL_TrackTexture( + metalCommandBuffer, + textureContainer->activeTexture); - metalCommandBuffer->vertexTextures[firstSlot + i] = - textureContainer->activeTexture->handle; + metalCommandBuffer->vertexTextures[firstSlot + i] = + textureContainer->activeTexture->handle; + + metalCommandBuffer->needVertexSamplerBind = true; + } } - - metalCommandBuffer->needVertexSamplerBind = true; } static void METAL_BindVertexStorageTextures( @@ -2517,15 +2501,17 @@ static void METAL_BindVertexStorageTextures( for (Uint32 i = 0; i < numBindings; i += 1) { textureContainer = (MetalTextureContainer *)storageTextures[i]; - METAL_INTERNAL_TrackTexture( - metalCommandBuffer, - textureContainer->activeTexture); + if (metalCommandBuffer->vertexStorageTextures[firstSlot + i] != textureContainer->activeTexture->handle) { + METAL_INTERNAL_TrackTexture( + metalCommandBuffer, + textureContainer->activeTexture); - metalCommandBuffer->vertexStorageTextures[firstSlot + i] = - textureContainer->activeTexture->handle; + metalCommandBuffer->vertexStorageTextures[firstSlot + i] = + textureContainer->activeTexture->handle; + + metalCommandBuffer->needVertexStorageTextureBind = true; + } } - - metalCommandBuffer->needVertexStorageTextureBind = true; } static void METAL_BindVertexStorageBuffers( @@ -2540,15 +2526,17 @@ static void METAL_BindVertexStorageBuffers( for (Uint32 i = 0; i < numBindings; i += 1) { bufferContainer = (MetalBufferContainer *)storageBuffers[i]; - METAL_INTERNAL_TrackBuffer( - metalCommandBuffer, - bufferContainer->activeBuffer); + if (metalCommandBuffer->vertexStorageBuffers[firstSlot + i] != bufferContainer->activeBuffer->handle) { + METAL_INTERNAL_TrackBuffer( + metalCommandBuffer, + bufferContainer->activeBuffer); - metalCommandBuffer->vertexStorageBuffers[firstSlot + i] = - bufferContainer->activeBuffer->handle; + metalCommandBuffer->vertexStorageBuffers[firstSlot + i] = + bufferContainer->activeBuffer->handle; + + metalCommandBuffer->needVertexStorageBufferBind = true; + } } - - metalCommandBuffer->needVertexStorageBufferBind = true; } static void METAL_BindFragmentSamplers( @@ -2559,22 +2547,28 @@ static void METAL_BindFragmentSamplers( { MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer; MetalTextureContainer *textureContainer; + MetalSampler *sampler; for (Uint32 i = 0; i < numBindings; i += 1) { textureContainer = (MetalTextureContainer *)textureSamplerBindings[i].texture; + sampler = (MetalSampler *)textureSamplerBindings[i].sampler; - METAL_INTERNAL_TrackTexture( - metalCommandBuffer, - textureContainer->activeTexture); + if (metalCommandBuffer->fragmentSamplers[firstSlot + i] != sampler->handle) { + metalCommandBuffer->fragmentSamplers[firstSlot + i] = sampler->handle; + metalCommandBuffer->needFragmentSamplerBind = true; + } - metalCommandBuffer->fragmentSamplers[firstSlot + i] = - ((MetalSampler *)textureSamplerBindings[i].sampler)->handle; + if (metalCommandBuffer->fragmentTextures[firstSlot + i] != textureContainer->activeTexture->handle) { + METAL_INTERNAL_TrackTexture( + metalCommandBuffer, + textureContainer->activeTexture); - metalCommandBuffer->fragmentTextures[firstSlot + i] = - textureContainer->activeTexture->handle; + metalCommandBuffer->fragmentTextures[firstSlot + i] = + textureContainer->activeTexture->handle; + + metalCommandBuffer->needFragmentSamplerBind = true; + } } - - metalCommandBuffer->needFragmentSamplerBind = true; } static void METAL_BindFragmentStorageTextures( @@ -2589,15 +2583,17 @@ static void METAL_BindFragmentStorageTextures( for (Uint32 i = 0; i < numBindings; i += 1) { textureContainer = (MetalTextureContainer *)storageTextures[i]; - METAL_INTERNAL_TrackTexture( - metalCommandBuffer, - textureContainer->activeTexture); + if (metalCommandBuffer->fragmentStorageTextures[firstSlot + i] != textureContainer->activeTexture->handle) { + METAL_INTERNAL_TrackTexture( + metalCommandBuffer, + textureContainer->activeTexture); - metalCommandBuffer->fragmentStorageTextures[firstSlot + i] = - textureContainer->activeTexture->handle; + metalCommandBuffer->fragmentStorageTextures[firstSlot + i] = + textureContainer->activeTexture->handle; + + metalCommandBuffer->needFragmentStorageTextureBind = true; + } } - - metalCommandBuffer->needFragmentStorageTextureBind = true; } static void METAL_BindFragmentStorageBuffers( @@ -2612,15 +2608,17 @@ static void METAL_BindFragmentStorageBuffers( for (Uint32 i = 0; i < numBindings; i += 1) { bufferContainer = (MetalBufferContainer *)storageBuffers[i]; - METAL_INTERNAL_TrackBuffer( - metalCommandBuffer, - bufferContainer->activeBuffer); + if (metalCommandBuffer->fragmentStorageBuffers[firstSlot + i] != bufferContainer->activeBuffer->handle) { + METAL_INTERNAL_TrackBuffer( + metalCommandBuffer, + bufferContainer->activeBuffer); - metalCommandBuffer->fragmentStorageBuffers[firstSlot + i] = - bufferContainer->activeBuffer->handle; + metalCommandBuffer->fragmentStorageBuffers[firstSlot + i] = + bufferContainer->activeBuffer->handle; + + metalCommandBuffer->needFragmentStorageBufferBind = true; + } } - - metalCommandBuffer->needFragmentStorageBufferBind = true; } // This function assumes that it's called from within an autorelease pool @@ -2630,85 +2628,115 @@ static void METAL_INTERNAL_BindGraphicsResources( MetalGraphicsPipeline *graphicsPipeline = commandBuffer->graphics_pipeline; NSUInteger offsets[MAX_STORAGE_BUFFERS_PER_STAGE] = { 0 }; + // Vertex Buffers + if (commandBuffer->needVertexBufferBind) { + id metalBuffers[MAX_VERTEX_BUFFERS]; + NSUInteger bufferOffsets[MAX_VERTEX_BUFFERS]; + NSRange range = NSMakeRange(METAL_FIRST_VERTEX_BUFFER_SLOT, commandBuffer->vertexBufferCount); + for (Uint32 i = 0; i < commandBuffer->vertexBufferCount; i += 1) { + metalBuffers[i] = commandBuffer->vertexBuffers[i]; + bufferOffsets[i] = commandBuffer->vertexBufferOffsets[i]; + } + [commandBuffer->renderEncoder setVertexBuffers:metalBuffers offsets:bufferOffsets withRange:range]; + commandBuffer->needVertexBufferBind = false; + } + // Vertex Samplers+Textures - if (graphicsPipeline->vertexSamplerCount > 0 && commandBuffer->needVertexSamplerBind) { - [commandBuffer->renderEncoder setVertexSamplerStates:commandBuffer->vertexSamplers - withRange:NSMakeRange(0, graphicsPipeline->vertexSamplerCount)]; - [commandBuffer->renderEncoder setVertexTextures:commandBuffer->vertexTextures - withRange:NSMakeRange(0, graphicsPipeline->vertexSamplerCount)]; + if (commandBuffer->needVertexSamplerBind) { + if (graphicsPipeline->vertexSamplerCount > 0) { + [commandBuffer->renderEncoder setVertexSamplerStates:commandBuffer->vertexSamplers + withRange:NSMakeRange(0, graphicsPipeline->vertexSamplerCount)]; + [commandBuffer->renderEncoder setVertexTextures:commandBuffer->vertexTextures + withRange:NSMakeRange(0, graphicsPipeline->vertexSamplerCount)]; + } commandBuffer->needVertexSamplerBind = false; } // Vertex Storage Textures - if (graphicsPipeline->vertexStorageTextureCount > 0 && commandBuffer->needVertexStorageTextureBind) { - [commandBuffer->renderEncoder setVertexTextures:commandBuffer->vertexStorageTextures - withRange:NSMakeRange(graphicsPipeline->vertexSamplerCount, - graphicsPipeline->vertexStorageTextureCount)]; + if (commandBuffer->needVertexStorageTextureBind) { + if (graphicsPipeline->vertexStorageTextureCount > 0) { + [commandBuffer->renderEncoder setVertexTextures:commandBuffer->vertexStorageTextures + withRange:NSMakeRange(graphicsPipeline->vertexSamplerCount, + graphicsPipeline->vertexStorageTextureCount)]; + } commandBuffer->needVertexStorageTextureBind = false; } // Vertex Storage Buffers - if (graphicsPipeline->vertexStorageBufferCount > 0 && commandBuffer->needVertexStorageBufferBind) { - [commandBuffer->renderEncoder setVertexBuffers:commandBuffer->vertexStorageBuffers - offsets:offsets - withRange:NSMakeRange(graphicsPipeline->vertexUniformBufferCount, - graphicsPipeline->vertexStorageBufferCount)]; + if (commandBuffer->needVertexStorageBufferBind) { + if (graphicsPipeline->vertexStorageBufferCount > 0) { + [commandBuffer->renderEncoder setVertexBuffers:commandBuffer->vertexStorageBuffers + offsets:offsets + withRange:NSMakeRange(graphicsPipeline->vertexUniformBufferCount, + graphicsPipeline->vertexStorageBufferCount)]; + } commandBuffer->needVertexStorageBufferBind = false; } // Vertex Uniform Buffers - if (graphicsPipeline->vertexUniformBufferCount > 0 && commandBuffer->needVertexUniformBind) { - for (Uint32 i = 0; i < graphicsPipeline->vertexUniformBufferCount; i += 1) { - [commandBuffer->renderEncoder - setVertexBuffer:commandBuffer->vertexUniformBuffers[i]->handle - offset:commandBuffer->vertexUniformBuffers[i]->drawOffset - atIndex:i]; + for (Uint32 i = 0; i < graphicsPipeline->vertexUniformBufferCount; i += 1) { + if (commandBuffer->needVertexUniformBufferBind[i]) { + if (graphicsPipeline->vertexUniformBufferCount > i) { + [commandBuffer->renderEncoder + setVertexBuffer:commandBuffer->vertexUniformBuffers[i]->handle + offset:commandBuffer->vertexUniformBuffers[i]->drawOffset + atIndex:i]; + } + commandBuffer->needVertexUniformBufferBind[i] = false; } - commandBuffer->needVertexUniformBind = false; } // Fragment Samplers+Textures - if (graphicsPipeline->fragmentSamplerCount > 0 && commandBuffer->needFragmentSamplerBind) { - [commandBuffer->renderEncoder setFragmentSamplerStates:commandBuffer->fragmentSamplers - withRange:NSMakeRange(0, graphicsPipeline->fragmentSamplerCount)]; - [commandBuffer->renderEncoder setFragmentTextures:commandBuffer->fragmentTextures - withRange:NSMakeRange(0, graphicsPipeline->fragmentSamplerCount)]; + if (commandBuffer->needFragmentSamplerBind) { + if (graphicsPipeline->fragmentSamplerCount > 0) { + [commandBuffer->renderEncoder setFragmentSamplerStates:commandBuffer->fragmentSamplers + withRange:NSMakeRange(0, graphicsPipeline->fragmentSamplerCount)]; + [commandBuffer->renderEncoder setFragmentTextures:commandBuffer->fragmentTextures + withRange:NSMakeRange(0, graphicsPipeline->fragmentSamplerCount)]; + } commandBuffer->needFragmentSamplerBind = false; } // Fragment Storage Textures - if (graphicsPipeline->fragmentStorageTextureCount > 0 && commandBuffer->needFragmentStorageTextureBind) { - [commandBuffer->renderEncoder setFragmentTextures:commandBuffer->fragmentStorageTextures - withRange:NSMakeRange(graphicsPipeline->fragmentSamplerCount, - graphicsPipeline->fragmentStorageTextureCount)]; + if (commandBuffer->needFragmentStorageTextureBind) { + if (graphicsPipeline->fragmentStorageTextureCount > 0) { + [commandBuffer->renderEncoder setFragmentTextures:commandBuffer->fragmentStorageTextures + withRange:NSMakeRange(graphicsPipeline->fragmentSamplerCount, + graphicsPipeline->fragmentStorageTextureCount)]; + } commandBuffer->needFragmentStorageTextureBind = false; } // Fragment Storage Buffers - if (graphicsPipeline->fragmentStorageBufferCount > 0 && commandBuffer->needFragmentStorageBufferBind) { - [commandBuffer->renderEncoder setFragmentBuffers:commandBuffer->fragmentStorageBuffers - offsets:offsets - withRange:NSMakeRange(graphicsPipeline->fragmentUniformBufferCount, - graphicsPipeline->fragmentStorageBufferCount)]; + if (commandBuffer->needFragmentStorageBufferBind) { + if (graphicsPipeline->fragmentStorageBufferCount > 0) { + [commandBuffer->renderEncoder setFragmentBuffers:commandBuffer->fragmentStorageBuffers + offsets:offsets + withRange:NSMakeRange(graphicsPipeline->fragmentUniformBufferCount, + graphicsPipeline->fragmentStorageBufferCount)]; + } commandBuffer->needFragmentStorageBufferBind = false; } // Fragment Uniform Buffers - if (graphicsPipeline->fragmentUniformBufferCount > 0 && commandBuffer->needFragmentUniformBind) { - for (Uint32 i = 0; i < graphicsPipeline->fragmentUniformBufferCount; i += 1) { - [commandBuffer->renderEncoder - setFragmentBuffer:commandBuffer->fragmentUniformBuffers[i]->handle - offset:commandBuffer->fragmentUniformBuffers[i]->drawOffset - atIndex:i]; + + for (Uint32 i = 0; i < graphicsPipeline->fragmentUniformBufferCount; i += 1) { + if (commandBuffer->needFragmentUniformBufferBind[i]) { + if (graphicsPipeline->fragmentUniformBufferCount > i) { + [commandBuffer->renderEncoder + setFragmentBuffer:commandBuffer->fragmentUniformBuffers[i]->handle + offset:commandBuffer->fragmentUniformBuffers[i]->drawOffset + atIndex:i]; + } + commandBuffer->needFragmentUniformBufferBind[i] = false; } - commandBuffer->needFragmentUniformBind = false; } } @@ -2720,7 +2748,6 @@ static void METAL_INTERNAL_BindComputeResources( NSUInteger offsets[MAX_STORAGE_BUFFERS_PER_STAGE] = { 0 }; if (commandBuffer->needComputeSamplerBind) { - // Bind sampler textures if (computePipeline->numSamplers > 0) { [commandBuffer->computeEncoder setTextures:commandBuffer->computeSamplerTextures withRange:NSMakeRange(0, computePipeline->numSamplers)]; @@ -2730,54 +2757,36 @@ static void METAL_INTERNAL_BindComputeResources( commandBuffer->needComputeSamplerBind = false; } - if (commandBuffer->needComputeTextureBind) { - // Bind read-only textures + if (commandBuffer->needComputeReadOnlyStorageTextureBind) { if (computePipeline->numReadonlyStorageTextures > 0) { [commandBuffer->computeEncoder setTextures:commandBuffer->computeReadOnlyTextures withRange:NSMakeRange( computePipeline->numSamplers, computePipeline->numReadonlyStorageTextures)]; } - - // Bind write-only textures - if (computePipeline->numReadWriteStorageTextures > 0) { - [commandBuffer->computeEncoder setTextures:commandBuffer->computeReadWriteTextures - withRange:NSMakeRange( - computePipeline->numSamplers + computePipeline->numReadonlyStorageTextures, - computePipeline->numReadWriteStorageTextures)]; - } - commandBuffer->needComputeTextureBind = false; + commandBuffer->needComputeReadOnlyStorageTextureBind = false; } - if (commandBuffer->needComputeBufferBind) { - // Bind read-only buffers + if (commandBuffer->needComputeReadOnlyStorageBufferBind) { if (computePipeline->numReadonlyStorageBuffers > 0) { [commandBuffer->computeEncoder setBuffers:commandBuffer->computeReadOnlyBuffers offsets:offsets withRange:NSMakeRange(computePipeline->numUniformBuffers, computePipeline->numReadonlyStorageBuffers)]; } - // Bind write-only buffers - if (computePipeline->numReadWriteStorageBuffers > 0) { - [commandBuffer->computeEncoder setBuffers:commandBuffer->computeReadWriteBuffers - offsets:offsets - withRange:NSMakeRange( - computePipeline->numUniformBuffers + - computePipeline->numReadonlyStorageBuffers, - computePipeline->numReadWriteStorageBuffers)]; - } - commandBuffer->needComputeBufferBind = false; + commandBuffer->needComputeReadOnlyStorageBufferBind = false; } - if (commandBuffer->needComputeUniformBind) { - for (Uint32 i = 0; i < computePipeline->numUniformBuffers; i += 1) { - [commandBuffer->computeEncoder - setBuffer:commandBuffer->computeUniformBuffers[i]->handle - offset:commandBuffer->computeUniformBuffers[i]->drawOffset - atIndex:i]; + for (Uint32 i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) { + if (commandBuffer->needComputeUniformBufferBind[i]) { + if (computePipeline->numUniformBuffers > i) { + [commandBuffer->computeEncoder + setBuffer:commandBuffer->computeUniformBuffers[i]->handle + offset:commandBuffer->computeUniformBuffers[i]->drawOffset + atIndex:i]; + } } - - commandBuffer->needComputeUniformBind = false; + commandBuffer->needComputeUniformBufferBind[i] = false; } } @@ -2892,6 +2901,11 @@ static void METAL_EndRenderPass( [metalCommandBuffer->renderEncoder endEncoding]; metalCommandBuffer->renderEncoder = nil; + for (Uint32 i = 0; i < MAX_VERTEX_BUFFERS; i += 1) { + metalCommandBuffer->vertexBuffers[i] = nil; + metalCommandBuffer->vertexBufferOffsets[i] = 0; + metalCommandBuffer->vertexBufferCount = 0; + } for (Uint32 i = 0; i < MAX_TEXTURE_SAMPLERS_PER_STAGE; i += 1) { metalCommandBuffer->vertexSamplers[i] = nil; metalCommandBuffer->vertexTextures[i] = nil; @@ -2976,11 +2990,11 @@ static void METAL_INTERNAL_PushUniformData( metalUniformBuffer->writeOffset += alignedDataLength; if (shaderStage == SDL_GPU_SHADERSTAGE_VERTEX) { - metalCommandBuffer->needVertexUniformBind = true; + metalCommandBuffer->needVertexUniformBufferBind[slotIndex] = true; } else if (shaderStage == SDL_GPU_SHADERSTAGE_FRAGMENT) { - metalCommandBuffer->needFragmentUniformBind = true; + metalCommandBuffer->needFragmentUniformBufferBind[slotIndex] = true; } else if (shaderStage == SDL_GPU_SHADERSTAGE_COMPUTE) { - metalCommandBuffer->needComputeUniformBind = true; + metalCommandBuffer->needComputeUniformBufferBind[slotIndex] = true; } else { SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized shader stage!"); } @@ -3078,7 +3092,6 @@ static void METAL_BeginComputePass( slices:NSMakeRange(storageTextureBindings[i].layer, 1)]; metalCommandBuffer->computeReadWriteTextures[i] = textureView; - metalCommandBuffer->needComputeTextureBind = true; } for (Uint32 i = 0; i < numStorageBufferBindings; i += 1) { @@ -3094,7 +3107,6 @@ static void METAL_BeginComputePass( buffer); metalCommandBuffer->computeReadWriteBuffers[i] = buffer->handle; - metalCommandBuffer->needComputeBufferBind = true; } } } @@ -3111,6 +3123,10 @@ static void METAL_BindComputePipeline( [metalCommandBuffer->computeEncoder setComputePipelineState:pipeline->handle]; + for (Uint32 i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) { + metalCommandBuffer->needComputeUniformBufferBind[i] = true; + } + for (Uint32 i = 0; i < pipeline->numUniformBuffers; i += 1) { if (metalCommandBuffer->computeUniformBuffers[i] == NULL) { metalCommandBuffer->computeUniformBuffers[i] = METAL_INTERNAL_AcquireUniformBufferFromPool( @@ -3118,7 +3134,24 @@ static void METAL_BindComputePipeline( } } - metalCommandBuffer->needComputeUniformBind = true; + // Bind write-only resources + if (pipeline->numReadWriteStorageTextures > 0) { + [metalCommandBuffer->computeEncoder setTextures:metalCommandBuffer->computeReadWriteTextures + withRange:NSMakeRange( + pipeline->numSamplers + + pipeline->numReadonlyStorageTextures, + pipeline->numReadWriteStorageTextures)]; + } + + NSUInteger offsets[MAX_COMPUTE_WRITE_BUFFERS] = { 0 }; + if (pipeline->numReadWriteStorageBuffers > 0) { + [metalCommandBuffer->computeEncoder setBuffers:metalCommandBuffer->computeReadWriteBuffers + offsets:offsets + withRange:NSMakeRange( + pipeline->numUniformBuffers + + pipeline->numReadonlyStorageBuffers, + pipeline->numReadWriteStorageBuffers)]; + } } } @@ -3130,22 +3163,28 @@ static void METAL_BindComputeSamplers( { MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer; MetalTextureContainer *textureContainer; + MetalSampler *sampler; for (Uint32 i = 0; i < numBindings; i += 1) { textureContainer = (MetalTextureContainer *)textureSamplerBindings[i].texture; + sampler = (MetalSampler *)textureSamplerBindings[i].sampler; - METAL_INTERNAL_TrackTexture( - metalCommandBuffer, - textureContainer->activeTexture); + if (metalCommandBuffer->computeSamplers[firstSlot + i] != sampler->handle) { + metalCommandBuffer->computeSamplers[firstSlot + i] = sampler->handle; + metalCommandBuffer->needComputeSamplerBind = true; + } - metalCommandBuffer->computeSamplers[firstSlot + i] = - ((MetalSampler *)textureSamplerBindings[i].sampler)->handle; + if (metalCommandBuffer->computeSamplerTextures[firstSlot + i] != textureContainer->activeTexture->handle) { + METAL_INTERNAL_TrackTexture( + metalCommandBuffer, + textureContainer->activeTexture); - metalCommandBuffer->computeSamplerTextures[firstSlot + i] = - textureContainer->activeTexture->handle; + metalCommandBuffer->computeSamplerTextures[firstSlot + i] = + textureContainer->activeTexture->handle; + + metalCommandBuffer->needComputeSamplerBind = true; + } } - - metalCommandBuffer->needComputeSamplerBind = true; } static void METAL_BindComputeStorageTextures( @@ -3160,15 +3199,17 @@ static void METAL_BindComputeStorageTextures( for (Uint32 i = 0; i < numBindings; i += 1) { textureContainer = (MetalTextureContainer *)storageTextures[i]; - METAL_INTERNAL_TrackTexture( - metalCommandBuffer, - textureContainer->activeTexture); + if (metalCommandBuffer->computeReadOnlyTextures[firstSlot + i] != textureContainer->activeTexture->handle) { + METAL_INTERNAL_TrackTexture( + metalCommandBuffer, + textureContainer->activeTexture); - metalCommandBuffer->computeReadOnlyTextures[firstSlot + i] = - textureContainer->activeTexture->handle; + metalCommandBuffer->computeReadOnlyTextures[firstSlot + i] = + textureContainer->activeTexture->handle; + + metalCommandBuffer->needComputeReadOnlyStorageTextureBind = true; + } } - - metalCommandBuffer->needComputeTextureBind = true; } static void METAL_BindComputeStorageBuffers( @@ -3183,15 +3224,17 @@ static void METAL_BindComputeStorageBuffers( for (Uint32 i = 0; i < numBindings; i += 1) { bufferContainer = (MetalBufferContainer *)storageBuffers[i]; - METAL_INTERNAL_TrackBuffer( - metalCommandBuffer, - bufferContainer->activeBuffer); + if (metalCommandBuffer->computeReadOnlyBuffers[firstSlot + i] != bufferContainer->activeBuffer->handle) { + METAL_INTERNAL_TrackBuffer( + metalCommandBuffer, + bufferContainer->activeBuffer); - metalCommandBuffer->computeReadOnlyBuffers[firstSlot + i] = - bufferContainer->activeBuffer->handle; + metalCommandBuffer->computeReadOnlyBuffers[firstSlot + i] = + bufferContainer->activeBuffer->handle; + + metalCommandBuffer->needComputeReadOnlyStorageBufferBind = true; + } } - - metalCommandBuffer->needComputeBufferBind = true; } static void METAL_PushComputeUniformData( @@ -3368,6 +3411,11 @@ static void METAL_INTERNAL_CleanCommandBuffer( commandBuffer->windowDataCount = 0; // Reset bindings + for (i = 0; i < MAX_VERTEX_BUFFERS; i += 1) { + commandBuffer->vertexBuffers[i] = nil; + commandBuffer->vertexBufferOffsets[i] = 0; + } + commandBuffer->vertexBufferCount = 0; commandBuffer->indexBuffer = NULL; for (i = 0; i < MAX_TEXTURE_SAMPLERS_PER_STAGE; i += 1) { commandBuffer->vertexSamplers[i] = nil; @@ -3394,6 +3442,22 @@ static void METAL_INTERNAL_CleanCommandBuffer( commandBuffer->computeReadWriteBuffers[i] = nil; } + commandBuffer->needVertexBufferBind = false; + commandBuffer->needVertexSamplerBind = false; + commandBuffer->needVertexStorageBufferBind = false; + commandBuffer->needVertexStorageTextureBind = false; + SDL_zeroa(commandBuffer->needVertexUniformBufferBind); + + commandBuffer->needFragmentSamplerBind = false; + commandBuffer->needFragmentStorageBufferBind = false; + commandBuffer->needFragmentStorageTextureBind = false; + SDL_zeroa(commandBuffer->needFragmentUniformBufferBind); + + commandBuffer->needComputeSamplerBind = false; + commandBuffer->needComputeReadOnlyStorageBufferBind = false; + commandBuffer->needComputeReadOnlyStorageTextureBind = false; + SDL_zeroa(commandBuffer->needComputeUniformBufferBind); + // The fence is now available (unless SubmitAndAcquireFence was called) if (commandBuffer->autoReleaseFence) { METAL_ReleaseFence( diff --git a/libs/SDL3/src/gpu/vulkan/SDL_gpu_vulkan.c b/libs/SDL3/src/gpu/vulkan/SDL_gpu_vulkan.c index d684ff9d..3014b4b3 100644 --- a/libs/SDL3/src/gpu/vulkan/SDL_gpu_vulkan.c +++ b/libs/SDL3/src/gpu/vulkan/SDL_gpu_vulkan.c @@ -56,8 +56,6 @@ typedef struct VulkanExtensions // Core since 1.2, but requires annoying paperwork to implement Uint8 KHR_driver_properties; - // EXT, probably not going to be Core - Uint8 EXT_vertex_attribute_divisor; // Only required for special implementations (i.e. MoltenVK) Uint8 KHR_portability_subset; // Only required for decoding HDR ASTC textures @@ -755,12 +753,12 @@ typedef struct VulkanPresentData Uint32 swapchainImageIndex; } VulkanPresentData; -typedef struct VulkanUniformBuffer +struct VulkanUniformBuffer { VulkanBuffer *buffer; Uint32 drawOffset; Uint32 writeOffset; -} VulkanUniformBuffer; +}; typedef struct VulkanDescriptorInfo { @@ -1035,6 +1033,11 @@ typedef struct VulkanCommandBuffer VkDescriptorSet computeReadWriteDescriptorSet; VkDescriptorSet computeUniformDescriptorSet; + VkBuffer vertexBuffers[MAX_VERTEX_BUFFERS]; + VkDeviceSize vertexBufferOffsets[MAX_VERTEX_BUFFERS]; + Uint32 vertexBufferCount; + bool needVertexBufferBind; + VulkanTexture *vertexSamplerTextures[MAX_TEXTURE_SAMPLERS_PER_STAGE]; VulkanSampler *vertexSamplers[MAX_TEXTURE_SAMPLERS_PER_STAGE]; VulkanTexture *vertexStorageTextures[MAX_STORAGE_TEXTURES_PER_STAGE]; @@ -1581,7 +1584,7 @@ static void VULKAN_INTERNAL_RemoveMemoryUsedRegion( static bool VULKAN_INTERNAL_CheckMemoryTypeArrayUnique( Uint32 memoryTypeIndex, - Uint32 *memoryTypeIndexArray, + const Uint32 *memoryTypeIndexArray, Uint32 count) { Uint32 i = 0; @@ -2919,57 +2922,74 @@ static void VULKAN_INTERNAL_DestroyFramebuffer( SDL_free(framebuffer); } +typedef struct CheckOneFramebufferForRemovalData +{ + Uint32 keysToRemoveCapacity; + Uint32 keysToRemoveCount; + FramebufferHashTableKey **keysToRemove; + VkImageView view; +} CheckOneFramebufferForRemovalData; + +static bool SDLCALL CheckOneFramebufferForRemoval(void *userdata, const SDL_HashTable *table, const void *vkey, const void *vvalue) +{ + CheckOneFramebufferForRemovalData *data = (CheckOneFramebufferForRemovalData *) userdata; + FramebufferHashTableKey *key = (FramebufferHashTableKey *) vkey; + VkImageView view = data->view; + bool remove = false; + + for (Uint32 i = 0; i < key->numColorTargets; i += 1) { + if (key->colorAttachmentViews[i] == view) { + remove = true; + } + } + for (Uint32 i = 0; i < key->numResolveAttachments; i += 1) { + if (key->resolveAttachmentViews[i] == view) { + remove = true; + } + } + if (key->depthStencilAttachmentView == view) { + remove = true; + } + + if (remove) { + if (data->keysToRemoveCount == data->keysToRemoveCapacity) { + data->keysToRemoveCapacity *= 2; + void *ptr = SDL_realloc(data->keysToRemove, data->keysToRemoveCapacity * sizeof(FramebufferHashTableKey *)); + if (!ptr) { + return false; // ugh, stop iterating. We're in trouble. + } + data->keysToRemove = (FramebufferHashTableKey **) ptr; + } + data->keysToRemove[data->keysToRemoveCount] = key; + data->keysToRemoveCount++; + } + + return true; // keep iterating. +} + static void VULKAN_INTERNAL_RemoveFramebuffersContainingView( VulkanRenderer *renderer, VkImageView view) { - FramebufferHashTableKey *key; - VulkanFramebuffer *value; - void *iter = NULL; - // Can't remove while iterating! - Uint32 keysToRemoveCapacity = 8; - Uint32 keysToRemoveCount = 0; - FramebufferHashTableKey **keysToRemove = SDL_malloc(keysToRemoveCapacity * sizeof(FramebufferHashTableKey *)); + + CheckOneFramebufferForRemovalData data = { 8, 0, NULL, view }; + data.keysToRemove = (FramebufferHashTableKey **) SDL_malloc(data.keysToRemoveCapacity * sizeof(FramebufferHashTableKey *)); + if (!data.keysToRemove) { + return; // uhoh. + } SDL_LockMutex(renderer->framebufferFetchLock); - while (SDL_IterateHashTable(renderer->framebufferHashTable, (const void **)&key, (const void **)&value, &iter)) { - bool remove = false; - for (Uint32 i = 0; i < key->numColorTargets; i += 1) { - if (key->colorAttachmentViews[i] == view) { - remove = true; - } - } - for (Uint32 i = 0; i < key->numResolveAttachments; i += 1) { - if (key->resolveAttachmentViews[i] == view) { - remove = true; - } - } - if (key->depthStencilAttachmentView == view) { - remove = true; - } + SDL_IterateHashTable(renderer->framebufferHashTable, CheckOneFramebufferForRemoval, &data); - if (remove) { - if (keysToRemoveCount == keysToRemoveCapacity) { - keysToRemoveCapacity *= 2; - keysToRemove = SDL_realloc( - keysToRemove, - keysToRemoveCapacity * sizeof(FramebufferHashTableKey *)); - } - - keysToRemove[keysToRemoveCount] = key; - keysToRemoveCount += 1; - } - } - - for (Uint32 i = 0; i < keysToRemoveCount; i += 1) { - SDL_RemoveFromHashTable(renderer->framebufferHashTable, (void *)keysToRemove[i]); + for (Uint32 i = 0; i < data.keysToRemoveCount; i += 1) { + SDL_RemoveFromHashTable(renderer->framebufferHashTable, (void *)data.keysToRemove[i]); } SDL_UnlockMutex(renderer->framebufferFetchLock); - SDL_free(keysToRemove); + SDL_free(data.keysToRemove); } static void VULKAN_INTERNAL_DestroyTexture( @@ -3275,7 +3295,7 @@ static void VULKAN_INTERNAL_DestroyDescriptorSetCache( // Hashtable functions -static Uint32 VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashFunction(const void *key, void *data) +static Uint32 SDLCALL VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashFunction(void *userdata, const void *key) { GraphicsPipelineResourceLayoutHashTableKey *hashTableKey = (GraphicsPipelineResourceLayoutHashTableKey *)key; /* The algorithm for this hashing function @@ -3294,19 +3314,19 @@ static Uint32 VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashFunction(const v result = result * hashFactor + hashTableKey->fragmentUniformBufferCount; return result; } -static bool VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashKeyMatch(const void *aKey, const void *bKey, void *data) +static bool SDLCALL VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashKeyMatch(void *userdata, const void *aKey, const void *bKey) { return SDL_memcmp(aKey, bKey, sizeof(GraphicsPipelineResourceLayoutHashTableKey)) == 0; } -static void VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashNuke(const void *key, const void *value, void *data) +static void SDLCALL VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashDestroy(void *userdata, const void *key, const void *value) { - VulkanRenderer *renderer = (VulkanRenderer *)data; + VulkanRenderer *renderer = (VulkanRenderer *)userdata; VulkanGraphicsPipelineResourceLayout *resourceLayout = (VulkanGraphicsPipelineResourceLayout *)value; VULKAN_INTERNAL_DestroyGraphicsPipelineResourceLayout(renderer, resourceLayout); SDL_free((void*)key); } -static Uint32 VULKAN_INTERNAL_ComputePipelineResourceLayoutHashFunction(const void *key, void *data) +static Uint32 SDLCALL VULKAN_INTERNAL_ComputePipelineResourceLayoutHashFunction(void *userdata, const void *key) { ComputePipelineResourceLayoutHashTableKey *hashTableKey = (ComputePipelineResourceLayoutHashTableKey *)key; /* The algorithm for this hashing function @@ -3324,20 +3344,20 @@ static Uint32 VULKAN_INTERNAL_ComputePipelineResourceLayoutHashFunction(const vo return result; } -static bool VULKAN_INTERNAL_ComputePipelineResourceLayoutHashKeyMatch(const void *aKey, const void *bKey, void *data) +static bool SDLCALL VULKAN_INTERNAL_ComputePipelineResourceLayoutHashKeyMatch(void *userdata, const void *aKey, const void *bKey) { return SDL_memcmp(aKey, bKey, sizeof(ComputePipelineResourceLayoutHashTableKey)) == 0; } -static void VULKAN_INTERNAL_ComputePipelineResourceLayoutHashNuke(const void *key, const void *value, void *data) +static void SDLCALL VULKAN_INTERNAL_ComputePipelineResourceLayoutHashDestroy(void *userdata, const void *key, const void *value) { - VulkanRenderer *renderer = (VulkanRenderer *)data; + VulkanRenderer *renderer = (VulkanRenderer *)userdata; VulkanComputePipelineResourceLayout *resourceLayout = (VulkanComputePipelineResourceLayout *)value; VULKAN_INTERNAL_DestroyComputePipelineResourceLayout(renderer, resourceLayout); SDL_free((void*)key); } -static Uint32 VULKAN_INTERNAL_DescriptorSetLayoutHashFunction(const void *key, void *data) +static Uint32 SDLCALL VULKAN_INTERNAL_DescriptorSetLayoutHashFunction(void *userdata, const void *key) { DescriptorSetLayoutHashTableKey *hashTableKey = (DescriptorSetLayoutHashTableKey *)key; @@ -3357,42 +3377,40 @@ static Uint32 VULKAN_INTERNAL_DescriptorSetLayoutHashFunction(const void *key, v return result; } -static bool VULKAN_INTERNAL_DescriptorSetLayoutHashKeyMatch(const void *aKey, const void *bKey, void *data) +static bool SDLCALL VULKAN_INTERNAL_DescriptorSetLayoutHashKeyMatch(void *userdata, const void *aKey, const void *bKey) { return SDL_memcmp(aKey, bKey, sizeof(DescriptorSetLayoutHashTableKey)) == 0; } -static void VULKAN_INTERNAL_DescriptorSetLayoutHashNuke(const void *key, const void *value, void *data) +static void SDLCALL VULKAN_INTERNAL_DescriptorSetLayoutHashDestroy(void *userdata, const void *key, const void *value) { - VulkanRenderer *renderer = (VulkanRenderer *)data; + VulkanRenderer *renderer = (VulkanRenderer *)userdata; DescriptorSetLayout *layout = (DescriptorSetLayout *)value; VULKAN_INTERNAL_DestroyDescriptorSetLayout(renderer, layout); SDL_free((void*)key); } -static Uint32 VULKAN_INTERNAL_CommandPoolHashFunction(const void *key, void *data) +static Uint32 SDLCALL VULKAN_INTERNAL_CommandPoolHashFunction(void *userdata, const void *key) { return (Uint32)((CommandPoolHashTableKey *)key)->threadID; } -static bool VULKAN_INTERNAL_CommandPoolHashKeyMatch(const void *aKey, const void *bKey, void *data) +static bool SDLCALL VULKAN_INTERNAL_CommandPoolHashKeyMatch(void *userdata, const void *aKey, const void *bKey) { CommandPoolHashTableKey *a = (CommandPoolHashTableKey *)aKey; CommandPoolHashTableKey *b = (CommandPoolHashTableKey *)bKey; return a->threadID == b->threadID; } -static void VULKAN_INTERNAL_CommandPoolHashNuke(const void *key, const void *value, void *data) +static void SDLCALL VULKAN_INTERNAL_CommandPoolHashDestroy(void *userdata, const void *key, const void *value) { - VulkanRenderer *renderer = (VulkanRenderer *)data; + VulkanRenderer *renderer = (VulkanRenderer *)userdata; VulkanCommandPool *pool = (VulkanCommandPool *)value; VULKAN_INTERNAL_DestroyCommandPool(renderer, pool); SDL_free((void *)key); } -static Uint32 VULKAN_INTERNAL_RenderPassHashFunction( - const void *key, - void *data) +static Uint32 SDLCALL VULKAN_INTERNAL_RenderPassHashFunction(void *userdata, const void *key) { RenderPassHashTableKey *hashTableKey = (RenderPassHashTableKey *)key; @@ -3424,10 +3442,7 @@ static Uint32 VULKAN_INTERNAL_RenderPassHashFunction( return result; } -static bool VULKAN_INTERNAL_RenderPassHashKeyMatch( - const void *aKey, - const void *bKey, - void *data) +static bool SDLCALL VULKAN_INTERNAL_RenderPassHashKeyMatch(void *userdata, const void *aKey, const void *bKey) { RenderPassHashTableKey *a = (RenderPassHashTableKey *)aKey; RenderPassHashTableKey *b = (RenderPassHashTableKey *)bKey; @@ -3487,9 +3502,9 @@ static bool VULKAN_INTERNAL_RenderPassHashKeyMatch( return 1; } -static void VULKAN_INTERNAL_RenderPassHashNuke(const void *key, const void *value, void *data) +static void SDLCALL VULKAN_INTERNAL_RenderPassHashDestroy(void *userdata, const void *key, const void *value) { - VulkanRenderer *renderer = (VulkanRenderer *)data; + VulkanRenderer *renderer = (VulkanRenderer *)userdata; VulkanRenderPassHashTableValue *renderPassWrapper = (VulkanRenderPassHashTableValue *)value; renderer->vkDestroyRenderPass( renderer->logicalDevice, @@ -3499,9 +3514,7 @@ static void VULKAN_INTERNAL_RenderPassHashNuke(const void *key, const void *valu SDL_free((void *)key); } -static Uint32 VULKAN_INTERNAL_FramebufferHashFunction( - const void *key, - void *data) +static Uint32 SDLCALL VULKAN_INTERNAL_FramebufferHashFunction(void *userdata, const void *key) { FramebufferHashTableKey *hashTableKey = (FramebufferHashTableKey *)key; @@ -3526,10 +3539,7 @@ static Uint32 VULKAN_INTERNAL_FramebufferHashFunction( return result; } -static bool VULKAN_INTERNAL_FramebufferHashKeyMatch( - const void *aKey, - const void *bKey, - void *data) +static bool SDLCALL VULKAN_INTERNAL_FramebufferHashKeyMatch(void *userdata, const void *aKey, const void *bKey) { FramebufferHashTableKey *a = (FramebufferHashTableKey *)aKey; FramebufferHashTableKey *b = (FramebufferHashTableKey *)bKey; @@ -3569,9 +3579,9 @@ static bool VULKAN_INTERNAL_FramebufferHashKeyMatch( return 1; } -static void VULKAN_INTERNAL_FramebufferHashNuke(const void *key, const void *value, void *data) +static void SDLCALL VULKAN_INTERNAL_FramebufferHashDestroy(void *userdata, const void *key, const void *value) { - VulkanRenderer *renderer = (VulkanRenderer *)data; + VulkanRenderer *renderer = (VulkanRenderer *)userdata; VulkanFramebuffer *framebuffer = (VulkanFramebuffer *)value; VULKAN_INTERNAL_ReleaseFramebuffer(renderer, framebuffer); SDL_free((void *)key); @@ -3636,7 +3646,7 @@ static bool VULKAN_INTERNAL_AllocateDescriptorsFromPool( } for (Uint32 i = descriptorSetLayout->samplerCount; i < descriptorSetLayout->samplerCount + descriptorSetLayout->storageTextureCount; i += 1) { - descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; // Yes, we are declaring the storage image as a sampled image, because shaders are stupid. descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; } @@ -3766,7 +3776,7 @@ static DescriptorSetLayout *VULKAN_INTERNAL_FetchDescriptorSetLayout( 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].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; // Yes, we are declaring the storage image as a sampled image, because shaders are stupid. descriptorSetLayoutBindings[i].stageFlags = shaderStage; descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; } @@ -3840,7 +3850,7 @@ static DescriptorSetLayout *VULKAN_INTERNAL_FetchDescriptorSetLayout( SDL_InsertIntoHashTable( renderer->descriptorSetLayoutHashTable, (const void *)allocedKey, - (const void *)layout); + (const void *)layout, true); return layout; } @@ -3957,7 +3967,7 @@ static VulkanGraphicsPipelineResourceLayout *VULKAN_INTERNAL_FetchGraphicsPipeli SDL_InsertIntoHashTable( renderer->graphicsPipelineResourceLayoutHashTable, (const void *)allocedKey, - (const void *)pipelineResourceLayout); + (const void *)pipelineResourceLayout, true); return pipelineResourceLayout; } @@ -4058,7 +4068,7 @@ static VulkanComputePipelineResourceLayout *VULKAN_INTERNAL_FetchComputePipeline SDL_InsertIntoHashTable( renderer->computePipelineResourceLayoutHashTable, (const void *)allocedKey, - (const void *)pipelineResourceLayout); + (const void *)pipelineResourceLayout, true); return pipelineResourceLayout; } @@ -4436,7 +4446,7 @@ static bool VULKAN_INTERNAL_VerifySwapSurfaceFormat( static bool VULKAN_INTERNAL_VerifySwapPresentMode( VkPresentModeKHR presentMode, - VkPresentModeKHR *availablePresentModes, + const VkPresentModeKHR *availablePresentModes, Uint32 availablePresentModesLength) { Uint32 i; @@ -4624,7 +4634,7 @@ static Uint32 VULKAN_INTERNAL_CreateSwapchain( swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; swapchainCreateInfo.queueFamilyIndexCount = 0; swapchainCreateInfo.pQueueFamilyIndices = NULL; - swapchainCreateInfo.preTransform = swapchainSupportDetails.capabilities.currentTransform; + swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; swapchainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; swapchainCreateInfo.presentMode = SDLToVK_PresentMode[windowData->presentMode]; swapchainCreateInfo.clipped = VK_TRUE; @@ -5027,6 +5037,7 @@ static void VULKAN_INTERNAL_BindGraphicsDescriptorSets( Uint32 dynamicOffsetCount = 0; if ( + !commandBuffer->needVertexBufferBind && !commandBuffer->needNewVertexResourceDescriptorSet && !commandBuffer->needNewVertexUniformDescriptorSet && !commandBuffer->needNewVertexUniformOffsets && @@ -5037,6 +5048,17 @@ static void VULKAN_INTERNAL_BindGraphicsDescriptorSets( return; } + if (commandBuffer->needVertexBufferBind && commandBuffer->vertexBufferCount > 0) { + renderer->vkCmdBindVertexBuffers( + commandBuffer->commandBuffer, + 0, + commandBuffer->vertexBufferCount, + commandBuffer->vertexBuffers, + commandBuffer->vertexBufferOffsets); + + commandBuffer->needVertexBufferBind = false; + } + resourceLayout = commandBuffer->currentGraphicsPipeline->resourceLayout; if (commandBuffer->needNewVertexResourceDescriptorSet) { @@ -5076,7 +5098,7 @@ static void VULKAN_INTERNAL_BindGraphicsDescriptorSets( currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; currentWriteDescriptorSet->descriptorCount = 1; - currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; // Yes, we are declaring a storage image as a sampled image, because shaders are stupid. currentWriteDescriptorSet->dstArrayElement = 0; currentWriteDescriptorSet->dstBinding = resourceLayout->vertexSamplerCount + i; currentWriteDescriptorSet->dstSet = commandBuffer->vertexResourceDescriptorSet; @@ -5195,7 +5217,7 @@ static void VULKAN_INTERNAL_BindGraphicsDescriptorSets( currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; currentWriteDescriptorSet->descriptorCount = 1; - currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; // Yes, we are declaring a storage image as a sampled image, because shaders are stupid. currentWriteDescriptorSet->dstArrayElement = 0; currentWriteDescriptorSet->dstBinding = resourceLayout->fragmentSamplerCount + i; currentWriteDescriptorSet->dstSet = commandBuffer->fragmentResourceDescriptorSet; @@ -5313,7 +5335,7 @@ static void VULKAN_DrawIndexedPrimitives( Uint32 firstInstance) { VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer; + VulkanRenderer *renderer = vulkanCommandBuffer->renderer; VULKAN_INTERNAL_BindGraphicsDescriptorSets(renderer, vulkanCommandBuffer); @@ -5334,7 +5356,7 @@ static void VULKAN_DrawPrimitives( Uint32 firstInstance) { VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer; + VulkanRenderer *renderer = vulkanCommandBuffer->renderer; VULKAN_INTERNAL_BindGraphicsDescriptorSets(renderer, vulkanCommandBuffer); @@ -5353,7 +5375,7 @@ static void VULKAN_DrawPrimitivesIndirect( Uint32 drawCount) { VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer; + VulkanRenderer *renderer = vulkanCommandBuffer->renderer; VulkanBuffer *vulkanBuffer = ((VulkanBufferContainer *)buffer)->activeBuffer; Uint32 pitch = sizeof(SDL_GPUIndirectDrawCommand); Uint32 i; @@ -5390,7 +5412,7 @@ static void VULKAN_DrawIndexedPrimitivesIndirect( Uint32 drawCount) { VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer; + VulkanRenderer *renderer = vulkanCommandBuffer->renderer; VulkanBuffer *vulkanBuffer = ((VulkanBufferContainer *)buffer)->activeBuffer; Uint32 pitch = sizeof(SDL_GPUIndexedIndirectDrawCommand); Uint32 i; @@ -5523,12 +5545,12 @@ static void VULKAN_InsertDebugLabel( const char *text) { VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer; + VulkanRenderer *renderer = vulkanCommandBuffer->renderer; VkDebugUtilsLabelEXT labelInfo; if (renderer->supportsDebugUtils) { + SDL_zero(labelInfo); labelInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; - labelInfo.pNext = NULL; labelInfo.pLabelName = text; renderer->vkCmdInsertDebugUtilsLabelEXT( @@ -5542,12 +5564,12 @@ static void VULKAN_PushDebugGroup( const char *name) { VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer; + VulkanRenderer *renderer = vulkanCommandBuffer->renderer; VkDebugUtilsLabelEXT labelInfo; if (renderer->supportsDebugUtils) { + SDL_zero(labelInfo); labelInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; - labelInfo.pNext = NULL; labelInfo.pLabelName = name; renderer->vkCmdBeginDebugUtilsLabelEXT( @@ -5560,7 +5582,7 @@ static void VULKAN_PopDebugGroup( SDL_GPUCommandBuffer *commandBuffer) { VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer; + VulkanRenderer *renderer = vulkanCommandBuffer->renderer; if (renderer->supportsDebugUtils) { renderer->vkCmdEndDebugUtilsLabelEXT(vulkanCommandBuffer->commandBuffer); @@ -5602,7 +5624,9 @@ static VulkanTexture *VULKAN_INTERNAL_CreateTexture( imageCreateFlags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT; } - if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_SAMPLER) { + if (createinfo->usage & (SDL_GPU_TEXTUREUSAGE_SAMPLER | + SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ | + SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ)) { vkUsageFlags |= VK_IMAGE_USAGE_SAMPLED_BIT; } if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) { @@ -5611,9 +5635,7 @@ static VulkanTexture *VULKAN_INTERNAL_CreateTexture( if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) { vkUsageFlags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; } - if (createinfo->usage & (SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ | - SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ | - SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE | + if (createinfo->usage & (SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE | SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE)) { vkUsageFlags |= VK_IMAGE_USAGE_STORAGE_BIT; } @@ -5672,7 +5694,7 @@ static VulkanTexture *VULKAN_INTERNAL_CreateTexture( imageViewCreateInfo.image = texture->image; imageViewCreateInfo.format = SDLToVK_TextureFormat[createinfo->format]; imageViewCreateInfo.components = texture->swizzle; - imageViewCreateInfo.subresourceRange.aspectMask = texture->aspectFlags; + imageViewCreateInfo.subresourceRange.aspectMask = texture->aspectFlags & ~VK_IMAGE_ASPECT_STENCIL_BIT; // Can't sample stencil values imageViewCreateInfo.subresourceRange.baseMipLevel = 0; imageViewCreateInfo.subresourceRange.levelCount = createinfo->num_levels; imageViewCreateInfo.subresourceRange.baseArrayLayer = 0; @@ -6178,11 +6200,8 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline( VkPipelineShaderStageCreateInfo shaderStageCreateInfos[2]; VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo; - VkPipelineVertexInputDivisorStateCreateInfoEXT divisorStateCreateInfo; VkVertexInputBindingDescription *vertexInputBindingDescriptions = SDL_stack_alloc(VkVertexInputBindingDescription, createinfo->vertex_input_state.num_vertex_buffers); VkVertexInputAttributeDescription *vertexInputAttributeDescriptions = SDL_stack_alloc(VkVertexInputAttributeDescription, createinfo->vertex_input_state.num_vertex_attributes); - VkVertexInputBindingDivisorDescriptionEXT *divisorDescriptions = SDL_stack_alloc(VkVertexInputBindingDivisorDescriptionEXT, createinfo->vertex_input_state.num_vertex_buffers); - Uint32 divisorDescriptionCount = 0; VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo; @@ -6265,10 +6284,6 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline( vertexInputBindingDescriptions[i].binding = createinfo->vertex_input_state.vertex_buffer_descriptions[i].slot; vertexInputBindingDescriptions[i].inputRate = SDLToVK_VertexInputRate[createinfo->vertex_input_state.vertex_buffer_descriptions[i].input_rate]; vertexInputBindingDescriptions[i].stride = createinfo->vertex_input_state.vertex_buffer_descriptions[i].pitch; - - if (createinfo->vertex_input_state.vertex_buffer_descriptions[i].input_rate == SDL_GPU_VERTEXINPUTRATE_INSTANCE) { - divisorDescriptionCount += 1; - } } for (i = 0; i < createinfo->vertex_input_state.num_vertex_attributes; i += 1) { @@ -6286,26 +6301,6 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline( vertexInputStateCreateInfo.vertexAttributeDescriptionCount = createinfo->vertex_input_state.num_vertex_attributes; vertexInputStateCreateInfo.pVertexAttributeDescriptions = vertexInputAttributeDescriptions; - if (divisorDescriptionCount > 0) { - divisorDescriptionCount = 0; - - for (i = 0; i < createinfo->vertex_input_state.num_vertex_buffers; i += 1) { - if (createinfo->vertex_input_state.vertex_buffer_descriptions[i].input_rate == SDL_GPU_VERTEXINPUTRATE_INSTANCE) { - divisorDescriptions[divisorDescriptionCount].binding = createinfo->vertex_input_state.vertex_buffer_descriptions[i].slot; - divisorDescriptions[divisorDescriptionCount].divisor = createinfo->vertex_input_state.vertex_buffer_descriptions[i].instance_step_rate; - - divisorDescriptionCount += 1; - } - } - - divisorStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT; - divisorStateCreateInfo.pNext = NULL; - divisorStateCreateInfo.vertexBindingDivisorCount = divisorDescriptionCount; - divisorStateCreateInfo.pVertexBindingDivisors = divisorDescriptions; - - vertexInputStateCreateInfo.pNext = &divisorStateCreateInfo; - } - // Topology inputAssemblyStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; @@ -6352,9 +6347,7 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline( // Multisample - Uint32 sampleMask = createinfo->multisample_state.enable_mask ? - createinfo->multisample_state.sample_mask : - 0xFFFFFFFF; + Uint32 sampleMask = 0xFFFFFFFF; multisampleStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; multisampleStateCreateInfo.pNext = NULL; @@ -6452,7 +6445,6 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline( SDL_stack_free(vertexInputBindingDescriptions); SDL_stack_free(vertexInputAttributeDescriptions); SDL_stack_free(colorBlendAttachmentStates); - SDL_stack_free(divisorDescriptions); SDL_free(graphicsPipeline); SET_STRING_ERROR_AND_RETURN("Failed to initialize pipeline resource layout!", NULL); } @@ -6491,7 +6483,6 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline( SDL_stack_free(vertexInputBindingDescriptions); SDL_stack_free(vertexInputAttributeDescriptions); SDL_stack_free(colorBlendAttachmentStates); - SDL_stack_free(divisorDescriptions); renderer->vkDestroyRenderPass( renderer->logicalDevice, @@ -6823,15 +6814,12 @@ static SDL_GPUTransferBuffer *VULKAN_CreateTransferBuffer( Uint32 size, const char *debugName) { - // We use dedicated allocations for download buffers to avoid an issue - // where a defrag is triggered after submitting a download but before - // waiting on the fence. return (SDL_GPUTransferBuffer *)VULKAN_INTERNAL_CreateBufferContainer( (VulkanRenderer *)driverData, (VkDeviceSize)size, 0, VULKAN_BUFFER_TYPE_TRANSFER, - usage == SDL_GPU_TRANSFERBUFFERUSAGE_DOWNLOAD, + true, // Dedicated allocations preserve the data even if a defrag is triggered. debugName); } @@ -7123,7 +7111,7 @@ static VkRenderPass VULKAN_INTERNAL_FetchRenderPass( SDL_InsertIntoHashTable( renderer->renderPassHashTable, (const void *)allocedKey, - (const void *)renderPassWrapper); + (const void *)renderPassWrapper, true); return renderPassHandle; } @@ -7268,7 +7256,7 @@ static VulkanFramebuffer *VULKAN_INTERNAL_FetchFramebuffer( SDL_InsertIntoHashTable( renderer->framebufferHashTable, (const void *)allocedKey, - (const void *)vulkanFramebuffer); + (const void *)vulkanFramebuffer, true); SDL_UnlockMutex(renderer->framebufferFetchLock); } else { @@ -7283,8 +7271,8 @@ static void VULKAN_INTERNAL_SetCurrentViewport( VulkanCommandBuffer *commandBuffer, const SDL_GPUViewport *viewport) { - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer; + VulkanCommandBuffer *vulkanCommandBuffer = commandBuffer; + VulkanRenderer *renderer = vulkanCommandBuffer->renderer; vulkanCommandBuffer->currentViewport.x = viewport->x; vulkanCommandBuffer->currentViewport.width = viewport->w; @@ -7317,7 +7305,7 @@ static void VULKAN_INTERNAL_SetCurrentScissor( VulkanCommandBuffer *vulkanCommandBuffer, const SDL_Rect *scissor) { - VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer; + VulkanRenderer *renderer = vulkanCommandBuffer->renderer; vulkanCommandBuffer->currentScissor.offset.x = scissor->x; vulkanCommandBuffer->currentScissor.offset.y = scissor->y; @@ -7346,7 +7334,7 @@ static void VULKAN_INTERNAL_SetCurrentBlendConstants( VulkanCommandBuffer *vulkanCommandBuffer, SDL_FColor blendConstants) { - VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer; + VulkanRenderer *renderer = vulkanCommandBuffer->renderer; vulkanCommandBuffer->blendConstants[0] = blendConstants.r; vulkanCommandBuffer->blendConstants[1] = blendConstants.g; @@ -7373,7 +7361,7 @@ static void VULKAN_INTERNAL_SetCurrentStencilReference( VulkanCommandBuffer *vulkanCommandBuffer, Uint8 reference) { - VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer; + VulkanRenderer *renderer = vulkanCommandBuffer->renderer; vulkanCommandBuffer->stencilRef = reference; @@ -7404,19 +7392,26 @@ static void VULKAN_BindVertexSamplers( for (Uint32 i = 0; i < numBindings; i += 1) { VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)textureSamplerBindings[i].texture; - vulkanCommandBuffer->vertexSamplerTextures[firstSlot + i] = textureContainer->activeTexture; - vulkanCommandBuffer->vertexSamplers[firstSlot + i] = (VulkanSampler *)textureSamplerBindings[i].sampler; + VulkanSampler *sampler = (VulkanSampler *)textureSamplerBindings[i].sampler; - VULKAN_INTERNAL_TrackSampler( - vulkanCommandBuffer, - (VulkanSampler *)textureSamplerBindings[i].sampler); + if (vulkanCommandBuffer->vertexSamplers[firstSlot + i] != sampler) { + VULKAN_INTERNAL_TrackSampler( + vulkanCommandBuffer, + (VulkanSampler *)textureSamplerBindings[i].sampler); - VULKAN_INTERNAL_TrackTexture( - vulkanCommandBuffer, - textureContainer->activeTexture); + vulkanCommandBuffer->vertexSamplers[firstSlot + i] = (VulkanSampler *)textureSamplerBindings[i].sampler; + vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true; + } + + if (vulkanCommandBuffer->vertexSamplerTextures[firstSlot + i] != textureContainer->activeTexture) { + VULKAN_INTERNAL_TrackTexture( + vulkanCommandBuffer, + textureContainer->activeTexture); + + vulkanCommandBuffer->vertexSamplerTextures[firstSlot + i] = textureContainer->activeTexture; + vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true; + } } - - vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true; } static void VULKAN_BindVertexStorageTextures( @@ -7430,14 +7425,15 @@ static void VULKAN_BindVertexStorageTextures( for (Uint32 i = 0; i < numBindings; i += 1) { VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)storageTextures[i]; - vulkanCommandBuffer->vertexStorageTextures[firstSlot + i] = textureContainer->activeTexture; + if (vulkanCommandBuffer->vertexStorageTextures[firstSlot + i] != textureContainer->activeTexture) { + VULKAN_INTERNAL_TrackTexture( + vulkanCommandBuffer, + textureContainer->activeTexture); - VULKAN_INTERNAL_TrackTexture( - vulkanCommandBuffer, - textureContainer->activeTexture); + vulkanCommandBuffer->vertexStorageTextures[firstSlot + i] = textureContainer->activeTexture; + vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true; + } } - - vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true; } static void VULKAN_BindVertexStorageBuffers( @@ -7447,20 +7443,19 @@ static void VULKAN_BindVertexStorageBuffers( Uint32 numBindings) { VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanBufferContainer *bufferContainer; - Uint32 i; - for (i = 0; i < numBindings; i += 1) { - bufferContainer = (VulkanBufferContainer *)storageBuffers[i]; + for (Uint32 i = 0; i < numBindings; i += 1) { + VulkanBufferContainer *bufferContainer = (VulkanBufferContainer *)storageBuffers[i]; - vulkanCommandBuffer->vertexStorageBuffers[firstSlot + i] = bufferContainer->activeBuffer; + if (vulkanCommandBuffer->vertexStorageBuffers[firstSlot + i] != bufferContainer->activeBuffer) { + VULKAN_INTERNAL_TrackBuffer( + vulkanCommandBuffer, + bufferContainer->activeBuffer); - VULKAN_INTERNAL_TrackBuffer( - vulkanCommandBuffer, - bufferContainer->activeBuffer); + vulkanCommandBuffer->vertexStorageBuffers[firstSlot + i] = bufferContainer->activeBuffer; + vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true; + } } - - vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true; } static void VULKAN_BindFragmentSamplers( @@ -7473,19 +7468,26 @@ static void VULKAN_BindFragmentSamplers( for (Uint32 i = 0; i < numBindings; i += 1) { VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)textureSamplerBindings[i].texture; - vulkanCommandBuffer->fragmentSamplerTextures[firstSlot + i] = textureContainer->activeTexture; - vulkanCommandBuffer->fragmentSamplers[firstSlot + i] = (VulkanSampler *)textureSamplerBindings[i].sampler; + VulkanSampler *sampler = (VulkanSampler *)textureSamplerBindings[i].sampler; - VULKAN_INTERNAL_TrackSampler( - vulkanCommandBuffer, - (VulkanSampler *)textureSamplerBindings[i].sampler); + if (vulkanCommandBuffer->fragmentSamplers[firstSlot + i] != sampler) { + VULKAN_INTERNAL_TrackSampler( + vulkanCommandBuffer, + (VulkanSampler *)textureSamplerBindings[i].sampler); - VULKAN_INTERNAL_TrackTexture( - vulkanCommandBuffer, - textureContainer->activeTexture); + vulkanCommandBuffer->fragmentSamplers[firstSlot + i] = (VulkanSampler *)textureSamplerBindings[i].sampler; + vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true; + } + + if (vulkanCommandBuffer->fragmentSamplerTextures[firstSlot + i] != textureContainer->activeTexture) { + VULKAN_INTERNAL_TrackTexture( + vulkanCommandBuffer, + textureContainer->activeTexture); + + vulkanCommandBuffer->fragmentSamplerTextures[firstSlot + i] = textureContainer->activeTexture; + vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true; + } } - - vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true; } static void VULKAN_BindFragmentStorageTextures( @@ -7499,15 +7501,15 @@ static void VULKAN_BindFragmentStorageTextures( for (Uint32 i = 0; i < numBindings; i += 1) { VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)storageTextures[i]; - vulkanCommandBuffer->fragmentStorageTextures[firstSlot + i] = - textureContainer->activeTexture; + if (vulkanCommandBuffer->fragmentStorageTextures[firstSlot + i] != textureContainer->activeTexture) { + VULKAN_INTERNAL_TrackTexture( + vulkanCommandBuffer, + textureContainer->activeTexture); - VULKAN_INTERNAL_TrackTexture( - vulkanCommandBuffer, - textureContainer->activeTexture); + vulkanCommandBuffer->fragmentStorageTextures[firstSlot + i] = textureContainer->activeTexture; + vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true; + } } - - vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true; } static void VULKAN_BindFragmentStorageBuffers( @@ -7523,14 +7525,15 @@ static void VULKAN_BindFragmentStorageBuffers( for (i = 0; i < numBindings; i += 1) { bufferContainer = (VulkanBufferContainer *)storageBuffers[i]; - vulkanCommandBuffer->fragmentStorageBuffers[firstSlot + i] = bufferContainer->activeBuffer; + if (vulkanCommandBuffer->fragmentStorageBuffers[firstSlot + i] != bufferContainer->activeBuffer) { + VULKAN_INTERNAL_TrackBuffer( + vulkanCommandBuffer, + bufferContainer->activeBuffer); - VULKAN_INTERNAL_TrackBuffer( - vulkanCommandBuffer, - bufferContainer->activeBuffer); + vulkanCommandBuffer->fragmentStorageBuffers[firstSlot + i] = bufferContainer->activeBuffer; + vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true; + } } - - vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true; } static VulkanUniformBuffer *VULKAN_INTERNAL_AcquireUniformBufferFromPool( @@ -7667,7 +7670,7 @@ static void VULKAN_BeginRenderPass( const SDL_GPUDepthStencilTargetInfo *depthStencilTargetInfo) { VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer; + VulkanRenderer *renderer = vulkanCommandBuffer->renderer; VkRenderPass renderPass; VulkanFramebuffer *framebuffer; @@ -7879,7 +7882,7 @@ static void VULKAN_BindGraphicsPipeline( SDL_GPUGraphicsPipeline *graphicsPipeline) { VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer; + VulkanRenderer *renderer = vulkanCommandBuffer->renderer; VulkanGraphicsPipeline *pipeline = (VulkanGraphicsPipeline *)graphicsPipeline; renderer->vkCmdBindPipeline( @@ -7922,28 +7925,20 @@ static void VULKAN_BindVertexBuffers( Uint32 numBindings) { VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer; - VulkanBuffer *currentVulkanBuffer; - VkBuffer *buffers = SDL_stack_alloc(VkBuffer, numBindings); - VkDeviceSize *offsets = SDL_stack_alloc(VkDeviceSize, numBindings); - Uint32 i; - for (i = 0; i < numBindings; i += 1) { - currentVulkanBuffer = ((VulkanBufferContainer *)bindings[i].buffer)->activeBuffer; - buffers[i] = currentVulkanBuffer->buffer; - offsets[i] = (VkDeviceSize)bindings[i].offset; - VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, currentVulkanBuffer); + for (Uint32 i = 0; i < numBindings; i += 1) { + VulkanBuffer *buffer = ((VulkanBufferContainer *)bindings[i].buffer)->activeBuffer; + if (vulkanCommandBuffer->vertexBuffers[i] != buffer->buffer || vulkanCommandBuffer->vertexBufferOffsets[i] != bindings[i].offset) { + VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, buffer); + + vulkanCommandBuffer->vertexBuffers[i] = buffer->buffer; + vulkanCommandBuffer->vertexBufferOffsets[i] = bindings[i].offset; + vulkanCommandBuffer->needVertexBufferBind = true; + } } - renderer->vkCmdBindVertexBuffers( - vulkanCommandBuffer->commandBuffer, - firstSlot, - numBindings, - buffers, - offsets); - - SDL_stack_free(buffers); - SDL_stack_free(offsets); + vulkanCommandBuffer->vertexBufferCount = + SDL_max(vulkanCommandBuffer->vertexBufferCount, firstSlot + numBindings); } static void VULKAN_BindIndexBuffer( @@ -7952,7 +7947,7 @@ static void VULKAN_BindIndexBuffer( SDL_GPUIndexElementSize indexElementSize) { VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer; + VulkanRenderer *renderer = vulkanCommandBuffer->renderer; VulkanBuffer *vulkanBuffer = ((VulkanBufferContainer *)binding->buffer)->activeBuffer; VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, vulkanBuffer); @@ -8000,7 +7995,7 @@ static void VULKAN_EndRenderPass( SDL_GPUCommandBuffer *commandBuffer) { VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer; + VulkanRenderer *renderer = vulkanCommandBuffer->renderer; Uint32 i; renderer->vkCmdEndRenderPass( @@ -8045,6 +8040,10 @@ static void VULKAN_EndRenderPass( SDL_zeroa(vulkanCommandBuffer->resolveAttachmentSubresources); vulkanCommandBuffer->depthStencilAttachmentSubresource = NULL; + SDL_zeroa(vulkanCommandBuffer->vertexBuffers); + SDL_zeroa(vulkanCommandBuffer->vertexBufferOffsets); + vulkanCommandBuffer->vertexBufferCount = 0; + SDL_zeroa(vulkanCommandBuffer->vertexSamplers); SDL_zeroa(vulkanCommandBuffer->vertexSamplerTextures); SDL_zeroa(vulkanCommandBuffer->vertexStorageTextures); @@ -8111,7 +8110,7 @@ static void VULKAN_BindComputePipeline( SDL_GPUComputePipeline *computePipeline) { VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer; + VulkanRenderer *renderer = vulkanCommandBuffer->renderer; VulkanComputePipeline *vulkanComputePipeline = (VulkanComputePipeline *)computePipeline; renderer->vkCmdBindPipeline( @@ -8148,19 +8147,26 @@ static void VULKAN_BindComputeSamplers( for (Uint32 i = 0; i < numBindings; i += 1) { VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)textureSamplerBindings[i].texture; - vulkanCommandBuffer->computeSamplerTextures[firstSlot + i] = textureContainer->activeTexture; - vulkanCommandBuffer->computeSamplers[firstSlot + i] = (VulkanSampler *)textureSamplerBindings[i].sampler; + VulkanSampler *sampler = (VulkanSampler *)textureSamplerBindings[i].sampler; - VULKAN_INTERNAL_TrackSampler( - vulkanCommandBuffer, - (VulkanSampler *)textureSamplerBindings[i].sampler); + if (vulkanCommandBuffer->computeSamplers[firstSlot + i] != sampler) { + VULKAN_INTERNAL_TrackSampler( + vulkanCommandBuffer, + sampler); - VULKAN_INTERNAL_TrackTexture( - vulkanCommandBuffer, - textureContainer->activeTexture); + vulkanCommandBuffer->computeSamplers[firstSlot + i] = sampler; + vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true; + } + + if (vulkanCommandBuffer->computeSamplerTextures[firstSlot + i] != textureContainer->activeTexture) { + VULKAN_INTERNAL_TrackTexture( + vulkanCommandBuffer, + textureContainer->activeTexture); + + vulkanCommandBuffer->computeSamplerTextures[firstSlot + i] = textureContainer->activeTexture; + vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true; + } } - - vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true; } static void VULKAN_BindComputeStorageTextures( @@ -8173,31 +8179,34 @@ static void VULKAN_BindComputeStorageTextures( VulkanRenderer *renderer = vulkanCommandBuffer->renderer; for (Uint32 i = 0; i < numBindings; i += 1) { - if (vulkanCommandBuffer->readOnlyComputeStorageTextures[firstSlot + i] != NULL) { - VULKAN_INTERNAL_TextureTransitionToDefaultUsage( + VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)storageTextures[i]; + + if (vulkanCommandBuffer->readOnlyComputeStorageTextures[firstSlot + i] != textureContainer->activeTexture) { + /* If a different texture as in this slot, transition it back to its default usage */ + if (vulkanCommandBuffer->readOnlyComputeStorageTextures[firstSlot + i] != NULL) { + VULKAN_INTERNAL_TextureTransitionToDefaultUsage( + renderer, + vulkanCommandBuffer, + VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ, + vulkanCommandBuffer->readOnlyComputeStorageTextures[firstSlot + i]); + } + + /* Then transition the new texture and prepare it for binding */ + VULKAN_INTERNAL_TextureTransitionFromDefaultUsage( renderer, vulkanCommandBuffer, VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ, - vulkanCommandBuffer->readOnlyComputeStorageTextures[firstSlot + i]); + textureContainer->activeTexture); + + + VULKAN_INTERNAL_TrackTexture( + vulkanCommandBuffer, + textureContainer->activeTexture); + + vulkanCommandBuffer->readOnlyComputeStorageTextures[firstSlot + i] = textureContainer->activeTexture; + vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true; } - - VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)storageTextures[i]; - - vulkanCommandBuffer->readOnlyComputeStorageTextures[firstSlot + i] = - textureContainer->activeTexture; - - VULKAN_INTERNAL_TextureTransitionFromDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ, - textureContainer->activeTexture); - - VULKAN_INTERNAL_TrackTexture( - vulkanCommandBuffer, - textureContainer->activeTexture); } - - vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true; } static void VULKAN_BindComputeStorageBuffers( @@ -8208,34 +8217,35 @@ static void VULKAN_BindComputeStorageBuffers( { VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - VulkanBufferContainer *bufferContainer; - Uint32 i; - for (i = 0; i < numBindings; i += 1) { - if (vulkanCommandBuffer->readOnlyComputeStorageBuffers[firstSlot + i] != NULL) { - VULKAN_INTERNAL_BufferTransitionToDefaultUsage( + for (Uint32 i = 0; i < numBindings; i += 1) { + VulkanBufferContainer *bufferContainer = (VulkanBufferContainer *)storageBuffers[i]; + + if (vulkanCommandBuffer->readOnlyComputeStorageBuffers[firstSlot + i] != bufferContainer->activeBuffer) { + /* If a different buffer was in this slot, transition it back to its default usage */ + if (vulkanCommandBuffer->readOnlyComputeStorageBuffers[firstSlot + i] != NULL) { + VULKAN_INTERNAL_BufferTransitionToDefaultUsage( + renderer, + vulkanCommandBuffer, + VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ, + vulkanCommandBuffer->readOnlyComputeStorageBuffers[firstSlot + i]); + } + + /* Then transition the new buffer and prepare it for binding */ + VULKAN_INTERNAL_BufferTransitionFromDefaultUsage( renderer, vulkanCommandBuffer, VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ, - vulkanCommandBuffer->readOnlyComputeStorageBuffers[firstSlot + i]); + bufferContainer->activeBuffer); + + VULKAN_INTERNAL_TrackBuffer( + vulkanCommandBuffer, + bufferContainer->activeBuffer); + + vulkanCommandBuffer->readOnlyComputeStorageBuffers[firstSlot + i] = bufferContainer->activeBuffer; + vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true; } - - bufferContainer = (VulkanBufferContainer *)storageBuffers[i]; - - vulkanCommandBuffer->readOnlyComputeStorageBuffers[firstSlot + i] = bufferContainer->activeBuffer; - - VULKAN_INTERNAL_BufferTransitionFromDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ, - bufferContainer->activeBuffer); - - VULKAN_INTERNAL_TrackBuffer( - vulkanCommandBuffer, - bufferContainer->activeBuffer); } - - vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true; } static void VULKAN_PushComputeUniformData( @@ -8323,7 +8333,7 @@ static void VULKAN_INTERNAL_BindComputeDescriptorSets( currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; currentWriteDescriptorSet->descriptorCount = 1; - currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; // Yes, we are declaring the readonly storage texture as a sampled image, because shaders are stupid. currentWriteDescriptorSet->dstArrayElement = 0; currentWriteDescriptorSet->dstBinding = resourceLayout->numSamplers + i; currentWriteDescriptorSet->dstSet = commandBuffer->computeReadOnlyDescriptorSet; @@ -8495,7 +8505,7 @@ static void VULKAN_DispatchCompute( Uint32 groupcountZ) { VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer; + VulkanRenderer *renderer = vulkanCommandBuffer->renderer; VULKAN_INTERNAL_BindComputeDescriptorSets(renderer, vulkanCommandBuffer); @@ -8512,7 +8522,7 @@ static void VULKAN_DispatchComputeIndirect( Uint32 offset) { VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer; + VulkanRenderer *renderer = vulkanCommandBuffer->renderer; VulkanBuffer *vulkanBuffer = ((VulkanBufferContainer *)buffer)->activeBuffer; VULKAN_INTERNAL_BindComputeDescriptorSets(renderer, vulkanCommandBuffer); @@ -8634,7 +8644,7 @@ static void VULKAN_UploadToTexture( bool cycle) { VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer; + VulkanRenderer *renderer = vulkanCommandBuffer->renderer; VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer *)source->transfer_buffer; VulkanTextureContainer *vulkanTextureContainer = (VulkanTextureContainer *)destination->texture; VulkanTextureSubresource *vulkanTextureSubresource; @@ -8690,7 +8700,7 @@ static void VULKAN_UploadToBuffer( bool cycle) { VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer; + VulkanRenderer *renderer = vulkanCommandBuffer->renderer; VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer *)source->transfer_buffer; VulkanBufferContainer *bufferContainer = (VulkanBufferContainer *)destination->buffer; VkBufferCopy bufferCopy; @@ -8833,7 +8843,7 @@ static void VULKAN_CopyTextureToTexture( bool cycle) { VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer; + VulkanRenderer *renderer = vulkanCommandBuffer->renderer; VulkanTextureSubresource *srcSubresource; VulkanTextureSubresource *dstSubresource; VkImageCopy imageCopy; @@ -8909,7 +8919,7 @@ static void VULKAN_CopyBufferToBuffer( bool cycle) { VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer; + VulkanRenderer *renderer = vulkanCommandBuffer->renderer; VulkanBufferContainer *srcContainer = (VulkanBufferContainer *)source->buffer; VulkanBufferContainer *dstContainer = (VulkanBufferContainer *)destination->buffer; VkBufferCopy bufferCopy; @@ -8959,7 +8969,7 @@ static void VULKAN_GenerateMipmaps( SDL_GPUTexture *texture) { VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer; + VulkanRenderer *renderer = vulkanCommandBuffer->renderer; VulkanTextureContainer *container = (VulkanTextureContainer *)texture; VulkanTextureSubresource *srcTextureSubresource; VulkanTextureSubresource *dstTextureSubresource; @@ -9060,7 +9070,7 @@ static void VULKAN_Blit( const SDL_GPUBlitInfo *info) { VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer; + VulkanRenderer *renderer = vulkanCommandBuffer->renderer; TextureCommonHeader *srcHeader = (TextureCommonHeader *)info->source.texture; TextureCommonHeader *dstHeader = (TextureCommonHeader *)info->destination.texture; VkImageBlit region; @@ -9226,6 +9236,7 @@ static bool VULKAN_INTERNAL_AllocateCommandBuffer( // Resource bind tracking + commandBuffer->needVertexBufferBind = false; commandBuffer->needNewVertexResourceDescriptorSet = true; commandBuffer->needNewVertexUniformDescriptorSet = true; commandBuffer->needNewVertexUniformOffsets = true; @@ -9349,7 +9360,7 @@ static VulkanCommandPool *VULKAN_INTERNAL_FetchCommandPool( SDL_InsertIntoHashTable( renderer->commandPoolHashTable, (const void *)allocedKey, - (const void *)vulkanCommandPool); + (const void *)vulkanCommandPool, true); return vulkanCommandPool; } @@ -9419,6 +9430,7 @@ static SDL_GPUCommandBuffer *VULKAN_AcquireCommandBuffer( commandBuffer->computeUniformBuffers[i] = NULL; } + commandBuffer->needVertexBufferBind = false; commandBuffer->needNewVertexResourceDescriptorSet = true; commandBuffer->needNewVertexUniformDescriptorSet = true; commandBuffer->needNewVertexUniformOffsets = true; @@ -9439,6 +9451,10 @@ static SDL_GPUCommandBuffer *VULKAN_AcquireCommandBuffer( commandBuffer->computeReadWriteDescriptorSet = VK_NULL_HANDLE; commandBuffer->computeUniformDescriptorSet = VK_NULL_HANDLE; + SDL_zeroa(commandBuffer->vertexBuffers); + SDL_zeroa(commandBuffer->vertexBufferOffsets); + commandBuffer->vertexBufferCount = 0; + SDL_zeroa(commandBuffer->vertexSamplerTextures); SDL_zeroa(commandBuffer->vertexSamplers); SDL_zeroa(commandBuffer->vertexStorageTextures); @@ -9787,7 +9803,7 @@ static bool VULKAN_INTERNAL_AcquireSwapchainTexture( Uint32 *swapchainTextureHeight) { VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer; + VulkanRenderer *renderer = vulkanCommandBuffer->renderer; Uint32 swapchainImageIndex; WindowData *windowData; VkResult acquireResult = VK_SUCCESS; @@ -9868,8 +9884,6 @@ static bool VULKAN_INTERNAL_AcquireSwapchainTexture( VK_NULL_HANDLE, &swapchainImageIndex); - //if (acquireResult == VK_ERROR_OUT_OF_DATE_KHR) { SDL_Log("VULKAN SWAPCHAIN OUT OF DATE"); } - if (acquireResult == VK_SUCCESS || acquireResult == VK_SUBOPTIMAL_KHR) { break; // we got the next image! } @@ -10407,7 +10421,7 @@ static bool VULKAN_Submit( SDL_GPUCommandBuffer *commandBuffer) { VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer; + VulkanRenderer *renderer = vulkanCommandBuffer->renderer; VkSubmitInfo submitInfo; VkPresentInfoKHR presentInfo; VulkanPresentData *presentData; @@ -10848,7 +10862,7 @@ static inline Uint8 CheckDeviceExtensions( supports->ext = 1; \ } CHECK(KHR_swapchain) - else CHECK(KHR_maintenance1) else CHECK(KHR_driver_properties) else CHECK(EXT_vertex_attribute_divisor) else CHECK(KHR_portability_subset) else CHECK(EXT_texture_compression_astc_hdr) + else CHECK(KHR_maintenance1) else CHECK(KHR_driver_properties) else CHECK(KHR_portability_subset) else CHECK(EXT_texture_compression_astc_hdr) #undef CHECK } @@ -10862,7 +10876,6 @@ static inline Uint32 GetDeviceExtensionCount(VulkanExtensions *supports) supports->KHR_swapchain + supports->KHR_maintenance1 + supports->KHR_driver_properties + - supports->EXT_vertex_attribute_divisor + supports->KHR_portability_subset + supports->EXT_texture_compression_astc_hdr); } @@ -10879,7 +10892,6 @@ static inline void CreateDeviceExtensionArray( CHECK(KHR_swapchain) CHECK(KHR_maintenance1) CHECK(KHR_driver_properties) - CHECK(EXT_vertex_attribute_divisor) CHECK(KHR_portability_subset) CHECK(EXT_texture_compression_astc_hdr) #undef CHECK @@ -11180,7 +11192,7 @@ static Uint8 VULKAN_INTERNAL_IsDeviceSuitable( &queueFamilyCount, NULL); - queueProps = (VkQueueFamilyProperties *)SDL_stack_alloc( + queueProps = SDL_stack_alloc( VkQueueFamilyProperties, queueFamilyCount); renderer->vkGetPhysicalDeviceQueueFamilyProperties( @@ -11696,59 +11708,53 @@ static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, S // Initialize caches - // manually synchronized due to submission timing renderer->commandPoolHashTable = SDL_CreateHashTable( - (void *)renderer, - 64, + 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful. + false, // manually synchronized due to submission timing VULKAN_INTERNAL_CommandPoolHashFunction, VULKAN_INTERNAL_CommandPoolHashKeyMatch, - VULKAN_INTERNAL_CommandPoolHashNuke, - false, false); + VULKAN_INTERNAL_CommandPoolHashDestroy, + (void *)renderer); - // thread-safe renderer->renderPassHashTable = SDL_CreateHashTable( - (void *)renderer, - 64, + 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful. + true, // thread-safe VULKAN_INTERNAL_RenderPassHashFunction, VULKAN_INTERNAL_RenderPassHashKeyMatch, - VULKAN_INTERNAL_RenderPassHashNuke, - true, false); + VULKAN_INTERNAL_RenderPassHashDestroy, + (void *)renderer); - // manually synchronized due to iteration renderer->framebufferHashTable = SDL_CreateHashTable( - (void *)renderer, - 64, + 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful. + false, // manually synchronized due to iteration VULKAN_INTERNAL_FramebufferHashFunction, VULKAN_INTERNAL_FramebufferHashKeyMatch, - VULKAN_INTERNAL_FramebufferHashNuke, - false, false); + VULKAN_INTERNAL_FramebufferHashDestroy, + (void *)renderer); - // thread-safe renderer->graphicsPipelineResourceLayoutHashTable = SDL_CreateHashTable( - (void *)renderer, - 64, + 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful. + true, // thread-safe VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashFunction, VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashKeyMatch, - VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashNuke, - true, false); + VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashDestroy, + (void *)renderer); - // thread-safe renderer->computePipelineResourceLayoutHashTable = SDL_CreateHashTable( - (void *)renderer, - 64, + 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful. + true, // thread-safe VULKAN_INTERNAL_ComputePipelineResourceLayoutHashFunction, VULKAN_INTERNAL_ComputePipelineResourceLayoutHashKeyMatch, - VULKAN_INTERNAL_ComputePipelineResourceLayoutHashNuke, - true, false); + VULKAN_INTERNAL_ComputePipelineResourceLayoutHashDestroy, + (void *)renderer); - // thread-safe renderer->descriptorSetLayoutHashTable = SDL_CreateHashTable( - (void *)renderer, - 64, + 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful. + true, // thread-safe VULKAN_INTERNAL_DescriptorSetLayoutHashFunction, VULKAN_INTERNAL_DescriptorSetLayoutHashKeyMatch, - VULKAN_INTERNAL_DescriptorSetLayoutHashNuke, - true, false); + VULKAN_INTERNAL_DescriptorSetLayoutHashDestroy, + (void *)renderer); // Initialize fence pool diff --git a/libs/SDL3/src/haptic/SDL_haptic.c b/libs/SDL3/src/haptic/SDL_haptic.c index ca1ab381..1c11db68 100644 --- a/libs/SDL3/src/haptic/SDL_haptic.c +++ b/libs/SDL3/src/haptic/SDL_haptic.c @@ -23,6 +23,84 @@ #include "SDL_syshaptic.h" #include "SDL_haptic_c.h" #include "../joystick/SDL_joystick_c.h" // For SDL_IsJoystickValid +#include "../SDL_hints_c.h" + +typedef struct SDL_Haptic_VIDPID_Naxes { + Uint16 vid; + Uint16 pid; + Uint16 naxes; +} SDL_Haptic_VIDPID_Naxes; + +static void SDL_Haptic_Load_Axes_List(SDL_Haptic_VIDPID_Naxes **entries, int *num_entries) +{ + SDL_Haptic_VIDPID_Naxes entry; + const char *spot; + int length = 0; + + spot = SDL_GetHint(SDL_HINT_JOYSTICK_HAPTIC_AXES); + if (!spot) + return; + + while (SDL_sscanf(spot, "0x%hx/0x%hx/%hu%n", &entry.vid, &entry.pid, &entry.naxes, &length) == 3) { + SDL_assert(length > 0); + spot += length; + length = 0; + + if ((*num_entries % 8) == 0) { + int new_max = *num_entries + 8; + SDL_Haptic_VIDPID_Naxes *new_entries = + (SDL_Haptic_VIDPID_Naxes *)SDL_realloc(*entries, new_max * sizeof(**entries)); + + // Out of memory, go with what we have already + if (!new_entries) + break; + + *entries = new_entries; + } + (*entries)[(*num_entries)++] = entry; + + if (spot[0] == ',') + spot++; + } +} + +// /* Return -1 if not found */ +static int SDL_Haptic_Naxes_List_Index(struct SDL_Haptic_VIDPID_Naxes *entries, int num_entries, Uint16 vid, Uint16 pid) +{ + if (!entries) + return -1; + + int i; + for (i = 0; i < num_entries; ++i) { + if (entries[i].vid == vid && entries[i].pid == pid) + return i; + } + + return -1; +} + +// Check if device needs a custom number of naxes +static int SDL_Haptic_Get_Naxes(Uint16 vid, Uint16 pid) +{ + int num_entries = 0, index = 0, naxes = -1; + SDL_Haptic_VIDPID_Naxes *naxes_list = NULL; + + SDL_Haptic_Load_Axes_List(&naxes_list, &num_entries); + if (!num_entries || !naxes_list) + return -1; + + // Perform "wildcard" pass + index = SDL_Haptic_Naxes_List_Index(naxes_list, num_entries, 0xffff, 0xffff); + if (index >= 0) + naxes = naxes_list[index].naxes; + + index = SDL_Haptic_Naxes_List_Index(naxes_list, num_entries, vid, pid); + if (index >= 0) + naxes = naxes_list[index].naxes; + + SDL_free(naxes_list); + return naxes; +} static SDL_Haptic *SDL_haptics = NULL; @@ -131,6 +209,7 @@ SDL_Haptic *SDL_OpenHaptic(SDL_HapticID instance_id) haptic->instance_id = instance_id; haptic->rumble_id = -1; if (!SDL_SYS_HapticOpen(haptic)) { + SDL_SetObjectValid(haptic, SDL_OBJECT_TYPE_HAPTIC, false); SDL_free(haptic); return NULL; } @@ -268,9 +347,11 @@ SDL_Haptic *SDL_OpenHapticFromJoystick(SDL_Joystick *joystick) /* Initialize the haptic device * This function should fill in the instance ID and name. */ + SDL_SetObjectValid(haptic, SDL_OBJECT_TYPE_HAPTIC, true); haptic->rumble_id = -1; if (!SDL_SYS_HapticOpenFromJoystick(haptic, joystick)) { SDL_SetError("Haptic: SDL_SYS_HapticOpenFromJoystick failed."); + SDL_SetObjectValid(haptic, SDL_OBJECT_TYPE_HAPTIC, false); SDL_free(haptic); SDL_UnlockJoysticks(); return NULL; @@ -279,6 +360,19 @@ SDL_Haptic *SDL_OpenHapticFromJoystick(SDL_Joystick *joystick) } SDL_UnlockJoysticks(); + // Check if custom number of haptic axes was defined + Uint16 vid = SDL_GetJoystickVendor(joystick); + Uint16 pid = SDL_GetJoystickProduct(joystick); + int general_axes = SDL_GetNumJoystickAxes(joystick); + + int naxes = SDL_Haptic_Get_Naxes(vid, pid); + if (naxes > 0) + haptic->naxes = naxes; + + // Limit to the actual number of axes found on the device + if (general_axes >= 0 && naxes > general_axes) + haptic->naxes = general_axes; + // Add haptic to list ++haptic->ref_count; // Link the haptic in the list diff --git a/libs/SDL3/src/hidapi/android/hid.cpp b/libs/SDL3/src/hidapi/android/hid.cpp index 1e43aa73..887390ed 100644 --- a/libs/SDL3/src/hidapi/android/hid.cpp +++ b/libs/SDL3/src/hidapi/android/hid.cpp @@ -1028,7 +1028,7 @@ extern "C" static void SDLCALL RequestBluetoothPermissionCallback( void *userdata, const char *permission, bool granted ) { - SDL_Log( "Bluetooth permission %s\n", granted ? "granted" : "denied" ); + SDL_Log( "Bluetooth permission %s", granted ? "granted" : "denied" ); if ( granted && g_HIDDeviceManagerCallbackHandler ) { diff --git a/libs/SDL3/src/io/SDL_asyncio.c b/libs/SDL3/src/io/SDL_asyncio.c index 3d1658db..aa5ba871 100644 --- a/libs/SDL3/src/io/SDL_asyncio.c +++ b/libs/SDL3/src/io/SDL_asyncio.c @@ -57,12 +57,14 @@ SDL_AsyncIO *SDL_AsyncIOFromFile(const char *file, const char *mode) } SDL_AsyncIO *asyncio = (SDL_AsyncIO *)SDL_calloc(1, sizeof(*asyncio)); - if (asyncio) { - asyncio->lock = SDL_CreateMutex(); - if (!asyncio->lock) { - SDL_free(asyncio); - return NULL; - } + if (!asyncio) { + return NULL; + } + + asyncio->lock = SDL_CreateMutex(); + if (!asyncio->lock) { + SDL_free(asyncio); + return NULL; } if (!SDL_SYS_AsyncIOFromFile(file, binary_mode, asyncio)) { diff --git a/libs/SDL3/src/io/SDL_iostream.c b/libs/SDL3/src/io/SDL_iostream.c index adaf5e04..989f3b9c 100644 --- a/libs/SDL3/src/io/SDL_iostream.c +++ b/libs/SDL3/src/io/SDL_iostream.c @@ -788,10 +788,13 @@ static bool SDLCALL mem_close(void *userdata) #if defined(HAVE_STDIO_H) && !defined(SDL_PLATFORM_WINDOWS) static bool IsRegularFileOrPipe(FILE *f) { +#ifndef SDL_PLATFORM_EMSCRIPTEN struct stat st; if (fstat(fileno(f), &st) < 0 || !(S_ISREG(st.st_mode) || S_ISFIFO(st.st_mode))) { return false; } +#endif // !SDL_PLATFORM_EMSCRIPTEN + return true; } #endif @@ -1153,7 +1156,7 @@ void *SDL_LoadFile_IO(SDL_IOStream *src, size_t *datasize, bool closeio) size = FILE_CHUNK_SIZE; loading_chunks = true; } - if (size >= SDL_SIZE_MAX) { + if (size >= SDL_SIZE_MAX - 1) { goto done; } data = (char *)SDL_malloc((size_t)(size + 1)); @@ -1166,7 +1169,7 @@ void *SDL_LoadFile_IO(SDL_IOStream *src, size_t *datasize, bool closeio) if (loading_chunks) { if ((size_total + FILE_CHUNK_SIZE) > size) { size = (size_total + FILE_CHUNK_SIZE); - if (size >= SDL_SIZE_MAX) { + if (size >= SDL_SIZE_MAX - 1) { newdata = NULL; } else { newdata = (char *)SDL_realloc(data, (size_t)(size + 1)); diff --git a/libs/SDL3/src/joystick/SDL_gamepad.c b/libs/SDL3/src/joystick/SDL_gamepad.c index d931ed23..8486865b 100644 --- a/libs/SDL3/src/joystick/SDL_gamepad.c +++ b/libs/SDL3/src/joystick/SDL_gamepad.c @@ -428,7 +428,7 @@ static bool SDLCALL SDL_GamepadEventWatcher(void *userdata, SDL_Event *event) orientation, so when it's changed orientation to be used as a gamepad, change the sensor orientation to match. */ -static void AdjustSensorOrientation(SDL_Joystick *joystick, float *src, float *dst) +static void AdjustSensorOrientation(const SDL_Joystick *joystick, const float *src, float *dst) { unsigned int i, j; @@ -562,12 +562,10 @@ static void PopMappingChangeTracking(void) GamepadMapping_t *old_mapping = gamepad ? gamepad->mapping : tracker->joystick_mappings[i]; if (new_mapping && !old_mapping) { - SDL_RemoveFromHashTable(s_gamepadInstanceIDs, (void *)(uintptr_t)joystick); - SDL_InsertIntoHashTable(s_gamepadInstanceIDs, (void *)(uintptr_t)joystick, (const void *)true); + SDL_InsertIntoHashTable(s_gamepadInstanceIDs, (void *)(uintptr_t)joystick, (const void *)true, true); SDL_PrivateGamepadAdded(joystick); } else if (old_mapping && !new_mapping) { - SDL_RemoveFromHashTable(s_gamepadInstanceIDs, (void *)(uintptr_t)joystick); - SDL_InsertIntoHashTable(s_gamepadInstanceIDs, (void *)(uintptr_t)joystick, (const void *)false); + SDL_InsertIntoHashTable(s_gamepadInstanceIDs, (void *)(uintptr_t)joystick, (const void *)false, true); SDL_PrivateGamepadRemoved(joystick); } else if (old_mapping != new_mapping || HasMappingChangeTracking(tracker, new_mapping)) { if (gamepad) { @@ -1393,6 +1391,60 @@ static void SDL_UpdateGamepadFaceStyle(SDL_Gamepad *gamepad) } } +static void SDL_FixupHIDAPIMapping(SDL_Gamepad *gamepad) +{ + // Check to see if we need fixup + bool need_fixup = false; + for (int i = 0; i < gamepad->num_bindings; ++i) { + SDL_GamepadBinding *binding = &gamepad->bindings[i]; + if (binding->output_type == SDL_GAMEPAD_BINDTYPE_BUTTON && + binding->output.button >= SDL_GAMEPAD_BUTTON_DPAD_UP) { + if (binding->input_type == SDL_GAMEPAD_BINDTYPE_BUTTON && + binding->input.button == binding->output.button) { + // Old style binding + need_fixup = true; + } + break; + } + } + if (!need_fixup) { + return; + } + + for (int i = 0; i < gamepad->num_bindings; ++i) { + SDL_GamepadBinding *binding = &gamepad->bindings[i]; + if (binding->input_type == SDL_GAMEPAD_BINDTYPE_BUTTON && + binding->output_type == SDL_GAMEPAD_BINDTYPE_BUTTON) { + switch (binding->output.button) { + case SDL_GAMEPAD_BUTTON_DPAD_UP: + binding->input_type = SDL_GAMEPAD_BINDTYPE_HAT; + binding->input.hat.hat = 0; + binding->input.hat.hat_mask = SDL_HAT_UP; + break; + case SDL_GAMEPAD_BUTTON_DPAD_DOWN: + binding->input_type = SDL_GAMEPAD_BINDTYPE_HAT; + binding->input.hat.hat = 0; + binding->input.hat.hat_mask = SDL_HAT_DOWN; + break; + case SDL_GAMEPAD_BUTTON_DPAD_LEFT: + binding->input_type = SDL_GAMEPAD_BINDTYPE_HAT; + binding->input.hat.hat = 0; + binding->input.hat.hat_mask = SDL_HAT_LEFT; + break; + case SDL_GAMEPAD_BUTTON_DPAD_RIGHT: + binding->input_type = SDL_GAMEPAD_BINDTYPE_HAT; + binding->input.hat.hat = 0; + binding->input.hat.hat_mask = SDL_HAT_RIGHT; + break; + default: + if (binding->output.button > SDL_GAMEPAD_BUTTON_DPAD_RIGHT) { + binding->input.button -= 4; + } + break; + } + } + } +} /* * Make a new button mapping struct @@ -1415,6 +1467,10 @@ static void SDL_PrivateLoadButtonMapping(SDL_Gamepad *gamepad, GamepadMapping_t SDL_PrivateParseGamepadConfigString(gamepad, pGamepadMapping->mapping); + if (SDL_IsJoystickHIDAPI(pGamepadMapping->guid)) { + SDL_FixupHIDAPIMapping(gamepad); + } + // Set the zero point for triggers for (i = 0; i < gamepad->num_bindings; ++i) { SDL_GamepadBinding *binding = &gamepad->bindings[i]; @@ -2584,9 +2640,9 @@ bool SDL_IsGamepad(SDL_JoystickID instance_id) } if (!s_gamepadInstanceIDs) { - s_gamepadInstanceIDs = SDL_CreateHashTable(NULL, 4, SDL_HashID, SDL_KeyMatchID, NULL, false, false); + s_gamepadInstanceIDs = SDL_CreateHashTable(0, false, SDL_HashID, SDL_KeyMatchID, NULL, NULL); } - SDL_InsertIntoHashTable(s_gamepadInstanceIDs, (void *)(uintptr_t)instance_id, (void *)(uintptr_t)result); + SDL_InsertIntoHashTable(s_gamepadInstanceIDs, (void *)(uintptr_t)instance_id, (void *)(uintptr_t)result, true); } } SDL_UnlockJoysticks(); @@ -2771,7 +2827,7 @@ bool SDL_GamepadHasAxis(SDL_Gamepad *gamepad, SDL_GamepadAxis axis) */ Sint16 SDL_GetGamepadAxis(SDL_Gamepad *gamepad, SDL_GamepadAxis axis) { - Sint16 result = true; + Sint16 result = 0; SDL_LockJoysticks(); { @@ -3001,7 +3057,7 @@ SDL_GamepadButtonLabel SDL_GetGamepadButtonLabel(SDL_Gamepad *gamepad, SDL_Gamep */ int SDL_GetNumGamepadTouchpads(SDL_Gamepad *gamepad) { - int result = true; + int result = 0; SDL_LockJoysticks(); { @@ -3020,7 +3076,7 @@ int SDL_GetNumGamepadTouchpads(SDL_Gamepad *gamepad) */ int SDL_GetNumGamepadTouchpadFingers(SDL_Gamepad *gamepad, int touchpad) { - int result = true; + int result = 0; SDL_LockJoysticks(); { @@ -3028,8 +3084,6 @@ int SDL_GetNumGamepadTouchpadFingers(SDL_Gamepad *gamepad, int touchpad) if (joystick) { if (touchpad >= 0 && touchpad < joystick->ntouchpads) { result = joystick->touchpads[touchpad].nfingers; - } else { - result = SDL_InvalidParamError("touchpad"); } } } @@ -3273,7 +3327,7 @@ SDL_JoystickID SDL_GetGamepadID(SDL_Gamepad *gamepad) SDL_PropertiesID SDL_GetGamepadProperties(SDL_Gamepad *gamepad) { - SDL_PropertiesID result = true; + SDL_PropertiesID result = 0; SDL_LockJoysticks(); { diff --git a/libs/SDL3/src/joystick/SDL_gamepad_db.h b/libs/SDL3/src/joystick/SDL_gamepad_db.h index 417eb6c4..d72e4223 100644 --- a/libs/SDL3/src/joystick/SDL_gamepad_db.h +++ b/libs/SDL3/src/joystick/SDL_gamepad_db.h @@ -50,6 +50,7 @@ static const char *s_GamepadMappings[] = { "03000000c82d00001038000000000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", "03000000c82d00000650000000000000,8BitDo M30 Gamepad,a:b0,b:b1,back:b10,guide:b2,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,", "03000000c82d00005106000000000000,8BitDo M30 Gamepad,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b10,guide:b2,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,", + "03000000c82d00002090000000000000,8BitDo Micro gamepad,a:b1,b:b0,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,guide:b12,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,righttrigger:b9,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", "03000000c82d00001590000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", "03000000c82d00006528000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", "030000003512000012ab000000000000,8BitDo NES30 Gamepad,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", @@ -214,6 +215,7 @@ static const char *s_GamepadMappings[] = { "03000000362800000100000000000000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,x:b1,y:b2,", "03000000782300000a10000000000000,Onlive Wireless Controller,a:b15,b:b14,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b11,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b13,y:b12,", "030000006b14000001a1000000000000,Orange Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,", + "0300000009120000072f000000000000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:-a2,leftx:a0,lefty:a1,righttrigger:-a5,start:b11,x:b3,y:b4,", "03000000120c0000f60e000000000000,P4 Wired Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,", "030000006f0e00000901000000000000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,", "03000000632500002306000000000000,PS Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,", @@ -299,7 +301,6 @@ static const char *s_GamepadMappings[] = { "03000000a30600002106000000000000,Saitek PS1000,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,", "03000000a306000020f6000000000000,Saitek PS2700,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,", "03000000300f00001101000000000000,Saitek Rumble Pad,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,", - "03000000790000000600000000000000,Sanwa Supply JY-P76USV,crc:20f0,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b2,y:b3,", "0300000000050000289b000000000000,Saturn_Adapter_2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,", "030000009b2800000500000000000000,Saturn_Adapter_2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,", "030000008f0e00000800000000000000,SpeedLink Strike FX,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,", @@ -350,6 +351,7 @@ static const char *s_GamepadMappings[] = { "03000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", "03000000c82d00000650000001000000,8BitDo M30 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a5,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", "03000000c82d00005106000000010000,8BitDo M30 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", + "05000000ac05000004000000a8986d04,8BitDo Micro gamepad,a:b1,b:b0,back:b4,dpdown:b7,dpleft:b8,dpright:b9,dpup:b10,guide:b2,leftshoulder:b11,lefttrigger:b12,rightshoulder:b13,righttrigger:b14,start:b3,x:b6,y:b5,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", "03000000c82d00001590000001000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", "03000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", "030000003512000012ab000001000000,8BitDo NES30 Gamepad,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", @@ -419,6 +421,7 @@ static const char *s_GamepadMappings[] = { "030000004b120000014d000000010000,NYKO AIRFLO EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,", "030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,", "050000007e05000009200000ff070000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", + "0300000009120000072f000000010000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a2,leftx:a0,lefty:a1,righttrigger:a5,start:b11,x:b3,y:b4,", "030000006f0e00000901000002010000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,", "030000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,", "030000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,", @@ -486,6 +489,7 @@ static const char *s_GamepadMappings[] = { "03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", "05000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", "05000000c82d00005106000000010000,8BitDo M30 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", + "05000000c82d00002090000000010000,8BitDo Micro gamepad,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b12,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,righttrigger:b9,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", "03000000c82d00001590000011010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", "05000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", "030000003512000012ab000010010000,8BitDo NES30 Gamepad,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", @@ -800,6 +804,7 @@ static const char *s_GamepadMappings[] = { #ifdef SDL_PLATFORM_ANDROID "05000000c82d000006500000ffff3f00,8BitDo M30 Gamepad,a:b1,b:b0,back:b4,guide:b17,leftshoulder:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a4,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", "05000000c82d000051060000ffff3f00,8BitDo M30 Gamepad,a:b1,b:b0,back:b4,guide:b17,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", + "05000000c82d000020900000ffff3f00,8BitDo Micro gamepad,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b5,leftshoulder:b9,lefttrigger:a6,rightshoulder:b10,righttrigger:a7,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", "05000000c82d000015900000ffff3f00,8BitDo N30 Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", "05000000c82d000065280000ffff3f00,8BitDo N30 Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", "050000000220000000900000ffff3f00,8BitDo NES30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", @@ -855,6 +860,8 @@ static const char *s_GamepadMappings[] = { "05000000ac05000001000000df076d01,*,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,", "05000000ac05000001000000ff076d01,*,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,", "05000000ac050000020000004f066d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,", + "05000000ac05000004000000a8986d04,8BitDo Micro gamepad,a:b1,b:b0,back:b4,dpdown:b7,dpleft:b8,dpright:b9,dpup:b10,guide:b2,leftshoulder:b11,lefttrigger:b12,rightshoulder:b13,righttrigger:b14,start:b3,x:b6,y:b5,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", + "05000000ac050000040000003b8a6d04,8BitDo SN30 Pro+,crc:3e00,a:b1,b:b0,back:b4,dpdown:b7,dpleft:b8,dpright:b9,dpup:b10,guide:b2,leftshoulder:b11,leftstick:b12,lefttrigger:b13,leftx:a0,lefty:a1~,rightshoulder:b14,rightstick:b15,righttrigger:b16,rightx:a2,righty:a3~,start:b3,x:b6,y:b5,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", "050000008a35000003010000ff070000,Backbone One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,", "050000008a35000004010000ff070000,Backbone One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,", "050000007e050000062000000f060000,Nintendo Switch Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b2,leftshoulder:b4,rightshoulder:b5,x:b1,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", @@ -893,6 +900,5 @@ static const char *s_GamepadMappings[] = { #ifdef SDL_JOYSTICK_N3DS "000000004e696e74656e646f20334400,Nintendo 3DS,crc:3210,a:b0,b:b1,back:b2,dpdown:b7,dpleft:b5,dpright:b4,dpup:b6,leftshoulder:b9,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b8,righttrigger:b15,rightx:a2,righty:a3,start:b3,x:b10,y:b11,", #endif - "hidapi,*,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,", NULL }; diff --git a/libs/SDL3/src/joystick/SDL_joystick.c b/libs/SDL3/src/joystick/SDL_joystick.c index 224f07fa..7574adc6 100644 --- a/libs/SDL3/src/joystick/SDL_joystick.c +++ b/libs/SDL3/src/joystick/SDL_joystick.c @@ -287,9 +287,9 @@ static SDL_vidpid_list blacklist_devices = { static Uint32 initial_flightstick_devices[] = { MAKE_VIDPID(0x044f, 0x0402), // HOTAS Warthog Joystick - MAKE_VIDPID(0x0738, 0x2221), // Saitek Pro Flight X-56 Rhino Stick MAKE_VIDPID(0x044f, 0xb10a), // ThrustMaster, Inc. T.16000M Joystick MAKE_VIDPID(0x046d, 0xc215), // Logitech Extreme 3D + MAKE_VIDPID(0x0738, 0x2221), // Saitek Pro Flight X-56 Rhino Stick MAKE_VIDPID(0x231d, 0x0126), // Gunfighter Mk.III 'Space Combat Edition' (right) MAKE_VIDPID(0x231d, 0x0127), // Gunfighter Mk.III 'Space Combat Edition' (left) MAKE_VIDPID(0x362c, 0x0001), // Yawman Arrow @@ -313,10 +313,10 @@ static SDL_vidpid_list gamecube_devices = { }; static Uint32 initial_rog_gamepad_mice[] = { - MAKE_VIDPID(0x0b05, 0x1906), // ROG Pugio II - MAKE_VIDPID(0x0b05, 0x1958), // ROG Chakram Core Mouse MAKE_VIDPID(0x0b05, 0x18e3), // ROG Chakram (wired) Mouse MAKE_VIDPID(0x0b05, 0x18e5), // ROG Chakram (wireless) Mouse + MAKE_VIDPID(0x0b05, 0x1906), // ROG Pugio II + MAKE_VIDPID(0x0b05, 0x1958), // ROG Chakram Core Mouse MAKE_VIDPID(0x0b05, 0x1a18), // ROG Chakram X (wired) Mouse MAKE_VIDPID(0x0b05, 0x1a1a), // ROG Chakram X (wireless) Mouse MAKE_VIDPID(0x0b05, 0x1a1c), // ROG Chakram X (Bluetooth) Mouse @@ -341,37 +341,37 @@ static SDL_vidpid_list throttle_devices = { static Uint32 initial_wheel_devices[] = { MAKE_VIDPID(0x0079, 0x1864), // DragonRise Inc. Wired Wheel (active mode) (also known as PXN V900 (PS3), Superdrive SV-750, or a Genesis Seaborg 400) + MAKE_VIDPID(0x044f, 0xb65d), // Thrustmaster Wheel FFB + 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, 0xb66d), // Thrustmaster T300RS (PS4 mode) + MAKE_VIDPID(0x044f, 0xb66d), // Thrustmaster Wheel FFB + MAKE_VIDPID(0x044f, 0xb66e), // Thrustmaster T300RS (normal mode) + MAKE_VIDPID(0x044f, 0xb66f), // Thrustmaster T300RS (advanced mode) + MAKE_VIDPID(0x044f, 0xb677), // Thrustmaster T150 + 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(0x044f, 0xb696), // Thrustmaster T248 + MAKE_VIDPID(0x046d, 0xc24f), // Logitech G29 (PS3) + MAKE_VIDPID(0x046d, 0xc260), // Logitech G29 (PS4) + MAKE_VIDPID(0x046d, 0xc261), // Logitech G920 (initial mode) + MAKE_VIDPID(0x046d, 0xc262), // Logitech G920 (active mode) + MAKE_VIDPID(0x046d, 0xc266), // Logitech G923 for Playstation 4 and PC (PC mode) + MAKE_VIDPID(0x046d, 0xc267), // Logitech G923 for Playstation 4 and PC (PS4 mode) + MAKE_VIDPID(0x046d, 0xc268), // Logitech PRO Racing Wheel (PC mode) + MAKE_VIDPID(0x046d, 0xc269), // Logitech PRO Racing Wheel (PS4/PS5 mode) + MAKE_VIDPID(0x046d, 0xc26d), // Logitech G923 (Xbox) + MAKE_VIDPID(0x046d, 0xc26e), // Logitech G923 + MAKE_VIDPID(0x046d, 0xc272), // Logitech PRO Racing Wheel for Xbox (PC mode) MAKE_VIDPID(0x046d, 0xc294), // Logitech generic wheel MAKE_VIDPID(0x046d, 0xc295), // Logitech Momo Force MAKE_VIDPID(0x046d, 0xc298), // Logitech Driving Force Pro MAKE_VIDPID(0x046d, 0xc299), // Logitech G25 MAKE_VIDPID(0x046d, 0xc29a), // Logitech Driving Force GT MAKE_VIDPID(0x046d, 0xc29b), // Logitech G27 - MAKE_VIDPID(0x046d, 0xc24f), // Logitech G29 (PS3) - MAKE_VIDPID(0x046d, 0xc260), // Logitech G29 (PS4) - MAKE_VIDPID(0x046d, 0xc261), // Logitech G920 (initial mode) - MAKE_VIDPID(0x046d, 0xc262), // Logitech G920 (active mode) - MAKE_VIDPID(0x046d, 0xc268), // Logitech PRO Racing Wheel (PC mode) - MAKE_VIDPID(0x046d, 0xc269), // Logitech PRO Racing Wheel (PS4/PS5 mode) - MAKE_VIDPID(0x046d, 0xc272), // Logitech PRO Racing Wheel for Xbox (PC mode) - MAKE_VIDPID(0x046d, 0xc26d), // Logitech G923 (Xbox) - MAKE_VIDPID(0x046d, 0xc26e), // Logitech G923 - MAKE_VIDPID(0x046d, 0xc266), // Logitech G923 for Playstation 4 and PC (PC mode) - MAKE_VIDPID(0x046d, 0xc267), // Logitech G923 for Playstation 4 and PC (PS4 mode) MAKE_VIDPID(0x046d, 0xca03), // Logitech Momo Racing - MAKE_VIDPID(0x044f, 0xb65d), // Thrustmaster Wheel FFB - MAKE_VIDPID(0x044f, 0xb66d), // Thrustmaster Wheel FFB - MAKE_VIDPID(0x044f, 0xb677), // Thrustmaster T150 - MAKE_VIDPID(0x044f, 0xb696), // Thrustmaster T248 - MAKE_VIDPID(0x044f, 0xb66e), // Thrustmaster T300RS (normal mode) - MAKE_VIDPID(0x044f, 0xb66f), // Thrustmaster T300RS (advanced mode) - MAKE_VIDPID(0x044f, 0xb66d), // Thrustmaster T300RS (PS4 mode) - 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) MAKE_VIDPID(0x0483, 0xa355), // VRS DirectForce Pro Wheel Base MAKE_VIDPID(0x0eb7, 0x0001), // Fanatec ClubSport Wheel Base V2 @@ -410,8 +410,8 @@ static SDL_vidpid_list wheel_devices = { }; static Uint32 initial_zero_centered_devices[] = { - MAKE_VIDPID(0x0e8f, 0x3013), // HuiJia SNES USB adapter MAKE_VIDPID(0x05a0, 0x3232), // 8Bitdo Zero Gamepad + MAKE_VIDPID(0x0e8f, 0x3013), // HuiJia SNES USB adapter }; static SDL_vidpid_list zero_centered_devices = { SDL_HINT_JOYSTICK_ZERO_CENTERED_DEVICES, 0, 0, NULL, @@ -2546,158 +2546,14 @@ void SDL_GetJoystickGUIDInfo(SDL_GUID guid, Uint16 *vendor, Uint16 *product, Uin } } -static int PrefixMatch(const char *a, const char *b) -{ - int matchlen = 0; - while (*a && *b) { - if (SDL_tolower((unsigned char)*a++) == SDL_tolower((unsigned char)*b++)) { - ++matchlen; - } else { - break; - } - } - return matchlen; -} - char *SDL_CreateJoystickName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name) { - static struct - { - const char *prefix; - const char *replacement; - } replacements[] = { - { "ASTRO Gaming", "ASTRO" }, - { "Bensussen Deutsch & Associates,Inc.(BDA)", "BDA" }, - { "Guangzhou Chicken Run Network Technology Co., Ltd.", "GameSir" }, - { "HORI CO.,LTD", "HORI" }, - { "HORI CO.,LTD.", "HORI" }, - { "Mad Catz Inc.", "Mad Catz" }, - { "Nintendo Co., Ltd.", "Nintendo" }, - { "NVIDIA Corporation ", "" }, - { "Performance Designed Products", "PDP" }, - { "QANBA USA, LLC", "Qanba" }, - { "QANBA USA,LLC", "Qanba" }, - { "Unknown ", "" }, - }; - const char *custom_name; - char *name; - size_t i, len; - - custom_name = GuessControllerName(vendor, product); + const char *custom_name = GuessControllerName(vendor, product); if (custom_name) { return SDL_strdup(custom_name); } - if (!vendor_name) { - vendor_name = ""; - } - if (!product_name) { - product_name = ""; - } - - while (*vendor_name == ' ') { - ++vendor_name; - } - while (*product_name == ' ') { - ++product_name; - } - - if (*vendor_name && *product_name) { - len = (SDL_strlen(vendor_name) + 1 + SDL_strlen(product_name) + 1); - name = (char *)SDL_malloc(len); - if (name) { - (void)SDL_snprintf(name, len, "%s %s", vendor_name, product_name); - } - } else if (*product_name) { - name = SDL_strdup(product_name); - } else if (vendor || product) { - // Couldn't find a controller name, try to give it one based on device type - switch (SDL_GetGamepadTypeFromVIDPID(vendor, product, NULL, true)) { - case SDL_GAMEPAD_TYPE_XBOX360: - name = SDL_strdup("Xbox 360 Controller"); - break; - case SDL_GAMEPAD_TYPE_XBOXONE: - name = SDL_strdup("Xbox One Controller"); - break; - case SDL_GAMEPAD_TYPE_PS3: - name = SDL_strdup("PS3 Controller"); - break; - case SDL_GAMEPAD_TYPE_PS4: - name = SDL_strdup("PS4 Controller"); - break; - case SDL_GAMEPAD_TYPE_PS5: - name = SDL_strdup("DualSense Wireless Controller"); - break; - case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO: - name = SDL_strdup("Nintendo Switch Pro Controller"); - break; - default: - len = (6 + 1 + 6 + 1); - name = (char *)SDL_malloc(len); - if (name) { - (void)SDL_snprintf(name, len, "0x%.4x/0x%.4x", vendor, product); - } - break; - } - } else { - name = SDL_strdup("Controller"); - } - - if (!name) { - return NULL; - } - - // Trim trailing whitespace - for (len = SDL_strlen(name); (len > 0 && name[len - 1] == ' '); --len) { - // continue - } - name[len] = '\0'; - - // Compress duplicate spaces - for (i = 0; i < (len - 1);) { - if (name[i] == ' ' && name[i + 1] == ' ') { - SDL_memmove(&name[i], &name[i + 1], (len - i)); - --len; - } else { - ++i; - } - } - - // Perform any manufacturer replacements - for (i = 0; i < SDL_arraysize(replacements); ++i) { - size_t prefixlen = SDL_strlen(replacements[i].prefix); - if (SDL_strncasecmp(name, replacements[i].prefix, prefixlen) == 0) { - size_t replacementlen = SDL_strlen(replacements[i].replacement); - if (replacementlen <= prefixlen) { - SDL_memcpy(name, replacements[i].replacement, replacementlen); - SDL_memmove(name + replacementlen, name + prefixlen, (len - prefixlen) + 1); - len -= (prefixlen - replacementlen); - } else { - // FIXME: Need to handle the expand case by reallocating the string - } - break; - } - } - - /* Remove duplicate manufacturer or product in the name - * e.g. Razer Razer Raiju Tournament Edition Wired - */ - for (i = 1; i < (len - 1); ++i) { - int matchlen = PrefixMatch(name, &name[i]); - while (matchlen > 0) { - if (name[matchlen] == ' ' || name[matchlen] == '-') { - SDL_memmove(name, name + matchlen + 1, len - matchlen); - break; - } - --matchlen; - } - if (matchlen > 0) { - // We matched the manufacturer's name and removed it - break; - } - } - - return name; + return SDL_CreateDeviceName(vendor, product, vendor_name, product_name, "Controller"); } SDL_GUID SDL_CreateJoystickGUID(Uint16 bus, Uint16 vendor, Uint16 product, Uint16 version, const char *vendor_name, const char *product_name, Uint8 driver_signature, Uint8 driver_data) @@ -2963,7 +2819,7 @@ bool SDL_IsJoystickXboxSeriesX(Uint16 vendor_id, Uint16 product_id) } } if (vendor_id == USB_VENDOR_THRUSTMASTER) { - if (product_id == USB_PRODUCT_THRUSTMASTER_ESWAPX_PRO) { + if (product_id == USB_PRODUCT_THRUSTMASTER_ESWAPX_PRO_SERIES_X) { return true; } } diff --git a/libs/SDL3/src/joystick/android/SDL_sysjoystick.c b/libs/SDL3/src/joystick/android/SDL_sysjoystick.c index 95ad99c0..9a3402eb 100644 --- a/libs/SDL3/src/joystick/android/SDL_sysjoystick.c +++ b/libs/SDL3/src/joystick/android/SDL_sysjoystick.c @@ -329,7 +329,7 @@ void Android_AddJoystick(int device_id, const char *name, const char *desc, int } #ifdef DEBUG_JOYSTICK - SDL_Log("Joystick: %s, descriptor %s, vendor = 0x%.4x, product = 0x%.4x, %d axes, %d hats\n", name, desc, vendor_id, product_id, naxes, nhats); + SDL_Log("Joystick: %s, descriptor %s, vendor = 0x%.4x, product = 0x%.4x, %d axes, %d hats", name, desc, vendor_id, product_id, naxes, nhats); #endif if (nhats > 0) { diff --git a/libs/SDL3/src/joystick/apple/SDL_mfijoystick.m b/libs/SDL3/src/joystick/apple/SDL_mfijoystick.m index 23d6b23f..811a9f1a 100644 --- a/libs/SDL3/src/joystick/apple/SDL_mfijoystick.m +++ b/libs/SDL3/src/joystick/apple/SDL_mfijoystick.m @@ -50,9 +50,7 @@ static id disconnectObserver = nil; #include -/* remove compilation warnings for strict builds by defining these selectors, even though - * they are only ever used indirectly through objc_msgSend - */ +// Fix build errors when using an older SDK by defining these selectors @interface GCController (SDL) #if !((__IPHONE_OS_VERSION_MAX_ALLOWED >= 140500) || (__APPLETV_OS_VERSION_MAX_ALLOWED >= 140500) || (__MAC_OS_X_VERSION_MAX_ALLOWED >= 110300)) @property(class, nonatomic, readwrite) BOOL shouldMonitorBackgroundEvents; diff --git a/libs/SDL3/src/joystick/controller_list.h b/libs/SDL3/src/joystick/controller_list.h index 5594d2bd..5a62ece1 100644 --- a/libs/SDL3/src/joystick/controller_list.h +++ b/libs/SDL3/src/joystick/controller_list.h @@ -455,6 +455,7 @@ static const ControllerDescription_t arrControllers[] = { { MAKE_CONTROLLER_ID( 0x03eb, 0xff01 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller { MAKE_CONTROLLER_ID( 0x0c12, 0x0ef8 ), k_eControllerType_XBox360Controller, NULL }, // Homemade fightstick based on brook pcb (with XInput driver??) { MAKE_CONTROLLER_ID( 0x046d, 0x1000 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller + { MAKE_CONTROLLER_ID( 0x11ff, 0x0511 ), k_eControllerType_XBox360Controller, NULL }, // PXN V900 { MAKE_CONTROLLER_ID( 0x1345, 0x6006 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller { MAKE_CONTROLLER_ID( 0x056e, 0x2012 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller @@ -488,7 +489,6 @@ static const ControllerDescription_t arrControllers[] = { // Added from Minidumps 10-9-19 { MAKE_CONTROLLER_ID( 0x0, 0x6686 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller - { MAKE_CONTROLLER_ID( 0x11ff, 0x511 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller { MAKE_CONTROLLER_ID( 0x12ab, 0x304 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller { MAKE_CONTROLLER_ID( 0x1430, 0x291 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller { MAKE_CONTROLLER_ID( 0x1430, 0x2a9 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller @@ -591,6 +591,9 @@ static const ControllerDescription_t arrControllers[] = { { MAKE_CONTROLLER_ID( 0x20d6, 0xa715 ), k_eControllerType_SwitchInputOnlyController, NULL }, // Power A Fusion Wireless Arcade Stick (USB Mode) Over BT is shows up as 057e 2009 { MAKE_CONTROLLER_ID( 0x20d6, 0xa716 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PowerA Nintendo Switch Fusion Pro Controller - USB requires toggling switch on back of device { MAKE_CONTROLLER_ID( 0x20d6, 0xa718 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PowerA Nintendo Switch Nano Wired Controller + { MAKE_CONTROLLER_ID( 0x33dd, 0x0001 ), k_eControllerType_SwitchInputOnlyController, NULL }, // ZUIKI MasCon for Nintendo Switch Black + { MAKE_CONTROLLER_ID( 0x33dd, 0x0002 ), k_eControllerType_SwitchInputOnlyController, NULL }, // ZUIKI MasCon for Nintendo Switch ?? + { MAKE_CONTROLLER_ID( 0x33dd, 0x0003 ), k_eControllerType_SwitchInputOnlyController, NULL }, // ZUIKI MasCon for Nintendo Switch Red // Valve products { MAKE_CONTROLLER_ID( 0x0000, 0x11fb ), k_eControllerType_MobileTouch, NULL }, // Streaming mobile touch virtual controls diff --git a/libs/SDL3/src/joystick/gdk/SDL_gameinputjoystick.c b/libs/SDL3/src/joystick/gdk/SDL_gameinputjoystick.c index 27e36e00..6cf0a902 100644 --- a/libs/SDL3/src/joystick/gdk/SDL_gameinputjoystick.c +++ b/libs/SDL3/src/joystick/gdk/SDL_gameinputjoystick.c @@ -24,9 +24,7 @@ #include "../SDL_sysjoystick.h" #include "../usb_ids.h" - -#define COBJMACROS -#include +#include "../../core/windows/SDL_gameinput.h" // Default value for SDL_HINT_JOYSTICK_GAMEINPUT #if defined(SDL_PLATFORM_GDK) @@ -67,12 +65,10 @@ typedef struct joystick_hwdata } GAMEINPUT_InternalJoystickHwdata; static GAMEINPUT_InternalList g_GameInputList = { NULL }; -static SDL_SharedObject *g_hGameInputDLL = NULL; static IGameInput *g_pGameInput = NULL; static GameInputCallbackToken g_GameInputCallbackToken = GAMEINPUT_INVALID_CALLBACK_TOKEN_VALUE; static Uint64 g_GameInputTimestampOffset; - static bool GAMEINPUT_InternalIsGamepad(const GameInputDeviceInfo *info) { if (info->supportedInput & GameInputKindGamepad) { @@ -245,24 +241,8 @@ static bool GAMEINPUT_JoystickInit(void) return true; } - if (!g_hGameInputDLL) { - g_hGameInputDLL = SDL_LoadObject("gameinput.dll"); - if (!g_hGameInputDLL) { - return false; - } - } - - if (!g_pGameInput) { - typedef HRESULT (WINAPI *GameInputCreate_t)(IGameInput * *gameInput); - GameInputCreate_t GameInputCreateFunc = (GameInputCreate_t)SDL_LoadFunction(g_hGameInputDLL, "GameInputCreate"); - if (!GameInputCreateFunc) { - return false; - } - - hR = GameInputCreateFunc(&g_pGameInput); - if (FAILED(hR)) { - return SDL_SetError("GameInputCreate failure with HRESULT of %08lX", hR); - } + if (!SDL_InitGameInput(&g_pGameInput)) { + return false; } hR = IGameInput_RegisterDeviceCallback(g_pGameInput, @@ -615,6 +595,7 @@ static void GAMEINPUT_JoystickUpdate(SDL_Joystick *joystick) } else { bool *button_state = SDL_stack_alloc(bool, info->controllerButtonCount); float *axis_state = SDL_stack_alloc(float, info->controllerAxisCount); + GameInputSwitchPosition *switch_state = SDL_stack_alloc(GameInputSwitchPosition, info->controllerSwitchCount); if (button_state) { uint32_t i; @@ -635,6 +616,46 @@ static void GAMEINPUT_JoystickUpdate(SDL_Joystick *joystick) SDL_stack_free(axis_state); } #undef CONVERT_AXIS + + if (switch_state) { + uint32_t i; + uint32_t switch_count = IGameInputReading_GetControllerSwitchState(reading, info->controllerSwitchCount, switch_state); + for (i = 0; i < switch_count; ++i) { + Uint8 hat; + switch (switch_state[i]) { + case GameInputSwitchUp: + hat = SDL_HAT_UP; + break; + case GameInputSwitchUpRight: + hat = SDL_HAT_UP | SDL_HAT_RIGHT; + break; + case GameInputSwitchRight: + hat = SDL_HAT_RIGHT; + break; + case GameInputSwitchDownRight: + hat = SDL_HAT_DOWN | SDL_HAT_RIGHT; + break; + case GameInputSwitchDown: + hat = SDL_HAT_DOWN; + break; + case GameInputSwitchDownLeft: + hat = SDL_HAT_DOWN | SDL_HAT_LEFT; + break; + case GameInputSwitchLeft: + hat = SDL_HAT_LEFT; + break; + case GameInputSwitchUpLeft: + hat = SDL_HAT_UP | SDL_HAT_LEFT; + break; + case GameInputSwitchCenter: + default: + hat = SDL_HAT_CENTERED; + break; + } + SDL_SendJoystickHat(timestamp, joystick, (Uint8)i, hat); + } + SDL_stack_free(switch_state); + } } if (info->supportedInput & GameInputKindTouch) { @@ -689,14 +710,9 @@ static void GAMEINPUT_JoystickQuit(void) GAMEINPUT_InternalRemoveByIndex(0); } - IGameInput_Release(g_pGameInput); + SDL_QuitGameInput(); g_pGameInput = NULL; } - - if (g_hGameInputDLL) { - SDL_UnloadObject(g_hGameInputDLL); - g_hGameInputDLL = NULL; - } } static bool GAMEINPUT_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) diff --git a/libs/SDL3/src/joystick/hidapi/SDL_hidapi_combined.c b/libs/SDL3/src/joystick/hidapi/SDL_hidapi_combined.c index abfce17e..5426edbd 100644 --- a/libs/SDL3/src/joystick/hidapi/SDL_hidapi_combined.c +++ b/libs/SDL3/src/joystick/hidapi/SDL_hidapi_combined.c @@ -70,6 +70,8 @@ static bool HIDAPI_DriverCombined_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Jo for (i = 0; i < device->num_children; ++i) { SDL_HIDAPI_Device *child = device->children[i]; if (!child->driver->OpenJoystick(child, joystick)) { + child->broken = true; + while (i-- > 0) { child = device->children[i]; child->driver->CloseJoystick(child, joystick); diff --git a/libs/SDL3/src/joystick/hidapi/SDL_hidapi_ps3.c b/libs/SDL3/src/joystick/hidapi/SDL_hidapi_ps3.c index bcb7d5b9..6c82647c 100644 --- a/libs/SDL3/src/joystick/hidapi/SDL_hidapi_ps3.c +++ b/libs/SDL3/src/joystick/hidapi/SDL_hidapi_ps3.c @@ -566,7 +566,7 @@ static bool HIDAPI_DriverPS3_UpdateDevice(SDL_HIDAPI_Device *device) break; default: #ifdef DEBUG_JOYSTICK - SDL_Log("Unknown PS3 packet: 0x%.2x\n", data[0]); + SDL_Log("Unknown PS3 packet: 0x%.2x", data[0]); #endif break; } @@ -1004,7 +1004,7 @@ static bool HIDAPI_DriverPS3ThirdParty_UpdateDevice(SDL_HIDAPI_Device *device) HIDAPI_DriverPS3ThirdParty_HandleStatePacket18(joystick, ctx, data, size); } else { #ifdef DEBUG_JOYSTICK - SDL_Log("Unknown PS3 packet, size %d\n", size); + SDL_Log("Unknown PS3 packet, size %d", size); #endif } } @@ -1357,7 +1357,7 @@ static bool HIDAPI_DriverPS3SonySixaxis_UpdateDevice(SDL_HIDAPI_Device *device) break; default: #ifdef DEBUG_JOYSTICK - SDL_Log("Unknown PS3 packet: 0x%.2x\n", data[0]); + SDL_Log("Unknown PS3 packet: 0x%.2x", data[0]); #endif break; } diff --git a/libs/SDL3/src/joystick/hidapi/SDL_hidapi_ps4.c b/libs/SDL3/src/joystick/hidapi/SDL_hidapi_ps4.c index 4fe7b03d..7404bf22 100644 --- a/libs/SDL3/src/joystick/hidapi/SDL_hidapi_ps4.c +++ b/libs/SDL3/src/joystick/hidapi/SDL_hidapi_ps4.c @@ -323,7 +323,7 @@ static bool HIDAPI_DriverPS4_InitDevice(SDL_HIDAPI_Device *device) if (size > 0) { HIDAPI_DumpPacket("PS4 first packet: size = %d", data, size); } else { - SDL_Log("PS4 first packet: size = %d\n", size); + SDL_Log("PS4 first packet: size = %d", size); } #endif if (size > 0 && @@ -468,7 +468,7 @@ static bool HIDAPI_DriverPS4_LoadOfficialCalibrationData(SDL_HIDAPI_Device *devi if (!ctx->official_controller) { #ifdef DEBUG_PS4_CALIBRATION - SDL_Log("Not an official controller, ignoring calibration\n"); + SDL_Log("Not an official controller, ignoring calibration"); #endif return false; } @@ -478,7 +478,7 @@ static bool HIDAPI_DriverPS4_LoadOfficialCalibrationData(SDL_HIDAPI_Device *devi size = ReadFeatureReport(device->dev, k_ePS4FeatureReportIdGyroCalibration_USB, data, sizeof(data)); if (size < 35) { #ifdef DEBUG_PS4_CALIBRATION - SDL_Log("Short read of calibration data: %d, ignoring calibration\n", size); + SDL_Log("Short read of calibration data: %d, ignoring calibration", size); #endif return false; } @@ -487,7 +487,7 @@ static bool HIDAPI_DriverPS4_LoadOfficialCalibrationData(SDL_HIDAPI_Device *devi size = ReadFeatureReport(device->dev, k_ePS4FeatureReportIdGyroCalibration_BT, data, sizeof(data)); if (size < 35) { #ifdef DEBUG_PS4_CALIBRATION - SDL_Log("Short read of calibration data: %d, ignoring calibration\n", size); + SDL_Log("Short read of calibration data: %d, ignoring calibration", size); #endif return false; } @@ -590,19 +590,19 @@ static bool HIDAPI_DriverPS4_LoadOfficialCalibrationData(SDL_HIDAPI_Device *devi ctx->hardware_calibration = true; for (i = 0; i < 6; ++i) { #ifdef DEBUG_PS4_CALIBRATION - SDL_Log("calibration[%d] bias = %d, sensitivity = %f\n", i, ctx->calibration[i].bias, ctx->calibration[i].scale); + SDL_Log("calibration[%d] bias = %d, sensitivity = %f", i, ctx->calibration[i].bias, ctx->calibration[i].scale); #endif // Some controllers have a bad calibration if (SDL_abs(ctx->calibration[i].bias) > 1024 || SDL_fabsf(1.0f - ctx->calibration[i].scale) > 0.5f) { #ifdef DEBUG_PS4_CALIBRATION - SDL_Log("invalid calibration, ignoring\n"); + SDL_Log("invalid calibration, ignoring"); #endif ctx->hardware_calibration = false; } } } else { #ifdef DEBUG_PS4_CALIBRATION - SDL_Log("Calibration data not available\n"); + SDL_Log("Calibration data not available"); #endif } return ctx->hardware_calibration; @@ -1291,7 +1291,7 @@ static bool HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device) break; default: #ifdef DEBUG_JOYSTICK - SDL_Log("Unknown PS4 packet: 0x%.2x\n", data[0]); + SDL_Log("Unknown PS4 packet: 0x%.2x", data[0]); #endif break; } diff --git a/libs/SDL3/src/joystick/hidapi/SDL_hidapi_ps5.c b/libs/SDL3/src/joystick/hidapi/SDL_hidapi_ps5.c index 7226fa20..abf59a87 100644 --- a/libs/SDL3/src/joystick/hidapi/SDL_hidapi_ps5.c +++ b/libs/SDL3/src/joystick/hidapi/SDL_hidapi_ps5.c @@ -402,7 +402,7 @@ static bool HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device) if (size > 0) { HIDAPI_DumpPacket("PS5 first packet: size = %d", data, size); } else { - SDL_Log("PS5 first packet: size = %d\n", size); + SDL_Log("PS5 first packet: size = %d", size); } #endif if (size == 64) { @@ -561,7 +561,7 @@ static void HIDAPI_DriverPS5_LoadCalibrationData(SDL_HIDAPI_Device *device) size = ReadFeatureReport(device->dev, k_EPS5FeatureReportIdCalibration, data, sizeof(data)); if (size < 35) { #ifdef DEBUG_PS5_CALIBRATION - SDL_Log("Short read of calibration data: %d, ignoring calibration\n", size); + SDL_Log("Short read of calibration data: %d, ignoring calibration", size); #endif return; } @@ -631,12 +631,12 @@ static void HIDAPI_DriverPS5_LoadCalibrationData(SDL_HIDAPI_Device *device) for (i = 0; i < 6; ++i) { float divisor = (i < 3 ? 64.0f : 1.0f); #ifdef DEBUG_PS5_CALIBRATION - SDL_Log("calibration[%d] bias = %d, sensitivity = %f\n", i, ctx->calibration[i].bias, ctx->calibration[i].sensitivity); + SDL_Log("calibration[%d] bias = %d, sensitivity = %f", i, ctx->calibration[i].bias, ctx->calibration[i].sensitivity); #endif // Some controllers have a bad calibration if ((SDL_abs(ctx->calibration[i].bias) > 1024) || (SDL_fabsf(1.0f - ctx->calibration[i].sensitivity / divisor) > 0.5f)) { #ifdef DEBUG_PS5_CALIBRATION - SDL_Log("invalid calibration, ignoring\n"); + SDL_Log("invalid calibration, ignoring"); #endif ctx->hardware_calibration = false; } @@ -952,7 +952,7 @@ static bool HIDAPI_DriverPS5_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystic SDL_AddHintCallback(SDL_HINT_JOYSTICK_ENHANCED_REPORTS, SDL_PS5EnhancedReportsChanged, ctx); - SDL_AddHintCallback(SDL_HINT_JOYSTICK_ENHANCED_REPORTS, + SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS5_PLAYER_LED, SDL_PS5PlayerLEDHintChanged, ctx); return true; @@ -1531,7 +1531,7 @@ static bool HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device) break; default: #ifdef DEBUG_JOYSTICK - SDL_Log("Unknown PS5 packet: 0x%.2x\n", data[0]); + SDL_Log("Unknown PS5 packet: 0x%.2x", data[0]); #endif break; } diff --git a/libs/SDL3/src/joystick/hidapi/SDL_hidapi_steam_hori.c b/libs/SDL3/src/joystick/hidapi/SDL_hidapi_steam_hori.c index ac547a19..0cd192d0 100644 --- a/libs/SDL3/src/joystick/hidapi/SDL_hidapi_steam_hori.c +++ b/libs/SDL3/src/joystick/hidapi/SDL_hidapi_steam_hori.c @@ -324,7 +324,7 @@ static void HIDAPI_DriverSteamHori_HandleStatePacket(SDL_Joystick *joystick, SDL 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] ); + // SDL_Log("%u %f, %f, %f ", 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; diff --git a/libs/SDL3/src/joystick/hidapi/SDL_hidapi_switch.c b/libs/SDL3/src/joystick/hidapi/SDL_hidapi_switch.c index 6d1e0b81..0e7b823c 100644 --- a/libs/SDL3/src/joystick/hidapi/SDL_hidapi_switch.c +++ b/libs/SDL3/src/joystick/hidapi/SDL_hidapi_switch.c @@ -521,11 +521,11 @@ static bool WriteProprietary(SDL_DriverSwitch_Context *ctx, ESwitchProprietaryCo } if (!waitForReply || ReadProprietaryReply(ctx, ucCommand)) { - // SDL_Log("Succeeded%s after %d tries\n", ctx->m_bSyncWrite ? " (sync)" : "", nTries); + // SDL_Log("Succeeded%s after %d tries", ctx->m_bSyncWrite ? " (sync)" : "", nTries); return true; } } - // SDL_Log("Failed%s after %d tries\n", ctx->m_bSyncWrite ? " (sync)" : "", nTries); + // SDL_Log("Failed%s after %d tries", ctx->m_bSyncWrite ? " (sync)" : "", nTries); return false; } @@ -579,7 +579,7 @@ static void EncodeRumble(SwitchRumbleData_t *pRumble, Uint16 usHighFreq, Uint8 u pRumble->rgucData[3] = usLowFreqAmp & 0xFF; #ifdef DEBUG_RUMBLE - SDL_Log("Freq: %.2X %.2X %.2X, Amp: %.2X %.2X %.2X\n", + SDL_Log("Freq: %.2X %.2X %.2X, Amp: %.2X %.2X %.2X", usHighFreq & 0xFF, ((usHighFreq >> 8) & 0x01), ucLowFreq, ucHighFreqAmp, ((usLowFreqAmp >> 8) & 0x80), usLowFreqAmp & 0xFF); #endif @@ -813,6 +813,12 @@ static Uint8 GetDefaultInputMode(SDL_DriverSwitch_Context *ctx) } break; } + + // Wired controllers break if they are put into simple controller state + if (input_mode == k_eSwitchInputReportIDs_SimpleControllerState && + !ctx->device->is_bluetooth) { + input_mode = k_eSwitchInputReportIDs_FullControllerState; + } return input_mode; } @@ -869,33 +875,22 @@ static void SetEnhancedModeAvailable(SDL_DriverSwitch_Context *ctx) } } -static void SetEnhancedMode(SDL_DriverSwitch_Context *ctx, bool bEnabled) -{ - if (bEnabled) { - SetEnhancedModeAvailable(ctx); - } - - if (bEnabled != ctx->m_bEnhancedMode) { - ctx->m_bEnhancedMode = bEnabled; - - UpdateInputMode(ctx); - } -} - static void SetEnhancedReportHint(SDL_DriverSwitch_Context *ctx, HIDAPI_Switch_EnhancedReportHint eEnhancedReportHint) { + ctx->m_eEnhancedReportHint = eEnhancedReportHint; + switch (eEnhancedReportHint) { case SWITCH_ENHANCED_REPORT_HINT_OFF: - SetEnhancedMode(ctx, false); + ctx->m_bEnhancedMode = false; break; case SWITCH_ENHANCED_REPORT_HINT_ON: - SetEnhancedMode(ctx, true); + SetEnhancedModeAvailable(ctx); + ctx->m_bEnhancedMode = true; break; case SWITCH_ENHANCED_REPORT_HINT_AUTO: SetEnhancedModeAvailable(ctx); break; } - ctx->m_eEnhancedReportHint = eEnhancedReportHint; UpdateInputMode(ctx); } @@ -954,8 +949,20 @@ static bool LoadStickCalibration(SDL_DriverSwitch_Context *ctx) readFactoryParams.unAddress = k_unSPIStickFactoryCalibrationStartOffset; readFactoryParams.ucLength = k_unSPIStickFactoryCalibrationLength; - if (!WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SPIFlashRead, (uint8_t *)&readFactoryParams, sizeof(readFactoryParams), &factory_reply)) { - return false; + const int MAX_ATTEMPTS = 3; + for (int attempt = 0; ; ++attempt) { + if (!WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SPIFlashRead, (uint8_t *)&readFactoryParams, sizeof(readFactoryParams), &factory_reply)) { + return false; + } + + if (factory_reply->stickFactoryCalibration.opData.unAddress == k_unSPIStickFactoryCalibrationStartOffset) { + // We successfully read the calibration data + break; + } + + if (attempt == MAX_ATTEMPTS) { + return false; + } } // Automatically select the user calibration if magic bytes are set @@ -1519,6 +1526,10 @@ static bool HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joys ctx->m_bSyncWrite = true; if (!ctx->m_bInputOnly) { +#ifdef SDL_PLATFORM_MACOS + // Wait for the OS to finish its handshake with the controller + SDL_Delay(250); +#endif GetInitialInputMode(ctx); ctx->m_nCurrentInputMode = ctx->m_nInitialInputMode; @@ -1647,7 +1658,7 @@ static bool HIDAPI_DriverSwitch_SendPendingRumble(SDL_DriverSwitch_Context *ctx) Uint16 high_frequency_rumble = (Uint16)ctx->m_unRumblePending; #ifdef DEBUG_RUMBLE - SDL_Log("Sent pending rumble %d/%d, %d ms after previous rumble\n", low_frequency_rumble, high_frequency_rumble, SDL_GetTicks() - ctx->m_ulRumbleSent); + SDL_Log("Sent pending rumble %d/%d, %d ms after previous rumble", low_frequency_rumble, high_frequency_rumble, SDL_GetTicks() - ctx->m_ulRumbleSent); #endif ctx->m_bRumblePending = false; ctx->m_unRumblePending = 0; @@ -1659,7 +1670,7 @@ static bool HIDAPI_DriverSwitch_SendPendingRumble(SDL_DriverSwitch_Context *ctx) ctx->m_bRumbleZeroPending = false; #ifdef DEBUG_RUMBLE - SDL_Log("Sent pending zero rumble, %d ms after previous rumble\n", SDL_GetTicks() - ctx->m_ulRumbleSent); + SDL_Log("Sent pending zero rumble, %d ms after previous rumble", SDL_GetTicks() - ctx->m_ulRumbleSent); #endif return HIDAPI_DriverSwitch_ActuallyRumbleJoystick(ctx, 0, 0); } @@ -1709,7 +1720,7 @@ static bool HIDAPI_DriverSwitch_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Jo } #ifdef DEBUG_RUMBLE - SDL_Log("Sent rumble %d/%d\n", low_frequency_rumble, high_frequency_rumble); + SDL_Log("Sent rumble %d/%d", low_frequency_rumble, high_frequency_rumble); #endif return HIDAPI_DriverSwitch_ActuallyRumbleJoystick(ctx, low_frequency_rumble, high_frequency_rumble); @@ -2719,7 +2730,7 @@ static bool HIDAPI_DriverSwitch_UpdateDevice(SDL_HIDAPI_Device *device) } else if (ctx->m_bRumbleActive && now >= (ctx->m_ulRumbleSent + RUMBLE_REFRESH_FREQUENCY_MS)) { #ifdef DEBUG_RUMBLE - SDL_Log("Sent continuing rumble, %d ms after previous rumble\n", now - ctx->m_ulRumbleSent); + SDL_Log("Sent continuing rumble, %d ms after previous rumble", now - ctx->m_ulRumbleSent); #endif WriteRumble(ctx); } @@ -2727,6 +2738,7 @@ static bool HIDAPI_DriverSwitch_UpdateDevice(SDL_HIDAPI_Device *device) // Reconnect the Bluetooth device once the USB device is gone if (device->num_joysticks == 0 && device->is_bluetooth && packet_count > 0 && + !device->parent && !HIDAPI_HasConnectedUSBDevice(device->serial)) { HIDAPI_JoystickConnected(device, NULL); } diff --git a/libs/SDL3/src/joystick/hidapi/SDL_hidapi_wii.c b/libs/SDL3/src/joystick/hidapi/SDL_hidapi_wii.c index c442cc5e..fb3e164a 100644 --- a/libs/SDL3/src/joystick/hidapi/SDL_hidapi_wii.c +++ b/libs/SDL3/src/joystick/hidapi/SDL_hidapi_wii.c @@ -1364,7 +1364,7 @@ static void HandleStatus(SDL_DriverWii_Context *ctx, SDL_Joystick *joystick) // The report data format has been reset, need to update it ResetButtonPacketType(ctx); - SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "HIDAPI Wii: Status update, extension %s\n", hasExtension ? "CONNECTED" : "DISCONNECTED"); + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "HIDAPI Wii: Status update, extension %s", hasExtension ? "CONNECTED" : "DISCONNECTED"); /* When Motion Plus is active, we get extension connect/disconnect status * through the Motion Plus packets. Otherwise we can use the status here. @@ -1404,7 +1404,7 @@ static void HandleResponse(SDL_DriverWii_Context *ctx, SDL_Joystick *joystick) if (ParseExtensionIdentifyResponse(ctx, &extension)) { if ((extension & WII_EXTENSION_MOTIONPLUS_MASK) == WII_EXTENSION_MOTIONPLUS_ID) { // Motion Plus is currently active - SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "HIDAPI Wii: Motion Plus CONNECTED (stage %d)\n", ctx->m_eCommState == k_eWiiCommunicationState_CheckMotionPlusStage1 ? 1 : 2); + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "HIDAPI Wii: Motion Plus CONNECTED (stage %d)", ctx->m_eCommState == k_eWiiCommunicationState_CheckMotionPlusStage1 ? 1 : 2); if (!ctx->m_bMotionPlusPresent) { // Reinitialize to get new sensor availability @@ -1420,7 +1420,7 @@ static void HandleResponse(SDL_DriverWii_Context *ctx, SDL_Joystick *joystick) } else { // Motion Plus is not present - SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "HIDAPI Wii: Motion Plus DISCONNECTED (stage %d)\n", ctx->m_eCommState == k_eWiiCommunicationState_CheckMotionPlusStage1 ? 1 : 2); + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "HIDAPI Wii: Motion Plus DISCONNECTED (stage %d)", ctx->m_eCommState == k_eWiiCommunicationState_CheckMotionPlusStage1 ? 1 : 2); if (ctx->m_bMotionPlusPresent) { // Reinitialize to get new sensor availability @@ -1443,7 +1443,7 @@ static void HandleButtonPacket(SDL_DriverWii_Context *ctx, SDL_Joystick *joystic // FIXME: This should see if the data format is compatible rather than equal if (eExpectedReport != ctx->m_rgucReadBuffer[0]) { - SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "HIDAPI Wii: Resetting report mode to %d\n", eExpectedReport); + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "HIDAPI Wii: Resetting report mode to %d", eExpectedReport); RequestButtonPacketType(ctx, eExpectedReport); } diff --git a/libs/SDL3/src/joystick/hidapi/SDL_hidapi_xbox360w.c b/libs/SDL3/src/joystick/hidapi/SDL_hidapi_xbox360w.c index a0d52627..bf63707a 100644 --- a/libs/SDL3/src/joystick/hidapi/SDL_hidapi_xbox360w.c +++ b/libs/SDL3/src/joystick/hidapi/SDL_hidapi_xbox360w.c @@ -306,7 +306,7 @@ static bool HIDAPI_DriverXbox360W_UpdateDevice(SDL_HIDAPI_Device *device) if (size == 2 && data[0] == 0x08) { bool connected = (data[1] & 0x80) ? true : false; #ifdef DEBUG_JOYSTICK - SDL_Log("Connected = %s\n", connected ? "TRUE" : "FALSE"); + SDL_Log("Connected = %s", connected ? "TRUE" : "FALSE"); #endif if (connected != ctx->connected) { ctx->connected = connected; @@ -323,14 +323,14 @@ static bool HIDAPI_DriverXbox360W_UpdateDevice(SDL_HIDAPI_Device *device) } else if (size == 29 && data[0] == 0x00 && data[1] == 0x0f && data[2] == 0x00 && data[3] == 0xf0) { // Serial number is data[7-13] #ifdef DEBUG_JOYSTICK - SDL_Log("Battery status (initial): %d\n", data[17]); + SDL_Log("Battery status (initial): %d", data[17]); #endif if (joystick) { UpdatePowerLevel(joystick, data[17]); } } else if (size == 29 && data[0] == 0x00 && data[1] == 0x00 && data[2] == 0x00 && data[3] == 0x13) { #ifdef DEBUG_JOYSTICK - SDL_Log("Battery status: %d\n", data[4]); + SDL_Log("Battery status: %d", data[4]); #endif if (joystick) { UpdatePowerLevel(joystick, data[4]); diff --git a/libs/SDL3/src/joystick/hidapi/SDL_hidapi_xboxone.c b/libs/SDL3/src/joystick/hidapi/SDL_hidapi_xboxone.c index 5d4742f0..342eabdf 100644 --- a/libs/SDL3/src/joystick/hidapi/SDL_hidapi_xboxone.c +++ b/libs/SDL3/src/joystick/hidapi/SDL_hidapi_xboxone.c @@ -213,7 +213,7 @@ static void SDLCALL SDL_HomeLEDHintChanged(void *userdata, const char *name, con static void SetInitState(SDL_DriverXboxOne_Context *ctx, SDL_XboxOneInitState state) { #ifdef DEBUG_JOYSTICK - SDL_Log("Setting init state %d\n", state); + SDL_Log("Setting init state %d", state); #endif ctx->init_state = state; } @@ -391,7 +391,7 @@ static bool HIDAPI_DriverXboxOne_InitDevice(SDL_HIDAPI_Device *device) } #ifdef DEBUG_JOYSTICK - SDL_Log("Controller version: %d (0x%.4x)\n", device->version, device->version); + SDL_Log("Controller version: %d (0x%.4x)", device->version, device->version); #endif device->type = SDL_GAMEPAD_TYPE_XBOXONE; @@ -620,7 +620,7 @@ static void HIDAPI_DriverXboxOne_HandleUnmappedStatePacket(SDL_Joystick *joystic return; } #ifdef DEBUG_XBOX_PROTOCOL - SDL_Log(">>> Paddles: %d,%d,%d,%d mapped = %s\n", + SDL_Log(">>> Paddles: %d,%d,%d,%d mapped = %s", (data[paddle_index] & button1_bit) ? 1 : 0, (data[paddle_index] & button2_bit) ? 1 : 0, (data[paddle_index] & button3_bit) ? 1 : 0, @@ -654,7 +654,7 @@ static void HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, SDL_D Uint8 packet[] = { 0x4d, 0x00, 0x00, 0x02, 0x07, 0x00 }; #ifdef DEBUG_JOYSTICK - SDL_Log("Enabling paddles on XBox Elite 2\n"); + SDL_Log("Enabling paddles on XBox Elite 2"); #endif SDL_HIDAPI_SendRumble(ctx->device, packet, sizeof(packet)); } @@ -787,7 +787,7 @@ static void HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, SDL_D paddles_mapped = (data[20] != 0); } #ifdef DEBUG_XBOX_PROTOCOL - SDL_Log(">>> Paddles: %d,%d,%d,%d mapped = %s\n", + SDL_Log(">>> Paddles: %d,%d,%d,%d mapped = %s", (data[paddle_index] & button1_bit) ? 1 : 0, (data[paddle_index] & button2_bit) ? 1 : 0, (data[paddle_index] & button3_bit) ? 1 : 0, @@ -954,7 +954,7 @@ static void HIDAPI_DriverXboxOneBluetooth_HandleButtons(Uint64 timestamp, SDL_Jo } #ifdef DEBUG_XBOX_PROTOCOL - SDL_Log(">>> Paddles: %d,%d,%d,%d mapped = %s\n", + SDL_Log(">>> Paddles: %d,%d,%d,%d mapped = %s", (data[paddle_index] & button1_bit) ? 1 : 0, (data[paddle_index] & button2_bit) ? 1 : 0, (data[paddle_index] & button3_bit) ? 1 : 0, @@ -990,7 +990,7 @@ static void HIDAPI_DriverXboxOneBluetooth_HandleStatePacket(SDL_Joystick *joysti HIDAPI_DriverXboxOneBluetooth_HandleButtons(timestamp, joystick, ctx, data, size); } else { #ifdef DEBUG_XBOX_PROTOCOL - SDL_Log("Unknown Bluetooth state packet format\n"); + SDL_Log("Unknown Bluetooth state packet format"); #endif return; } @@ -1104,7 +1104,7 @@ static void HIDAPI_DriverXboxOne_HandleSerialIDPacket(SDL_DriverXboxOne_Context serial[i * 2] = '\0'; #ifdef DEBUG_JOYSTICK - SDL_Log("Setting serial number to %s\n", serial); + SDL_Log("Setting serial number to %s", serial); #endif HIDAPI_SetDeviceSerial(ctx->device, serial); } @@ -1129,7 +1129,7 @@ static bool HIDAPI_DriverXboxOne_UpdateInitState(SDL_DriverXboxOne_Context *ctx) if (SDL_GetTicks() >= (ctx->send_time + CONTROLLER_IDENTIFY_TIMEOUT_MS)) { // We haven't heard anything, let's move on #ifdef DEBUG_JOYSTICK - SDL_Log("Identification request timed out after %llu ms\n", (SDL_GetTicks() - ctx->send_time)); + SDL_Log("Identification request timed out after %llu ms", (SDL_GetTicks() - ctx->send_time)); #endif SetInitState(ctx, XBOX_ONE_INIT_STATE_STARTUP); } @@ -1146,7 +1146,7 @@ static bool HIDAPI_DriverXboxOne_UpdateInitState(SDL_DriverXboxOne_Context *ctx) case XBOX_ONE_INIT_STATE_PREPARE_INPUT: if (SDL_GetTicks() >= (ctx->send_time + CONTROLLER_PREPARE_INPUT_TIMEOUT_MS)) { #ifdef DEBUG_JOYSTICK - SDL_Log("Prepare input complete after %llu ms\n", (SDL_GetTicks() - ctx->send_time)); + SDL_Log("Prepare input complete after %llu ms", (SDL_GetTicks() - ctx->send_time)); #endif SetInitState(ctx, XBOX_ONE_INIT_STATE_COMPLETE); } @@ -1323,7 +1323,7 @@ static bool HIDAPI_GIP_SendPacket(SDL_DriverXboxOne_Context *ctx, struct gip_hea hdr_len = HIDAPI_GIP_GetHeaderLength(hdr); size = (hdr_len + hdr->packet_length); if (size > sizeof(packet)) { - SDL_SetError("Couldn't send GIP packet, size (%d) too large\n", size); + SDL_SetError("Couldn't send GIP packet, size (%d) too large", size); return false; } @@ -1397,7 +1397,7 @@ static bool HIDAPI_GIP_DispatchPacket(SDL_Joystick *joystick, SDL_DriverXboxOne_ then 8 bytes of unknown data */ #ifdef DEBUG_JOYSTICK - SDL_Log("Controller announce after %llu ms\n", (SDL_GetTicks() - ctx->start_time)); + SDL_Log("Controller announce after %llu ms", (SDL_GetTicks() - ctx->start_time)); #endif SetInitState(ctx, XBOX_ONE_INIT_STATE_ANNOUNCED); break; @@ -1407,7 +1407,7 @@ static bool HIDAPI_GIP_DispatchPacket(SDL_Joystick *joystick, SDL_DriverXboxOne_ break; case GIP_CMD_IDENTIFY: #ifdef DEBUG_JOYSTICK - SDL_Log("Identification request completed after %llu ms\n", (SDL_GetTicks() - ctx->send_time)); + SDL_Log("Identification request completed after %llu ms", (SDL_GetTicks() - ctx->send_time)); #endif #ifdef DEBUG_XBOX_PROTOCOL HIDAPI_DumpPacket("Xbox One identification data: size = %d", data, size); @@ -1440,7 +1440,7 @@ static bool HIDAPI_GIP_DispatchPacket(SDL_Joystick *joystick, SDL_DriverXboxOne_ break; default: #ifdef DEBUG_JOYSTICK - SDL_Log("Unknown Xbox One packet: 0x%.2x\n", hdr->command); + SDL_Log("Unknown Xbox One packet: 0x%.2x", hdr->command); #endif break; } @@ -1452,7 +1452,7 @@ static bool HIDAPI_GIP_DispatchPacket(SDL_Joystick *joystick, SDL_DriverXboxOne_ // Ignore the first input, it may be spurious #ifdef DEBUG_JOYSTICK - SDL_Log("Controller ignoring spurious input\n"); + SDL_Log("Controller ignoring spurious input"); #endif break; } @@ -1469,7 +1469,7 @@ static bool HIDAPI_GIP_DispatchPacket(SDL_Joystick *joystick, SDL_DriverXboxOne_ break; default: #ifdef DEBUG_JOYSTICK - SDL_Log("Unknown Xbox One packet: 0x%.2x\n", hdr->command); + SDL_Log("Unknown Xbox One packet: 0x%.2x", hdr->command); #endif break; } @@ -1596,7 +1596,7 @@ static bool HIDAPI_DriverXboxOne_UpdateDevice(SDL_HIDAPI_Device *device) HIDAPI_DriverXboxOneBluetooth_HandleStatePacket(joystick, ctx, data, size); } else { #ifdef DEBUG_JOYSTICK - SDL_Log("Unknown Xbox One Bluetooth packet size: %d\n", size); + SDL_Log("Unknown Xbox One Bluetooth packet size: %d", size); #endif } break; @@ -1614,7 +1614,7 @@ static bool HIDAPI_DriverXboxOne_UpdateDevice(SDL_HIDAPI_Device *device) break; default: #ifdef DEBUG_JOYSTICK - SDL_Log("Unknown Xbox One packet: 0x%.2x\n", data[0]); + SDL_Log("Unknown Xbox One packet: 0x%.2x", data[0]); #endif break; } diff --git a/libs/SDL3/src/joystick/hidapi/SDL_hidapijoystick.c b/libs/SDL3/src/joystick/hidapi/SDL_hidapijoystick.c index c8ddd3d4..bec9c907 100644 --- a/libs/SDL3/src/joystick/hidapi/SDL_hidapijoystick.c +++ b/libs/SDL3/src/joystick/hidapi/SDL_hidapijoystick.c @@ -192,7 +192,13 @@ bool HIDAPI_SupportsPlaystationDetection(Uint16 vendor, Uint16 product) case USB_VENDOR_SHANWAN_ALT: return true; case USB_VENDOR_THRUSTMASTER: - return true; + /* Most of these are wheels, don't have the full set of effects, and + * at least in the case of the T248 and T300 RS, the hid-tmff2 driver + * puts them in a non-standard report mode and they can't be read. + * + * If these should use the HIDAPI driver, add them to controller_list.h + */ + return false; case USB_VENDOR_ZEROPLUS: return true; case 0x7545 /* SZ-MYPOWER */: @@ -357,7 +363,7 @@ static SDL_HIDAPI_Device *HIDAPI_GetDeviceByIndex(int device_index, SDL_Joystick SDL_AssertJoysticksLocked(); for (device = SDL_HIDAPI_devices; device; device = device->next) { - if (device->parent) { + if (device->parent || device->broken) { continue; } if (device->driver) { @@ -458,7 +464,7 @@ static void HIDAPI_SetupDeviceDriver(SDL_HIDAPI_Device *device, bool *removed) S if (dev == NULL) { SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, - "HIDAPI_SetupDeviceDriver() couldn't open %s: %s\n", + "HIDAPI_SetupDeviceDriver() couldn't open %s: %s", device->path, SDL_GetError()); return; } @@ -527,24 +533,6 @@ static bool HIDAPI_JoystickInit(void) return true; } -#ifdef SDL_USE_LIBUDEV - if (linux_enumeration_method == ENUMERATION_UNSET) { - if (!SDL_GetHintBoolean(SDL_HINT_HIDAPI_UDEV, true)) { - SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, - "udev disabled by SDL_HINT_HIDAPI_UDEV"); - linux_enumeration_method = ENUMERATION_FALLBACK; - } else if (SDL_GetSandbox() != SDL_SANDBOX_NONE) { - SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, - "Container detected, disabling HIDAPI udev integration"); - linux_enumeration_method = ENUMERATION_FALLBACK; - } else { - SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, - "Using udev for HIDAPI joystick device discovery"); - linux_enumeration_method = ENUMERATION_LIBUDEV; - } - } -#endif - if (SDL_hid_init() < 0) { return SDL_SetError("Couldn't initialize hidapi"); } @@ -697,7 +685,7 @@ bool HIDAPI_HasConnectedUSBDevice(const char *serial) } for (device = SDL_HIDAPI_devices; device; device = device->next) { - if (!device->driver) { + if (!device->driver || device->broken) { continue; } @@ -723,7 +711,7 @@ void HIDAPI_DisconnectBluetoothDevice(const char *serial) } for (device = SDL_HIDAPI_devices; device; device = device->next) { - if (!device->driver) { + if (!device->driver || device->broken) { continue; } @@ -955,7 +943,7 @@ static SDL_HIDAPI_Device *HIDAPI_AddDevice(const struct SDL_hid_device_info *inf return NULL; } - SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "Added HIDAPI device '%s' VID 0x%.4x, PID 0x%.4x, bluetooth %d, version %d, serial %s, interface %d, interface_class %d, interface_subclass %d, interface_protocol %d, usage page 0x%.4x, usage 0x%.4x, path = %s, driver = %s (%s)\n", device->name, device->vendor_id, device->product_id, device->is_bluetooth, device->version, + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "Added HIDAPI device '%s' VID 0x%.4x, PID 0x%.4x, bluetooth %d, version %d, serial %s, interface %d, interface_class %d, interface_subclass %d, interface_protocol %d, usage page 0x%.4x, usage 0x%.4x, path = %s, driver = %s (%s)", device->name, device->vendor_id, device->product_id, device->is_bluetooth, device->version, device->serial ? device->serial : "NONE", device->interface_number, device->interface_class, device->interface_subclass, device->interface_protocol, device->usage_page, device->usage, device->path, device->driver ? device->driver->name : "NONE", device->driver && device->driver->enabled ? "ENABLED" : "DISABLED"); @@ -969,7 +957,7 @@ static void HIDAPI_DelDevice(SDL_HIDAPI_Device *device) SDL_AssertJoysticksLocked(); - SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "Removing HIDAPI device '%s' VID 0x%.4x, PID 0x%.4x, bluetooth %d, version %d, serial %s, interface %d, interface_class %d, interface_subclass %d, interface_protocol %d, usage page 0x%.4x, usage 0x%.4x, path = %s, driver = %s (%s)\n", device->name, device->vendor_id, device->product_id, device->is_bluetooth, device->version, + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "Removing HIDAPI device '%s' VID 0x%.4x, PID 0x%.4x, bluetooth %d, version %d, serial %s, interface %d, interface_class %d, interface_subclass %d, interface_protocol %d, usage page 0x%.4x, usage 0x%.4x, path = %s, driver = %s (%s)", device->name, device->vendor_id, device->product_id, device->is_bluetooth, device->version, device->serial ? device->serial : "NONE", device->interface_number, device->interface_class, device->interface_subclass, device->interface_protocol, device->usage_page, device->usage, device->path, device->driver ? device->driver->name : "NONE", device->driver && device->driver->enabled ? "ENABLED" : "DISABLED"); @@ -1028,6 +1016,10 @@ static bool HIDAPI_CreateCombinedJoyCons(void) // This device is already part of a combined device continue; } + if (device->broken) { + // This device can't be used + continue; + } SDL_GetJoystickGUIDInfo(device->guid, &vendor, &product, NULL, NULL); @@ -1148,6 +1140,12 @@ check_removed: SDL_HIDAPI_change_count = 0; } } + if (device->broken && device->parent) { + HIDAPI_DelDevice(device->parent); + + // We deleted a different device here, restart the loop + goto check_removed; + } device = next; } @@ -1229,7 +1227,7 @@ bool HIDAPI_IsDeviceTypePresent(SDL_GamepadType type) SDL_UnlockJoysticks(); #ifdef DEBUG_HIDAPI - SDL_Log("HIDAPI_IsDeviceTypePresent() returning %s for %d\n", result ? "true" : "false", type); + SDL_Log("HIDAPI_IsDeviceTypePresent() returning %s for %d", result ? "true" : "false", type); #endif return result; } @@ -1280,7 +1278,7 @@ bool HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, SDL_UnlockJoysticks(); #ifdef DEBUG_HIDAPI - SDL_Log("HIDAPI_IsDevicePresent() returning %s for 0x%.4x / 0x%.4x\n", result ? "true" : "false", vendor_id, product_id); + SDL_Log("HIDAPI_IsDevicePresent() returning %s for 0x%.4x / 0x%.4x", result ? "true" : "false", vendor_id, product_id); #endif return result; } @@ -1490,9 +1488,9 @@ static bool HIDAPI_JoystickOpen(SDL_Joystick *joystick, int device_index) SDL_AssertJoysticksLocked(); - if (!device || !device->driver) { + if (!device || !device->driver || device->broken) { // This should never happen - validated before being called - return SDL_SetError("Couldn't find HIDAPI device at index %d\n", device_index); + return SDL_SetError("Couldn't find HIDAPI device at index %d", device_index); } hwdata = (struct joystick_hwdata *)SDL_calloc(1, sizeof(*hwdata)); diff --git a/libs/SDL3/src/joystick/hidapi/SDL_hidapijoystick_c.h b/libs/SDL3/src/joystick/hidapi/SDL_hidapijoystick_c.h index f8d77093..9cd9f400 100644 --- a/libs/SDL3/src/joystick/hidapi/SDL_hidapijoystick_c.h +++ b/libs/SDL3/src/joystick/hidapi/SDL_hidapijoystick_c.h @@ -101,6 +101,10 @@ typedef struct SDL_HIDAPI_Device // Used to flag that the device is being updated bool updating; + // Used to flag devices that failed open + // This can happen on Windows with Bluetooth devices that have turned off + bool broken; + struct SDL_HIDAPI_Device *parent; int num_children; struct SDL_HIDAPI_Device **children; diff --git a/libs/SDL3/src/joystick/linux/SDL_sysjoystick.c b/libs/SDL3/src/joystick/linux/SDL_sysjoystick.c index 8fbaca99..ea73821c 100644 --- a/libs/SDL3/src/joystick/linux/SDL_sysjoystick.c +++ b/libs/SDL3/src/joystick/linux/SDL_sysjoystick.c @@ -327,7 +327,7 @@ static bool IsJoystick(const char *path, int *fd, char **name_return, Uint16 *ve FixupDeviceInfoForMapping(*fd, &inpid); #ifdef DEBUG_JOYSTICK - SDL_Log("Joystick: %s, bustype = %d, vendor = 0x%.4x, product = 0x%.4x, version = %d\n", name, inpid.bustype, inpid.vendor, inpid.product, inpid.version); + SDL_Log("Joystick: %s, bustype = %d, vendor = 0x%.4x, product = 0x%.4x, version = %d", name, inpid.bustype, inpid.vendor, inpid.product, inpid.version); #endif if (SDL_ShouldIgnoreJoystick(inpid.vendor, inpid.product, inpid.version, name)) { @@ -470,12 +470,12 @@ static void MaybeAddDevice(const char *path) } #ifdef DEBUG_INPUT_EVENTS - SDL_Log("Checking %s\n", path); + SDL_Log("Checking %s", path); #endif if (IsJoystick(path, &fd, &name, &vendor, &product, &guid)) { #ifdef DEBUG_INPUT_EVENTS - SDL_Log("found joystick: %s\n", path); + SDL_Log("found joystick: %s", path); #endif item = (SDL_joylist_item *)SDL_calloc(1, sizeof(SDL_joylist_item)); if (!item) { @@ -516,7 +516,7 @@ static void MaybeAddDevice(const char *path) if (IsSensor(path, &fd)) { #ifdef DEBUG_INPUT_EVENTS - SDL_Log("found sensor: %s\n", path); + SDL_Log("found sensor: %s", path); #endif item_sensor = (SDL_sensorlist_item *)SDL_calloc(1, sizeof(SDL_sensorlist_item)); if (!item_sensor) { @@ -1217,7 +1217,7 @@ static void ConfigJoystick(SDL_Joystick *joystick, int fd, int fd_sensor) for (i = BTN_JOYSTICK; i < KEY_MAX; ++i) { if (test_bit(i, keybit)) { #ifdef DEBUG_INPUT_EVENTS - SDL_Log("Joystick has button: 0x%x\n", i); + SDL_Log("Joystick has button: 0x%x", i); #endif joystick->hwdata->key_map[i] = joystick->nbuttons; joystick->hwdata->has_key[i] = true; @@ -1227,7 +1227,7 @@ static void ConfigJoystick(SDL_Joystick *joystick, int fd, int fd_sensor) for (i = 0; i < BTN_JOYSTICK; ++i) { if (test_bit(i, keybit)) { #ifdef DEBUG_INPUT_EVENTS - SDL_Log("Joystick has button: 0x%x\n", i); + SDL_Log("Joystick has button: 0x%x", i); #endif joystick->hwdata->key_map[i] = joystick->nbuttons; joystick->hwdata->has_key[i] = true; @@ -1250,14 +1250,14 @@ static void ConfigJoystick(SDL_Joystick *joystick, int fd, int fd_sensor) const int hat_index = (i - ABS_HAT0X) / 2; struct hat_axis_correct *correct = &joystick->hwdata->hat_correct[hat_index]; #ifdef DEBUG_INPUT_EVENTS - SDL_Log("Joystick has digital hat: #%d\n", hat_index); + SDL_Log("Joystick has digital hat: #%d", hat_index); if (hat_x >= 0) { - SDL_Log("X Values = { val:%d, min:%d, max:%d, fuzz:%d, flat:%d, res:%d }\n", + SDL_Log("X Values = { val:%d, min:%d, max:%d, fuzz:%d, flat:%d, res:%d }", absinfo_x.value, absinfo_x.minimum, absinfo_x.maximum, absinfo_x.fuzz, absinfo_x.flat, absinfo_x.resolution); } if (hat_y >= 0) { - SDL_Log("Y Values = { val:%d, min:%d, max:%d, fuzz:%d, flat:%d, res:%d }\n", + SDL_Log("Y Values = { val:%d, min:%d, max:%d, fuzz:%d, flat:%d, res:%d }", absinfo_y.value, absinfo_y.minimum, absinfo_y.maximum, absinfo_y.fuzz, absinfo_y.flat, absinfo_y.resolution); } @@ -1285,8 +1285,8 @@ static void ConfigJoystick(SDL_Joystick *joystick, int fd, int fd_sensor) continue; } #ifdef DEBUG_INPUT_EVENTS - SDL_Log("Joystick has absolute axis: 0x%.2x\n", i); - SDL_Log("Values = { val:%d, min:%d, max:%d, fuzz:%d, flat:%d, res:%d }\n", + SDL_Log("Joystick has absolute axis: 0x%.2x", i); + SDL_Log("Values = { val:%d, min:%d, max:%d, fuzz:%d, flat:%d, res:%d }", absinfo.value, absinfo.minimum, absinfo.maximum, absinfo.fuzz, absinfo.flat, absinfo.resolution); #endif // DEBUG_INPUT_EVENTS @@ -1340,7 +1340,7 @@ static void ConfigJoystick(SDL_Joystick *joystick, int fd, int fd_sensor) for (i = 0; i < key_pam_size; ++i) { Uint16 code = joystick->hwdata->key_pam[i]; #ifdef DEBUG_INPUT_EVENTS - SDL_Log("Joystick has button: 0x%x\n", code); + SDL_Log("Joystick has button: 0x%x", code); #endif joystick->hwdata->key_map[code] = joystick->nbuttons; joystick->hwdata->has_key[code] = true; @@ -1366,7 +1366,7 @@ static void ConfigJoystick(SDL_Joystick *joystick, int fd, int fd_sensor) int hat_index = (code - ABS_HAT0X) / 2; if (!joystick->hwdata->has_hat[hat_index]) { #ifdef DEBUG_INPUT_EVENTS - SDL_Log("Joystick has digital hat: #%d\n", hat_index); + SDL_Log("Joystick has digital hat: #%d", hat_index); #endif joystick->hwdata->hats_indices[hat_index] = joystick->nhats++; joystick->hwdata->has_hat[hat_index] = true; @@ -1377,7 +1377,7 @@ static void ConfigJoystick(SDL_Joystick *joystick, int fd, int fd_sensor) } } else { #ifdef DEBUG_INPUT_EVENTS - SDL_Log("Joystick has absolute axis: 0x%.2x\n", code); + SDL_Log("Joystick has absolute axis: 0x%.2x", code); #endif joystick->hwdata->abs_map[code] = joystick->naxes; joystick->hwdata->has_abs[code] = true; @@ -1398,8 +1398,8 @@ static void ConfigJoystick(SDL_Joystick *joystick, int fd, int fd_sensor) } joystick->hwdata->accelerometer_scale[i] = absinfo.resolution; #ifdef DEBUG_INPUT_EVENTS - SDL_Log("Joystick has accelerometer axis: 0x%.2x\n", ABS_X + i); - SDL_Log("Values = { val:%d, min:%d, max:%d, fuzz:%d, flat:%d, res:%d }\n", + SDL_Log("Joystick has accelerometer axis: 0x%.2x", ABS_X + i); + SDL_Log("Values = { val:%d, min:%d, max:%d, fuzz:%d, flat:%d, res:%d }", absinfo.value, absinfo.minimum, absinfo.maximum, absinfo.fuzz, absinfo.flat, absinfo.resolution); #endif // DEBUG_INPUT_EVENTS @@ -1416,8 +1416,8 @@ static void ConfigJoystick(SDL_Joystick *joystick, int fd, int fd_sensor) } joystick->hwdata->gyro_scale[i] = absinfo.resolution; #ifdef DEBUG_INPUT_EVENTS - SDL_Log("Joystick has gyro axis: 0x%.2x\n", ABS_RX + i); - SDL_Log("Values = { val:%d, min:%d, max:%d, fuzz:%d, flat:%d, res:%d }\n", + SDL_Log("Joystick has gyro axis: 0x%.2x", ABS_RX + i); + SDL_Log("Values = { val:%d, min:%d, max:%d, fuzz:%d, flat:%d, res:%d }", absinfo.value, absinfo.minimum, absinfo.maximum, absinfo.fuzz, absinfo.flat, absinfo.resolution); #endif // DEBUG_INPUT_EVENTS @@ -1518,11 +1518,12 @@ static SDL_sensorlist_item *GetSensor(SDL_joylist_item *item) return NULL; } if (ioctl(fd_item, EVIOCGUNIQ(sizeof(uniq_item) - 1), &uniq_item) < 0) { + close(fd_item); return NULL; } close(fd_item); #ifdef DEBUG_INPUT_EVENTS - SDL_Log("Joystick UNIQ: %s\n", uniq_item); + SDL_Log("Joystick UNIQ: %s", uniq_item); #endif // DEBUG_INPUT_EVENTS for (item_sensor = SDL_sensorlist; item_sensor; item_sensor = item_sensor->next) { @@ -1544,7 +1545,7 @@ static SDL_sensorlist_item *GetSensor(SDL_joylist_item *item) } close(fd_sensor); #ifdef DEBUG_INPUT_EVENTS - SDL_Log("Sensor UNIQ: %s\n", uniq_sensor); + SDL_Log("Sensor UNIQ: %s", uniq_sensor); #endif // DEBUG_INPUT_EVENTS if (SDL_strcmp(uniq_item, uniq_sensor) == 0) { @@ -1800,7 +1801,7 @@ static void PollAllValues(Uint64 timestamp, SDL_Joystick *joystick) absinfo.value = AxisCorrect(joystick, i, absinfo.value); #ifdef DEBUG_INPUT_EVENTS - SDL_Log("Joystick : Re-read Axis %d (%d) val= %d\n", + SDL_Log("Joystick : Re-read Axis %d (%d) val= %d", joystick->hwdata->abs_map[i], i, absinfo.value); #endif SDL_SendJoystickAxis(timestamp, joystick, @@ -1831,7 +1832,7 @@ static void PollAllValues(Uint64 timestamp, SDL_Joystick *joystick) if (joystick->hwdata->has_key[i]) { bool down = test_bit(i, keyinfo); #ifdef DEBUG_INPUT_EVENTS - SDL_Log("Joystick : Re-read Button %d (%d) val= %d\n", + SDL_Log("Joystick : Re-read Button %d (%d) val= %d", joystick->hwdata->key_map[i], i, down); #endif SDL_SendJoystickButton(timestamp, joystick, @@ -1858,7 +1859,7 @@ static void PollAllSensors(Uint64 timestamp, SDL_Joystick *joystick) if (ioctl(joystick->hwdata->fd_sensor, EVIOCGABS(ABS_RX + i), &absinfo) >= 0) { data[i] = absinfo.value * (SDL_PI_F / 180.f) / joystick->hwdata->gyro_scale[i]; #ifdef DEBUG_INPUT_EVENTS - SDL_Log("Joystick : Re-read Gyro (axis %d) val= %f\n", i, data[i]); + SDL_Log("Joystick : Re-read Gyro (axis %d) val= %f", i, data[i]); #endif } } @@ -1870,7 +1871,7 @@ static void PollAllSensors(Uint64 timestamp, SDL_Joystick *joystick) if (ioctl(joystick->hwdata->fd_sensor, EVIOCGABS(ABS_X + i), &absinfo) >= 0) { data[i] = absinfo.value * SDL_STANDARD_GRAVITY / joystick->hwdata->accelerometer_scale[i]; #ifdef DEBUG_INPUT_EVENTS - SDL_Log("Joystick : Re-read Accelerometer (axis %d) val= %f\n", i, data[i]); + SDL_Log("Joystick : Re-read Accelerometer (axis %d) val= %f", i, data[i]); #endif } } @@ -1913,7 +1914,7 @@ static void HandleInputEvents(SDL_Joystick *joystick) switch (event->type) { case EV_KEY: #ifdef DEBUG_INPUT_EVENTS - SDL_Log("Key 0x%.2x %s\n", code, event->value ? "PRESSED" : "RELEASED"); + SDL_Log("Key 0x%.2x %s", code, event->value ? "PRESSED" : "RELEASED"); #endif SDL_SendJoystickButton(SDL_EVDEV_GetEventTimestamp(event), joystick, joystick->hwdata->key_map[code], @@ -1932,7 +1933,7 @@ static void HandleInputEvents(SDL_Joystick *joystick) hat_index = (code - ABS_HAT0X) / 2; if (joystick->hwdata->has_hat[hat_index]) { #ifdef DEBUG_INPUT_EVENTS - SDL_Log("Axis 0x%.2x = %d\n", code, event->value); + SDL_Log("Axis 0x%.2x = %d", code, event->value); #endif HandleHat(SDL_EVDEV_GetEventTimestamp(event), joystick, hat_index, code % 2, event->value); break; @@ -1940,7 +1941,7 @@ static void HandleInputEvents(SDL_Joystick *joystick) SDL_FALLTHROUGH; default: #ifdef DEBUG_INPUT_EVENTS - SDL_Log("Axis 0x%.2x = %d\n", code, event->value); + SDL_Log("Axis 0x%.2x = %d", code, event->value); #endif event->value = AxisCorrect(joystick, code, event->value); SDL_SendJoystickAxis(SDL_EVDEV_GetEventTimestamp(event), joystick, @@ -1964,7 +1965,7 @@ static void HandleInputEvents(SDL_Joystick *joystick) switch (code) { case SYN_DROPPED: #ifdef DEBUG_INPUT_EVENTS - SDL_Log("Event SYN_DROPPED detected\n"); + SDL_Log("Event SYN_DROPPED detected"); #endif joystick->hwdata->recovering_from_dropped = true; break; @@ -2047,7 +2048,7 @@ static void HandleInputEvents(SDL_Joystick *joystick) switch (code) { case SYN_DROPPED: #ifdef DEBUG_INPUT_EVENTS - SDL_Log("Event SYN_DROPPED detected\n"); + SDL_Log("Event SYN_DROPPED detected"); #endif joystick->hwdata->recovering_from_dropped_sensor = true; break; diff --git a/libs/SDL3/src/joystick/usb_ids.h b/libs/SDL3/src/joystick/usb_ids.h index c978c198..794beb86 100644 --- a/libs/SDL3/src/joystick/usb_ids.h +++ b/libs/SDL3/src/joystick/usb_ids.h @@ -123,7 +123,8 @@ #define USB_PRODUCT_SONY_DS5 0x0ce6 #define USB_PRODUCT_SONY_DS5_EDGE 0x0df2 #define USB_PRODUCT_SWITCH_RETROBIT_CONTROLLER 0x0575 -#define USB_PRODUCT_THRUSTMASTER_ESWAPX_PRO 0xd012 +#define USB_PRODUCT_THRUSTMASTER_ESWAPX_PRO_PS4 0xd00e +#define USB_PRODUCT_THRUSTMASTER_ESWAPX_PRO_SERIES_X 0xd012 #define USB_PRODUCT_TURTLE_BEACH_SERIES_X_REACT_R 0x7013 #define USB_PRODUCT_TURTLE_BEACH_SERIES_X_RECON 0x7009 #define USB_PRODUCT_VALVE_STEAM_CONTROLLER_DONGLE 0x1142 diff --git a/libs/SDL3/src/joystick/windows/SDL_rawinputjoystick.c b/libs/SDL3/src/joystick/windows/SDL_rawinputjoystick.c index 5ef4a302..d5166def 100644 --- a/libs/SDL3/src/joystick/windows/SDL_rawinputjoystick.c +++ b/libs/SDL3/src/joystick/windows/SDL_rawinputjoystick.c @@ -703,12 +703,12 @@ static void RAWINPUT_InitWindowsGamingInput(RAWINPUT_DeviceContext *ctx) hr = __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_add_GamepadAdded(wgi_state.gamepad_statics, &gamepad_added.iface, &wgi_state.gamepad_added_token); if (!SUCCEEDED(hr)) { - SDL_SetError("add_GamepadAdded() failed: 0x%lx\n", hr); + SDL_SetError("add_GamepadAdded() failed: 0x%lx", hr); } hr = __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_add_GamepadRemoved(wgi_state.gamepad_statics, &gamepad_removed.iface, &wgi_state.gamepad_removed_token); if (!SUCCEEDED(hr)) { - SDL_SetError("add_GamepadRemoved() failed: 0x%lx\n", hr); + SDL_SetError("add_GamepadRemoved() failed: 0x%lx", hr); } } } @@ -935,7 +935,7 @@ static void RAWINPUT_AddDevice(HANDLE hDevice) device->joystick_id = SDL_GetNextObjectID(); #ifdef DEBUG_RAWINPUT - SDL_Log("Adding RAWINPUT device '%s' VID 0x%.4x, PID 0x%.4x, version %d, handle 0x%.8x\n", device->name, device->vendor_id, device->product_id, device->version, device->hDevice); + SDL_Log("Adding RAWINPUT device '%s' VID 0x%.4x, PID 0x%.4x, version %d, handle 0x%.8x", device->name, device->vendor_id, device->product_id, device->version, device->hDevice); #endif // Add it to the list @@ -985,7 +985,7 @@ static void RAWINPUT_DelDevice(SDL_RAWINPUT_Device *device, bool send_event) SDL_PrivateJoystickRemoved(device->joystick_id); #ifdef DEBUG_RAWINPUT - SDL_Log("Removing RAWINPUT device '%s' VID 0x%.4x, PID 0x%.4x, version %d, handle %p\n", device->name, device->vendor_id, device->product_id, device->version, device->hDevice); + SDL_Log("Removing RAWINPUT device '%s' VID 0x%.4x, PID 0x%.4x, version %d, handle %p", device->name, device->vendor_id, device->product_id, device->version, device->hDevice); #endif RAWINPUT_ReleaseDevice(device); return; @@ -1511,7 +1511,7 @@ static bool RAWINPUT_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_ gamepad_state->vibration.RightTrigger = (DOUBLE)right_rumble / SDL_MAX_UINT16; hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(gamepad_state->gamepad, gamepad_state->vibration); if (!SUCCEEDED(hr)) { - return SDL_SetError("Setting vibration failed: 0x%lx\n", hr); + return SDL_SetError("Setting vibration failed: 0x%lx", hr); } return true; } else { @@ -1779,7 +1779,7 @@ static void RAWINPUT_UpdateOtherAPIs(SDL_Joystick *joystick) triggers for a frame. */ if (ctx->wgi_uncorrelate_count >= 5) { #ifdef DEBUG_RAWINPUT - SDL_Log("UN-Correlated joystick %d to WindowsGamingInput device #%d\n", joystick->instance_id, ctx->wgi_slot); + SDL_Log("UN-Correlated joystick %d to WindowsGamingInput device #%d", joystick->instance_id, ctx->wgi_slot); #endif RAWINPUT_MarkWindowsGamingInputSlotFree(ctx->wgi_slot); ctx->wgi_correlated = false; @@ -1811,7 +1811,7 @@ static void RAWINPUT_UpdateOtherAPIs(SDL_Joystick *joystick) // correlation stayed steady and uncontested across multiple frames, guaranteed match ctx->wgi_correlated = true; #ifdef DEBUG_RAWINPUT - SDL_Log("Correlated joystick %d to WindowsGamingInput device #%d\n", joystick->instance_id, slot_idx); + SDL_Log("Correlated joystick %d to WindowsGamingInput device #%d", joystick->instance_id, slot_idx); #endif correlated = true; RAWINPUT_MarkWindowsGamingInputSlotUsed(ctx->wgi_slot, ctx); @@ -1875,7 +1875,7 @@ static void RAWINPUT_UpdateOtherAPIs(SDL_Joystick *joystick) triggers for a frame. */ if (ctx->xinput_uncorrelate_count >= 5) { #ifdef DEBUG_RAWINPUT - SDL_Log("UN-Correlated joystick %d to XInput device #%d\n", joystick->instance_id, ctx->xinput_slot); + SDL_Log("UN-Correlated joystick %d to XInput device #%d", joystick->instance_id, ctx->xinput_slot); #endif RAWINPUT_MarkXInputSlotFree(ctx->xinput_slot); ctx->xinput_correlated = false; @@ -1907,7 +1907,7 @@ static void RAWINPUT_UpdateOtherAPIs(SDL_Joystick *joystick) // correlation stayed steady and uncontested across multiple frames, guaranteed match ctx->xinput_correlated = true; #ifdef DEBUG_RAWINPUT - SDL_Log("Correlated joystick %d to XInput device #%d\n", joystick->instance_id, slot_idx); + SDL_Log("Correlated joystick %d to XInput device #%d", joystick->instance_id, slot_idx); #endif correlated = true; RAWINPUT_MarkXInputSlotUsed(ctx->xinput_slot); diff --git a/libs/SDL3/src/render/SDL_render.c b/libs/SDL3/src/render/SDL_render.c index 45f3686a..a66552f3 100644 --- a/libs/SDL3/src/render/SDL_render.c +++ b/libs/SDL3/src/render/SDL_render.c @@ -25,6 +25,7 @@ #include "SDL_sysrender.h" #include "SDL_render_debug_font.h" #include "software/SDL_render_sw_c.h" +#include "../events/SDL_windowevents_c.h" #include "../video/SDL_pixels_c.h" #include "../video/SDL_video_c.h" @@ -471,17 +472,18 @@ static bool QueueCmdSetClipRect(SDL_Renderer *renderer) { bool result = true; - SDL_Rect clip_rect = renderer->view->pixel_clip_rect; + const SDL_RenderViewState *view = renderer->view; + SDL_Rect clip_rect = view->pixel_clip_rect; if (!renderer->cliprect_queued || - renderer->view->clipping_enabled != renderer->last_queued_cliprect_enabled || + view->clipping_enabled != renderer->last_queued_cliprect_enabled || SDL_memcmp(&clip_rect, &renderer->last_queued_cliprect, sizeof(clip_rect)) != 0) { SDL_RenderCommand *cmd = AllocateRenderCommand(renderer); if (cmd) { cmd->command = SDL_RENDERCMD_SETCLIPRECT; - cmd->data.cliprect.enabled = renderer->view->clipping_enabled; + cmd->data.cliprect.enabled = view->clipping_enabled; SDL_copyp(&cmd->data.cliprect.rect, &clip_rect); SDL_copyp(&renderer->last_queued_cliprect, &clip_rect); - renderer->last_queued_cliprect_enabled = renderer->view->clipping_enabled; + renderer->last_queued_cliprect_enabled = view->clipping_enabled; renderer->cliprect_queued = true; } else { result = false; @@ -736,9 +738,9 @@ static void UpdateMainViewDimensions(SDL_Renderer *renderer) if (renderer->window) { SDL_GetWindowSize(renderer->window, &window_w, &window_h); } - SDL_GetRenderOutputSize(renderer, &renderer->output_pixel_w, &renderer->output_pixel_h); - renderer->main_view.pixel_w = renderer->output_pixel_w; - renderer->main_view.pixel_h = renderer->output_pixel_h; + + SDL_GetRenderOutputSize(renderer, &renderer->main_view.pixel_w, &renderer->main_view.pixel_h); + if (window_w > 0 && window_h > 0) { renderer->dpi_scale.x = (float)renderer->main_view.pixel_w / window_w; renderer->dpi_scale.y = (float)renderer->main_view.pixel_h / window_h; @@ -810,8 +812,7 @@ const char *SDL_GetRenderDriver(int index) { #ifndef SDL_RENDER_DISABLED if (index < 0 || index >= SDL_GetNumRenderDrivers()) { - SDL_SetError("index must be in the range of 0 - %d", - SDL_GetNumRenderDrivers() - 1); + SDL_InvalidParamError("index"); return NULL; } return render_drivers[index]->name; @@ -821,42 +822,39 @@ const char *SDL_GetRenderDriver(int index) #endif } -static bool SDLCALL SDL_RendererEventWatch(void *userdata, SDL_Event *event) +static bool SDL_RendererEventWatch(void *userdata, SDL_Event *event) { SDL_Renderer *renderer = (SDL_Renderer *)userdata; + SDL_Window *window = renderer->window; - if (event->type >= SDL_EVENT_WINDOW_FIRST && event->type <= SDL_EVENT_WINDOW_LAST) { - SDL_Window *window = SDL_GetWindowFromID(event->window.windowID); - if (window == renderer->window) { - if (renderer->WindowEvent) { - renderer->WindowEvent(renderer, &event->window); - } - - if (event->type == SDL_EVENT_WINDOW_RESIZED || - event->type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED || - event->type == SDL_EVENT_WINDOW_METAL_VIEW_RESIZED) { - UpdateLogicalPresentation(renderer); - } else if (event->type == SDL_EVENT_WINDOW_HIDDEN) { - renderer->hidden = true; - } else if (event->type == SDL_EVENT_WINDOW_SHOWN) { - if (!(SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED)) { - renderer->hidden = false; - } - } else if (event->type == SDL_EVENT_WINDOW_MINIMIZED) { - renderer->hidden = true; - } else if (event->type == SDL_EVENT_WINDOW_RESTORED || - event->type == SDL_EVENT_WINDOW_MAXIMIZED) { - if (!(SDL_GetWindowFlags(window) & SDL_WINDOW_HIDDEN)) { - renderer->hidden = false; - } - } else if (event->type == SDL_EVENT_WINDOW_DISPLAY_CHANGED) { - UpdateHDRProperties(renderer); - } - } - } else if (event->type == SDL_EVENT_WINDOW_HDR_STATE_CHANGED) { - UpdateHDRProperties(renderer); + if (renderer->WindowEvent) { + renderer->WindowEvent(renderer, &event->window); } + if (event->type == SDL_EVENT_WINDOW_RESIZED || + event->type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED || + event->type == SDL_EVENT_WINDOW_METAL_VIEW_RESIZED) { + SDL_RenderViewState *view = renderer->view; + renderer->view = &renderer->main_view; // only update the main_view (the window framebuffer) for window changes. + UpdateLogicalPresentation(renderer); + renderer->view = view; // put us back on whatever the current render target's actual view is. + } else if (event->type == SDL_EVENT_WINDOW_HIDDEN) { + renderer->hidden = true; + } else if (event->type == SDL_EVENT_WINDOW_SHOWN) { + if (!(SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED)) { + renderer->hidden = false; + } + } else if (event->type == SDL_EVENT_WINDOW_MINIMIZED) { + renderer->hidden = true; + } else if (event->type == SDL_EVENT_WINDOW_RESTORED || + event->type == SDL_EVENT_WINDOW_MAXIMIZED) { + if (!(SDL_GetWindowFlags(window) & SDL_WINDOW_HIDDEN)) { + renderer->hidden = false; + } + } else if (event->type == SDL_EVENT_WINDOW_DISPLAY_CHANGED || + event->type == SDL_EVENT_WINDOW_HDR_STATE_CHANGED) { + UpdateHDRProperties(renderer); + } return true; } @@ -1111,12 +1109,13 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props) if (window) { SDL_SetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_RENDERER_POINTER, renderer); + SDL_AddWindowRenderer(window, renderer); } SDL_SetRenderViewport(renderer, NULL); if (window) { - SDL_AddEventWatch(SDL_RendererEventWatch, renderer); + SDL_AddWindowEventWatch(SDL_WINDOW_EVENT_WATCH_NORMAL, SDL_RendererEventWatch, renderer); } int vsync = (int)SDL_GetNumberProperty(props, SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER, 0); @@ -1250,11 +1249,12 @@ bool SDL_GetCurrentRenderOutputSize(SDL_Renderer *renderer, int *w, int *h) CHECK_RENDERER_MAGIC(renderer, false); + const SDL_RenderViewState *view = renderer->view; if (w) { - *w = renderer->view->pixel_w; + *w = view->pixel_w; } if (h) { - *h = renderer->view->pixel_h; + *h = view->pixel_h; } return true; } @@ -1293,7 +1293,19 @@ static SDL_PixelFormat GetClosestSupportedFormat(SDL_Renderer *renderer, SDL_Pix { int i; - if (SDL_ISPIXELFORMAT_FOURCC(format)) { + if (format == SDL_PIXELFORMAT_MJPG) { + // We'll decode to SDL_PIXELFORMAT_NV12 or SDL_PIXELFORMAT_RGBA32 + for (i = 0; i < renderer->num_texture_formats; ++i) { + if (renderer->texture_formats[i] == SDL_PIXELFORMAT_NV12) { + return renderer->texture_formats[i]; + } + } + for (i = 0; i < renderer->num_texture_formats; ++i) { + if (renderer->texture_formats[i] == SDL_PIXELFORMAT_RGBA32) { + return renderer->texture_formats[i]; + } + } + } else if (SDL_ISPIXELFORMAT_FOURCC(format)) { // Look for an exact match for (i = 0; i < renderer->num_texture_formats; ++i) { if (renderer->texture_formats[i] == format) { @@ -1422,11 +1434,15 @@ SDL_Texture *SDL_CreateTextureWithProperties(SDL_Renderer *renderer, SDL_Propert closest_format = renderer->texture_formats[0]; } - default_colorspace = SDL_GetDefaultColorspaceForFormat(closest_format); - if (SDL_COLORSPACETYPE(texture->colorspace) == SDL_COLORSPACETYPE(default_colorspace)) { - SDL_SetNumberProperty(native_props, SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER, texture->colorspace); + if (format == SDL_PIXELFORMAT_MJPG && closest_format == SDL_PIXELFORMAT_NV12) { + SDL_SetNumberProperty(native_props, SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER, SDL_COLORSPACE_JPEG); } else { - SDL_SetNumberProperty(native_props, SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER, default_colorspace); + default_colorspace = SDL_GetDefaultColorspaceForFormat(closest_format); + if (SDL_COLORSPACETYPE(texture->colorspace) == SDL_COLORSPACETYPE(default_colorspace)) { + SDL_SetNumberProperty(native_props, SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER, texture->colorspace); + } else { + SDL_SetNumberProperty(native_props, SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER, default_colorspace); + } } SDL_SetNumberProperty(native_props, SDL_PROP_TEXTURE_CREATE_FORMAT_NUMBER, closest_format); SDL_SetNumberProperty(native_props, SDL_PROP_TEXTURE_CREATE_ACCESS_NUMBER, texture->access); @@ -1455,7 +1471,9 @@ SDL_Texture *SDL_CreateTextureWithProperties(SDL_Renderer *renderer, SDL_Propert texture->next = texture->native; renderer->textures = texture; - if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) { + if (texture->format == SDL_PIXELFORMAT_MJPG) { + // We have a custom decode + upload path for this + } else if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) { #ifdef SDL_HAVE_YUV texture->yuv = SDL_SW_CreateYUVTexture(texture->format, texture->colorspace, w, h); #else @@ -2041,9 +2059,9 @@ static bool SDL_UpdateTextureNative(SDL_Texture *texture, const SDL_Rect *rect, if (!SDL_LockTexture(native, rect, &native_pixels, &native_pitch)) { return false; } - SDL_ConvertPixels(rect->w, rect->h, - texture->format, pixels, pitch, - native->format, native_pixels, native_pitch); + SDL_ConvertPixelsAndColorspace(rect->w, rect->h, + texture->format, texture->colorspace, 0, pixels, pitch, + native->format, native->colorspace, 0, native_pixels, native_pitch); SDL_UnlockTexture(native); } else { // Use a temporary buffer for updating @@ -2054,9 +2072,9 @@ static bool SDL_UpdateTextureNative(SDL_Texture *texture, const SDL_Rect *rect, if (!temp_pixels) { return false; } - SDL_ConvertPixels(rect->w, rect->h, - texture->format, pixels, pitch, - native->format, temp_pixels, temp_pitch); + SDL_ConvertPixelsAndColorspace(rect->w, rect->h, + texture->format, texture->colorspace, 0, pixels, pitch, + native->format, native->colorspace, 0, temp_pixels, temp_pitch); SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch); SDL_free(temp_pixels); } @@ -2552,121 +2570,134 @@ SDL_Texture *SDL_GetRenderTarget(SDL_Renderer *renderer) static void UpdateLogicalPresentation(SDL_Renderer *renderer) { - if (renderer->logical_presentation_mode == SDL_LOGICAL_PRESENTATION_DISABLED) { - renderer->main_view.logical_offset.x = renderer->main_view.logical_offset.y = 0.0f; - renderer->main_view.logical_scale.x = renderer->main_view.logical_scale.y = 1.0f; - renderer->main_view.current_scale.x = renderer->main_view.scale.x; // skip the multiplications against 1.0f. - renderer->main_view.current_scale.y = renderer->main_view.scale.y; - UpdateMainViewDimensions(renderer); - UpdatePixelClipRect(renderer, &renderer->main_view); - return; // All done! - } - + SDL_RenderViewState *view = renderer->view; + const bool is_main_view = (view == &renderer->main_view); + const float logical_w = view->logical_w; + const float logical_h = view->logical_h; int iwidth, iheight; - SDL_GetRenderOutputSize(renderer, &iwidth, &iheight); - const float output_w = (float)iwidth; - const float output_h = (float)iheight; - const float logical_w = renderer->logical_w; - const float logical_h = renderer->logical_h; - const float want_aspect = logical_w / logical_h; - const float real_aspect = output_w / output_h; - - renderer->logical_src_rect.x = 0.0f; - renderer->logical_src_rect.y = 0.0f; - renderer->logical_src_rect.w = logical_w; - renderer->logical_src_rect.h = logical_h; - - if ((logical_w <= 0.0f) || (logical_h <= 0.0f)) { - renderer->logical_dst_rect.x = 0.0f; - renderer->logical_dst_rect.y = 0.0f; - renderer->logical_dst_rect.w = output_w; - renderer->logical_dst_rect.h = output_h; - } else if (renderer->logical_presentation_mode == SDL_LOGICAL_PRESENTATION_INTEGER_SCALE) { - float scale; - if (want_aspect > real_aspect) { - scale = (float)((int)output_w / (int)logical_w); // This an integer division! - } else { - scale = (float)((int)output_h / (int)logical_h); // This an integer division! - } - - if (scale < 1.0f) { - scale = 1.0f; - } - - renderer->logical_dst_rect.w = SDL_floorf(logical_w * scale); - renderer->logical_dst_rect.x = (output_w - renderer->logical_dst_rect.w) / 2.0f; - renderer->logical_dst_rect.h = SDL_floorf(logical_h * scale); - renderer->logical_dst_rect.y = (output_h - renderer->logical_dst_rect.h) / 2.0f; - - } else if (renderer->logical_presentation_mode == SDL_LOGICAL_PRESENTATION_STRETCH || - SDL_fabsf(want_aspect - real_aspect) < 0.0001f) { - renderer->logical_dst_rect.x = 0.0f; - renderer->logical_dst_rect.y = 0.0f; - renderer->logical_dst_rect.w = output_w; - renderer->logical_dst_rect.h = output_h; - - } else if (want_aspect > real_aspect) { - if (renderer->logical_presentation_mode == SDL_LOGICAL_PRESENTATION_LETTERBOX) { - // We want a wider aspect ratio than is available - letterbox it - const float scale = output_w / logical_w; - renderer->logical_dst_rect.x = 0.0f; - renderer->logical_dst_rect.w = output_w; - renderer->logical_dst_rect.h = SDL_floorf(logical_h * scale); - renderer->logical_dst_rect.y = (output_h - renderer->logical_dst_rect.h) / 2.0f; - } else { // renderer->logical_presentation_mode == SDL_LOGICAL_PRESENTATION_OVERSCAN - /* We want a wider aspect ratio than is available - - zoom so logical height matches the real height - and the width will grow off the screen - */ - const float scale = output_h / logical_h; - renderer->logical_dst_rect.y = 0.0f; - renderer->logical_dst_rect.h = output_h; - renderer->logical_dst_rect.w = SDL_floorf(logical_w * scale); - renderer->logical_dst_rect.x = (output_w - renderer->logical_dst_rect.w) / 2.0f; - } + if (renderer->target) { + iwidth = (int)renderer->target->w; + iheight = (int)renderer->target->h; } else { - if (renderer->logical_presentation_mode == SDL_LOGICAL_PRESENTATION_LETTERBOX) { - // We want a narrower aspect ratio than is available - use side-bars - const float scale = output_h / logical_h; - renderer->logical_dst_rect.y = 0.0f; - renderer->logical_dst_rect.h = output_h; - renderer->logical_dst_rect.w = SDL_floorf(logical_w * scale); - renderer->logical_dst_rect.x = (output_w - renderer->logical_dst_rect.w) / 2.0f; - } else { // renderer->logical_presentation_mode == SDL_LOGICAL_PRESENTATION_OVERSCAN - /* We want a narrower aspect ratio than is available - - zoom so logical width matches the real width - and the height will grow off the screen - */ - const float scale = output_w / logical_w; - renderer->logical_dst_rect.x = 0.0f; - renderer->logical_dst_rect.w = output_w; - renderer->logical_dst_rect.h = SDL_floorf(logical_h * scale); - renderer->logical_dst_rect.y = (output_h - renderer->logical_dst_rect.h) / 2.0f; - } + SDL_GetRenderOutputSize(renderer, &iwidth, &iheight); } - renderer->main_view.logical_scale.x = (logical_w > 0.0f) ? renderer->logical_dst_rect.w / logical_w : 0.0f; - renderer->main_view.logical_scale.y = (logical_h > 0.0f) ? renderer->logical_dst_rect.h / logical_h : 0.0f; - renderer->main_view.current_scale.x = renderer->main_view.scale.x * renderer->main_view.logical_scale.x; - renderer->main_view.current_scale.y = renderer->main_view.scale.y * renderer->main_view.logical_scale.y; - renderer->main_view.logical_offset.x = renderer->logical_dst_rect.x; - renderer->main_view.logical_offset.y = renderer->logical_dst_rect.y; + view->logical_src_rect.x = 0.0f; + view->logical_src_rect.y = 0.0f; + view->logical_src_rect.w = logical_w; + view->logical_src_rect.h = logical_h; - UpdateMainViewDimensions(renderer); // this will replace pixel_w and pixel_h while making sure the dpi_scale is right. - renderer->main_view.pixel_w = (int) renderer->logical_dst_rect.w; - renderer->main_view.pixel_h = (int) renderer->logical_dst_rect.h; - UpdatePixelViewport(renderer, &renderer->main_view); - UpdatePixelClipRect(renderer, &renderer->main_view); + if (view->logical_presentation_mode == SDL_LOGICAL_PRESENTATION_DISABLED) { + view->logical_dst_rect.x = 0.0f; + view->logical_dst_rect.y = 0.0f; + view->logical_dst_rect.w = iwidth; + view->logical_dst_rect.h = iheight; + view->logical_offset.x = view->logical_offset.y = 0.0f; + view->logical_scale.x = view->logical_scale.y = 1.0f; + view->current_scale.x = view->scale.x; // skip the multiplications against 1.0f. + view->current_scale.y = view->scale.y; + } else { + const float output_w = (float)iwidth; + const float output_h = (float)iheight; + const float want_aspect = logical_w / logical_h; + const float real_aspect = output_w / output_h; + + if ((logical_w <= 0.0f) || (logical_h <= 0.0f)) { + view->logical_dst_rect.x = 0.0f; + view->logical_dst_rect.y = 0.0f; + view->logical_dst_rect.w = output_w; + view->logical_dst_rect.h = output_h; + } else if (view->logical_presentation_mode == SDL_LOGICAL_PRESENTATION_INTEGER_SCALE) { + float scale; + if (want_aspect > real_aspect) { + scale = (float)((int)output_w / (int)logical_w); // This an integer division! + } else { + scale = (float)((int)output_h / (int)logical_h); // This an integer division! + } + + if (scale < 1.0f) { + scale = 1.0f; + } + + view->logical_dst_rect.w = SDL_floorf(logical_w * scale); + view->logical_dst_rect.x = (output_w - view->logical_dst_rect.w) / 2.0f; + view->logical_dst_rect.h = SDL_floorf(logical_h * scale); + view->logical_dst_rect.y = (output_h - view->logical_dst_rect.h) / 2.0f; + + } else if (view->logical_presentation_mode == SDL_LOGICAL_PRESENTATION_STRETCH || SDL_fabsf(want_aspect - real_aspect) < 0.0001f) { + view->logical_dst_rect.x = 0.0f; + view->logical_dst_rect.y = 0.0f; + view->logical_dst_rect.w = output_w; + view->logical_dst_rect.h = output_h; + + } else if (want_aspect > real_aspect) { + if (view->logical_presentation_mode == SDL_LOGICAL_PRESENTATION_LETTERBOX) { + // We want a wider aspect ratio than is available - letterbox it + const float scale = output_w / logical_w; + view->logical_dst_rect.x = 0.0f; + view->logical_dst_rect.w = output_w; + view->logical_dst_rect.h = SDL_floorf(logical_h * scale); + view->logical_dst_rect.y = (output_h - view->logical_dst_rect.h) / 2.0f; + } else { // view->logical_presentation_mode == SDL_LOGICAL_PRESENTATION_OVERSCAN + /* We want a wider aspect ratio than is available - + zoom so logical height matches the real height + and the width will grow off the screen + */ + const float scale = output_h / logical_h; + view->logical_dst_rect.y = 0.0f; + view->logical_dst_rect.h = output_h; + view->logical_dst_rect.w = SDL_floorf(logical_w * scale); + view->logical_dst_rect.x = (output_w - view->logical_dst_rect.w) / 2.0f; + } + } else { + if (view->logical_presentation_mode == SDL_LOGICAL_PRESENTATION_LETTERBOX) { + // We want a narrower aspect ratio than is available - use side-bars + const float scale = output_h / logical_h; + view->logical_dst_rect.y = 0.0f; + view->logical_dst_rect.h = output_h; + view->logical_dst_rect.w = SDL_floorf(logical_w * scale); + view->logical_dst_rect.x = (output_w - view->logical_dst_rect.w) / 2.0f; + } else { // view->logical_presentation_mode == SDL_LOGICAL_PRESENTATION_OVERSCAN + /* We want a narrower aspect ratio than is available - + zoom so logical width matches the real width + and the height will grow off the screen + */ + const float scale = output_w / logical_w; + view->logical_dst_rect.x = 0.0f; + view->logical_dst_rect.w = output_w; + view->logical_dst_rect.h = SDL_floorf(logical_h * scale); + view->logical_dst_rect.y = (output_h - view->logical_dst_rect.h) / 2.0f; + } + } + + view->logical_scale.x = (logical_w > 0.0f) ? view->logical_dst_rect.w / logical_w : 0.0f; + view->logical_scale.y = (logical_h > 0.0f) ? view->logical_dst_rect.h / logical_h : 0.0f; + view->current_scale.x = view->scale.x * view->logical_scale.x; + view->current_scale.y = view->scale.y * view->logical_scale.y; + view->logical_offset.x = view->logical_dst_rect.x; + view->logical_offset.y = view->logical_dst_rect.y; + } + + if (is_main_view) { + // This makes sure the dpi_scale is right. It also sets pixel_w and pixel_h, but we're going to change them directly below here. + UpdateMainViewDimensions(renderer); + } + + view->pixel_w = (int) view->logical_dst_rect.w; + view->pixel_h = (int) view->logical_dst_rect.h; + UpdatePixelViewport(renderer, view); + UpdatePixelClipRect(renderer, view); } bool SDL_SetRenderLogicalPresentation(SDL_Renderer *renderer, int w, int h, SDL_RendererLogicalPresentation mode) { CHECK_RENDERER_MAGIC(renderer, false); - renderer->logical_presentation_mode = mode; - renderer->logical_w = w; - renderer->logical_h = h; + SDL_RenderViewState *view = renderer->view; + view->logical_presentation_mode = mode; + view->logical_w = w; + view->logical_h = h; UpdateLogicalPresentation(renderer); @@ -2683,9 +2714,10 @@ bool SDL_GetRenderLogicalPresentation(SDL_Renderer *renderer, int *w, int *h, SD CHECK_RENDERER_MAGIC(renderer, false); - SETVAL(w, renderer->logical_w); - SETVAL(h, renderer->logical_h); - SETVAL(mode, renderer->logical_presentation_mode); + const SDL_RenderViewState *view = renderer->view; + SETVAL(w, view->logical_w); + SETVAL(h, view->logical_h); + SETVAL(mode, view->logical_presentation_mode); #undef SETVAL @@ -2701,21 +2733,14 @@ bool SDL_GetRenderLogicalPresentationRect(SDL_Renderer *renderer, SDL_FRect *rec CHECK_RENDERER_MAGIC(renderer, false); if (rect) { - if (renderer->logical_presentation_mode == SDL_LOGICAL_PRESENTATION_DISABLED) { - rect->x = 0.0f; - rect->y = 0.0f; - rect->w = (float)renderer->output_pixel_w; - rect->h = (float)renderer->output_pixel_h; - } else { - SDL_copyp(rect, &renderer->logical_dst_rect); - } + SDL_copyp(rect, &renderer->view->logical_dst_rect); } return true; } -static void SDL_RenderLogicalBorders(SDL_Renderer *renderer) +static void SDL_RenderLogicalBorders(SDL_Renderer *renderer, const SDL_FRect *dst) { - const SDL_FRect *dst = &renderer->logical_dst_rect; + const SDL_RenderViewState *view = renderer->view; if (dst->x > 0.0f || dst->y > 0.0f) { SDL_BlendMode saved_blend_mode = renderer->blendMode; @@ -2730,11 +2755,11 @@ static void SDL_RenderLogicalBorders(SDL_Renderer *renderer) rect.x = 0.0f; rect.y = 0.0f; rect.w = dst->x; - rect.h = (float)renderer->view->pixel_h; + rect.h = (float)view->pixel_h; SDL_RenderFillRect(renderer, &rect); rect.x = dst->x + dst->w; - rect.w = (float)renderer->view->pixel_w - rect.x; + rect.w = (float)view->pixel_w - rect.x; SDL_RenderFillRect(renderer, &rect); } @@ -2743,12 +2768,12 @@ static void SDL_RenderLogicalBorders(SDL_Renderer *renderer) rect.x = 0.0f; rect.y = 0.0f; - rect.w = (float)renderer->view->pixel_w; + rect.w = (float)view->pixel_w; rect.h = dst->y; SDL_RenderFillRect(renderer, &rect); rect.y = dst->y + dst->h; - rect.h = (float)renderer->view->pixel_h - rect.y; + rect.h = (float)view->pixel_h - rect.y; SDL_RenderFillRect(renderer, &rect); } @@ -2759,17 +2784,19 @@ static void SDL_RenderLogicalBorders(SDL_Renderer *renderer) static void SDL_RenderLogicalPresentation(SDL_Renderer *renderer) { - const SDL_RendererLogicalPresentation mode = renderer->logical_presentation_mode; + SDL_assert(renderer->view == &renderer->main_view); + + SDL_RenderViewState *view = &renderer->main_view; + const SDL_RendererLogicalPresentation mode = view->logical_presentation_mode; if (mode == SDL_LOGICAL_PRESENTATION_LETTERBOX) { // save off some state we're going to trample. - SDL_assert(renderer->view == &renderer->main_view); - SDL_RenderViewState *view = &renderer->main_view; - const int logical_w = renderer->logical_w; - const int logical_h = renderer->logical_h; + const int logical_w = view->logical_w; + const int logical_h = view->logical_h; const float scale_x = view->scale.x; const float scale_y = view->scale.y; const bool clipping_enabled = view->clipping_enabled; SDL_Rect orig_viewport, orig_cliprect; + const SDL_FRect logical_dst_rect = view->logical_dst_rect; SDL_copyp(&orig_viewport, &view->viewport); if (clipping_enabled) { @@ -2785,10 +2812,10 @@ static void SDL_RenderLogicalPresentation(SDL_Renderer *renderer) SDL_SetRenderScale(renderer, 1.0f, 1.0f); // draw the borders. - SDL_RenderLogicalBorders(renderer); + SDL_RenderLogicalBorders(renderer, &logical_dst_rect); // now set everything back. - renderer->logical_presentation_mode = mode; + view->logical_presentation_mode = mode; SDL_SetRenderViewport(renderer, &orig_viewport); if (clipping_enabled) { SDL_SetRenderClipRect(renderer, &orig_cliprect); @@ -2799,21 +2826,21 @@ static void SDL_RenderLogicalPresentation(SDL_Renderer *renderer) } } -static bool SDL_RenderVectorFromWindow(SDL_Renderer *renderer, float window_dx, float window_dy, float *restrict dx, float *restrict dy) +static bool SDL_RenderVectorFromWindow(SDL_Renderer *renderer, float window_dx, float window_dy, float *dx, float *dy) { // Convert from window coordinates to pixels within the window window_dx *= renderer->dpi_scale.x; window_dy *= renderer->dpi_scale.y; // Convert from pixels within the window to pixels within the view - if (renderer->logical_presentation_mode != SDL_LOGICAL_PRESENTATION_DISABLED) { - const SDL_FRect *src = &renderer->logical_src_rect; - const SDL_FRect *dst = &renderer->logical_dst_rect; + const SDL_RenderViewState *view = &renderer->main_view; + if (view->logical_presentation_mode != SDL_LOGICAL_PRESENTATION_DISABLED) { + const SDL_FRect *src = &view->logical_src_rect; + const SDL_FRect *dst = &view->logical_dst_rect; window_dx = (window_dx * src->w) / dst->w; window_dy = (window_dy * src->h) / dst->h; } - const SDL_RenderViewState *view = &renderer->main_view; window_dx /= view->scale.x; window_dy /= view->scale.y; @@ -2833,14 +2860,14 @@ bool SDL_RenderCoordinatesFromWindow(SDL_Renderer *renderer, float window_x, flo render_y = window_y * renderer->dpi_scale.y; // Convert from pixels within the window to pixels within the view - if (renderer->logical_presentation_mode != SDL_LOGICAL_PRESENTATION_DISABLED) { - const SDL_FRect *src = &renderer->logical_src_rect; - const SDL_FRect *dst = &renderer->logical_dst_rect; + const SDL_RenderViewState *view = &renderer->main_view; + if (view->logical_presentation_mode != SDL_LOGICAL_PRESENTATION_DISABLED) { + const SDL_FRect *src = &view->logical_src_rect; + const SDL_FRect *dst = &view->logical_dst_rect; render_x = ((render_x - dst->x) * src->w) / dst->w; render_y = ((render_y - dst->y) * src->h) / dst->h; } - const SDL_RenderViewState *view = &renderer->main_view; render_x = (render_x / view->scale.x) - view->viewport.x; render_y = (render_y / view->scale.y) - view->viewport.y; @@ -2862,9 +2889,9 @@ bool SDL_RenderCoordinatesToWindow(SDL_Renderer *renderer, float x, float y, flo y = (view->viewport.y + y) * view->scale.y; // Convert from render coordinates to pixels within the window - if (renderer->logical_presentation_mode != SDL_LOGICAL_PRESENTATION_DISABLED) { - const SDL_FRect *src = &renderer->logical_src_rect; - const SDL_FRect *dst = &renderer->logical_dst_rect; + if (view->logical_presentation_mode != SDL_LOGICAL_PRESENTATION_DISABLED) { + const SDL_FRect *src = &view->logical_src_rect; + const SDL_FRect *dst = &view->logical_dst_rect; x = dst->x + ((x * dst->w) / src->w); y = dst->y + ((y * dst->h) / src->h); } @@ -2955,18 +2982,17 @@ bool SDL_SetRenderViewport(SDL_Renderer *renderer, const SDL_Rect *rect) { CHECK_RENDERER_MAGIC(renderer, false); + SDL_RenderViewState *view = renderer->view; if (rect) { if ((rect->w < 0) || (rect->h < 0)) { return SDL_SetError("rect has a negative size"); } - SDL_copyp(&renderer->view->viewport, rect); + SDL_copyp(&view->viewport, rect); } else { - renderer->view->viewport.x = 0; - renderer->view->viewport.y = 0; - renderer->view->viewport.w = -1; - renderer->view->viewport.h = -1; + view->viewport.x = view->viewport.y = 0; + view->viewport.w = view->viewport.h = -1; } - UpdatePixelViewport(renderer, renderer->view); + UpdatePixelViewport(renderer, view); return QueueCmdSetViewport(renderer); } @@ -2988,7 +3014,7 @@ bool SDL_GetRenderViewport(SDL_Renderer *renderer, SDL_Rect *rect) } else { rect->w = (int)SDL_ceilf(view->pixel_w / view->current_scale.x); } - if (renderer->view->viewport.h >= 0) { + if (view->viewport.h >= 0) { rect->h = view->viewport.h; } else { rect->h = (int)SDL_ceilf(view->pixel_h / view->current_scale.y); @@ -3001,11 +3027,8 @@ bool SDL_RenderViewportSet(SDL_Renderer *renderer) { CHECK_RENDERER_MAGIC(renderer, false); - if (renderer->view->viewport.w >= 0 && - renderer->view->viewport.h >= 0) { - return true; - } - return false; + const SDL_RenderViewState *view = renderer->view; + return (view->viewport.w >= 0 && view->viewport.h >= 0); } static void GetRenderViewportSize(SDL_Renderer *renderer, SDL_FRect *rect) @@ -3081,14 +3104,15 @@ bool SDL_SetRenderClipRect(SDL_Renderer *renderer, const SDL_Rect *rect) { CHECK_RENDERER_MAGIC(renderer, false) + SDL_RenderViewState *view = renderer->view; if (rect && rect->w >= 0 && rect->h >= 0) { - renderer->view->clipping_enabled = true; - SDL_copyp(&renderer->view->clip_rect, rect); + view->clipping_enabled = true; + SDL_copyp(&view->clip_rect, rect); } else { - renderer->view->clipping_enabled = false; - SDL_zero(renderer->view->clip_rect); + view->clipping_enabled = false; + SDL_zero(view->clip_rect); } - UpdatePixelClipRect(renderer, renderer->view); + UpdatePixelClipRect(renderer, view); return QueueCmdSetClipRect(renderer); } @@ -3119,17 +3143,18 @@ bool SDL_SetRenderScale(SDL_Renderer *renderer, float scaleX, float scaleY) CHECK_RENDERER_MAGIC(renderer, false); - if (renderer->view->scale.x == scaleX && - renderer->view->scale.y == scaleY) { + SDL_RenderViewState *view = renderer->view; + + if ((view->scale.x == scaleX) && (view->scale.y == scaleY)) { return true; } - renderer->view->scale.x = scaleX; - renderer->view->scale.y = scaleY; - renderer->view->current_scale.x = scaleX * renderer->view->logical_scale.x; - renderer->view->current_scale.y = scaleY * renderer->view->logical_scale.y; - UpdatePixelViewport(renderer, renderer->view); - UpdatePixelClipRect(renderer, renderer->view); + view->scale.x = scaleX; + view->scale.y = scaleY; + view->current_scale.x = scaleX * view->logical_scale.x; + view->current_scale.y = scaleY * view->logical_scale.y; + UpdatePixelViewport(renderer, view); + UpdatePixelClipRect(renderer, view); // The scale affects the existing viewport and clip rectangle result &= QueueCmdSetViewport(renderer); @@ -3148,11 +3173,13 @@ bool SDL_GetRenderScale(SDL_Renderer *renderer, float *scaleX, float *scaleY) CHECK_RENDERER_MAGIC(renderer, false); + const SDL_RenderViewState *view = renderer->view; + if (scaleX) { - *scaleX = renderer->view->scale.x; + *scaleX = view->scale.x; } if (scaleY) { - *scaleY = renderer->view->scale.y; + *scaleY = view->scale.y; } return true; } @@ -3337,8 +3364,9 @@ static bool RenderPointsWithRects(SDL_Renderer *renderer, const SDL_FPoint *fpoi return false; } - const float scale_x = renderer->view->current_scale.x; - const float scale_y = renderer->view->current_scale.y; + const SDL_RenderViewState *view = renderer->view; + const float scale_x = view->current_scale.x; + const float scale_y = view->current_scale.y; for (i = 0; i < count; ++i) { frects[i].x = fpoints[i].x * scale_x; frects[i].y = fpoints[i].y * scale_y; @@ -3373,7 +3401,8 @@ bool SDL_RenderPoints(SDL_Renderer *renderer, const SDL_FPoint *points, int coun } #endif - if ((renderer->view->current_scale.x != 1.0f) || (renderer->view->current_scale.y != 1.0f)) { + const SDL_RenderViewState *view = renderer->view; + if ((view->current_scale.x != 1.0f) || (view->current_scale.y != 1.0f)) { result = RenderPointsWithRects(renderer, points, count); } else { result = QueueCmdDrawPoints(renderer, points, count); @@ -3393,7 +3422,8 @@ bool SDL_RenderLine(SDL_Renderer *renderer, float x1, float y1, float x2, float static bool RenderLineBresenham(SDL_Renderer *renderer, int x1, int y1, int x2, int y2, bool draw_last) { - const int MAX_PIXELS = SDL_max(renderer->view->pixel_w, renderer->view->pixel_h) * 4; + const SDL_RenderViewState *view = renderer->view; + const int MAX_PIXELS = SDL_max(view->pixel_w, view->pixel_h) * 4; int i, deltax, deltay, numpixels; int d, dinc1, dinc2; int x, xinc1, xinc2; @@ -3406,7 +3436,7 @@ static bool RenderLineBresenham(SDL_Renderer *renderer, int x1, int y1, int x2, /* the backend might clip this further to the clipping rect, but we just want a basic safety against generating millions of points for massive lines. */ - viewport = renderer->view->pixel_viewport; + viewport = view->pixel_viewport; viewport.x = 0; viewport.y = 0; if (!SDL_GetRectAndLineIntersection(&viewport, &x1, &y1, &x2, &y2)) { @@ -3475,7 +3505,7 @@ static bool RenderLineBresenham(SDL_Renderer *renderer, int x1, int y1, int x2, } } - if ((renderer->view->current_scale.x != 1.0f) || (renderer->view->current_scale.y != 1.0f)) { + if ((view->current_scale.x != 1.0f) || (view->current_scale.y != 1.0f)) { result = RenderPointsWithRects(renderer, points, numpixels); } else { result = QueueCmdDrawPoints(renderer, points, numpixels); @@ -3488,8 +3518,9 @@ static bool RenderLineBresenham(SDL_Renderer *renderer, int x1, int y1, int x2, static bool RenderLinesWithRectsF(SDL_Renderer *renderer, const SDL_FPoint *points, const int count) { - const float scale_x = renderer->view->current_scale.x; - const float scale_y = renderer->view->current_scale.y; + const SDL_RenderViewState *view = renderer->view; + const float scale_x = view->current_scale.x; + const float scale_y = view->current_scale.y; SDL_FRect *frect; SDL_FRect *frects; int i, nrects = 0; @@ -3576,11 +3607,12 @@ bool SDL_RenderLines(SDL_Renderer *renderer, const SDL_FPoint *points, int count } #endif - const bool islogical = ((renderer->logical_presentation_mode != SDL_LOGICAL_PRESENTATION_DISABLED) && (renderer->view == &renderer->main_view)); + SDL_RenderViewState *view = renderer->view; + const bool islogical = ((view == &renderer->main_view) && (view->logical_presentation_mode != SDL_LOGICAL_PRESENTATION_DISABLED)); if (islogical || (renderer->line_method == SDL_RENDERLINEMETHOD_GEOMETRY)) { - const float scale_x = renderer->view->current_scale.x; - const float scale_y = renderer->view->current_scale.y; + const float scale_x = view->current_scale.x; + const float scale_y = view->current_scale.y; bool isstack1; bool isstack2; float *xy = SDL_small_alloc(float, 4 * 2 * count, &isstack1); @@ -3699,7 +3731,7 @@ bool SDL_RenderLines(SDL_Renderer *renderer, const SDL_FPoint *points, int count } else if (renderer->line_method == SDL_RENDERLINEMETHOD_POINTS) { result = RenderLinesWithRectsF(renderer, points, count); - } else if (renderer->view->scale.x != 1.0f || renderer->view->scale.y != 1.0f) { /* we checked for logical scale elsewhere. */ + } else if (view->scale.x != 1.0f || view->scale.y != 1.0f) { /* we checked for logical scale elsewhere. */ result = RenderLinesWithRectsF(renderer, points, count); } else { result = QueueCmdDrawLines(renderer, points, count); @@ -3804,8 +3836,9 @@ bool SDL_RenderFillRects(SDL_Renderer *renderer, const SDL_FRect *rects, int cou return false; } - const float scale_x = renderer->view->current_scale.x; - const float scale_y = renderer->view->current_scale.y; + const SDL_RenderViewState *view = renderer->view; + const float scale_x = view->current_scale.x; + const float scale_y = view->current_scale.y; for (i = 0; i < count; ++i) { frects[i].x = rects[i].x * scale_x; frects[i].y = rects[i].y * scale_y; @@ -3822,8 +3855,9 @@ bool SDL_RenderFillRects(SDL_Renderer *renderer, const SDL_FRect *rects, int cou static bool SDL_RenderTextureInternal(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_FRect *srcrect, const SDL_FRect *dstrect) { - const float scale_x = renderer->view->current_scale.x; - const float scale_y = renderer->view->current_scale.y; + const SDL_RenderViewState *view = renderer->view; + const float scale_x = view->current_scale.x; + const float scale_y = view->current_scale.y; const bool use_rendergeometry = (!renderer->QueueCopy); bool result; @@ -3900,7 +3934,8 @@ bool SDL_RenderTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_F real_srcrect.w = (float)texture->w; real_srcrect.h = (float)texture->h; if (srcrect) { - if (!SDL_GetRectIntersectionFloat(srcrect, &real_srcrect, &real_srcrect)) { + if (!SDL_GetRectIntersectionFloat(srcrect, &real_srcrect, &real_srcrect) || + real_srcrect.w == 0.0f || real_srcrect.h == 0.0f) { return true; } } @@ -3962,8 +3997,9 @@ bool SDL_RenderTextureAffine(SDL_Renderer *renderer, SDL_Texture *texture, texture->last_command_generation = renderer->render_command_generation; - const float scale_x = renderer->view->current_scale.x; - const float scale_y = renderer->view->current_scale.y; + const SDL_RenderViewState *view = renderer->view; + const float scale_x = view->current_scale.x; + const float scale_y = view->current_scale.y; { float xy[8]; @@ -4096,8 +4132,9 @@ bool SDL_RenderTextureRotated(SDL_Renderer *renderer, SDL_Texture *texture, texture->last_command_generation = renderer->render_command_generation; - const float scale_x = renderer->view->current_scale.x; - const float scale_y = renderer->view->current_scale.y; + const SDL_RenderViewState *view = renderer->view; + const float scale_x = view->current_scale.x; + const float scale_y = view->current_scale.y; const bool use_rendergeometry = (!renderer->QueueCopyEx); if (use_rendergeometry) { @@ -4228,10 +4265,11 @@ static bool SDL_RenderTextureTiled_Wrap(SDL_Renderer *renderer, SDL_Texture *tex xy[6] = minx; xy[7] = maxy; + const SDL_RenderViewState *view = renderer->view; return QueueCmdGeometry(renderer, texture, xy, xy_stride, &texture->color, 0 /* color_stride */, uv, uv_stride, num_vertices, indices, num_indices, size_indices, - renderer->view->current_scale.x, renderer->view->current_scale.y, SDL_TEXTURE_ADDRESS_WRAP); + view->current_scale.x, view->current_scale.y, SDL_TEXTURE_ADDRESS_WRAP); } static bool SDL_RenderTextureTiled_Iterate(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_FRect *srcrect, float scale, const SDL_FRect *dstrect) @@ -4426,6 +4464,7 @@ bool SDL_RenderTexture9Grid(SDL_Renderer *renderer, SDL_Texture *texture, const // Lower-right corner curr_src.y = srcrect->y + srcrect->h - bottom_height; + curr_src.h = bottom_height; curr_dst.y = dstrect->y + dstrect->h - dst_bottom_height; curr_dst.h = dst_bottom_height; if (!SDL_RenderTexture(renderer, texture, &curr_src, &curr_dst)) { @@ -4474,6 +4513,7 @@ bool SDL_RenderTexture9Grid(SDL_Renderer *renderer, SDL_Texture *texture, const // Bottom curr_src.y = srcrect->y + srcrect->h - bottom_height; + curr_src.h = bottom_height; curr_dst.y = dstrect->y + dstrect->h - dst_bottom_height; curr_dst.h = dst_bottom_height; if (!SDL_RenderTexture(renderer, texture, &curr_src, &curr_dst)) { @@ -4580,8 +4620,9 @@ static bool SDLCALL SDL_SW_RenderGeometryRaw(SDL_Renderer *renderer, float texw = 0.0f, texh = 0.0f; SDL_BlendMode blendMode = SDL_BLENDMODE_NONE; float r = 0, g = 0, b = 0, a = 0; - const float scale_x = renderer->view->current_scale.x; - const float scale_y = renderer->view->current_scale.y; + const SDL_RenderViewState *view = renderer->view; + const float scale_x = view->current_scale.x; + const float scale_y = view->current_scale.y; // Save SDL_GetRenderDrawBlendMode(renderer, &blendMode); @@ -4981,10 +5022,11 @@ bool SDL_RenderGeometryRaw(SDL_Renderer *renderer, } #endif + const SDL_RenderViewState *view = renderer->view; return QueueCmdGeometry(renderer, texture, xy, xy_stride, color, color_stride, uv, uv_stride, num_vertices, indices, num_indices, size_indices, - renderer->view->current_scale.x, renderer->view->current_scale.y, + view->current_scale.x, view->current_scale.y, texture_address_mode); } @@ -5003,6 +5045,7 @@ SDL_Surface *SDL_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect) if (rect) { if (!SDL_GetRectIntersection(rect, &real_rect, &real_rect)) { + SDL_SetError("Can't read outside the current viewport"); return NULL; } } @@ -5215,15 +5258,20 @@ void SDL_DestroyRendererWithoutFreeing(SDL_Renderer *renderer) renderer->destroyed = true; - SDL_RemoveEventWatch(SDL_RendererEventWatch, renderer); + SDL_RemoveWindowEventWatch(SDL_WINDOW_EVENT_WATCH_NORMAL, SDL_RendererEventWatch, renderer); if (renderer->window) { SDL_PropertiesID props = SDL_GetWindowProperties(renderer->window); if (SDL_GetPointerProperty(props, SDL_PROP_WINDOW_RENDERER_POINTER, NULL) == renderer) { SDL_ClearProperty(props, SDL_PROP_WINDOW_RENDERER_POINTER); } + SDL_RemoveWindowRenderer(renderer->window, renderer); } + if (renderer->software) { + // Make sure all drawing to a surface is complete + FlushRenderCommands(renderer); + } SDL_DiscardAllCommands(renderer); if (renderer->debug_char_texture_atlas) { diff --git a/libs/SDL3/src/render/SDL_sysrender.h b/libs/SDL3/src/render/SDL_sysrender.h index 9c39bb1d..9d39dfd3 100644 --- a/libs/SDL3/src/render/SDL_sysrender.h +++ b/libs/SDL3/src/render/SDL_sysrender.h @@ -65,8 +65,15 @@ typedef struct SDL_RenderViewState SDL_Rect pixel_clip_rect; bool clipping_enabled; SDL_FPoint scale; + + // Support for logical output coordinates + SDL_RendererLogicalPresentation logical_presentation_mode; + int logical_w, logical_h; + SDL_FRect logical_src_rect; + SDL_FRect logical_dst_rect; SDL_FPoint logical_scale; SDL_FPoint logical_offset; + SDL_FPoint current_scale; // this is just `scale * logical_scale`, precalculated, since we use it a lot. } SDL_RenderViewState; @@ -248,18 +255,9 @@ struct SDL_Renderer Uint64 simulate_vsync_interval_ns; Uint64 last_present; - // Support for logical output coordinates - SDL_RendererLogicalPresentation logical_presentation_mode; - int logical_w, logical_h; - SDL_FRect logical_src_rect; - SDL_FRect logical_dst_rect; - SDL_RenderViewState *view; SDL_RenderViewState main_view; - // Cache the output size in pixels - int output_pixel_w, output_pixel_h; - // The window pixel to point coordinate scale SDL_FPoint dpi_scale; diff --git a/libs/SDL3/src/render/SDL_yuv_sw.c b/libs/SDL3/src/render/SDL_yuv_sw.c index 64250de3..abe9e162 100644 --- a/libs/SDL3/src/render/SDL_yuv_sw.c +++ b/libs/SDL3/src/render/SDL_yuv_sw.c @@ -385,7 +385,7 @@ bool SDL_SW_CopyYUVToRGB(SDL_SW_YUVTexture *swdata, const SDL_Rect *srcrect, SDL } if (stretch) { SDL_Rect rect = *srcrect; - return SDL_SoftStretch(swdata->stretch, &rect, swdata->display, NULL, SDL_SCALEMODE_NEAREST); + return SDL_StretchSurface(swdata->stretch, &rect, swdata->display, NULL, SDL_SCALEMODE_NEAREST); } else { return true; } diff --git a/libs/SDL3/src/render/direct3d11/SDL_render_d3d11.c b/libs/SDL3/src/render/direct3d11/SDL_render_d3d11.c index f84a5f05..dc1a7229 100644 --- a/libs/SDL3/src/render/direct3d11/SDL_render_d3d11.c +++ b/libs/SDL3/src/render/direct3d11/SDL_render_d3d11.c @@ -231,11 +231,14 @@ SDL_PixelFormat D3D11_DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat) case DXGI_FORMAT_B8G8R8A8_UNORM: case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: return SDL_PIXELFORMAT_ARGB8888; + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + return SDL_PIXELFORMAT_ABGR8888; case DXGI_FORMAT_B8G8R8X8_UNORM: case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: return SDL_PIXELFORMAT_XRGB8888; case DXGI_FORMAT_R10G10B10A2_UNORM: - return SDL_PIXELFORMAT_XBGR2101010; + return SDL_PIXELFORMAT_ABGR2101010; case DXGI_FORMAT_R16G16B16A16_FLOAT: return SDL_PIXELFORMAT_RGBA64_FLOAT; default: @@ -248,13 +251,18 @@ static DXGI_FORMAT SDLPixelFormatToDXGITextureFormat(Uint32 format, Uint32 outpu switch (format) { case SDL_PIXELFORMAT_RGBA64_FLOAT: return DXGI_FORMAT_R16G16B16A16_FLOAT; - case SDL_PIXELFORMAT_XBGR2101010: + case SDL_PIXELFORMAT_ABGR2101010: return DXGI_FORMAT_R10G10B10A2_UNORM; case SDL_PIXELFORMAT_ARGB8888: if (output_colorspace == SDL_COLORSPACE_SRGB_LINEAR) { return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; } return DXGI_FORMAT_B8G8R8A8_UNORM; + case SDL_PIXELFORMAT_ABGR8888: + if (output_colorspace == SDL_COLORSPACE_SRGB_LINEAR) { + return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + } + return DXGI_FORMAT_R8G8B8A8_UNORM; case SDL_PIXELFORMAT_XRGB8888: if (output_colorspace == SDL_COLORSPACE_SRGB_LINEAR) { return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB; @@ -278,13 +286,18 @@ static DXGI_FORMAT SDLPixelFormatToDXGIMainResourceViewFormat(Uint32 format, Uin switch (format) { case SDL_PIXELFORMAT_RGBA64_FLOAT: return DXGI_FORMAT_R16G16B16A16_FLOAT; - case SDL_PIXELFORMAT_XBGR2101010: + case SDL_PIXELFORMAT_ABGR2101010: return DXGI_FORMAT_R10G10B10A2_UNORM; case SDL_PIXELFORMAT_ARGB8888: if (colorspace == SDL_COLORSPACE_SRGB_LINEAR) { return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; } return DXGI_FORMAT_B8G8R8A8_UNORM; + case SDL_PIXELFORMAT_ABGR8888: + if (colorspace == SDL_COLORSPACE_SRGB_LINEAR) { + return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + } + return DXGI_FORMAT_R8G8B8A8_UNORM; case SDL_PIXELFORMAT_XRGB8888: if (colorspace == SDL_COLORSPACE_SRGB_LINEAR) { return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB; @@ -997,7 +1010,7 @@ static HRESULT D3D11_CreateWindowSizeDependentResources(SDL_Renderer *renderer) */ SDL_GetWindowSizeInPixels(renderer->window, &w, &h); data->rotation = D3D11_GetCurrentRotation(); - // SDL_Log("%s: windowSize={%d,%d}, orientation=%d\n", __FUNCTION__, w, h, (int)data->rotation); + // SDL_Log("%s: windowSize={%d,%d}, orientation=%d", __FUNCTION__, w, h, (int)data->rotation); if (D3D11_IsDisplayRotated90Degrees(data->rotation)) { int tmp = w; w = h; @@ -1078,7 +1091,7 @@ static bool D3D11_HandleDeviceLost(SDL_Renderer *renderer) SUCCEEDED(D3D11_CreateWindowSizeDependentResources(renderer))) { recovered = true; } else { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Renderer couldn't recover from device lost: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Renderer couldn't recover from device lost: %s", SDL_GetError()); D3D11_ReleaseAll(renderer); } @@ -1990,7 +2003,7 @@ static bool D3D11_UpdateViewport(SDL_Renderer *renderer) * SDL_CreateRenderer is calling it, and will call it again later * with a non-empty viewport. */ - // SDL_Log("%s, no viewport was set!\n", __FUNCTION__); + // SDL_Log("%s, no viewport was set!", __FUNCTION__); return false; } @@ -2057,7 +2070,7 @@ static bool D3D11_UpdateViewport(SDL_Renderer *renderer) d3dviewport.Height = orientationAlignedViewport.h; d3dviewport.MinDepth = 0.0f; d3dviewport.MaxDepth = 1.0f; - // SDL_Log("%s: D3D viewport = {%f,%f,%f,%f}\n", __FUNCTION__, d3dviewport.TopLeftX, d3dviewport.TopLeftY, d3dviewport.Width, d3dviewport.Height); + // SDL_Log("%s: D3D viewport = {%f,%f,%f,%f}", __FUNCTION__, d3dviewport.TopLeftX, d3dviewport.TopLeftY, d3dviewport.Width, d3dviewport.Height); ID3D11DeviceContext_RSSetViewports(data->d3dContext, 1, &d3dviewport); data->viewportDirty = false; @@ -2315,7 +2328,7 @@ static bool D3D11_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand * textureSampler = rendererData->samplers[D3D11_SAMPLER_NEAREST_WRAP]; break; default: - return SDL_SetError("Unknown texture address mode: %d\n", cmd->data.draw.texture_address_mode); + return SDL_SetError("Unknown texture address mode: %d", cmd->data.draw.texture_address_mode); } break; case D3D11_FILTER_MIN_MAG_MIP_LINEAR: @@ -2327,11 +2340,11 @@ static bool D3D11_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand * textureSampler = rendererData->samplers[D3D11_SAMPLER_LINEAR_WRAP]; break; default: - return SDL_SetError("Unknown texture address mode: %d\n", cmd->data.draw.texture_address_mode); + return SDL_SetError("Unknown texture address mode: %d", cmd->data.draw.texture_address_mode); } break; default: - return SDL_SetError("Unknown scale mode: %d\n", textureData->scaleMode); + return SDL_SetError("Unknown scale mode: %d", textureData->scaleMode); } #ifdef SDL_HAVE_YUV if (textureData->yuv) { @@ -2718,8 +2731,9 @@ static bool D3D11_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL renderer->name = D3D11_RenderDriver.name; SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB8888); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR8888); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XRGB8888); - SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XBGR2101010); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR2101010); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA64_FLOAT); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_YV12); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_IYUV); diff --git a/libs/SDL3/src/render/direct3d12/D3D12_PixelShader_Advanced.h b/libs/SDL3/src/render/direct3d12/D3D12_PixelShader_Advanced.h index e795a0c5..b8f40fea 100644 --- a/libs/SDL3/src/render/direct3d12/D3D12_PixelShader_Advanced.h +++ b/libs/SDL3/src/render/direct3d12/D3D12_PixelShader_Advanced.h @@ -685,12 +685,12 @@ attributes #2 = { nounwind readonly } #endif const unsigned char g_main[] = { - 0x44, 0x58, 0x42, 0x43, 0x2b, 0xe5, 0x43, 0x0a, 0x03, 0x52, 0x0f, 0x2c, - 0xe8, 0x70, 0xa0, 0x5e, 0x29, 0xbe, 0x51, 0x24, 0x01, 0x00, 0x00, 0x00, - 0xc1, 0x20, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x44, 0x58, 0x42, 0x43, 0x78, 0xad, 0xb4, 0x13, 0x3d, 0x52, 0x26, 0xa9, + 0x43, 0x6f, 0x29, 0xd4, 0x3d, 0xe5, 0x45, 0x27, 0x01, 0x00, 0x00, 0x00, + 0xd9, 0x20, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x15, 0x01, 0x00, 0x00, - 0x61, 0x02, 0x00, 0x00, 0x49, 0x03, 0x00, 0x00, 0xc1, 0x0c, 0x00, 0x00, - 0xdd, 0x0c, 0x00, 0x00, 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00, + 0x61, 0x02, 0x00, 0x00, 0x61, 0x03, 0x00, 0x00, 0xd9, 0x0c, 0x00, 0x00, + 0xf5, 0x0c, 0x00, 0x00, 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x83, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -736,23 +736,25 @@ const unsigned char g_main[] = { 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x52, 0x54, 0x53, - 0x30, 0xe0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, - 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, + 0x30, 0xf8, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, - 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, - 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, - 0x00, 0xc0, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, + 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, + 0x00, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x01, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, - 0x00, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x53, 0x54, 0x41, 0x54, 0x70, 0x09, 0x00, 0x00, 0x60, 0x00, 0x00, diff --git a/libs/SDL3/src/render/direct3d12/D3D12_PixelShader_Colors.h b/libs/SDL3/src/render/direct3d12/D3D12_PixelShader_Colors.h index 88859b98..7b1a9170 100644 --- a/libs/SDL3/src/render/direct3d12/D3D12_PixelShader_Colors.h +++ b/libs/SDL3/src/render/direct3d12/D3D12_PixelShader_Colors.h @@ -152,12 +152,12 @@ attributes #2 = { nounwind readonly } #endif const unsigned char g_main[] = { - 0x44, 0x58, 0x42, 0x43, 0x02, 0x08, 0x1c, 0x9e, 0xe7, 0x83, 0x00, 0x57, - 0x68, 0x79, 0x21, 0xa9, 0x0a, 0xf5, 0x0a, 0xa7, 0x01, 0x00, 0x00, 0x00, - 0x99, 0x0f, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x44, 0x58, 0x42, 0x43, 0xe0, 0x6a, 0x51, 0x4c, 0x14, 0x1a, 0x6a, 0x67, + 0x04, 0x23, 0x10, 0x54, 0xf8, 0xe3, 0xa6, 0x1a, 0x01, 0x00, 0x00, 0x00, + 0xb1, 0x0f, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x15, 0x01, 0x00, 0x00, - 0x01, 0x02, 0x00, 0x00, 0x39, 0x02, 0x00, 0x00, 0x6d, 0x09, 0x00, 0x00, - 0x89, 0x09, 0x00, 0x00, 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00, + 0x01, 0x02, 0x00, 0x00, 0x51, 0x02, 0x00, 0x00, 0x85, 0x09, 0x00, 0x00, + 0xa1, 0x09, 0x00, 0x00, 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x83, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -195,10 +195,12 @@ const unsigned char g_main[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x52, 0x54, 0x53, - 0x30, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, + 0x30, 0x48, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x53, 0x54, 0x41, 0x54, 0x2c, 0x07, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xcb, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x07, 0x00, diff --git a/libs/SDL3/src/render/direct3d12/D3D12_PixelShader_Textures.h b/libs/SDL3/src/render/direct3d12/D3D12_PixelShader_Textures.h index 829f5d33..4aa8ef08 100644 --- a/libs/SDL3/src/render/direct3d12/D3D12_PixelShader_Textures.h +++ b/libs/SDL3/src/render/direct3d12/D3D12_PixelShader_Textures.h @@ -180,12 +180,12 @@ attributes #2 = { nounwind readonly } #endif const unsigned char g_main[] = { - 0x44, 0x58, 0x42, 0x43, 0x7e, 0x01, 0x52, 0x7e, 0xc9, 0xe3, 0xe4, 0xf6, - 0x3d, 0xab, 0x9a, 0xb9, 0xeb, 0xf9, 0xcb, 0xde, 0x01, 0x00, 0x00, 0x00, - 0xc9, 0x12, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x44, 0x58, 0x42, 0x43, 0xb2, 0xdd, 0x4e, 0x8d, 0x7f, 0x3c, 0x1f, 0x5e, + 0x6f, 0x0e, 0x03, 0xe7, 0x8c, 0xce, 0x62, 0x95, 0x01, 0x00, 0x00, 0x00, + 0xe1, 0x12, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x15, 0x01, 0x00, 0x00, - 0x31, 0x02, 0x00, 0x00, 0xc1, 0x02, 0x00, 0x00, 0x19, 0x0b, 0x00, 0x00, - 0x35, 0x0b, 0x00, 0x00, 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00, + 0x31, 0x02, 0x00, 0x00, 0xd9, 0x02, 0x00, 0x00, 0x31, 0x0b, 0x00, 0x00, + 0x4d, 0x0b, 0x00, 0x00, 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x83, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -227,16 +227,18 @@ const unsigned char g_main[] = { 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x52, 0x54, 0x53, - 0x30, 0x88, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, - 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, + 0x30, 0xa0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, - 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, - 0x00, 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, + 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x01, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0xff, 0x01, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x53, 0x54, 0x41, 0x54, 0x50, 0x08, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x14, 0x02, 0x00, diff --git a/libs/SDL3/src/render/direct3d12/D3D12_RootSig_Advanced.h b/libs/SDL3/src/render/direct3d12/D3D12_RootSig_Advanced.h index b050059c..ac88cbb6 100644 --- a/libs/SDL3/src/render/direct3d12/D3D12_RootSig_Advanced.h +++ b/libs/SDL3/src/render/direct3d12/D3D12_RootSig_Advanced.h @@ -3,8 +3,8 @@ Disassembly failed #endif const unsigned char g_AdvancedRS[] = { - 0x44, 0x58, 0x42, 0x43, 0xc2, 0xcd, 0x2f, 0xaf, 0x3b, 0x72, 0x07, 0x2a, - 0xa9, 0x73, 0x1b, 0xab, 0x8e, 0x46, 0xf7, 0x46, 0x01, 0x00, 0x00, 0x00, + 0x44, 0x58, 0x42, 0x43, 0x61, 0xd8, 0x65, 0x6e, 0x1d, 0x30, 0x64, 0x8a, + 0x54, 0x75, 0xb7, 0x59, 0xea, 0x11, 0x73, 0xec, 0x01, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x52, 0x54, 0x53, 0x30, 0xf8, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -16,7 +16,7 @@ const unsigned char g_AdvancedRS[] = { 0x05, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, diff --git a/libs/SDL3/src/render/direct3d12/D3D12_RootSig_Color.h b/libs/SDL3/src/render/direct3d12/D3D12_RootSig_Color.h index 4d5306bd..e47eb5c3 100644 --- a/libs/SDL3/src/render/direct3d12/D3D12_RootSig_Color.h +++ b/libs/SDL3/src/render/direct3d12/D3D12_RootSig_Color.h @@ -3,8 +3,8 @@ Disassembly failed #endif const unsigned char g_ColorRS[] = { - 0x44, 0x58, 0x42, 0x43, 0x24, 0x3f, 0x6b, 0x5a, 0xb1, 0xd3, 0x78, 0x2f, - 0x7f, 0xd4, 0x83, 0xd9, 0x7d, 0x6b, 0xc4, 0x31, 0x01, 0x00, 0x00, 0x00, + 0x44, 0x58, 0x42, 0x43, 0x1a, 0x67, 0x3b, 0x20, 0xac, 0xdc, 0xbb, 0xa0, + 0x3c, 0x72, 0xa7, 0xdf, 0x14, 0xa5, 0x3a, 0x2e, 0x01, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x52, 0x54, 0x53, 0x30, 0x48, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -12,5 +12,5 @@ const unsigned char g_ColorRS[] = { 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00 + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00 }; diff --git a/libs/SDL3/src/render/direct3d12/D3D12_RootSig_Texture.h b/libs/SDL3/src/render/direct3d12/D3D12_RootSig_Texture.h index 00e3c0ae..2675b98b 100644 --- a/libs/SDL3/src/render/direct3d12/D3D12_RootSig_Texture.h +++ b/libs/SDL3/src/render/direct3d12/D3D12_RootSig_Texture.h @@ -3,8 +3,8 @@ Disassembly failed #endif const unsigned char g_TextureRS[] = { - 0x44, 0x58, 0x42, 0x43, 0x25, 0x9c, 0x4f, 0xa4, 0x10, 0x16, 0x82, 0x9d, - 0x3d, 0x46, 0xb7, 0x5d, 0xf0, 0xc2, 0x90, 0xa7, 0x01, 0x00, 0x00, 0x00, + 0x44, 0x58, 0x42, 0x43, 0xbc, 0x46, 0x63, 0x56, 0xe3, 0xea, 0x41, 0x4c, + 0xf7, 0x90, 0x24, 0xc2, 0x14, 0x4d, 0x79, 0xdd, 0x01, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x52, 0x54, 0x53, 0x30, 0xa0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -14,7 +14,7 @@ const unsigned char g_TextureRS[] = { 0x05, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, diff --git a/libs/SDL3/src/render/direct3d12/D3D12_VertexShader_Advanced.h b/libs/SDL3/src/render/direct3d12/D3D12_VertexShader_Advanced.h index 3f2896a3..5c358d59 100644 --- a/libs/SDL3/src/render/direct3d12/D3D12_VertexShader_Advanced.h +++ b/libs/SDL3/src/render/direct3d12/D3D12_VertexShader_Advanced.h @@ -236,8 +236,8 @@ attributes #2 = { nounwind readonly } #endif const unsigned char g_mainAdvanced[] = { - 0x44, 0x58, 0x42, 0x43, 0x2a, 0x90, 0x76, 0x57, 0x08, 0xab, 0xff, 0xa1, - 0x21, 0xd0, 0xb4, 0x0c, 0x31, 0xf8, 0x05, 0x5d, 0x01, 0x00, 0x00, 0x00, + 0x44, 0x58, 0x42, 0x43, 0xff, 0x5d, 0x02, 0x19, 0xed, 0x89, 0xe9, 0x33, + 0xf6, 0x5b, 0x76, 0x8c, 0x9f, 0x8b, 0x4d, 0xf1, 0x01, 0x00, 0x00, 0x00, 0x63, 0x13, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x63, 0x01, 0x00, 0x00, 0x87, 0x02, 0x00, 0x00, 0x87, 0x03, 0x00, 0x00, 0x3f, 0x0a, 0x00, 0x00, @@ -300,7 +300,7 @@ const unsigned char g_mainAdvanced[] = { 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, diff --git a/libs/SDL3/src/render/direct3d12/D3D12_VertexShader_Color.h b/libs/SDL3/src/render/direct3d12/D3D12_VertexShader_Color.h index a7eff5b1..36909c10 100644 --- a/libs/SDL3/src/render/direct3d12/D3D12_VertexShader_Color.h +++ b/libs/SDL3/src/render/direct3d12/D3D12_VertexShader_Color.h @@ -236,8 +236,8 @@ attributes #2 = { nounwind readonly } #endif const unsigned char g_mainColor[] = { - 0x44, 0x58, 0x42, 0x43, 0xd2, 0x9c, 0xbb, 0x08, 0x88, 0xc9, 0x51, 0x6d, - 0x10, 0xea, 0x39, 0xeb, 0x7b, 0xab, 0xdf, 0x50, 0x01, 0x00, 0x00, 0x00, + 0x44, 0x58, 0x42, 0x43, 0x28, 0x20, 0xca, 0xe8, 0xab, 0xe5, 0x24, 0x7a, + 0x5d, 0x2b, 0x6f, 0xa4, 0x2c, 0x10, 0xa8, 0xb6, 0x01, 0x00, 0x00, 0x00, 0xa3, 0x12, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x63, 0x01, 0x00, 0x00, 0x87, 0x02, 0x00, 0x00, 0xd7, 0x02, 0x00, 0x00, 0x87, 0x09, 0x00, 0x00, @@ -296,7 +296,7 @@ const unsigned char g_mainColor[] = { 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x53, 0x54, 0x41, 0x54, 0xa8, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x53, 0x54, 0x41, 0x54, 0xa8, 0x06, 0x00, 0x00, 0x60, 0x00, 0x01, 0x00, 0xaa, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x90, 0x06, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0xa1, diff --git a/libs/SDL3/src/render/direct3d12/D3D12_VertexShader_Texture.h b/libs/SDL3/src/render/direct3d12/D3D12_VertexShader_Texture.h index 0573c1e2..ac68e32e 100644 --- a/libs/SDL3/src/render/direct3d12/D3D12_VertexShader_Texture.h +++ b/libs/SDL3/src/render/direct3d12/D3D12_VertexShader_Texture.h @@ -236,8 +236,8 @@ attributes #2 = { nounwind readonly } #endif const unsigned char g_mainTexture[] = { - 0x44, 0x58, 0x42, 0x43, 0x74, 0x5e, 0x15, 0x62, 0x5c, 0xf4, 0x2a, 0x49, - 0x52, 0xac, 0x1f, 0x81, 0x9a, 0xff, 0xaa, 0xbf, 0x01, 0x00, 0x00, 0x00, + 0x44, 0x58, 0x42, 0x43, 0xda, 0xc9, 0x75, 0xea, 0x0d, 0x18, 0xc7, 0xf5, + 0xb4, 0x80, 0x10, 0xd9, 0xd7, 0x88, 0x5a, 0x23, 0x01, 0x00, 0x00, 0x00, 0xff, 0x12, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x63, 0x01, 0x00, 0x00, 0x87, 0x02, 0x00, 0x00, 0x2f, 0x03, 0x00, 0x00, 0xdf, 0x09, 0x00, 0x00, @@ -298,7 +298,7 @@ const unsigned char g_mainTexture[] = { 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x68, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x03, diff --git a/libs/SDL3/src/render/direct3d12/SDL_render_d3d12.c b/libs/SDL3/src/render/direct3d12/SDL_render_d3d12.c index 3233e194..06535f0e 100644 --- a/libs/SDL3/src/render/direct3d12/SDL_render_d3d12.c +++ b/libs/SDL3/src/render/direct3d12/SDL_render_d3d12.c @@ -298,11 +298,14 @@ static SDL_PixelFormat D3D12_DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat) case DXGI_FORMAT_B8G8R8A8_UNORM: case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: return SDL_PIXELFORMAT_ARGB8888; + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + return SDL_PIXELFORMAT_ABGR8888; case DXGI_FORMAT_B8G8R8X8_UNORM: case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: return SDL_PIXELFORMAT_XRGB8888; case DXGI_FORMAT_R10G10B10A2_UNORM: - return SDL_PIXELFORMAT_XBGR2101010; + return SDL_PIXELFORMAT_ABGR2101010; case DXGI_FORMAT_R16G16B16A16_FLOAT: return SDL_PIXELFORMAT_RGBA64_FLOAT; default: @@ -315,13 +318,18 @@ static DXGI_FORMAT SDLPixelFormatToDXGITextureFormat(Uint32 format, Uint32 outpu switch (format) { case SDL_PIXELFORMAT_RGBA64_FLOAT: return DXGI_FORMAT_R16G16B16A16_FLOAT; - case SDL_PIXELFORMAT_XBGR2101010: + case SDL_PIXELFORMAT_ABGR2101010: return DXGI_FORMAT_R10G10B10A2_UNORM; case SDL_PIXELFORMAT_ARGB8888: if (output_colorspace == SDL_COLORSPACE_SRGB_LINEAR) { return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; } return DXGI_FORMAT_B8G8R8A8_UNORM; + case SDL_PIXELFORMAT_ABGR8888: + if (output_colorspace == SDL_COLORSPACE_SRGB_LINEAR) { + return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + } + return DXGI_FORMAT_R8G8B8A8_UNORM; case SDL_PIXELFORMAT_XRGB8888: if (output_colorspace == SDL_COLORSPACE_SRGB_LINEAR) { return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB; @@ -345,13 +353,18 @@ static DXGI_FORMAT SDLPixelFormatToDXGIMainResourceViewFormat(Uint32 format, Uin switch (format) { case SDL_PIXELFORMAT_RGBA64_FLOAT: return DXGI_FORMAT_R16G16B16A16_FLOAT; - case SDL_PIXELFORMAT_XBGR2101010: + case SDL_PIXELFORMAT_ABGR2101010: return DXGI_FORMAT_R10G10B10A2_UNORM; case SDL_PIXELFORMAT_ARGB8888: if (colorspace == SDL_COLORSPACE_SRGB_LINEAR) { return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; } return DXGI_FORMAT_B8G8R8A8_UNORM; + case SDL_PIXELFORMAT_ABGR8888: + if (colorspace == SDL_COLORSPACE_SRGB_LINEAR) { + return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + } + return DXGI_FORMAT_R8G8B8A8_UNORM; case SDL_PIXELFORMAT_XRGB8888: if (colorspace == SDL_COLORSPACE_SRGB_LINEAR) { return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB; @@ -1453,7 +1466,7 @@ static bool D3D12_HandleDeviceLost(SDL_Renderer *renderer) SUCCEEDED(D3D12_CreateWindowSizeDependentResources(renderer))) { recovered = true; } else { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Renderer couldn't recover from device lost: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Renderer couldn't recover from device lost: %s", SDL_GetError()); D3D12_ReleaseAll(renderer); } @@ -2430,7 +2443,7 @@ static bool D3D12_UpdateViewport(SDL_Renderer *renderer) * SDL_CreateRenderer is calling it, and will call it again later * with a non-empty viewport. */ - // SDL_Log("%s, no viewport was set!\n", __FUNCTION__); + // SDL_Log("%s, no viewport was set!", __FUNCTION__); return false; } @@ -2497,7 +2510,7 @@ static bool D3D12_UpdateViewport(SDL_Renderer *renderer) d3dviewport.Height = orientationAlignedViewport.h; d3dviewport.MinDepth = 0.0f; d3dviewport.MaxDepth = 1.0f; - // SDL_Log("%s: D3D viewport = {%f,%f,%f,%f}\n", __FUNCTION__, d3dviewport.TopLeftX, d3dviewport.TopLeftY, d3dviewport.Width, d3dviewport.Height); + // SDL_Log("%s: D3D viewport = {%f,%f,%f,%f}", __FUNCTION__, d3dviewport.TopLeftX, d3dviewport.TopLeftY, d3dviewport.Width, d3dviewport.Height); ID3D12GraphicsCommandList_RSSetViewports(data->commandList, 1, &d3dviewport); data->viewportDirty = false; @@ -2742,7 +2755,7 @@ static bool D3D12_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand * textureSampler = &rendererData->samplers[D3D12_SAMPLER_NEAREST_WRAP]; break; default: - return SDL_SetError("Unknown texture address mode: %d\n", cmd->data.draw.texture_address_mode); + return SDL_SetError("Unknown texture address mode: %d", cmd->data.draw.texture_address_mode); } break; case D3D12_FILTER_MIN_MAG_MIP_LINEAR: @@ -2754,11 +2767,11 @@ static bool D3D12_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand * textureSampler = &rendererData->samplers[D3D12_SAMPLER_LINEAR_WRAP]; break; default: - return SDL_SetError("Unknown texture address mode: %d\n", cmd->data.draw.texture_address_mode); + return SDL_SetError("Unknown texture address mode: %d", cmd->data.draw.texture_address_mode); } break; default: - return SDL_SetError("Unknown scale mode: %d\n", textureData->scaleMode); + return SDL_SetError("Unknown scale mode: %d", textureData->scaleMode); } #ifdef SDL_HAVE_YUV if (textureData->yuv) { @@ -3254,8 +3267,9 @@ bool D3D12_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_Proper renderer->name = D3D12_RenderDriver.name; SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB8888); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR8888); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XRGB8888); - SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XBGR2101010); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR2101010); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA64_FLOAT); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_YV12); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_IYUV); diff --git a/libs/SDL3/src/render/gpu/SDL_pipeline_gpu.c b/libs/SDL3/src/render/gpu/SDL_pipeline_gpu.c index 0f7fabfe..07833740 100644 --- a/libs/SDL3/src/render/gpu/SDL_pipeline_gpu.c +++ b/libs/SDL3/src/render/gpu/SDL_pipeline_gpu.c @@ -36,58 +36,50 @@ struct GPU_PipelineCacheKeyStruct Uint64 primitive_type : 3; }; -typedef union GPU_PipelineCacheKey +typedef union GPU_PipelineCacheKeyConverter { struct GPU_PipelineCacheKeyStruct as_struct; Uint64 as_uint64; -} GPU_PipelineCacheKey; +} GPU_PipelineCacheKeyConverter; -SDL_COMPILE_TIME_ASSERT(GPU_PipelineCacheKey_Size, sizeof(GPU_PipelineCacheKey) <= sizeof(Uint64)); +SDL_COMPILE_TIME_ASSERT(GPU_PipelineCacheKeyConverter_Size, sizeof(GPU_PipelineCacheKeyConverter) <= sizeof(Uint64)); -typedef struct GPU_PipelineCacheEntry +static Uint32 SDLCALL HashPipelineCacheKey(void *userdata, const void *key) { - GPU_PipelineCacheKey key; - SDL_GPUGraphicsPipeline *pipeline; -} GPU_PipelineCacheEntry; + const GPU_PipelineParameters *params = (const GPU_PipelineParameters *) key; + GPU_PipelineCacheKeyConverter cvt; + cvt.as_uint64 = 0; + cvt.as_struct.blend_mode = params->blend_mode; + cvt.as_struct.frag_shader = params->frag_shader; + cvt.as_struct.vert_shader = params->vert_shader; + cvt.as_struct.attachment_format = params->attachment_format; + cvt.as_struct.primitive_type = params->primitive_type; -static Uint32 HashPipelineCacheKey(const GPU_PipelineCacheKey *key) -{ - Uint64 x = key->as_uint64; // 64-bit uint hash function stolen from taisei (which stole it from somewhere else) + Uint64 x = cvt.as_uint64; x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9); x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb); x = x ^ (x >> 31); return (Uint32)(x & 0xffffffff); } -static Uint32 HashPassthrough(const void *key, void *data) +static bool SDLCALL MatchPipelineCacheKey(void *userdata, const void *a, const void *b) { - // double-cast to silence a clang warning - return (Uint32)(uintptr_t)key; + return (SDL_memcmp(a, b, sizeof (GPU_PipelineParameters)) == 0); } -static bool MatchPipelineCacheKey(const void *a, const void *b, void *data) +static void SDLCALL DestroyPipelineCacheHashItem(void *userdata, const void *key, const void *value) { - return a == b; -} - -static void NukePipelineCacheEntry(const void *key, const void *value, void *data) -{ - GPU_PipelineCacheEntry *entry = (GPU_PipelineCacheEntry *)value; - SDL_GPUDevice *device = data; - - SDL_ReleaseGPUGraphicsPipeline(device, entry->pipeline); - SDL_free(entry); + SDL_GPUGraphicsPipeline *pipeline = (SDL_GPUGraphicsPipeline *) value; + SDL_GPUDevice *device = (SDL_GPUDevice *) userdata; + SDL_ReleaseGPUGraphicsPipeline(device, pipeline); + SDL_free((GPU_PipelineParameters *) key); } bool GPU_InitPipelineCache(GPU_PipelineCache *cache, SDL_GPUDevice *device) { - // FIXME how many buckets do we need? - cache->table = SDL_CreateHashTable(device, 32, HashPassthrough, MatchPipelineCacheKey, NukePipelineCacheEntry, false, true); - if (!cache->table) { - return false; - } - return true; + cache->table = SDL_CreateHashTable(0, false, HashPipelineCacheKey, MatchPipelineCacheKey, DestroyPipelineCacheHashItem, device); + return (cache->table != NULL); } void GPU_DestroyPipelineCache(GPU_PipelineCache *cache) @@ -180,45 +172,30 @@ static SDL_GPUGraphicsPipeline *MakePipeline(SDL_GPUDevice *device, GPU_Shaders return SDL_CreateGPUGraphicsPipeline(device, &pci); } -static GPU_PipelineCacheKey MakePipelineCacheKey(const GPU_PipelineParameters *params) -{ - GPU_PipelineCacheKey key; - SDL_zero(key); - key.as_struct.blend_mode = params->blend_mode; - key.as_struct.frag_shader = params->frag_shader; - key.as_struct.vert_shader = params->vert_shader; - key.as_struct.attachment_format = params->attachment_format; - key.as_struct.primitive_type = params->primitive_type; - return key; -} - SDL_GPUGraphicsPipeline *GPU_GetPipeline(GPU_PipelineCache *cache, GPU_Shaders *shaders, SDL_GPUDevice *device, const GPU_PipelineParameters *params) { - GPU_PipelineCacheKey key = MakePipelineCacheKey(params); - void *keyval = (void *)(uintptr_t)HashPipelineCacheKey(&key); SDL_GPUGraphicsPipeline *pipeline = NULL; + if (!SDL_FindInHashTable(cache->table, params, (const void **) &pipeline)) { + bool inserted = false; + // !!! FIXME: why don't we have an SDL_alloc_copy function/macro? + GPU_PipelineParameters *paramscpy = (GPU_PipelineParameters *) SDL_malloc(sizeof (*paramscpy)); + if (paramscpy) { + SDL_copyp(paramscpy, params); + pipeline = MakePipeline(device, shaders, params); + if (pipeline) { + inserted = SDL_InsertIntoHashTable(cache->table, paramscpy, pipeline, false); + } + } - void *iter = NULL; - GPU_PipelineCacheEntry *entry = NULL; - - while (SDL_IterateHashTableKey(cache->table, keyval, (const void **)&entry, &iter)) { - if (entry->key.as_uint64 == key.as_uint64) { - return entry->pipeline; + if (!inserted) { + SDL_free(paramscpy); + if (pipeline) { + SDL_ReleaseGPUGraphicsPipeline(device, pipeline); + pipeline = NULL; + } } } - pipeline = MakePipeline(device, shaders, params); - - if (pipeline == NULL) { - return NULL; - } - - entry = SDL_malloc(sizeof(*entry)); - entry->key = key; - entry->pipeline = pipeline; - - SDL_InsertIntoHashTable(cache->table, keyval, entry); - return pipeline; } diff --git a/libs/SDL3/src/render/gpu/SDL_render_gpu.c b/libs/SDL3/src/render/gpu/SDL_render_gpu.c index 57ec05e8..73c1dbe7 100644 --- a/libs/SDL3/src/render/gpu/SDL_render_gpu.c +++ b/libs/SDL3/src/render/gpu/SDL_render_gpu.c @@ -1242,10 +1242,10 @@ static bool GPU_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_P SDL_SetGPUAllowedFramesInFlight(data->device, 1); - SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA32); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRA32); - SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBX32); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA32); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRX32); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBX32); SDL_SetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER, 16384); diff --git a/libs/SDL3/src/render/metal/SDL_render_metal.m b/libs/SDL3/src/render/metal/SDL_render_metal.m index 0aac565d..63d9770d 100644 --- a/libs/SDL3/src/render/metal/SDL_render_metal.m +++ b/libs/SDL3/src/render/metal/SDL_render_metal.m @@ -1482,7 +1482,7 @@ static bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, c mtlsampler = data.mtlsamplers[SDL_METAL_SAMPLER_NEAREST_WRAP]; break; default: - return SDL_SetError("Unknown texture address mode: %d\n", cmd->data.draw.texture_address_mode); + return SDL_SetError("Unknown texture address mode: %d", cmd->data.draw.texture_address_mode); } } else { switch (cmd->data.draw.texture_address_mode) { @@ -1493,7 +1493,7 @@ static bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, c mtlsampler = data.mtlsamplers[SDL_METAL_SAMPLER_LINEAR_WRAP]; break; default: - return SDL_SetError("Unknown texture address mode: %d\n", cmd->data.draw.texture_address_mode); + return SDL_SetError("Unknown texture address mode: %d", cmd->data.draw.texture_address_mode); } } [data.mtlcmdencoder setFragmentSamplerState:mtlsampler atIndex:0]; diff --git a/libs/SDL3/src/render/opengl/SDL_render_gl.c b/libs/SDL3/src/render/opengl/SDL_render_gl.c index 64164a6d..d5344382 100644 --- a/libs/SDL3/src/render/opengl/SDL_render_gl.c +++ b/libs/SDL3/src/render/opengl/SDL_render_gl.c @@ -1132,7 +1132,7 @@ static bool SetTextureAddressMode(GL_RenderData *data, GLenum textype, SDL_Textu data->glTexParameteri(textype, GL_TEXTURE_WRAP_T, GL_REPEAT); break; default: - return SDL_SetError("Unknown texture address mode: %d\n", addressMode); + return SDL_SetError("Unknown texture address mode: %d", addressMode); } return true; } diff --git a/libs/SDL3/src/render/opengl/SDL_shaders_gl.c b/libs/SDL3/src/render/opengl/SDL_shaders_gl.c index c70bcdb1..b09b12e7 100644 --- a/libs/SDL3/src/render/opengl/SDL_shaders_gl.c +++ b/libs/SDL3/src/render/opengl/SDL_shaders_gl.c @@ -350,7 +350,10 @@ static bool CompileShader(GL_ShaderContext *ctx, GLhandleARB shader, const char info = SDL_small_alloc(char, length + 1, &isstack); if (info) { ctx->glGetInfoLogARB(shader, length, NULL, info); - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Failed to compile shader:\n%s%s\n%s", defines, source, info); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Failed to compile shader:"); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "%s", defines); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "%s", source); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "%s", info); SDL_small_free(info, isstack); } return false; diff --git a/libs/SDL3/src/render/opengles2/SDL_render_gles2.c b/libs/SDL3/src/render/opengles2/SDL_render_gles2.c index 1a013d57..0e142a78 100644 --- a/libs/SDL3/src/render/opengles2/SDL_render_gles2.c +++ b/libs/SDL3/src/render/opengles2/SDL_render_gles2.c @@ -539,7 +539,7 @@ static GLuint GLES2_CacheShader(GLES2_RenderData *data, GLES2_ShaderType type, G SDL_asprintf(&message, "%s%s", last_message, shader_src_list[i]); SDL_free(last_message); } - SDL_Log("%s\n", message); + SDL_Log("%s", message); SDL_free(message); } #endif @@ -1041,7 +1041,7 @@ static bool SetTextureAddressMode(GLES2_RenderData *data, GLenum textype, SDL_Te data->glTexParameteri(textype, GL_TEXTURE_WRAP_T, GL_REPEAT); break; default: - return SDL_SetError("Unknown texture address mode: %d\n", addressMode); + return SDL_SetError("Unknown texture address mode: %d", addressMode); } return true; } @@ -2099,8 +2099,8 @@ static bool GLES2_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL renderer->window = window; renderer->name = GLES2_RenderDriver.name; - SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA32); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRA32); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA32); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRX32); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBX32); diff --git a/libs/SDL3/src/render/vitagxm/SDL_render_vita_gxm.c b/libs/SDL3/src/render/vitagxm/SDL_render_vita_gxm.c index 42477f34..acf31c3d 100644 --- a/libs/SDL3/src/render/vitagxm/SDL_render_vita_gxm.c +++ b/libs/SDL3/src/render/vitagxm/SDL_render_vita_gxm.c @@ -324,11 +324,11 @@ static void VITA_GXM_SetYUVProfile(SDL_Renderer *renderer, SDL_Texture *texture) ret = sceGxmSetYuvProfile(data->gxm_context, 0, SCE_GXM_YUV_PROFILE_BT709_FULL_RANGE); } } else { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Unsupported YUV colorspace\n"); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Unsupported YUV colorspace"); } if (ret < 0) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Setting YUV profile failed: %x\n", ret); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Setting YUV profile failed: %x", ret); } } diff --git a/libs/SDL3/src/render/vitagxm/SDL_render_vita_gxm_tools.c b/libs/SDL3/src/render/vitagxm/SDL_render_vita_gxm_tools.c index 38d7fd9f..9140a62c 100644 --- a/libs/SDL3/src/render/vitagxm/SDL_render_vita_gxm_tools.c +++ b/libs/SDL3/src/render/vitagxm/SDL_render_vita_gxm_tools.c @@ -87,7 +87,7 @@ void *pool_malloc(VITA_GXM_RenderData *data, unsigned int size) data->pool_index += size; return addr; } - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "POOL OVERFLOW\n"); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "POOL OVERFLOW"); return NULL; } @@ -99,7 +99,7 @@ void *pool_memalign(VITA_GXM_RenderData *data, unsigned int size, unsigned int a data->pool_index = new_index + size; return addr; } - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "POOL OVERFLOW\n"); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "POOL OVERFLOW"); return NULL; } @@ -173,7 +173,7 @@ static void make_fragment_programs(VITA_GXM_RenderData *data, fragment_programs &out->color); if (err != 0) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Patcher create fragment failed: %d\n", err); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Patcher create fragment failed: %d", err); return; } @@ -187,7 +187,7 @@ static void make_fragment_programs(VITA_GXM_RenderData *data, fragment_programs &out->texture); if (err != 0) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Patcher create fragment failed: %d\n", err); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Patcher create fragment failed: %d", err); return; } } @@ -387,7 +387,7 @@ int gxm_init(SDL_Renderer *renderer) err = sceGxmInitialize(&initializeParams); if (err != 0) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "gxm init failed: %d\n", err); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "gxm init failed: %d", err); return err; } @@ -433,7 +433,7 @@ int gxm_init(SDL_Renderer *renderer) err = sceGxmCreateContext(&data->contextParams, &data->gxm_context); if (err != 0) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create context failed: %d\n", err); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create context failed: %d", err); return err; } @@ -450,7 +450,7 @@ int gxm_init(SDL_Renderer *renderer) // create the render target err = sceGxmCreateRenderTarget(&renderTargetParams, &data->renderTarget); if (err != 0) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "render target creation failed: %d\n", err); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "render target creation failed: %d", err); return err; } @@ -486,14 +486,14 @@ int gxm_init(SDL_Renderer *renderer) data->displayBufferData[i]); if (err != 0) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "color surface init failed: %d\n", err); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "color surface init failed: %d", err); return err; } // create a sync object that we will associate with this buffer err = sceGxmSyncObjectCreate(&data->displayBufferSync[i]); if (err != 0) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "sync object creation failed: %d\n", err); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "sync object creation failed: %d", err); return err; } } @@ -576,81 +576,81 @@ int gxm_init(SDL_Renderer *renderer) err = sceGxmShaderPatcherCreate(&patcherParams, &data->shaderPatcher); if (err != 0) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "shader patcher creation failed: %d\n", err); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "shader patcher creation failed: %d", err); return err; } // check the shaders err = sceGxmProgramCheck(clearVertexProgramGxp); if (err != 0) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "check program (clear vertex) failed: %d\n", err); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "check program (clear vertex) failed: %d", err); return err; } err = sceGxmProgramCheck(clearFragmentProgramGxp); if (err != 0) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "check program (clear fragment) failed: %d\n", err); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "check program (clear fragment) failed: %d", err); return err; } err = sceGxmProgramCheck(colorVertexProgramGxp); if (err != 0) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "check program (color vertex) failed: %d\n", err); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "check program (color vertex) failed: %d", err); return err; } err = sceGxmProgramCheck(colorFragmentProgramGxp); if (err != 0) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "check program (color fragment) failed: %d\n", err); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "check program (color fragment) failed: %d", err); return err; } err = sceGxmProgramCheck(textureVertexProgramGxp); if (err != 0) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "check program (texture vertex) failed: %d\n", err); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "check program (texture vertex) failed: %d", err); return err; } err = sceGxmProgramCheck(textureFragmentProgramGxp); if (err != 0) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "check program (texture fragment) failed: %d\n", err); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "check program (texture fragment) failed: %d", err); return err; } // register programs with the patcher err = sceGxmShaderPatcherRegisterProgram(data->shaderPatcher, clearVertexProgramGxp, &data->clearVertexProgramId); if (err != 0) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "register program (clear vertex) failed: %d\n", err); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "register program (clear vertex) failed: %d", err); return err; } err = sceGxmShaderPatcherRegisterProgram(data->shaderPatcher, clearFragmentProgramGxp, &data->clearFragmentProgramId); if (err != 0) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "register program (clear fragment) failed: %d\n", err); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "register program (clear fragment) failed: %d", err); return err; } err = sceGxmShaderPatcherRegisterProgram(data->shaderPatcher, colorVertexProgramGxp, &data->colorVertexProgramId); if (err != 0) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "register program (color vertex) failed: %d\n", err); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "register program (color vertex) failed: %d", err); return err; } err = sceGxmShaderPatcherRegisterProgram(data->shaderPatcher, colorFragmentProgramGxp, &data->colorFragmentProgramId); if (err != 0) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "register program (color fragment) failed: %d\n", err); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "register program (color fragment) failed: %d", err); return err; } err = sceGxmShaderPatcherRegisterProgram(data->shaderPatcher, textureVertexProgramGxp, &data->textureVertexProgramId); if (err != 0) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "register program (texture vertex) failed: %d\n", err); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "register program (texture vertex) failed: %d", err); return err; } err = sceGxmShaderPatcherRegisterProgram(data->shaderPatcher, textureFragmentProgramGxp, &data->textureFragmentProgramId); if (err != 0) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "register program (texture fragment) failed: %d\n", err); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "register program (texture fragment) failed: %d", err); return err; } @@ -679,7 +679,7 @@ int gxm_init(SDL_Renderer *renderer) 1, &data->clearVertexProgram); if (err != 0) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create program (clear vertex) failed: %d\n", err); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create program (clear vertex) failed: %d", err); return err; } @@ -692,7 +692,7 @@ int gxm_init(SDL_Renderer *renderer) clearVertexProgramGxp, &data->clearFragmentProgram); if (err != 0) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create program (clear fragment) failed: %d\n", err); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create program (clear fragment) failed: %d", err); return err; } @@ -760,7 +760,7 @@ int gxm_init(SDL_Renderer *renderer) 1, &data->colorVertexProgram); if (err != 0) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create program (color vertex) failed: %d\n", err); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create program (color vertex) failed: %d", err); return err; } } @@ -805,7 +805,7 @@ int gxm_init(SDL_Renderer *renderer) 1, &data->textureVertexProgram); if (err != 0) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create program (texture vertex) failed: %x\n", err); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create program (texture vertex) failed: %x", err); return err; } } @@ -1016,7 +1016,7 @@ gxm_texture *create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsig // Try SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE in case we're out of VRAM if (!texture_data) { - SDL_LogWarn(SDL_LOG_CATEGORY_RENDER, "CDRAM texture allocation failed\n"); + SDL_LogWarn(SDL_LOG_CATEGORY_RENDER, "CDRAM texture allocation failed"); texture_data = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, tex_size, @@ -1040,7 +1040,7 @@ gxm_texture *create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsig ret = sceGxmTextureInitLinear(&texture->gxm_tex, texture_data, format, texture_w, h, 0); if (ret < 0) { free_gxm_texture(data, texture); - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "texture init failed: %x\n", ret); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "texture init failed: %x", ret); return NULL; } @@ -1065,7 +1065,7 @@ gxm_texture *create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsig if (err < 0) { free_gxm_texture(data, texture); - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "color surface init failed: %x\n", err); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "color surface init failed: %x", err); return NULL; } @@ -1088,7 +1088,7 @@ gxm_texture *create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsig if (err < 0) { free_gxm_texture(data, texture); - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "depth stencil init failed: %x\n", err); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "depth stencil init failed: %x", err); return NULL; } @@ -1113,7 +1113,7 @@ gxm_texture *create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsig if (err < 0) { free_gxm_texture(data, texture); - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create render target failed: %x\n", err); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create render target failed: %x", err); return NULL; } } diff --git a/libs/SDL3/src/render/vulkan/SDL_render_vulkan.c b/libs/SDL3/src/render/vulkan/SDL_render_vulkan.c index e61a88f5..d2157c30 100644 --- a/libs/SDL3/src/render/vulkan/SDL_render_vulkan.c +++ b/libs/SDL3/src/render/vulkan/SDL_render_vulkan.c @@ -41,14 +41,14 @@ #define SET_ERROR_CODE(message, rc) \ if (SDL_GetHintBoolean(SDL_HINT_RENDER_VULKAN_DEBUG, false)) { \ - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "%s: %s\n", message, SDL_Vulkan_GetResultString(rc)); \ + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "%s: %s", message, SDL_Vulkan_GetResultString(rc)); \ SDL_TriggerBreakpoint(); \ } \ SDL_SetError("%s: %s", message, SDL_Vulkan_GetResultString(rc)) \ #define SET_ERROR_MESSAGE(message) \ if (SDL_GetHintBoolean(SDL_HINT_RENDER_VULKAN_DEBUG, false)) { \ - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "%s\n", message); \ + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "%s", message); \ SDL_TriggerBreakpoint(); \ } \ SDL_SetError("%s", message) \ @@ -398,6 +398,8 @@ static SDL_PixelFormat VULKAN_VkFormatToSDLPixelFormat(VkFormat vkFormat) switch (vkFormat) { case VK_FORMAT_B8G8R8A8_UNORM: return SDL_PIXELFORMAT_ARGB8888; + case VK_FORMAT_R8G8B8A8_UNORM: + return SDL_PIXELFORMAT_ABGR8888; case VK_FORMAT_A2R10G10B10_UNORM_PACK32: return SDL_PIXELFORMAT_ABGR2101010; case VK_FORMAT_R16G16B16A16_SFLOAT: @@ -452,6 +454,11 @@ static VkFormat SDLPixelFormatToVkTextureFormat(Uint32 format, Uint32 output_col return VK_FORMAT_B8G8R8A8_SRGB; } return VK_FORMAT_B8G8R8A8_UNORM; + case SDL_PIXELFORMAT_ABGR8888: + if (output_colorspace == SDL_COLORSPACE_SRGB_LINEAR) { + return VK_FORMAT_R8G8B8A8_SRGB; + } + return VK_FORMAT_R8G8B8A8_UNORM; case SDL_PIXELFORMAT_YUY2: return VK_FORMAT_G8B8G8R8_422_UNORM; case SDL_PIXELFORMAT_UYVY: @@ -1228,7 +1235,7 @@ static VULKAN_PipelineState *VULKAN_CreatePipelineState(SDL_Renderer *renderer, // Input assembly inputAssemblyStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - inputAssemblyStateCreateInfo.topology = ( VkPrimitiveTopology ) topology; + inputAssemblyStateCreateInfo.topology = topology; inputAssemblyStateCreateInfo.primitiveRestartEnable = VK_FALSE; viewportStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; @@ -2512,7 +2519,7 @@ static bool VULKAN_HandleDeviceLost(SDL_Renderer *renderer) VULKAN_CreateWindowSizeDependentResources(renderer) == VK_SUCCESS) { recovered = true; } else { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Renderer couldn't recover from device lost: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Renderer couldn't recover from device lost: %s", SDL_GetError()); VULKAN_DestroyAll(renderer); } @@ -3253,7 +3260,7 @@ static bool VULKAN_UpdateVertexBuffer(SDL_Renderer *renderer, stateCache->vertexBuffer = vertexBuffer->buffer; - rendererData->currentVertexBuffer++; + rendererData->currentVertexBuffer = vbidx + 1; if (rendererData->currentVertexBuffer >= SDL_VULKAN_NUM_VERTEX_BUFFERS) { rendererData->currentVertexBuffer = 0; rendererData->issueBatch = true; @@ -3296,7 +3303,7 @@ static bool VULKAN_UpdateViewport(SDL_Renderer *renderer) * SDL_CreateRenderer is calling it, and will call it again later * with a non-empty viewport. */ - // SDL_Log("%s, no viewport was set!\n", __FUNCTION__); + // SDL_Log("%s, no viewport was set!", __FUNCTION__); return false; } @@ -3778,7 +3785,7 @@ static bool VULKAN_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand textureSampler = rendererData->samplers[VULKAN_SAMPLER_NEAREST_WRAP]; break; default: - return SDL_SetError("Unknown texture address mode: %d\n", cmd->data.draw.texture_address_mode); + return SDL_SetError("Unknown texture address mode: %d", cmd->data.draw.texture_address_mode); } break; case VK_FILTER_LINEAR: @@ -3790,7 +3797,7 @@ static bool VULKAN_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand textureSampler = rendererData->samplers[VULKAN_SAMPLER_LINEAR_WRAP]; break; default: - return SDL_SetError("Unknown texture address mode: %d\n", cmd->data.draw.texture_address_mode); + return SDL_SetError("Unknown texture address mode: %d", cmd->data.draw.texture_address_mode); } break; default: @@ -4303,6 +4310,7 @@ static bool VULKAN_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SD renderer->name = VULKAN_RenderDriver.name; SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB8888); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR8888); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR2101010); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA64_FLOAT); SDL_SetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER, 16384); diff --git a/libs/SDL3/src/sensor/windows/SDL_windowssensor.c b/libs/SDL3/src/sensor/windows/SDL_windowssensor.c index 77da14d0..059747ee 100644 --- a/libs/SDL3/src/sensor/windows/SDL_windowssensor.c +++ b/libs/SDL3/src/sensor/windows/SDL_windowssensor.c @@ -132,7 +132,7 @@ static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_OnStateChanged(ISensorEvents SDL_LockSensors(); for (i = 0; i < SDL_num_sensors; ++i) { if (pSensor == SDL_sensors[i].sensor) { - SDL_Log("Sensor %s state changed to %d\n", SDL_sensors[i].name, state); + SDL_Log("Sensor %s state changed to %d", SDL_sensors[i].name, state); } } SDL_UnlockSensors(); @@ -156,7 +156,7 @@ static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_OnDataUpdated(ISensorEvents * Uint64 sensor_timestamp; #ifdef DEBUG_SENSORS - SDL_Log("Sensor %s data updated\n", SDL_sensors[i].name); + SDL_Log("Sensor %s data updated", SDL_sensors[i].name); #endif if (SUCCEEDED(ISensorDataReport_GetTimestamp(pNewData, &sensor_systemtime)) && SystemTimeToFileTime(&sensor_systemtime, &sensor_filetime)) { @@ -219,7 +219,7 @@ static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_OnEvent(ISensorEvents *This, SDL_LockSensors(); for (i = 0; i < SDL_num_sensors; ++i) { if (pSensor == SDL_sensors[i].sensor) { - SDL_Log("Sensor %s event occurred\n", SDL_sensors[i].name); + SDL_Log("Sensor %s event occurred", SDL_sensors[i].name); } } SDL_UnlockSensors(); @@ -235,7 +235,7 @@ static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_OnLeave(ISensorEvents *This, for (i = 0; i < SDL_num_sensors; ++i) { if (WIN_IsEqualIID(ID, &SDL_sensors[i].sensor_id)) { #ifdef DEBUG_SENSORS - SDL_Log("Sensor %s disconnected\n", SDL_sensors[i].name); + SDL_Log("Sensor %s disconnected", SDL_sensors[i].name); #endif DisconnectSensor(SDL_sensors[i].sensor); } diff --git a/libs/SDL3/src/stdlib/SDL_getenv.c b/libs/SDL3/src/stdlib/SDL_getenv.c index 2659bd42..b4a19224 100644 --- a/libs/SDL3/src/stdlib/SDL_getenv.c +++ b/libs/SDL3/src/stdlib/SDL_getenv.c @@ -53,7 +53,7 @@ static char **environ; struct SDL_Environment { - SDL_Mutex *lock; + SDL_Mutex *lock; // !!! FIXME: reuse SDL_HashTable's lock. SDL_HashTable *strings; }; static SDL_Environment *SDL_environment; @@ -88,13 +88,13 @@ SDL_Environment *SDL_CreateEnvironment(bool populated) return NULL; } - env->strings = SDL_CreateHashTable(NULL, 16, SDL_HashString, SDL_KeyMatchString, SDL_NukeFreeKey, false, false); + env->strings = SDL_CreateHashTable(0, false, SDL_HashString, SDL_KeyMatchString, SDL_DestroyHashKey, NULL); if (!env->strings) { SDL_free(env); return NULL; } - // Don't fail if we can't create a mutex (e.g. on a single-thread environment) + // Don't fail if we can't create a mutex (e.g. on a single-thread environment) // !!! FIXME: single-threaded environments should still return a non-NULL, do-nothing object here. Check for failure! env->lock = SDL_CreateMutex(); if (populated) { @@ -114,7 +114,7 @@ SDL_Environment *SDL_CreateEnvironment(bool populated) } *value++ = '\0'; - SDL_InsertIntoHashTable(env->strings, variable, value); + SDL_InsertIntoHashTable(env->strings, variable, value, true); } FreeEnvironmentStringsW(strings); } @@ -138,7 +138,7 @@ SDL_Environment *SDL_CreateEnvironment(bool populated) } *value++ = '\0'; - SDL_InsertIntoHashTable(env->strings, variable, value); + SDL_InsertIntoHashTable(env->strings, variable, value, true); } } #endif // SDL_PLATFORM_WINDOWS @@ -170,6 +170,49 @@ const char *SDL_GetEnvironmentVariable(SDL_Environment *env, const char *name) return result; } +typedef struct CountEnvStringsData +{ + size_t count; + size_t length; +} CountEnvStringsData; + +static bool SDLCALL CountEnvStrings(void *userdata, const SDL_HashTable *table, const void *key, const void *value) +{ + CountEnvStringsData *data = (CountEnvStringsData *) userdata; + data->length += SDL_strlen((const char *) key) + 1 + SDL_strlen((const char *) value) + 1; + data->count++; + return true; // keep iterating. +} + +typedef struct CopyEnvStringsData +{ + char **result; + char *string; + size_t count; +} CopyEnvStringsData; + +static bool SDLCALL CopyEnvStrings(void *userdata, const SDL_HashTable *table, const void *vkey, const void *vvalue) +{ + CopyEnvStringsData *data = (CopyEnvStringsData *) userdata; + const char *key = (const char *) vkey; + const char *value = (const char *) vvalue; + size_t len; + + len = SDL_strlen(key); + data->result[data->count] = data->string; + SDL_memcpy(data->string, key, len); + data->string += len; + *(data->string++) = '='; + + len = SDL_strlen(value); + SDL_memcpy(data->string, value, len); + data->string += len; + *(data->string++) = '\0'; + data->count++; + + return true; // keep iterating. +} + char **SDL_GetEnvironmentVariables(SDL_Environment *env) { char **result = NULL; @@ -181,40 +224,20 @@ char **SDL_GetEnvironmentVariables(SDL_Environment *env) SDL_LockMutex(env->lock); { - size_t count, length = 0; - void *iter; - const char *key, *value; - // First pass, get the size we need for all the strings - count = 0; - iter = NULL; - while (SDL_IterateHashTable(env->strings, (const void **)&key, (const void **)&value, &iter)) { - length += SDL_strlen(key) + 1 + SDL_strlen(value) + 1; - ++count; - } + CountEnvStringsData countdata = { 0, 0 }; + SDL_IterateHashTable(env->strings, CountEnvStrings, &countdata); // Allocate memory for the strings - result = (char **)SDL_malloc((count + 1) * sizeof(*result) + length); - char *string = (char *)(result + count + 1); - - // Second pass, copy the strings - count = 0; - iter = NULL; - while (SDL_IterateHashTable(env->strings, (const void **)&key, (const void **)&value, &iter)) { - size_t len; - - result[count] = string; - len = SDL_strlen(key); - SDL_memcpy(string, key, len); - string += len; - *string++ = '='; - len = SDL_strlen(value); - SDL_memcpy(string, value, len); - string += len; - *string++ = '\0'; - ++count; + result = (char **)SDL_malloc((countdata.count + 1) * sizeof(*result) + countdata.length); + if (result) { + // Second pass, copy the strings + char *string = (char *)(result + countdata.count + 1); + CopyEnvStringsData cpydata = { result, string, 0 }; + SDL_IterateHashTable(env->strings, CopyEnvStrings, &cpydata); + SDL_assert(countdata.count == cpydata.count); + result[cpydata.count] = NULL; } - result[count] = NULL; } SDL_UnlockMutex(env->lock); @@ -235,26 +258,23 @@ bool SDL_SetEnvironmentVariable(SDL_Environment *env, const char *name, const ch SDL_LockMutex(env->lock); { - const void *existing_value; - bool insert = true; - - if (SDL_FindInHashTable(env->strings, name, &existing_value)) { - if (!overwrite) { - result = true; - insert = false; - } else { - SDL_RemoveFromHashTable(env->strings, name); - } - } - - if (insert) { - char *string = NULL; - if (SDL_asprintf(&string, "%s=%s", name, value) > 0) { - size_t len = SDL_strlen(name); - string[len] = '\0'; - name = string; - value = string + len + 1; - result = SDL_InsertIntoHashTable(env->strings, name, value); + char *string = NULL; + if (SDL_asprintf(&string, "%s=%s", name, value) > 0) { + const size_t len = SDL_strlen(name); + string[len] = '\0'; + const char *origname = name; + name = string; + value = string + len + 1; + result = SDL_InsertIntoHashTable(env->strings, name, value, overwrite); + if (!result) { + SDL_free(string); + if (!overwrite) { + const void *existing_value = NULL; + // !!! FIXME: InsertIntoHashTable does this lookup too, maybe we should have a means to report that, to avoid duplicate work? + if (SDL_FindInHashTable(env->strings, origname, &existing_value)) { + result = true; // it already existed, and we refused to overwrite it. Call it success. + } + } } } } diff --git a/libs/SDL3/src/stdlib/SDL_malloc.c b/libs/SDL3/src/stdlib/SDL_malloc.c index ea09d1e5..008675f3 100644 --- a/libs/SDL3/src/stdlib/SDL_malloc.c +++ b/libs/SDL3/src/stdlib/SDL_malloc.c @@ -6324,10 +6324,10 @@ History: #endif /* !HAVE_MALLOC */ #ifdef HAVE_MALLOC -static void* SDLCALL real_malloc(size_t s) { return malloc(s); } -static void* SDLCALL real_calloc(size_t n, size_t s) { return calloc(n, s); } -static void* SDLCALL real_realloc(void *p, size_t s) { return realloc(p,s); } -static void SDLCALL real_free(void *p) { free(p); } +static void * SDLCALL real_malloc(size_t s) { return malloc(s); } +static void * SDLCALL real_calloc(size_t n, size_t s) { return calloc(n, s); } +static void * SDLCALL real_realloc(void *p, size_t s) { return realloc(p,s); } +static void SDLCALL real_free(void *p) { free(p); } #else #define real_malloc dlmalloc #define real_calloc dlcalloc diff --git a/libs/SDL3/src/stdlib/SDL_qsort.c b/libs/SDL3/src/stdlib/SDL_qsort.c index 901e9250..4ed2863e 100644 --- a/libs/SDL3/src/stdlib/SDL_qsort.c +++ b/libs/SDL3/src/stdlib/SDL_qsort.c @@ -361,7 +361,7 @@ typedef struct { char * first; char * last; } stack_entry; /* ---------------------------------------------------------------------- */ static char * pivot_big(char *first, char *mid, char *last, size_t size, - int (SDLCALL * compare)(void *, const void *, const void *), void *userdata) { + int (SDLCALL *compare)(void *, const void *, const void *), void *userdata) { size_t d=(((last-first)/size)>>3)*size; #ifdef DEBUG_QSORT fprintf(stderr, "pivot_big: first=%p last=%p size=%lu n=%lu\n", first, (unsigned long)last, size, (unsigned long)((last-first+1)/size)); @@ -402,7 +402,7 @@ fprintf(stderr,"-> %d %d %d @ %p %p %p\n",*(int*)m1,*(int*)m2,*(int*)m3, m1,m2,m /* ---------------------------------------------------------------------- */ static void qsort_r_nonaligned(void *base, size_t nmemb, size_t size, - int (SDLCALL * compare)(void *, const void *, const void *), void *userdata) { + int (SDLCALL *compare)(void *, const void *, const void *), void *userdata) { stack_entry stack[STACK_SIZE]; int stacktop=0; @@ -433,7 +433,7 @@ static void qsort_r_nonaligned(void *base, size_t nmemb, size_t size, } static void qsort_r_aligned(void *base, size_t nmemb, size_t size, - int (SDLCALL * compare)(void *,const void *, const void *), void *userdata) { + int (SDLCALL *compare)(void *,const void *, const void *), void *userdata) { stack_entry stack[STACK_SIZE]; int stacktop=0; @@ -464,7 +464,7 @@ static void qsort_r_aligned(void *base, size_t nmemb, size_t size, } static void qsort_r_words(void *base, size_t nmemb, - int (SDLCALL * compare)(void *,const void *, const void *), void *userdata) { + int (SDLCALL *compare)(void *,const void *, const void *), void *userdata) { stack_entry stack[STACK_SIZE]; int stacktop=0; diff --git a/libs/SDL3/src/stdlib/SDL_string.c b/libs/SDL3/src/stdlib/SDL_string.c index 39c49e46..007719ef 100644 --- a/libs/SDL3/src/stdlib/SDL_string.c +++ b/libs/SDL3/src/stdlib/SDL_string.c @@ -1448,6 +1448,7 @@ static bool CharacterMatchesSet(char c, const char *set, size_t set_len) // NOLINTNEXTLINE(readability-non-const-parameter) int SDL_vsscanf(const char *text, SDL_SCANF_FORMAT_STRING const char *fmt, va_list ap) { + const char *start = text; int result = 0; if (!text || !*text) { @@ -1718,6 +1719,36 @@ int SDL_vsscanf(const char *text, SDL_SCANF_FORMAT_STRING const char *fmt, va_li } done = true; break; + case 'n': + switch (inttype) { + case DO_SHORT: + { + short *valuep = va_arg(ap, short *); + *valuep = (short)(text - start); + } break; + case DO_INT: + { + int *valuep = va_arg(ap, int *); + *valuep = (int)(text - start); + } break; + case DO_LONG: + { + long *valuep = va_arg(ap, long *); + *valuep = (long)(text - start); + } break; + case DO_LONGLONG: + { + long long *valuep = va_arg(ap, long long *); + *valuep = (long long)(text - start); + } break; + case DO_SIZE_T: + { + size_t *valuep = va_arg(ap, size_t *); + *valuep = (size_t)(text - start); + } break; + } + done = true; + break; case '[': { const char *set = fmt + 1; diff --git a/libs/SDL3/src/test/SDL_test_common.c b/libs/SDL3/src/test/SDL_test_common.c index 8e0590ae..3203ddea 100644 --- a/libs/SDL3/src/test/SDL_test_common.c +++ b/libs/SDL3/src/test/SDL_test_common.c @@ -1092,12 +1092,12 @@ static void SDLTest_PrintRenderer(SDL_Renderer *renderer) name = SDL_GetRendererName(renderer); - SDL_Log(" Renderer %s:\n", name); + SDL_Log(" Renderer %s:", name); if (SDL_strcmp(name, "gpu") == 0) { SDL_GPUDevice *device = SDL_GetPointerProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_GPU_DEVICE_POINTER, NULL); - SDL_Log(" Driver: %s\n", SDL_GetGPUDeviceDriver(device)); + SDL_Log(" Driver: %s", SDL_GetGPUDeviceDriver(device)); } - SDL_Log(" VSync: %d\n", (int)SDL_GetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_VSYNC_NUMBER, 0)); + SDL_Log(" VSync: %d", (int)SDL_GetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_VSYNC_NUMBER, 0)); texture_formats = (const SDL_PixelFormat *)SDL_GetPointerProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_TEXTURE_FORMATS_POINTER, NULL); if (texture_formats) { @@ -1108,12 +1108,12 @@ static void SDLTest_PrintRenderer(SDL_Renderer *renderer) } SDLTest_PrintPixelFormat(text, sizeof(text), texture_formats[i]); } - SDL_Log("%s\n", text); + SDL_Log("%s", text); } max_texture_size = (int)SDL_GetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER, 0); if (max_texture_size) { - SDL_Log(" Max Texture Size: %dx%d\n", max_texture_size, max_texture_size); + SDL_Log(" Max Texture Size: %dx%d", max_texture_size, max_texture_size); } } @@ -1124,7 +1124,7 @@ static SDL_Surface *SDLTest_LoadIcon(const char *file) /* Load the icon surface */ icon = SDL_LoadBMP(file); if (!icon) { - SDL_Log("Couldn't load %s: %s\n", file, SDL_GetError()); + SDL_Log("Couldn't load %s: %s", file, SDL_GetError()); return NULL; } @@ -1142,40 +1142,40 @@ static SDL_HitTestResult SDLCALL SDLTest_ExampleHitTestCallback(SDL_Window *win, const int RESIZE_BORDER = 8; const int DRAGGABLE_TITLE = 32; - /*SDL_Log("Hit test point %d,%d\n", area->x, area->y);*/ + /*SDL_Log("Hit test point %d,%d", area->x, area->y);*/ SDL_GetWindowSize(win, &w, &h); if (area->x < RESIZE_BORDER) { if (area->y < RESIZE_BORDER) { - SDL_Log("SDL_HITTEST_RESIZE_TOPLEFT\n"); + SDL_Log("SDL_HITTEST_RESIZE_TOPLEFT"); return SDL_HITTEST_RESIZE_TOPLEFT; } else if (area->y >= (h - RESIZE_BORDER)) { - SDL_Log("SDL_HITTEST_RESIZE_BOTTOMLEFT\n"); + SDL_Log("SDL_HITTEST_RESIZE_BOTTOMLEFT"); return SDL_HITTEST_RESIZE_BOTTOMLEFT; } else { - SDL_Log("SDL_HITTEST_RESIZE_LEFT\n"); + SDL_Log("SDL_HITTEST_RESIZE_LEFT"); return SDL_HITTEST_RESIZE_LEFT; } } else if (area->x >= (w - RESIZE_BORDER)) { if (area->y < RESIZE_BORDER) { - SDL_Log("SDL_HITTEST_RESIZE_TOPRIGHT\n"); + SDL_Log("SDL_HITTEST_RESIZE_TOPRIGHT"); return SDL_HITTEST_RESIZE_TOPRIGHT; } else if (area->y >= (h - RESIZE_BORDER)) { - SDL_Log("SDL_HITTEST_RESIZE_BOTTOMRIGHT\n"); + SDL_Log("SDL_HITTEST_RESIZE_BOTTOMRIGHT"); return SDL_HITTEST_RESIZE_BOTTOMRIGHT; } else { - SDL_Log("SDL_HITTEST_RESIZE_RIGHT\n"); + SDL_Log("SDL_HITTEST_RESIZE_RIGHT"); return SDL_HITTEST_RESIZE_RIGHT; } } else if (area->y >= (h - RESIZE_BORDER)) { - SDL_Log("SDL_HITTEST_RESIZE_BOTTOM\n"); + SDL_Log("SDL_HITTEST_RESIZE_BOTTOM"); return SDL_HITTEST_RESIZE_BOTTOM; } else if (area->y < RESIZE_BORDER) { - SDL_Log("SDL_HITTEST_RESIZE_TOP\n"); + SDL_Log("SDL_HITTEST_RESIZE_TOP"); return SDL_HITTEST_RESIZE_TOP; } else if (area->y < DRAGGABLE_TITLE) { - SDL_Log("SDL_HITTEST_DRAGGABLE\n"); + SDL_Log("SDL_HITTEST_DRAGGABLE"); return SDL_HITTEST_DRAGGABLE; } return SDL_HITTEST_NORMAL; @@ -1190,7 +1190,7 @@ bool SDLTest_CommonInit(SDLTest_CommonState *state) if (state->verbose & VERBOSE_VIDEO) { n = SDL_GetNumVideoDrivers(); if (n == 0) { - SDL_Log("No built-in video drivers\n"); + SDL_Log("No built-in video drivers"); } else { (void)SDL_snprintf(text, sizeof(text), "Built-in video drivers:"); for (i = 0; i < n; ++i) { @@ -1199,16 +1199,16 @@ bool SDLTest_CommonInit(SDLTest_CommonState *state) } SDL_snprintfcat(text, sizeof(text), " %s", SDL_GetVideoDriver(i)); } - SDL_Log("%s\n", text); + SDL_Log("%s", text); } } if (!SDL_InitSubSystem(SDL_INIT_VIDEO)) { - SDL_Log("Couldn't initialize video driver: %s\n", + SDL_Log("Couldn't initialize video driver: %s", SDL_GetError()); return false; } if (state->verbose & VERBOSE_VIDEO) { - SDL_Log("Video driver: %s\n", + SDL_Log("Video driver: %s", SDL_GetCurrentVideoDriver()); } @@ -1257,10 +1257,10 @@ bool SDLTest_CommonInit(SDLTest_CommonState *state) int outputIndex = 0; #endif displays = SDL_GetDisplays(&n); - SDL_Log("Number of displays: %d\n", n); + SDL_Log("Number of displays: %d", n); for (i = 0; i < n; ++i) { SDL_DisplayID displayID = displays[i]; - SDL_Log("Display %" SDL_PRIu32 ": %s\n", displayID, SDL_GetDisplayName(displayID)); + SDL_Log("Display %" SDL_PRIu32 ": %s", displayID, SDL_GetDisplayName(displayID)); SDL_zero(bounds); SDL_GetDisplayBounds(displayID, &bounds); @@ -1268,46 +1268,46 @@ bool SDLTest_CommonInit(SDLTest_CommonState *state) SDL_zero(usablebounds); SDL_GetDisplayUsableBounds(displayID, &usablebounds); - SDL_Log("Bounds: %dx%d at %d,%d\n", bounds.w, bounds.h, bounds.x, bounds.y); - SDL_Log("Usable bounds: %dx%d at %d,%d\n", usablebounds.w, usablebounds.h, usablebounds.x, usablebounds.y); + SDL_Log("Bounds: %dx%d at %d,%d", bounds.w, bounds.h, bounds.x, bounds.y); + SDL_Log("Usable bounds: %dx%d at %d,%d", usablebounds.w, usablebounds.h, usablebounds.x, usablebounds.y); mode = SDL_GetDesktopDisplayMode(displayID); SDL_GetMasksForPixelFormat(mode->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask); - SDL_Log(" Desktop mode: %dx%d@%gx %gHz, %d bits-per-pixel (%s)\n", + SDL_Log(" Desktop mode: %dx%d@%gx %gHz, %d bits-per-pixel (%s)", mode->w, mode->h, mode->pixel_density, mode->refresh_rate, bpp, SDL_GetPixelFormatName(mode->format)); if (Rmask || Gmask || Bmask) { - SDL_Log(" Red Mask = 0x%.8" SDL_PRIx32 "\n", Rmask); - SDL_Log(" Green Mask = 0x%.8" SDL_PRIx32 "\n", Gmask); - SDL_Log(" Blue Mask = 0x%.8" SDL_PRIx32 "\n", Bmask); + SDL_Log(" Red Mask = 0x%.8" SDL_PRIx32, Rmask); + SDL_Log(" Green Mask = 0x%.8" SDL_PRIx32, Gmask); + SDL_Log(" Blue Mask = 0x%.8" SDL_PRIx32, Bmask); if (Amask) { - SDL_Log(" Alpha Mask = 0x%.8" SDL_PRIx32 "\n", Amask); + SDL_Log(" Alpha Mask = 0x%.8" SDL_PRIx32, Amask); } } /* Print available fullscreen video modes */ modes = SDL_GetFullscreenDisplayModes(displayID, &m); if (m == 0) { - SDL_Log("No available fullscreen video modes\n"); + SDL_Log("No available fullscreen video modes"); } else { - SDL_Log(" Fullscreen video modes:\n"); + SDL_Log(" Fullscreen video modes:"); for (j = 0; j < m; ++j) { mode = modes[j]; SDL_GetMasksForPixelFormat(mode->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask); - SDL_Log(" Mode %d: %dx%d@%gx %gHz, %d bits-per-pixel (%s)\n", + SDL_Log(" Mode %d: %dx%d@%gx %gHz, %d bits-per-pixel (%s)", j, mode->w, mode->h, mode->pixel_density, mode->refresh_rate, bpp, SDL_GetPixelFormatName(mode->format)); if (Rmask || Gmask || Bmask) { - SDL_Log(" Red Mask = 0x%.8" SDL_PRIx32 "\n", + SDL_Log(" Red Mask = 0x%.8" SDL_PRIx32, Rmask); - SDL_Log(" Green Mask = 0x%.8" SDL_PRIx32 "\n", + SDL_Log(" Green Mask = 0x%.8" SDL_PRIx32, Gmask); - SDL_Log(" Blue Mask = 0x%.8" SDL_PRIx32 "\n", + SDL_Log(" Blue Mask = 0x%.8" SDL_PRIx32, Bmask); if (Amask) { - SDL_Log(" Alpha Mask = 0x%.8" SDL_PRIx32 "\n", Amask); + SDL_Log(" Alpha Mask = 0x%.8" SDL_PRIx32, Amask); } } } @@ -1330,11 +1330,11 @@ bool SDLTest_CommonInit(SDLTest_CommonState *state) if (state->verbose & VERBOSE_RENDER) { n = SDL_GetNumRenderDrivers(); if (n == 0) { - SDL_Log("No built-in render drivers\n"); + SDL_Log("No built-in render drivers"); } else { - SDL_Log("Built-in render drivers:\n"); + SDL_Log("Built-in render drivers:"); for (i = 0; i < n; ++i) { - SDL_Log(" %s\n", SDL_GetRenderDriver(i)); + SDL_Log(" %s", SDL_GetRenderDriver(i)); } } } @@ -1374,7 +1374,7 @@ bool SDLTest_CommonInit(SDLTest_CommonState *state) (SDL_Texture **)SDL_calloc(state->num_windows, sizeof(*state->targets)); if (!state->windows || !state->renderers) { - SDL_Log("Out of memory!\n"); + SDL_Log("Out of memory!"); return false; } for (i = 0; i < state->num_windows; ++i) { @@ -1412,7 +1412,7 @@ bool SDLTest_CommonInit(SDLTest_CommonState *state) state->windows[i] = SDL_CreateWindowWithProperties(props); SDL_DestroyProperties(props); if (!state->windows[i]) { - SDL_Log("Couldn't create window: %s\n", + SDL_Log("Couldn't create window: %s", SDL_GetError()); return false; } @@ -1427,7 +1427,7 @@ bool SDLTest_CommonInit(SDLTest_CommonState *state) } SDL_GetWindowSize(state->windows[i], &w, &h); if (!(state->window_flags & SDL_WINDOW_RESIZABLE) && (w != r.w || h != r.h)) { - SDL_Log("Window requested size %dx%d, got %dx%d\n", r.w, r.h, w, h); + SDL_Log("Window requested size %dx%d, got %dx%d", r.w, r.h, w, h); state->window_w = w; state->window_h = h; } @@ -1459,7 +1459,7 @@ bool SDLTest_CommonInit(SDLTest_CommonState *state) if (!state->skip_renderer && (state->renderdriver || !(state->window_flags & (SDL_WINDOW_OPENGL | SDL_WINDOW_VULKAN | SDL_WINDOW_METAL)))) { state->renderers[i] = SDL_CreateRenderer(state->windows[i], state->renderdriver); if (!state->renderers[i]) { - SDL_Log("Couldn't create renderer: %s\n", + SDL_Log("Couldn't create renderer: %s", SDL_GetError()); return false; } @@ -1471,14 +1471,14 @@ bool SDLTest_CommonInit(SDLTest_CommonState *state) SDL_SetRenderVSync(state->renderers[i], state->render_vsync); } if (!SDL_SetRenderLogicalPresentation(state->renderers[i], state->logical_w, state->logical_h, state->logical_presentation)) { - SDL_Log("Couldn't set logical presentation: %s\n", SDL_GetError()); + SDL_Log("Couldn't set logical presentation: %s", SDL_GetError()); return false; } if (state->scale != 0.0f) { SDL_SetRenderScale(state->renderers[i], state->scale, state->scale); } if (state->verbose & VERBOSE_RENDER) { - SDL_Log("Current renderer:\n"); + SDL_Log("Current renderer:"); SDLTest_PrintRenderer(state->renderers[i]); } } @@ -1494,7 +1494,7 @@ bool SDLTest_CommonInit(SDLTest_CommonState *state) if (state->verbose & VERBOSE_AUDIO) { n = SDL_GetNumAudioDrivers(); if (n == 0) { - SDL_Log("No built-in audio drivers\n"); + SDL_Log("No built-in audio drivers"); } else { (void)SDL_snprintf(text, sizeof(text), "Built-in audio drivers:"); for (i = 0; i < n; ++i) { @@ -1503,23 +1503,23 @@ bool SDLTest_CommonInit(SDLTest_CommonState *state) } SDL_snprintfcat(text, sizeof(text), " %s", SDL_GetAudioDriver(i)); } - SDL_Log("%s\n", text); + SDL_Log("%s", text); } } if (!SDL_InitSubSystem(SDL_INIT_AUDIO)) { - SDL_Log("Couldn't initialize audio driver: %s\n", + SDL_Log("Couldn't initialize audio driver: %s", SDL_GetError()); return false; } if (state->verbose & VERBOSE_AUDIO) { - SDL_Log("Audio driver: %s\n", + SDL_Log("Audio driver: %s", SDL_GetCurrentAudioDriver()); } const SDL_AudioSpec spec = { state->audio_format, state->audio_channels, state->audio_freq }; state->audio_id = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec); if (!state->audio_id) { - SDL_Log("Couldn't open audio: %s\n", SDL_GetError()); + SDL_Log("Couldn't open audio: %s", SDL_GetError()); return false; } } @@ -1676,7 +1676,7 @@ void SDLTest_PrintEvent(const SDL_Event *event) SDL_Rect rect; SDL_GetWindowSafeArea(SDL_GetWindowFromEvent(event), &rect); - SDL_Log("SDL EVENT: Window %" SDL_PRIu32 " changed safe area to: %d,%d %dx%d\n", + SDL_Log("SDL EVENT: Window %" SDL_PRIu32 " changed safe area to: %d,%d %dx%d", event->window.windowID, rect.x, rect.y, rect.w, rect.h); break; } @@ -2058,7 +2058,7 @@ static void SDLCALL SDLTest_ScreenShotClipboardCleanup(void *context) { SDLTest_ClipboardData *data = (SDLTest_ClipboardData *)context; - SDL_Log("Cleaning up screenshot image data\n"); + SDL_Log("Cleaning up screenshot image data"); if (data->image) { SDL_free(data->image); @@ -2071,14 +2071,14 @@ static const void * SDLCALL SDLTest_ScreenShotClipboardProvider(void *context, c SDLTest_ClipboardData *data = (SDLTest_ClipboardData *)context; if (SDL_strncmp(mime_type, "text", 4) == 0) { - SDL_Log("Providing screenshot title to clipboard!\n"); + SDL_Log("Providing screenshot title to clipboard!"); /* Return "Test screenshot" */ *size = 15; return "Test screenshot (but this isn't part of it)"; } - SDL_Log("Providing screenshot image to clipboard!\n"); + SDL_Log("Providing screenshot image to clipboard!"); if (!data->image) { SDL_IOStream *file; @@ -2089,7 +2089,7 @@ static const void * SDLCALL SDLTest_ScreenShotClipboardProvider(void *context, c void *image = SDL_malloc(length); if (image) { if (SDL_ReadIO(file, image, length) != length) { - SDL_Log("Couldn't read %s: %s\n", SCREENSHOT_FILE, SDL_GetError()); + SDL_Log("Couldn't read %s: %s", SCREENSHOT_FILE, SDL_GetError()); SDL_free(image); image = NULL; } @@ -2101,7 +2101,7 @@ static const void * SDLCALL SDLTest_ScreenShotClipboardProvider(void *context, c data->size = length; } } else { - SDL_Log("Couldn't load %s: %s\n", SCREENSHOT_FILE, SDL_GetError()); + SDL_Log("Couldn't load %s: %s", SCREENSHOT_FILE, SDL_GetError()); } } @@ -2124,12 +2124,12 @@ static void SDLTest_CopyScreenShot(SDL_Renderer *renderer) surface = SDL_RenderReadPixels(renderer, NULL); if (!surface) { - SDL_Log("Couldn't read screen: %s\n", SDL_GetError()); + SDL_Log("Couldn't read screen: %s", SDL_GetError()); return; } if (!SDL_SaveBMP(surface, SCREENSHOT_FILE)) { - SDL_Log("Couldn't save %s: %s\n", SCREENSHOT_FILE, SDL_GetError()); + SDL_Log("Couldn't save %s: %s", SCREENSHOT_FILE, SDL_GetError()); SDL_DestroySurface(surface); return; } @@ -2137,11 +2137,11 @@ static void SDLTest_CopyScreenShot(SDL_Renderer *renderer) clipboard_data = (SDLTest_ClipboardData *)SDL_calloc(1, sizeof(*clipboard_data)); if (!clipboard_data) { - SDL_Log("Couldn't allocate clipboard data\n"); + SDL_Log("Couldn't allocate clipboard data"); return; } SDL_SetClipboardData(SDLTest_ScreenShotClipboardProvider, SDLTest_ScreenShotClipboardCleanup, clipboard_data, image_formats, SDL_arraysize(image_formats)); - SDL_Log("Saved screenshot to %s and clipboard\n", SCREENSHOT_FILE); + SDL_Log("Saved screenshot to %s and clipboard", SCREENSHOT_FILE); } static void SDLTest_PasteScreenShot(void) @@ -2336,7 +2336,7 @@ SDL_AppResult SDLTest_CommonEventMainCallbacks(SDLTest_CommonState *state, const } else { dest = displays[(current_index + num_displays + 1) % num_displays]; } - SDL_Log("Centering on display (%" SDL_PRIu32 ")\n", dest); + SDL_Log("Centering on display (%" SDL_PRIu32 ")", dest); SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED_DISPLAY(dest), SDL_WINDOWPOS_CENTERED_DISPLAY(dest)); @@ -2365,7 +2365,7 @@ SDL_AppResult SDLTest_CommonEventMainCallbacks(SDLTest_CommonState *state, const x += delta; } - SDL_Log("Setting position to (%d, %d)\n", x, y); + SDL_Log("Setting position to (%d, %d)", x, y); SDL_SetWindowPosition(window, x, y); } } @@ -2399,7 +2399,7 @@ SDL_AppResult SDLTest_CommonEventMainCallbacks(SDLTest_CommonState *state, const if (withAlt) { /* Alt-C copy awesome text to the primary selection! */ SDL_SetPrimarySelectionText("SDL rocks!\nYou know it!"); - SDL_Log("Copied text to primary selection\n"); + SDL_Log("Copied text to primary selection"); } else if (withControl) { if (withShift) { @@ -2415,7 +2415,7 @@ SDL_AppResult SDLTest_CommonEventMainCallbacks(SDLTest_CommonState *state, const } else { /* Ctrl-C copy awesome text! */ SDL_SetClipboardText("SDL rocks!\nYou know it!"); - SDL_Log("Copied text to clipboard\n"); + SDL_Log("Copied text to clipboard"); } break; } @@ -2425,9 +2425,9 @@ SDL_AppResult SDLTest_CommonEventMainCallbacks(SDLTest_CommonState *state, const /* Alt-V paste awesome text from the primary selection! */ char *text = SDL_GetPrimarySelectionText(); if (*text) { - SDL_Log("Primary selection: %s\n", text); + SDL_Log("Primary selection: %s", text); } else { - SDL_Log("Primary selection is empty\n"); + SDL_Log("Primary selection is empty"); } SDL_free(text); @@ -2439,9 +2439,9 @@ SDL_AppResult SDLTest_CommonEventMainCallbacks(SDLTest_CommonState *state, const /* Ctrl-V paste awesome text! */ char *text = SDL_GetClipboardText(); if (*text) { - SDL_Log("Clipboard: %s\n", text); + SDL_Log("Clipboard: %s", text); } else { - SDL_Log("Clipboard is empty\n"); + SDL_Log("Clipboard is empty"); } SDL_free(text); } @@ -2498,7 +2498,7 @@ SDL_AppResult SDLTest_CommonEventMainCallbacks(SDLTest_CommonState *state, const if (window) { const bool shouldCapture = !(SDL_GetWindowFlags(window) & SDL_WINDOW_MOUSE_CAPTURE); const bool rc = SDL_CaptureMouse(shouldCapture); - SDL_Log("%sapturing mouse %s!\n", shouldCapture ? "C" : "Unc", rc ? "succeeded" : "failed"); + SDL_Log("%sapturing mouse %s!", shouldCapture ? "C" : "Unc", rc ? "succeeded" : "failed"); } } break; diff --git a/libs/SDL3/src/test/SDL_test_fuzzer.c b/libs/SDL3/src/test/SDL_test_fuzzer.c index caa330c9..67638b5e 100644 --- a/libs/SDL3/src/test/SDL_test_fuzzer.c +++ b/libs/SDL3/src/test/SDL_test_fuzzer.c @@ -144,7 +144,7 @@ Sint32 SDLTest_RandomIntegerInRange(Sint32 min, Sint32 max) Uint64 range = (Sint64)max - (Sint64)min; if (range < SDL_MAX_SINT32) { - return min + (Sint32) SDL_rand_r(&rndContext, (Sint32) range + 1); + return min + SDL_rand_r(&rndContext, (Sint32) range + 1); } else { Uint64 add = SDL_rand_bits_r(&rndContext) | ((Uint64) SDL_rand_bits_r(&rndContext) << 32); return (Sint32) (min + (Sint64) (add % (range + 1))); diff --git a/libs/SDL3/src/test/SDL_test_harness.c b/libs/SDL3/src/test/SDL_test_harness.c index 7156b112..d6a3b8d3 100644 --- a/libs/SDL3/src/test/SDL_test_harness.c +++ b/libs/SDL3/src/test/SDL_test_harness.c @@ -515,6 +515,7 @@ int SDLTest_ExecuteTestSuiteRunner(SDLTest_TestSuiteRunner *runner) arraySuites = SDL_malloc(nbSuites * sizeof(int)); if (!arraySuites) { + SDL_free((void *)failedTests); return SDL_OutOfMemory(); } for (i = 0; i < nbSuites; i++) { @@ -586,6 +587,8 @@ int SDLTest_ExecuteTestSuiteRunner(SDLTest_TestSuiteRunner *runner) arrayTestCases = SDL_malloc(nbTestCases * sizeof(int)); if (!arrayTestCases) { + SDL_free(arraySuites); + SDL_free((void *)failedTests); return SDL_OutOfMemory(); } for (j = 0; j < nbTestCases; j++) { diff --git a/libs/SDL3/src/test/SDL_test_memory.c b/libs/SDL3/src/test/SDL_test_memory.c index 8b853c62..b90c4a5d 100644 --- a/libs/SDL3/src/test/SDL_test_memory.c +++ b/libs/SDL3/src/test/SDL_test_memory.c @@ -229,7 +229,7 @@ static void rand_fill_memory(void* ptr, size_t start, size_t end) } } -static void *SDLCALL SDLTest_TrackedMalloc(size_t size) +static void * SDLCALL SDLTest_TrackedMalloc(size_t size) { void *mem; @@ -241,7 +241,7 @@ static void *SDLCALL SDLTest_TrackedMalloc(size_t size) return mem; } -static void *SDLCALL SDLTest_TrackedCalloc(size_t nmemb, size_t size) +static void * SDLCALL SDLTest_TrackedCalloc(size_t nmemb, size_t size) { void *mem; @@ -252,7 +252,7 @@ static void *SDLCALL SDLTest_TrackedCalloc(size_t nmemb, size_t size) return mem; } -static void *SDLCALL SDLTest_TrackedRealloc(void *ptr, size_t size) +static void * SDLCALL SDLTest_TrackedRealloc(void *ptr, size_t size) { void *mem; size_t old_size = 0; diff --git a/libs/SDL3/src/thread/SDL_thread.c b/libs/SDL3/src/thread/SDL_thread.c index 884a6cd6..99cb9dd7 100644 --- a/libs/SDL3/src/thread/SDL_thread.c +++ b/libs/SDL3/src/thread/SDL_thread.c @@ -314,7 +314,7 @@ static bool ThreadValid(SDL_Thread *thread) void SDL_RunThread(SDL_Thread *thread) { void *userdata = thread->userdata; - int(SDLCALL * userfunc)(void *) = thread->userfunc; + int(SDLCALL *userfunc)(void *) = thread->userfunc; int *statusloc = &thread->status; @@ -334,7 +334,6 @@ void SDL_RunThread(SDL_Thread *thread) if (!SDL_CompareAndSwapAtomicInt(&thread->state, SDL_THREAD_ALIVE, SDL_THREAD_COMPLETE)) { // Clean up if something already detached us. if (SDL_GetThreadState(thread) == SDL_THREAD_DETACHED) { - SDL_SetObjectValid(thread, SDL_OBJECT_TYPE_THREAD, false); SDL_free(thread->name); // Can't free later, we've already cleaned up TLS SDL_free(thread); } @@ -457,7 +456,7 @@ bool SDL_SetCurrentThreadPriority(SDL_ThreadPriority priority) void SDL_WaitThread(SDL_Thread *thread, int *status) { - if (!ThreadValid(thread) || SDL_GetThreadState(thread) == SDL_THREAD_DETACHED) { + if (!ThreadValid(thread)) { if (status) { *status = -1; } @@ -488,6 +487,9 @@ void SDL_DetachThread(SDL_Thread *thread) return; } + // The thread may vanish at any time, it's no longer valid + SDL_SetObjectValid(thread, SDL_OBJECT_TYPE_THREAD, false); + // Grab dibs if the state is alive+joinable. if (SDL_CompareAndSwapAtomicInt(&thread->state, SDL_THREAD_ALIVE, SDL_THREAD_DETACHED)) { SDL_SYS_DetachThread(thread); diff --git a/libs/SDL3/src/thread/n3ds/SDL_syscond.c b/libs/SDL3/src/thread/n3ds/SDL_syscond.c deleted file mode 100644 index d5c4067d..00000000 --- a/libs/SDL3/src/thread/n3ds/SDL_syscond.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 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_THREAD_N3DS - -// An implementation of condition variables using libctru's CondVar - -#include "SDL_sysmutex_c.h" - -struct SDL_Condition -{ - CondVar cond_variable; -}; - -// Create a condition variable -SDL_Condition *SDL_CreateCondition(void) -{ - SDL_Condition *cond = (SDL_Condition *)SDL_malloc(sizeof(SDL_Condition)); - if (cond) { - CondVar_Init(&cond->cond_variable); - } - return cond; -} - -// Destroy a condition variable -void SDL_DestroyCondition(SDL_Condition *cond) -{ - if (cond) { - SDL_free(cond); - } -} - -// Restart one of the threads that are waiting on the condition variable -void SDL_SignalCondition(SDL_Condition *cond) -{ - if (!cond) { - return; - } - - CondVar_Signal(&cond->cond_variable); -} - -// Restart all threads that are waiting on the condition variable -void SDL_BroadcastCondition(SDL_Condition *cond) -{ - if (!cond) { - return; - } - - CondVar_Broadcast(&cond->cond_variable); -} - -/* Wait on the condition variable for at most 'timeoutNS' nanoseconds. - The mutex must be locked before entering this function! - The mutex is unlocked during the wait, and locked again after the wait. - -Typical use: - -Thread A: - SDL_LockMutex(lock); - while ( ! condition ) { - SDL_WaitCondition(cond, lock); - } - SDL_UnlockMutex(lock); - -Thread B: - SDL_LockMutex(lock); - ... - condition = true; - ... - SDL_SignalCondition(cond); - SDL_UnlockMutex(lock); - */ -bool SDL_WaitConditionTimeoutNS(SDL_Condition *cond, SDL_Mutex *mutex, Sint64 timeoutNS) -{ - Result res; - - if (!cond || !mutex) { - return true; - } - - res = 0; - if (timeoutNS < 0) { - CondVar_Wait(&cond->cond_variable, &mutex->lock.lock); - } else { - res = CondVar_WaitTimeout(&cond->cond_variable, &mutex->lock.lock, timeoutNS); - } - - return R_SUCCEEDED(res); -} - -#endif // SDL_THREAD_N3DS diff --git a/libs/SDL3/src/thread/windows/SDL_systhread.c b/libs/SDL3/src/thread/windows/SDL_systhread.c index c30694a2..c5bee81f 100644 --- a/libs/SDL3/src/thread/windows/SDL_systhread.c +++ b/libs/SDL3/src/thread/windows/SDL_systhread.c @@ -153,7 +153,7 @@ void SDL_SYS_SetupThread(const char *name) inf.dwFlags = 0; // The debugger catches this, renames the thread, continues on. - RaiseException(SDL_DEBUGGER_NAME_EXCEPTION_CODE, 0, sizeof(inf) / sizeof(ULONG), (const ULONG_PTR *)&inf); + RaiseException(SDL_DEBUGGER_NAME_EXCEPTION_CODE, 0, sizeof(inf) / sizeof(ULONG_PTR), (const ULONG_PTR *)&inf); RemoveVectoredExceptionHandler(exceptionHandlerHandle); } } diff --git a/libs/SDL3/src/timer/windows/SDL_systimer.c b/libs/SDL3/src/timer/windows/SDL_systimer.c index 01e908c6..f6f4b15c 100644 --- a/libs/SDL3/src/timer/windows/SDL_systimer.c +++ b/libs/SDL3/src/timer/windows/SDL_systimer.c @@ -24,28 +24,53 @@ #include "../../core/windows/SDL_windows.h" +/* CREATE_WAITABLE_TIMER_HIGH_RESOLUTION flag was added in Windows 10 version 1803. */ +#ifndef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION +#define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 0x2 +#endif + +typedef HANDLE (WINAPI *CreateWaitableTimerExW_t)(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCWSTR lpTimerName, DWORD dwFlags, DWORD dwDesiredAccess); +static CreateWaitableTimerExW_t pCreateWaitableTimerExW; + +typedef BOOL (WINAPI *SetWaitableTimerEx_t)(HANDLE hTimer, const LARGE_INTEGER *lpDueTime, LONG lPeriod, PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine, PREASON_CONTEXT WakeContext, ULONG TolerableDelay); +static SetWaitableTimerEx_t pSetWaitableTimerEx; static void SDL_CleanupWaitableHandle(void *handle) { CloseHandle(handle); } -#ifdef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION static HANDLE SDL_GetWaitableTimer(void) { static SDL_TLSID TLS_timer_handle; HANDLE timer; + if (!pCreateWaitableTimerExW || !pSetWaitableTimerEx) { + static bool initialized; + + if (!initialized) { + HMODULE module = GetModuleHandle(TEXT("kernel32.dll")); + if (module) { + pCreateWaitableTimerExW = (CreateWaitableTimerExW_t)GetProcAddress(module, "CreateWaitableTimerExW"); + pSetWaitableTimerEx = (SetWaitableTimerEx_t)GetProcAddress(module, "SetWaitableTimerEx"); + } + initialized = true; + } + + if (!pCreateWaitableTimerExW || !pSetWaitableTimerEx) { + return NULL; + } + } + timer = SDL_GetTLS(&TLS_timer_handle); if (!timer) { - timer = CreateWaitableTimerExW(NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS); + timer = pCreateWaitableTimerExW(NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS); if (timer) { SDL_SetTLS(&TLS_timer_handle, timer, SDL_CleanupWaitableHandle); } } return timer; } -#endif // CREATE_WAITABLE_TIMER_HIGH_RESOLUTION static HANDLE SDL_GetWaitableEvent(void) { @@ -80,21 +105,15 @@ Uint64 SDL_GetPerformanceFrequency(void) void SDL_SYS_DelayNS(Uint64 ns) { - /* CREATE_WAITABLE_TIMER_HIGH_RESOLUTION flag was added in Windows 10 version 1803. - * - * Use the compiler version to determine availability. - */ -#ifdef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION HANDLE timer = SDL_GetWaitableTimer(); if (timer) { LARGE_INTEGER due_time; due_time.QuadPart = -((LONGLONG)ns / 100); - if (SetWaitableTimerEx(timer, &due_time, 0, NULL, NULL, NULL, 0)) { + if (pSetWaitableTimerEx(timer, &due_time, 0, NULL, NULL, NULL, 0)) { WaitForSingleObject(timer, INFINITE); } return; } -#endif const Uint64 max_delay = 0xffffffffLL * SDL_NS_PER_MS; if (ns > max_delay) { diff --git a/libs/SDL3/src/tray/cocoa/SDL_tray.m b/libs/SDL3/src/tray/cocoa/SDL_tray.m index ae8d6be8..fd7f9551 100644 --- a/libs/SDL3/src/tray/cocoa/SDL_tray.m +++ b/libs/SDL3/src/tray/cocoa/SDL_tray.m @@ -285,15 +285,15 @@ SDL_TrayMenu *SDL_GetTraySubmenu(SDL_TrayEntry *entry) return entry->submenu; } -const SDL_TrayEntry **SDL_GetTrayEntries(SDL_TrayMenu *menu, int *size) +const SDL_TrayEntry **SDL_GetTrayEntries(SDL_TrayMenu *menu, int *count) { if (!menu) { SDL_InvalidParamError("menu"); return NULL; } - if (size) { - *size = menu->nEntries; + if (count) { + *count = menu->nEntries; } return (const SDL_TrayEntry **)menu->entries; } diff --git a/libs/SDL3/src/tray/dummy/SDL_tray.c b/libs/SDL3/src/tray/dummy/SDL_tray.c index db76db25..766fb925 100644 --- a/libs/SDL3/src/tray/dummy/SDL_tray.c +++ b/libs/SDL3/src/tray/dummy/SDL_tray.c @@ -66,7 +66,7 @@ SDL_TrayMenu *SDL_GetTraySubmenu(SDL_TrayEntry *entry) return NULL; } -const SDL_TrayEntry **SDL_GetTrayEntries(SDL_TrayMenu *menu, int *size) +const SDL_TrayEntry **SDL_GetTrayEntries(SDL_TrayMenu *menu, int *count) { SDL_InvalidParamError("menu"); return NULL; diff --git a/libs/SDL3/src/tray/unix/SDL_tray.c b/libs/SDL3/src/tray/unix/SDL_tray.c index 5f017c2f..dc2d0ca6 100644 --- a/libs/SDL3/src/tray/unix/SDL_tray.c +++ b/libs/SDL3/src/tray/unix/SDL_tray.c @@ -58,6 +58,13 @@ typedef enum static gulong (*g_signal_connect_data)(gpointer instance, const gchar *detailed_signal, GCallback c_handler, gpointer data, GClosureNotify destroy_data, GConnectFlags connect_flags); static void (*g_object_unref)(gpointer object); static gchar *(*g_mkdtemp)(gchar *template); +gpointer (*g_object_ref_sink)(gpointer object); +gpointer (*g_object_ref)(gpointer object); + +// glib_typeof requires compiler-specific code and includes that are too complex +// to be worth copy-pasting here +//#define g_object_ref(Obj) ((glib_typeof (Obj)) (g_object_ref) (Obj)) +//#define g_object_ref_sink(Obj) ((glib_typeof (Obj)) (g_object_ref_sink) (Obj)) #define g_signal_connect(instance, detailed_signal, c_handler, data) \ g_signal_connect_data ((instance), (detailed_signal), (c_handler), (data), NULL, (GConnectFlags) 0) @@ -248,6 +255,8 @@ static bool init_gtk(void) g_mkdtemp = dlsym(libgdk, "g_mkdtemp"); g_signal_connect_data = dlsym(libgdk, "g_signal_connect_data"); g_object_unref = dlsym(libgdk, "g_object_unref"); + g_object_ref_sink = dlsym(libgdk, "g_object_ref_sink"); + g_object_ref = dlsym(libgdk, "g_object_ref"); app_indicator_new = dlsym(libappindicator, "app_indicator_new"); app_indicator_set_status = dlsym(libappindicator, "app_indicator_set_status"); @@ -268,6 +277,8 @@ static bool init_gtk(void) !gtk_menu_shell_insert || !gtk_widget_destroy || !g_mkdtemp || + !g_object_ref_sink || + !g_object_ref || !g_signal_connect_data || !g_object_unref || !app_indicator_new || @@ -326,6 +337,8 @@ struct SDL_Tray { SDL_TrayMenu *menu; char icon_dir[sizeof(ICON_DIR_TEMPLATE)]; char icon_path[256]; + + GtkMenuShell *menu_cached; }; static void call_callback(GtkMenuItem *item, gpointer ptr) @@ -384,6 +397,11 @@ static void DestroySDLMenu(SDL_TrayMenu *menu) } SDL_free(menu->entries[i]); } + + if (menu->menu) { + g_object_unref(menu->menu); + } + SDL_free(menu->entries); SDL_free(menu); } @@ -421,18 +439,24 @@ SDL_Tray *SDL_CreateTray(SDL_Surface *icon, const char *tooltip) return NULL; } - if (!new_tmp_filename(tray)) { - SDL_free(tray); - return NULL; - } + if (icon) { + if (!new_tmp_filename(tray)) { + SDL_free(tray); + return NULL; + } - SDL_SaveBMP(icon, tray->icon_path); + SDL_SaveBMP(icon, tray->icon_path); + } tray->indicator = app_indicator_new(get_appindicator_id(), tray->icon_path, APP_INDICATOR_CATEGORY_APPLICATION_STATUS); app_indicator_set_status(tray->indicator, APP_INDICATOR_STATUS_ACTIVE); + // The tray icon isn't shown before a menu is created; create one early. + tray->menu_cached = (GtkMenuShell *) g_object_ref_sink(gtk_menu_new()); + app_indicator_set_menu(tray->indicator, GTK_MENU(tray->menu_cached)); + SDL_RegisterTray(tray); return tray; @@ -476,14 +500,12 @@ SDL_TrayMenu *SDL_CreateTrayMenu(SDL_Tray *tray) return NULL; } - tray->menu->menu = (GtkMenuShell *)gtk_menu_new(); + tray->menu->menu = g_object_ref(tray->menu_cached); tray->menu->parent_tray = tray; tray->menu->parent_entry = NULL; tray->menu->nEntries = 0; tray->menu->entries = NULL; - app_indicator_set_menu(tray->indicator, GTK_MENU(tray->menu->menu)); - return tray->menu; } @@ -540,15 +562,15 @@ SDL_TrayMenu *SDL_GetTraySubmenu(SDL_TrayEntry *entry) return entry->submenu; } -const SDL_TrayEntry **SDL_GetTrayEntries(SDL_TrayMenu *menu, int *size) +const SDL_TrayEntry **SDL_GetTrayEntries(SDL_TrayMenu *menu, int *count) { if (!menu) { SDL_InvalidParamError("menu"); return NULL; } - if (size) { - *size = menu->nEntries; + if (count) { + *count = menu->nEntries; } return (const SDL_TrayEntry **)menu->entries; } @@ -783,6 +805,10 @@ void SDL_DestroyTray(SDL_Tray *tray) SDL_RemovePath(tray->icon_dir); } + if (tray->menu_cached) { + g_object_unref(tray->menu_cached); + } + if (tray->indicator) { g_object_unref(tray->indicator); } diff --git a/libs/SDL3/src/tray/windows/SDL_tray.c b/libs/SDL3/src/tray/windows/SDL_tray.c index a7e27c06..18008ee2 100644 --- a/libs/SDL3/src/tray/windows/SDL_tray.c +++ b/libs/SDL3/src/tray/windows/SDL_tray.c @@ -115,7 +115,10 @@ LRESULT CALLBACK TrayWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPar case WM_TRAYICON: if (LOWORD(lParam) == WM_CONTEXTMENU || LOWORD(lParam) == WM_LBUTTONUP) { SetForegroundWindow(hwnd); - TrackPopupMenu(tray->menu->hMenu, TPM_BOTTOMALIGN | TPM_RIGHTALIGN, GET_X_LPARAM(wParam), GET_Y_LPARAM(wParam), 0, hwnd, NULL); + + if (tray->menu) { + TrackPopupMenu(tray->menu->hMenu, TPM_BOTTOMALIGN | TPM_RIGHTALIGN, GET_X_LPARAM(wParam), GET_Y_LPARAM(wParam), 0, hwnd, NULL); + } } break; @@ -364,15 +367,15 @@ SDL_TrayMenu *SDL_GetTraySubmenu(SDL_TrayEntry *entry) return entry->submenu; } -const SDL_TrayEntry **SDL_GetTrayEntries(SDL_TrayMenu *menu, int *size) +const SDL_TrayEntry **SDL_GetTrayEntries(SDL_TrayMenu *menu, int *count) { if (!menu) { SDL_InvalidParamError("menu"); return NULL; } - if (size) { - *size = menu->nEntries; + if (count) { + *count = menu->nEntries; } return (const SDL_TrayEntry **)menu->entries; } diff --git a/libs/SDL3/src/video/SDL_bmp.c b/libs/SDL3/src/video/SDL_bmp.c index d8b1c9db..688086fc 100644 --- a/libs/SDL3/src/video/SDL_bmp.c +++ b/libs/SDL3/src/video/SDL_bmp.c @@ -46,11 +46,23 @@ #endif // Logical color space values for BMP files +// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wmf/eb4bbd50-b3ce-4917-895c-be31f214797f #ifndef LCS_WINDOWS_COLOR_SPACE // 0x57696E20 == "Win " #define LCS_WINDOWS_COLOR_SPACE 0x57696E20 #endif +#ifndef LCS_sRGB +// 0x73524742 == "sRGB" +#define LCS_sRGB 0x73524742 +#endif + +// Logical/physical color relationship +// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wmf/9fec0834-607d-427d-abd5-ab240fb0db38 +#ifndef LCS_GM_GRAPHICS +#define LCS_GM_GRAPHICS 0x00000002 +#endif + static bool readRlePixels(SDL_Surface *surface, SDL_IOStream *src, int isRle8) { /* @@ -64,16 +76,16 @@ static bool readRlePixels(SDL_Surface *surface, SDL_IOStream *src, int isRle8) int ofs = 0; Uint8 ch; Uint8 needsPad; + const int pixels_per_byte = (isRle8 ? 1 : 2); #define COPY_PIXEL(x) \ spot = &bits[ofs++]; \ if (spot >= start && spot < end) \ - *spot = (x) + *spot = (x) - // !!! FIXME: for all these reads, handle error vs eof? handle -2 if non-blocking? for (;;) { if (!SDL_ReadU8(src, &ch)) { - return true; + return false; } /* | encoded mode starts with a run length, and then a byte @@ -82,26 +94,12 @@ static bool readRlePixels(SDL_Surface *surface, SDL_IOStream *src, int isRle8) if (ch) { Uint8 pixel; if (!SDL_ReadU8(src, &pixel)) { - return true; - } - if (isRle8) { // 256-color bitmap, compressed - do { - COPY_PIXEL(pixel); - } while (--ch); - } else { // 16-color bitmap, compressed - Uint8 pixel0 = pixel >> 4; - Uint8 pixel1 = pixel & 0x0F; - for (;;) { - COPY_PIXEL(pixel0); // even count, high nibble - if (!--ch) { - break; - } - COPY_PIXEL(pixel1); // odd count, low nibble - if (!--ch) { - break; - } - } + return false; } + ch /= pixels_per_byte; + do { + COPY_PIXEL(pixel); + } while (--ch); } else { /* | A leading zero is an escape; it may signal the end of the bitmap, @@ -109,7 +107,7 @@ static bool readRlePixels(SDL_Surface *surface, SDL_IOStream *src, int isRle8) | zero tag may be absolute mode or an escape */ if (!SDL_ReadU8(src, &ch)) { - return true; + return false; } switch (ch) { case 0: // end of line @@ -117,47 +115,32 @@ static bool readRlePixels(SDL_Surface *surface, SDL_IOStream *src, int isRle8) bits -= pitch; // go to previous break; case 1: // end of bitmap - return false; // success! + return true; // success! case 2: // delta if (!SDL_ReadU8(src, &ch)) { - return true; + return false; } - ofs += ch; + ofs += ch / pixels_per_byte; + if (!SDL_ReadU8(src, &ch)) { - return true; + return false; } - bits -= (ch * pitch); + bits -= ((ch / pixels_per_byte) * pitch); break; default: // no compression - if (isRle8) { - needsPad = (ch & 1); - do { - Uint8 pixel; - if (!SDL_ReadU8(src, &pixel)) { - return true; - } - COPY_PIXEL(pixel); - } while (--ch); - } else { - needsPad = (((ch + 1) >> 1) & 1); // (ch+1)>>1: bytes size - for (;;) { - Uint8 pixel; - if (!SDL_ReadU8(src, &pixel)) { - return true; - } - COPY_PIXEL(pixel >> 4); - if (!--ch) { - break; - } - COPY_PIXEL(pixel & 0x0F); - if (!--ch) { - break; - } + ch /= pixels_per_byte; + needsPad = (ch & 1); + do { + Uint8 pixel; + if (!SDL_ReadU8(src, &pixel)) { + return false; } - } + COPY_PIXEL(pixel); + } while (--ch); + // pad at even boundary if (needsPad && !SDL_ReadU8(src, &ch)) { - return true; + return false; } break; } @@ -501,10 +484,13 @@ SDL_Surface *SDL_LoadBMP_IO(SDL_IOStream *src, bool closeio) goto done; } if ((biCompression == BI_RLE4) || (biCompression == BI_RLE8)) { - was_error = readRlePixels(surface, src, biCompression == BI_RLE8); - if (was_error) { + if (!readRlePixels(surface, src, biCompression == BI_RLE8)) { SDL_SetError("Error reading from datastream"); + goto done; } + + // Success! + was_error = false; goto done; } top = (Uint8 *)surface->pixels; @@ -637,6 +623,12 @@ bool SDL_SaveBMP_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio) Uint32 bV4GammaGreen = 0; Uint32 bV4GammaBlue = 0; + // The additional header members from the Win32 BITMAPV5HEADER struct (124 bytes in total) + Uint32 bV5Intent = 0; + Uint32 bV5ProfileData = 0; + Uint32 bV5ProfileSize = 0; + Uint32 bV5Reserved = 0; + // Make sure we have somewhere to save if (!SDL_SurfaceValid(surface)) { SDL_InvalidParamError("surface"); @@ -728,19 +720,25 @@ bool SDL_SaveBMP_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio) } biClrImportant = 0; - // Set the BMP info values for the version 4 header + // Set the BMP info values if (save32bit && !saveLegacyBMP) { - biSize = 108; + biSize = 124; + // Version 4 values biCompression = BI_BITFIELDS; // The BMP format is always little endian, these masks stay the same bV4RedMask = 0x00ff0000; bV4GreenMask = 0x0000ff00; bV4BlueMask = 0x000000ff; bV4AlphaMask = 0xff000000; - bV4CSType = LCS_WINDOWS_COLOR_SPACE; + bV4CSType = LCS_sRGB; bV4GammaRed = 0; bV4GammaGreen = 0; bV4GammaBlue = 0; + // Version 5 values + bV5Intent = LCS_GM_GRAPHICS; + bV5ProfileData = 0; + bV5ProfileSize = 0; + bV5Reserved = 0; } // Write the BMP info values @@ -758,8 +756,9 @@ bool SDL_SaveBMP_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio) goto done; } - // Write the BMP info values for the version 4 header + // Write the BMP info values if (save32bit && !saveLegacyBMP) { + // Version 4 values if (!SDL_WriteU32LE(dst, bV4RedMask) || !SDL_WriteU32LE(dst, bV4GreenMask) || !SDL_WriteU32LE(dst, bV4BlueMask) || @@ -777,6 +776,13 @@ bool SDL_SaveBMP_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio) !SDL_WriteU32LE(dst, bV4GammaBlue)) { goto done; } + // Version 5 values + if (!SDL_WriteU32LE(dst, bV5Intent) || + !SDL_WriteU32LE(dst, bV5ProfileData) || + !SDL_WriteU32LE(dst, bV5ProfileSize) || + !SDL_WriteU32LE(dst, bV5Reserved)) { + goto done; + } } // Write the palette (in BGR color order) diff --git a/libs/SDL3/src/video/SDL_egl.c b/libs/SDL3/src/video/SDL_egl.c index edeb033f..86502549 100644 --- a/libs/SDL3/src/video/SDL_egl.c +++ b/libs/SDL3/src/video/SDL_egl.c @@ -719,7 +719,7 @@ static void dumpconfig(SDL_VideoDevice *_this, EGLConfig config) for (attr = 0; attr < sizeof(all_attributes) / sizeof(Attribute); attr++) { EGLint value; _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display, config, all_attributes[attr].attribute, &value); - SDL_Log("\t%-32s: %10d (0x%08x)\n", all_attributes[attr].name, value, value); + SDL_Log("\t%-32s: %10d (0x%08x)", all_attributes[attr].name, value, value); } } diff --git a/libs/SDL3/src/video/SDL_pixels.c b/libs/SDL3/src/video/SDL_pixels.c index 1a1b59ca..5fede225 100644 --- a/libs/SDL3/src/video/SDL_pixels.c +++ b/libs/SDL3/src/video/SDL_pixels.c @@ -155,6 +155,7 @@ const char *SDL_GetPixelFormatName(SDL_PixelFormat format) CASE(SDL_PIXELFORMAT_NV21) CASE(SDL_PIXELFORMAT_P010) CASE(SDL_PIXELFORMAT_EXTERNAL_OES) + CASE(SDL_PIXELFORMAT_MJPG) default: return "SDL_PIXELFORMAT_UNKNOWN"; @@ -647,7 +648,7 @@ const SDL_PixelFormatDetails *SDL_GetPixelFormatDetails(SDL_PixelFormat format) SDL_PixelFormatDetails *details; if (SDL_ShouldInit(&SDL_format_details_init)) { - SDL_format_details = SDL_CreateHashTable(NULL, 8, SDL_HashID, SDL_KeyMatchID, SDL_NukeFreeValue, true, false); + SDL_format_details = SDL_CreateHashTable(0, true, SDL_HashID, SDL_KeyMatchID, SDL_DestroyHashValue, NULL); if (!SDL_format_details) { SDL_SetInitialized(&SDL_format_details_init, false); return NULL; @@ -670,9 +671,13 @@ const SDL_PixelFormatDetails *SDL_GetPixelFormatDetails(SDL_PixelFormat format) return NULL; } - if (!SDL_InsertIntoHashTable(SDL_format_details, (const void *)(uintptr_t)format, (void *)details)) { + if (!SDL_InsertIntoHashTable(SDL_format_details, (const void *)(uintptr_t)format, (void *)details, false)) { SDL_free(details); - return NULL; + // uh...did another thread beat us to inserting this? + if (SDL_FindInHashTable(SDL_format_details, (const void *)(uintptr_t)format, (const void **)&details)) { + return details; + } + return NULL; // oh well. } return details; @@ -690,7 +695,9 @@ void SDL_QuitPixelFormatDetails(void) SDL_Colorspace SDL_GetDefaultColorspaceForFormat(SDL_PixelFormat format) { if (SDL_ISPIXELFORMAT_FOURCC(format)) { - if (format == SDL_PIXELFORMAT_P010) { + if (format == SDL_PIXELFORMAT_MJPG) { + return SDL_COLORSPACE_SRGB; + } else if (format == SDL_PIXELFORMAT_P010) { return SDL_COLORSPACE_HDR10; } else { return SDL_COLORSPACE_YUV_DEFAULT; @@ -1130,7 +1137,7 @@ Uint8 SDL_LookupRGBAColor(SDL_HashTable *palette_map, Uint32 pixel, const SDL_Pa Uint8 b = (Uint8)((pixel >> 8) & 0xFF); Uint8 a = (Uint8)((pixel >> 0) & 0xFF); color_index = SDL_FindColor(pal, r, g, b, a); - SDL_InsertIntoHashTable(palette_map, (const void *)(uintptr_t)pixel, (const void *)(uintptr_t)color_index); + SDL_InsertIntoHashTable(palette_map, (const void *)(uintptr_t)pixel, (const void *)(uintptr_t)color_index, true); } return color_index; } @@ -1496,7 +1503,7 @@ bool SDL_MapSurface(SDL_Surface *src, SDL_Surface *dst) } else { if (SDL_ISPIXELFORMAT_INDEXED(dstfmt->format)) { // BitField --> Palette - map->info.palette_map = SDL_CreateHashTable(NULL, 32, SDL_HashID, SDL_KeyMatchID, NULL, false, false); + map->info.palette_map = SDL_CreateHashTable(0, false, SDL_HashID, SDL_KeyMatchID, NULL, NULL); } else { // BitField --> BitField if (srcfmt == dstfmt) { diff --git a/libs/SDL3/src/video/SDL_stb.c b/libs/SDL3/src/video/SDL_stb.c new file mode 100644 index 00000000..934c1add --- /dev/null +++ b/libs/SDL3/src/video/SDL_stb.c @@ -0,0 +1,121 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 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" + +#include "SDL_stb_c.h" + + +// We currently only support JPEG, but we could add other image formats if we wanted +#ifdef SDL_HAVE_STB +#define malloc SDL_malloc +#define realloc SDL_realloc +#define free SDL_free +#undef memcpy +#define memcpy SDL_memcpy +#undef memset +#define memset SDL_memset +#undef strcmp +#define strcmp SDL_strcmp +#undef strncmp +#define strncmp SDL_strncmp +#define strtol SDL_strtol + +#define abs SDL_abs +#define pow SDL_pow +#define ldexp SDL_scalbn + +#define STB_IMAGE_STATIC +#define STBI_NO_THREAD_LOCALS +#define STBI_FAILURE_USERMSG +#if defined(SDL_NEON_INTRINSICS) +#define STBI_NEON +#endif +#define STBI_ONLY_JPEG +#define STBI_NO_GIF +#define STBI_NO_PNG +#define STBI_NO_HDR +#define STBI_NO_LINEAR +#define STBI_NO_ZLIB +#define STBI_NO_STDIO +#define STBI_ASSERT SDL_assert +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" + +#undef memset +#endif + +#ifdef SDL_HAVE_STB +static bool SDL_ConvertPixels_MJPG_to_NV12(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) +{ + int w = 0, h = 0, format = 0; + stbi__context s; + stbi__start_mem(&s, src, src_pitch); + + stbi__result_info ri; + SDL_zero(ri); + ri.bits_per_channel = 8; + ri.channel_order = STBI_ORDER_RGB; + ri.num_channels = 0; + + stbi__nv12 nv12; + nv12.w = width; + nv12.h = height; + nv12.pitch = dst_pitch; + nv12.y = (stbi_uc *)dst; + nv12.uv = nv12.y + (nv12.h * nv12.pitch); + + void *pixels = stbi__jpeg_load(&s, &w, &h, &format, 4, &nv12, &ri); + if (!pixels) { + return false; + } + return true; +} +#endif // SDL_HAVE_STB + +bool SDL_ConvertPixels_STB(int width, int height, + SDL_PixelFormat src_format, SDL_Colorspace src_colorspace, SDL_PropertiesID src_properties, const void *src, int src_pitch, + SDL_PixelFormat dst_format, SDL_Colorspace dst_colorspace, SDL_PropertiesID dst_properties, void *dst, int dst_pitch) +{ +#ifdef SDL_HAVE_STB + if (src_format == SDL_PIXELFORMAT_MJPG && dst_format == SDL_PIXELFORMAT_NV12) { + return SDL_ConvertPixels_MJPG_to_NV12(width, height, src, src_pitch, dst, dst_pitch); + } + + bool result; + int w = 0, h = 0, format = 0; + int len = (src_format == SDL_PIXELFORMAT_MJPG) ? src_pitch : (height * src_pitch); + void *pixels = stbi_load_from_memory(src, len, &w, &h, &format, 4); + if (!pixels) { + return false; + } + + if (w == width && h == height) { + result = SDL_ConvertPixelsAndColorspace(w, h, SDL_PIXELFORMAT_RGBA32, SDL_COLORSPACE_SRGB, 0, pixels, width * 4, dst_format, dst_colorspace, dst_properties, dst, dst_pitch); + } else { + result = SDL_SetError("Expected image size %dx%d, actual size %dx%d", width, height, w, h); + } + stbi_image_free(pixels); + + return result; +#else + return SDL_SetError("SDL not built with STB image support"); +#endif +} diff --git a/libs/SDL3/src/video/SDL_stb_c.h b/libs/SDL3/src/video/SDL_stb_c.h new file mode 100644 index 00000000..bf8cc4da --- /dev/null +++ b/libs/SDL3/src/video/SDL_stb_c.h @@ -0,0 +1,31 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 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. +*/ + +#ifndef SDL_stb_c_h_ +#define SDL_stb_c_h_ + +#include "SDL_internal.h" + +// Image conversion functions + +extern bool SDL_ConvertPixels_STB(int width, int height, SDL_PixelFormat src_format, SDL_Colorspace src_colorspace, SDL_PropertiesID src_properties, const void *src, int src_pitch, SDL_PixelFormat dst_format, SDL_Colorspace dst_colorspace, SDL_PropertiesID dst_properties, void *dst, int dst_pitch); + +#endif // SDL_stb_c_h_ diff --git a/libs/SDL3/src/video/SDL_stretch.c b/libs/SDL3/src/video/SDL_stretch.c index acdc63bd..c893cc34 100644 --- a/libs/SDL3/src/video/SDL_stretch.c +++ b/libs/SDL3/src/video/SDL_stretch.c @@ -22,10 +22,10 @@ #include "SDL_surface_c.h" -static bool SDL_LowerSoftStretchNearest(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect); -static bool SDL_LowerSoftStretchLinear(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect); +static bool SDL_StretchSurfaceUncheckedNearest(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect); +static bool SDL_StretchSurfaceUncheckedLinear(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect); -bool SDL_SoftStretch(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect, SDL_ScaleMode scaleMode) +bool SDL_StretchSurface(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect, SDL_ScaleMode scaleMode) { bool result; int src_locked; @@ -46,7 +46,7 @@ bool SDL_SoftStretch(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst if (!src_tmp) { return false; } - result = SDL_SoftStretch(src_tmp, srcrect, dst, dstrect, scaleMode); + result = SDL_StretchSurface(src_tmp, srcrect, dst, dstrect, scaleMode); SDL_DestroySurface(src_tmp); return result; } @@ -64,7 +64,7 @@ bool SDL_SoftStretch(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst SDL_Surface *src_tmp = SDL_ConvertSurface(src, SDL_PIXELFORMAT_XRGB8888); SDL_Surface *dst_tmp = SDL_CreateSurface(dstrect->w, dstrect->h, SDL_PIXELFORMAT_XRGB8888); if (src_tmp && dst_tmp) { - result = SDL_SoftStretch(src_tmp, srcrect, dst_tmp, NULL, scaleMode); + result = SDL_StretchSurface(src_tmp, srcrect, dst_tmp, NULL, scaleMode); if (result) { result = SDL_ConvertPixelsAndColorspace(dstrect->w, dstrect->h, dst_tmp->format, SDL_COLORSPACE_SRGB, 0, @@ -152,9 +152,9 @@ bool SDL_SoftStretch(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst } if (scaleMode == SDL_SCALEMODE_NEAREST) { - result = SDL_LowerSoftStretchNearest(src, srcrect, dst, dstrect); + result = SDL_StretchSurfaceUncheckedNearest(src, srcrect, dst, dstrect); } else { - result = SDL_LowerSoftStretchLinear(src, srcrect, dst, dstrect); + result = SDL_StretchSurfaceUncheckedLinear(src, srcrect, dst, dstrect); } // We need to unlock the surfaces if they're locked @@ -825,7 +825,7 @@ static bool scale_mat_NEON(const Uint32 *src, int src_w, int src_h, int src_pitc } #endif -bool SDL_LowerSoftStretchLinear(SDL_Surface *s, const SDL_Rect *srcrect, SDL_Surface *d, const SDL_Rect *dstrect) +bool SDL_StretchSurfaceUncheckedLinear(SDL_Surface *s, const SDL_Rect *srcrect, SDL_Surface *d, const SDL_Rect *dstrect) { bool result = false; int src_w = srcrect->w; @@ -953,7 +953,7 @@ static bool scale_mat_nearest_4(const Uint32 *src_ptr, int src_w, int src_h, int return true; } -bool SDL_LowerSoftStretchNearest(SDL_Surface *s, const SDL_Rect *srcrect, SDL_Surface *d, const SDL_Rect *dstrect) +bool SDL_StretchSurfaceUncheckedNearest(SDL_Surface *s, const SDL_Rect *srcrect, SDL_Surface *d, const SDL_Rect *dstrect) { int src_w = srcrect->w; int src_h = srcrect->h; diff --git a/libs/SDL3/src/video/SDL_surface.c b/libs/SDL3/src/video/SDL_surface.c index 84db8bb4..945fda60 100644 --- a/libs/SDL3/src/video/SDL_surface.c +++ b/libs/SDL3/src/video/SDL_surface.c @@ -24,6 +24,7 @@ #include "SDL_video_c.h" #include "SDL_RLEaccel_c.h" #include "SDL_pixels_c.h" +#include "SDL_stb_c.h" #include "SDL_yuv_c.h" #include "../render/SDL_sysrender.h" @@ -1256,7 +1257,7 @@ bool SDL_BlitSurfaceUncheckedScaled(SDL_Surface *src, const SDL_Rect *srcrect, S src->format == dst->format && !SDL_ISPIXELFORMAT_INDEXED(src->format) && SDL_BYTESPERPIXEL(src->format) <= 4) { - return SDL_SoftStretch(src, srcrect, dst, dstrect, SDL_SCALEMODE_NEAREST); + return SDL_StretchSurface(src, srcrect, dst, dstrect, SDL_SCALEMODE_NEAREST); } else if (SDL_BITSPERPIXEL(src->format) < 8) { // Scaling bitmap not yet supported, convert to RGBA for blit bool result = false; @@ -1276,7 +1277,7 @@ bool SDL_BlitSurfaceUncheckedScaled(SDL_Surface *src, const SDL_Rect *srcrect, S SDL_BYTESPERPIXEL(src->format) == 4 && src->format != SDL_PIXELFORMAT_ARGB2101010) { // fast path - return SDL_SoftStretch(src, srcrect, dst, dstrect, SDL_SCALEMODE_LINEAR); + return SDL_StretchSurface(src, srcrect, dst, dstrect, SDL_SCALEMODE_LINEAR); } else if (SDL_BITSPERPIXEL(src->format) < 8) { // Scaling bitmap not yet supported, convert to RGBA for blit bool result = false; @@ -1335,7 +1336,7 @@ bool SDL_BlitSurfaceUncheckedScaled(SDL_Surface *src, const SDL_Rect *srcrect, S if (is_complex_copy_flags || src->format != dst->format) { SDL_Rect tmprect; SDL_Surface *tmp2 = SDL_CreateSurface(dstrect->w, dstrect->h, src->format); - SDL_SoftStretch(src, &srcrect2, tmp2, NULL, SDL_SCALEMODE_LINEAR); + SDL_StretchSurface(src, &srcrect2, tmp2, NULL, SDL_SCALEMODE_LINEAR); SDL_SetSurfaceColorMod(tmp2, r, g, b); SDL_SetSurfaceAlphaMod(tmp2, alpha); @@ -1348,7 +1349,7 @@ bool SDL_BlitSurfaceUncheckedScaled(SDL_Surface *src, const SDL_Rect *srcrect, S result = SDL_BlitSurfaceUnchecked(tmp2, &tmprect, dst, dstrect); SDL_DestroySurface(tmp2); } else { - result = SDL_SoftStretch(src, &srcrect2, dst, dstrect, SDL_SCALEMODE_LINEAR); + result = SDL_StretchSurface(src, &srcrect2, dst, dstrect, SDL_SCALEMODE_LINEAR); } SDL_DestroySurface(tmp1); @@ -2277,6 +2278,10 @@ bool SDL_ConvertPixelsAndColorspace(int width, int height, dst_colorspace = SDL_GetDefaultColorspaceForFormat(dst_format); } + if (src_format == SDL_PIXELFORMAT_MJPG) { + return SDL_ConvertPixels_STB(width, height, src_format, src_colorspace, src_properties, src, src_pitch, dst_format, dst_colorspace, dst_properties, dst, dst_pitch); + } + #ifdef SDL_HAVE_YUV if (SDL_ISPIXELFORMAT_FOURCC(src_format) && SDL_ISPIXELFORMAT_FOURCC(dst_format)) { return SDL_ConvertPixels_YUV_to_YUV(width, height, src_format, src_colorspace, src_properties, src, src_pitch, dst_format, dst_colorspace, dst_properties, dst, dst_pitch); @@ -2293,13 +2298,17 @@ bool SDL_ConvertPixelsAndColorspace(int width, int height, // Fast path for same format copy if (src_format == dst_format && src_colorspace == dst_colorspace) { - int i; - const int bpp = SDL_BYTESPERPIXEL(src_format); - width *= bpp; - for (i = height; i--;) { - SDL_memcpy(dst, src, width); - src = (const Uint8 *)src + src_pitch; - dst = (Uint8 *)dst + dst_pitch; + if (src_pitch == dst_pitch) { + SDL_memcpy(dst, src, height * src_pitch); + } else { + int i; + const int bpp = SDL_BYTESPERPIXEL(src_format); + width *= bpp; + for (i = height; i--;) { + SDL_memcpy(dst, src, width); + src = (const Uint8 *)src + src_pitch; + dst = (Uint8 *)dst + dst_pitch; + } } return true; } diff --git a/libs/SDL3/src/video/SDL_surface_c.h b/libs/SDL3/src/video/SDL_surface_c.h index 1dc430f5..27dc88a6 100644 --- a/libs/SDL3/src/video/SDL_surface_c.h +++ b/libs/SDL3/src/video/SDL_surface_c.h @@ -88,6 +88,5 @@ extern float SDL_GetSurfaceSDRWhitePoint(SDL_Surface *surface, SDL_Colorspace co extern float SDL_GetDefaultHDRHeadroom(SDL_Colorspace colorspace); extern float SDL_GetSurfaceHDRHeadroom(SDL_Surface *surface, SDL_Colorspace colorspace); extern SDL_Surface *SDL_GetSurfaceImage(SDL_Surface *surface, float display_scale); -extern bool SDL_SoftStretch(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect, SDL_ScaleMode scaleMode); #endif // SDL_surface_c_h_ diff --git a/libs/SDL3/src/video/SDL_sysvideo.h b/libs/SDL3/src/video/SDL_sysvideo.h index 418b8239..6951d456 100644 --- a/libs/SDL3/src/video/SDL_sysvideo.h +++ b/libs/SDL3/src/video/SDL_sysvideo.h @@ -124,6 +124,9 @@ struct SDL_Window SDL_PropertiesID props; + int num_renderers; + SDL_Renderer **renderers; + SDL_WindowData *internal; SDL_Window *prev; @@ -501,6 +504,7 @@ typedef struct VideoBootStrap const char *desc; SDL_VideoDevice *(*create)(void); bool (*ShowMessageBox)(const SDL_MessageBoxData *messageboxdata, int *buttonID); // can be done without initializing backend! + bool is_preferred; } VideoBootStrap; // Not all of these are available in a given build. Use #ifdefs, etc. diff --git a/libs/SDL3/src/video/SDL_video.c b/libs/SDL3/src/video/SDL_video.c index 80b1bb02..3a400d81 100644 --- a/libs/SDL3/src/video/SDL_video.c +++ b/libs/SDL3/src/video/SDL_video.c @@ -334,6 +334,9 @@ static bool SDL_CreateWindowTexture(SDL_VideoDevice *_this, SDL_Window *window, if (!render_driver) { render_driver = SDL_GetHint(SDL_HINT_RENDER_DRIVER); } + if (render_driver && SDL_strcasecmp(render_driver, SDL_SOFTWARE_RENDERER) == 0) { + render_driver = NULL; + } char *render_driver_copy = NULL; if (render_driver && *render_driver) { @@ -593,6 +596,7 @@ const char *SDL_GetVideoDriver(int index) if (index >= 0 && index < SDL_GetNumVideoDrivers()) { return deduped_bootstrap[index]->name; } + SDL_InvalidParamError("index"); return NULL; } @@ -651,7 +655,8 @@ bool SDL_VideoInit(const char *driver_name) : SDL_strlen(driver_attempt); for (i = 0; bootstrap[i]; ++i) { - if ((driver_attempt_len == SDL_strlen(bootstrap[i]->name)) && + if (!bootstrap[i]->is_preferred && + (driver_attempt_len == SDL_strlen(bootstrap[i]->name)) && (SDL_strncasecmp(bootstrap[i]->name, driver_attempt, driver_attempt_len) == 0)) { video = bootstrap[i]->create(); if (video) { @@ -2151,7 +2156,7 @@ void SDL_ToggleDragAndDropSupport(void) } } -SDL_Window **SDLCALL SDL_GetWindows(int *count) +SDL_Window ** SDLCALL SDL_GetWindows(int *count) { if (count) { *count = 0; @@ -2762,9 +2767,16 @@ bool SDL_SetWindowTitle(SDL_Window *window, const char *title) if (title == window->title) { return true; } + if (!title) { + title = ""; + } + if (window->title && SDL_strcmp(title, window->title) == 0) { + return true; + } + SDL_free(window->title); - window->title = SDL_strdup(title ? title : ""); + window->title = SDL_strdup(title); if (_this->SetWindowTitle) { _this->SetWindowTitle(_this, window); @@ -4129,6 +4141,31 @@ SDL_Window *SDL_GetToplevelForKeyboardFocus(void) return focus; } +bool SDL_AddWindowRenderer(SDL_Window *window, SDL_Renderer *renderer) +{ + SDL_Renderer **renderers = (SDL_Renderer **)SDL_realloc(window->renderers, (window->num_renderers + 1) * sizeof(*renderers)); + if (!renderers) { + return false; + } + + window->renderers = renderers; + window->renderers[window->num_renderers++] = renderer; + return true; +} + +void SDL_RemoveWindowRenderer(SDL_Window *window, SDL_Renderer *renderer) +{ + for (int i = 0; i < window->num_renderers; ++i) { + if (window->renderers[i] == renderer) { + if (i < (window->num_renderers - 1)) { + SDL_memmove(&window->renderers[i], &window->renderers[i + 1], (window->num_renderers - i - 1) * sizeof(window->renderers[i])); + } + --window->num_renderers; + break; + } + } +} + void SDL_DestroyWindow(SDL_Window *window) { CHECK_WINDOW_MAGIC(window,); @@ -4235,6 +4272,7 @@ void SDL_DestroyWindow(SDL_Window *window) _this->windows = window->next; } + SDL_free(window->renderers); SDL_free(window); #ifdef SDL_VIDEO_DRIVER_UIKIT @@ -4291,7 +4329,9 @@ void SDL_VideoQuit(void) } // Halt event processing before doing anything else +#if 0 // This was moved to the end to fix a memory leak SDL_QuitPen(); +#endif SDL_QuitTouch(); SDL_QuitMouse(); SDL_QuitKeyboard(); @@ -4322,6 +4362,9 @@ void SDL_VideoQuit(void) } _this->free(_this); _this = NULL; + + // This needs to happen after the video subsystem has removed pen data + SDL_QuitPen(); } bool SDL_GL_LoadLibrary(const char *path) diff --git a/libs/SDL3/src/video/SDL_video_c.h b/libs/SDL3/src/video/SDL_video_c.h index b3f4350a..fc0843b1 100644 --- a/libs/SDL3/src/video/SDL_video_c.h +++ b/libs/SDL3/src/video/SDL_video_c.h @@ -63,4 +63,7 @@ extern bool SDL_SetWindowTextureVSync(struct SDL_VideoDevice *_this, SDL_Window const char *SDL_GetCSSCursorName(SDL_SystemCursor id, const char **fallback_name); #endif +extern bool SDL_AddWindowRenderer(SDL_Window *window, SDL_Renderer *renderer); +extern void SDL_RemoveWindowRenderer(SDL_Window *window, SDL_Renderer *renderer); + #endif // SDL_video_c_h_ diff --git a/libs/SDL3/src/video/SDL_yuv.c b/libs/SDL3/src/video/SDL_yuv.c index da8116e9..ccacfcf4 100644 --- a/libs/SDL3/src/video/SDL_yuv.c +++ b/libs/SDL3/src/video/SDL_yuv.c @@ -921,7 +921,7 @@ static bool SDL_ConvertPixels_XRGB8888_to_YUV(int width, int height, const void int plane_skip; if (dst_pitch < row_size) { - return SDL_SetError("Destination pitch is too small, expected at least %d\n", row_size); + return SDL_SetError("Destination pitch is too small, expected at least %d", row_size); } plane_skip = (dst_pitch - row_size); diff --git a/libs/SDL3/src/video/android/SDL_androidvideo.c b/libs/SDL3/src/video/android/SDL_androidvideo.c index ed8106aa..b154ff73 100644 --- a/libs/SDL3/src/video/android/SDL_androidvideo.c +++ b/libs/SDL3/src/video/android/SDL_androidvideo.c @@ -157,7 +157,8 @@ static SDL_VideoDevice *Android_CreateDevice(void) VideoBootStrap Android_bootstrap = { ANDROID_VID_DRIVER_NAME, "SDL Android video driver", Android_CreateDevice, - Android_ShowMessageBox + Android_ShowMessageBox, + false }; bool Android_VideoInit(SDL_VideoDevice *_this) diff --git a/libs/SDL3/src/video/cocoa/SDL_cocoakeyboard.m b/libs/SDL3/src/video/cocoa/SDL_cocoakeyboard.m index 550f533f..e458be94 100644 --- a/libs/SDL3/src/video/cocoa/SDL_cocoakeyboard.m +++ b/libs/SDL3/src/video/cocoa/SDL_cocoakeyboard.m @@ -30,8 +30,11 @@ #include -// #define DEBUG_IME NSLog +#if 0 +#define DEBUG_IME NSLog +#else #define DEBUG_IME(...) +#endif @interface SDL3TranslatorResponder : NSView { @@ -133,8 +136,12 @@ // This key event was consumed by the IME [self clearPendingKey]; + NSUInteger utf32SelectedRangeLocation = [[aString substringToIndex:selectedRange.location] lengthOfBytesUsingEncoding:NSUTF32StringEncoding] / 4; + NSUInteger utf32SelectionRangeEnd = [[aString substringToIndex:(selectedRange.location + selectedRange.length)] lengthOfBytesUsingEncoding:NSUTF32StringEncoding] / 4; + NSUInteger utf32SelectionRangeLength = utf32SelectionRangeEnd - utf32SelectedRangeLocation; + SDL_SendEditingText([aString UTF8String], - (int)selectedRange.location, (int)selectedRange.length); + (int)utf32SelectedRangeLocation, (int)utf32SelectionRangeLength); DEBUG_IME(@"setMarkedText: %@, (%d, %d) replacement range (%d, %d)", _markedText, (int)selectedRange.location, (int)selectedRange.length, @@ -540,7 +547,7 @@ void Cocoa_HandleKeyEvent(SDL_VideoDevice *_this, NSEvent *event) #ifdef DEBUG_SCANCODES if (code == SDL_SCANCODE_UNKNOWN) { - SDL_Log("The key you just pressed is not recognized by SDL. To help get this fixed, report this to the SDL forums/mailing list or to Christian Walther . Mac virtual key code is %d.\n", scancode); + SDL_Log("The key you just pressed is not recognized by SDL. To help get this fixed, report this to the SDL forums/mailing list or to Christian Walther . Mac virtual key code is %d.", scancode); } #endif if (SDL_TextInputActive(SDL_GetKeyboardFocus())) { diff --git a/libs/SDL3/src/video/cocoa/SDL_cocoametalview.m b/libs/SDL3/src/video/cocoa/SDL_cocoametalview.m index d8566451..af84e935 100644 --- a/libs/SDL3/src/video/cocoa/SDL_cocoametalview.m +++ b/libs/SDL3/src/video/cocoa/SDL_cocoametalview.m @@ -26,6 +26,8 @@ */ #include "SDL_internal.h" +#include "../../events/SDL_windowevents_c.h" + #import "SDL_cocoametalview.h" #if defined(SDL_VIDEO_DRIVER_COCOA) && (defined(SDL_VIDEO_VULKAN) || defined(SDL_VIDEO_METAL)) @@ -88,7 +90,7 @@ static bool SDLCALL SDL_MetalViewEventWatch(void *userdata, SDL_Event *event) self.layer.opaque = opaque; - SDL_AddEventWatch(SDL_MetalViewEventWatch, (__bridge void *)(self)); + SDL_AddWindowEventWatch(SDL_WINDOW_EVENT_WATCH_EARLY, SDL_MetalViewEventWatch, (__bridge void *)(self)); [self updateDrawableSize]; } @@ -98,7 +100,7 @@ static bool SDLCALL SDL_MetalViewEventWatch(void *userdata, SDL_Event *event) - (void)dealloc { - SDL_RemoveEventWatch(SDL_MetalViewEventWatch, (__bridge void *)(self)); + SDL_RemoveWindowEventWatch(SDL_WINDOW_EVENT_WATCH_EARLY, SDL_MetalViewEventWatch, (__bridge void *)(self)); } - (NSInteger)tag diff --git a/libs/SDL3/src/video/cocoa/SDL_cocoamouse.m b/libs/SDL3/src/video/cocoa/SDL_cocoamouse.m index 77ebf109..530ca0c8 100644 --- a/libs/SDL3/src/video/cocoa/SDL_cocoamouse.m +++ b/libs/SDL3/src/video/cocoa/SDL_cocoamouse.m @@ -447,13 +447,23 @@ void Cocoa_HandleMouseEvent(SDL_VideoDevice *_this, NSEvent *event) float deltaX, deltaY; bool seenWarp; - switch ([event type]) { - case NSEventTypeMouseEntered: - Cocoa_MouseFocus = [event window]; - return; - case NSEventTypeMouseExited: + // All events except NSEventTypeMouseExited can only happen if the window + // has mouse focus, so we'll always set the focus even if we happen to miss + // NSEventTypeMouseEntered, which apparently happens if the window is + // created under the mouse on macOS 12.7 + NSEventType event_type = [event type]; + if (event_type == NSEventTypeMouseExited) { Cocoa_MouseFocus = NULL; + } else { + Cocoa_MouseFocus = [event window]; + } + + switch (event_type) { + case NSEventTypeMouseEntered: + case NSEventTypeMouseExited: + // Focus is handled above return; + case NSEventTypeMouseMoved: case NSEventTypeLeftMouseDragged: case NSEventTypeRightMouseDragged: diff --git a/libs/SDL3/src/video/cocoa/SDL_cocoapen.m b/libs/SDL3/src/video/cocoa/SDL_cocoapen.m index 35fe7926..6c30bfb1 100644 --- a/libs/SDL3/src/video/cocoa/SDL_cocoapen.m +++ b/libs/SDL3/src/video/cocoa/SDL_cocoapen.m @@ -135,7 +135,7 @@ static void Cocoa_HandlePenPointEvent(SDL_CocoaWindowData *_data, NSEvent *event SDL_SendPenAxis(timestamp, pen, window, SDL_PEN_AXIS_PRESSURE, [event pressure]); SDL_SendPenAxis(timestamp, pen, window, SDL_PEN_AXIS_ROTATION, [event rotation]); SDL_SendPenAxis(timestamp, pen, window, SDL_PEN_AXIS_XTILT, ((float) tilt.x) * 90.0f); - SDL_SendPenAxis(timestamp, pen, window, SDL_PEN_AXIS_YTILT, ((float) tilt.y) * 90.0f); + SDL_SendPenAxis(timestamp, pen, window, SDL_PEN_AXIS_YTILT, ((float) -tilt.y) * 90.0f); SDL_SendPenAxis(timestamp, pen, window, SDL_PEN_AXIS_TANGENTIAL_PRESSURE, event.tangentialPressure); } diff --git a/libs/SDL3/src/video/cocoa/SDL_cocoavideo.m b/libs/SDL3/src/video/cocoa/SDL_cocoavideo.m index aae54eba..81baf782 100644 --- a/libs/SDL3/src/video/cocoa/SDL_cocoavideo.m +++ b/libs/SDL3/src/video/cocoa/SDL_cocoavideo.m @@ -195,7 +195,8 @@ static SDL_VideoDevice *Cocoa_CreateDevice(void) VideoBootStrap COCOA_bootstrap = { "cocoa", "SDL Cocoa video driver", Cocoa_CreateDevice, - Cocoa_ShowMessageBox + Cocoa_ShowMessageBox, + false }; static bool Cocoa_VideoInit(SDL_VideoDevice *_this) diff --git a/libs/SDL3/src/video/cocoa/SDL_cocoawindow.m b/libs/SDL3/src/video/cocoa/SDL_cocoawindow.m index 06ba56ad..8ed3bcc9 100644 --- a/libs/SDL3/src/video/cocoa/SDL_cocoawindow.m +++ b/libs/SDL3/src/video/cocoa/SDL_cocoawindow.m @@ -411,6 +411,27 @@ bool Cocoa_IsWindowInFullscreenSpace(SDL_Window *window) } } +bool Cocoa_IsWindowZoomed(SDL_Window *window) +{ + SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; + NSWindow *nswindow = data.nswindow; + bool zoomed = false; + + // isZoomed always returns true if the window is not resizable or the window is fullscreen + if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed] && + !(window->flags & SDL_WINDOW_FULLSCREEN) && !Cocoa_IsWindowInFullscreenSpace(window)) { + // If we are at our desired floating area, then we're not zoomed + bool floating = (window->x == window->floating.x && + window->y == window->floating.y && + window->w == window->floating.w && + window->h == window->floating.h); + if (!floating) { + zoomed = true; + } + } + return zoomed; +} + typedef enum CocoaMenuVisibility { COCOA_MENU_VISIBILITY_AUTO = 0, @@ -692,7 +713,7 @@ static void Cocoa_SetKeyboardFocus(SDL_Window *window, bool set_active_focus) toplevel_data.keyboard_focus = window; if (set_active_focus && !window->is_hiding && !window->is_destroying) { - SDL_SetKeyboardFocus(window); + SDL_SetKeyboardFocus(window); } } @@ -1172,7 +1193,7 @@ static NSCursor *Cocoa_GetDesiredCursor(void) } if (!zoomed) { SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESTORED, 0, 0); - } else if (zoomed) { + } else { SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_MAXIMIZED, 0, 0); if ([self windowOperationIsPending:PENDING_OPERATION_MINIMIZE]) { [nswindow miniaturize:nil]; @@ -1208,8 +1229,7 @@ static NSCursor *Cocoa_GetDesiredCursor(void) // Always send restored before maximized. SDL_SendWindowEvent(_data.window, SDL_EVENT_WINDOW_RESTORED, 0, 0); - // isZoomed always returns true if the window is not resizable. - if ((_data.window->flags & SDL_WINDOW_RESIZABLE) && [_data.nswindow isZoomed]) { + if (Cocoa_IsWindowZoomed(_data.window)) { SDL_SendWindowEvent(_data.window, SDL_EVENT_WINDOW_MAXIMIZED, 0, 0); } @@ -2469,30 +2489,24 @@ void Cocoa_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window) return; } - // isZoomed always returns true if the window is not resizable - if (!(window->flags & SDL_WINDOW_RESIZABLE) || ![nswindow isZoomed]) { - if (!(window->flags & SDL_WINDOW_FULLSCREEN)) { - int x, y; - NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]]; + if (!Cocoa_IsWindowZoomed(window)) { + int x, y; + NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]]; - /* Cocoa will resize the window from the bottom-left rather than the - * top-left when -[nswindow setContentSize:] is used, so we must set the - * entire frame based on the new size, in order to preserve the position. - */ - SDL_RelativeToGlobalForWindow(window, window->floating.x, window->floating.y, &x, &y); - rect.origin.x = x; - rect.origin.y = y; - rect.size.width = window->pending.w; - rect.size.height = window->pending.h; - ConvertNSRect(&rect); + /* Cocoa will resize the window from the bottom-left rather than the + * top-left when -[nswindow setContentSize:] is used, so we must set the + * entire frame based on the new size, in order to preserve the position. + */ + SDL_RelativeToGlobalForWindow(window, window->floating.x, window->floating.y, &x, &y); + rect.origin.x = x; + rect.origin.y = y; + rect.size.width = window->pending.w; + rect.size.height = window->pending.h; + ConvertNSRect(&rect); - [nswindow setFrame:[nswindow frameRectForContentRect:rect] display:YES]; - ScheduleContextUpdates(windata); - } else { - // Can't set the window size. - window->last_size_pending = false; - } - } else { + [nswindow setFrame:[nswindow frameRectForContentRect:rect] display:YES]; + ScheduleContextUpdates(windata); + } else { // Can't set the window size. window->last_size_pending = false; } @@ -2741,7 +2755,7 @@ void Cocoa_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window) ![data.listener isInFullscreenSpace]) { if ([nswindow isMiniaturized]) { [nswindow deminiaturize:nil]; - } else if ((window->flags & SDL_WINDOW_RESIZABLE) && [data.nswindow isZoomed]) { + } else if (Cocoa_IsWindowZoomed(window)) { [nswindow zoom:nil]; } } else if (data.was_zoomed) { @@ -2767,6 +2781,7 @@ void Cocoa_SetWindowBordered(SDL_VideoDevice *_this, SDL_Window *window, bool bo } else { data.border_toggled = true; } + Cocoa_UpdateClipCursor(window); } } diff --git a/libs/SDL3/src/video/dummy/SDL_nullvideo.c b/libs/SDL3/src/video/dummy/SDL_nullvideo.c index e5525a63..7be4ae1c 100644 --- a/libs/SDL3/src/video/dummy/SDL_nullvideo.c +++ b/libs/SDL3/src/video/dummy/SDL_nullvideo.c @@ -121,7 +121,8 @@ static SDL_VideoDevice *DUMMY_CreateDevice(void) VideoBootStrap DUMMY_bootstrap = { DUMMYVID_DRIVER_NAME, "SDL dummy video driver", DUMMY_CreateDevice, - NULL // no ShowMessageBox implementation + NULL, // no ShowMessageBox implementation + false }; #ifdef SDL_INPUT_LINUXEV @@ -144,7 +145,8 @@ static SDL_VideoDevice *DUMMY_EVDEV_CreateDevice(void) VideoBootStrap DUMMY_evdev_bootstrap = { DUMMYVID_DRIVER_EVDEV_NAME, "SDL dummy video driver with evdev", DUMMY_EVDEV_CreateDevice, - NULL // no ShowMessageBox implementation + NULL, // no ShowMessageBox implementation + false }; #endif // SDL_INPUT_LINUXEV diff --git a/libs/SDL3/src/video/emscripten/SDL_emscriptenevents.c b/libs/SDL3/src/video/emscripten/SDL_emscriptenevents.c index de9ec57a..49a140f3 100644 --- a/libs/SDL3/src/video/emscripten/SDL_emscriptenevents.c +++ b/libs/SDL3/src/video/emscripten/SDL_emscriptenevents.c @@ -1095,11 +1095,11 @@ void Emscripten_UnregisterEventHandlers(SDL_WindowData *data) emscripten_set_pointerlockchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, NULL, 0, NULL); target = SDL_GetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT); - if (!target) { + if (!target || !*target) { target = EMSCRIPTEN_EVENT_TARGET_WINDOW; } - if (*target) { + if (SDL_strcmp(target, "#none") != 0) { emscripten_set_keydown_callback(target, NULL, 0, NULL); emscripten_set_keyup_callback(target, NULL, 0, NULL); emscripten_set_keypress_callback(target, NULL, 0, NULL); diff --git a/libs/SDL3/src/video/emscripten/SDL_emscriptenvideo.c b/libs/SDL3/src/video/emscripten/SDL_emscriptenvideo.c index 413d96fc..14962686 100644 --- a/libs/SDL3/src/video/emscripten/SDL_emscriptenvideo.c +++ b/libs/SDL3/src/video/emscripten/SDL_emscriptenvideo.c @@ -195,7 +195,8 @@ static SDL_VideoDevice *Emscripten_CreateDevice(void) VideoBootStrap Emscripten_bootstrap = { EMSCRIPTENVID_DRIVER_NAME, "SDL emscripten video driver", Emscripten_CreateDevice, - NULL // no ShowMessageBox implementation + NULL, // no ShowMessageBox implementation + false }; bool Emscripten_VideoInit(SDL_VideoDevice *_this) diff --git a/libs/SDL3/src/video/haiku/SDL_bvideo.cc b/libs/SDL3/src/video/haiku/SDL_bvideo.cc index 9669dd47..d7f9e7c8 100644 --- a/libs/SDL3/src/video/haiku/SDL_bvideo.cc +++ b/libs/SDL3/src/video/haiku/SDL_bvideo.cc @@ -113,7 +113,8 @@ static SDL_VideoDevice * HAIKU_CreateDevice(void) VideoBootStrap HAIKU_bootstrap = { "haiku", "Haiku graphics", HAIKU_CreateDevice, - HAIKU_ShowMessageBox + HAIKU_ShowMessageBox, + false }; void HAIKU_DeleteDevice(SDL_VideoDevice * device) @@ -240,6 +241,9 @@ static bool HAIKU_SetRelativeMouseMode(bool enabled) SDL_BWin *bewin = _ToBeWin(window); BGLView *_SDL_GLView = bewin->GetGLView(); + if (!_SDL_GLView) { + return false; + } bewin->Lock(); if (enabled) diff --git a/libs/SDL3/src/video/kmsdrm/SDL_kmsdrmdyn.c b/libs/SDL3/src/video/kmsdrm/SDL_kmsdrmdyn.c index 467fb27f..a532ceaf 100644 --- a/libs/SDL3/src/video/kmsdrm/SDL_kmsdrmdyn.c +++ b/libs/SDL3/src/video/kmsdrm/SDL_kmsdrmdyn.c @@ -59,9 +59,9 @@ static void *KMSDRM_GetSym(const char *fnname, int *pHasModule, bool required) #if DEBUG_DYNAMIC_KMSDRM if (fn) - SDL_Log("KMSDRM: Found '%s' in %s (%p)\n", fnname, kmsdrmlibs[i].libname, fn); + SDL_Log("KMSDRM: Found '%s' in %s (%p)", fnname, kmsdrmlibs[i].libname, fn); else - SDL_Log("KMSDRM: Symbol '%s' NOT FOUND!\n", fnname); + SDL_Log("KMSDRM: Symbol '%s' NOT FOUND!", fnname); #endif if (!fn && required) { diff --git a/libs/SDL3/src/video/kmsdrm/SDL_kmsdrmvideo.c b/libs/SDL3/src/video/kmsdrm/SDL_kmsdrmvideo.c index 1d25b8d0..be1db82b 100644 --- a/libs/SDL3/src/video/kmsdrm/SDL_kmsdrmvideo.c +++ b/libs/SDL3/src/video/kmsdrm/SDL_kmsdrmvideo.c @@ -163,7 +163,7 @@ static int get_driindex(void) close(drm_fd); } else { SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, - "Failed to open KMSDRM device %s, errno: %d\n", device, errno); + "Failed to open KMSDRM device %s, errno: %d", device, errno); } } } @@ -332,7 +332,8 @@ VideoBootStrap KMSDRM_bootstrap = { "kmsdrm", "KMS/DRM Video Driver", KMSDRM_CreateDevice, - NULL // no ShowMessageBox implementation + NULL, // no ShowMessageBox implementation + false }; static void KMSDRM_FBDestroyCallback(struct gbm_bo *bo, void *data) diff --git a/libs/SDL3/src/video/kmsdrm/SDL_kmsdrmvulkan.c b/libs/SDL3/src/video/kmsdrm/SDL_kmsdrmvulkan.c index dd50d39e..d58277b7 100644 --- a/libs/SDL3/src/video/kmsdrm/SDL_kmsdrmvulkan.c +++ b/libs/SDL3/src/video/kmsdrm/SDL_kmsdrmvulkan.c @@ -328,7 +328,7 @@ bool KMSDRM_Vulkan_CreateSurface(SDL_VideoDevice *_this, &mode_count, NULL); if (mode_count == 0) { - SDL_SetError("Vulkan can't find any video modes for display %i (%s)\n", 0, + SDL_SetError("Vulkan can't find any video modes for display %i (%s)", 0, display_props[display_index].displayName); goto clean; } diff --git a/libs/SDL3/src/video/n3ds/SDL_n3dsvideo.c b/libs/SDL3/src/video/n3ds/SDL_n3dsvideo.c index 21982797..8e925bf4 100644 --- a/libs/SDL3/src/video/n3ds/SDL_n3dsvideo.c +++ b/libs/SDL3/src/video/n3ds/SDL_n3dsvideo.c @@ -118,7 +118,7 @@ static SDL_VideoDevice *N3DS_CreateDevice(void) return device; } -VideoBootStrap N3DS_bootstrap = { N3DSVID_DRIVER_NAME, "N3DS Video Driver", N3DS_CreateDevice, NULL /* no ShowMessageBox implementation */ }; +VideoBootStrap N3DS_bootstrap = { N3DSVID_DRIVER_NAME, "N3DS Video Driver", N3DS_CreateDevice, NULL, /* no ShowMessageBox implementation */ false }; static bool N3DS_VideoInit(SDL_VideoDevice *_this) { diff --git a/libs/SDL3/src/video/offscreen/SDL_offscreenvideo.c b/libs/SDL3/src/video/offscreen/SDL_offscreenvideo.c index bcd4ffe6..1ef0f9ea 100644 --- a/libs/SDL3/src/video/offscreen/SDL_offscreenvideo.c +++ b/libs/SDL3/src/video/offscreen/SDL_offscreenvideo.c @@ -118,7 +118,8 @@ static SDL_VideoDevice *OFFSCREEN_CreateDevice(void) VideoBootStrap OFFSCREEN_bootstrap = { OFFSCREENVID_DRIVER_NAME, "SDL offscreen video driver", OFFSCREEN_CreateDevice, - NULL // no ShowMessageBox implementation + NULL, // no ShowMessageBox implementation + false }; static bool OFFSCREEN_VideoInit(SDL_VideoDevice *_this) diff --git a/libs/SDL3/src/video/openvr/SDL_openvrvideo.c b/libs/SDL3/src/video/openvr/SDL_openvrvideo.c index 271ce93c..6387c374 100644 --- a/libs/SDL3/src/video/openvr/SDL_openvrvideo.c +++ b/libs/SDL3/src/video/openvr/SDL_openvrvideo.c @@ -661,7 +661,7 @@ static bool OPENVR_SetupFrame(SDL_VideoDevice *_this, SDL_Window *window) { int error = ov_glGetError(); if (error) - SDL_Log("Found GL Error before beginning frame: %d / (Framebuffer:%d)\n", error, ov_glCheckNamedFramebufferStatus(videodata->fbo, GL_FRAMEBUFFER)); + SDL_Log("Found GL Error before beginning frame: %d / (Framebuffer:%d)", error, ov_glCheckNamedFramebufferStatus(videodata->fbo, GL_FRAMEBUFFER)); } #endif @@ -698,7 +698,7 @@ static bool OPENVR_ReleaseFrame(SDL_VideoDevice *_this) { int error = ov_glGetError(); if (error) { - SDL_Log("Found GL Error before release frame: %d / (Framebuffer:%d)\n", error, ov_glCheckNamedFramebufferStatus(videodata->fbo, GL_FRAMEBUFFER)); + SDL_Log("Found GL Error before release frame: %d / (Framebuffer:%d)", error, ov_glCheckNamedFramebufferStatus(videodata->fbo, GL_FRAMEBUFFER)); } } #endif @@ -895,7 +895,7 @@ static SDL_GLContext OPENVR_GL_CreateContext(SDL_VideoDevice *_this, SDL_Window const char *ccc = (const char *)ov_glGetStringi(GL_EXTENSIONS, i); if (SDL_strcmp(ccc, "GL_KHR_debug") == 0) { #ifdef DEBUG_OPENVR - SDL_Log("Found renderdoc debug extension.\n"); + SDL_Log("Found renderdoc debug extension."); #endif videodata->renderdoc_debugmarker_frame_end = true; } @@ -911,7 +911,7 @@ static SDL_GLContext OPENVR_GL_CreateContext(SDL_VideoDevice *_this, SDL_Window OPENVR_SetupFrame(_this, window); - SDL_GLContext result = malloc(sizeof(struct SDL_GLContextState)); + SDL_GLContext result = SDL_malloc(sizeof(struct SDL_GLContextState)); if (!result) { return NULL; } @@ -968,7 +968,7 @@ static bool SDL_EGL_InitInternal(SDL_VideoData * vd) vd->eglDpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); #ifdef DEBUG_OPENVR - SDL_Log("EGL Display: %p\n", vd->eglDpy); + SDL_Log("EGL Display: %p", vd->eglDpy); #endif if (vd->eglDpy == 0) { @@ -1040,7 +1040,7 @@ static SDL_GLContext OVR_EGL_CreateContext(SDL_VideoDevice *_this, SDL_Window * const char * ccc = (const char*)ov_glGetStringi(GL_EXTENSIONS, i); if (SDL_strcmp(ccc, "GL_KHR_debug") == 0) { #ifdef DEBUG_OPENVR - SDL_Log("Found renderdoc debug extension.\n"); + SDL_Log("Found renderdoc debug extension."); #endif videodata->renderdoc_debugmarker_frame_end = true; } @@ -1657,7 +1657,7 @@ error: } VideoBootStrap OPENVR_bootstrap = { - "openvr", "SDL OpenVR video driver", OPENVR_CreateDevice + "openvr", "SDL OpenVR video driver", OPENVR_CreateDevice, NULL, false }; #endif // SDL_VIDEO_DRIVER_WINDOWS diff --git a/libs/SDL3/src/video/ps2/SDL_ps2video.c b/libs/SDL3/src/video/ps2/SDL_ps2video.c index 72b8a725..e8d26358 100644 --- a/libs/SDL3/src/video/ps2/SDL_ps2video.c +++ b/libs/SDL3/src/video/ps2/SDL_ps2video.c @@ -114,7 +114,8 @@ VideoBootStrap PS2_bootstrap = { "ps2", "PS2 Video Driver", PS2_CreateDevice, - NULL // no ShowMessageBox implementation + NULL, // no ShowMessageBox implementation + false }; #endif // SDL_VIDEO_DRIVER_PS2 diff --git a/libs/SDL3/src/video/psp/SDL_pspvideo.c b/libs/SDL3/src/video/psp/SDL_pspvideo.c index 08e1e8d9..2458235e 100644 --- a/libs/SDL3/src/video/psp/SDL_pspvideo.c +++ b/libs/SDL3/src/video/psp/SDL_pspvideo.c @@ -265,7 +265,8 @@ VideoBootStrap PSP_bootstrap = { "psp", "PSP Video Driver", PSP_Create, - PSP_ShowMessageBox + PSP_ShowMessageBox, + false }; /*****************************************************************************/ diff --git a/libs/SDL3/src/video/qnx/SDL_qnxvideo.c b/libs/SDL3/src/video/qnx/SDL_qnxvideo.c index db231439..4192cdbc 100644 --- a/libs/SDL3/src/video/qnx/SDL_qnxvideo.c +++ b/libs/SDL3/src/video/qnx/SDL_qnxvideo.c @@ -346,5 +346,6 @@ static SDL_VideoDevice *createDevice(void) VideoBootStrap QNX_bootstrap = { "qnx", "QNX Screen", createDevice, - NULL // no ShowMessageBox implementation + NULL, // no ShowMessageBox implementation + false }; diff --git a/libs/SDL3/src/video/raspberry/SDL_rpivideo.c b/libs/SDL3/src/video/raspberry/SDL_rpivideo.c index 2d1e507a..d313f9e2 100644 --- a/libs/SDL3/src/video/raspberry/SDL_rpivideo.c +++ b/libs/SDL3/src/video/raspberry/SDL_rpivideo.c @@ -135,7 +135,8 @@ VideoBootStrap RPI_bootstrap = { "rpi", "RPI Video Driver", RPI_Create, - NULL // no ShowMessageBox implementation + NULL, // no ShowMessageBox implementation + false }; /*****************************************************************************/ diff --git a/libs/SDL3/src/video/riscos/SDL_riscosvideo.c b/libs/SDL3/src/video/riscos/SDL_riscosvideo.c index 1002a45c..1f556d23 100644 --- a/libs/SDL3/src/video/riscos/SDL_riscosvideo.c +++ b/libs/SDL3/src/video/riscos/SDL_riscosvideo.c @@ -96,7 +96,8 @@ static SDL_VideoDevice *RISCOS_CreateDevice(void) VideoBootStrap RISCOS_bootstrap = { RISCOSVID_DRIVER_NAME, "SDL RISC OS video driver", RISCOS_CreateDevice, - RISCOS_ShowMessageBox + RISCOS_ShowMessageBox, + false }; static bool RISCOS_VideoInit(SDL_VideoDevice *_this) diff --git a/libs/SDL3/src/video/stb_image.h b/libs/SDL3/src/video/stb_image.h new file mode 100644 index 00000000..f22de1bb --- /dev/null +++ b/libs/SDL3/src/video/stb_image.h @@ -0,0 +1,8252 @@ +/* stb_image - v2.30 - public domain image loader - http://nothings.org/stb + no warranty implied; use at your own risk + + Do this: + #define STB_IMAGE_IMPLEMENTATION + before you include this file in *one* C or C++ file to create the implementation. + + // i.e. it should look like this: + #include ... + #include ... + #include ... + #define STB_IMAGE_IMPLEMENTATION + #include "stb_image.h" + + You can #define STBI_ASSERT(x) before the #include to avoid using assert.h. + And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free + + + QUICK NOTES: + Primarily of interest to game developers and other people who can + avoid problematic images and only need the trivial interface + + JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) + PNG 1/2/4/8/16-bit-per-channel + + TGA (not sure what subset, if a subset) + BMP non-1bpp, non-RLE + PSD (composited view only, no extra channels, 8/16 bit-per-channel) + + GIF (*comp always reports as 4-channel) + HDR (radiance rgbE format) + PIC (Softimage PIC) + PNM (PPM and PGM binary only) + + Animated GIF still needs a proper API, but here's one way to do it: + http://gist.github.com/urraka/685d9a6340b26b830d49 + + - decode from memory or through FILE (define STBI_NO_STDIO to remove code) + - decode from arbitrary I/O callbacks + - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) + + Full documentation under "DOCUMENTATION" below. + + +LICENSE + + See end of file for license information. + +RECENT REVISION HISTORY: + + 2.30 (2024-05-31) avoid erroneous gcc warning + 2.29 (2023-05-xx) optimizations + 2.28 (2023-01-29) many error fixes, security errors, just tons of stuff + 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes + 2.26 (2020-07-13) many minor fixes + 2.25 (2020-02-02) fix warnings + 2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically + 2.23 (2019-08-11) fix clang static analysis warning + 2.22 (2019-03-04) gif fixes, fix warnings + 2.21 (2019-02-25) fix typo in comment + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings + 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes + 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 + RGB-format JPEG; remove white matting in PSD; + allocate large structures on the stack; + correct channel count for PNG & BMP + 2.10 (2016-01-22) avoid warning introduced in 2.09 + 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED + + See end of file for full revision history. + + + ============================ Contributors ========================= + + Image formats Extensions, features + Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info) + Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info) + Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG) + Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks) + Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG) + Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) + Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) + github:urraka (animated gif) Junggon Kim (PNM comments) + Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA) + socks-the-fox (16-bit PNG) + Jeremy Sawicki (handle all ImageNet JPGs) + Optimizations & bugfixes Mikhail Morozov (1-bit BMP) + Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) + Arseny Kapoulkine Simon Breuss (16-bit PNM) + John-Mark Allen Katelyn Gadd (indexed color loading) + Carmelo J Fdez-Aguera + + Bug & warning fixes + Marc LeBlanc David Woo Guillaume George Martins Mozeiko + Christpher Lloyd Jerry Jansson Joseph Thomson Blazej Dariusz Roszkowski + Phil Jordan Dave Moore Roy Eltham + Hayaki Saito Nathan Reed Won Chun + Luke Graham Johan Duparc Nick Verigakis the Horde3D community + Thomas Ruf Ronny Chevalier github:rlyeh + Janez Zemva John Bartholomew Michal Cichon github:romigrou + Jonathan Blow Ken Hamada Tero Hanninen github:svdijk + Eugene Golushkov Laurent Gomila Cort Stratton github:snagar + Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex + Cass Everitt Ryamond Barbiero github:grim210 + Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw + Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus + Josh Tobin Neil Bickford Matthew Gregan github:poppolopoppo + Julian Raschke Gregory Mullen Christian Floisand github:darealshinji + Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 + Brad Weinberger Matvey Cherevko github:mosra + Luca Sas Alexander Veselov Zack Middleton [reserved] + Ryan C. Gordon [reserved] [reserved] + DO NOT ADD YOUR NAME HERE + + Jacko Dirks + + To add your name to the credits, pick a random blank space in the middle and fill it. + 80% of merge conflicts on stb PRs are due to people adding their name at the end + of the credits. +*/ + +#ifndef STBI_INCLUDE_STB_IMAGE_H +#define STBI_INCLUDE_STB_IMAGE_H + +// DOCUMENTATION +// +// Limitations: +// - no 12-bit-per-channel JPEG +// - no JPEGs with arithmetic coding +// - GIF always returns *comp=4 +// +// Basic usage (see HDR discussion below for HDR usage): +// int x,y,n; +// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); +// // ... process data if not NULL ... +// // ... x = width, y = height, n = # 8-bit components per pixel ... +// // ... replace '0' with '1'..'4' to force that many components per pixel +// // ... but 'n' will always be the number that it would have been if you said 0 +// stbi_image_free(data); +// +// Standard parameters: +// int *x -- outputs image width in pixels +// int *y -- outputs image height in pixels +// int *channels_in_file -- outputs # of image components in image file +// int desired_channels -- if non-zero, # of image components requested in result +// +// The return value from an image loader is an 'unsigned char *' which points +// to the pixel data, or NULL on an allocation failure or if the image is +// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels, +// with each pixel consisting of N interleaved 8-bit components; the first +// pixel pointed to is top-left-most in the image. There is no padding between +// image scanlines or between pixels, regardless of format. The number of +// components N is 'desired_channels' if desired_channels is non-zero, or +// *channels_in_file otherwise. If desired_channels is non-zero, +// *channels_in_file has the number of components that _would_ have been +// output otherwise. E.g. if you set desired_channels to 4, you will always +// get RGBA output, but you can check *channels_in_file to see if it's trivially +// opaque because e.g. there were only 3 channels in the source image. +// +// An output image with N components has the following components interleaved +// in this order in each pixel: +// +// N=#comp components +// 1 grey +// 2 grey, alpha +// 3 red, green, blue +// 4 red, green, blue, alpha +// +// If image loading fails for any reason, the return value will be NULL, +// and *x, *y, *channels_in_file will be unchanged. The function +// stbi_failure_reason() can be queried for an extremely brief, end-user +// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS +// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly +// more user-friendly ones. +// +// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. +// +// To query the width, height and component count of an image without having to +// decode the full file, you can use the stbi_info family of functions: +// +// int x,y,n,ok; +// ok = stbi_info(filename, &x, &y, &n); +// // returns ok=1 and sets x, y, n if image is a supported format, +// // 0 otherwise. +// +// Note that stb_image pervasively uses ints in its public API for sizes, +// including sizes of memory buffers. This is now part of the API and thus +// hard to change without causing breakage. As a result, the various image +// loaders all have certain limits on image size; these differ somewhat +// by format but generally boil down to either just under 2GB or just under +// 1GB. When the decoded image would be larger than this, stb_image decoding +// will fail. +// +// Additionally, stb_image will reject image files that have any of their +// dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS, +// which defaults to 2**24 = 16777216 pixels. Due to the above memory limit, +// the only way to have an image with such dimensions load correctly +// is for it to have a rather extreme aspect ratio. Either way, the +// assumption here is that such larger images are likely to be malformed +// or malicious. If you do need to load an image with individual dimensions +// larger than that, and it still fits in the overall size limit, you can +// #define STBI_MAX_DIMENSIONS on your own to be something larger. +// +// =========================================================================== +// +// UNICODE: +// +// If compiling for Windows and you wish to use Unicode filenames, compile +// with +// #define STBI_WINDOWS_UTF8 +// and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert +// Windows wchar_t filenames to utf8. +// +// =========================================================================== +// +// Philosophy +// +// stb libraries are designed with the following priorities: +// +// 1. easy to use +// 2. easy to maintain +// 3. good performance +// +// Sometimes I let "good performance" creep up in priority over "easy to maintain", +// and for best performance I may provide less-easy-to-use APIs that give higher +// performance, in addition to the easy-to-use ones. Nevertheless, it's important +// to keep in mind that from the standpoint of you, a client of this library, +// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all. +// +// Some secondary priorities arise directly from the first two, some of which +// provide more explicit reasons why performance can't be emphasized. +// +// - Portable ("ease of use") +// - Small source code footprint ("easy to maintain") +// - No dependencies ("ease of use") +// +// =========================================================================== +// +// I/O callbacks +// +// I/O callbacks allow you to read from arbitrary sources, like packaged +// files or some other source. Data read from callbacks are processed +// through a small internal buffer (currently 128 bytes) to try to reduce +// overhead. +// +// The three functions you must define are "read" (reads some bytes of data), +// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). +// +// =========================================================================== +// +// SIMD support +// +// The JPEG decoder will try to automatically use SIMD kernels on x86 when +// supported by the compiler. For ARM Neon support, you must explicitly +// request it. +// +// (The old do-it-yourself SIMD API is no longer supported in the current +// code.) +// +// On x86, SSE2 will automatically be used when available based on a run-time +// test; if not, the generic C versions are used as a fall-back. On ARM targets, +// the typical path is to have separate builds for NEON and non-NEON devices +// (at least this is true for iOS and Android). Therefore, the NEON support is +// toggled by a build flag: define STBI_NEON to get NEON loops. +// +// If for some reason you do not want to use any of SIMD code, or if +// you have issues compiling it, you can disable it entirely by +// defining STBI_NO_SIMD. +// +// =========================================================================== +// +// HDR image support (disable by defining STBI_NO_HDR) +// +// stb_image supports loading HDR images in general, and currently the Radiance +// .HDR file format specifically. You can still load any file through the existing +// interface; if you attempt to load an HDR file, it will be automatically remapped +// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; +// both of these constants can be reconfigured through this interface: +// +// stbi_hdr_to_ldr_gamma(2.2f); +// stbi_hdr_to_ldr_scale(1.0f); +// +// (note, do not use _inverse_ constants; stbi_image will invert them +// appropriately). +// +// Additionally, there is a new, parallel interface for loading files as +// (linear) floats to preserve the full dynamic range: +// +// float *data = stbi_loadf(filename, &x, &y, &n, 0); +// +// If you load LDR images through this interface, those images will +// be promoted to floating point values, run through the inverse of +// constants corresponding to the above: +// +// stbi_ldr_to_hdr_scale(1.0f); +// stbi_ldr_to_hdr_gamma(2.2f); +// +// Finally, given a filename (or an open file or memory block--see header +// file for details) containing image data, you can query for the "most +// appropriate" interface to use (that is, whether the image is HDR or +// not), using: +// +// stbi_is_hdr(char *filename); +// +// =========================================================================== +// +// iPhone PNG support: +// +// We optionally support converting iPhone-formatted PNGs (which store +// premultiplied BGRA) back to RGB, even though they're internally encoded +// differently. To enable this conversion, call +// stbi_convert_iphone_png_to_rgb(1). +// +// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per +// pixel to remove any premultiplied alpha *only* if the image file explicitly +// says there's premultiplied data (currently only happens in iPhone images, +// and only if iPhone convert-to-rgb processing is on). +// +// =========================================================================== +// +// ADDITIONAL CONFIGURATION +// +// - You can suppress implementation of any of the decoders to reduce +// your code footprint by #defining one or more of the following +// symbols before creating the implementation. +// +// STBI_NO_JPEG +// STBI_NO_PNG +// STBI_NO_BMP +// STBI_NO_PSD +// STBI_NO_TGA +// STBI_NO_GIF +// STBI_NO_HDR +// STBI_NO_PIC +// STBI_NO_PNM (.ppm and .pgm) +// +// - You can request *only* certain decoders and suppress all other ones +// (this will be more forward-compatible, as addition of new decoders +// doesn't require you to disable them explicitly): +// +// STBI_ONLY_JPEG +// STBI_ONLY_PNG +// STBI_ONLY_BMP +// STBI_ONLY_PSD +// STBI_ONLY_TGA +// STBI_ONLY_GIF +// STBI_ONLY_HDR +// STBI_ONLY_PIC +// STBI_ONLY_PNM (.ppm and .pgm) +// +// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still +// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB +// +// - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater +// than that size (in either width or height) without further processing. +// This is to let programs in the wild set an upper bound to prevent +// denial-of-service attacks on untrusted data, as one could generate a +// valid image of gigantic dimensions and force stb_image to allocate a +// huge block of memory and spend disproportionate time decoding it. By +// default this is set to (1 << 24), which is 16777216, but that's still +// very big. + +#ifndef STBI_NO_STDIO +#include +#endif // STBI_NO_STDIO + +#define STBI_VERSION 1 + +enum +{ + STBI_default = 0, // only used for desired_channels + + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4 +}; + +#if 0 /* SDL change */ +#include +typedef unsigned char stbi_uc; +typedef unsigned short stbi_us; +#else +typedef Uint8 stbi_uc; +typedef Uint16 stbi_us; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef STBIDEF +#ifdef STB_IMAGE_STATIC +#define STBIDEF static +#else +#define STBIDEF extern +#endif +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// PRIMARY API - works on images of any type +// + +// +// load image by filename, open file, or memory buffer +// + +typedef struct +{ + int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read + void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative + int (*eof) (void *user); // returns nonzero if we are at end of file/data +} stbi_io_callbacks; + +//////////////////////////////////// +// +// 8-bits-per-channel interface +// + +STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); +#if 0 /* not used in SDL */ +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); +#endif + +#ifndef STBI_NO_STDIO +STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +// for stbi_load_from_file, file pointer is left pointing immediately after image +#endif + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +#endif + +#ifdef STBI_WINDOWS_UTF8 +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +#endif + +//////////////////////////////////// +// +// 8-bits-per-channel indexed color +// Will fail if image is not an 8-bit PNG or TGA with a palette. +// Palette buffer needs to be at least 256 entries for PNG. +// + +#if 0 /* not used in SDL */ +STBIDEF stbi_uc *stbi_load_from_memory_with_palette (stbi_uc const *buffer, int len , int *x, int *y, unsigned int *palette_buffer, int palette_buffer_len); +STBIDEF stbi_uc *stbi_load_from_callbacks_with_palette(stbi_io_callbacks const *clbk, void *user, int *x, int *y, unsigned int *palette_buffer, int palette_buffer_len); +#endif + +//////////////////////////////////// +// +// 16-bits-per-channel interface +// + +#if 0 /* not used in SDL */ +STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); +#endif + +#ifndef STBI_NO_STDIO +STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +#endif + +//////////////////////////////////// +// +// float-per-channel interface +// +#ifndef STBI_NO_LINEAR + STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + + #ifndef STBI_NO_STDIO + STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); + #endif +#endif + +#ifndef STBI_NO_HDR + STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); + STBIDEF void stbi_hdr_to_ldr_scale(float scale); +#endif // STBI_NO_HDR + +#ifndef STBI_NO_LINEAR + STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); + STBIDEF void stbi_ldr_to_hdr_scale(float scale); +#endif // STBI_NO_LINEAR + +#if 0 /* not used in SDL */ +// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); +#endif +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename); +STBIDEF int stbi_is_hdr_from_file(FILE *f); +#endif // STBI_NO_STDIO + + +#if 0 /* not used in SDL */ +// get a VERY brief reason for failure +// on most compilers (and ALL modern mainstream compilers) this is threadsafe +STBIDEF const char *stbi_failure_reason (void); +#endif + +// free the loaded image -- this is just free() +STBIDEF void stbi_image_free (void *retval_from_stbi_load); + +#if 0 /* not used in SDL */ +// get image dimensions & components without fully decoding +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user); +#endif + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit (char const *filename); +STBIDEF int stbi_is_16_bit_from_file(FILE *f); +#endif + + +#ifndef STBI_NO_PNG +#if 0 /* not used in SDL */ +// for image formats that explicitly notate that they have premultiplied alpha, +// we just return the colors as stored in the file. set this flag to force +// unpremultiplication. results are undefined if the unpremultiply overflow. +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); + +// indicate whether we should process iphone images back to canonical format, +// or just pass them through "as-is" +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); + +// flip the image vertically, so the first pixel in the output array is the bottom left +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); +#endif /**/ + +#ifndef STBI_NO_THREAD_LOCALS /**/ +// as above, but only applies to images loaded on the thread that calls the function +// this function is only available if your compiler supports thread-local variables; +// calling it will fail to link if your compiler doesn't +STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply); +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert); +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip); +#endif +#endif + +// ZLIB client - used by PNG, available for other purposes + +#ifndef STBI_NO_ZLIB +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); +STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + +STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); +#endif + + +#ifdef __cplusplus +} +#endif + +// +// +//// end header file ///////////////////////////////////////////////////// +#endif // STBI_INCLUDE_STB_IMAGE_H + +#ifdef STB_IMAGE_IMPLEMENTATION + +#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ + || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ + || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ + || defined(STBI_ONLY_ZLIB) + #ifndef STBI_ONLY_JPEG + #define STBI_NO_JPEG + #endif + #ifndef STBI_ONLY_PNG + #define STBI_NO_PNG + #endif + #ifndef STBI_ONLY_BMP + #define STBI_NO_BMP + #endif + #ifndef STBI_ONLY_PSD + #define STBI_NO_PSD + #endif + #ifndef STBI_ONLY_TGA + #define STBI_NO_TGA + #endif + #ifndef STBI_ONLY_GIF + #define STBI_NO_GIF + #endif + #ifndef STBI_ONLY_HDR + #define STBI_NO_HDR + #endif + #ifndef STBI_ONLY_PIC + #define STBI_NO_PIC + #endif + #ifndef STBI_ONLY_PNM + #define STBI_NO_PNM + #endif +#endif + +#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) +#define STBI_NO_ZLIB +#endif + + +#if 0 /* SDL change */ +#include +#include // ptrdiff_t on osx +#include +#include +#include + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#include // ldexp, pow +#endif +#else /* SDL change */ +#ifndef UINT_MAX +#define UINT_MAX SDL_MAX_UINT32 +#endif +#ifndef INT_MAX +#define INT_MAX SDL_MAX_SINT32 +#endif +#ifndef INT_MIN +#define INT_MIN SDL_MIN_SINT32 +#endif +#ifndef SHRT_MAX +#define SHRT_MAX SDL_MAX_SINT16 +#endif +#ifndef SHRT_MIN +#define SHRT_MIN SDL_MIN_SINT16 +#endif +#endif + +#ifndef STBI_NO_STDIO +#include +#endif + +#ifndef STBI_ASSERT +#include +#define STBI_ASSERT(x) assert(x) +#endif + +#ifdef __cplusplus +#define STBI_EXTERN extern "C" +#else +#define STBI_EXTERN extern +#endif + + +#ifndef _MSC_VER + #ifdef __cplusplus + #define stbi_inline inline + #else + #define stbi_inline + #endif +#else + #define stbi_inline __forceinline +#endif + +#ifndef STBI_NO_THREAD_LOCALS + #if defined(__cplusplus) && __cplusplus >= 201103L + #define STBI_THREAD_LOCAL thread_local + #elif defined(__GNUC__) && __GNUC__ < 5 + #define STBI_THREAD_LOCAL __thread + #elif defined(_MSC_VER) + #define STBI_THREAD_LOCAL __declspec(thread) + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__) + #define STBI_THREAD_LOCAL _Thread_local + #endif + + #ifndef STBI_THREAD_LOCAL + #if defined(__GNUC__) + #define STBI_THREAD_LOCAL __thread + #endif + #endif +#endif + +#if 0 /* SDL change */ +#if defined(_MSC_VER) || defined(__SYMBIAN32__) +typedef unsigned short stbi__uint16; +typedef signed short stbi__int16; +typedef unsigned int stbi__uint32; +typedef signed int stbi__int32; +#else +#include +typedef uint16_t stbi__uint16; +typedef int16_t stbi__int16; +typedef uint32_t stbi__uint32; +typedef int32_t stbi__int32; +#endif +#else +typedef Uint16 stbi__uint16; +typedef Sint16 stbi__int16; +typedef Uint32 stbi__uint32; +typedef Sint32 stbi__int32; +#endif + +#ifndef STBI_BUFFER_SIZE +#define STBI_BUFFER_SIZE 128 +#endif + +// should produce compiler error if size is wrong +typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; + +#ifdef _MSC_VER +#define STBI_NOTUSED(v) (void)(v) +#else +#define STBI_NOTUSED(v) (void)sizeof(v) +#endif + +#if 0 /* SDL change: */ +#ifdef _MSC_VER +#define STBI_HAS_LROTL +#endif +#endif + +#ifdef STBI_HAS_LROTL + #define stbi_lrot(x,y) _lrotl(x,y) +#else + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (-(y) & 31))) +#endif + +#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) +// ok +#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED) +// ok +#else +#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)." +#endif + +#ifndef STBI_MALLOC +#define STBI_MALLOC(sz) malloc(sz) +#define STBI_REALLOC(p,newsz) realloc(p,newsz) +#define STBI_FREE(p) free(p) +#endif + +#ifndef STBI_REALLOC_SIZED +#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) +#endif + +// x86/x64 detection +#if defined(__x86_64__) || defined(_M_X64) +#define STBI__X64_TARGET +#elif defined(__i386) || defined(_M_IX86) +#define STBI__X86_TARGET +#endif + +#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) +// gcc doesn't support sse2 intrinsics unless you compile with -msse2, +// which in turn means it gets to use SSE2 everywhere. This is unfortunate, +// but previous attempts to provide the SSE2 functions with runtime +// detection caused numerous issues. The way architecture extensions are +// exposed in GCC/Clang is, sadly, not really suited for one-file libs. +// New behavior: if compiled with -msse2, we use SSE2 without any +// detection; if not, we don't use it at all. +#define STBI_NO_SIMD +#endif + +#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD) +// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET +// +// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the +// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant. +// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not +// simultaneously enabling "-mstackrealign". +// +// See https://github.com/nothings/stb/issues/81 for more information. +// +// So default to no SSE2 on 32-bit MinGW. If you've read this far and added +// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2. +#define STBI_NO_SIMD +#endif + +#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) +#define STBI_SSE2 +#include + +#ifdef _MSC_VER + +#if _MSC_VER >= 1400 // not VC6 +#include // __cpuid +static int stbi__cpuid3(void) +{ + int info[4]; + __cpuid(info,1); + return info[3]; +} +#else +static int stbi__cpuid3(void) +{ + int res; + __asm { + mov eax,1 + cpuid + mov res,edx + } + return res; +} +#endif + +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name + +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) +static int stbi__sse2_available(void) +{ + int info3 = stbi__cpuid3(); + return ((info3 >> 26) & 1) != 0; +} +#endif + +#else // assume GCC-style if not VC++ +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) + +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) +static int stbi__sse2_available(void) +{ + // If we're even attempting to compile this on GCC/Clang, that means + // -msse2 is on, which means the compiler is allowed to use SSE2 + // instructions at will, and so are we. + return 1; +} +#endif + +#endif +#endif + +// ARM NEON +#if defined(STBI_NO_SIMD) && defined(STBI_NEON) +#undef STBI_NEON +#endif + +#ifdef STBI_NEON +#include +#ifdef _MSC_VER +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name +#else +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) +#endif +#endif + +#ifndef STBI_SIMD_ALIGN +#define STBI_SIMD_ALIGN(type, name) type name +#endif + +#ifndef STBI_MAX_DIMENSIONS +#define STBI_MAX_DIMENSIONS (1 << 24) +#endif + +/////////////////////////////////////////////// +// +// stbi__context struct and start_xxx functions + +// stbi__context structure is our basic context used by all images, so it +// contains all the IO context, plus some basic image information +typedef struct +{ + stbi__uint32 img_x, img_y; + int img_n, img_out_n; + + stbi_io_callbacks io; + void *io_user_data; + + int read_from_callbacks; + int buflen; + stbi_uc buffer_start[128]; + int callback_already_read; + + stbi_uc *img_buffer, *img_buffer_end; + stbi_uc *img_buffer_original, *img_buffer_original_end; +} stbi__context; + + +static void stbi__refill_buffer(stbi__context *s); + +// initialize a memory-decode context +static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) +{ + s->io.read = NULL; + s->read_from_callbacks = 0; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; + s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; +} + +#if 0 /* not used in SDL */ +// initialize a callback-based context +static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) +{ + s->io = *c; + s->io_user_data = user; + s->buflen = sizeof(s->buffer_start); + s->read_from_callbacks = 1; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = s->buffer_start; + stbi__refill_buffer(s); + s->img_buffer_original_end = s->img_buffer_end; +} +#endif + +#ifndef STBI_NO_STDIO + +static int stbi__stdio_read(void *user, char *data, int size) +{ + return (int) fread(data,1,size,(FILE*) user); +} + +static void stbi__stdio_skip(void *user, int n) +{ + int ch; + fseek((FILE*) user, n, SEEK_CUR); + ch = fgetc((FILE*) user); /* have to read a byte to reset feof()'s flag */ + if (ch != EOF) { + ungetc(ch, (FILE *) user); /* push byte back onto stream if valid. */ + } +} + +static int stbi__stdio_eof(void *user) +{ + return feof((FILE*) user) || ferror((FILE *) user); +} + +static stbi_io_callbacks stbi__stdio_callbacks = +{ + stbi__stdio_read, + stbi__stdio_skip, + stbi__stdio_eof, +}; + +static void stbi__start_file(stbi__context *s, FILE *f) +{ + stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); +} + +//static void stop_file(stbi__context *s) { } + +#endif // !STBI_NO_STDIO + +static void stbi__rewind(stbi__context *s) +{ + // conceptually rewind SHOULD rewind to the beginning of the stream, + // but we just rewind to the beginning of the initial buffer, because + // we only use it after doing 'test', which only ever looks at at most 92 bytes + s->img_buffer = s->img_buffer_original; + s->img_buffer_end = s->img_buffer_original_end; +} + +enum +{ + STBI_ORDER_RGB, + STBI_ORDER_BGR +}; + +typedef struct +{ + int w; + int h; + int pitch; + stbi_uc *y; + stbi_uc *uv; +} stbi__nv12; + +typedef struct +{ + int bits_per_channel; + int num_channels; + int channel_order; +} stbi__result_info; + +#ifndef STBI_NO_JPEG +static int stbi__jpeg_test(stbi__context *s); +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__nv12 *nv12, stbi__result_info *ri); +#if 0 /* not used in SDL */ +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); +#endif +#endif + +#ifndef STBI_NO_PNG +static int stbi__png_test(stbi__context *s); +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, unsigned int *palette_buffer, int palette_buffer_len, stbi__result_info *ri); +#if 0 /* not used in SDL */ +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__png_is16(stbi__context *s); +#endif +#endif + +#ifndef STBI_NO_BMP +static int stbi__bmp_test(stbi__context *s); +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_TGA +static int stbi__tga_test(stbi__context *s); +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, unsigned int *palette_buffer, int palette_buffer_len, stbi__result_info *ri); +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s); +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__psd_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_HDR +static int stbi__hdr_test(stbi__context *s); +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_test(stbi__context *s); +static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_GIF +static int stbi__gif_test(stbi__context *s); +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNM +static int stbi__pnm_test(stbi__context *s); +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__pnm_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_FAILURE_STRINGS +#if 1 /* SDL change: */ +static int stbi__err(const char *str) +{ + SDL_SetError("%s", str); + return 0; +} +#else /* SDL change. */ +static +#ifdef STBI_THREAD_LOCAL +STBI_THREAD_LOCAL +#endif +const char *stbi__g_failure_reason; + +STBIDEF const char *stbi_failure_reason(void) +{ + return stbi__g_failure_reason; +} + +static int stbi__err(const char *str) +{ + stbi__g_failure_reason = str; + return 0; +} +#endif /**/ +#endif + +static void *stbi__malloc(size_t size) +{ + return STBI_MALLOC(size); +} + +// stb_image uses ints pervasively, including for offset calculations. +// therefore the largest decoded image size we can support with the +// current code, even on 64-bit targets, is INT_MAX. this is not a +// significant limitation for the intended use case. +// +// we do, however, need to make sure our size calculations don't +// overflow. hence a few helper functions for size calculations that +// multiply integers together, making sure that they're non-negative +// and no overflow occurs. + +// return 1 if the sum is valid, 0 on overflow. +// negative terms are considered invalid. +static int stbi__addsizes_valid(int a, int b) +{ + if (b < 0) return 0; + // now 0 <= b <= INT_MAX, hence also + // 0 <= INT_MAX - b <= INTMAX. + // And "a + b <= INT_MAX" (which might overflow) is the + // same as a <= INT_MAX - b (no overflow) + return a <= INT_MAX - b; +} + +// returns 1 if the product is valid, 0 on overflow. +// negative factors are considered invalid. +static int stbi__mul2sizes_valid(int a, int b) +{ + if (a < 0 || b < 0) return 0; + if (b == 0) return 1; // mul-by-0 is always safe + // portable way to check for no overflows in a*b + return a <= INT_MAX/b; +} + +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) +// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow +static int stbi__mad2sizes_valid(int a, int b, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); +} +#endif + +// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow +static int stbi__mad3sizes_valid(int a, int b, int c, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__addsizes_valid(a*b*c, add); +} + +// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) +static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); +} +#endif + +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) +// mallocs with size overflow checking +static void *stbi__malloc_mad2(int a, int b, int add) +{ + if (!stbi__mad2sizes_valid(a, b, add)) return NULL; + return stbi__malloc(a*b + add); +} +#endif + +static void *stbi__malloc_mad3(int a, int b, int c, int add) +{ + if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; + return stbi__malloc(a*b*c + add); +} + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) +static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) +{ + if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; + return stbi__malloc(a*b*c*d + add); +} +#endif + +// returns 1 if the sum of two signed ints is valid (between -2^31 and 2^31-1 inclusive), 0 on overflow. +static int stbi__addints_valid(int a, int b) +{ + if ((a >= 0) != (b >= 0)) return 1; // a and b have different signs, so no overflow + if (a < 0 && b < 0) return a >= INT_MIN - b; // same as a + b >= INT_MIN; INT_MIN - b cannot overflow since b < 0. + return a <= INT_MAX - b; +} + +// returns 1 if the product of two ints fits in a signed short, 0 on overflow. +static int stbi__mul2shorts_valid(int a, int b) +{ + if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow + if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid + if (b < 0) return a <= SHRT_MIN / b; // same as a * b >= SHRT_MIN + return a >= SHRT_MIN / b; +} + +// stbi__err - error +// stbi__errpf - error returning pointer to float +// stbi__errpuc - error returning pointer to unsigned char + +#ifdef STBI_NO_FAILURE_STRINGS + #define stbi__err(x,y) 0 +#elif defined(STBI_FAILURE_USERMSG) + #define stbi__err(x,y) stbi__err(y) +#else + #define stbi__err(x,y) stbi__err(x) +#endif + +#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL)) +#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL)) + +STBIDEF void stbi_image_free(void *retval_from_stbi_load) +{ + STBI_FREE(retval_from_stbi_load); +} + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); +#endif + +#ifndef STBI_NO_HDR +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); +#endif + +static int stbi__vertically_flip_on_load_global = 0; + +#ifndef STBI_NO_PNG +#if 0 /* not used in SDL */ +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_global = flag_true_if_should_flip; +} +#endif /**/ +#endif + +#ifndef STBI_THREAD_LOCAL +#define stbi__vertically_flip_on_load stbi__vertically_flip_on_load_global +#else +static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set; + +#ifndef STBI_NO_PNG +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_local = flag_true_if_should_flip; + stbi__vertically_flip_on_load_set = 1; +} +#endif + +#define stbi__vertically_flip_on_load (stbi__vertically_flip_on_load_set \ + ? stbi__vertically_flip_on_load_local \ + : stbi__vertically_flip_on_load_global) +#endif // STBI_THREAD_LOCAL + +static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc, unsigned int *palette_buffer, int palette_buffer_len) +{ + memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields + ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed + ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order + ri->num_channels = 0; + + // test the formats with a very explicit header first (at least a FOURCC + // or distinctive magic number first) + #ifndef STBI_NO_PNG + if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, palette_buffer, palette_buffer_len, ri); + #endif + #ifndef STBI_NO_BMP + if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_GIF + if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PSD + if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); + #else + STBI_NOTUSED(bpc); + #endif + #ifndef STBI_NO_PIC + if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); + #endif + + // then the formats that can end up attempting to load with just 1 or 2 + // bytes matching expectations; these are prone to false positives, so + // try them later + #ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp,NULL, ri); + #endif + #ifndef STBI_NO_PNM + if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri); + return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } + #endif + + #ifndef STBI_NO_TGA + // test tga last because it's a crappy test! + if (stbi__tga_test(s)) + return stbi__tga_load(s,x,y,comp,req_comp, palette_buffer, palette_buffer_len, ri); + #endif + + return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); +} + +static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi_uc *reduced; + + reduced = (stbi_uc *) stbi__malloc(img_len); + if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling + + STBI_FREE(orig); + return reduced; +} + +#if 0 /* not used in SDL */ +static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi__uint16 *enlarged; + + enlarged = (stbi__uint16 *) stbi__malloc(img_len*2); + if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff + + STBI_FREE(orig); + return enlarged; +} +#endif + +static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) +{ + int row; + size_t bytes_per_row = (size_t)w * bytes_per_pixel; + stbi_uc temp[2048]; + stbi_uc *bytes = (stbi_uc *)image; + + for (row = 0; row < (h>>1); row++) { + stbi_uc *row0 = bytes + row*bytes_per_row; + stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row; + // swap row0 with row1 + size_t bytes_left = bytes_per_row; + while (bytes_left) { + size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); + memcpy(temp, row0, bytes_copy); + memcpy(row0, row1, bytes_copy); + memcpy(row1, temp, bytes_copy); + row0 += bytes_copy; + row1 += bytes_copy; + bytes_left -= bytes_copy; + } + } +} + +#ifndef STBI_NO_GIF +static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) +{ + int slice; + int slice_size = w * h * bytes_per_pixel; + + stbi_uc *bytes = (stbi_uc *)image; + for (slice = 0; slice < z; ++slice) { + stbi__vertical_flip(bytes, w, h, bytes_per_pixel); + bytes += slice_size; + } +} +#endif + +#if 0 /* not used in SDL */ +static unsigned char *stbi__load_indexed(stbi__context *s, int *x, int *y, unsigned int *palette_buffer, int palette_buffer_len) +{ + stbi__result_info ri; + int comp; + void *result; + + if (!palette_buffer) + return NULL; + + result = stbi__load_main(s, x, y, &comp, 1, &ri, 8, palette_buffer, palette_buffer_len); + if (result == NULL) + return NULL; + + if (comp != 1) { + stbi_image_free(result); + return NULL; + } + + if (ri.bits_per_channel != 8) { + stbi_image_free(result); + return NULL; + } + + // @TODO: move stbi__convert_format to here + + if (stbi__vertically_flip_on_load) { + int channels = 1; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); + } + + return (unsigned char *) result; +} +#endif /**/ + +static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8, NULL, 0); + + if (result == NULL) + return NULL; + + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + + if (ri.bits_per_channel != 8) { + result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 8; + } + + // @TODO: move stbi__convert_format to here + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); + } + + return (unsigned char *) result; +} + +#if 0 /* not used in SDL */ +static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16, NULL, 0); + + if (result == NULL) + return NULL; + + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + + if (ri.bits_per_channel != 16) { + result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 16; + } + + // @TODO: move stbi__convert_format16 to here + // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); + } + + return (stbi__uint16 *) result; +} +#endif /**/ + +#if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR) +static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) +{ + if (stbi__vertically_flip_on_load && result != NULL) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); + } +} +#endif + +#ifndef STBI_NO_STDIO + +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) +STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); +STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); +#endif + +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) +{ + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +} +#endif + +static FILE *stbi__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) + return 0; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; +#else + f = _wfopen(wFilename, wMode); +#endif + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + + +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + unsigned char *result; + if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__uint16 *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + stbi__uint16 *result; + if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file_16(f,x,y,comp,req_comp); + fclose(f); + return result; +} + + +#endif //!STBI_NO_STDIO + +#if 0 /* not used in SDL */ +STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} +#endif /**/ + +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +#if 0 /* not used in SDL */ +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +STBIDEF stbi_uc *stbi_load_from_memory_with_palette(stbi_uc const *buffer, int len, int *x, int *y, unsigned int *palette_buffer, int palette_buffer_len) +{ + stbi__context s; + stbi__start_mem(&s, buffer, len); + return stbi__load_indexed(&s, x, y, palette_buffer, palette_buffer_len); +} + +STBIDEF stbi_uc *stbi_load_from_callbacks_with_palette(stbi_io_callbacks const *clbk, void *user, int *x, int *y, unsigned int *palette_buffer, int palette_buffer_len) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__load_indexed(&s, x, y, palette_buffer, palette_buffer_len); +} +#endif + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_mem(&s,buffer,len); + + result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); + if (stbi__vertically_flip_on_load) { + stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); + } + + return result; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *data; + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + stbi__result_info ri; + float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri); + if (hdr_data) + stbi__float_postprocess(hdr_data,x,y,comp,req_comp); + return hdr_data; + } + #endif + data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); + if (data) + return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); +} + +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_STDIO +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + float *result; + FILE *f = stbi__fopen(filename, "rb"); + if (!f) return stbi__errpf("can't fopen", "Unable to open file"); + result = stbi_loadf_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_file(&s,f); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} +#endif // !STBI_NO_STDIO + +#endif // !STBI_NO_LINEAR + +#if 0 /* not used in SDL */ +// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is +// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always +// reports false! + +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(buffer); + STBI_NOTUSED(len); + return 0; + #endif +} +#endif + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result=0; + if (f) { + result = stbi_is_hdr_from_file(f); + fclose(f); + } + return result; +} + +STBIDEF int stbi_is_hdr_from_file(FILE *f) +{ + #ifndef STBI_NO_HDR + long pos = ftell(f); + int res; + stbi__context s; + stbi__start_file(&s,f); + res = stbi__hdr_test(&s); + fseek(f, pos, SEEK_SET); + return res; + #else + STBI_NOTUSED(f); + return 0; + #endif +} +#endif // !STBI_NO_STDIO + +#if 0 /* not used in SDL */ +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(clbk); + STBI_NOTUSED(user); + return 0; + #endif +} +#endif + +#ifndef STBI_NO_LINEAR +static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; + +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } +STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } +#endif + +#ifndef STBI_NO_HDR +static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; + +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } +STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } +#endif + + +////////////////////////////////////////////////////////////////////////////// +// +// Common code used by all image loaders +// + +enum +{ + STBI__SCAN_load=0, + STBI__SCAN_type, + STBI__SCAN_header +}; + +static void stbi__refill_buffer(stbi__context *s) +{ + int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); + s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original); + if (n == 0) { + // at end of file, treat same as if from memory, but need to handle case + // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file + s->read_from_callbacks = 0; + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start+1; + *s->img_buffer = 0; + } else { + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + n; + } +} + +stbi_inline static stbi_uc stbi__get8(stbi__context *s) +{ + if (s->img_buffer < s->img_buffer_end) + return *s->img_buffer++; + if (s->read_from_callbacks) { + stbi__refill_buffer(s); + return *s->img_buffer++; + } + return 0; +} + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +stbi_inline static int stbi__at_eof(stbi__context *s) +{ + if (s->io.read) { + if (!(s->io.eof)(s->io_user_data)) return 0; + // if feof() is true, check if buffer = end + // special case: we've only got the special 0 character at the end + if (s->read_from_callbacks == 0) return 1; + } + + return s->img_buffer >= s->img_buffer_end; +} +#endif + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) +// nothing +#else +static void stbi__skip(stbi__context *s, int n) +{ + if (n == 0) return; // already there! + if (n < 0) { + s->img_buffer = s->img_buffer_end; + return; + } + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + s->img_buffer = s->img_buffer_end; + (s->io.skip)(s->io_user_data, n - blen); + return; + } + } + s->img_buffer += n; +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM) +// nothing +#else +static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) +{ + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + int res, count; + + memcpy(buffer, s->img_buffer, blen); + + count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); + res = (count == (n-blen)); + s->img_buffer = s->img_buffer_end; + return res; + } + } + + if (s->img_buffer+n <= s->img_buffer_end) { + memcpy(buffer, s->img_buffer, n); + s->img_buffer += n; + return 1; + } else + return 0; +} +#endif + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else +static int stbi__get16be(stbi__context *s) +{ + int z = stbi__get8(s); + return (z << 8) + stbi__get8(s); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else +static stbi__uint32 stbi__get32be(stbi__context *s) +{ + stbi__uint32 z = stbi__get16be(s); + return (z << 16) + stbi__get16be(s); +} +#endif + +#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) +// nothing +#else +static int stbi__get16le(stbi__context *s) +{ + int z = stbi__get8(s); + return z + (stbi__get8(s) << 8); +} +#endif + +#ifndef STBI_NO_BMP +static stbi__uint32 stbi__get32le(stbi__context *s) +{ + stbi__uint32 z = stbi__get16le(s); + z += (stbi__uint32)stbi__get16le(s) << 16; + return z; +} +#endif + +#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +////////////////////////////////////////////////////////////////////////////// +// +// generic converter from built-in img_n to req_comp +// individual types do this automatically as much as possible (e.g. jpeg +// does all cases internally since it needs to colorspace convert anyway, +// and it never has alpha, so very few cases ). png can automatically +// interleave an alpha=255 channel, but falls back to this for other cases +// +// assume data buffer is malloced, so malloc a new one and free that one +// only failure mode is malloc failing + +static stbi_uc stbi__compute_y(int r, int g, int b) +{ + return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + unsigned char *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); + if (good == NULL) { + STBI_FREE(data); + return stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + unsigned char *src = data + j * x * img_n ; + unsigned char *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc("unsupported", "Unsupported format conversion"); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else +static stbi__uint16 stbi__compute_y_16(int r, int g, int b) +{ + return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else +static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + stbi__uint16 *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); + if (good == NULL) { + STBI_FREE(data); + return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + stbi__uint16 *src = data + j * x * img_n ; + stbi__uint16 *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc("unsupported", "Unsupported format conversion"); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) +{ + int i,k,n; + float *output; + if (!data) return NULL; + output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); + } + } + if (n < comp) { + for (i=0; i < x*y; ++i) { + output[i*comp + n] = data[i*comp + n]/255.0f; + } + } + STBI_FREE(data); + return output; +} +#endif + +#ifndef STBI_NO_HDR +#define stbi__float2int(x) ((int) (x)) +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) +{ + int i,k,n; + stbi_uc *output; + if (!data) return NULL; + output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + if (k < comp) { + float z = data[i*comp+k] * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + } + STBI_FREE(data); + return output; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// "baseline" JPEG/JFIF decoder +// +// simple implementation +// - doesn't support delayed output of y-dimension +// - simple interface (only one output format: 8-bit interleaved RGB) +// - doesn't try to recover corrupt jpegs +// - doesn't allow partial loading, loading multiple at once +// - still fast on x86 (copying globals into locals doesn't help x86) +// - allocates lots of intermediate memory (full size of all components) +// - non-interleaved case requires this anyway +// - allows good upsampling (see next) +// high-quality +// - upsampled channels are bilinearly interpolated, even across blocks +// - quality integer IDCT derived from IJG's 'slow' +// performance +// - fast huffman; reasonable integer IDCT +// - some SIMD kernels for common paths on targets with SSE2/NEON +// - uses a lot of intermediate memory, could cache poorly + +#ifndef STBI_NO_JPEG + +// huffman decoding acceleration +#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache + +typedef struct +{ + stbi_uc fast[1 << FAST_BITS]; + // weirdly, repacking this into AoS is a 10% speed loss, instead of a win + stbi__uint16 code[256]; + stbi_uc values[256]; + stbi_uc size[257]; + unsigned int maxcode[18]; + int delta[17]; // old 'firstsymbol' - old 'firstcode' +} stbi__huffman; + +typedef struct +{ + stbi__context *s; + stbi__huffman huff_dc[4]; + stbi__huffman huff_ac[4]; + stbi__uint16 dequant[4][64]; + stbi__int16 fast_ac[4][1 << FAST_BITS]; + +// sizes for components, interleaved MCUs + int img_h_max, img_v_max; + int img_mcu_x, img_mcu_y; + int img_mcu_w, img_mcu_h; + +// definition of jpeg image component + struct + { + int id; + int h,v; + int tq; + int hd,ha; + int dc_pred; + + int x,y,w2,h2; + stbi_uc *data; + void *raw_data, *raw_coeff; + stbi_uc *linebuf; + short *coeff; // progressive only + int coeff_w, coeff_h; // number of 8x8 coefficient blocks + } img_comp[4]; + + stbi__uint32 code_buffer; // jpeg entropy-coded buffer + int code_bits; // number of valid bits + unsigned char marker; // marker seen while filling entropy buffer + int nomore; // flag if we saw a marker so must stop + + int progressive; + int spec_start; + int spec_end; + int succ_high; + int succ_low; + int eob_run; + int jfif; + int app14_color_transform; // Adobe APP14 tag + int rgb; + + int scan_n, order[4]; + int restart_interval, todo; + +// kernels + void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); + void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); + stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); +} stbi__jpeg; + +static int stbi__build_huffman(stbi__huffman *h, int *count) +{ + int i,j,k=0; + unsigned int code; + // build size list for each symbol (from JPEG spec) + for (i=0; i < 16; ++i) { + for (j=0; j < count[i]; ++j) { + h->size[k++] = (stbi_uc) (i+1); + if(k >= 257) return stbi__err("bad size list","Corrupt JPEG"); + } + } + h->size[k] = 0; + + // compute actual symbols (from jpeg spec) + code = 0; + k = 0; + for(j=1; j <= 16; ++j) { + // compute delta to add to code to compute symbol id + h->delta[j] = k - code; + if (h->size[k] == j) { + while (h->size[k] == j) + h->code[k++] = (stbi__uint16) (code++); + if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG"); + } + // compute largest code + 1 for this size, preshifted as needed later + h->maxcode[j] = code << (16-j); + code <<= 1; + } + h->maxcode[j] = 0xffffffff; + + // build non-spec acceleration table; 255 is flag for not-accelerated + memset(h->fast, 255, 1 << FAST_BITS); + for (i=0; i < k; ++i) { + int s = h->size[i]; + if (s <= FAST_BITS) { + int c = h->code[i] << (FAST_BITS-s); + int m = 1 << (FAST_BITS-s); + for (j=0; j < m; ++j) { + h->fast[c+j] = (stbi_uc) i; + } + } + } + return 1; +} + +// build a table that decodes both magnitude and value of small ACs in +// one go. +static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) +{ + int i; + for (i=0; i < (1 << FAST_BITS); ++i) { + stbi_uc fast = h->fast[i]; + fast_ac[i] = 0; + if (fast < 255) { + int rs = h->values[fast]; + int run = (rs >> 4) & 15; + int magbits = rs & 15; + int len = h->size[fast]; + + if (magbits && len + magbits <= FAST_BITS) { + // magnitude code followed by receive_extend code + int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); + int m = 1 << (magbits - 1); + if (k < m) k += (~0U << magbits) + 1; + // if the result is small enough, we can fit it in fast_ac table + if (k >= -128 && k <= 127) + fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits)); + } + } + } +} + +static void stbi__grow_buffer_unsafe(stbi__jpeg *j) +{ + do { + unsigned int b = j->nomore ? 0 : stbi__get8(j->s); + if (b == 0xff) { + int c = stbi__get8(j->s); + while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes + if (c != 0) { + j->marker = (unsigned char) c; + j->nomore = 1; + return; + } + } + j->code_buffer |= b << (24 - j->code_bits); + j->code_bits += 8; + } while (j->code_bits <= 24); +} + +// (1 << n) - 1 +static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; + +// decode a jpeg huffman value from the bitstream +stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) +{ + unsigned int temp; + int c,k; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + // look at the top FAST_BITS and determine what symbol ID it is, + // if the code is <= FAST_BITS + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + k = h->fast[c]; + if (k < 255) { + int s = h->size[k]; + if (s > j->code_bits) + return -1; + j->code_buffer <<= s; + j->code_bits -= s; + return h->values[k]; + } + + // naive test is to shift the code_buffer down so k bits are + // valid, then test against maxcode. To speed this up, we've + // preshifted maxcode left so that it has (16-k) 0s at the + // end; in other words, regardless of the number of bits, it + // wants to be compared against something shifted to have 16; + // that way we don't need to shift inside the loop. + temp = j->code_buffer >> 16; + for (k=FAST_BITS+1 ; ; ++k) + if (temp < h->maxcode[k]) + break; + if (k == 17) { + // error! code not found + j->code_bits -= 16; + return -1; + } + + if (k > j->code_bits) + return -1; + + // convert the huffman code to the symbol id + c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + if(c < 0 || c >= 256) // symbol id out of bounds! + return -1; + STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); + + // convert the id to a symbol + j->code_bits -= k; + j->code_buffer <<= k; + return h->values[c]; +} + +// bias[n] = (-1<code_bits < n) stbi__grow_buffer_unsafe(j); + if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing + + sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative) + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k + (stbi__jbias[n] & (sgn - 1)); +} + +// get some unsigned bits +stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) +{ + unsigned int k; + if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k; +} + +stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) +{ + unsigned int k; + if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); + if (j->code_bits < 1) return 0; // ran out of bits from stream, return 0s intead of continuing + k = j->code_buffer; + j->code_buffer <<= 1; + --j->code_bits; + return k & 0x80000000; +} + +// given a value that's at position X in the zigzag stream, +// where does it appear in the 8x8 matrix coded as row-major? +static const stbi_uc stbi__jpeg_dezigzag[64+15] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + // let corrupt input sample past end + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63 +}; + +// decode one 64-entry block-- +static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant) +{ + int diff,dc,k; + int t; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0 || t > 15) return stbi__err("bad huffman code","Corrupt JPEG"); + + // 0 all the ac values now so we can do it 32-bits at a time + memset(data,0,64*sizeof(data[0])); + + diff = t ? stbi__extend_receive(j, t) : 0; + if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta","Corrupt JPEG"); + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + if (!stbi__mul2shorts_valid(dc, dequant[0])) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + data[0] = (short) (dc * dequant[0]); + + // decode AC components, see JPEG spec + k = 1; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); + j->code_buffer <<= s; + j->code_bits -= s; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * dequant[zig]); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (rs != 0xf0) break; // end block + k += 16; + } else { + k += r; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); + } + } + } while (k < 64); + return 1; +} + +static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) +{ + int diff,dc; + int t; + if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + if (j->succ_high == 0) { + // first scan for DC coefficient, must be first + memset(data,0,64*sizeof(data[0])); // 0 all the ac values now + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + diff = t ? stbi__extend_receive(j, t) : 0; + + if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta", "Corrupt JPEG"); + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + if (!stbi__mul2shorts_valid(dc, 1 << j->succ_low)) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + data[0] = (short) (dc * (1 << j->succ_low)); + } else { + // refinement scan for DC coefficient + if (stbi__jpeg_get_bit(j)) + data[0] += (short) (1 << j->succ_low); + } + return 1; +} + +// @OPTIMIZE: store non-zigzagged during the decode passes, +// and only de-zigzag when dequantizing +static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) +{ + int k; + if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->succ_high == 0) { + int shift = j->succ_low; + + if (j->eob_run) { + --j->eob_run; + return 1; + } + + k = j->spec_start; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); + j->code_buffer <<= s; + j->code_bits -= s; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * (1 << shift)); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r); + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + --j->eob_run; + break; + } + k += 16; + } else { + k += r; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * (1 << shift)); + } + } + } while (k <= j->spec_end); + } else { + // refinement scan for these AC coefficients + + short bit = (short) (1 << j->succ_low); + + if (j->eob_run) { + --j->eob_run; + for (k = j->spec_start; k <= j->spec_end; ++k) { + short *p = &data[stbi__jpeg_dezigzag[k]]; + if (*p != 0) + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } + } else { + k = j->spec_start; + do { + int r,s; + int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r) - 1; + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + r = 64; // force end of block + } else { + // r=15 s=0 should write 16 0s, so we just do + // a run of 15 0s and then write s (which is 0), + // so we don't have to do anything special here + } + } else { + if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); + // sign bit + if (stbi__jpeg_get_bit(j)) + s = bit; + else + s = -bit; + } + + // advance by r + while (k <= j->spec_end) { + short *p = &data[stbi__jpeg_dezigzag[k++]]; + if (*p != 0) { + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } else { + if (r == 0) { + *p = (short) s; + break; + } + --r; + } + } + } while (k <= j->spec_end); + } + } + return 1; +} + +// take a -128..127 value and stbi__clamp it and convert to 0..255 +stbi_inline static stbi_uc stbi__clamp(int x) +{ + // trick to use a single test to catch both cases + if ((unsigned int) x > 255) { + if (x < 0) return 0; + if (x > 255) return 255; + } + return (stbi_uc) x; +} + +#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) +#define stbi__fsh(x) ((x) * 4096) + +// derived from jidctint -- DCT_ISLOW +#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ + int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ + p2 = s2; \ + p3 = s6; \ + p1 = (p2+p3) * stbi__f2f(0.5411961f); \ + t2 = p1 + p3*stbi__f2f(-1.847759065f); \ + t3 = p1 + p2*stbi__f2f( 0.765366865f); \ + p2 = s0; \ + p3 = s4; \ + t0 = stbi__fsh(p2+p3); \ + t1 = stbi__fsh(p2-p3); \ + x0 = t0+t3; \ + x3 = t0-t3; \ + x1 = t1+t2; \ + x2 = t1-t2; \ + t0 = s7; \ + t1 = s5; \ + t2 = s3; \ + t3 = s1; \ + p3 = t0+t2; \ + p4 = t1+t3; \ + p1 = t0+t3; \ + p2 = t1+t2; \ + p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ + t0 = t0*stbi__f2f( 0.298631336f); \ + t1 = t1*stbi__f2f( 2.053119869f); \ + t2 = t2*stbi__f2f( 3.072711026f); \ + t3 = t3*stbi__f2f( 1.501321110f); \ + p1 = p5 + p1*stbi__f2f(-0.899976223f); \ + p2 = p5 + p2*stbi__f2f(-2.562915447f); \ + p3 = p3*stbi__f2f(-1.961570560f); \ + p4 = p4*stbi__f2f(-0.390180644f); \ + t3 += p1+p4; \ + t2 += p2+p3; \ + t1 += p2+p4; \ + t0 += p1+p3; + +static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) +{ + int i,val[64],*v=val; + stbi_uc *o; + short *d = data; + + // columns + for (i=0; i < 8; ++i,++d, ++v) { + // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing + if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 + && d[40]==0 && d[48]==0 && d[56]==0) { + // no shortcut 0 seconds + // (1|2|3|4|5|6|7)==0 0 seconds + // all separate -0.047 seconds + // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds + int dcterm = d[0]*4; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) + // constants scaled things up by 1<<12; let's bring them back + // down, but keep 2 extra bits of precision + x0 += 512; x1 += 512; x2 += 512; x3 += 512; + v[ 0] = (x0+t3) >> 10; + v[56] = (x0-t3) >> 10; + v[ 8] = (x1+t2) >> 10; + v[48] = (x1-t2) >> 10; + v[16] = (x2+t1) >> 10; + v[40] = (x2-t1) >> 10; + v[24] = (x3+t0) >> 10; + v[32] = (x3-t0) >> 10; + } + } + + for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { + // no fast case since the first 1D IDCT spread components out + STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) + // constants scaled things up by 1<<12, plus we had 1<<2 from first + // loop, plus horizontal and vertical each scale by sqrt(8) so together + // we've got an extra 1<<3, so 1<<17 total we need to remove. + // so we want to round that, which means adding 0.5 * 1<<17, + // aka 65536. Also, we'll end up with -128 to 127 that we want + // to encode as 0..255 by adding 128, so we'll add that before the shift + x0 += 65536 + (128<<17); + x1 += 65536 + (128<<17); + x2 += 65536 + (128<<17); + x3 += 65536 + (128<<17); + // tried computing the shifts into temps, or'ing the temps to see + // if any were out of range, but that was slower + o[0] = stbi__clamp((x0+t3) >> 17); + o[7] = stbi__clamp((x0-t3) >> 17); + o[1] = stbi__clamp((x1+t2) >> 17); + o[6] = stbi__clamp((x1-t2) >> 17); + o[2] = stbi__clamp((x2+t1) >> 17); + o[5] = stbi__clamp((x2-t1) >> 17); + o[3] = stbi__clamp((x3+t0) >> 17); + o[4] = stbi__clamp((x3-t0) >> 17); + } +} + +#ifdef STBI_SSE2 +// sse2 integer IDCT. not the fastest possible implementation but it +// produces bit-identical results to the generic C version so it's +// fully "transparent". +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + // This is constructed to match our regular (generic) integer IDCT exactly. + __m128i row0, row1, row2, row3, row4, row5, row6, row7; + __m128i tmp; + + // dot product constant: even elems=x, odd elems=y + #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) + + // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) + // out(1) = c1[even]*x + c1[odd]*y + #define dct_rot(out0,out1, x,y,c0,c1) \ + __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ + __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ + __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ + __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ + __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ + __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) + + // out = in << 12 (in 16-bit, out 32-bit) + #define dct_widen(out, in) \ + __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ + __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) + + // wide add + #define dct_wadd(out, a, b) \ + __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_add_epi32(a##_h, b##_h) + + // wide sub + #define dct_wsub(out, a, b) \ + __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) + + // butterfly a/b, add bias, then shift by "s" and pack + #define dct_bfly32o(out0, out1, a,b,bias,s) \ + { \ + __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ + __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ + dct_wadd(sum, abiased, b); \ + dct_wsub(dif, abiased, b); \ + out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ + out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ + } + + // 8-bit interleave step (for transposes) + #define dct_interleave8(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi8(a, b); \ + b = _mm_unpackhi_epi8(tmp, b) + + // 16-bit interleave step (for transposes) + #define dct_interleave16(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi16(a, b); \ + b = _mm_unpackhi_epi16(tmp, b) + + #define dct_pass(bias,shift) \ + do { \ + /* even part */ \ + dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ + __m128i sum04 = _mm_add_epi16(row0, row4); \ + __m128i dif04 = _mm_sub_epi16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ + dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ + __m128i sum17 = _mm_add_epi16(row1, row7); \ + __m128i sum35 = _mm_add_epi16(row3, row5); \ + dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ + dct_wadd(x4, y0o, y4o); \ + dct_wadd(x5, y1o, y5o); \ + dct_wadd(x6, y2o, y5o); \ + dct_wadd(x7, y3o, y4o); \ + dct_bfly32o(row0,row7, x0,x7,bias,shift); \ + dct_bfly32o(row1,row6, x1,x6,bias,shift); \ + dct_bfly32o(row2,row5, x2,x5,bias,shift); \ + dct_bfly32o(row3,row4, x3,x4,bias,shift); \ + } while ( 0 ) + + __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); + __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); + __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); + __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); + __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); + __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); + __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); + __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); + + // rounding biases in column/row passes, see stbi__idct_block for explanation. + __m128i bias_0 = _mm_set1_epi32(512); + __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); + + // load + row0 = _mm_load_si128((const __m128i *) (data + 0*8)); + row1 = _mm_load_si128((const __m128i *) (data + 1*8)); + row2 = _mm_load_si128((const __m128i *) (data + 2*8)); + row3 = _mm_load_si128((const __m128i *) (data + 3*8)); + row4 = _mm_load_si128((const __m128i *) (data + 4*8)); + row5 = _mm_load_si128((const __m128i *) (data + 5*8)); + row6 = _mm_load_si128((const __m128i *) (data + 6*8)); + row7 = _mm_load_si128((const __m128i *) (data + 7*8)); + + // column pass + dct_pass(bias_0, 10); + + { + // 16bit 8x8 transpose pass 1 + dct_interleave16(row0, row4); + dct_interleave16(row1, row5); + dct_interleave16(row2, row6); + dct_interleave16(row3, row7); + + // transpose pass 2 + dct_interleave16(row0, row2); + dct_interleave16(row1, row3); + dct_interleave16(row4, row6); + dct_interleave16(row5, row7); + + // transpose pass 3 + dct_interleave16(row0, row1); + dct_interleave16(row2, row3); + dct_interleave16(row4, row5); + dct_interleave16(row6, row7); + } + + // row pass + dct_pass(bias_1, 17); + + { + // pack + __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 + __m128i p1 = _mm_packus_epi16(row2, row3); + __m128i p2 = _mm_packus_epi16(row4, row5); + __m128i p3 = _mm_packus_epi16(row6, row7); + + // 8bit 8x8 transpose pass 1 + dct_interleave8(p0, p2); // a0e0a1e1... + dct_interleave8(p1, p3); // c0g0c1g1... + + // transpose pass 2 + dct_interleave8(p0, p1); // a0c0e0g0... + dct_interleave8(p2, p3); // b0d0f0h0... + + // transpose pass 3 + dct_interleave8(p0, p2); // a0b0c0d0... + dct_interleave8(p1, p3); // a4b4c4d4... + + // store + _mm_storel_epi64((__m128i *) out, p0); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p2); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p1); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p3); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); + } + +#undef dct_const +#undef dct_rot +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_interleave8 +#undef dct_interleave16 +#undef dct_pass +} + +#endif // STBI_SSE2 + +#ifdef STBI_NEON + +// NEON integer IDCT. should produce bit-identical +// results to the generic C version. +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; + + int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); + int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); + int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); + int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); + int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); + int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); + int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); + int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); + int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); + int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); + int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); + int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); + +#define dct_long_mul(out, inq, coeff) \ + int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) + +#define dct_long_mac(out, acc, inq, coeff) \ + int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) + +#define dct_widen(out, inq) \ + int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ + int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) + +// wide add +#define dct_wadd(out, a, b) \ + int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vaddq_s32(a##_h, b##_h) + +// wide sub +#define dct_wsub(out, a, b) \ + int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vsubq_s32(a##_h, b##_h) + +// butterfly a/b, then shift using "shiftop" by "s" and pack +#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ + do { \ + dct_wadd(sum, a, b); \ + dct_wsub(dif, a, b); \ + out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ + out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ + } while ( 0 ) + +#define dct_pass(shiftop, shift) \ + do { \ + /* even part */ \ + int16x8_t sum26 = vaddq_s16(row2, row6); \ + dct_long_mul(p1e, sum26, rot0_0); \ + dct_long_mac(t2e, p1e, row6, rot0_1); \ + dct_long_mac(t3e, p1e, row2, rot0_2); \ + int16x8_t sum04 = vaddq_s16(row0, row4); \ + int16x8_t dif04 = vsubq_s16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + int16x8_t sum15 = vaddq_s16(row1, row5); \ + int16x8_t sum17 = vaddq_s16(row1, row7); \ + int16x8_t sum35 = vaddq_s16(row3, row5); \ + int16x8_t sum37 = vaddq_s16(row3, row7); \ + int16x8_t sumodd = vaddq_s16(sum17, sum35); \ + dct_long_mul(p5o, sumodd, rot1_0); \ + dct_long_mac(p1o, p5o, sum17, rot1_1); \ + dct_long_mac(p2o, p5o, sum35, rot1_2); \ + dct_long_mul(p3o, sum37, rot2_0); \ + dct_long_mul(p4o, sum15, rot2_1); \ + dct_wadd(sump13o, p1o, p3o); \ + dct_wadd(sump24o, p2o, p4o); \ + dct_wadd(sump23o, p2o, p3o); \ + dct_wadd(sump14o, p1o, p4o); \ + dct_long_mac(x4, sump13o, row7, rot3_0); \ + dct_long_mac(x5, sump24o, row5, rot3_1); \ + dct_long_mac(x6, sump23o, row3, rot3_2); \ + dct_long_mac(x7, sump14o, row1, rot3_3); \ + dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ + dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ + dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ + dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ + } while ( 0 ) + + // load + row0 = vld1q_s16(data + 0*8); + row1 = vld1q_s16(data + 1*8); + row2 = vld1q_s16(data + 2*8); + row3 = vld1q_s16(data + 3*8); + row4 = vld1q_s16(data + 4*8); + row5 = vld1q_s16(data + 5*8); + row6 = vld1q_s16(data + 6*8); + row7 = vld1q_s16(data + 7*8); + + // add DC bias + row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); + + // column pass + dct_pass(vrshrn_n_s32, 10); + + // 16bit 8x8 transpose + { +// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. +// whether compilers actually get this is another story, sadly. +#define dct_trn16(x, y) do { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } while ( 0 ) +#define dct_trn32(x, y) do { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } while ( 0 ) +#define dct_trn64(x, y) do { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } while ( 0 ) + + // pass 1 + dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 + dct_trn16(row2, row3); + dct_trn16(row4, row5); + dct_trn16(row6, row7); + + // pass 2 + dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 + dct_trn32(row1, row3); + dct_trn32(row4, row6); + dct_trn32(row5, row7); + + // pass 3 + dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 + dct_trn64(row1, row5); + dct_trn64(row2, row6); + dct_trn64(row3, row7); + +#undef dct_trn16 +#undef dct_trn32 +#undef dct_trn64 + } + + // row pass + // vrshrn_n_s32 only supports shifts up to 16, we need + // 17. so do a non-rounding shift of 16 first then follow + // up with a rounding shift by 1. + dct_pass(vshrn_n_s32, 16); + + { + // pack and round + uint8x8_t p0 = vqrshrun_n_s16(row0, 1); + uint8x8_t p1 = vqrshrun_n_s16(row1, 1); + uint8x8_t p2 = vqrshrun_n_s16(row2, 1); + uint8x8_t p3 = vqrshrun_n_s16(row3, 1); + uint8x8_t p4 = vqrshrun_n_s16(row4, 1); + uint8x8_t p5 = vqrshrun_n_s16(row5, 1); + uint8x8_t p6 = vqrshrun_n_s16(row6, 1); + uint8x8_t p7 = vqrshrun_n_s16(row7, 1); + + // again, these can translate into one instruction, but often don't. +#define dct_trn8_8(x, y) do { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } while ( 0 ) +#define dct_trn8_16(x, y) do { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } while ( 0 ) +#define dct_trn8_32(x, y) do { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } while ( 0 ) + + // sadly can't use interleaved stores here since we only write + // 8 bytes to each scan line! + + // 8x8 8-bit transpose pass 1 + dct_trn8_8(p0, p1); + dct_trn8_8(p2, p3); + dct_trn8_8(p4, p5); + dct_trn8_8(p6, p7); + + // pass 2 + dct_trn8_16(p0, p2); + dct_trn8_16(p1, p3); + dct_trn8_16(p4, p6); + dct_trn8_16(p5, p7); + + // pass 3 + dct_trn8_32(p0, p4); + dct_trn8_32(p1, p5); + dct_trn8_32(p2, p6); + dct_trn8_32(p3, p7); + + // store + vst1_u8(out, p0); out += out_stride; + vst1_u8(out, p1); out += out_stride; + vst1_u8(out, p2); out += out_stride; + vst1_u8(out, p3); out += out_stride; + vst1_u8(out, p4); out += out_stride; + vst1_u8(out, p5); out += out_stride; + vst1_u8(out, p6); out += out_stride; + vst1_u8(out, p7); + +#undef dct_trn8_8 +#undef dct_trn8_16 +#undef dct_trn8_32 + } + +#undef dct_long_mul +#undef dct_long_mac +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_pass +} + +#endif // STBI_NEON + +#define STBI__MARKER_none 0xff +// if there's a pending marker from the entropy stream, return that +// otherwise, fetch from the stream and get a marker. if there's no +// marker, return 0xff, which is never a valid marker value +static stbi_uc stbi__get_marker(stbi__jpeg *j) +{ + stbi_uc x; + if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } + x = stbi__get8(j->s); + if (x != 0xff) return STBI__MARKER_none; + while (x == 0xff) + x = stbi__get8(j->s); // consume repeated 0xff fill bytes + return x; +} + +// in each scan, we'll have scan_n components, and the order +// of the components is specified by order[] +#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) + +// after a restart interval, stbi__jpeg_reset the entropy decoder and +// the dc prediction +static void stbi__jpeg_reset(stbi__jpeg *j) +{ + j->code_bits = 0; + j->code_buffer = 0; + j->nomore = 0; + j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0; + j->marker = STBI__MARKER_none; + j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; + j->eob_run = 0; + // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, + // since we don't even allow 1<<30 pixels +} + +static int stbi__parse_entropy_coded_data(stbi__jpeg *z) +{ + stbi__jpeg_reset(z); + if (!z->progressive) { + if (z->scan_n == 1) { + int i,j; + STBI_SIMD_ALIGN(short, data[64]); + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + STBI_SIMD_ALIGN(short, data[64]); + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x)*8; + int y2 = (j*z->img_comp[n].v + y)*8; + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } else { + if (z->scan_n == 1) { + int i,j; + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + if (z->spec_start == 0) { + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } else { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) + return 0; + } + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x); + int y2 = (j*z->img_comp[n].v + y); + short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } +} + +static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) +{ + int i; + for (i=0; i < 64; ++i) + data[i] *= dequant[i]; +} + +static void stbi__jpeg_finish(stbi__jpeg *z) +{ + if (z->progressive) { + // dequantize and idct the data + int i,j,n; + for (n=0; n < z->s->img_n; ++n) { + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + } + } + } + } +} + +static int stbi__process_marker(stbi__jpeg *z, int m) +{ + int L; + switch (m) { + case STBI__MARKER_none: // no marker found + return stbi__err("expected marker","Corrupt JPEG"); + + case 0xDD: // DRI - specify restart interval + if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); + z->restart_interval = stbi__get16be(z->s); + return 1; + + case 0xDB: // DQT - define quantization table + L = stbi__get16be(z->s)-2; + while (L > 0) { + int q = stbi__get8(z->s); + int p = q >> 4, sixteen = (p != 0); + int t = q & 15,i; + if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG"); + if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); + + for (i=0; i < 64; ++i) + z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); + L -= (sixteen ? 129 : 65); + } + return L==0; + + case 0xC4: // DHT - define huffman table + L = stbi__get16be(z->s)-2; + while (L > 0) { + stbi_uc *v; + int sizes[16],i,n=0; + int q = stbi__get8(z->s); + int tc = q >> 4; + int th = q & 15; + if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); + for (i=0; i < 16; ++i) { + sizes[i] = stbi__get8(z->s); + n += sizes[i]; + } + if(n > 256) return stbi__err("bad DHT header","Corrupt JPEG"); // Loop over i < n would write past end of values! + L -= 17; + if (tc == 0) { + if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; + v = z->huff_dc[th].values; + } else { + if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; + v = z->huff_ac[th].values; + } + for (i=0; i < n; ++i) + v[i] = stbi__get8(z->s); + if (tc != 0) + stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); + L -= n; + } + return L==0; + } + + // check for comment block or APP blocks + if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { + L = stbi__get16be(z->s); + if (L < 2) { + if (m == 0xFE) + return stbi__err("bad COM len","Corrupt JPEG"); + else + return stbi__err("bad APP len","Corrupt JPEG"); + } + L -= 2; + + if (m == 0xE0 && L >= 5) { // JFIF APP0 segment + static const unsigned char tag[5] = {'J','F','I','F','\0'}; + int ok = 1; + int i; + for (i=0; i < 5; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 5; + if (ok) + z->jfif = 1; + } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment + static const unsigned char tag[6] = {'A','d','o','b','e','\0'}; + int ok = 1; + int i; + for (i=0; i < 6; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 6; + if (ok) { + stbi__get8(z->s); // version + stbi__get16be(z->s); // flags0 + stbi__get16be(z->s); // flags1 + z->app14_color_transform = stbi__get8(z->s); // color transform + L -= 6; + } + } + + stbi__skip(z->s, L); + return 1; + } + + return stbi__err("unknown marker","Corrupt JPEG"); +} + +// after we see SOS +static int stbi__process_scan_header(stbi__jpeg *z) +{ + int i; + int Ls = stbi__get16be(z->s); + z->scan_n = stbi__get8(z->s); + if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); + if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); + for (i=0; i < z->scan_n; ++i) { + int id = stbi__get8(z->s), which; + int q = stbi__get8(z->s); + for (which = 0; which < z->s->img_n; ++which) + if (z->img_comp[which].id == id) + break; + if (which == z->s->img_n) return 0; // no match + z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); + z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); + z->order[i] = which; + } + + { + int aa; + z->spec_start = stbi__get8(z->s); + z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 + aa = stbi__get8(z->s); + z->succ_high = (aa >> 4); + z->succ_low = (aa & 15); + if (z->progressive) { + if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) + return stbi__err("bad SOS", "Corrupt JPEG"); + } else { + if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); + if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); + z->spec_end = 63; + } + } + + return 1; +} + +static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) +{ + int i; + for (i=0; i < ncomp; ++i) { + if (z->img_comp[i].raw_data) { + STBI_FREE(z->img_comp[i].raw_data); + z->img_comp[i].raw_data = NULL; + z->img_comp[i].data = NULL; + } + if (z->img_comp[i].raw_coeff) { + STBI_FREE(z->img_comp[i].raw_coeff); + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].coeff = 0; + } + if (z->img_comp[i].linebuf) { + STBI_FREE(z->img_comp[i].linebuf); + z->img_comp[i].linebuf = NULL; + } + } + return why; +} + +static int stbi__process_frame_header(stbi__jpeg *z, int scan) +{ + stbi__context *s = z->s; + int Lf,p,i,q, h_max=1,v_max=1,c; + Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG + p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline + s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG + s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + c = stbi__get8(s); + if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); + s->img_n = c; + for (i=0; i < c; ++i) { + z->img_comp[i].data = NULL; + z->img_comp[i].linebuf = NULL; + } + + if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); + + z->rgb = 0; + for (i=0; i < s->img_n; ++i) { + static const unsigned char rgb[3] = { 'R', 'G', 'B' }; + z->img_comp[i].id = stbi__get8(s); + if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) + ++z->rgb; + q = stbi__get8(s); + z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); + z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); + z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); + } + + if (scan != STBI__SCAN_load) return 1; + + if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode"); + + for (i=0; i < s->img_n; ++i) { + if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; + if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; + } + + // check that plane subsampling factors are integer ratios; our resamplers can't deal with fractional ratios + // and I've never seen a non-corrupted JPEG file actually use them + for (i=0; i < s->img_n; ++i) { + if (h_max % z->img_comp[i].h != 0) return stbi__err("bad H","Corrupt JPEG"); + if (v_max % z->img_comp[i].v != 0) return stbi__err("bad V","Corrupt JPEG"); + } + + // compute interleaved mcu info + z->img_h_max = h_max; + z->img_v_max = v_max; + z->img_mcu_w = h_max * 8; + z->img_mcu_h = v_max * 8; + // these sizes can't be more than 17 bits + z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; + z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; + + for (i=0; i < s->img_n; ++i) { + // number of effective pixels (e.g. for non-interleaved MCU) + z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; + z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; + // to simplify generation, we'll allocate enough memory to decode + // the bogus oversized data from using interleaved MCUs and their + // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't + // discard the extra data until colorspace conversion + // + // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) + // so these muls can't overflow with 32-bit ints (which we require) + z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; + z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; + z->img_comp[i].coeff = 0; + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].linebuf = NULL; + z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); + if (z->img_comp[i].raw_data == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + // align blocks for idct using mmx/sse + z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); + if (z->progressive) { + // w2, h2 are multiples of 8 (see above) + z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; + z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; + z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); + if (z->img_comp[i].raw_coeff == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); + } + } + + return 1; +} + +// use comparisons since in some cases we handle more than one case (e.g. SOF) +#define stbi__DNL(x) ((x) == 0xdc) +#define stbi__SOI(x) ((x) == 0xd8) +#define stbi__EOI(x) ((x) == 0xd9) +#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) +#define stbi__SOS(x) ((x) == 0xda) + +#define stbi__SOF_progressive(x) ((x) == 0xc2) + +static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) +{ + int m; + z->jfif = 0; + z->app14_color_transform = -1; // valid values are 0,1,2 + z->marker = STBI__MARKER_none; // initialize cached marker to empty + m = stbi__get_marker(z); + if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); + if (scan == STBI__SCAN_type) return 1; + m = stbi__get_marker(z); + while (!stbi__SOF(m)) { + if (!stbi__process_marker(z,m)) return 0; + m = stbi__get_marker(z); + while (m == STBI__MARKER_none) { + // some files have extra padding after their blocks, so ok, we'll scan + if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); + m = stbi__get_marker(z); + } + } + z->progressive = stbi__SOF_progressive(m); + if (!stbi__process_frame_header(z, scan)) return 0; + return 1; +} + +static stbi_uc stbi__skip_jpeg_junk_at_end(stbi__jpeg *j) +{ + // some JPEGs have junk at end, skip over it but if we find what looks + // like a valid marker, resume there + while (!stbi__at_eof(j->s)) { + stbi_uc x = stbi__get8(j->s); + while (x == 0xff) { // might be a marker + if (stbi__at_eof(j->s)) return STBI__MARKER_none; + x = stbi__get8(j->s); + if (x != 0x00 && x != 0xff) { + // not a stuffed zero or lead-in to another marker, looks + // like an actual marker, return it + return x; + } + // stuffed zero has x=0 now which ends the loop, meaning we go + // back to regular scan loop. + // repeated 0xff keeps trying to read the next byte of the marker. + } + } + return STBI__MARKER_none; +} + +// decode image to YCbCr format +static int stbi__decode_jpeg_image(stbi__jpeg *j) +{ + int m; + for (m = 0; m < 4; m++) { + j->img_comp[m].raw_data = NULL; + j->img_comp[m].raw_coeff = NULL; + } + j->restart_interval = 0; + if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; + m = stbi__get_marker(j); + while (!stbi__EOI(m)) { + if (stbi__SOS(m)) { + if (!stbi__process_scan_header(j)) return 0; + if (!stbi__parse_entropy_coded_data(j)) return 0; + if (j->marker == STBI__MARKER_none ) { + j->marker = stbi__skip_jpeg_junk_at_end(j); + // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 + } + m = stbi__get_marker(j); + if (STBI__RESTART(m)) + m = stbi__get_marker(j); + } else if (stbi__DNL(m)) { + int Ld = stbi__get16be(j->s); + stbi__uint32 NL = stbi__get16be(j->s); + if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); + if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); + m = stbi__get_marker(j); + } else { + if (!stbi__process_marker(j, m)) return 1; + m = stbi__get_marker(j); + } + } + if (j->progressive) + stbi__jpeg_finish(j); + return 1; +} + +// static jfif-centered resampling (across block boundaries) + +typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, + int w, int hs); + +#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) + +static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + STBI_NOTUSED(out); + STBI_NOTUSED(in_far); + STBI_NOTUSED(w); + STBI_NOTUSED(hs); + return in_near; +} + +static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples vertically for every one in input + int i; + STBI_NOTUSED(hs); + for (i=0; i < w; ++i) + out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); + return out; +} + +static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples horizontally for every one in input + int i; + stbi_uc *input = in_near; + + if (w == 1) { + // if only one sample, can't do any interpolation + out[0] = out[1] = input[0]; + return out; + } + + out[0] = input[0]; + out[1] = stbi__div4(input[0]*3 + input[1] + 2); + for (i=1; i < w-1; ++i) { + int n = 3*input[i]+2; + out[i*2+0] = stbi__div4(n+input[i-1]); + out[i*2+1] = stbi__div4(n+input[i+1]); + } + out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); + out[i*2+1] = input[w-1]; + + STBI_NOTUSED(in_far); + STBI_NOTUSED(hs); + + return out; +} + +#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) + +static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i,t0,t1; + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + out[0] = stbi__div4(t1+2); + for (i=1; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i=0,t0,t1; + + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + // process groups of 8 pixels for as long as we can. + // note we can't handle the last pixel in a row in this loop + // because we need to handle the filter boundary conditions. + for (; i < ((w-1) & ~7); i += 8) { +#if defined(STBI_SSE2) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + __m128i zero = _mm_setzero_si128(); + __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); + __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); + __m128i farw = _mm_unpacklo_epi8(farb, zero); + __m128i nearw = _mm_unpacklo_epi8(nearb, zero); + __m128i diff = _mm_sub_epi16(farw, nearw); + __m128i nears = _mm_slli_epi16(nearw, 2); + __m128i curr = _mm_add_epi16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + __m128i prv0 = _mm_slli_si128(curr, 2); + __m128i nxt0 = _mm_srli_si128(curr, 2); + __m128i prev = _mm_insert_epi16(prv0, t1, 0); + __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + __m128i bias = _mm_set1_epi16(8); + __m128i curs = _mm_slli_epi16(curr, 2); + __m128i prvd = _mm_sub_epi16(prev, curr); + __m128i nxtd = _mm_sub_epi16(next, curr); + __m128i curb = _mm_add_epi16(curs, bias); + __m128i even = _mm_add_epi16(prvd, curb); + __m128i odd = _mm_add_epi16(nxtd, curb); + + // interleave even and odd pixels, then undo scaling. + __m128i int0 = _mm_unpacklo_epi16(even, odd); + __m128i int1 = _mm_unpackhi_epi16(even, odd); + __m128i de0 = _mm_srli_epi16(int0, 4); + __m128i de1 = _mm_srli_epi16(int1, 4); + + // pack and write output + __m128i outv = _mm_packus_epi16(de0, de1); + _mm_storeu_si128((__m128i *) (out + i*2), outv); +#elif defined(STBI_NEON) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + uint8x8_t farb = vld1_u8(in_far + i); + uint8x8_t nearb = vld1_u8(in_near + i); + int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); + int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); + int16x8_t curr = vaddq_s16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + int16x8_t prv0 = vextq_s16(curr, curr, 7); + int16x8_t nxt0 = vextq_s16(curr, curr, 1); + int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); + int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + int16x8_t curs = vshlq_n_s16(curr, 2); + int16x8_t prvd = vsubq_s16(prev, curr); + int16x8_t nxtd = vsubq_s16(next, curr); + int16x8_t even = vaddq_s16(curs, prvd); + int16x8_t odd = vaddq_s16(curs, nxtd); + + // undo scaling and round, then store with even/odd phases interleaved + uint8x8x2_t o; + o.val[0] = vqrshrun_n_s16(even, 4); + o.val[1] = vqrshrun_n_s16(odd, 4); + vst2_u8(out + i*2, o); +#endif + + // "previous" value for next iter + t1 = 3*in_near[i+7] + in_far[i+7]; + } + + t0 = t1; + t1 = 3*in_near[i] + in_far[i]; + out[i*2] = stbi__div16(3*t1 + t0 + 8); + + for (++i; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} +#endif + +static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // resample with nearest-neighbor + int i,j; + STBI_NOTUSED(in_far); + for (i=0; i < w; ++i) + for (j=0; j < hs; ++j) + out[i*hs+j] = in_near[i]; + return out; +} + +// this is a reduced-precision calculation of YCbCr-to-RGB introduced +// to make sure the code produces the same results in both SIMD and scalar +#define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) +{ + int i = 0; + +#ifdef STBI_SSE2 + // step == 3 is pretty ugly on the final interleave, and i'm not convinced + // it's useful in practice (you wouldn't use it for textures, for example). + // so just accelerate step == 4 case. + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + __m128i signflip = _mm_set1_epi8(-0x80); + __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); + __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); + __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); + __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); + __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); + __m128i xw = _mm_set1_epi16(255); // alpha channel + + for (; i+7 < count; i += 8) { + // load + __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); + __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); + __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); + __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 + __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 + + // unpack to short (and left-shift cr, cb by 8) + __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); + __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); + __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); + + // color transform + __m128i yws = _mm_srli_epi16(yw, 4); + __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); + __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); + __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); + __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); + __m128i rws = _mm_add_epi16(cr0, yws); + __m128i gwt = _mm_add_epi16(cb0, yws); + __m128i bws = _mm_add_epi16(yws, cb1); + __m128i gws = _mm_add_epi16(gwt, cr1); + + // descale + __m128i rw = _mm_srai_epi16(rws, 4); + __m128i bw = _mm_srai_epi16(bws, 4); + __m128i gw = _mm_srai_epi16(gws, 4); + + // back to byte, set up for transpose + __m128i brb = _mm_packus_epi16(rw, bw); + __m128i gxb = _mm_packus_epi16(gw, xw); + + // transpose to interleave channels + __m128i t0 = _mm_unpacklo_epi8(brb, gxb); + __m128i t1 = _mm_unpackhi_epi8(brb, gxb); + __m128i o0 = _mm_unpacklo_epi16(t0, t1); + __m128i o1 = _mm_unpackhi_epi16(t0, t1); + + // store + _mm_storeu_si128((__m128i *) (out + 0), o0); + _mm_storeu_si128((__m128i *) (out + 16), o1); + out += 32; + } + } +#endif + +#ifdef STBI_NEON + // in this version, step=3 support would be easy to add. but is there demand? + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + uint8x8_t signflip = vdup_n_u8(0x80); + int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); + int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); + int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); + int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); + + for (; i+7 < count; i += 8) { + // load + uint8x8_t y_bytes = vld1_u8(y + i); + uint8x8_t cr_bytes = vld1_u8(pcr + i); + uint8x8_t cb_bytes = vld1_u8(pcb + i); + int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); + int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); + + // expand to s16 + int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); + int16x8_t crw = vshll_n_s8(cr_biased, 7); + int16x8_t cbw = vshll_n_s8(cb_biased, 7); + + // color transform + int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); + int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); + int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); + int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); + int16x8_t rws = vaddq_s16(yws, cr0); + int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); + int16x8_t bws = vaddq_s16(yws, cb1); + + // undo scaling, round, convert to byte + uint8x8x4_t o; + o.val[0] = vqrshrun_n_s16(rws, 4); + o.val[1] = vqrshrun_n_s16(gws, 4); + o.val[2] = vqrshrun_n_s16(bws, 4); + o.val[3] = vdup_n_u8(255); + + // store, interleaving r/g/b/a + vst4_u8(out, o); + out += 8*4; + } + } +#endif + + for (; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#endif + +// set up the kernels +static void stbi__setup_jpeg(stbi__jpeg *j) +{ + j->idct_block_kernel = stbi__idct_block; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; + +#ifdef STBI_SSE2 + if (stbi__sse2_available()) { + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + } +#endif + +#ifdef STBI_NEON + if (SDL_HasNEON()) { /* SDL change */ + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + } /**/ +#endif +} + +// clean up the temporary component buffers +static void stbi__cleanup_jpeg(stbi__jpeg *j) +{ + stbi__free_jpeg_components(j, j->s->img_n, 0); +} + +typedef struct +{ + resample_row_func resample; + stbi_uc *line0,*line1; + int hs,vs; // expansion factor in each axis + int w_lores; // horizontal pixels pre-expansion + int ystep; // how far through vertical expansion we are + int ypos; // which pre-expansion row we're on +} stbi__resample; + +// fast 0..255 * 0..255 => 0..255 rounded multiplication +static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) +{ + unsigned int t = x*y + 128; + return (stbi_uc) ((t + (t >>8)) >> 8); +} + +static stbi_uc *output_jpeg_nv12(stbi__jpeg *z, stbi__nv12 *nv12) +{ + unsigned int i,j; + + // Copy the Y plane + if (nv12->pitch == (int)z->s->img_x) { + memcpy(nv12->y, z->img_comp[0].data, z->s->img_y * z->s->img_x); + } else { + for (i=0; i < z->s->img_y; ++i) { + memcpy(nv12->y + i * nv12->pitch, z->img_comp[0].data + i * z->s->img_x, z->s->img_x); + } + } + + if (z->s->img_n == 3) { + // NV12: U and V are interleaved, each subsampled by 2 + const int nv12_hs = 2; + const int nv12_vs = 2; + const int u_hs = (z->img_h_max / z->img_comp[1].h); + const int u_vs = (z->img_v_max / z->img_comp[1].v); + const int v_hs = (z->img_h_max / z->img_comp[2].h); + const int v_vs = (z->img_v_max / z->img_comp[2].v); + for (i=0; i < (z->s->img_y + 1) / 2; ++i) { + stbi_uc *src_u = z->img_comp[1].data + i * (1 + (nv12_vs - u_vs)) * z->img_comp[1].x; + stbi_uc *src_v = z->img_comp[2].data + i * (1 + (nv12_vs - v_vs)) * z->img_comp[2].x; + stbi_uc *dst = nv12->uv + i * nv12->pitch; + for (j=0; j < (z->s->img_x + 1) / 2; ++j) { + *dst++ = *src_u; + src_u += 1 + (nv12_hs - u_hs); + *dst++ = *src_v; + src_v += 1 + (nv12_hs - v_hs); + } + } + } else { + // Grayscale + for (i=0; i < (z->s->img_y + 1) / 2; ++i) { + memset(nv12->uv + i * nv12->pitch, 0x80808080, ((z->s->img_x + 1) / 2) * 2); + } + } + + return nv12->y; +} + +static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp, stbi__nv12 *nv12) +{ + int n, decode_n, is_rgb; + z->s->img_n = 0; // make stbi__cleanup_jpeg safe + + // validate req_comp + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + + // load a jpeg image from whichever source, but leave in YCbCr format + if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } + + // determine actual number of components to generate + n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; + + is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); + + if (z->s->img_n == 3 && n < 3 && !is_rgb) + decode_n = 1; + else + decode_n = z->s->img_n; + + // nothing to do if no components requested; check this now to avoid + // accessing uninitialized coutput[0] later + if (decode_n <= 0) { stbi__cleanup_jpeg(z); return NULL; } + + // resample and color-convert + { + int k; + unsigned int i,j; + stbi_uc *output; + stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL }; + + stbi__resample res_comp[4]; + + if (nv12) { + if (nv12->w != (int)z->s->img_x || nv12->h != (int)z->s->img_y) { + stbi__cleanup_jpeg(z); + return stbi__errpuc("badsize", "Unexpected size"); + } + + if (is_rgb) { + stbi__cleanup_jpeg(z); + return stbi__errpuc("rgbtonv12", "Can't convert RGB to NV12"); + } + + output = output_jpeg_nv12(z, nv12); + } else { + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + + // allocate line buffer big enough for upsampling off the edges + // with upsample factor of 4 + z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); + if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + r->hs = z->img_h_max / z->img_comp[k].h; + r->vs = z->img_v_max / z->img_comp[k].v; + r->ystep = r->vs >> 1; + r->w_lores = (z->s->img_x + r->hs-1) / r->hs; + r->ypos = 0; + r->line0 = r->line1 = z->img_comp[k].data; + + if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; + else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; + else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; + else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; + else r->resample = stbi__resample_row_generic; + } + + // can't error after this so, this is safe + output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); + if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + // now go ahead and resample + for (j=0; j < z->s->img_y; ++j) { + stbi_uc *out = output + n * z->s->img_x * j; + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + int y_bot = r->ystep >= (r->vs >> 1); + coutput[k] = r->resample(z->img_comp[k].linebuf, + y_bot ? r->line1 : r->line0, + y_bot ? r->line0 : r->line1, + r->w_lores, r->hs); + if (++r->ystep >= r->vs) { + r->ystep = 0; + r->line0 = r->line1; + if (++r->ypos < z->img_comp[k].y) + r->line1 += z->img_comp[k].w2; + } + } + if (n >= 3) { + stbi_uc *y = coutput[0]; + if (z->s->img_n == 3) { + if (is_rgb) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = y[i]; + out[1] = coutput[1][i]; + out[2] = coutput[2][i]; + out[3] = 255; + out += n; + } + } else { + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else if (z->s->img_n == 4) { + if (z->app14_color_transform == 0) { // CMYK + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(coutput[0][i], m); + out[1] = stbi__blinn_8x8(coutput[1][i], m); + out[2] = stbi__blinn_8x8(coutput[2][i], m); + out[3] = 255; + out += n; + } + } else if (z->app14_color_transform == 2) { // YCCK + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(255 - out[0], m); + out[1] = stbi__blinn_8x8(255 - out[1], m); + out[2] = stbi__blinn_8x8(255 - out[2], m); + out += n; + } + } else { // YCbCr + alpha? Ignore the fourth channel for now + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else + for (i=0; i < z->s->img_x; ++i) { + out[0] = out[1] = out[2] = y[i]; + out[3] = 255; // not used if n==3 + out += n; + } + } else { + if (is_rgb) { + if (n == 1) + for (i=0; i < z->s->img_x; ++i) + *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + else { + for (i=0; i < z->s->img_x; ++i, out += 2) { + out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + out[1] = 255; + } + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); + stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); + stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); + out[0] = stbi__compute_y(r, g, b); + out[1] = 255; + out += n; + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); + out[1] = 255; + out += n; + } + } else { + stbi_uc *y = coutput[0]; + if (n == 1) + for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; + else + for (i=0; i < z->s->img_x; ++i) { *out++ = y[i]; *out++ = 255; } + } + } + } + } + stbi__cleanup_jpeg(z); + *out_x = z->s->img_x; + *out_y = z->s->img_y; + if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output + return output; + } +} + +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__nv12 *nv12, stbi__result_info *ri) +{ + unsigned char* result; + stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); + if (!j) return stbi__errpuc("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); + STBI_NOTUSED(ri); + j->s = s; + stbi__setup_jpeg(j); + result = load_jpeg_image(j, x,y,comp,req_comp,nv12); + STBI_FREE(j); + return result; +} + +static int stbi__jpeg_test(stbi__context *s) +{ + int r; + stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); + if (!j) return stbi__err("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); + j->s = s; + stbi__setup_jpeg(j); + r = stbi__decode_jpeg_header(j, STBI__SCAN_type); + stbi__rewind(s); + STBI_FREE(j); + return r; +} + +#if 0 /* not used in SDL */ +static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) +{ + if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { + stbi__rewind( j->s ); + return 0; + } + if (x) *x = j->s->img_x; + if (y) *y = j->s->img_y; + if (comp) *comp = j->s->img_n >= 3 ? 3 : 1; + return 1; +} + +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) +{ + int result; + stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); + if (!j) return stbi__err("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); + j->s = s; + result = stbi__jpeg_info_raw(j, x, y, comp); + STBI_FREE(j); + return result; +} +#endif /**/ +#endif + +// public domain zlib decode v0.2 Sean Barrett 2006-11-18 +// simple implementation +// - all input must be provided in an upfront buffer +// - all output is written to a single output buffer (can malloc/realloc) +// performance +// - fast huffman + +#ifndef STBI_NO_ZLIB + +// fast-way is faster to check than jpeg huffman, but slow way is slower +#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables +#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) +#define STBI__ZNSYMS 288 // number of symbols in literal/length alphabet + +// zlib-style huffman encoding +// (jpegs packs from left, zlib from right, so can't share code) +typedef struct +{ + stbi__uint16 fast[1 << STBI__ZFAST_BITS]; + stbi__uint16 firstcode[16]; + int maxcode[17]; + stbi__uint16 firstsymbol[16]; + stbi_uc size[STBI__ZNSYMS]; + stbi__uint16 value[STBI__ZNSYMS]; +} stbi__zhuffman; + +stbi_inline static int stbi__bitreverse16(int n) +{ + n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); + n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); + n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); + n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); + return n; +} + +stbi_inline static int stbi__bit_reverse(int v, int bits) +{ + STBI_ASSERT(bits <= 16); + // to bit reverse n bits, reverse 16 and shift + // e.g. 11 bits, bit reverse and shift away 5 + return stbi__bitreverse16(v) >> (16-bits); +} + +static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num) +{ + int i,k=0; + int code, next_code[16], sizes[17]; + + // DEFLATE spec for generating codes + memset(sizes, 0, sizeof(sizes)); + memset(z->fast, 0, sizeof(z->fast)); + for (i=0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for (i=1; i < 16; ++i) + if (sizes[i] > (1 << i)) + return stbi__err("bad sizes", "Corrupt PNG"); + code = 0; + for (i=1; i < 16; ++i) { + next_code[i] = code; + z->firstcode[i] = (stbi__uint16) code; + z->firstsymbol[i] = (stbi__uint16) k; + code = (code + sizes[i]); + if (sizes[i]) + if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); + z->maxcode[i] = code << (16-i); // preshift for inner loop + code <<= 1; + k += sizes[i]; + } + z->maxcode[16] = 0x10000; // sentinel + for (i=0; i < num; ++i) { + int s = sizelist[i]; + if (s) { + int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); + z->size [c] = (stbi_uc ) s; + z->value[c] = (stbi__uint16) i; + if (s <= STBI__ZFAST_BITS) { + int j = stbi__bit_reverse(next_code[s],s); + while (j < (1 << STBI__ZFAST_BITS)) { + z->fast[j] = fastv; + j += (1 << s); + } + } + ++next_code[s]; + } + } + return 1; +} + +// zlib-from-memory implementation for PNG reading +// because PNG allows splitting the zlib stream arbitrarily, +// and it's annoying structurally to have PNG call ZLIB call PNG, +// we require PNG read all the IDATs and combine them into a single +// memory buffer + +typedef struct +{ + stbi_uc *zbuffer, *zbuffer_end; + int num_bits; + int hit_zeof_once; + stbi__uint32 code_buffer; + + char *zout; + char *zout_start; + char *zout_end; + int z_expandable; + + stbi__zhuffman z_length, z_distance; +} stbi__zbuf; + +stbi_inline static int stbi__zeof(stbi__zbuf *z) +{ + return (z->zbuffer >= z->zbuffer_end); +} + +stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) +{ + return stbi__zeof(z) ? 0 : *z->zbuffer++; +} + +static void stbi__fill_bits(stbi__zbuf *z) +{ + do { + if (z->code_buffer >= (1U << z->num_bits)) { + z->zbuffer = z->zbuffer_end; /* treat this as EOF so we fail. */ + return; + } + z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; + z->num_bits += 8; + } while (z->num_bits <= 24); +} + +stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) +{ + unsigned int k; + if (z->num_bits < n) stbi__fill_bits(z); + k = z->code_buffer & ((1 << n) - 1); + z->code_buffer >>= n; + z->num_bits -= n; + return k; +} + +static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s,k; + // not resolved by fast table, so compute it the slow way + // use jpeg approach, which requires MSbits at top + k = stbi__bit_reverse(a->code_buffer, 16); + for (s=STBI__ZFAST_BITS+1; ; ++s) + if (k < z->maxcode[s]) + break; + if (s >= 16) return -1; // invalid code! + // code size is s, so: + b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; + if (b >= STBI__ZNSYMS) return -1; // some data was corrupt somewhere! + if (z->size[b] != s) return -1; // was originally an assert, but report failure instead. + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; +} + +stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s; + if (a->num_bits < 16) { + if (stbi__zeof(a)) { + if (!a->hit_zeof_once) { + // This is the first time we hit eof, insert 16 extra padding btis + // to allow us to keep going; if we actually consume any of them + // though, that is invalid data. This is caught later. + a->hit_zeof_once = 1; + a->num_bits += 16; // add 16 implicit zero bits + } else { + // We already inserted our extra 16 padding bits and are again + // out, this stream is actually prematurely terminated. + return -1; + } + } else { + stbi__fill_bits(a); + } + } + b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; + if (b) { + s = b >> 9; + a->code_buffer >>= s; + a->num_bits -= s; + return b & 511; + } + return stbi__zhuffman_decode_slowpath(a, z); +} + +static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes +{ + char *q; + unsigned int cur, limit, old_limit; + z->zout = zout; + if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); + cur = (unsigned int) (z->zout - z->zout_start); + limit = old_limit = (unsigned) (z->zout_end - z->zout_start); + if (UINT_MAX - cur < (unsigned) n) return stbi__err("outofmem", "Out of memory"); + while (cur + n > limit) { + if(limit > UINT_MAX / 2) return stbi__err("outofmem", "Out of memory"); + limit *= 2; + } + q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); + STBI_NOTUSED(old_limit); + if (q == NULL) return stbi__err("outofmem", "Out of memory"); + z->zout_start = q; + z->zout = q + cur; + z->zout_end = q + limit; + return 1; +} + +static const int stbi__zlength_base[31] = { + 3,4,5,6,7,8,9,10,11,13, + 15,17,19,23,27,31,35,43,51,59, + 67,83,99,115,131,163,195,227,258,0,0 }; + +static const int stbi__zlength_extra[31]= +{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + +static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, +257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + +static const int stbi__zdist_extra[32] = +{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +static int stbi__parse_huffman_block(stbi__zbuf *a) +{ + char *zout = a->zout; + for(;;) { + int z = stbi__zhuffman_decode(a, &a->z_length); + if (z < 256) { + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes + if (zout >= a->zout_end) { + if (!stbi__zexpand(a, zout, 1)) return 0; + zout = a->zout; + } + *zout++ = (char) z; + } else { + stbi_uc *p; + int len,dist; + if (z == 256) { + a->zout = zout; + if (a->hit_zeof_once && a->num_bits < 16) { + // The first time we hit zeof, we inserted 16 extra zero bits into our bit + // buffer so the decoder can just do its speculative decoding. But if we + // actually consumed any of those bits (which is the case when num_bits < 16), + // the stream actually read past the end so it is malformed. + return stbi__err("unexpected end","Corrupt PNG"); + } + return 1; + } + if (z >= 286) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data + z -= 257; + len = stbi__zlength_base[z]; + if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); + z = stbi__zhuffman_decode(a, &a->z_distance); + if (z < 0 || z >= 30) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, distance codes 30 and 31 must not appear in compressed data + dist = stbi__zdist_base[z]; + if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); + if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); + if (len > a->zout_end - zout) { + if (!stbi__zexpand(a, zout, len)) return 0; + zout = a->zout; + } + p = (stbi_uc *) (zout - dist); + if (dist == 1) { // run of one byte; common in images. + stbi_uc v = *p; + if (len) { do *zout++ = v; while (--len); } + } else { + if (len) { do *zout++ = *p++; while (--len); } + } + } + } +} + +static int stbi__compute_huffman_codes(stbi__zbuf *a) +{ + static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + stbi__zhuffman z_codelength; + stbi_uc lencodes[286+32+137];//padding for maximum single op + stbi_uc codelength_sizes[19]; + int i,n; + + int hlit = stbi__zreceive(a,5) + 257; + int hdist = stbi__zreceive(a,5) + 1; + int hclen = stbi__zreceive(a,4) + 4; + int ntot = hlit + hdist; + + memset(codelength_sizes, 0, sizeof(codelength_sizes)); + for (i=0; i < hclen; ++i) { + int s = stbi__zreceive(a,3); + codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; + } + if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + + n = 0; + while (n < ntot) { + int c = stbi__zhuffman_decode(a, &z_codelength); + if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); + if (c < 16) + lencodes[n++] = (stbi_uc) c; + else { + stbi_uc fill = 0; + if (c == 16) { + c = stbi__zreceive(a,2)+3; + if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); + fill = lencodes[n-1]; + } else if (c == 17) { + c = stbi__zreceive(a,3)+3; + } else if (c == 18) { + c = stbi__zreceive(a,7)+11; + } else { + return stbi__err("bad codelengths", "Corrupt PNG"); + } + if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); + memset(lencodes+n, fill, c); + n += c; + } + } + if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG"); + if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; + return 1; +} + +static int stbi__parse_uncompressed_block(stbi__zbuf *a) +{ + stbi_uc header[4]; + int len,nlen,k; + if (a->num_bits & 7) + stbi__zreceive(a, a->num_bits & 7); // discard + // drain the bit-packed data into header + k = 0; + while (a->num_bits > 0) { + header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check + a->code_buffer >>= 8; + a->num_bits -= 8; + } + if (a->num_bits < 0) return stbi__err("zlib corrupt","Corrupt PNG"); + // now fill header the normal way + while (k < 4) + header[k++] = stbi__zget8(a); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); + if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); + if (a->zout + len > a->zout_end) + if (!stbi__zexpand(a, a->zout, len)) return 0; + memcpy(a->zout, a->zbuffer, len); + a->zbuffer += len; + a->zout += len; + return 1; +} + +static int stbi__parse_zlib_header(stbi__zbuf *a) +{ + int cmf = stbi__zget8(a); + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = stbi__zget8(a); + if (stbi__zeof(a)) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png + if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; +} + +static const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] = +{ + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8 +}; +static const stbi_uc stbi__zdefault_distance[32] = +{ + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 +}; +/* +Init algorithm: +{ + int i; // use <= to match clearly with spec + for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; + for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; + for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; + for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; + + for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; +} +*/ + +static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) +{ + int final, type; + if (parse_header) + if (!stbi__parse_zlib_header(a)) return 0; + a->num_bits = 0; + a->code_buffer = 0; + a->hit_zeof_once = 0; + do { + final = stbi__zreceive(a,1); + type = stbi__zreceive(a,2); + if (type == 0) { + if (!stbi__parse_uncompressed_block(a)) return 0; + } else if (type == 3) { + return 0; + } else { + if (type == 1) { + // use fixed code lengths + if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , STBI__ZNSYMS)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; + } else { + if (!stbi__compute_huffman_codes(a)) return 0; + } + if (!stbi__parse_huffman_block(a)) return 0; + } + } while (!final); + return 1; +} + +static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) +{ + a->zout_start = obuf; + a->zout = obuf; + a->zout_end = obuf + olen; + a->z_expandable = exp; + + return stbi__parse_zlib(a, parse_header); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) +{ + return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) + return (int) (a.zout - a.zout_start); + else + return -1; +} + +STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(16384); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer+len; + if (stbi__do_zlib(&a, p, 16384, 1, 0)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) + return (int) (a.zout - a.zout_start); + else + return -1; +} +#endif + +// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 +// simple implementation +// - only 8-bit samples +// - no CRC checking +// - allocates lots of intermediate memory +// - avoids problem of streaming data between subsystems +// - avoids explicit window management +// performance +// - uses stb_zlib, a PD zlib implementation with fast huffman decoding + +#ifndef STBI_NO_PNG +typedef struct +{ + stbi__uint32 length; + stbi__uint32 type; +} stbi__pngchunk; + +static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) +{ + stbi__pngchunk c; + c.length = stbi__get32be(s); + c.type = stbi__get32be(s); + return c; +} + +static int stbi__check_png_header(stbi__context *s) +{ + static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; + int i; + for (i=0; i < 8; ++i) + if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); + return 1; +} + +typedef struct +{ + stbi__context *s; + stbi_uc *idata, *expanded, *out; + int depth; +} stbi__png; + + +enum { + STBI__F_none=0, + STBI__F_sub=1, + STBI__F_up=2, + STBI__F_avg=3, + STBI__F_paeth=4, + // synthetic filter used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first +}; + +static stbi_uc first_row_filter[5] = +{ + STBI__F_none, + STBI__F_sub, + STBI__F_none, + STBI__F_avg_first, + STBI__F_sub // Paeth with b=c=0 turns out to be equivalent to sub +}; + +static int stbi__paeth(int a, int b, int c) +{ + // This formulation looks very different from the reference in the PNG spec, but is + // actually equivalent and has favorable data dependencies and admits straightforward + // generation of branch-free code, which helps performance significantly. + int thresh = c*3 - (a + b); + int lo = a < b ? a : b; + int hi = a < b ? b : a; + int t0 = (hi <= thresh) ? lo : c; + int t1 = (thresh <= lo) ? hi : t0; + return t1; +} + +static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; + +// adds an extra all-255 alpha channel +// dest == src is legal +// img_n must be 1 or 3 +static void stbi__create_png_alpha_expand8(stbi_uc *dest, stbi_uc *src, stbi__uint32 x, int img_n) +{ + int i; + // must process data backwards since we allow dest==src + if (img_n == 1) { + for (i=x-1; i >= 0; --i) { + dest[i*2+1] = 255; + dest[i*2+0] = src[i]; + } + } else { + STBI_ASSERT(img_n == 3); + for (i=x-1; i >= 0; --i) { + dest[i*4+3] = 255; + dest[i*4+2] = src[i*3+2]; + dest[i*4+1] = src[i*3+1]; + dest[i*4+0] = src[i*3+0]; + } + } +} + +// create the png data from post-deflated data +static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) +{ + int bytes = (depth == 16 ? 2 : 1); + stbi__context *s = a->s; + stbi__uint32 i,j,stride = x*out_n*bytes; + stbi__uint32 img_len, img_width_bytes; + stbi_uc *filter_buf; + int all_ok = 1; + int k; + int img_n = s->img_n; // copy it into a local for later + + int output_bytes = out_n*bytes; + int filter_bytes = img_n*bytes; + int width = x; + + STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); + a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into + if (!a->out) return stbi__err("outofmem", "Out of memory"); + + // note: error exits here don't need to clean up a->out individually, + // stbi__do_png always does on error. + if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); + img_width_bytes = (((img_n * x * depth) + 7) >> 3); + if (!stbi__mad2sizes_valid(img_width_bytes, y, img_width_bytes)) return stbi__err("too large", "Corrupt PNG"); + img_len = (img_width_bytes + 1) * y; + + // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, + // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), + // so just check for raw_len < img_len always. + if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + + // Allocate two scan lines worth of filter workspace buffer. + filter_buf = (stbi_uc *) stbi__malloc_mad2(img_width_bytes, 2, 0); + if (!filter_buf) return stbi__err("outofmem", "Out of memory"); + + // Filtering for low-bit-depth images + if (depth < 8) { + filter_bytes = 1; + width = img_width_bytes; + } + + for (j=0; j < y; ++j) { + // cur/prior filter buffers alternate + stbi_uc *cur = filter_buf + (j & 1)*img_width_bytes; + stbi_uc *prior = filter_buf + (~j & 1)*img_width_bytes; + stbi_uc *dest = a->out + stride*j; + int nk = width * filter_bytes; + int filter = *raw++; + + // check filter type + if (filter > 4) { + all_ok = stbi__err("invalid filter","Corrupt PNG"); + break; + } + + // if first row, use special filter that doesn't sample previous row + if (j == 0) filter = first_row_filter[filter]; + + // perform actual filtering + switch (filter) { + case STBI__F_none: + memcpy(cur, raw, nk); + break; + case STBI__F_sub: + memcpy(cur, raw, filter_bytes); + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); + break; + case STBI__F_up: + for (k = 0; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + prior[k]); + break; + case STBI__F_avg: + for (k = 0; k < filter_bytes; ++k) + cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); + break; + case STBI__F_paeth: + for (k = 0; k < filter_bytes; ++k) + cur[k] = STBI__BYTECAST(raw[k] + prior[k]); // prior[k] == stbi__paeth(0,prior[k],0) + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes], prior[k], prior[k-filter_bytes])); + break; + case STBI__F_avg_first: + memcpy(cur, raw, filter_bytes); + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); + break; + } + + raw += nk; + + // expand decoded bits in cur to dest, also adding an extra alpha channel if desired + if (depth < 8) { + stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + stbi_uc *in = cur; + stbi_uc *out = dest; + stbi_uc inb = 0; + stbi__uint32 nsmp = x*img_n; + + // expand bits to bytes first + if (depth == 4) { + for (i=0; i < nsmp; ++i) { + if ((i & 1) == 0) inb = *in++; + *out++ = scale * (inb >> 4); + inb <<= 4; + } + } else if (depth == 2) { + for (i=0; i < nsmp; ++i) { + if ((i & 3) == 0) inb = *in++; + *out++ = scale * (inb >> 6); + inb <<= 2; + } + } else { + STBI_ASSERT(depth == 1); + for (i=0; i < nsmp; ++i) { + if ((i & 7) == 0) inb = *in++; + *out++ = scale * (inb >> 7); + inb <<= 1; + } + } + + // insert alpha=255 values if desired + if (img_n != out_n) + stbi__create_png_alpha_expand8(dest, dest, x, img_n); + } else if (depth == 8) { + if (img_n == out_n) + memcpy(dest, cur, x*img_n); + else + stbi__create_png_alpha_expand8(dest, cur, x, img_n); + } else if (depth == 16) { + // convert the image data from big-endian to platform-native + stbi__uint16 *dest16 = (stbi__uint16*)dest; + stbi__uint32 nsmp = x*img_n; + + if (img_n == out_n) { + for (i = 0; i < nsmp; ++i, ++dest16, cur += 2) + *dest16 = (cur[0] << 8) | cur[1]; + } else { + STBI_ASSERT(img_n+1 == out_n); + if (img_n == 1) { + for (i = 0; i < x; ++i, dest16 += 2, cur += 2) { + dest16[0] = (cur[0] << 8) | cur[1]; + dest16[1] = 0xffff; + } + } else { + STBI_ASSERT(img_n == 3); + for (i = 0; i < x; ++i, dest16 += 4, cur += 6) { + dest16[0] = (cur[0] << 8) | cur[1]; + dest16[1] = (cur[2] << 8) | cur[3]; + dest16[2] = (cur[4] << 8) | cur[5]; + dest16[3] = 0xffff; + } + } + } + } + } + + STBI_FREE(filter_buf); + if (!all_ok) return 0; + + return 1; +} + +static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) +{ + int bytes = (depth == 16 ? 2 : 1); + int out_bytes = out_n * bytes; + stbi_uc *final; + int p; + if (!interlaced) + return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); + + // de-interlacing + final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + if (!final) return stbi__err("outofmem", "Out of memory"); + for (p=0; p < 7; ++p) { + int xorig[] = { 0,4,0,2,0,1,0 }; + int yorig[] = { 0,0,4,0,2,0,1 }; + int xspc[] = { 8,8,4,4,2,2,1 }; + int yspc[] = { 8,8,8,4,4,2,2 }; + int i,j,x,y; + // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 + x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; + y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; + if (x && y) { + stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; + if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { + STBI_FREE(final); + return 0; + } + for (j=0; j < y; ++j) { + for (i=0; i < x; ++i) { + int out_y = j*yspc[p]+yorig[p]; + int out_x = i*xspc[p]+xorig[p]; + memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, + a->out + (j*x+i)*out_bytes, out_bytes); + } + } + STBI_FREE(a->out); + image_data += img_len; + image_data_len -= img_len; + } + } + a->out = final; + + return 1; +} + +static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + // compute color-based transparency, assuming we've + // already got 255 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i=0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 255); + p += 2; + } + } else { + for (i=0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi__uint16 *p = (stbi__uint16*) z->out; + + // compute color-based transparency, assuming we've + // already got 65535 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i = 0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 65535); + p += 2; + } + } else { + for (i = 0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) +{ + stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; + stbi_uc *p, *temp_out, *orig = a->out; + + p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); + if (p == NULL) return stbi__err("outofmem", "Out of memory"); + + // between here and free(out) below, exitting would leak + temp_out = p; + + if (pal_img_n == 3) { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p += 3; + } + } else { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p[3] = palette[n+3]; + p += 4; + } + } + STBI_FREE(a->out); + a->out = temp_out; + + STBI_NOTUSED(len); + + return 1; +} + +static int stbi__unpremultiply_on_load_global = 0; +static int stbi__de_iphone_flag_global = 0; + +#if 0 /* not used in SDL */ +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag_global = flag_true_if_should_convert; +} +#endif + +#ifndef STBI_THREAD_LOCAL +#define stbi__unpremultiply_on_load stbi__unpremultiply_on_load_global +#define stbi__de_iphone_flag stbi__de_iphone_flag_global +#else +static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set; +static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set; + +STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply; + stbi__unpremultiply_on_load_set = 1; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag_local = flag_true_if_should_convert; + stbi__de_iphone_flag_set = 1; +} + +#define stbi__unpremultiply_on_load (stbi__unpremultiply_on_load_set \ + ? stbi__unpremultiply_on_load_local \ + : stbi__unpremultiply_on_load_global) +#define stbi__de_iphone_flag (stbi__de_iphone_flag_set \ + ? stbi__de_iphone_flag_local \ + : stbi__de_iphone_flag_global) +#endif // STBI_THREAD_LOCAL + +static void stbi__de_iphone(stbi__png *z) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + if (s->img_out_n == 3) { // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 3; + } + } else { + STBI_ASSERT(s->img_out_n == 4); + if (stbi__unpremultiply_on_load) { + // convert bgr to rgb and unpremultiply + for (i=0; i < pixel_count; ++i) { + stbi_uc a = p[3]; + stbi_uc t = p[0]; + if (a) { + stbi_uc half = a / 2; + p[0] = (p[2] * 255 + half) / a; + p[1] = (p[1] * 255 + half) / a; + p[2] = ( t * 255 + half) / a; + } else { + p[0] = p[2]; + p[2] = t; + } + p += 4; + } + } else { + // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 4; + } + } + } +} + +#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d)) + +static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp, unsigned int *palette_buffer, int palette_buffer_len) +{ + stbi_uc _palette[1024], pal_img_n=0; + stbi_uc *palette = _palette; + stbi_uc has_trans=0, tc[3]={0}; + stbi__uint16 tc16[3]; + stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; + int first=1,k,interlace=0, color=0, is_iphone=0; + stbi__context *s = z->s; + + if (palette_buffer) { + if (palette_buffer_len < 256) + return stbi__err("palette buffer too small", "palette buffer len must be 256"); + else if (req_comp != 1) + return stbi__err("invalid req_comp", "req_comp must be 1 when loading paletted"); + else + palette = (stbi_uc *)(void *)palette_buffer; + } + + z->expanded = NULL; + z->idata = NULL; + z->out = NULL; + + if (!stbi__check_png_header(s)) return 0; + + if (scan == STBI__SCAN_type) return 1; + + for (;;) { + stbi__pngchunk c = stbi__get_chunk_header(s); + switch (c.type) { + case STBI__PNG_TYPE('C','g','B','I'): + is_iphone = 1; + stbi__skip(s, c.length); + break; + case STBI__PNG_TYPE('I','H','D','R'): { + int comp,filter; + if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); + first = 0; + if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); + s->img_x = stbi__get32be(s); + s->img_y = stbi__get32be(s); + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); + color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); + comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); + filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); + interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); + if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); + if (!pal_img_n) { + s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + } else { + // if paletted, then pal_n is our final components, and + // img_n is # components to decompress/filter. + s->img_n = 1; + if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); + } + // even with SCAN_header, have to scan to see if we have a tRNS + break; + } + + case STBI__PNG_TYPE('P','L','T','E'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); + pal_len = c.length / 3; + if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); + for (i=0; i < pal_len; ++i) { + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + } + break; + } + + case STBI__PNG_TYPE('t','R','N','S'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); + if (pal_img_n) { + if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } + if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); + if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); + pal_img_n = 4; + for (i=0; i < c.length; ++i) + palette[i*4+3] = stbi__get8(s); + } else { + if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); + if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); + has_trans = 1; + // non-paletted with tRNS = constant alpha. if header-scanning, we can stop now. + if (scan == STBI__SCAN_header) { ++s->img_n; return 1; } + if (z->depth == 16) { + for (k = 0; k < s->img_n && k < 3; ++k) // extra loop test to suppress false GCC warning + tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is + } else { + for (k = 0; k < s->img_n && k < 3; ++k) + tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger + } + } + break; + } + + case STBI__PNG_TYPE('I','D','A','T'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); + if (scan == STBI__SCAN_header) { + // header scan definitely stops at first IDAT + if (pal_img_n) + s->img_n = pal_img_n; + return 1; + } + if (c.length > (1u << 30)) return stbi__err("IDAT size limit", "IDAT section larger than 2^30 bytes"); + if ((int)(ioff + c.length) < (int)ioff) return 0; + if (ioff + c.length > idata_limit) { + stbi__uint32 idata_limit_old = idata_limit; + stbi_uc *p; + if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; + while (ioff + c.length > idata_limit) + idata_limit *= 2; + STBI_NOTUSED(idata_limit_old); + p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); + z->idata = p; + } + if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); + ioff += c.length; + break; + } + + case STBI__PNG_TYPE('I','E','N','D'): { + stbi__uint32 raw_len, bpl; + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (scan != STBI__SCAN_load) return 1; + if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); + // initial guess for decoded data size to avoid unnecessary reallocs + bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component + raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; + z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); + if (z->expanded == NULL) return 0; // zlib should set error + STBI_FREE(z->idata); z->idata = NULL; + if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) + s->img_out_n = s->img_n+1; + else + s->img_out_n = s->img_n; + if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; + if (has_trans) { + if (z->depth == 16) { + if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; + } else { + if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; + } + } + if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) + stbi__de_iphone(z); + if (pal_img_n) { + // pal_img_n == 3 or 4 + s->img_n = pal_img_n; // record the actual colors we had + s->img_out_n = pal_img_n; + if (req_comp >= 3) s->img_out_n = req_comp; + if (!palette_buffer) + if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) + return 0; + } else if (has_trans) { + // non-paletted image with tRNS -> source image has (constant) alpha + ++s->img_n; + } + STBI_FREE(z->expanded); z->expanded = NULL; + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + if (s->io.skip && s->img_buffer_end > s->img_buffer) { + // rewind the additional bytes that have been read to the buffer + (s->io.skip)(s->io_user_data, (int)(s->img_buffer - s->img_buffer_end)); + } + return 1; + } + + default: + // if critical, fail + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if ((c.type & (1 << 29)) == 0) { + #ifndef STBI_NO_FAILURE_STRINGS + // not threadsafe + static char invalid_chunk[] = "XXXX PNG chunk not known"; + invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); + invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); + invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); + invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); + (void)invalid_chunk; + #endif + return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); + } + stbi__skip(s, c.length); + break; + } + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + } +} + +static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, unsigned int *palette_buffer, int palette_buffer_len, stbi__result_info *ri) +{ + void *result=NULL; + if (palette_buffer && req_comp != 1) { + stbi__err("bad req_comp", "req_comp must be 1 if loading paletted image without expansion"); + return NULL; + } + if (req_comp < 0 || req_comp > 4) { + stbi__err("bad req_comp", "Internal error"); + return NULL; + } + if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp, palette_buffer, palette_buffer_len)) { + if (p->depth <= 8) + ri->bits_per_channel = 8; + else if (p->depth == 16) + ri->bits_per_channel = 16; + else + return stbi__errpuc("bad bits_per_channel", "PNG not supported: unsupported color depth"); + result = p->out; + p->out = NULL; + if (req_comp && req_comp != p->s->img_out_n) { + if (palette_buffer) + ; + else if (ri->bits_per_channel == 8) + result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + else + result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + p->s->img_out_n = req_comp; + if (result == NULL) return result; + } + *x = p->s->img_x; + *y = p->s->img_y; + if (n) { + if (palette_buffer) + *n = 1; + else + *n = p->s->img_n; + } + } + STBI_FREE(p->out); p->out = NULL; + STBI_FREE(p->expanded); p->expanded = NULL; + STBI_FREE(p->idata); p->idata = NULL; + + return result; +} + +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, unsigned int *palette_buffer, int palette_buffer_len, stbi__result_info *ri) +{ + stbi__png p; + p.s = s; + return stbi__do_png(&p, x,y,comp,req_comp, palette_buffer, palette_buffer_len, ri); +} + +static int stbi__png_test(stbi__context *s) +{ + int r; + r = stbi__check_png_header(s); + stbi__rewind(s); + return r; +} + +#if 0 /* not used in SDL */ +static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) +{ + if (!stbi__parse_png_file(p, STBI__SCAN_header, NULL, 0, NULL)) { + stbi__rewind( p->s ); + return 0; + } + if (x) *x = p->s->img_x; + if (y) *y = p->s->img_y; + if (comp) *comp = p->s->img_n; + return 1; +} + +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__png p; + p.s = s; + return stbi__png_info_raw(&p, x, y, comp); +} + +static int stbi__png_is16(stbi__context *s) +{ + stbi__png p; + p.s = s; + if (!stbi__png_info_raw(&p, NULL, NULL, NULL)) + return 0; + if (p.depth != 16) { + stbi__rewind(p.s); + return 0; + } + return 1; +} +#endif /**/ +#endif + +// Microsoft/Windows BMP image + +#ifndef STBI_NO_BMP +static int stbi__bmp_test_raw(stbi__context *s) +{ + int r; + int sz; + if (stbi__get8(s) != 'B') return 0; + if (stbi__get8(s) != 'M') return 0; + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + stbi__get32le(s); // discard data offset + sz = stbi__get32le(s); + r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); + return r; +} + +static int stbi__bmp_test(stbi__context *s) +{ + int r = stbi__bmp_test_raw(s); + stbi__rewind(s); + return r; +} + + +// returns 0..31 for the highest set bit +static int stbi__high_bit(unsigned int z) +{ + int n=0; + if (z == 0) return -1; + if (z >= 0x10000) { n += 16; z >>= 16; } + if (z >= 0x00100) { n += 8; z >>= 8; } + if (z >= 0x00010) { n += 4; z >>= 4; } + if (z >= 0x00004) { n += 2; z >>= 2; } + if (z >= 0x00002) { n += 1;/* >>= 1;*/ } + return n; +} + +static int stbi__bitcount(unsigned int a) +{ + a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 + a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits + a = (a + (a >> 8)); // max 16 per 8 bits + a = (a + (a >> 16)); // max 32 per 8 bits + return a & 0xff; +} + +// extract an arbitrarily-aligned N-bit value (N=bits) +// from v, and then make it 8-bits long and fractionally +// extend it to full full range. +static int stbi__shiftsigned(unsigned int v, int shift, int bits) +{ + static unsigned int mul_table[9] = { + 0, + 0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/, + 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/, + }; + static unsigned int shift_table[9] = { + 0, 0,0,1,0,2,4,6,0, + }; + if (shift < 0) + v <<= -shift; + else + v >>= shift; + STBI_ASSERT(v < 256); + v >>= (8-bits); + STBI_ASSERT(bits >= 0 && bits <= 8); + return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; +} + +typedef struct +{ + int bpp, offset, hsz; + unsigned int mr,mg,mb,ma, all_a; + int extra_read; +} stbi__bmp_data; + +static int stbi__bmp_set_mask_defaults(stbi__bmp_data *info, int compress) +{ + // BI_BITFIELDS specifies masks explicitly, don't override + if (compress == 3) + return 1; + + if (compress == 0) { + if (info->bpp == 16) { + info->mr = 31u << 10; + info->mg = 31u << 5; + info->mb = 31u << 0; + } else if (info->bpp == 32) { + info->mr = 0xffu << 16; + info->mg = 0xffu << 8; + info->mb = 0xffu << 0; + info->ma = 0xffu << 24; + info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + // otherwise, use defaults, which is all-0 + info->mr = info->mg = info->mb = info->ma = 0; + } + return 1; + } + return 0; // error +} + +static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) +{ + int hsz; + if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + info->offset = stbi__get32le(s); + info->hsz = hsz = stbi__get32le(s); + info->mr = info->mg = info->mb = info->ma = 0; + info->extra_read = 14; + + if (info->offset < 0) return stbi__errpuc("bad BMP", "bad BMP"); + + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); + if (hsz == 12) { + s->img_x = stbi__get16le(s); + s->img_y = stbi__get16le(s); + } else { + s->img_x = stbi__get32le(s); + s->img_y = stbi__get32le(s); + } + if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); + info->bpp = stbi__get16le(s); + if (hsz != 12) { + int compress = stbi__get32le(s); + if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + if (compress >= 4) return stbi__errpuc("BMP JPEG/PNG", "BMP type not supported: unsupported compression"); // this includes PNG/JPEG modes + if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc("bad BMP", "bad BMP"); // bitfields requires 16 or 32 bits/pixel + stbi__get32le(s); // discard sizeof + stbi__get32le(s); // discard hres + stbi__get32le(s); // discard vres + stbi__get32le(s); // discard colorsused + stbi__get32le(s); // discard max important + if (hsz == 40 || hsz == 56) { + if (hsz == 56) { + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + } + if (info->bpp == 16 || info->bpp == 32) { + if (compress == 0) { + stbi__bmp_set_mask_defaults(info, compress); + } else if (compress == 3) { + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->extra_read += 12; + // not documented, but generated by photoshop and handled by mspaint + if (info->mr == info->mg && info->mg == info->mb) { + // ?!?!? + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else { + // V4/V5 header + int i; + if (hsz != 108 && hsz != 124) + return stbi__errpuc("bad BMP", "bad BMP"); + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->ma = stbi__get32le(s); + if (compress != 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs + stbi__bmp_set_mask_defaults(info, compress); + stbi__get32le(s); // discard color space + for (i=0; i < 12; ++i) + stbi__get32le(s); // discard color space parameters + if (hsz == 124) { + stbi__get32le(s); // discard rendering intent + stbi__get32le(s); // discard offset of profile data + stbi__get32le(s); // discard size of profile data + stbi__get32le(s); // discard reserved + } + } + } + return (void *) 1; +} + + +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + unsigned int mr=0,mg=0,mb=0,ma=0, all_a; + stbi_uc pal[256][4]; + int psize=0,i,j,width; + int flip_vertically, pad, target; + stbi__bmp_data info; + STBI_NOTUSED(ri); + + info.all_a = 255; + if (stbi__bmp_parse_header(s, &info) == NULL) + return NULL; // error code already set + + flip_vertically = ((int) s->img_y) > 0; + s->img_y = abs((int) s->img_y); + + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + mr = info.mr; + mg = info.mg; + mb = info.mb; + ma = info.ma; + all_a = info.all_a; + + if (info.hsz == 12) { + if (info.bpp < 24) + psize = (info.offset - info.extra_read - 24) / 3; + } else { + if (info.bpp < 16) + psize = (info.offset - info.extra_read - info.hsz) >> 2; + } + if (psize == 0) { + // accept some number of extra bytes after the header, but if the offset points either to before + // the header ends or implies a large amount of extra data, reject the file as malformed + int bytes_read_so_far = s->callback_already_read + (int)(s->img_buffer - s->img_buffer_original); + int header_limit = 1024; // max we actually read is below 256 bytes currently. + int extra_data_limit = 256*4; // what ordinarily goes here is a palette; 256 entries*4 bytes is its max size. + if (bytes_read_so_far <= 0 || bytes_read_so_far > header_limit) { + return stbi__errpuc("bad header", "Corrupt BMP"); + } + // we established that bytes_read_so_far is positive and sensible. + // the first half of this test rejects offsets that are either too small positives, or + // negative, and guarantees that info.offset >= bytes_read_so_far > 0. this in turn + // ensures the number computed in the second half of the test can't overflow. + if (info.offset < bytes_read_so_far || info.offset - bytes_read_so_far > extra_data_limit) { + return stbi__errpuc("bad offset", "Corrupt BMP"); + } else { + stbi__skip(s, info.offset - bytes_read_so_far); + } + } + + if (info.bpp == 24 && ma == 0xff000000) + s->img_n = 3; + else + s->img_n = ma ? 4 : 3; + if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 + target = req_comp; + else + target = s->img_n; // if they want monochrome, we'll post-convert + + // sanity-check size + if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "Corrupt BMP"); + + out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + if (info.bpp < 16) { + int z=0; + if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } + for (i=0; i < psize; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + if (info.hsz != 12) stbi__get8(s); + pal[i][3] = 255; + } + stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); + if (info.bpp == 1) width = (s->img_x + 7) >> 3; + else if (info.bpp == 4) width = (s->img_x + 1) >> 1; + else if (info.bpp == 8) width = s->img_x; + else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } + pad = (-width)&3; + if (info.bpp == 1) { + for (j=0; j < (int) s->img_y; ++j) { + int bit_offset = 7, v = stbi__get8(s); + for (i=0; i < (int) s->img_x; ++i) { + int color = (v>>bit_offset)&0x1; + out[z++] = pal[color][0]; + out[z++] = pal[color][1]; + out[z++] = pal[color][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + if((--bit_offset) < 0) { + bit_offset = 7; + v = stbi__get8(s); + } + } + stbi__skip(s, pad); + } + } else { + for (j=0; j < (int) s->img_y; ++j) { + for (i=0; i < (int) s->img_x; i += 2) { + int v=stbi__get8(s),v2=0; + if (info.bpp == 4) { + v2 = v & 15; + v >>= 4; + } + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + v = (info.bpp == 8) ? stbi__get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + } + stbi__skip(s, pad); + } + } + } else { + int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; + int z = 0; + int easy=0; + stbi__skip(s, info.offset - info.extra_read - info.hsz); + if (info.bpp == 24) width = 3 * s->img_x; + else if (info.bpp == 16) width = 2*s->img_x; + else /* bpp = 32 and pad = 0 */ width=0; + pad = (-width) & 3; + if (info.bpp == 24) { + easy = 1; + } else if (info.bpp == 32) { + if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) + easy = 2; + } + if (!easy) { + if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + // right shift amt to put high bit in position #7 + rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); + gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); + bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); + ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); + if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + } + for (j=0; j < (int) s->img_y; ++j) { + if (easy) { + for (i=0; i < (int) s->img_x; ++i) { + unsigned char a; + out[z+2] = stbi__get8(s); + out[z+1] = stbi__get8(s); + out[z+0] = stbi__get8(s); + z += 3; + a = (easy == 2 ? stbi__get8(s) : 255); + all_a |= a; + if (target == 4) out[z++] = a; + } + } else { + int bpp = info.bpp; + for (i=0; i < (int) s->img_x; ++i) { + stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); + unsigned int a; + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); + a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); + all_a |= a; + if (target == 4) out[z++] = STBI__BYTECAST(a); + } + } + stbi__skip(s, pad); + } + } + + // if alpha channel is all 0s, replace with all 255s + if (target == 4 && all_a == 0) + for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) + out[i] = 255; + + if (flip_vertically) { + stbi_uc t; + for (j=0; j < (int) s->img_y>>1; ++j) { + stbi_uc *p1 = out + j *s->img_x*target; + stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; + for (i=0; i < (int) s->img_x*target; ++i) { + t = p1[i]; p1[i] = p2[i]; p2[i] = t; + } + } + } + + if (req_comp && req_comp != target) { + out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + return out; +} +#endif + +// Targa Truevision - TGA +// by Jonathan Dummer +#ifndef STBI_NO_TGA +// returns STBI_rgb or whatever, 0 on error +static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) +{ + // only RGB or RGBA (incl. 16bit) or grey allowed + if (is_rgb16) *is_rgb16 = 0; + switch(bits_per_pixel) { + case 8: return STBI_grey; + case 16: if(is_grey) return STBI_grey_alpha; + // fallthrough + case 15: if(is_rgb16) *is_rgb16 = 1; + return STBI_rgb; + case 24: // fallthrough + case 32: return bits_per_pixel/8; + default: return 0; + } +} + +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) +{ + int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; + int sz, tga_colormap_type; + stbi__get8(s); // discard Offset + tga_colormap_type = stbi__get8(s); // colormap type + if( tga_colormap_type > 1 ) { + stbi__rewind(s); + return 0; // only RGB or indexed allowed + } + tga_image_type = stbi__get8(s); // image type + if ( tga_colormap_type == 1 ) { // colormapped (paletted) image + if (tga_image_type != 1 && tga_image_type != 9) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip image x and y origin + tga_colormap_bpp = sz; + } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE + if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) { + stbi__rewind(s); + return 0; // only RGB or grey allowed, +/- RLE + } + stbi__skip(s,9); // skip colormap specification and image x/y origin + tga_colormap_bpp = 0; + } + tga_w = stbi__get16le(s); + if( tga_w < 1 ) { + stbi__rewind(s); + return 0; // test width + } + tga_h = stbi__get16le(s); + if( tga_h < 1 ) { + stbi__rewind(s); + return 0; // test height + } + tga_bits_per_pixel = stbi__get8(s); // bits per pixel + stbi__get8(s); // ignore alpha bits + if (tga_colormap_bpp != 0) { + if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { + // when using a colormap, tga_bits_per_pixel is the size of the indexes + // I don't think anything but 8 or 16bit indexes makes sense + stbi__rewind(s); + return 0; + } + tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); + } else { + tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL); + } + if(!tga_comp) { + stbi__rewind(s); + return 0; + } + if (x) *x = tga_w; + if (y) *y = tga_h; + if (comp) *comp = tga_comp; + return 1; // seems to have passed everything +} + +static int stbi__tga_test(stbi__context *s) +{ + int res = 0; + int sz, tga_color_type; + stbi__get8(s); // discard Offset + tga_color_type = stbi__get8(s); // color type + if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed + sz = stbi__get8(s); // image type + if ( tga_color_type == 1 ) { // colormapped (paletted) image + if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9 + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + stbi__skip(s,4); // skip image x and y origin + } else { // "normal" image w/o colormap + if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE + stbi__skip(s,9); // skip colormap specification and image x/y origin + } + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height + sz = stbi__get8(s); // bits per pixel + if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + + res = 1; // if we got this far, everything's good and we can return 1 instead of 0 + +errorEnd: + stbi__rewind(s); + return res; +} + +// read 16bit value and convert to 24bit RGB +static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) +{ + stbi__uint16 px = (stbi__uint16)stbi__get16le(s); + stbi__uint16 fiveBitMask = 31; + // we have 3 channels with 5bits each + int r = (px >> 10) & fiveBitMask; + int g = (px >> 5) & fiveBitMask; + int b = px & fiveBitMask; + // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later + out[0] = (stbi_uc)((r * 255)/31); + out[1] = (stbi_uc)((g * 255)/31); + out[2] = (stbi_uc)((b * 255)/31); + + // some people claim that the most significant bit might be used for alpha + // (possibly if an alpha-bit is set in the "image descriptor byte") + // but that only made 16bit test images completely translucent.. + // so let's treat all 15 and 16bit TGAs as RGB with no alpha. +} + +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, unsigned int *palette_buffer, int palette_buffer_len, stbi__result_info *ri) +{ + // read in the TGA header stuff + int tga_offset = stbi__get8(s); + int tga_indexed = stbi__get8(s); + int tga_image_type = stbi__get8(s); + int tga_is_RLE = 0; + int tga_palette_start = stbi__get16le(s); + int tga_palette_len = stbi__get16le(s); + int tga_palette_bits = stbi__get8(s); + int tga_x_origin = stbi__get16le(s); + int tga_y_origin = stbi__get16le(s); + int tga_width = stbi__get16le(s); + int tga_height = stbi__get16le(s); + int tga_bits_per_pixel = stbi__get8(s); + int tga_comp, tga_rgb16=0; + int tga_inverted = stbi__get8(s); + // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) + // image data + unsigned char *tga_data; + unsigned char *tga_palette = NULL; + int i, j; + unsigned char raw_data[4] = {0}; + int RLE_count = 0; + int RLE_repeating = 0; + int read_next_pixel = 1; + STBI_NOTUSED(ri); + STBI_NOTUSED(tga_x_origin); // @TODO + STBI_NOTUSED(tga_y_origin); // @TODO + + if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + // do a tiny bit of precessing + if ( tga_image_type >= 8 ) + { + tga_image_type -= 8; + tga_is_RLE = 1; + } + tga_inverted = 1 - ((tga_inverted >> 5) & 1); + + // If I'm paletted, then I'll use the number of bits from the palette + if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); + else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16); + + if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency + return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); + + // tga info + *x = tga_width; + *y = tga_height; + if (comp) *comp = tga_comp; + + if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) + return stbi__errpuc("too large", "Corrupt TGA"); + + tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); + if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); + + // skip to the data's starting position (offset usually = 0) + stbi__skip(s, tga_offset ); + + if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) { + for (i=0; i < tga_height; ++i) { + int row = tga_inverted ? tga_height -i - 1 : i; + stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; + stbi__getn(s, tga_row, tga_width * tga_comp); + } + } else { + // do I need to load a palette? + if ( tga_indexed) + { + if (tga_palette_len == 0) { /* you have to have at least one entry! */ + STBI_FREE(tga_data); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + + // any data to skip? (offset usually = 0) + stbi__skip(s, tga_palette_start ); + // load the palette + if (palette_buffer) { + if (palette_buffer_len < tga_palette_len * tga_comp) { + STBI_FREE(tga_data); + return stbi__errpuc("buffer too small", "Palette buffer too small"); + } + tga_palette = (unsigned char*)(void*)palette_buffer; + } else { + tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); + if (!tga_palette) { + STBI_FREE(tga_data); + return stbi__errpuc("outofmem", "Out of memory"); + } + } + if (tga_rgb16) { + stbi_uc *pal_entry = tga_palette; + STBI_ASSERT(tga_comp == STBI_rgb); + for (i=0; i < tga_palette_len; ++i) { + stbi__tga_read_rgb16(s, pal_entry); + pal_entry += tga_comp; + } + } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { + STBI_FREE(tga_data); + if (!palette_buffer) + STBI_FREE(tga_palette); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + } + // load the data + for (i=0; i < tga_width * tga_height; ++i) + { + // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? + if ( tga_is_RLE ) + { + if ( RLE_count == 0 ) + { + // yep, get the next byte as a RLE command + int RLE_cmd = stbi__get8(s); + RLE_count = 1 + (RLE_cmd & 127); + RLE_repeating = RLE_cmd >> 7; + read_next_pixel = 1; + } else if ( !RLE_repeating ) + { + read_next_pixel = 1; + } + } else + { + read_next_pixel = 1; + } + // OK, if I need to read a pixel, do it now + if ( read_next_pixel ) + { + // load however much data we did have + if ( tga_indexed && !palette_buffer ) + { + // read in index, then perform the lookup + int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); + if ( pal_idx >= tga_palette_len ) { + // invalid index + pal_idx = 0; + } + pal_idx *= tga_comp; + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = tga_palette[pal_idx+j]; + } + } else if(tga_rgb16) { + STBI_ASSERT(tga_comp == STBI_rgb); + stbi__tga_read_rgb16(s, raw_data); + } else { + // read in the data raw + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = stbi__get8(s); + } + } + // clear the reading flag for the next pixel + read_next_pixel = 0; + } // end of reading a pixel + + // copy data + for (j = 0; j < tga_comp; ++j) + tga_data[i*tga_comp+j] = raw_data[j]; + + // in case we're in RLE mode, keep counting down + --RLE_count; + } + // do I need to invert the image? + if ( tga_inverted ) + { + for (j = 0; j*2 < tga_height; ++j) + { + int index1 = j * tga_width * tga_comp; + int index2 = (tga_height - 1 - j) * tga_width * tga_comp; + for (i = tga_width * tga_comp; i > 0; --i) + { + unsigned char temp = tga_data[index1]; + tga_data[index1] = tga_data[index2]; + tga_data[index2] = temp; + ++index1; + ++index2; + } + } + } + // clear my palette, if I had one + if ( tga_palette != NULL && !palette_buffer ) + { + STBI_FREE( tga_palette ); + } + } + + // swap RGB - if the source data was RGB16, it already is in the right order + if (tga_comp >= 3 && !tga_rgb16) + { + unsigned char* tga_pixel = tga_data; + for (i=0; i < tga_width * tga_height; ++i) + { + unsigned char temp = tga_pixel[0]; + tga_pixel[0] = tga_pixel[2]; + tga_pixel[2] = temp; + tga_pixel += tga_comp; + } + } + + // convert to target component count + if (req_comp && req_comp != tga_comp) + tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); + + // the things I do to get rid of an error message, and yet keep + // Microsoft's C compilers happy... [8^( + tga_palette_start = tga_palette_len = tga_palette_bits = + tga_x_origin = tga_y_origin = 0; + STBI_NOTUSED(tga_palette_start); + // OK, done + return tga_data; +} +#endif + +// ************************************************************************************************* +// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s) +{ + int r = (stbi__get32be(s) == 0x38425053); + stbi__rewind(s); + return r; +} + +static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) +{ + int count, nleft, len; + + count = 0; + while ((nleft = pixelCount - count) > 0) { + len = stbi__get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + if (len > nleft) return 0; // corrupt data + count += len; + while (len) { + *p = stbi__get8(s); + p += 4; + len--; + } + } else if (len > 128) { + stbi_uc val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len = 257 - len; + if (len > nleft) return 0; // corrupt data + val = stbi__get8(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } + + return 1; +} + +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + int pixelCount; + int channelCount, compression; + int channel, i; + int bitdepth; + int w,h; + stbi_uc *out; + STBI_NOTUSED(ri); + + // Check identifier + if (stbi__get32be(s) != 0x38425053) // "8BPS" + return stbi__errpuc("not PSD", "Corrupt PSD image"); + + // Check file type version. + if (stbi__get16be(s) != 1) + return stbi__errpuc("wrong version", "Unsupported version of PSD image"); + + // Skip 6 reserved bytes. + stbi__skip(s, 6 ); + + // Read the number of channels (R, G, B, A, etc). + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) + return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); + + // Read the rows and columns of the image. + h = stbi__get32be(s); + w = stbi__get32be(s); + + if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + // Make sure the depth is 8 bits. + bitdepth = stbi__get16be(s); + if (bitdepth != 8 && bitdepth != 16) + return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); + + // Make sure the color mode is RGB. + // Valid options are: + // 0: Bitmap + // 1: Grayscale + // 2: Indexed color + // 3: RGB color + // 4: CMYK color + // 7: Multichannel + // 8: Duotone + // 9: Lab color + if (stbi__get16be(s) != 3) + return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); + + // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) + stbi__skip(s,stbi__get32be(s) ); + + // Skip the image resources. (resolution, pen tool paths, etc) + stbi__skip(s, stbi__get32be(s) ); + + // Skip the reserved data. + stbi__skip(s, stbi__get32be(s) ); + + // Find out if the data is compressed. + // Known values: + // 0: no compression + // 1: RLE compressed + compression = stbi__get16be(s); + if (compression > 1) + return stbi__errpuc("bad compression", "PSD has an unknown compression format"); + + // Check size + if (!stbi__mad3sizes_valid(4, w, h, 0)) + return stbi__errpuc("too large", "Corrupt PSD"); + + // Create the destination image. + + if (!compression && bitdepth == 16 && bpc == 16) { + out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0); + ri->bits_per_channel = 16; + } else + out = (stbi_uc *) stbi__malloc(4 * w*h); + + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + pixelCount = w*h; + + // Initialize the data to zero. + //memset( out, 0, pixelCount * 4 ); + + // Finally, the image data. + if (compression) { + // RLE as used by .PSD and .TIFF + // Loop until you get the number of unpacked bytes you are expecting: + // Read the next source byte into n. + // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. + // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. + // Else if n is 128, noop. + // Endloop + + // The RLE-compressed data is preceded by a 2-byte data count for each row in the data, + // which we're going to just skip. + stbi__skip(s, h * channelCount * 2 ); + + // Read the RLE data by channel. + for (channel = 0; channel < 4; channel++) { + stbi_uc *p; + + p = out+channel; + if (channel >= channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++, p += 4) + *p = (channel == 3 ? 255 : 0); + } else { + // Read the RLE data. + if (!stbi__psd_decode_rle(s, p, pixelCount)) { + STBI_FREE(out); + return stbi__errpuc("corrupt", "bad RLE data"); + } + } + } + + } else { + // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) + // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image. + + // Read the data by channel. + for (channel = 0; channel < 4; channel++) { + if (channel >= channelCount) { + // Fill this channel with default data. + if (bitdepth == 16 && bpc == 16) { + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + stbi__uint16 val = channel == 3 ? 65535 : 0; + for (i = 0; i < pixelCount; i++, q += 4) + *q = val; + } else { + stbi_uc *p = out+channel; + stbi_uc val = channel == 3 ? 255 : 0; + for (i = 0; i < pixelCount; i++, p += 4) + *p = val; + } + } else { + if (ri->bits_per_channel == 16) { // output bpc + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + for (i = 0; i < pixelCount; i++, q += 4) + *q = (stbi__uint16) stbi__get16be(s); + } else { + stbi_uc *p = out+channel; + if (bitdepth == 16) { // input bpc + for (i = 0; i < pixelCount; i++, p += 4) + *p = (stbi_uc) (stbi__get16be(s) >> 8); + } else { + for (i = 0; i < pixelCount; i++, p += 4) + *p = stbi__get8(s); + } + } + } + } + } + + // remove weird white matte from PSD + if (channelCount >= 4) { + if (ri->bits_per_channel == 16) { + for (i=0; i < w*h; ++i) { + stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i; + if (pixel[3] != 0 && pixel[3] != 65535) { + float a = pixel[3] / 65535.0f; + float ra = 1.0f / a; + float inv_a = 65535.0f * (1 - ra); + pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a); + pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a); + pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a); + } + } + } else { + for (i=0; i < w*h; ++i) { + unsigned char *pixel = out + 4*i; + if (pixel[3] != 0 && pixel[3] != 255) { + float a = pixel[3] / 255.0f; + float ra = 1.0f / a; + float inv_a = 255.0f * (1 - ra); + pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); + pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); + pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); + } + } + } + } + + // convert to desired output format + if (req_comp && req_comp != 4) { + if (ri->bits_per_channel == 16) + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h); + else + out = stbi__convert_format(out, 4, req_comp, w, h); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + if (comp) *comp = 4; + *y = h; + *x = w; + + return out; +} +#endif + +// ************************************************************************************************* +// Softimage PIC loader +// by Tom Seddon +// +// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format +// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ + +#ifndef STBI_NO_PIC +static int stbi__pic_is4(stbi__context *s,const char *str) +{ + int i; + for (i=0; i<4; ++i) + if (stbi__get8(s) != (stbi_uc)str[i]) + return 0; + + return 1; +} + +static int stbi__pic_test_core(stbi__context *s) +{ + int i; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) + return 0; + + for(i=0;i<84;++i) + stbi__get8(s); + + if (!stbi__pic_is4(s,"PICT")) + return 0; + + return 1; +} + +typedef struct +{ + stbi_uc size,type,channel; +} stbi__pic_packet; + +static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) +{ + int mask=0x80, i; + + for (i=0; i<4; ++i, mask>>=1) { + if (channel & mask) { + if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); + dest[i]=stbi__get8(s); + } + } + + return dest; +} + +static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) +{ + int mask=0x80,i; + + for (i=0;i<4; ++i, mask>>=1) + if (channel&mask) + dest[i]=src[i]; +} + +static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) +{ + int act_comp=0,num_packets=0,y,chained; + stbi__pic_packet packets[10]; + + // this will (should...) cater for even some bizarre stuff like having data + // for the same channel in multiple packets. + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return stbi__errpuc("bad format","too many packets"); + + packet = &packets[num_packets++]; + + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + + act_comp |= packet->channel; + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); + if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? + + for(y=0; ytype) { + default: + return stbi__errpuc("bad format","packet has bad compression type"); + + case 0: {//uncompressed + int x; + + for(x=0;xchannel,dest)) + return 0; + break; + } + + case 1://Pure RLE + { + int left=width, i; + + while (left>0) { + stbi_uc count,value[4]; + + count=stbi__get8(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); + + if (count > left) + count = (stbi_uc) left; + + if (!stbi__readval(s,packet->channel,value)) return 0; + + for(i=0; ichannel,dest,value); + left -= count; + } + } + break; + + case 2: {//Mixed RLE + int left=width; + while (left>0) { + int count = stbi__get8(s), i; + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); + + if (count >= 128) { // Repeated + stbi_uc value[4]; + + if (count==128) + count = stbi__get16be(s); + else + count -= 127; + if (count > left) + return stbi__errpuc("bad file","scanline overrun"); + + if (!stbi__readval(s,packet->channel,value)) + return 0; + + for(i=0;ichannel,dest,value); + } else { // Raw + ++count; + if (count>left) return stbi__errpuc("bad file","scanline overrun"); + + for(i=0;ichannel,dest)) + return 0; + } + left-=count; + } + break; + } + } + } + } + + return result; +} + +static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri) +{ + stbi_uc *result; + int i, x,y, internal_comp; + STBI_NOTUSED(ri); + + if (!comp) comp = &internal_comp; + + for (i=0; i<92; ++i) + stbi__get8(s); + + x = stbi__get16be(s); + y = stbi__get16be(s); + + if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); + if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); + + stbi__get32be(s); //skip `ratio' + stbi__get16be(s); //skip `fields' + stbi__get16be(s); //skip `pad' + + // intermediate buffer is RGBA + result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); + if (!result) return stbi__errpuc("outofmem", "Out of memory"); + memset(result, 0xff, x*y*4); + + if (!stbi__pic_load_core(s,x,y,comp, result)) { + STBI_FREE(result); + return 0; + } + *px = x; + *py = y; + if (req_comp == 0) req_comp = *comp; + result=stbi__convert_format(result,4,req_comp,x,y); + + return result; +} + +static int stbi__pic_test(stbi__context *s) +{ + int r = stbi__pic_test_core(s); + stbi__rewind(s); + return r; +} +#endif + +// ************************************************************************************************* +// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb + +#ifndef STBI_NO_GIF +typedef struct +{ + stbi__int16 prefix; + stbi_uc first; + stbi_uc suffix; +} stbi__gif_lzw; + +typedef struct +{ + int w,h; + stbi_uc *out; // output buffer (always 4 components) + stbi_uc *background; // The current "background" as far as a gif is concerned + stbi_uc *history; + int flags, bgindex, ratio, transparent, eflags; + stbi_uc pal[256][4]; + stbi_uc lpal[256][4]; + stbi__gif_lzw codes[8192]; + stbi_uc *color_table; + int parse, step; + int lflags; + int start_x, start_y; + int max_x, max_y; + int cur_x, cur_y; + int line_size; + int delay; +} stbi__gif; + +static int stbi__gif_test_raw(stbi__context *s) +{ + int sz; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; + sz = stbi__get8(s); + if (sz != '9' && sz != '7') return 0; + if (stbi__get8(s) != 'a') return 0; + return 1; +} + +static int stbi__gif_test(stbi__context *s) +{ + int r = stbi__gif_test_raw(s); + stbi__rewind(s); + return r; +} + +static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) +{ + int i; + for (i=0; i < num_entries; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + pal[i][3] = transp == i ? 0 : 255; + } +} + +static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) +{ + stbi_uc version; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') + return stbi__err("not GIF", "Corrupt GIF"); + + version = stbi__get8(s); + if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); + if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); + + stbi__g_failure_reason = ""; + g->w = stbi__get16le(s); + g->h = stbi__get16le(s); + g->flags = stbi__get8(s); + g->bgindex = stbi__get8(s); + g->ratio = stbi__get8(s); + g->transparent = -1; + + if (g->w > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (g->h > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + + if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments + + if (is_info) return 1; + + if (g->flags & 0x80) + stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); + + return 1; +} + +static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); + if (!g) return stbi__err("outofmem", "Out of memory"); + if (!stbi__gif_header(s, g, comp, 1)) { + STBI_FREE(g); + stbi__rewind( s ); + return 0; + } + if (x) *x = g->w; + if (y) *y = g->h; + STBI_FREE(g); + return 1; +} + +static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) +{ + stbi_uc *p, *c; + int idx; + + // recurse to decode the prefixes, since the linked-list is backwards, + // and working backwards through an interleaved image would be nasty + if (g->codes[code].prefix >= 0) + stbi__out_gif_code(g, g->codes[code].prefix); + + if (g->cur_y >= g->max_y) return; + + idx = g->cur_x + g->cur_y; + p = &g->out[idx]; + g->history[idx / 4] = 1; + + c = &g->color_table[g->codes[code].suffix * 4]; + if (c[3] > 128) { // don't render transparent pixels; + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } + g->cur_x += 4; + + if (g->cur_x >= g->max_x) { + g->cur_x = g->start_x; + g->cur_y += g->step; + + while (g->cur_y >= g->max_y && g->parse > 0) { + g->step = (1 << g->parse) * g->line_size; + g->cur_y = g->start_y + (g->step >> 1); + --g->parse; + } + } +} + +static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) +{ + stbi_uc lzw_cs; + stbi__int32 len, init_code; + stbi__uint32 first; + stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; + stbi__gif_lzw *p; + + lzw_cs = stbi__get8(s); + if (lzw_cs > 12) return NULL; + clear = 1 << lzw_cs; + first = 1; + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + bits = 0; + valid_bits = 0; + for (init_code = 0; init_code < clear; init_code++) { + g->codes[init_code].prefix = -1; + g->codes[init_code].first = (stbi_uc) init_code; + g->codes[init_code].suffix = (stbi_uc) init_code; + } + + // support no starting clear code + avail = clear+2; + oldcode = -1; + + len = 0; + for(;;) { + if (valid_bits < codesize) { + if (len == 0) { + len = stbi__get8(s); // start new block + if (len == 0) + return g->out; + } + --len; + bits |= (stbi__int32) stbi__get8(s) << valid_bits; + valid_bits += 8; + } else { + stbi__int32 code = bits & codemask; + bits >>= codesize; + valid_bits -= codesize; + // @OPTIMIZE: is there some way we can accelerate the non-clear path? + if (code == clear) { // clear code + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + avail = clear + 2; + oldcode = -1; + first = 0; + } else if (code == clear + 1) { // end of stream code + stbi__skip(s, len); + while ((len = stbi__get8(s)) > 0) + stbi__skip(s,len); + return g->out; + } else if (code <= avail) { + if (first) { + return stbi__errpuc("no clear code", "Corrupt GIF"); + } + + if (oldcode >= 0) { + p = &g->codes[avail++]; + if (avail > 8192) { + return stbi__errpuc("too many codes", "Corrupt GIF"); + } + + p->prefix = (stbi__int16) oldcode; + p->first = g->codes[oldcode].first; + p->suffix = (code == avail) ? p->first : g->codes[code].first; + } else if (code == avail) + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + + stbi__out_gif_code(g, (stbi__uint16) code); + + if ((avail & codemask) == 0 && avail <= 0x0FFF) { + codesize++; + codemask = (1 << codesize) - 1; + } + + oldcode = code; + } else { + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + } + } + } +} + +// this function is designed to support animated gifs, although stb_image doesn't support it +// two back is the image from two frames ago, used for a very specific disposal format +static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) +{ + int dispose; + int first_frame; + int pi; + int pcount; + STBI_NOTUSED(req_comp); + + // on first frame, any non-written pixels get the background colour (non-transparent) + first_frame = 0; + if (g->out == 0) { + if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header + if (!stbi__mad3sizes_valid(4, g->w, g->h, 0)) + return stbi__errpuc("too large", "GIF image is too large"); + pcount = g->w * g->h; + g->out = (stbi_uc *) stbi__malloc(4 * pcount); + g->background = (stbi_uc *) stbi__malloc(4 * pcount); + g->history = (stbi_uc *) stbi__malloc(pcount); + if (!g->out || !g->background || !g->history) + return stbi__errpuc("outofmem", "Out of memory"); + + // image is treated as "transparent" at the start - ie, nothing overwrites the current background; + // background colour is only used for pixels that are not rendered first frame, after that "background" + // color refers to the color that was there the previous frame. + memset(g->out, 0x00, 4 * pcount); + memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent) + memset(g->history, 0x00, pcount); // pixels that were affected previous frame + first_frame = 1; + } else { + // second frame - how do we dispose of the previous one? + dispose = (g->eflags & 0x1C) >> 2; + pcount = g->w * g->h; + + if ((dispose == 3) && (two_back == 0)) { + dispose = 2; // if I don't have an image to revert back to, default to the old background + } + + if (dispose == 3) { // use previous graphic + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); + } + } + } else if (dispose == 2) { + // restore what was changed last frame to background before that frame; + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); + } + } + } else { + // This is a non-disposal case eithe way, so just + // leave the pixels as is, and they will become the new background + // 1: do not dispose + // 0: not specified. + } + + // background is what out is after the undoing of the previou frame; + memcpy( g->background, g->out, 4 * g->w * g->h ); + } + + // clear my history; + memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame + + for (;;) { + int tag = stbi__get8(s); + switch (tag) { + case 0x2C: /* Image Descriptor */ + { + stbi__int32 x, y, w, h; + stbi_uc *o; + + x = stbi__get16le(s); + y = stbi__get16le(s); + w = stbi__get16le(s); + h = stbi__get16le(s); + if (((x + w) > (g->w)) || ((y + h) > (g->h))) + return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); + + g->line_size = g->w * 4; + g->start_x = x * 4; + g->start_y = y * g->line_size; + g->max_x = g->start_x + w * 4; + g->max_y = g->start_y + h * g->line_size; + g->cur_x = g->start_x; + g->cur_y = g->start_y; + + // if the width of the specified rectangle is 0, that means + // we may not see *any* pixels or the image is malformed; + // to make sure this is caught, move the current y down to + // max_y (which is what out_gif_code checks). + if (w == 0) + g->cur_y = g->max_y; + + g->lflags = stbi__get8(s); + + if (g->lflags & 0x40) { + g->step = 8 * g->line_size; // first interlaced spacing + g->parse = 3; + } else { + g->step = g->line_size; + g->parse = 0; + } + + if (g->lflags & 0x80) { + stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); + g->color_table = (stbi_uc *) g->lpal; + } else if (g->flags & 0x80) { + g->color_table = (stbi_uc *) g->pal; + } else + return stbi__errpuc("missing color table", "Corrupt GIF"); + + o = stbi__process_gif_raster(s, g); + if (!o) return NULL; + + // if this was the first frame, + pcount = g->w * g->h; + if (first_frame && (g->bgindex > 0)) { + // if first frame, any pixel not drawn to gets the background color + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi] == 0) { + g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; + memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); + } + } + } + + return o; + } + + case 0x21: // Comment Extension. + { + int len; + int ext = stbi__get8(s); + if (ext == 0xF9) { // Graphic Control Extension. + len = stbi__get8(s); + if (len == 4) { + g->eflags = stbi__get8(s); + g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths. + + // unset old transparent + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 255; + } + if (g->eflags & 0x01) { + g->transparent = stbi__get8(s); + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 0; + } + } else { + // don't need transparent + stbi__skip(s, 1); + g->transparent = -1; + } + } else { + stbi__skip(s, len); + break; + } + } + while ((len = stbi__get8(s)) != 0) { + stbi__skip(s, len); + } + break; + } + + case 0x3B: // gif stream termination code + return (stbi_uc *) s; // using '1' causes warning on some compilers + + default: + return stbi__errpuc("unknown code", "Corrupt GIF"); + } + } +} + +static void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, int **delays) +{ + STBI_FREE(g->out); + STBI_FREE(g->history); + STBI_FREE(g->background); + + if (out) STBI_FREE(out); + if (delays && *delays) STBI_FREE(*delays); + return stbi__errpuc("outofmem", "Out of memory"); +} + +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + if (stbi__gif_test(s)) { + int layers = 0; + stbi_uc *u = 0; + stbi_uc *out = 0; + stbi_uc *two_back = 0; + stbi__gif g; + int stride; + int out_size = 0; + int delays_size = 0; + + STBI_NOTUSED(out_size); + STBI_NOTUSED(delays_size); + + memset(&g, 0, sizeof(g)); + if (delays) { + *delays = 0; + } + + do { + u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + + if (u) { + *x = g.w; + *y = g.h; + ++layers; + stride = g.w * g.h * 4; + + if (out) { + void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride ); + if (!tmp) + return stbi__load_gif_main_outofmem(&g, out, delays); + else { + out = (stbi_uc*) tmp; + out_size = layers * stride; + } + + if (delays) { + int *new_delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers ); + if (!new_delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + *delays = new_delays; + delays_size = layers * sizeof(int); + } + } else { + out = (stbi_uc*)stbi__malloc( layers * stride ); + if (!out) + return stbi__load_gif_main_outofmem(&g, out, delays); + out_size = layers * stride; + if (delays) { + *delays = (int*) stbi__malloc( layers * sizeof(int) ); + if (!*delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + delays_size = layers * sizeof(int); + } + } + memcpy( out + ((layers - 1) * stride), u, stride ); + if (layers >= 2) { + two_back = out - 2 * stride; + } + + if (delays) { + (*delays)[layers - 1U] = g.delay; + } + } + } while (u != 0); + + // free temp buffer; + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); + + // do the final conversion after loading everything; + if (req_comp && req_comp != 4) + out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); + + *z = layers; + return out; + } else { + return stbi__errpuc("not GIF", "Image was not as a gif type."); + } +} + +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *u = 0; + stbi__gif g; + memset(&g, 0, sizeof(g)); + STBI_NOTUSED(ri); + + u = stbi__gif_load_next(s, &g, comp, req_comp, 0); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + if (u) { + *x = g.w; + *y = g.h; + + // moved conversion to after successful load so that the same + // can be done for multiple frames. + if (req_comp && req_comp != 4) + u = stbi__convert_format(u, 4, req_comp, g.w, g.h); + } else if (g.out) { + // if there was an error and we allocated an image buffer, free it! + STBI_FREE(g.out); + } + + // free buffers needed for multiple frame loading; + STBI_FREE(g.history); + STBI_FREE(g.background); + + return u; +} + +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) +{ + return stbi__gif_info_raw(s,x,y,comp); +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR loader +// originally by Nicolas Schulz +#ifndef STBI_NO_HDR +static int stbi__hdr_test_core(stbi__context *s, const char *signature) +{ + int i; + for (i=0; signature[i]; ++i) + if (stbi__get8(s) != signature[i]) + return 0; + stbi__rewind(s); + return 1; +} + +static int stbi__hdr_test(stbi__context* s) +{ + int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); + stbi__rewind(s); + if(!r) { + r = stbi__hdr_test_core(s, "#?RGBE\n"); + stbi__rewind(s); + } + return r; +} + +#define STBI__HDR_BUFLEN 1024 +static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) +{ + int len=0; + char c = '\0'; + + c = (char) stbi__get8(z); + + while (!stbi__at_eof(z) && c != '\n') { + buffer[len++] = c; + if (len == STBI__HDR_BUFLEN-1) { + // flush to end of line + while (!stbi__at_eof(z) && stbi__get8(z) != '\n') + ; + break; + } + c = (char) stbi__get8(z); + } + + buffer[len] = 0; + return buffer; +} + +static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) +{ + if ( input[3] != 0 ) { + float f1; + // Exponent + f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); + if (req_comp <= 2) + output[0] = (input[0] + input[1] + input[2]) * f1 / 3; + else { + output[0] = input[0] * f1; + output[1] = input[1] * f1; + output[2] = input[2] * f1; + } + if (req_comp == 2) output[1] = 1; + if (req_comp == 4) output[3] = 1; + } else { + switch (req_comp) { + case 4: output[3] = 1; /* fallthrough */ + case 3: output[0] = output[1] = output[2] = 0; + break; + case 2: output[1] = 1; /* fallthrough */ + case 1: output[0] = 0; + break; + } + } +} + +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int width, height; + stbi_uc *scanline; + float *hdr_data; + int len; + unsigned char count, value; + int i, j, k, c1,c2, z; + const char *headerToken; + STBI_NOTUSED(ri); + + // Check identifier + headerToken = stbi__hdr_gettoken(s,buffer); + if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) + return stbi__errpf("not HDR", "Corrupt HDR image"); + + // Parse header + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); + + // Parse width and height + // can't use sscanf() if we're not using stdio! + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + height = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + width = (int) strtol(token, NULL, 10); + + if (height > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + if (width > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + + *x = width; + *y = height; + + if (comp) *comp = 3; + if (req_comp == 0) req_comp = 3; + + if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) + return stbi__errpf("too large", "HDR image is too large"); + + // Read data + hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); + if (!hdr_data) + return stbi__errpf("outofmem", "Out of memory"); + + // Load image data + // image data is stored as some number of sca + if ( width < 8 || width >= 32768) { + // Read flat data + for (j=0; j < height; ++j) { + for (i=0; i < width; ++i) { + stbi_uc rgbe[4]; + main_decode_loop: + stbi__getn(s, rgbe, 4); + stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); + } + } + } else { + // Read RLE-encoded data + scanline = NULL; + + for (j = 0; j < height; ++j) { + c1 = stbi__get8(s); + c2 = stbi__get8(s); + len = stbi__get8(s); + if (c1 != 2 || c2 != 2 || (len & 0x80)) { + // not run-length encoded, so we have to actually use THIS data as a decoded + // pixel (note this can't be a valid pixel--one of RGB must be >= 128) + stbi_uc rgbe[4]; + rgbe[0] = (stbi_uc) c1; + rgbe[1] = (stbi_uc) c2; + rgbe[2] = (stbi_uc) len; + rgbe[3] = (stbi_uc) stbi__get8(s); + stbi__hdr_convert(hdr_data, rgbe, req_comp); + i = 1; + j = 0; + STBI_FREE(scanline); + goto main_decode_loop; // yes, this makes no sense + } + len <<= 8; + len |= stbi__get8(s); + if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } + if (scanline == NULL) { + scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0); + if (!scanline) { + STBI_FREE(hdr_data); + return stbi__errpf("outofmem", "Out of memory"); + } + } + + for (k = 0; k < 4; ++k) { + int nleft; + i = 0; + while ((nleft = width - i) > 0) { + count = stbi__get8(s); + if (count > 128) { + // Run + value = stbi__get8(s); + count -= 128; + if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump + if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = stbi__get8(s); + } + } + } + for (i=0; i < width; ++i) + stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); + } + if (scanline) + STBI_FREE(scanline); + } + + return hdr_data; +} + +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int dummy; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (stbi__hdr_test(s) == 0) { + stbi__rewind( s ); + return 0; + } + + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) { + stbi__rewind( s ); + return 0; + } + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *y = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *x = (int) strtol(token, NULL, 10); + *comp = 3; + return 1; +} +#endif // STBI_NO_HDR + +#ifndef STBI_NO_BMP +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) +{ + void *p; + stbi__bmp_data info; + + info.all_a = 255; + p = stbi__bmp_parse_header(s, &info); + if (p == NULL) { + stbi__rewind( s ); + return 0; + } + if (x) *x = s->img_x; + if (y) *y = s->img_y; + if (comp) { + if (info.bpp == 24 && info.ma == 0xff000000) + *comp = 3; + else + *comp = info.ma ? 4 : 3; + } + return 1; +} +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) +{ + int channelCount, dummy, depth; + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + *y = stbi__get32be(s); + *x = stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 8 && depth != 16) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 3) { + stbi__rewind( s ); + return 0; + } + *comp = 4; + return 1; +} + +static int stbi__psd_is16(stbi__context *s) +{ + int channelCount, depth; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + STBI_NOTUSED(stbi__get32be(s)); + STBI_NOTUSED(stbi__get32be(s)); + depth = stbi__get16be(s); + if (depth != 16) { + stbi__rewind( s ); + return 0; + } + return 1; +} +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) +{ + int act_comp=0,num_packets=0,chained,dummy; + stbi__pic_packet packets[10]; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { + stbi__rewind(s); + return 0; + } + + stbi__skip(s, 88); + + *x = stbi__get16be(s); + *y = stbi__get16be(s); + if (stbi__at_eof(s)) { + stbi__rewind( s); + return 0; + } + if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { + stbi__rewind( s ); + return 0; + } + + stbi__skip(s, 8); + + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return 0; + + packet = &packets[num_packets++]; + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + act_comp |= packet->channel; + + if (stbi__at_eof(s)) { + stbi__rewind( s ); + return 0; + } + if (packet->size != 8) { + stbi__rewind( s ); + return 0; + } + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); + + return 1; +} +#endif + +// ************************************************************************************************* +// Portable Gray Map and Portable Pixel Map loader +// by Ken Miller +// +// PGM: http://netpbm.sourceforge.net/doc/pgm.html +// PPM: http://netpbm.sourceforge.net/doc/ppm.html +// +// Known limitations: +// Does not support comments in the header section +// Does not support ASCII image data (formats P2 and P3) + +#ifndef STBI_NO_PNM + +static int stbi__pnm_test(stbi__context *s) +{ + char p, t; + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind( s ); + return 0; + } + return 1; +} + +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + STBI_NOTUSED(ri); + + ri->bits_per_channel = stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n); + if (ri->bits_per_channel == 0) + return 0; + + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + + if (!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0)) + return stbi__errpuc("too large", "PNM too large"); + + out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + if (!stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8))) { + STBI_FREE(out); + return stbi__errpuc("bad PNM", "PNM file truncated"); + } + + if (req_comp && req_comp != s->img_n) { + if (ri->bits_per_channel == 16) { + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, s->img_n, req_comp, s->img_x, s->img_y); + } else { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + } + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + return out; +} + +static int stbi__pnm_isspace(char c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; +} + +static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) +{ + for (;;) { + while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) + *c = (char) stbi__get8(s); + + if (stbi__at_eof(s) || *c != '#') + break; + + while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' ) + *c = (char) stbi__get8(s); + } +} + +static int stbi__pnm_isdigit(char c) +{ + return c >= '0' && c <= '9'; +} + +static int stbi__pnm_getinteger(stbi__context *s, char *c) +{ + int value = 0; + + while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { + value = value*10 + (*c - '0'); + *c = (char) stbi__get8(s); + if((value > 214748364) || (value == 214748364 && *c > '7')) + return stbi__err("integer parse overflow", "Parsing an integer in the PPM header overflowed a 32-bit int"); + } + + return value; +} + +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) +{ + int maxv, dummy; + char c, p, t; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + stbi__rewind(s); + + // Get identifier + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind(s); + return 0; + } + + *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm + + c = (char) stbi__get8(s); + stbi__pnm_skip_whitespace(s, &c); + + *x = stbi__pnm_getinteger(s, &c); // read width + if(*x == 0) + return stbi__err("invalid width", "PPM image header had zero or overflowing width"); + stbi__pnm_skip_whitespace(s, &c); + + *y = stbi__pnm_getinteger(s, &c); // read height + if (*y == 0) + return stbi__err("invalid width", "PPM image header had zero or overflowing width"); + stbi__pnm_skip_whitespace(s, &c); + + maxv = stbi__pnm_getinteger(s, &c); // read max value + if (maxv > 65535) + return stbi__err("max value > 65535", "PPM image supports only 8-bit and 16-bit images"); + else if (maxv > 255) + return 16; + else + return 8; +} + +static int stbi__pnm_is16(stbi__context *s) +{ + if (stbi__pnm_info(s, NULL, NULL, NULL) == 16) + return 1; + return 0; +} +#endif + +#if 0 /* not used in SDL */ +static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) +{ + #ifndef STBI_NO_JPEG + if (stbi__jpeg_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNG + if (stbi__png_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_GIF + if (stbi__gif_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_BMP + if (stbi__bmp_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PIC + if (stbi__pic_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_info(s, x, y, comp)) return 1; + #endif + + // test tga last because it's a crappy test! + #ifndef STBI_NO_TGA + if (stbi__tga_info(s, x, y, comp)) + return 1; + #endif + return stbi__err("unknown image type", "Image not of any known type, or corrupt"); +} + +static int stbi__is_16_main(stbi__context *s) +{ + #ifndef STBI_NO_PNG + if (stbi__png_is16(s)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_is16(s)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_is16(s)) return 1; + #endif + return 0; +} +#endif /**/ + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_info_from_file(f, x, y, comp); + fclose(f); + return result; +} + +STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__info_main(&s,x,y,comp); + fseek(f,pos,SEEK_SET); + return r; +} + +STBIDEF int stbi_is_16_bit(char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_is_16_bit_from_file(f); + fclose(f); + return result; +} + +STBIDEF int stbi_is_16_bit_from_file(FILE *f) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__is_16_main(&s); + fseek(f,pos,SEEK_SET); + return r; +} +#endif // !STBI_NO_STDIO + +#if 0 /* not used in SDL */ +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__is_16_main(&s); +} + +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__is_16_main(&s); +} +#endif /**/ + +#endif // STB_IMAGE_IMPLEMENTATION + +/* + revision history: + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug + 1-bit BMP + *_is_16_bit api + avoid warnings + 2.16 (2017-07-23) all functions have 16-bit variants; + STBI_NO_STDIO works again; + compilation fixes; + fix rounding in unpremultiply; + optimize vertical flip; + disable raw_len validation; + documentation fixes + 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; + warning fixes; disable run-time SSE detection on gcc; + uniform handling of optional "return" values; + thread-safe initialization of zlib tables + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) allocate large structures on the stack + remove white matting for transparent PSD + fix reported channel count for PNG & BMP + re-enable SSE2 in non-gcc 64-bit + support RGB-formatted JPEG + read 16-bit PNGs (only as 8-bit) + 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED + 2.09 (2016-01-16) allow comments in PNM files + 16-bit-per-pixel TGA (not bit-per-component) + info() for TGA could break due to .hdr handling + info() for BMP to shares code instead of sloppy parse + can use STBI_REALLOC_SIZED if allocator doesn't support realloc + code cleanup + 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA + 2.07 (2015-09-13) fix compiler warnings + partial animated GIF support + limited 16-bpc PSD support + #ifdef unused functions + bug with < 92 byte PIC,PNM,HDR,TGA + 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value + 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning + 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit + 2.03 (2015-04-12) extra corruption checking (mmozeiko) + stbi_set_flip_vertically_on_load (nguillemot) + fix NEON support; fix mingw support + 2.02 (2015-01-19) fix incorrect assert, fix warning + 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 + 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG + 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) + progressive JPEG (stb) + PGM/PPM support (Ken Miller) + STBI_MALLOC,STBI_REALLOC,STBI_FREE + GIF bugfix -- seemingly never worked + STBI_NO_*, STBI_ONLY_* + 1.48 (2014-12-14) fix incorrectly-named assert() + 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) + optimize PNG (ryg) + fix bug in interlaced PNG with user-specified channel count (stb) + 1.46 (2014-08-26) + fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG + 1.45 (2014-08-16) + fix MSVC-ARM internal compiler error by wrapping malloc + 1.44 (2014-08-07) + various warning fixes from Ronny Chevalier + 1.43 (2014-07-15) + fix MSVC-only compiler problem in code changed in 1.42 + 1.42 (2014-07-09) + don't define _CRT_SECURE_NO_WARNINGS (affects user code) + fixes to stbi__cleanup_jpeg path + added STBI_ASSERT to avoid requiring assert.h + 1.41 (2014-06-25) + fix search&replace from 1.36 that messed up comments/error messages + 1.40 (2014-06-22) + fix gcc struct-initialization warning + 1.39 (2014-06-15) + fix to TGA optimization when req_comp != number of components in TGA; + fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) + add support for BMP version 5 (more ignored fields) + 1.38 (2014-06-06) + suppress MSVC warnings on integer casts truncating values + fix accidental rename of 'skip' field of I/O + 1.37 (2014-06-04) + remove duplicate typedef + 1.36 (2014-06-03) + convert to header file single-file library + if de-iphone isn't set, load iphone images color-swapped instead of returning NULL + 1.35 (2014-05-27) + various warnings + fix broken STBI_SIMD path + fix bug where stbi_load_from_file no longer left file pointer in correct place + fix broken non-easy path for 32-bit BMP (possibly never used) + TGA optimization by Arseny Kapoulkine + 1.34 (unknown) + use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case + 1.33 (2011-07-14) + make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements + 1.32 (2011-07-13) + support for "info" function for all supported filetypes (SpartanJ) + 1.31 (2011-06-20) + a few more leak fixes, bug in PNG handling (SpartanJ) + 1.30 (2011-06-11) + added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) + removed deprecated format-specific test/load functions + removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway + error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) + fix inefficiency in decoding 32-bit BMP (David Woo) + 1.29 (2010-08-16) + various warning fixes from Aurelien Pocheville + 1.28 (2010-08-01) + fix bug in GIF palette transparency (SpartanJ) + 1.27 (2010-08-01) + cast-to-stbi_uc to fix warnings + 1.26 (2010-07-24) + fix bug in file buffering for PNG reported by SpartanJ + 1.25 (2010-07-17) + refix trans_data warning (Won Chun) + 1.24 (2010-07-12) + perf improvements reading from files on platforms with lock-heavy fgetc() + minor perf improvements for jpeg + deprecated type-specific functions so we'll get feedback if they're needed + attempt to fix trans_data warning (Won Chun) + 1.23 fixed bug in iPhone support + 1.22 (2010-07-10) + removed image *writing* support + stbi_info support from Jetro Lauha + GIF support from Jean-Marc Lienher + iPhone PNG-extensions from James Brown + warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) + 1.21 fix use of 'stbi_uc' in header (reported by jon blow) + 1.20 added support for Softimage PIC, by Tom Seddon + 1.19 bug in interlaced PNG corruption check (found by ryg) + 1.18 (2008-08-02) + fix a threading bug (local mutable static) + 1.17 support interlaced PNG + 1.16 major bugfix - stbi__convert_format converted one too many pixels + 1.15 initialize some fields for thread safety + 1.14 fix threadsafe conversion bug + header-file-only version (#define STBI_HEADER_FILE_ONLY before including) + 1.13 threadsafe + 1.12 const qualifiers in the API + 1.11 Support installable IDCT, colorspace conversion routines + 1.10 Fixes for 64-bit (don't use "unsigned long") + optimized upsampling by Fabian "ryg" Giesen + 1.09 Fix format-conversion for PSD code (bad global variables!) + 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz + 1.07 attempt to fix C++ warning/errors again + 1.06 attempt to fix C++ warning/errors again + 1.05 fix TGA loading to return correct *comp and use good luminance calc + 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free + 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR + 1.02 support for (subset of) HDR files, float interface for preferred access to them + 1.01 fix bug: possible bug in handling right-side up bmps... not sure + fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all + 1.00 interface to zlib that skips zlib header + 0.99 correct handling of alpha in palette + 0.98 TGA loader by lonesock; dynamically add loaders (untested) + 0.97 jpeg errors on too large a file; also catch another malloc failure + 0.96 fix detection of invalid v value - particleman@mollyrocket forum + 0.95 during header scan, seek to markers in case of padding + 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same + 0.93 handle jpegtran output; verbose errors + 0.92 read 4,8,16,24,32-bit BMP files of several formats + 0.91 output 24-bit Windows 3.0 BMP files + 0.90 fix a few more warnings; bump version number to approach 1.0 + 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd + 0.60 fix compiling as c++ + 0.59 fix warnings: merge Dave Moore's -Wall fixes + 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian + 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available + 0.56 fix bug: zlib uncompressed mode len vs. nlen + 0.55 fix bug: restart_interval not initialized to 0 + 0.54 allow NULL for 'int *comp' + 0.53 fix bug in png 3->4; speedup png decoding + 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments + 0.51 obey req_comp requests, 1-component jpegs return as 1-component, + on 'test' only check type, not whether we support this variant + 0.50 (2006-11-19) + first released version +*/ + + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/libs/SDL3/src/video/uikit/SDL_uikitpen.m b/libs/SDL3/src/video/uikit/SDL_uikitpen.m index 622513c2..52096816 100644 --- a/libs/SDL3/src/video/uikit/SDL_uikitpen.m +++ b/libs/SDL3/src/video/uikit/SDL_uikitpen.m @@ -28,6 +28,31 @@ #include "../../events/SDL_pen_c.h" +// Fix build errors when using an older SDK by defining these selectors +#if !defined(SDL_PLATFORM_TVOS) + +@interface UITouch (SDL) +#if !(__IPHONE_OS_VERSION_MAX_ALLOWED >= 170500) +@property (nonatomic, readonly) CGFloat rollAngle; +#endif +@end + +@interface UIHoverGestureRecognizer (SDL) +#if !(__IPHONE_OS_VERSION_MAX_ALLOWED >= 160100) +@property (nonatomic, readonly) CGFloat zOffset; +#endif +#if !(__IPHONE_OS_VERSION_MAX_ALLOWED >= 160400) +- (CGFloat) azimuthAngleInView:(UIView *) view; + +@property (nonatomic, readonly) CGFloat altitudeAngle; +#endif +#if !(__IPHONE_OS_VERSION_MAX_ALLOWED >= 170500) +@property (nonatomic, readonly) CGFloat rollAngle; +#endif +@end + +#endif // !SDL_PLATFORM_TVOS + static SDL_PenID apple_pencil_id = 0; bool UIKit_InitPen(SDL_VideoDevice *_this) @@ -142,11 +167,11 @@ extern void UIKit_HandlePenHover(SDL_uikitview *view, UIHoverGestureRecognizer * static void UIKit_HandlePenAxesFromUITouch(SDL_uikitview *view, UITouch *pencil) { float rollAngle = 0.0f; - #if !defined(SDL_PLATFORM_TVOS) +#if !defined(SDL_PLATFORM_TVOS) if (@available(iOS 17.5, *)) { rollAngle = (float) [pencil rollAngle]; } - #endif +#endif SDL_Window *window = [view getSDLWindow]; const CGPoint point = [pencil locationInView:view]; diff --git a/libs/SDL3/src/video/uikit/SDL_uikitvideo.m b/libs/SDL3/src/video/uikit/SDL_uikitvideo.m index 43f0b30d..5c3987d1 100644 --- a/libs/SDL3/src/video/uikit/SDL_uikitvideo.m +++ b/libs/SDL3/src/video/uikit/SDL_uikitvideo.m @@ -144,7 +144,8 @@ static SDL_VideoDevice *UIKit_CreateDevice(void) VideoBootStrap UIKIT_bootstrap = { UIKITVID_DRIVER_NAME, "SDL UIKit video driver", UIKit_CreateDevice, - UIKit_ShowMessageBox + UIKit_ShowMessageBox, + false }; static bool UIKit_VideoInit(SDL_VideoDevice *_this) diff --git a/libs/SDL3/src/video/vita/SDL_vitavideo.c b/libs/SDL3/src/video/vita/SDL_vitavideo.c index 603b0939..6b5dbd78 100644 --- a/libs/SDL3/src/video/vita/SDL_vitavideo.c +++ b/libs/SDL3/src/video/vita/SDL_vitavideo.c @@ -160,7 +160,8 @@ VideoBootStrap VITA_bootstrap = { "vita", "VITA Video Driver", VITA_Create, - VITA_ShowMessageBox + VITA_ShowMessageBox, + false }; /*****************************************************************************/ diff --git a/libs/SDL3/src/video/vivante/SDL_vivantevideo.c b/libs/SDL3/src/video/vivante/SDL_vivantevideo.c index 269367bf..245c4969 100644 --- a/libs/SDL3/src/video/vivante/SDL_vivantevideo.c +++ b/libs/SDL3/src/video/vivante/SDL_vivantevideo.c @@ -107,7 +107,8 @@ VideoBootStrap VIVANTE_bootstrap = { "vivante", "Vivante EGL Video Driver", VIVANTE_Create, - NULL // no ShowMessageBox implementation + NULL, // no ShowMessageBox implementation + false }; /*****************************************************************************/ diff --git a/libs/SDL3/src/video/wayland/SDL_waylandcolor.c b/libs/SDL3/src/video/wayland/SDL_waylandcolor.c new file mode 100644 index 00000000..dfc69bb5 --- /dev/null +++ b/libs/SDL3/src/video/wayland/SDL_waylandcolor.c @@ -0,0 +1,303 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 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_VIDEO_DRIVER_WAYLAND + +#include "SDL_waylandcolor.h" +#include "SDL_waylandvideo.h" +#include "SDL_waylandwindow.h" +#include "color-management-v1-client-protocol.h" +#include "../../events/SDL_windowevents_c.h" + +typedef struct Wayland_ColorInfoState +{ + struct wp_image_description_v1 *wp_image_description; + struct wp_image_description_info_v1 *wp_image_description_info; + + union + { + SDL_WindowData *window_data; + SDL_DisplayData *display_data; + }; + + enum + { + WAYLAND_COLOR_OBJECT_TYPE_WINDOW, + WAYLAND_COLOR_OBJECT_TYPE_DISPLAY + } object_type; + + SDL_HDROutputProperties HDR; + + // The ICC fd is only valid if the size is non-zero. + int icc_fd; + Uint32 icc_size; + + bool deferred_event_processing; +} Wayland_ColorInfoState; + +static void Wayland_CancelColorInfoRequest(Wayland_ColorInfoState *state) +{ + if (state) { + if (state->wp_image_description_info) { + wp_image_description_info_v1_destroy(state->wp_image_description_info); + state->wp_image_description_info = NULL; + } + if (state->wp_image_description) { + wp_image_description_v1_destroy(state->wp_image_description); + state->wp_image_description = NULL; + } + } +} + +void Wayland_FreeColorInfoState(Wayland_ColorInfoState *state) +{ + if (state) { + Wayland_CancelColorInfoRequest(state); + + switch (state->object_type) { + case WAYLAND_COLOR_OBJECT_TYPE_WINDOW: + state->window_data->color_info_state = NULL; + break; + case WAYLAND_COLOR_OBJECT_TYPE_DISPLAY: + state->display_data->color_info_state = NULL; + break; + } + + SDL_free(state); + } +} + +static void image_description_info_handle_done(void *data, + struct wp_image_description_info_v1 *wp_image_description_info_v1) +{ + Wayland_ColorInfoState *state = (Wayland_ColorInfoState *)data; + Wayland_CancelColorInfoRequest(state); + + switch (state->object_type) { + case WAYLAND_COLOR_OBJECT_TYPE_WINDOW: + { + SDL_SetWindowHDRProperties(state->window_data->sdlwindow, &state->HDR, true); + if (state->icc_size) { + state->window_data->icc_fd = state->icc_fd; + state->window_data->icc_size = state->icc_size; + SDL_SendWindowEvent(state->window_data->sdlwindow, SDL_EVENT_WINDOW_ICCPROF_CHANGED, 0, 0); + } + } break; + case WAYLAND_COLOR_OBJECT_TYPE_DISPLAY: + { + SDL_copyp(&state->display_data->HDR, &state->HDR); + } break; + } +} + +static void image_description_info_handle_icc_file(void *data, + struct wp_image_description_info_v1 *wp_image_description_info_v1, + int32_t icc, uint32_t icc_size) +{ + Wayland_ColorInfoState *state = (Wayland_ColorInfoState *)data; + + state->icc_fd = icc; + state->icc_size = icc_size; +} + +static void image_description_info_handle_primaries(void *data, + struct wp_image_description_info_v1 *wp_image_description_info_v1, + int32_t r_x, int32_t r_y, + int32_t g_x, int32_t g_y, + int32_t b_x, int32_t b_y, + int32_t w_x, int32_t w_y) +{ + // NOP +} + +static void image_description_info_handle_primaries_named(void *data, + struct wp_image_description_info_v1 *wp_image_description_info_v1, + uint32_t primaries) +{ + // NOP +} + +static void image_description_info_handle_tf_power(void *data, + struct wp_image_description_info_v1 *wp_image_description_info_v1, + uint32_t eexp) +{ + // NOP +} + +static void image_description_info_handle_tf_named(void *data, + struct wp_image_description_info_v1 *wp_image_description_info_v1, + uint32_t tf) +{ + // NOP +} + +static void image_description_info_handle_luminances(void *data, + struct wp_image_description_info_v1 *wp_image_description_info_v1, + uint32_t min_lum, + uint32_t max_lum, + uint32_t reference_lum) +{ + Wayland_ColorInfoState *state = (Wayland_ColorInfoState *)data; + state->HDR.HDR_headroom = (float)max_lum / (float)reference_lum; +} + +static void image_description_info_handle_target_primaries(void *data, + struct wp_image_description_info_v1 *wp_image_description_info_v1, + int32_t r_x, int32_t r_y, + int32_t g_x, int32_t g_y, + int32_t b_x, int32_t b_y, + int32_t w_x, int32_t w_y) +{ + // NOP +} + +static void image_description_info_handle_target_luminance(void *data, + struct wp_image_description_info_v1 *wp_image_description_info_v1, + uint32_t min_lum, + uint32_t max_lum) +{ + // NOP +} + +static void image_description_info_handle_target_max_cll(void *data, + struct wp_image_description_info_v1 *wp_image_description_info_v1, + uint32_t max_cll) +{ + // NOP +} + +static void image_description_info_handle_target_max_fall(void *data, + struct wp_image_description_info_v1 *wp_image_description_info_v1, + uint32_t max_fall) +{ + // NOP +} + +static const struct wp_image_description_info_v1_listener image_description_info_listener = { + image_description_info_handle_done, + image_description_info_handle_icc_file, + image_description_info_handle_primaries, + image_description_info_handle_primaries_named, + image_description_info_handle_tf_power, + image_description_info_handle_tf_named, + image_description_info_handle_luminances, + image_description_info_handle_target_primaries, + image_description_info_handle_target_luminance, + image_description_info_handle_target_max_cll, + image_description_info_handle_target_max_fall +}; + +static void PumpColorspaceEvents(Wayland_ColorInfoState *state) +{ + SDL_VideoData *vid = SDL_GetVideoDevice()->internal; + + // Run the image description sequence to completion in its own queue. + struct wl_event_queue *queue = WAYLAND_wl_display_create_queue(vid->display); + if (state->deferred_event_processing) { + WAYLAND_wl_proxy_set_queue((struct wl_proxy *)state->wp_image_description_info, queue); + } else { + WAYLAND_wl_proxy_set_queue((struct wl_proxy *)state->wp_image_description, queue); + } + + while (state->wp_image_description) { + WAYLAND_wl_display_dispatch_queue(vid->display, queue); + } + + WAYLAND_wl_event_queue_destroy(queue); + Wayland_FreeColorInfoState(state); +} + +static void image_description_handle_failed(void *data, + struct wp_image_description_v1 *wp_image_description_v1, + uint32_t cause, + const char *msg) +{ + Wayland_ColorInfoState *state = (Wayland_ColorInfoState *)data; + Wayland_CancelColorInfoRequest(state); + + if (state->deferred_event_processing) { + Wayland_FreeColorInfoState(state); + } +} + +static void image_description_handle_ready(void *data, + struct wp_image_description_v1 *wp_image_description_v1, + uint32_t identity) +{ + Wayland_ColorInfoState *state = (Wayland_ColorInfoState *)data; + + // This will inherit the queue of the factory image description object. + state->wp_image_description_info = wp_image_description_v1_get_information(state->wp_image_description); + wp_image_description_info_v1_add_listener(state->wp_image_description_info, &image_description_info_listener, data); + + if (state->deferred_event_processing) { + PumpColorspaceEvents(state); + } +} + +static const struct wp_image_description_v1_listener image_description_listener = { + image_description_handle_failed, + image_description_handle_ready +}; + +void Wayland_GetColorInfoForWindow(SDL_WindowData *window_data, bool defer_event_processing) +{ + // Cancel any pending request, as it is out-of-date. + Wayland_FreeColorInfoState(window_data->color_info_state); + Wayland_ColorInfoState *state = SDL_calloc(1, sizeof(Wayland_ColorInfoState)); + + if (state) { + window_data->color_info_state = state; + state->window_data = window_data; + state->object_type = WAYLAND_COLOR_OBJECT_TYPE_WINDOW; + state->deferred_event_processing = defer_event_processing; + state->wp_image_description = wp_color_management_surface_feedback_v1_get_preferred(window_data->wp_color_management_surface_feedback); + wp_image_description_v1_add_listener(state->wp_image_description, &image_description_listener, state); + + if (!defer_event_processing) { + PumpColorspaceEvents(state); + } + } +} + +void Wayland_GetColorInfoForOutput(SDL_DisplayData *display_data, bool defer_event_processing) +{ + // Cancel any pending request, as it is out-of-date. + Wayland_FreeColorInfoState(display_data->color_info_state); + Wayland_ColorInfoState *state = SDL_calloc(1, sizeof(Wayland_ColorInfoState)); + + if (state) { + display_data->color_info_state = state; + state->display_data = display_data; + state->object_type = WAYLAND_COLOR_OBJECT_TYPE_DISPLAY; + state->deferred_event_processing = defer_event_processing; + state->wp_image_description = wp_color_management_output_v1_get_image_description(display_data->wp_color_management_output); + wp_image_description_v1_add_listener(state->wp_image_description, &image_description_listener, state); + + if (!defer_event_processing) { + PumpColorspaceEvents(state); + } + } +} + +#endif // SDL_VIDEO_DRIVER_WAYLAND diff --git a/libs/SDL3/src/video/wayland/SDL_waylandcolor.h b/libs/SDL3/src/video/wayland/SDL_waylandcolor.h new file mode 100644 index 00000000..bef5d8c3 --- /dev/null +++ b/libs/SDL3/src/video/wayland/SDL_waylandcolor.h @@ -0,0 +1,35 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 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" + +#ifndef SDL_waylandcolor_h_ +#define SDL_waylandcolor_h_ + +#include "../SDL_sysvideo.h" + +struct Wayland_ColorInfoState; + +extern void Wayland_FreeColorInfoState(struct Wayland_ColorInfoState *state); +extern void Wayland_GetColorInfoForWindow(SDL_WindowData *window_data, bool defer_event_processing); +extern void Wayland_GetColorInfoForOutput(SDL_DisplayData *display_data, bool defer_event_processing); + +#endif // SDL_waylandcolor_h_ diff --git a/libs/SDL3/src/video/wayland/SDL_waylanddatamanager.c b/libs/SDL3/src/video/wayland/SDL_waylanddatamanager.c index 8c75e3d0..6f5b32bb 100644 --- a/libs/SDL3/src/video/wayland/SDL_waylanddatamanager.c +++ b/libs/SDL3/src/video/wayland/SDL_waylanddatamanager.c @@ -272,7 +272,7 @@ void Wayland_primary_selection_source_set_callback(SDL_WaylandPrimarySelectionSo } } -static void *Wayland_clone_data_buffer(const void *buffer, size_t *len) +static void *Wayland_clone_data_buffer(const void *buffer, const size_t *len) { void *clone = NULL; if (*len > 0 && buffer) { @@ -382,7 +382,7 @@ void *Wayland_data_offer_receive(SDL_WaylandDataOffer *offer, close(pipefd[0]); } SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Wayland_data_offer_receive for '%s', buffer (%ld) at %p\n", + ". In Wayland_data_offer_receive for '%s', buffer (%zu) at %p", mime_type, *length, buffer); return buffer; } @@ -418,7 +418,7 @@ void *Wayland_primary_selection_offer_receive(SDL_WaylandPrimarySelectionOffer * close(pipefd[0]); } SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Wayland_primary_selection_offer_receive for '%s', buffer (%ld) at %p\n", + ". In Wayland_primary_selection_offer_receive for '%s', buffer (%zu) at %p", mime_type, *length, buffer); return buffer; } diff --git a/libs/SDL3/src/video/wayland/SDL_waylanddyn.c b/libs/SDL3/src/video/wayland/SDL_waylanddyn.c index dd0f3fc1..7d6d42f3 100644 --- a/libs/SDL3/src/video/wayland/SDL_waylanddyn.c +++ b/libs/SDL3/src/video/wayland/SDL_waylanddyn.c @@ -66,9 +66,9 @@ static void *WAYLAND_GetSym(const char *fnname, int *pHasModule, bool required) #if DEBUG_DYNAMIC_WAYLAND if (fn) { - SDL_Log("WAYLAND: Found '%s' in %s (%p)\n", fnname, dynlib->libname, fn); + SDL_Log("WAYLAND: Found '%s' in %s (%p)", fnname, dynlib->libname, fn); } else { - SDL_Log("WAYLAND: Symbol '%s' NOT FOUND!\n", fnname); + SDL_Log("WAYLAND: Symbol '%s' NOT FOUND!", fnname); } #endif diff --git a/libs/SDL3/src/video/wayland/SDL_waylandevents.c b/libs/SDL3/src/video/wayland/SDL_waylandevents.c index c6260b86..83c414fb 100644 --- a/libs/SDL3/src/video/wayland/SDL_waylandevents.c +++ b/libs/SDL3/src/video/wayland/SDL_waylandevents.c @@ -1397,7 +1397,7 @@ static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, close(fd); if (!input->xkb.keymap) { - SDL_SetError("failed to compile keymap\n"); + SDL_SetError("failed to compile keymap"); return; } @@ -1422,7 +1422,7 @@ static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, } input->xkb.state = WAYLAND_xkb_state_new(input->xkb.keymap); if (!input->xkb.state) { - SDL_SetError("failed to create XKB state\n"); + SDL_SetError("failed to create XKB state"); WAYLAND_xkb_keymap_unref(input->xkb.keymap); input->xkb.keymap = NULL; return; @@ -1472,7 +1472,7 @@ static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, input->xkb.compose_state = WAYLAND_xkb_compose_state_new(input->xkb.compose_table, XKB_COMPOSE_STATE_NO_FLAGS); if (!input->xkb.compose_state) { - SDL_SetError("could not create XKB compose state\n"); + SDL_SetError("could not create XKB compose state"); WAYLAND_xkb_compose_table_unref(input->xkb.compose_table); input->xkb.compose_table = NULL; } @@ -1987,7 +1987,7 @@ static void seat_handle_capabilities(void *data, struct wl_seat *seat, Wayland_input_init_relative_pointer(input->display); input->pointer_id = SDL_GetNextObjectID(); - SDL_AddMouse(input->pointer_id, WAYLAND_DEFAULT_POINTER_NAME, true); + SDL_AddMouse(input->pointer_id, WAYLAND_DEFAULT_POINTER_NAME, !input->display->initializing); } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) { if (input->relative_pointer) { zwp_relative_pointer_v1_destroy(input->relative_pointer); @@ -2028,7 +2028,7 @@ static void seat_handle_capabilities(void *data, struct wl_seat *seat, input); input->keyboard_id = SDL_GetNextObjectID(); - SDL_AddKeyboard(input->keyboard_id, WAYLAND_DEFAULT_KEYBOARD_NAME, true); + SDL_AddKeyboard(input->keyboard_id, WAYLAND_DEFAULT_KEYBOARD_NAME, !input->display->initializing); } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) { wl_keyboard_destroy(input->keyboard); input->keyboard = NULL; @@ -2179,7 +2179,7 @@ static void data_offer_handle_offer(void *data, struct wl_data_offer *wl_data_of SDL_WaylandDataOffer *offer = data; Wayland_data_offer_add_mime(offer, mime_type); SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In wl_data_offer_listener . data_offer_handle_offer on data_offer 0x%08x for MIME '%s'\n", + ". In wl_data_offer_listener . data_offer_handle_offer on data_offer 0x%08x for MIME '%s'", (wl_data_offer ? WAYLAND_wl_proxy_get_id((struct wl_proxy *)wl_data_offer) : -1), mime_type); } @@ -2188,7 +2188,7 @@ static void data_offer_handle_source_actions(void *data, struct wl_data_offer *w uint32_t source_actions) { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In wl_data_offer_listener . data_offer_handle_source_actions on data_offer 0x%08x for Source Actions '%d'\n", + ". In wl_data_offer_listener . data_offer_handle_source_actions on data_offer 0x%08x for Source Actions '%d'", (wl_data_offer ? WAYLAND_wl_proxy_get_id((struct wl_proxy *)wl_data_offer) : -1), source_actions); } @@ -2197,7 +2197,7 @@ static void data_offer_handle_actions(void *data, struct wl_data_offer *wl_data_ uint32_t dnd_action) { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In wl_data_offer_listener . data_offer_handle_actions on data_offer 0x%08x for DND Actions '%d'\n", + ". In wl_data_offer_listener . data_offer_handle_actions on data_offer 0x%08x for DND Actions '%d'", (wl_data_offer ? WAYLAND_wl_proxy_get_id((struct wl_proxy *)wl_data_offer) : -1), dnd_action); } @@ -2214,7 +2214,7 @@ static void primary_selection_offer_handle_offer(void *data, struct zwp_primary_ SDL_WaylandPrimarySelectionOffer *offer = data; Wayland_primary_selection_offer_add_mime(offer, mime_type); SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In zwp_primary_selection_offer_v1_listener . primary_selection_offer_handle_offer on primary_selection_offer 0x%08x for MIME '%s'\n", + ". In zwp_primary_selection_offer_v1_listener . primary_selection_offer_handle_offer on primary_selection_offer 0x%08x for MIME '%s'", (zwp_primary_selection_offer_v1 ? WAYLAND_wl_proxy_get_id((struct wl_proxy *)zwp_primary_selection_offer_v1) : -1), mime_type); } @@ -2234,7 +2234,7 @@ static void data_device_handle_data_offer(void *data, struct wl_data_device *wl_ wl_data_offer_set_user_data(id, data_offer); wl_data_offer_add_listener(id, &data_offer_listener, data_offer); SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In wl_data_device_listener . data_device_handle_data_offer on data_offer 0x%08x\n", + ". In wl_data_device_listener . data_device_handle_data_offer on data_offer 0x%08x", (id ? WAYLAND_wl_proxy_get_id((struct wl_proxy *)id) : -1)); } } @@ -2292,25 +2292,25 @@ static void data_device_handle_enter(void *data, struct wl_data_device *wl_data_ const float dy = (float)wl_fixed_to_double(y); SDL_SendDropPosition(data_device->dnd_window, dx, dy); SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In wl_data_device_listener . data_device_handle_enter on data_offer 0x%08x at %d x %d into window %d for serial %d\n", + ". In wl_data_device_listener . data_device_handle_enter on data_offer 0x%08x at %d x %d into window %d for serial %d", WAYLAND_wl_proxy_get_id((struct wl_proxy *)id), wl_fixed_to_int(x), wl_fixed_to_int(y), SDL_GetWindowID(data_device->dnd_window), serial); } else { data_device->dnd_window = NULL; SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In wl_data_device_listener . data_device_handle_enter on data_offer 0x%08x at %d x %d for serial %d\n", + ". In wl_data_device_listener . data_device_handle_enter on data_offer 0x%08x at %d x %d for serial %d", WAYLAND_wl_proxy_get_id((struct wl_proxy *)id), wl_fixed_to_int(x), wl_fixed_to_int(y), serial); } } else { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In wl_data_device_listener . data_device_handle_enter on data_offer 0x%08x at %d x %d for serial %d\n", + ". In wl_data_device_listener . data_device_handle_enter on data_offer 0x%08x at %d x %d for serial %d", WAYLAND_wl_proxy_get_id((struct wl_proxy *)id), wl_fixed_to_int(x), wl_fixed_to_int(y), serial); } } else { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In wl_data_device_listener . data_device_handle_enter on data_offer 0x%08x at %d x %d for serial %d\n", + ". In wl_data_device_listener . data_device_handle_enter on data_offer 0x%08x at %d x %d for serial %d", -1, wl_fixed_to_int(x), wl_fixed_to_int(y), serial); } } @@ -2323,12 +2323,12 @@ static void data_device_handle_leave(void *data, struct wl_data_device *wl_data_ if (data_device->dnd_window) { SDL_SendDropComplete(data_device->dnd_window); SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In wl_data_device_listener . data_device_handle_leave on data_offer 0x%08x from window %d for serial %d\n", + ". In wl_data_device_listener . data_device_handle_leave on data_offer 0x%08x from window %d for serial %d", WAYLAND_wl_proxy_get_id((struct wl_proxy *)data_device->drag_offer->offer), SDL_GetWindowID(data_device->dnd_window), data_device->drag_serial); } else { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In wl_data_device_listener . data_device_handle_leave on data_offer 0x%08x for serial %d\n", + ". In wl_data_device_listener . data_device_handle_leave on data_offer 0x%08x for serial %d", WAYLAND_wl_proxy_get_id((struct wl_proxy *)data_device->drag_offer->offer), data_device->drag_serial); } @@ -2336,7 +2336,7 @@ static void data_device_handle_leave(void *data, struct wl_data_device *wl_data_ data_device->drag_offer = NULL; } else { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In wl_data_device_listener . data_device_handle_leave on data_offer 0x%08x for serial %d\n", + ". In wl_data_device_listener . data_device_handle_leave on data_offer 0x%08x for serial %d", -1, -1); } data_device->has_mime_file = false; @@ -2358,13 +2358,13 @@ static void data_device_handle_motion(void *data, struct wl_data_device *wl_data */ SDL_SendDropPosition(data_device->dnd_window, dx, dy); SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In wl_data_device_listener . data_device_handle_motion on data_offer 0x%08x at %d x %d in window %d serial %d\n", + ". In wl_data_device_listener . data_device_handle_motion on data_offer 0x%08x at %d x %d in window %d serial %d", WAYLAND_wl_proxy_get_id((struct wl_proxy *)data_device->drag_offer->offer), wl_fixed_to_int(x), wl_fixed_to_int(y), SDL_GetWindowID(data_device->dnd_window), data_device->drag_serial); } else { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In wl_data_device_listener . data_device_handle_motion on data_offer 0x%08x at %d x %d serial %d\n", + ". In wl_data_device_listener . data_device_handle_motion on data_offer 0x%08x at %d x %d serial %d", -1, wl_fixed_to_int(x), wl_fixed_to_int(y), -1); } } @@ -2375,7 +2375,7 @@ static void data_device_handle_drop(void *data, struct wl_data_device *wl_data_d if (data_device->drag_offer && data_device->dnd_window && (data_device->has_mime_file || data_device->has_mime_text)) { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In wl_data_device_listener . data_device_handle_drop on data_offer 0x%08x in window %d serial %d\n", + ". In wl_data_device_listener . data_device_handle_drop on data_offer 0x%08x in window %d serial %d", WAYLAND_wl_proxy_get_id((struct wl_proxy *)data_device->drag_offer->offer), SDL_GetWindowID(data_device->dnd_window), data_device->drag_serial); // TODO: SDL Support more mime types @@ -2457,7 +2457,7 @@ static void data_device_handle_drop(void *data, struct wl_data_device *wl_data_d } } else { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In wl_data_device_listener . data_device_handle_drop on data_offer 0x%08x serial %d\n", + ". In wl_data_device_listener . data_device_handle_drop on data_offer 0x%08x serial %d", -1, -1); } @@ -2511,7 +2511,7 @@ static void data_device_handle_selection(void *data, struct wl_data_device *wl_d } SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In data_device_listener . data_device_handle_selection on data_offer 0x%08x\n", + ". In data_device_listener . data_device_handle_selection on data_offer 0x%08x", (id ? WAYLAND_wl_proxy_get_id((struct wl_proxy *)id) : -1)); if (data_device->selection_offer != offer) { Wayland_data_offer_destroy(data_device->selection_offer); @@ -2542,7 +2542,7 @@ static void primary_selection_device_handle_offer(void *data, struct zwp_primary zwp_primary_selection_offer_v1_add_listener(id, &primary_selection_offer_listener, primary_selection_offer); } SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In zwp_primary_selection_device_v1_listener . primary_selection_device_handle_offer on primary_selection_offer 0x%08x\n", + ". In zwp_primary_selection_device_v1_listener . primary_selection_device_handle_offer on primary_selection_offer 0x%08x", (id ? WAYLAND_wl_proxy_get_id((struct wl_proxy *)id) : -1)); } @@ -2561,10 +2561,8 @@ static void primary_selection_device_handle_selection(void *data, struct zwp_pri primary_selection_device->selection_offer = offer; } SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In zwp_primary_selection_device_v1_listener . primary_selection_device_handle_selection on primary_selection_offer 0x%08x\n", + ". In zwp_primary_selection_device_v1_listener . primary_selection_device_handle_selection on primary_selection_offer 0x%08x", (id ? WAYLAND_wl_proxy_get_id((struct wl_proxy *)id) : -1)); - - notifyFromMimes(offer ? &offer->mimes : NULL); } static const struct zwp_primary_selection_device_v1_listener primary_selection_device_listener = { diff --git a/libs/SDL3/src/video/wayland/SDL_waylandmouse.c b/libs/SDL3/src/video/wayland/SDL_waylandmouse.c index 968cb6f0..8075c3a2 100644 --- a/libs/SDL3/src/video/wayland/SDL_waylandmouse.c +++ b/libs/SDL3/src/video/wayland/SDL_waylandmouse.c @@ -598,6 +598,13 @@ static SDL_Cursor *Wayland_CreateDefaultCursor(void) static void Wayland_FreeCursorData(SDL_CursorData *d) { + SDL_VideoDevice *vd = SDL_GetVideoDevice(); + struct SDL_WaylandInput *input = vd->internal->input; + + if (input->current_cursor == d) { + input->current_cursor = NULL; + } + // Buffers for system cursors must not be destroyed. if (d->is_system_cursor) { if (d->cursor_data.system.frame_callback) { diff --git a/libs/SDL3/src/video/wayland/SDL_waylandvideo.c b/libs/SDL3/src/video/wayland/SDL_waylandvideo.c index 7ea5a582..43019535 100644 --- a/libs/SDL3/src/video/wayland/SDL_waylandvideo.c +++ b/libs/SDL3/src/video/wayland/SDL_waylandvideo.c @@ -27,6 +27,7 @@ #include "../../events/SDL_events_c.h" #include "SDL_waylandclipboard.h" +#include "SDL_waylandcolor.h" #include "SDL_waylandevents_c.h" #include "SDL_waylandkeyboard.h" #include "SDL_waylandmessagebox.h" @@ -63,6 +64,7 @@ #include "xdg-output-unstable-v1-client-protocol.h" #include "xdg-shell-client-protocol.h" #include "xdg-toplevel-icon-v1-client-protocol.h" +#include "color-management-v1-client-protocol.h" #ifdef HAVE_LIBDECOR_H #include @@ -249,7 +251,7 @@ static int SDLCALL Wayland_DisplayPositionCompare(const void *a, const void *b) * The primary is determined by the following criteria, in order: * - Landscape is preferred over portrait * - The highest native resolution - * - TODO: A higher HDR range is preferred + * - A higher HDR range is preferred * - Higher refresh is preferred (ignoring small differences) * - Lower scale values are preferred (larger display) */ @@ -271,6 +273,7 @@ static int Wayland_GetPrimaryDisplay(SDL_VideoData *vid) int best_width = 0; int best_height = 0; double best_scale = 0.0; + float best_headroom = 0.0f; int best_refresh = 0; bool best_is_landscape = false; int best_index = 0; @@ -286,11 +289,15 @@ static int Wayland_GetPrimaryDisplay(SDL_VideoData *vid) if (d->pixel_width > best_width || d->pixel_height > best_height) { have_new_best = true; } else if (d->pixel_width == best_width && d->pixel_height == best_height) { - if (d->refresh - best_refresh > REFRESH_DELTA) { // Favor a higher refresh rate, but ignore small differences (e.g. 59.97 vs 60.1) - have_new_best = true; - } else if (d->scale_factor < best_scale && SDL_abs(d->refresh - best_refresh) <= REFRESH_DELTA) { - // Prefer a lower scale display if the difference in refresh rate is small. + if (d->HDR.HDR_headroom > best_headroom) { // Favor a higher HDR luminance range have_new_best = true; + } else if (d->HDR.HDR_headroom == best_headroom) { + if (d->refresh - best_refresh > REFRESH_DELTA) { // Favor a higher refresh rate, but ignore small differences (e.g. 59.97 vs 60.1) + have_new_best = true; + } else if (d->scale_factor < best_scale && SDL_abs(d->refresh - best_refresh) <= REFRESH_DELTA) { + // Prefer a lower scale display if the difference in refresh rate is small. + have_new_best = true; + } } } } @@ -299,6 +306,7 @@ static int Wayland_GetPrimaryDisplay(SDL_VideoData *vid) best_width = d->pixel_width; best_height = d->pixel_height; best_scale = d->scale_factor; + best_headroom = d->HDR.HDR_headroom; best_refresh = d->refresh; best_is_landscape = is_landscape; best_index = i; @@ -630,6 +638,7 @@ static SDL_VideoDevice *Wayland_CreateDevice(bool require_preferred_protocols) device->SetWindowIcon = Wayland_SetWindowIcon; device->GetWindowSizeInPixels = Wayland_GetWindowSizeInPixels; device->GetWindowContentScale = Wayland_GetWindowContentScale; + device->GetWindowICCProfile = Wayland_GetWindowICCProfile; device->GetDisplayForWindow = Wayland_GetDisplayForWindow; device->DestroyWindow = Wayland_DestroyWindow; device->SetWindowHitTest = Wayland_SetWindowHitTest; @@ -685,13 +694,15 @@ static SDL_VideoDevice *Wayland_Fallback_CreateDevice(void) VideoBootStrap Wayland_preferred_bootstrap = { WAYLANDVID_DRIVER_NAME, "SDL Wayland video driver", Wayland_Preferred_CreateDevice, - Wayland_ShowMessageBox + Wayland_ShowMessageBox, + true }; VideoBootStrap Wayland_bootstrap = { WAYLANDVID_DRIVER_NAME, "SDL Wayland video driver", Wayland_Fallback_CreateDevice, - Wayland_ShowMessageBox + Wayland_ShowMessageBox, + false }; static void xdg_output_handle_logical_position(void *data, struct zxdg_output_v1 *xdg_output, @@ -716,7 +727,7 @@ static void xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xd static void xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output) { - SDL_DisplayData *internal = (void *)data; + SDL_DisplayData *internal = data; /* * xdg-output.done events are deprecated and only apply below version 3 of the protocol. @@ -1025,6 +1036,10 @@ static void display_handle_done(void *data, // Expose the unscaled, native resolution if the scale is 1.0 or viewports are available... if (internal->scale_factor == 1.0 || video->viewporter) { SDL_AddFullscreenDisplayMode(dpy, &native_mode); + if (native_mode.w != desktop_mode.w || + native_mode.h != desktop_mode.h) { + SDL_AddFullscreenDisplayMode(dpy, &desktop_mode); + } } else { // ...otherwise expose the integer scaled variants of the desktop resolution down to 1. int i; @@ -1044,6 +1059,8 @@ static void display_handle_done(void *data, AddEmulatedModes(internal, native_mode.w, native_mode.h); } + SDL_SetDisplayHDRProperties(dpy, &internal->HDR); + if (internal->display == 0) { // First time getting display info, initialize the VideoDisplay if (internal->physical_width_mm >= internal->physical_height_mm) { @@ -1101,6 +1118,18 @@ static const struct wl_output_listener output_listener = { display_handle_description // Version 4 }; +static void handle_output_image_description_changed(void *data, + struct wp_color_management_output_v1 *wp_color_management_output_v1) +{ + SDL_DisplayData *display = (SDL_DisplayData *)data; + // wl_display.done is called after this event, so the display HDR status will be updated there. + Wayland_GetColorInfoForOutput(display, false); +} + +static const struct wp_color_management_output_v1_listener wp_color_management_output_listener = { + handle_output_image_description_changed +}; + static bool Wayland_add_display(SDL_VideoData *d, uint32_t id, uint32_t version) { struct wl_output *output; @@ -1130,6 +1159,11 @@ static bool Wayland_add_display(SDL_VideoData *d, uint32_t id, uint32_t version) data->xdg_output = zxdg_output_manager_v1_get_xdg_output(data->videodata->xdg_output_manager, output); zxdg_output_v1_add_listener(data->xdg_output, &xdg_output_listener, data); } + if (data->videodata->wp_color_manager_v1) { + data->wp_color_management_output = wp_color_manager_v1_get_output(data->videodata->wp_color_manager_v1, output); + wp_color_management_output_v1_add_listener(data->wp_color_management_output, &wp_color_management_output_listener, data); + Wayland_GetColorInfoForOutput(data, true); + } return true; } @@ -1147,6 +1181,11 @@ static void Wayland_free_display(SDL_VideoDisplay *display, bool send_event) SDL_free(display_data->wl_output_name); + if (display_data->wp_color_management_output) { + Wayland_FreeColorInfoState(display_data->color_info_state); + wp_color_management_output_v1_destroy(display_data->wp_color_management_output); + } + if (display_data->xdg_output) { zxdg_output_v1_destroy(display_data->xdg_output); } @@ -1174,13 +1213,23 @@ static void Wayland_FinalizeDisplays(SDL_VideoData *vid) static void Wayland_init_xdg_output(SDL_VideoData *d) { - for(int i = 0; i < d->output_count; ++i) { + for (int i = 0; i < d->output_count; ++i) { SDL_DisplayData *disp = d->output_list[i]; disp->xdg_output = zxdg_output_manager_v1_get_xdg_output(disp->videodata->xdg_output_manager, disp->output); zxdg_output_v1_add_listener(disp->xdg_output, &xdg_output_listener, disp); } } +static void Wayland_InitColorManager(SDL_VideoData *d) +{ + for (int i = 0; i < d->output_count; ++i) { + SDL_DisplayData *disp = d->output_list[i]; + disp->wp_color_management_output = wp_color_manager_v1_get_output(disp->videodata->wp_color_manager_v1, disp->output); + wp_color_management_output_v1_add_listener(disp->wp_color_management_output, &wp_color_management_output_listener, disp); + Wayland_GetColorInfoForOutput(disp, true); + } +} + static void handle_ping_xdg_wm_base(void *data, struct xdg_wm_base *xdg, uint32_t serial) { xdg_wm_base_pong(xdg, serial); @@ -1195,7 +1244,7 @@ static void libdecor_error(struct libdecor *context, enum libdecor_error error, const char *message) { - SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "libdecor error (%d): %s\n", error, message); + SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "libdecor error (%d): %s", error, message); } static struct libdecor_interface libdecor_interface = { @@ -1274,6 +1323,9 @@ static void display_handle_global(void *data, struct wl_registry *registry, uint d->xdg_toplevel_icon_manager_v1 = wl_registry_bind(d->registry, id, &xdg_toplevel_icon_manager_v1_interface, 1); } else if (SDL_strcmp(interface, "frog_color_management_factory_v1") == 0) { d->frog_color_management_factory_v1 = wl_registry_bind(d->registry, id, &frog_color_management_factory_v1_interface, 1); + } else if (SDL_strcmp(interface, "wp_color_manager_v1") == 0) { + d->wp_color_manager_v1 = wl_registry_bind(d->registry, id, &wp_color_manager_v1_interface, 1); + Wayland_InitColorManager(d); } } @@ -1362,10 +1414,16 @@ bool Wayland_VideoInit(SDL_VideoDevice *_this) // First roundtrip to receive all registry objects. WAYLAND_wl_display_roundtrip(data->display); - // Require viewports for display scaling. - if (data->scale_to_display_enabled && !data->viewporter) { - SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "wayland: Display scaling requires the missing 'wp_viewporter' protocol: disabling"); - data->scale_to_display_enabled = false; + // Require viewports and xdg-output for display scaling. + if (data->scale_to_display_enabled) { + if (!data->viewporter) { + SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "wayland: Display scaling requires the missing 'wp_viewporter' protocol: disabling"); + data->scale_to_display_enabled = false; + } + if (!data->xdg_output_manager) { + SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "wayland: Display scaling requires the missing 'zxdg_output_manager_v1' protocol: disabling"); + data->scale_to_display_enabled = false; + } } // Now that we have all the protocols, load libdecor if applicable @@ -1555,6 +1613,11 @@ static void Wayland_VideoCleanup(SDL_VideoDevice *_this) data->frog_color_management_factory_v1 = NULL; } + if (data->wp_color_manager_v1) { + wp_color_manager_v1_destroy(data->wp_color_manager_v1); + data->wp_color_manager_v1 = NULL; + } + if (data->compositor) { wl_compositor_destroy(data->compositor); data->compositor = NULL; diff --git a/libs/SDL3/src/video/wayland/SDL_waylandvideo.h b/libs/SDL3/src/video/wayland/SDL_waylandvideo.h index 44f5f359..8cde64c9 100644 --- a/libs/SDL3/src/video/wayland/SDL_waylandvideo.h +++ b/libs/SDL3/src/video/wayland/SDL_waylandvideo.h @@ -83,6 +83,7 @@ struct SDL_VideoData struct wp_alpha_modifier_v1 *wp_alpha_modifier_v1; struct xdg_toplevel_icon_manager_v1 *xdg_toplevel_icon_manager_v1; struct frog_color_management_factory_v1 *frog_color_management_factory_v1; + struct wp_color_manager_v1 *wp_color_manager_v1; struct zwp_tablet_manager_v2 *tablet_manager; struct xkb_context *xkb_context; @@ -102,6 +103,7 @@ struct SDL_DisplayData SDL_VideoData *videodata; struct wl_output *output; struct zxdg_output_v1 *xdg_output; + struct wp_color_management_output_v1 *wp_color_management_output; char *wl_output_name; double scale_factor; uint32_t registry_id; @@ -111,9 +113,12 @@ struct SDL_DisplayData SDL_DisplayOrientation orientation; int physical_width_mm, physical_height_mm; bool has_logical_position, has_logical_size; + bool running_colorspace_event_queue; + SDL_HDROutputProperties HDR; SDL_DisplayID display; SDL_VideoDisplay placeholder; int wl_output_done_count; + struct Wayland_ColorInfoState *color_info_state; }; // Needed here to get wl_surface declaration, fixes GitHub#4594 diff --git a/libs/SDL3/src/video/wayland/SDL_waylandwindow.c b/libs/SDL3/src/video/wayland/SDL_waylandwindow.c index ebf79a26..212fd54f 100644 --- a/libs/SDL3/src/video/wayland/SDL_waylandwindow.c +++ b/libs/SDL3/src/video/wayland/SDL_waylandwindow.c @@ -23,6 +23,8 @@ #ifdef SDL_VIDEO_DRIVER_WAYLAND +#include + #include "../SDL_sysvideo.h" #include "../../events/SDL_events_c.h" #include "../../core/unix/SDL_appid.h" @@ -31,6 +33,7 @@ #include "SDL_waylandwindow.h" #include "SDL_waylandvideo.h" #include "../../SDL_hints_c.h" +#include "SDL_waylandcolor.h" #include "alpha-modifier-v1-client-protocol.h" #include "xdg-shell-client-protocol.h" @@ -43,6 +46,7 @@ #include "xdg-dialog-v1-client-protocol.h" #include "frog-color-management-v1-client-protocol.h" #include "xdg-toplevel-icon-v1-client-protocol.h" +#include "color-management-v1-client-protocol.h" #ifdef HAVE_LIBDECOR_H #include @@ -1647,6 +1651,18 @@ static const struct frog_color_managed_surface_listener frog_surface_listener = frog_preferred_metadata_handler }; +static void feedback_surface_preferred_changed(void *data, + struct wp_color_management_surface_feedback_v1 *wp_color_management_surface_feedback_v1, + uint32_t identity) +{ + SDL_WindowData *wind = (SDL_WindowData *)data; + Wayland_GetColorInfoForWindow(wind, false); +} + +static const struct wp_color_management_surface_feedback_v1_listener color_management_surface_feedback_listener = { + feedback_surface_preferred_changed +}; + static void SetKeyboardFocus(SDL_Window *window, bool set_focus) { SDL_Window *toplevel = window; @@ -1838,7 +1854,10 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window) } else { libdecor_frame_set_app_id(data->shell_surface.libdecor.frame, data->app_id); libdecor_frame_map(data->shell_surface.libdecor.frame); - libdecor_frame_set_visibility(data->shell_surface.libdecor.frame, !(window->flags & SDL_WINDOW_BORDERLESS)); + if (window->flags & SDL_WINDOW_BORDERLESS) { + // Note: Calling this with 'true' immediately after mapping will cause the libdecor Cairo plugin to crash. + libdecor_frame_set_visibility(data->shell_surface.libdecor.frame, false); + } if (c->zxdg_exporter_v2) { data->exported = zxdg_exporter_v2_export_toplevel(c->zxdg_exporter_v2, data->surface); @@ -2594,7 +2613,11 @@ bool Wayland_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Proper } if (!custom_surface_role) { - if (c->frog_color_management_factory_v1) { + if (c->wp_color_manager_v1) { + data->wp_color_management_surface_feedback = wp_color_manager_v1_get_surface_feedback(c->wp_color_manager_v1, data->surface); + wp_color_management_surface_feedback_v1_add_listener(data->wp_color_management_surface_feedback, &color_management_surface_feedback_listener, data); + Wayland_GetColorInfoForWindow(data, true); + } else if (c->frog_color_management_factory_v1) { data->frog_color_managed_surface = frog_color_management_factory_v1_get_color_managed_surface(c->frog_color_management_factory_v1, data->surface); frog_color_managed_surface_add_listener(data->frog_color_managed_surface, &frog_surface_listener, data); } @@ -2837,28 +2860,56 @@ bool Wayland_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surfa struct xdg_toplevel *toplevel = NULL; if (!_this->internal->xdg_toplevel_icon_manager_v1) { - return SDL_SetError("wayland: cannot set icon; xdg_toplevel_icon_v1 protocol not supported"); + return SDL_SetError("wayland: cannot set icon; required xdg_toplevel_icon_v1 protocol not supported"); } if (icon->w != icon->h) { return SDL_SetError("wayland: icon width and height must be equal, got %ix%i", icon->w, icon->h); } + int image_count = 0; + SDL_Surface **images = SDL_GetSurfaceImages(icon, &image_count); + if (!images || !image_count) { + return false; + } + + // Release the old icon resources. if (wind->xdg_toplevel_icon_v1) { xdg_toplevel_icon_v1_destroy(wind->xdg_toplevel_icon_v1); wind->xdg_toplevel_icon_v1 = NULL; } - // TODO: Add high-DPI icon support - Wayland_ReleaseSHMBuffer(&wind->icon); - if (!Wayland_AllocSHMBuffer(icon->w, icon->h, &wind->icon)) { - return SDL_SetError("wayland: failed to allocate SHM buffer for the icon"); + for (int i = 0; i < wind->icon_buffer_count; ++i) { + Wayland_ReleaseSHMBuffer(&wind->icon_buffers[i]); } - - SDL_PremultiplyAlpha(icon->w, icon->h, icon->format, icon->pixels, icon->pitch, SDL_PIXELFORMAT_ARGB8888, wind->icon.shm_data, icon->w * 4, true); + SDL_free(wind->icon_buffers); + wind->icon_buffer_count = 0; wind->xdg_toplevel_icon_v1 = xdg_toplevel_icon_manager_v1_create_icon(_this->internal->xdg_toplevel_icon_manager_v1); - xdg_toplevel_icon_v1_add_buffer(wind->xdg_toplevel_icon_v1, wind->icon.wl_buffer, 1); + wind->icon_buffers = SDL_calloc(image_count, sizeof(struct Wayland_SHMBuffer)); + if (!wind->icon_buffers) { + goto failure_cleanup; + } + + for (int i = 0; i < image_count; ++i) { + if (images[i]->w == images[i]->h) { + struct Wayland_SHMBuffer *buffer = &wind->icon_buffers[wind->icon_buffer_count]; + + if (!Wayland_AllocSHMBuffer(images[i]->w, images[i]->h, buffer)) { + SDL_SetError("wayland: failed to allocate SHM buffer for the icon"); + goto failure_cleanup; + } + + SDL_PremultiplyAlpha(images[i]->w, images[i]->h, images[i]->format, images[i]->pixels, images[i]->pitch, SDL_PIXELFORMAT_ARGB8888, buffer->shm_data, images[i]->w * 4, true); + const int scale = (int)SDL_ceil((double)images[i]->w / (double)icon->w); + xdg_toplevel_icon_v1_add_buffer(wind->xdg_toplevel_icon_v1, buffer->wl_buffer, scale); + wind->icon_buffer_count++; + } else { + SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "wayland: icon width and height must be equal, got %ix%i for image level %i; skipping", images[i]->w, images[i]->h, i); + } + } + + SDL_free(images); #ifdef HAVE_LIBDECOR_H if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR && wind->shell_surface.libdecor.frame) { @@ -2874,6 +2925,42 @@ bool Wayland_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surfa } return true; + +failure_cleanup: + + if (wind->xdg_toplevel_icon_v1) { + xdg_toplevel_icon_v1_destroy(wind->xdg_toplevel_icon_v1); + wind->xdg_toplevel_icon_v1 = NULL; + } + + for (int i = 0; i < wind->icon_buffer_count; ++i) { + Wayland_ReleaseSHMBuffer(&wind->icon_buffers[i]); + } + SDL_free(wind->icon_buffers); + wind->icon_buffers = NULL; + wind->icon_buffer_count = 0; + + return false; +} + +void *Wayland_GetWindowICCProfile(SDL_VideoDevice *_this, SDL_Window *window, size_t *size) +{ + SDL_WindowData *wind = window->internal; + void *ret = NULL; + + if (wind->icc_size > 0) { + void *icc_map = mmap(NULL, wind->icc_size, PROT_READ, MAP_PRIVATE, wind->icc_fd, 0); + if (icc_map != MAP_FAILED) { + ret = SDL_malloc(wind->icc_size); + if (ret) { + *size = wind->icc_size; + SDL_memcpy(ret, icc_map, *size); + } + munmap(icc_map, wind->icc_size); + } + } + + return ret; } bool Wayland_SyncWindow(SDL_VideoDevice *_this, SDL_Window *window) @@ -2995,6 +3082,11 @@ void Wayland_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window) frog_color_managed_surface_destroy(wind->frog_color_managed_surface); } + if (wind->wp_color_management_surface_feedback) { + Wayland_FreeColorInfoState(wind->color_info_state); + wp_color_management_surface_feedback_v1_destroy(wind->wp_color_management_surface_feedback); + } + SDL_free(wind->outputs); SDL_free(wind->app_id); @@ -3018,7 +3110,11 @@ void Wayland_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window) xdg_toplevel_icon_v1_destroy(wind->xdg_toplevel_icon_v1); } - Wayland_ReleaseSHMBuffer(&wind->icon); + for (int i = 0; i < wind->icon_buffer_count; ++i) { + Wayland_ReleaseSHMBuffer(&wind->icon_buffers[i]); + } + SDL_free(wind->icon_buffers); + wind->icon_buffer_count = 0; SDL_free(wind); WAYLAND_wl_display_flush(data->display); diff --git a/libs/SDL3/src/video/wayland/SDL_waylandwindow.h b/libs/SDL3/src/video/wayland/SDL_waylandwindow.h index 906c5e44..619fd79e 100644 --- a/libs/SDL3/src/video/wayland/SDL_waylandwindow.h +++ b/libs/SDL3/src/video/wayland/SDL_waylandwindow.h @@ -116,6 +116,9 @@ struct SDL_WindowData struct wp_alpha_modifier_surface_v1 *wp_alpha_modifier_surface_v1; struct xdg_toplevel_icon_v1 *xdg_toplevel_icon_v1; struct frog_color_managed_surface *frog_color_managed_surface; + struct wp_color_management_surface_feedback_v1 *wp_color_management_surface_feedback; + + struct Wayland_ColorInfoState *color_info_state; SDL_AtomicInt swap_interval_ready; @@ -127,7 +130,8 @@ struct SDL_WindowData char *app_id; double scale_factor; - struct Wayland_SHMBuffer icon; + struct Wayland_SHMBuffer *icon_buffers; + int icon_buffer_count; struct { @@ -184,6 +188,8 @@ struct SDL_WindowData int fullscreen_deadline_count; int maximized_restored_deadline_count; Uint64 last_focus_event_time_ns; + int icc_fd; + Uint32 icc_size; bool floating; bool suspended; bool resizing; @@ -231,6 +237,7 @@ extern void Wayland_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window); extern bool Wayland_SuspendScreenSaver(SDL_VideoDevice *_this); extern bool Wayland_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *icon); extern float Wayland_GetWindowContentScale(SDL_VideoDevice *_this, SDL_Window *window); +extern void *Wayland_GetWindowICCProfile(SDL_VideoDevice *_this, SDL_Window *window, size_t *size); extern bool Wayland_SetWindowHitTest(SDL_Window *window, bool enabled); extern bool Wayland_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation); diff --git a/libs/SDL3/src/video/windows/SDL_windowsclipboard.c b/libs/SDL3/src/video/windows/SDL_windowsclipboard.c index 46e579a9..39f86ef3 100644 --- a/libs/SDL3/src/video/windows/SDL_windowsclipboard.c +++ b/libs/SDL3/src/video/windows/SDL_windowsclipboard.c @@ -145,7 +145,7 @@ static void *WIN_ConvertDIBtoBMP(HANDLE hMem, size_t *size) pbfh->bfSize = (DWORD)bmp_size; pbfh->bfReserved1 = 0; pbfh->bfReserved2 = 0; - pbfh->bfOffBits = (DWORD)(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + color_table_size); + pbfh->bfOffBits = (DWORD)(sizeof(BITMAPFILEHEADER) + pbih->biSize + color_table_size); SDL_memcpy((Uint8 *)bmp + sizeof(BITMAPFILEHEADER), dib, dib_size); *size = bmp_size; } diff --git a/libs/SDL3/src/video/windows/SDL_windowsevents.c b/libs/SDL3/src/video/windows/SDL_windowsevents.c index b65d81ac..f271db85 100644 --- a/libs/SDL3/src/video/windows/SDL_windowsevents.c +++ b/libs/SDL3/src/video/windows/SDL_windowsevents.c @@ -157,17 +157,17 @@ static Uint64 WIN_GetEventTimestamp(void) timestamp += timestamp_offset; if (!timestamp_offset) { // Initializing timestamp offset - //SDL_Log("Initializing timestamp offset\n"); + //SDL_Log("Initializing timestamp offset"); timestamp_offset = (now - timestamp); timestamp = now; } else if ((Sint64)(now - timestamp - TIMESTAMP_WRAP_OFFSET) >= 0) { // The windows message tick wrapped - //SDL_Log("Adjusting timestamp offset for wrapping tick\n"); + //SDL_Log("Adjusting timestamp offset for wrapping tick"); timestamp_offset += TIMESTAMP_WRAP_OFFSET; timestamp += TIMESTAMP_WRAP_OFFSET; } else if (timestamp > now) { // We got a newer timestamp, but it can't be newer than now, so adjust our offset - //SDL_Log("Adjusting timestamp offset, %.2f ms newer\n", (double)(timestamp - now) / SDL_NS_PER_MS); + //SDL_Log("Adjusting timestamp offset, %.2f ms newer", (double)(timestamp - now) / SDL_NS_PER_MS); timestamp_offset -= (timestamp - now); timestamp = now; } @@ -317,6 +317,41 @@ static void WIN_CheckAsyncMouseRelease(Uint64 timestamp, SDL_WindowData *data) data->mouse_button_flags = (WPARAM)-1; } +static void WIN_UpdateMouseCapture(void) +{ + SDL_Window *focusWindow = SDL_GetKeyboardFocus(); + + if (focusWindow && (focusWindow->flags & SDL_WINDOW_MOUSE_CAPTURE)) { + SDL_WindowData *data = focusWindow->internal; + + if (!data->mouse_tracked) { + POINT cursorPos; + + if (GetCursorPos(&cursorPos) && ScreenToClient(data->hwnd, &cursorPos)) { + bool swapButtons = GetSystemMetrics(SM_SWAPBUTTON) != 0; + SDL_MouseID mouseID = SDL_GLOBAL_MOUSE_ID; + + SDL_SendMouseMotion(WIN_GetEventTimestamp(), data->window, mouseID, false, (float)cursorPos.x, (float)cursorPos.y); + SDL_SendMouseButton(WIN_GetEventTimestamp(), data->window, mouseID, + !swapButtons ? SDL_BUTTON_LEFT : SDL_BUTTON_RIGHT, + (GetAsyncKeyState(VK_LBUTTON) & 0x8000) != 0); + SDL_SendMouseButton(WIN_GetEventTimestamp(), data->window, mouseID, + !swapButtons ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT, + (GetAsyncKeyState(VK_RBUTTON) & 0x8000) != 0); + SDL_SendMouseButton(WIN_GetEventTimestamp(), data->window, mouseID, + SDL_BUTTON_MIDDLE, + (GetAsyncKeyState(VK_MBUTTON) & 0x8000) != 0); + SDL_SendMouseButton(WIN_GetEventTimestamp(), data->window, mouseID, + SDL_BUTTON_X1, + (GetAsyncKeyState(VK_XBUTTON1) & 0x8000) != 0); + SDL_SendMouseButton(WIN_GetEventTimestamp(), data->window, mouseID, + SDL_BUTTON_X2, + (GetAsyncKeyState(VK_XBUTTON2) & 0x8000) != 0); + } + } + } +} + static void WIN_UpdateFocus(SDL_Window *window, bool expect_focus) { SDL_WindowData *data = window->internal; @@ -861,31 +896,96 @@ static bool HasDeviceID(Uint32 deviceID, const Uint32 *list, int count) } #if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) -static void GetDeviceName(HDEVINFO devinfo, const char *instance, char *name, size_t len) +static char *GetDeviceName(HANDLE hDevice, HDEVINFO devinfo, const char *instance, const char *default_name, bool hid_loaded) { - name[0] = '\0'; + char *vendor_name = NULL; + char *product_name = NULL; + char *name = NULL; - SP_DEVINFO_DATA data; - SDL_zero(data); - data.cbSize = sizeof(data); - for (DWORD i = 0;; ++i) { - if (!SetupDiEnumDeviceInfo(devinfo, i, &data)) { - if (GetLastError() == ERROR_NO_MORE_ITEMS) { - break; - } else { - continue; + // These are 126 for USB, but can be longer for Bluetooth devices + WCHAR vend[256], prod[256]; + vend[0] = 0; + prod[0] = 0; + + + HIDD_ATTRIBUTES attr; + attr.VendorID = 0; + attr.ProductID = 0; + attr.Size = sizeof(attr); + + if (hid_loaded) { + char devName[MAX_PATH + 1]; + UINT cap = sizeof(devName) - 1; + UINT len = GetRawInputDeviceInfoA(hDevice, RIDI_DEVICENAME, devName, &cap); + if (len != (UINT)-1) { + devName[len] = '\0'; + + // important: for devices with exclusive access mode as per + // https://learn.microsoft.com/en-us/windows-hardware/drivers/hid/top-level-collections-opened-by-windows-for-system-use + // they can only be opened with a desired access of none instead of generic read. + HANDLE hFile = CreateFileA(devName, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + if (hFile != INVALID_HANDLE_VALUE) { + SDL_HidD_GetAttributes(hFile, &attr); + SDL_HidD_GetManufacturerString(hFile, vend, sizeof(vend)); + SDL_HidD_GetProductString(hFile, prod, sizeof(prod)); + CloseHandle(hFile); } } + } - char DeviceInstanceId[64]; - if (!SetupDiGetDeviceInstanceIdA(devinfo, &data, DeviceInstanceId, sizeof(DeviceInstanceId), NULL)) - continue; + if (vend[0]) { + vendor_name = WIN_StringToUTF8W(vend); + } - if (SDL_strcasecmp(instance, DeviceInstanceId) == 0) { - SetupDiGetDeviceRegistryPropertyA(devinfo, &data, SPDRP_DEVICEDESC, NULL, (PBYTE)name, (DWORD)len, NULL); - return; + if (prod[0]) { + product_name = WIN_StringToUTF8W(prod); + } else { + SP_DEVINFO_DATA data; + SDL_zero(data); + data.cbSize = sizeof(data); + for (DWORD i = 0;; ++i) { + if (!SetupDiEnumDeviceInfo(devinfo, i, &data)) { + if (GetLastError() == ERROR_NO_MORE_ITEMS) { + break; + } else { + continue; + } + } + + char DeviceInstanceId[64]; + if (!SetupDiGetDeviceInstanceIdA(devinfo, &data, DeviceInstanceId, sizeof(DeviceInstanceId), NULL)) + continue; + + if (SDL_strcasecmp(instance, DeviceInstanceId) == 0) { + DWORD size = 0; + if (SetupDiGetDeviceRegistryPropertyW(devinfo, &data, SPDRP_DEVICEDESC, NULL, (PBYTE)prod, sizeof(prod), &size)) { + // Make sure the device description is null terminated + size /= sizeof(*prod); + if (size >= SDL_arraysize(prod)) { + // Truncated description... + size = (SDL_arraysize(prod) - 1); + } + prod[size] = 0; + + if (attr.VendorID || attr.ProductID) { + SDL_asprintf(&product_name, "%S (0x%.4x/0x%.4x)", prod, attr.VendorID, attr.ProductID); + } else { + product_name = WIN_StringToUTF8W(prod); + } + } + break; + } } } + + if (!product_name && (attr.VendorID || attr.ProductID)) { + SDL_asprintf(&product_name, "%s (0x%.4x/0x%.4x)", default_name, attr.VendorID, attr.ProductID); + } + name = SDL_CreateDeviceName(attr.VendorID, attr.ProductID, vendor_name, product_name, default_name); + SDL_free(vendor_name); + SDL_free(product_name); + + return name; } void WIN_CheckKeyboardAndMouseHotplug(SDL_VideoDevice *_this, bool initial_check) @@ -931,6 +1031,7 @@ void WIN_CheckKeyboardAndMouseHotplug(SDL_VideoDevice *_this, bool initial_check old_keyboards = SDL_GetKeyboards(&old_keyboard_count); old_mice = SDL_GetMice(&old_mouse_count); + bool hid_loaded = WIN_LoadHIDDLL(); for (UINT i = 0; i < raw_device_count; i++) { RID_DEVICE_INFO rdi; char devName[MAX_PATH] = { 0 }; @@ -938,7 +1039,7 @@ void WIN_CheckKeyboardAndMouseHotplug(SDL_VideoDevice *_this, bool initial_check UINT nameSize = SDL_arraysize(devName); int vendor = 0, product = 0; DWORD dwType = raw_devices[i].dwType; - char *instance, *ptr, name[64]; + char *instance, *ptr, *name; if (dwType != RIM_TYPEKEYBOARD && dwType != RIM_TYPEMOUSE) { continue; @@ -976,8 +1077,9 @@ void WIN_CheckKeyboardAndMouseHotplug(SDL_VideoDevice *_this, bool initial_check SDL_KeyboardID keyboardID = (Uint32)(uintptr_t)raw_devices[i].hDevice; AddDeviceID(keyboardID, &new_keyboards, &new_keyboard_count); if (!HasDeviceID(keyboardID, old_keyboards, old_keyboard_count)) { - GetDeviceName(devinfo, instance, name, sizeof(name)); + name = GetDeviceName(raw_devices[i].hDevice, devinfo, instance, "Keyboard", hid_loaded); SDL_AddKeyboard(keyboardID, name, send_event); + SDL_free(name); } } break; @@ -986,8 +1088,9 @@ void WIN_CheckKeyboardAndMouseHotplug(SDL_VideoDevice *_this, bool initial_check SDL_MouseID mouseID = (Uint32)(uintptr_t)raw_devices[i].hDevice; AddDeviceID(mouseID, &new_mice, &new_mouse_count); if (!HasDeviceID(mouseID, old_mice, old_mouse_count)) { - GetDeviceName(devinfo, instance, name, sizeof(name)); + name = GetDeviceName(raw_devices[i].hDevice, devinfo, instance, "Mouse", hid_loaded); SDL_AddMouse(mouseID, name, send_event); + SDL_free(name); } } break; @@ -995,6 +1098,9 @@ void WIN_CheckKeyboardAndMouseHotplug(SDL_VideoDevice *_this, bool initial_check break; } } + if (hid_loaded) { + WIN_UnloadHIDDLL(); + } for (int i = old_keyboard_count; i--;) { if (!HasDeviceID(old_keyboards[i], new_keyboards, new_keyboard_count)) { @@ -1318,6 +1424,8 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara if (TrackMouseEvent(&trackMouseEvent)) { data->mouse_tracked = true; } + + WIN_CheckAsyncMouseRelease(WIN_GetEventTimestamp(), data); } if (!data->videodata->raw_mouse_enabled) { @@ -1525,6 +1633,15 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara case WM_NCLBUTTONDOWN: { data->in_title_click = true; + + // Fix for 500ms hang after user clicks on the title bar, but before moving mouse + // Reference: https://gamedev.net/forums/topic/672094-keeping-things-moving-during-win32-moveresize-events/5254386/ + if (SendMessage(hwnd, WM_NCHITTEST, wParam, lParam) == HTCAPTION) { + POINT cursorPos; + GetCursorPos(&cursorPos); + ScreenToClient(hwnd, &cursorPos); + PostMessage(hwnd, WM_MOUSEMOVE, 0, cursorPos.x | cursorPos.y << 16); + } } break; case WM_CAPTURECHANGED: @@ -1721,6 +1838,12 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara case WM_ENTERSIZEMOVE: case WM_ENTERMENULOOP: { + if (g_WindowsMessageHook) { + if (!DispatchModalLoopMessageHook(&hwnd, &msg, &wParam, &lParam)) { + return 0; + } + } + ++data->in_modal_loop; if (data->in_modal_loop == 1) { data->initial_size_rect.left = data->window->x; @@ -2239,7 +2362,7 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara int w, h; #ifdef HIGHDPI_DEBUG - SDL_Log("WM_DPICHANGED: to %d\tsuggested rect: (%d, %d), (%dx%d)\n", newDPI, + SDL_Log("WM_DPICHANGED: to %d\tsuggested rect: (%d, %d), (%dx%d)", newDPI, suggestedRect->left, suggestedRect->top, suggestedRect->right - suggestedRect->left, suggestedRect->bottom - suggestedRect->top); #endif @@ -2270,7 +2393,7 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara } #ifdef HIGHDPI_DEBUG - SDL_Log("WM_DPICHANGED: current SDL window size: (%dx%d)\tcalling SetWindowPos: (%d, %d), (%dx%d)\n", + SDL_Log("WM_DPICHANGED: current SDL window size: (%dx%d)\tcalling SetWindowPos: (%d, %d), (%dx%d)", data->window->w, data->window->h, suggestedRect->left, suggestedRect->top, w, h); #endif @@ -2311,43 +2434,6 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara } } -#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) -static void WIN_UpdateMouseCapture(void) -{ - SDL_Window *focusWindow = SDL_GetKeyboardFocus(); - - if (focusWindow && (focusWindow->flags & SDL_WINDOW_MOUSE_CAPTURE)) { - SDL_WindowData *data = focusWindow->internal; - - if (!data->mouse_tracked) { - POINT cursorPos; - - if (GetCursorPos(&cursorPos) && ScreenToClient(data->hwnd, &cursorPos)) { - bool swapButtons = GetSystemMetrics(SM_SWAPBUTTON) != 0; - SDL_MouseID mouseID = SDL_GLOBAL_MOUSE_ID; - - SDL_SendMouseMotion(WIN_GetEventTimestamp(), data->window, mouseID, false, (float)cursorPos.x, (float)cursorPos.y); - SDL_SendMouseButton(WIN_GetEventTimestamp(), data->window, mouseID, - !swapButtons ? SDL_BUTTON_LEFT : SDL_BUTTON_RIGHT, - (GetAsyncKeyState(VK_LBUTTON) & 0x8000) != 0); - SDL_SendMouseButton(WIN_GetEventTimestamp(), data->window, mouseID, - !swapButtons ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT, - (GetAsyncKeyState(VK_RBUTTON) & 0x8000) != 0); - SDL_SendMouseButton(WIN_GetEventTimestamp(), data->window, mouseID, - SDL_BUTTON_MIDDLE, - (GetAsyncKeyState(VK_MBUTTON) & 0x8000) != 0); - SDL_SendMouseButton(WIN_GetEventTimestamp(), data->window, mouseID, - SDL_BUTTON_X1, - (GetAsyncKeyState(VK_XBUTTON1) & 0x8000) != 0); - SDL_SendMouseButton(WIN_GetEventTimestamp(), data->window, mouseID, - SDL_BUTTON_X2, - (GetAsyncKeyState(VK_XBUTTON2) & 0x8000) != 0); - } - } - } -} -#endif // !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) - int WIN_WaitEventTimeout(SDL_VideoDevice *_this, Sint64 timeoutNS) { if (g_WindowsEnableMessageLoop) { diff --git a/libs/SDL3/src/video/windows/SDL_windowsgameinput.c b/libs/SDL3/src/video/windows/SDL_windowsgameinput.c index 6db142f1..183733a3 100644 --- a/libs/SDL3/src/video/windows/SDL_windowsgameinput.c +++ b/libs/SDL3/src/video/windows/SDL_windowsgameinput.c @@ -27,9 +27,7 @@ #ifdef HAVE_GAMEINPUT_H -#define COBJMACROS -#include - +#include "../../core/windows/SDL_gameinput.h" #include "../../events/SDL_mouse_c.h" #include "../../events/SDL_keyboard_c.h" #include "../../events/scancodes_windows.h" @@ -61,7 +59,6 @@ typedef struct GAMEINPUT_Device struct WIN_GameInputData { - void *hGameInputDLL; IGameInput *pGameInput; GameInputCallbackToken gameinput_callback_token; int num_devices; @@ -237,20 +234,7 @@ bool WIN_InitGameInput(SDL_VideoDevice *_this) goto done; } - data->hGameInputDLL = SDL_LoadObject("gameinput.dll"); - if (!data->hGameInputDLL) { - goto done; - } - - typedef HRESULT (WINAPI *GameInputCreate_t)(IGameInput * *gameInput); - GameInputCreate_t GameInputCreateFunc = (GameInputCreate_t)SDL_LoadFunction(data->hGameInputDLL, "GameInputCreate"); - if (!GameInputCreateFunc) { - goto done; - } - - hr = GameInputCreateFunc(&data->pGameInput); - if (FAILED(hr)) { - SDL_SetError("GameInputCreate failure with HRESULT of %08X", hr); + if (!SDL_InitGameInput(&data->pGameInput)) { goto done; } @@ -391,7 +375,7 @@ static void DumpKeys(const char *prefix, GameInputKeyState *keys, uint32_t count for (uint32_t i = 0; i < count; ++i) { char str[5]; *SDL_UCS4ToUTF8(keys[i].codePoint, str) = '\0'; - SDL_Log(" Key 0x%.2x (%s)\n", keys[i].scanCode, str); + SDL_Log(" Key 0x%.2x (%s)", keys[i].scanCode, str); } } #endif // DEBUG_KEYS @@ -413,7 +397,7 @@ static void GAMEINPUT_HandleKeyboardDelta(WIN_GameInputData *data, SDL_Window *w uint32_t num_last = IGameInputReading_GetKeyState(last_reading, max_keys, last); uint32_t num_keys = IGameInputReading_GetKeyState(reading, max_keys, keys); #ifdef DEBUG_KEYS - SDL_Log("Timestamp: %llu\n", timestamp); + SDL_Log("Timestamp: %llu", timestamp); DumpKeys("Last keys:", last, num_last); DumpKeys("New keys:", keys, num_keys); #endif @@ -485,12 +469,13 @@ void WIN_UpdateGameInput(SDL_VideoDevice *_this) device->last_mouse_reading = reading; } if (hr != GAMEINPUT_E_READING_NOT_FOUND) { - // The last reading is too old, resynchronize - IGameInputReading_Release(device->last_mouse_reading); - device->last_mouse_reading = NULL; + if (SUCCEEDED(IGameInput_GetCurrentReading(data->pGameInput, GameInputKindMouse, device->pDevice, &reading))) { + GAMEINPUT_HandleMouseDelta(data, window, device, device->last_mouse_reading, reading); + IGameInputReading_Release(device->last_mouse_reading); + device->last_mouse_reading = reading; + } } - } - if (!device->last_mouse_reading) { + } else { if (SUCCEEDED(IGameInput_GetCurrentReading(data->pGameInput, GameInputKindMouse, device->pDevice, &reading))) { GAMEINPUT_InitialMouseReading(data, window, device, reading); device->last_mouse_reading = reading; @@ -514,12 +499,13 @@ void WIN_UpdateGameInput(SDL_VideoDevice *_this) device->last_keyboard_reading = reading; } if (hr != GAMEINPUT_E_READING_NOT_FOUND) { - // The last reading is too old, resynchronize - IGameInputReading_Release(device->last_keyboard_reading); - device->last_keyboard_reading = NULL; + if (SUCCEEDED(IGameInput_GetCurrentReading(data->pGameInput, GameInputKindKeyboard, device->pDevice, &reading))) { + GAMEINPUT_HandleKeyboardDelta(data, window, device, device->last_keyboard_reading, reading); + IGameInputReading_Release(device->last_keyboard_reading); + device->last_keyboard_reading = reading; + } } - } - if (!device->last_keyboard_reading) { + } else { if (SUCCEEDED(IGameInput_GetCurrentReading(data->pGameInput, GameInputKindKeyboard, device->pDevice, &reading))) { GAMEINPUT_InitialKeyboardReading(data, window, device, reading); device->last_keyboard_reading = reading; @@ -587,9 +573,9 @@ void WIN_QuitGameInput(SDL_VideoDevice *_this) data->pGameInput = NULL; } - if (data->hGameInputDLL) { - SDL_UnloadObject(data->hGameInputDLL); - data->hGameInputDLL = NULL; + if (data->pGameInput) { + SDL_QuitGameInput(); + data->pGameInput = NULL; } if (data->lock) { diff --git a/libs/SDL3/src/video/windows/SDL_windowskeyboard.c b/libs/SDL3/src/video/windows/SDL_windowskeyboard.c index 5f934e02..75e8ad4a 100644 --- a/libs/SDL3/src/video/windows/SDL_windowskeyboard.c +++ b/libs/SDL3/src/video/windows/SDL_windowskeyboard.c @@ -741,7 +741,7 @@ static void IME_GetCompositionString(SDL_VideoData *videodata, HIMC himc, DWORD videodata->ime_cursor = LOWORD(ImmGetCompositionStringW(himc, GCS_CURSORPOS, 0, 0)); videodata->ime_selected_start = 0; videodata->ime_selected_length = 0; - SDL_DebugIMELog("Cursor = %d\n", videodata->ime_cursor); + SDL_DebugIMELog("Cursor = %d", videodata->ime_cursor); length = ImmGetCompositionStringW(himc, string, NULL, 0); if (length > 0 && videodata->ime_composition_length < length) { @@ -786,7 +786,7 @@ static void IME_GetCompositionString(SDL_VideoData *videodata, HIMC himc, DWORD } for (LONG i = 0; i < length; ++i) { - SDL_DebugIMELog("attrib[%d] = %d\n", i, attributes[i]); + SDL_DebugIMELog("attrib[%d] = %d", i, attributes[i]); } for (start = 0; start < length; ++start) { @@ -987,7 +987,7 @@ bool WIN_HandleIMEMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SD HIMC himc = 0; if (msg == WM_IME_SETCONTEXT) { - SDL_DebugIMELog("WM_IME_SETCONTEXT\n"); + SDL_DebugIMELog("WM_IME_SETCONTEXT"); LPARAM element_mask; if (videodata->ime_internal_composition && videodata->ime_internal_candidates) { @@ -1013,35 +1013,35 @@ bool WIN_HandleIMEMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SD switch (msg) { case WM_KEYDOWN: if (wParam == VK_PROCESSKEY) { - SDL_DebugIMELog("WM_KEYDOWN VK_PROCESSKEY\n"); + SDL_DebugIMELog("WM_KEYDOWN VK_PROCESSKEY"); trap = true; } else { - SDL_DebugIMELog("WM_KEYDOWN normal\n"); + SDL_DebugIMELog("WM_KEYDOWN normal"); } break; case WM_INPUTLANGCHANGE: - SDL_DebugIMELog("WM_INPUTLANGCHANGE\n"); + SDL_DebugIMELog("WM_INPUTLANGCHANGE"); IME_InputLangChanged(videodata); break; case WM_IME_STARTCOMPOSITION: - SDL_DebugIMELog("WM_IME_STARTCOMPOSITION\n"); + SDL_DebugIMELog("WM_IME_STARTCOMPOSITION"); if (videodata->ime_internal_composition) { trap = true; } break; case WM_IME_COMPOSITION: - SDL_DebugIMELog("WM_IME_COMPOSITION %x\n", lParam); + SDL_DebugIMELog("WM_IME_COMPOSITION %x", lParam); if (videodata->ime_internal_composition) { trap = true; himc = ImmGetContext(hwnd); if (*lParam & GCS_RESULTSTR) { - SDL_DebugIMELog("GCS_RESULTSTR\n"); + SDL_DebugIMELog("GCS_RESULTSTR"); IME_GetCompositionString(videodata, himc, GCS_RESULTSTR); IME_SendClearComposition(videodata); IME_SendInputEvent(videodata); } if (*lParam & GCS_COMPSTR) { - SDL_DebugIMELog("GCS_COMPSTR\n"); + SDL_DebugIMELog("GCS_COMPSTR"); videodata->ime_readingstring[0] = 0; IME_GetCompositionString(videodata, himc, GCS_COMPSTR); IME_SendEditingEvent(videodata); @@ -1050,7 +1050,7 @@ bool WIN_HandleIMEMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SD } break; case WM_IME_ENDCOMPOSITION: - SDL_DebugIMELog("WM_IME_ENDCOMPOSITION\n"); + SDL_DebugIMELog("WM_IME_ENDCOMPOSITION"); if (videodata->ime_internal_composition) { trap = true; videodata->ime_composition[0] = 0; @@ -1062,32 +1062,32 @@ bool WIN_HandleIMEMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SD } break; case WM_IME_NOTIFY: - SDL_DebugIMELog("WM_IME_NOTIFY %x\n", wParam); + SDL_DebugIMELog("WM_IME_NOTIFY %x", wParam); switch (wParam) { case IMN_SETCOMPOSITIONWINDOW: - SDL_DebugIMELog("IMN_SETCOMPOSITIONWINDOW\n"); + SDL_DebugIMELog("IMN_SETCOMPOSITIONWINDOW"); break; case IMN_SETCOMPOSITIONFONT: - SDL_DebugIMELog("IMN_SETCOMPOSITIONFONT\n"); + SDL_DebugIMELog("IMN_SETCOMPOSITIONFONT"); break; case IMN_SETCANDIDATEPOS: - SDL_DebugIMELog("IMN_SETCANDIDATEPOS\n"); + SDL_DebugIMELog("IMN_SETCANDIDATEPOS"); break; case IMN_SETCONVERSIONMODE: case IMN_SETOPENSTATUS: - SDL_DebugIMELog("%s\n", wParam == IMN_SETCONVERSIONMODE ? "IMN_SETCONVERSIONMODE" : "IMN_SETOPENSTATUS"); + SDL_DebugIMELog("%s", wParam == IMN_SETCONVERSIONMODE ? "IMN_SETCONVERSIONMODE" : "IMN_SETOPENSTATUS"); IME_UpdateInputLocale(videodata); break; case IMN_OPENCANDIDATE: case IMN_CHANGECANDIDATE: - SDL_DebugIMELog("%s\n", wParam == IMN_OPENCANDIDATE ? "IMN_OPENCANDIDATE" : "IMN_CHANGECANDIDATE"); + SDL_DebugIMELog("%s", wParam == IMN_OPENCANDIDATE ? "IMN_OPENCANDIDATE" : "IMN_CHANGECANDIDATE"); if (videodata->ime_internal_candidates) { trap = true; videodata->ime_update_candidates = true; } break; case IMN_CLOSECANDIDATE: - SDL_DebugIMELog("IMN_CLOSECANDIDATE\n"); + SDL_DebugIMELog("IMN_CLOSECANDIDATE"); if (videodata->ime_internal_candidates) { trap = true; videodata->ime_update_candidates = false; @@ -1097,7 +1097,7 @@ bool WIN_HandleIMEMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SD case IMN_PRIVATE: { DWORD dwId = IME_GetId(videodata, 0); - SDL_DebugIMELog("IMN_PRIVATE %u\n", dwId); + SDL_DebugIMELog("IMN_PRIVATE %u", dwId); IME_GetReadingString(videodata, hwnd); switch (dwId) { case IMEID_CHT_VER42: diff --git a/libs/SDL3/src/video/windows/SDL_windowsmodes.c b/libs/SDL3/src/video/windows/SDL_windowsmodes.c index bfb0baff..77ebab29 100644 --- a/libs/SDL3/src/video/windows/SDL_windowsmodes.c +++ b/libs/SDL3/src/video/windows/SDL_windowsmodes.c @@ -561,7 +561,7 @@ static void WIN_AddDisplay(SDL_VideoDevice *_this, HMONITOR hMonitor, const MONI float content_scale = WIN_GetContentScale(_this, hMonitor); #ifdef DEBUG_MODES - SDL_Log("Display: %s\n", WIN_StringToUTF8W(info->szDevice)); + SDL_Log("Display: %s", WIN_StringToUTF8W(info->szDevice)); #endif dxgi_output = WIN_GetDXGIOutput(_this, info->szDevice); diff --git a/libs/SDL3/src/video/windows/SDL_windowsmouse.c b/libs/SDL3/src/video/windows/SDL_windowsmouse.c index 3a1c7cac..3d6bcc42 100644 --- a/libs/SDL3/src/video/windows/SDL_windowsmouse.c +++ b/libs/SDL3/src/video/windows/SDL_windowsmouse.c @@ -72,18 +72,22 @@ static SDL_Cursor *WIN_CreateCursorAndData(HCURSOR hcursor) } SDL_Cursor *cursor = (SDL_Cursor *)SDL_calloc(1, sizeof(*cursor)); - if (cursor) { - SDL_CursorData *data = (SDL_CursorData *)SDL_calloc(1, sizeof(*data)); - if (!data) { - SDL_free(cursor); - return NULL; - } - data->cursor = hcursor; - cursor->internal = data; + if (!cursor) { + return NULL; } + + SDL_CursorData *data = (SDL_CursorData *)SDL_calloc(1, sizeof(*data)); + if (!data) { + SDL_free(cursor); + return NULL; + } + + data->cursor = hcursor; + cursor->internal = data; return cursor; } + static bool IsMonochromeSurface(SDL_Surface *surface) { int x, y; @@ -129,6 +133,9 @@ static HBITMAP CreateColorBitmap(SDL_Surface *surface) bitmap = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, &pixels, NULL, 0); if (!bitmap || !pixels) { WIN_SetError("CreateDIBSection()"); + if (bitmap) { + DeleteObject(bitmap); + } return NULL; } @@ -158,6 +165,7 @@ static HBITMAP CreateMaskBitmap(SDL_Surface *surface, bool is_monochrome) pixels = SDL_small_alloc(Uint8, size * (is_monochrome ? 2 : 1), &isstack); if (!pixels) { + SDL_OutOfMemory(); return NULL; } @@ -210,20 +218,30 @@ static HCURSOR WIN_CreateHCursor(SDL_Surface *surface, int hot_x, int hot_y) if (!ii.hbmMask || (!is_monochrome && !ii.hbmColor)) { SDL_SetError("Couldn't create cursor bitmaps"); + if (ii.hbmMask) { + DeleteObject(ii.hbmMask); + } + if (ii.hbmColor) { + DeleteObject(ii.hbmColor); + } return NULL; } hcursor = CreateIconIndirect(&ii); + if (!hcursor) { + WIN_SetError("CreateIconIndirect()"); + DeleteObject(ii.hbmMask); + if (ii.hbmColor) { + DeleteObject(ii.hbmColor); + } + return NULL; + } DeleteObject(ii.hbmMask); if (ii.hbmColor) { DeleteObject(ii.hbmColor); } - if (!hcursor) { - WIN_SetError("CreateIconIndirect()"); - return NULL; - } return hcursor; } @@ -286,7 +304,7 @@ static SDL_Cursor *WIN_CreateSystemCursor(SDL_SystemCursor id) name = IDC_CROSS; break; case SDL_SYSTEM_CURSOR_PROGRESS: - name = IDC_WAIT; + name = IDC_APPSTARTING; break; case SDL_SYSTEM_CURSOR_NWSE_RESIZE: name = IDC_SIZENWSE; @@ -353,7 +371,9 @@ static void WIN_FreeCursor(SDL_Cursor *cursor) while (data->cache) { CachedCursor *entry = data->cache; data->cache = entry->next; - DestroyCursor(entry->cursor); + if (entry->cursor) { + DestroyCursor(entry->cursor); + } SDL_free(entry); } if (data->cursor) { @@ -710,7 +730,7 @@ void WIN_UpdateMouseSystemScale(void) int v = 10; if (SystemParametersInfo(SPI_GETMOUSESPEED, 0, &v, 0)) { v = SDL_max(1, SDL_min(v, 20)); - data->dpiscale = SDL_max(SDL_max(v, (v - 2) << 2), (v - 6) << 3); + data->dpiscale = SDL_max(SDL_max(v, (v - 2) * 4), (v - 6) * 8); } int params[3]; diff --git a/libs/SDL3/src/video/windows/SDL_windowsshape.c b/libs/SDL3/src/video/windows/SDL_windowsshape.c index ae6b9510..db4e4a0e 100644 --- a/libs/SDL3/src/video/windows/SDL_windowsshape.c +++ b/libs/SDL3/src/video/windows/SDL_windowsshape.c @@ -82,7 +82,7 @@ bool WIN_UpdateWindowShape(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surfa if (!stretched) { return false; } - if (!SDL_SoftStretch(shape, NULL, stretched, NULL, SDL_SCALEMODE_LINEAR)) { + if (!SDL_StretchSurface(shape, NULL, stretched, NULL, SDL_SCALEMODE_LINEAR)) { SDL_DestroySurface(stretched); return false; } @@ -116,6 +116,7 @@ bool WIN_UpdateWindowShape(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surfa } } if (!SetWindowRgn(data->hwnd, mask, TRUE)) { + DeleteObject(mask); return WIN_SetError("SetWindowRgn failed"); } return true; diff --git a/libs/SDL3/src/video/windows/SDL_windowsvideo.c b/libs/SDL3/src/video/windows/SDL_windowsvideo.c index 819cdee4..04415b54 100644 --- a/libs/SDL3/src/video/windows/SDL_windowsvideo.c +++ b/libs/SDL3/src/video/windows/SDL_windowsvideo.c @@ -76,10 +76,15 @@ static void SDLCALL UpdateWindowFrameUsableWhileCursorHidden(void *userdata, con #if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) static bool WIN_SuspendScreenSaver(SDL_VideoDevice *_this) { + DWORD result; if (_this->suspend_screensaver) { - SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED); + result = SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED); } else { - SetThreadExecutionState(ES_CONTINUOUS); + result = SetThreadExecutionState(ES_CONTINUOUS); + } + if (result == 0) { + SDL_SetError("SetThreadExecutionState() failed"); + return false; } return true; } @@ -330,10 +335,11 @@ static SDL_VideoDevice *WIN_CreateDevice(void) VideoBootStrap WINDOWS_bootstrap = { "windows", "SDL Windows video driver", WIN_CreateDevice, #if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) - WIN_ShowMessageBox + WIN_ShowMessageBox, #else - NULL + NULL, #endif + false }; static BOOL WIN_DeclareDPIAwareUnaware(SDL_VideoDevice *_this) @@ -482,11 +488,11 @@ static bool WIN_VideoInit(SDL_VideoDevice *_this) if (SUCCEEDED(hr)) { data->oleinitialized = true; } else { - SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "OleInitialize() failed: 0x%.8x, using fallback drag-n-drop functionality\n", (unsigned int)hr); + SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "OleInitialize() failed: 0x%.8x, using fallback drag-n-drop functionality", (unsigned int)hr); } #endif // !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) } else { - SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "CoInitialize() failed: 0x%.8x, using fallback drag-n-drop functionality\n", (unsigned int)hr); + SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "CoInitialize() failed: 0x%.8x, using fallback drag-n-drop functionality", (unsigned int)hr); } WIN_InitDPIAwareness(_this); diff --git a/libs/SDL3/src/video/windows/SDL_windowswindow.c b/libs/SDL3/src/video/windows/SDL_windowswindow.c index 1711fc0a..36c8de7f 100644 --- a/libs/SDL3/src/video/windows/SDL_windowswindow.c +++ b/libs/SDL3/src/video/windows/SDL_windowswindow.c @@ -842,6 +842,7 @@ bool WIN_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Properties return WIN_SetError("SetPixelFormat()"); } } else { +#endif // !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) if (!(window->flags & SDL_WINDOW_OPENGL)) { return true; } @@ -874,6 +875,7 @@ bool WIN_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Properties #else return SDL_SetError("Could not create GL window (WGL support not configured)"); #endif +#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) } #endif // !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) @@ -1389,6 +1391,35 @@ SDL_FullscreenResult WIN_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Window &w, &h, SDL_WINDOWRECT_FLOATING); data->windowed_mode_was_maximized = false; + + /* A window may have been maximized by dragging it to the top of another display, in which case the floating + * position may be out-of-date. If the window is being restored to maximized, and the maximized and floating + * position are on different displays, try to center the window on the maximized display for restoration, which + * mimics native Windows behavior. + */ + if (enterMaximized) { + const SDL_Point windowed_point = { window->windowed.x, window->windowed.y }; + const SDL_Point floating_point = { window->floating.x, window->floating.y }; + const SDL_DisplayID floating_display = SDL_GetDisplayForPoint(&floating_point); + const SDL_DisplayID windowed_display = SDL_GetDisplayForPoint(&windowed_point); + + if (floating_display != windowed_display) { + SDL_Rect bounds; + + SDL_zero(bounds); + SDL_GetDisplayUsableBounds(windowed_display, &bounds); + if (w < bounds.w) { + x = bounds.x + (bounds.w - w) / 2; + } else { + x = bounds.x; + } + if (h < bounds.h) { + y = bounds.y + (bounds.h - h) / 2; + } else { + y = bounds.y; + } + } + } } /* Always reset the window to the base floating size before possibly re-applying the maximized state, @@ -1862,16 +1893,16 @@ static STDMETHODIMP SDLDropTarget_DragEnter(SDLDropTarget *target, POINTL pt, DWORD *pdwEffect) { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In DragEnter at %ld, %ld\n", pt.x, pt.y); + ". In DragEnter at %ld, %ld", pt.x, pt.y); *pdwEffect = DROPEFFECT_COPY; POINT pnt = { pt.x, pt.y }; if (ScreenToClient(target->hwnd, &pnt)) { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In DragEnter at %ld, %ld => window %u at %ld, %ld\n", pt.x, pt.y, target->window->id, pnt.x, pnt.y); + ". In DragEnter at %ld, %ld => window %u at %ld, %ld", pt.x, pt.y, target->window->id, pnt.x, pnt.y); SDL_SendDropPosition(target->window, pnt.x, pnt.y); } else { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In DragEnter at %ld, %ld => nil, nil\n", pt.x, pt.y); + ". In DragEnter at %ld, %ld => nil, nil", pt.x, pt.y); } return S_OK; } @@ -1881,16 +1912,16 @@ static STDMETHODIMP SDLDropTarget_DragOver(SDLDropTarget *target, POINTL pt, DWORD *pdwEffect) { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In DragOver at %ld, %ld\n", pt.x, pt.y); + ". In DragOver at %ld, %ld", pt.x, pt.y); *pdwEffect = DROPEFFECT_COPY; POINT pnt = { pt.x, pt.y }; if (ScreenToClient(target->hwnd, &pnt)) { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In DragOver at %ld, %ld => window %u at %ld, %ld\n", pt.x, pt.y, target->window->id, pnt.x, pnt.y); + ". In DragOver at %ld, %ld => window %u at %ld, %ld", pt.x, pt.y, target->window->id, pnt.x, pnt.y); SDL_SendDropPosition(target->window, pnt.x, pnt.y); } else { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In DragOver at %ld, %ld => nil, nil\n", pt.x, pt.y); + ". In DragOver at %ld, %ld => nil, nil", pt.x, pt.y); } return S_OK; } @@ -1898,7 +1929,7 @@ static STDMETHODIMP SDLDropTarget_DragOver(SDLDropTarget *target, static STDMETHODIMP SDLDropTarget_DragLeave(SDLDropTarget *target) { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In DragLeave\n"); + ". In DragLeave"); SDL_SendDropComplete(target->window); return S_OK; } @@ -1911,11 +1942,11 @@ static STDMETHODIMP SDLDropTarget_Drop(SDLDropTarget *target, POINT pnt = { pt.x, pt.y }; if (ScreenToClient(target->hwnd, &pnt)) { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Drop at %ld, %ld => window %u at %ld, %ld\n", pt.x, pt.y, target->window->id, pnt.x, pnt.y); + ". In Drop at %ld, %ld => window %u at %ld, %ld", pt.x, pt.y, target->window->id, pnt.x, pnt.y); SDL_SendDropPosition(target->window, pnt.x, pnt.y); } else { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Drop at %ld, %ld => nil, nil\n", pt.x, pt.y); + ". In Drop at %ld, %ld => nil, nil", pt.x, pt.y); } { @@ -1923,7 +1954,7 @@ static STDMETHODIMP SDLDropTarget_Drop(SDLDropTarget *target, HRESULT hres; hres = pDataObject->lpVtbl->EnumFormatEtc(pDataObject, DATADIR_GET, &pEnumFormatEtc); SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Drop for EnumFormatEtc, HRESULT is %08lx\n", hres); + ". In Drop for EnumFormatEtc, HRESULT is %08lx", hres); if (hres == S_OK) { FORMATETC fetc; while (pEnumFormatEtc->lpVtbl->Next(pEnumFormatEtc, 1, &fetc, NULL) == S_OK) { @@ -1931,10 +1962,10 @@ static STDMETHODIMP SDLDropTarget_Drop(SDLDropTarget *target, const char *cfnm = SDLGetClipboardFormatName(fetc.cfFormat, name, 256); if (cfnm) { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Drop, Supported format is %08x, '%s'\n", fetc.cfFormat, cfnm); + ". In Drop, Supported format is %08x, '%s'", fetc.cfFormat, cfnm); } else { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Drop, Supported format is %08x, Predefined\n", fetc.cfFormat); + ". In Drop, Supported format is %08x, Predefined", fetc.cfFormat); } } } @@ -1950,18 +1981,18 @@ static STDMETHODIMP SDLDropTarget_Drop(SDLDropTarget *target, const char *format_mime = "text/uri-list"; if (SUCCEEDED(pDataObject->lpVtbl->QueryGetData(pDataObject, &fetc))) { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Drop File for QueryGetData, format %08x '%s', success\n", + ". In Drop File for QueryGetData, format %08x '%s', success", fetc.cfFormat, format_mime); STGMEDIUM med; HRESULT hres = pDataObject->lpVtbl->GetData(pDataObject, &fetc, &med); SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Drop File for GetData, format %08x '%s', HRESULT is %08lx\n", + ". In Drop File for GetData, format %08x '%s', HRESULT is %08lx", fetc.cfFormat, format_mime, hres); if (SUCCEEDED(hres)) { const size_t bsize = GlobalSize(med.hGlobal); const void *buffer = (void *)GlobalLock(med.hGlobal); SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Drop File for GlobalLock, format %08x '%s', memory (%lu) %p\n", + ". In Drop File for GlobalLock, format %08x '%s', memory (%lu) %p", fetc.cfFormat, format_mime, (unsigned long)bsize, buffer); if (buffer) { char *text = (char *)SDL_malloc(bsize + sizeof(Uint32)); @@ -1972,7 +2003,7 @@ static STDMETHODIMP SDLDropTarget_Drop(SDLDropTarget *target, while (token != NULL) { if (SDL_URIToLocal(token, token) >= 0) { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Drop File, file (%lu of %lu) '%s'\n", + ". In Drop File, file (%lu of %lu) '%s'", (unsigned long)SDL_strlen(token), (unsigned long)bsize, token); SDL_SendDropFile(target->window, NULL, token); } @@ -1998,18 +2029,18 @@ static STDMETHODIMP SDLDropTarget_Drop(SDLDropTarget *target, const char *format_mime = "text/plain;charset=utf-8"; if (SUCCEEDED(pDataObject->lpVtbl->QueryGetData(pDataObject, &fetc))) { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Drop Text for QueryGetData, format %08x '%s', success\n", + ". In Drop Text for QueryGetData, format %08x '%s', success", fetc.cfFormat, format_mime); STGMEDIUM med; HRESULT hres = pDataObject->lpVtbl->GetData(pDataObject, &fetc, &med); SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Drop Text for GetData, format %08x '%s', HRESULT is %08lx\n", + ". In Drop Text for GetData, format %08x '%s', HRESULT is %08lx", fetc.cfFormat, format_mime, hres); if (SUCCEEDED(hres)) { const size_t bsize = GlobalSize(med.hGlobal); const void *buffer = (void *)GlobalLock(med.hGlobal); SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Drop Text for GlobalLock, format %08x '%s', memory (%lu) %p\n", + ". In Drop Text for GlobalLock, format %08x '%s', memory (%lu) %p", fetc.cfFormat, format_mime, (unsigned long)bsize, buffer); if (buffer) { char *text = (char *)SDL_malloc(bsize + sizeof(Uint32)); @@ -2019,7 +2050,7 @@ static STDMETHODIMP SDLDropTarget_Drop(SDLDropTarget *target, char *token = SDL_strtok_r(text, "\r\n", &saveptr); while (token != NULL) { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Drop Text, text (%lu of %lu) '%s'\n", + ". In Drop Text, text (%lu of %lu) '%s'", (unsigned long)SDL_strlen(token), (unsigned long)bsize, token); SDL_SendDropText(target->window, (char *)token); token = SDL_strtok_r(NULL, "\r\n", &saveptr); @@ -2044,25 +2075,25 @@ static STDMETHODIMP SDLDropTarget_Drop(SDLDropTarget *target, const char *format_mime = "CF_UNICODETEXT"; if (SUCCEEDED(pDataObject->lpVtbl->QueryGetData(pDataObject, &fetc))) { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Drop Text for QueryGetData, format %08x '%s', success\n", + ". In Drop Text for QueryGetData, format %08x '%s', success", fetc.cfFormat, format_mime); STGMEDIUM med; HRESULT hres = pDataObject->lpVtbl->GetData(pDataObject, &fetc, &med); SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Drop Text for GetData, format %08x '%s', HRESULT is %08lx\n", + ". In Drop Text for GetData, format %08x '%s', HRESULT is %08lx", fetc.cfFormat, format_mime, hres); if (SUCCEEDED(hres)) { const size_t bsize = GlobalSize(med.hGlobal); const void *buffer = (void *)GlobalLock(med.hGlobal); SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Drop Text for GlobalLock, format %08x '%s', memory (%lu) %p\n", + ". In Drop Text for GlobalLock, format %08x '%s', memory (%lu) %p", fetc.cfFormat, format_mime, (unsigned long)bsize, buffer); if (buffer) { buffer = WIN_StringToUTF8((const wchar_t *)buffer); if (buffer) { const size_t lbuffer = SDL_strlen((const char *)buffer); SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Drop Text for StringToUTF8, format %08x '%s', memory (%lu) %p\n", + ". In Drop Text for StringToUTF8, format %08x '%s', memory (%lu) %p", fetc.cfFormat, format_mime, (unsigned long)lbuffer, buffer); char *text = (char *)SDL_malloc(lbuffer + sizeof(Uint32)); SDL_memcpy((Uint8 *)text, buffer, lbuffer); @@ -2071,7 +2102,7 @@ static STDMETHODIMP SDLDropTarget_Drop(SDLDropTarget *target, char *token = SDL_strtok_r(text, "\r\n", &saveptr); while (token != NULL) { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Drop Text, text (%lu of %lu) '%s'\n", + ". In Drop Text, text (%lu of %lu) '%s'", (unsigned long)SDL_strlen(token), (unsigned long)lbuffer, token); SDL_SendDropText(target->window, (char *)token); token = SDL_strtok_r(NULL, "\r\n", &saveptr); @@ -2098,18 +2129,18 @@ static STDMETHODIMP SDLDropTarget_Drop(SDLDropTarget *target, const char *format_mime = "CF_TEXT"; if (SUCCEEDED(pDataObject->lpVtbl->QueryGetData(pDataObject, &fetc))) { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Drop Text for QueryGetData, format %08x '%s', success\n", + ". In Drop Text for QueryGetData, format %08x '%s', success", fetc.cfFormat, format_mime); STGMEDIUM med; HRESULT hres = pDataObject->lpVtbl->GetData(pDataObject, &fetc, &med); SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Drop Text for GetData, format %08x '%s', HRESULT is %08lx\n", + ". In Drop Text for GetData, format %08x '%s', HRESULT is %08lx", fetc.cfFormat, format_mime, hres); if (SUCCEEDED(hres)) { const size_t bsize = GlobalSize(med.hGlobal); const void *buffer = (void *)GlobalLock(med.hGlobal); SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Drop Text for GlobalLock, format %08x '%s', memory (%lu) %p\n", + ". In Drop Text for GlobalLock, format %08x '%s', memory (%lu) %p", fetc.cfFormat, format_mime, (unsigned long)bsize, buffer); if (buffer) { char *text = (char *)SDL_malloc(bsize + sizeof(Uint32)); @@ -2119,7 +2150,7 @@ static STDMETHODIMP SDLDropTarget_Drop(SDLDropTarget *target, char *token = SDL_strtok_r(text, "\r\n", &saveptr); while (token != NULL) { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Drop Text, text (%lu of %lu) '%s'\n", + ". In Drop Text, text (%lu of %lu) '%s'", (unsigned long)SDL_strlen(token), (unsigned long)bsize, token); SDL_SendDropText(target->window, (char *)token); token = SDL_strtok_r(NULL, "\r\n", &saveptr); @@ -2144,18 +2175,18 @@ static STDMETHODIMP SDLDropTarget_Drop(SDLDropTarget *target, const char *format_mime = "CF_HDROP"; if (SUCCEEDED(pDataObject->lpVtbl->QueryGetData(pDataObject, &fetc))) { SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Drop File for QueryGetData, format %08x '%s', success\n", + ". In Drop File for QueryGetData, format %08x '%s', success", fetc.cfFormat, format_mime); STGMEDIUM med; HRESULT hres = pDataObject->lpVtbl->GetData(pDataObject, &fetc, &med); SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Drop File for GetData, format %08x '%s', HRESULT is %08lx\n", + ". In Drop File for GetData, format %08x '%s', HRESULT is %08lx", fetc.cfFormat, format_mime, hres); if (SUCCEEDED(hres)) { const size_t bsize = GlobalSize(med.hGlobal); HDROP drop = (HDROP)GlobalLock(med.hGlobal); SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Drop File for GlobalLock, format %08x '%s', memory (%lu) %p\n", + ". In Drop File for GlobalLock, format %08x '%s', memory (%lu) %p", fetc.cfFormat, format_mime, (unsigned long)bsize, drop); UINT count = DragQueryFile(drop, 0xFFFFFFFF, NULL, 0); for (UINT i = 0; i < count; ++i) { @@ -2165,7 +2196,7 @@ static STDMETHODIMP SDLDropTarget_Drop(SDLDropTarget *target, if (DragQueryFile(drop, i, buffer, size)) { char *file = WIN_StringToUTF8(buffer); SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Drop File, file (%lu of %lu) '%s'\n", + ". In Drop File, file (%lu of %lu) '%s'", (unsigned long)SDL_strlen(file), (unsigned long)bsize, file); SDL_SendDropFile(target->window, NULL, file); SDL_free(file); @@ -2211,7 +2242,7 @@ void WIN_AcceptDragAndDrop(SDL_Window *window, bool accept) SDLDropTarget_AddRef(drop_target); RegisterDragDrop(data->hwnd, (LPDROPTARGET)drop_target); SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Accept Drag and Drop, window %u, enabled Full OLE IDropTarget\n", + ". In Accept Drag and Drop, window %u, enabled Full OLE IDropTarget", window->id); } } else if (!accept && data->drop_target) { @@ -2219,13 +2250,13 @@ void WIN_AcceptDragAndDrop(SDL_Window *window, bool accept) SDLDropTarget_Release(data->drop_target); data->drop_target = NULL; SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Accept Drag and Drop, window %u, disabled Full OLE IDropTarget\n", + ". In Accept Drag and Drop, window %u, disabled Full OLE IDropTarget", window->id); } } else { DragAcceptFiles(data->hwnd, accept ? TRUE : FALSE); SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In Accept Drag and Drop, window %u, %s Fallback WM_DROPFILES\n", + ". In Accept Drag and Drop, window %u, %s Fallback WM_DROPFILES", window->id, (accept ? "enabled" : "disabled")); } } diff --git a/libs/SDL3/src/video/x11/SDL_x11events.c b/libs/SDL3/src/video/x11/SDL_x11events.c index 90ce95c5..02c2d905 100644 --- a/libs/SDL3/src/video/x11/SDL_x11events.c +++ b/libs/SDL3/src/video/x11/SDL_x11events.c @@ -233,7 +233,7 @@ void SDL_SetX11EventHook(SDL_X11EventHook callback, void *userdata) #ifdef SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS static void X11_HandleGenericEvent(SDL_VideoDevice *_this, XEvent *xev) { - SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; + SDL_VideoData *videodata = _this->internal; // event is a union, so cookie == &event, but this is type safe. XGenericEventCookie *cookie = &xev->xcookie; @@ -310,6 +310,12 @@ static void X11_ReconcileModifiers(SDL_VideoData *viddata) viddata->xkb.sdl_modifiers &= ~SDL_KMOD_MODE; } + if (xk_modifiers & LockMask) { + viddata->xkb.sdl_modifiers |= SDL_KMOD_CAPS; + } else { + viddata->xkb.sdl_modifiers &= ~SDL_KMOD_CAPS; + } + if (xk_modifiers & viddata->xkb.numlock_mask) { viddata->xkb.sdl_modifiers |= SDL_KMOD_NUM; } else { @@ -325,10 +331,11 @@ static void X11_ReconcileModifiers(SDL_VideoData *viddata) SDL_SetModState(viddata->xkb.sdl_modifiers); } -static void X11_HandleModifierKeys(SDL_VideoData *viddata, SDL_Scancode scancode, bool pressed, bool reconcile) +static void X11_HandleModifierKeys(SDL_VideoData *viddata, SDL_Scancode scancode, bool pressed, bool allow_reconciliation) { const SDL_Keycode keycode = SDL_GetKeyFromScancode(scancode, SDL_KMOD_NONE, false); SDL_Keymod mod = SDL_KMOD_NONE; + bool reconcile = false; /* SDL clients expect modifier state to be activated at the same time as the * source keypress, so we set pressed modifier state with the usual modifier @@ -367,7 +374,36 @@ static void X11_HandleModifierKeys(SDL_VideoData *viddata, SDL_Scancode scancode case SDLK_LEVEL5_SHIFT: mod = SDL_KMOD_LEVEL5; break; + case SDLK_CAPSLOCK: + case SDLK_NUMLOCKCLEAR: + case SDLK_SCROLLLOCK: + { + /* For locking modifier keys, query the lock state directly, or we may have to wait until the next + * key press event to know if a lock was actually activated from the key event. + */ + unsigned int cur_mask = viddata->xkb.xkb_modifiers; + X11_UpdateSystemKeyModifiers(viddata); + + if (viddata->xkb.xkb_modifiers & LockMask) { + cur_mask |= LockMask; + } else { + cur_mask &= ~LockMask; + } + if (viddata->xkb.xkb_modifiers & viddata->xkb.numlock_mask) { + cur_mask |= viddata->xkb.numlock_mask; + } else { + cur_mask &= ~viddata->xkb.numlock_mask; + } + if (viddata->xkb.xkb_modifiers & viddata->xkb.scrolllock_mask) { + cur_mask |= viddata->xkb.scrolllock_mask; + } else { + cur_mask &= ~viddata->xkb.scrolllock_mask; + } + + viddata->xkb.xkb_modifiers = cur_mask; + } SDL_FALLTHROUGH; default: + reconcile = true; break; } @@ -377,8 +413,12 @@ static void X11_HandleModifierKeys(SDL_VideoData *viddata, SDL_Scancode scancode viddata->xkb.sdl_modifiers &= ~mod; } - if (reconcile) { - X11_ReconcileModifiers(viddata); + if (allow_reconciliation) { + if (reconcile) { + X11_ReconcileModifiers(viddata); + } else { + SDL_SetModState(viddata->xkb.sdl_modifiers); + } } } @@ -430,7 +470,7 @@ void X11_ReconcileKeyboardState(SDL_VideoDevice *_this) static void X11_DispatchFocusIn(SDL_VideoDevice *_this, SDL_WindowData *data) { #ifdef DEBUG_XEVENTS - SDL_Log("window 0x%lx: Dispatching FocusIn\n", data->xwindow); + SDL_Log("window 0x%lx: Dispatching FocusIn", data->xwindow); #endif SDL_SetKeyboardFocus(data->window); X11_ReconcileKeyboardState(_this); @@ -447,7 +487,7 @@ static void X11_DispatchFocusIn(SDL_VideoDevice *_this, SDL_WindowData *data) static void X11_DispatchFocusOut(SDL_VideoDevice *_this, SDL_WindowData *data) { #ifdef DEBUG_XEVENTS - SDL_Log("window 0x%lx: Dispatching FocusOut\n", data->xwindow); + SDL_Log("window 0x%lx: Dispatching FocusOut", data->xwindow); #endif /* If another window has already processed a focus in, then don't try to * remove focus here. Doing so will incorrectly remove focus from that @@ -606,7 +646,7 @@ static void X11_UpdateUserTime(SDL_WindowData *data, const unsigned long latest) XA_CARDINAL, 32, PropModeReplace, (const unsigned char *)&latest, 1); #ifdef DEBUG_XEVENTS - SDL_Log("window 0x%lx: updating _NET_WM_USER_TIME to %lu\n", data->xwindow, latest); + SDL_Log("window 0x%lx: updating _NET_WM_USER_TIME to %lu", data->xwindow, latest); #endif data->user_time = latest; } @@ -636,7 +676,7 @@ static void X11_HandleClipboardEvent(SDL_VideoDevice *_this, const XEvent *xeven #ifdef DEBUG_XEVENTS char *atom_name; atom_name = X11_XGetAtomName(display, req->target); - SDL_Log("window CLIPBOARD: SelectionRequest (requestor = 0x%lx, target = 0x%lx, mime_type = %s)\n", + SDL_Log("window CLIPBOARD: SelectionRequest (requestor = 0x%lx, target = 0x%lx, mime_type = %s)", req->requestor, req->target, atom_name); if (atom_name) { X11_XFree(atom_name); @@ -709,7 +749,7 @@ static void X11_HandleClipboardEvent(SDL_VideoDevice *_this, const XEvent *xeven const char *propName = xsel->property ? X11_XGetAtomName(display, xsel->property) : "None"; const char *targetName = xsel->target ? X11_XGetAtomName(display, xsel->target) : "None"; - SDL_Log("window CLIPBOARD: SelectionNotify (requestor = 0x%lx, target = %s, property = %s)\n", + SDL_Log("window CLIPBOARD: SelectionNotify (requestor = 0x%lx, target = %s, property = %s)", xsel->requestor, targetName, propName); #endif if (xsel->target == videodata->atoms.TARGETS && xsel->property == videodata->atoms.SDL_FORMATS) { @@ -761,7 +801,7 @@ static void X11_HandleClipboardEvent(SDL_VideoDevice *_this, const XEvent *xeven SDLX11_ClipboardData *clipboard = NULL; #ifdef DEBUG_XEVENTS - SDL_Log("window CLIPBOARD: SelectionClear (requestor = 0x%lx, target = 0x%lx)\n", + SDL_Log("window CLIPBOARD: SelectionClear (requestor = 0x%lx, target = 0x%lx)", xevent->xselection.requestor, xevent->xselection.target); #endif @@ -857,7 +897,7 @@ static int XLookupStringAsUTF8(XKeyEvent *event_struct, char *buffer_return, int SDL_WindowData *X11_FindWindow(SDL_VideoDevice *_this, Window window) { - const SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; + const SDL_VideoData *videodata = _this->internal; int i; if (videodata && videodata->windowlist) { @@ -879,7 +919,7 @@ Uint64 X11_GetEventTimestamp(unsigned long time) void X11_HandleKeyEvent(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_KeyboardID keyboardID, XEvent *xevent) { - SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; + SDL_VideoData *videodata = _this->internal; Display *display = videodata->display; KeyCode keycode = xevent->xkey.keycode; KeySym keysym = NoSymbol; @@ -892,27 +932,27 @@ void X11_HandleKeyEvent(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_ Uint64 timestamp = X11_GetEventTimestamp(xevent->xkey.time); #ifdef DEBUG_XEVENTS - SDL_Log("window 0x%lx %s (X11 keycode = 0x%X)\n", xevent->xany.window, (xevent->type == KeyPress ? "KeyPress" : "KeyRelease"), xevent->xkey.keycode); + SDL_Log("window 0x%lx %s (X11 keycode = 0x%X)", xevent->xany.window, (xevent->type == KeyPress ? "KeyPress" : "KeyRelease"), xevent->xkey.keycode); #endif #ifdef DEBUG_SCANCODES if (scancode == SDL_SCANCODE_UNKNOWN && keycode) { int min_keycode, max_keycode; X11_XDisplayKeycodes(display, &min_keycode, &max_keycode); keysym = X11_KeyCodeToSym(_this, keycode, xevent->xkey.state >> 13); - SDL_Log("The key you just pressed is not recognized by SDL. To help get this fixed, please report this to the SDL forums/mailing list X11 KeyCode %d (%d), X11 KeySym 0x%lX (%s).\n", + SDL_Log("The key you just pressed is not recognized by SDL. To help get this fixed, please report this to the SDL forums/mailing list X11 KeyCode %d (%d), X11 KeySym 0x%lX (%s).", keycode, keycode - min_keycode, keysym, X11_XKeysymToString(keysym)); } #endif // DEBUG SCANCODES text[0] = '\0'; - X11_UpdateSystemKeyModifiers(videodata); + videodata->xkb.xkb_modifiers = xevent->xkey.state; if (SDL_TextInputActive(windowdata->window)) { // filter events catches XIM events and sends them to the correct handler if (X11_XFilterEvent(xevent, None)) { #ifdef DEBUG_XEVENTS - SDL_Log("Filtered event type = %d display = %p window = 0x%lx\n", + SDL_Log("Filtered event type = %d display = %p window = 0x%lx", xevent->type, xevent->xany.display, xevent->xany.window); #endif handled_by_ime = true; @@ -961,13 +1001,13 @@ void X11_HandleKeyEvent(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_ void X11_HandleButtonPress(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_MouseID mouseID, int button, float x, float y, unsigned long time) { SDL_Window *window = windowdata->window; - const SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; + const SDL_VideoData *videodata = _this->internal; Display *display = videodata->display; int xticks = 0, yticks = 0; Uint64 timestamp = X11_GetEventTimestamp(time); #ifdef DEBUG_XEVENTS - SDL_Log("window 0x%lx: ButtonPress (X11 button = %d)\n", windowdata->xwindow, button); + SDL_Log("window 0x%lx: ButtonPress (X11 button = %d)", windowdata->xwindow, button); #endif SDL_Mouse *mouse = SDL_GetMouse(); @@ -1008,14 +1048,14 @@ void X11_HandleButtonPress(SDL_VideoDevice *_this, SDL_WindowData *windowdata, S void X11_HandleButtonRelease(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_MouseID mouseID, int button, unsigned long time) { SDL_Window *window = windowdata->window; - const SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; + const SDL_VideoData *videodata = _this->internal; Display *display = videodata->display; // The X server sends a Release event for each Press for wheels. Ignore them. int xticks = 0, yticks = 0; Uint64 timestamp = X11_GetEventTimestamp(time); #ifdef DEBUG_XEVENTS - SDL_Log("window 0x%lx: ButtonRelease (X11 button = %d)\n", windowdata->xwindow, button); + SDL_Log("window 0x%lx: ButtonRelease (X11 button = %d)", windowdata->xwindow, button); #endif if (!X11_IsWheelEvent(display, button, &xticks, &yticks)) { if (button > 7) { @@ -1048,7 +1088,7 @@ void X11_GetBorderValues(SDL_WindowData *data) X11_XFree(property); #ifdef DEBUG_XEVENTS - SDL_Log("New _NET_FRAME_EXTENTS: left=%d right=%d, top=%d, bottom=%d\n", data->border_left, data->border_right, data->border_top, data->border_bottom); + SDL_Log("New _NET_FRAME_EXTENTS: left=%d right=%d, top=%d, bottom=%d", data->border_left, data->border_right, data->border_top, data->border_bottom); #endif } } else { @@ -1072,7 +1112,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) if (xevent->type != KeyPress && xevent->type != KeyRelease) { if (X11_XFilterEvent(xevent, None)) { #ifdef DEBUG_XEVENTS - SDL_Log("Filtered event type = %d display = %p window = 0x%lx\n", + SDL_Log("Filtered event type = %d display = %p window = 0x%lx", xevent->type, xevent->xany.display, xevent->xany.window); #endif return; @@ -1100,7 +1140,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) #endif #ifdef DEBUG_XEVENTS - SDL_Log("X11 event type = %d display = %p window = 0x%lx\n", + SDL_Log("X11 event type = %d display = %p window = 0x%lx", xevent->type, xevent->xany.display, xevent->xany.window); #endif @@ -1110,7 +1150,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) XFixesSelectionNotifyEvent *ev = (XFixesSelectionNotifyEvent *)xevent; #ifdef DEBUG_XEVENTS - SDL_Log("window CLIPBOARD: XFixesSelectionNotify (selection = %s)\n", + SDL_Log("window CLIPBOARD: XFixesSelectionNotify (selection = %s)", X11_XGetAtomName(display, ev->selection)); #endif @@ -1154,7 +1194,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) // The window for KeymapNotify, etc events is 0 if (xevent->type == KeymapNotify) { #ifdef DEBUG_XEVENTS - SDL_Log("window 0x%lx: KeymapNotify!\n", xevent->xany.window); + SDL_Log("window 0x%lx: KeymapNotify!", xevent->xany.window); #endif if (SDL_GetKeyboardFocus() != NULL) { #ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM @@ -1176,7 +1216,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) const int request = xevent->xmapping.request; #ifdef DEBUG_XEVENTS - SDL_Log("window 0x%lx: MappingNotify!\n", xevent->xany.window); + SDL_Log("window 0x%lx: MappingNotify!", xevent->xany.window); #endif if ((request == MappingKeyboard) || (request == MappingModifier)) { X11_XRefreshKeyboardMapping(&xevent->xmapping); @@ -1221,15 +1261,15 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) { SDL_Mouse *mouse = SDL_GetMouse(); #ifdef DEBUG_XEVENTS - SDL_Log("window 0x%lx: EnterNotify! (%d,%d,%d)\n", xevent->xany.window, + SDL_Log("window 0x%lx: EnterNotify! (%d,%d,%d)", xevent->xany.window, xevent->xcrossing.x, xevent->xcrossing.y, xevent->xcrossing.mode); if (xevent->xcrossing.mode == NotifyGrab) { - SDL_Log("Mode: NotifyGrab\n"); + SDL_Log("Mode: NotifyGrab"); } if (xevent->xcrossing.mode == NotifyUngrab) { - SDL_Log("Mode: NotifyUngrab\n"); + SDL_Log("Mode: NotifyUngrab"); } #endif SDL_SetMouseFocus(data->window); @@ -1260,15 +1300,15 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) case LeaveNotify: { #ifdef DEBUG_XEVENTS - SDL_Log("window 0x%lx: LeaveNotify! (%d,%d,%d)\n", xevent->xany.window, + SDL_Log("window 0x%lx: LeaveNotify! (%d,%d,%d)", xevent->xany.window, xevent->xcrossing.x, xevent->xcrossing.y, xevent->xcrossing.mode); if (xevent->xcrossing.mode == NotifyGrab) { - SDL_Log("Mode: NotifyGrab\n"); + SDL_Log("Mode: NotifyGrab"); } if (xevent->xcrossing.mode == NotifyUngrab) { - SDL_Log("Mode: NotifyUngrab\n"); + SDL_Log("Mode: NotifyUngrab"); } #endif if (!SDL_GetMouse()->relative_mode) { @@ -1295,19 +1335,19 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) if (xevent->xfocus.mode == NotifyGrab || xevent->xfocus.mode == NotifyUngrab) { // Someone is handling a global hotkey, ignore it #ifdef DEBUG_XEVENTS - SDL_Log("window 0x%lx: FocusIn (NotifyGrab/NotifyUngrab, ignoring)\n", xevent->xany.window); + SDL_Log("window 0x%lx: FocusIn (NotifyGrab/NotifyUngrab, ignoring)", xevent->xany.window); #endif break; } if (xevent->xfocus.detail == NotifyInferior || xevent->xfocus.detail == NotifyPointer) { #ifdef DEBUG_XEVENTS - SDL_Log("window 0x%lx: FocusIn (NotifyInferior/NotifyPointer, ignoring)\n", xevent->xany.window); + SDL_Log("window 0x%lx: FocusIn (NotifyInferior/NotifyPointer, ignoring)", xevent->xany.window); #endif break; } #ifdef DEBUG_XEVENTS - SDL_Log("window 0x%lx: FocusIn!\n", xevent->xany.window); + SDL_Log("window 0x%lx: FocusIn!", xevent->xany.window); #endif if (!videodata->last_mode_change_deadline) /* no recent mode changes */ { data->pending_focus = PENDING_FOCUS_NONE; @@ -1326,7 +1366,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) if (xevent->xfocus.mode == NotifyGrab || xevent->xfocus.mode == NotifyUngrab) { // Someone is handling a global hotkey, ignore it #ifdef DEBUG_XEVENTS - SDL_Log("window 0x%lx: FocusOut (NotifyGrab/NotifyUngrab, ignoring)\n", xevent->xany.window); + SDL_Log("window 0x%lx: FocusOut (NotifyGrab/NotifyUngrab, ignoring)", xevent->xany.window); #endif break; } @@ -1335,12 +1375,12 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) care about the position of the pointer when the keyboard focus changed. */ #ifdef DEBUG_XEVENTS - SDL_Log("window 0x%lx: FocusOut (NotifyInferior/NotifyPointer, ignoring)\n", xevent->xany.window); + SDL_Log("window 0x%lx: FocusOut (NotifyInferior/NotifyPointer, ignoring)", xevent->xany.window); #endif break; } #ifdef DEBUG_XEVENTS - SDL_Log("window 0x%lx: FocusOut!\n", xevent->xany.window); + SDL_Log("window 0x%lx: FocusOut!", xevent->xany.window); #endif if (!videodata->last_mode_change_deadline) /* no recent mode changes */ { data->pending_focus = PENDING_FOCUS_NONE; @@ -1366,7 +1406,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) XEvent ev; #ifdef DEBUG_XEVENTS - SDL_Log("window 0x%lx: UnmapNotify!\n", xevent->xany.window); + SDL_Log("window 0x%lx: UnmapNotify!", xevent->xany.window); #endif if (X11_XCheckIfEvent(display, &ev, &isReparentNotify, (XPointer)&xevent->xunmap)) { @@ -1387,7 +1427,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) case MapNotify: { #ifdef DEBUG_XEVENTS - SDL_Log("window 0x%lx: MapNotify!\n", xevent->xany.window); + SDL_Log("window 0x%lx: MapNotify!", xevent->xany.window); #endif X11_DispatchMapNotify(data); @@ -1403,7 +1443,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) case ConfigureNotify: { #ifdef DEBUG_XEVENTS - SDL_Log("window 0x%lx: ConfigureNotify! (position: %d,%d, size: %dx%d)\n", xevent->xany.window, + SDL_Log("window 0x%lx: ConfigureNotify! (position: %d,%d, size: %dx%d)", xevent->xany.window, xevent->xconfigure.x, xevent->xconfigure.y, xevent->xconfigure.width, xevent->xconfigure.height); #endif @@ -1424,7 +1464,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) if (xevent->xconfigure.x != data->last_xconfigure.x || xevent->xconfigure.y != data->last_xconfigure.y) { - if (!data->disable_size_position_events) { + if (!data->size_move_event_flags) { SDL_Window *w; int x = xevent->xconfigure.x; int y = xevent->xconfigure.y; @@ -1448,7 +1488,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) if (xevent->xconfigure.width != data->last_xconfigure.width || xevent->xconfigure.height != data->last_xconfigure.height) { - if (!data->disable_size_position_events) { + if (!data->size_move_event_flags) { data->pending_operation &= ~X11_PENDING_OP_RESIZE; SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_RESIZED, xevent->xconfigure.width, @@ -1470,9 +1510,9 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) data->xdnd_source = xevent->xclient.data.l[0]; xdnd_version = (xevent->xclient.data.l[1] >> 24); #ifdef DEBUG_XEVENTS - SDL_Log("XID of source window : 0x%lx\n", data->xdnd_source); - SDL_Log("Protocol version to use : %d\n", xdnd_version); - SDL_Log("More then 3 data types : %d\n", (int)use_list); + SDL_Log("XID of source window : 0x%lx", data->xdnd_source); + SDL_Log("Protocol version to use : %d", xdnd_version); + SDL_Log("More then 3 data types : %d", (int)use_list); #endif if (use_list) { @@ -1488,7 +1528,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) } } else if (xevent->xclient.message_type == videodata->atoms.XdndLeave) { #ifdef DEBUG_XEVENTS - SDL_Log("XID of source window : 0x%lx\n", xevent->xclient.data.l[0]); + SDL_Log("XID of source window : 0x%lx", xevent->xclient.data.l[0]); #endif SDL_SendDropComplete(data->window); } else if (xevent->xclient.message_type == videodata->atoms.XdndPosition) { @@ -1498,7 +1538,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) if (xdnd_version >= 2) { act = xevent->xclient.data.l[4]; } - SDL_Log("Action requested by user is : %s\n", X11_XGetAtomName(display, act)); + SDL_Log("Action requested by user is : %s", X11_XGetAtomName(display, act)); #endif { // Drag and Drop position @@ -1555,7 +1595,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) Window root = DefaultRootWindow(display); #ifdef DEBUG_XEVENTS - SDL_Log("window 0x%lx: _NET_WM_PING\n", xevent->xany.window); + SDL_Log("window 0x%lx: _NET_WM_PING", xevent->xany.window); #endif xevent->xclient.window = root; X11_XSendEvent(display, root, False, SubstructureRedirectMask | SubstructureNotifyMask, xevent); @@ -1567,7 +1607,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) (xevent->xclient.data.l[0] == videodata->atoms.WM_DELETE_WINDOW)) { #ifdef DEBUG_XEVENTS - SDL_Log("window 0x%lx: WM_DELETE_WINDOW\n", xevent->xany.window); + SDL_Log("window 0x%lx: WM_DELETE_WINDOW", xevent->xany.window); #endif SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_CLOSE_REQUESTED, 0, 0); break; @@ -1589,7 +1629,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) case Expose: { #ifdef DEBUG_XEVENTS - SDL_Log("window 0x%lx: Expose (count = %d)\n", xevent->xany.window, xevent->xexpose.count); + SDL_Log("window 0x%lx: Expose (count = %d)", xevent->xany.window, xevent->xexpose.count); #endif SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_EXPOSED, 0, 0); } break; @@ -1614,7 +1654,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) case MotionNotify: { - if (data->xinput2_mouse_enabled) { + if (data->xinput2_mouse_enabled && !data->mouse_grabbed) { // This input is being handled by XInput2 break; } @@ -1622,7 +1662,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) SDL_Mouse *mouse = SDL_GetMouse(); if (!mouse->relative_mode) { #ifdef DEBUG_MOTION - SDL_Log("window 0x%lx: X11 motion: %d,%d\n", xevent->xany.window, xevent->xmotion.x, xevent->xmotion.y); + SDL_Log("window 0x%lx: X11 motion: %d,%d", xevent->xany.window, xevent->xmotion.x, xevent->xmotion.y); #endif X11_ProcessHitTest(_this, data, (float)xevent->xmotion.x, (float)xevent->xmotion.y, false); @@ -1661,7 +1701,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) char *name = X11_XGetAtomName(display, xevent->xproperty.atom); if (name) { - SDL_Log("window 0x%lx: PropertyNotify: %s %s time=%lu\n", xevent->xany.window, name, (xevent->xproperty.state == PropertyDelete) ? "deleted" : "changed", xevent->xproperty.time); + SDL_Log("window 0x%lx: PropertyNotify: %s %s time=%lu", xevent->xany.window, name, (xevent->xproperty.state == PropertyDelete) ? "deleted" : "changed", xevent->xproperty.time); X11_XFree(name); } @@ -1674,7 +1714,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) for (i = 0; i < items_read; i++) { SDL_Log(" %d", values[i]); } - SDL_Log(" }\n"); + SDL_Log(" }"); } else if (real_type == XA_CARDINAL) { if (real_format == 32) { Uint32 *values = (Uint32 *)propdata; @@ -1683,7 +1723,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) for (i = 0; i < items_read; i++) { SDL_Log(" %d", values[i]); } - SDL_Log(" }\n"); + SDL_Log(" }"); } else if (real_format == 16) { Uint16 *values = (Uint16 *)propdata; @@ -1691,7 +1731,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) for (i = 0; i < items_read; i++) { SDL_Log(" %d", values[i]); } - SDL_Log(" }\n"); + SDL_Log(" }"); } else if (real_format == 8) { Uint8 *values = (Uint8 *)propdata; @@ -1699,11 +1739,11 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) for (i = 0; i < items_read; i++) { SDL_Log(" %d", values[i]); } - SDL_Log(" }\n"); + SDL_Log(" }"); } } else if (real_type == XA_STRING || real_type == videodata->atoms.UTF8_STRING) { - SDL_Log("{ \"%s\" }\n", propdata); + SDL_Log("{ \"%s\" }", propdata); } else if (real_type == XA_ATOM) { Atom *atoms = (Atom *)propdata; @@ -1715,10 +1755,10 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) X11_XFree(atomname); } } - SDL_Log(" }\n"); + SDL_Log(" }"); } else { char *atomname = X11_XGetAtomName(display, real_type); - SDL_Log("Unknown type: 0x%lx (%s)\n", real_type, atomname ? atomname : "UNKNOWN"); + SDL_Log("Unknown type: 0x%lx (%s)", real_type, atomname ? atomname : "UNKNOWN"); if (atomname) { X11_XFree(atomname); } @@ -1799,7 +1839,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) * shut off to avoid bogus window sizes and positions, and * note that the old borders were non-zero for restoration. */ - data->disable_size_position_events = true; + data->size_move_event_flags |= X11_SIZE_MOVE_EVENTS_WAIT_FOR_BORDERS; data->previous_borders_nonzero = true; } else if (!(flags & SDL_WINDOW_FULLSCREEN) && data->previous_borders_nonzero && @@ -1809,10 +1849,10 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) * off size events until the borders come back to avoid bogus * window sizes and positions. */ - data->disable_size_position_events = true; + data->size_move_event_flags |= X11_SIZE_MOVE_EVENTS_WAIT_FOR_BORDERS; data->previous_borders_nonzero = false; } else { - data->disable_size_position_events = false; + data->size_move_event_flags = 0; data->previous_borders_nonzero = false; if (!(data->window->flags & SDL_WINDOW_FULLSCREEN) && data->toggle_borders) { @@ -1845,7 +1885,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) data->pending_operation |= X11_PENDING_OP_MOVE; data->expected.x = data->window->pending.x - data->border_left; data->expected.y = data->window->pending.y - data->border_top; - X11_XMoveWindow(display, data->xwindow, data->window->pending.x - data->border_left, data->window->pending.y - data->border_top); + X11_XMoveWindow(display, data->xwindow, data->expected.x, data->expected.y); } if (data->pending_size) { data->pending_size = false; @@ -1875,37 +1915,13 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) right approach, but it seems to work. */ X11_UpdateKeymap(_this, true); } else if (xevent->xproperty.atom == videodata->atoms._NET_FRAME_EXTENTS) { - if (data->disable_size_position_events) { - /* Re-enable size events if they were turned off waiting for the borders to come back - * when leaving fullscreen. - */ - data->disable_size_position_events = false; + /* Events are disabled when leaving fullscreen until the borders appear to avoid + * incorrect size/position events. + */ + if (data->size_move_event_flags) { + data->size_move_event_flags &= ~X11_SIZE_MOVE_EVENTS_WAIT_FOR_BORDERS; X11_GetBorderValues(data); - if (data->border_top != 0 || data->border_left != 0 || data->border_right != 0 || data->border_bottom != 0) { - // Adjust if the window size/position changed to accommodate the borders. - data->pending_operation |= X11_PENDING_OP_MOVE | X11_PENDING_OP_RESIZE; - if (data->pending_position) { - data->pending_position = false; - data->expected.x = data->window->pending.x - data->border_left; - data->expected.y = data->window->pending.y - data->border_top; - - } else { - data->expected.x = data->window->windowed.x - data->border_left; - data->expected.y = data->window->windowed.y - data->border_top; - } - - if (data->pending_size) { - data->pending_size = false; - data->expected.w = data->window->pending.w; - data->expected.h = data->window->pending.h; - } else { - data->expected.w = data->window->windowed.w; - data->expected.h = data->window->windowed.h; - } - X11_XMoveWindow(display, data->xwindow, data->expected.x, data->expected.y - data->border_top); - X11_XResizeWindow(display, data->xwindow, data->expected.w, data->expected.h); - } } if (!(data->window->flags & SDL_WINDOW_FULLSCREEN) && data->toggle_borders) { data->toggle_borders = false; @@ -1918,7 +1934,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) { Atom target = xevent->xselection.target; #ifdef DEBUG_XEVENTS - SDL_Log("window 0x%lx: SelectionNotify (requestor = 0x%lx, target = 0x%lx)\n", xevent->xany.window, + SDL_Log("window 0x%lx: SelectionNotify (requestor = 0x%lx, target = 0x%lx)", xevent->xany.window, xevent->xselection.requestor, xevent->xselection.target); #endif if (target == data->xdnd_req) { @@ -1969,7 +1985,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) default: { #ifdef DEBUG_XEVENTS - SDL_Log("window 0x%lx: Unhandled event %d\n", xevent->xany.window, xevent->type); + SDL_Log("window 0x%lx: Unhandled event %d", xevent->xany.window, xevent->type); #endif } break; } diff --git a/libs/SDL3/src/video/x11/SDL_x11keyboard.c b/libs/SDL3/src/video/x11/SDL_x11keyboard.c index 336f906e..c48e8291 100644 --- a/libs/SDL3/src/video/x11/SDL_x11keyboard.c +++ b/libs/SDL3/src/video/x11/SDL_x11keyboard.c @@ -239,7 +239,7 @@ bool X11_InitKeyboard(SDL_VideoDevice *_this) const SDL_Scancode *table = SDL_GetScancodeTable(scancode_set[best_index], &table_size); #ifdef DEBUG_KEYBOARD - SDL_Log("Using scancode set %d, min_keycode = %d, max_keycode = %d, table_size = %d\n", best_index, min_keycode, max_keycode, table_size); + SDL_Log("Using scancode set %d, min_keycode = %d, max_keycode = %d, table_size = %d", best_index, min_keycode, max_keycode, table_size); #endif // This should never happen, but just in case... if (table_size > (SDL_arraysize(data->key_layout) - min_keycode)) { @@ -267,14 +267,14 @@ bool X11_InitKeyboard(SDL_VideoDevice *_this) if ((SDL_GetKeymapKeycode(NULL, scancode, SDL_KMOD_NONE) & (SDLK_SCANCODE_MASK | SDLK_EXTENDED_MASK)) && X11_ScancodeIsRemappable(scancode)) { // Not a character key and the scancode is safe to remap #ifdef DEBUG_KEYBOARD - SDL_Log("Changing scancode, was %d (%s), now %d (%s)\n", data->key_layout[i], SDL_GetScancodeName(data->key_layout[i]), scancode, SDL_GetScancodeName(scancode)); + SDL_Log("Changing scancode, was %d (%s), now %d (%s)", data->key_layout[i], SDL_GetScancodeName(data->key_layout[i]), scancode, SDL_GetScancodeName(scancode)); #endif data->key_layout[i] = scancode; } } } else { #ifdef DEBUG_SCANCODES - SDL_Log("Keyboard layout unknown, please report the following to the SDL forums/mailing list (https://discourse.libsdl.org/):\n"); + SDL_Log("Keyboard layout unknown, please report the following to the SDL forums/mailing list (https://discourse.libsdl.org/):"); #endif // Determine key_layout - only works on US QWERTY layout @@ -288,9 +288,9 @@ bool X11_InitKeyboard(SDL_VideoDevice *_this) (unsigned int)sym, sym == NoSymbol ? "NoSymbol" : X11_XKeysymToString(sym)); } if (scancode == SDL_SCANCODE_UNKNOWN) { - SDL_Log("scancode not found\n"); + SDL_Log("scancode not found"); } else { - SDL_Log("scancode = %d (%s)\n", scancode, SDL_GetScancodeName(scancode)); + SDL_Log("scancode = %d (%s)", scancode, SDL_GetScancodeName(scancode)); } #endif data->key_layout[i] = scancode; @@ -592,12 +592,12 @@ static void preedit_draw_callback(XIC xic, XPointer client_data, XIMPreeditDrawC #ifdef DEBUG_XIM if (call_data->chg_length > 0) { - SDL_Log("Draw callback deleted %d characters at %d\n", call_data->chg_length, call_data->chg_first); + SDL_Log("Draw callback deleted %d characters at %d", call_data->chg_length, call_data->chg_first); } if (text) { - SDL_Log("Draw callback inserted %s at %d, caret: %d\n", text->string.multi_byte, call_data->chg_first, call_data->caret); + SDL_Log("Draw callback inserted %s at %d, caret: %d", text->string.multi_byte, call_data->chg_first, call_data->caret); } - SDL_Log("Pre-edit text: %s\n", data->preedit_text); + SDL_Log("Pre-edit text: %s", data->preedit_text); #endif X11_SendEditingEvent(data); @@ -660,7 +660,8 @@ void X11_CreateInputContext(SDL_WindowData *data) NULL); X11_XFree(attr); } - } else { + } + if (!data->ic) { data->ic = X11_XCreateIC(videodata->im, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, data->xwindow, diff --git a/libs/SDL3/src/video/x11/SDL_x11pen.c b/libs/SDL3/src/video/x11/SDL_x11pen.c index 38a331f8..f16da51c 100644 --- a/libs/SDL3/src/video/x11/SDL_x11pen.c +++ b/libs/SDL3/src/video/x11/SDL_x11pen.c @@ -31,7 +31,7 @@ // Does this device have a valuator for pressure sensitivity? static bool X11_XInput2DeviceIsPen(SDL_VideoDevice *_this, const XIDeviceInfo *dev) { - const SDL_VideoData *data = (SDL_VideoData *)_this->internal; + const SDL_VideoData *data = _this->internal; for (int i = 0; i < dev->num_classes; i++) { const XIAnyClassInfo *classinfo = dev->classes[i]; if (classinfo->type == XIValuatorClass) { @@ -49,7 +49,7 @@ static bool X11_XInput2DeviceIsPen(SDL_VideoDevice *_this, const XIDeviceInfo *d static bool X11_XInput2PenIsEraser(SDL_VideoDevice *_this, int deviceid, char *devicename) { #define PEN_ERASER_NAME_TAG "eraser" // String constant to identify erasers - SDL_VideoData *data = (SDL_VideoData *)_this->internal; + SDL_VideoData *data = _this->internal; if (data->atoms.pen_atom_wacom_tool_type != None) { Atom type_return; @@ -81,10 +81,13 @@ static bool X11_XInput2PenIsEraser(SDL_VideoDevice *_this, int deviceid, char *d } if (tooltype_name) { - if (0 == SDL_strcasecmp(tooltype_name, PEN_ERASER_NAME_TAG)) { + if (SDL_strcasecmp(tooltype_name, PEN_ERASER_NAME_TAG) == 0) { result = true; } - X11_XFree(tooltype_name_info); + if (tooltype_name != (char *)tooltype_name_info) { + X11_XFree(tooltype_name_info); + } + X11_XFree(tooltype_name); return result; } @@ -102,7 +105,7 @@ static bool X11_XInput2PenIsEraser(SDL_VideoDevice *_this, int deviceid, char *d // Returns number of Sint32s written (<= max_words), or 0 on error. static size_t X11_XInput2PenGetIntProperty(SDL_VideoDevice *_this, int deviceid, Atom property, Sint32 *dest, size_t max_words) { - const SDL_VideoData *data = (SDL_VideoData *)_this->internal; + const SDL_VideoData *data = _this->internal; Atom type_return; int format_return; unsigned long num_items_return; @@ -150,7 +153,7 @@ static size_t X11_XInput2PenGetIntProperty(SDL_VideoDevice *_this, int deviceid, // Identify Wacom devices (if true is returned) and extract their device type and serial IDs static bool X11_XInput2PenWacomDeviceID(SDL_VideoDevice *_this, int deviceid, Uint32 *wacom_devicetype_id, Uint32 *wacom_serial) { - SDL_VideoData *data = (SDL_VideoData *)_this->internal; + SDL_VideoData *data = _this->internal; Sint32 serial_id_buf[3]; int result; @@ -193,7 +196,7 @@ X11_PenHandle *X11_FindPenByDeviceID(int deviceid) static X11_PenHandle *X11_MaybeAddPen(SDL_VideoDevice *_this, const XIDeviceInfo *dev) { - SDL_VideoData *data = (SDL_VideoData *)_this->internal; + SDL_VideoData *data = _this->internal; SDL_PenCapabilityFlags capabilities = 0; X11_PenHandle *handle = NULL; @@ -280,12 +283,14 @@ static X11_PenHandle *X11_MaybeAddPen(SDL_VideoDevice *_this, const XIDeviceInfo X11_PenHandle *X11_MaybeAddPenByDeviceID(SDL_VideoDevice *_this, int deviceid) { - SDL_VideoData *data = (SDL_VideoData *)_this->internal; + SDL_VideoData *data = _this->internal; int num_device_info = 0; XIDeviceInfo *device_info = X11_XIQueryDevice(data->display, deviceid, &num_device_info); if (device_info) { SDL_assert(num_device_info == 1); - return X11_MaybeAddPen(_this, device_info); + X11_PenHandle *handle = X11_MaybeAddPen(_this, device_info); + X11_XIFreeDeviceInfo(device_info); + return handle; } return NULL; } @@ -301,7 +306,7 @@ void X11_RemovePenByDeviceID(int deviceid) void X11_InitPen(SDL_VideoDevice *_this) { - SDL_VideoData *data = (SDL_VideoData *)_this->internal; + SDL_VideoData *data = _this->internal; #define LOOKUP_PEN_ATOM(X) X11_XInternAtom(data->display, X, False) data->atoms.pen_atom_device_product_id = LOOKUP_PEN_ATOM("Device Product ID"); diff --git a/libs/SDL3/src/video/x11/SDL_x11shape.c b/libs/SDL3/src/video/x11/SDL_x11shape.c index 710eb329..e4335988 100644 --- a/libs/SDL3/src/video/x11/SDL_x11shape.c +++ b/libs/SDL3/src/video/x11/SDL_x11shape.c @@ -31,7 +31,7 @@ static Uint8 *GenerateShapeMask(SDL_Surface *shape) { int x, y; const size_t ppb = 8; - const size_t bytes_per_scanline = (size_t)(shape->w + (ppb - 1)) / ppb; + const size_t bytes_per_scanline = (shape->w + (ppb - 1)) / ppb; const Uint8 *a; Uint8 *mask; Uint8 *mask_scanline; @@ -71,7 +71,7 @@ bool X11_UpdateWindowShape(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surfa if (!stretched) { return false; } - if (!SDL_SoftStretch(shape, NULL, stretched, NULL, SDL_SCALEMODE_LINEAR)) { + if (!SDL_StretchSurface(shape, NULL, stretched, NULL, SDL_SCALEMODE_LINEAR)) { SDL_DestroySurface(stretched); return false; } diff --git a/libs/SDL3/src/video/x11/SDL_x11video.c b/libs/SDL3/src/video/x11/SDL_x11video.c index d87dcc0f..62b4330e 100644 --- a/libs/SDL3/src/video/x11/SDL_x11video.c +++ b/libs/SDL3/src/video/x11/SDL_x11video.c @@ -271,7 +271,8 @@ static SDL_VideoDevice *X11_CreateDevice(void) VideoBootStrap X11_bootstrap = { "x11", "SDL X11 video driver", X11_CreateDevice, - X11_ShowMessageBox + X11_ShowMessageBox, + false }; static int (*handler)(Display *, XErrorEvent *) = NULL; diff --git a/libs/SDL3/src/video/x11/SDL_x11window.c b/libs/SDL3/src/video/x11/SDL_x11window.c index 0ecabec6..55620533 100644 --- a/libs/SDL3/src/video/x11/SDL_x11window.c +++ b/libs/SDL3/src/video/x11/SDL_x11window.c @@ -100,6 +100,14 @@ static bool X11_IsWindowMapped(SDL_VideoDevice *_this, SDL_Window *window) } } +static bool X11_IsDisplayOk(Display *display) +{ + if (display->flags & XlibDisplayIOError) { + return false; + } + return true; +} + #if 0 static bool X11_IsActionAllowed(SDL_Window *window, Atom action) { @@ -387,11 +395,11 @@ static bool SetupWindowData(SDL_VideoDevice *_this, SDL_Window *window, Window w X11_XGetWindowAttributes(data->videodata->display, w, &attrib); if (!SDL_WINDOW_IS_POPUP(window)) { - window->x = data->expected.x = attrib.x; - window->y = data->expected.y = attrib.y - data->border_top; + window->x = window->windowed.x = window->floating.x = attrib.x; + window->y = window->windowed.y = window->floating.y = attrib.y - data->border_top; } - window->w = data->expected.w = attrib.width; - window->h = data->expected.h = attrib.height; + window->w = window->windowed.w = window->floating.w = attrib.width; + window->h = window->windowed.h = window->floating.h = attrib.height; if (attrib.map_state != IsUnmapped) { window->flags &= ~SDL_WINDOW_HIDDEN; } else { @@ -1065,8 +1073,12 @@ void X11_UpdateWindowPosition(SDL_Window *window, bool use_current_position) &data->expected.x, &data->expected.y); // Attempt to move the window - data->pending_operation |= X11_PENDING_OP_MOVE; - X11_XMoveWindow(display, data->xwindow, data->expected.x, data->expected.y); + if (window->flags & SDL_WINDOW_HIDDEN) { + window->internal->pending_position = true; + } else { + data->pending_operation |= X11_PENDING_OP_MOVE; + X11_XMoveWindow(display, data->xwindow, data->expected.x, data->expected.y); + } } bool X11_SetWindowPosition(SDL_VideoDevice *_this, SDL_Window *window) @@ -1095,41 +1107,6 @@ bool X11_SetWindowPosition(SDL_VideoDevice *_this, SDL_Window *window) return true; } -static void X11_SetWMNormalHints(SDL_VideoDevice *_this, SDL_Window *window, XSizeHints *sizehints) -{ - SDL_WindowData *data = window->internal; - Display *display = data->videodata->display; - int dest_x, dest_y; - - X11_XSetWMNormalHints(display, data->xwindow, sizehints); - - /* From Pierre-Loup: - WMs each have their little quirks with that. When you change the - size hints, they get a ConfigureNotify event with the - WM_NORMAL_SIZE_HINTS Atom. They all save the hints then, but they - don't all resize the window right away to enforce the new hints. - - Some of them resize only after: - - A user-initiated move or resize - - A code-initiated move or resize - - Hiding & showing window (Unmap & map) - - The following move & resize seems to help a lot of WMs that didn't - properly update after the hints were changed. We don't do a - hide/show, because there are supposedly subtle problems with doing so - and transitioning from windowed to fullscreen in Unity. - */ - X11_XResizeWindow(display, data->xwindow, window->pending.w, window->pending.h); - const int x = window->last_position_pending ? window->pending.x : window->floating.x; - const int y = window->last_position_pending ? window->pending.y : window->floating.y; - SDL_RelativeToGlobalForWindow(window, - x - data->border_left, - y - data->border_top, - &dest_x, &dest_y); - X11_XMoveWindow(display, data->xwindow, dest_x, dest_y); - X11_XRaiseWindow(display, data->xwindow); -} - void X11_SetWindowMinMax(SDL_Window *window, bool use_current) { SDL_WindowData *data = window->internal; @@ -1231,6 +1208,7 @@ void X11_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window) */ XSizeHints *sizehints = X11_XAllocSizeHints(); long userhints; + int dest_x, dest_y; X11_XGetWMNormalHints(display, data->xwindow, sizehints, &userhints); @@ -1238,7 +1216,33 @@ void X11_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window) sizehints->min_height = sizehints->max_height = window->pending.h; sizehints->flags |= PMinSize | PMaxSize; - X11_SetWMNormalHints(_this, window, sizehints); + X11_XSetWMNormalHints(display, data->xwindow, sizehints); + + /* From Pierre-Loup: + WMs each have their little quirks with that. When you change the + size hints, they get a ConfigureNotify event with the + WM_NORMAL_SIZE_HINTS Atom. They all save the hints then, but they + don't all resize the window right away to enforce the new hints. + + Some of them resize only after: + - A user-initiated move or resize + - A code-initiated move or resize + - Hiding & showing window (Unmap & map) + + The following move & resize seems to help a lot of WMs that didn't + properly update after the hints were changed. We don't do a + hide/show, because there are supposedly subtle problems with doing so + and transitioning from windowed to fullscreen in Unity. + */ + X11_XResizeWindow(display, data->xwindow, window->pending.w, window->pending.h); + const int x = window->last_position_pending ? window->pending.x : window->x; + const int y = window->last_position_pending ? window->pending.y : window->y; + SDL_RelativeToGlobalForWindow(window, + x - data->border_left, + y - data->border_top, + &dest_x, &dest_y); + X11_XMoveWindow(display, data->xwindow, dest_x, dest_y); + X11_XRaiseWindow(display, data->xwindow); X11_XFree(sizehints); } @@ -1432,16 +1436,19 @@ void X11_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window) SDL_WindowData *data = window->internal; Display *display = data->videodata->display; bool bActivate = SDL_GetHintBoolean(SDL_HINT_WINDOW_ACTIVATE_WHEN_SHOWN, true); + bool position_is_absolute = false; + bool set_position = false; XEvent event; if (SDL_WINDOW_IS_POPUP(window)) { // Update the position in case the parent moved while we were hidden X11_ConstrainPopup(window, true); - X11_UpdateWindowPosition(window, false); - } + data->pending_position = true; - const int target_x = window->last_position_pending ? window->pending.x : window->x; - const int target_y = window->last_position_pending ? window->pending.y : window->y; + // Coordinates after X11_ConstrainPopup() are already in the global space. + position_is_absolute = true; + set_position = true; + } /* Whether XMapRaised focuses the window is based on the window type and it is * wm specific. There isn't much we can do here */ @@ -1452,10 +1459,12 @@ void X11_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window) /* Blocking wait for "MapNotify" event. * We use X11_XIfEvent because pXWindowEvent takes a mask rather than a type, * and XCheckTypedWindowEvent doesn't block */ - if (!(window->flags & SDL_WINDOW_EXTERNAL)) { + if (!(window->flags & SDL_WINDOW_EXTERNAL) && X11_IsDisplayOk(display)) { X11_XIfEvent(display, &event, &isMapNotify, (XPointer)&data->xwindow); } X11_XFlush(display); + set_position = data->pending_position || + (!(window->flags & SDL_WINDOW_BORDERLESS) && !window->undefined_x && !window->undefined_y); } if (!data->videodata->net_wm) { @@ -1475,33 +1484,38 @@ void X11_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window) X11_GetBorderValues(data); } - /* Some window managers can send garbage coordinates while mapping the window, and need the position sent again - * after mapping or the window may not be positioned properly. - * - * Don't emit size and position events during the initial configure events, they will be sent afterwards, when the - * final coordinates are available to avoid sending garbage values. + if (set_position) { + // Apply the window position, accounting for offsets due to the borders appearing. + const int tx = data->pending_position ? window->pending.x : window->x; + const int ty = data->pending_position ? window->pending.y : window->y; + int x, y; + if (position_is_absolute) { + x = tx; + y = ty; + } else { + SDL_RelativeToGlobalForWindow(window, + tx - data->border_left, ty - data->border_top, + &x, &y); + } + data->pending_position = false; + X11_XMoveWindow(display, data->xwindow, x, y); + } + + /* Some window managers can send garbage coordinates while mapping the window, so don't emit size and position + * events during the initial configure events. */ - data->disable_size_position_events = true; + data->size_move_event_flags = X11_SIZE_MOVE_EVENTS_DISABLE; X11_XSync(display, False); X11_PumpEvents(_this); + data->size_move_event_flags = 0; // If a configure event was received (type is non-zero), send the final window size and coordinates. if (data->last_xconfigure.type) { - int x = data->last_xconfigure.x; - int y = data->last_xconfigure.y; - SDL_GlobalToRelativeForWindow(data->window, x, y, &x, &y); - - // If the borders appeared, this happened automatically in the event system, otherwise, set the position now. - if (data->disable_size_position_events && (target_x != x || target_y != y)) { - data->pending_operation = X11_PENDING_OP_MOVE; - X11_XMoveWindow(display, data->xwindow, target_x, target_y); - } - + int x, y; + SDL_GlobalToRelativeForWindow(data->window, data->last_xconfigure.x, data->last_xconfigure.y, &x, &y); SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, data->last_xconfigure.width, data->last_xconfigure.height); SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_MOVED, x, y); } - - data->disable_size_position_events = false; } void X11_HideWindow(SDL_VideoDevice *_this, SDL_Window *window) @@ -1515,7 +1529,7 @@ void X11_HideWindow(SDL_VideoDevice *_this, SDL_Window *window) if (X11_IsWindowMapped(_this, window)) { X11_XWithdrawWindow(display, data->xwindow, screen); // Blocking wait for "UnmapNotify" event - if (!(window->flags & SDL_WINDOW_EXTERNAL)) { + if (!(window->flags & SDL_WINDOW_EXTERNAL) && X11_IsDisplayOk(display)) { X11_XIfEvent(display, &event, &isUnmapNotify, (XPointer)&data->xwindow); } X11_XFlush(display); @@ -1890,7 +1904,7 @@ void *X11_GetWindowICCProfile(SDL_VideoDevice *_this, SDL_Window *window, size_t icc_profile_atom = X11_XInternAtom(display, icc_atom_string, True); if (icc_profile_atom == None) { - SDL_SetError("Screen is not calibrated.\n"); + SDL_SetError("Screen is not calibrated."); return NULL; } @@ -1899,7 +1913,7 @@ void *X11_GetWindowICCProfile(SDL_VideoDevice *_this, SDL_Window *window, size_t real_nitems = atomProp.count; icc_profile_data = atomProp.data; if (real_format == None) { - SDL_SetError("Screen is not calibrated.\n"); + SDL_SetError("Screen is not calibrated."); return NULL; } diff --git a/libs/SDL3/src/video/x11/SDL_x11window.h b/libs/SDL3/src/video/x11/SDL_x11window.h index 16936033..f1a73ab5 100644 --- a/libs/SDL3/src/video/x11/SDL_x11window.h +++ b/libs/SDL3/src/video/x11/SDL_x11window.h @@ -103,10 +103,15 @@ struct SDL_WindowData X11_PENDING_OP_RESIZE = 0x20 } pending_operation; + enum + { + X11_SIZE_MOVE_EVENTS_DISABLE = 0x01, // Events are completely disabled. + X11_SIZE_MOVE_EVENTS_WAIT_FOR_BORDERS = 0x02, // Events are disabled until a _NET_FRAME_EXTENTS event arrives. + } size_move_event_flags; + bool pending_size; bool pending_position; bool window_was_maximized; - bool disable_size_position_events; bool previous_borders_nonzero; bool toggle_borders; bool fullscreen_borders_forced_on; diff --git a/libs/SDL3/src/video/x11/SDL_x11xinput2.c b/libs/SDL3/src/video/x11/SDL_x11xinput2.c index 32a62dd1..afe4a7c8 100644 --- a/libs/SDL3/src/video/x11/SDL_x11xinput2.c +++ b/libs/SDL3/src/video/x11/SDL_x11xinput2.c @@ -129,6 +129,11 @@ bool X11_InitXinput2(SDL_VideoDevice *_this) unsigned char mask[4] = { 0, 0, 0, 0 }; int event, err; + /* XInput2 is required for relative mouse mode, so you probably want to leave this enabled */ + if (!SDL_GetHintBoolean("SDL_VIDEO_X11_XINPUT2", true)) { + return false; + } + /* * Initialize XInput 2 * According to http://who-t.blogspot.com/2009/05/xi2-recipes-part-1.html its better @@ -279,7 +284,7 @@ static SDL_XInput2DeviceInfo *xinput2_get_device_info(SDL_VideoData *videodata, void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie) { #ifdef SDL_VIDEO_DRIVER_X11_XINPUT2 - SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; + SDL_VideoData *videodata = _this->internal; if (cookie->extension != xinput2_opcode) { return; @@ -550,10 +555,10 @@ bool X11_Xinput2IsInitialized(void) bool X11_Xinput2SelectMouseAndKeyboard(SDL_VideoDevice *_this, SDL_Window *window) { - SDL_WindowData *windowdata = (SDL_WindowData *)window->internal; + SDL_WindowData *windowdata = window->internal; #ifdef SDL_VIDEO_DRIVER_X11_XINPUT2 - const SDL_VideoData *data = (SDL_VideoData *)_this->internal; + const SDL_VideoData *data = _this->internal; if (X11_Xinput2IsInitialized()) { XIEventMask eventmask; @@ -584,7 +589,7 @@ bool X11_Xinput2SelectMouseAndKeyboard(SDL_VideoDevice *_this, SDL_Window *windo XISetMask(mask, XI_PropertyEvent); // E.g., when swapping tablet pens if (X11_XISelectEvents(data->display, windowdata->xwindow, &eventmask, 1) != Success) { - SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Could not enable XInput2 event handling\n"); + SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Could not enable XInput2 event handling"); windowdata->xinput2_keyboard_enabled = false; windowdata->xinput2_mouse_enabled = false; } diff --git a/libs/SDL3/src/video/x11/SDL_x11xsync.c b/libs/SDL3/src/video/x11/SDL_x11xsync.c index 5981f6f1..5310d671 100644 --- a/libs/SDL3/src/video/x11/SDL_x11xsync.c +++ b/libs/SDL3/src/video/x11/SDL_x11xsync.c @@ -42,7 +42,7 @@ static bool xsync_version_atleast(const int version, const int wantmajor, const void X11_InitXsync(SDL_VideoDevice *_this) { - SDL_VideoData *data = (SDL_VideoData *) _this->internal; + SDL_VideoData *data = _this->internal; int version = 0; int event, error; @@ -70,7 +70,7 @@ int X11_XsyncIsInitialized(void) int X11_InitResizeSync(SDL_Window *window) { SDL_assert(window != NULL); - SDL_WindowData *data = (SDL_WindowData *) window->internal; + SDL_WindowData *data = window->internal; Display *display = data->videodata->display; Atom counter_prop = data->videodata->atoms._NET_WM_SYNC_REQUEST_COUNTER; XSyncCounter counter; @@ -99,7 +99,7 @@ int X11_InitResizeSync(SDL_Window *window) void X11_TermResizeSync(SDL_Window *window) { - SDL_WindowData *data = (SDL_WindowData *) window->internal; + SDL_WindowData *data = window->internal; Display *display = data->videodata->display; Atom counter_prop = data->videodata->atoms._NET_WM_SYNC_REQUEST_COUNTER; XSyncCounter counter = data->resize_counter; @@ -112,7 +112,7 @@ void X11_TermResizeSync(SDL_Window *window) void X11_HandleSyncRequest(SDL_Window *window, XClientMessageEvent *event) { - SDL_WindowData *data = (SDL_WindowData *) window->internal; + SDL_WindowData *data = window->internal; data->resize_id.lo = event->data.l[2]; data->resize_id.hi = event->data.l[3]; @@ -121,7 +121,7 @@ void X11_HandleSyncRequest(SDL_Window *window, XClientMessageEvent *event) void X11_HandleConfigure(SDL_Window *window, XConfigureEvent *event) { - SDL_WindowData *data = (SDL_WindowData *) window->internal; + SDL_WindowData *data = window->internal; if (data->resize_id.lo || data->resize_id.hi) { data->resize_in_progress = true; @@ -130,7 +130,7 @@ void X11_HandleConfigure(SDL_Window *window, XConfigureEvent *event) void X11_HandlePresent(SDL_Window *window) { - SDL_WindowData *data = (SDL_WindowData *) window->internal; + SDL_WindowData *data = window->internal; Display *display = data->videodata->display; XSyncCounter counter = data->resize_counter; diff --git a/libs/SDL3/test/CMakeLists.txt b/libs/SDL3/test/CMakeLists.txt index 5ac19672..3be04e21 100644 --- a/libs/SDL3/test/CMakeLists.txt +++ b/libs/SDL3/test/CMakeLists.txt @@ -354,11 +354,7 @@ elseif(IOS OR TVOS) find_library(GLES_LIB OpenGLES REQUIRED) target_link_libraries(testgles PRIVATE "${GLES_LIB}") endif() -check_include_file("GLES2/gl2platform.h" HAVE_GLES2_GL2PLATFORM_H) -if(HAVE_GLES2_GL2PLATFORM_H OR (TARGET SDL3-static OR SDL3-shared)) - add_sdl_test_executable(testgles2 SOURCES testgles2.c) - add_sdl_test_executable(testgles2_sdf NEEDS_RESOURCES TESTUTILS SOURCES testgles2_sdf.c) -endif() +add_sdl_test_executable(testgles2 SOURCES testgles2.c) add_sdl_test_executable(testhaptic SOURCES testhaptic.c) add_sdl_test_executable(testhotplug SOURCES testhotplug.c) add_sdl_test_executable(testpen SOURCES testpen.c) diff --git a/libs/SDL3/test/android/cmake/AndroidManifest.xml.cmake b/libs/SDL3/test/android/cmake/AndroidManifest.xml.cmake index a9fc3d56..06d87af9 100644 --- a/libs/SDL3/test/android/cmake/AndroidManifest.xml.cmake +++ b/libs/SDL3/test/android/cmake/AndroidManifest.xml.cmake @@ -43,8 +43,8 @@ android:roundIcon="@mipmap/sdl-test_round" android:label="@string/label" android:supportsRtl="true" - android:hardwareAccelerated="true" - tools:targetApi="31"> + android:theme="@style/AppTheme" + android:hardwareAccelerated="true"> + + + + diff --git a/libs/SDL3/test/checkkeys.c b/libs/SDL3/test/checkkeys.c index 67954923..ab7df8ee 100644 --- a/libs/SDL3/test/checkkeys.c +++ b/libs/SDL3/test/checkkeys.c @@ -185,7 +185,7 @@ static void PrintModifierState(void) left = sizeof(message); print_modifiers(&spot, &left, SDL_GetModState()); - SDL_Log("Initial state:%s\n", message); + SDL_Log("Initial state:%s", message); } static void PrintKey(SDL_KeyboardEvent *event) @@ -218,7 +218,7 @@ static void PrintKey(SDL_KeyboardEvent *event) if (event->repeat) { print_string(&spot, &left, " (repeat)"); } - SDL_Log("%s\n", message); + SDL_Log("%s", message); } static void PrintText(const char *eventtype, const char *text) @@ -231,7 +231,7 @@ static void PrintText(const char *eventtype, const char *text) size_t length = SDL_strlen(expanded); (void)SDL_snprintf(expanded + length, sizeof(expanded) - length, "\\x%.2x", (unsigned char)*spot); } - SDL_Log("%s Text (%s): \"%s%s\"\n", eventtype, expanded, *text == '"' ? "\\" : "", text); + SDL_Log("%s Text (%s): \"%s%s\"", eventtype, expanded, *text == '"' ? "\\" : "", text); } static void CountKeysDown(void) @@ -244,7 +244,7 @@ static void CountKeysDown(void) ++count; } } - SDL_Log("Keys down: %d\n", count); + SDL_Log("Keys down: %d", count); } static void DrawCursor(int i) @@ -373,10 +373,10 @@ static void loop(void) { SDL_Window *window = SDL_GetWindowFromEvent(&event); if (SDL_TextInputActive(window)) { - SDL_Log("Stopping text input for window %" SDL_PRIu32 "\n", event.tfinger.windowID); + SDL_Log("Stopping text input for window %" SDL_PRIu32, event.tfinger.windowID); SDL_StopTextInput(window); } else { - SDL_Log("Starting text input for window %" SDL_PRIu32 "\n", event.tfinger.windowID); + SDL_Log("Starting text input for window %" SDL_PRIu32, event.tfinger.windowID); SDL_StartTextInput(window); } break; @@ -385,16 +385,16 @@ static void loop(void) if (event.button.button == SDL_BUTTON_RIGHT) { SDL_Window *window = SDL_GetWindowFromEvent(&event); if (SDL_TextInputActive(window)) { - SDL_Log("Stopping text input for window %" SDL_PRIu32 "\n", event.button.windowID); + SDL_Log("Stopping text input for window %" SDL_PRIu32, event.button.windowID); SDL_StopTextInput(window); } else { - SDL_Log("Starting text input for window %" SDL_PRIu32 "\n", event.button.windowID); + SDL_Log("Starting text input for window %" SDL_PRIu32, event.button.windowID); SDL_StartTextInput(window); } } break; case SDL_EVENT_KEYMAP_CHANGED: - SDL_Log("Keymap changed!\n"); + SDL_Log("Keymap changed!"); break; case SDL_EVENT_QUIT: done = 1; @@ -466,13 +466,13 @@ int main(int argc, char *argv[]) /* Initialize SDL */ if (!SDLTest_CommonInit(state)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError()); return 1; } windowstates = (TextWindowState *)SDL_calloc(state->num_windows, sizeof(*windowstates)); if (!windowstates) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't allocate text windows: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't allocate text windows: %s", SDL_GetError()); goto done; } diff --git a/libs/SDL3/test/childprocess.c b/libs/SDL3/test/childprocess.c index 333fc3c9..772d86d7 100644 --- a/libs/SDL3/test/childprocess.c +++ b/libs/SDL3/test/childprocess.c @@ -142,7 +142,7 @@ int main(int argc, char *argv[]) { #else SDL_strlcpy(error, strerror(errno), sizeof(error)); #endif - SDL_Log("Error reading from stdin: %s\n", error); + SDL_Log("Error reading from stdin: %s", error); } break; } diff --git a/libs/SDL3/test/emscripten/driver.py b/libs/SDL3/test/emscripten/driver.py index 9735e95b..ee91610d 100644 --- a/libs/SDL3/test/emscripten/driver.py +++ b/libs/SDL3/test/emscripten/driver.py @@ -32,6 +32,10 @@ class SDLSeleniumTestDriver: self.failed_messages: list[str] = [] self.return_code = None + options = [ + "--headless", + ] + driver_contructor = None match browser: case "firefox": @@ -44,12 +48,9 @@ class SDLSeleniumTestDriver: driver_options = webdriver.ChromeOptions() if self.chrome_binary: driver_options.binary_location = self.chrome_binary + options.append("--no-sandbox") if driver_contructor is None: raise ValueError(f"Invalid {browser=}") - - options = [ - "--headless", - ] for o in options: driver_options.add_argument(o) logger.debug("About to create driver") diff --git a/libs/SDL3/test/loopwave.c b/libs/SDL3/test/loopwave.c index 901abaad..8a2d7a0e 100644 --- a/libs/SDL3/test/loopwave.c +++ b/libs/SDL3/test/loopwave.c @@ -78,20 +78,20 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) /* Load the SDL library */ if (!SDL_Init(SDL_INIT_AUDIO | SDL_INIT_EVENTS)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError()); return SDL_APP_FAILURE; } filename = GetResourceFilename(filename, "sample.wav"); if (!filename) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s", SDL_GetError()); return SDL_APP_FAILURE; } /* Load the wave file into memory */ if (!SDL_LoadWAV(filename, &wave.spec, &wave.sound, &wave.soundlen)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s\n", filename, SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s", filename, SDL_GetError()); SDL_free(filename); return SDL_APP_FAILURE; } @@ -104,11 +104,11 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) SDL_Log("%i: %s", i, SDL_GetAudioDriver(i)); } - SDL_Log("Using audio driver: %s\n", SDL_GetCurrentAudioDriver()); + SDL_Log("Using audio driver: %s", SDL_GetCurrentAudioDriver()); stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &wave.spec, NULL, NULL); if (!stream) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create audio stream: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create audio stream: %s", SDL_GetError()); return SDL_APP_FAILURE; } diff --git a/libs/SDL3/test/testatomic.c b/libs/SDL3/test/testatomic.c index 52d3fd9a..37695349 100644 --- a/libs/SDL3/test/testatomic.c +++ b/libs/SDL3/test/testatomic.c @@ -40,39 +40,43 @@ static void RunBasicTest(void) SDL_AtomicInt v; bool tfret = false; - SDL_Log("\nspin lock---------------------------------------\n\n"); + SDL_Log("%s", ""); + SDL_Log("spin lock---------------------------------------"); + SDL_Log("%s", ""); SDL_LockSpinlock(&lock); - SDL_Log("AtomicLock lock=%d\n", lock); + SDL_Log("AtomicLock lock=%d", lock); SDL_UnlockSpinlock(&lock); - SDL_Log("AtomicUnlock lock=%d\n", lock); + SDL_Log("AtomicUnlock lock=%d", lock); - SDL_Log("\natomic -----------------------------------------\n\n"); + SDL_Log("%s", ""); + SDL_Log("atomic -----------------------------------------"); + SDL_Log("%s", ""); SDL_SetAtomicInt(&v, 0); tfret = SDL_SetAtomicInt(&v, 10) == 0; - SDL_Log("AtomicSet(10) tfret=%s val=%d\n", tf(tfret), SDL_GetAtomicInt(&v)); + SDL_Log("AtomicSet(10) tfret=%s val=%d", tf(tfret), SDL_GetAtomicInt(&v)); tfret = SDL_AddAtomicInt(&v, 10) == 10; - SDL_Log("AtomicAdd(10) tfret=%s val=%d\n", tf(tfret), SDL_GetAtomicInt(&v)); + SDL_Log("AtomicAdd(10) tfret=%s val=%d", tf(tfret), SDL_GetAtomicInt(&v)); SDL_SetAtomicInt(&v, 0); SDL_AtomicIncRef(&v); tfret = (SDL_GetAtomicInt(&v) == 1); - SDL_Log("AtomicIncRef() tfret=%s val=%d\n", tf(tfret), SDL_GetAtomicInt(&v)); + SDL_Log("AtomicIncRef() tfret=%s val=%d", tf(tfret), SDL_GetAtomicInt(&v)); SDL_AtomicIncRef(&v); tfret = (SDL_GetAtomicInt(&v) == 2); - SDL_Log("AtomicIncRef() tfret=%s val=%d\n", tf(tfret), SDL_GetAtomicInt(&v)); + SDL_Log("AtomicIncRef() tfret=%s val=%d", tf(tfret), SDL_GetAtomicInt(&v)); tfret = (SDL_AtomicDecRef(&v) == false); - SDL_Log("AtomicDecRef() tfret=%s val=%d\n", tf(tfret), SDL_GetAtomicInt(&v)); + SDL_Log("AtomicDecRef() tfret=%s val=%d", tf(tfret), SDL_GetAtomicInt(&v)); tfret = (SDL_AtomicDecRef(&v) == true); - SDL_Log("AtomicDecRef() tfret=%s val=%d\n", tf(tfret), SDL_GetAtomicInt(&v)); + SDL_Log("AtomicDecRef() tfret=%s val=%d", tf(tfret), SDL_GetAtomicInt(&v)); SDL_SetAtomicInt(&v, 10); tfret = (SDL_CompareAndSwapAtomicInt(&v, 0, 20) == false); - SDL_Log("AtomicCAS() tfret=%s val=%d\n", tf(tfret), SDL_GetAtomicInt(&v)); + SDL_Log("AtomicCAS() tfret=%s val=%d", tf(tfret), SDL_GetAtomicInt(&v)); value = SDL_GetAtomicInt(&v); tfret = (SDL_CompareAndSwapAtomicInt(&v, value, 20) == true); - SDL_Log("AtomicCAS() tfret=%s val=%d\n", tf(tfret), SDL_GetAtomicInt(&v)); + SDL_Log("AtomicCAS() tfret=%s val=%d", tf(tfret), SDL_GetAtomicInt(&v)); } /**************************************************************************/ @@ -115,7 +119,7 @@ static SDL_Semaphore *threadDone; static int SDLCALL adder(void *junk) { unsigned long N = NInter; - SDL_Log("Thread subtracting %d %lu times\n", CountInc, N); + SDL_Log("Thread subtracting %d %lu times", CountInc, N); while (N--) { SDL_AddAtomicInt(&good, -CountInc); bad -= CountInc; @@ -153,7 +157,7 @@ static void runAdder(void) end = SDL_GetTicksNS(); - SDL_Log("Finished in %f sec\n", (end - start) / 1000000000.0); + SDL_Log("Finished in %f sec", (end - start) / 1000000000.0); } static void RunEpicTest(void) @@ -161,28 +165,30 @@ static void RunEpicTest(void) int b; atomicValue v; - SDL_Log("\nepic test---------------------------------------\n\n"); + SDL_Log("%s", ""); + SDL_Log("epic test---------------------------------------"); + SDL_Log("%s", ""); - SDL_Log("Size asserted to be >= 32-bit\n"); + SDL_Log("Size asserted to be >= 32-bit"); SDL_assert(sizeof(atomicValue) >= 4); - SDL_Log("Check static initializer\n"); + SDL_Log("Check static initializer"); v = SDL_GetAtomicInt(&good); SDL_assert(v == 42); SDL_assert(bad == 42); - SDL_Log("Test negative values\n"); + SDL_Log("Test negative values"); SDL_SetAtomicInt(&good, -5); v = SDL_GetAtomicInt(&good); SDL_assert(v == -5); - SDL_Log("Verify maximum value\n"); + SDL_Log("Verify maximum value"); SDL_SetAtomicInt(&good, CountTo); v = SDL_GetAtomicInt(&good); SDL_assert(v == CountTo); - SDL_Log("Test compare and exchange\n"); + SDL_Log("Test compare and exchange"); b = SDL_CompareAndSwapAtomicInt(&good, 500, 43); SDL_assert(!b); /* no swap since CountTo!=500 */ @@ -194,7 +200,7 @@ static void RunEpicTest(void) v = SDL_GetAtomicInt(&good); SDL_assert(v == 44); - SDL_Log("Test Add\n"); + SDL_Log("Test Add"); v = SDL_AddAtomicInt(&good, 1); SDL_assert(v == 44); @@ -206,7 +212,7 @@ static void RunEpicTest(void) v = SDL_GetAtomicInt(&good); SDL_assert(v == 55); - SDL_Log("Test Add (Negative values)\n"); + SDL_Log("Test Add (Negative values)"); v = SDL_AddAtomicInt(&good, -20); SDL_assert(v == 55); @@ -223,7 +229,7 @@ static void RunEpicTest(void) v = SDL_GetAtomicInt(&good); SDL_assert(v == 15); - SDL_Log("Reset before count down test\n"); + SDL_Log("Reset before count down test"); SDL_SetAtomicInt(&good, CountTo); v = SDL_GetAtomicInt(&good); SDL_assert(v == CountTo); @@ -231,11 +237,11 @@ static void RunEpicTest(void) bad = CountTo; SDL_assert(bad == CountTo); - SDL_Log("Counting down from %d, Expect %d remaining\n", CountTo, Expect); + SDL_Log("Counting down from %d, Expect %d remaining", CountTo, Expect); runAdder(); v = SDL_GetAtomicInt(&good); - SDL_Log("Atomic %d Non-Atomic %d\n", v, bad); + SDL_Log("Atomic %d Non-Atomic %d", v, bad); SDL_assert(v == Expect); /* We can't guarantee that bad != Expect, this would happen on a single core system, for example. */ /*SDL_assert(bad != Expect);*/ @@ -431,7 +437,7 @@ static bool EnqueueEvent_Mutex(SDL_EventQueue *queue, const SDL_Event *event) } else if (delta < 0) { /* We ran into an old queue entry, which means it still needs to be dequeued */ } else { - SDL_Log("ERROR: mutex failed!\n"); + SDL_Log("ERROR: mutex failed!"); } SDL_UnlockMutex(queue->mutex); @@ -464,7 +470,7 @@ static bool DequeueEvent_Mutex(SDL_EventQueue *queue, SDL_Event *event) } else if (delta < 0) { /* We ran into an old queue entry, which means we've hit empty */ } else { - SDL_Log("ERROR: mutex failed!\n"); + SDL_Log("ERROR: mutex failed!"); } SDL_UnlockMutex(queue->mutex); @@ -597,8 +603,10 @@ static void RunFIFOTest(bool lock_free) char textBuffer[1024]; size_t len; - SDL_Log("\nFIFO test---------------------------------------\n\n"); - SDL_Log("Mode: %s\n", lock_free ? "LockFree" : "Mutex"); + SDL_Log("%s", ""); + SDL_Log("FIFO test---------------------------------------"); + SDL_Log("%s", ""); + SDL_Log("Mode: %s", lock_free ? "LockFree" : "Mutex"); SDL_memset(&queue, 0xff, sizeof(queue)); @@ -617,7 +625,7 @@ static void RunFIFOTest(bool lock_free) #endif /* Start the readers first */ - SDL_Log("Starting %d readers\n", NUM_READERS); + SDL_Log("Starting %d readers", NUM_READERS); SDL_zeroa(readerData); for (i = 0; i < NUM_READERS; ++i) { char name[64]; @@ -628,7 +636,7 @@ static void RunFIFOTest(bool lock_free) } /* Start up the writers */ - SDL_Log("Starting %d writers\n", NUM_WRITERS); + SDL_Log("Starting %d writers", NUM_WRITERS); SDL_zeroa(writerData); for (i = 0; i < NUM_WRITERS; ++i) { char name[64]; @@ -663,16 +671,16 @@ static void RunFIFOTest(bool lock_free) SDL_DestroyMutex(queue.mutex); } - SDL_Log("Finished in %f sec\n", (end - start) / 1000000000.0); + SDL_Log("Finished in %f sec", (end - start) / 1000000000.0); - SDL_Log("\n"); + SDL_Log("%s", ""); for (i = 0; i < NUM_WRITERS; ++i) { - SDL_Log("Writer %d wrote %d events, had %d waits\n", i, EVENTS_PER_WRITER, writerData[i].waits); + SDL_Log("Writer %d wrote %d events, had %d waits", i, EVENTS_PER_WRITER, writerData[i].waits); } - SDL_Log("Writers wrote %d total events\n", NUM_WRITERS * EVENTS_PER_WRITER); + SDL_Log("Writers wrote %d total events", NUM_WRITERS * EVENTS_PER_WRITER); /* Print a breakdown of which readers read messages from which writer */ - SDL_Log("\n"); + SDL_Log("%s", ""); grand_total = 0; for (i = 0; i < NUM_READERS; ++i) { int total = 0; @@ -680,7 +688,7 @@ static void RunFIFOTest(bool lock_free) total += readerData[i].counters[j]; } grand_total += total; - SDL_Log("Reader %d read %d events, had %d waits\n", i, total, readerData[i].waits); + SDL_Log("Reader %d read %d events, had %d waits", i, total, readerData[i].waits); (void)SDL_snprintf(textBuffer, sizeof(textBuffer), " { "); for (j = 0; j < NUM_WRITERS; ++j) { if (j > 0) { @@ -694,7 +702,7 @@ static void RunFIFOTest(bool lock_free) (void)SDL_snprintf(textBuffer + len, sizeof(textBuffer) - len, " }\n"); SDL_Log("%s", textBuffer); } - SDL_Log("Readers read %d total events\n", grand_total); + SDL_Log("Readers read %d total events", grand_total); } /* End FIFO test */ diff --git a/libs/SDL3/test/testaudio.c b/libs/SDL3/test/testaudio.c index c39861f3..8abb3b2d 100644 --- a/libs/SDL3/test/testaudio.c +++ b/libs/SDL3/test/testaudio.c @@ -300,6 +300,7 @@ static void DestroyThing(Thing *thing) } if (thing->prev) { + SDL_assert(thing != things); thing->prev->next = thing->next; } else { SDL_assert(thing == things); diff --git a/libs/SDL3/test/testaudiohotplug.c b/libs/SDL3/test/testaudiohotplug.c index 9b77e8f8..00b851e6 100644 --- a/libs/SDL3/test/testaudiohotplug.c +++ b/libs/SDL3/test/testaudiohotplug.c @@ -69,7 +69,7 @@ static void iteration(void) done = 1; } } else if (e.type == SDL_EVENT_AUDIO_DEVICE_ADDED) { - const SDL_AudioDeviceID which = (SDL_AudioDeviceID) e.adevice.which; + const SDL_AudioDeviceID which = e.adevice.which; const bool recording = e.adevice.recording ? true : false; const char *name = SDL_GetAudioDeviceName(which); if (name) { @@ -84,7 +84,7 @@ static void iteration(void) if (!stream) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create/bind an audio stream to %u ('%s'): %s", (unsigned int) which, name, SDL_GetError()); } else { - SDL_Log("Opened '%s' as %u\n", name, (unsigned int) which); + SDL_Log("Opened '%s' as %u", name, (unsigned int) which); /* !!! FIXME: laziness, this used to loop the audio, but we'll just play it once for now on each connect. */ SDL_PutAudioStreamData(stream, sound, soundlen); SDL_FlushAudioStream(stream); @@ -93,8 +93,8 @@ static void iteration(void) } } } else if (e.type == SDL_EVENT_AUDIO_DEVICE_REMOVED) { - dev = (SDL_AudioDeviceID)e.adevice.which; - SDL_Log("%s device %u removed.\n", devtypestr(e.adevice.recording), (unsigned int)dev); + dev = e.adevice.which; + SDL_Log("%s device %u removed.", devtypestr(e.adevice.recording), (unsigned int)dev); /* !!! FIXME: we need to keep track of our streams and destroy them here. */ } } @@ -144,14 +144,14 @@ int main(int argc, char *argv[]) /* Load the SDL library */ if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError()); return 1; } /* Some targets (Mac CoreAudio) need an event queue for audio hotplug, so make and immediately hide a window. */ window = SDL_CreateWindow("testaudiohotplug", 640, 480, 0); if (!window) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateWindow failed: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateWindow failed: %s", SDL_GetError()); quit(1); } SDL_MinimizeWindow(window); @@ -159,13 +159,13 @@ int main(int argc, char *argv[]) filename = GetResourceFilename(filename, "sample.wav"); if (!filename) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s", SDL_GetError()); quit(1); } /* Load the wave file into memory */ if (!SDL_LoadWAV(filename, &spec, &sound, &soundlen)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s\n", filename, SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s", filename, SDL_GetError()); quit(1); } @@ -187,8 +187,8 @@ int main(int argc, char *argv[]) SDL_Log("%i: %s", i, SDL_GetAudioDriver(i)); } - SDL_Log("Select a driver with the SDL_AUDIO_DRIVER environment variable.\n"); - SDL_Log("Using audio driver: %s\n", SDL_GetCurrentAudioDriver()); + SDL_Log("Select a driver with the SDL_AUDIO_DRIVER environment variable."); + SDL_Log("Using audio driver: %s", SDL_GetCurrentAudioDriver()); #ifdef SDL_PLATFORM_EMSCRIPTEN emscripten_set_main_loop(loop, 0, 1); diff --git a/libs/SDL3/test/testaudioinfo.c b/libs/SDL3/test/testaudioinfo.c index b561fb7f..a9139ec8 100644 --- a/libs/SDL3/test/testaudioinfo.c +++ b/libs/SDL3/test/testaudioinfo.c @@ -23,28 +23,30 @@ print_devices(bool recording) SDL_AudioDeviceID *devices = recording ? SDL_GetAudioRecordingDevices(&n) : SDL_GetAudioPlaybackDevices(&n); if (!devices) { - SDL_Log(" Driver failed to report %s devices: %s\n\n", typestr, SDL_GetError()); + SDL_Log(" Driver failed to report %s devices: %s", typestr, SDL_GetError()); + SDL_Log("%s", ""); } else if (n == 0) { - SDL_Log(" No %s devices found.\n\n", typestr); + SDL_Log(" No %s devices found.", typestr); + SDL_Log("%s", ""); } else { int i; - SDL_Log("Found %d %s device%s:\n", n, typestr, n != 1 ? "s" : ""); + SDL_Log("Found %d %s device%s:", n, typestr, n != 1 ? "s" : ""); for (i = 0; i < n; i++) { const char *name = SDL_GetAudioDeviceName(devices[i]); if (name) { - SDL_Log(" %d: %s\n", i, name); + SDL_Log(" %d: %s", i, name); } else { - SDL_Log(" %d Error: %s\n", i, SDL_GetError()); + SDL_Log(" %d Error: %s", i, SDL_GetError()); } if (SDL_GetAudioDeviceFormat(devices[i], &spec, &frames)) { - SDL_Log(" Sample Rate: %d\n", spec.freq); - SDL_Log(" Channels: %d\n", spec.channels); - SDL_Log(" SDL_AudioFormat: %X\n", spec.format); - SDL_Log(" Buffer Size: %d frames\n", frames); + SDL_Log(" Sample Rate: %d", spec.freq); + SDL_Log(" Channels: %d", spec.channels); + SDL_Log(" SDL_AudioFormat: %X", spec.format); + SDL_Log(" Buffer Size: %d frames", frames); } } - SDL_Log("\n"); + SDL_Log("%s", ""); } SDL_free(devices); } @@ -70,45 +72,47 @@ int main(int argc, char **argv) /* Load the SDL library */ if (!SDL_Init(SDL_INIT_AUDIO)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError()); return 1; } /* Print available audio drivers */ n = SDL_GetNumAudioDrivers(); if (n == 0) { - SDL_Log("No built-in audio drivers\n\n"); + SDL_Log("No built-in audio drivers"); + SDL_Log("%s", ""); } else { - SDL_Log("Built-in audio drivers:\n"); + SDL_Log("Built-in audio drivers:"); for (i = 0; i < n; ++i) { - SDL_Log(" %d: %s\n", i, SDL_GetAudioDriver(i)); + SDL_Log(" %d: %s", i, SDL_GetAudioDriver(i)); } - SDL_Log("Select a driver with the SDL_AUDIO_DRIVER environment variable.\n"); + SDL_Log("Select a driver with the SDL_AUDIO_DRIVER environment variable."); } - SDL_Log("Using audio driver: %s\n\n", SDL_GetCurrentAudioDriver()); + SDL_Log("Using audio driver: %s", SDL_GetCurrentAudioDriver()); + SDL_Log("%s", ""); print_devices(false); print_devices(true); if (SDL_GetAudioDeviceFormat(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, &frames)) { - SDL_Log("Default Playback Device:\n"); - SDL_Log("Sample Rate: %d\n", spec.freq); - SDL_Log("Channels: %d\n", spec.channels); - SDL_Log("SDL_AudioFormat: %X\n", spec.format); - SDL_Log("Buffer Size: %d frames\n", frames); + SDL_Log("Default Playback Device:"); + SDL_Log("Sample Rate: %d", spec.freq); + SDL_Log("Channels: %d", spec.channels); + SDL_Log("SDL_AudioFormat: %X", spec.format); + SDL_Log("Buffer Size: %d frames", frames); } else { - SDL_Log("Error when calling SDL_GetAudioDeviceFormat(default playback): %s\n", SDL_GetError()); + SDL_Log("Error when calling SDL_GetAudioDeviceFormat(default playback): %s", SDL_GetError()); } if (SDL_GetAudioDeviceFormat(SDL_AUDIO_DEVICE_DEFAULT_RECORDING, &spec, &frames)) { - SDL_Log("Default Recording Device:\n"); - SDL_Log("Sample Rate: %d\n", spec.freq); - SDL_Log("Channels: %d\n", spec.channels); - SDL_Log("SDL_AudioFormat: %X\n", spec.format); - SDL_Log("Buffer Size: %d frames\n", frames); + SDL_Log("Default Recording Device:"); + SDL_Log("Sample Rate: %d", spec.freq); + SDL_Log("Channels: %d", spec.channels); + SDL_Log("SDL_AudioFormat: %X", spec.format); + SDL_Log("Buffer Size: %d frames", frames); } else { - SDL_Log("Error when calling SDL_GetAudioDeviceFormat(default recording): %s\n", SDL_GetError()); + SDL_Log("Error when calling SDL_GetAudioDeviceFormat(default recording): %s", SDL_GetError()); } SDL_Quit(); diff --git a/libs/SDL3/test/testaudiorecording.c b/libs/SDL3/test/testaudiorecording.c index 88cbc73d..2e33da80 100644 --- a/libs/SDL3/test/testaudiorecording.c +++ b/libs/SDL3/test/testaudiorecording.c @@ -62,31 +62,31 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char **argv) /* Load the SDL library */ if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError()); return SDL_APP_SUCCESS; } if (!SDL_CreateWindowAndRenderer("testaudiorecording", 320, 240, 0, &window, &renderer)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create SDL window and renderer: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create SDL window and renderer: %s", SDL_GetError()); return SDL_APP_SUCCESS; } SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); SDL_RenderClear(renderer); SDL_RenderPresent(renderer); - SDL_Log("Using audio driver: %s\n", SDL_GetCurrentAudioDriver()); + SDL_Log("Using audio driver: %s", SDL_GetCurrentAudioDriver()); devices = SDL_GetAudioRecordingDevices(NULL); for (i = 0; devices[i] != 0; i++) { const char *name = SDL_GetAudioDeviceName(devices[i]); - SDL_Log(" Recording device #%d: '%s'\n", i, name); + SDL_Log(" Recording device #%d: '%s'", i, name); if (devname && (SDL_strcmp(devname, name) == 0)) { want_device = devices[i]; } } if (devname && (want_device == SDL_AUDIO_DEVICE_DEFAULT_RECORDING)) { - SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Didn't see a recording device named '%s', using the system default instead.\n", devname); + SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Didn't see a recording device named '%s', using the system default instead.", devname); devname = NULL; } @@ -96,10 +96,10 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char **argv) open your recording devices second in case you land in those bizarre circumstances. */ - SDL_Log("Opening default playback device...\n"); + SDL_Log("Opening default playback device..."); device = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, NULL); if (!device) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open an audio device for playback: %s!\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open an audio device for playback: %s!", SDL_GetError()); SDL_free(devices); return SDL_APP_FAILURE; } @@ -107,23 +107,23 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char **argv) SDL_GetAudioDeviceFormat(device, &outspec, NULL); stream_out = SDL_CreateAudioStream(&outspec, &outspec); if (!stream_out) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create an audio stream for playback: %s!\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create an audio stream for playback: %s!", SDL_GetError()); SDL_free(devices); return SDL_APP_FAILURE; } else if (!SDL_BindAudioStream(device, stream_out)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't bind an audio stream for playback: %s!\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't bind an audio stream for playback: %s!", SDL_GetError()); SDL_free(devices); return SDL_APP_FAILURE; } - SDL_Log("Opening recording device %s%s%s...\n", + SDL_Log("Opening recording device %s%s%s...", devname ? "'" : "", devname ? devname : "[[default]]", devname ? "'" : ""); device = SDL_OpenAudioDevice(want_device, NULL); if (!device) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open an audio device for recording: %s!\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open an audio device for recording: %s!", SDL_GetError()); SDL_free(devices); return SDL_APP_FAILURE; } @@ -132,16 +132,16 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char **argv) SDL_GetAudioDeviceFormat(device, &inspec, NULL); stream_in = SDL_CreateAudioStream(&inspec, &inspec); if (!stream_in) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create an audio stream for recording: %s!\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create an audio stream for recording: %s!", SDL_GetError()); return SDL_APP_FAILURE; } else if (!SDL_BindAudioStream(device, stream_in)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't bind an audio stream for recording: %s!\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't bind an audio stream for recording: %s!", SDL_GetError()); return SDL_APP_FAILURE; } SDL_SetAudioStreamFormat(stream_in, NULL, &outspec); /* make sure we output at the playback format. */ - SDL_Log("Ready! Hold down mouse or finger to record!\n"); + SDL_Log("Ready! Hold down mouse or finger to record!"); return SDL_APP_CONTINUE; } @@ -185,10 +185,10 @@ SDL_AppResult SDL_AppIterate(void *appstate) Uint8 buf[1024]; const int br = SDL_GetAudioStreamData(stream_in, buf, sizeof(buf)); if (br < 0) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to read from input audio stream: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to read from input audio stream: %s", SDL_GetError()); return SDL_APP_FAILURE; } else if (!SDL_PutAudioStreamData(stream_out, buf, br)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to write to output audio stream: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to write to output audio stream: %s", SDL_GetError()); return SDL_APP_FAILURE; } } @@ -198,7 +198,7 @@ SDL_AppResult SDL_AppIterate(void *appstate) void SDL_AppQuit(void *appstate, SDL_AppResult result) { - SDL_Log("Shutting down.\n"); + SDL_Log("Shutting down."); const SDL_AudioDeviceID devid_in = SDL_GetAudioStreamDevice(stream_in); const SDL_AudioDeviceID devid_out = SDL_GetAudioStreamDevice(stream_out); SDL_CloseAudioDevice(devid_in); /* !!! FIXME: use SDL_OpenAudioDeviceStream instead so we can dump this. */ diff --git a/libs/SDL3/test/testaudiostreamdynamicresample.c b/libs/SDL3/test/testaudiostreamdynamicresample.c index 0dbde731..9ee2c841 100644 --- a/libs/SDL3/test/testaudiostreamdynamicresample.c +++ b/libs/SDL3/test/testaudiostreamdynamicresample.c @@ -396,7 +396,7 @@ int main(int argc, char *argv[]) /* Load the SDL library */ if (!SDLTest_CommonInit(state)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError()); return 1; } diff --git a/libs/SDL3/test/testautomation_audio.c b/libs/SDL3/test/testautomation_audio.c index 9d03338d..7c141b3a 100644 --- a/libs/SDL3/test/testautomation_audio.c +++ b/libs/SDL3/test/testautomation_audio.c @@ -809,6 +809,7 @@ static int SDLCALL audio_convertAudio(void *arg) src_buf = (Uint8 *)SDL_malloc(src_len); SDLTest_AssertCheck(src_buf != NULL, "Check src data buffer to convert is not NULL"); if (src_buf == NULL) { + SDL_DestroyAudioStream(stream); return TEST_ABORTED; } @@ -819,6 +820,8 @@ static int SDLCALL audio_convertAudio(void *arg) dst_buf = (Uint8 *)SDL_malloc(dst_len); SDLTest_AssertCheck(dst_buf != NULL, "Check dst data buffer to convert is not NULL"); if (dst_buf == NULL) { + SDL_DestroyAudioStream(stream); + SDL_free(src_buf); return TEST_ABORTED; } @@ -828,6 +831,9 @@ static int SDLCALL audio_convertAudio(void *arg) /* Run the audio converter */ if (!SDL_PutAudioStreamData(stream, src_buf, src_len) || !SDL_FlushAudioStream(stream)) { + SDL_DestroyAudioStream(stream); + SDL_free(src_buf); + SDL_free(dst_buf); return TEST_ABORTED; } @@ -837,6 +843,9 @@ static int SDLCALL audio_convertAudio(void *arg) real_dst_len = SDL_GetAudioStreamData(stream, dst_buf, dst_len); SDLTest_AssertCheck(dst_len == real_dst_len, "Verify result value; expected: %i; got: %i", dst_len, real_dst_len); if (dst_len != real_dst_len) { + SDL_DestroyAudioStream(stream); + SDL_free(src_buf); + SDL_free(dst_buf); return TEST_ABORTED; } @@ -848,6 +857,9 @@ static int SDLCALL audio_convertAudio(void *arg) for (m = 0; m < dst_len; ++m) { if (dst_buf[m] != dst_silence) { SDLTest_LogError("Output buffer is not silent"); + SDL_DestroyAudioStream(stream); + SDL_free(src_buf); + SDL_free(dst_buf); return TEST_ABORTED; } } @@ -1104,6 +1116,7 @@ static int SDLCALL audio_resampleLoss(void *arg) SDLTest_AssertCheck(buf_out != NULL, "Expected output buffer to be created."); if (buf_out == NULL) { SDL_DestroyAudioStream(stream); + SDL_free(buf_in); return TEST_ABORTED; } @@ -1114,6 +1127,7 @@ static int SDLCALL audio_resampleLoss(void *arg) SDL_free(buf_in); if (len_out != len_target) { SDL_DestroyAudioStream(stream); + SDL_free(buf_out); return TEST_ABORTED; } @@ -1130,6 +1144,7 @@ static int SDLCALL audio_resampleLoss(void *arg) sum_squared_value += target * target; } } + SDL_DestroyAudioStream(stream); SDL_free(buf_out); signal_to_noise = 10 * SDL_log10(sum_squared_value / sum_squared_error); /* decibel */ SDLTest_AssertCheck(ISFINITE(sum_squared_value), "Sum of squared target should be finite."); diff --git a/libs/SDL3/test/testautomation_events.c b/libs/SDL3/test/testautomation_events.c index aca6fafb..ed4e684c 100644 --- a/libs/SDL3/test/testautomation_events.c +++ b/libs/SDL3/test/testautomation_events.c @@ -211,48 +211,93 @@ static int SDLCALL events_addDelEventWatchWithUserdata(void *arg) * */ +typedef struct IncrementCounterData_t +{ + Uint32 delay; + int counter; +} IncrementCounterData_t; + static void SDLCALL IncrementCounter(void *userdata) { - int *value = (int *)userdata; - *value = *value + 1; + IncrementCounterData_t *data = (IncrementCounterData_t *)userdata; + ++data->counter; } #ifndef SDL_PLATFORM_EMSCRIPTEN /* Emscripten doesn't have threads */ static int SDLCALL IncrementCounterThread(void *userdata) { + IncrementCounterData_t *data = (IncrementCounterData_t *)userdata; + SDL_Event event; + SDL_assert(!SDL_IsMainThread()); - SDL_RunOnMainThread(IncrementCounter, userdata, false); - SDL_RunOnMainThread(IncrementCounter, userdata, true); + + if (data->delay > 0) { + SDL_Delay(data->delay); + } + + if (!SDL_RunOnMainThread(IncrementCounter, userdata, false)) { + SDLTest_LogError("Couldn't run IncrementCounter asynchronously on main thread: %s", SDL_GetError()); + } + if (!SDL_RunOnMainThread(IncrementCounter, userdata, true)) { + SDLTest_LogError("Couldn't run IncrementCounter synchronously on main thread: %s", SDL_GetError()); + } + + /* Send an event to unblock the main thread, which is waiting in SDL_WaitEvent() */ + event.type = SDL_EVENT_USER; + SDL_PushEvent(&event); + return 0; } #endif /* !SDL_PLATFORM_EMSCRIPTEN */ static int SDLCALL events_mainThreadCallbacks(void *arg) { - int counter = 0; + IncrementCounterData_t data = { 0, 0 }; /* Make sure we're on the main thread */ SDLTest_AssertCheck(SDL_IsMainThread(), "Verify we're on the main thread"); - SDL_RunOnMainThread(IncrementCounter, &counter, true); - SDLTest_AssertCheck(counter == 1, "Incremented counter on main thread, expected 1, got %d", counter); + SDL_RunOnMainThread(IncrementCounter, &data, true); + SDLTest_AssertCheck(data.counter == 1, "Incremented counter on main thread, expected 1, got %d", data.counter); #ifndef SDL_PLATFORM_EMSCRIPTEN /* Emscripten doesn't have threads */ { + SDL_Window *window; SDL_Thread *thread; + SDL_Event event; - thread = SDL_CreateThread(IncrementCounterThread, NULL, &counter); + window = SDL_CreateWindow("test", 0, 0, SDL_WINDOW_HIDDEN); + SDLTest_AssertCheck(window != NULL, "Create window, expected non-NULL, got %p", window); + + /* Flush any pending events */ + SDL_PumpEvents(); + SDL_FlushEvents(SDL_EVENT_FIRST, SDL_EVENT_LAST); + + /* Increment the counter on a thread, waiting for both calls to be queued */ + thread = SDL_CreateThread(IncrementCounterThread, NULL, &data); SDLTest_AssertCheck(thread != NULL, "Create counter thread"); /* Wait for both increment calls to be queued up */ SDL_Delay(100); /* Run the main callbacks */ - while (counter < 3) { - SDL_PumpEvents(); - } + SDL_WaitEvent(&event); + SDLTest_AssertCheck(event.type == SDL_EVENT_USER, "Expected user event (0x%.4x), got 0x%.4x", SDL_EVENT_USER, (int)event.type); SDL_WaitThread(thread, NULL); - SDLTest_AssertCheck(counter == 3, "Incremented counter on main thread, expected 3, got %d", counter); + SDLTest_AssertCheck(data.counter == 3, "Incremented counter on main thread, expected 3, got %d", data.counter); + + /* Try again, but this time delay the calls until we've started waiting for events */ + data.delay = 100; + thread = SDL_CreateThread(IncrementCounterThread, NULL, &data); + SDLTest_AssertCheck(thread != NULL, "Create counter thread"); + + /* Run the main callbacks */ + SDL_WaitEvent(&event); + SDLTest_AssertCheck(event.type == SDL_EVENT_USER, "Expected user event (0x%.4x), got 0x%.4x", SDL_EVENT_USER, (int)event.type); + SDL_WaitThread(thread, NULL); + SDLTest_AssertCheck(data.counter == 5, "Incremented counter on main thread, expected 5, got %d", data.counter); + + SDL_DestroyWindow(window); } #endif /* !SDL_PLATFORM_EMSCRIPTEN */ diff --git a/libs/SDL3/test/testautomation_intrinsics.c b/libs/SDL3/test/testautomation_intrinsics.c index 4b9cb65c..8338d33d 100644 --- a/libs/SDL3/test/testautomation_intrinsics.c +++ b/libs/SDL3/test/testautomation_intrinsics.c @@ -323,6 +323,7 @@ static int SDLCALL intrinsics_selftest(void *arg) size_t size; Uint32 *dest, *a, *b; if (allocate_random_uint_arrays(&dest, &a, &b, &size) < 0) { + free_arrays(dest, a, b); return TEST_ABORTED; } kernel_uints_mul_cpu(dest, a, b, size); @@ -333,6 +334,7 @@ static int SDLCALL intrinsics_selftest(void *arg) size_t size; Uint32 *dest, *a, *b; if (allocate_random_uint_arrays(&dest, &a, &b, &size) < 0) { + free_arrays(dest, a, b); return TEST_ABORTED; } kernel_uints_add_cpu(dest, a, b, size); @@ -343,6 +345,7 @@ static int SDLCALL intrinsics_selftest(void *arg) size_t size; float *dest, *a, *b; if (allocate_random_float_arrays(&dest, &a, &b, &size) < 0) { + free_arrays(dest, a, b); return TEST_ABORTED; } kernel_floats_add_cpu(dest, a, b, size); @@ -353,6 +356,7 @@ static int SDLCALL intrinsics_selftest(void *arg) size_t size; double *dest, *a, *b; if (allocate_random_double_arrays(&dest, &a, &b, &size) < 0) { + free_arrays(dest, a, b); return TEST_ABORTED; } kernel_doubles_add_cpu(dest, a, b, size); @@ -373,6 +377,7 @@ static int SDLCALL intrinsics_testMMX(void *arg) SDLTest_AssertCheck(true, "Test executable uses MMX intrinsics."); if (allocate_random_uint_arrays(&dest, &a, &b, &size) < 0) { + free_arrays(dest, a, b); return TEST_ABORTED; } kernel_uints_add_mmx(dest, a, b, size); @@ -401,6 +406,7 @@ static int SDLCALL intrinsics_testSSE(void *arg) SDLTest_AssertCheck(true, "Test executable uses SSE intrinsics."); if (allocate_random_float_arrays(&dest, &a, &b, &size) < 0) { + free_arrays(dest, a, b); return TEST_ABORTED; } kernel_floats_add_sse(dest, a, b, size); @@ -429,6 +435,7 @@ static int SDLCALL intrinsics_testSSE2(void *arg) SDLTest_AssertCheck(true, "Test executable uses SSE2 intrinsics."); if (allocate_random_double_arrays(&dest, &a, &b, &size) < 0) { + free_arrays(dest, a, b); return TEST_ABORTED; } kernel_doubles_add_sse2(dest, a, b, size); @@ -457,6 +464,7 @@ static int SDLCALL intrinsics_testSSE3(void *arg) SDLTest_AssertCheck(true, "Test executable uses SSE3 intrinsics."); if (allocate_random_uint_arrays(&dest, &a, &b, &size) < 0) { + free_arrays(dest, a, b); return TEST_ABORTED; } kernel_uints_add_sse3(dest, a, b, size); @@ -485,6 +493,7 @@ static int SDLCALL intrinsics_testSSE4_1(void *arg) SDLTest_AssertCheck(true, "Test executable uses SSE4.1 intrinsics."); if (allocate_random_uint_arrays(&dest, &a, &b, &size) < 0) { + free_arrays(dest, a, b); return TEST_ABORTED; } kernel_uints_mul_sse4_1(dest, a, b, size); @@ -548,6 +557,7 @@ static int SDLCALL intrinsics_testAVX(void *arg) SDLTest_AssertCheck(true, "Test executable uses AVX intrinsics."); if (allocate_random_float_arrays(&dest, &a, &b, &size) < 0) { + free_arrays(dest, a, b); return TEST_ABORTED; } kernel_floats_add_avx(dest, a, b, size); @@ -576,6 +586,7 @@ static int SDLCALL intrinsics_testAVX2(void *arg) SDLTest_AssertCheck(true, "Test executable uses AVX2 intrinsics."); if (allocate_random_uint_arrays(&dest, &a, &b, &size) < 0) { + free_arrays(dest, a, b); return TEST_ABORTED; } kernel_uints_add_avx2(dest, a, b, size); @@ -604,6 +615,7 @@ static int SDLCALL intrinsics_testAVX512F(void *arg) SDLTest_AssertCheck(true, "Test executable uses AVX512F intrinsics."); if (allocate_random_float_arrays(&dest, &a, &b, &size) < 0) { + free_arrays(dest, a, b); return TEST_ABORTED; } kernel_floats_add_avx512f(dest, a, b, size); diff --git a/libs/SDL3/test/testautomation_render.c b/libs/SDL3/test/testautomation_render.c index 25572ee0..8310e92a 100644 --- a/libs/SDL3/test/testautomation_render.c +++ b/libs/SDL3/test/testautomation_render.c @@ -1439,8 +1439,8 @@ static int SDLCALL render_testUVWrapping(void *arg) rect.w = (float)tface->w * 2; rect.h = (float)tface->h * 2; - rect.x = (float)(TESTRENDER_SCREEN_W - rect.w) / 2; - rect.y = (float)(TESTRENDER_SCREEN_H - rect.h) / 2; + rect.x = (TESTRENDER_SCREEN_W - rect.w) / 2; + rect.y = (TESTRENDER_SCREEN_H - rect.h) / 2; /* * 0--1 diff --git a/libs/SDL3/test/testautomation_stdlib.c b/libs/SDL3/test/testautomation_stdlib.c index 30735106..bd7e17a5 100644 --- a/libs/SDL3/test/testautomation_stdlib.c +++ b/libs/SDL3/test/testautomation_stdlib.c @@ -731,6 +731,7 @@ static int SDLCALL stdlib_getsetenv(void *arg) #endif #define FMT_PRILLd "%" SDL_PRILLd +#define FMT_PRILLdn "%" SDL_PRILLd "%" SDL_PRILL_PREFIX "n" #define FMT_PRILLu "%" SDL_PRILLu /** @@ -740,11 +741,12 @@ static int SDLCALL stdlib_sscanf(void *arg) { int output; int result; + int length; int expected_output; int expected_result; - short short_output, expected_short_output; - long long_output, expected_long_output; - long long long_long_output, expected_long_long_output; + short short_output, expected_short_output, short_length; + long long_output, expected_long_output, long_length; + long long long_long_output, expected_long_long_output, long_long_length; size_t size_output, expected_size_output; void *ptr_output, *expected_ptr_output; char text[128], text2[128]; @@ -764,43 +766,51 @@ static int SDLCALL stdlib_sscanf(void *arg) SDLTest_AssertCheck(expected_result == result, "Check return value, expected: %i, got: %i", expected_result, result); output = 123; + length = 0; expected_output = 2; expected_result = 1; - result = SDL_sscanf("2", "%i", &output); - SDLTest_AssertPass("Call to SDL_sscanf(\"2\", \"%%i\", &output)"); + result = SDL_sscanf("2", "%i%n", &output, &length); + SDLTest_AssertPass("Call to SDL_sscanf(\"2\", \"%%i%%n\", &output, &length)"); SDLTest_AssertCheck(expected_output == output, "Check output, expected: %i, got: %i", expected_output, output); SDLTest_AssertCheck(expected_result == result, "Check return value, expected: %i, got: %i", expected_result, result); + SDLTest_AssertCheck(length == 1, "Check length, expected: 1, got: %i", length); output = 123; + length = 0; expected_output = 0xa; expected_result = 1; - result = SDL_sscanf("aa", "%1x", &output); - SDLTest_AssertPass("Call to SDL_sscanf(\"aa\", \"%%1x\", &output)"); + result = SDL_sscanf("aa", "%1x%n", &output, &length); + SDLTest_AssertPass("Call to SDL_sscanf(\"aa\", \"%%1x%%n\", &output, &length)"); SDLTest_AssertCheck(expected_output == output, "Check output, expected: %i, got: %i", expected_output, output); SDLTest_AssertCheck(expected_result == result, "Check return value, expected: %i, got: %i", expected_result, result); + SDLTest_AssertCheck(length == 1, "Check length, expected: 1, got: %i", length); -#define SIZED_TEST_CASE(type, var, format_specifier) \ +#define SIZED_TEST_CASE(type, var, printf_specifier, scanf_specifier) \ var##_output = 123; \ + var##_length = 0; \ expected_##var##_output = (type)(((unsigned type)(~0)) >> 1); \ expected_result = 1; \ - result = SDL_snprintf(text, sizeof(text), format_specifier, expected_##var##_output); \ - result = SDL_sscanf(text, format_specifier, &var##_output); \ - SDLTest_AssertPass("Call to SDL_sscanf(\"%s\", \"%s\", &output)", text, #format_specifier); \ - SDLTest_AssertCheck(expected_##var##_output == var##_output, "Check output, expected: " format_specifier ", got: " format_specifier, expected_##var##_output, var##_output); \ + result = SDL_snprintf(text, sizeof(text), printf_specifier, expected_##var##_output); \ + result = SDL_sscanf(text, scanf_specifier, &var##_output, &var##_length); \ + SDLTest_AssertPass("Call to SDL_sscanf(\"%s\", %s, &output, &length)", text, #scanf_specifier); \ + SDLTest_AssertCheck(expected_##var##_output == var##_output, "Check output, expected: " printf_specifier ", got: " printf_specifier, expected_##var##_output, var##_output); \ SDLTest_AssertCheck(expected_result == result, "Check return value, expected: %i, got: %i", expected_result, result); \ + SDLTest_AssertCheck(var##_length == (type)SDL_strlen(text), "Check length, expected: %i, got: %i", (int)SDL_strlen(text), (int)var##_length); \ \ var##_output = 123; \ + var##_length = 0; \ expected_##var##_output = ~(type)(((unsigned type)(~0)) >> 1); \ expected_result = 1; \ - result = SDL_snprintf(text, sizeof(text), format_specifier, expected_##var##_output); \ - result = SDL_sscanf(text, format_specifier, &var##_output); \ - SDLTest_AssertPass("Call to SDL_sscanf(\"%s\", \"%s\", &output)", text, #format_specifier); \ - SDLTest_AssertCheck(expected_##var##_output == var##_output, "Check output, expected: " format_specifier ", got: " format_specifier, expected_##var##_output, var##_output); \ - SDLTest_AssertCheck(expected_result == result, "Check return value, expected: %i, got: %i", expected_result, result); + result = SDL_snprintf(text, sizeof(text), printf_specifier, expected_##var##_output); \ + result = SDL_sscanf(text, scanf_specifier, &var##_output, &var##_length); \ + SDLTest_AssertPass("Call to SDL_sscanf(\"%s\", %s, &output, &length)", text, #scanf_specifier); \ + SDLTest_AssertCheck(expected_##var##_output == var##_output, "Check output, expected: " printf_specifier ", got: " printf_specifier, expected_##var##_output, var##_output); \ + SDLTest_AssertCheck(expected_result == result, "Check return value, expected: %i, got: %i", expected_result, result); \ + SDLTest_AssertCheck(var##_length == (type)SDL_strlen(text), "Check length, expected: %i, got: %i", (int)SDL_strlen(text), (int)var##_length); \ - SIZED_TEST_CASE(short, short, "%hd") - SIZED_TEST_CASE(long, long, "%ld") - SIZED_TEST_CASE(long long, long_long, FMT_PRILLd) + SIZED_TEST_CASE(short, short, "%hd", "%hd%hn") + SIZED_TEST_CASE(long, long, "%ld", "%ld%ln") + SIZED_TEST_CASE(long long, long_long, FMT_PRILLd, FMT_PRILLdn) size_output = 123; expected_size_output = ~((size_t)0); diff --git a/libs/SDL3/test/testcamera.c b/libs/SDL3/test/testcamera.c index f83347f2..b2709211 100644 --- a/libs/SDL3/test/testcamera.c +++ b/libs/SDL3/test/testcamera.c @@ -36,10 +36,10 @@ static void PrintCameraSpecs(SDL_CameraID camera_id) if (specs) { int i; - SDL_Log("Available formats:\n"); + SDL_Log("Available formats:"); for (i = 0; specs[i]; ++i) { const SDL_CameraSpec *s = specs[i]; - SDL_Log(" %dx%d %.2f FPS %s\n", s->width, s->height, (float)s->framerate_numerator / s->framerate_denominator, SDL_GetPixelFormatName(s->format)); + SDL_Log(" %dx%d %.2f FPS %s", s->width, s->height, (float)s->framerate_numerator / s->framerate_denominator, SDL_GetPixelFormatName(s->format)); } SDL_free(specs); } @@ -97,8 +97,6 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) NULL, }; SDLTest_CommonLogUsage(state, argv[0], options); - SDL_Quit(); - SDLTest_CommonDestroyState(state); return SDL_APP_FAILURE; } i += consumed; diff --git a/libs/SDL3/test/testclipboard.c b/libs/SDL3/test/testclipboard.c index 634f81c3..9dad02be 100644 --- a/libs/SDL3/test/testclipboard.c +++ b/libs/SDL3/test/testclipboard.c @@ -41,12 +41,12 @@ static const void *ClipboardDataCallback(void *userdata, const char *mime_type, SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) { if (!SDL_Init(SDL_INIT_VIDEO)) { - SDL_Log("Couldn't initialize SDL: %s\n", SDL_GetError()); + SDL_Log("Couldn't initialize SDL: %s", SDL_GetError()); return SDL_APP_FAILURE; } if (!SDL_CreateWindowAndRenderer("testclipboard", 640, 480, 0, &window, &renderer)) { - SDL_Log("Couldn't create window and renderer: %s\n", SDL_GetError()); + SDL_Log("Couldn't create window and renderer: %s", SDL_GetError()); return SDL_APP_FAILURE; } return SDL_APP_CONTINUE; @@ -63,18 +63,20 @@ SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) if (event->key.key == SDLK_C && event->key.mod & SDL_KMOD_CTRL) { SDL_SetClipboardData(ClipboardDataCallback, NULL, NULL, mime_types, SDL_arraysize(mime_types)); break; + } else if (event->key.key == SDLK_P && event->key.mod & SDL_KMOD_CTRL) { + SDL_SetPrimarySelectionText("SDL Primary Selection Text!"); } break; case SDL_EVENT_CLIPBOARD_UPDATE: if (event->clipboard.num_mime_types > 0) { int i; - SDL_Log("Clipboard updated:\n"); + SDL_Log("Clipboard updated:"); for (i = 0; event->clipboard.mime_types[i]; ++i) { - SDL_Log(" %s\n", event->clipboard.mime_types[i]); + SDL_Log(" %s", event->clipboard.mime_types[i]); } } else { - SDL_Log("Clipboard cleared\n"); + SDL_Log("Clipboard cleared"); } break; @@ -99,6 +101,15 @@ static float PrintClipboardText(float x, float y, const char *mime_type) return 0.0f; } +static float PrintPrimarySelectionText(float x, float y) +{ + if (SDL_HasPrimarySelectionText()) { + SDL_RenderDebugText(renderer, x, y, SDL_GetPrimarySelectionText()); + return SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE + 2.0f; + } + return 0.0f; +} + static float PrintClipboardImage(float x, float y, const char *mime_type) { /* We don't actually need to read this data each frame, but this is a simple example */ @@ -134,7 +145,7 @@ static float PrintClipboardImage(float x, float y, const char *mime_type) return 0.0f; } -static void PrintClipboardContents(float x, float y) +static float PrintClipboardContents(float x, float y) { char **clipboard_mime_types = SDL_GetClipboardMimeTypes(NULL); if (clipboard_mime_types) { @@ -152,6 +163,8 @@ static void PrintClipboardContents(float x, float y) } SDL_free(clipboard_mime_types); } + + return y; } SDL_AppResult SDL_AppIterate(void *appstate) @@ -164,10 +177,18 @@ SDL_AppResult SDL_AppIterate(void *appstate) float y = 4.0f; SDL_RenderDebugText(renderer, x, y, "Press Ctrl+C to copy content to the clipboard"); y += SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * 2; + SDL_RenderDebugText(renderer, x, y, "Press Ctrl+P to set the primary selection text"); + y += SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * 2; SDL_RenderDebugText(renderer, x, y, "Clipboard contents:"); x += SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * 2; y += SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE + 2; - PrintClipboardContents(x, y); + y = PrintClipboardContents(x, y); + if (SDL_HasPrimarySelectionText()) { + x = 4.0f; + SDL_RenderDebugText(renderer, x, y, "Primary selection text contents:"); + y += SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE + 2; + PrintPrimarySelectionText(x + SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * 2, y); + } SDL_RenderPresent(renderer); diff --git a/libs/SDL3/test/testcolorspace.c b/libs/SDL3/test/testcolorspace.c index 14877cbe..c3bcd3bf 100644 --- a/libs/SDL3/test/testcolorspace.c +++ b/libs/SDL3/test/testcolorspace.c @@ -64,12 +64,12 @@ static void UpdateHDRState(void) props = SDL_GetWindowProperties(window); HDR_enabled = SDL_GetBooleanProperty(props, SDL_PROP_WINDOW_HDR_ENABLED_BOOLEAN, false); - SDL_Log("HDR %s\n", HDR_enabled ? "enabled" : "disabled"); + SDL_Log("HDR %s", HDR_enabled ? "enabled" : "disabled"); if (HDR_enabled) { props = SDL_GetRendererProperties(renderer); if (SDL_GetNumberProperty(props, SDL_PROP_RENDERER_OUTPUT_COLORSPACE_NUMBER, SDL_COLORSPACE_SRGB) != SDL_COLORSPACE_SRGB_LINEAR) { - SDL_Log("Run with --colorspace linear to display HDR colors\n"); + SDL_Log("Run with --colorspace linear to display HDR colors"); } HDR_headroom = SDL_GetFloatProperty(props, SDL_PROP_RENDERER_HDR_HEADROOM_FLOAT, 1.0f); } @@ -86,12 +86,12 @@ static void CreateRenderer(void) renderer = SDL_CreateRendererWithProperties(props); SDL_DestroyProperties(props); if (!renderer) { - SDL_Log("Couldn't create renderer: %s\n", SDL_GetError()); + SDL_Log("Couldn't create renderer: %s", SDL_GetError()); return; } renderer_name = SDL_GetRendererName(renderer); - SDL_Log("Created renderer %s\n", renderer_name); + SDL_Log("Created renderer %s", renderer_name); UpdateHDRState(); } @@ -159,11 +159,11 @@ static bool ReadPixel(int x, int y, SDL_Color *c) if (SDL_ReadSurfacePixel(surface, 0, 0, &c->r, &c->g, &c->b, &c->a)) { result = true; } else { - SDL_Log("Couldn't read pixel: %s\n", SDL_GetError()); + SDL_Log("Couldn't read pixel: %s", SDL_GetError()); } SDL_DestroySurface(surface); } else { - SDL_Log("Couldn't read back pixels: %s\n", SDL_GetError()); + SDL_Log("Couldn't read back pixels: %s", SDL_GetError()); } return result; } @@ -662,7 +662,7 @@ static void loop(void) static void LogUsage(const char *argv0) { - SDL_Log("Usage: %s [--renderer renderer] [--colorspace colorspace]\n", argv0); + SDL_Log("Usage: %s [--renderer renderer] [--colorspace colorspace]", argv0); } int main(int argc, char *argv[]) @@ -691,7 +691,7 @@ int main(int argc, char *argv[]) colorspace = SDL_COLORSPACE_HDR10; */ } else { - SDL_Log("Unknown colorspace %s\n", argv[i + 1]); + SDL_Log("Unknown colorspace %s", argv[i + 1]); goto quit; } ++i; @@ -707,20 +707,20 @@ int main(int argc, char *argv[]) window = SDL_CreateWindow("SDL colorspace test", WINDOW_WIDTH, WINDOW_HEIGHT, 0); if (!window) { - SDL_Log("Couldn't create window: %s\n", SDL_GetError()); + SDL_Log("Couldn't create window: %s", SDL_GetError()); return_code = 2; goto quit; } renderer_count = SDL_GetNumRenderDrivers(); - SDL_Log("There are %d render drivers:\n", renderer_count); + SDL_Log("There are %d render drivers:", renderer_count); for (i = 0; i < renderer_count; ++i) { const char *name = SDL_GetRenderDriver(i); if (renderer_name && SDL_strcasecmp(renderer_name, name) == 0) { renderer_index = i; } - SDL_Log(" %s\n", name); + SDL_Log(" %s", name); } CreateRenderer(); diff --git a/libs/SDL3/test/testcontroller.c b/libs/SDL3/test/testcontroller.c index da87c727..b717b30e 100644 --- a/libs/SDL3/test/testcontroller.c +++ b/libs/SDL3/test/testcontroller.c @@ -923,9 +923,9 @@ static void AddController(SDL_JoystickID id, bool verbose) const char *name = SDL_GetJoystickName(joystick); const char *path = SDL_GetJoystickPath(joystick); char guid[33]; - SDL_Log("Opened joystick %s%s%s\n", name, path ? ", " : "", path ? path : ""); + SDL_Log("Opened joystick %s%s%s", name, path ? ", " : "", path ? path : ""); SDL_GUIDToString(SDL_GetJoystickGUID(joystick), guid, sizeof(guid)); - SDL_Log("No gamepad mapping for %s\n", guid); + SDL_Log("No gamepad mapping for %s", guid); } } else { SDL_Log("Couldn't open joystick: %s", SDL_GetError()); @@ -1021,7 +1021,7 @@ static void HandleGamepadAdded(SDL_JoystickID id, bool verbose) if (i < 0) { return; } - SDL_Log("Gamepad %" SDL_PRIu32 " added\n", id); + SDL_Log("Gamepad %" SDL_PRIu32 " added", id); SDL_assert(!controllers[i].gamepad); controllers[i].gamepad = SDL_OpenGamepad(id); @@ -1035,11 +1035,11 @@ static void HandleGamepadAdded(SDL_JoystickID id, bool verbose) SDL_GUID guid = SDL_GetGamepadGUIDForID(id); char guid_string[33]; SDL_GUIDToString(guid, guid_string, sizeof(guid_string)); - SDL_Log("Opened gamepad %s, guid %s%s%s\n", name, guid_string, path ? ", " : "", path ? path : ""); + SDL_Log("Opened gamepad %s, guid %s%s%s", name, guid_string, path ? ", " : "", path ? path : ""); firmware_version = SDL_GetGamepadFirmwareVersion(gamepad); if (firmware_version) { - SDL_Log("Firmware version: 0x%x (%d)\n", firmware_version, firmware_version); + SDL_Log("Firmware version: 0x%x (%d)", firmware_version, firmware_version); } if (SDL_GetBooleanProperty(props, SDL_PROP_GAMEPAD_CAP_PLAYER_LED_BOOLEAN, false)) { @@ -1055,7 +1055,36 @@ static void HandleGamepadAdded(SDL_JoystickID id, bool verbose) } if (SDL_GetGamepadPlayerIndex(gamepad) >= 0) { - SDL_Log("Player index: %d\n", SDL_GetGamepadPlayerIndex(gamepad)); + SDL_Log("Player index: %d", SDL_GetGamepadPlayerIndex(gamepad)); + } + + switch (SDL_GetJoystickTypeForID(id)) { + case SDL_JOYSTICK_TYPE_WHEEL: + SDL_Log("Controller is a wheel"); + break; + case SDL_JOYSTICK_TYPE_ARCADE_STICK: + SDL_Log("Controller is an arcade stick"); + break; + case SDL_JOYSTICK_TYPE_FLIGHT_STICK: + SDL_Log("Controller is a flight stick"); + break; + case SDL_JOYSTICK_TYPE_DANCE_PAD: + SDL_Log("Controller is a dance pad"); + break; + case SDL_JOYSTICK_TYPE_GUITAR: + SDL_Log("Controller is a guitar"); + break; + case SDL_JOYSTICK_TYPE_DRUM_KIT: + SDL_Log("Controller is a drum kit"); + break; + case SDL_JOYSTICK_TYPE_ARCADE_PAD: + SDL_Log("Controller is an arcade pad"); + break; + case SDL_JOYSTICK_TYPE_THROTTLE: + SDL_Log("Controller is a throttle"); + break; + default: + break; } } @@ -1064,7 +1093,7 @@ static void HandleGamepadAdded(SDL_JoystickID id, bool verbose) if (SDL_GamepadHasSensor(gamepad, sensor)) { if (verbose) { - SDL_Log("Enabling %s at %.2f Hz\n", GetSensorName(sensor), SDL_GetGamepadSensorDataRate(gamepad, sensor)); + SDL_Log("Enabling %s at %.2f Hz", GetSensorName(sensor), SDL_GetGamepadSensorDataRate(gamepad, sensor)); } SDL_SetGamepadSensorEnabled(gamepad, sensor, true); } @@ -1073,7 +1102,7 @@ static void HandleGamepadAdded(SDL_JoystickID id, bool verbose) if (verbose) { char *mapping = SDL_GetGamepadMapping(gamepad); if (mapping) { - SDL_Log("Mapping: %s\n", mapping); + SDL_Log("Mapping: %s", mapping); SDL_free(mapping); } } @@ -1093,7 +1122,7 @@ static void HandleGamepadRemoved(SDL_JoystickID id) if (i < 0) { return; } - SDL_Log("Gamepad %" SDL_PRIu32 " removed\n", id); + SDL_Log("Gamepad %" SDL_PRIu32 " removed", id); if (controllers[i].mapping) { SDL_free(controllers[i].mapping); @@ -1137,24 +1166,24 @@ static bool ShowingFront(void) static void SDLCALL VirtualGamepadSetPlayerIndex(void *userdata, int player_index) { - SDL_Log("Virtual Gamepad: player index set to %d\n", player_index); + SDL_Log("Virtual Gamepad: player index set to %d", player_index); } static bool SDLCALL VirtualGamepadRumble(void *userdata, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) { - SDL_Log("Virtual Gamepad: rumble set to %d/%d\n", low_frequency_rumble, high_frequency_rumble); + SDL_Log("Virtual Gamepad: rumble set to %d/%d", low_frequency_rumble, high_frequency_rumble); return true; } static bool SDLCALL VirtualGamepadRumbleTriggers(void *userdata, Uint16 left_rumble, Uint16 right_rumble) { - SDL_Log("Virtual Gamepad: trigger rumble set to %d/%d\n", left_rumble, right_rumble); + SDL_Log("Virtual Gamepad: trigger rumble set to %d/%d", left_rumble, right_rumble); return true; } static bool SDLCALL VirtualGamepadSetLED(void *userdata, Uint8 red, Uint8 green, Uint8 blue) { - SDL_Log("Virtual Gamepad: LED set to RGB %d,%d,%d\n", red, green, blue); + SDL_Log("Virtual Gamepad: LED set to RGB %d,%d,%d", red, green, blue); return true; } @@ -1184,11 +1213,11 @@ static void OpenVirtualGamepad(void) virtual_id = SDL_AttachVirtualJoystick(&desc); if (virtual_id == 0) { - SDL_Log("Couldn't attach virtual device: %s\n", SDL_GetError()); + SDL_Log("Couldn't attach virtual device: %s", SDL_GetError()); } else { virtual_joystick = SDL_OpenJoystick(virtual_id); if (!virtual_joystick) { - SDL_Log("Couldn't open virtual device: %s\n", SDL_GetError()); + SDL_Log("Couldn't open virtual device: %s", SDL_GetError()); } } } @@ -1620,7 +1649,7 @@ SDL_AppResult SDLCALL SDL_AppEvent(void *appstate, SDL_Event *event) } #ifdef DEBUG_AXIS_MAPPING - SDL_Log("AXIS %d nValue %d nCurrentDistance %d nFarthestDistance %d\n", event->jaxis.axis, nValue, nCurrentDistance, nFarthestDistance); + SDL_Log("AXIS %d nValue %d nCurrentDistance %d nFarthestDistance %d", event->jaxis.axis, nValue, nCurrentDistance, nFarthestDistance); #endif /* If we've gone out far enough and started to come back, let's bind this axis */ if (nFarthestDistance >= 16000 && nCurrentDistance <= 10000) { @@ -1642,7 +1671,7 @@ SDL_AppResult SDLCALL SDL_AppEvent(void *appstate, SDL_Event *event) } } #ifdef DEBUG_AXIS_MAPPING - SDL_Log("AXIS %d axis_min = %d, axis_max = %d, binding = %s\n", event->jaxis.axis, axis_min, axis_max, binding); + SDL_Log("AXIS %d axis_min = %d, axis_max = %d, binding = %s", event->jaxis.axis, axis_min, axis_max, binding); #endif CommitBindingElement(binding, false); } @@ -1698,7 +1727,7 @@ SDL_AppResult SDLCALL SDL_AppEvent(void *appstate, SDL_Event *event) case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN: case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION: case SDL_EVENT_GAMEPAD_TOUCHPAD_UP: - SDL_Log("Gamepad %" SDL_PRIu32 " touchpad %" SDL_PRIs32 " finger %" SDL_PRIs32 " %s %.2f, %.2f, %.2f\n", + SDL_Log("Gamepad %" SDL_PRIu32 " touchpad %" SDL_PRIs32 " finger %" SDL_PRIs32 " %s %.2f, %.2f, %.2f", event->gtouchpad.which, event->gtouchpad.touchpad, event->gtouchpad.finger, @@ -1711,7 +1740,7 @@ SDL_AppResult SDLCALL SDL_AppEvent(void *appstate, SDL_Event *event) #ifdef VERBOSE_SENSORS case SDL_EVENT_GAMEPAD_SENSOR_UPDATE: - SDL_Log("Gamepad %" SDL_PRIu32 " sensor %s: %.2f, %.2f, %.2f (%" SDL_PRIu64 ")\n", + SDL_Log("Gamepad %" SDL_PRIu32 " sensor %s: %.2f, %.2f, %.2f (%" SDL_PRIu64 ")", event->gsensor.which, GetSensorName((SDL_SensorType) event->gsensor.sensor), event->gsensor.data[0], @@ -1728,7 +1757,7 @@ SDL_AppResult SDLCALL SDL_AppEvent(void *appstate, SDL_Event *event) SetController(event->gaxis.which); } } - SDL_Log("Gamepad %" SDL_PRIu32 " axis %s changed to %d\n", + SDL_Log("Gamepad %" SDL_PRIu32 " axis %s changed to %d", event->gaxis.which, SDL_GetGamepadStringForAxis((SDL_GamepadAxis) event->gaxis.axis), event->gaxis.value); @@ -1743,7 +1772,7 @@ SDL_AppResult SDLCALL SDL_AppEvent(void *appstate, SDL_Event *event) } } #ifdef VERBOSE_BUTTONS - SDL_Log("Gamepad %" SDL_PRIu32 " button %s %s\n", + SDL_Log("Gamepad %" SDL_PRIu32 " button %s %s", event->gbutton.which, SDL_GetGamepadStringForButton((SDL_GamepadButton) event->gbutton.button), event->gbutton.state ? "pressed" : "released"); @@ -1784,8 +1813,8 @@ SDL_AppResult SDLCALL SDL_AppEvent(void *appstate, SDL_Event *event) } else if (display_mode == CONTROLLER_MODE_BINDING) { if (GamepadButtonContains(done_mapping_button, event->button.x, event->button.y)) { if (controller->mapping) { - SDL_Log("Mapping complete:\n"); - SDL_Log("%s\n", controller->mapping); + SDL_Log("Mapping complete:"); + SDL_Log("%s", controller->mapping); } SetDisplayMode(CONTROLLER_MODE_TESTING); } else if (GamepadButtonContains(cancel_button, event->button.x, event->button.y)) { @@ -2047,7 +2076,7 @@ SDL_AppResult SDLCALL SDL_AppInit(void **appstate, int argc, char *argv[]) /* Initialize SDL (Note: video is required to start event loop) */ if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError()); return SDL_APP_FAILURE; } @@ -2057,11 +2086,11 @@ SDL_AppResult SDLCALL SDL_AppInit(void **appstate, int argc, char *argv[]) int count = 0; char **mappings = SDL_GetGamepadMappings(&count); int map_i; - SDL_Log("Supported mappings:\n"); + SDL_Log("Supported mappings:"); for (map_i = 0; map_i < count; ++map_i) { - SDL_Log("\t%s\n", mappings[map_i]); + SDL_Log("\t%s", mappings[map_i]); } - SDL_Log("\n"); + SDL_Log("%s", ""); SDL_free(mappings); } @@ -2072,15 +2101,15 @@ SDL_AppResult SDLCALL SDL_AppInit(void **appstate, int argc, char *argv[]) } screen_width = (int)SDL_ceilf(SCREEN_WIDTH * content_scale); screen_height = (int)SDL_ceilf(SCREEN_HEIGHT * content_scale); - window = SDL_CreateWindow("SDL Controller Test", screen_width, screen_height, 0); + window = SDL_CreateWindow("SDL Controller Test", screen_width, screen_height, SDL_WINDOW_HIGH_PIXEL_DENSITY); if (!window) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window: %s", SDL_GetError()); return SDL_APP_FAILURE; } screen = SDL_CreateRenderer(window, NULL); if (!screen) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s", SDL_GetError()); SDL_DestroyWindow(window); return SDL_APP_FAILURE; } diff --git a/libs/SDL3/test/testdialog.c b/libs/SDL3/test/testdialog.c index 92f453bb..3d19fb94 100644 --- a/libs/SDL3/test/testdialog.c +++ b/libs/SDL3/test/testdialog.c @@ -21,7 +21,7 @@ const SDL_DialogFileFilter filters[3] = { { "PNG images", "png" } }; -static void SDLCALL callback(void* userdata, const char* const* files, int filter) { +static void SDLCALL callback(void *userdata, const char * const *files, int filter) { if (files) { const char* filter_name = "(filter fetching unsupported)"; @@ -33,14 +33,14 @@ static void SDLCALL callback(void* userdata, const char* const* files, int filte } } - SDL_Log("Filter used: '%s'\n", filter_name); + SDL_Log("Filter used: '%s'", filter_name); while (*files) { - SDL_Log("'%s'\n", *files); + SDL_Log("'%s'", *files); files++; } } else { - SDL_Log("Error: %s\n", SDL_GetError()); + SDL_Log("Error: %s", SDL_GetError()); } } @@ -82,7 +82,7 @@ int main(int argc, char *argv[]) return 1; } if (!SDL_CreateWindowAndRenderer("testdialog", 640, 480, 0, &w, &r)) { - SDL_Log("Failed to create window and/or renderer: %s\n", SDL_GetError()); + SDL_Log("Failed to create window and/or renderer: %s", SDL_GetError()); SDL_Quit(); return 1; } @@ -90,7 +90,7 @@ int main(int argc, char *argv[]) initial_path = SDL_GetUserFolder(SDL_FOLDER_HOME); if (!initial_path) { - SDL_Log("Will not use an initial path, couldn't get the home directory path: %s\n", SDL_GetError()); + SDL_Log("Will not use an initial path, couldn't get the home directory path: %s", SDL_GetError()); } while (1) { diff --git a/libs/SDL3/test/testdisplayinfo.c b/libs/SDL3/test/testdisplayinfo.c index 2c5063e9..af37dde1 100644 --- a/libs/SDL3/test/testdisplayinfo.c +++ b/libs/SDL3/test/testdisplayinfo.c @@ -25,7 +25,7 @@ print_mode(const char *prefix, const SDL_DisplayMode *mode) return; } - SDL_Log("%s: %dx%d@%gx, %gHz, fmt=%s\n", + SDL_Log("%s: %dx%d@%gx, %gHz, fmt=%s", prefix, mode->w, mode->h, mode->pixel_density, mode->refresh_rate, SDL_GetPixelFormatName(mode->format)); @@ -52,14 +52,14 @@ int main(int argc, char *argv[]) /* Load the SDL library */ if (!SDL_Init(SDL_INIT_VIDEO)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError()); return 1; } - SDL_Log("Using video target '%s'.\n", SDL_GetCurrentVideoDriver()); + SDL_Log("Using video target '%s'.", SDL_GetCurrentVideoDriver()); displays = SDL_GetDisplays(&num_displays); - SDL_Log("See %d displays.\n", num_displays); + SDL_Log("See %d displays.", num_displays); for (i = 0; i < num_displays; i++) { SDL_DisplayID dpy = displays[i]; @@ -70,20 +70,20 @@ int main(int argc, char *argv[]) SDL_GetDisplayBounds(dpy, &rect); modes = SDL_GetFullscreenDisplayModes(dpy, &num_modes); - SDL_Log("%" SDL_PRIu32 ": \"%s\" (%dx%d at %d,%d), content scale %.2f, %d fullscreen modes, HDR capable: %s.\n", dpy, SDL_GetDisplayName(dpy), rect.w, rect.h, rect.x, rect.y, SDL_GetDisplayContentScale(dpy), num_modes, has_HDR ? "yes" : "no"); + SDL_Log("%" SDL_PRIu32 ": \"%s\" (%dx%d at %d,%d), content scale %.2f, %d fullscreen modes, HDR capable: %s.", dpy, SDL_GetDisplayName(dpy), rect.w, rect.h, rect.x, rect.y, SDL_GetDisplayContentScale(dpy), num_modes, has_HDR ? "yes" : "no"); mode = SDL_GetCurrentDisplayMode(dpy); if (mode) { print_mode("CURRENT", mode); } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, " CURRENT: failed to query (%s)\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, " CURRENT: failed to query (%s)", SDL_GetError()); } mode = SDL_GetDesktopDisplayMode(dpy); if (mode) { print_mode("DESKTOP", mode); } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, " DESKTOP: failed to query (%s)\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, " DESKTOP: failed to query (%s)", SDL_GetError()); } for (m = 0; m < num_modes; m++) { @@ -93,7 +93,7 @@ int main(int argc, char *argv[]) } SDL_free(modes); - SDL_Log("\n"); + SDL_Log("%s", ""); } SDL_free(displays); diff --git a/libs/SDL3/test/testdraw.c b/libs/SDL3/test/testdraw.c index 9f07f3a2..2ed62117 100644 --- a/libs/SDL3/test/testdraw.c +++ b/libs/SDL3/test/testdraw.c @@ -167,8 +167,8 @@ static void DrawRects(SDL_Renderer *renderer) rect.w = (float)SDL_rand(viewport.h / 2); rect.h = (float)SDL_rand(viewport.h / 2); - rect.x = (float)((SDL_rand(viewport.w * 2) - viewport.w) - (rect.w / 2)); - rect.y = (float)((SDL_rand(viewport.h * 2) - viewport.h) - (rect.h / 2)); + rect.x = (SDL_rand(viewport.w * 2) - viewport.w) - (rect.w / 2); + rect.y = (SDL_rand(viewport.h * 2) - viewport.h) - (rect.h / 2); SDL_RenderFillRect(renderer, &rect); } } @@ -208,7 +208,7 @@ static void loop(void) /* Print out some timing information */ const Uint64 then = next_fps_check - fps_check_delay; const double fps = ((double)frames * 1000) / (now - then); - SDL_Log("%2.2f frames per second\n", fps); + SDL_Log("%2.2f frames per second", fps); next_fps_check = now + fps_check_delay; frames = 0; } diff --git a/libs/SDL3/test/testdrawchessboard.c b/libs/SDL3/test/testdrawchessboard.c index 6c58482a..c68771c1 100644 --- a/libs/SDL3/test/testdrawchessboard.c +++ b/libs/SDL3/test/testdrawchessboard.c @@ -50,8 +50,8 @@ static void DrawChessBoard(void) rect.w = (float)(darea.w / 8); rect.h = (float)(darea.h / 8); - rect.x = (float)(x * rect.w); - rect.y = (float)(row * rect.h); + rect.x = x * rect.w; + rect.y = row * rect.h; x = x + 2; SDL_RenderFillRect(renderer, &rect); @@ -132,14 +132,14 @@ int main(int argc, char *argv[]) /* Initialize SDL */ if (!SDL_Init(SDL_INIT_VIDEO)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_Init fail : %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_Init fail : %s", SDL_GetError()); return 1; } /* Create window and renderer for given surface */ window = SDL_CreateWindow("Chess Board", 640, 480, SDL_WINDOW_RESIZABLE); if (!window) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Window creation fail : %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Window creation fail : %s", SDL_GetError()); return 1; } #ifdef USE_SOFTWARE_RENDERER @@ -149,7 +149,7 @@ int main(int argc, char *argv[]) renderer = SDL_CreateRenderer(window, NULL); #endif if (!renderer) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Render creation for surface fail : %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Render creation for surface fail : %s", SDL_GetError()); return 1; } diff --git a/libs/SDL3/test/testerror.c b/libs/SDL3/test/testerror.c index 07056ecb..687cb433 100644 --- a/libs/SDL3/test/testerror.c +++ b/libs/SDL3/test/testerror.c @@ -38,10 +38,10 @@ ThreadFunc(void *data) SDL_SetError("Thread %s (%" SDL_PRIu64 ") had a problem: %s", (char *)data, SDL_GetCurrentThreadID(), "nevermind"); while (alive) { - SDL_Log("Thread '%s' is alive!\n", (char *)data); + SDL_Log("Thread '%s' is alive!", (char *)data); SDL_Delay(1 * 1000); } - SDL_Log("Child thread error string: %s\n", SDL_GetError()); + SDL_Log("Child thread error string: %s", SDL_GetError()); return 0; } @@ -83,7 +83,7 @@ int main(int argc, char *argv[]) /* Load the SDL library */ if (!SDL_Init(0)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError()); return 1; } @@ -100,16 +100,16 @@ int main(int argc, char *argv[]) alive = 1; thread = SDL_CreateThread(ThreadFunc, NULL, "#1"); if (!thread) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create thread: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create thread: %s", SDL_GetError()); quit(1); } SDL_Delay(5 * 1000); - SDL_Log("Waiting for thread #1\n"); + SDL_Log("Waiting for thread #1"); alive = 0; SDL_WaitThread(thread, NULL); } - SDL_Log("Main thread error string: %s\n", SDL_GetError()); + SDL_Log("Main thread error string: %s", SDL_GetError()); SDL_Quit(); SDLTest_CommonDestroyState(state); diff --git a/libs/SDL3/test/testffmpeg.c b/libs/SDL3/test/testffmpeg.c index 5c072fcd..63bc3cb5 100644 --- a/libs/SDL3/test/testffmpeg.c +++ b/libs/SDL3/test/testffmpeg.c @@ -171,7 +171,7 @@ static bool CreateWindowAndRenderer(SDL_WindowFlags window_flags, const char *dr return false; } - SDL_Log("Created renderer %s\n", SDL_GetRendererName(renderer)); + SDL_Log("Created renderer %s", SDL_GetRendererName(renderer)); #ifdef HAVE_EGL if (useEGL) { @@ -377,9 +377,9 @@ static enum AVPixelFormat GetSupportedPixelFormat(AVCodecContext *s, const enum } if (*p == AV_PIX_FMT_NONE) { - SDL_Log("Couldn't find a supported pixel format:\n"); + SDL_Log("Couldn't find a supported pixel format:"); for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { - SDL_Log(" %s\n", av_get_pix_fmt_name(*p)); + SDL_Log(" %s", av_get_pix_fmt_name(*p)); } } @@ -395,7 +395,7 @@ static AVCodecContext *OpenVideoStream(AVFormatContext *ic, int stream, const AV int i; int result; - SDL_Log("Video stream: %s %dx%d\n", avcodec_get_name(codec->id), codecpar->width, codecpar->height); + SDL_Log("Video stream: %s %dx%d", avcodec_get_name(codec->id), codecpar->width, codecpar->height); context = avcodec_alloc_context3(NULL); if (!context) { @@ -405,7 +405,7 @@ static AVCodecContext *OpenVideoStream(AVFormatContext *ic, int stream, const AV result = avcodec_parameters_to_context(context, ic->streams[stream]->codecpar); if (result < 0) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "avcodec_parameters_to_context failed: %s\n", av_err2str(result)); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "avcodec_parameters_to_context failed: %s", av_err2str(result)); avcodec_free_context(&context); return NULL; } @@ -416,7 +416,7 @@ static AVCodecContext *OpenVideoStream(AVFormatContext *ic, int stream, const AV while (!context->hw_device_ctx && (config = avcodec_get_hw_config(codec, i++)) != NULL) { #if 0 - SDL_Log("Found %s hardware acceleration with pixel format %s\n", av_hwdevice_get_type_name(config->device_type), av_get_pix_fmt_name(config->pix_fmt)); + SDL_Log("Found %s hardware acceleration with pixel format %s", av_hwdevice_get_type_name(config->device_type), av_get_pix_fmt_name(config->pix_fmt)); #endif if (!(config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX) || @@ -440,7 +440,7 @@ static AVCodecContext *OpenVideoStream(AVFormatContext *ic, int stream, const AV if (result < 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create %s hardware device context: %s", av_hwdevice_get_type_name(config->device_type), av_err2str(result)); } else { - SDL_Log("Using %s hardware acceleration with pixel format %s\n", av_hwdevice_get_type_name(config->device_type), av_get_pix_fmt_name(config->pix_fmt)); + SDL_Log("Using %s hardware acceleration with pixel format %s", av_hwdevice_get_type_name(config->device_type), av_get_pix_fmt_name(config->pix_fmt)); } } else #endif @@ -456,14 +456,14 @@ static AVCodecContext *OpenVideoStream(AVFormatContext *ic, int stream, const AV if (result < 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create %s hardware device context: %s", av_hwdevice_get_type_name(config->device_type), av_err2str(result)); } else { - SDL_Log("Using %s hardware acceleration with pixel format %s\n", av_hwdevice_get_type_name(config->device_type), av_get_pix_fmt_name(config->pix_fmt)); + SDL_Log("Using %s hardware acceleration with pixel format %s", av_hwdevice_get_type_name(config->device_type), av_get_pix_fmt_name(config->pix_fmt)); } } else { result = av_hwdevice_ctx_create(&context->hw_device_ctx, config->device_type, NULL, NULL, 0); if (result < 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create %s hardware device context: %s", av_hwdevice_get_type_name(config->device_type), av_err2str(result)); } else { - SDL_Log("Using %s hardware acceleration with pixel format %s\n", av_hwdevice_get_type_name(config->device_type), av_get_pix_fmt_name(config->pix_fmt)); + SDL_Log("Using %s hardware acceleration with pixel format %s", av_hwdevice_get_type_name(config->device_type), av_get_pix_fmt_name(config->pix_fmt)); } } } @@ -498,7 +498,7 @@ static SDL_Colorspace GetFrameColorspace(AVFrame *frame) if (frame && frame->colorspace != AVCOL_SPC_RGB) { #ifdef DEBUG_COLORSPACE - SDL_Log("Frame colorspace: range: %d, primaries: %d, trc: %d, colorspace: %d, chroma_location: %d\n", frame->color_range, frame->color_primaries, frame->color_trc, frame->colorspace, frame->chroma_location); + SDL_Log("Frame colorspace: range: %d, primaries: %d, trc: %d, colorspace: %d, chroma_location: %d", frame->color_range, frame->color_primaries, frame->color_trc, frame->colorspace, frame->chroma_location); #endif colorspace = SDL_DEFINE_COLORSPACE(SDL_COLOR_TYPE_YCBCR, frame->color_range, @@ -731,7 +731,7 @@ static bool GetNV12TextureForDRMFrame(AVFrame *frame, SDL_Texture **texture) EGLImage image = eglCreateImage(display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attr); if (image == EGL_NO_IMAGE) { - SDL_Log("Couldn't create image: %d\n", glGetError()); + SDL_Log("Couldn't create image: %d", glGetError()); return false; } @@ -916,7 +916,7 @@ static bool GetOESTextureForDRMFrame(AVFrame *frame, SDL_Texture **texture) EGLImage image = eglCreateImage(display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attr); if (image == EGL_NO_IMAGE) { - SDL_Log("Couldn't create image: %d\n", glGetError()); + SDL_Log("Couldn't create image: %d", glGetError()); return false; } @@ -1082,7 +1082,7 @@ static void DisplayVideoTexture(AVFrame *frame) { /* Update the video texture */ if (!GetTextureForFrame(frame, &video_texture)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't get texture for frame: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't get texture for frame: %s", SDL_GetError()); return; } @@ -1138,17 +1138,17 @@ static AVCodecContext *OpenAudioStream(AVFormatContext *ic, int stream, const AV AVCodecContext *context; int result; - SDL_Log("Audio stream: %s %d channels, %d Hz\n", avcodec_get_name(codec->id), codecpar->ch_layout.nb_channels, codecpar->sample_rate); + SDL_Log("Audio stream: %s %d channels, %d Hz", avcodec_get_name(codec->id), codecpar->ch_layout.nb_channels, codecpar->sample_rate); context = avcodec_alloc_context3(NULL); if (!context) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "avcodec_alloc_context3 failed\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "avcodec_alloc_context3 failed"); return NULL; } result = avcodec_parameters_to_context(context, ic->streams[stream]->codecpar); if (result < 0) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "avcodec_parameters_to_context failed: %s\n", av_err2str(result)); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "avcodec_parameters_to_context failed: %s", av_err2str(result)); avcodec_free_context(&context); return NULL; } @@ -1471,7 +1471,7 @@ int main(int argc, char *argv[]) positions = (SDL_FRect *)SDL_malloc(num_sprites * sizeof(*positions)); velocities = (SDL_FRect *)SDL_malloc(num_sprites * sizeof(*velocities)); if (!positions || !velocities) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!"); return_code = 3; goto quit; } @@ -1510,7 +1510,7 @@ int main(int argc, char *argv[]) if (!flushing) { result = av_read_frame(ic, pkt); if (result < 0) { - SDL_Log("End of stream, finishing decode\n"); + SDL_Log("End of stream, finishing decode"); if (audio_context) { avcodec_flush_buffers(audio_context); } diff --git a/libs/SDL3/test/testffmpeg_vulkan.c b/libs/SDL3/test/testffmpeg_vulkan.c index e0a0ad45..4f2ba811 100644 --- a/libs/SDL3/test/testffmpeg_vulkan.c +++ b/libs/SDL3/test/testffmpeg_vulkan.c @@ -146,7 +146,7 @@ static int loadDeviceFunctions(VulkanVideoContext *context) #define VULKAN_DEVICE_FUNCTION(name) \ context->name = (PFN_##name)context->vkGetDeviceProcAddr(context->device, #name); \ if (!context->name) { \ - return SDL_SetError("vkGetDeviceProcAddr(device, \"" #name "\") failed\n"); \ + return SDL_SetError("vkGetDeviceProcAddr(device, \"" #name "\") failed"); \ } VULKAN_FUNCTIONS() #undef VULKAN_GLOBAL_FUNCTION @@ -243,7 +243,7 @@ static int createInstance(VulkanVideoContext *context) result = context->vkCreateInstance(&instanceCreateInfo, NULL, &context->instance); if (result != VK_SUCCESS) { context->instance = VK_NULL_HANDLE; - return SDL_SetError("vkCreateInstance(): %s\n", getVulkanResultString(result)); + return SDL_SetError("vkCreateInstance(): %s", getVulkanResultString(result)); } if (loadInstanceFunctions(context) < 0) { return -1; diff --git a/libs/SDL3/test/testfile.c b/libs/SDL3/test/testfile.c index 352b57fb..f3d57aa1 100644 --- a/libs/SDL3/test/testfile.c +++ b/libs/SDL3/test/testfile.c @@ -53,7 +53,7 @@ cleanup(void) static void iostrm_error_quit(unsigned line, SDL_IOStream *iostrm) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "testfile.c(%d): failed\n", line); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "testfile.c(%d): failed", line); if (iostrm) { SDL_CloseIO(iostrm); } @@ -105,7 +105,7 @@ int main(int argc, char *argv[]) if (iostrm) { RWOP_ERR_QUIT(iostrm); } - SDL_Log("test1 OK\n"); + SDL_Log("test1 OK"); /* test 2 : check that inexistent file is not successfully opened/created when required */ /* modes : r, r+ imply that file MUST exist @@ -144,7 +144,7 @@ int main(int argc, char *argv[]) } SDL_CloseIO(iostrm); unlink(FBASENAME2); - SDL_Log("test2 OK\n"); + SDL_Log("test2 OK"); /* test 3 : creation, writing , reading, seeking, test : w mode, r mode, w+ mode @@ -257,7 +257,7 @@ int main(int argc, char *argv[]) RWOP_ERR_QUIT(iostrm); } SDL_CloseIO(iostrm); - SDL_Log("test3 OK\n"); + SDL_Log("test3 OK"); /* test 4: same in r+ mode */ iostrm = SDL_IOFromFile(FBASENAME1, "rb+"); /* write + read + file must exists, no truncation */ @@ -308,7 +308,7 @@ int main(int argc, char *argv[]) RWOP_ERR_QUIT(iostrm); } SDL_CloseIO(iostrm); - SDL_Log("test4 OK\n"); + SDL_Log("test4 OK"); /* test5 : append mode */ iostrm = SDL_IOFromFile(FBASENAME1, "ab+"); /* write + read + append */ @@ -365,7 +365,7 @@ int main(int argc, char *argv[]) RWOP_ERR_QUIT(iostrm); } SDL_CloseIO(iostrm); - SDL_Log("test5 OK\n"); + SDL_Log("test5 OK"); cleanup(); SDL_Quit(); SDLTest_CommonDestroyState(state); diff --git a/libs/SDL3/test/testfilesystem.c b/libs/SDL3/test/testfilesystem.c index bdd0bac5..11235ebf 100644 --- a/libs/SDL3/test/testfilesystem.c +++ b/libs/SDL3/test/testfilesystem.c @@ -106,42 +106,42 @@ int main(int argc, char *argv[]) } if (!SDL_Init(0)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_Init() failed: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_Init() failed: %s", SDL_GetError()); return 1; } base_path = SDL_GetBasePath(); if (!base_path) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't find base path: %s\n", + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't find base path: %s", SDL_GetError()); } else { - SDL_Log("base path: '%s'\n", base_path); + SDL_Log("base path: '%s'", base_path); } pref_path = SDL_GetPrefPath("libsdl", "test_filesystem"); if (!pref_path) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't find pref path: %s\n", + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't find pref path: %s", SDL_GetError()); } else { - SDL_Log("pref path: '%s'\n", pref_path); + SDL_Log("pref path: '%s'", pref_path); } SDL_free(pref_path); pref_path = SDL_GetPrefPath(NULL, "test_filesystem"); if (!pref_path) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't find pref path without organization: %s\n", + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't find pref path without organization: %s", SDL_GetError()); } else { - SDL_Log("pref path: '%s'\n", pref_path); + SDL_Log("pref path: '%s'", pref_path); } SDL_free(pref_path); curdir = SDL_GetCurrentDirectory(); if (!curdir) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't find current directory: %s\n", + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't find current directory: %s", SDL_GetError()); } else { - SDL_Log("current directory: '%s'\n", curdir); + SDL_Log("current directory: '%s'", curdir); } SDL_free(curdir); @@ -209,13 +209,13 @@ int main(int argc, char *argv[]) textA = (char *)SDL_LoadFile("testfilesystem-A", &sizeA); if (!textA || sizeA != SDL_strlen(text) || SDL_strcmp(textA, text) != 0) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Contents of testfilesystem-A didn't match, expected %s, got %s\n", text, textA); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Contents of testfilesystem-A didn't match, expected %s, got %s", text, textA); } SDL_free(textA); textB = (char *)SDL_LoadFile("testfilesystem-B", &sizeB); if (!textB || sizeB != SDL_strlen(text) || SDL_strcmp(textB, text) != 0) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Contents of testfilesystem-B didn't match, expected %s, got %s\n", text, textB); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Contents of testfilesystem-B didn't match, expected %s, got %s", text, textB); } SDL_free(textB); } diff --git a/libs/SDL3/test/testgeometry.c b/libs/SDL3/test/testgeometry.c index cd00b5b0..a510cfd4 100644 --- a/libs/SDL3/test/testgeometry.c +++ b/libs/SDL3/test/testgeometry.c @@ -57,7 +57,7 @@ static int LoadSprite(const char *file) return -1; } if (!SDL_SetTextureBlendMode(sprites[i], blendMode)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set blend mode: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set blend mode: %s", SDL_GetError()); SDL_DestroyTexture(sprites[i]); return -1; } @@ -239,7 +239,7 @@ int main(int argc, char *argv[]) sprites = (SDL_Texture **)SDL_malloc(state->num_windows * sizeof(*sprites)); if (!sprites) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!"); quit(2); } /* Create the windows and initialize the renderers */ @@ -274,7 +274,7 @@ int main(int argc, char *argv[]) now = SDL_GetTicks(); if (now > then) { double fps = ((double)frames * 1000) / (now - then); - SDL_Log("%2.2f frames per second\n", fps); + SDL_Log("%2.2f frames per second", fps); } quit(0); diff --git a/libs/SDL3/test/testgl.c b/libs/SDL3/test/testgl.c index f109def3..4a49b1e7 100644 --- a/libs/SDL3/test/testgl.c +++ b/libs/SDL3/test/testgl.c @@ -203,9 +203,9 @@ static void LogSwapInterval(void) { int interval = 0; if (SDL_GL_GetSwapInterval(&interval)) { - SDL_Log("Swap Interval : %d\n", interval); + SDL_Log("Swap Interval : %d", interval); } else { - SDL_Log("Swap Interval : %d error: %s\n", interval, SDL_GetError()); + SDL_Log("Swap Interval : %d error: %s", interval, SDL_GetError()); } } @@ -282,13 +282,13 @@ int main(int argc, char *argv[]) /* Create OpenGL context */ context = SDL_GL_CreateContext(state->windows[0]); if (!context) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_GL_CreateContext(): %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_GL_CreateContext(): %s", SDL_GetError()); quit(2); } /* Important: call this *after* creating the context */ if (!LoadContext(&ctx)) { - SDL_Log("Could not load GL functions\n"); + SDL_Log("Could not load GL functions"); quit(2); return 0; } @@ -298,68 +298,68 @@ int main(int argc, char *argv[]) mode = SDL_GetCurrentDisplayMode(SDL_GetPrimaryDisplay()); if (mode) { - SDL_Log("Screen BPP : %d\n", SDL_BITSPERPIXEL(mode->format)); + SDL_Log("Screen BPP : %d", SDL_BITSPERPIXEL(mode->format)); } LogSwapInterval(); SDL_GetWindowSize(state->windows[0], &dw, &dh); - SDL_Log("Window Size : %d,%d\n", dw, dh); + SDL_Log("Window Size : %d,%d", dw, dh); SDL_GetWindowSizeInPixels(state->windows[0], &dw, &dh); - SDL_Log("Draw Size : %d,%d\n", dw, dh); - SDL_Log("\n"); - SDL_Log("Vendor : %s\n", ctx.glGetString(GL_VENDOR)); - SDL_Log("Renderer : %s\n", ctx.glGetString(GL_RENDERER)); - SDL_Log("Version : %s\n", ctx.glGetString(GL_VERSION)); - SDL_Log("Extensions : %s\n", ctx.glGetString(GL_EXTENSIONS)); - SDL_Log("\n"); + SDL_Log("Draw Size : %d,%d", dw, dh); + SDL_Log("%s", ""); + SDL_Log("Vendor : %s", ctx.glGetString(GL_VENDOR)); + SDL_Log("Renderer : %s", ctx.glGetString(GL_RENDERER)); + SDL_Log("Version : %s", ctx.glGetString(GL_VERSION)); + SDL_Log("Extensions : %s", ctx.glGetString(GL_EXTENSIONS)); + SDL_Log("%s", ""); if (SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &value)) { - SDL_Log("SDL_GL_RED_SIZE: requested %d, got %d\n", 5, value); + SDL_Log("SDL_GL_RED_SIZE: requested %d, got %d", 5, value); } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_RED_SIZE: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_RED_SIZE: %s", SDL_GetError()); } if (SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &value)) { - SDL_Log("SDL_GL_GREEN_SIZE: requested %d, got %d\n", 5, value); + SDL_Log("SDL_GL_GREEN_SIZE: requested %d, got %d", 5, value); } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_GREEN_SIZE: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_GREEN_SIZE: %s", SDL_GetError()); } if (SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &value)) { - SDL_Log("SDL_GL_BLUE_SIZE: requested %d, got %d\n", 5, value); + SDL_Log("SDL_GL_BLUE_SIZE: requested %d, got %d", 5, value); } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_BLUE_SIZE: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_BLUE_SIZE: %s", SDL_GetError()); } if (SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &value)) { - SDL_Log("SDL_GL_DEPTH_SIZE: requested %d, got %d\n", 16, value); + SDL_Log("SDL_GL_DEPTH_SIZE: requested %d, got %d", 16, value); } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_DEPTH_SIZE: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_DEPTH_SIZE: %s", SDL_GetError()); } if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_RELEASE_BEHAVIOR, &value)) { - SDL_Log("SDL_GL_CONTEXT_RELEASE_BEHAVIOR: requested %d, got %d\n", 0, value); + SDL_Log("SDL_GL_CONTEXT_RELEASE_BEHAVIOR: requested %d, got %d", 0, value); } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_CONTEXT_RELEASE_BEHAVIOR: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_CONTEXT_RELEASE_BEHAVIOR: %s", SDL_GetError()); } if (fsaa) { if (SDL_GL_GetAttribute(SDL_GL_MULTISAMPLEBUFFERS, &value)) { - SDL_Log("SDL_GL_MULTISAMPLEBUFFERS: requested 1, got %d\n", value); + SDL_Log("SDL_GL_MULTISAMPLEBUFFERS: requested 1, got %d", value); } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_MULTISAMPLEBUFFERS: %s\n", + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_MULTISAMPLEBUFFERS: %s", SDL_GetError()); } if (SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &value)) { - SDL_Log("SDL_GL_MULTISAMPLESAMPLES: requested %d, got %d\n", fsaa, + SDL_Log("SDL_GL_MULTISAMPLESAMPLES: requested %d, got %d", fsaa, value); } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_MULTISAMPLESAMPLES: %s\n", + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_MULTISAMPLESAMPLES: %s", SDL_GetError()); } } if (accel >= 0) { if (SDL_GL_GetAttribute(SDL_GL_ACCELERATED_VISUAL, &value)) { - SDL_Log("SDL_GL_ACCELERATED_VISUAL: requested %d, got %d\n", accel, + SDL_Log("SDL_GL_ACCELERATED_VISUAL: requested %d, got %d", accel, value); } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_ACCELERATED_VISUAL: %s\n", + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_ACCELERATED_VISUAL: %s", SDL_GetError()); } } @@ -398,7 +398,7 @@ int main(int argc, char *argv[]) } if (update_swap_interval) { - SDL_Log("Swap interval to be set to %d\n", swap_interval); + SDL_Log("Swap interval to be set to %d", swap_interval); } for (i = 0; i < state->num_windows; ++i) { @@ -428,7 +428,7 @@ int main(int argc, char *argv[]) /* Print out some timing information */ now = SDL_GetTicks(); if (now > then) { - SDL_Log("%2.2f frames per second\n", + SDL_Log("%2.2f frames per second", ((double)frames * 1000) / (now - then)); } quit(0); @@ -439,7 +439,7 @@ int main(int argc, char *argv[]) int main(int argc, char *argv[]) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "No OpenGL support on this system\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "No OpenGL support on this system"); return 1; } diff --git a/libs/SDL3/test/testgles.c b/libs/SDL3/test/testgles.c index 09f426f6..73097c71 100644 --- a/libs/SDL3/test/testgles.c +++ b/libs/SDL3/test/testgles.c @@ -173,7 +173,7 @@ int main(int argc, char *argv[]) context = (SDL_GLContext *)SDL_calloc(state->num_windows, sizeof(*context)); if (!context) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!"); quit(2); } @@ -181,7 +181,7 @@ int main(int argc, char *argv[]) for (i = 0; i < state->num_windows; i++) { context[i] = SDL_GL_CreateContext(state->windows[i]); if (!context[i]) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_GL_CreateContext(): %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_GL_CreateContext(): %s", SDL_GetError()); quit(2); } } @@ -190,59 +190,59 @@ int main(int argc, char *argv[]) mode = SDL_GetCurrentDisplayMode(SDL_GetPrimaryDisplay()); if (mode) { - SDL_Log("Screen bpp: %d\n", SDL_BITSPERPIXEL(mode->format)); - SDL_Log("\n"); + SDL_Log("Screen bpp: %d", SDL_BITSPERPIXEL(mode->format)); + SDL_Log("%s", ""); } - SDL_Log("Vendor : %s\n", glGetString(GL_VENDOR)); - SDL_Log("Renderer : %s\n", glGetString(GL_RENDERER)); - SDL_Log("Version : %s\n", glGetString(GL_VERSION)); - SDL_Log("Extensions : %s\n", glGetString(GL_EXTENSIONS)); - SDL_Log("\n"); + SDL_Log("Vendor : %s", glGetString(GL_VENDOR)); + SDL_Log("Renderer : %s", glGetString(GL_RENDERER)); + SDL_Log("Version : %s", glGetString(GL_VERSION)); + SDL_Log("Extensions : %s", glGetString(GL_EXTENSIONS)); + SDL_Log("%s", ""); if (SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &value)) { - SDL_Log("SDL_GL_RED_SIZE: requested %d, got %d\n", 5, value); + SDL_Log("SDL_GL_RED_SIZE: requested %d, got %d", 5, value); } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_RED_SIZE: %s\n", + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_RED_SIZE: %s", SDL_GetError()); } if (SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &value)) { - SDL_Log("SDL_GL_GREEN_SIZE: requested %d, got %d\n", 5, value); + SDL_Log("SDL_GL_GREEN_SIZE: requested %d, got %d", 5, value); } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_GREEN_SIZE: %s\n", + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_GREEN_SIZE: %s", SDL_GetError()); } if (SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &value)) { - SDL_Log("SDL_GL_BLUE_SIZE: requested %d, got %d\n", 5, value); + SDL_Log("SDL_GL_BLUE_SIZE: requested %d, got %d", 5, value); } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_BLUE_SIZE: %s\n", + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_BLUE_SIZE: %s", SDL_GetError()); } if (SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &value)) { - SDL_Log("SDL_GL_DEPTH_SIZE: requested %d, got %d\n", depth, value); + SDL_Log("SDL_GL_DEPTH_SIZE: requested %d, got %d", depth, value); } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_DEPTH_SIZE: %s\n", + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_DEPTH_SIZE: %s", SDL_GetError()); } if (fsaa) { if (SDL_GL_GetAttribute(SDL_GL_MULTISAMPLEBUFFERS, &value)) { - SDL_Log("SDL_GL_MULTISAMPLEBUFFERS: requested 1, got %d\n", value); + SDL_Log("SDL_GL_MULTISAMPLEBUFFERS: requested 1, got %d", value); } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_MULTISAMPLEBUFFERS: %s\n", + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_MULTISAMPLEBUFFERS: %s", SDL_GetError()); } if (SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &value)) { - SDL_Log("SDL_GL_MULTISAMPLESAMPLES: requested %d, got %d\n", fsaa, + SDL_Log("SDL_GL_MULTISAMPLESAMPLES: requested %d, got %d", fsaa, value); } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_MULTISAMPLESAMPLES: %s\n", + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_MULTISAMPLESAMPLES: %s", SDL_GetError()); } } if (accel) { if (SDL_GL_GetAttribute(SDL_GL_ACCELERATED_VISUAL, &value)) { - SDL_Log("SDL_GL_ACCELERATED_VISUAL: requested 1, got %d\n", value); + SDL_Log("SDL_GL_ACCELERATED_VISUAL: requested 1, got %d", value); } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_ACCELERATED_VISUAL: %s\n", + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_ACCELERATED_VISUAL: %s", SDL_GetError()); } } @@ -252,7 +252,7 @@ int main(int argc, char *argv[]) float aspectAdjust; if (!SDL_GL_MakeCurrent(state->windows[i], context[i])) { - SDL_Log("SDL_GL_MakeCurrent(): %s\n", SDL_GetError()); + SDL_Log("SDL_GL_MakeCurrent(): %s", SDL_GetError()); /* Continue for next window */ continue; @@ -282,7 +282,7 @@ int main(int argc, char *argv[]) for (i = 0; i < state->num_windows; ++i) { if (event.window.windowID == SDL_GetWindowID(state->windows[i])) { if (!SDL_GL_MakeCurrent(state->windows[i], context[i])) { - SDL_Log("SDL_GL_MakeCurrent(): %s\n", SDL_GetError()); + SDL_Log("SDL_GL_MakeCurrent(): %s", SDL_GetError()); break; } /* Change view port to the new window dimensions */ @@ -301,7 +301,7 @@ int main(int argc, char *argv[]) continue; } if (!SDL_GL_MakeCurrent(state->windows[i], context[i])) { - SDL_Log("SDL_GL_MakeCurrent(): %s\n", SDL_GetError()); + SDL_Log("SDL_GL_MakeCurrent(): %s", SDL_GetError()); /* Continue for next window */ continue; @@ -314,7 +314,7 @@ int main(int argc, char *argv[]) /* Print out some timing information */ now = SDL_GetTicks(); if (now > then) { - SDL_Log("%2.2f frames per second\n", + SDL_Log("%2.2f frames per second", ((double)frames * 1000) / (now - then)); } #ifndef SDL_PLATFORM_ANDROID @@ -327,7 +327,7 @@ int main(int argc, char *argv[]) int main(int argc, char *argv[]) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "No OpenGL ES support on this system\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "No OpenGL ES support on this system"); return 1; } diff --git a/libs/SDL3/test/testgles2.c b/libs/SDL3/test/testgles2.c index 6183c2f7..1184eab7 100644 --- a/libs/SDL3/test/testgles2.c +++ b/libs/SDL3/test/testgles2.c @@ -124,7 +124,7 @@ quit(int rc) { \ GLenum glError = ctx.glGetError(); \ if (glError != GL_NO_ERROR) { \ - SDL_Log("glGetError() = %i (0x%.8x) at line %i\n", glError, glError, __LINE__); \ + SDL_Log("glGetError() = %i (0x%.8x) at line %i", glError, glError, __LINE__); \ quit(1); \ } \ } @@ -551,7 +551,7 @@ render_window(int index) } if (!SDL_GL_MakeCurrent(state->windows[index], context[index])) { - SDL_Log("SDL_GL_MakeCurrent(): %s\n", SDL_GetError()); + SDL_Log("SDL_GL_MakeCurrent(): %s", SDL_GetError()); return; } @@ -750,7 +750,7 @@ int main(int argc, char *argv[]) context = (SDL_GLContext *)SDL_calloc(state->num_windows, sizeof(*context)); if (!context) { - SDL_Log("Out of memory!\n"); + SDL_Log("Out of memory!"); quit(2); } @@ -758,14 +758,14 @@ int main(int argc, char *argv[]) for (i = 0; i < state->num_windows; i++) { context[i] = SDL_GL_CreateContext(state->windows[i]); if (!context[i]) { - SDL_Log("SDL_GL_CreateContext(): %s\n", SDL_GetError()); + SDL_Log("SDL_GL_CreateContext(): %s", SDL_GetError()); quit(2); } } /* Important: call this *after* creating the context */ if (!LoadContext(&ctx)) { - SDL_Log("Could not load GLES2 functions\n"); + SDL_Log("Could not load GLES2 functions"); quit(2); return 0; } @@ -773,61 +773,61 @@ int main(int argc, char *argv[]) SDL_GL_SetSwapInterval(state->render_vsync); mode = SDL_GetCurrentDisplayMode(SDL_GetPrimaryDisplay()); - SDL_Log("Threaded : %s\n", threaded ? "yes" : "no"); + SDL_Log("Threaded : %s", threaded ? "yes" : "no"); if (mode) { - SDL_Log("Screen bpp: %d\n", SDL_BITSPERPIXEL(mode->format)); - SDL_Log("\n"); + SDL_Log("Screen bpp: %d", SDL_BITSPERPIXEL(mode->format)); + SDL_Log("%s", ""); } - SDL_Log("Vendor : %s\n", ctx.glGetString(GL_VENDOR)); - SDL_Log("Renderer : %s\n", ctx.glGetString(GL_RENDERER)); - SDL_Log("Version : %s\n", ctx.glGetString(GL_VERSION)); - SDL_Log("Extensions : %s\n", ctx.glGetString(GL_EXTENSIONS)); - SDL_Log("\n"); + SDL_Log("Vendor : %s", ctx.glGetString(GL_VENDOR)); + SDL_Log("Renderer : %s", ctx.glGetString(GL_RENDERER)); + SDL_Log("Version : %s", ctx.glGetString(GL_VERSION)); + SDL_Log("Extensions : %s", ctx.glGetString(GL_EXTENSIONS)); + SDL_Log("%s", ""); if (SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &value)) { - SDL_Log("SDL_GL_RED_SIZE: requested %d, got %d\n", 5, value); + SDL_Log("SDL_GL_RED_SIZE: requested %d, got %d", 5, value); } else { - SDL_Log("Failed to get SDL_GL_RED_SIZE: %s\n", + SDL_Log("Failed to get SDL_GL_RED_SIZE: %s", SDL_GetError()); } if (SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &value)) { - SDL_Log("SDL_GL_GREEN_SIZE: requested %d, got %d\n", 5, value); + SDL_Log("SDL_GL_GREEN_SIZE: requested %d, got %d", 5, value); } else { - SDL_Log("Failed to get SDL_GL_GREEN_SIZE: %s\n", + SDL_Log("Failed to get SDL_GL_GREEN_SIZE: %s", SDL_GetError()); } if (SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &value)) { - SDL_Log("SDL_GL_BLUE_SIZE: requested %d, got %d\n", 5, value); + SDL_Log("SDL_GL_BLUE_SIZE: requested %d, got %d", 5, value); } else { - SDL_Log("Failed to get SDL_GL_BLUE_SIZE: %s\n", + SDL_Log("Failed to get SDL_GL_BLUE_SIZE: %s", SDL_GetError()); } if (SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &value)) { - SDL_Log("SDL_GL_DEPTH_SIZE: requested %d, got %d\n", depth, value); + SDL_Log("SDL_GL_DEPTH_SIZE: requested %d, got %d", depth, value); } else { - SDL_Log("Failed to get SDL_GL_DEPTH_SIZE: %s\n", + SDL_Log("Failed to get SDL_GL_DEPTH_SIZE: %s", SDL_GetError()); } if (fsaa) { if (SDL_GL_GetAttribute(SDL_GL_MULTISAMPLEBUFFERS, &value)) { - SDL_Log("SDL_GL_MULTISAMPLEBUFFERS: requested 1, got %d\n", value); + SDL_Log("SDL_GL_MULTISAMPLEBUFFERS: requested 1, got %d", value); } else { - SDL_Log("Failed to get SDL_GL_MULTISAMPLEBUFFERS: %s\n", + SDL_Log("Failed to get SDL_GL_MULTISAMPLEBUFFERS: %s", SDL_GetError()); } if (SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &value)) { - SDL_Log("SDL_GL_MULTISAMPLESAMPLES: requested %d, got %d\n", fsaa, + SDL_Log("SDL_GL_MULTISAMPLESAMPLES: requested %d, got %d", fsaa, value); } else { - SDL_Log("Failed to get SDL_GL_MULTISAMPLESAMPLES: %s\n", + SDL_Log("Failed to get SDL_GL_MULTISAMPLESAMPLES: %s", SDL_GetError()); } } if (accel) { if (SDL_GL_GetAttribute(SDL_GL_ACCELERATED_VISUAL, &value)) { - SDL_Log("SDL_GL_ACCELERATED_VISUAL: requested 1, got %d\n", value); + SDL_Log("SDL_GL_ACCELERATED_VISUAL: requested 1, got %d", value); } else { - SDL_Log("Failed to get SDL_GL_ACCELERATED_VISUAL: %s\n", + SDL_Log("Failed to get SDL_GL_ACCELERATED_VISUAL: %s", SDL_GetError()); } } @@ -839,7 +839,7 @@ int main(int argc, char *argv[]) int w, h; if (!SDL_GL_MakeCurrent(state->windows[i], context[i])) { - SDL_Log("SDL_GL_MakeCurrent(): %s\n", SDL_GetError()); + SDL_Log("SDL_GL_MakeCurrent(): %s", SDL_GetError()); /* Continue for next window */ continue; @@ -936,7 +936,7 @@ int main(int argc, char *argv[]) /* Print out some timing information */ now = SDL_GetTicks(); if (now > then) { - SDL_Log("%2.2f frames per second\n", + SDL_Log("%2.2f frames per second", ((double)frames * 1000) / (now - then)); } #ifndef SDL_PLATFORM_ANDROID @@ -949,7 +949,7 @@ int main(int argc, char *argv[]) int main(int argc, char *argv[]) { - SDL_Log("No OpenGL ES support on this system\n"); + SDL_Log("No OpenGL ES support on this system"); return 1; } diff --git a/libs/SDL3/test/testgles2_sdf.c b/libs/SDL3/test/testgles2_sdf.c deleted file mode 100644 index 37890684..00000000 --- a/libs/SDL3/test/testgles2_sdf.c +++ /dev/null @@ -1,785 +0,0 @@ -/* - Copyright (C) 1997-2025 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. -*/ - -#include -#include -#include "testutils.h" - -#ifdef SDL_PLATFORM_EMSCRIPTEN -#include -#endif - -#include - -#if defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_ANDROID) || defined(SDL_PLATFORM_EMSCRIPTEN) || defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_LINUX) -#define HAVE_OPENGLES2 -#endif - -#ifdef HAVE_OPENGLES2 - -#include - -typedef struct GLES2_Context -{ -#define SDL_PROC(ret, func, params) ret (APIENTRY *func) params; -#include "../src/render/opengles2/SDL_gles2funcs.h" -#undef SDL_PROC -} GLES2_Context; - -static SDL_Surface *g_surf_sdf = NULL; -static GLenum g_texture; -static GLenum g_texture_type = GL_TEXTURE_2D; -static GLfloat g_verts[24]; -typedef enum -{ - GLES2_ATTRIBUTE_POSITION = 0, - GLES2_ATTRIBUTE_TEXCOORD = 1, - GLES2_ATTRIBUTE_ANGLE = 2, - GLES2_ATTRIBUTE_CENTER = 3, -} GLES2_Attribute; - -typedef enum -{ - GLES2_UNIFORM_PROJECTION, - GLES2_UNIFORM_TEXTURE, - GLES2_UNIFORM_COLOR, -} GLES2_Uniform; - -static GLint g_uniform_locations[16]; - -static SDLTest_CommonState *state; -static SDL_GLContext *context = NULL; -static int depth = 16; -static GLES2_Context ctx; - -static bool LoadContext(GLES2_Context *data) -{ -#ifdef SDL_VIDEO_DRIVER_UIKIT -#define __SDL_NOGETPROCADDR__ -#elif defined(SDL_VIDEO_DRIVER_ANDROID) -#define __SDL_NOGETPROCADDR__ -#endif - -#if defined __SDL_NOGETPROCADDR__ -#define SDL_PROC(ret, func, params) data->func = func; -#else -#define SDL_PROC(ret, func, params) \ - do { \ - data->func = (ret (APIENTRY *) params)SDL_GL_GetProcAddress(#func); \ - if (!data->func) { \ - return SDL_SetError("Couldn't load GLES2 function %s: %s", #func, SDL_GetError()); \ - } \ - } while (0); -#endif /* __SDL_NOGETPROCADDR__ */ - -#include "../src/render/opengles2/SDL_gles2funcs.h" -#undef SDL_PROC - return true; -} - -/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ -static void -quit(int rc) -{ - int i; - - if (context) { - for (i = 0; i < state->num_windows; i++) { - if (context[i]) { - SDL_GL_DestroyContext(context[i]); - } - } - - SDL_free(context); - } - - SDLTest_CommonQuit(state); - /* Let 'main()' return normally */ - if (rc != 0) { - exit(rc); - } -} - -#define GL_CHECK(x) \ - x; \ - { \ - GLenum glError = ctx.glGetError(); \ - if (glError != GL_NO_ERROR) { \ - SDL_Log("glGetError() = %i (0x%.8x) at line %i\n", glError, glError, __LINE__); \ - quit(1); \ - } \ - } - -/** - * Create shader, load in source, compile, dump debug as necessary. - * - * shader: Pointer to return created shader ID. - * source: Passed-in shader source code. - * shader_type: Passed to GL, e.g. GL_VERTEX_SHADER. - */ -static void process_shader(GLenum *shader, const char *source, GLenum shader_type) -{ - GLint status = GL_FALSE; - const char *shaders[1] = { NULL }; - char buffer[1024]; - GLsizei length; - - /* Create shader and load into GL. */ - *shader = GL_CHECK(ctx.glCreateShader(shader_type)); - - shaders[0] = source; - - GL_CHECK(ctx.glShaderSource(*shader, 1, shaders, NULL)); - - /* Clean up shader source. */ - shaders[0] = NULL; - - /* Try compiling the shader. */ - GL_CHECK(ctx.glCompileShader(*shader)); - GL_CHECK(ctx.glGetShaderiv(*shader, GL_COMPILE_STATUS, &status)); - - /* Dump debug info (source and log) if compilation failed. */ - if (status != GL_TRUE) { - ctx.glGetShaderInfoLog(*shader, sizeof(buffer), &length, &buffer[0]); - buffer[length] = '\0'; - SDL_Log("Shader compilation failed: %s", buffer); - quit(-1); - } -} - -/* Notes on a_angle: - * It is a vector containing sine and cosine for rotation matrix - * To get correct rotation for most cases when a_angle is disabled cosine - * value is decremented by 1.0 to get proper output with 0.0 which is default value - */ -static const char GLES2_VertexSrc_Default_[] = " \ - uniform mat4 u_projection; \ - attribute vec2 a_position; \ - attribute vec2 a_texCoord; \ - attribute vec2 a_angle; \ - attribute vec2 a_center; \ - varying vec2 v_texCoord; \ - \ - void main() \ - { \ - float s = a_angle[0]; \ - float c = a_angle[1] + 1.0; \ - mat2 rotationMatrix = mat2(c, -s, s, c); \ - vec2 position = rotationMatrix * (a_position - a_center) + a_center; \ - v_texCoord = a_texCoord; \ - gl_Position = u_projection * vec4(position, 0.0, 1.0);\ - gl_PointSize = 1.0; \ - } \ -"; - -static const char GLES2_FragmentSrc_TextureABGRSrc_[] = " \ - precision mediump float; \ - uniform sampler2D u_texture; \ - uniform vec4 u_color; \ - varying vec2 v_texCoord; \ - \ - void main() \ - { \ - gl_FragColor = texture2D(u_texture, v_texCoord); \ - gl_FragColor *= u_color; \ - } \ -"; - -/* RGB to ABGR conversion */ -static const char GLES2_FragmentSrc_TextureABGRSrc_SDF[] = " \ - #extension GL_OES_standard_derivatives : enable\n\ - \ - precision mediump float; \ - uniform sampler2D u_texture; \ - uniform vec4 u_color; \ - varying vec2 v_texCoord; \ - \ - void main() \ - { \ - vec4 abgr = texture2D(u_texture, v_texCoord); \ -\ - float sigDist = abgr.a; \ - \ - float w = fwidth( sigDist );\ - float alpha = clamp(smoothstep(0.5 - w, 0.5 + w, sigDist), 0.0, 1.0); \ -\ - gl_FragColor = vec4(abgr.rgb, abgr.a * alpha); \ - gl_FragColor.rgb *= gl_FragColor.a; \ - gl_FragColor *= u_color; \ - } \ -"; - -/* RGB to ABGR conversion DEBUG */ -static const char *GLES2_FragmentSrc_TextureABGRSrc_SDF_dbg = " \ - #extension GL_OES_standard_derivatives : enable\n\ - \ - precision mediump float; \ - uniform sampler2D u_texture; \ - uniform vec4 u_color; \ - varying vec2 v_texCoord; \ - \ - void main() \ - { \ - vec4 abgr = texture2D(u_texture, v_texCoord); \ -\ - float a = abgr.a; \ - gl_FragColor = vec4(a, a, a, 1.0); \ - } \ -"; - -static float g_val = 1.0f; -static int g_use_SDF = 1; -static int g_use_SDF_debug = 0; -static float g_angle = 0.0f; -static float matrix_mvp[4][4]; - -typedef struct shader_data -{ - GLint shader_program; - GLenum shader_frag, shader_vert; - - GLint attr_position; - GLint attr_color, attr_mvp; - -} shader_data; - -static void -Render(int width, int height, shader_data *data) -{ - float *verts = g_verts; - ctx.glViewport(0, 0, 640, 480); - - GL_CHECK(ctx.glClear(GL_COLOR_BUFFER_BIT)); - - GL_CHECK(ctx.glUniformMatrix4fv(g_uniform_locations[GLES2_UNIFORM_PROJECTION], 1, GL_FALSE, (const float *)matrix_mvp)); - GL_CHECK(ctx.glUniform4f(g_uniform_locations[GLES2_UNIFORM_COLOR], 1.0f, 1.0f, 1.0f, 1.0f)); - - GL_CHECK(ctx.glVertexAttribPointer(GLES2_ATTRIBUTE_ANGLE, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *)(verts + 16))); - GL_CHECK(ctx.glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *)(verts + 8))); - GL_CHECK(ctx.glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *)verts)); - - GL_CHECK(ctx.glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)); -} - -static void renderCopy_angle(float degree_angle) -{ - const float radian_angle = (float)(3.141592 * degree_angle) / 180.0f; - const GLfloat s = (GLfloat)SDL_sin(radian_angle); - const GLfloat c = (GLfloat)SDL_cos(radian_angle) - 1.0f; - GLfloat *verts = g_verts + 16; - *(verts++) = s; - *(verts++) = c; - *(verts++) = s; - *(verts++) = c; - *(verts++) = s; - *(verts++) = c; - *(verts++) = s; - *(verts++) = c; -} - -static void renderCopy_position(SDL_Rect *srcrect, SDL_Rect *dstrect) -{ - GLfloat minx, miny, maxx, maxy; - GLfloat minu, maxu, minv, maxv; - GLfloat *verts = g_verts; - - minx = (GLfloat)dstrect->x; - miny = (GLfloat)dstrect->y; - maxx = (GLfloat)(dstrect->x + dstrect->w); - maxy = (GLfloat)(dstrect->y + dstrect->h); - - minu = (GLfloat)srcrect->x / (GLfloat)g_surf_sdf->w; - maxu = (GLfloat)(srcrect->x + srcrect->w) / (GLfloat)g_surf_sdf->w; - minv = (GLfloat)srcrect->y / (GLfloat)g_surf_sdf->h; - maxv = (GLfloat)(srcrect->y + srcrect->h) / (GLfloat)g_surf_sdf->h; - - *(verts++) = minx; - *(verts++) = miny; - *(verts++) = maxx; - *(verts++) = miny; - *(verts++) = minx; - *(verts++) = maxy; - *(verts++) = maxx; - *(verts++) = maxy; - - *(verts++) = minu; - *(verts++) = minv; - *(verts++) = maxu; - *(verts++) = minv; - *(verts++) = minu; - *(verts++) = maxv; - *(verts++) = maxu; - *(verts++) = maxv; -} - -static int done; -static Uint32 frames; -static shader_data *datas; - -static void loop(void) -{ - SDL_Event event; - int i; - - /* Check for events */ - ++frames; - while (SDL_PollEvent(&event) && !done) { - switch (event.type) { - case SDL_EVENT_KEY_DOWN: - { - const int sym = event.key.key; - - if (sym == SDLK_TAB) { - SDL_Log("Tab"); - } - - if (sym == SDLK_LEFT) { - g_val -= 0.05f; - } - if (sym == SDLK_RIGHT) { - g_val += 0.05f; - } - if (sym == SDLK_UP) { - g_angle -= 1.0f; - } - if (sym == SDLK_DOWN) { - g_angle += 1.0f; - } - - break; - } - - case SDL_EVENT_WINDOW_RESIZED: - for (i = 0; i < state->num_windows; ++i) { - if (event.window.windowID == SDL_GetWindowID(state->windows[i])) { - int w, h; - if (!SDL_GL_MakeCurrent(state->windows[i], context[i])) { - SDL_Log("SDL_GL_MakeCurrent(): %s\n", SDL_GetError()); - break; - } - /* Change view port to the new window dimensions */ - SDL_GetWindowSizeInPixels(state->windows[i], &w, &h); - ctx.glViewport(0, 0, w, h); - state->window_w = event.window.data1; - state->window_h = event.window.data2; - /* Update window content */ - Render(event.window.data1, event.window.data2, &datas[i]); - SDL_GL_SwapWindow(state->windows[i]); - break; - } - } - break; - - default: - break; - } - SDLTest_CommonEvent(state, &event, &done); - } - - matrix_mvp[3][0] = -1.0f; - matrix_mvp[3][3] = 1.0f; - - matrix_mvp[0][0] = 2.0f / 640.0f; - matrix_mvp[1][1] = -2.0f / 480.0f; - matrix_mvp[3][1] = 1.0f; - - renderCopy_angle(g_angle); - - { - int w, h; - SDL_Rect rs, rd; - - SDL_GetWindowSizeInPixels(state->windows[0], &w, &h); - - rs.x = 0; - rs.y = 0; - rs.w = g_surf_sdf->w; - rs.h = g_surf_sdf->h; - rd.w = (int)((float)g_surf_sdf->w * g_val); - rd.h = (int)((float)g_surf_sdf->h * g_val); - rd.x = (w - rd.w) / 2; - rd.y = (h - rd.h) / 2; - renderCopy_position(&rs, &rd); - } - - if (!done) { - for (i = 0; i < state->num_windows; ++i) { - if (!SDL_GL_MakeCurrent(state->windows[i], context[i])) { - SDL_Log("SDL_GL_MakeCurrent(): %s\n", SDL_GetError()); - - /* Continue for next window */ - continue; - } - Render(state->window_w, state->window_h, &datas[i]); - SDL_GL_SwapWindow(state->windows[i]); - } - } -#ifdef SDL_PLATFORM_EMSCRIPTEN - else { - emscripten_cancel_main_loop(); - } -#endif -} - -int main(int argc, char *argv[]) -{ - int fsaa, accel; - int value; - int i; - const SDL_DisplayMode *mode; - Uint64 then, now; - shader_data *data; - char *path = NULL; - - /* Initialize parameters */ - fsaa = 0; - accel = 0; - - /* Initialize test framework */ - state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO); - if (!state) { - return 1; - } - for (i = 1; i < argc;) { - int consumed; - - consumed = SDLTest_CommonArg(state, i); - if (consumed == 0) { - if (SDL_strcasecmp(argv[i], "--fsaa") == 0) { - ++fsaa; - consumed = 1; - } else if (SDL_strcasecmp(argv[i], "--accel") == 0) { - ++accel; - consumed = 1; - } else if (SDL_strcasecmp(argv[i], "--zdepth") == 0) { - i++; - if (!argv[i]) { - consumed = -1; - } else { - char *endptr = NULL; - depth = (int)SDL_strtol(argv[i], &endptr, 0); - if (endptr != argv[i] && *endptr == '\0') { - consumed = 1; - } else { - consumed = -1; - } - } - } else { - consumed = -1; - } - } - if (consumed < 0) { - static const char *options[] = { "[--fsaa]", "[--accel]", "[--zdepth %d]", NULL }; - SDLTest_CommonLogUsage(state, argv[0], options); - quit(1); - } - i += consumed; - } - - /* Set OpenGL parameters */ - state->window_flags |= SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; - state->gl_red_size = 5; - state->gl_green_size = 5; - state->gl_blue_size = 5; - state->gl_depth_size = depth; - state->gl_major_version = 2; - state->gl_minor_version = 0; - state->gl_profile_mask = SDL_GL_CONTEXT_PROFILE_ES; - - if (fsaa) { - state->gl_multisamplebuffers = 1; - state->gl_multisamplesamples = fsaa; - } - if (accel) { - state->gl_accelerated = 1; - } - if (!SDLTest_CommonInit(state)) { - quit(2); - return 0; - } - - context = (SDL_GLContext *)SDL_calloc(state->num_windows, sizeof(*context)); - if (!context) { - SDL_Log("Out of memory!\n"); - quit(2); - } - - /* Create OpenGL ES contexts */ - for (i = 0; i < state->num_windows; i++) { - context[i] = SDL_GL_CreateContext(state->windows[i]); - if (!context[i]) { - SDL_Log("SDL_GL_CreateContext(): %s\n", SDL_GetError()); - quit(2); - } - } - - /* Important: call this *after* creating the context */ - if (!LoadContext(&ctx)) { - SDL_Log("Could not load GLES2 functions\n"); - quit(2); - return 0; - } - - SDL_memset(matrix_mvp, 0, sizeof(matrix_mvp)); - - { - SDL_Surface *tmp; - char *f; - g_use_SDF = 1; - g_use_SDF_debug = 0; - - if (g_use_SDF) { - f = "testgles2_sdf_img_sdf.bmp"; - } else { - f = "testgles2_sdf_img_normal.bmp"; - } - - SDL_Log("SDF is %s", g_use_SDF ? "enabled" : "disabled"); - - /* Load SDF BMP image */ -#if 1 - path = GetNearbyFilename(f); - - if (!path) { - path = SDL_strdup(f); - } - - if (!path) { - SDL_Log("out of memory\n"); - exit(-1); - } - - tmp = SDL_LoadBMP(path); - if (!tmp) { - SDL_Log("missing image file: %s", path); - exit(-1); - } else { - SDL_Log("Load image file: %s", path); - } - - SDL_free(path); -#else - /* Generate SDF image using SDL_ttf */ - -#include "SDL_ttf.h" - char *font_file = "./font/DroidSansFallback.ttf"; - char *str = "Abcde"; - SDL_Color color = { 0, 0, 0, 255 }; - - TTF_Init(); - TTF_Font *font = TTF_OpenFont(font_file, 72); - - if (font == NULL) { - SDL_Log("Cannot open font %s", font_file); - } - - TTF_SetFontSDF(font, g_use_SDF); - SDL_Surface *tmp = TTF_RenderUTF8_Blended(font, str, color); - - SDL_Log("err: %s", SDL_GetError()); - if (tmp == NULL) { - SDL_Log("can't render text"); - return -1; - } - - SDL_SaveBMP(tmp, f); - - TTF_CloseFont(font); - TTF_Quit(); -#endif - g_surf_sdf = SDL_ConvertSurface(tmp, SDL_PIXELFORMAT_ABGR8888); - - SDL_SetSurfaceBlendMode(g_surf_sdf, SDL_BLENDMODE_BLEND); - } - - SDL_GL_SetSwapInterval(state->render_vsync); - - mode = SDL_GetCurrentDisplayMode(SDL_GetPrimaryDisplay()); - if (mode) { - SDL_Log("Screen bpp: %d\n", SDL_BITSPERPIXEL(mode->format)); - SDL_Log("\n"); - } - SDL_Log("Vendor : %s\n", ctx.glGetString(GL_VENDOR)); - SDL_Log("Renderer : %s\n", ctx.glGetString(GL_RENDERER)); - SDL_Log("Version : %s\n", ctx.glGetString(GL_VERSION)); - SDL_Log("Extensions : %s\n", ctx.glGetString(GL_EXTENSIONS)); - SDL_Log("\n"); - - if (SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &value)) { - SDL_Log("SDL_GL_RED_SIZE: requested %d, got %d\n", 5, value); - } else { - SDL_Log("Failed to get SDL_GL_RED_SIZE: %s\n", - SDL_GetError()); - } - if (SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &value)) { - SDL_Log("SDL_GL_GREEN_SIZE: requested %d, got %d\n", 5, value); - } else { - SDL_Log("Failed to get SDL_GL_GREEN_SIZE: %s\n", - SDL_GetError()); - } - if (SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &value)) { - SDL_Log("SDL_GL_BLUE_SIZE: requested %d, got %d\n", 5, value); - } else { - SDL_Log("Failed to get SDL_GL_BLUE_SIZE: %s\n", - SDL_GetError()); - } - if (SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &value)) { - SDL_Log("SDL_GL_DEPTH_SIZE: requested %d, got %d\n", depth, value); - } else { - SDL_Log("Failed to get SDL_GL_DEPTH_SIZE: %s\n", - SDL_GetError()); - } - if (fsaa) { - if (SDL_GL_GetAttribute(SDL_GL_MULTISAMPLEBUFFERS, &value)) { - SDL_Log("SDL_GL_MULTISAMPLEBUFFERS: requested 1, got %d\n", value); - } else { - SDL_Log("Failed to get SDL_GL_MULTISAMPLEBUFFERS: %s\n", - SDL_GetError()); - } - if (SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &value)) { - SDL_Log("SDL_GL_MULTISAMPLESAMPLES: requested %d, got %d\n", fsaa, - value); - } else { - SDL_Log("Failed to get SDL_GL_MULTISAMPLESAMPLES: %s\n", - SDL_GetError()); - } - } - if (accel) { - if (SDL_GL_GetAttribute(SDL_GL_ACCELERATED_VISUAL, &value)) { - SDL_Log("SDL_GL_ACCELERATED_VISUAL: requested 1, got %d\n", value); - } else { - SDL_Log("Failed to get SDL_GL_ACCELERATED_VISUAL: %s\n", - SDL_GetError()); - } - } - - datas = (shader_data *)SDL_calloc(state->num_windows, sizeof(shader_data)); - - /* Set rendering settings for each context */ - for (i = 0; i < state->num_windows; ++i) { - - int w, h; - if (!SDL_GL_MakeCurrent(state->windows[i], context[i])) { - SDL_Log("SDL_GL_MakeCurrent(): %s\n", SDL_GetError()); - - /* Continue for next window */ - continue; - } - - { - int format = GL_RGBA; - int type = GL_UNSIGNED_BYTE; - - GL_CHECK(ctx.glGenTextures(1, &g_texture)); - - ctx.glActiveTexture(GL_TEXTURE0); - ctx.glPixelStorei(GL_PACK_ALIGNMENT, 1); - ctx.glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - ctx.glBindTexture(g_texture_type, g_texture); - - ctx.glTexParameteri(g_texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - ctx.glTexParameteri(g_texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - ctx.glTexParameteri(g_texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - ctx.glTexParameteri(g_texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - GL_CHECK(ctx.glTexImage2D(g_texture_type, 0, format, g_surf_sdf->w, g_surf_sdf->h, 0, format, type, NULL)); - GL_CHECK(ctx.glTexSubImage2D(g_texture_type, 0, 0 /* xoffset */, 0 /* yoffset */, g_surf_sdf->w, g_surf_sdf->h, format, type, g_surf_sdf->pixels)); - } - - SDL_GetWindowSizeInPixels(state->windows[i], &w, &h); - ctx.glViewport(0, 0, w, h); - - data = &datas[i]; - - /* Shader Initialization */ - process_shader(&data->shader_vert, GLES2_VertexSrc_Default_, GL_VERTEX_SHADER); - - if (g_use_SDF) { - if (g_use_SDF_debug == 0) { - process_shader(&data->shader_frag, GLES2_FragmentSrc_TextureABGRSrc_SDF, GL_FRAGMENT_SHADER); - } else { - process_shader(&data->shader_frag, GLES2_FragmentSrc_TextureABGRSrc_SDF_dbg, GL_FRAGMENT_SHADER); - } - } else { - process_shader(&data->shader_frag, GLES2_FragmentSrc_TextureABGRSrc_, GL_FRAGMENT_SHADER); - } - - /* Create shader_program (ready to attach shaders) */ - data->shader_program = GL_CHECK(ctx.glCreateProgram()); - - /* Attach shaders and link shader_program */ - GL_CHECK(ctx.glAttachShader(data->shader_program, data->shader_vert)); - GL_CHECK(ctx.glAttachShader(data->shader_program, data->shader_frag)); - GL_CHECK(ctx.glLinkProgram(data->shader_program)); - - ctx.glBindAttribLocation(data->shader_program, GLES2_ATTRIBUTE_POSITION, "a_position"); - ctx.glBindAttribLocation(data->shader_program, GLES2_ATTRIBUTE_TEXCOORD, "a_texCoord"); - ctx.glBindAttribLocation(data->shader_program, GLES2_ATTRIBUTE_ANGLE, "a_angle"); - ctx.glBindAttribLocation(data->shader_program, GLES2_ATTRIBUTE_CENTER, "a_center"); - - /* Predetermine locations of uniform variables */ - g_uniform_locations[GLES2_UNIFORM_PROJECTION] = ctx.glGetUniformLocation(data->shader_program, "u_projection"); - g_uniform_locations[GLES2_UNIFORM_TEXTURE] = ctx.glGetUniformLocation(data->shader_program, "u_texture"); - g_uniform_locations[GLES2_UNIFORM_COLOR] = ctx.glGetUniformLocation(data->shader_program, "u_color"); - - GL_CHECK(ctx.glUseProgram(data->shader_program)); - - ctx.glEnableVertexAttribArray((GLenum)GLES2_ATTRIBUTE_ANGLE); - ctx.glDisableVertexAttribArray((GLenum)GLES2_ATTRIBUTE_CENTER); - ctx.glEnableVertexAttribArray(GLES2_ATTRIBUTE_POSITION); - ctx.glEnableVertexAttribArray((GLenum)GLES2_ATTRIBUTE_TEXCOORD); - - ctx.glUniform1i(g_uniform_locations[GLES2_UNIFORM_TEXTURE], 0); /* always texture unit 0. */ - ctx.glActiveTexture(GL_TEXTURE0); - ctx.glBindTexture(g_texture_type, g_texture); - GL_CHECK(ctx.glClearColor(1, 1, 1, 1)); - - /* SDL_BLENDMODE_BLEND */ - GL_CHECK(ctx.glEnable(GL_BLEND)); - ctx.glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - ctx.glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD); - } - - /* Main render loop */ - frames = 0; - then = SDL_GetTicks(); - done = 0; - -#ifdef SDL_PLATFORM_EMSCRIPTEN - emscripten_set_main_loop(loop, 0, 1); -#else - while (!done) { - loop(); - } -#endif - - /* Print out some timing information */ - now = SDL_GetTicks(); - if (now > then) { - SDL_Log("%2.2f frames per second\n", - ((double)frames * 1000) / (now - then)); - } -#ifndef SDL_PLATFORM_ANDROID - quit(0); -#endif - return 0; -} - -#else /* HAVE_OPENGLES2 */ - -int main(int argc, char *argv[]) -{ - SDL_Log("No OpenGL ES support on this system\n"); - return 1; -} - -#endif /* HAVE_OPENGLES2 */ diff --git a/libs/SDL3/test/testgles2_sdf_img_normal.bmp b/libs/SDL3/test/testgles2_sdf_img_normal.bmp deleted file mode 100644 index 1209e1b1df7105dad9e3e401b9dd9a0d255e4162..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68122 zcmeHP3AA3*6@Ez&No!mPk;*euL8uZ#7ZGD9RU|bh7VSz}sZ^F4O00@`imECLMcT?L zOCvS5B_gD0kkrr`s-iXP!lQ_>`hD@v%6aGQeeSvUp8LnDy_YZd+;jGHzW?rX&%OWu z?ELlqeS5S~P6ECM%mEGrdbG8-^}_L*KA(=G>B%Q;ZJ++fzE9f6jTz|;TGJRX28;n? zz!)$Fi~(c77%&Em0b{@zFb0ePW55_N28;n?z!)$Fi~(c77%&Em0b{@zFb0ePW55_N z28;n?z!)$Fi~(c77%&Em0b{@zFb0ePW55_N28;n?;QyC_l`ys8zHBl24J2=!u83w_uIpZj2jr|oc$d9 zb}XN;K4>=}$nPsSm-PG?TKg{8wg>)loeqYh8Gsf$wf`mf*a;{rYrx=UAT^G!_cZKy zFY{#|ocKDf?dw!+^Uuw{50qI$T>S9JI=>qj3265Ma-*%IQ!v(Q;d&6xgXjG0$&Dt` zbw9>aJ{avX>x`5`2Yl?}`K;UIz5Z0-BS4B*rSGVcNo@yx?iH%UayGoqI1eY>)3`DJ z=*Fua*M}kZ1-{Q*ZLU$8{2l{Rod2Mod(l?OY6!$Vjg-p;1xZNtaa*U&2pqLFK#CRX zdmp}X?6cQfX27JN~D1xUFs8m#!wFxb7R_?2Rn?TgjNp^><} z_q0m*zi!dywRu4jQho4#!T$}+JBr`Gqo4Ok)*jctOMyE9twvpLZ$oD@ppNia%K3{O zIfn(npMbf*QvmnSnoVkba4qhL_;LQ{K<6spbYK#21#mB*aWooZ(q}<`Rb^Kgrri5^ zALG93QQ$scKJW|>_ z{_#qTuM23hA_m3-Zveg>@6#G@7%DCNoQm!n-2WT~tQzq?0AsxGpA5_f!u`Zx^u^>l z4EpnQZSE&liWz1aYlk0=*B>OrNU0C*CH6@0>tz>U8ZZhdlCe;5@xmkT3%uv13a?4t*Frzid8$vRS5(K(L6M(P6=B}r0l3aF z*P{C1JxrPt`%=~ z^MH%*AMYx#%`yCl68qLf=SB7L(?ma#8rNl?55HaJdKv^j+C7r%0N+11Ee9ijpTFO} zr$%r-k7>^&E=C#m-1EN*I9vb7XORudILoAau96Se-u{_lNNzS!;*yip_XDx|;I;Q9 zDR5%nR?zc5AHU6ge5y=_qHpWBuS#`NQ;+M7AJ=blk5)&14rAY6*e>Jy=!maV%Q(uY z%k?dslRM|Vt|>Vaj$Iu8*n$4kXW&?U{4qn~_bNFu-}VIm-1lhv8m>PB5`5HE;hL9Qb0mk!8Det{;4`zvQ)-A+pvW~t^7D&SCk^TGU6GU*`_^k9 z=C+Y|JCukQs}HVgb%pzDjhB=<9viXe?hR0`x|ClN`@Tz*SpO(FzgT^&P|}yA&b4tNAn`I=G6?!&d-GO2mouFyfRsP`a_#R< zkHo-Gl4#Gt%(Lh{Q&NDMN_W6s;_>mCenazK=y+L)H8E5!IM?dq^#Z#x!;e8(;^nmj zC)`6xwtSz}H^DxK${ZyJelNuO&mo7vi8N34rHXd_@ml#TNNkQ#EfHM361 zI9h%1n$9J$y+faZAWvglnk%2ZS|$HPASs8O9C806#b95ma2=L>Jdo<3VLh&AZz(x) zt?9@FZND-L{>zG1AAIkWOJaMZwF-jpy^Hjj^LJIP679E$RruC&-Vp=RJlU5jyuKtK zccnULf!;Mrj#A#a`>K3juhmED_lqf%UJ&7g@26tId!oeCA7Vxs$GCrz;AdevuRweUGH& zp7XjJ9GPn@KQ|WRO3Oc2{}V2Wgkw+WJO|{8o$6<5LT-|ZRv$M?$`$)ghMhJKzNglN z&nBAP4VqEr{#NC%Wn``?Q;OxOahR*WOnq=JXGi9mE2q%Uo+%^>I$C{96LhO~O@d*V zuRD*uqvcxT^upuqRg)=c*DI1k&OPXmNSu_EV_b#YwaIco#hl-aQsloVMfN-J1H^9TdHX9Z8Yw4^*^4P zpriWo?LP{97$ZTZ_R=rFDSMT7ue+-enrV)ZpI+{ zDKW@Vs%Y<_HSTluKbo4Lr*|ycQvBD^zqF^9+T?FkB!BGNEY*pir`1Q5H9>H{sOuK| ztL46oX4KjLpkn(D`g46ZSCGP@zdM!k&-uOEx0QJ^ZmRH|x0EM2JRk!&U&()!b)p}9 zY4_#5F;-S4!a&N6*LNM!>Vw}qrrQEqMERv~EkZjr4USynUJoel6FJ_8y2K;FA zObv0Z;$wcQg91IRKJF;6(}uZ+m*zZ0Gl=v*rTD7*`+2QCnD^?Dd{T$_T%_ws z6zE7CvTvUR`y474MRLgXy9mCo*5;WyhY5<0H&Y!H=xN`RUR_|P4IhL7Y0mtPeOb*& z=-*oL!}}BOQ*|U(AN(ClT^Rxg5(n(NIKlbu5qmz@v_g(R5N!^}WJ)0R?2sB_+en@p zr8-gc`bT^puhZuY&j*SR z-tYNdvuW7?0i@56eSEg6E9=97=AZqkvJ@1x>upS`6Ge~TA80x5s@SA-^WG!*P5pk0 z`xEW`$%vE$3Up%i@koJf$}oLM^XK0JteWBgI=3r6=r;!kDQRfyJKqzmoZ=v&b27#x zj$B{FwA;{iim#d7G|P2dsQBgHnQK^8845!;PyhHX`ct0mw7TtpeVIL)mVc~1nD2I) zVM702(DCQ&x9?7{cPfWO{P6d^Ro(|W->FCL1^xW}_QX^tf?jX*y%6!uIAvrQl>OZN z_TVy(JYC+G_%6lw<=R!B&7J!mXlQHC!A>c1{3XU*F8=X~h)tQHqWZWW&Z_KT_}=y* zz|Yxlr_9~WgT9`R_~QPvY1teB{QUj)YZ&WaF@Z@Dzb-~u*Ygygv(R7VvmCGZV}9QP z>dKjL;O6Qdrx!Tped}$-cKZU`)ZwD~V7^xYtn)I$??L^!`t5&Vtn8Zq-H1Q>o(Po9 z5hiV`@t;JQ0X=^netR~?SjS~#ER?n1-1@%D_@r*^zI|3nXT0aU1^D^6_Os~cy``>f z3^E=j2m=6n;dW!sjr4&lURe&u3zM zP-rNe^Y3)_1vsYX{-pLJ(BZ!2NPxNWbLLue2Eh1y_Vew2hVxXp6pFrW*nR`!-0y7z zkQWNqSbmqZ8^Ezwfza-C^nD=oQ?H7w0;A`FFpfLt=X4sd6|fvYVV8lj896l7#ntu5FY*XO>9*GV1O z1;%A!`th|kuT4HDr$`?tX=|P2pSc#@C*Fh3c7V2z!B8dH5>{^lQeI&n*Nmb(oz1h* zW&Pz8zRQ%ZclL2C6s?|k56>xDeVl?Iyk_nJ94~c_{I255Kn~d%PIyh%$tScuutZ{9 zyZ)9bKKIz%>ruGggn9A2jwY;VLq`tqxM{Z7e51kE2@v8LQ3SVVpWhl=8s>E_OufTq2XHdS2asA=3Q>F4@ z16aFntgG9I=1;QAI5zMI(rH~<(0@ZLBS;5xXZ zh0k+Cfc=0&fy04s0DNv42=oA&67sS=z~`A!0C{2D{yZfW!r#eYhS=W9Os43DN4~h9-iUPn7|ykHyq*Z!XmU_W_qGW1B8E&)U-J=0K=t|pMoQ5^>68fZf3gf$)W<9g| z$Vz8rXI39wsXGRzVSPyF{C>S(SJSL#Rv%gEtnAF{qbqf*;8eO-gf((YSF`MARv+0Z zt>n<^qdRTW(G}K1cwXgu-R_a}9;*+Xn^ulkeROA=-ywzd;Ge&Naen9Cq*#44$!@xD ztB>wn^+p$Kz^@6veR+42>^)W=*(t5$(CR~`?Fw}JHQ~4UJB6mj>Z56f)BIa~$UJR> z?)wBxlhw2LT76`vw30)sk4m&PZe;b*IK@c;tUi)xYPpitN6RS}16qBEv@G#XzGHq` zfdBVVOFYTXK>`~KpMm>aJ_pmcDH;RDfH7bU7z4(DF<=ZB1IBX8( nfH7bU7z4(DF<=ZB1IBX8(fH7bUkb(aJ?X9&q diff --git a/libs/SDL3/test/testgles2_sdf_img_sdf.bmp b/libs/SDL3/test/testgles2_sdf_img_sdf.bmp deleted file mode 100644 index 5f983d2d211509e9e91e4e65e173d78c1a9d64cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 72202 zcmeI&2Y6If-uUsgUef zcmKokHe2a$mJ4wP-o(*Z>2GcSwhEt#P5--|!<6#xzy0mM|KquTw;eL*n3T%gVJ-r> z2;?I0pBe!-w3VCur}Z(lZ<#jU71`g^wpV03%j?;x{dGS7jClDjo1A7LHp*2JGt z9Csd?>y!0f=k?9qWB=DcY6=w(mX0(s4T8E^z!^k=k}QzS}4JX1nIl)+oS+O~+ArWxfUX z7|W$uS8F!4<@`IhK66*>3FDI5U*|I{UhS!K%=X>=Xl1mdmTPtCC731kXY(6-D2f;R*>yy`cz3gAuJ%>@(1AD+VWS%;9@3)O(a3cDkANn`( zyXQ+`jBLX^at&?^*X6Rl58NMp&Nk=-`*;8j!4WtXC!sG=`{wb=B?By7a z5x5kWHGTU1B3K{9z?eCA-C)kP#X4A;;`?A5_#AW4`8CGRRx=elSnQU;+{muA*)foHN@#0M60cSk|&G4{%@Tj+1c?E=O~H zvfk^w{%qJk`gE$H9voVR}!aNOSGIPIfjbdHaLu{B4w zz^brp2>WgS9Y@fB^tSzOpKSMPm_rv~2>Qckc+R>^^I^=bH~;LT`Pdoe zXQq(E7I^2xgFd4=v;P=#c8QVA_z+!u^P2@ZhmZH={% zURL3Rbb%&tzDowdebwih6UO>pIQ}X;h19+U{d<9brI2@1dUyms;W{%tOr?>5Q+cj?H&RsB%ZF4wWN5(cRuRL!oC!ieWqj|YC%+sK( z#6bZH;cv3u=nHeuvAKqBg3q$Q58*L9joC0x0lynB$78&VZ4%yl3lbQO3vnilSugB~ zZLlU%OKZN^FXK88=9bTLu3kk=glg*SgE{Fq`eA?k9jjq!%NpF+0o`#5E`_;dOkPG* zpRD&fuXjIs6k+$gNS(2E&Tqs$Fc+T1D|i#{V*x(KCrzJze-HnJF_?u1Vg8u+mtiQ( z2glGEn_wkmDr<3aTkMX*&=2RpdAtEWcP7k-d3YVQNbg(FzmKT1e{aESy~mt!9o&bB zFz3$4$v6PU+kV>L<1qw|!|~h+$LBa5ujBUlsd2GwzuPCFJHdV*gF$e;Iwr^F7=wAVzi;3je26;O*MQ$WpBk^1_-+n7 zhUswp=0_YC;dJ!IuGkEzWnI1)N9%`T0(^#J`w9&aKBevj7_TcZ80Le|TMtWHHsD70 zO#3th#wiK&e<7m!WWCoJQ~PBueTGc;)Ny_eoM-dpIn0N7QI8++FZ?@$Upe@`~4%l z_H)=r^XdhdCyv?t7=pvG6T0I>oQ<(CH>YD39N!1{5{}#PXKFiWcMoE&1J;o`4uGM+Ka3$L1JqcL99ncla5+m+*7hGGe&wFq^hQmGYKy<*G2#Wo*f4wmjj>GXdE@P6Z{oveU>TB>IY^NN@ z!ra&#OIx<$#=UVohQU}l9%E!|g7!0gnmaGzKDY*};rwN~*7L^8Iq>r%e2cKSXL^R` zoC{<1K5W~*PDUK(z9`oz!nu0__Ui-q{9h2(hvv>N;a+pt zJ#ap%a1$=Tao8XB)Baw8N$`EWC31-<9QQ5BGWzg&wQ#x0x^`J z2>B>LC%EoUf_)u_+fWJjL!a*$8({mH+R65u>&tQ5|2N>ex))bs2%IzfwjP4gngi$g zU<||WLH-L}UXXlcpghV9S;1276xFbf|dD%aEdljQnp z)FaavoY%KdgN0~mzNA0X_OFT=!=qj>&ig&a?U9`fW+yvbpv*p6Nbo{~yK;I1fi-S8Rl!tir+8=!%nY5pIV0 z@D_eRRGZHCJor8sk24Xh+x0naX|ZqS*x_(~ufqK>USA@rFOIne55l}m!u#rx>Av4N z?>ou4_BhiuEj?%Md&=Z1 z@Dy&vaGZ!i7zNMSZ~Ol#!g9a4b~4pF4-1f~&T|cL{wk3`3?(SSw%7;mOP&wby?Gk+ z^=FR5p1rK+8+mpu+-E9Kj#6|%0aA1~)Uu?S)#>Kqt3*X(_ zp)K}?`EfR`#NC*Mx8dFp)yC4+{l;@Yz*D#t!_gP+qxRGOz69U1j$>)t3A^vBh-aEh zHLwo}#884Fn4j)PWf+CqU|zVE+`pC}tj*2v*M-Ih681G4V9R8;G8tKnlUf+M?*&pC3 z7^mUzcYwbw+=u4CdgIxWHnWXS)EqX@W(_KlKnx`)g8NWkq^^7C_EW5gb)PIm#sLlH;%_JRKRzR@16#vKR@;R7u36_O~X|f0^_g~Hbl0?ez^}FfwOQm z9>B|p+SlyMBDh!0z%_^?31eQ5)c$63?7Pr5ov#H=>iGN|-@*K8?m3IO#`W zXdAZsF%~rO*nBW&enZgLY(BlG29-!4h7!2{xDWZ=eaUtI9Ne#dMmEp(cWVR8lOR@p znj6N;IrUj#^J=VXQH2VWqZD0Gfb_BfCw4?{oQd(c5A(1PQGGV9&V#?ZZ^Q*S0efRB zWK&k=qOH*tC&7K_W|)h$_z_`!Fa~vSZ@mj+5JwW`s4)w>H~qZtE5~b_uH)x1tI2FW zU&Nd68s{ke{`BvzM`LI#&4r;j9K{%j(YOP)@jkN2kDs{C_TRzlaE$g#9=oqNAMe5T z%@@aI-^}q3@Dy&va0GKbm*Y zf&!$MH8{~8zE|!0NZbzN?z}|hj_rPg*|-CvFaSNVJzAr=vNjiV#K9N{*Mw`s`Kd!N zu1udlQ19G63fG`(F^(k6uX<#!%Wnmx!(X^aZNSs?*tf&Bd{|z!aB{^gnIjS6wXEhL7pw*I4owK{}SnK z$2pg5I$zIc)crx-LasCR#@4;$YK+E6jKF1ZPA9>9c@4H5+@I<559;eM2d+(@cRKpP zXWoVy_+%%^S{@dmxjDayb4SmrE{c#qIi*1>s@8TzfJ=gQL?_9VKx<+Ft z!xb>TFW@soJ;OS$aXhZ28*v%V!C(w*;&X?h9GAepUWZAzA2X4Jxp^tBg!$uhzeH3Y zoCnv2<2LVnwlO*teVUxY=MdPo`Rkb7@3R?S1J~7{5(&gm0{0*Hp}Q~#b@&}&eYNfr z%)@jTtIJ_b&O{I^KaH3DJr@_j{4plpb0_S}Gk6xk9%5g-_YmxWwUMc`;^em2560(W zxW_$#cMz4=e^6fs+qECIX&idB&>*fKi@WhWj7wPDJl}vf@GvSc48|yqB&t!5sApLB z1)O(tYXZ!Z?p?{k;s1%Qnpy^WF32ysQAEuIFn}4&%`S zU7H-p=Mix3U9a{voBXj|=duRIB!L(XZ~CGw8RKv^eAYhL8ml0zY(hmB_0) z-LM}H#jzNGq3}Lq)E~oPzC8)wJHH~T4na8aVd}#9-ft!F|Z};hypXqMq|9^>c9#%n8SBe~eX8h+R3qH+rB1uC0M6$4Fd? zi(u@mb8j{7>mjPFO{H^UoP3^fy9>s#4!(!N#_|(&=7u?P3nnb3+qlm;eiuI@ti4~T zGY_7Ec{&p2Ng3iuq8jxGdxqz2Bk1={9A5xqW_-8AN>~|f;G9_JHD3EDYT?+U+Hj7a zhp`-uk(i8Ga4r9iu=|%#_aUCaWH`5{!nrR*KGtZ`nos9=6Ko6jfW6QYy>U2t!8rMx zDR>rj2y5T-#@hLK9L}w4@g(evwpaz0bzq(q!~7YGyD=9F5!FTm^);wO0x|T#CAb|= z;{zCvu;&E*e3EN!h4=PF$x=G5>HdCvo(SW25cY=S+!VpsIs9M6ylIQBFkTnoW|%i` zp}D=`W3G7))0dI){}f?y^ZYk>9W&uO&3Bu7b{XPGq8jyxdd_#$&&PxCIqs{zpLfAV z2+D>W?2IFD7M$}Lun*rNsttb=z69T+_H8t#!Zr38qV9FA8hiKW8!-&dv+sc|5LQ;D zA|G2}dlX?OxVBD%du6t{{yo>efroHC&c)H#6&oWc=GHdYALiglOvY?1K-4%JsINgK z5{ThcT#h?oUVVb7XQa;MbzEydea`YSgl8GMW6=Xe*aT6ffXZE9-q?=`xF6=`mxvnA z*VMnZ9MtfP=5jPxyXK|);2<1=GMKYT*ynmg_1Sg#DjtAi9fDrygmn>=wK#B3vW>wQ zkD!gOIBu?u*SKanCg2L(hnLV?Oc!&FYqk;zxRwuxYhwdsQ}VbdAB8AJ8RAI7K757d z`frSa{tw}}H#)=Trj{-F;{NS^J{%L_`{I2pL0CHt)YYI83B)i6<8UwL;R}S_@A*Y| z8Ro0cSl*mF*Y`O%8Qswl>msbQreb@zj}5>mOu;OCh^Uw}QvdC8@+;2?i`|dZ)#5P( zzdsybdahJ+t{!2}@x1k3mqZ+8C`KWSMNn4fpaYDHd(;@*jTf*GQEdeK=1i`;23Nv4 ze+6G7>fUyskHI(;J78^OTfFukI1FdvDm;K}`%ulbNyJfxVick^Qj5QV_JHru z3ve@>r+4rR!p7P_T@5PXI*8#6T#5T(KNlhFe$Tr%y$GMNA{ej9a30P^DVqD8z$O3n z8^Jy1cnm`Y9)|Dy21JeN&!}@heHo7LYMg~5;T${HaU@ZVdPMc<3+m_L9*o85=!p(k z13~e(%(gfHr(hKB#2hsDJLCth`6nL2^{~$~@H!SFoBp{+kHbJ5gzc~}=GQ^QYHR=)7?&s9MfV(jUr=bVhV>JY2B@VX6e&~lwF$K?}4pD6ce*-pKH+mg?PMJPcG2~?s64alYsQ@L(52B14K^`U_C zT~La0RGyMFeO+JP95cS@U8t?L``;PYA>&?v@;cto)un!zt8RAHy8uf^3*BH&kRE)*|bVob1 zLTYKlm#*l85txKoSb%>=FptcqDpbJVd^0g0jwkBgh1Ac*RE)*|bVob1Lbhc+F5D4^ z<1Ac*nV667u)O+Ez_Yrb6y>Nu6>8Cluy$MrHK;@aF`R{KFcb6f9m4MaGtMufecw^j z;5%k84naq>MpW6H%01wF`#f9+$K`wX8~hpl&(y}}wCx_@dhxfle;b#;zt4+NhB&OR zMm;h;Cpfo|`ni~j(HMa4XoprvEp7PH6@4%QlQ0Vl@CW`K;%CmkjYn}Ku7Rv7?ZI2>o;8qCCee23-LhXS6}1*IrQ1*%YsMufG~KwS+g zkw6S*;Tp`ue0+zn`~Qsdi)jC4Ov88##v$m4)`%+kRCdClD8o41jpxza-wP{hY`@a> z`*<3Y;BPK}!xnwj&^8;)Y678UC{?4FbT7;0RN6) z9+^*7sDSxWi5fH@>fVLa&&5=X#sG9jJG4T!Wj!w35haKrflAb%0n4io1w5+@N>Ppq zRG}7)2y4ea*q2Hq5NqPG=W5V^u>1dv^NVQzWlY0(48|eoh}MWI&egWq4}EYkCgO3p z*G9!=MUBmWJ2b8j!oTawaV-2dmO>Px3~?k;je11&$M@X}aIYAH)6fI$u^NK15(itu zc=W@in1W~VF{0Y|iTbzTZ`2!bHD-Fgqk;&k*x2ds{4%eq|H8ND$S zS7QcV$6`eF;dAO=z}*;w)6fI$u^Lj#CVbf)&dV^|gvam>enD6}t`+CD5(&gG6jx&g zUdLjD-T!BtUqt&aV;aU|Fb+XSv_^Af6E5h2qu{>}I?m~M6^jrxhK1C(RCBriDbJjX zd*I)LgK-!-qY%X?LmWv|qaIQH{DS&I2jU=XhcytCRXO-O4uJ2(QMeP&;ZsDl z@dNe#&G!)e-8=ygz&L(`sC&Pn-f=jdILc6rLS!?CT=rjO9sau$dSM7Ape22HiRYku>Td@35`XiW|JkVJI`{FgxcEMFk8^Hr#U<#A z{b8OvCdXEWIFhJFJ;I*pdF#C{i8x%Nhrn^SMo?T^uCbml7GrS_Ucl#wYNLVr8dTyM z*pBU0qaIQBenb7Mm=4!~YoRyXL-LVraV(DM5Ddn6OvB4qgs47P?{)XXzgf?~VfY8u zMrvupmwjiJ*teEV@9uD~E1 zjP0=|nky@FL0cG~6LBGKhJRQ4`^9}Xto_u#b*6G%6!-Y%elt0z=G6?Cljq=Q?1oKI zh+>o>jwGs4kFY*^{u{i8AYX@aoGD+|;k@~CD9oqvmeF1A*!^daszDK#QoqP48%CNAI!rSh>B5at{eNaa0GUS&ku_4 z@NIDb`r|U(foy&gr?wHSr_;E149p$(n*V#^QAJLv>YjMyK2V)S%;U3I`xfs<(1NFwzd`KXMez+8qF&hgI^^9O|G*&J3I`=d;kDqdl z@iGT5hjBa*?a&I@lsqol4m~gcqhKz~g75Gp2peMqb#LGy+<^1pGvsdpf44me^W|rR zJ?97N-om4}85iLsbj8-NkA)~k8RAHy8ubW!uIGP&?LUrN5Ioy=vd_+k>vbF0p6z;# z*FJ`K(1@ru%va~(PB;(45sdvkj(V-;6B#|n_yFHh4v`IUg!z;!DE_~ z@Yx-GVEk{#({LVtLs%b{G+pxypOY{W{b4S3fblU-o54NjNSuWPro(r$xgPd>&o`h3 zmGHh8PCyWA=f_z8g0Sb9CvV~rI6v8Xh-?1|_tvmy|3TdX%)(@hL|^O&^JFDtTejrF zy>UE-p#l%XwbFpFKKzTi4-m}5r5vAv!Em2;@0yEG5%vtve+k!y@5Ko))<<9$6d(_U zC`K9LNTM3`h=p2BUo80Bz( zF^0{}qt7)L-9I0M_g#p-D8@e6y~)0Ox?XzWI1GTXIv=(<6#ZbG^LP{7qiXRJ!p7kF zg_wu?;BSo~a1Qo>@i9)us3&a0ao&Q*kj?YWqZ(8qff$a)xwsCFeLfZ=te@@)A7U1! zU=)m182dO8PvBkrg0N>>=QWSRakP7 za6TQg`FSMVlbsuLdL~}OA_ULL^!YvYZ{iVnpJN|_t1u1r(fuORy}`L(sW%4C;%<1a zYveSXh+~_a#OJ9n#@1hk3AhmzF#hI&@eAG`j@fa1gP^@kpAFRi6IHkwm%#RqLN6F6 zV4_Q#`0xM$F&#+`*eJop?vqb z_rN}Wf~bA*JL=!SLoj#GgX8Uj0<@&8!Nu)yAk3+exE)X7Jw&bRpdSx&opb8=Mq(14 z#``c|(&G|*Z=lX`q~33A+!wZlB@cxtMj7Hrq8jxGo)z}_GuPOUS-2a{=Lnb=#(fCR z#>KcA&cSSafT*$Cp7U!ze7BloKFfS|@4N%E@ezJQSpPh4zMIca;4WN)%P}0rRQAv3 zj)!Y^GHlm1@CeLrbIko>5XQl=%*AJjYX5iYT^BFFec(E{ri_bYGET%680l}I3l5}0q7ViKN4bNSN9HSgjXOvMBkqoAKY*S%&8ZiTUV1K%R5kIv&u zaO}Z*p%=%Uk&l*^&ADL@90S*;@tld*;arFHWeIg3ViqRjGC1Ga?l%j$c3#u<-ggEZ zM-kSCB@cxtMj7Hrq8jxG>s#viuer{Abx{u$u)nk5S{w`4 z(QruzBq5G{k(zi&WAB_jeLTrJ}#mDL(D?zJoeyw2dsgX zmV9pLghNq=akv}L!~O(g$@FO+*l*|HN>t!sG?z!eaLs#o3eNio^uqyYht*-pLm`S` z-{MH38uiH3r}T5?tJl`z1(*-Udj_UsCLV+1H9xa??zdcL{ySF3JPaqmJUJ8Y56<^o z7(@Gz-mlc}K_AWim+>sj8T%!VJ!hNb6 zemWn|z%kdM5n<2re5QFkp7VQSD=bZE#ZB8{KlH)Hm3 zuK6VhyDw7?lyd#<*bG6*hK)y!4)_Iy>TG=;S$_}D%h6umimmaV`Kdl>hM0yZ+UG0zJPs9%{kvaj_FAR zd(%LU$KX!Pg6r=WgtZ%-cRpSJ#>2Q6ALHa0Y{R;2ViY{jPp_{*B@&3C1l@2FE`)oM zYu2{1nb*Z!XFSsT={j?)uDM^4+K=>O_k%hF^BCtin8zJC-T+HmHsQuDI0|ROaZkr9 zh#H@La!;9sDYzfia6IY#PyKEz9LH3Q#ULDle_&k%C69wb6r&7rBvFleq&_qC_>YJ> z^UAz&PR#QLG$Qr>sN+RkTLbsPn=l-Gus@99kr)c!QNHJ&g>&4JHtfIa*0o}PJ&x+r zXVm*%xfjOBycmY-F%!sde_%xELSfWW4N0>NVLO`yAs{i3DOO!A|In!7vA0 z`_I62`vbChetJK>FLkepdWQK^gG}?-j`OQyY0KK&*bxWgbc}}MGZz-%cZBuLwPSv} zma6b3qT=x*^|g2m?&0R+$>@e{uquL*$3Y>AQHD5@s75`)`V`gQuzRvO@3@@rS-1=1 za3&7NF6e**&oh7uH^8%}`zy%y$>`@#aamn^UTr9a30;T^bsGtJ{BoL`o*GB>xyzBm!) z!c7R)hwZ2LDfn)kYshP}S$|(~-OG3YSK}-kiCwWVQcE6R3Q>$Q#F0cb>JjuI)93Qe zokrUG2+p_j?)(pfzghN!dz$mGGkU>%9)(-+2wsKnk>-AfWEx9z=X`&Ch*_8d+Z}*& zVT|v?b9f)_3C%sPCH1x)73&7-Yfy;=+B!Zf^usNZkC3l`v6yn?7a|BZUbG8=c`a-4>P zP>8jVTJref`C^nIjwGs4kFfatL0ughBCZL$H`96Nz%jmvnQ-1m!oHgiJHq(+8(|yl zjZzp#-(i#Beq(&h6Q7r`M6F?2qB7fWO~gfa@-5e{4w~+#B2@zC+l3 z&Or?-kw6S3D8g3Q1Ma71U^H&S!+06XJ67%`=3g+6zB5L^_3S*_C+Bf_lsq1?9eUtY zT!zV*1?RwhC@f~?wz*P^s9Z7b|HLD>5f|VD?1MH~38}?C6`~krh$D$=)FZ4vp8o{z z;+tl!i+YB2?!6yi9^5-8!hOK`HxJB*Hdqywd~A>XaXik(6_^C`#JPMQU&H;Sx%RWE zcWxHJci;oK3PaEv192(Lof&XnehPjJCY zKv>^hLvN!F_C4&nz?ToYHqIWNIZ*bwO@j}wI`Mj7Hrq8jxGYsd4S!rwUd-Q({O zb$xo>k6gbHZ($D1Mdx5N>~|@;!hBc@sbwR+`~%%_BF=_+G7&y!Hs+%a&hxKGZ$F#w zjofD(+;e^2Gq@9D;5s@ON5PzNe{@YffZ1>z1aXO)v-E!0=9h53U%;C%R_WIT-_4sE zR3d>GN>GG+tdEX30Pa6$!TtxaGWJ1VzvK9K1kY~n(`&uQaheCuVmfYyd*YdJ9`{8% zq|YO#mZ>;4$Jq;KU_9=_JeXTi{rBDcRm3&sjQhjWm<0FCQ((?@z?w)ed7LOjG0G4} z64j_jRDV9B{&_qK`|rB2kBjgj_~tmxX)Vu32N~Y9>=|?fH~Vi@N-nA5M|Sv-upaShIg z>$oe-m7_5jBVqeq_b5{1Vmxj8XV_j47uz*1_RYL}2QT9(RKYme->|u8pw2N?B7qo6 zP=tI~+<$h!0XPoEY7}n3JqY^xCdUil_+2MKoPxgEZ_hQrHSe|Ft-*tEPRnsD_QV#*RPs1kh+>o> zjwGs4kFd5p{~4agUGSdA@EpuP_dD~#JpQ2R)9;?Q-s`;nemMTCa1jQ<-0X%zY>2S3 z5)~WcA8_q?pYMzda0PCH^J_ee?_9hJ`|vi5chEnN?Vq{vI$pvYxYm8&-H8gs;qy<$ zAuwmRgKO$YoQ?}|C2qwum}idHHSz|6w$tNc-|XWPn2yP)LM<8*HW%i$^InMrVkkio z@)48*4t9XCDuuB&=Js_WoWm+Si)zeAEsRajSC2hso!88U_uL1cF&>WJc{mDPu{}1x ziYlA&;5~2*&ck(>3Fq+}gvISg>i!i`|0#9Ohx^SH7>vWv8S5ca$>U@picy9*lBh;K z!usO*g|NM;n1Ea0+Ij#F!S(Va%w<3Q{xGcf9EhjF+bu36Vs&^L4Z2?YJ~*#13&N*DvzkbO*GG%my$@cDBR$C_xeOky?zE`E87i zbzgY>2)M3p!X0oQa38XLV-w7w$M)Ykukl*%@m`UXX2eg}^CR$PL<*dKq#YRFXbI9Z5d*q1nxs75`)`r`S8mHnNI0bWP%sgkE zF&YK$@m`W55qC&2iHWAB(XsTu1G&F>Eij z_2I2I^{1i3DOOK@swisTgDP z!oHd#-QgbOcpdkdFo#m(WS@hIBZ+F%BfYKE?+dA)i>Vlm0XPV~;aWZp z#@adZ)9;>lt`9~x?21BciFL6&itmh#@pp8_9&l~hrhPN!$KrU{x1fKXD}}jnC|nP& zA^YfBZ;Or4T%N4WHJih{a$R?Ydq!&8QE{;k<)}avYSD<)*ry&hP*;OWBoIRhija?} zvKE#0wF7p>K5*Q<;68E;f;ib{k3DCddzIIEkM}y>&EPZt>|)HFBj@;Zn2&ejSuDWs zNR3(4@ef@479PdTxCkeqE4Ice2rGG1n9s#1LmWv|qaIQ1E~I`gro#RYKzBHg=Ae1J z7xr%Y^taJt*a7X)1_f}wqT)#P z|0=CHg@~+b=~qDo}-5G$L#+8mOy5B@&3C1VzY4HYJaX+$$WfYpWB2 zz6No!&mQjv*N@kD?N;z!pYeZHR;J;$aQ}0Eybw3R_`Qkm5f;Dn^IvjpHSWg*7*Bs^ z7>@!(6=P6{Vw53{B&t!5^tMvJFQk4hreZV(pgY>Z_-=~Lu|?CT-#zafn`_44&nm8k zJlOVza2;<3`Tv^gHK;@a zF_fSP`DkfbgB#XCrZ^chV`tsE@Y?^BVr*UK{=OKBt1t~O;R~e3EbMp**L{dtn1WF- zuY1Bh(Hx2@))%4}Wr!n*YSbgFUC%GXTujAi3_y3ZLo4J;%OX&~cFqa9iyS6UW<0xs`@Qk0_tRj5TH!seoZx*Aj>ff!0qgnay!iaBroxdvPd zt_j!1Q+N-*AS{kwQ}-GwaV^e8DRzf{H)d1vxTp}tC_@}cRHGhYZF_zp=3**FV*t9N z9a8upAYrLM<8*HWv-l)xbPRAchhYAs>IWV(z;JO5vJtZOnvgWg)%{ z@e${r!&HpLARK~!z<+zmrsQ!^A&OCkIFhJFJ;LTNx1I>jaxMituM5nBa#WxSwP-}x zTr^NugGwY2LkWtIkH10<9Ol*&!CB6wfai5VDauiSD%7G8VRO+yT@5OcKnx`)LO%X##oTudbj1lc z4_D%L+ynof%Eb4QYw25jKap^+a%%b1C3?T~La0 zRGtL3hSM=!3H{627a(g&4zm-%GBgW6%}t;Qw}* zZSmUeVY>riTdraMJ>+97is0|fIk*#}a4HVO-?1ukrDYNDe~)xOJPPOHdIbO0`xVDw zbMZNKFXI7Bz!3C;`IPPNelGq0s;tatHpforfl~B`IUeRT>imu8d&#xrx>z4ADdzpQ z*dP9T$R(JFhv9Ec=PArw>ioTVBQC^=*cWY(D=m+J?-JL5Yr%i(y#oFQ@!zKWy%07J zFH!dxCgXCL7YD(7$irW?nA@A8Blf@nFfL(wQr8W;!1q#1*Alnpd`>y&swu{h#x~<{gOKW0j%Uay%vz*7{F%%=<{^%Tq8Asj4a4+?J>buE4uYp`y zx(F0-+m1K{{ZS70tFSrnd>og-zY$!A{=V4(>mgVECjzT-Xl{maKU?{KE?=f2-zm<4 zYw9RCmxC}kg7tlI1cKk2xj7^l%TQWz?^f6q2gChs0HWrhjQUgH-_Wil*Q38Va^?Rv z0INz?nE?Ab|o7|o&DG_l0+yb58?>5&+)I2y(-LWS+!nL#ta^?R% z0{-^f4E}B_g!2<-d+N4@^OuKQS$+}lcZYuu`!|rk#lz;n^UhOyxCZ@OAy@wMBH-^1 z*GTIK*87_@S5|BU{9PY457w==V!M!gdM*OF2;?G=i$E>{xd`MUkc&Vr0=Wp}B9Mzf zE&{m-{xd`MUkc&Vr0=Wp}B9MzfE&{m-{xd{CK7J>f<{G2Sw diff --git a/libs/SDL3/test/testgpu_simple_clear.c b/libs/SDL3/test/testgpu_simple_clear.c index 5c48607e..41016ee8 100644 --- a/libs/SDL3/test/testgpu_simple_clear.c +++ b/libs/SDL3/test/testgpu_simple_clear.c @@ -54,13 +54,13 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) mode = SDL_GetCurrentDisplayMode(SDL_GetPrimaryDisplay()); if (mode) { - SDL_Log("Screen BPP : %d\n", SDL_BITSPERPIXEL(mode->format)); + SDL_Log("Screen BPP : %d", SDL_BITSPERPIXEL(mode->format)); } SDL_GetWindowSize(state->windows[0], &dw, &dh); - SDL_Log("Window Size : %d,%d\n", dw, dh); + SDL_Log("Window Size : %d,%d", dw, dh); SDL_GetWindowSizeInPixels(state->windows[0], &dw, &dh); - SDL_Log("Draw Size : %d,%d\n", dw, dh); - SDL_Log("\n"); + SDL_Log("Draw Size : %d,%d", dw, dh); + SDL_Log("%s", ""); then = SDL_GetTicks(); @@ -119,7 +119,7 @@ void SDL_AppQuit(void *appstate, SDL_AppResult result) /* Print out some timing information */ const Uint64 now = SDL_GetTicks(); if (now > then) { - SDL_Log("%2.2f frames per second\n", ((double)frames * 1000) / (now - then)); + SDL_Log("%2.2f frames per second", ((double)frames * 1000) / (now - then)); } SDL_ReleaseWindowFromGPUDevice(gpu_device, state->windows[0]); diff --git a/libs/SDL3/test/testgpu_spinning_cube.c b/libs/SDL3/test/testgpu_spinning_cube.c index ff9ece81..0eeb034f 100644 --- a/libs/SDL3/test/testgpu_spinning_cube.c +++ b/libs/SDL3/test/testgpu_spinning_cube.c @@ -27,7 +27,7 @@ #define TESTGPU_SUPPORTED_FORMATS (SDL_GPU_SHADERFORMAT_SPIRV | SDL_GPU_SHADERFORMAT_DXBC | SDL_GPU_SHADERFORMAT_DXIL | SDL_GPU_SHADERFORMAT_METALLIB) -#define CHECK_CREATE(var, thing) { if (!(var)) { SDL_Log("Failed to create %s: %s\n", thing, SDL_GetError()); quit(2); } } +#define CHECK_CREATE(var, thing) { if (!(var)) { SDL_Log("Failed to create %s: %s", thing, SDL_GetError()); quit(2); } } static Uint32 frames = 0; @@ -152,7 +152,7 @@ perspective_matrix(float fovy, float aspect, float znear, float zfar, float *r) * major. In-place multiplication is supported. */ static void -multiply_matrix(float *lhs, float *rhs, float *r) +multiply_matrix(const float *lhs, const float *rhs, float *r) { int i, j, k; float tmp[16]; @@ -641,7 +641,7 @@ init_render_state(int msaa) window_states = (WindowState *) SDL_calloc(state->num_windows, sizeof (WindowState)); if (!window_states) { - SDL_Log("Out of memory!\n"); + SDL_Log("Out of memory!"); quit(2); } @@ -729,7 +729,7 @@ main(int argc, char *argv[]) } mode = SDL_GetCurrentDisplayMode(SDL_GetDisplayForWindow(state->windows[0])); - SDL_Log("Screen bpp: %d\n", SDL_BITSPERPIXEL(mode->format)); + SDL_Log("Screen bpp: %d", SDL_BITSPERPIXEL(mode->format)); init_render_state(msaa); @@ -749,7 +749,7 @@ main(int argc, char *argv[]) /* Print out some timing information */ now = SDL_GetTicks(); if (now > then) { - SDL_Log("%2.2f frames per second\n", + SDL_Log("%2.2f frames per second", ((double) frames * 1000) / (now - then)); } #if !defined(__ANDROID__) diff --git a/libs/SDL3/test/testhaptic.c b/libs/SDL3/test/testhaptic.c index f458b469..a31d2786 100644 --- a/libs/SDL3/test/testhaptic.c +++ b/libs/SDL3/test/testhaptic.c @@ -69,9 +69,9 @@ int main(int argc, char **argv) if (consumed <= 0) { static const char *options[] = { "[device]", NULL }; SDLTest_CommonLogUsage(state, argv[0], options); - SDL_Log("\n"); - SDL_Log("If device is a two-digit number it'll use it as an index, otherwise\n" - "it'll use it as if it were part of the device's name.\n"); + SDL_Log("%s", ""); + SDL_Log("If device is a two-digit number it'll use it as an index, otherwise"); + SDL_Log("it'll use it as if it were part of the device's name."); return 1; } @@ -81,12 +81,12 @@ int main(int argc, char **argv) /* Initialize the force feedbackness */ SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC); haptics = SDL_GetHaptics(&num_haptics); - SDL_Log("%d Haptic devices detected.\n", num_haptics); + SDL_Log("%d Haptic devices detected.", num_haptics); for (i = 0; i < num_haptics; ++i) { - SDL_Log(" %s\n", SDL_GetHapticNameForID(haptics[i])); + SDL_Log(" %s", SDL_GetHapticNameForID(haptics[i])); } if (num_haptics == 0) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "No Haptic devices found!\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "No Haptic devices found!"); SDL_free(haptics); return 1; } @@ -96,7 +96,7 @@ int main(int argc, char **argv) i = (index != -1) ? index : 0; if (i >= num_haptics) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Index out of range, aborting.\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Index out of range, aborting."); SDL_free(haptics); return 1; } @@ -110,7 +110,7 @@ int main(int argc, char **argv) } if (i >= num_haptics) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to find device matching '%s', aborting.\n", name); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to find device matching '%s', aborting.", name); SDL_free(haptics); return 1; } @@ -118,11 +118,11 @@ int main(int argc, char **argv) haptic = SDL_OpenHaptic(haptics[i]); if (!haptic) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create the haptic device: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create the haptic device: %s", SDL_GetError()); SDL_free(haptics); return 1; } - SDL_Log("Device: %s\n", SDL_GetHapticName(haptic)); + SDL_Log("Device: %s", SDL_GetHapticName(haptic)); HapticPrintSupported(haptic); SDL_free(haptics); @@ -134,10 +134,11 @@ int main(int argc, char **argv) nefx = 0; supported = SDL_GetHapticFeatures(haptic); - SDL_Log("\nUploading effects\n"); + SDL_Log("%s", ""); + SDL_Log("Uploading effects"); /* First we'll try a SINE effect. */ if (supported & SDL_HAPTIC_SINE) { - SDL_Log(" effect %d: Sine Wave\n", nefx); + SDL_Log(" effect %d: Sine Wave", nefx); efx[nefx].type = SDL_HAPTIC_SINE; efx[nefx].periodic.period = 1000; efx[nefx].periodic.magnitude = -0x2000; /* Negative magnitude and ... */ @@ -147,14 +148,14 @@ int main(int argc, char **argv) efx[nefx].periodic.fade_length = 1000; id[nefx] = SDL_CreateHapticEffect(haptic, &efx[nefx]); if (id[nefx] < 0) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s", SDL_GetError()); abort_execution(); } nefx++; } /* Now we'll try a SAWTOOTHUP */ if (supported & SDL_HAPTIC_SAWTOOTHUP) { - SDL_Log(" effect %d: Sawtooth Up\n", nefx); + SDL_Log(" effect %d: Sawtooth Up", nefx); efx[nefx].type = SDL_HAPTIC_SAWTOOTHUP; efx[nefx].periodic.period = 500; efx[nefx].periodic.magnitude = 0x5000; @@ -163,7 +164,7 @@ int main(int argc, char **argv) efx[nefx].periodic.fade_length = 1000; id[nefx] = SDL_CreateHapticEffect(haptic, &efx[nefx]); if (id[nefx] < 0) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s", SDL_GetError()); abort_execution(); } nefx++; @@ -171,7 +172,7 @@ int main(int argc, char **argv) /* Now the classical constant effect. */ if (supported & SDL_HAPTIC_CONSTANT) { - SDL_Log(" effect %d: Constant Force\n", nefx); + SDL_Log(" effect %d: Constant Force", nefx); efx[nefx].type = SDL_HAPTIC_CONSTANT; efx[nefx].constant.direction.type = SDL_HAPTIC_POLAR; efx[nefx].constant.direction.dir[0] = 20000; /* Force comes from the south-west. */ @@ -181,7 +182,7 @@ int main(int argc, char **argv) efx[nefx].constant.fade_length = 1000; id[nefx] = SDL_CreateHapticEffect(haptic, &efx[nefx]); if (id[nefx] < 0) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s", SDL_GetError()); abort_execution(); } nefx++; @@ -189,7 +190,7 @@ int main(int argc, char **argv) /* The cute spring effect. */ if (supported & SDL_HAPTIC_SPRING) { - SDL_Log(" effect %d: Condition Spring\n", nefx); + SDL_Log(" effect %d: Condition Spring", nefx); efx[nefx].type = SDL_HAPTIC_SPRING; efx[nefx].condition.length = 5000; for (i = 0; i < SDL_GetNumHapticAxes(haptic); i++) { @@ -201,14 +202,14 @@ int main(int argc, char **argv) } id[nefx] = SDL_CreateHapticEffect(haptic, &efx[nefx]); if (id[nefx] < 0) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s", SDL_GetError()); abort_execution(); } nefx++; } /* The interesting damper effect. */ if (supported & SDL_HAPTIC_DAMPER) { - SDL_Log(" effect %d: Condition Damper\n", nefx); + SDL_Log(" effect %d: Condition Damper", nefx); efx[nefx].type = SDL_HAPTIC_DAMPER; efx[nefx].condition.length = 5000; for (i = 0; i < SDL_GetNumHapticAxes(haptic); i++) { @@ -219,14 +220,14 @@ int main(int argc, char **argv) } id[nefx] = SDL_CreateHapticEffect(haptic, &efx[nefx]); if (id[nefx] < 0) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s", SDL_GetError()); abort_execution(); } nefx++; } /* The pretty awesome inertia effect. */ if (supported & SDL_HAPTIC_INERTIA) { - SDL_Log(" effect %d: Condition Inertia\n", nefx); + SDL_Log(" effect %d: Condition Inertia", nefx); efx[nefx].type = SDL_HAPTIC_INERTIA; efx[nefx].condition.length = 5000; for (i = 0; i < SDL_GetNumHapticAxes(haptic); i++) { @@ -238,14 +239,14 @@ int main(int argc, char **argv) } id[nefx] = SDL_CreateHapticEffect(haptic, &efx[nefx]); if (id[nefx] < 0) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s", SDL_GetError()); abort_execution(); } nefx++; } /* The hot friction effect. */ if (supported & SDL_HAPTIC_FRICTION) { - SDL_Log(" effect %d: Condition Friction\n", nefx); + SDL_Log(" effect %d: Condition Friction", nefx); efx[nefx].type = SDL_HAPTIC_FRICTION; efx[nefx].condition.length = 5000; for (i = 0; i < SDL_GetNumHapticAxes(haptic); i++) { @@ -256,7 +257,7 @@ int main(int argc, char **argv) } id[nefx] = SDL_CreateHapticEffect(haptic, &efx[nefx]); if (id[nefx] < 0) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s", SDL_GetError()); abort_execution(); } nefx++; @@ -264,7 +265,7 @@ int main(int argc, char **argv) /* Now we'll try a ramp effect */ if (supported & SDL_HAPTIC_RAMP) { - SDL_Log(" effect %d: Ramp\n", nefx); + SDL_Log(" effect %d: Ramp", nefx); efx[nefx].type = SDL_HAPTIC_RAMP; efx[nefx].ramp.direction.type = SDL_HAPTIC_CARTESIAN; efx[nefx].ramp.direction.dir[0] = 1; /* Force comes from */ @@ -276,7 +277,7 @@ int main(int argc, char **argv) efx[nefx].ramp.fade_length = 1000; id[nefx] = SDL_CreateHapticEffect(haptic, &efx[nefx]); if (id[nefx] < 0) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s", SDL_GetError()); abort_execution(); } nefx++; @@ -284,22 +285,23 @@ int main(int argc, char **argv) /* Finally we'll try a left/right effect. */ if (supported & SDL_HAPTIC_LEFTRIGHT) { - SDL_Log(" effect %d: Left/Right\n", nefx); + SDL_Log(" effect %d: Left/Right", nefx); efx[nefx].type = SDL_HAPTIC_LEFTRIGHT; efx[nefx].leftright.length = 5000; efx[nefx].leftright.large_magnitude = 0x3000; efx[nefx].leftright.small_magnitude = 0xFFFF; id[nefx] = SDL_CreateHapticEffect(haptic, &efx[nefx]); if (id[nefx] < 0) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s", SDL_GetError()); abort_execution(); } nefx++; } - SDL_Log("\nNow playing effects for 5 seconds each with 1 second delay between\n"); + SDL_Log("%s", ""); + SDL_Log("Now playing effects for 5 seconds each with 1 second delay between"); for (i = 0; i < nefx; i++) { - SDL_Log(" Playing effect %d\n", i); + SDL_Log(" Playing effect %d", i); SDL_RunHapticEffect(haptic, id[i], 1); SDL_Delay(6000); /* Effects only have length 5000 */ } @@ -320,7 +322,8 @@ int main(int argc, char **argv) static void abort_execution(void) { - SDL_Log("\nAborting program execution.\n"); + SDL_Log("%s", ""); + SDL_Log("Aborting program execution."); SDL_CloseHaptic(haptic); SDL_Quit(); @@ -338,54 +341,54 @@ HapticPrintSupported(SDL_Haptic *ptr) unsigned int supported; supported = SDL_GetHapticFeatures(ptr); - SDL_Log(" Supported effects [%d effects, %d playing]:\n", + SDL_Log(" Supported effects [%d effects, %d playing]:", SDL_GetMaxHapticEffects(ptr), SDL_GetMaxHapticEffectsPlaying(ptr)); if (supported & SDL_HAPTIC_CONSTANT) { - SDL_Log(" constant\n"); + SDL_Log(" constant"); } if (supported & SDL_HAPTIC_SINE) { - SDL_Log(" sine\n"); + SDL_Log(" sine"); } if (supported & SDL_HAPTIC_SQUARE) - SDL_Log(" square\n"); + SDL_Log(" square"); if (supported & SDL_HAPTIC_TRIANGLE) { - SDL_Log(" triangle\n"); + SDL_Log(" triangle"); } if (supported & SDL_HAPTIC_SAWTOOTHUP) { - SDL_Log(" sawtoothup\n"); + SDL_Log(" sawtoothup"); } if (supported & SDL_HAPTIC_SAWTOOTHDOWN) { - SDL_Log(" sawtoothdown\n"); + SDL_Log(" sawtoothdown"); } if (supported & SDL_HAPTIC_RAMP) { - SDL_Log(" ramp\n"); + SDL_Log(" ramp"); } if (supported & SDL_HAPTIC_FRICTION) { - SDL_Log(" friction\n"); + SDL_Log(" friction"); } if (supported & SDL_HAPTIC_SPRING) { - SDL_Log(" spring\n"); + SDL_Log(" spring"); } if (supported & SDL_HAPTIC_DAMPER) { - SDL_Log(" damper\n"); + SDL_Log(" damper"); } if (supported & SDL_HAPTIC_INERTIA) { - SDL_Log(" inertia\n"); + SDL_Log(" inertia"); } if (supported & SDL_HAPTIC_CUSTOM) { - SDL_Log(" custom\n"); + SDL_Log(" custom"); } if (supported & SDL_HAPTIC_LEFTRIGHT) { - SDL_Log(" left/right\n"); + SDL_Log(" left/right"); } - SDL_Log(" Supported capabilities:\n"); + SDL_Log(" Supported capabilities:"); if (supported & SDL_HAPTIC_GAIN) { - SDL_Log(" gain\n"); + SDL_Log(" gain"); } if (supported & SDL_HAPTIC_AUTOCENTER) { - SDL_Log(" autocenter\n"); + SDL_Log(" autocenter"); } if (supported & SDL_HAPTIC_STATUS) { - SDL_Log(" status\n"); + SDL_Log(" status"); } } diff --git a/libs/SDL3/test/testhittesting.c b/libs/SDL3/test/testhittesting.c index 24ff250d..c276d42d 100644 --- a/libs/SDL3/test/testhittesting.c +++ b/libs/SDL3/test/testhittesting.c @@ -47,14 +47,14 @@ hitTest(SDL_Window *window, const SDL_Point *pt, void *data) for (i = 0; i < numareas; i++) { if (SDL_PointInRect(&adj_pt, &areas[i])) { - SDL_Log("HIT-TEST: DRAGGABLE\n"); + SDL_Log("HIT-TEST: DRAGGABLE"); return SDL_HITTEST_DRAGGABLE; } } #define REPORT_RESIZE_HIT(name) \ { \ - SDL_Log("HIT-TEST: RESIZE_" #name "\n"); \ + SDL_Log("HIT-TEST: RESIZE_" #name ""); \ return SDL_HITTEST_RESIZE_##name; \ } @@ -76,7 +76,7 @@ hitTest(SDL_Window *window, const SDL_Point *pt, void *data) REPORT_RESIZE_HIT(LEFT); } - SDL_Log("HIT-TEST: NORMAL\n"); + SDL_Log("HIT-TEST: NORMAL"); return SDL_HITTEST_NORMAL; } @@ -130,15 +130,15 @@ int main(int argc, char **argv) switch (e.type) { case SDL_EVENT_MOUSE_BUTTON_DOWN: - SDL_Log("button down!\n"); + SDL_Log("button down!"); break; case SDL_EVENT_MOUSE_BUTTON_UP: - SDL_Log("button up!\n"); + SDL_Log("button up!"); break; case SDL_EVENT_WINDOW_MOVED: - SDL_Log("Window event moved to (%d, %d)!\n", (int)e.window.data1, (int)e.window.data2); + SDL_Log("Window event moved to (%d, %d)!", (int)e.window.data1, (int)e.window.data2); break; case SDL_EVENT_KEY_DOWN: diff --git a/libs/SDL3/test/testhotplug.c b/libs/SDL3/test/testhotplug.c index 6a7df424..f050adea 100644 --- a/libs/SDL3/test/testhotplug.c +++ b/libs/SDL3/test/testhotplug.c @@ -66,7 +66,7 @@ int main(int argc, char *argv[]) /* Initialize SDL (Note: video is required to start event loop) */ if (!SDL_Init(init_subsystems)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError()); exit(1); } @@ -75,18 +75,18 @@ int main(int argc, char *argv[]) */ SDL_free(SDL_GetKeyboards(&num_keyboards)); - SDL_Log("There are %d keyboards at startup\n", num_keyboards); + SDL_Log("There are %d keyboards at startup", num_keyboards); SDL_free(SDL_GetMice(&num_mice)); - SDL_Log("There are %d mice at startup\n", num_mice); + SDL_Log("There are %d mice at startup", num_mice); SDL_free(SDL_GetJoysticks(&num_joysticks)); - SDL_Log("There are %d joysticks at startup\n", num_joysticks); + SDL_Log("There are %d joysticks at startup", num_joysticks); if (enable_haptic) { int num_haptics; SDL_free(SDL_GetHaptics(&num_haptics)); - SDL_Log("There are %d haptic devices at startup\n", num_haptics); + SDL_Log("There are %d haptic devices at startup", num_haptics); } while (keepGoing) { @@ -97,46 +97,46 @@ int main(int argc, char *argv[]) keepGoing = false; break; case SDL_EVENT_KEYBOARD_ADDED: - SDL_Log("Keyboard '%s' added : %" SDL_PRIu32 "\n", SDL_GetKeyboardNameForID(event.kdevice.which), event.kdevice.which); + SDL_Log("Keyboard '%s' added : %" SDL_PRIu32, SDL_GetKeyboardNameForID(event.kdevice.which), event.kdevice.which); break; case SDL_EVENT_KEYBOARD_REMOVED: - SDL_Log("Keyboard removed: %" SDL_PRIu32 "\n", event.kdevice.which); + SDL_Log("Keyboard removed: %" SDL_PRIu32, event.kdevice.which); break; case SDL_EVENT_MOUSE_ADDED: - SDL_Log("Mouse '%s' added : %" SDL_PRIu32 "\n", SDL_GetMouseNameForID(event.mdevice.which), event.mdevice.which); + SDL_Log("Mouse '%s' added : %" SDL_PRIu32, SDL_GetMouseNameForID(event.mdevice.which), event.mdevice.which); break; case SDL_EVENT_MOUSE_REMOVED: - SDL_Log("Mouse removed: %" SDL_PRIu32 "\n", event.mdevice.which); + SDL_Log("Mouse removed: %" SDL_PRIu32, event.mdevice.which); break; case SDL_EVENT_JOYSTICK_ADDED: if (joystick) { - SDL_Log("Only one joystick supported by this test\n"); + SDL_Log("Only one joystick supported by this test"); } else { joystick = SDL_OpenJoystick(event.jdevice.which); instance = event.jdevice.which; - SDL_Log("Joy Added : %" SDL_PRIu32 " : %s\n", event.jdevice.which, SDL_GetJoystickName(joystick)); + SDL_Log("Joy Added : %" SDL_PRIu32 " : %s", event.jdevice.which, SDL_GetJoystickName(joystick)); if (enable_haptic) { if (SDL_IsJoystickHaptic(joystick)) { haptic = SDL_OpenHapticFromJoystick(joystick); if (haptic) { - SDL_Log("Joy Haptic Opened\n"); + SDL_Log("Joy Haptic Opened"); if (!SDL_InitHapticRumble(haptic)) { - SDL_Log("Could not init Rumble!: %s\n", SDL_GetError()); + SDL_Log("Could not init Rumble!: %s", SDL_GetError()); SDL_CloseHaptic(haptic); haptic = NULL; } } else { - SDL_Log("Joy haptic open FAILED!: %s\n", SDL_GetError()); + SDL_Log("Joy haptic open FAILED!: %s", SDL_GetError()); } } else { - SDL_Log("No haptic found\n"); + SDL_Log("No haptic found"); } } } break; case SDL_EVENT_JOYSTICK_REMOVED: if (instance == event.jdevice.which) { - SDL_Log("Joy Removed: %" SDL_PRIs32 "\n", event.jdevice.which); + SDL_Log("Joy Removed: %" SDL_PRIs32, event.jdevice.which); instance = 0; if (enable_haptic && haptic) { SDL_CloseHaptic(haptic); @@ -145,29 +145,29 @@ int main(int argc, char *argv[]) SDL_CloseJoystick(joystick); joystick = NULL; } else { - SDL_Log("Unknown joystick disconnected\n"); + SDL_Log("Unknown joystick disconnected"); } break; case SDL_EVENT_JOYSTICK_AXIS_MOTION: /* - // SDL_Log("Axis Move: %d\n", event.jaxis.axis); + // SDL_Log("Axis Move: %d", event.jaxis.axis); */ if (enable_haptic) { SDL_PlayHapticRumble(haptic, 0.25, 250); } break; case SDL_EVENT_JOYSTICK_BUTTON_DOWN: - SDL_Log("Button Press: %d\n", event.jbutton.button); + SDL_Log("Button Press: %d", event.jbutton.button); if (enable_haptic && haptic) { SDL_PlayHapticRumble(haptic, 0.25, 250); } if (event.jbutton.button == 0) { - SDL_Log("Exiting due to button press of button 0\n"); + SDL_Log("Exiting due to button press of button 0"); keepGoing = false; } break; case SDL_EVENT_JOYSTICK_BUTTON_UP: - SDL_Log("Button Release: %d\n", event.jbutton.button); + SDL_Log("Button Release: %d", event.jbutton.button); break; default: break; diff --git a/libs/SDL3/test/testiconv.c b/libs/SDL3/test/testiconv.c index e339e5fa..189c02f4 100644 --- a/libs/SDL3/test/testiconv.c +++ b/libs/SDL3/test/testiconv.c @@ -111,7 +111,7 @@ int main(int argc, char *argv[]) fname = GetResourceFilename(fname, "utf8.txt"); fdata = (Uint8 *) (fname ? SDL_LoadFile(fname, &fdatalen) : NULL); if (!fdata) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to load %s\n", fname); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to load %s", fname); return 1; } @@ -126,7 +126,7 @@ int main(int argc, char *argv[]) test[0] = SDL_iconv_string(formats[i], "UCS-4", ucs4, len); test[1] = SDL_iconv_string("UCS-4", formats[i], test[0], len); if (!test[1] || SDL_memcmp(test[1], ucs4, len) != 0) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "FAIL: %s\n", formats[i]); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "FAIL: %s", formats[i]); ++errors; } SDL_free(test[0]); @@ -140,7 +140,7 @@ int main(int argc, char *argv[]) SDL_free(fdata); SDL_free(fname); - SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Total errors: %d\n", errors); + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Total errors: %d", errors); SDL_Quit(); SDLTest_CommonDestroyState(state); return errors ? errors + 1 : 0; diff --git a/libs/SDL3/test/testime.c b/libs/SDL3/test/testime.c index bcc1f3cd..ea56d3c8 100644 --- a/libs/SDL3/test/testime.c +++ b/libs/SDL3/test/testime.c @@ -163,7 +163,7 @@ static int unifont_init(const char *fontname) /* Allocate memory for the glyph data so the file can be closed after initialization. */ unifontGlyph = (struct UnifontGlyph *)SDL_malloc(unifontGlyphSize); if (!unifontGlyph) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to allocate %d KiB for glyph data.\n", (int)(unifontGlyphSize + 1023) / 1024); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to allocate %d KiB for glyph data.", (int)(unifontGlyphSize + 1023) / 1024); return -1; } SDL_memset(unifontGlyph, 0, unifontGlyphSize); @@ -171,20 +171,20 @@ static int unifont_init(const char *fontname) /* Allocate memory for texture pointers for all renderers. */ unifontTexture = (SDL_Texture **)SDL_malloc(unifontTextureSize); if (!unifontTexture) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to allocate %d KiB for texture pointer data.\n", (int)(unifontTextureSize + 1023) / 1024); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to allocate %d KiB for texture pointer data.", (int)(unifontTextureSize + 1023) / 1024); return -1; } SDL_memset(unifontTexture, 0, unifontTextureSize); filename = GetResourceFilename(NULL, fontname); if (!filename) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory"); return -1; } hexFile = SDL_IOFromFile(filename, "rb"); SDL_free(filename); if (!hexFile) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to open font file: %s\n", fontname); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to open font file: %s", fontname); return -1; } @@ -200,7 +200,7 @@ static int unifont_init(const char *fontname) break; /* EOF */ } if ((numGlyphs == 0 && bytesRead == 0) || (numGlyphs > 0 && bytesRead < 9)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Unexpected end of hex file.\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Unexpected end of hex file."); return -1; } @@ -214,16 +214,16 @@ static int unifont_init(const char *fontname) } else if (hexBuffer[8] == ':') { codepointHexSize = 8; } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Could not find codepoint and glyph data separator symbol in hex file on line %d.\n", lineNumber); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Could not find codepoint and glyph data separator symbol in hex file on line %d.", lineNumber); return -1; } if (!validate_hex((const char *)hexBuffer, codepointHexSize, &codepoint)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Malformed hexadecimal number in hex file on line %d.\n", lineNumber); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Malformed hexadecimal number in hex file on line %d.", lineNumber); return -1; } if (codepoint > UNIFONT_MAX_CODEPOINT) { - SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "unifont: Codepoint on line %d exceeded limit of 0x%x.\n", lineNumber, UNIFONT_MAX_CODEPOINT); + SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "unifont: Codepoint on line %d exceeded limit of 0x%x.", lineNumber, UNIFONT_MAX_CODEPOINT); } /* If there was glyph data read in the last file read, move it to the front of the buffer. */ @@ -234,7 +234,7 @@ static int unifont_init(const char *fontname) bytesRead = SDL_ReadIO(hexFile, hexBuffer + bytesOverread, 33 - bytesOverread); if (bytesRead < (33 - bytesOverread)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Unexpected end of hex file.\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Unexpected end of hex file."); return -1; } if (hexBuffer[32] == '\n') { @@ -243,19 +243,19 @@ static int unifont_init(const char *fontname) glyphWidth = 16; bytesRead = SDL_ReadIO(hexFile, hexBuffer + 33, 32); if (bytesRead < 32) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Unexpected end of hex file.\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Unexpected end of hex file."); return -1; } } if (!validate_hex((const char *)hexBuffer, glyphWidth * 4, NULL)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Malformed hexadecimal glyph data in hex file on line %d.\n", lineNumber); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Malformed hexadecimal glyph data in hex file on line %d.", lineNumber); return -1; } if (codepoint <= UNIFONT_MAX_CODEPOINT) { if (unifontGlyph[codepoint].width > 0) { - SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "unifont: Ignoring duplicate codepoint 0x%08" SDL_PRIx32 " in hex file on line %d.\n", codepoint, lineNumber); + SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "unifont: Ignoring duplicate codepoint 0x%08" SDL_PRIx32 " in hex file on line %d.", codepoint, lineNumber); } else { unifontGlyph[codepoint].width = glyphWidth; /* Pack the hex data into a more compact form. */ @@ -270,7 +270,7 @@ static int unifont_init(const char *fontname) } while (bytesRead > 0); SDL_CloseIO(hexFile); - SDL_Log("unifont: Loaded %" SDL_PRIu32 " glyphs.\n", numGlyphs); + SDL_Log("unifont: Loaded %" SDL_PRIu32 " glyphs.", numGlyphs); return 0; } @@ -310,13 +310,13 @@ static int unifont_load_texture(Uint32 textureID) Uint8 *textureRGBA; if (textureID >= UNIFONT_NUM_TEXTURES) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Tried to load out of range texture %" SDL_PRIu32 "\n", textureID); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Tried to load out of range texture %" SDL_PRIu32, textureID); return -1; } textureRGBA = (Uint8 *)SDL_malloc(UNIFONT_TEXTURE_SIZE); if (!textureRGBA) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to allocate %d MiB for a texture.\n", UNIFONT_TEXTURE_SIZE / 1024 / 1024); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to allocate %d MiB for a texture.", UNIFONT_TEXTURE_SIZE / 1024 / 1024); return -1; } SDL_memset(textureRGBA, 0, UNIFONT_TEXTURE_SIZE); @@ -340,13 +340,13 @@ static int unifont_load_texture(Uint32 textureID) } tex = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, UNIFONT_TEXTURE_WIDTH, UNIFONT_TEXTURE_WIDTH); if (tex == NULL) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to create texture %" SDL_PRIu32 " for renderer %d.\n", textureID, i); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to create texture %" SDL_PRIu32 " for renderer %d.", textureID, i); return -1; } unifontTexture[UNIFONT_NUM_TEXTURES * i + textureID] = tex; SDL_SetTextureBlendMode(tex, SDL_BLENDMODE_BLEND); if (!SDL_UpdateTexture(tex, NULL, textureRGBA, UNIFONT_TEXTURE_PITCH)) { - SDL_Log("unifont error: Failed to update texture %" SDL_PRIu32 " data for renderer %d.\n", textureID, i); + SDL_Log("unifont error: Failed to update texture %" SDL_PRIu32 " data for renderer %d.", textureID, i); } } @@ -970,7 +970,7 @@ int main(int argc, char *argv[]) windowstate = (WindowState *)SDL_calloc(state->num_windows, sizeof(*windowstate)); if (!windowstate) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't allocate window state: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't allocate window state: %s", SDL_GetError()); return -1; } @@ -980,7 +980,7 @@ int main(int argc, char *argv[]) return -1; } - SDL_Log("Using font: %s\n", fontname); + SDL_Log("Using font: %s", fontname); /* Initialize window state */ for (i = 0; i < state->num_windows; ++i) { @@ -1082,7 +1082,7 @@ int main(int argc, char *argv[]) break; } - SDL_Log("Keyboard: scancode 0x%08X = %s, keycode 0x%08" SDL_PRIX32 " = %s\n", + SDL_Log("Keyboard: scancode 0x%08X = %s, keycode 0x%08" SDL_PRIX32 " = %s", event.key.scancode, SDL_GetScancodeName(event.key.scancode), SDL_static_cast(Uint32, event.key.key), @@ -1099,13 +1099,13 @@ int main(int argc, char *argv[]) break; } - SDL_Log("Keyboard: text input \"%s\"\n", event.text.text); + SDL_Log("Keyboard: text input \"%s\"", event.text.text); if (SDL_strlen(ctx->text) + SDL_strlen(event.text.text) < sizeof(ctx->text)) { SDL_strlcat(ctx->text, event.text.text, sizeof(ctx->text)); } - SDL_Log("text inputted: %s\n", ctx->text); + SDL_Log("text inputted: %s", ctx->text); /* After text inputted, we can clear up markedText because it */ /* is committed */ @@ -1118,7 +1118,7 @@ int main(int argc, char *argv[]) break; } - SDL_Log("text editing \"%s\", selected range (%" SDL_PRIs32 ", %" SDL_PRIs32 ")\n", + SDL_Log("text editing \"%s\", selected range (%" SDL_PRIs32 ", %" SDL_PRIs32 ")", event.edit.text, event.edit.start, event.edit.length); SDL_strlcpy(ctx->markedText, event.edit.text, sizeof(ctx->markedText)); @@ -1132,9 +1132,9 @@ int main(int argc, char *argv[]) break; } - SDL_Log("text candidates:\n"); + SDL_Log("text candidates:"); for (i = 0; i < event.edit_candidates.num_candidates; ++i) { - SDL_Log("%c%s\n", i == event.edit_candidates.selected_candidate ? '>' : ' ', event.edit_candidates.candidates[i]); + SDL_Log("%c%s", i == event.edit_candidates.selected_candidate ? '>' : ' ', event.edit_candidates.candidates[i]); } ClearCandidates(ctx); diff --git a/libs/SDL3/test/testintersections.c b/libs/SDL3/test/testintersections.c index d3e42182..cc58511f 100644 --- a/libs/SDL3/test/testintersections.c +++ b/libs/SDL3/test/testintersections.c @@ -92,7 +92,7 @@ static int add_line(float x1, float y1, float x2, float y2) return 0; } - SDL_Log("adding line (%g, %g), (%g, %g)\n", x1, y1, x2, y2); + SDL_Log("adding line (%g, %g), (%g, %g)", x1, y1, x2, y2); lines[num_lines].x = x1; lines[num_lines].y = y1; lines[num_lines].w = x2; @@ -142,7 +142,7 @@ static int add_rect(float x1, float y1, float x2, float y2) SWAP(float, y1, y2); } - SDL_Log("adding rect (%g, %g), (%g, %g) [%gx%g]\n", x1, y1, x2, y2, + SDL_Log("adding rect (%g, %g), (%g, %g) [%gx%g]", x1, y1, x2, y2, x2 - x1, y2 - y1); rects[num_rects].x = x1; @@ -385,7 +385,7 @@ int main(int argc, char *argv[]) if (now > then) { double fps = ((double)frames * 1000) / (now - then); - SDL_Log("%2.2f frames per second\n", fps); + SDL_Log("%2.2f frames per second", fps); } return 0; } diff --git a/libs/SDL3/test/testkeys.c b/libs/SDL3/test/testkeys.c index 166b4a19..c7733847 100644 --- a/libs/SDL3/test/testkeys.c +++ b/libs/SDL3/test/testkeys.c @@ -35,11 +35,11 @@ int main(int argc, char *argv[]) } if (!SDL_Init(SDL_INIT_VIDEO)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError()); exit(1); } for (scancode = 0; scancode < SDL_SCANCODE_COUNT; ++scancode) { - SDL_Log("Scancode #%d, \"%s\"\n", scancode, + SDL_Log("Scancode #%d, \"%s\"", scancode, SDL_GetScancodeName(scancode)); } SDL_Quit(); diff --git a/libs/SDL3/test/testloadso.c b/libs/SDL3/test/testloadso.c index 0a8d1659..106fbc71 100644 --- a/libs/SDL3/test/testloadso.c +++ b/libs/SDL3/test/testloadso.c @@ -24,8 +24,8 @@ typedef int (*fntype)(const char *); static void log_usage(char *progname, SDLTest_CommonState *state) { static const char *options[] = { "library", "functionname|--hello", NULL }; SDLTest_CommonLogUsage(state, progname, options); - SDL_Log("USAGE: %s \n", progname); - SDL_Log(" %s --hello\n", progname); + SDL_Log("USAGE: %s ", progname); + SDL_Log(" %s --hello", progname); } int main(int argc, char *argv[]) @@ -80,28 +80,28 @@ int main(int argc, char *argv[]) /* Initialize SDL */ if (!SDL_Init(0)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError()); return 2; } lib = SDL_LoadObject(libname); if (!lib) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_LoadObject('%s') failed: %s\n", + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_LoadObject('%s') failed: %s", libname, SDL_GetError()); result = 3; } else { fn = (fntype)SDL_LoadFunction(lib, symname); if (!fn) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_LoadFunction('%s') failed: %s\n", + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_LoadFunction('%s') failed: %s", symname, SDL_GetError()); result = 4; } else { - SDL_Log("Found %s in %s at %p\n", symname, libname, fn); + SDL_Log("Found %s in %s at %p", symname, libname, fn); if (hello) { - SDL_Log("Calling function...\n"); + SDL_Log("Calling function..."); fn(" HELLO, WORLD!\n"); - SDL_Log("...apparently, we survived. :)\n"); - SDL_Log("Unloading library...\n"); + SDL_Log("...apparently, we survived. :)"); + SDL_Log("Unloading library..."); } } SDL_UnloadObject(lib); diff --git a/libs/SDL3/test/testlock.c b/libs/SDL3/test/testlock.c index 60aab55d..971b3032 100644 --- a/libs/SDL3/test/testlock.c +++ b/libs/SDL3/test/testlock.c @@ -42,7 +42,7 @@ SDL_Quit_Wrapper(void) static void printid(void) { - SDL_Log("Thread %" SDL_PRIu64 ": exiting\n", SDL_GetCurrentThreadID()); + SDL_Log("Thread %" SDL_PRIu64 ": exiting", SDL_GetCurrentThreadID()); } static void terminate(int sig) @@ -55,7 +55,7 @@ static void closemutex(int sig) { SDL_ThreadID id = SDL_GetCurrentThreadID(); int i; - SDL_Log("Thread %" SDL_PRIu64 ": Cleaning up...\n", id == mainthread ? 0 : id); + SDL_Log("Thread %" SDL_PRIu64 ": Cleaning up...", id == mainthread ? 0 : id); SDL_SetAtomicInt(&doterminate, 1); if (threads) { for (i = 0; i < nb_threads; ++i) { @@ -81,21 +81,21 @@ Run(void *data) } SDL_Log("Thread %" SDL_PRIu64 ": starting up", current_thread); while (!SDL_GetAtomicInt(&doterminate)) { - SDL_Log("Thread %" SDL_PRIu64 ": ready to work\n", current_thread); + SDL_Log("Thread %" SDL_PRIu64 ": ready to work", current_thread); SDL_LockMutex(mutex); - SDL_Log("Thread %" SDL_PRIu64 ": start work!\n", current_thread); + SDL_Log("Thread %" SDL_PRIu64 ": start work!", current_thread); SDL_Delay(1 * worktime); - SDL_Log("Thread %" SDL_PRIu64 ": work done!\n", current_thread); + SDL_Log("Thread %" SDL_PRIu64 ": work done!", current_thread); SDL_UnlockMutex(mutex); /* If this sleep isn't done, then threads may starve */ SDL_Delay(10); } if (current_thread == mainthread && SDL_GetAtomicInt(&doterminate)) { - SDL_Log("Thread %" SDL_PRIu64 ": raising SIGTERM\n", current_thread); + SDL_Log("Thread %" SDL_PRIu64 ": raising SIGTERM", current_thread); (void)raise(SIGTERM); } - SDL_Log("Thread %" SDL_PRIu64 ": exiting!\n", current_thread); + SDL_Log("Thread %" SDL_PRIu64 ": exiting!", current_thread); return 0; } @@ -174,7 +174,7 @@ int main(int argc, char *argv[]) /* Load the SDL library */ if (!SDL_Init(0)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s", SDL_GetError()); exit(1); } (void)atexit(SDL_Quit_Wrapper); @@ -183,19 +183,19 @@ int main(int argc, char *argv[]) mutex = SDL_CreateMutex(); if (!mutex) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create mutex: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create mutex: %s", SDL_GetError()); exit(1); } mainthread = SDL_GetCurrentThreadID(); - SDL_Log("Main thread: %" SDL_PRIu64 "\n", mainthread); + SDL_Log("Main thread: %" SDL_PRIu64, mainthread); (void)atexit(printid); for (i = 0; i < nb_threads; ++i) { char name[64]; (void)SDL_snprintf(name, sizeof(name), "Worker%d", i); threads[i] = SDL_CreateThread(Run, name, NULL); if (threads[i] == NULL) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create thread!\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create thread!"); } } diff --git a/libs/SDL3/test/testmessage.c b/libs/SDL3/test/testmessage.c index 30c70054..1e5dbc9a 100644 --- a/libs/SDL3/test/testmessage.c +++ b/libs/SDL3/test/testmessage.c @@ -64,7 +64,7 @@ button_messagebox(void *eventNumber) success = SDL_ShowMessageBox(&data, &button); if (success == -1) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error Presenting MessageBox: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error Presenting MessageBox: %s", SDL_GetError()); if (eventNumber) { SDL_Event event; event.type = (Uint32)(intptr_t)eventNumber; @@ -74,7 +74,7 @@ button_messagebox(void *eventNumber) quit(2); } } - SDL_Log("Pressed button: %d, %s\n", button, button == -1 ? "[closed]" : button == 1 ? "Cancel" + SDL_Log("Pressed button: %d, %s", button, button == -1 ? "[closed]" : button == 1 ? "Cancel" : "OK"); if (eventNumber) { @@ -107,7 +107,7 @@ int main(int argc, char *argv[]) "This is a simple error MessageBox", NULL); if (!success) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error Presenting MessageBox: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error Presenting MessageBox: %s", SDL_GetError()); quit(1); } @@ -116,7 +116,7 @@ int main(int argc, char *argv[]) "This is a simple MessageBox with a newline:\r\nHello world!", NULL); if (!success) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error Presenting MessageBox: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error Presenting MessageBox: %s", SDL_GetError()); quit(1); } @@ -125,7 +125,7 @@ int main(int argc, char *argv[]) "NULL Title", NULL); if (!success) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error Presenting MessageBox: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error Presenting MessageBox: %s", SDL_GetError()); quit(1); } @@ -134,7 +134,7 @@ int main(int argc, char *argv[]) NULL, NULL); if (!success) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error Presenting MessageBox: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error Presenting MessageBox: %s", SDL_GetError()); quit(1); } @@ -144,7 +144,7 @@ int main(int argc, char *argv[]) "Unicode text: '牛肉西蘭花' ...", NULL); if (!success) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error Presenting MessageBox: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error Presenting MessageBox: %s", SDL_GetError()); quit(1); } @@ -154,7 +154,7 @@ int main(int argc, char *argv[]) "Unicode text and newline:\r\n'牛肉西蘭花'\n'牛肉西蘭花'", NULL); if (!success) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error Presenting MessageBox: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error Presenting MessageBox: %s", SDL_GetError()); quit(1); } @@ -164,7 +164,7 @@ int main(int argc, char *argv[]) "Unicode text in the title.", NULL); if (!success) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error Presenting MessageBox: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error Presenting MessageBox: %s", SDL_GetError()); quit(1); } @@ -177,7 +177,7 @@ int main(int argc, char *argv[]) subsystem on the main thread. */ if (!SDL_Init(SDL_INIT_VIDEO)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL video subsystem: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL video subsystem: %s", SDL_GetError()); return 1; } { @@ -194,7 +194,7 @@ int main(int argc, char *argv[]) SDL_WaitThread(thread, &status); - SDL_Log("Message box thread return %i\n", status); + SDL_Log("Message box thread return %i", status); } /* Test showing a message box with a parent window */ @@ -213,7 +213,7 @@ int main(int argc, char *argv[]) "This is a simple error MessageBox with a parent window. Press a key or close the window after dismissing this messagebox.", window); if (!success) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error Presenting MessageBox: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error Presenting MessageBox: %s", SDL_GetError()); quit(1); } diff --git a/libs/SDL3/test/testmodal.c b/libs/SDL3/test/testmodal.c index 156d61e2..9e5ea63e 100644 --- a/libs/SDL3/test/testmodal.c +++ b/libs/SDL3/test/testmodal.c @@ -52,13 +52,13 @@ int main(int argc, char *argv[]) } if (!SDL_CreateWindowAndRenderer("Parent Window", 640, 480, 0, &w1, &r1)) { - SDL_Log("Failed to create parent window and/or renderer: %s\n", SDL_GetError()); + SDL_Log("Failed to create parent window and/or renderer: %s", SDL_GetError()); exit_code = 1; goto sdl_quit; } if (!SDL_CreateWindowAndRenderer("Non-Modal Window", 320, 200, 0, &w2, &r2)) { - SDL_Log("Failed to create parent window and/or renderer: %s\n", SDL_GetError()); + SDL_Log("Failed to create parent window and/or renderer: %s", SDL_GetError()); exit_code = 1; goto sdl_quit; } @@ -91,7 +91,7 @@ int main(int argc, char *argv[]) } else if (e.type == SDL_EVENT_KEY_DOWN) { if ((e.key.key == SDLK_M || e.key.key == SDLK_N) && !w2) { if (!SDL_CreateWindowAndRenderer("Non-Modal Window", 320, 200, SDL_WINDOW_HIDDEN, &w2, &r2)) { - SDL_Log("Failed to create modal window and/or renderer: %s\n", SDL_GetError()); + SDL_Log("Failed to create modal window and/or renderer: %s", SDL_GetError()); exit_code = 1; goto sdl_quit; } diff --git a/libs/SDL3/test/testmouse.c b/libs/SDL3/test/testmouse.c index 7d475864..bc839c09 100644 --- a/libs/SDL3/test/testmouse.c +++ b/libs/SDL3/test/testmouse.c @@ -295,7 +295,7 @@ int main(int argc, char *argv[]) /* Initialize SDL (Note: video is required to start event loop) */ if (!SDL_Init(SDL_INIT_VIDEO)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError()); exit(1); } @@ -313,7 +313,7 @@ int main(int argc, char *argv[]) window = SDL_CreateWindow("Mouse Test", SCREEN_WIDTH, SCREEN_HEIGHT, 0); #endif if (!window) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window: %s", SDL_GetError()); return 0; } @@ -321,7 +321,7 @@ int main(int argc, char *argv[]) loop_data.renderer = SDL_CreateRenderer(window, NULL); if (!loop_data.renderer) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s", SDL_GetError()); SDL_DestroyWindow(window); return 0; } diff --git a/libs/SDL3/test/testmultiaudio.c b/libs/SDL3/test/testmultiaudio.c index 1e8f020b..7e1b8dc7 100644 --- a/libs/SDL3/test/testmultiaudio.c +++ b/libs/SDL3/test/testmultiaudio.c @@ -86,7 +86,7 @@ test_multi_audio(const SDL_AudioDeviceID *devices, int devcount) } /* note that Emscripten currently doesn't run this part (but maybe only has a single audio device anyhow?) */ - SDL_Log("Playing on all devices...\n"); + SDL_Log("Playing on all devices..."); streams = (SDL_AudioStream **) SDL_calloc(devcount, sizeof (SDL_AudioStream *)); if (!streams) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!"); @@ -130,7 +130,7 @@ test_multi_audio(const SDL_AudioDeviceID *devices, int devcount) SDL_free(streams); } - SDL_Log("All done!\n"); + SDL_Log("All done!"); } int main(int argc, char **argv) @@ -169,11 +169,11 @@ int main(int argc, char **argv) /* Load the SDL library */ if (!SDLTest_CommonInit(state)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError()); return 1; } - SDL_Log("Using audio driver: %s\n", SDL_GetCurrentAudioDriver()); + SDL_Log("Using audio driver: %s", SDL_GetCurrentAudioDriver()); filename = GetResourceFilename(filename, "sample.wav"); @@ -186,7 +186,7 @@ int main(int argc, char **argv) test_multi_audio(devices, devcount); SDL_free(sound); } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s\n", filename, + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s", filename, SDL_GetError()); } SDL_free(devices); diff --git a/libs/SDL3/test/testnative.c b/libs/SDL3/test/testnative.c index cf91250a..a4b58fa4 100644 --- a/libs/SDL3/test/testnative.c +++ b/libs/SDL3/test/testnative.c @@ -120,7 +120,7 @@ int main(int argc, char *argv[]) } if (!SDL_Init(SDL_INIT_VIDEO)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL video: %s\n", + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL video: %s", SDL_GetError()); exit(1); } @@ -134,14 +134,14 @@ int main(int argc, char *argv[]) } } if (!factory) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't find native window code for %s driver\n", + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't find native window code for %s driver", driver); quit(2); } - SDL_Log("Creating native window for %s driver\n", driver); + SDL_Log("Creating native window for %s driver", driver); native_window = factory->CreateNativeWindow(WINDOW_W, WINDOW_H); if (!native_window) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create native window\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create native window"); quit(3); } props = SDL_CreateProperties(); @@ -152,7 +152,7 @@ int main(int argc, char *argv[]) window = SDL_CreateWindowWithProperties(props); SDL_DestroyProperties(props); if (!window) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create SDL window: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create SDL window: %s", SDL_GetError()); quit(4); } SDL_SetWindowTitle(window, "SDL Native Window Test"); @@ -160,7 +160,7 @@ int main(int argc, char *argv[]) /* Create the renderer */ renderer = SDL_CreateRenderer(window, NULL); if (!renderer) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s", SDL_GetError()); quit(5); } @@ -178,7 +178,7 @@ int main(int argc, char *argv[]) positions = (SDL_FRect *)SDL_malloc(NUM_SPRITES * sizeof(*positions)); velocities = (SDL_FRect *)SDL_malloc(NUM_SPRITES * sizeof(*velocities)); if (!positions || !velocities) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!"); quit(2); } for (i = 0; i < NUM_SPRITES; ++i) { diff --git a/libs/SDL3/test/testoffscreen.c b/libs/SDL3/test/testoffscreen.c index 249c87b9..8100bee4 100644 --- a/libs/SDL3/test/testoffscreen.c +++ b/libs/SDL3/test/testoffscreen.c @@ -108,7 +108,7 @@ int main(int argc, char *argv[]) /* Force the offscreen renderer, if it cannot be created then fail out */ SDL_SetHint(SDL_HINT_VIDEO_DRIVER, "offscreen"); if (!SDL_InitSubSystem(SDL_INIT_VIDEO)) { - SDL_Log("Couldn't initialize the offscreen video driver: %s\n", + SDL_Log("Couldn't initialize the offscreen video driver: %s", SDL_GetError()); return 1; } @@ -117,14 +117,14 @@ int main(int argc, char *argv[]) window = SDL_CreateWindow("Offscreen Test", width, height, 0); if (!window) { - SDL_Log("Couldn't create window: %s\n", SDL_GetError()); + SDL_Log("Couldn't create window: %s", SDL_GetError()); return 1; } renderer = SDL_CreateRenderer(window, NULL); if (!renderer) { - SDL_Log("Couldn't create renderer: %s\n", + SDL_Log("Couldn't create renderer: %s", SDL_GetError()); return 1; } @@ -138,7 +138,7 @@ int main(int argc, char *argv[]) done = 0; #endif - SDL_Log("Rendering %u frames offscreen\n", max_frames); + SDL_Log("Rendering %u frames offscreen", max_frames); #ifdef SDL_PLATFORM_EMSCRIPTEN emscripten_set_main_loop(loop, 0, 1); @@ -152,7 +152,7 @@ int main(int argc, char *argv[]) now = SDL_GetTicks(); if (now > then) { double fps = ((double)frames * 1000) / (now - then); - SDL_Log("Frames remaining: %" SDL_PRIu32 " rendering at %2.2f frames per second\n", max_frames - frames, fps); + SDL_Log("Frames remaining: %" SDL_PRIu32 " rendering at %2.2f frames per second", max_frames - frames, fps); } } } diff --git a/libs/SDL3/test/testoverlay.c b/libs/SDL3/test/testoverlay.c index 7e9f97c5..ac568eee 100644 --- a/libs/SDL3/test/testoverlay.c +++ b/libs/SDL3/test/testoverlay.c @@ -311,7 +311,7 @@ static void loop(void) /* Print out some timing information */ const Uint64 then = next_fps_check - fps_check_delay; const double fps = ((double)frames * 1000) / (now - then); - SDL_Log("%2.2f frames per second\n", fps); + SDL_Log("%2.2f frames per second", fps); next_fps_check = now + fps_check_delay; frames = 0; } @@ -347,15 +347,15 @@ int main(int argc, char **argv) consumed = 2; fps = SDL_atoi(argv[i + 1]); if (fps == 0) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "The --fps option requires an argument [from 1 to 1000], default is 12.\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "The --fps option requires an argument [from 1 to 1000], default is 12."); quit(10); } if ((fps < 0) || (fps > 1000)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "The --fps option must be in range from 1 to 1000, default is 12.\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "The --fps option must be in range from 1 to 1000, default is 12."); quit(10); } } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "The --fps option requires an argument [from 1 to 1000], default is 12.\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "The --fps option requires an argument [from 1 to 1000], default is 12."); quit(10); } } else if (SDL_strcmp(argv[i], "--nodelay") == 0) { @@ -369,15 +369,15 @@ int main(int argc, char **argv) if (argv[i + 1]) { scale = SDL_atoi(argv[i + 1]); if (scale == 0) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "The --scale option requires an argument [from 1 to 50], default is 5.\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "The --scale option requires an argument [from 1 to 50], default is 5."); quit(10); } if ((scale < 0) || (scale > 50)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "The --scale option must be in range from 1 to 50, default is 5.\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "The --scale option must be in range from 1 to 50, default is 5."); quit(10); } } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "The --fps option requires an argument [from 1 to 1000], default is 12.\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "The --fps option requires an argument [from 1 to 1000], default is 12."); quit(10); } } else if (SDL_strcmp(argv[i], "--yuvformat") == 0) { @@ -400,11 +400,11 @@ int main(int argc, char **argv) } else if (SDL_strcmp(fmt, "NV21") == 0) { yuv_format = SDL_PIXELFORMAT_NV21; } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "The --yuvformat option requires one of the: YV12 (default), IYUV, YUY2, UYVY, YVYU, NV12, NV21)\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "The --yuvformat option requires one of the: YV12 (default), IYUV, YUY2, UYVY, YVYU, NV12, NV21)"); quit(10); } } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "The --yuvformat option requires one of the: YV12 (default), IYUV, YUY2, UYVY, YVYU, NV12, NV21)\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "The --yuvformat option requires one of the: YV12 (default), IYUV, YUY2, UYVY, YVYU, NV12, NV21)"); quit(10); } } @@ -435,20 +435,20 @@ int main(int argc, char **argv) RawMooseData = (Uint8 *)SDL_malloc(MOOSEFRAME_SIZE * MOOSEFRAMES_COUNT); if (!RawMooseData) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Can't allocate memory for movie !\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Can't allocate memory for movie !"); quit(1); } /* load the trojan moose images */ filename = GetResourceFilename(NULL, "moose.dat"); if (!filename) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory"); quit(2); } handle = SDL_IOFromFile(filename, "rb"); SDL_free(filename); if (!handle) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Can't find the file moose.dat !\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Can't find the file moose.dat !"); quit(2); } @@ -461,7 +461,7 @@ int main(int argc, char **argv) window_h = MOOSEPIC_H * scale; if (state->num_windows != 1) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Only one window allowed\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Only one window allowed"); quit(1); } @@ -471,7 +471,7 @@ int main(int argc, char **argv) if (streaming) { MooseTexture = SDL_CreateTexture(renderer, yuv_format, SDL_TEXTUREACCESS_STREAMING, MOOSEPIC_W, MOOSEPIC_H); if (!MooseTexture) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set create texture: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set create texture: %s", SDL_GetError()); quit(5); } } diff --git a/libs/SDL3/test/testplatform.c b/libs/SDL3/test/testplatform.c index e48dc08c..c1eb6aa6 100644 --- a/libs/SDL3/test/testplatform.c +++ b/libs/SDL3/test/testplatform.c @@ -50,36 +50,36 @@ static int TestTypes(bool verbose) if (badsize(sizeof(bool), 1)) { if (verbose) { - SDL_Log("sizeof(bool) != 1, instead = %u\n", (unsigned int)sizeof(bool)); + SDL_Log("sizeof(bool) != 1, instead = %u", (unsigned int)sizeof(bool)); } ++error; } if (badsize(sizeof(Uint8), 1)) { if (verbose) { - SDL_Log("sizeof(Uint8) != 1, instead = %u\n", (unsigned int)sizeof(Uint8)); + SDL_Log("sizeof(Uint8) != 1, instead = %u", (unsigned int)sizeof(Uint8)); } ++error; } if (badsize(sizeof(Uint16), 2)) { if (verbose) { - SDL_Log("sizeof(Uint16) != 2, instead = %u\n", (unsigned int)sizeof(Uint16)); + SDL_Log("sizeof(Uint16) != 2, instead = %u", (unsigned int)sizeof(Uint16)); } ++error; } if (badsize(sizeof(Uint32), 4)) { if (verbose) { - SDL_Log("sizeof(Uint32) != 4, instead = %u\n", (unsigned int)sizeof(Uint32)); + SDL_Log("sizeof(Uint32) != 4, instead = %u", (unsigned int)sizeof(Uint32)); } ++error; } if (badsize(sizeof(Uint64), 8)) { if (verbose) { - SDL_Log("sizeof(Uint64) != 8, instead = %u\n", (unsigned int)sizeof(Uint64)); + SDL_Log("sizeof(Uint64) != 8, instead = %u", (unsigned int)sizeof(Uint64)); } ++error; } if (verbose && !error) { - SDL_Log("All data types are the expected size.\n"); + SDL_Log("All data types are the expected size."); } return error ? 1 : 0; @@ -112,7 +112,7 @@ static int TestEndian(bool verbose) value_double.d = 3.141593; if (verbose) { - SDL_Log("Detected a %s endian machine.\n", + SDL_Log("Detected a %s endian machine.", (SDL_BYTEORDER == SDL_LIL_ENDIAN) ? "little" : "big"); } if ((*((char *)&value) >> 4) == 0x1) { @@ -122,13 +122,13 @@ static int TestEndian(bool verbose) } if (real_byteorder != SDL_BYTEORDER) { if (verbose) { - SDL_Log("Actually a %s endian machine!\n", + SDL_Log("Actually a %s endian machine!", (real_byteorder == SDL_LIL_ENDIAN) ? "little" : "big"); } ++error; } if (verbose) { - SDL_Log("Detected a %s endian float word order machine.\n", + SDL_Log("Detected a %s endian float word order machine.", (SDL_FLOATWORDORDER == SDL_LIL_ENDIAN) ? "little" : "big"); } if (value_double.ui32[0] == 0x82c2bd7f && value_double.ui32[1] == 0x400921fb) { @@ -138,40 +138,40 @@ static int TestEndian(bool verbose) } if (real_floatwordorder != SDL_FLOATWORDORDER) { if (verbose) { - SDL_Log("Actually a %s endian float word order machine!\n", + SDL_Log("Actually a %s endian float word order machine!", (real_floatwordorder == SDL_LIL_ENDIAN) ? "little" : (real_floatwordorder == SDL_BIG_ENDIAN) ? "big" : "unknown"); } ++error; } if (verbose) { - SDL_Log("Value 16 = 0x%X, swapped = 0x%X\n", value16, + SDL_Log("Value 16 = 0x%X, swapped = 0x%X", value16, SDL_Swap16(value16)); } if (SDL_Swap16(value16) != swapped16) { if (verbose) { - SDL_Log("16 bit value swapped incorrectly!\n"); + SDL_Log("16 bit value swapped incorrectly!"); } ++error; } if (verbose) { - SDL_Log("Value 32 = 0x%" SDL_PRIX32 ", swapped = 0x%" SDL_PRIX32 "\n", + SDL_Log("Value 32 = 0x%" SDL_PRIX32 ", swapped = 0x%" SDL_PRIX32, value32, SDL_Swap32(value32)); } if (SDL_Swap32(value32) != swapped32) { if (verbose) { - SDL_Log("32 bit value swapped incorrectly!\n"); + SDL_Log("32 bit value swapped incorrectly!"); } ++error; } if (verbose) { - SDL_Log("Value 64 = 0x%" SDL_PRIX64 ", swapped = 0x%" SDL_PRIX64 "\n", value64, + SDL_Log("Value 64 = 0x%" SDL_PRIX64 ", swapped = 0x%" SDL_PRIX64, value64, SDL_Swap64(value64)); } if (SDL_Swap64(value64) != swapped64) { if (verbose) { - SDL_Log("64 bit value swapped incorrectly!\n"); + SDL_Log("64 bit value swapped incorrectly!"); } ++error; } @@ -380,14 +380,14 @@ static int Test64Bit(bool verbose) if (!t->routine(&t->a, &t->b, t->arg, &result, &t->expected_result)) { if (verbose) { - SDL_Log("%s(0x%08X%08X, 0x%08X%08X, %3d, produced: 0x%08X%08X, expected: 0x%08X%08X\n", t->operation, al[1], al[0], bl[1], bl[0], + SDL_Log("%s(0x%08X%08X, 0x%08X%08X, %3d, produced: 0x%08X%08X, expected: 0x%08X%08X", t->operation, al[1], al[0], bl[1], bl[0], t->arg, rl[1], rl[0], el[1], el[0]); } ++failed; } } if (verbose && (failed == 0)) { - SDL_Log("All 64bit intrinsic tests passed\n"); + SDL_Log("All 64bit intrinsic tests passed"); } return failed ? 1 : 0; } @@ -395,23 +395,23 @@ static int Test64Bit(bool verbose) static int TestCPUInfo(bool verbose) { if (verbose) { - SDL_Log("Number of logical CPU cores: %d\n", SDL_GetNumLogicalCPUCores()); - SDL_Log("CPU cache line size: %d\n", SDL_GetCPUCacheLineSize()); - SDL_Log("AltiVec %s\n", SDL_HasAltiVec() ? "detected" : "not detected"); - SDL_Log("MMX %s\n", SDL_HasMMX() ? "detected" : "not detected"); - SDL_Log("SSE %s\n", SDL_HasSSE() ? "detected" : "not detected"); - SDL_Log("SSE2 %s\n", SDL_HasSSE2() ? "detected" : "not detected"); - SDL_Log("SSE3 %s\n", SDL_HasSSE3() ? "detected" : "not detected"); - SDL_Log("SSE4.1 %s\n", SDL_HasSSE41() ? "detected" : "not detected"); - SDL_Log("SSE4.2 %s\n", SDL_HasSSE42() ? "detected" : "not detected"); - SDL_Log("AVX %s\n", SDL_HasAVX() ? "detected" : "not detected"); - SDL_Log("AVX2 %s\n", SDL_HasAVX2() ? "detected" : "not detected"); - SDL_Log("AVX-512F %s\n", SDL_HasAVX512F() ? "detected" : "not detected"); - SDL_Log("ARM SIMD %s\n", SDL_HasARMSIMD() ? "detected" : "not detected"); - SDL_Log("NEON %s\n", SDL_HasNEON() ? "detected" : "not detected"); - SDL_Log("LSX %s\n", SDL_HasLSX() ? "detected" : "not detected"); - SDL_Log("LASX %s\n", SDL_HasLASX() ? "detected" : "not detected"); - SDL_Log("System RAM %d MB\n", SDL_GetSystemRAM()); + SDL_Log("Number of logical CPU cores: %d", SDL_GetNumLogicalCPUCores()); + SDL_Log("CPU cache line size: %d", SDL_GetCPUCacheLineSize()); + SDL_Log("AltiVec %s", SDL_HasAltiVec() ? "detected" : "not detected"); + SDL_Log("MMX %s", SDL_HasMMX() ? "detected" : "not detected"); + SDL_Log("SSE %s", SDL_HasSSE() ? "detected" : "not detected"); + SDL_Log("SSE2 %s", SDL_HasSSE2() ? "detected" : "not detected"); + SDL_Log("SSE3 %s", SDL_HasSSE3() ? "detected" : "not detected"); + SDL_Log("SSE4.1 %s", SDL_HasSSE41() ? "detected" : "not detected"); + SDL_Log("SSE4.2 %s", SDL_HasSSE42() ? "detected" : "not detected"); + SDL_Log("AVX %s", SDL_HasAVX() ? "detected" : "not detected"); + SDL_Log("AVX2 %s", SDL_HasAVX2() ? "detected" : "not detected"); + SDL_Log("AVX-512F %s", SDL_HasAVX512F() ? "detected" : "not detected"); + SDL_Log("ARM SIMD %s", SDL_HasARMSIMD() ? "detected" : "not detected"); + SDL_Log("NEON %s", SDL_HasNEON() ? "detected" : "not detected"); + SDL_Log("LSX %s", SDL_HasLSX() ? "detected" : "not detected"); + SDL_Log("LASX %s", SDL_HasLASX() ? "detected" : "not detected"); + SDL_Log("System RAM %d MB", SDL_GetSystemRAM()); } return 0; } @@ -434,7 +434,7 @@ static int TestAssertions(bool verbose) { const SDL_AssertData *item = SDL_GetAssertionReport(); while (item) { - SDL_Log("'%s', %s (%s:%d), triggered %u times, always ignore: %s.\n", + SDL_Log("'%s', %s (%s:%d), triggered %u times, always ignore: %s.", item->condition, item->function, item->filename, item->linenum, item->trigger_count, item->always_ignore ? "yes" : "no"); @@ -478,7 +478,7 @@ int main(int argc, char *argv[]) } if (verbose) { - SDL_Log("This system is running %s\n", SDL_GetPlatform()); + SDL_Log("This system is running %s", SDL_GetPlatform()); } status += TestTypes(verbose); diff --git a/libs/SDL3/test/testpower.c b/libs/SDL3/test/testpower.c index 3bd056d8..912ee67b 100644 --- a/libs/SDL3/test/testpower.c +++ b/libs/SDL3/test/testpower.c @@ -22,7 +22,7 @@ report_power(void) const SDL_PowerState state = SDL_GetPowerInfo(&seconds, &percent); const char *statestr = NULL; - SDL_Log("SDL-reported power info...\n"); + SDL_Log("SDL-reported power info..."); switch (state) { case SDL_POWERSTATE_UNKNOWN: statestr = "Unknown"; @@ -44,18 +44,18 @@ report_power(void) break; } - SDL_Log("State: %s\n", statestr); + SDL_Log("State: %s", statestr); if (percent == -1) { - SDL_Log("Percent left: unknown\n"); + SDL_Log("Percent left: unknown"); } else { - SDL_Log("Percent left: %d%%\n", percent); + SDL_Log("Percent left: %d%%", percent); } if (seconds == -1) { - SDL_Log("Time left: unknown\n"); + SDL_Log("Time left: unknown"); } else { - SDL_Log("Time left: %d minutes, %d seconds\n", seconds / 60, seconds % 60); + SDL_Log("Time left: %d minutes, %d seconds", seconds / 60, seconds % 60); } } @@ -75,7 +75,7 @@ int main(int argc, char *argv[]) } if (!SDL_Init(0)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_Init() failed: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_Init() failed: %s", SDL_GetError()); return 1; } diff --git a/libs/SDL3/test/testqsort.c b/libs/SDL3/test/testqsort.c index 38d14701..6230e746 100644 --- a/libs/SDL3/test/testqsort.c +++ b/libs/SDL3/test/testqsort.c @@ -91,7 +91,7 @@ int main(int argc, char *argv[]) seed_seen = 1; consumed = 1; } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Invalid seed. Use a decimal or hexadecimal number.\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Invalid seed. Use a decimal or hexadecimal number."); return 1; } } @@ -108,7 +108,7 @@ int main(int argc, char *argv[]) if (!seed_seen) { seed = SDL_GetPerformanceCounter(); } - SDL_Log("Using random seed 0x%" SDL_PRIx64 "\n", seed); + SDL_Log("Using random seed 0x%" SDL_PRIx64, seed); for (iteration = 0; iteration < SDL_arraysize(itervals); iteration++) { const int arraylen = itervals[iteration]; diff --git a/libs/SDL3/test/testrendercopyex.c b/libs/SDL3/test/testrendercopyex.c index 0b3b3073..e46d522a 100644 --- a/libs/SDL3/test/testrendercopyex.c +++ b/libs/SDL3/test/testrendercopyex.c @@ -75,8 +75,8 @@ static void Draw(DrawState *s) s->scale_direction = 1; } } - s->sprite_rect.x = (float)((viewport.w - s->sprite_rect.w) / 2); - s->sprite_rect.y = (float)((viewport.h - s->sprite_rect.h) / 2); + s->sprite_rect.x = (viewport.w - s->sprite_rect.w) / 2; + s->sprite_rect.y = (viewport.h - s->sprite_rect.h) / 2; SDL_RenderTextureRotated(s->renderer, s->sprite, NULL, &s->sprite_rect, (double)s->sprite_rect.w, center, SDL_FLIP_NONE); @@ -161,7 +161,7 @@ int main(int argc, char *argv[]) now = SDL_GetTicks(); if (now > then) { double fps = ((double)frames * 1000) / (now - then); - SDL_Log("%2.2f frames per second\n", fps); + SDL_Log("%2.2f frames per second", fps); } SDL_stack_free(drawstates); diff --git a/libs/SDL3/test/testrendertarget.c b/libs/SDL3/test/testrendertarget.c index 4e33210a..bad57fdc 100644 --- a/libs/SDL3/test/testrendertarget.c +++ b/libs/SDL3/test/testrendertarget.c @@ -79,7 +79,7 @@ DrawComposite(DrawState *s) if (surface) { Uint8 r, g, b, a; if (SDL_ReadSurfacePixel(surface, 0, 0, &r, &g, &b, &a)) { - SDL_Log("Blended pixel: 0x%.2x%.2x%.2x%.2x\n", r, g, b, a); + SDL_Log("Blended pixel: 0x%.2x%.2x%.2x%.2x", r, g, b, a); } SDL_DestroySurface(surface); } @@ -113,8 +113,8 @@ DrawComposite(DrawState *s) s->scale_direction = 1; } } - s->sprite_rect.x = (float)((viewport.w - s->sprite_rect.w) / 2); - s->sprite_rect.y = (float)((viewport.h - s->sprite_rect.h) / 2); + s->sprite_rect.x = (viewport.w - s->sprite_rect.w) / 2; + s->sprite_rect.y = (viewport.h - s->sprite_rect.h) / 2; SDL_RenderTexture(s->renderer, s->sprite, NULL, &s->sprite_rect); @@ -148,7 +148,7 @@ Draw(DrawState *s) target = SDL_CreateTexture(s->renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, viewport.w, viewport.h); if (!target) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create render target texture: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create render target texture: %s", SDL_GetError()); return false; } SDL_SetRenderTarget(s->renderer, target); @@ -168,8 +168,8 @@ Draw(DrawState *s) s->scale_direction = 1; } } - s->sprite_rect.x = (float)((viewport.w - s->sprite_rect.w) / 2); - s->sprite_rect.y = (float)((viewport.h - s->sprite_rect.h) / 2); + s->sprite_rect.x = (viewport.w - s->sprite_rect.w) / 2; + s->sprite_rect.y = (viewport.h - s->sprite_rect.h) / 2; SDL_RenderTexture(s->renderer, s->sprite, NULL, &s->sprite_rect); @@ -283,7 +283,7 @@ int main(int argc, char *argv[]) now = SDL_GetTicks(); if (now > then) { double fps = ((double)frames * 1000) / (now - then); - SDL_Log("%2.2f frames per second\n", fps); + SDL_Log("%2.2f frames per second", fps); } SDL_stack_free(drawstates); diff --git a/libs/SDL3/test/testresample.c b/libs/SDL3/test/testresample.c index 0ca95c49..55db2f3f 100644 --- a/libs/SDL3/test/testresample.c +++ b/libs/SDL3/test/testresample.c @@ -93,20 +93,20 @@ int main(int argc, char **argv) } if (!SDL_Init(SDL_INIT_AUDIO)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_Init() failed: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_Init() failed: %s", SDL_GetError()); ret = 2; goto end; } if (!SDL_LoadWAV(file_in, &spec, &data, &len)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "failed to load %s: %s\n", file_in, SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "failed to load %s: %s", file_in, SDL_GetError()); ret = 3; goto end; } cvtspec.format = spec.format; if (!SDL_ConvertAudioSamples(&spec, data, len, &cvtspec, &dst_buf, &dst_len)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "failed to convert samples: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "failed to convert samples: %s", SDL_GetError()); ret = 4; goto end; } @@ -114,7 +114,7 @@ int main(int argc, char **argv) /* write out a WAV header... */ io = SDL_IOFromFile(file_out, "wb"); if (!io) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "opening '%s' failed: %s\n", file_out, SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "opening '%s' failed: %s", file_out, SDL_GetError()); ret = 5; goto end; } @@ -139,7 +139,7 @@ int main(int argc, char **argv) SDL_WriteIO(io, dst_buf, dst_len); if (!SDL_CloseIO(io)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "closing '%s' failed: %s\n", file_out, SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "closing '%s' failed: %s", file_out, SDL_GetError()); ret = 6; goto end; } diff --git a/libs/SDL3/test/testrumble.c b/libs/SDL3/test/testrumble.c index 0dc06cd9..df35e0bb 100644 --- a/libs/SDL3/test/testrumble.c +++ b/libs/SDL3/test/testrumble.c @@ -72,9 +72,9 @@ int main(int argc, char **argv) if (consumed <= 0) { static const char *options[] = { "[device]", NULL }; SDLTest_CommonLogUsage(state, argv[0], options); - SDL_Log("\n"); + SDL_Log("%s", ""); SDL_Log("If device is a two-digit number it'll use it as an index, otherwise\n" - "it'll use it as if it were part of the device's name.\n"); + "it'll use it as if it were part of the device's name."); return 1; } @@ -84,9 +84,9 @@ int main(int argc, char **argv) /* Initialize the force feedbackness */ SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC); haptics = SDL_GetHaptics(&num_haptics); - SDL_Log("%d Haptic devices detected.\n", num_haptics); + SDL_Log("%d Haptic devices detected.", num_haptics); if (num_haptics == 0) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "No Haptic devices found!\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "No Haptic devices found!"); SDL_free(haptics); return 1; } @@ -96,7 +96,7 @@ int main(int argc, char **argv) i = (index != -1) ? index : 0; if (i >= num_haptics) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Index out of range, aborting.\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Index out of range, aborting."); SDL_free(haptics); return 1; } @@ -110,7 +110,7 @@ int main(int argc, char **argv) } if (i >= num_haptics) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to find device matching '%s', aborting.\n", name); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to find device matching '%s', aborting.", name); SDL_free(haptics); return 1; } @@ -118,36 +118,36 @@ int main(int argc, char **argv) haptic = SDL_OpenHaptic(haptics[i]); if (!haptic) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create the haptic device: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create the haptic device: %s", SDL_GetError()); SDL_free(haptics); return 1; } - SDL_Log("Device: %s\n", SDL_GetHapticName(haptic)); + SDL_Log("Device: %s", SDL_GetHapticName(haptic)); SDL_free(haptics); /* We only want force feedback errors. */ SDL_ClearError(); if (!SDL_HapticRumbleSupported(haptic)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Rumble not supported!\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Rumble not supported!"); return 1; } if (!SDL_InitHapticRumble(haptic)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to initialize rumble: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to initialize rumble: %s", SDL_GetError()); return 1; } - SDL_Log("Playing 2 second rumble at 0.5 magnitude.\n"); + SDL_Log("Playing 2 second rumble at 0.5 magnitude."); if (!SDL_PlayHapticRumble(haptic, 0.5, 5000)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to play rumble: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to play rumble: %s", SDL_GetError()); return 1; } SDL_Delay(2000); - SDL_Log("Stopping rumble.\n"); + SDL_Log("Stopping rumble."); SDL_StopHapticRumble(haptic); SDL_Delay(2000); - SDL_Log("Playing 2 second rumble at 0.3 magnitude.\n"); + SDL_Log("Playing 2 second rumble at 0.3 magnitude."); if (!SDL_PlayHapticRumble(haptic, 0.3f, 5000)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to play rumble: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to play rumble: %s", SDL_GetError()); return 1; } SDL_Delay(2000); diff --git a/libs/SDL3/test/testrwlock.c b/libs/SDL3/test/testrwlock.c index d39b74fb..a80873c9 100644 --- a/libs/SDL3/test/testrwlock.c +++ b/libs/SDL3/test/testrwlock.c @@ -34,16 +34,16 @@ static void DoWork(const int workticks) /* "Work" */ const bool is_reader = tid != mainthread; const char *typestr = is_reader ? "Reader" : "Writer"; - SDL_Log("%s Thread %" SDL_PRIu64 ": ready to work\n", typestr, tid); + SDL_Log("%s Thread %" SDL_PRIu64 ": ready to work", typestr, tid); if (is_reader) { SDL_LockRWLockForReading(rwlock); } else { SDL_LockRWLockForWriting(rwlock); } - SDL_Log("%s Thread %" SDL_PRIu64 ": start work!\n", typestr, tid); + SDL_Log("%s Thread %" SDL_PRIu64 ": start work!", typestr, tid); SDL_Delay(workticks); - SDL_Log("%s Thread %" SDL_PRIu64 ": work done!\n", typestr, tid); + SDL_Log("%s Thread %" SDL_PRIu64 ": work done!", typestr, tid); SDL_UnlockRWLock(rwlock); /* If this sleep isn't done, then threads may starve */ @@ -57,7 +57,7 @@ ReaderRun(void *data) while (!SDL_GetAtomicInt(&doterminate)) { DoWork(worktime); } - SDL_Log("Reader Thread %" SDL_PRIu64 ": exiting!\n", SDL_GetCurrentThreadID()); + SDL_Log("Reader Thread %" SDL_PRIu64 ": exiting!", SDL_GetCurrentThreadID()); return 0; } @@ -132,7 +132,7 @@ int main(int argc, char *argv[]) /* Load the SDL library */ if (!SDL_Init(0)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s", SDL_GetError()); return 1; } @@ -140,20 +140,20 @@ int main(int argc, char *argv[]) rwlock = SDL_CreateRWLock(); if (!rwlock) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create rwlock: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create rwlock: %s", SDL_GetError()); SDL_Quit(); SDLTest_CommonDestroyState(state); return 1; } mainthread = SDL_GetCurrentThreadID(); - SDL_Log("Writer thread: %" SDL_PRIu64 "\n", mainthread); + SDL_Log("Writer thread: %" SDL_PRIu64, mainthread); for (i = 0; i < nb_threads; ++i) { char name[64]; (void)SDL_snprintf(name, sizeof(name), "Reader%d", i); threads[i] = SDL_CreateThread(ReaderRun, name, NULL); if (threads[i] == NULL) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create reader thread! %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create reader thread! %s", SDL_GetError()); } } diff --git a/libs/SDL3/test/testscale.c b/libs/SDL3/test/testscale.c index 4082a455..a282b07f 100644 --- a/libs/SDL3/test/testscale.c +++ b/libs/SDL3/test/testscale.c @@ -68,8 +68,8 @@ static void Draw(DrawState *s) s->scale_direction = 1; } } - s->sprite_rect.x = (float)((viewport.w - s->sprite_rect.w) / 2); - s->sprite_rect.y = (float)((viewport.h - s->sprite_rect.h) / 2); + s->sprite_rect.x = (viewport.w - s->sprite_rect.w) / 2; + s->sprite_rect.y = (viewport.h - s->sprite_rect.h) / 2; SDL_RenderTexture(s->renderer, s->sprite, NULL, &s->sprite_rect); @@ -153,7 +153,7 @@ int main(int argc, char *argv[]) now = SDL_GetTicks(); if (now > then) { double fps = ((double)frames * 1000) / (now - then); - SDL_Log("%2.2f frames per second\n", fps); + SDL_Log("%2.2f frames per second", fps); } SDL_stack_free(drawstates); diff --git a/libs/SDL3/test/testsem.c b/libs/SDL3/test/testsem.c index a8390c4e..78de5330 100644 --- a/libs/SDL3/test/testsem.c +++ b/libs/SDL3/test/testsem.c @@ -53,16 +53,16 @@ ThreadFuncRealWorld(void *data) Thread_State *state = (Thread_State *)data; while (alive) { SDL_WaitSemaphore(sem); - SDL_Log("Thread number %d has got the semaphore (value = %" SDL_PRIu32 ")!\n", + SDL_Log("Thread number %d has got the semaphore (value = %" SDL_PRIu32 ")!", state->number, SDL_GetSemaphoreValue(sem)); SDL_Delay(200); SDL_SignalSemaphore(sem); - SDL_Log("Thread number %d has released the semaphore (value = %" SDL_PRIu32 ")!\n", + SDL_Log("Thread number %d has released the semaphore (value = %" SDL_PRIu32 ")!", state->number, SDL_GetSemaphoreValue(sem)); ++state->loop_count; SDL_Delay(1); /* For the scheduler */ } - SDL_Log("Thread number %d exiting.\n", state->number); + SDL_Log("Thread number %d exiting.", state->number); return 0; } @@ -75,7 +75,7 @@ TestRealWorld(int init_sem) sem = SDL_CreateSemaphore(init_sem); - SDL_Log("Running %d threads, semaphore value = %d\n", NUM_THREADS, + SDL_Log("Running %d threads, semaphore value = %d", NUM_THREADS, init_sem); alive = 1; /* Create all the threads */ @@ -90,14 +90,15 @@ TestRealWorld(int init_sem) SDL_Delay(10 * 1000); /* Wait for all threads to finish */ - SDL_Log("Waiting for threads to finish\n"); + SDL_Log("Waiting for threads to finish"); alive = 0; loop_count = 0; for (i = 0; i < NUM_THREADS; ++i) { SDL_WaitThread(thread_states[i].thread, NULL); loop_count += thread_states[i].loop_count; } - SDL_Log("Finished waiting for threads, ran %d loops in total\n\n", loop_count); + SDL_Log("Finished waiting for threads, ran %d loops in total", loop_count); + SDL_Log("%s", ""); SDL_DestroySemaphore(sem); } @@ -111,7 +112,7 @@ TestWaitTimeout(void) bool result; sem = SDL_CreateSemaphore(0); - SDL_Log("Waiting 2 seconds on semaphore\n"); + SDL_Log("Waiting 2 seconds on semaphore"); start_ticks = SDL_GetTicks(); result = SDL_WaitSemaphoreTimeout(sem, 2000); @@ -120,12 +121,14 @@ TestWaitTimeout(void) duration = end_ticks - start_ticks; /* Accept a little offset in the effective wait */ - SDL_Log("Wait took %" SDL_PRIu64 " milliseconds\n\n", duration); + SDL_Log("Wait took %" SDL_PRIu64 " milliseconds", duration); + SDL_Log("%s", ""); SDL_assert(duration > 1900 && duration < 2050); /* Check to make sure the return value indicates timed out */ if (result) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_WaitSemaphoreTimeout returned: %d; expected: false\n\n", result); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_WaitSemaphoreTimeout returned: %d; expected: false", result); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s", ""); } SDL_DestroySemaphore(sem); @@ -140,7 +143,7 @@ TestOverheadUncontended(void) int i, j; sem = SDL_CreateSemaphore(0); - SDL_Log("Doing %d uncontended Post/Wait operations on semaphore\n", NUM_OVERHEAD_OPS * NUM_OVERHEAD_OPS_MULT); + SDL_Log("Doing %d uncontended Post/Wait operations on semaphore", NUM_OVERHEAD_OPS * NUM_OVERHEAD_OPS_MULT); start_ticks = SDL_GetTicks(); for (i = 0; i < NUM_OVERHEAD_OPS_MULT; i++) { @@ -154,7 +157,8 @@ TestOverheadUncontended(void) end_ticks = SDL_GetTicks(); duration = end_ticks - start_ticks; - SDL_Log("Took %" SDL_PRIu64 " milliseconds\n\n", duration); + SDL_Log("Took %" SDL_PRIu64 " milliseconds", duration); + SDL_Log("%s", ""); SDL_DestroySemaphore(sem); } @@ -197,7 +201,7 @@ TestOverheadContended(bool try_wait) size_t len; sem = SDL_CreateSemaphore(0); - SDL_Log("Doing %d contended %s operations on semaphore using %d threads\n", + SDL_Log("Doing %d contended %s operations on semaphore using %d threads", NUM_OVERHEAD_OPS * NUM_OVERHEAD_OPS_MULT, try_wait ? "Post/TryWait" : "Post/WaitTimeout", NUM_THREADS); alive = 1; /* Create multiple threads to starve the semaphore and cause contention */ @@ -232,7 +236,7 @@ TestOverheadContended(bool try_wait) SDL_assert_release((loop_count - content_count) == NUM_OVERHEAD_OPS * NUM_OVERHEAD_OPS_MULT); duration = end_ticks - start_ticks; - SDL_Log("Took %" SDL_PRIu64 " milliseconds, threads %s %d out of %d times in total (%.2f%%)\n", + SDL_Log("Took %" SDL_PRIu64 " milliseconds, threads %s %d out of %d times in total (%.2f%%)", duration, try_wait ? "where contended" : "timed out", content_count, loop_count, ((float)content_count * 100) / loop_count); /* Print how many semaphores where consumed per thread */ @@ -246,8 +250,8 @@ TestOverheadContended(bool try_wait) (void)SDL_snprintf(textBuffer + len, sizeof(textBuffer) - len, "%d", thread_states[i].loop_count - thread_states[i].content_count); } len = SDL_strlen(textBuffer); - (void)SDL_snprintf(textBuffer + len, sizeof(textBuffer) - len, " }\n"); - SDL_Log("%s\n", textBuffer); + (void)SDL_snprintf(textBuffer + len, sizeof(textBuffer) - len, " }"); + SDL_Log("%s", textBuffer); SDL_DestroySemaphore(sem); } @@ -300,7 +304,7 @@ int main(int argc, char **argv) /* Load the SDL library */ if (!SDL_Init(0)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError()); return 1; } (void)signal(SIGTERM, killed); diff --git a/libs/SDL3/test/testsensor.c b/libs/SDL3/test/testsensor.c index 2574b4e7..42d1fa68 100644 --- a/libs/SDL3/test/testsensor.c +++ b/libs/SDL3/test/testsensor.c @@ -39,19 +39,19 @@ static void HandleSensorEvent(SDL_SensorEvent *event) { SDL_Sensor *sensor = SDL_GetSensorFromID(event->which); if (!sensor) { - SDL_Log("Couldn't get sensor for sensor event\n"); + SDL_Log("Couldn't get sensor for sensor event"); return; } switch (SDL_GetSensorType(sensor)) { case SDL_SENSOR_ACCEL: - SDL_Log("Accelerometer update: %.2f, %.2f, %.2f\n", event->data[0], event->data[1], event->data[2]); + SDL_Log("Accelerometer update: %.2f, %.2f, %.2f", event->data[0], event->data[1], event->data[2]); break; case SDL_SENSOR_GYRO: - SDL_Log("Gyro update: %.2f, %.2f, %.2f\n", event->data[0], event->data[1], event->data[2]); + SDL_Log("Gyro update: %.2f, %.2f, %.2f", event->data[0], event->data[1], event->data[2]); break; default: - SDL_Log("Sensor update for sensor type %s\n", GetSensorTypeString(SDL_GetSensorType(sensor))); + SDL_Log("Sensor update for sensor type %s", GetSensorTypeString(SDL_GetSensorType(sensor))); break; } } @@ -76,7 +76,7 @@ int main(int argc, char **argv) /* Load the SDL library */ if (!SDL_Init(SDL_INIT_SENSOR)) { - SDL_Log("Couldn't initialize SDL: %s\n", SDL_GetError()); + SDL_Log("Couldn't initialize SDL: %s", SDL_GetError()); SDL_Quit(); SDLTest_CommonDestroyState(state); return 1; @@ -85,10 +85,10 @@ int main(int argc, char **argv) sensors = SDL_GetSensors(&num_sensors); num_opened = 0; - SDL_Log("There are %d sensors available\n", num_sensors); + SDL_Log("There are %d sensors available", num_sensors); if (sensors) { for (i = 0; i < num_sensors; ++i) { - SDL_Log("Sensor %" SDL_PRIu32 ": %s, type %s, platform type %d\n", + SDL_Log("Sensor %" SDL_PRIu32 ": %s, type %s, platform type %d", sensors[i], SDL_GetSensorNameForID(sensors[i]), GetSensorTypeString(SDL_GetSensorTypeForID(sensors[i])), @@ -97,7 +97,7 @@ int main(int argc, char **argv) if (SDL_GetSensorTypeForID(sensors[i]) != SDL_SENSOR_UNKNOWN) { SDL_Sensor *sensor = SDL_OpenSensor(sensors[i]); if (!sensor) { - SDL_Log("Couldn't open sensor %" SDL_PRIu32 ": %s\n", sensors[i], SDL_GetError()); + SDL_Log("Couldn't open sensor %" SDL_PRIu32 ": %s", sensors[i], SDL_GetError()); } else { ++num_opened; } @@ -105,7 +105,7 @@ int main(int argc, char **argv) } SDL_free(sensors); } - SDL_Log("Opened %d sensors\n", num_opened); + SDL_Log("Opened %d sensors", num_opened); if (num_opened > 0) { bool done = false; diff --git a/libs/SDL3/test/testshader.c b/libs/SDL3/test/testshader.c index ca9b0c37..9b13890b 100644 --- a/libs/SDL3/test/testshader.c +++ b/libs/SDL3/test/testshader.c @@ -145,7 +145,9 @@ static bool CompileShader(GLhandleARB shader, const char *source) SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!"); } else { pglGetInfoLogARB(shader, length, NULL, info); - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to compile shader:\n%s\n%s", source, info); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to compile shader:"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s", source); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s", info); SDL_free(info); } return false; @@ -173,7 +175,8 @@ static bool LinkProgram(ShaderData *data) SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!"); } else { pglGetInfoLogARB(data->program, length, NULL, info); - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to link program:\n%s", info); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to link program:"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s", info); SDL_free(info); } return false; @@ -279,7 +282,7 @@ static bool InitShaders(void) /* Compile all the shaders */ for (i = 0; i < NUM_SHADERS; ++i) { if (!CompileShaderProgram(&shaders[i])) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to compile shader!\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to compile shader!"); return false; } } @@ -480,20 +483,20 @@ int main(int argc, char **argv) /* Initialize SDL for video output */ if (!SDL_Init(SDL_INIT_VIDEO)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to initialize SDL: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to initialize SDL: %s", SDL_GetError()); exit(1); } /* Create a 640x480 OpenGL screen */ window = SDL_CreateWindow("Shader Demo", 640, 480, SDL_WINDOW_OPENGL); if (!window) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create OpenGL window: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create OpenGL window: %s", SDL_GetError()); SDL_Quit(); exit(2); } if (!SDL_GL_CreateContext(window)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create OpenGL context: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create OpenGL context: %s", SDL_GetError()); SDL_Quit(); exit(2); } @@ -503,7 +506,7 @@ int main(int argc, char **argv) SDL_free(filename); if (!surface) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to load icon.bmp: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to load icon.bmp: %s", SDL_GetError()); SDL_Quit(); exit(3); } @@ -513,9 +516,9 @@ int main(int argc, char **argv) /* Loop, drawing and checking events */ InitGL(640, 480); if (InitShaders()) { - SDL_Log("Shaders supported, press SPACE to cycle them.\n"); + SDL_Log("Shaders supported, press SPACE to cycle them."); } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Shaders not supported!\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Shaders not supported!"); } done = 0; while (!done) { @@ -549,7 +552,7 @@ int main(int argc, char **argv) int main(int argc, char *argv[]) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "No OpenGL support on this system\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "No OpenGL support on this system"); return 1; } diff --git a/libs/SDL3/test/testshape.c b/libs/SDL3/test/testshape.c index dd85b36c..9a884e6a 100644 --- a/libs/SDL3/test/testshape.c +++ b/libs/SDL3/test/testshape.c @@ -48,7 +48,7 @@ int main(int argc, char *argv[]) } else if (!image_file) { image_file = argv[i]; } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Usage: %s [--resizable] [shape.bmp]\n", argv[0]); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Usage: %s [--resizable] [shape.bmp]", argv[0]); goto quit; } } @@ -56,18 +56,18 @@ int main(int argc, char *argv[]) if (image_file) { shape = SDL_LoadBMP(image_file); if (!shape) { - SDL_Log("Couldn't load %s: %s\n", image_file, SDL_GetError()); + SDL_Log("Couldn't load %s: %s", image_file, SDL_GetError()); goto quit; } } else { SDL_IOStream *stream = SDL_IOFromConstMem(glass_bmp, sizeof(glass_bmp)); if (!stream) { - SDL_Log("Couldn't create iostream for glass.bmp: %s\n", SDL_GetError()); + SDL_Log("Couldn't create iostream for glass.bmp: %s", SDL_GetError()); goto quit; } shape = SDL_LoadBMP_IO(stream, true); if (!shape) { - SDL_Log("Couldn't load glass.bmp: %s\n", SDL_GetError()); + SDL_Log("Couldn't load glass.bmp: %s", SDL_GetError()); goto quit; } } @@ -81,13 +81,13 @@ int main(int argc, char *argv[]) } window = SDL_CreateWindow("SDL Shape Test", shape->w, shape->h, flags); if (!window) { - SDL_Log("Couldn't create transparent window: %s\n", SDL_GetError()); + SDL_Log("Couldn't create transparent window: %s", SDL_GetError()); goto quit; } renderer = SDL_CreateRenderer(window, NULL); if (!renderer) { - SDL_Log("Couldn't create renderer: %s\n", SDL_GetError()); + SDL_Log("Couldn't create renderer: %s", SDL_GetError()); goto quit; } @@ -102,7 +102,7 @@ int main(int argc, char *argv[]) if (!resizable) { /* Set the hit test callback so we can drag the window */ if (!SDL_SetWindowHitTest(window, ShapeHitTest, shape)) { - SDL_Log("Couldn't set hit test callback: %s\n", SDL_GetError()); + SDL_Log("Couldn't set hit test callback: %s", SDL_GetError()); goto quit; } } diff --git a/libs/SDL3/test/testsprite.c b/libs/SDL3/test/testsprite.c index e8d8a7dc..2f202d6d 100644 --- a/libs/SDL3/test/testsprite.c +++ b/libs/SDL3/test/testsprite.c @@ -67,7 +67,7 @@ static int LoadSprite(const char *file) return -1; } if (!SDL_SetTextureBlendMode(sprites[i], blendMode)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set blend mode: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set blend mode: %s", SDL_GetError()); SDL_DestroyTexture(sprites[i]); return -1; } @@ -502,7 +502,7 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) sprites = (SDL_Texture **)SDL_malloc(state->num_windows * sizeof(*sprites)); if (!sprites) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!"); return SDL_APP_FAILURE; } for (i = 0; i < state->num_windows; ++i) { @@ -518,7 +518,7 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) positions = (SDL_FRect *)SDL_malloc(num_sprites * sizeof(*positions)); velocities = (SDL_FRect *)SDL_malloc(num_sprites * sizeof(*velocities)); if (!positions || !velocities) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!"); return SDL_APP_FAILURE; } @@ -588,7 +588,7 @@ SDL_AppResult SDL_AppIterate(void *appstate) /* Print out some timing information */ const Uint64 then = next_fps_check - fps_check_delay; const double fps = ((double)frames * 1000) / (now - then); - SDL_Log("%2.2f frames per second\n", fps); + SDL_Log("%2.2f frames per second", fps); next_fps_check = now + fps_check_delay; frames = 0; } diff --git a/libs/SDL3/test/testspriteminimal.c b/libs/SDL3/test/testspriteminimal.c index 19bb200d..bf2a834d 100644 --- a/libs/SDL3/test/testspriteminimal.c +++ b/libs/SDL3/test/testspriteminimal.c @@ -113,7 +113,7 @@ int main(int argc, char *argv[]) int i; if (argc > 1) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "USAGE: %s\n", argv[0]); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "USAGE: %s", argv[0]); return_code = 1; goto quit; } diff --git a/libs/SDL3/test/testspritesurface.c b/libs/SDL3/test/testspritesurface.c index 80d61a39..68b926d0 100644 --- a/libs/SDL3/test/testspritesurface.c +++ b/libs/SDL3/test/testspritesurface.c @@ -106,7 +106,7 @@ int main(int argc, char *argv[]) int i; if (argc > 1) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "USAGE: %s\n", argv[0]); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "USAGE: %s", argv[0]); return_code = 1; goto quit; } diff --git a/libs/SDL3/test/teststreaming.c b/libs/SDL3/test/teststreaming.c index 2ed8c462..ea61b0e0 100644 --- a/libs/SDL3/test/teststreaming.c +++ b/libs/SDL3/test/teststreaming.c @@ -86,7 +86,7 @@ static void UpdateTexture(SDL_Texture *texture) int pitch; if (!SDL_LockTexture(texture, NULL, &pixels, &pitch)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't lock texture: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't lock texture: %s", SDL_GetError()); quit(5); } src = MooseFrames[frame]; @@ -152,20 +152,20 @@ int main(int argc, char **argv) } if (!SDL_Init(SDL_INIT_VIDEO)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError()); return 1; } /* load the moose images */ filename = GetResourceFilename(NULL, "moose.dat"); if (!filename) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory"); return -1; } handle = SDL_IOFromFile(filename, "rb"); SDL_free(filename); if (!handle) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Can't find the file moose.dat !\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Can't find the file moose.dat !"); quit(2); } SDL_ReadIO(handle, MooseFrames, MOOSEFRAME_SIZE * MOOSEFRAMES_COUNT); @@ -174,19 +174,19 @@ int main(int argc, char **argv) /* Create the window and renderer */ window = SDL_CreateWindow("Happy Moose", MOOSEPIC_W * 4, MOOSEPIC_H * 4, SDL_WINDOW_RESIZABLE); if (!window) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set create window: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set create window: %s", SDL_GetError()); quit(3); } renderer = SDL_CreateRenderer(window, NULL); if (!renderer) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set create renderer: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set create renderer: %s", SDL_GetError()); quit(4); } MooseTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, MOOSEPIC_W, MOOSEPIC_H); if (!MooseTexture) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set create texture: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set create texture: %s", SDL_GetError()); quit(5); } diff --git a/libs/SDL3/test/testsurround.c b/libs/SDL3/test/testsurround.c index 0c66163d..36b33f4c 100644 --- a/libs/SDL3/test/testsurround.c +++ b/libs/SDL3/test/testsurround.c @@ -209,7 +209,7 @@ int main(int argc, char *argv[]) } if (!SDL_Init(SDL_INIT_AUDIO)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError()); return 1; } @@ -219,11 +219,11 @@ int main(int argc, char *argv[]) SDL_Log("%i: %s", i, SDL_GetAudioDriver(i)); } - SDL_Log("Using audio driver: %s\n", SDL_GetCurrentAudioDriver()); + SDL_Log("Using audio driver: %s", SDL_GetCurrentAudioDriver()); devices = SDL_GetAudioPlaybackDevices(&devcount); if (!devices) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_GetAudioPlaybackDevices() failed: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_GetAudioPlaybackDevices() failed: %s", SDL_GetError()); } SDL_Log("Available audio devices:"); @@ -237,14 +237,14 @@ int main(int argc, char *argv[]) int j; SDL_AudioSpec spec; - SDL_Log("Testing audio device: %s\n", devname); + SDL_Log("Testing audio device: %s", devname); if (!SDL_GetAudioDeviceFormat(devices[i], &spec, NULL)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_GetAudioDeviceFormat() failed: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_GetAudioDeviceFormat() failed: %s", SDL_GetError()); continue; } - SDL_Log(" (%d channels)\n", spec.channels); + SDL_Log(" (%d channels)", spec.channels); spec.freq = SAMPLE_RATE_HZ; spec.format = SDL_AUDIO_S16; @@ -255,7 +255,7 @@ int main(int argc, char *argv[]) stream = SDL_OpenAudioDeviceStream(devices[i], &spec, fill_buffer, NULL); if (!stream) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_OpenAudioDeviceStream() failed: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_OpenAudioDeviceStream() failed: %s", SDL_GetError()); continue; } SDL_ResumeAudioStreamDevice(stream); @@ -263,7 +263,7 @@ int main(int argc, char *argv[]) for (j = 0; j < total_channels; j++) { const int sine_freq = is_lfe_channel(j, total_channels) ? LFE_SINE_FREQ_HZ : SINE_FREQ_HZ; - SDL_Log("Playing %d Hz test tone on channel: %s\n", sine_freq, get_channel_name(j, total_channels)); + SDL_Log("Playing %d Hz test tone on channel: %s", sine_freq, get_channel_name(j, total_channels)); /* fill_buffer() will increment the active channel */ if (SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "SDL_TESTS_QUICK") != NULL) { diff --git a/libs/SDL3/test/testthread.c b/libs/SDL3/test/testthread.c index 5a4c4781..70710eac 100644 --- a/libs/SDL3/test/testthread.c +++ b/libs/SDL3/test/testthread.c @@ -60,13 +60,13 @@ ThreadFunc(void *data) SDL_ThreadPriority prio = SDL_THREAD_PRIORITY_NORMAL; SDL_SetTLS(&tls, "baby thread", NULL); - SDL_Log("Started thread %s: My thread id is %" SDL_PRIu64 ", thread data = %s\n", + SDL_Log("Started thread %s: My thread id is %" SDL_PRIu64 ", thread data = %s", (char *)data, SDL_GetCurrentThreadID(), (const char *)SDL_GetTLS(&tls)); while (SDL_GetAtomicInt(&alive)) { - SDL_Log("Thread '%s' is alive!\n", (char *)data); + SDL_Log("Thread '%s' is alive!", (char *)data); if (testprio) { - SDL_Log("SDL_SetCurrentThreadPriority(%s):%d\n", getprioritystr(prio), SDL_SetCurrentThreadPriority(prio)); + SDL_Log("SDL_SetCurrentThreadPriority(%s):%d", getprioritystr(prio), SDL_SetCurrentThreadPriority(prio)); if (++prio > SDL_THREAD_PRIORITY_TIME_CRITICAL) { prio = SDL_THREAD_PRIORITY_LOW; } @@ -74,14 +74,14 @@ ThreadFunc(void *data) SDL_Delay(1 * 1000); } - SDL_Log("Thread '%s' exiting!\n", (char *)data); + SDL_Log("Thread '%s' exiting!", (char *)data); return 0; } static void killed(int sig) { - SDL_Log("Killed with SIGTERM, waiting 5 seconds to exit\n"); + SDL_Log("Killed with SIGTERM, waiting 5 seconds to exit"); SDL_Delay(5 * 1000); SDL_SetAtomicInt(&alive, 0); SDL_WaitThread(thread, NULL); @@ -120,7 +120,7 @@ int main(int argc, char *argv[]) /* Load the SDL library */ if (!SDL_Init(0)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError()); return 1; } @@ -131,26 +131,26 @@ int main(int argc, char *argv[]) } SDL_SetTLS(&tls, "main thread", NULL); - SDL_Log("Main thread data initially: %s\n", (const char *)SDL_GetTLS(&tls)); + SDL_Log("Main thread data initially: %s", (const char *)SDL_GetTLS(&tls)); SDL_SetAtomicInt(&alive, 1); thread = SDL_CreateThread(ThreadFunc, "One", "#1"); if (!thread) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create thread: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create thread: %s", SDL_GetError()); quit(1); } SDL_Delay(5 * 1000); - SDL_Log("Waiting for thread #1\n"); + SDL_Log("Waiting for thread #1"); SDL_SetAtomicInt(&alive, 0); SDL_WaitThread(thread, NULL); - SDL_Log("Main thread data finally: %s\n", (const char *)SDL_GetTLS(&tls)); + SDL_Log("Main thread data finally: %s", (const char *)SDL_GetTLS(&tls)); SDL_SetAtomicInt(&alive, 1); (void)signal(SIGTERM, killed); thread = SDL_CreateThread(ThreadFunc, "Two", "#2"); if (!thread) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create thread: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create thread: %s", SDL_GetError()); quit(1); } (void)raise(SIGTERM); diff --git a/libs/SDL3/test/testtimer.c b/libs/SDL3/test/testtimer.c index f099a8f4..0f12dce7 100644 --- a/libs/SDL3/test/testtimer.c +++ b/libs/SDL3/test/testtimer.c @@ -68,7 +68,7 @@ callback(void *param, SDL_TimerID timerID, Uint32 interval) { int value = (int)(uintptr_t)param; SDL_assert( value == 1 || value == 2 || value == 3 ); - SDL_Log("Timer %" SDL_PRIu32 " : param = %d\n", interval, value); + SDL_Log("Timer %" SDL_PRIu32 " : param = %d", interval, value); return interval; } @@ -123,13 +123,13 @@ int main(int argc, char *argv[]) } /* Verify SDL_GetTicks* acts monotonically increasing, and not erratic. */ - SDL_Log("Sanity-checking GetTicks\n"); + SDL_Log("Sanity-checking GetTicks"); for (i = 0; i < 1000; ++i) { start = SDL_GetTicks(); SDL_Delay(1); now = SDL_GetTicks() - start; if (now > 100) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "testtimer.c: Delta time erratic at iter %d. Delay 1ms = %d ms in ticks\n", i, (int)now); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "testtimer.c: Delta time erratic at iter %d. Delay 1ms = %d ms in ticks", i, (int)now); SDL_Quit(); return 1; } @@ -143,7 +143,7 @@ int main(int argc, char *argv[]) t1 = SDL_AddTimer(desired, ticktock, NULL); /* Wait 1 seconds */ - SDL_Log("Waiting 1 seconds for millisecond timer\n"); + SDL_Log("Waiting 1 seconds for millisecond timer"); SDL_Delay(1 * 1000); /* Stop the timer */ @@ -151,7 +151,7 @@ int main(int argc, char *argv[]) /* Print the results */ if (ticks) { - SDL_Log("Millisecond timer resolution: desired = %d ms, actual = %f ms\n", + SDL_Log("Millisecond timer resolution: desired = %d ms, actual = %f ms", desired, (double)(10 * 1000) / ticks); } @@ -163,7 +163,7 @@ int main(int argc, char *argv[]) t1 = SDL_AddTimerNS(desired, ticktockNS, NULL); /* Wait 1 seconds */ - SDL_Log("Waiting 1 seconds for nanosecond timer\n"); + SDL_Log("Waiting 1 seconds for nanosecond timer"); SDL_Delay(1 * 1000); /* Stop the timer */ @@ -171,7 +171,7 @@ int main(int argc, char *argv[]) /* Print the results */ if (ticks) { - SDL_Log("Nanosecond timer resolution: desired = %d ns, actual = %f ns\n", + SDL_Log("Nanosecond timer resolution: desired = %d ns, actual = %f ns", desired, (double)(10 * 1000000) / ticks); } @@ -188,9 +188,9 @@ int main(int argc, char *argv[]) SDL_DelayNS(1); now = SDL_GetTicksNS(); actual_delay = (now - start); - SDL_Log("Minimum nanosecond delay: %" SDL_PRIu64 " ns\n", actual_delay); + SDL_Log("Minimum nanosecond delay: %" SDL_PRIu64 " ns", actual_delay); - SDL_Log("Timing 100 frames at 60 FPS\n"); + SDL_Log("Timing 100 frames at 60 FPS"); for (i = 0; i < 100; ++i) { start = SDL_GetTicksNS(); SDL_DelayNS(desired_delay); @@ -200,7 +200,7 @@ int main(int argc, char *argv[]) total_overslept += (actual_delay - desired_delay); } } - SDL_Log("Overslept %.2f ms\n", (double)total_overslept / SDL_NS_PER_MS); + SDL_Log("Overslept %.2f ms", (double)total_overslept / SDL_NS_PER_MS); } /* Wait for the results to be seen */ @@ -216,9 +216,9 @@ int main(int argc, char *argv[]) SDL_DelayPrecise(1); now = SDL_GetTicksNS(); actual_delay = (now - start); - SDL_Log("Minimum precise delay: %" SDL_PRIu64 " ns\n", actual_delay); + SDL_Log("Minimum precise delay: %" SDL_PRIu64 " ns", actual_delay); - SDL_Log("Timing 100 frames at 60 FPS\n"); + SDL_Log("Timing 100 frames at 60 FPS"); for (i = 0; i < 100; ++i) { start = SDL_GetTicksNS(); SDL_DelayPrecise(desired_delay); @@ -228,32 +228,32 @@ int main(int argc, char *argv[]) total_overslept += (actual_delay - desired_delay); } } - SDL_Log("Overslept %.2f ms\n", (double)total_overslept / SDL_NS_PER_MS); + SDL_Log("Overslept %.2f ms", (double)total_overslept / SDL_NS_PER_MS); } /* Wait for the results to be seen */ SDL_Delay(1 * 1000); /* Test multiple timers */ - SDL_Log("Testing multiple timers...\n"); + SDL_Log("Testing multiple timers..."); t1 = SDL_AddTimer(100, callback, (void *)1); if (!t1) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not create timer 1: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not create timer 1: %s", SDL_GetError()); } t2 = SDL_AddTimer(50, callback, (void *)2); if (!t2) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not create timer 2: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not create timer 2: %s", SDL_GetError()); } t3 = SDL_AddTimer(233, callback, (void *)3); if (!t3) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not create timer 3: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not create timer 3: %s", SDL_GetError()); } /* Wait 3 seconds */ - SDL_Log("Waiting 3 seconds\n"); + SDL_Log("Waiting 3 seconds"); SDL_Delay(3 * 1000); - SDL_Log("Removing timer 1 and waiting 3 more seconds\n"); + SDL_Log("Removing timer 1 and waiting 3 more seconds"); SDL_RemoveTimer(t1); SDL_Delay(3 * 1000); @@ -267,15 +267,15 @@ int main(int argc, char *argv[]) ticktock(NULL, 0, 0); } now_perf = SDL_GetPerformanceCounter(); - SDL_Log("1 million iterations of ticktock took %f ms\n", (double)((now_perf - start_perf) * 1000) / SDL_GetPerformanceFrequency()); + SDL_Log("1 million iterations of ticktock took %f ms", (double)((now_perf - start_perf) * 1000) / SDL_GetPerformanceFrequency()); - SDL_Log("Performance counter frequency: %" SDL_PRIu64 "\n", SDL_GetPerformanceFrequency()); + SDL_Log("Performance counter frequency: %" SDL_PRIu64, SDL_GetPerformanceFrequency()); start = SDL_GetTicks(); start_perf = SDL_GetPerformanceCounter(); SDL_Delay(1000); now_perf = SDL_GetPerformanceCounter(); now = SDL_GetTicks(); - SDL_Log("Delay 1 second = %d ms in ticks, %f ms according to performance counter\n", (int)(now - start), (double)((now_perf - start_perf) * 1000) / SDL_GetPerformanceFrequency()); + SDL_Log("Delay 1 second = %d ms in ticks, %f ms according to performance counter", (int)(now - start), (double)((now_perf - start_perf) * 1000) / SDL_GetPerformanceFrequency()); if (run_interactive_tests) { return_code = test_sdl_delay_within_bounds(); diff --git a/libs/SDL3/test/testtray.c b/libs/SDL3/test/testtray.c index f3cf8ba4..fdb12daf 100644 --- a/libs/SDL3/test/testtray.c +++ b/libs/SDL3/test/testtray.c @@ -52,7 +52,7 @@ static void SDLCALL change_icon(void *ptr, SDL_TrayEntry *entry) static void SDLCALL print_entry(void *ptr, SDL_TrayEntry *entry) { - SDL_Log("Clicked on button '%s'\n", SDL_GetTrayEntryLabel(entry)); + SDL_Log("Clicked on button '%s'", SDL_GetTrayEntryLabel(entry)); } static void SDLCALL set_entry_enabled(void *ptr, SDL_TrayEntry *entry) @@ -88,7 +88,7 @@ static void SDLCALL remove_entry(void *ptr, SDL_TrayEntry *entry) SDL_TrayEntry *ctrl_entry = SDL_GetTrayMenuParentEntry(ctrl_submenu); if (!ctrl_entry) { - SDL_Log("Attempt to remove a menu that isn't a submenu. This shouldn't happen.\n"); + SDL_Log("Attempt to remove a menu that isn't a submenu. This shouldn't happen."); return; } @@ -108,7 +108,7 @@ static void SDLCALL append_button_to(void *ptr, SDL_TrayEntry *entry) new_ctrl = SDL_InsertTrayEntryAt(SDL_GetTrayEntryParent(entry), -1, "New button", SDL_TRAYENTRY_SUBMENU); if (!new_ctrl) { - SDL_Log("Couldn't insert entry in control tray: %s\n", SDL_GetError()); + SDL_Log("Couldn't insert entry in control tray: %s", SDL_GetError()); return; } @@ -117,7 +117,7 @@ static void SDLCALL append_button_to(void *ptr, SDL_TrayEntry *entry) submenu = SDL_CreateTraySubmenu(new_ctrl); if (!new_ctrl) { - SDL_Log("Couldn't create control tray entry submenu: %s\n", SDL_GetError()); + SDL_Log("Couldn't create control tray entry submenu: %s", SDL_GetError()); SDL_RemoveTrayEntry(new_ctrl); return; } @@ -127,7 +127,7 @@ static void SDLCALL append_button_to(void *ptr, SDL_TrayEntry *entry) new_example = SDL_InsertTrayEntryAt(menu, -1, "New button", SDL_TRAYENTRY_BUTTON); if (new_example == NULL) { - SDL_Log("Couldn't insert entry in example tray: %s\n", SDL_GetError()); + SDL_Log("Couldn't insert entry in example tray: %s", SDL_GetError()); SDL_RemoveTrayEntry(new_ctrl); return; } @@ -139,7 +139,7 @@ static void SDLCALL append_button_to(void *ptr, SDL_TrayEntry *entry) new_ctrl_remove = SDL_InsertTrayEntryAt(submenu, -1, "Remove", SDL_TRAYENTRY_BUTTON); if (new_ctrl_remove == NULL) { - SDL_Log("Couldn't insert new_ctrl_remove: %s\n", SDL_GetError()); + SDL_Log("Couldn't insert new_ctrl_remove: %s", SDL_GetError()); SDL_RemoveTrayEntry(new_ctrl); SDL_RemoveTrayEntry(new_example); return; @@ -152,7 +152,7 @@ static void SDLCALL append_button_to(void *ptr, SDL_TrayEntry *entry) new_ctrl_enabled = SDL_InsertTrayEntryAt(submenu, -1, "Enable", SDL_TRAYENTRY_BUTTON); if (new_ctrl_enabled == NULL) { - SDL_Log("Couldn't insert new_ctrl_enabled: %s\n", SDL_GetError()); + SDL_Log("Couldn't insert new_ctrl_enabled: %s", SDL_GetError()); SDL_RemoveTrayEntry(new_ctrl); SDL_RemoveTrayEntry(new_example); return; @@ -165,7 +165,7 @@ static void SDLCALL append_button_to(void *ptr, SDL_TrayEntry *entry) new_ctrl_disabled = SDL_InsertTrayEntryAt(submenu, -1, "Disable", SDL_TRAYENTRY_BUTTON); if (new_ctrl_disabled == NULL) { - SDL_Log("Couldn't insert new_ctrl_disabled: %s\n", SDL_GetError()); + SDL_Log("Couldn't insert new_ctrl_disabled: %s", SDL_GetError()); SDL_RemoveTrayEntry(new_ctrl); SDL_RemoveTrayEntry(new_example); return; @@ -189,7 +189,7 @@ static void SDLCALL append_checkbox_to(void *ptr, SDL_TrayEntry *entry) new_ctrl = SDL_InsertTrayEntryAt(SDL_GetTrayEntryParent(entry), -1, "New checkbox", SDL_TRAYENTRY_SUBMENU); if (!new_ctrl) { - SDL_Log("Couldn't insert entry in control tray: %s\n", SDL_GetError()); + SDL_Log("Couldn't insert entry in control tray: %s", SDL_GetError()); return; } @@ -198,7 +198,7 @@ static void SDLCALL append_checkbox_to(void *ptr, SDL_TrayEntry *entry) submenu = SDL_CreateTraySubmenu(new_ctrl); if (!new_ctrl) { - SDL_Log("Couldn't create control tray entry submenu: %s\n", SDL_GetError()); + SDL_Log("Couldn't create control tray entry submenu: %s", SDL_GetError()); SDL_RemoveTrayEntry(new_ctrl); return; } @@ -208,7 +208,7 @@ static void SDLCALL append_checkbox_to(void *ptr, SDL_TrayEntry *entry) new_example = SDL_InsertTrayEntryAt(menu, -1, "New checkbox", SDL_TRAYENTRY_CHECKBOX); if (new_example == NULL) { - SDL_Log("Couldn't insert entry in example tray: %s\n", SDL_GetError()); + SDL_Log("Couldn't insert entry in example tray: %s", SDL_GetError()); SDL_RemoveTrayEntry(new_ctrl); return; } @@ -220,7 +220,7 @@ static void SDLCALL append_checkbox_to(void *ptr, SDL_TrayEntry *entry) new_ctrl_remove = SDL_InsertTrayEntryAt(submenu, -1, "Remove", SDL_TRAYENTRY_BUTTON); if (new_ctrl_remove == NULL) { - SDL_Log("Couldn't insert new_ctrl_remove: %s\n", SDL_GetError()); + SDL_Log("Couldn't insert new_ctrl_remove: %s", SDL_GetError()); SDL_RemoveTrayEntry(new_ctrl); SDL_RemoveTrayEntry(new_example); return; @@ -233,7 +233,7 @@ static void SDLCALL append_checkbox_to(void *ptr, SDL_TrayEntry *entry) new_ctrl_enabled = SDL_InsertTrayEntryAt(submenu, -1, "Enable", SDL_TRAYENTRY_BUTTON); if (new_ctrl_enabled == NULL) { - SDL_Log("Couldn't insert new_ctrl_enabled: %s\n", SDL_GetError()); + SDL_Log("Couldn't insert new_ctrl_enabled: %s", SDL_GetError()); SDL_RemoveTrayEntry(new_ctrl); SDL_RemoveTrayEntry(new_example); return; @@ -246,7 +246,7 @@ static void SDLCALL append_checkbox_to(void *ptr, SDL_TrayEntry *entry) new_ctrl_disabled = SDL_InsertTrayEntryAt(submenu, -1, "Disable", SDL_TRAYENTRY_BUTTON); if (new_ctrl_disabled == NULL) { - SDL_Log("Couldn't insert new_ctrl_disabled: %s\n", SDL_GetError()); + SDL_Log("Couldn't insert new_ctrl_disabled: %s", SDL_GetError()); SDL_RemoveTrayEntry(new_ctrl); SDL_RemoveTrayEntry(new_example); return; @@ -259,7 +259,7 @@ static void SDLCALL append_checkbox_to(void *ptr, SDL_TrayEntry *entry) new_ctrl_checked = SDL_InsertTrayEntryAt(submenu, -1, "Check", SDL_TRAYENTRY_BUTTON); if (new_ctrl_checked == NULL) { - SDL_Log("Couldn't insert new_ctrl_checked: %s\n", SDL_GetError()); + SDL_Log("Couldn't insert new_ctrl_checked: %s", SDL_GetError()); SDL_RemoveTrayEntry(new_ctrl); SDL_RemoveTrayEntry(new_example); return; @@ -272,7 +272,7 @@ static void SDLCALL append_checkbox_to(void *ptr, SDL_TrayEntry *entry) new_ctrl_unchecked = SDL_InsertTrayEntryAt(submenu, -1, "Uncheck", SDL_TRAYENTRY_BUTTON); if (new_ctrl_unchecked == NULL) { - SDL_Log("Couldn't insert new_ctrl_unchecked: %s\n", SDL_GetError()); + SDL_Log("Couldn't insert new_ctrl_unchecked: %s", SDL_GetError()); SDL_RemoveTrayEntry(new_ctrl); SDL_RemoveTrayEntry(new_example); return; @@ -292,7 +292,7 @@ static void SDLCALL append_separator_to(void *ptr, SDL_TrayEntry *entry) new_ctrl = SDL_InsertTrayEntryAt(SDL_GetTrayEntryParent(entry), -1, "[Separator]", SDL_TRAYENTRY_SUBMENU); if (!new_ctrl) { - SDL_Log("Couldn't insert entry in control tray: %s\n", SDL_GetError()); + SDL_Log("Couldn't insert entry in control tray: %s", SDL_GetError()); return; } @@ -301,7 +301,7 @@ static void SDLCALL append_separator_to(void *ptr, SDL_TrayEntry *entry) submenu = SDL_CreateTraySubmenu(new_ctrl); if (!new_ctrl) { - SDL_Log("Couldn't create control tray entry submenu: %s\n", SDL_GetError()); + SDL_Log("Couldn't create control tray entry submenu: %s", SDL_GetError()); SDL_RemoveTrayEntry(new_ctrl); return; } @@ -311,7 +311,7 @@ static void SDLCALL append_separator_to(void *ptr, SDL_TrayEntry *entry) new_example = SDL_InsertTrayEntryAt(menu, -1, NULL, SDL_TRAYENTRY_BUTTON); if (new_example == NULL) { - SDL_Log("Couldn't insert separator in example tray: %s\n", SDL_GetError()); + SDL_Log("Couldn't insert separator in example tray: %s", SDL_GetError()); SDL_RemoveTrayEntry(new_ctrl); return; } @@ -321,7 +321,7 @@ static void SDLCALL append_separator_to(void *ptr, SDL_TrayEntry *entry) new_ctrl_remove = SDL_InsertTrayEntryAt(submenu, -1, "Remove", SDL_TRAYENTRY_BUTTON); if (new_ctrl_remove == NULL) { - SDL_Log("Couldn't insert new_ctrl_remove: %s\n", SDL_GetError()); + SDL_Log("Couldn't insert new_ctrl_remove: %s", SDL_GetError()); SDL_RemoveTrayEntry(new_ctrl); SDL_RemoveTrayEntry(new_example); return; @@ -344,7 +344,7 @@ static void SDLCALL append_submenu_to(void *ptr, SDL_TrayEntry *entry) new_ctrl = SDL_InsertTrayEntryAt(SDL_GetTrayEntryParent(entry), -1, "New submenu", SDL_TRAYENTRY_SUBMENU); if (!new_ctrl) { - SDL_Log("Couldn't insert entry in control tray: %s\n", SDL_GetError()); + SDL_Log("Couldn't insert entry in control tray: %s", SDL_GetError()); return; } @@ -353,7 +353,7 @@ static void SDLCALL append_submenu_to(void *ptr, SDL_TrayEntry *entry) submenu = SDL_CreateTraySubmenu(new_ctrl); if (!new_ctrl) { - SDL_Log("Couldn't create control tray entry submenu: %s\n", SDL_GetError()); + SDL_Log("Couldn't create control tray entry submenu: %s", SDL_GetError()); SDL_RemoveTrayEntry(new_ctrl); return; } @@ -363,7 +363,7 @@ static void SDLCALL append_submenu_to(void *ptr, SDL_TrayEntry *entry) new_example = SDL_InsertTrayEntryAt(menu, -1, "New submenu", SDL_TRAYENTRY_SUBMENU); if (new_example == NULL) { - SDL_Log("Couldn't insert entry in example tray: %s\n", SDL_GetError()); + SDL_Log("Couldn't insert entry in example tray: %s", SDL_GetError()); SDL_RemoveTrayEntry(new_ctrl); return; } @@ -375,7 +375,7 @@ static void SDLCALL append_submenu_to(void *ptr, SDL_TrayEntry *entry) entry_submenu = SDL_CreateTraySubmenu(new_example); if (entry_submenu == NULL) { - SDL_Log("Couldn't create new entry submenu: %s\n", SDL_GetError()); + SDL_Log("Couldn't create new entry submenu: %s", SDL_GetError()); SDL_RemoveTrayEntry(new_ctrl); SDL_RemoveTrayEntry(new_example); return; @@ -386,7 +386,7 @@ static void SDLCALL append_submenu_to(void *ptr, SDL_TrayEntry *entry) new_ctrl_remove = SDL_InsertTrayEntryAt(submenu, -1, "Remove", SDL_TRAYENTRY_BUTTON); if (new_ctrl_remove == NULL) { - SDL_Log("Couldn't insert new_ctrl_remove: %s\n", SDL_GetError()); + SDL_Log("Couldn't insert new_ctrl_remove: %s", SDL_GetError()); SDL_RemoveTrayEntry(new_ctrl); SDL_RemoveTrayEntry(new_example); return; @@ -399,7 +399,7 @@ static void SDLCALL append_submenu_to(void *ptr, SDL_TrayEntry *entry) new_ctrl_enabled = SDL_InsertTrayEntryAt(submenu, -1, "Enable", SDL_TRAYENTRY_BUTTON); if (new_ctrl_enabled == NULL) { - SDL_Log("Couldn't insert new_ctrl_enabled: %s\n", SDL_GetError()); + SDL_Log("Couldn't insert new_ctrl_enabled: %s", SDL_GetError()); SDL_RemoveTrayEntry(new_ctrl); SDL_RemoveTrayEntry(new_example); return; @@ -412,7 +412,7 @@ static void SDLCALL append_submenu_to(void *ptr, SDL_TrayEntry *entry) new_ctrl_disabled = SDL_InsertTrayEntryAt(submenu, -1, "Disable", SDL_TRAYENTRY_BUTTON); if (new_ctrl_disabled == NULL) { - SDL_Log("Couldn't insert new_ctrl_disabled: %s\n", SDL_GetError()); + SDL_Log("Couldn't insert new_ctrl_disabled: %s", SDL_GetError()); SDL_RemoveTrayEntry(new_ctrl); SDL_RemoveTrayEntry(new_example); return; @@ -429,7 +429,7 @@ static void SDLCALL append_submenu_to(void *ptr, SDL_TrayEntry *entry) SDL_TrayEntry *entry_newbtn = SDL_InsertTrayEntryAt(submenu, -1, "Create button", SDL_TRAYENTRY_BUTTON); if (entry_newbtn == NULL) { - SDL_Log("Couldn't insert entry_newbtn: %s\n", SDL_GetError()); + SDL_Log("Couldn't insert entry_newbtn: %s", SDL_GetError()); SDL_RemoveTrayEntry(new_ctrl); SDL_RemoveTrayEntry(new_example); return; @@ -442,7 +442,7 @@ static void SDLCALL append_submenu_to(void *ptr, SDL_TrayEntry *entry) SDL_TrayEntry *entry_newchk = SDL_InsertTrayEntryAt(submenu, -1, "Create checkbox", SDL_TRAYENTRY_BUTTON); if (entry_newchk == NULL) { - SDL_Log("Couldn't insert entry_newchk: %s\n", SDL_GetError()); + SDL_Log("Couldn't insert entry_newchk: %s", SDL_GetError()); SDL_RemoveTrayEntry(new_ctrl); SDL_RemoveTrayEntry(new_example); return; @@ -455,7 +455,7 @@ static void SDLCALL append_submenu_to(void *ptr, SDL_TrayEntry *entry) SDL_TrayEntry *entry_newsub = SDL_InsertTrayEntryAt(submenu, -1, "Create submenu", SDL_TRAYENTRY_BUTTON); if (entry_newsub == NULL) { - SDL_Log("Couldn't insert entry_newsub: %s\n", SDL_GetError()); + SDL_Log("Couldn't insert entry_newsub: %s", SDL_GetError()); SDL_RemoveTrayEntry(new_ctrl); SDL_RemoveTrayEntry(new_example); return; @@ -468,7 +468,7 @@ static void SDLCALL append_submenu_to(void *ptr, SDL_TrayEntry *entry) SDL_TrayEntry *entry_newsep = SDL_InsertTrayEntryAt(submenu, -1, "Create separator", SDL_TRAYENTRY_BUTTON); if (entry_newsep == NULL) { - SDL_Log("Couldn't insert entry_newsep: %s\n", SDL_GetError()); + SDL_Log("Couldn't insert entry_newsep: %s", SDL_GetError()); SDL_RemoveTrayEntry(new_ctrl); SDL_RemoveTrayEntry(new_example); return; diff --git a/libs/SDL3/test/testurl.c b/libs/SDL3/test/testurl.c index 3f4b2231..cc2cb61c 100644 --- a/libs/SDL3/test/testurl.c +++ b/libs/SDL3/test/testurl.c @@ -26,7 +26,7 @@ int main(int argc, char **argv) { int i; if (!SDL_Init(SDL_INIT_VIDEO)) { - SDL_Log("SDL_Init failed: %s\n", SDL_GetError()); + SDL_Log("SDL_Init failed: %s", SDL_GetError()); return 1; } diff --git a/libs/SDL3/test/testutils.c b/libs/SDL3/test/testutils.c index 6ca778dc..ab044bf2 100644 --- a/libs/SDL3/test/testutils.c +++ b/libs/SDL3/test/testutils.c @@ -127,7 +127,7 @@ SDL_Texture *LoadTexture(SDL_Renderer *renderer, const char *file, bool transpar texture = SDL_CreateTextureFromSurface(renderer, temp); if (!texture) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create texture: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create texture: %s", SDL_GetError()); } } SDL_DestroySurface(temp); diff --git a/libs/SDL3/test/testver.c b/libs/SDL3/test/testver.c index bed2a6a6..b8730384 100644 --- a/libs/SDL3/test/testver.c +++ b/libs/SDL3/test/testver.c @@ -25,15 +25,15 @@ int main(int argc, char *argv[]) } #if SDL_VERSION_ATLEAST(3, 0, 0) - SDL_Log("Compiled with SDL 3.0 or newer\n"); + SDL_Log("Compiled with SDL 3.0 or newer"); #else - SDL_Log("Compiled with SDL older than 3.0\n"); + SDL_Log("Compiled with SDL older than 3.0"); #endif - SDL_Log("Compiled version: %d.%d.%d (%s)\n", + SDL_Log("Compiled version: %d.%d.%d (%s)", SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_MICRO_VERSION, SDL_REVISION); int version = SDL_GetVersion(); - SDL_Log("Runtime version: %d.%d.%d (%s)\n", + SDL_Log("Runtime version: %d.%d.%d (%s)", SDL_VERSIONNUM_MAJOR(version), SDL_VERSIONNUM_MINOR(version), SDL_VERSIONNUM_MICRO(version), SDL_GetRevision()); SDL_Quit(); diff --git a/libs/SDL3/test/testviewport.c b/libs/SDL3/test/testviewport.c index 904cc901..01e27e7b 100644 --- a/libs/SDL3/test/testviewport.c +++ b/libs/SDL3/test/testviewport.c @@ -85,7 +85,7 @@ static void DrawOnViewport(SDL_Renderer *renderer) /* Add a box at the top */ rect.w = 8.0f; rect.h = 8.0f; - rect.x = (float)((viewport.w - rect.w) / 2); + rect.x = (viewport.w - rect.w) / 2; rect.y = 0.0f; SDL_RenderFillRect(renderer, &rect); @@ -227,7 +227,7 @@ int main(int argc, char *argv[]) now = SDL_GetTicks(); if (now > then) { double fps = ((double)frames * 1000) / (now - then); - SDL_Log("%2.2f frames per second\n", fps); + SDL_Log("%2.2f frames per second", fps); } quit(0); return 0; diff --git a/libs/SDL3/test/testvulkan.c b/libs/SDL3/test/testvulkan.c index 9d9d80a0..a728b79e 100644 --- a/libs/SDL3/test/testvulkan.c +++ b/libs/SDL3/test/testvulkan.c @@ -18,7 +18,7 @@ int main(int argc, char *argv[]) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "No Vulkan support on this system\n"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "No Vulkan support on this system"); return 1; } @@ -198,18 +198,18 @@ static void loadGlobalFunctions(void) vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_Vulkan_GetVkGetInstanceProcAddr(); if (!vkGetInstanceProcAddr) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "SDL_Vulkan_GetVkGetInstanceProcAddr(): %s\n", + "SDL_Vulkan_GetVkGetInstanceProcAddr(): %s", SDL_GetError()); quit(2); } #define VULKAN_DEVICE_FUNCTION(name) -#define VULKAN_GLOBAL_FUNCTION(name) \ - name = (PFN_##name)vkGetInstanceProcAddr(VK_NULL_HANDLE, #name); \ - if (!name) { \ - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, \ - "vkGetInstanceProcAddr(VK_NULL_HANDLE, \"" #name "\") failed\n"); \ - quit(2); \ +#define VULKAN_GLOBAL_FUNCTION(name) \ + name = (PFN_##name)vkGetInstanceProcAddr(VK_NULL_HANDLE, #name); \ + if (!name) { \ + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, \ + "vkGetInstanceProcAddr(VK_NULL_HANDLE, \"" #name "\") failed"); \ + quit(2); \ } #define VULKAN_INSTANCE_FUNCTION(name) VULKAN_FUNCTIONS() @@ -237,7 +237,7 @@ static void createInstance(void) if (result != VK_SUCCESS) { vulkanContext->instance = VK_NULL_HANDLE; SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "vkCreateInstance(): %s\n", + "vkCreateInstance(): %s", getVulkanResultString(result)); quit(2); } @@ -247,12 +247,12 @@ static void loadInstanceFunctions(void) { #define VULKAN_DEVICE_FUNCTION(name) #define VULKAN_GLOBAL_FUNCTION(name) -#define VULKAN_INSTANCE_FUNCTION(name) \ - name = (PFN_##name)vkGetInstanceProcAddr(vulkanContext->instance, #name); \ - if (!name) { \ - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, \ - "vkGetInstanceProcAddr(instance, \"" #name "\") failed\n"); \ - quit(2); \ +#define VULKAN_INSTANCE_FUNCTION(name) \ + name = (PFN_##name)vkGetInstanceProcAddr(vulkanContext->instance, #name); \ + if (!name) { \ + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, \ + "vkGetInstanceProcAddr(instance, \"" #name "\") failed"); \ + quit(2); \ } VULKAN_FUNCTIONS() #undef VULKAN_DEVICE_FUNCTION @@ -264,7 +264,7 @@ static void createSurface(void) { if (!SDL_Vulkan_CreateSurface(vulkanContext->window, vulkanContext->instance, NULL, &vulkanContext->surface)) { vulkanContext->surface = VK_NULL_HANDLE; - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_Vulkan_CreateSurface(): %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_Vulkan_CreateSurface(): %s", SDL_GetError()); quit(2); } } @@ -283,13 +283,13 @@ static void findPhysicalDevice(void) result = vkEnumeratePhysicalDevices(vulkanContext->instance, &physicalDeviceCount, NULL); if (result != VK_SUCCESS) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "vkEnumeratePhysicalDevices(): %s\n", + "vkEnumeratePhysicalDevices(): %s", getVulkanResultString(result)); quit(2); } if (physicalDeviceCount == 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "vkEnumeratePhysicalDevices(): no physical devices\n"); + "vkEnumeratePhysicalDevices(): no physical devices"); quit(2); } physicalDevices = (VkPhysicalDevice *)SDL_malloc(sizeof(VkPhysicalDevice) * physicalDeviceCount); @@ -300,7 +300,7 @@ static void findPhysicalDevice(void) if (result != VK_SUCCESS) { SDL_free(physicalDevices); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "vkEnumeratePhysicalDevices(): %s\n", + "vkEnumeratePhysicalDevices(): %s", getVulkanResultString(result)); quit(2); } @@ -353,7 +353,7 @@ static void findPhysicalDevice(void) SDL_free(queueFamiliesProperties); SDL_free(deviceExtensions); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "vkGetPhysicalDeviceSurfaceSupportKHR(): %s\n", + "vkGetPhysicalDeviceSurfaceSupportKHR(): %s", getVulkanResultString(result)); quit(2); } @@ -369,7 +369,7 @@ static void findPhysicalDevice(void) SDL_free(queueFamiliesProperties); SDL_free(deviceExtensions); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "SDL_Vulkan_GetPresentationSupport(): %s\n", + "SDL_Vulkan_GetPresentationSupport(): %s", SDL_GetError()); quit(2); } @@ -393,7 +393,7 @@ static void findPhysicalDevice(void) SDL_free(queueFamiliesProperties); SDL_free(deviceExtensions); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "vkEnumerateDeviceExtensionProperties(): %s\n", + "vkEnumerateDeviceExtensionProperties(): %s", getVulkanResultString(result)); quit(2); } @@ -416,7 +416,7 @@ static void findPhysicalDevice(void) SDL_free(queueFamiliesProperties); SDL_free(deviceExtensions); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "vkEnumerateDeviceExtensionProperties(): %s\n", + "vkEnumerateDeviceExtensionProperties(): %s", getVulkanResultString(result)); quit(2); } @@ -478,19 +478,19 @@ static void createDevice(void) result = vkCreateDevice(vulkanContext->physicalDevice, &deviceCreateInfo, NULL, &vulkanContext->device); if (result != VK_SUCCESS) { vulkanContext->device = VK_NULL_HANDLE; - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "vkCreateDevice(): %s\n", getVulkanResultString(result)); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "vkCreateDevice(): %s", getVulkanResultString(result)); quit(2); } } static void loadDeviceFunctions(void) { -#define VULKAN_DEVICE_FUNCTION(name) \ - name = (PFN_##name)vkGetDeviceProcAddr(vulkanContext->device, #name); \ - if (!name) { \ - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, \ - "vkGetDeviceProcAddr(device, \"" #name "\") failed\n"); \ - quit(2); \ +#define VULKAN_DEVICE_FUNCTION(name) \ + name = (PFN_##name)vkGetDeviceProcAddr(vulkanContext->device, #name); \ + if (!name) { \ + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, \ + "vkGetDeviceProcAddr(device, \"" #name "\") failed"); \ + quit(2); \ } #define VULKAN_GLOBAL_FUNCTION(name) #define VULKAN_INSTANCE_FUNCTION(name) @@ -528,7 +528,7 @@ static void createSemaphore(VkSemaphore *semaphore) if (result != VK_SUCCESS) { *semaphore = VK_NULL_HANDLE; SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "vkCreateSemaphore(): %s\n", + "vkCreateSemaphore(): %s", getVulkanResultString(result)); quit(2); } @@ -545,7 +545,7 @@ static void getSurfaceCaps(void) VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vulkanContext->physicalDevice, vulkanContext->surface, &vulkanContext->surfaceCapabilities); if (result != VK_SUCCESS) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "vkGetPhysicalDeviceSurfaceCapabilitiesKHR(): %s\n", + "vkGetPhysicalDeviceSurfaceCapabilitiesKHR(): %s", getVulkanResultString(result)); quit(2); } @@ -553,7 +553,7 @@ static void getSurfaceCaps(void) // check surface usage if (!(vulkanContext->surfaceCapabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "Vulkan surface doesn't support VK_IMAGE_USAGE_TRANSFER_DST_BIT\n"); + "Vulkan surface doesn't support VK_IMAGE_USAGE_TRANSFER_DST_BIT"); quit(2); } } @@ -567,7 +567,7 @@ static void getSurfaceFormats(void) if (result != VK_SUCCESS) { vulkanContext->surfaceFormatsCount = 0; SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "vkGetPhysicalDeviceSurfaceFormatsKHR(): %s\n", + "vkGetPhysicalDeviceSurfaceFormatsKHR(): %s", getVulkanResultString(result)); quit(2); } @@ -587,7 +587,7 @@ static void getSurfaceFormats(void) if (result != VK_SUCCESS) { vulkanContext->surfaceFormatsCount = 0; SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "vkGetPhysicalDeviceSurfaceFormatsKHR(): %s\n", + "vkGetPhysicalDeviceSurfaceFormatsKHR(): %s", getVulkanResultString(result)); quit(2); } @@ -603,7 +603,7 @@ static void getSwapchainImages(void) if (result != VK_SUCCESS) { vulkanContext->swapchainImageCount = 0; SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "vkGetSwapchainImagesKHR(): %s\n", + "vkGetSwapchainImagesKHR(): %s", getVulkanResultString(result)); quit(2); } @@ -620,7 +620,7 @@ static void getSwapchainImages(void) vulkanContext->swapchainImages = NULL; vulkanContext->swapchainImageCount = 0; SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "vkGetSwapchainImagesKHR(): %s\n", + "vkGetSwapchainImagesKHR(): %s", getVulkanResultString(result)); quit(2); } @@ -706,7 +706,7 @@ static bool createSwapchain(void) if (result != VK_SUCCESS) { vulkanContext->swapchain = VK_NULL_HANDLE; SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "vkCreateSwapchainKHR(): %s\n", + "vkCreateSwapchainKHR(): %s", getVulkanResultString(result)); quit(2); } @@ -756,7 +756,7 @@ static void createCommandPool(void) if (result != VK_SUCCESS) { vulkanContext->commandPool = VK_NULL_HANDLE; SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "vkCreateCommandPool(): %s\n", + "vkCreateCommandPool(): %s", getVulkanResultString(result)); quit(2); } @@ -776,7 +776,7 @@ static void createCommandBuffers(void) SDL_free(vulkanContext->commandBuffers); vulkanContext->commandBuffers = NULL; SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "vkAllocateCommandBuffers(): %s\n", + "vkAllocateCommandBuffers(): %s", getVulkanResultString(result)); quit(2); } @@ -803,7 +803,7 @@ static void createFences(void) SDL_free(vulkanContext->fences); vulkanContext->fences = NULL; SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "vkCreateFence(): %s\n", + "vkCreateFence(): %s", getVulkanResultString(result)); quit(2); } @@ -868,7 +868,7 @@ static void rerecordCommandBuffer(uint32_t frameIndex, const VkClearColorValue * VkResult result = vkResetCommandBuffer(commandBuffer, 0); if (result != VK_SUCCESS) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "vkResetCommandBuffer(): %s\n", + "vkResetCommandBuffer(): %s", getVulkanResultString(result)); quit(2); } @@ -877,7 +877,7 @@ static void rerecordCommandBuffer(uint32_t frameIndex, const VkClearColorValue * result = vkBeginCommandBuffer(commandBuffer, &beginInfo); if (result != VK_SUCCESS) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "vkBeginCommandBuffer(): %s\n", + "vkBeginCommandBuffer(): %s", getVulkanResultString(result)); quit(2); } @@ -902,7 +902,7 @@ static void rerecordCommandBuffer(uint32_t frameIndex, const VkClearColorValue * result = vkEndCommandBuffer(commandBuffer); if (result != VK_SUCCESS) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "vkEndCommandBuffer(): %s\n", + "vkEndCommandBuffer(): %s", getVulkanResultString(result)); quit(2); } @@ -1034,18 +1034,18 @@ static bool render(void) if ((rc != VK_SUBOPTIMAL_KHR) && (rc != VK_SUCCESS)) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "vkAcquireNextImageKHR(): %s\n", + "vkAcquireNextImageKHR(): %s", getVulkanResultString(rc)); quit(2); } rc = vkWaitForFences(vulkanContext->device, 1, &vulkanContext->fences[frameIndex], VK_FALSE, UINT64_MAX); if (rc != VK_SUCCESS) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "vkWaitForFences(): %s\n", getVulkanResultString(rc)); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "vkWaitForFences(): %s", getVulkanResultString(rc)); quit(2); } rc = vkResetFences(vulkanContext->device, 1, &vulkanContext->fences[frameIndex]); if (rc != VK_SUCCESS) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "vkResetFences(): %s\n", getVulkanResultString(rc)); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "vkResetFences(): %s", getVulkanResultString(rc)); quit(2); } currentTime = (double)SDL_GetPerformanceCounter() / SDL_GetPerformanceFrequency(); @@ -1065,7 +1065,7 @@ static bool render(void) rc = vkQueueSubmit(vulkanContext->graphicsQueue, 1, &submitInfo, vulkanContext->fences[frameIndex]); if (rc != VK_SUCCESS) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "vkQueueSubmit(): %s\n", getVulkanResultString(rc)); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "vkQueueSubmit(): %s", getVulkanResultString(rc)); quit(2); } presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; @@ -1081,7 +1081,7 @@ static bool render(void) if (rc != VK_SUCCESS) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "vkQueuePresentKHR(): %s\n", + "vkQueuePresentKHR(): %s", getVulkanResultString(rc)); quit(2); } @@ -1118,13 +1118,13 @@ int main(int argc, char **argv) mode = SDL_GetCurrentDisplayMode(SDL_GetPrimaryDisplay()); if (mode) { - SDL_Log("Screen BPP : %d\n", SDL_BITSPERPIXEL(mode->format)); + SDL_Log("Screen BPP : %d", SDL_BITSPERPIXEL(mode->format)); } SDL_GetWindowSize(state->windows[0], &dw, &dh); - SDL_Log("Window Size : %d,%d\n", dw, dh); + SDL_Log("Window Size : %d,%d", dw, dh); SDL_GetWindowSizeInPixels(state->windows[0], &dw, &dh); - SDL_Log("Draw Size : %d,%d\n", dw, dh); - SDL_Log("\n"); + SDL_Log("Draw Size : %d,%d", dw, dh); + SDL_Log("%s", ""); initVulkan(); @@ -1159,7 +1159,7 @@ int main(int argc, char **argv) /* Print out some timing information */ now = SDL_GetTicks(); if (now > then) { - SDL_Log("%2.2f frames per second\n", ((double)frames * 1000) / (now - then)); + SDL_Log("%2.2f frames per second", ((double)frames * 1000) / (now - then)); } shutdownVulkan(true); diff --git a/libs/SDL3/test/testwm.c b/libs/SDL3/test/testwm.c index 0d25c0fd..b46ee435 100644 --- a/libs/SDL3/test/testwm.c +++ b/libs/SDL3/test/testwm.c @@ -157,10 +157,10 @@ static void loop(void) /* Wait up to 20 ms for input, as a test */ Uint64 then = SDL_GetTicks(); if (SDL_WaitEventTimeout(NULL, 20)) { - SDL_Log("Got an event!\n"); + SDL_Log("Got an event!"); } Uint64 now = SDL_GetTicks(); - SDL_Log("Waited %d ms for events\n", (int)(now - then)); + SDL_Log("Waited %d ms for events", (int)(now - then)); #endif while (SDL_PollEvent(&event)) { @@ -170,7 +170,7 @@ static void loop(void) if (event.type == SDL_EVENT_WINDOW_RESIZED) { SDL_Window *window = SDL_GetWindowFromEvent(&event); if (window) { - SDL_Log("Window %" SDL_PRIu32 " resized to %" SDL_PRIs32 "x%" SDL_PRIs32 "\n", + SDL_Log("Window %" SDL_PRIu32 " resized to %" SDL_PRIs32 "x%" SDL_PRIs32, event.window.windowID, event.window.data1, event.window.data2); @@ -179,7 +179,7 @@ static void loop(void) if (event.type == SDL_EVENT_WINDOW_MOVED) { SDL_Window *window = SDL_GetWindowFromEvent(&event); if (window) { - SDL_Log("Window %" SDL_PRIu32 " moved to %" SDL_PRIs32 ",%" SDL_PRIs32 " (display %s)\n", + SDL_Log("Window %" SDL_PRIu32 " moved to %" SDL_PRIs32 ",%" SDL_PRIs32 " (display %s)", event.window.windowID, event.window.data1, event.window.data2, diff --git a/libs/SDL3/test/testyuv.c b/libs/SDL3/test/testyuv.c index 0cd28238..8dda4c5e 100644 --- a/libs/SDL3/test/testyuv.c +++ b/libs/SDL3/test/testyuv.c @@ -89,7 +89,7 @@ static bool verify_yuv_data(Uint32 format, SDL_Colorspace colorspace, const Uint int deltaB = (int)actual[2] - expected[2]; int distance = (deltaR * deltaR + deltaG * deltaG + deltaB * deltaB); if (distance > tolerance) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Pixel at %d,%d was 0x%.2x,0x%.2x,0x%.2x, expected 0x%.2x,0x%.2x,0x%.2x, distance = %d\n", x, y, actual[0], actual[1], actual[2], expected[0], expected[1], expected[2], distance); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Pixel at %d,%d was 0x%.2x,0x%.2x,0x%.2x, expected 0x%.2x,0x%.2x,0x%.2x, distance = %d", x, y, actual[0], actual[1], actual[2], expected[0], expected[1], expected[2], distance); result = false; } actual += 3; @@ -97,7 +97,7 @@ static bool verify_yuv_data(Uint32 format, SDL_Colorspace colorspace, const Uint } } } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s\n", SDL_GetPixelFormatName(format), SDL_GetPixelFormatName(surface->format), SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s", SDL_GetPixelFormatName(format), SDL_GetPixelFormatName(surface->format), SDL_GetError()); } SDL_free(rgb); @@ -138,12 +138,12 @@ static bool run_automated_tests(int pattern_size, int extra_pitch) /* Verify conversion from YUV formats */ for (i = 0; i < SDL_arraysize(formats); ++i) { if (!ConvertRGBtoYUV(formats[i], pattern->pixels, pattern->pitch, yuv1, pattern->w, pattern->h, mode, 0, 100)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ConvertRGBtoYUV() doesn't support converting to %s\n", SDL_GetPixelFormatName(formats[i])); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ConvertRGBtoYUV() doesn't support converting to %s", SDL_GetPixelFormatName(formats[i])); goto done; } yuv1_pitch = CalculateYUVPitch(formats[i], pattern->w); if (!verify_yuv_data(formats[i], colorspace, yuv1, yuv1_pitch, pattern, tight_tolerance)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed conversion from %s to RGB\n", SDL_GetPixelFormatName(formats[i])); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed conversion from %s to RGB", SDL_GetPixelFormatName(formats[i])); goto done; } } @@ -152,11 +152,11 @@ static bool run_automated_tests(int pattern_size, int extra_pitch) for (i = 0; i < SDL_arraysize(formats); ++i) { yuv1_pitch = CalculateYUVPitch(formats[i], pattern->w) + extra_pitch; if (!SDL_ConvertPixelsAndColorspace(pattern->w, pattern->h, pattern->format, SDL_COLORSPACE_SRGB, 0, pattern->pixels, pattern->pitch, formats[i], colorspace, 0, yuv1, yuv1_pitch)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s\n", SDL_GetPixelFormatName(pattern->format), SDL_GetPixelFormatName(formats[i]), SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s", SDL_GetPixelFormatName(pattern->format), SDL_GetPixelFormatName(formats[i]), SDL_GetError()); goto done; } if (!verify_yuv_data(formats[i], colorspace, yuv1, yuv1_pitch, pattern, tight_tolerance)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed conversion from RGB to %s\n", SDL_GetPixelFormatName(formats[i])); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed conversion from RGB to %s", SDL_GetPixelFormatName(formats[i])); goto done; } } @@ -167,15 +167,15 @@ static bool run_automated_tests(int pattern_size, int extra_pitch) yuv1_pitch = CalculateYUVPitch(formats[i], pattern->w) + extra_pitch; yuv2_pitch = CalculateYUVPitch(formats[j], pattern->w) + extra_pitch; if (!SDL_ConvertPixelsAndColorspace(pattern->w, pattern->h, pattern->format, SDL_COLORSPACE_SRGB, 0, pattern->pixels, pattern->pitch, formats[i], colorspace, 0, yuv1, yuv1_pitch)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s\n", SDL_GetPixelFormatName(pattern->format), SDL_GetPixelFormatName(formats[i]), SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s", SDL_GetPixelFormatName(pattern->format), SDL_GetPixelFormatName(formats[i]), SDL_GetError()); goto done; } if (!SDL_ConvertPixelsAndColorspace(pattern->w, pattern->h, formats[i], colorspace, 0, yuv1, yuv1_pitch, formats[j], colorspace, 0, yuv2, yuv2_pitch)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s\n", SDL_GetPixelFormatName(formats[i]), SDL_GetPixelFormatName(formats[j]), SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s", SDL_GetPixelFormatName(formats[i]), SDL_GetPixelFormatName(formats[j]), SDL_GetError()); goto done; } if (!verify_yuv_data(formats[j], colorspace, yuv2, yuv2_pitch, pattern, tight_tolerance)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed conversion from %s to %s\n", SDL_GetPixelFormatName(formats[i]), SDL_GetPixelFormatName(formats[j])); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed conversion from %s to %s", SDL_GetPixelFormatName(formats[i]), SDL_GetPixelFormatName(formats[j])); goto done; } } @@ -192,15 +192,15 @@ static bool run_automated_tests(int pattern_size, int extra_pitch) yuv1_pitch = CalculateYUVPitch(formats[i], pattern->w) + extra_pitch; yuv2_pitch = CalculateYUVPitch(formats[j], pattern->w) + extra_pitch; if (!SDL_ConvertPixelsAndColorspace(pattern->w, pattern->h, pattern->format, SDL_COLORSPACE_SRGB, 0, pattern->pixels, pattern->pitch, formats[i], colorspace, 0, yuv1, yuv1_pitch)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s\n", SDL_GetPixelFormatName(pattern->format), SDL_GetPixelFormatName(formats[i]), SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s", SDL_GetPixelFormatName(pattern->format), SDL_GetPixelFormatName(formats[i]), SDL_GetError()); goto done; } if (!SDL_ConvertPixelsAndColorspace(pattern->w, pattern->h, formats[i], colorspace, 0, yuv1, yuv1_pitch, formats[j], colorspace, 0, yuv1, yuv2_pitch)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s\n", SDL_GetPixelFormatName(formats[i]), SDL_GetPixelFormatName(formats[j]), SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s", SDL_GetPixelFormatName(formats[i]), SDL_GetPixelFormatName(formats[j]), SDL_GetError()); goto done; } if (!verify_yuv_data(formats[j], colorspace, yuv1, yuv2_pitch, pattern, tight_tolerance)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed conversion from %s to %s\n", SDL_GetPixelFormatName(formats[i]), SDL_GetPixelFormatName(formats[j])); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed conversion from %s to %s", SDL_GetPixelFormatName(formats[i]), SDL_GetPixelFormatName(formats[j])); goto done; } } @@ -209,24 +209,24 @@ static bool run_automated_tests(int pattern_size, int extra_pitch) /* Verify round trip through BT.2020 */ colorspace = SDL_COLORSPACE_BT2020_FULL; if (!ConvertRGBtoYUV(SDL_PIXELFORMAT_P010, pattern->pixels, pattern->pitch, yuv1, pattern->w, pattern->h, YUV_CONVERSION_BT2020, 0, 100)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ConvertRGBtoYUV() doesn't support converting to %s\n", SDL_GetPixelFormatName(SDL_PIXELFORMAT_P010)); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ConvertRGBtoYUV() doesn't support converting to %s", SDL_GetPixelFormatName(SDL_PIXELFORMAT_P010)); goto done; } yuv1_pitch = CalculateYUVPitch(SDL_PIXELFORMAT_P010, pattern->w); if (!verify_yuv_data(SDL_PIXELFORMAT_P010, colorspace, yuv1, yuv1_pitch, pattern, tight_tolerance)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed conversion from %s to RGB\n", SDL_GetPixelFormatName(SDL_PIXELFORMAT_P010)); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed conversion from %s to RGB", SDL_GetPixelFormatName(SDL_PIXELFORMAT_P010)); goto done; } /* The pitch needs to be Uint16 aligned for P010 pixels */ yuv1_pitch = CalculateYUVPitch(SDL_PIXELFORMAT_P010, pattern->w) + ((extra_pitch + 1) & ~1); if (!SDL_ConvertPixelsAndColorspace(pattern->w, pattern->h, pattern->format, SDL_COLORSPACE_SRGB, 0, pattern->pixels, pattern->pitch, SDL_PIXELFORMAT_P010, colorspace, 0, yuv1, yuv1_pitch)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s\n", SDL_GetPixelFormatName(pattern->format), SDL_GetPixelFormatName(SDL_PIXELFORMAT_P010), SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s", SDL_GetPixelFormatName(pattern->format), SDL_GetPixelFormatName(SDL_PIXELFORMAT_P010), SDL_GetError()); goto done; } /* Going through XRGB2101010 format during P010 conversion is slightly lossy, so use looser tolerance here */ if (!verify_yuv_data(SDL_PIXELFORMAT_P010, colorspace, yuv1, yuv1_pitch, pattern, loose_tolerance)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed conversion from RGB to %s\n", SDL_GetPixelFormatName(SDL_PIXELFORMAT_P010)); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed conversion from RGB to %s", SDL_GetPixelFormatName(SDL_PIXELFORMAT_P010)); goto done; } @@ -265,13 +265,13 @@ static bool run_colorspace_test(void) int i; if (!SDL_CreateWindowAndRenderer("testyuv", 320, 240, 0, &window, &renderer)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window and renderer: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window and renderer: %s", SDL_GetError()); goto done; } rgb = SDL_CreateSurface(32, 32, SDL_PIXELFORMAT_XRGB8888); if (!rgb) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create RGB surface: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create RGB surface: %s", SDL_GetError()); goto done; } SDL_FillSurfaceRect(rgb, NULL, SDL_MapSurfaceRGB(rgb, 255, 0, 0)); @@ -280,28 +280,28 @@ static bool run_colorspace_test(void) bool next = false; Uint8 r, g, b, a; - SDL_Log("Checking colorspace %s\n", colorspaces[i].name); + SDL_Log("Checking colorspace %s", colorspaces[i].name); yuv = SDL_ConvertSurfaceAndColorspace(rgb, SDL_PIXELFORMAT_NV12, NULL, colorspaces[i].colorspace, 0); if (!yuv) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create YUV surface: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create YUV surface: %s", SDL_GetError()); goto done; } if (!SDL_ReadSurfacePixel(yuv, 0, 0, &r, &g, &b, &a)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't read YUV surface: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't read YUV surface: %s", SDL_GetError()); goto done; } if (SDL_abs((int)r - 255) > allowed_error || SDL_abs((int)g - 0) > allowed_error || SDL_abs((int)b - 0) > allowed_error) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed color conversion, expected 255,0,0, got %d,%d,%d\n", r, g, b); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed color conversion, expected 255,0,0, got %d,%d,%d", r, g, b); } texture = SDL_CreateTextureFromSurface(renderer, yuv); if (!texture) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create YUV texture: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create YUV texture: %s", SDL_GetError()); goto done; } @@ -312,14 +312,14 @@ static bool run_colorspace_test(void) yuv = SDL_RenderReadPixels(renderer, NULL); if (!SDL_ReadSurfacePixel(yuv, 0, 0, &r, &g, &b, &a)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't read YUV surface: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't read YUV surface: %s", SDL_GetError()); goto done; } if (SDL_abs((int)r - 255) > allowed_error || SDL_abs((int)g - 0) > allowed_error || SDL_abs((int)b - 0) > allowed_error) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed renderer color conversion, expected 255,0,0, got %d,%d,%d\n", r, g, b); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed renderer color conversion, expected 255,0,0, got %d,%d,%d", r, g, b); } while (!next) { @@ -530,7 +530,7 @@ int main(int argc, char **argv) /* Run automated tests */ if (should_run_automated_tests) { for (i = 0; i < (int)SDL_arraysize(automated_test_params); ++i) { - SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Running automated test, pattern size %d, extra pitch %d, intrinsics %s\n", + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Running automated test, pattern size %d, extra pitch %d, intrinsics %s", automated_test_params[i].pattern_size, automated_test_params[i].extra_pitch, automated_test_params[i].enable_intrinsics ? "enabled" : "disabled"); @@ -553,7 +553,7 @@ int main(int argc, char **argv) original = SDL_ConvertSurface(bmp, SDL_PIXELFORMAT_RGB24); SDL_DestroySurface(bmp); if (!original) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s\n", filename, SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s", filename, SDL_GetError()); return 3; } @@ -586,7 +586,7 @@ int main(int argc, char **argv) converted = SDL_CreateSurface(original->w, original->h, rgb_format); if (!converted) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create converted surface: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create converted surface: %s", SDL_GetError()); return 3; } @@ -595,17 +595,17 @@ int main(int argc, char **argv) SDL_ConvertPixelsAndColorspace(original->w, original->h, yuv_format, yuv_colorspace, 0, raw_yuv, pitch, rgb_format, rgb_colorspace, 0, converted->pixels, converted->pitch); } now = SDL_GetTicks(); - SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "%d iterations in %" SDL_PRIu64 " ms, %.2fms each\n", iterations, (now - then), (float)(now - then) / iterations); + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "%d iterations in %" SDL_PRIu64 " ms, %.2fms each", iterations, (now - then), (float)(now - then) / iterations); window = SDL_CreateWindow("YUV test", original->w, original->h, 0); if (!window) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window: %s", SDL_GetError()); return 4; } renderer = SDL_CreateRenderer(window, NULL); if (!renderer) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s", SDL_GetError()); return 4; } @@ -620,7 +620,7 @@ int main(int argc, char **argv) output[2] = SDL_CreateTextureWithProperties(renderer, props); SDL_DestroyProperties(props); if (!output[0] || !output[1] || !output[2]) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set create texture: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set create texture: %s", SDL_GetError()); return 5; } SDL_UpdateTexture(output[2], NULL, raw_yuv, pitch); diff --git a/libs/SDL3/test/torturethread.c b/libs/SDL3/test/torturethread.c index cbc254dc..a572fe9f 100644 --- a/libs/SDL3/test/torturethread.c +++ b/libs/SDL3/test/torturethread.c @@ -52,7 +52,7 @@ ThreadFunc(void *data) int i; int tid = (int)(uintptr_t)data; - SDL_Log("Creating Thread %d\n", tid); + SDL_Log("Creating Thread %d", tid); for (i = 0; i < NUMTHREADS; i++) { char name[64]; @@ -61,18 +61,18 @@ ThreadFunc(void *data) sub_threads[i] = SDL_CreateThread(SubThreadFunc, name, &flags[i]); } - SDL_Log("Thread '%d' waiting for signal\n", tid); + SDL_Log("Thread '%d' waiting for signal", tid); while (SDL_GetAtomicInt(&time_for_threads_to_die[tid]) != 1) { ; /* do nothing */ } - SDL_Log("Thread '%d' sending signals to subthreads\n", tid); + SDL_Log("Thread '%d' sending signals to subthreads", tid); for (i = 0; i < NUMTHREADS; i++) { SDL_SetAtomicInt(&flags[i], 1); SDL_WaitThread(sub_threads[i], NULL); } - SDL_Log("Thread '%d' exiting!\n", tid); + SDL_Log("Thread '%d' exiting!", tid); return 0; } @@ -103,7 +103,7 @@ int main(int argc, char *argv[]) threads[i] = SDL_CreateThread(ThreadFunc, name, (void *)(uintptr_t)i); if (threads[i] == NULL) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create thread: %s\n", SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create thread: %s", SDL_GetError()); quit(1); } } diff --git a/libs/SDL3/wayland-protocols/color-management-v1.xml b/libs/SDL3/wayland-protocols/color-management-v1.xml new file mode 100644 index 00000000..7f8da78f --- /dev/null +++ b/libs/SDL3/wayland-protocols/color-management-v1.xml @@ -0,0 +1,1631 @@ + + + + Copyright 2019 Sebastian Wick + Copyright 2019 Erwin Burema + Copyright 2020 AMD + Copyright 2020-2024 Collabora, Ltd. + Copyright 2024 Xaver Hugl + Copyright 2022-2025 Red Hat, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + The aim of the color management extension is to allow clients to know + the color properties of outputs, and to tell the compositor about the color + properties of their content on surfaces. Doing this enables a compositor + to perform automatic color management of content for different outputs + according to how content is intended to look like. + + The color properties are represented as an image description object which + is immutable after it has been created. A wl_output always has an + associated image description that clients can observe. A wl_surface + always has an associated preferred image description as a hint chosen by + the compositor that clients can also observe. Clients can set an image + description on a wl_surface to denote the color characteristics of the + surface contents. + + An image description includes SDR and HDR colorimetry and encoding, HDR + metadata, and viewing environment parameters. An image description does + not include the properties set through color-representation extension. + It is expected that the color-representation extension is used in + conjunction with the color management extension when necessary, + particularly with the YUV family of pixel formats. + + Recommendation ITU-T H.273 + "Coding-independent code points for video signal type identification" + shall be referred to as simply H.273 here. + + The color-and-hdr repository + (https://gitlab.freedesktop.org/pq/color-and-hdr) contains + background information on the protocol design and legacy color management. + It also contains a glossary, learning resources for digital color, tools, + samples and more. + + The terminology used in this protocol is based on common color science and + color encoding terminology where possible. The glossary in the color-and-hdr + repository shall be the authority on the definition of terms in this + protocol. + + Warning! The protocol described in this file is currently in the testing + phase. Backward compatible changes may be added together with the + corresponding interface version bump. Backward incompatible changes can + only be done by creating a new major version of the extension. + + + + + A singleton global interface used for getting color management extensions + for wl_surface and wl_output objects, and for creating client defined + image description objects. The extension interfaces allow + getting the image description of outputs and setting the image + description of surfaces. + + Compositors should never remove this global. + + + + + Destroy the wp_color_manager_v1 object. This does not affect any other + objects in any way. + + + + + + + + + + + See the ICC.1:2022 specification from the International Color Consortium + for more details about rendering intents. + + The principles of ICC defined rendering intents apply with all types of + image descriptions, not only those with ICC file profiles. + + Compositors must support the perceptual rendering intent. Other + rendering intents are optional. + + + + + + + + + + + + + + + + + + + + The compositor supports set_mastering_display_primaries request with a + target color volume fully contained inside the primary color volume. + + + + + The compositor additionally supports target color volumes that + extend outside of the primary color volume. + + This can only be advertised if feature set_mastering_display_primaries + is supported as well. + + + + + + + + Named color primaries used to encode well-known sets of primaries. H.273 + is the authority, when it comes to the exact values of primaries and + authoritative specifications, where an equivalent code point exists. + + A value of 0 is invalid and will never be present in the list of enums. + + Descriptions do list the specifications for convenience. + + + + + Color primaries as defined by + - Rec. ITU-R BT.709-6 + - Rec. ITU-R BT.1361-0 conventional colour gamut system and extended + colour gamut system (historical) + - IEC 61966-2-1 sRGB or sYCC + - IEC 61966-2-4 + - Society of Motion Picture and Television Engineers (SMPTE) RP 177 + (1993) Annex B + Equivalent to H.273 ColourPrimaries code point 1. + + + + + Color primaries as defined by + - Rec. ITU-R BT.470-6 System M (historical) + - United States National Television System Committee 1953 + Recommendation for transmission standards for color television + - United States Federal Communications Commission (2003) Title 47 Code + of Federal Regulations 73.682 (a)(20) + Equivalent to H.273 ColourPrimaries code point 4. + + + + + Color primaries as defined by + - Rec. ITU-R BT.470-6 System B, G (historical) + - Rec. ITU-R BT.601-7 625 + - Rec. ITU-R BT.1358-0 625 (historical) + - Rec. ITU-R BT.1700-0 625 PAL and 625 SECAM + Equivalent to H.273 ColourPrimaries code point 5. + + + + + Color primaries as defined by + - Rec. ITU-R BT.601-7 525 + - Rec. ITU-R BT.1358-1 525 or 625 (historical) + - Rec. ITU-R BT.1700-0 NTSC + - SMPTE 170M (2004) + - SMPTE 240M (1999) (historical) + Equivalent to H.273 ColourPrimaries code point 6 and 7. + + + + + Color primaries as defined by H.273 for generic film. + Equivalent to H.273 ColourPrimaries code point 8. + + + + + Color primaries as defined by + - Rec. ITU-R BT.2020-2 + - Rec. ITU-R BT.2100-0 + Equivalent to H.273 ColourPrimaries code point 9. + + + + + Color primaries as defined as the maximum of the CIE 1931 XYZ color + space by + - SMPTE ST 428-1 + - (CIE 1931 XYZ as in ISO 11664-1) + Equivalent to H.273 ColourPrimaries code point 10. + + + + + Color primaries as defined by Digital Cinema System and published in + SMPTE RP 431-2 (2011). Equivalent to H.273 ColourPrimaries code point + 11. + + + + + Color primaries as defined by Digital Cinema System and published in + SMPTE EG 432-1 (2010). + Equivalent to H.273 ColourPrimaries code point 12. + + + + + Color primaries as defined by Adobe as "Adobe RGB" and later published + by ISO 12640-4 (2011). + + + + + + + Named transfer functions used to represent well-known transfer + characteristics. H.273 is the authority, when it comes to the exact + formulas and authoritative specifications, where an equivalent code + point exists. + + A value of 0 is invalid and will never be present in the list of enums. + + Descriptions do list the specifications for convenience. + + + + + Rec. ITU-R BT.1886 is the display transfer characteristic assumed by + - Rec. ITU-R BT.601-7 525 and 625 + - Rec. ITU-R BT.709-6 + - Rec. ITU-R BT.2020-2 + These recommendations are referred to by H.273 TransferCharacteristics + code points 1, 6, 14, and 15, which are all equivalent. + + This TF implies these default luminances from Rec. ITU-R BT.2035: + - primary color volume minimum: 0.01 cd/m² + - primary color volume maximum: 100 cd/m² + - reference white: 100 cd/m² + + + + + Transfer characteristics as defined by + - Rec. ITU-R BT.470-6 System M (historical) + - United States National Television System Committee 1953 + Recommendation for transmission standards for color television + - United States Federal Communications Commission (2003) Title 47 Code + of Federal Regulations 73.682 (a) (20) + - Rec. ITU-R BT.1700-0 625 PAL and 625 SECAM + Equivalent to H.273 TransferCharacteristics code point 4. + + + + + Transfer characteristics as defined by + - Rec. ITU-R BT.470-6 System B, G (historical) + Equivalent to H.273 TransferCharacteristics code point 5. + + + + + Transfer characteristics as defined by + - SMPTE ST 240 (1999) + Equivalent to H.273 TransferCharacteristics code point 7. + + + + + Linear transfer function defined over all real numbers. + Normalised electrical values are equal the normalised optical values. + + The differences to H.273 TransferCharacteristics code point 8 are + the definition over all real numbers. + + + + + Logarithmic transfer characteristic (100:1 range). + Equivalent to H.273 TransferCharacteristics code point 9. + + + + + Logarithmic transfer characteristic (100 * Sqrt(10) : 1 range). + Equivalent to H.273 TransferCharacteristics code point 10. + + + + + Transfer characteristics as defined by + - IEC 61966-2-4 + Equivalent to H.273 TransferCharacteristics code point 11. + + + + + Transfer characteristics as defined by + - IEC 61966-2-1 sRGB + Equivalent to H.273 TransferCharacteristics code point 13 with + MatrixCoefficients set to 0. + + + + + Transfer characteristics as defined by + - IEC 61966-2-1 sYCC + Equivalent to H.273 TransferCharacteristics code point 13 with + MatrixCoefficients set to anything but 0. + + + + + Transfer characteristics as defined by + - SMPTE ST 2084 (2014) for 10-, 12-, 14- and 16-bit systems + - Rec. ITU-R BT.2100-2 perceptual quantization (PQ) system + Equivalent to H.273 TransferCharacteristics code point 16. + + This TF implies these default luminances + - primary color volume minimum: 0.005 cd/m² + - primary color volume maximum: 10000 cd/m² + - reference white: 203 cd/m² + + The difference between the primary color volume minimum and maximum + must be approximately 10000 cd/m² as that is the swing of the EOTF + defined by ST 2084 and BT.2100. The default value for the + reference white is a protocol addition: it is suggested by + Report ITU-R BT.2408-7 and is not part of ST 2084 or BT.2100. + + + + + Transfer characteristics as defined by + - SMPTE ST 428-1 (2019) + Equivalent to H.273 TransferCharacteristics code point 17. + + + + + Transfer characteristics as defined by + - ARIB STD-B67 (2015) + - Rec. ITU-R BT.2100-2 hybrid log-gamma (HLG) system + Equivalent to H.273 TransferCharacteristics code point 18. + + This TF implies these default luminances + - primary color volume minimum: 0.005 cd/m² + - primary color volume maximum: 1000 cd/m² + - reference white: 203 cd/m² + + HLG is a relative display-referred signal with a specified + non-linear mapping to the display peak luminance (the HLG OOTF). + All absolute luminance values used here for HLG assume a 1000 cd/m² + peak display. + + The default value for the reference white is a protocol addition: + it is suggested by Report ITU-R BT.2408-7 and is not part of + ARIB STD-B67 or BT.2100. + + + + + + + This creates a new wp_color_management_output_v1 object for the + given wl_output. + + See the wp_color_management_output_v1 interface for more details. + + + + + + + + + If a wp_color_management_surface_v1 object already exists for the given + wl_surface, the protocol error surface_exists is raised. + + This creates a new color wp_color_management_surface_v1 object for the + given wl_surface. + + See the wp_color_management_surface_v1 interface for more details. + + + + + + + + + This creates a new color wp_color_management_surface_feedback_v1 object + for the given wl_surface. + + See the wp_color_management_surface_feedback_v1 interface for more + details. + + + + + + + + + Makes a new ICC-based image description creator object with all + properties initially unset. The client can then use the object's + interface to define all the required properties for an image description + and finally create a wp_image_description_v1 object. + + This request can be used when the compositor advertises + wp_color_manager_v1.feature.icc_v2_v4. + Otherwise this request raises the protocol error unsupported_feature. + + + + + + + + Makes a new parametric image description creator object with all + properties initially unset. The client can then use the object's + interface to define all the required properties for an image description + and finally create a wp_image_description_v1 object. + + This request can be used when the compositor advertises + wp_color_manager_v1.feature.parametric. + Otherwise this request raises the protocol error unsupported_feature. + + + + + + + + This creates a pre-defined image description for the so-called + Windows-scRGB stimulus encoding. This comes from the Windows 10 handling + of its own definition of an scRGB color space for an HDR screen + driven in BT.2100/PQ signalling mode. + + Windows-scRGB uses sRGB (BT.709) color primaries and white point. + The transfer characteristic is extended linear. + + The nominal color channel value range is extended, meaning it includes + negative and greater than 1.0 values. Negative values are used to + escape the sRGB color gamut boundaries. To make use of the extended + range, the client needs to use a pixel format that can represent those + values, e.g. floating-point 16 bits per channel. + + Nominal color value R=G=B=0.0 corresponds to BT.2100/PQ system + 0 cd/m², and R=G=B=1.0 corresponds to BT.2100/PQ system 80 cd/m². + The maximum is R=G=B=125.0 corresponding to 10k cd/m². + + Windows-scRGB is displayed by Windows 10 by converting it to + BT.2100/PQ, maintaining the CIE 1931 chromaticity and mapping the + luminance as above. No adjustment is made to the signal to account + for the viewing conditions. + + The reference white level of Windows-scRGB is unknown. If a + reference white level must be assumed for compositor processing, it + should be R=G=B=2.5375 corresponding to 203 cd/m² of Report ITU-R + BT.2408-7. + + The target color volume of Windows-scRGB is unknown. The color gamut + may be anything between sRGB and BT.2100. + + Note: EGL_EXT_gl_colorspace_scrgb_linear definition differs from + Windows-scRGB by using R=G=B=1.0 as the reference white level, while + Windows-scRGB reference white level is unknown or varies. However, + it seems probable that Windows implements both + EGL_EXT_gl_colorspace_scrgb_linear and Vulkan + VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT as Windows-scRGB. + + This request can be used when the compositor advertises + wp_color_manager_v1.feature.windows_scrgb. + Otherwise this request raises the protocol error unsupported_feature. + + The resulting image description object does not allow get_information + request. The wp_image_description_v1.ready event shall be sent. + + + + + + + + When this object is created, it shall immediately send this event once + for each rendering intent the compositor supports. + + + + + + + + When this object is created, it shall immediately send this event once + for each compositor supported feature listed in the enumeration. + + + + + + + + When this object is created, it shall immediately send this event once + for each named transfer function the compositor supports with the + parametric image description creator. + + + + + + + + When this object is created, it shall immediately send this event once + for each named set of primaries the compositor supports with the + parametric image description creator. + + + + + + + + This event is sent when all supported rendering intents, features, + transfer functions and named primaries have been sent. + + + + + + + A wp_color_management_output_v1 describes the color properties of an + output. + + The wp_color_management_output_v1 is associated with the wl_output global + underlying the wl_output object. Therefore the client destroying the + wl_output object has no impact, but the compositor removing the output + global makes the wp_color_management_output_v1 object inert. + + + + + Destroy the color wp_color_management_output_v1 object. This does not + affect any remaining protocol objects. + + + + + + This event is sent whenever the image description of the output changed, + followed by one wl_output.done event common to output events across all + extensions. + + If the client wants to use the updated image description, it needs to do + get_image_description again, because image description objects are + immutable. + + + + + + This creates a new wp_image_description_v1 object for the current image + description of the output. There always is exactly one image description + active for an output so the client should destroy the image description + created by earlier invocations of this request. This request is usually + sent as a reaction to the image_description_changed event or when + creating a wp_color_management_output_v1 object. + + The image description of an output represents the color encoding the + output expects. There might be performance and power advantages, as well + as improved color reproduction, if a content update matches the image + description of the output it is being shown on. If a content update is + shown on any other output than the one it matches the image description + of, then the color reproduction on those outputs might be considerably + worse. + + The created wp_image_description_v1 object preserves the image + description of the output from the time the object was created. + + The resulting image description object allows get_information request. + + If this protocol object is inert, the resulting image description object + shall immediately deliver the wp_image_description_v1.failed event with + the no_output cause. + + If the interface version is inadequate for the output's image + description, meaning that the client does not support all the events + needed to deliver the crucial information, the resulting image + description object shall immediately deliver the + wp_image_description_v1.failed event with the low_version cause. + + Otherwise the object shall immediately deliver the ready event. + + + + + + + + + A wp_color_management_surface_v1 allows the client to set the color + space and HDR properties of a surface. + + If the wl_surface associated with the wp_color_management_surface_v1 is + destroyed, the wp_color_management_surface_v1 object becomes inert. + + + + + Destroy the wp_color_management_surface_v1 object and do the same as + unset_image_description. + + + + + + + + + + + + + If this protocol object is inert, the protocol error inert is raised. + + Set the image description of the underlying surface. The image + description and rendering intent are double-buffered state, see + wl_surface.commit. + + It is the client's responsibility to understand the image description + it sets on a surface, and to provide content that matches that image + description. Compositors might convert images to match their own or any + other image descriptions. + + Image descriptions which are not ready (see wp_image_description_v1) + are forbidden in this request, and in such case the protocol error + image_description is raised. + + All image descriptions which are ready (see wp_image_description_v1) + are allowed and must always be accepted by the compositor. + + A rendering intent provides the client's preference on how content + colors should be mapped to each output. The render_intent value must + be one advertised by the compositor with + wp_color_manager_v1.render_intent event, otherwise the protocol error + render_intent is raised. + + When an image description is set on a surface, the Transfer + Characteristics of the image description defines the valid range of + the nominal (real-valued) color channel values. The processing of + out-of-range color channel values is undefined, but compositors are + recommended to clamp the values to the valid range when possible. + + By default, a surface does not have an associated image description + nor a rendering intent. The handling of color on such surfaces is + compositor implementation defined. Compositors should handle such + surfaces as sRGB, but may handle them differently if they have specific + requirements. + + Setting the image description has copy semantics; after this request, + the image description can be immediately destroyed without affecting + the pending state of the surface. + + + + + + + + + If this protocol object is inert, the protocol error inert is raised. + + This request removes any image description from the surface. See + set_image_description for how a compositor handles a surface without + an image description. This is double-buffered state, see + wl_surface.commit. + + + + + + + A wp_color_management_surface_feedback_v1 allows the client to get the + preferred image description of a surface. + + If the wl_surface associated with this object is destroyed, the + wp_color_management_surface_feedback_v1 object becomes inert. + + + + + Destroy the wp_color_management_surface_feedback_v1 object. + + + + + + + + + + + + The preferred image description is the one which likely has the most + performance and/or quality benefits for the compositor if used by the + client for its wl_surface contents. This event is sent whenever the + compositor changes the wl_surface's preferred image description. + + This event sends the identity of the new preferred state as the argument, + so clients who are aware of the image description already can reuse it. + Otherwise, if the client client wants to know what the preferred image + description is, it shall use the get_preferred request. + + The preferred image description is not automatically used for anything. + It is only a hint, and clients may set any valid image description with + set_image_description, but there might be performance and color accuracy + improvements by providing the wl_surface contents in the preferred + image description. Therefore clients that can, should render according + to the preferred image description + + + + + + + + If this protocol object is inert, the protocol error inert is raised. + + The preferred image description represents the compositor's preferred + color encoding for this wl_surface at the current time. There might be + performance and power advantages, as well as improved color + reproduction, if the image description of a content update matches the + preferred image description. + + This creates a new wp_image_description_v1 object for the currently + preferred image description for the wl_surface. The client should + stop using and destroy the image descriptions created by earlier + invocations of this request for the associated wl_surface. + This request is usually sent as a reaction to the preferred_changed + event or when creating a wp_color_management_surface_feedback_v1 object + if the client is capable of adapting to image descriptions. + + The created wp_image_description_v1 object preserves the preferred image + description of the wl_surface from the time the object was created. + + The resulting image description object allows get_information request. + + If the image description is parametric, the client should set it on its + wl_surface only if the image description is an exact match with the + client content. Particularly if everything else matches, but the target + color volume is greater than what the client needs, the client should + create its own parameric image description with its exact parameters. + + If the interface version is inadequate for the preferred image + description, meaning that the client does not support all the + events needed to deliver the crucial information, the resulting image + description object shall immediately deliver the + wp_image_description_v1.failed event with the low_version cause, + otherwise the object shall immediately deliver the ready event. + + + + + + + + The same description as for get_preferred applies, except the returned + image description is guaranteed to be parametric. This is meant for + clients that can only deal with parametric image descriptions. + + If the compositor doesn't support parametric image descriptions, the + unsupported_feature error is emitted. + + + + + + + + + This type of object is used for collecting all the information required + to create a wp_image_description_v1 object from an ICC file. A complete + set of required parameters consists of these properties: + - ICC file + + Each required property must be set exactly once if the client is to create + an image description. The set requests verify that a property was not + already set. The create request verifies that all required properties are + set. There may be several alternative requests for setting each property, + and in that case the client must choose one of them. + + Once all properties have been set, the create request must be used to + create the image description object, destroying the creator in the + process. + + + + + + + + + + + + + + + Create an image description object based on the ICC information + previously set on this object. A compositor must parse the ICC data in + some undefined but finite amount of time. + + The completeness of the parameter set is verified. If the set is not + complete, the protocol error incomplete_set is raised. For the + definition of a complete set, see the description of this interface. + + If the particular combination of the information is not supported + by the compositor, the resulting image description object shall + immediately deliver the wp_image_description_v1.failed event with the + 'unsupported' cause. If a valid image description was created from the + information, the wp_image_description_v1.ready event will eventually + be sent instead. + + This request destroys the wp_image_description_creator_icc_v1 object. + + The resulting image description object does not allow get_information + request. + + + + + + + + Sets the ICC profile file to be used as the basis of the image + description. + + The data shall be found through the given fd at the given offset, having + the given length. The fd must be seekable and readable. Violating these + requirements raises the bad_fd protocol error. + + If reading the data fails due to an error independent of the client, the + compositor shall send the wp_image_description_v1.failed event on the + created wp_image_description_v1 with the 'operating_system' cause. + + The maximum size of the ICC profile is 32 MB. If length is greater than + that or zero, the protocol error bad_size is raised. If offset + length + exceeds the file size, the protocol error out_of_file is raised. + + A compositor may read the file at any time starting from this request + and only until whichever happens first: + - If create request was issued, the wp_image_description_v1 object + delivers either failed or ready event; or + - if create request was not issued, this + wp_image_description_creator_icc_v1 object is destroyed. + + A compositor shall not modify the contents of the file, and the fd may + be sealed for writes and size changes. The client must ensure to its + best ability that the data does not change while the compositor is + reading it. + + The data must represent a valid ICC profile. The ICC profile version + must be 2 or 4, it must be a 3 channel profile and the class must be + Display or ColorSpace. Violating these requirements will not result in a + protocol error, but will eventually send the + wp_image_description_v1.failed event on the created + wp_image_description_v1 with the 'unsupported' cause. + + See the International Color Consortium specification ICC.1:2022 for more + details about ICC profiles. + + If ICC file has already been set on this object, the protocol error + already_set is raised. + + + + + + + + + + + This type of object is used for collecting all the parameters required + to create a wp_image_description_v1 object. A complete set of required + parameters consists of these properties: + - transfer characteristic function (tf) + - chromaticities of primaries and white point (primary color volume) + + The following properties are optional and have a well-defined default + if not explicitly set: + - primary color volume luminance range + - reference white luminance level + - mastering display primaries and white point (target color volume) + - mastering luminance range + + The following properties are optional and will be ignored + if not explicitly set: + - maximum content light level + - maximum frame-average light level + + Each required property must be set exactly once if the client is to create + an image description. The set requests verify that a property was not + already set. The create request verifies that all required properties are + set. There may be several alternative requests for setting each property, + and in that case the client must choose one of them. + + Once all properties have been set, the create request must be used to + create the image description object, destroying the creator in the + process. + + + + + + + + + + + + + + + + Create an image description object based on the parameters previously + set on this object. + + The completeness of the parameter set is verified. If the set is not + complete, the protocol error incomplete_set is raised. For the + definition of a complete set, see the description of this interface. + + The protocol error invalid_luminance is raised if any of the following + requirements is not met: + - When max_cll is set, it must be greater than min L and less or equal + to max L of the mastering luminance range. + - When max_fall is set, it must be greater than min L and less or equal + to max L of the mastering luminance range. + - When both max_cll and max_fall are set, max_fall must be less or equal + to max_cll. + + If the particular combination of the parameter set is not supported + by the compositor, the resulting image description object shall + immediately deliver the wp_image_description_v1.failed event with the + 'unsupported' cause. If a valid image description was created from the + parameter set, the wp_image_description_v1.ready event will eventually + be sent instead. + + This request destroys the wp_image_description_creator_params_v1 + object. + + The resulting image description object does not allow get_information + request. + + + + + + + + Sets the transfer characteristic using explicitly enumerated named + functions. + + When the resulting image description is attached to an image, the + content should be encoded and decoded according to the industry standard + practices for the transfer characteristic. + + Only names advertised with wp_color_manager_v1 event supported_tf_named + are allowed. Other values shall raise the protocol error invalid_tf. + + If transfer characteristic has already been set on this object, the + protocol error already_set is raised. + + + + + + + + Sets the color component transfer characteristic to a power curve with + the given exponent. Negative values are handled by mirroring the + positive half of the curve through the origin. The valid domain and + range of the curve are all finite real numbers. This curve represents + the conversion from electrical to optical color channel values. + + When the resulting image description is attached to an image, the + content should be encoded with the inverse of the power curve. + + The curve exponent shall be multiplied by 10000 to get the argument eexp + value to carry the precision of 4 decimals. + + The curve exponent must be at least 1.0 and at most 10.0. Otherwise the + protocol error invalid_tf is raised. + + If transfer characteristic has already been set on this object, the + protocol error already_set is raised. + + This request can be used when the compositor advertises + wp_color_manager_v1.feature.set_tf_power. Otherwise this request raises + the protocol error unsupported_feature. + + + + + + + + Sets the color primaries and white point using explicitly named sets. + This describes the primary color volume which is the basis for color + value encoding. + + Only names advertised with wp_color_manager_v1 event + supported_primaries_named are allowed. Other values shall raise the + protocol error invalid_primaries_named. + + If primaries have already been set on this object, the protocol error + already_set is raised. + + + + + + + + Sets the color primaries and white point using CIE 1931 xy chromaticity + coordinates. This describes the primary color volume which is the basis + for color value encoding. + + Each coordinate value is multiplied by 1 million to get the argument + value to carry precision of 6 decimals. + + If primaries have already been set on this object, the protocol error + already_set is raised. + + This request can be used if the compositor advertises + wp_color_manager_v1.feature.set_primaries. Otherwise this request raises + the protocol error unsupported_feature. + + + + + + + + + + + + + + + Sets the primary color volume luminance range and the reference white + luminance level. These values include the minimum display emission + and ambient flare luminances, assumed to be optically additive and have + the chromaticity of the primary color volume white point. + + The default luminances from + https://www.color.org/chardata/rgb/srgb.xalter are + - primary color volume minimum: 0.2 cd/m² + - primary color volume maximum: 80 cd/m² + - reference white: 80 cd/m² + + Setting a named transfer characteristic can imply other default + luminances. + + The default luminances get overwritten when this request is used. + With transfer_function.st2084_pq the given 'max_lum' value is ignored, + and 'max_lum' is taken as 'min_lum' + 10000 cd/m². + + 'min_lum' and 'max_lum' specify the minimum and maximum luminances of + the primary color volume as reproduced by the targeted display. + + 'reference_lum' specifies the luminance of the reference white as + reproduced by the targeted display, and reflects the targeted viewing + environment. + + Compositors should make sure that all content is anchored, meaning that + an input signal level of 'reference_lum' on one image description and + another input signal level of 'reference_lum' on another image + description should produce the same output level, even though the + 'reference_lum' on both image representations can be different. + + 'reference_lum' may be higher than 'max_lum'. In that case reaching + the reference white output level in image content requires the + 'extended_target_volume' feature support. + + If 'max_lum' or 'reference_lum' are less than or equal to 'min_lum', + the protocol error invalid_luminance is raised. + + The minimum luminance is multiplied by 10000 to get the argument + 'min_lum' value and carries precision of 4 decimals. The maximum + luminance and reference white luminance values are unscaled. + + If the primary color volume luminance range and the reference white + luminance level have already been set on this object, the protocol error + already_set is raised. + + This request can be used if the compositor advertises + wp_color_manager_v1.feature.set_luminances. Otherwise this request + raises the protocol error unsupported_feature. + + + + + + + + + + Provides the color primaries and white point of the mastering display + using CIE 1931 xy chromaticity coordinates. This is compatible with the + SMPTE ST 2086 definition of HDR static metadata. + + The mastering display primaries and mastering display luminances define + the target color volume. + + If mastering display primaries are not explicitly set, the target color + volume is assumed to have the same primaries as the primary color volume. + + The target color volume is defined by all tristimulus values between 0.0 + and 1.0 (inclusive) of the color space defined by the given mastering + display primaries and white point. The colorimetry is identical between + the container color space and the mastering display color space, + including that no chromatic adaptation is applied even if the white + points differ. + + The target color volume can exceed the primary color volume to allow for + a greater color volume with an existing color space definition (for + example scRGB). It can be smaller than the primary color volume to + minimize gamut and tone mapping distances for big color spaces (HDR + metadata). + + To make use of the entire target color volume a suitable pixel format + has to be chosen (e.g. floating point to exceed the primary color + volume, or abusing limited quantization range as with xvYCC). + + Each coordinate value is multiplied by 1 million to get the argument + value to carry precision of 6 decimals. + + If mastering display primaries have already been set on this object, the + protocol error already_set is raised. + + This request can be used if the compositor advertises + wp_color_manager_v1.feature.set_mastering_display_primaries. Otherwise + this request raises the protocol error unsupported_feature. The + advertisement implies support only for target color volumes fully + contained within the primary color volume. + + If a compositor additionally supports target color volume exceeding the + primary color volume, it must advertise + wp_color_manager_v1.feature.extended_target_volume. If a client uses + target color volume exceeding the primary color volume and the + compositor does not support it, the result is implementation defined. + Compositors are recommended to detect this case and fail the image + description gracefully, but it may as well result in color artifacts. + + + + + + + + + + + + + + + Sets the luminance range that was used during the content mastering + process as the minimum and maximum absolute luminance L. These values + include the minimum display emission and ambient flare luminances, + assumed to be optically additive and have the chromaticity of the + primary color volume white point. This should be + compatible with the SMPTE ST 2086 definition of HDR static metadata. + + The mastering display primaries and mastering display luminances define + the target color volume. + + If mastering luminances are not explicitly set, the target color volume + is assumed to have the same min and max luminances as the primary color + volume. + + If max L is less than or equal to min L, the protocol error + invalid_luminance is raised. + + Min L value is multiplied by 10000 to get the argument min_lum value + and carry precision of 4 decimals. Max L value is unscaled for max_lum. + + This request can be used if the compositor advertises + wp_color_manager_v1.feature.set_mastering_display_primaries. Otherwise + this request raises the protocol error unsupported_feature. The + advertisement implies support only for target color volumes fully + contained within the primary color volume. + + If a compositor additionally supports target color volume exceeding the + primary color volume, it must advertise + wp_color_manager_v1.feature.extended_target_volume. If a client uses + target color volume exceeding the primary color volume and the + compositor does not support it, the result is implementation defined. + Compositors are recommended to detect this case and fail the image + description gracefully, but it may as well result in color artifacts. + + + + + + + + + Sets the maximum content light level (max_cll) as defined by CTA-861-H. + + max_cll is undefined by default. + + + + + + + + Sets the maximum frame-average light level (max_fall) as defined by + CTA-861-H. + + max_fall is undefined by default. + + + + + + + + + An image description carries information about the color encoding used on + a surface when attached to a wl_surface via + wp_color_management_surface_v1.set_image_description. A compositor can use + this information to decode pixel values into colorimetrically meaningful + quantities. + + Note, that the wp_image_description_v1 object is not ready to be used + immediately after creation. The object eventually delivers either the + 'ready' or the 'failed' event, specified in all requests creating it. The + object is deemed "ready" after receiving the 'ready' event. + + An object which is not ready is illegal to use, it can only be destroyed. + Any other request in this interface shall result in the 'not_ready' + protocol error. Attempts to use an object which is not ready through other + interfaces shall raise protocol errors defined there. + + Once created and regardless of how it was created, a + wp_image_description_v1 object always refers to one fixed image + description. It cannot change after creation. + + + + + Destroy this object. It is safe to destroy an object which is not ready. + + Destroying a wp_image_description_v1 object has no side-effects, not + even if a wp_color_management_surface_v1.set_image_description has not + yet been followed by a wl_surface.commit. + + + + + + + + + + + + + + + + + + + + + + If creating a wp_image_description_v1 object fails for a reason that is + not defined as a protocol error, this event is sent. + + The requests that create image description objects define whether and + when this can occur. Only such creation requests can trigger this event. + This event cannot be triggered after the image description was + successfully formed. + + Once this event has been sent, the wp_image_description_v1 object will + never become ready and it can only be destroyed. + + + + + + + + + Once this event has been sent, the wp_image_description_v1 object is + deemed "ready". Ready objects can be used to send requests and can be + used through other interfaces. + + Every ready wp_image_description_v1 protocol object refers to an + underlying image description record in the compositor. Multiple protocol + objects may end up referring to the same record. Clients may identify + these "copies" by comparing their id numbers: if the numbers from two + protocol objects are identical, the protocol objects refer to the same + image description record. Two different image description records + cannot have the same id number simultaneously. The id number does not + change during the lifetime of the image description record. + + The id number is valid only as long as the protocol object is alive. If + all protocol objects referring to the same image description record are + destroyed, the id number may be recycled for a different image + description record. + + Image description id number is not a protocol object id. Zero is + reserved as an invalid id number. It shall not be possible for a client + to refer to an image description by its id number in protocol. The id + numbers might not be portable between Wayland connections. A compositor + shall not send an invalid id number. + + This identity allows clients to de-duplicate image description records + and avoid get_information request if they already have the image + description information. + + + + + + + + Creates a wp_image_description_info_v1 object which delivers the + information that makes up the image description. + + Not all image description protocol objects allow get_information + request. Whether it is allowed or not is defined by the request that + created the object. If get_information is not allowed, the protocol + error no_information is raised. + + + + + + + + + Sends all matching events describing an image description object exactly + once and finally sends the 'done' event. + + This means + - if the image description is parametric, it must send + - primaries + - named_primaries, if applicable + - at least one of tf_power and tf_named, as applicable + - luminances + - target_primaries + - target_luminance + - if the image description is parametric, it may send, if applicable, + - target_max_cll + - target_max_fall + - if the image description contains an ICC profile, it must send the + icc_file event + + Once a wp_image_description_info_v1 object has delivered a 'done' event it + is automatically destroyed. + + Every wp_image_description_info_v1 created from the same + wp_image_description_v1 shall always return the exact same data. + + + + + Signals the end of information events and destroys the object. + + + + + + The icc argument provides a file descriptor to the client which may be + memory-mapped to provide the ICC profile matching the image description. + The fd is read-only, and if mapped then it must be mapped with + MAP_PRIVATE by the client. + + The ICC profile version and other details are determined by the + compositor. There is no provision for a client to ask for a specific + kind of a profile. + + + + + + + + + + Delivers the primary color volume primaries and white point using CIE + 1931 xy chromaticity coordinates. + + Each coordinate value is multiplied by 1 million to get the argument + value to carry precision of 6 decimals. + + + + + + + + + + + + + + + Delivers the primary color volume primaries and white point using an + explicitly enumerated named set. + + + + + + + + The color component transfer characteristic of this image description is + a pure power curve. This event provides the exponent of the power + function. This curve represents the conversion from electrical to + optical pixel or color values. + + The curve exponent has been multiplied by 10000 to get the argument eexp + value to carry the precision of 4 decimals. + + + + + + + + Delivers the transfer characteristic using an explicitly enumerated + named function. + + + + + + + + Delivers the primary color volume luminance range and the reference + white luminance level. These values include the minimum display emission + and ambient flare luminances, assumed to be optically additive and have + the chromaticity of the primary color volume white point. + + The minimum luminance is multiplied by 10000 to get the argument + 'min_lum' value and carries precision of 4 decimals. The maximum + luminance and reference white luminance values are unscaled. + + + + + + + + + + Provides the color primaries and white point of the target color volume + using CIE 1931 xy chromaticity coordinates. This is compatible with the + SMPTE ST 2086 definition of HDR static metadata for mastering displays. + + While primary color volume is about how color is encoded, the target + color volume is the actually displayable color volume. If target color + volume is equal to the primary color volume, then this event is not + sent. + + Each coordinate value is multiplied by 1 million to get the argument + value to carry precision of 6 decimals. + + + + + + + + + + + + + + + Provides the luminance range that the image description is targeting as + the minimum and maximum absolute luminance L. These values include the + minimum display emission and ambient flare luminances, assumed to be + optically additive and have the chromaticity of the primary color + volume white point. This should be compatible with the SMPTE ST 2086 + definition of HDR static metadata. + + This luminance range is only theoretical and may not correspond to the + luminance of light emitted on an actual display. + + Min L value is multiplied by 10000 to get the argument min_lum value and + carry precision of 4 decimals. Max L value is unscaled for max_lum. + + + + + + + + + Provides the targeted max_cll of the image description. max_cll is + defined by CTA-861-H. + + This luminance is only theoretical and may not correspond to the + luminance of light emitted on an actual display. + + + + + + + + Provides the targeted max_fall of the image description. max_fall is + defined by CTA-861-H. + + This luminance is only theoretical and may not correspond to the + luminance of light emitted on an actual display. + + + + + +