Compare commits

...
Author SHA1 Message Date
Caleb Cornett c9a6709bd2 gpu: Add BC2_RGBA_UNORM_SRGB to GetBlockWidth/Height functions 2025-06-02 13:53:42 -07:00
Evan Hemsley 25816bea41 GPU: Binding validation and prevent null dereference if expected binding is missing (#13164) 2025-06-02 13:40:40 -07:00
Sam Lantinga e0f6e96da0 Use HEAPU8.set rather than Module.HEAPU8.set (thanks @sbc100!)
The Module object is the external interface to the application, internal symbols like HEAPU8 don't need to be exported to be used and usage should not be prefixed with Module.

Fixes https://github.com/libsdl-org/SDL/issues/13156
Closes https://github.com/libsdl-org/SDL/pull/13157

(cherry picked from commit cf6c42e6e6)
2025-06-02 09:48:55 -07:00
Sam Lantinga 57de46ae7e Mark gamepads as invalid if they can't be opened
Fixes https://github.com/libsdl-org/SDL/issues/13129

(cherry picked from commit 4b0f48c4cf)
2025-06-02 09:25:10 -07:00
Sam Lantinga 59693c8996 Updated to version 3.2.16 for release 2025-06-01 14:37:23 -07:00
Ryan C. Gordon f0efffc093 x11: Be a little less aggressive with Xinput2IsInitialized checks.
Just in case this ever get deinitialized sooner, we'd still like to SDL_free()
things on shutdown, etc.

Reference PR #13148.

(cherry picked from commit 9e0d9f30a7)
2025-06-01 10:15:54 -04:00
Mason Remaley 1b41cd759c Checks if xinput is loaded before trying to call xinput functions
(cherry picked from commit 57b6e6c7f9)
2025-06-01 10:15:47 -04:00
Ryan C. Gordon d42a1402e8 audio: corrected comment about device format minimums.
(cherry picked from commit ac3ab026fe)
2025-06-01 03:01:47 -04:00
Ryan C. Gordon 5c44678d55 audio: Opened device spec must be >= simple minimums, not device's defaults.
Fixes #13159.

(cherry picked from commit 83cc3bc234)
2025-06-01 02:58:41 -04:00
Ryan C. Gordon 0638fd58ce pulseaudio: Request more recording data per-fragment.
This seems to help some devices that can't keep up with smaller fragment sizes
for whatever reason.

Fixes #13110.

(cherry picked from commit 14a4ae521a)
2025-06-01 02:48:49 -04:00
Ryan C. Gordon cb662b6730 cocoa: add explicit tracking areas to the window.
This makes sure we get reliable mouse enter/exit events from the system on
older macOS releases.

Newer releases don't have this problem--my assumption is that Cocoa has a
more aggressive default tracking area installed for some newer UI feature.

For 3.2.16, we'll use the explicit tracking area on older macOSes only, but
I'll remove that check in revision control for newer OSes and see what
happens.

Fixes #12725.

(cherry picked from commit f61d956a04)
2025-05-31 14:45:43 -04:00
Caleb Heuer e874c7515e Pass text input rect to steam deck keyboard invocation
(cherry picked from commit 51dfca813b)
2025-05-30 09:54:53 -07:00
Ethan Lee 2ba797576b storage: Declare a private bootstrap for NDA user storage 2025-05-30 12:15:43 -04:00
Sam Lantinga 180b454d61 kmsdrm: fixed creating GBM surfaces on NVIDIA cards
(cherry picked from commit fc1c0618de)
2025-05-29 11:20:44 -07:00
DracoRooks 6ce7ae77b1 Update SDL_pixels.h
Added an opening bracket in line 520, in the comment block of SDL_PixelFormat. Simple addition to the readability of documentation.

(cherry picked from commit 03a6d98aee)
2025-05-29 11:03:54 -07:00
Sam Lantinga abbaf95cf0 Added macros to push/pop error messages while cleaning up
(cherry picked from commit 885e611f3c)
2025-05-29 10:54:46 -07:00
Sam Lantinga 1081b70951 Fixed typos
(cherry picked from commit 61d105247e)
2025-05-29 10:54:46 -07:00
Sam Lantinga 4f51f956ad Updated SDL_StretchSurface() documentation
Fixes https://github.com/libsdl-org/SDL/issues/13135

(cherry picked from commit 7db0ac7380)
2025-05-29 09:09:29 -07:00
Sam Lantinga b076f4b590 Removed obsolete documentation
(cherry picked from commit 737b9e117d)
2025-05-28 15:57:23 -07:00
Sam Lantinga 91180f8cb4 Disable SDL_HINT_JOYSTICK_RAWINPUT by default
Windows can get in a state when it stops reporting raw input events for game controllers until reboot.

The downside of this change is that we lose support for trigger rumble and are limited to 4 controllers again, but if that's important for your application you can use SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, true) to enable this functionality.

Fixes https://github.com/libsdl-org/SDL/issues/13047

(cherry picked from commit aa870d511e)
2025-05-27 09:51:58 -07:00
Ethan Lee 99aa859362 gpu: Xbox buildfix 2025-05-27 12:42:46 -04:00
Frank Praznik 31267feb03 wayland: Use raw timestamps to calculate the elapsed repeat time on a key up event
Using processed timestamps can result in anomalies that cause excessive repeat events, and hard caps can cause issues.

In the key event handler, use the raw elapsed time to calculate any remaining repeat events to avoid the artifacts that can result from using processed timestamps.

The Wayland key repeat rate ranges from 0 to 1000 per second, so millisecond resolution doesn't lose any precision.

(cherry picked from commit e3d44cdd51)
2025-05-27 11:18:56 -04:00
Sander Ledegen 6a5bac72cb PSP fullscreen is the only mode (#13125)
(cherry picked from commit 9b025e3cab)
2025-05-26 10:32:13 -07:00
Ozkan Sezer 2ed5062950 SDL_video.c: remove two stray line continuation chars .
(cherry picked from commit 25db127450)
2025-05-26 01:45:50 +03:00
Christian Kündig 0b0b02c5a1 emscripten: Proxy Emscripten_GetSystemTheme and EMSCRIPTENAUDIO_OpenDevice to the main thread.
(cherry picked from commit 168d1a9253)
2025-05-25 13:50:19 -07:00
mattbsage 28c71368a1 Clean up INTERFACE_COMPILE_OPTIONS
The extra text causes Meson/Ninja builds to fail as headers are not found.

(cherry picked from commit f62572344f)
2025-05-24 19:13:41 -07:00
Frank Praznik 25bd4285ab x11: Assume the window was mapped after showing
Not all window managers send a MapNotify or PropertyNotify event when the window is shown, so assume that it was mapped and set the flag accordingly.

(cherry picked from commit b70919ecd9)
2025-05-24 10:00:43 -04:00
Frank Praznik 180171cad6 x11: Always send fullscreen dimensions except on XWayland
More non-compositing window managers than just openbox seem to need this, so always force sending the window position and dimensions when entering/leaving fullscreen. If they are wrong, they will be immediately overwritten by the correct dimensions from a subsequent ConfigureNotify event.

This is disabled on XWayland, as it seems to cause hitching on some compositors.

(cherry picked from commit 0657ece55d)
2025-05-24 10:00:43 -04:00
Sam Lantinga bc3eeecf7f Set the initial axis values for HIDAPI and XInput controllers
Fixes https://github.com/libsdl-org/SDL/issues/13020

(cherry picked from commit 1f6b5c681d)
2025-05-23 12:09:58 -07:00
Frank Praznik 9178d14519 x11: Include the XTest header when needed
Fixes building when statically linking.

(cherry picked from commit fdc4f8fa39)
2025-05-23 13:12:47 -04:00
Ivan Epifanov 6cd35f5b72 VITA: support only fullscreen windows. Fixes #13079
(cherry picked from commit 2b4d61e4a6)
2025-05-23 08:45:49 -07:00
kyle-sylvestre 72d5eb0ecb fix error handling in WideCharToMultiByte
(cherry picked from commit ead32c706d)
2025-05-22 15:25:58 -07:00
kyle-sylvestre 5cf924420d bugfix advancing UTF-8 length in UTF-16 string
(cherry picked from commit 8ddb074889)
2025-05-22 15:25:58 -07:00
Ryan C. Gordon 290574e6f6 stdinc: Corrected documentation for SDL_atan2 and SDL_atan2f.
Fixes #13099.

(cherry picked from commit 8d9a4fe843)
2025-05-22 09:52:51 -04:00
Frank Praznik d9db975b4b wayland: Use SDL_memcpy instead of SDL_copyp to copy the repeated text string
SDL_copyp is not intended to copy arrays. Use SDL_memcpy with the explicit size instead.

(cherry picked from commit abcfa1b7de)
2025-05-21 20:39:03 -04:00
Matteo Hausner e5c0e5efa7 Fix #13083 segfault in SDL_RemoveTrayEntry() for submenu entries
Use `g_object_ref_sink()` in `SDL_CreateTraySubmenu()` as introduced with
3be67ced64 for the top-level menu.

(cherry picked from commit 22828d5f2a)
2025-05-21 13:32:47 -07:00
Sam Lantinga 26a1aae098 Fixed the Bluetooth flag for the combined Joy-Con controller
(cherry picked from commit 264eb8d440)
2025-05-21 13:30:30 -07:00
Frank Praznik ab114490fc wayland: Cap the max key repeat elapsed time
Cap the elapsed time to something sane in case the compositor sends a bad timestamp, which can result it in it looking like the key has been pressed for a *very* long time, bringing everything to a halt while it tries to enqueue all the repeat events.

(cherry picked from commit 05f779f61e)
2025-05-21 12:20:31 -04:00
kyle-sylvestre 9546c54286 use SDL style - else on same line as closing brace
(cherry picked from commit b8e055ce64)
2025-05-20 17:13:47 -07:00
kyle-sylvestre 4d3cdb70b5 get preferred locales on android
(cherry picked from commit 8e22194217)
2025-05-20 17:13:47 -07:00
Anthony Fisher a66816a72f gpu/d3d12: Acknowledge that we've bound vertex buffers (#13088) 2025-05-20 16:34:27 -04:00
Francisco Javier Trujillo Mata c925f72562 Fix wrong callback type
(cherry picked from commit c89357bf60)
2025-05-20 11:11:01 -07:00
Logan ef97329f41 GPU: Update D3D12 to create multisample textures with default MSAA alignment
(cherry picked from commit f4942b3eae)
2025-05-20 11:07:54 -07:00
Frank Praznik 195f709eda wayland: Set the text input cursor rect properly
The text input cursor should reflect the cursor position, not the entire text input rect. Set it correctly so that IME chooser dialogs appear in the correct location.

(cherry-picked from commit c7549eb0b6)
2025-05-20 13:42:21 -04:00
cosmonaut eb57d94ec5 GPU: Add missing compute-writeable texture formats 2025-05-19 18:11:06 -07:00
Sam Lantinga d6212ae839 Fixed rare crash trying to interrupt SDL_WaitEvent()
Fixes https://github.com/libsdl-org/SDL/issues/12797

(cherry picked from commit 992e4c59bd)
2025-05-19 14:16:25 -07:00
Frank Praznik b494897b3d wayland: Don't add the nanosecond timestamp offset to the pre-conversion millisecond value
(cherry picked from commit 6c61a94a4b)
2025-05-19 14:00:12 -04:00
Sam Lantinga 559d4415eb Fixed touch not being delivered as mouse events by default on Vita
Closes https://github.com/libsdl-org/SDL/pull/13070

(cherry picked from commit 25f2376e79)
2025-05-19 08:33:28 -07:00
Joe [ReRezd] 49e9134774 Fix: GameCube controller adapter hotplug not working
SDL_PrivateJoystickAdded was called before setting the InstanceId in the adapters ctx->joysticks array.  This would eventually broadcast the SDL_EVENT_JOYSTICK_ADDED event with the new InstanceId, if your program listens for the added events and opens joysticks at that point it would always fail because there would be no matching InstanceId in the ctx->joysticks array.

(cherry picked from commit afd1e51023)
2025-05-19 08:25:16 -07:00
Logan 9571b0ece8 GPU: Update to set supported shader formats inside CreateDevice
(cherry picked from commit 8289656a4e)
2025-05-18 18:33:07 -07:00
danginsburg b55cfaf90b Fix #13057 - fixes bug with NSEventTypeMouseMoved having a NULL window causing us to suppress future mouse move events because the window was considered out of focus.
(cherry picked from commit 968222e74f)
2025-05-16 17:07:49 -07:00
ScolderCreations 509168856f Fix reference to nonexistent "README-3ds.md"
(cherry picked from commit d16371b923)
2025-05-15 11:23:17 -07:00
Stéphane GINIER 24fa2722c3 MacOS: fix cocoa clipboard text
Adjust Cocoa_SetClipboardData so that SetClipboardText text can be pasted outside SDL

(cherry picked from commit 945eb6dc87)
2025-05-15 10:54:15 -07:00
Evan Hemsley 142700f909 GPU: Check that a texture format is valid for compute writes (#13044) 2025-05-14 16:25:24 -07:00
Evan Hemsley f3611681df GPU: Always return NULL if beginning a pass fails an assert check 2025-05-14 15:23:57 -07:00
Sam Lantinga 7f0a5d6a10 Updated to version 3.2.15 for development 2025-05-14 13:08:44 -07:00
cosmonaut 2001cc15d5 GPU: Debug mode layer and level index checks 2025-05-14 12:25:18 -07:00
Frank Praznik 8d604353a5 renderer: Always use the output size when updating the main view
The main view always reflects the size of the output, so don't use the dimensions of the currently bound render target texture when updating it, or it will reflect an incorrect size when the render target texture is unbound.

(cherry picked from commit 8aa5b97bb5)
2025-05-14 09:38:13 -07:00
Ryan C. Gordon 8410e11ecb wikiheaders: Man pages should escape apostrophe chars.
This prevents problems if one starts a line, which would cause it to be
interpreted as a command character.

Fixes #13038.

(cherry picked from commit 1f7aa16eae)
2025-05-14 11:41:14 -04:00
krizej 9f8161bf4a docs: improve man page generation
(cherry picked from commit a390f5716e)
2025-05-14 11:40:58 -04:00
Sam Lantinga c038d6f7f8 Updated to version 3.2.14 for release 2025-05-13 14:24:40 -07:00
Frank Praznik 2fff37fffc Revert "x11: Send key events for dead keys consumed by the IME"
This and its related commits introduced some bugs and quirks such as duplicated and delayed/missed key events that can't be easily worked around, so revert this for now.

This reverts commit 47162a4168.

(cherry picked from commit 1eeffc5933)
2025-05-13 09:22:13 -07:00
Frank Praznik 6feb86be71 Revert "x11: Filter out duplicate key presses when an IME is active"
This reverts commit f4813ca2cf.

(cherry picked from commit 3304d24bea)
2025-05-13 09:22:13 -07:00
Sam Lantinga ed22220bc6 Fixed crash if out of memory in the Vulkan GPU driver
(cherry picked from commit cd95152b2c)
2025-05-13 09:08:19 -07:00
Andrey Moura 219cb1a59d joystick: Fix linker error when building without virtual joystick support
SDL_VIRTUAL_JoystickDriver was referenced outside an #ifdef when setting is_virtual, which caused a linker error. I modified it so that is_virtual is set to false if virtual joystick support is not enabled.
2025-05-13 08:55:29 -07:00
Simon McVittie 71bd25a893 audio: Assert that all devices from device_hash are the appropriate type
The keys and values of device_hash are pairs
`(SDL_AudioDeviceID devid, void *dev)` where dev can be either a
`SDL_AudioDevice *` or a `SDL_LogicalAudioDevice *`, depending on
bit 1 of devid.

We can confirm that we have got this right by looking at the
instance_id member, because logical audio devices happen to start with
the devid, whereas physical devices start with a pointer which is
unlikely to match the devid by chance.

Signed-off-by: Simon McVittie <smcv@collabora.com>
(cherry picked from commit 70b2d162e3)
2025-05-13 08:53:35 -07:00
Ryan C. Gordon 01ef4c46a1 audio: Fix SDL_GetAudioDeviceName() not working with logical devices.
Fixes #12977.

(cherry picked from commit 0a34279578)
2025-05-12 13:54:52 -04:00
yunline 64f728ec48 tray: Fix wrong fByPositon parameter of SetMenuItemInfoW in SDL_SetTrayEntryLabel
(cherry picked from commit 9a6f70d75a)
2025-05-12 08:40:44 -07:00
Mike Kosek ba10adf1fb Added rightx and righty
(cherry picked from commit 38da39c8c9)
2025-05-12 08:40:44 -07:00
Dominic Bolin c18aa99358 GPU Vulkan: set correct destination usage mode for storage buffer read/write bindings (#13009) 2025-05-11 16:12:37 -07:00
ManuBlack 3498412611 AAudio: Implemented sample frames hint
(cherry picked from commit c6e9d6cc79)
2025-05-11 16:06:13 -07:00
Ryan C. Gordon 8c1b3ff210 Revert "pulseaudio: cleanup TLS every time we finish a threaded-mainloop callback."
This reverts commit 3b91017682.

This apparently is cleaning up more threads than expected, so this needs a
rethink.

Fixes #12986.
Fixes https://github.com/libsdl-org/sdl2-compat/issues/486
Fixes https://github.com/libsdl-org/sdl2-compat/issues/482

(cherry picked from commit e1066ceea1)
2025-05-11 10:23:04 -07:00
Frank Praznik 1870052af6 x11: Fix the Openbox quirk flag
Openbox needs fullscreen size/position event synthesized, but does not send display changed events.

(cherry picked from commit 84308e7fba)
2025-05-10 15:50:48 -04:00
dbolin 3b1e3d5176 GPU Vulkan: fix for Swapchain Semaphore Reuse
(cherry picked from commit 6344712b04)
2025-05-10 07:56:07 -07:00
RipleyTom cdf26c6e97 Add hid_version and hid_version_str to renamed LIBUSB impl symbols
(cherry picked from commit e90f7ac4a8)
2025-05-10 07:45:37 -07:00
Evan Hemsley 9f1a1405a6 GPU: Special case to avoid assert on GenerateMipmaps (#12995)
(cherry picked from commit 86b206dadf)
2025-05-09 22:00:57 -07:00
Sam Lantinga 6e97d8d1b3 Fixed crash if WGI isn't correlated in RAWINPUT_JoystickRumble()
(cherry picked from commit 87fe9ef79b)
2025-05-08 15:39:50 -07:00
Sam Lantinga 9d9a24d325 Define illegal_instruction() when it will be actually used
(cherry picked from commit 29d2116495)
2025-05-08 12:50:08 -07:00
Sam Lantinga 0897f4a7d1 Backported Metal sampler improvements from main
Fixes https://github.com/libsdl-org/SDL/issues/12988
2025-05-08 10:22:17 -07:00
Sam Lantinga 5aec645191 Added GCController mapping for the 8BitDo SN30 Pro on macOS
(cherry picked from commit 2b57d58f7d)
2025-05-08 09:57:36 -07:00
Sam Lantinga 07c33068f3 Added GCController mapping for the 8BitDo Pro 2 on macOS
Fixes https://github.com/libsdl-org/SDL/issues/12987

(cherry picked from commit d157600d3d)
2025-05-08 09:49:46 -07:00
expikr d684e5d57e fix #12963
(cherry picked from commit 6b048f59d7)
2025-05-06 21:18:02 -07:00
Frank Praznik 219500d95c x11: Filter out duplicate key presses when an IME is active
IME text events can result in sending duplicate key press events, which will result in undesired repeated key presses. Since the events are exact duplicates, compare the serials to filter out redundant key down events.

(cherry picked from commit f4813ca2cf)
2025-05-06 18:21:39 -04:00
Frank Praznik 810addf7ae x11: Don't update grab on enter when the mouse is captured
The xserver will still send EnterNotify events while the pointer is captured, and the grab shouldn't be updated in these cases, as it will cause the capture to be lost.

(cherry picked from commit 33e5f4885a)
2025-05-06 14:50:16 -07:00
Frank Praznik 4ef077ca52 Revert "x11: Better handle XInput2 mouse tracking outside the window"
This reverts commit 8c733d1f7b.

(cherry picked from commit 1abac3ccc3)
2025-05-06 14:50:16 -07:00
Sam Clegg 7d2275c4dc [emscripten] Remove referenc to Module['createContext']
The Module interface is the one used by the outside world.  This code
is inside the module itself so can use the internal name, avoiding the
need to export this function on the Module at all.

See https://github.com/emscripten-core/emscripten/pull/24269

(cherry picked from commit 8e1f4bafb4)
2025-05-06 14:16:36 -07:00
Ivan Epifanov cbd8917047 VITA: fix audio playback
(cherry picked from commit 1dbb813316)
2025-05-06 12:55:34 -07:00
Frank Praznik c98a19401c x11: #ifdef the XRandR path in the message box code
The runtime check isn't sufficient as the functions are undefined if built without XRandR.

(cherry picked from commit c91f9f6968)
2025-05-05 11:16:03 -04:00
A. Wilcox 434836c480 cpuinfo: Use auxv for AltiVec on Linux if possible
The SIGILL handler is not very reliable and can cause crashes.

Linux provides the CPU's AltiVec support status in getauxval.

(cherry picked from commit 7490471796)
2025-05-04 13:53:10 -07:00
Sam Lantinga 50d02ad732 Updated to version 3.2.13 for development 2025-05-04 10:56:10 -07:00
Ozkan Sezer 5ac37a8ffc don't prototype strdup() for __clang_analyzer__ case in windows builds.
Fixes:  https://github.com/libsdl-org/SDL/issues/12948.
(cherry picked from commit 17bba029ba)
2025-05-04 10:36:33 -07:00
Sam Lantinga 7dd2915475 Updated to version 3.2.12 for release 2025-05-04 10:09:23 -07:00
Frank Praznik 0ae1ddee17 win32: Hide the borders when showing a fullscreen window
If it is known that the window will immediately enter fullscreen upon being shown, set the borderless style when showing the window to hide the borders, or they may linger in the background if the client takes some time to draw the first frame.

Unnecessarily calling ShowWindow with SW_RESTORE when applying the window flags must be suppressed in this case, or the borders can reappear in a weird, partial state.

(cherry picked from commit d73fe0bc53)
2025-05-02 14:22:14 -04:00
Sam Lantinga db4c7e47f1 Added support for the share button on the GameSir-K1 FLUX controller
(cherry picked from commit ab12b7cbba)
2025-05-02 10:15:39 -07:00
Sam Lantinga 362445460e Added support for the PowerA Battle Dragon Advanced Wireless Controller
(cherry picked from commit 1e6a25324c)
2025-05-02 10:01:42 -07:00
Ryan C. Gordon de5cb9db23 dialog: Cocoa backend should reactivate the app after the modal dialog.
Otherwise the window won't have focus until you click on it again. Calling
makeKeyAndOrderFront isn't enough to fix it, either.

This trick comes from a similar problem we solve in our
applicationDidFinishLaunching implementation: activate (give app focus to) the
system Dock, as something that definitely exists that isn't us and is harmless
to activate, and then activate us right afterwards. This unconfuses whatever
is getting confused inside Cocoa.

Fixes #12684.

(cherry picked from commit 57346f2ba8)
2025-05-02 01:54:56 -04:00
Ryan C. Gordon 418eab29eb uikit: Use SDL_RunOnMainThread instead of dispatch_sync for message boxes.
Reference Issue #12741.

(cherry picked from commit 193b0c8963)
2025-05-02 01:54:17 -04:00
Ryan C. Gordon 2f3d242183 dialog: Cocoa shouldn't crash if there's a '.' in the filters.
So something like "index.pb" will now accept any file with a ".pb" extension,
to make macOS happy. This seems like a reasonable tradeoff.

Other minor cleanups.

Fixes #12778.

(cherry picked from commit 691cc5bb5e)
2025-05-01 21:37:54 -07:00
Cameron Gutman 4ad6d18203 events: Add integer wheel fields for sdl2-compat
It's way simpler to just add them back to SDL3 than emulate them purely in sdl2-compat.

(cherry picked from commit 0447c2f3c3)
2025-05-01 22:51:54 -05:00
Temdog007 cd4a4f8a9f X11: Center Message Box on Multi Monitor Displays (#12819)
Use XRandr to find the position of the current screen to center the message box on that window

(cherry picked from commit 4ef8b6ce1b)
2025-05-01 13:39:26 -07:00
Frank Praznik a96e72da02 video: Store the preferred fullscreen display in a property for sdl2-compat
sdl2-compat will call SDL_GetDisplayForWindow() when querying the display to use for fullscreen, which won't always be correct if the backend can't actually reposition the window. When calling this function, get the ideal fullscreen display and store it in a property for retrieval by sdl2-compat.

(cherry picked from commit c5d5967c3a)
2025-05-01 11:25:03 -07:00
Sam Lantinga 337f012de2 Fixed right mouse button emulation when using a pen
Pen button 1 is typically used as right click. Pen button 2 (Wacom eraser) doesn't have a specific mapping, but we'll use middle click for now.

(cherry picked from commit e3df61b070)
2025-04-30 11:08:24 -07:00
Sam Lantinga 3c29b620e4 Fixed missing simulated mouse events using a Wacom tablet
The low 16-bits of the message extra info is an event sequence number when using the Wacom tablet with Windows Ink disabled. The high bits of normal mouse motion when using touch input match the touch signature, 0xFF515700. The high bits of raw input mouse motion when using touch input do not match that signature, so we have to check for the touch bit in that case.

Fixes https://github.com/libsdl-org/SDL/issues/12927

(cherry picked from commit 106ccc722e)
2025-04-30 11:08:24 -07:00
Sam Lantinga 579fc161f0 Fixed build
(cherry picked from commit 8ae962c904)
2025-04-29 19:57:15 -07:00
Sam Lantinga 22e968af4e Fixed right click mouse emulation for the Wacom tablet
The problems are two-fold. When this happens a WM_POINTERDOWN event is sent with IS_POINTER_INCONTACT_WPARAM() evaluating as true. So when SDL_SendPenButton() is sent for the barrel button, there is no pen in contact yet, so the right mouse button is sent. Then SDL_SendPenTouch() is sent, which generates a left button press event.

Fixes https://github.com/libsdl-org/SDL/issues/12926

(cherry picked from commit e04064350f)
2025-04-29 19:57:15 -07:00
Ryan C. Gordon e37e96cfff pen: Windows can't check WM_POINTER[DOWN|UP] for touches directly.
These events fire for other things, such as pressing a barrel button while
the pen is hovering.

The correct thing to do is check IS_POINTER_INCONTACT_WPARAM in the event.

If the pen is already touching or not, SDL_SendPenTouch() will do the right
thing, so it's safe to call it even if we're already in the right state.

(cherry picked from commit ea67133e4f)
2025-04-29 19:57:15 -07:00
Evan Hemsley 56c76c20a0 GPU: Validate that textures are not bound for both read and write on render passes (#12925)
(cherry picked from commit a163257295)
2025-04-29 16:53:45 -07:00
Evan Hemsley efd812c399 GPU Vulkan: Add locks for layout object lookups (#12924)
(cherry picked from commit e1a41c1c97)
2025-04-29 15:44:37 -07:00
Sam Lantinga b2b92bbe25 Removed timeout in SDL_RunOnMainThread()
Fixes https://github.com/libsdl-org/SDL/issues/12923

(cherry picked from commit 8abcc27535)
2025-04-29 08:58:54 -07:00
Sam Lantinga a29c67ac94 Always enable D3D12 GPU on Windows
This isn't dependent on the render subsystem

Fixes https://github.com/libsdl-org/SDL/issues/12922

(cherry picked from commit ef54c3bf18)
2025-04-29 08:53:40 -07:00
Cameron Gutman f88e0aaac0 events: Fix undefined behavior when disabling some event types
Shifting a signed int left by 31 is UB.

(cherry picked from commit 39d3148185)
2025-04-29 00:27:02 -05:00
Ozkan Sezer 29a4a4a5d1 tray, unix: make pointers g_object_ref and g_object_ref_sink static
Fixes:  https://github.com/libsdl-org/SDL/issues/12908.
(cherry picked from commit 016ba86f93)
2025-04-27 10:22:18 -07:00
Frank Praznik 01000c73b0 cocoa: Immediately update the mouse focus when showing/hiding a popup menu
When showing or hiding a popup menu, manually check and set the focus if the new topmost window under the cursor is an SDL window. Otherwise, the focus won't be updated until the cursor is actually moved.

(cherry picked from commit 6f5892e543)
2025-04-27 09:39:36 -04:00
Frank Praznik 1a5d1dfef0 x11: Better handle XInput2 mouse tracking outside the window
There is a quirk with XInput2 mouse capture that causes a leave event to be sent if the pointer moves out->in->out, which breaks mouse tracking outside the window. If the mouse leaves the window with buttons pressed, continue tracking it until the buttons are released.

(cherry picked from commit 8c733d1f7b)
2025-04-26 13:16:19 -04:00
Austin Almond 2c38143834 GDK: Handle ProjectDir with space
The call to compile_shaders_xbox.bat fails if ProjectDir contains a space. Wrapping the command in quotes fixes the issue.

(cherry picked from commit 14ae45c2b8)
2025-04-25 15:01:07 -07:00
Ryan C. Gordon c56a1c664c aaudio: We PlayDevice first and WaitDevice after; reduce semaphore count by 1.
Previously, we would WaitDevice first, but that would feed a silent buffer
to AAudio upfront, introducing latency. When this change was made, the
semaphore count should have been adjusted, since we're waiting on one less
buffer.

Fixes #12882.

(cherry picked from commit 2767c1a440)
2025-04-25 15:08:56 -04:00
Ryan C. Gordon 41cae64580 pipewire: Use a more specific stream name than "Audio Stream".
This info shows up in `pw-top` ...Gnome's sound preferences (etc) would
already show something more app-specific, but this command line tool shows
specific stream names.

(cherry picked from commit a9bee3c0bf)
2025-04-25 14:26:03 -04:00
Ryan C. Gordon c6dd2662c3 pulseaudio: cleanup TLS every time we finish a threaded-mainloop callback.
These callbacks run in a thread we don't control, but might call SDL_SetError,
which will claim a TLS slot that never gets otherwise deallocated. To prevent
the leak, finish each callback by explicitly freeing any thread-local data.

Fixes #12732.

(cherry picked from commit 3b91017682)
2025-04-25 14:25:51 -04:00
Ryan C. Gordon f48027cf12 audio: Tweak SDL_GetAudioDeviceName.
- Add checks that ObtainPhysicalAudioDevice() was previously doing
  (is subsystem initialized, is device valid).
- Remove optimizations that copy string to stack to release device_hash_lock
  before SDL_GetPersistentString is called. Probably not necessary, and made
  the code more complex.

(cherry picked from commit b28449a58c)
2025-04-25 08:12:52 -07:00
Anonymous Maarten fabbc8d183 cmake: use CMAKE_ANDROID_NDK variable as root of Android ndk
This variable is always defined when targeting Android:
- when using the toolchain file shipped along the ndk
  (using  -DCMAKE_TOOLCHAIN_FILE=$ENV{ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake)
- when using the toolchain file provided by CMake
  (using -DCMAKE_SYSTEM_NAME=Android)

(cherry picked from commit 5b1e92ae88)
2025-04-25 07:59:05 -07:00
Frank Praznik a142e5ef7d cocoa: Popup menus always accept first click
(cherry picked from commit 09b2aae47e)
2025-04-25 09:36:12 -04:00
Sam Lantinga 825c0c7691 Reset the keyboard when entering a modal loop on Windows
Fixes https://github.com/libsdl-org/SDL/issues/12876

(cherry picked from commit da3c864d4c)
2025-04-24 13:58:56 -07:00
expikr dc30a00a26 use GetMessagePos instead of GetCursorPos
(cherry picked from commit a82f70dc21)
2025-04-24 13:27:42 -07:00
kiddkaffeine 5a05ef01ad Fix crash in UIKit indirect pointer handling
(cherry picked from commit 5cacdf2513)
2025-04-24 13:05:23 -07:00
Alynne 0237997e4d Add Padix Rockfire devices (#12884)
(cherry picked from commit 32bbabe2a5)
2025-04-24 11:28:48 -07:00
Robert Müller 4f90432a49 Emscripten: fix incorrect error check for WebGL context creation
According to the documentation and testing the `emscripten_webgl_create_context` function returns `0` on error as oppposed to a negative number. This was causing the error message to be empty when the later `emscripten_webgl_make_context_current` call fails given the invalid context.

See https://emscripten.org/docs/api_reference/html5.h.html#c.emscripten_webgl_create_context

(cherry picked from commit 7e1d4f843c)
2025-04-24 11:26:16 -07:00
expikr 0cd6942bfc defer clipcursor refresh unto pump finish
(cherry picked from commit dd625a6763)
2025-04-24 10:37:30 -07:00
expikr 1beb6fdedf pass ground-truth cursor pos to WIN_UpdateFocus
(cherry picked from commit c84c2aa2c4)
2025-04-24 10:37:30 -07:00
Frank Praznik 3b4472ecf7 x11: Handle size/position events arriving before state events
Xfce, unlike every other window manager in existence, sends ConfigureNotify events before PropertyNotify events when toggling the fullscreen and maximized window state. Check the window state when handling ConfigureNotify events, and defer emitting SDL size/position events until the corresponding PropertyNotify event arrives, since SDL and clients expect to get the window state before the new size and position.

(cherry picked from commit 11a3296a42)
2025-04-24 12:29:24 -04:00
Frank Praznik faed8b620c audio: Fix warning C4701: potentially uninitialized local variable 'isstack' used
This warning is actually wrong, as the variable is only used if the string pointer is valid, in which case it was initialized, but this is needed to quiet MSVC.

(cherry picked from commit fb940fff80)
2025-04-24 08:49:48 -07:00
Ryan C. Gordon 982b778e45 audio: SDL_GetAudioDeviceName() doesn't need a full device lock.
Fixes https://github.com/libsdl-org/sdl2-compat/issues/468

(cherry picked from commit e8bd9cc150)
2025-04-24 08:49:48 -07:00
Vicki Pfau 3a8f1cb7c5 Joystick: Add trigger rumble resend
This was already present for regular rumble to ensure that controllers would
continue rumbling for extended periods, but was missing for trigger rumble. I
don't know if this affects any controllers at the moment, but it's helpful for
future-proofing.

(cherry picked from commit ceb9fecfc1)
2025-04-24 08:48:19 -07:00
Logan Benjamin 3c2d7ecdd6 GPU D3D12 - Update to use typeless formats for depth buffer (#12701)
For a depth buffer in D3D12 that is also going to be used in a texture sampler, the creation (on an Intel HD 5500 igpu) fails. e.g. SDL_GPUTextureCreateInfo type = TEXTURE_2D, format = D32_FLOAT, usage = DEPTH_STENCIL_TARGET | SAMPLER

The error messages are:

D32_FLOAT
D3D12 ERROR: ID3D12Device::CreateShaderResourceView: The Format (0x29, R32_FLOAT) is invalid when creating a View; the
Resource was already created with a fully qualified Format, which is not castable (0x28, D32_FLOAT).

D24_UNORM
D3D12 ERROR: ID3D12Device::CreateShaderResourceView: For the resource format D24_UNORM_S8_UINT, when making a D3D view, the format name for the view can't be R24_UNORM_X8_TYPELESS.

I found this is because the texture format needs to be created as _TYPELESS, then the views (depth stencil view, shader resource view) should then be created as their respective types - e.g. texture = R32_TYPELESS, dsv = D32_FLOAT, srv = R32_FLOAT

Tested and working on:
NVidia RTX 3050 (D3D12 feature set 12_2)
Intel HD 5500 (D3D12 feature set 11_1)

(cherry picked from commit c81b62293a)
2025-04-23 16:30:47 -07:00
Petar Popovic 0834f1d6ce SDL_GetRectIntersectionFloat(): Allow rendering zero-sized srcrect
(cherry picked from commit 27b256022b)
2025-04-23 16:16:24 -07:00
Lucas Murray 6ce446b768 GPU: Make D3D12 debug layers optional
(cherry picked from commit d04b28926c)
2025-04-23 16:16:24 -07:00
Sam Lantinga e045edb567 Corrected documentation for SDL_SetGPUSwapchainParameters()
(cherry picked from commit 695cad459b)
2025-04-23 16:16:24 -07:00
Ozkan Sezer 6cd14660cf stb_image.h: apply mainstream PR/1736
Fix root-cause of CVE-2021-45340 : dereference of NULL ptr.
Patch authored by Henner Zeller <h.zeller@acm.org>
Mainstream pull request: https://github.com/nothings/stb/pull/1736

(cherry picked from commit b5ed0d0138)
2025-04-23 17:55:24 +03:00
Sam Lantinga f5ac58c9f4 Added tests to cover invalid surface blits
Reproduction case for https://github.com/libsdl-org/SDL/issues/12844

(cherry picked from commit 89d7d406ab)
2025-04-22 13:06:36 -07:00
Petar Popovic c1779ca4a5 SDL_BlitSurfaceScaled(): Do not divide by zero
(cherry picked from commit fe849f1572)
2025-04-22 13:06:35 -07:00
Petar Popovic 6d8309f72e SDL_BlitSurfaceScaled(): Do not blit if surfaces have no pixel data
(cherry picked from commit 8017d38adc)
2025-04-22 13:06:35 -07:00
Sam Lantinga cf95db46a7 Renamed SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_UINT8 to SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_NUMBER
Typically we will name the property with the function that is used to set it, and document the range of values.

(cherry picked from commit 18fbe6a92f)
2025-04-22 10:28:43 -07:00
Petar Popovic b8abfeb7f3 SDL_BlitSurface() comment: Remove sentence about final blit rect being stored in srcrect and dstrect
(cherry picked from commit a696b108ac)
2025-04-22 10:21:54 -07:00
Sam Lantinga 014e24e1a8 Removed incorrect documentation for SDL_RenderViewportSet()
Closes https://github.com/libsdl-org/SDL/pull/12854

(cherry picked from commit c076b0d17f)
2025-04-22 10:17:57 -07:00
Cameron Gutman e42071a47c x11: Send key events for dead keys consumed by the IME
This matches the Wayland backend and what apps originally written for SDL2 are expecting.

(cherry picked from commit 47162a4168)
2025-04-22 09:18:46 -07:00
Sam Lantinga 1543f523b7 Updated documentation for SDL_HINT_GPU_DRIVER
(cherry picked from commit 3aed80cd82)
2025-04-22 08:58:58 -07:00
Frank Praznik f2d0e965fc wayland: Account for timer rollover when calculating the elapsed time for key repeats.
The 32-bit millisecond timer can roll over after about 49 days, so this needs to be accounted for.

(cherry picked from commit 5bd1578a45)
2025-04-22 10:46:34 -04:00
Frank Praznik f782278d20 cocoa: Use CGFLOAT_MAX for unbounded max window dimensions
(cherry picked from commit 10f51da28d)
2025-04-21 21:11:07 -04:00
Frank Praznik 3b17d08eb2 win32: Check internal data when positioning child windows
Under certain circumstances, processing events may try to position a child before it is fully initialized. Check the internal data before proceeding.

(cherry picked from commit 9da46bc37f)
2025-04-16 12:50:34 -04:00
Sam Lantinga 18d367afd2 Fixed process I/O redirection to NUL on Windows
(cherry picked from commit 4093e4a193)
2025-04-11 15:45:33 -07:00
Sam Lantinga 9a4faf9ab9 Add the CREATE_NO_WINDOW flag for background processes
Fixes https://github.com/libsdl-org/SDL/issues/12097

(cherry picked from commit c025fdbb7c)
2025-04-11 15:45:33 -07:00
Sam Lantinga cb0ba020d4 Don't reset the render target when invalidating GPU renderer cache state
Fixes https://github.com/libsdl-org/SDL/issues/12646

(cherry picked from commit f35a2736b7)
2025-04-11 09:24:38 -07:00
Sam Lantinga f705e2f9f7 Fixed conflict when linking both SDL and hidapi statically
Fixes https://github.com/libsdl-org/SDL/issues/12790

(cherry picked from commit 98e76d283f)
2025-04-10 09:58:13 -07:00
Patrick José Pereira e76bffa183 Add Turtle Beach VelocityOne
Signed-off-by: Patrick José Pereira <patrickelectric@gmail.com>
(cherry picked from commit f6db5ba4c9)
2025-04-10 09:48:58 -07:00
Adam Kewley a4e19dc567 [Windows]: dialog: Add OFN_OVERWRITEPROMPT to save dialogs (#12782)
(cherry picked from commit 0add037803)
2025-04-08 21:34:23 -07:00
Sam Lantinga 4e1282617a Fixed non-XBox controllers being detected as Series X controllers
First make sure we have an XBox One controller before checking whether it's a Series X/S controller.

(cherry picked from commit 93ac1e6894)
2025-04-08 12:21:34 -07:00
Sam Lantinga f102ff16a2 Don't treat the Keychron K1 Pro System Control keyboard as a joystick
Fixes https://github.com/libsdl-org/SDL/issues/12758

(cherry picked from commit d29bb902f3)
2025-04-08 11:08:55 -07:00
Ozkan Sezer 50935a9d41 fix sdlgenblit.pl so that it actually matches the generated source
(cherry picked from commit b0a0d236d8)
2025-04-08 18:24:40 +03:00
Sam Lantinga a1dde664d1 Updated version documentation to match SDL 3.x practice
(cherry picked from commit cccad933a0)
2025-04-07 10:23:27 -07:00
Frank Praznik ba5325fba1 x11/wayland: Ignore redundant restore and fullscreen leave requests when showing the window
The window may be initially maximized or made fullscreen by the window manager for various reasons, such as automatically declaring a window that precisely fills the usable desktop space as maximized, or a "kiosk-mode" automatically making the window fullscreen.

Don't redundantly make restored or unset fullscreen calls when initially showing a window, or the expected state can be unset.

(cherry picked from commit adad7dcae0)
2025-04-07 12:38:12 -04:00
Frank Praznik e225a10ea8 x11: Only enable _NET_WM_SYNC_REQUEST for OpenGL windows
It doesn't work well with Vulkan, and Vulkan windows may not have the Vulkan flag set in all circumstances, so only enable it if we explicitly know that OpenGL is being requested instead.

(cherry picked from commit 646f1f243f)
2025-04-05 15:45:35 -04:00
Evan Hemsley c4fba75a12 GPU Vulkan: Clean up in Submit in headless mode (#12744)
(cherry picked from commit 33f90f2e41)
2025-04-04 14:27:53 -07:00
Lucas Murray 5b052e6f8c GPU: Add missing error code to VkErrorMessages()
(cherry picked from commit 906c6c7516)
2025-04-04 07:39:44 -07:00
Lucas Murray d89c3489f8 GPU: The D3D12 blit shaders are DXIL
(cherry picked from commit 205c34c62a)
2025-04-04 07:39:43 -07:00
Sam Lantinga a447863e4f Set a default shader entry point
The default should be the entrypoint generated by SDL_shadercross. That way it doesn't need to be hand-specified in the common workflow.

(cherry picked from commit dcb97a5f49)
2025-04-04 07:39:16 -07:00
Lucas Murray 34db21cea8 GPU: Don't pass null properties to SDL_CopyProperties()
(cherry picked from commit 300013cea7)
2025-04-04 07:36:30 -07:00
Evan Hemsley 943226edc1 GPU Vulkan: Fix recursive Submit calls causing defrag to fail (#12718)
---------

Co-authored-by: Sam Lantinga <slouken@libsdl.org>
(cherry picked from commit b53e7b4478)
2025-04-03 15:01:43 -07:00
Frank Praznik 281494676a x11: Send a restored event before entering fullscreen
Ensures that the maximized flag is cleared on fullscreen windows.

(cherry picked from commit ca613b9d8f)
2025-04-03 17:02:43 -04:00
Frank Praznik 413b55deb7 x11: Don't set the hidden flag when minimizing windows
On non-compositing window managers, XIconifyWindow can trigger map/unmap events, which would toggle the window hidden/shown state. This should not be done, as a hidden window in SDL is equivalent to a withdrawn window in X, and SDL will try to set/reset state when it is shown again.

Unless the window is explicitly being withdrawn via X11_HideWindow(), set unmapped windows to the minimized/occluded state, and send a restored event when mapped again.

(cherry picked from commit 667b706a93)
2025-04-03 16:53:33 -04:00
Sam Lantinga 8222513f63 Added special handling for SDL_HINT_ANDROID_ALLOW_RECREATE_ACTIVITY
This hint needs to persist outside of the normal application flow, so use the environment to set the initial value, and then save the value set via SDL_SetHint() after that.

Fixes https://github.com/libsdl-org/SDL/issues/12677

(cherry picked from commit 6bb16296b0)
2025-04-03 11:34:03 -07:00
Sam Lantinga 2dd20ce8e7 Fixed building for Xbox One
Fixes https://github.com/libsdl-org/SDL/issues/12714

(cherry picked from commit 756b455d3a)
2025-04-03 09:10:01 -07:00
SDL Wiki Bot d308df6d62 Sync SDL3 wiki -> header
[ci skip]

(cherry picked from commit 008690d016)
2025-04-03 08:54:27 -07:00
Sam Lantinga f51b88e6b5 Note that you might get a different size window than you expect
(cherry picked from commit df32827407)
2025-04-03 08:54:27 -07:00
Sam Lantinga 7cb0fa5c56 Fixed documentation for SDL_GL_*_SIZE
(cherry picked from commit ab34ea5a26)
2025-04-02 22:32:39 -07:00
Sam Lantinga 976c92a2fb Added support for the HORI Taiko No Tatsujin Drum Controller
(cherry picked from commit 82b245d13a)
2025-04-02 08:30:55 -07:00
Frank Praznik 15db51d7ff cocoa: Ignore both clicks and motion on tooltip windows
(cherry picked from commit ad2584813f)
2025-04-01 22:50:33 -04:00
Frank Praznik 4aa4e6a18e x11: Enable legacy synchronization for external window resize and move events
External windows often handle their own events, and SDL implicitly processing events during synchronization can be unexpected and cause issues. For requests that don't change the window state beyond size or position, use the legacy synchronization method that synthesizes events from the window attributes without processing events.

(cherry picked from commit 6e2d3c9b5d)
2025-04-01 21:34:34 -04:00
Sam Lantinga 0759f22a91 More clarification for high DPI support
(cherry picked from commit 4de396734d)
2025-03-31 18:53:57 -07:00
Sam Lantinga 02036ee643 Fixed texture colorspace when creating a texture from a surface
Fixes https://github.com/libsdl-org/SDL/issues/12691

(cherry picked from commit 36fc1c2c9c)
2025-03-31 18:50:45 -07:00
blukai 9109e05f3f fix vulkan vertex buffer indexing
this was causing problems when i was specifying non-zero buffer slots in
`SDL_BindGPUVertexBuffers`, `SDL_GPUVertexAttribute` and
`SDL_GPUVertexBufferDescription`.

`firstSlot + 1` is simply copied over from metal and d3d12 backends.

(cherry picked from commit 512485869c)
2025-03-31 18:42:03 -07:00
Sam Lantinga 2103451d00 Clarify high DPI support and best practices
(cherry picked from commit 2e494fda30)
2025-03-31 16:49:55 -07:00
Sam Lantinga b6db091d60 Fixed A/B/X/Y buttons on Nintendo 3DS
Fixes https://github.com/libsdl-org/SDL/issues/12690

(cherry picked from commit 44faac2921)
2025-03-31 15:38:16 -07:00
Sam Lantinga 9827653c38 Updated to version 3.2.11 for development 2025-03-31 13:54:19 -07:00
108 changed files with 2448 additions and 1116 deletions

No files matched your search

+5 -5
View File
@@ -5,7 +5,7 @@ if(NOT DEFINED CMAKE_BUILD_TYPE)
endif()
# See docs/release_checklist.md
project(SDL3 LANGUAGES C VERSION "3.2.10")
project(SDL3 LANGUAGES C VERSION "3.2.16")
if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
set(SDL3_MAINPROJECT ON)
@@ -1291,8 +1291,8 @@ if(ANDROID)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake/android")
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/core/android/*.c")
sdl_sources("${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c")
set_property(SOURCE "${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c" APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-declaration-after-statement")
sdl_sources("${CMAKE_ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c")
set_property(SOURCE "${CMAKE_ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c" APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-declaration-after-statement")
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/misc/android/*.c")
set(HAVE_SDL_MISC TRUE)
@@ -3017,7 +3017,7 @@ if(SDL_GPU)
set(SDL_GPU_D3D11 1)
set(HAVE_SDL_GPU TRUE)
endif()
if(SDL_RENDER_D3D12)
if(WINDOWS)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/gpu/d3d12/*.c")
set(SDL_GPU_D3D12 1)
set(HAVE_SDL_GPU TRUE)
@@ -3288,7 +3288,7 @@ else()
endif()
if(ANDROID)
sdl_include_directories(PRIVATE SYSTEM "${ANDROID_NDK}/sources/android/cpufeatures")
sdl_include_directories(PRIVATE SYSTEM "${CMAKE_ANDROID_NDK}/sources/android/cpufeatures")
endif()
if(APPLE)
+2 -2
View File
@@ -168,8 +168,8 @@
</Link>
<PreBuildEvent>
<Command>
call $(ProjectDir)..\..\src\render\direct3d12\compile_shaders_xbox.bat $(ProjectDir)..\
call $(ProjectDir)..\..\src\gpu\d3d12\compile_shaders_xbox.bat $(ProjectDir)..\
call "$(ProjectDir)..\..\src\render\direct3d12\compile_shaders_xbox.bat" "$(ProjectDir)..\"
call "$(ProjectDir)..\..\src\gpu\d3d12\compile_shaders_xbox.bat" "$(ProjectDir)..\"
</Command>
</PreBuildEvent>
<PreBuildEvent>
+2 -2
View File
@@ -19,10 +19,10 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>3.2.10</string>
<string>3.2.16</string>
<key>CFBundleSignature</key>
<string>SDLX</string>
<key>CFBundleVersion</key>
<string>3.2.10</string>
<string>3.2.16</string>
</dict>
</plist>
+4 -4
View File
@@ -3086,7 +3086,7 @@
CLANG_ENABLE_OBJC_ARC = YES;
DEPLOYMENT_POSTPROCESSING = YES;
DYLIB_COMPATIBILITY_VERSION = 201.0.0;
DYLIB_CURRENT_VERSION = 201.10.0;
DYLIB_CURRENT_VERSION = 201.16.0;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_ALTIVEC_EXTENSIONS = YES;
@@ -3121,7 +3121,7 @@
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 3.2.10;
MARKETING_VERSION = 3.2.16;
OTHER_LDFLAGS = "$(CONFIG_FRAMEWORK_LDFLAGS)";
PRODUCT_BUNDLE_IDENTIFIER = org.libsdl.SDL3;
PRODUCT_NAME = SDL3;
@@ -3150,7 +3150,7 @@
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
DYLIB_COMPATIBILITY_VERSION = 201.0.0;
DYLIB_CURRENT_VERSION = 201.10.0;
DYLIB_CURRENT_VERSION = 201.16.0;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
@@ -3182,7 +3182,7 @@
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 3.2.10;
MARKETING_VERSION = 3.2.16;
ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = "$(CONFIG_FRAMEWORK_LDFLAGS)";
PRODUCT_BUNDLE_IDENTIFIER = org.libsdl.SDL3;
+1 -1
View File
@@ -1,4 +1,4 @@
Title SDL 3.2.10
Title SDL 3.2.16
Version 1
Description SDL Library for macOS (http://www.libsdl.org)
DefaultLocation /Library/Frameworks
@@ -92,7 +92,7 @@ if(NOT TARGET SDL3::Headers)
add_library(SDL3::Headers INTERFACE IMPORTED)
set_target_properties(SDL3::Headers
PROPERTIES
INTERFACE_COMPILE_OPTIONS "SHELL:-F \"${_sdl3_framework_parent_path}\""
INTERFACE_COMPILE_OPTIONS "-F${_sdl3_framework_parent_path}"
)
endif()
set(SDL3_Headers_FOUND TRUE)
+2
View File
@@ -51,6 +51,8 @@
boolean supportsRelativeMouse();
int openFileDescriptor(java.lang.String, java.lang.String);
boolean showFileDialog(java.lang.String[], boolean, boolean, int);
java.lang.String getPreferredLocales();
java.lang.String formatLocale(java.util.Locale);
}
-keep,includedescriptorclasses,allowoptimization class org.libsdl.app.HIDDeviceManager {
@@ -23,6 +23,7 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.LocaleList;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.util.DisplayMetrics;
@@ -60,7 +61,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 = 10;
private static final int SDL_MICRO_VERSION = 16;
/*
// Display InputType.SOURCE/CLASS of events and devices
//
@@ -2116,6 +2117,44 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
int requestCode;
boolean multipleChoice;
}
/**
* This method is called by SDL using JNI.
*/
public static String getPreferredLocales() {
String result = "";
if (Build.VERSION.SDK_INT >= 24 /* Android 7 (N) */) {
LocaleList locales = LocaleList.getAdjustedDefault();
for (int i = 0; i < locales.size(); i++) {
if (i != 0) result += ",";
result += formatLocale(locales.get(i));
}
} else if (mCurrentLocale != null) {
result = formatLocale(mCurrentLocale);
}
return result;
}
public static String formatLocale(Locale locale) {
String result = "";
String lang = "";
if (locale.getLanguage() == "in") {
// Indonesian is "id" according to ISO 639.2, but on Android is "in" because of Java backwards compatibility
lang = "id";
} else if (locale.getLanguage() == "") {
// Make sure language is never empty
lang = "und";
} else {
lang = locale.getLanguage();
}
if (locale.getCountry() == "") {
result = lang;
} else {
result = lang + "_" + locale.getCountry();
}
return result;
}
}
/**
+63 -15
View File
@@ -424,7 +424,11 @@ sub dewikify_chunk {
$str .= "\n```$codelang\n$code\n```\n";
}
} elsif ($dewikify_mode eq 'manpage') {
$str =~ s/\./\\[char46]/gms; # make sure these can't become control codes.
# make sure these can't become part of roff syntax.
$str =~ s/\./\\[char46]/gms;
$str =~ s/"/\\(dq/gms;
$str =~ s/'/\\(aq/gms;
if ($wikitype eq 'mediawiki') {
# Dump obvious wikilinks.
if (defined $apiprefixregex) {
@@ -449,33 +453,52 @@ sub dewikify_chunk {
# bullets
$str =~ s/^\* /\n\\\(bu /gm;
} elsif ($wikitype eq 'md') {
# bullets
$str =~ s/^\- /\n\\(bu /gm;
# merge paragraphs
$str =~ s/^[ \t]+//gm;
$str =~ s/([^\-\n])\n([^\-\n])/$1 $2/g;
$str =~ s/\n\n/\n.PP\n/g;
# Dump obvious wikilinks.
if (defined $apiprefixregex) {
$str =~ s/\[(\`?$apiprefixregex[a-zA-Z0-9_]+\`?)\]\($apiprefixregex[a-zA-Z0-9_]+\)/\n.BR $1\n/gms;
my $apr = $apiprefixregex;
if(!($apr =~ /\A\(.*\)\Z/s)) {
# we're relying on the apiprefixregex having a capturing group.
$apr = "(" . $apr . ")";
}
$str =~ s/(\S*?)\[\`?($apr[a-zA-Z0-9_]+)\`?\]\($apr[a-zA-Z0-9_]+\)(\S*)\s*/\n.BR "" "$1" "$2" "$5"\n/gm;
# handle cases like "[x](x), [y](y), [z](z)" being separated.
while($str =~ s/(\.BR[^\n]*)\n\n\.BR/$1\n.BR/gm) {}
}
# links
$str =~ s/\[(.*?)]\((https?\:\/\/.*?)\)/\n.URL "$2" "$1"\n/g;
# <code></code> is also popular. :/
$str =~ s/\s*\`(.*?)\`\s*/\n.BR $1\n/gms;
$str =~ s/\s*(\S*?)\`([^\n]*?)\`(\S*)\s*/\n.BR "" "$1" "$2" "$3"\n/gms;
# bold+italic (this looks bad, just make it bold).
$str =~ s/\s*\*\*\*(.*?)\*\*\*\s*/\n.B $1\n/gms;
$str =~ s/\s*(\S*?)\*\*\*([^\n]*?)\*\*\*(\S*)\s*/\n.BR "" "$1" "$2" "$3"\n/gms;
# bold
$str =~ s/\s*\*\*(.*?)\*\*\s*/\n.B $1\n/gms;
$str =~ s/\s*(\S*?)\*\*([^\n]*?)\*\*(\S*)\s*/\n.BR "" "$1" "$2" "$3"\n/gms;
# italic
$str =~ s/\s*\*(.*?)\*\s*/\n.I $1\n/gms;
# bullets
$str =~ s/^\- /\n\\\(bu /gm;
$str =~ s/\s*(\S*?)\*([^\n]*?)\*(\S*)\s*/\n.IR "" "$1" "$2" "$3"\n/gms;
}
# cleanup unnecessary quotes
$str =~ s/(\.[IB]R?)(.*?) ""\n/$1$2\n/gm;
$str =~ s/(\.[IB]R?) "" ""(.*?)\n/$1$2\n/gm;
$str =~ s/"(\S+)"/$1/gm;
# cleanup unnecessary whitespace
$str =~ s/ +\n/\n/gm;
if (defined $code) {
$code =~ s/\A\n+//gms;
$code =~ s/\n+\Z//gms;
$code =~ s/\\/\\(rs/gms;
if ($dewikify_manpage_code_indent) {
$str .= "\n.IP\n"
} else {
@@ -580,7 +603,7 @@ sub dewikify {
$retval .= dewikify_chunk($wikitype, $1, $2, $3);
}
} elsif ($wikitype eq 'md') {
while ($str =~ s/\A(.*?)\n```(.*?)\n(.*?)\n```\n//ms) {
while ($str =~ s/\A(.*?)\n?```(.*?)\n(.*?)\n```\n//ms) {
$retval .= dewikify_chunk($wikitype, $1, $2, $3);
}
}
@@ -2765,7 +2788,6 @@ __EOF__
my $wikitype = $wikitypes{$sym};
my $sectionsref = $wikisyms{$sym};
my $remarks = $sectionsref->{'Remarks'};
my $params = $sectionsref->{'Function Parameters'};
my $returns = $sectionsref->{'Return Value'};
my $version = $sectionsref->{'Version'};
my $threadsafety = $sectionsref->{'Thread Safety'};
@@ -2773,6 +2795,23 @@ __EOF__
my $examples = $sectionsref->{'Code Examples'};
my $deprecated = $sectionsref->{'Deprecated'};
my $headerfile = $manpageheaderfiletext;
my $params = undef;
if ($symtype == -1) { # category documentation block.
# nothing to be done here.
} elsif (($symtype == 1) || (($symtype == 5))) { # we'll assume a typedef (5) with a \param is a function pointer typedef.
$params = $sectionsref->{'Function Parameters'};
} elsif ($symtype == 2) {
$params = $sectionsref->{'Macro Parameters'};
} elsif ($symtype == 3) {
$params = $sectionsref->{'Fields'};
} elsif ($symtype == 4) {
$params = $sectionsref->{'Values'};
} else {
die("Unexpected symtype $symtype");
}
$headerfile =~ s/\%fname\%/$headersymslocation{$sym}/g;
$headerfile .= "\n";
@@ -2839,18 +2878,22 @@ __EOF__
$str .= dewikify($wikitype, $deprecated) . "\n";
}
my $incfile = $mainincludefname;
if (defined $headerfile) {
$str .= ".SH HEADER FILE\n";
$str .= dewikify($wikitype, $headerfile) . "\n";
if($headerfile =~ /Defined in (.*)/) {
$incfile = $1;
}
}
$str .= ".SH SYNOPSIS\n";
$str .= ".nf\n";
$str .= ".B #include \\(dq$mainincludefname\\(dq\n";
$str .= ".B #include <$incfile>\n";
$str .= ".PP\n";
my @decllines = split /\n/, $decl;
foreach (@decllines) {
$_ =~ s/\\/\\(rs/g; # fix multiline macro defs
$_ =~ s/"/\\(dq/g;
$str .= ".BI \"$_\n";
}
$str .= ".fi\n";
@@ -2938,8 +2981,11 @@ __EOF__
}
if (defined $returns) {
# Chop datatype in parentheses off the front.
if(!($returns =~ s/\A\([^\[]*\[[^\]]*\]\([^\)]*\)[^\)]*\) //ms)) {
$returns =~ s/\A\([^\)]*\) //ms;
}
$returns = dewikify($wikitype, $returns);
$returns =~ s/\A\(.*?\)\s*//; # Chop datatype in parentheses off the front.
$str .= ".SH RETURN VALUE\n";
$str .= "$returns\n";
}
@@ -2975,6 +3021,8 @@ __EOF__
s/\A\/*//;
s/\A\.BR\s+//; # dewikify added this, but we want to handle it.
s/\A\.I\s+//; # dewikify added this, but we want to handle it.
s/\A\.PP\s*//; # dewikify added this, but we want to handle it.
s/\\\(bu//; # dewikify added this, but we want to handle it.
s/\A\s*[\:\*\-]\s*//;
s/\A\s+//;
s/\s+\Z//;
+30 -26
View File
@@ -1,32 +1,6 @@
SDL 3.0 has new support for high DPI displays. Interfaces provided by SDL uses the platform's native coordinates unless otherwise specified.
To reconcile platform differences in their approach to high-density scaling, SDL provides the following interfaces:
- `SDL_GetWindowSize()` retrieves the window dimensions in native coordinates.
- `SDL_GetWindowSizeInPixels()` retrieves the window dimensions in pixels-addressable.
- `SDL_GetDisplayContentScale()` retrieves the suggested amplification factor when drawing in native coordinates.
- `SDL_GetWindowDisplayScale()` retrieves the suggested amplification factor when drawing in pixels-addressable.
- `SDL_GetWindowPixelDensity()` retrieves how many addressable pixels correspond to one unit of native coordinates.
- `SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED` is emitted when the value retrievable from `SDL_GetWindowSizeInPixels()` changes.
- `SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED` is emitted when the value retrievable from `SDL_GetWindowDisplayScale()` changes.
- Windows created with `SDL_WINDOW_HIGH_PIXEL_DENSITY` will ask the platform to display addressable pixels at their natural scale.
## Numeric example
Given a fullscreen window spanning a 3840x2160 monitor set to 2x display or 200% scaling, the following tabulates the effect of creating a window with or without `SDL_WINDOW_HIGH_PIXEL_DENSITY` on MacOS and Win32:
| Value | MacOS (Default) | MacOS (HD) | Win32 (Default & HD) |
|--------------------------------|-----------------|------------|----------------------|
| `SDL_GetWindowSize()` | 1920x1080 | 1920x1080 | 3840x2160 |
| `SDL_GetWindowSizeInPixels()` | 1920x1080 | 3840x2160 | 3840x2160 |
| `SDL_GetDisplayContentScale()` | 1.0 | 1.0 | 2.0 |
| `SDL_GetWindowDisplayScale()` | 1.0 | 2.0 | 2.0 |
| `SDL_GetWindowPixelDensity()` | 1.0 | 2.0 | 1.0 |
Observe the philosophical difference between the approaches taken by MacOS and Win32:
- Win32 coordinate system always deals in physical device pixels, high DPI support is achieved by providing an advisory hint for the developer to enlarge drawn objects. Ignoring the advisory scale factor results in graphics appearing tiny.
- MacOS coordinate system always deals in physical content sizes, high DPI support is achieved by providing an optional flag for the developer to request finer granularity. Omitting the granularity request results in graphics appearing coarse.
## Explanation
Displays now have a content display scale, which is the expected scale for content based on the DPI settings of the display. For example, a 4K display might have a 2.0 (200%) display scale, which means that the user expects UI elements to be twice as big on this display, to aid in readability. You can query the display content scale using `SDL_GetDisplayContentScale()`, and when this changes you get an `SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED` event.
@@ -34,3 +8,33 @@ Displays now have a content display scale, which is the expected scale for conte
The window size is now distinct from the window pixel size, and the ratio between the two is the window pixel density. If the window is created with the `SDL_WINDOW_HIGH_PIXEL_DENSITY` flag, SDL will try to match the native pixel density for the display, otherwise it will try to have the pixel size match the window size. You can query the window pixel density using `SDL_GetWindowPixelDensity()`. You can query the window pixel size using `SDL_GetWindowSizeInPixels()`, and when this changes you get an `SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED` event. You are guaranteed to get a `SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED` event when a window is created and resized, and you can use this event to create and resize your graphics context for the window.
The window has a display scale, which is the scale from the pixel resolution to the desired content size, e.g. the combination of the pixel density and the content scale. For example, a 3840x2160 window displayed at 200% on Windows, and a 1920x1080 window with the high density flag on a 2x display on macOS will both have a pixel size of 3840x2160 and a display scale of 2.0. You can query the window display scale using `SDL_GetWindowDisplayScale()`, and when this changes you get an `SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED` event.
## Numeric example
Given a window spanning a 3840x2160 monitor set to 2x display or 200% scaling, the following tabulates the effect of creating a window with or without `SDL_WINDOW_HIGH_PIXEL_DENSITY` on macOS and Windows:
| Value | macOS (Default) | macOS (HD) | Windows (Default & HD) |
|--------------------------------|-----------------|------------|------------------------|
| `SDL_GetWindowSize()` | 1920x1080 | 1920x1080 | 3840x2160 |
| `SDL_GetWindowSizeInPixels()` | 1920x1080 | 3840x2160 | 3840x2160 |
| `SDL_GetDisplayContentScale()` | 1.0 | 1.0 | 2.0 |
| `SDL_GetWindowDisplayScale()` | 1.0 | 2.0 | 2.0 |
| `SDL_GetWindowPixelDensity()` | 1.0 | 2.0 | 1.0 |
Observe the difference between the approaches taken by macOS and Windows:
- The Windows and Android coordinate system always deals in physical device pixels, high DPI support is achieved by providing a content scale that tells the developer to draw objects larger. Ignoring this scale factor results in graphics appearing tiny.
- The macOS and iOS coordinate system always deals in window coordinates, high DPI support is achieved by providing an optional flag for the developer to request more pixels. Omitting this flag results in graphics having low detail.
- On Linux, X11 uses a similar approach to Windows and Wayland uses a similar approach to macOS.
## Solution
Proper high DPI support takes into account both the content scale and the pixel density.
First, you'd create your window with the `SDL_WINDOW_HIGH_PIXEL_DENSITY` flag, assuming you want the highest detail possible. Then you'd get the window display scale to see how much your UI elements should be enlarged to be readable.
If you're using the SDL 2D renderer, SDL provides the function `SDL_ConvertEventToRenderCoordinates()` to convert mouse coordinates between window coordinates and rendering coordinates, and the more general functions `SDL_RenderCoordinatesFromWindow()` and `SDL_RenderCoordinatesToWindow()` to do other conversion between them.
If you're not using the 2D renderer, you can implement this yourself using `SDL_GetWindowPixelDensity()` as scale factor to convert from window coordinates to pixels.
Finally you'll want to test on both Windows and macOS if possible to make sure your high DPI support works in all environments.
+1 -1
View File
@@ -11,7 +11,7 @@
- [macOS](README-macos.md)
- [NetBSD](README-bsd.md)
- [Nintendo Switch](README-switch.md)
- [Nintendo 3DS](README-3ds.md)
- [Nintendo 3DS](README-n3ds.md)
- [OpenBSD](README-bsd.md)
- [PlayStation 2](README-ps2.md)
- [PlayStation 4](README-ps4.md)
+28 -40
View File
@@ -1,60 +1,48 @@
# Versioning
## Since 2.23.0
## Since 3.2.0
SDL follows an "odd/even" versioning policy, similar to GLib, GTK, Flatpak
and older versions of the Linux kernel:
* The major version (first part) increases when backwards compatibility
is broken, which will happen infrequently.
* If the minor version (second part) is divisible by 2
(for example 2.24.x, 2.26.x), this indicates a version of SDL that
is believed to be stable and suitable for production use.
* If the minor version (second part) and the patch version (third part) is
divisible by 2 (for example 3.2.6, 3.4.0), this indicates a version of
SDL that is believed to be stable and suitable for production use.
* In stable releases, the patchlevel or micro version (third part)
indicates bugfix releases. Bugfix releases should not add or
remove ABI, so the ".0" release (for example 2.24.0) should be
forwards-compatible with all the bugfix releases from the
same cycle (for example 2.24.1).
indicates bugfix releases. Bugfix releases may add small changes
to the ABI, so newer patch versions are backwards-compatible but
not fully forwards-compatible. For example, programs built against
SDL 3.2.0 should work fine with SDL 3.2.8, but programs built against
SDL 3.2.8 may not work with 3.2.0.
* The minor version increases when new API or ABI is added, or when
other significant changes are made. Newer minor versions are
backwards-compatible, but not fully forwards-compatible.
For example, programs built against SDL 2.24.x should work fine
with SDL 2.26.x, but programs built against SDL 2.26.x will not
necessarily work with 2.24.x.
* The minor version increases when significant changes are made that
require longer development or testing time, e.g. major new functionality,
or revamping support for a platform. Newer minor versions are
backwards-compatible, but not fully forwards-compatible. For example,
programs built against SDL 3.2.x should work fine with SDL 3.4.x,
but programs built against SDL 3.4.x may not work with 3.2.x.
* If the minor version (second part) is not divisible by 2
(for example 2.23.x, 2.25.x), this indicates a development prerelease
of SDL that is not suitable for stable software distributions.
* If the minor version (second part) or patch version (third part) is not
divisible by 2 (for example 3.2.9, 3.3.x), this indicates a development
prerelease of SDL that is not suitable for stable software distributions.
Use with caution.
* The patchlevel or micro version (third part) increases with
each prerelease.
* Each prerelease might add new API and/or ABI.
* The patchlevel or micro version (third part) increases with each prerelease.
* Prereleases are backwards-compatible with older stable branches.
For example, 2.25.x will be backwards-compatible with 2.24.x.
For example, programs built against SDL 3.2.x should work fine with
SDL 3.3.x, but programs built against SDL 3.3.x may not work with 3.2.x.
* Prereleases are not guaranteed to be backwards-compatible with
each other. For example, new API or ABI added in 2.25.1
might be removed or changed in 2.25.2.
If this would be a problem for you, please do not use prereleases.
* Prereleases are not guaranteed to be backwards-compatible with each other.
For example, new API or ABI added in 3.3.0 might be removed or changed in
3.3.1. If this would be a problem for you, please do not use prereleases.
* Only upgrade to a prerelease if you can guarantee that you will
promptly upgrade to the stable release that follows it.
For example, do not upgrade to 2.23.x unless you will be able to
upgrade to 2.24.0 when it becomes available.
* Only use a prerelease if you can guarantee that you will promptly upgrade
to the stable release that follows it. For example, do not use 3.3.x
unless you will be able to upgrade to 3.4.0 when it becomes available.
* Software distributions that have a freeze policy (in particular Linux
distributions with a release cycle, such as Debian and Fedora)
should usually only package stable releases, and not prereleases.
should only package stable releases, and not prereleases.
## Before 2.23.0
Older versions of SDL followed a similar policy, but instead of the
odd/even rule applying to the minor version, it applied to the patchlevel
(micro version, third part). For example, 2.0.22 was a stable release
and 2.0.21 was a prerelease.
+1 -1
View File
@@ -20,7 +20,7 @@
*/
/**
* Main include header for the SDL library, version 3.2.10
* Main include header for the SDL library, version 3.2.16
*
* It is almost always best to include just this one header instead of
* picking out individual headers included here. There are exceptions to
+2
View File
@@ -492,6 +492,8 @@ typedef struct SDL_MouseWheelEvent
SDL_MouseWheelDirection direction; /**< Set to one of the SDL_MOUSEWHEEL_* defines. When FLIPPED the values in X and Y will be opposite. Multiply by -1 to change them back */
float mouse_x; /**< X coordinate, relative to window */
float mouse_y; /**< Y coordinate, relative to window */
Sint32 integer_x; /**< The amount scrolled horizontally, accumulated to whole scroll "ticks" (added in 3.2.12) */
Sint32 integer_y; /**< The amount scrolled vertically, accumulated to whole scroll "ticks" (added in 3.2.12) */
} SDL_MouseWheelEvent;
/**
+10 -10
View File
@@ -2467,9 +2467,9 @@ extern SDL_DECLSPEC SDL_GPUShader * SDLCALL SDL_CreateGPUShader(
* - `SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_DEPTH_FLOAT`: (Direct3D 12 only)
* if the texture usage is SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET, clear
* the texture to a depth of this value. Defaults to zero.
* - `SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_UINT8`: (Direct3D 12
* - `SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_NUMBER`: (Direct3D 12
* only) if the texture usage is SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET,
* clear the texture to a stencil of this value. Defaults to zero.
* clear the texture to a stencil of this Uint8 value. Defaults to zero.
* - `SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING`: a name that can be displayed
* in debugging tools.
*
@@ -2495,13 +2495,13 @@ extern SDL_DECLSPEC SDL_GPUTexture * SDLCALL SDL_CreateGPUTexture(
SDL_GPUDevice *device,
const SDL_GPUTextureCreateInfo *createinfo);
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_R_FLOAT "SDL.gpu.texture.create.d3d12.clear.r"
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_G_FLOAT "SDL.gpu.texture.create.d3d12.clear.g"
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_B_FLOAT "SDL.gpu.texture.create.d3d12.clear.b"
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_A_FLOAT "SDL.gpu.texture.create.d3d12.clear.a"
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_DEPTH_FLOAT "SDL.gpu.texture.create.d3d12.clear.depth"
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_UINT8 "SDL.gpu.texture.create.d3d12.clear.stencil"
#define SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING "SDL.gpu.texture.create.name"
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_R_FLOAT "SDL.gpu.texture.create.d3d12.clear.r"
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_G_FLOAT "SDL.gpu.texture.create.d3d12.clear.g"
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_B_FLOAT "SDL.gpu.texture.create.d3d12.clear.b"
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_A_FLOAT "SDL.gpu.texture.create.d3d12.clear.a"
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_DEPTH_FLOAT "SDL.gpu.texture.create.d3d12.clear.depth"
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_NUMBER "SDL.gpu.texture.create.d3d12.clear.stencil"
#define SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING "SDL.gpu.texture.create.name"
/**
* Creates a buffer object to be used in graphics or compute workflows.
@@ -3775,7 +3775,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_ReleaseWindowFromGPUDevice(
* supported via SDL_WindowSupportsGPUPresentMode /
* SDL_WindowSupportsGPUSwapchainComposition prior to calling this function.
*
* SDL_GPU_PRESENTMODE_VSYNC and SDL_GPU_SWAPCHAINCOMPOSITION_SDR are always
* SDL_GPU_PRESENTMODE_VSYNC with SDL_GPU_SWAPCHAINCOMPOSITION_SDR are always
* supported.
*
* \param device a GPU context.
+4 -4
View File
@@ -1074,8 +1074,8 @@ extern "C" {
*
* By default, SDL will try all available GPU backends in a reasonable order
* until it finds one that can work, but this hint allows the app or user to
* force a specific target, such as "direct3d11" if, say, your hardware
* supports D3D12 but want to try using D3D11 instead.
* force a specific target, such as "direct3d12" if, say, your hardware
* supports Vulkan but you want to try using D3D12 instead.
*
* This hint should be set before any GPU functions are called.
*
@@ -2026,8 +2026,8 @@ extern "C" {
*
* The variable can be set to the following values:
*
* - "0": RAWINPUT drivers are not used.
* - "1": RAWINPUT drivers are used. (default)
* - "0": RAWINPUT drivers are not used. (default)
* - "1": RAWINPUT drivers are used.
*
* This hint should be set before SDL is initialized.
*
+1 -1
View File
@@ -79,7 +79,7 @@ typedef Uint32 SDL_InitFlags;
#define SDL_INIT_AUDIO 0x00000010u /**< `SDL_INIT_AUDIO` implies `SDL_INIT_EVENTS` */
#define SDL_INIT_VIDEO 0x00000020u /**< `SDL_INIT_VIDEO` implies `SDL_INIT_EVENTS`, should be initialized on the main thread */
#define SDL_INIT_JOYSTICK 0x00000200u /**< `SDL_INIT_JOYSTICK` implies `SDL_INIT_EVENTS`, should be initialized on the same thread as SDL_INIT_VIDEO on Windows if you don't set SDL_HINT_JOYSTICK_THREAD */
#define SDL_INIT_JOYSTICK 0x00000200u /**< `SDL_INIT_JOYSTICK` implies `SDL_INIT_EVENTS` */
#define SDL_INIT_HAPTIC 0x00001000u
#define SDL_INIT_GAMEPAD 0x00002000u /**< `SDL_INIT_GAMEPAD` implies `SDL_INIT_JOYSTICK` */
#define SDL_INIT_EVENTS 0x00004000u
+1 -1
View File
@@ -517,7 +517,7 @@ typedef enum SDL_PackedLayout
* ABGR32, define a platform-independent encoding into bytes in the order
* specified. For example, in RGB24 data, each pixel is encoded in 3 bytes
* (red, green, blue) in that order, and in ABGR32 data, each pixel is
* encoded in 4 bytes alpha, blue, green, red) in that order. Use these
* encoded in 4 bytes (alpha, blue, green, red) in that order. Use these
* names if the property of a format that is important to you is the order
* of the bytes in memory or on disk.
* - Names with a bit count per component, such as ARGB8888 and XRGB1555, are
+1 -2
View File
@@ -1607,8 +1607,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderViewport(SDL_Renderer *renderer, S
* Return whether an explicit rectangle was set as the viewport.
*
* This is useful if you're saving and restoring the viewport and want to know
* whether you should restore a specific rectangle or NULL. Note that the
* viewport is always reset when changing rendering targets.
* whether you should restore a specific rectangle or NULL.
*
* Each render target has its own viewport. This function checks the viewport
* for the current render target.
+6 -2
View File
@@ -4656,7 +4656,7 @@ extern SDL_DECLSPEC float SDLCALL SDL_atanf(float x);
*
* Domain: `-INF <= x <= INF`, `-INF <= y <= INF`
*
* Range: `-Pi/2 <= y <= Pi/2`
* Range: `-Pi <= y <= Pi`
*
* This function operates on double-precision floating point values, use
* SDL_atan2f for single-precision floats.
@@ -4692,7 +4692,7 @@ extern SDL_DECLSPEC double SDLCALL SDL_atan2(double y, double x);
*
* Domain: `-INF <= x <= INF`, `-INF <= y <= INF`
*
* Range: `-Pi/2 <= y <= Pi/2`
* Range: `-Pi <= y <= Pi`
*
* This function operates on single-precision floating point values, use
* SDL_atan2 for double-precision floats.
@@ -5974,8 +5974,12 @@ size_t wcslcpy(wchar_t *dst, const wchar_t *src, size_t size);
size_t wcslcat(wchar_t *dst, const wchar_t *src, size_t size);
#endif
#ifndef _WIN32
/* strdup is not ANSI but POSIX, and its prototype might be hidden... */
/* not for windows: might conflict with string.h where strdup may have
* dllimport attribute: https://github.com/libsdl-org/SDL/issues/12948 */
char *strdup(const char *str);
#endif
/* Starting LLVM 16, the analyser errors out if these functions do not have
their prototype defined (clang-diagnostic-implicit-function-declaration) */
+3 -5
View File
@@ -1135,9 +1135,6 @@ extern SDL_DECLSPEC bool SDLCALL SDL_FillSurfaceRects(SDL_Surface *dst, const SD
* If either `srcrect` or `dstrect` are NULL, the entire surface (`src` or
* `dst`) is copied while ensuring clipping to `dst->clip_rect`.
*
* The final blit rectangles are saved in `srcrect` and `dstrect` after all
* clipping is performed.
*
* The blit function should not be called on a locked surface.
*
* The blit semantics for surfaces with and without blending and colorkey are
@@ -1282,10 +1279,11 @@ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurfaceUncheckedScaled(SDL_Surface *src
*
* \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.
* copied, or NULL to copy the entire surface.
* \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.
* the destination surface, or NULL to fill the entire
* destination surface.
* \param scaleMode the SDL_ScaleMode to be used.
* \returns true on success or false on failure; call SDL_GetError() for more
* information.
+1 -1
View File
@@ -62,7 +62,7 @@ extern "C" {
*
* \since This macro is available since SDL 3.2.0.
*/
#define SDL_MICRO_VERSION 10
#define SDL_MICRO_VERSION 16
/**
* This macro turns the version numbers into a numeric value.
+16 -4
View File
@@ -426,10 +426,10 @@ typedef SDL_EGLint *(SDLCALL *SDL_EGLIntArrayCallback)(void *userdata, SDL_EGLDi
*/
typedef enum SDL_GLAttr
{
SDL_GL_RED_SIZE, /**< the minimum number of bits for the red channel of the color buffer; defaults to 3. */
SDL_GL_GREEN_SIZE, /**< the minimum number of bits for the green channel of the color buffer; defaults to 3. */
SDL_GL_BLUE_SIZE, /**< the minimum number of bits for the blue channel of the color buffer; defaults to 2. */
SDL_GL_ALPHA_SIZE, /**< the minimum number of bits for the alpha channel of the color buffer; defaults to 0. */
SDL_GL_RED_SIZE, /**< the minimum number of bits for the red channel of the color buffer; defaults to 8. */
SDL_GL_GREEN_SIZE, /**< the minimum number of bits for the green channel of the color buffer; defaults to 8. */
SDL_GL_BLUE_SIZE, /**< the minimum number of bits for the blue channel of the color buffer; defaults to 8. */
SDL_GL_ALPHA_SIZE, /**< the minimum number of bits for the alpha channel of the color buffer; defaults to 8. */
SDL_GL_BUFFER_SIZE, /**< the minimum number of bits for frame buffer size; defaults to 0. */
SDL_GL_DOUBLEBUFFER, /**< whether the output is single or double buffered; defaults to double buffering on. */
SDL_GL_DEPTH_SIZE, /**< the minimum number of bits in the depth buffer; defaults to 16. */
@@ -1041,6 +1041,10 @@ extern SDL_DECLSPEC SDL_Window ** SDLCALL SDL_GetWindows(int *count);
/**
* Create a window with the specified dimensions and flags.
*
* The window size is a request and may be different than expected based on
* the desktop layout and window manager policies. Your application should be
* prepared to handle a window of any size.
*
* `flags` may be any of the following OR'd together:
*
* - `SDL_WINDOW_FULLSCREEN`: fullscreen window at desktop resolution
@@ -1127,6 +1131,10 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreateWindow(const char *title, int
/**
* Create a child popup window of the specified parent window.
*
* The window size is a request and may be different than expected based on
* the desktop layout and window manager policies. Your application should be
* prepared to handle a window of any size.
*
* The flags parameter **must** contain at least one of the following:
*
* - `SDL_WINDOW_TOOLTIP`: The popup window is a tooltip and will not pass any
@@ -1189,6 +1197,10 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreatePopupWindow(SDL_Window *paren
/**
* Create a window with the specified properties.
*
* The window size is a request and may be different than expected based on
* the desktop layout and window manager policies. Your application should be
* prepared to handle a window of any size.
*
* These are the supported properties:
*
* - `SDL_PROP_WINDOW_CREATE_ALWAYS_ON_TOP_BOOLEAN`: true if the window should
+33
View File
@@ -22,6 +22,10 @@
#include "SDL_hints_c.h"
#ifdef SDL_PLATFORM_ANDROID
#include "core/android/SDL_android.h"
#endif
typedef struct SDL_HintWatch
{
SDL_HintCallback callback;
@@ -147,6 +151,13 @@ bool SDL_SetHintWithPriority(const char *name, const char *value, SDL_HintPriori
}
}
#ifdef SDL_PLATFORM_ANDROID
if (SDL_strcmp(name, SDL_HINT_ANDROID_ALLOW_RECREATE_ACTIVITY) == 0) {
// Special handling for this hint, which needs to persist outside the normal application flow
Android_SetAllowRecreateActivity(SDL_GetStringBoolean(value, false));
}
#endif // SDL_PLATFORM_ANDROID
SDL_UnlockProperties(hints);
return result;
@@ -185,6 +196,17 @@ bool SDL_ResetHint(const char *name)
result = true;
}
#ifdef SDL_PLATFORM_ANDROID
if (SDL_strcmp(name, SDL_HINT_ANDROID_ALLOW_RECREATE_ACTIVITY) == 0) {
// Special handling for this hint, which needs to persist outside the normal application flow
if (env) {
Android_SetAllowRecreateActivity(SDL_GetStringBoolean(env, false));
} else {
Android_SetAllowRecreateActivity(false);
}
}
#endif // SDL_PLATFORM_ANDROID
SDL_UnlockProperties(hints);
return result;
@@ -210,6 +232,17 @@ static void SDLCALL ResetHintsCallback(void *userdata, SDL_PropertiesID hints, c
SDL_free(hint->value);
hint->value = NULL;
hint->priority = SDL_HINT_DEFAULT;
#ifdef SDL_PLATFORM_ANDROID
if (SDL_strcmp(name, SDL_HINT_ANDROID_ALLOW_RECREATE_ACTIVITY) == 0) {
// Special handling for this hint, which needs to persist outside the normal application flow
if (env) {
Android_SetAllowRecreateActivity(SDL_GetStringBoolean(env, false));
} else {
Android_SetAllowRecreateActivity(false);
}
}
#endif // SDL_PLATFORM_ANDROID
}
void SDL_ResetHints(void)
+6
View File
@@ -265,6 +265,12 @@ extern "C" {
#include "SDL_utils_c.h"
#include "SDL_hashtable.h"
#define PUSH_SDL_ERROR() \
{ char *_error = SDL_strdup(SDL_GetError());
#define POP_SDL_ERROR() \
SDL_SetError("%s", _error); SDL_free(_error); }
// Do any initialization that needs to happen before threads are started
extern void SDL_InitMainThread(void);
+5 -1
View File
@@ -403,6 +403,10 @@ const char *SDL_GetPersistentString(const char *string)
static int PrefixMatch(const char *a, const char *b)
{
int matchlen = 0;
// Fixes the "HORI HORl Taiko No Tatsujin Drum Controller"
if (SDL_strncmp(a, "HORI ", 5) == 0 && SDL_strncmp(b, "HORl ", 5) == 0) {
return 5;
}
while (*a && *b) {
if (SDL_tolower((unsigned char)*a++) == SDL_tolower((unsigned char)*b++)) {
++matchlen;
@@ -424,8 +428,8 @@ char *SDL_CreateDeviceName(Uint16 vendor, Uint16 product, const char *vendor_nam
{ "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" },
{ "HORI CO.,LTD", "HORI" },
{ "Mad Catz Inc.", "Mad Catz" },
{ "Nintendo Co., Ltd.", "Nintendo" },
{ "NVIDIA Corporation ", "" },
+44 -11
View File
@@ -410,6 +410,7 @@ static SDL_LogicalAudioDevice *ObtainLogicalAudioDevice(SDL_AudioDeviceID devid,
SDL_LockRWLockForReading(current_audio.device_hash_lock);
SDL_FindInHashTable(current_audio.device_hash, (const void *) (uintptr_t) devid, (const void **) &logdev);
if (logdev) {
SDL_assert(logdev->instance_id == devid);
device = logdev->physical_device;
SDL_assert(device != NULL);
RefPhysicalAudioDevice(device); // reference it, in case the logical device migrates to a new default.
@@ -459,6 +460,7 @@ static SDL_AudioDevice *ObtainPhysicalAudioDevice(SDL_AudioDeviceID devid) // !
} else {
SDL_LockRWLockForReading(current_audio.device_hash_lock);
SDL_FindInHashTable(current_audio.device_hash, (const void *) (uintptr_t) devid, (const void **) &device);
SDL_assert(device->instance_id == devid);
SDL_UnlockRWLock(current_audio.device_hash_lock);
if (!device) {
@@ -883,6 +885,7 @@ static bool SDLCALL FindLowestDeviceID(void *userdata, const SDL_HashTable *tabl
if (isphysical && (devid_recording == data->recording) && (devid < data->highest)) {
data->highest = devid;
data->result = (SDL_AudioDevice *) value;
SDL_assert(data->result->instance_id == devid);
}
return true; // keep iterating.
}
@@ -1051,7 +1054,10 @@ static bool SDLCALL DestroyOnePhysicalAudioDevice(void *userdata, const SDL_Hash
const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
const bool isphysical = !!(devid & (1<<1));
if (isphysical) {
DestroyPhysicalAudioDevice((SDL_AudioDevice *) value);
SDL_AudioDevice *dev = (SDL_AudioDevice *) value;
SDL_assert(dev->instance_id == devid);
DestroyPhysicalAudioDevice(dev);
}
return true; // keep iterating.
}
@@ -1464,6 +1470,7 @@ static bool SDLCALL FindAudioDeviceByCallback(void *userdata, const SDL_HashTabl
SDL_AudioDevice *device = (SDL_AudioDevice *) value;
if (data->callback(device, data->userdata)) { // found it?
data->retval = device;
SDL_assert(data->retval->instance_id == devid);
return false; // stop iterating, we found it.
}
}
@@ -1502,12 +1509,33 @@ SDL_AudioDevice *SDL_FindPhysicalAudioDeviceByHandle(void *handle)
const char *SDL_GetAudioDeviceName(SDL_AudioDeviceID devid)
{
// bit #1 of devid is set for physical devices and unset for logical.
const bool islogical = !(devid & (1<<1));
const char *result = NULL;
SDL_AudioDevice *device = ObtainPhysicalAudioDevice(devid);
if (device) {
result = SDL_GetPersistentString(device->name);
const void *vdev = NULL;
if (!SDL_GetCurrentAudioDriver()) {
SDL_SetError("Audio subsystem is not initialized");
} else {
// This does not call ObtainPhysicalAudioDevice() because the device's name never changes, so
// it doesn't have to lock the whole device. However, just to make sure the device pointer itself
// remains valid (in case the device is unplugged at the wrong moment), we hold the
// device_hash_lock while we copy the string.
SDL_LockRWLockForReading(current_audio.device_hash_lock);
SDL_FindInHashTable(current_audio.device_hash, (const void *) (uintptr_t) devid, &vdev);
if (!vdev) {
SDL_SetError("Invalid audio device instance ID");
} else if (islogical) {
const SDL_LogicalAudioDevice *logdev = (const SDL_LogicalAudioDevice *) vdev;
SDL_assert(logdev->instance_id == devid);
result = SDL_GetPersistentString(logdev->physical_device->name);
} else {
const SDL_AudioDevice *device = (const SDL_AudioDevice *) vdev;
SDL_assert(device->instance_id == devid);
result = SDL_GetPersistentString(device->name);
}
SDL_UnlockRWLock(current_audio.device_hash_lock);
}
ReleaseAudioDevice(device);
return result;
}
@@ -1715,13 +1743,18 @@ static bool OpenPhysicalAudioDevice(SDL_AudioDevice *device, const SDL_AudioSpec
SDL_copyp(&spec, inspec ? inspec : &device->default_spec);
PrepareAudioFormat(device->recording, &spec);
/* We allow the device format to change if it's better than the current settings (by various definitions of "better"). This prevents
something low quality, like an old game using S8/8000Hz audio, from ruining a music thing playing at CD quality that tries to open later.
(or some VoIP library that opens for mono output ruining your surround-sound game because it got there first).
/* We impose a simple minimum on device formats. This prevents something low quality, like an old game using S8/8000Hz audio,
from ruining a music thing playing at CD quality that tries to open later, or some VoIP library that opens for mono output
ruining your surround-sound game because it got there first.
These are just requests! The backend may change any of these values during OpenDevice method! */
device->spec.format = (SDL_AUDIO_BITSIZE(device->default_spec.format) >= SDL_AUDIO_BITSIZE(spec.format)) ? device->default_spec.format : spec.format;
device->spec.freq = SDL_max(device->default_spec.freq, spec.freq);
device->spec.channels = SDL_max(device->default_spec.channels, spec.channels);
const SDL_AudioFormat minimum_format = device->recording ? DEFAULT_AUDIO_RECORDING_FORMAT : DEFAULT_AUDIO_PLAYBACK_FORMAT;
const int minimum_channels = device->recording ? DEFAULT_AUDIO_RECORDING_CHANNELS : DEFAULT_AUDIO_PLAYBACK_CHANNELS;
const int minimum_freq = device->recording ? DEFAULT_AUDIO_RECORDING_FREQUENCY : DEFAULT_AUDIO_PLAYBACK_FREQUENCY;
device->spec.format = (SDL_AUDIO_BITSIZE(minimum_format) >= SDL_AUDIO_BITSIZE(spec.format)) ? minimum_format : spec.format;
device->spec.channels = SDL_max(minimum_channels, spec.channels);
device->spec.freq = SDL_max(minimum_freq, spec.freq);
device->sample_frames = SDL_GetDefaultSampleFramesFromFreq(device->spec.freq);
SDL_UpdatedAudioDeviceFormat(device); // start this off sane.
+7 -1
View File
@@ -308,6 +308,12 @@ static bool BuildAAudioStream(SDL_AudioDevice *device)
ctx.AAudioStreamBuilder_setFormat(builder, format);
ctx.AAudioStreamBuilder_setSampleRate(builder, device->spec.freq);
ctx.AAudioStreamBuilder_setChannelCount(builder, device->spec.channels);
// If no specific buffer size has been requested, the device will pick the optimal
if(SDL_GetHint(SDL_HINT_AUDIO_DEVICE_SAMPLE_FRAMES)) {
ctx.AAudioStreamBuilder_setBufferCapacityInFrames(builder, 2 * device->sample_frames); // AAudio requires that the buffer capacity is at least
ctx.AAudioStreamBuilder_setFramesPerDataCallback(builder, device->sample_frames); // twice the size of the data callback buffer size
}
const aaudio_direction_t direction = (recording ? AAUDIO_DIRECTION_INPUT : AAUDIO_DIRECTION_OUTPUT);
ctx.AAudioStreamBuilder_setDirection(builder, direction);
@@ -366,7 +372,7 @@ static bool BuildAAudioStream(SDL_AudioDevice *device)
hidden->processed_bytes = 0;
hidden->callback_bytes = 0;
hidden->semaphore = SDL_CreateSemaphore(recording ? 0 : hidden->num_buffers);
hidden->semaphore = SDL_CreateSemaphore(recording ? 0 : hidden->num_buffers - 1);
if (!hidden->semaphore) {
LOGI("SDL Failed SDL_CreateSemaphore %s recording:%d", SDL_GetError(), recording);
return false;
+1 -1
View File
@@ -31,7 +31,7 @@ SDL_PROC_UNUSED(void, AAudioStreamBuilder_setSamplesPerFrame, (AAudioStreamBuild
SDL_PROC(void, AAudioStreamBuilder_setFormat, (AAudioStreamBuilder * builder, aaudio_format_t format))
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setSharingMode, (AAudioStreamBuilder * builder, aaudio_sharing_mode_t sharingMode))
SDL_PROC(void, AAudioStreamBuilder_setDirection, (AAudioStreamBuilder * builder, aaudio_direction_t direction))
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setBufferCapacityInFrames, (AAudioStreamBuilder * builder, int32_t numFrames))
SDL_PROC(void, AAudioStreamBuilder_setBufferCapacityInFrames, (AAudioStreamBuilder * builder, int32_t numFrames))
SDL_PROC(void, AAudioStreamBuilder_setPerformanceMode, (AAudioStreamBuilder * builder, aaudio_performance_mode_t mode))
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setUsage, (AAudioStreamBuilder * builder, aaudio_usage_t usage)) // API 28
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setContentType, (AAudioStreamBuilder * builder, aaudio_content_type_t contentType)) // API 28
+1 -1
View File
@@ -189,7 +189,7 @@ static bool EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device)
}
// limit to native freq
device->spec.freq = EM_ASM_INT({ return Module['SDL3'].audioContext.sampleRate; });
device->spec.freq = MAIN_THREAD_EM_ASM_INT({ return Module['SDL3'].audioContext.sampleRate; });
device->sample_frames = SDL_GetDefaultSampleFramesFromFreq(device->spec.freq) * 2; // double the buffer size, some browsers need more, and we'll just have to live with the latency.
SDL_UpdatedAudioDeviceFormat(device);
+7 -1
View File
@@ -1118,7 +1118,13 @@ static bool PIPEWIRE_OpenDevice(SDL_AudioDevice *device)
stream_name = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_STREAM_NAME);
if (!stream_name || *stream_name == '\0') {
stream_name = "Audio Stream";
if (app_name) {
stream_name = app_name;
} else if (app_id) {
stream_name = app_id;
} else {
stream_name = "SDL Audio Stream";
}
}
/*
+2 -1
View File
@@ -672,7 +672,8 @@ static bool PULSEAUDIO_OpenDevice(SDL_AudioDevice *device)
paspec.rate = device->spec.freq;
// Reduced prebuffering compared to the defaults.
paattr.fragsize = device->buffer_size; // despite the name, this is only used for recording devices, according to PulseAudio docs!
paattr.fragsize = device->buffer_size * 2; // despite the name, this is only used for recording devices, according to PulseAudio docs! (times 2 because we want _more_ than our buffer size sent from the server at a time, which helps some drivers).
paattr.tlength = device->buffer_size;
paattr.prebuf = -1;
paattr.maxlength = -1;
+2 -1
View File
@@ -130,7 +130,8 @@ static bool VITAAUD_OpenDevice(SDL_AudioDevice *device)
static bool VITAAUD_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size)
{
return (sceAudioOutOutput(device->hidden->port, buffer) == 0);
// sceAudioOutOutput returns amount of samples queued or < 0 on error
return (sceAudioOutOutput(device->hidden->port, buffer) >= 0);
}
// This function waits until it is possible to write a full sound buffer
@@ -61,7 +61,7 @@ static SDL_CameraFrameResult EMSCRIPTENCAMERA_AcquireFrame(SDL_Camera *device, S
SDL3.camera.ctx2d.drawImage(SDL3.camera.video, 0, 0, w, h);
const imgrgba = SDL3.camera.ctx2d.getImageData(0, 0, w, h).data;
Module.HEAPU8.set(imgrgba, rgba);
HEAPU8.set(imgrgba, rgba);
return 1;
}, device->actual_spec.width, device->actual_spec.height, rgba);
+34 -58
View File
@@ -371,6 +371,7 @@ static jmethodID midShowTextInput;
static jmethodID midSupportsRelativeMouse;
static jmethodID midOpenFileDescriptor;
static jmethodID midShowFileDialog;
static jmethodID midGetPreferredLocales;
// audio manager
static jclass mAudioManagerClass;
@@ -660,6 +661,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cl
midSupportsRelativeMouse = (*env)->GetStaticMethodID(env, mActivityClass, "supportsRelativeMouse", "()Z");
midOpenFileDescriptor = (*env)->GetStaticMethodID(env, mActivityClass, "openFileDescriptor", "(Ljava/lang/String;Ljava/lang/String;)I");
midShowFileDialog = (*env)->GetStaticMethodID(env, mActivityClass, "showFileDialog", "([Ljava/lang/String;ZZI)Z");
midGetPreferredLocales = (*env)->GetStaticMethodID(env, mActivityClass, "getPreferredLocales", "()Ljava/lang/String;");
if (!midClipboardGetText ||
!midClipboardHasText ||
@@ -691,7 +693,8 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cl
!midShowTextInput ||
!midSupportsRelativeMouse ||
!midOpenFileDescriptor ||
!midShowFileDialog) {
!midShowFileDialog ||
!midGetPreferredLocales) {
__android_log_print(ANDROID_LOG_WARN, "SDL", "Missing some Java callbacks, do you have the latest version of SDLActivity.java?");
}
@@ -751,6 +754,8 @@ JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeSetupJNI)(JNIEnv *env
typedef int (*SDL_main_func)(int argc, char *argv[]);
static int run_count = 0;
static bool allow_recreate_activity;
static bool allow_recreate_activity_set;
JNIEXPORT int JNICALL SDL_JAVA_INTERFACE(nativeCheckSDLThreadCounter)(
JNIEnv *env, jclass jcls)
@@ -760,10 +765,16 @@ JNIEXPORT int JNICALL SDL_JAVA_INTERFACE(nativeCheckSDLThreadCounter)(
return tmp;
}
void Android_SetAllowRecreateActivity(bool enabled)
{
allow_recreate_activity = enabled;
allow_recreate_activity_set = true;
}
JNIEXPORT jboolean JNICALL SDL_JAVA_INTERFACE(nativeAllowRecreateActivity)(
JNIEnv *env, jclass jcls)
{
return SDL_GetHintBoolean(SDL_HINT_ANDROID_ALLOW_RECREATE_ACTIVITY, false);
return allow_recreate_activity;
}
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeInitMainThread)(
@@ -1526,6 +1537,14 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetenv)(
// Note that we call setenv() directly to avoid affecting SDL environments
setenv(utfname, utfvalue, 1); // This should NOT be SDL_setenv()
if (SDL_strcmp(utfname, SDL_HINT_ANDROID_ALLOW_RECREATE_ACTIVITY) == 0) {
// Special handling for this hint, which needs to persist outside the normal application flow
// Only set this the first time we run, in case it's been set by the application via SDL_SetHint()
if (!allow_recreate_activity_set) {
Android_SetAllowRecreateActivity(SDL_GetStringBoolean(utfvalue, false));
}
}
(*env)->ReleaseStringUTFChars(env, name, utfname);
(*env)->ReleaseStringUTFChars(env, value, utfvalue);
}
@@ -2569,65 +2588,22 @@ bool Android_JNI_ShowToast(const char *message, int duration, int gravity, int x
bool Android_JNI_GetLocale(char *buf, size_t buflen)
{
AConfiguration *cfg;
SDL_assert(buflen > 6);
// Need to re-create the asset manager if locale has changed (SDL_EVENT_LOCALE_CHANGED)
Internal_Android_Destroy_AssetManager();
if (!asset_manager) {
Internal_Android_Create_AssetManager();
}
if (!asset_manager) {
return false;
}
cfg = AConfiguration_new();
if (!cfg) {
return false;
}
{
char language[2] = {};
char country[2] = {};
size_t id = 0;
AConfiguration_fromAssetManager(cfg, asset_manager);
AConfiguration_getLanguage(cfg, language);
AConfiguration_getCountry(cfg, country);
// Indonesian is "id" according to ISO 639.2, but on Android is "in" because of Java backwards compatibility
if (language[0] == 'i' && language[1] == 'n') {
language[1] = 'd';
}
// copy language (not null terminated)
if (language[0]) {
buf[id++] = language[0];
if (language[1]) {
buf[id++] = language[1];
bool result = false;
if (buf && buflen > 0) {
*buf = '\0';
JNIEnv *env = Android_JNI_GetEnv();
jstring string = (jstring)(*env)->CallStaticObjectMethod(env, mActivityClass, midGetPreferredLocales);
if (string) {
const char *utf8string = (*env)->GetStringUTFChars(env, string, NULL);
if (utf8string) {
result = true;
SDL_strlcpy(buf, utf8string, buflen);
(*env)->ReleaseStringUTFChars(env, string, utf8string);
}
(*env)->DeleteLocalRef(env, string);
}
buf[id++] = '_';
// copy country (not null terminated)
if (country[0]) {
buf[id++] = country[0];
if (country[1]) {
buf[id++] = country[1];
}
}
buf[id++] = '\0';
SDL_assert(id <= buflen);
}
AConfiguration_delete(cfg);
return true;
return result;
}
bool Android_JNI_OpenURL(const char *url)
+2
View File
@@ -55,6 +55,8 @@ bool Android_WaitLifecycleEvent(SDL_AndroidLifecycleEvent *event, Sint64 timeout
void Android_LockActivityMutex(void);
void Android_UnlockActivityMutex(void);
void Android_SetAllowRecreateActivity(bool enabled);
// Interface from the SDL library into the Android Java activity
extern void Android_JNI_SetActivityTitle(const char *title);
extern void Android_JNI_SetWindowStyle(bool fullscreen);
+4 -4
View File
@@ -9,8 +9,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 3,2,10,0
PRODUCTVERSION 3,2,10,0
FILEVERSION 3,2,16,0
PRODUCTVERSION 3,2,16,0
FILEFLAGSMASK 0x3fL
FILEFLAGS 0x0L
FILEOS 0x40004L
@@ -23,12 +23,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "\0"
VALUE "FileDescription", "SDL\0"
VALUE "FileVersion", "3, 2, 10, 0\0"
VALUE "FileVersion", "3, 2, 16, 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, 10, 0\0"
VALUE "ProductVersion", "3, 2, 16, 0\0"
END
END
BLOCK "VarFileInfo"
+7 -1
View File
@@ -115,7 +115,11 @@
#define CPU_CFG2_LSX (1 << 6)
#define CPU_CFG2_LASX (1 << 7)
#if defined(SDL_ALTIVEC_BLITTERS) && defined(HAVE_SETJMP) && !defined(SDL_PLATFORM_MACOS) && !defined(SDL_PLATFORM_OPENBSD) && !defined(SDL_PLATFORM_FREEBSD)
#if !defined(SDL_CPUINFO_DISABLED) && \
!((defined(SDL_PLATFORM_MACOS) && (defined(__ppc__) || defined(__ppc64__))) || (defined(SDL_PLATFORM_OPENBSD) && defined(__powerpc__))) && \
!(defined(SDL_PLATFORM_FREEBSD) && defined(__powerpc__)) && \
!(defined(SDL_PLATFORM_LINUX) && defined(__powerpc__) && defined(HAVE_GETAUXVAL)) && \
defined(SDL_ALTIVEC_BLITTERS) && defined(HAVE_SETJMP)
/* This is the brute force way of detecting instruction sets...
the idea is borrowed from the libmpeg2 library - thanks!
*/
@@ -344,6 +348,8 @@ static int CPU_haveAltiVec(void)
elf_aux_info(AT_HWCAP, &cpufeatures, sizeof(cpufeatures));
altivec = cpufeatures & PPC_FEATURE_HAS_ALTIVEC;
return altivec;
#elif defined(SDL_PLATFORM_LINUX) && defined(__powerpc__) && defined(HAVE_GETAUXVAL)
altivec = getauxval(AT_HWCAP) & PPC_FEATURE_HAS_ALTIVEC;
#elif defined(SDL_ALTIVEC_BLITTERS) && defined(HAVE_SETJMP)
void (*handler)(int sig);
handler = signal(SIGILL, illegal_instruction);
+36 -11
View File
@@ -27,6 +27,35 @@
#import <Cocoa/Cocoa.h>
#import <UniformTypeIdentifiers/UTType.h>
static void AddFileExtensionType(NSMutableArray *types, const char *pattern_ptr)
{
if (!*pattern_ptr) {
return; // in case the string had an extra ';' at the end.
}
// -[UTType typeWithFilenameExtension] will return nil if there's a period in the string. It's better to
// allow too many files than not allow the one the user actually needs, so just take the part after the '.'
const char *dot = SDL_strrchr(pattern_ptr, '.');
NSString *extstr = [NSString stringWithFormat: @"%s", dot ? (dot + 1) : pattern_ptr];
if (@available(macOS 11.0, *)) {
UTType *uttype = [UTType typeWithFilenameExtension:extstr];
if (uttype) { // still failed? Don't add the pattern. This is what the pre-macOS11 path does internally anyhow.
[types addObject:uttype];
}
} else {
[types addObject:extstr];
}
}
static void ReactivateAfterDialog(void)
{
for (NSRunningApplication *i in [NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.apple.dock"]) {
[i activateWithOptions:0];
break;
}
[NSApp activateIgnoringOtherApps:YES];
}
void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props)
{
SDL_Window* window = SDL_GetPointerProperty(props, SDL_PROP_FILE_DIALOG_WINDOW_POINTER, NULL);
@@ -87,7 +116,7 @@ void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFil
if (filters) {
// On macOS 11.0 and up, this is an array of UTType. Prior to that, it's an array of NSString
NSMutableArray *types = [[NSMutableArray alloc] initWithCapacity:nfilters ];
NSMutableArray *types = [[NSMutableArray alloc] initWithCapacity:nfilters];
int has_all_files = 0;
for (int i = 0; i < nfilters; i++) {
@@ -102,21 +131,14 @@ void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFil
for (char *c = pattern; *c; c++) {
if (*c == ';') {
*c = '\0';
if(@available(macOS 11.0, *)) {
[types addObject: [UTType typeWithFilenameExtension:[NSString stringWithFormat: @"%s", pattern_ptr]]];
} else {
[types addObject: [NSString stringWithFormat: @"%s", pattern_ptr]];
}
AddFileExtensionType(types, pattern_ptr);
pattern_ptr = c + 1;
} else if (*c == '*') {
has_all_files = 1;
}
}
if(@available(macOS 11.0, *)) {
[types addObject: [UTType typeWithFilenameExtension:[NSString stringWithFormat: @"%s", pattern_ptr]]];
} else {
[types addObject: [NSString stringWithFormat: @"%s", pattern_ptr]];
}
AddFileExtensionType(types, pattern_ptr); // get the last piece of the string.
SDL_free(pattern);
}
@@ -163,6 +185,8 @@ void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFil
const char *files[1] = { NULL };
callback(userdata, files, -1);
}
ReactivateAfterDialog();
}];
} else {
if ([dialog runModal] == NSModalResponseOK) {
@@ -182,6 +206,7 @@ void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFil
const char *files[1] = { NULL };
callback(userdata, files, -1);
}
ReactivateAfterDialog();
}
}
+13 -5
View File
@@ -261,7 +261,7 @@ void windows_ShowFileDialog(void *ptr)
chosen_files_list[nfiles] = NULL;
if (WideCharToMultiByte(CP_UTF8, 0, file_ptr, -1, chosen_folder, MAX_PATH, NULL, NULL) >= MAX_PATH) {
if (WideCharToMultiByte(CP_UTF8, 0, file_ptr, -1, chosen_folder, MAX_PATH, NULL, NULL) == 0) {
SDL_SetError("Path too long or invalid character in path");
SDL_free(chosen_files_list);
callback(userdata, NULL, -1);
@@ -273,7 +273,7 @@ void windows_ShowFileDialog(void *ptr)
SDL_strlcpy(chosen_file, chosen_folder, MAX_PATH);
chosen_file[chosen_folder_size] = '\\';
file_ptr += SDL_strlen(chosen_folder) + 1;
file_ptr += SDL_wcslen(file_ptr) + 1;
while (*file_ptr) {
nfiles++;
@@ -295,7 +295,7 @@ void windows_ShowFileDialog(void *ptr)
int diff = ((int) chosen_folder_size) + 1;
if (WideCharToMultiByte(CP_UTF8, 0, file_ptr, -1, chosen_file + diff, MAX_PATH - diff, NULL, NULL) >= MAX_PATH - diff) {
if (WideCharToMultiByte(CP_UTF8, 0, file_ptr, -1, chosen_file + diff, MAX_PATH - diff, NULL, NULL) == 0) {
SDL_SetError("Path too long or invalid character in path");
for (size_t i = 0; i < nfiles - 1; i++) {
@@ -308,7 +308,7 @@ void windows_ShowFileDialog(void *ptr)
return;
}
file_ptr += SDL_strlen(chosen_file) + 1 - diff;
file_ptr += SDL_wcslen(file_ptr) + 1;
chosen_files_list[nfiles - 1] = SDL_strdup(chosen_file);
@@ -516,6 +516,14 @@ static void ShowFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_
filters_str = win_get_filters(filters, nfilters);
DWORD flags = 0;
if (allow_many) {
flags |= OFN_ALLOWMULTISELECT;
}
if (is_save) {
flags |= OFN_OVERWRITEPROMPT;
}
if (!filters_str && filters) {
callback(userdata, NULL, -1);
SDL_free(args);
@@ -526,7 +534,7 @@ static void ShowFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_
args->filters_str = filters_str;
args->default_file = default_location ? SDL_strdup(default_location) : NULL;
args->parent = window;
args->flags = allow_many ? OFN_ALLOWMULTISELECT : 0;
args->flags = flags;
args->callback = callback;
args->userdata = userdata;
args->title = title ? SDL_strdup(title) : NULL;
+14 -33
View File
@@ -633,9 +633,10 @@ static void SDL_LogEvent(const SDL_Event *event)
#undef PRINT_MBUTTON_EVENT
SDL_EVENT_CASE(SDL_EVENT_MOUSE_WHEEL)
(void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u x=%g y=%g direction=%s)",
(void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u x=%g y=%g integer_x=%d integer_y=%d direction=%s)",
(uint)event->wheel.timestamp, (uint)event->wheel.windowID,
(uint)event->wheel.which, event->wheel.x, event->wheel.y,
(int)event->wheel.integer_x, (int)event->wheel.integer_y,
event->wheel.direction == SDL_MOUSEWHEEL_NORMAL ? "normal" : "flipped");
break;
@@ -1076,16 +1077,11 @@ static void SDL_SendWakeupEvent(void)
return;
}
SDL_LockMutex(_this->wakeup_lock);
{
if (_this->wakeup_window) {
_this->SendWakeupEvent(_this, _this->wakeup_window);
// No more wakeup events needed until we enter a new wait
_this->wakeup_window = NULL;
}
// We only want to do this once while waiting for an event, so set it to NULL atomically here
SDL_Window *wakeup_window = (SDL_Window *)SDL_SetAtomicPointer(&_this->wakeup_window, NULL);
if (wakeup_window) {
_this->SendWakeupEvent(_this, wakeup_window);
}
SDL_UnlockMutex(_this->wakeup_lock);
#endif
}
@@ -1379,9 +1375,7 @@ bool SDL_RunOnMainThread(SDL_MainThreadCallback callback, void *userdata, bool w
return true;
}
// Maximum wait of 30 seconds to prevent deadlocking forever
const Sint32 MAX_CALLBACK_WAIT = 30 * 1000;
SDL_WaitSemaphoreTimeout(entry->semaphore, MAX_CALLBACK_WAIT);
SDL_WaitSemaphore(entry->semaphore);
switch (SDL_GetAtomicInt(&entry->state)) {
case SDL_MAIN_CALLBACK_COMPLETE:
@@ -1525,18 +1519,7 @@ static int SDL_WaitEventTimeout_Device(SDL_VideoDevice *_this, SDL_Window *wakeu
*/
SDL_PumpEventsInternal(true);
SDL_LockMutex(_this->wakeup_lock);
{
status = SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST);
// If status == 0 we are going to block so wakeup will be needed.
if (status == 0) {
_this->wakeup_window = wakeup_window;
} else {
_this->wakeup_window = NULL;
}
}
SDL_UnlockMutex(_this->wakeup_lock);
status = SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST);
if (status < 0) {
// Got an error: return
break;
@@ -1549,8 +1532,6 @@ static int SDL_WaitEventTimeout_Device(SDL_VideoDevice *_this, SDL_Window *wakeu
if (timeoutNS > 0) {
Sint64 elapsed = SDL_GetTicksNS() - start;
if (elapsed >= timeoutNS) {
// Set wakeup_window to NULL without holding the lock.
_this->wakeup_window = NULL;
return 0;
}
loop_timeoutNS = (timeoutNS - elapsed);
@@ -1563,9 +1544,9 @@ static int SDL_WaitEventTimeout_Device(SDL_VideoDevice *_this, SDL_Window *wakeu
loop_timeoutNS = poll_intervalNS;
}
}
SDL_SetAtomicPointer(&_this->wakeup_window, wakeup_window);
status = _this->WaitEventTimeout(_this, loop_timeoutNS);
// Set wakeup_window to NULL without holding the lock.
_this->wakeup_window = NULL;
SDL_SetAtomicPointer(&_this->wakeup_window, NULL);
if (status == 0 && poll_intervalNS != SDL_MAX_SINT64 && loop_timeoutNS == poll_intervalNS) {
// We may have woken up to poll. Try again
continue;
@@ -1823,7 +1804,7 @@ void SDL_SetEventEnabled(Uint32 type, bool enabled)
Uint8 lo = (type & 0xff);
if (SDL_disabled_events[hi] &&
(SDL_disabled_events[hi]->bits[lo / 32] & (1 << (lo & 31)))) {
(SDL_disabled_events[hi]->bits[lo / 32] & (1U << (lo & 31)))) {
current_state = false;
} else {
current_state = true;
@@ -1832,7 +1813,7 @@ void SDL_SetEventEnabled(Uint32 type, bool enabled)
if ((enabled != false) != current_state) {
if (enabled) {
SDL_assert(SDL_disabled_events[hi] != NULL);
SDL_disabled_events[hi]->bits[lo / 32] &= ~(1 << (lo & 31));
SDL_disabled_events[hi]->bits[lo / 32] &= ~(1U << (lo & 31));
// Gamepad events depend on joystick events
switch (type) {
@@ -1863,7 +1844,7 @@ void SDL_SetEventEnabled(Uint32 type, bool enabled)
}
// Out of memory, nothing we can do...
if (SDL_disabled_events[hi]) {
SDL_disabled_events[hi]->bits[lo / 32] |= (1 << (lo & 31));
SDL_disabled_events[hi]->bits[lo / 32] |= (1U << (lo & 31));
SDL_FlushEvent(type);
}
}
@@ -1882,7 +1863,7 @@ bool SDL_EventEnabled(Uint32 type)
Uint8 lo = (type & 0xff);
if (SDL_disabled_events[hi] &&
(SDL_disabled_events[hi]->bits[lo / 32] & (1 << (lo & 31)))) {
(SDL_disabled_events[hi]->bits[lo / 32] & (1U << (lo & 31)))) {
return false;
} else {
return true;
+27 -12
View File
@@ -138,21 +138,25 @@ static void SDLCALL SDL_TouchMouseEventsChanged(void *userdata, const char *name
#ifdef SDL_PLATFORM_VITA
static void SDLCALL SDL_VitaTouchMouseDeviceChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
{
Uint8 vita_touch_mouse_device = 1;
SDL_Mouse *mouse = (SDL_Mouse *)userdata;
if (hint) {
switch (*hint) {
default:
case '0':
mouse->vita_touch_mouse_device = 1;
vita_touch_mouse_device = 1;
break;
case '1':
mouse->vita_touch_mouse_device = 2;
vita_touch_mouse_device = 2;
break;
case '2':
mouse->vita_touch_mouse_device = 3;
vita_touch_mouse_device = 3;
break;
default:
break;
}
}
mouse->vita_touch_mouse_device = vita_touch_mouse_device;
}
#endif
@@ -1022,18 +1026,14 @@ void SDL_SendMouseWheel(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseI
SDL_SetMouseFocus(window);
}
// Accumulate fractional wheel motion if integer mode is enabled
if (mouse->integer_mode_flags & 2) {
mouse->integer_mode_residual_scroll_x = SDL_modff(mouse->integer_mode_residual_scroll_x + x, &x);
mouse->integer_mode_residual_scroll_y = SDL_modff(mouse->integer_mode_residual_scroll_y + y, &y);
}
if (x == 0.0f && y == 0.0f) {
return;
}
// Post the event, if desired
if (SDL_EventEnabled(SDL_EVENT_MOUSE_WHEEL)) {
float integer_x, integer_y;
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;
@@ -1044,11 +1044,26 @@ void SDL_SendMouseWheel(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseI
event.common.timestamp = timestamp;
event.wheel.windowID = mouse->focus ? mouse->focus->id : 0;
event.wheel.which = mouseID;
event.wheel.x = x;
event.wheel.y = y;
event.wheel.direction = direction;
event.wheel.mouse_x = mouse->x;
event.wheel.mouse_y = mouse->y;
mouse->residual_scroll_x = SDL_modff(mouse->residual_scroll_x + x, &integer_x);
event.wheel.integer_x = (Sint32)integer_x;
mouse->residual_scroll_y = SDL_modff(mouse->residual_scroll_y + y, &integer_y);
event.wheel.integer_y = (Sint32)integer_y;
// Return the accumulated values in x/y when integer wheel mode is enabled.
// This is necessary for compatibility with sdl2-compat 2.32.54.
if (mouse->integer_mode_flags & 2) {
event.wheel.x = integer_x;
event.wheel.y = integer_y;
} else {
event.wheel.x = x;
event.wheel.y = y;
}
SDL_PushEvent(&event);
}
}
+2 -2
View File
@@ -95,8 +95,6 @@ typedef struct
Uint8 integer_mode_flags; // 1 to enable mouse quantization, 2 to enable wheel quantization
float integer_mode_residual_motion_x;
float integer_mode_residual_motion_y;
float integer_mode_residual_scroll_x;
float integer_mode_residual_scroll_y;
// Data common to all mice
SDL_Window *focus;
@@ -105,6 +103,8 @@ typedef struct
float x_accu;
float y_accu;
float last_x, last_y; // the last reported x and y coordinates
float residual_scroll_x;
float residual_scroll_y;
double click_motion_x;
double click_motion_y;
bool has_position;
+11 -2
View File
@@ -565,10 +565,19 @@ void SDL_SendPenButton(Uint64 timestamp, SDL_PenID instance_id, SDL_Window *wind
event.pbutton.down = down;
SDL_PushEvent(&event);
if (window && (pen_touching == instance_id)) {
if (window && (!pen_touching || (pen_touching == instance_id))) {
SDL_Mouse *mouse = SDL_GetMouse();
if (mouse && mouse->pen_mouse_events) {
SDL_SendMouseButton(timestamp, window, SDL_PEN_MOUSEID, button + 1, down);
static const Uint8 mouse_buttons[] = {
SDL_BUTTON_LEFT,
SDL_BUTTON_RIGHT,
SDL_BUTTON_MIDDLE,
SDL_BUTTON_X1,
SDL_BUTTON_X2
};
if (button < SDL_arraysize(mouse_buttons)) {
SDL_SendMouseButton(timestamp, window, SDL_PEN_MOUSEID, mouse_buttons[button], down);
}
}
}
}
+407 -33
View File
@@ -56,15 +56,47 @@
}
#define CHECK_RENDERPASS \
if (!((Pass *)render_pass)->in_progress) { \
if (!((RenderPass *)render_pass)->in_progress) { \
SDL_assert_release(!"Render pass not in progress!"); \
return; \
}
#define CHECK_GRAPHICS_PIPELINE_BOUND \
if (!((CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER)->graphics_pipeline_bound) { \
SDL_assert_release(!"Graphics pipeline not bound!"); \
return; \
#define CHECK_SAMPLER_TEXTURES \
RenderPass *rp = (RenderPass *)render_pass; \
for (Uint32 color_target_index = 0; color_target_index < rp->num_color_targets; color_target_index += 1) { \
for (Uint32 texture_sampler_index = 0; texture_sampler_index < num_bindings; texture_sampler_index += 1) { \
if (rp->color_targets[color_target_index] == texture_sampler_bindings[texture_sampler_index].texture) { \
SDL_assert_release(!"Texture cannot be simultaneously bound as a color target and a sampler!"); \
} \
} \
} \
\
for (Uint32 texture_sampler_index = 0; texture_sampler_index < num_bindings; texture_sampler_index += 1) { \
if (rp->depth_stencil_target != NULL && rp->depth_stencil_target == texture_sampler_bindings[texture_sampler_index].texture) { \
SDL_assert_release(!"Texture cannot be simultaneously bound as a depth stencil target and a sampler!"); \
} \
}
#define CHECK_STORAGE_TEXTURES \
RenderPass *rp = (RenderPass *)render_pass; \
for (Uint32 color_target_index = 0; color_target_index < rp->num_color_targets; color_target_index += 1) { \
for (Uint32 texture_sampler_index = 0; texture_sampler_index < num_bindings; texture_sampler_index += 1) { \
if (rp->color_targets[color_target_index] == storage_textures[texture_sampler_index]) { \
SDL_assert_release(!"Texture cannot be simultaneously bound as a color target and a storage texture!"); \
} \
} \
} \
\
for (Uint32 texture_sampler_index = 0; texture_sampler_index < num_bindings; texture_sampler_index += 1) { \
if (rp->depth_stencil_target != NULL && rp->depth_stencil_target == storage_textures[texture_sampler_index]) { \
SDL_assert_release(!"Texture cannot be simultaneously bound as a depth stencil target and a storage texture!"); \
} \
}
#define CHECK_GRAPHICS_PIPELINE_BOUND \
if (!((RenderPass *)render_pass)->graphics_pipeline) { \
SDL_assert_release(!"Graphics pipeline not bound!"); \
return; \
}
#define CHECK_COMPUTEPASS \
@@ -74,7 +106,7 @@
}
#define CHECK_COMPUTE_PIPELINE_BOUND \
if (!((CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER)->compute_pipeline_bound) { \
if (!((ComputePass *)compute_pass)->compute_pipeline) { \
SDL_assert_release(!"Compute pipeline not bound!"); \
return; \
}
@@ -137,23 +169,137 @@
((CommandBufferCommonHeader *)command_buffer)->device
#define RENDERPASS_COMMAND_BUFFER \
((Pass *)render_pass)->command_buffer
((RenderPass *)render_pass)->command_buffer
#define RENDERPASS_DEVICE \
((CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER)->device
#define RENDERPASS_BOUND_PIPELINE \
((RenderPass *)render_pass)->graphics_pipeline
#define COMPUTEPASS_COMMAND_BUFFER \
((Pass *)compute_pass)->command_buffer
#define COMPUTEPASS_DEVICE \
((CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER)->device
#define COMPUTEPASS_BOUND_PIPELINE \
((ComputePass *)compute_pass)->compute_pipeline
#define COPYPASS_COMMAND_BUFFER \
((Pass *)copy_pass)->command_buffer
#define COPYPASS_DEVICE \
((CommandBufferCommonHeader *)COPYPASS_COMMAND_BUFFER)->device
static bool TextureFormatIsComputeWritable[] = {
false, // INVALID
false, // A8_UNORM
true, // R8_UNORM
true, // R8G8_UNORM
true, // R8G8B8A8_UNORM
true, // R16_UNORM
true, // R16G16_UNORM
true, // R16G16B16A16_UNORM
true, // R10G10B10A2_UNORM
false, // B5G6R5_UNORM
false, // B5G5R5A1_UNORM
false, // B4G4R4A4_UNORM
false, // B8G8R8A8_UNORM
false, // BC1_UNORM
false, // BC2_UNORM
false, // BC3_UNORM
false, // BC4_UNORM
false, // BC5_UNORM
false, // BC7_UNORM
false, // BC6H_FLOAT
false, // BC6H_UFLOAT
true, // R8_SNORM
true, // R8G8_SNORM
true, // R8G8B8A8_SNORM
true, // R16_SNORM
true, // R16G16_SNORM
true, // R16G16B16A16_SNORM
true, // R16_FLOAT
true, // R16G16_FLOAT
true, // R16G16B16A16_FLOAT
true, // R32_FLOAT
true, // R32G32_FLOAT
true, // R32G32B32A32_FLOAT
true, // R11G11B10_UFLOAT
true, // R8_UINT
true, // R8G8_UINT
true, // R8G8B8A8_UINT
true, // R16_UINT
true, // R16G16_UINT
true, // R16G16B16A16_UINT
true, // R32_UINT
true, // R32G32_UINT
true, // R32G32B32A32_UINT
true, // R8_INT
true, // R8G8_INT
true, // R8G8B8A8_INT
true, // R16_INT
true, // R16G16_INT
true, // R16G16B16A16_INT
true, // R32_INT
true, // R32G32_INT
true, // R32G32B32A32_INT
false, // R8G8B8A8_UNORM_SRGB
false, // B8G8R8A8_UNORM_SRGB
false, // BC1_UNORM_SRGB
false, // BC3_UNORM_SRGB
false, // BC3_UNORM_SRGB
false, // BC7_UNORM_SRGB
false, // D16_UNORM
false, // D24_UNORM
false, // D32_FLOAT
false, // D24_UNORM_S8_UINT
false, // D32_FLOAT_S8_UINT
false, // ASTC_4x4_UNORM
false, // ASTC_5x4_UNORM
false, // ASTC_5x5_UNORM
false, // ASTC_6x5_UNORM
false, // ASTC_6x6_UNORM
false, // ASTC_8x5_UNORM
false, // ASTC_8x6_UNORM
false, // ASTC_8x8_UNORM
false, // ASTC_10x5_UNORM
false, // ASTC_10x6_UNORM
false, // ASTC_10x8_UNORM
false, // ASTC_10x10_UNORM
false, // ASTC_12x10_UNORM
false, // ASTC_12x12_UNORM
false, // ASTC_4x4_UNORM_SRGB
false, // ASTC_5x4_UNORM_SRGB
false, // ASTC_5x5_UNORM_SRGB
false, // ASTC_6x5_UNORM_SRGB
false, // ASTC_6x6_UNORM_SRGB
false, // ASTC_8x5_UNORM_SRGB
false, // ASTC_8x6_UNORM_SRGB
false, // ASTC_8x8_UNORM_SRGB
false, // ASTC_10x5_UNORM_SRGB
false, // ASTC_10x6_UNORM_SRGB
false, // ASTC_10x8_UNORM_SRGB
false, // ASTC_10x10_UNORM_SRGB
false, // ASTC_12x10_UNORM_SRGB
false, // ASTC_12x12_UNORM_SRGB
false, // ASTC_4x4_FLOAT
false, // ASTC_5x4_FLOAT
false, // ASTC_5x5_FLOAT
false, // ASTC_6x5_FLOAT
false, // ASTC_6x6_FLOAT
false, // ASTC_8x5_FLOAT
false, // ASTC_8x6_FLOAT
false, // ASTC_8x8_FLOAT
false, // ASTC_10x5_FLOAT
false, // ASTC_10x6_FLOAT
false, // ASTC_10x8_FLOAT
false, // ASTC_10x10_FLOAT
false, // ASTC_12x10_FLOAT
false // ASTC_12x12_FLOAT
};
// Drivers
#ifndef SDL_GPU_DISABLED
@@ -371,6 +517,73 @@ void SDL_GPU_BlitCommon(
SDL_EndGPURenderPass(render_pass);
}
static void SDL_GPU_CheckGraphicsBindings(SDL_GPURenderPass *render_pass)
{
RenderPass *rp = (RenderPass *)render_pass;
GraphicsPipelineCommonHeader *pipeline = (GraphicsPipelineCommonHeader *)RENDERPASS_BOUND_PIPELINE;
for (Uint32 i = 0; i < pipeline->num_vertex_samplers; i += 1) {
if (!rp->vertex_sampler_bound[i]) {
SDL_assert_release(!"Missing vertex sampler binding!");
}
}
for (Uint32 i = 0; i < pipeline->num_vertex_storage_textures; i += 1) {
if (!rp->vertex_storage_texture_bound[i]) {
SDL_assert_release(!"Missing vertex storage texture binding!");
}
}
for (Uint32 i = 0; i < pipeline->num_vertex_storage_buffers; i += 1) {
if (!rp->vertex_storage_buffer_bound[i]) {
SDL_assert_release(!"Missing vertex storage buffer binding!");
}
}
for (Uint32 i = 0; i < pipeline->num_fragment_samplers; i += 1) {
if (!rp->fragment_sampler_bound[i]) {
SDL_assert_release(!"Missing fragment sampler binding!");
}
}
for (Uint32 i = 0; i < pipeline->num_fragment_storage_textures; i += 1) {
if (!rp->fragment_storage_texture_bound[i]) {
SDL_assert_release(!"Missing fragment storage texture binding!");
}
}
for (Uint32 i = 0; i < pipeline->num_fragment_storage_buffers; i += 1) {
if (!rp->fragment_storage_buffer_bound[i]) {
SDL_assert_release(!"Missing fragment storage buffer binding!");
}
}
}
static void SDL_GPU_CheckComputeBindings(SDL_GPUComputePass *compute_pass)
{
ComputePass *cp = (ComputePass *)compute_pass;
ComputePipelineCommonHeader *pipeline = (ComputePipelineCommonHeader *)COMPUTEPASS_BOUND_PIPELINE;
for (Uint32 i = 0; i < pipeline->numSamplers; i += 1) {
if (!cp->sampler_bound[i]) {
SDL_assert_release(!"Missing compute sampler binding!");
}
}
for (Uint32 i = 0; i < pipeline->numReadonlyStorageTextures; i += 1) {
if (!cp->read_only_storage_texture_bound[i]) {
SDL_assert_release(!"Missing compute readonly storage texture binding!");
}
}
for (Uint32 i = 0; i < pipeline->numReadonlyStorageBuffers; i += 1) {
if (!cp->read_only_storage_buffer_bound[i]) {
SDL_assert_release(!"Missing compute readonly storage buffer binding!");
}
}
for (Uint32 i = 0; i < pipeline->numReadWriteStorageTextures; i += 1) {
if (!cp->read_write_storage_texture_bound[i]) {
SDL_assert_release(!"Missing compute read-write storage texture binding!");
}
}
for (Uint32 i = 0; i < pipeline->numReadWriteStorageBuffers; i += 1) {
if (!cp->read_write_storage_buffer_bound[i]) {
SDL_assert_release(!"Missing compute read-write storage buffer bbinding!");
}
}
}
// Driver Functions
#ifndef SDL_GPU_DISABLED
@@ -532,7 +745,6 @@ SDL_GPUDevice *SDL_CreateGPUDeviceWithProperties(SDL_PropertiesID props)
result = selectedBackend->CreateDevice(debug_mode, preferLowPower, props);
if (result != NULL) {
result->backend = selectedBackend->name;
result->shader_formats = selectedBackend->shader_formats;
result->debug_mode = debug_mode;
}
}
@@ -721,6 +933,13 @@ bool SDL_GPUTextureSupportsFormat(
CHECK_TEXTUREFORMAT_ENUM_INVALID(format, false)
}
if ((usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE) ||
(usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE)) {
if (!TextureFormatIsComputeWritable[format]) {
return false;
}
}
return device->SupportsTextureFormat(
device->driverData,
format,
@@ -1343,15 +1562,29 @@ SDL_GPUCommandBuffer *SDL_AcquireGPUCommandBuffer(
commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
commandBufferHeader->device = device;
commandBufferHeader->render_pass.command_buffer = command_buffer;
commandBufferHeader->render_pass.in_progress = false;
commandBufferHeader->graphics_pipeline_bound = false;
commandBufferHeader->compute_pass.command_buffer = command_buffer;
commandBufferHeader->compute_pass.in_progress = false;
commandBufferHeader->compute_pipeline_bound = false;
commandBufferHeader->copy_pass.command_buffer = command_buffer;
commandBufferHeader->copy_pass.in_progress = false;
commandBufferHeader->swapchain_texture_acquired = false;
commandBufferHeader->submitted = false;
if (device->debug_mode) {
commandBufferHeader->render_pass.in_progress = false;
commandBufferHeader->render_pass.graphics_pipeline = NULL;
commandBufferHeader->compute_pass.in_progress = false;
commandBufferHeader->compute_pass.compute_pipeline = NULL;
commandBufferHeader->copy_pass.in_progress = false;
commandBufferHeader->swapchain_texture_acquired = false;
commandBufferHeader->submitted = false;
SDL_zeroa(commandBufferHeader->render_pass.vertex_sampler_bound);
SDL_zeroa(commandBufferHeader->render_pass.vertex_storage_texture_bound);
SDL_zeroa(commandBufferHeader->render_pass.vertex_storage_buffer_bound);
SDL_zeroa(commandBufferHeader->render_pass.fragment_sampler_bound);
SDL_zeroa(commandBufferHeader->render_pass.fragment_storage_texture_bound);
SDL_zeroa(commandBufferHeader->render_pass.fragment_storage_buffer_bound);
SDL_zeroa(commandBufferHeader->compute_pass.sampler_bound);
SDL_zeroa(commandBufferHeader->compute_pass.read_only_storage_texture_bound);
SDL_zeroa(commandBufferHeader->compute_pass.read_only_storage_buffer_bound);
SDL_zeroa(commandBufferHeader->compute_pass.read_write_storage_texture_bound);
SDL_zeroa(commandBufferHeader->compute_pass.read_write_storage_buffer_bound);
}
return command_buffer;
}
@@ -1469,30 +1702,47 @@ SDL_GPURenderPass *SDL_BeginGPURenderPass(
if (color_target_infos[i].cycle && color_target_infos[i].load_op == SDL_GPU_LOADOP_LOAD) {
SDL_assert_release(!"Cannot cycle color target when load op is LOAD!");
return NULL;
}
if (color_target_infos[i].store_op == SDL_GPU_STOREOP_RESOLVE || color_target_infos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) {
if (color_target_infos[i].resolve_texture == NULL) {
SDL_assert_release(!"Store op is RESOLVE or RESOLVE_AND_STORE but resolve_texture is NULL!");
return NULL;
} else {
TextureCommonHeader *resolveTextureHeader = (TextureCommonHeader *)color_target_infos[i].resolve_texture;
if (textureHeader->info.sample_count == SDL_GPU_SAMPLECOUNT_1) {
SDL_assert_release(!"Store op is RESOLVE or RESOLVE_AND_STORE but texture is not multisample!");
return NULL;
}
if (resolveTextureHeader->info.sample_count != SDL_GPU_SAMPLECOUNT_1) {
SDL_assert_release(!"Resolve texture must have a sample count of 1!");
return NULL;
}
if (resolveTextureHeader->info.format != textureHeader->info.format) {
SDL_assert_release(!"Resolve texture must have the same format as its corresponding color target!");
return NULL;
}
if (resolveTextureHeader->info.type == SDL_GPU_TEXTURETYPE_3D) {
SDL_assert_release(!"Resolve texture must not be of TEXTURETYPE_3D!");
return NULL;
}
if (!(resolveTextureHeader->info.usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET)) {
SDL_assert_release(!"Resolve texture usage must include COLOR_TARGET!");
return NULL;
}
}
}
if (color_target_infos[i].layer_or_depth_plane >= textureHeader->info.layer_count_or_depth) {
SDL_assert_release(!"Color target layer index must be less than the texture's layer count!");
return NULL;
}
if (color_target_infos[i].mip_level >= textureHeader->info.num_levels) {
SDL_assert_release(!"Color target mip level must be less than the texture's level count!");
return NULL;
}
}
if (depth_stencil_target_info != NULL) {
@@ -1500,10 +1750,12 @@ SDL_GPURenderPass *SDL_BeginGPURenderPass(
TextureCommonHeader *textureHeader = (TextureCommonHeader *)depth_stencil_target_info->texture;
if (!(textureHeader->info.usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET)) {
SDL_assert_release(!"Depth target must have been created with the DEPTH_STENCIL_TARGET usage flag!");
return NULL;
}
if (depth_stencil_target_info->cycle && (depth_stencil_target_info->load_op == SDL_GPU_LOADOP_LOAD || depth_stencil_target_info->stencil_load_op == SDL_GPU_LOADOP_LOAD)) {
SDL_assert_release(!"Cannot cycle depth target when load op or stencil load op is LOAD!");
return NULL;
}
if (depth_stencil_target_info->store_op == SDL_GPU_STOREOP_RESOLVE ||
@@ -1511,6 +1763,7 @@ SDL_GPURenderPass *SDL_BeginGPURenderPass(
depth_stencil_target_info->store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE ||
depth_stencil_target_info->stencil_store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) {
SDL_assert_release(!"RESOLVE store ops are not supported for depth-stencil targets!");
return NULL;
}
}
}
@@ -1522,7 +1775,18 @@ SDL_GPURenderPass *SDL_BeginGPURenderPass(
depth_stencil_target_info);
commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
commandBufferHeader->render_pass.in_progress = true;
if (COMMAND_BUFFER_DEVICE->debug_mode) {
commandBufferHeader->render_pass.in_progress = true;
for (Uint32 i = 0; i < num_color_targets; i += 1) {
commandBufferHeader->render_pass.color_targets[i] = color_target_infos[i].texture;
}
commandBufferHeader->render_pass.num_color_targets = num_color_targets;
if (depth_stencil_target_info != NULL) {
commandBufferHeader->render_pass.depth_stencil_target = depth_stencil_target_info->texture;
}
}
return (SDL_GPURenderPass *)&(commandBufferHeader->render_pass);
}
@@ -1530,8 +1794,6 @@ void SDL_BindGPUGraphicsPipeline(
SDL_GPURenderPass *render_pass,
SDL_GPUGraphicsPipeline *graphics_pipeline)
{
CommandBufferCommonHeader *commandBufferHeader;
if (render_pass == NULL) {
SDL_InvalidParamError("render_pass");
return;
@@ -1545,8 +1807,10 @@ void SDL_BindGPUGraphicsPipeline(
RENDERPASS_COMMAND_BUFFER,
graphics_pipeline);
commandBufferHeader = (CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER;
commandBufferHeader->graphics_pipeline_bound = true;
if (RENDERPASS_DEVICE->debug_mode) {
RENDERPASS_BOUND_PIPELINE = graphics_pipeline;
}
}
void SDL_SetGPUViewport(
@@ -1696,6 +1960,15 @@ void SDL_BindGPUVertexSamplers(
if (RENDERPASS_DEVICE->debug_mode) {
CHECK_RENDERPASS
if (!((CommandBufferCommonHeader*)RENDERPASS_COMMAND_BUFFER)->ignore_render_pass_texture_validation)
{
CHECK_SAMPLER_TEXTURES
}
for (Uint32 i = 0; i < num_bindings; i += 1) {
((RenderPass *)render_pass)->vertex_sampler_bound[first_slot + i] = true;
}
}
RENDERPASS_DEVICE->BindVertexSamplers(
@@ -1722,6 +1995,11 @@ void SDL_BindGPUVertexStorageTextures(
if (RENDERPASS_DEVICE->debug_mode) {
CHECK_RENDERPASS
CHECK_STORAGE_TEXTURES
for (Uint32 i = 0; i < num_bindings; i += 1) {
((RenderPass *)render_pass)->vertex_storage_texture_bound[first_slot + i] = true;
}
}
RENDERPASS_DEVICE->BindVertexStorageTextures(
@@ -1748,6 +2026,10 @@ void SDL_BindGPUVertexStorageBuffers(
if (RENDERPASS_DEVICE->debug_mode) {
CHECK_RENDERPASS
for (Uint32 i = 0; i < num_bindings; i += 1) {
((RenderPass *)render_pass)->vertex_storage_buffer_bound[first_slot + i] = true;
}
}
RENDERPASS_DEVICE->BindVertexStorageBuffers(
@@ -1774,6 +2056,14 @@ void SDL_BindGPUFragmentSamplers(
if (RENDERPASS_DEVICE->debug_mode) {
CHECK_RENDERPASS
if (!((CommandBufferCommonHeader*)RENDERPASS_COMMAND_BUFFER)->ignore_render_pass_texture_validation) {
CHECK_SAMPLER_TEXTURES
}
for (Uint32 i = 0; i < num_bindings; i += 1) {
((RenderPass *)render_pass)->fragment_sampler_bound[first_slot + i] = true;
}
}
RENDERPASS_DEVICE->BindFragmentSamplers(
@@ -1800,6 +2090,11 @@ void SDL_BindGPUFragmentStorageTextures(
if (RENDERPASS_DEVICE->debug_mode) {
CHECK_RENDERPASS
CHECK_STORAGE_TEXTURES
for (Uint32 i = 0; i < num_bindings; i += 1) {
((RenderPass *)render_pass)->fragment_storage_texture_bound[first_slot + i] = true;
}
}
RENDERPASS_DEVICE->BindFragmentStorageTextures(
@@ -1826,6 +2121,10 @@ void SDL_BindGPUFragmentStorageBuffers(
if (RENDERPASS_DEVICE->debug_mode) {
CHECK_RENDERPASS
for (Uint32 i = 0; i < num_bindings; i += 1) {
((RenderPass *)render_pass)->fragment_storage_buffer_bound[first_slot + i] = true;
}
}
RENDERPASS_DEVICE->BindFragmentStorageBuffers(
@@ -1851,6 +2150,7 @@ void SDL_DrawGPUIndexedPrimitives(
if (RENDERPASS_DEVICE->debug_mode) {
CHECK_RENDERPASS
CHECK_GRAPHICS_PIPELINE_BOUND
SDL_GPU_CheckGraphicsBindings(render_pass);
}
RENDERPASS_DEVICE->DrawIndexedPrimitives(
@@ -1877,6 +2177,7 @@ void SDL_DrawGPUPrimitives(
if (RENDERPASS_DEVICE->debug_mode) {
CHECK_RENDERPASS
CHECK_GRAPHICS_PIPELINE_BOUND
SDL_GPU_CheckGraphicsBindings(render_pass);
}
RENDERPASS_DEVICE->DrawPrimitives(
@@ -1905,6 +2206,7 @@ void SDL_DrawGPUPrimitivesIndirect(
if (RENDERPASS_DEVICE->debug_mode) {
CHECK_RENDERPASS
CHECK_GRAPHICS_PIPELINE_BOUND
SDL_GPU_CheckGraphicsBindings(render_pass);
}
RENDERPASS_DEVICE->DrawPrimitivesIndirect(
@@ -1932,6 +2234,7 @@ void SDL_DrawGPUIndexedPrimitivesIndirect(
if (RENDERPASS_DEVICE->debug_mode) {
CHECK_RENDERPASS
CHECK_GRAPHICS_PIPELINE_BOUND
SDL_GPU_CheckGraphicsBindings(render_pass);
}
RENDERPASS_DEVICE->DrawIndexedPrimitivesIndirect(
@@ -1945,6 +2248,7 @@ void SDL_EndGPURenderPass(
SDL_GPURenderPass *render_pass)
{
CommandBufferCommonHeader *commandBufferCommonHeader;
commandBufferCommonHeader = (CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER;
if (render_pass == NULL) {
SDL_InvalidParamError("render_pass");
@@ -1958,9 +2262,22 @@ void SDL_EndGPURenderPass(
RENDERPASS_DEVICE->EndRenderPass(
RENDERPASS_COMMAND_BUFFER);
commandBufferCommonHeader = (CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER;
commandBufferCommonHeader->render_pass.in_progress = false;
commandBufferCommonHeader->graphics_pipeline_bound = false;
if (RENDERPASS_DEVICE->debug_mode) {
commandBufferCommonHeader->render_pass.in_progress = false;
for (Uint32 i = 0; i < MAX_COLOR_TARGET_BINDINGS; i += 1)
{
commandBufferCommonHeader->render_pass.color_targets[i] = NULL;
}
commandBufferCommonHeader->render_pass.num_color_targets = 0;
commandBufferCommonHeader->render_pass.depth_stencil_target = NULL;
commandBufferCommonHeader->render_pass.graphics_pipeline = NULL;
SDL_zeroa(commandBufferCommonHeader->render_pass.vertex_sampler_bound);
SDL_zeroa(commandBufferCommonHeader->render_pass.vertex_storage_texture_bound);
SDL_zeroa(commandBufferCommonHeader->render_pass.vertex_storage_buffer_bound);
SDL_zeroa(commandBufferCommonHeader->render_pass.fragment_sampler_bound);
SDL_zeroa(commandBufferCommonHeader->render_pass.fragment_storage_texture_bound);
SDL_zeroa(commandBufferCommonHeader->render_pass.fragment_storage_buffer_bound);
}
}
// Compute Pass
@@ -2004,6 +2321,16 @@ SDL_GPUComputePass *SDL_BeginGPUComputePass(
SDL_assert_release(!"Texture must be created with COMPUTE_STORAGE_WRITE or COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE flag");
return NULL;
}
if (storage_texture_bindings[i].layer >= header->info.layer_count_or_depth) {
SDL_assert_release(!"Storage texture layer index must be less than the texture's layer count!");
return NULL;
}
if (storage_texture_bindings[i].mip_level >= header->info.num_levels) {
SDL_assert_release(!"Storage texture mip level must be less than the texture's level count!");
return NULL;
}
}
// TODO: validate buffer usage?
@@ -2017,7 +2344,19 @@ SDL_GPUComputePass *SDL_BeginGPUComputePass(
num_storage_buffer_bindings);
commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
commandBufferHeader->compute_pass.in_progress = true;
if (COMMAND_BUFFER_DEVICE->debug_mode) {
commandBufferHeader->compute_pass.in_progress = true;
for (Uint32 i = 0; i < num_storage_texture_bindings; i += 1) {
commandBufferHeader->compute_pass.read_write_storage_texture_bound[i] = true;
}
for (Uint32 i = 0; i < num_storage_buffer_bindings; i += 1) {
commandBufferHeader->compute_pass.read_write_storage_buffer_bound[i] = true;
}
}
return (SDL_GPUComputePass *)&(commandBufferHeader->compute_pass);
}
@@ -2025,8 +2364,6 @@ void SDL_BindGPUComputePipeline(
SDL_GPUComputePass *compute_pass,
SDL_GPUComputePipeline *compute_pipeline)
{
CommandBufferCommonHeader *commandBufferHeader;
if (compute_pass == NULL) {
SDL_InvalidParamError("compute_pass");
return;
@@ -2044,8 +2381,10 @@ void SDL_BindGPUComputePipeline(
COMPUTEPASS_COMMAND_BUFFER,
compute_pipeline);
commandBufferHeader = (CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER;
commandBufferHeader->compute_pipeline_bound = true;
if (COMPUTEPASS_DEVICE->debug_mode) {
COMPUTEPASS_BOUND_PIPELINE = compute_pipeline;
}
}
void SDL_BindGPUComputeSamplers(
@@ -2065,6 +2404,10 @@ void SDL_BindGPUComputeSamplers(
if (COMPUTEPASS_DEVICE->debug_mode) {
CHECK_COMPUTEPASS
for (Uint32 i = 0; i < num_bindings; i += 1) {
((ComputePass *)compute_pass)->sampler_bound[first_slot + i] = true;
}
}
COMPUTEPASS_DEVICE->BindComputeSamplers(
@@ -2091,6 +2434,10 @@ void SDL_BindGPUComputeStorageTextures(
if (COMPUTEPASS_DEVICE->debug_mode) {
CHECK_COMPUTEPASS
for (Uint32 i = 0; i < num_bindings; i += 1) {
((ComputePass *)compute_pass)->read_only_storage_texture_bound[first_slot + i] = true;
}
}
COMPUTEPASS_DEVICE->BindComputeStorageTextures(
@@ -2117,6 +2464,10 @@ void SDL_BindGPUComputeStorageBuffers(
if (COMPUTEPASS_DEVICE->debug_mode) {
CHECK_COMPUTEPASS
for (Uint32 i = 0; i < num_bindings; i += 1) {
((ComputePass *)compute_pass)->read_only_storage_buffer_bound[first_slot + i] = true;
}
}
COMPUTEPASS_DEVICE->BindComputeStorageBuffers(
@@ -2140,6 +2491,7 @@ void SDL_DispatchGPUCompute(
if (COMPUTEPASS_DEVICE->debug_mode) {
CHECK_COMPUTEPASS
CHECK_COMPUTE_PIPELINE_BOUND
SDL_GPU_CheckComputeBindings(compute_pass);
}
COMPUTEPASS_DEVICE->DispatchCompute(
@@ -2162,6 +2514,7 @@ void SDL_DispatchGPUComputeIndirect(
if (COMPUTEPASS_DEVICE->debug_mode) {
CHECK_COMPUTEPASS
CHECK_COMPUTE_PIPELINE_BOUND
SDL_GPU_CheckComputeBindings(compute_pass);
}
COMPUTEPASS_DEVICE->DispatchComputeIndirect(
@@ -2187,9 +2540,16 @@ void SDL_EndGPUComputePass(
COMPUTEPASS_DEVICE->EndComputePass(
COMPUTEPASS_COMMAND_BUFFER);
commandBufferCommonHeader = (CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER;
commandBufferCommonHeader->compute_pass.in_progress = false;
commandBufferCommonHeader->compute_pipeline_bound = false;
if (COMPUTEPASS_DEVICE->debug_mode) {
commandBufferCommonHeader = (CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER;
commandBufferCommonHeader->compute_pass.in_progress = false;
commandBufferCommonHeader->compute_pass.compute_pipeline = false;
SDL_zeroa(commandBufferCommonHeader->compute_pass.sampler_bound);
SDL_zeroa(commandBufferCommonHeader->compute_pass.read_only_storage_texture_bound);
SDL_zeroa(commandBufferCommonHeader->compute_pass.read_only_storage_buffer_bound);
SDL_zeroa(commandBufferCommonHeader->compute_pass.read_write_storage_texture_bound);
SDL_zeroa(commandBufferCommonHeader->compute_pass.read_write_storage_buffer_bound);
}
}
// TransferBuffer Data
@@ -2247,7 +2607,11 @@ SDL_GPUCopyPass *SDL_BeginGPUCopyPass(
command_buffer);
commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
commandBufferHeader->copy_pass.in_progress = true;
if (COMMAND_BUFFER_DEVICE->debug_mode) {
commandBufferHeader->copy_pass.in_progress = true;
}
return (SDL_GPUCopyPass *)&(commandBufferHeader->copy_pass);
}
@@ -2498,7 +2862,9 @@ void SDL_EndGPUCopyPass(
COPYPASS_DEVICE->EndCopyPass(
COPYPASS_COMMAND_BUFFER);
((CommandBufferCommonHeader *)COPYPASS_COMMAND_BUFFER)->copy_pass.in_progress = false;
if (COPYPASS_DEVICE->debug_mode) {
((CommandBufferCommonHeader *)COPYPASS_COMMAND_BUFFER)->copy_pass.in_progress = false;
}
}
void SDL_GenerateMipmapsForGPUTexture(
@@ -2528,11 +2894,19 @@ void SDL_GenerateMipmapsForGPUTexture(
SDL_assert_release(!"GenerateMipmaps texture must be created with SAMPLER and COLOR_TARGET usage flags!");
return;
}
CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
commandBufferHeader->ignore_render_pass_texture_validation = true;
}
COMMAND_BUFFER_DEVICE->GenerateMipmaps(
command_buffer,
texture);
if (COMMAND_BUFFER_DEVICE->debug_mode) {
CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
commandBufferHeader->ignore_render_pass_texture_validation = false;
}
}
void SDL_BlitGPUTexture(
+79 -19
View File
@@ -24,6 +24,21 @@
#ifndef SDL_GPU_DRIVER_H
#define SDL_GPU_DRIVER_H
// GraphicsDevice Limits
#define MAX_TEXTURE_SAMPLERS_PER_STAGE 16
#define MAX_STORAGE_TEXTURES_PER_STAGE 8
#define MAX_STORAGE_BUFFERS_PER_STAGE 8
#define MAX_UNIFORM_BUFFERS_PER_STAGE 4
#define MAX_COMPUTE_WRITE_TEXTURES 8
#define MAX_COMPUTE_WRITE_BUFFERS 8
#define UNIFORM_BUFFER_SIZE 32768
#define MAX_VERTEX_BUFFERS 16
#define MAX_VERTEX_ATTRIBUTES 16
#define MAX_COLOR_TARGET_BINDINGS 4
#define MAX_PRESENT_COUNT 16
#define MAX_FRAMES_IN_FLIGHT 3
// Common Structs
typedef struct Pass
@@ -32,16 +47,51 @@ typedef struct Pass
bool in_progress;
} Pass;
typedef struct ComputePass
{
SDL_GPUCommandBuffer *command_buffer;
bool in_progress;
SDL_GPUComputePipeline *compute_pipeline;
bool sampler_bound[MAX_TEXTURE_SAMPLERS_PER_STAGE];
bool read_only_storage_texture_bound[MAX_STORAGE_TEXTURES_PER_STAGE];
bool read_only_storage_buffer_bound[MAX_STORAGE_BUFFERS_PER_STAGE];
bool read_write_storage_texture_bound[MAX_COMPUTE_WRITE_TEXTURES];
bool read_write_storage_buffer_bound[MAX_COMPUTE_WRITE_BUFFERS];
} ComputePass;
typedef struct RenderPass
{
SDL_GPUCommandBuffer *command_buffer;
bool in_progress;
SDL_GPUTexture *color_targets[MAX_COLOR_TARGET_BINDINGS];
Uint32 num_color_targets;
SDL_GPUTexture *depth_stencil_target;
SDL_GPUGraphicsPipeline *graphics_pipeline;
bool vertex_sampler_bound[MAX_TEXTURE_SAMPLERS_PER_STAGE];
bool vertex_storage_texture_bound[MAX_STORAGE_TEXTURES_PER_STAGE];
bool vertex_storage_buffer_bound[MAX_STORAGE_BUFFERS_PER_STAGE];
bool fragment_sampler_bound[MAX_TEXTURE_SAMPLERS_PER_STAGE];
bool fragment_storage_texture_bound[MAX_STORAGE_TEXTURES_PER_STAGE];
bool fragment_storage_buffer_bound[MAX_STORAGE_BUFFERS_PER_STAGE];
} RenderPass;
typedef struct CommandBufferCommonHeader
{
SDL_GPUDevice *device;
Pass render_pass;
bool graphics_pipeline_bound;
Pass compute_pass;
bool compute_pipeline_bound;
RenderPass render_pass;
ComputePass compute_pass;
Pass copy_pass;
bool swapchain_texture_acquired;
bool submitted;
// used to avoid tripping assert on GenerateMipmaps
bool ignore_render_pass_texture_validation;
} CommandBufferCommonHeader;
typedef struct TextureCommonHeader
@@ -49,6 +99,29 @@ typedef struct TextureCommonHeader
SDL_GPUTextureCreateInfo info;
} TextureCommonHeader;
typedef struct GraphicsPipelineCommonHeader
{
Uint32 num_vertex_samplers;
Uint32 num_vertex_storage_textures;
Uint32 num_vertex_storage_buffers;
Uint32 num_vertex_uniform_buffers;
Uint32 num_fragment_samplers;
Uint32 num_fragment_storage_textures;
Uint32 num_fragment_storage_buffers;
Uint32 num_fragment_uniform_buffers;
} GraphicsPipelineCommonHeader;
typedef struct ComputePipelineCommonHeader
{
Uint32 numSamplers;
Uint32 numReadonlyStorageTextures;
Uint32 numReadonlyStorageBuffers;
Uint32 numReadWriteStorageTextures;
Uint32 numReadWriteStorageBuffers;
Uint32 numUniformBuffers;
} ComputePipelineCommonHeader;
typedef struct BlitFragmentUniforms
{
// texcoord space
@@ -136,6 +209,7 @@ static inline Sint32 Texture_GetBlockWidth(
case SDL_GPU_TEXTUREFORMAT_BC6H_RGB_FLOAT:
case SDL_GPU_TEXTUREFORMAT_BC6H_RGB_UFLOAT:
case SDL_GPU_TEXTUREFORMAT_BC1_RGBA_UNORM_SRGB:
case SDL_GPU_TEXTUREFORMAT_BC2_RGBA_UNORM_SRGB:
case SDL_GPU_TEXTUREFORMAT_BC3_RGBA_UNORM_SRGB:
case SDL_GPU_TEXTUREFORMAT_BC7_RGBA_UNORM_SRGB:
case SDL_GPU_TEXTUREFORMAT_ASTC_4x4_UNORM:
@@ -253,6 +327,7 @@ static inline Sint32 Texture_GetBlockHeight(
case SDL_GPU_TEXTUREFORMAT_BC6H_RGB_FLOAT:
case SDL_GPU_TEXTUREFORMAT_BC6H_RGB_UFLOAT:
case SDL_GPU_TEXTUREFORMAT_BC1_RGBA_UNORM_SRGB:
case SDL_GPU_TEXTUREFORMAT_BC2_RGBA_UNORM_SRGB:
case SDL_GPU_TEXTUREFORMAT_BC3_RGBA_UNORM_SRGB:
case SDL_GPU_TEXTUREFORMAT_BC7_RGBA_UNORM_SRGB:
case SDL_GPU_TEXTUREFORMAT_ASTC_5x4_UNORM:
@@ -385,21 +460,6 @@ static inline Uint32 BytesPerRow(
return blocksPerRow * SDL_GPUTextureFormatTexelBlockSize(format);
}
// GraphicsDevice Limits
#define MAX_TEXTURE_SAMPLERS_PER_STAGE 16
#define MAX_STORAGE_TEXTURES_PER_STAGE 8
#define MAX_STORAGE_BUFFERS_PER_STAGE 8
#define MAX_UNIFORM_BUFFERS_PER_STAGE 4
#define MAX_COMPUTE_WRITE_TEXTURES 8
#define MAX_COMPUTE_WRITE_BUFFERS 8
#define UNIFORM_BUFFER_SIZE 32768
#define MAX_VERTEX_BUFFERS 16
#define MAX_VERTEX_ATTRIBUTES 16
#define MAX_COLOR_TARGET_BINDINGS 4
#define MAX_PRESENT_COUNT 16
#define MAX_FRAMES_IN_FLIGHT 3
// Internal Macros
#define EXPAND_ARRAY_IF_NEEDED(arr, elementType, newCount, capacity, newCapacity) \
File diff suppressed because it is too large. Load diff
+69 -74
View File
@@ -476,33 +476,21 @@ typedef struct MetalShader
typedef struct MetalGraphicsPipeline
{
GraphicsPipelineCommonHeader header;
id<MTLRenderPipelineState> handle;
SDL_GPURasterizerState rasterizerState;
SDL_GPUPrimitiveType primitiveType;
id<MTLDepthStencilState> depth_stencil_state;
Uint32 vertexSamplerCount;
Uint32 vertexUniformBufferCount;
Uint32 vertexStorageBufferCount;
Uint32 vertexStorageTextureCount;
Uint32 fragmentSamplerCount;
Uint32 fragmentUniformBufferCount;
Uint32 fragmentStorageBufferCount;
Uint32 fragmentStorageTextureCount;
} MetalGraphicsPipeline;
typedef struct MetalComputePipeline
{
ComputePipelineCommonHeader header;
id<MTLComputePipelineState> handle;
Uint32 numSamplers;
Uint32 numReadonlyStorageTextures;
Uint32 numReadWriteStorageTextures;
Uint32 numReadonlyStorageBuffers;
Uint32 numReadWriteStorageBuffers;
Uint32 numUniformBuffers;
Uint32 threadcountX;
Uint32 threadcountY;
Uint32 threadcountZ;
@@ -840,6 +828,10 @@ static MetalLibraryFunction METAL_INTERNAL_CompileShader(
dispatch_data_t data;
id<MTLFunction> function;
if (!entrypoint) {
entrypoint = "main0";
}
if (format == SDL_GPU_SHADERFORMAT_MSL) {
NSString *codeString = [[NSString alloc]
initWithBytes:code
@@ -1055,12 +1047,12 @@ static SDL_GPUComputePipeline *METAL_CreateComputePipeline(
pipeline = SDL_calloc(1, sizeof(MetalComputePipeline));
pipeline->handle = handle;
pipeline->numSamplers = createinfo->num_samplers;
pipeline->numReadonlyStorageTextures = createinfo->num_readonly_storage_textures;
pipeline->numReadWriteStorageTextures = createinfo->num_readwrite_storage_textures;
pipeline->numReadonlyStorageBuffers = createinfo->num_readonly_storage_buffers;
pipeline->numReadWriteStorageBuffers = createinfo->num_readwrite_storage_buffers;
pipeline->numUniformBuffers = createinfo->num_uniform_buffers;
pipeline->header.numSamplers = createinfo->num_samplers;
pipeline->header.numReadonlyStorageTextures = createinfo->num_readonly_storage_textures;
pipeline->header.numReadWriteStorageTextures = createinfo->num_readwrite_storage_textures;
pipeline->header.numReadonlyStorageBuffers = createinfo->num_readonly_storage_buffers;
pipeline->header.numReadWriteStorageBuffers = createinfo->num_readwrite_storage_buffers;
pipeline->header.numUniformBuffers = createinfo->num_uniform_buffers;
pipeline->threadcountX = createinfo->threadcount_x;
pipeline->threadcountY = createinfo->threadcount_y;
pipeline->threadcountZ = createinfo->threadcount_z;
@@ -1203,14 +1195,14 @@ static SDL_GPUGraphicsPipeline *METAL_CreateGraphicsPipeline(
result->depth_stencil_state = depthStencilState;
result->rasterizerState = createinfo->rasterizer_state;
result->primitiveType = createinfo->primitive_type;
result->vertexSamplerCount = vertexShader->numSamplers;
result->vertexUniformBufferCount = vertexShader->numUniformBuffers;
result->vertexStorageBufferCount = vertexShader->numStorageBuffers;
result->vertexStorageTextureCount = vertexShader->numStorageTextures;
result->fragmentSamplerCount = fragmentShader->numSamplers;
result->fragmentUniformBufferCount = fragmentShader->numUniformBuffers;
result->fragmentStorageBufferCount = fragmentShader->numStorageBuffers;
result->fragmentStorageTextureCount = fragmentShader->numStorageTextures;
result->header.num_vertex_samplers = vertexShader->numSamplers;
result->header.num_vertex_uniform_buffers = vertexShader->numUniformBuffers;
result->header.num_vertex_storage_buffers = vertexShader->numStorageBuffers;
result->header.num_vertex_storage_textures = vertexShader->numStorageTextures;
result->header.num_fragment_samplers = fragmentShader->numSamplers;
result->header.num_fragment_uniform_buffers = fragmentShader->numUniformBuffers;
result->header.num_fragment_storage_buffers = fragmentShader->numStorageBuffers;
result->header.num_fragment_storage_textures = fragmentShader->numStorageTextures;
return (SDL_GPUGraphicsPipeline *)result;
}
}
@@ -1494,7 +1486,9 @@ static SDL_GPUTexture *METAL_CreateTexture(
// Copy properties so we don't lose information when the client destroys them
container->header.info = *createinfo;
container->header.info.props = SDL_CreateProperties();
SDL_CopyProperties(createinfo->props, container->header.info.props);
if (createinfo->props) {
SDL_CopyProperties(createinfo->props, container->header.info.props);
}
container->activeTexture = texture;
container->textureCapacity = 1;
@@ -2406,14 +2400,14 @@ static void METAL_BindGraphicsPipeline(
metalCommandBuffer->needFragmentUniformBufferBind[i] = true;
}
for (i = 0; i < pipeline->vertexUniformBufferCount; i += 1) {
for (i = 0; i < pipeline->header.num_vertex_uniform_buffers; i += 1) {
if (metalCommandBuffer->vertexUniformBuffers[i] == NULL) {
metalCommandBuffer->vertexUniformBuffers[i] = METAL_INTERNAL_AcquireUniformBufferFromPool(
metalCommandBuffer);
}
}
for (i = 0; i < pipeline->fragmentUniformBufferCount; i += 1) {
for (i = 0; i < pipeline->header.num_fragment_uniform_buffers; i += 1) {
if (metalCommandBuffer->fragmentUniformBuffers[i] == NULL) {
metalCommandBuffer->fragmentUniformBuffers[i] = METAL_INTERNAL_AcquireUniformBufferFromPool(
metalCommandBuffer);
@@ -2644,11 +2638,11 @@ static void METAL_INTERNAL_BindGraphicsResources(
// Vertex Samplers+Textures
if (commandBuffer->needVertexSamplerBind) {
if (graphicsPipeline->vertexSamplerCount > 0) {
if (graphicsPipeline->header.num_vertex_samplers > 0) {
[commandBuffer->renderEncoder setVertexSamplerStates:commandBuffer->vertexSamplers
withRange:NSMakeRange(0, graphicsPipeline->vertexSamplerCount)];
withRange:NSMakeRange(0, graphicsPipeline->header.num_vertex_samplers)];
[commandBuffer->renderEncoder setVertexTextures:commandBuffer->vertexTextures
withRange:NSMakeRange(0, graphicsPipeline->vertexSamplerCount)];
withRange:NSMakeRange(0, graphicsPipeline->header.num_vertex_samplers)];
}
commandBuffer->needVertexSamplerBind = false;
}
@@ -2656,10 +2650,10 @@ static void METAL_INTERNAL_BindGraphicsResources(
// Vertex Storage Textures
if (commandBuffer->needVertexStorageTextureBind) {
if (graphicsPipeline->vertexStorageTextureCount > 0) {
if (graphicsPipeline->header.num_vertex_storage_textures > 0) {
[commandBuffer->renderEncoder setVertexTextures:commandBuffer->vertexStorageTextures
withRange:NSMakeRange(graphicsPipeline->vertexSamplerCount,
graphicsPipeline->vertexStorageTextureCount)];
withRange:NSMakeRange(graphicsPipeline->header.num_vertex_samplers,
graphicsPipeline->header.num_vertex_storage_textures)];
}
commandBuffer->needVertexStorageTextureBind = false;
}
@@ -2667,20 +2661,20 @@ static void METAL_INTERNAL_BindGraphicsResources(
// Vertex Storage Buffers
if (commandBuffer->needVertexStorageBufferBind) {
if (graphicsPipeline->vertexStorageBufferCount > 0) {
if (graphicsPipeline->header.num_vertex_storage_buffers > 0) {
[commandBuffer->renderEncoder setVertexBuffers:commandBuffer->vertexStorageBuffers
offsets:offsets
withRange:NSMakeRange(graphicsPipeline->vertexUniformBufferCount,
graphicsPipeline->vertexStorageBufferCount)];
withRange:NSMakeRange(graphicsPipeline->header.num_vertex_uniform_buffers,
graphicsPipeline->header.num_vertex_storage_buffers)];
}
commandBuffer->needVertexStorageBufferBind = false;
}
// Vertex Uniform Buffers
for (Uint32 i = 0; i < graphicsPipeline->vertexUniformBufferCount; i += 1) {
for (Uint32 i = 0; i < graphicsPipeline->header.num_vertex_uniform_buffers; i += 1) {
if (commandBuffer->needVertexUniformBufferBind[i]) {
if (graphicsPipeline->vertexUniformBufferCount > i) {
if (graphicsPipeline->header.num_vertex_uniform_buffers > i) {
[commandBuffer->renderEncoder
setVertexBuffer:commandBuffer->vertexUniformBuffers[i]->handle
offset:commandBuffer->vertexUniformBuffers[i]->drawOffset
@@ -2693,11 +2687,11 @@ static void METAL_INTERNAL_BindGraphicsResources(
// Fragment Samplers+Textures
if (commandBuffer->needFragmentSamplerBind) {
if (graphicsPipeline->fragmentSamplerCount > 0) {
if (graphicsPipeline->header.num_fragment_samplers > 0) {
[commandBuffer->renderEncoder setFragmentSamplerStates:commandBuffer->fragmentSamplers
withRange:NSMakeRange(0, graphicsPipeline->fragmentSamplerCount)];
withRange:NSMakeRange(0, graphicsPipeline->header.num_fragment_samplers)];
[commandBuffer->renderEncoder setFragmentTextures:commandBuffer->fragmentTextures
withRange:NSMakeRange(0, graphicsPipeline->fragmentSamplerCount)];
withRange:NSMakeRange(0, graphicsPipeline->header.num_fragment_samplers)];
}
commandBuffer->needFragmentSamplerBind = false;
}
@@ -2705,10 +2699,10 @@ static void METAL_INTERNAL_BindGraphicsResources(
// Fragment Storage Textures
if (commandBuffer->needFragmentStorageTextureBind) {
if (graphicsPipeline->fragmentStorageTextureCount > 0) {
if (graphicsPipeline->header.num_fragment_storage_textures > 0) {
[commandBuffer->renderEncoder setFragmentTextures:commandBuffer->fragmentStorageTextures
withRange:NSMakeRange(graphicsPipeline->fragmentSamplerCount,
graphicsPipeline->fragmentStorageTextureCount)];
withRange:NSMakeRange(graphicsPipeline->header.num_fragment_samplers,
graphicsPipeline->header.num_fragment_storage_textures)];
}
commandBuffer->needFragmentStorageTextureBind = false;
}
@@ -2716,20 +2710,20 @@ static void METAL_INTERNAL_BindGraphicsResources(
// Fragment Storage Buffers
if (commandBuffer->needFragmentStorageBufferBind) {
if (graphicsPipeline->fragmentStorageBufferCount > 0) {
if (graphicsPipeline->header.num_fragment_storage_buffers > 0) {
[commandBuffer->renderEncoder setFragmentBuffers:commandBuffer->fragmentStorageBuffers
offsets:offsets
withRange:NSMakeRange(graphicsPipeline->fragmentUniformBufferCount,
graphicsPipeline->fragmentStorageBufferCount)];
withRange:NSMakeRange(graphicsPipeline->header.num_fragment_uniform_buffers,
graphicsPipeline->header.num_fragment_storage_buffers)];
}
commandBuffer->needFragmentStorageBufferBind = false;
}
// Fragment Uniform Buffers
for (Uint32 i = 0; i < graphicsPipeline->fragmentUniformBufferCount; i += 1) {
for (Uint32 i = 0; i < graphicsPipeline->header.num_fragment_uniform_buffers; i += 1) {
if (commandBuffer->needFragmentUniformBufferBind[i]) {
if (graphicsPipeline->fragmentUniformBufferCount > i) {
if (graphicsPipeline->header.num_fragment_uniform_buffers > i) {
[commandBuffer->renderEncoder
setFragmentBuffer:commandBuffer->fragmentUniformBuffers[i]->handle
offset:commandBuffer->fragmentUniformBuffers[i]->drawOffset
@@ -2748,38 +2742,38 @@ static void METAL_INTERNAL_BindComputeResources(
NSUInteger offsets[MAX_STORAGE_BUFFERS_PER_STAGE] = { 0 };
if (commandBuffer->needComputeSamplerBind) {
if (computePipeline->numSamplers > 0) {
if (computePipeline->header.numSamplers > 0) {
[commandBuffer->computeEncoder setTextures:commandBuffer->computeSamplerTextures
withRange:NSMakeRange(0, computePipeline->numSamplers)];
withRange:NSMakeRange(0, computePipeline->header.numSamplers)];
[commandBuffer->computeEncoder setSamplerStates:commandBuffer->computeSamplers
withRange:NSMakeRange(0, computePipeline->numSamplers)];
withRange:NSMakeRange(0, computePipeline->header.numSamplers)];
}
commandBuffer->needComputeSamplerBind = false;
}
if (commandBuffer->needComputeReadOnlyStorageTextureBind) {
if (computePipeline->numReadonlyStorageTextures > 0) {
if (computePipeline->header.numReadonlyStorageTextures > 0) {
[commandBuffer->computeEncoder setTextures:commandBuffer->computeReadOnlyTextures
withRange:NSMakeRange(
computePipeline->numSamplers,
computePipeline->numReadonlyStorageTextures)];
computePipeline->header.numSamplers,
computePipeline->header.numReadonlyStorageTextures)];
}
commandBuffer->needComputeReadOnlyStorageTextureBind = false;
}
if (commandBuffer->needComputeReadOnlyStorageBufferBind) {
if (computePipeline->numReadonlyStorageBuffers > 0) {
if (computePipeline->header.numReadonlyStorageBuffers > 0) {
[commandBuffer->computeEncoder setBuffers:commandBuffer->computeReadOnlyBuffers
offsets:offsets
withRange:NSMakeRange(computePipeline->numUniformBuffers,
computePipeline->numReadonlyStorageBuffers)];
withRange:NSMakeRange(computePipeline->header.numUniformBuffers,
computePipeline->header.numReadonlyStorageBuffers)];
}
commandBuffer->needComputeReadOnlyStorageBufferBind = false;
}
for (Uint32 i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) {
if (commandBuffer->needComputeUniformBufferBind[i]) {
if (computePipeline->numUniformBuffers > i) {
if (computePipeline->header.numUniformBuffers > i) {
[commandBuffer->computeEncoder
setBuffer:commandBuffer->computeUniformBuffers[i]->handle
offset:commandBuffer->computeUniformBuffers[i]->drawOffset
@@ -3127,7 +3121,7 @@ static void METAL_BindComputePipeline(
metalCommandBuffer->needComputeUniformBufferBind[i] = true;
}
for (Uint32 i = 0; i < pipeline->numUniformBuffers; i += 1) {
for (Uint32 i = 0; i < pipeline->header.numUniformBuffers; i += 1) {
if (metalCommandBuffer->computeUniformBuffers[i] == NULL) {
metalCommandBuffer->computeUniformBuffers[i] = METAL_INTERNAL_AcquireUniformBufferFromPool(
metalCommandBuffer);
@@ -3135,22 +3129,22 @@ static void METAL_BindComputePipeline(
}
// Bind write-only resources
if (pipeline->numReadWriteStorageTextures > 0) {
if (pipeline->header.numReadWriteStorageTextures > 0) {
[metalCommandBuffer->computeEncoder setTextures:metalCommandBuffer->computeReadWriteTextures
withRange:NSMakeRange(
pipeline->numSamplers +
pipeline->numReadonlyStorageTextures,
pipeline->numReadWriteStorageTextures)];
pipeline->header.numSamplers +
pipeline->header.numReadonlyStorageTextures,
pipeline->header.numReadWriteStorageTextures)];
}
NSUInteger offsets[MAX_COMPUTE_WRITE_BUFFERS] = { 0 };
if (pipeline->numReadWriteStorageBuffers > 0) {
if (pipeline->header.numReadWriteStorageBuffers > 0) {
[metalCommandBuffer->computeEncoder setBuffers:metalCommandBuffer->computeReadWriteBuffers
offsets:offsets
withRange:NSMakeRange(
pipeline->numUniformBuffers +
pipeline->numReadonlyStorageBuffers,
pipeline->numReadWriteStorageBuffers)];
pipeline->header.numUniformBuffers +
pipeline->header.numReadonlyStorageBuffers,
pipeline->header.numReadWriteStorageBuffers)];
}
}
}
@@ -4564,6 +4558,7 @@ static SDL_GPUDevice *METAL_CreateDevice(bool debugMode, bool preferLowPower, SD
SDL_GPUDevice *result = SDL_calloc(1, sizeof(SDL_GPUDevice));
ASSIGN_DRIVER(METAL)
result->driverData = (SDL_GPURenderer *)renderer;
result->shader_formats = SDL_GPU_SHADERFORMAT_MSL | SDL_GPU_SHADERFORMAT_METALLIB;
renderer->sdlGPUDevice = result;
return result;
File diff suppressed because it is too large. Load diff
+2
View File
@@ -807,6 +807,8 @@ typedef struct LIBUSB_hid_device_ LIBUSB_hid_device;
#define hid_send_feature_report LIBUSB_hid_send_feature_report
#define hid_set_nonblocking LIBUSB_hid_set_nonblocking
#define hid_write LIBUSB_hid_write
#define hid_version LIBUSB_hid_version
#define hid_version_str LIBUSB_hid_version_str
#define input_report LIBUSB_input_report
#define make_path LIBUSB_make_path
#define new_hid_device LIBUSB_new_hid_device
+4
View File
@@ -62,6 +62,10 @@
#define wcsstr SDL_wcsstr
#define wcstol SDL_wcstol
// These functions conflict when linking both SDL and hidapi statically
#define hid_winapi_descriptor_reconstruct_pp_data SDL_hid_winapi_descriptor_reconstruct_pp_data
#define hid_winapi_get_container_id SDL_hid_winapi_get_container_id
#undef HIDAPI_H__
#include "windows/hid.c"
#define HAVE_PLATFORM_BACKEND 1
+1
View File
@@ -1238,6 +1238,7 @@ static void init_xbox360(libusb_device_handle *device_handle, unsigned short idV
(void)conf_desc;
if ((idVendor == 0x05ac && idProduct == 0x055b) /* Gamesir-G3w */ ||
(idVendor == 0x20d6 && idProduct == 0x4010) /* PowerA Battle Dragon Advanced Wireless Controller */ ||
idVendor == 0x0f0d /* Hori Xbox controllers */) {
unsigned char data[20];
+13 -7
View File
@@ -775,13 +775,7 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid)
// All other gamepads have the standard set of 19 buttons and 6 axes
SDL_strlcat(mapping_string, "a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,", sizeof(mapping_string));
if (SDL_IsJoystickXboxSeriesX(vendor, product)) {
// XBox Series X Controllers have a share button under the guide button
SDL_strlcat(mapping_string, "misc1:b11,", sizeof(mapping_string));
} else if (SDL_IsJoystickXboxOneElite(vendor, product)) {
// XBox One Elite Controllers have 4 back paddle buttons
SDL_strlcat(mapping_string, "paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,", sizeof(mapping_string));
} else if (SDL_IsJoystickSteamController(vendor, product)) {
if (SDL_IsJoystickSteamController(vendor, product)) {
// Steam controllers have 2 back paddle buttons
SDL_strlcat(mapping_string, "paddle1:b12,paddle2:b11,", sizeof(mapping_string));
} else if (SDL_IsJoystickNintendoSwitchPro(vendor, product) ||
@@ -822,6 +816,15 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid)
SDL_strlcat(mapping_string, "paddle1:b16,paddle2:b15,paddle3:b14,paddle4:b13,", sizeof(mapping_string));
}
break;
case SDL_GAMEPAD_TYPE_XBOXONE:
if (SDL_IsJoystickXboxOneElite(vendor, product)) {
// XBox One Elite Controllers have 4 back paddle buttons
SDL_strlcat(mapping_string, "paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,", sizeof(mapping_string));
} else if (SDL_IsJoystickXboxSeriesX(vendor, product)) {
// XBox Series X Controllers have a share button under the guide button
SDL_strlcat(mapping_string, "misc1:b11,", sizeof(mapping_string));
}
break;
default:
if (vendor == 0 && product == 0) {
// This is a Bluetooth Nintendo Switch Pro controller
@@ -2751,6 +2754,7 @@ SDL_Gamepad *SDL_OpenGamepad(SDL_JoystickID instance_id)
gamepad->joystick = SDL_OpenJoystick(instance_id);
if (!gamepad->joystick) {
SDL_SetObjectValid(gamepad, SDL_OBJECT_TYPE_GAMEPAD, false);
SDL_free(gamepad);
SDL_UnlockJoysticks();
return NULL;
@@ -2759,6 +2763,7 @@ SDL_Gamepad *SDL_OpenGamepad(SDL_JoystickID instance_id)
if (gamepad->joystick->naxes) {
gamepad->last_match_axis = (SDL_GamepadBinding **)SDL_calloc(gamepad->joystick->naxes, sizeof(*gamepad->last_match_axis));
if (!gamepad->last_match_axis) {
SDL_SetObjectValid(gamepad, SDL_OBJECT_TYPE_GAMEPAD, false);
SDL_CloseJoystick(gamepad->joystick);
SDL_free(gamepad);
SDL_UnlockJoysticks();
@@ -2768,6 +2773,7 @@ SDL_Gamepad *SDL_OpenGamepad(SDL_JoystickID instance_id)
if (gamepad->joystick->nhats) {
gamepad->last_hat_mask = (Uint8 *)SDL_calloc(gamepad->joystick->nhats, sizeof(*gamepad->last_hat_mask));
if (!gamepad->last_hat_mask) {
SDL_SetObjectValid(gamepad, SDL_OBJECT_TYPE_GAMEPAD, false);
SDL_CloseJoystick(gamepad->joystick);
SDL_free(gamepad->last_match_axis);
SDL_free(gamepad);
+6 -3
View File
@@ -215,7 +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,",
"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,rightx:a3,righty:a4,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,",
@@ -421,7 +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,",
"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,rightx:a3,righty:a4,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,",
@@ -553,6 +553,7 @@ static const char *s_GamepadMappings[] = {
"03000000341a000005f7000010010000,GameCube {HuiJia USB box},a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,",
"03000000bc2000000055000011010000,GameSir G3w,a:b0,b:b1,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:b3,y:b4,",
"0500000049190000020400001b010000,GameSir T4 Pro,crc:8283,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b23,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"03000000373500009710000001020000,GameSir-K1 FLUX,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"03000000ac0500001a06000011010000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"0500000047532047616d657061640000,GameStop Gamepad,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,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"03000000c01100000140000011010000,GameStop PS4 Fun Controller,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:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
@@ -867,7 +868,9 @@ static const char *s_GamepadMappings[] = {
"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,",
"05000000ac05000004000000fd216d04,8BitDo Pro 2,crc:ac95,a:b3,b:b2,back:b6,dpdown:b9,dpleft:b10,dpright:b11,dpup:b12,guide:b4,leftshoulder:b13,leftstick:b14,lefttrigger:+a2,leftx:a0,lefty:a1~,paddle1:b1,paddle2:b0,rightshoulder:b16,rightstick:b17,righttrigger:+a5,rightx:a3,righty:a4~,start:b5,x:b8,y:b7,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,",
"05000000ac05000004000000209f6d04,8Bitdo SN30 Pro,crc:40d6,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,",
@@ -904,7 +907,7 @@ static const char *s_GamepadMappings[] = {
"0000000050535669746120436f6e7400,PSVita Controller,crc:d598,a:b2,b:b1,back:b10,dpdown:b6,dpleft:b7,dpright:b9,dpup:b8,leftshoulder:b4,leftstick:b14,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,",
#endif
#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,",
"000000004e696e74656e646f20334400,Nintendo 3DS,crc:3210,a:b1,b:b0,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:b11,y:b10,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
#endif
NULL
};
+72 -3
View File
@@ -277,6 +277,7 @@ static Uint32 initial_blacklist_devices[] = {
MAKE_VIDPID(0x1532, 0x0282), // Razer Huntsman Mini Analog, non-functional DInput device
MAKE_VIDPID(0x26ce, 0x01a2), // ASRock LED Controller
MAKE_VIDPID(0x20d6, 0x0002), // PowerA Enhanced Wireless Controller for Nintendo Switch (charging port only)
MAKE_VIDPID(0x3434, 0x0211), // Keychron K1 Pro System Control
};
static SDL_vidpid_list blacklist_devices = {
SDL_HINT_JOYSTICK_BLACKLIST_DEVICES, 0, 0, NULL,
@@ -289,7 +290,17 @@ static Uint32 initial_flightstick_devices[] = {
MAKE_VIDPID(0x044f, 0x0402), // HOTAS Warthog Joystick
MAKE_VIDPID(0x044f, 0xb10a), // ThrustMaster, Inc. T.16000M Joystick
MAKE_VIDPID(0x046d, 0xc215), // Logitech Extreme 3D
MAKE_VIDPID(0x0583, 0x6258), // Padix USB joystick with viewfinder
MAKE_VIDPID(0x0583, 0x688f), // Padix QF-688uv Windstorm Pro
MAKE_VIDPID(0x0583, 0x7070), // Padix QF-707u Bazooka
MAKE_VIDPID(0x0583, 0xa019), // Padix USB vibration joystick with viewfinder
MAKE_VIDPID(0x0583, 0xa131), // Padix USB Wireless 2.4GHz
MAKE_VIDPID(0x0583, 0xa209), // Padix MetalStrike ForceFeedback
MAKE_VIDPID(0x0583, 0xb010), // Padix MetalStrike Pro
MAKE_VIDPID(0x0583, 0xb012), // Padix Wireless MetalStrike
MAKE_VIDPID(0x0583, 0xb013), // Padix USB Wireless 2.4GHZ
MAKE_VIDPID(0x0738, 0x2221), // Saitek Pro Flight X-56 Rhino Stick
MAKE_VIDPID(0x10f5, 0x7084), // Turtle Beach VelocityOne
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
@@ -331,6 +342,7 @@ static SDL_vidpid_list rog_gamepad_mice = {
static Uint32 initial_throttle_devices[] = {
MAKE_VIDPID(0x044f, 0x0404), // HOTAS Warthog Throttle
MAKE_VIDPID(0x0738, 0xa221), // Saitek Pro Flight X-56 Rhino Throttle
MAKE_VIDPID(0x10f5, 0x7085), // Turtle Beach VelocityOne Throttle
};
static SDL_vidpid_list throttle_devices = {
SDL_HINT_JOYSTICK_THROTTLE_DEVICES, 0, 0, NULL,
@@ -374,6 +386,14 @@ static Uint32 initial_wheel_devices[] = {
MAKE_VIDPID(0x046d, 0xca03), // Logitech Momo Racing
MAKE_VIDPID(0x0483, 0x0522), // Simagic Wheelbase (including M10, Alpha Mini, Alpha, Alpha U)
MAKE_VIDPID(0x0483, 0xa355), // VRS DirectForce Pro Wheel Base
MAKE_VIDPID(0x0583, 0xa132), // Padix USB Wireless 2.4GHz Wheelpad
MAKE_VIDPID(0x0583, 0xa133), // Padix USB Wireless 2.4GHz Wheel
MAKE_VIDPID(0x0583, 0xa202), // Padix Force Feedback Wheel
MAKE_VIDPID(0x0583, 0xb002), // Padix Vibration USB Wheel
MAKE_VIDPID(0x0583, 0xb005), // Padix USB Wheel
MAKE_VIDPID(0x0583, 0xb008), // Padix USB Wireless 2.4GHz Wheel
MAKE_VIDPID(0x0583, 0xb009), // Padix USB Wheel
MAKE_VIDPID(0x0583, 0xb018), // Padix TW6 Wheel
MAKE_VIDPID(0x0eb7, 0x0001), // Fanatec ClubSport Wheel Base V2
MAKE_VIDPID(0x0eb7, 0x0004), // Fanatec ClubSport Wheel Base V2.5
MAKE_VIDPID(0x0eb7, 0x0005), // Fanatec CSL Elite Wheel Base+ (PS4)
@@ -1122,7 +1142,11 @@ SDL_Joystick *SDL_OpenJoystick(SDL_JoystickID instance_id)
joystick->attached = true;
joystick->led_expiration = SDL_GetTicks();
joystick->battery_percent = -1;
#ifdef SDL_JOYSTICK_VIRTUAL
joystick->is_virtual = (driver == &SDL_VIRTUAL_JoystickDriver);
#else
joystick->is_virtual = false;
#endif
if (!driver->Open(joystick, device_index)) {
SDL_SetObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK, false);
@@ -1166,9 +1190,35 @@ SDL_Joystick *SDL_OpenJoystick(SDL_JoystickID instance_id)
// If this joystick is known to have all zero centered axes, skip the auto-centering code
if (SDL_JoystickAxesCenteredAtZero(joystick)) {
int i;
for (int i = 0; i < joystick->naxes; ++i) {
joystick->axes[i].has_initial_value = true;
}
}
for (i = 0; i < joystick->naxes; ++i) {
// We know the initial values for HIDAPI and XInput joysticks
if ((SDL_IsJoystickHIDAPI(joystick->guid) ||
SDL_IsJoystickXInput(joystick->guid) ||
SDL_IsJoystickRAWINPUT(joystick->guid) ||
SDL_IsJoystickWGI(joystick->guid)) &&
joystick->naxes >= SDL_GAMEPAD_AXIS_COUNT) {
int left_trigger, right_trigger;
if (SDL_IsJoystickXInput(joystick->guid)) {
left_trigger = 2;
right_trigger = 5;
} else {
left_trigger = SDL_GAMEPAD_AXIS_LEFT_TRIGGER;
right_trigger = SDL_GAMEPAD_AXIS_RIGHT_TRIGGER;
}
for (int i = 0; i < SDL_GAMEPAD_AXIS_COUNT; ++i) {
int initial_value;
if (i == left_trigger || i == right_trigger) {
initial_value = SDL_MIN_SINT16;
} else {
initial_value = 0;
}
joystick->axes[i].value = initial_value;
joystick->axes[i].zero = initial_value;
joystick->axes[i].initial_value = initial_value;
joystick->axes[i].has_initial_value = true;
}
}
@@ -1814,6 +1864,14 @@ bool SDL_RumbleJoystickTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint
result = true;
} else {
result = joystick->driver->RumbleTriggers(joystick, left_rumble, right_rumble);
if (result) {
joystick->trigger_rumble_resend = SDL_GetTicks() + SDL_RUMBLE_RESEND_MS;
if (joystick->trigger_rumble_resend == 0) {
joystick->trigger_rumble_resend = 1;
}
} else {
joystick->trigger_rumble_resend = 0;
}
}
if (result) {
@@ -1824,6 +1882,7 @@ bool SDL_RumbleJoystickTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint
joystick->trigger_rumble_expiration = SDL_GetTicks() + SDL_min(duration_ms, SDL_MAX_RUMBLE_DURATION_MS);
} else {
joystick->trigger_rumble_expiration = 0;
joystick->trigger_rumble_resend = 0;
}
}
}
@@ -2478,6 +2537,15 @@ void SDL_UpdateJoysticks(void)
if (joystick->trigger_rumble_expiration && now >= joystick->trigger_rumble_expiration) {
SDL_RumbleJoystickTriggers(joystick, 0, 0, 0);
joystick->trigger_rumble_resend = 0;
}
if (joystick->trigger_rumble_resend && now >= joystick->trigger_rumble_resend) {
joystick->driver->RumbleTriggers(joystick, joystick->left_trigger_rumble, joystick->right_trigger_rumble);
joystick->trigger_rumble_resend = now + SDL_RUMBLE_RESEND_MS;
if (joystick->trigger_rumble_resend == 0) {
joystick->trigger_rumble_resend = 1;
}
}
}
@@ -2858,7 +2926,8 @@ bool SDL_IsJoystickXboxSeriesX(Uint16 vendor_id, Uint16 product_id)
}
if (vendor_id == USB_VENDOR_HORI) {
if (product_id == USB_PRODUCT_HORI_FIGHTING_COMMANDER_OCTA_SERIES_X ||
product_id == USB_PRODUCT_HORI_HORIPAD_PRO_SERIES_X) {
product_id == USB_PRODUCT_HORI_HORIPAD_PRO_SERIES_X ||
product_id == USB_PRODUCT_HORI_TAIKO_DRUM_CONTROLLER) {
return true;
}
}
+1
View File
@@ -113,6 +113,7 @@ struct SDL_Joystick
Uint16 left_trigger_rumble _guarded;
Uint16 right_trigger_rumble _guarded;
Uint64 trigger_rumble_expiration _guarded;
Uint64 trigger_rumble_resend _guarded;
Uint8 led_red _guarded;
Uint8 led_green _guarded;
+8 -2
View File
@@ -751,11 +751,12 @@ bool HIDAPI_JoystickConnected(SDL_HIDAPI_Device *device, SDL_JoystickID *pJoysti
++SDL_HIDAPI_numjoysticks;
SDL_PrivateJoystickAdded(joystickID);
if (pJoystickID) {
*pJoystickID = joystickID;
}
SDL_PrivateJoystickAdded(joystickID);
return true;
}
@@ -1051,6 +1052,11 @@ static bool HIDAPI_CreateCombinedJoyCons(void)
info.usage = USB_USAGE_GENERIC_GAMEPAD;
info.manufacturer_string = L"Nintendo";
info.product_string = L"Switch Joy-Con (L/R)";
if (children[0]->is_bluetooth || children[1]->is_bluetooth) {
info.bus_type = SDL_HID_API_BUS_BLUETOOTH;
} else {
info.bus_type = SDL_HID_API_BUS_USB;
}
combined = HIDAPI_AddDevice(&info, 2, children);
if (combined && combined->driver) {
+1
View File
@@ -76,6 +76,7 @@
#define USB_PRODUCT_HORI_FIGHTING_STICK_ALPHA_PS5 0x0184
#define USB_PRODUCT_HORI_STEAM_CONTROLLER 0x01AB
#define USB_PRODUCT_HORI_STEAM_CONTROLLER_BT 0x0196
#define USB_PRODUCT_HORI_TAIKO_DRUM_CONTROLLER 0x01b2
#define USB_PRODUCT_LOGITECH_F310 0xc216
#define USB_PRODUCT_LOGITECH_CHILLSTREAM 0xcad1
#define USB_PRODUCT_MADCATZ_SAITEK_SIDE_PANEL_CONTROL_DECK 0x2218
+9 -11
View File
@@ -158,6 +158,7 @@ struct joystick_hwdata
Uint8 wgi_correlation_count;
Uint8 wgi_uncorrelate_count;
WindowsGamingInputGamepadState *wgi_slot;
struct __x_ABI_CWindows_CGaming_CInput_CGamepadVibration vibration;
#endif
bool triggers_rumbling;
@@ -449,7 +450,6 @@ typedef struct WindowsGamingInputGamepadState
bool used; // Is currently mapped to an SDL device
bool connected; // Just used during update to track disconnected
Uint8 correlation_id;
struct __x_ABI_CWindows_CGaming_CInput_CGamepadVibration vibration;
} WindowsGamingInputGamepadState;
static struct
@@ -1030,7 +1030,7 @@ static bool RAWINPUT_JoystickInit(void)
{
SDL_assert(!SDL_RAWINPUT_inited);
if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_RAWINPUT, true)) {
if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_RAWINPUT, false)) {
return true;
}
@@ -1482,12 +1482,11 @@ static bool RAWINPUT_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency
#ifdef SDL_JOYSTICK_RAWINPUT_WGI
// Save off the motor state in case trigger rumble is started
WindowsGamingInputGamepadState *gamepad_state = ctx->wgi_slot;
HRESULT hr;
gamepad_state->vibration.LeftMotor = (DOUBLE)low_frequency_rumble / SDL_MAX_UINT16;
gamepad_state->vibration.RightMotor = (DOUBLE)high_frequency_rumble / SDL_MAX_UINT16;
ctx->vibration.LeftMotor = (DOUBLE)low_frequency_rumble / SDL_MAX_UINT16;
ctx->vibration.RightMotor = (DOUBLE)high_frequency_rumble / SDL_MAX_UINT16;
if (!rumbled && ctx->wgi_correlated) {
hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(gamepad_state->gamepad, gamepad_state->vibration);
WindowsGamingInputGamepadState *gamepad_state = ctx->wgi_slot;
HRESULT hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(gamepad_state->gamepad, ctx->vibration);
if (SUCCEEDED(hr)) {
rumbled = true;
}
@@ -1509,12 +1508,11 @@ static bool RAWINPUT_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_
#ifdef SDL_JOYSTICK_RAWINPUT_WGI
RAWINPUT_DeviceContext *ctx = joystick->hwdata;
ctx->vibration.LeftTrigger = (DOUBLE)left_rumble / SDL_MAX_UINT16;
ctx->vibration.RightTrigger = (DOUBLE)right_rumble / SDL_MAX_UINT16;
if (ctx->wgi_correlated) {
WindowsGamingInputGamepadState *gamepad_state = ctx->wgi_slot;
HRESULT hr;
gamepad_state->vibration.LeftTrigger = (DOUBLE)left_rumble / SDL_MAX_UINT16;
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);
HRESULT hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(gamepad_state->gamepad, ctx->vibration);
if (!SUCCEEDED(hr)) {
return SDL_SetError("Setting vibration failed: 0x%lx", hr);
}
+4 -3
View File
@@ -304,6 +304,7 @@ bool SDL_SYS_CreateProcessWithProperties(SDL_Process *process, SDL_PropertiesID
if (stderr_option == SDL_PROCESS_STDIO_INHERITED) {
stderr_option = SDL_PROCESS_STDIO_NULL;
}
creation_flags |= CREATE_NO_WINDOW;
}
switch (stdin_option) {
@@ -329,7 +330,7 @@ bool SDL_SYS_CreateProcessWithProperties(SDL_Process *process, SDL_PropertiesID
startup_info.hStdInput = stdin_pipe[READ_END];
break;
case SDL_PROCESS_STDIO_NULL:
startup_info.hStdInput = CreateFile(TEXT("\\\\.\\NUL"), GENERIC_ALL, 0, &security_attributes, OPEN_EXISTING, 0, NULL);
startup_info.hStdInput = CreateFile(TEXT("\\\\.\\NUL"), (GENERIC_READ | GENERIC_WRITE), 0, &security_attributes, OPEN_EXISTING, 0, NULL);
break;
case SDL_PROCESS_STDIO_INHERITED:
default:
@@ -366,7 +367,7 @@ bool SDL_SYS_CreateProcessWithProperties(SDL_Process *process, SDL_PropertiesID
startup_info.hStdOutput = stdout_pipe[WRITE_END];
break;
case SDL_PROCESS_STDIO_NULL:
startup_info.hStdOutput = CreateFile(TEXT("\\\\.\\NUL"), GENERIC_ALL, 0, &security_attributes, OPEN_EXISTING, 0, NULL);
startup_info.hStdOutput = CreateFile(TEXT("\\\\.\\NUL"), (GENERIC_READ | GENERIC_WRITE), 0, &security_attributes, OPEN_EXISTING, 0, NULL);
break;
case SDL_PROCESS_STDIO_INHERITED:
default:
@@ -412,7 +413,7 @@ bool SDL_SYS_CreateProcessWithProperties(SDL_Process *process, SDL_PropertiesID
startup_info.hStdError = stderr_pipe[WRITE_END];
break;
case SDL_PROCESS_STDIO_NULL:
startup_info.hStdError = CreateFile(TEXT("\\\\.\\NUL"), GENERIC_ALL, 0, &security_attributes, OPEN_EXISTING, 0, NULL);
startup_info.hStdError = CreateFile(TEXT("\\\\.\\NUL"), (GENERIC_READ | GENERIC_WRITE), 0, &security_attributes, OPEN_EXISTING, 0, NULL);
break;
case SDL_PROCESS_STDIO_INHERITED:
default:
+5 -5
View File
@@ -1658,8 +1658,6 @@ SDL_Texture *SDL_CreateTextureFromSurface(SDL_Renderer *renderer, SDL_Surface *s
}
}
surface_colorspace = SDL_GetSurfaceColorspace(surface);
// Try to have the best pixel format for the texture
// No alpha, but a colorkey => promote to alpha
if (!SDL_ISPIXELFORMAT_ALPHA(surface->format) && SDL_SurfaceHasColorKey(surface)) {
@@ -1721,6 +1719,9 @@ SDL_Texture *SDL_CreateTextureFromSurface(SDL_Renderer *renderer, SDL_Surface *s
}
}
surface_colorspace = SDL_GetSurfaceColorspace(surface);
texture_colorspace = surface_colorspace;
if (surface_colorspace == SDL_COLORSPACE_SRGB_LINEAR ||
SDL_COLORSPACETRANSFER(surface_colorspace) == SDL_TRANSFER_CHARACTERISTICS_PQ) {
if (SDL_ISPIXELFORMAT_FLOAT(format)) {
@@ -2572,7 +2573,7 @@ static void UpdateLogicalPresentation(SDL_Renderer *renderer)
const float logical_h = view->logical_h;
int iwidth, iheight;
if (renderer->target) {
if (!is_main_view && renderer->target) {
iwidth = (int)renderer->target->w;
iheight = (int)renderer->target->h;
} else {
@@ -3930,8 +3931,7 @@ 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) ||
real_srcrect.w == 0.0f || real_srcrect.h == 0.0f) {
if (!SDL_GetRectIntersectionFloat(srcrect, &real_srcrect, &real_srcrect)) {
return true;
}
}
-1
View File
@@ -445,7 +445,6 @@ static void GPU_InvalidateCachedState(SDL_Renderer *renderer)
{
GPU_RenderData *data = (GPU_RenderData *)renderer->internal;
data->state.render_target = NULL;
data->state.scissor_enabled = false;
}
+78 -59
View File
@@ -79,15 +79,10 @@ static const size_t CONSTANTS_OFFSET_DECODE_BT2020_LIMITED = ALIGN_CONSTANTS(16,
static const size_t CONSTANTS_OFFSET_DECODE_BT2020_FULL = ALIGN_CONSTANTS(16, CONSTANTS_OFFSET_DECODE_BT2020_LIMITED + sizeof(float) * 4 * 4);
static const size_t CONSTANTS_LENGTH = CONSTANTS_OFFSET_DECODE_BT2020_FULL + sizeof(float) * 4 * 4;
// Sampler types
typedef enum
{
SDL_METAL_SAMPLER_NEAREST_CLAMP,
SDL_METAL_SAMPLER_NEAREST_WRAP,
SDL_METAL_SAMPLER_LINEAR_CLAMP,
SDL_METAL_SAMPLER_LINEAR_WRAP,
SDL_NUM_METAL_SAMPLERS
} SDL_METAL_sampler_type;
#define RENDER_SAMPLER_HASHKEY(scale_mode, address_u, address_v) \
(((scale_mode == SDL_SCALEMODE_NEAREST) << 0) | \
((address_u == SDL_TEXTURE_ADDRESS_WRAP) << 1) | \
((address_v == SDL_TEXTURE_ADDRESS_WRAP) << 2))
typedef enum SDL_MetalVertexFunction
{
@@ -139,7 +134,7 @@ typedef struct METAL_ShaderPipelines
@property(nonatomic, retain) id<MTLRenderCommandEncoder> mtlcmdencoder;
@property(nonatomic, retain) id<MTLLibrary> mtllibrary;
@property(nonatomic, retain) id<CAMetalDrawable> mtlbackbuffer;
@property(nonatomic, retain) NSMutableArray<id<MTLSamplerState>> *mtlsamplers;
@property(nonatomic, retain) NSMutableDictionary<NSNumber *, id<MTLSamplerState>> *mtlsamplers;
@property(nonatomic, retain) id<MTLBuffer> mtlbufconstants;
@property(nonatomic, retain) id<MTLBuffer> mtlbufquadindices;
@property(nonatomic, assign) SDL_MetalView mtlview;
@@ -1295,6 +1290,9 @@ typedef struct
__unsafe_unretained id<MTLBuffer> vertex_buffer;
size_t constants_offset;
SDL_Texture *texture;
SDL_ScaleMode texture_scale_mode;
SDL_TextureAddressMode texture_address_mode_u;
SDL_TextureAddressMode texture_address_mode_v;
bool cliprect_dirty;
bool cliprect_enabled;
SDL_Rect cliprect;
@@ -1452,6 +1450,58 @@ static bool SetDrawState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, c
return true;
}
static id<MTLSamplerState> GetSampler(SDL3METAL_RenderData *data, SDL_ScaleMode scale_mode, SDL_TextureAddressMode address_u, SDL_TextureAddressMode address_v)
{
NSNumber *key = [NSNumber numberWithInteger:RENDER_SAMPLER_HASHKEY(scale_mode, address_u, address_v)];
id<MTLSamplerState> mtlsampler = data.mtlsamplers[key];
if (mtlsampler == nil) {
MTLSamplerDescriptor *samplerdesc;
samplerdesc = [[MTLSamplerDescriptor alloc] init];
switch (scale_mode) {
case SDL_SCALEMODE_NEAREST:
samplerdesc.minFilter = MTLSamplerMinMagFilterNearest;
samplerdesc.magFilter = MTLSamplerMinMagFilterNearest;
break;
case SDL_SCALEMODE_LINEAR:
samplerdesc.minFilter = MTLSamplerMinMagFilterLinear;
samplerdesc.magFilter = MTLSamplerMinMagFilterLinear;
break;
default:
SDL_SetError("Unknown scale mode: %d", scale_mode);
return nil;
}
switch (address_u) {
case SDL_TEXTURE_ADDRESS_CLAMP:
samplerdesc.sAddressMode = MTLSamplerAddressModeClampToEdge;
break;
case SDL_TEXTURE_ADDRESS_WRAP:
samplerdesc.sAddressMode = MTLSamplerAddressModeRepeat;
break;
default:
SDL_SetError("Unknown texture address mode: %d", address_u);
return nil;
}
switch (address_v) {
case SDL_TEXTURE_ADDRESS_CLAMP:
samplerdesc.tAddressMode = MTLSamplerAddressModeClampToEdge;
break;
case SDL_TEXTURE_ADDRESS_WRAP:
samplerdesc.tAddressMode = MTLSamplerAddressModeRepeat;
break;
default:
SDL_SetError("Unknown texture address mode: %d", address_v);
return nil;
}
mtlsampler = [data.mtldevice newSamplerStateWithDescriptor:samplerdesc];
if (mtlsampler == nil) {
SDL_SetError("Couldn't create sampler");
return nil;
}
data.mtlsamplers[key] = mtlsampler;
}
return mtlsampler;
}
static bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, const size_t constants_offset,
id<MTLBuffer> mtlbufvertex, METAL_DrawStateCache *statecache)
{
@@ -1467,33 +1517,6 @@ static bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, c
}
if (texture != statecache->texture) {
id<MTLSamplerState> mtlsampler;
if (cmd->data.draw.texture_scale_mode == SDL_SCALEMODE_NEAREST) {
switch (cmd->data.draw.texture_address_mode) {
case SDL_TEXTURE_ADDRESS_CLAMP:
mtlsampler = data.mtlsamplers[SDL_METAL_SAMPLER_NEAREST_CLAMP];
break;
case SDL_TEXTURE_ADDRESS_WRAP:
mtlsampler = data.mtlsamplers[SDL_METAL_SAMPLER_NEAREST_WRAP];
break;
default:
return SDL_SetError("Unknown texture address mode: %d", cmd->data.draw.texture_address_mode);
}
} else {
switch (cmd->data.draw.texture_address_mode) {
case SDL_TEXTURE_ADDRESS_CLAMP:
mtlsampler = data.mtlsamplers[SDL_METAL_SAMPLER_LINEAR_CLAMP];
break;
case SDL_TEXTURE_ADDRESS_WRAP:
mtlsampler = data.mtlsamplers[SDL_METAL_SAMPLER_LINEAR_WRAP];
break;
default:
return SDL_SetError("Unknown texture address mode: %d", cmd->data.draw.texture_address_mode);
}
}
[data.mtlcmdencoder setFragmentSamplerState:mtlsampler atIndex:0];
[data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture atIndex:0];
#ifdef SDL_HAVE_YUV
if (texturedata.yuv || texturedata.nv12) {
@@ -1503,6 +1526,20 @@ static bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, c
#endif
statecache->texture = texture;
}
if (cmd->data.draw.texture_scale_mode != statecache->texture_scale_mode ||
cmd->data.draw.texture_address_mode != statecache->texture_address_mode_u ||
cmd->data.draw.texture_address_mode != statecache->texture_address_mode_v) {
id<MTLSamplerState> mtlsampler = GetSampler(data, cmd->data.draw.texture_scale_mode, cmd->data.draw.texture_address_mode, cmd->data.draw.texture_address_mode);
if (mtlsampler == nil) {
return false;
}
[data.mtlcmdencoder setFragmentSamplerState:mtlsampler atIndex:0];
statecache->texture_scale_mode = cmd->data.draw.texture_scale_mode;
statecache->texture_address_mode_u = cmd->data.draw.texture_address_mode;
statecache->texture_address_mode_v = cmd->data.draw.texture_address_mode;
}
return true;
}
@@ -1523,6 +1560,9 @@ static bool METAL_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd
statecache.vertex_buffer = nil;
statecache.constants_offset = CONSTANTS_OFFSET_INVALID;
statecache.texture = NULL;
statecache.texture_scale_mode = SDL_SCALEMODE_INVALID;
statecache.texture_address_mode_u = SDL_TEXTURE_ADDRESS_INVALID;
statecache.texture_address_mode_v = SDL_TEXTURE_ADDRESS_INVALID;
statecache.shader_constants_dirty = true;
statecache.cliprect_dirty = true;
statecache.viewport_dirty = true;
@@ -1883,7 +1923,6 @@ static bool METAL_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL
int maxtexsize, quadcount = UINT16_MAX / 4;
UInt16 *indexdata;
size_t indicessize = sizeof(UInt16) * quadcount * 6;
MTLSamplerDescriptor *samplerdesc;
id<MTLCommandQueue> mtlcmdqueue;
id<MTLLibrary> mtllibrary;
id<MTLBuffer> mtlbufconstantstaging, mtlbufquadindicesstaging, mtlbufconstants, mtlbufquadindices;
@@ -2043,27 +2082,7 @@ static bool METAL_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL
data.allpipelines = NULL;
ChooseShaderPipelines(data, MTLPixelFormatBGRA8Unorm);
static struct
{
MTLSamplerMinMagFilter filter;
MTLSamplerAddressMode address;
} samplerParams[] = {
{ MTLSamplerMinMagFilterNearest, MTLSamplerAddressModeClampToEdge },
{ MTLSamplerMinMagFilterNearest, MTLSamplerAddressModeRepeat },
{ MTLSamplerMinMagFilterLinear, MTLSamplerAddressModeClampToEdge },
{ MTLSamplerMinMagFilterLinear, MTLSamplerAddressModeRepeat },
};
SDL_COMPILE_TIME_ASSERT(samplerParams_SIZE, SDL_arraysize(samplerParams) == SDL_NUM_METAL_SAMPLERS);
data.mtlsamplers = [[NSMutableArray<id<MTLSamplerState>> alloc] init];
samplerdesc = [[MTLSamplerDescriptor alloc] init];
for (int i = 0; i < SDL_arraysize(samplerParams); ++i) {
samplerdesc.minFilter = samplerParams[i].filter;
samplerdesc.magFilter = samplerParams[i].filter;
samplerdesc.sAddressMode = samplerParams[i].address;
samplerdesc.tAddressMode = samplerParams[i].address;
[data.mtlsamplers addObject:[data.mtldevice newSamplerStateWithDescriptor:samplerdesc]];
}
data.mtlsamplers = [[NSMutableDictionary<NSNumber *, id<MTLSamplerState>> alloc] init];
mtlbufconstantstaging = [data.mtldevice newBufferWithLength:CONSTANTS_LENGTH options:MTLResourceStorageModeShared];
+1 -1
View File
@@ -60,7 +60,7 @@ typedef struct
static int vsync_sema_id = 0;
// PRIVATE METHODS
static int vsync_handler(void)
static int vsync_handler(int reason)
{
iSignalSema(vsync_sema_id);
+3
View File
@@ -34,6 +34,9 @@ static TitleStorageBootStrap *titlebootstrap[] = {
static UserStorageBootStrap *userbootstrap[] = {
#ifdef SDL_STORAGE_STEAM
&STEAM_userbootstrap,
#endif
#ifdef SDL_STORAGE_PRIVATE
&PRIVATE_userbootstrap,
#endif
&GENERIC_userbootstrap,
NULL
+1
View File
@@ -44,6 +44,7 @@ extern TitleStorageBootStrap GENERIC_titlebootstrap;
// Steam does not have title storage APIs
extern UserStorageBootStrap GENERIC_userbootstrap;
extern UserStorageBootStrap PRIVATE_userbootstrap;
extern UserStorageBootStrap STEAM_userbootstrap;
extern SDL_Storage *GENERIC_OpenFileStorage(const char *path);
+3 -3
View File
@@ -58,8 +58,8 @@ 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);
static gpointer (*g_object_ref_sink)(gpointer object);
static gpointer (*g_object_ref)(gpointer object);
// glib_typeof requires compiler-specific code and includes that are too complex
// to be worth copy-pasting here
@@ -541,7 +541,7 @@ SDL_TrayMenu *SDL_CreateTraySubmenu(SDL_TrayEntry *entry)
return NULL;
}
entry->submenu->menu = (GtkMenuShell *)gtk_menu_new();
entry->submenu->menu = g_object_ref_sink(gtk_menu_new());
entry->submenu->parent_tray = NULL;
entry->submenu->parent_entry = entry;
entry->submenu->nEntries = 0;
+1 -1
View File
@@ -544,7 +544,7 @@ void SDL_SetTrayEntryLabel(SDL_TrayEntry *entry, const char *label)
mii.dwTypeData = label_w;
mii.cch = (UINT) SDL_wcslen(label_w);
if (!SetMenuItemInfoW(entry->parent->hMenu, (UINT) entry->id, TRUE, &mii)) {
if (!SetMenuItemInfoW(entry->parent->hMenu, (UINT) entry->id, FALSE, &mii)) {
SDL_SetError("Couldn't update tray entry label");
}
+2 -1
View File
@@ -20,12 +20,13 @@
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "SDL_blit.h"
#ifdef SDL_HAVE_BLIT_AUTO
/* *INDENT-OFF* */ // clang-format off
#include "SDL_blit.h"
extern SDL_BlitFuncEntry SDL_GeneratedBlitFuncTable[];
/* *INDENT-ON* */ // clang-format on
+9 -2
View File
@@ -1101,9 +1101,9 @@ bool SDL_BlitSurfaceScaled(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surfac
int dst_w, dst_h;
// Make sure the surfaces aren't locked
if (!SDL_SurfaceValid(src)) {
if (!SDL_SurfaceValid(src) || !src->pixels) {
return SDL_InvalidParamError("src");
} else if (!SDL_SurfaceValid(dst)) {
} else if (!SDL_SurfaceValid(dst) || !dst->pixels) {
return SDL_InvalidParamError("dst");
} else if ((src->flags & SDL_SURFACE_LOCKED) || (dst->flags & SDL_SURFACE_LOCKED)) {
return SDL_SetError("Surfaces must not be locked during blit");
@@ -1133,6 +1133,13 @@ bool SDL_BlitSurfaceScaled(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surfac
return SDL_BlitSurface(src, srcrect, dst, dstrect);
}
if (src_w == 0) {
src_w = 1;
}
if (src_h == 0) {
src_h = 1;
}
scaling_w = (double)dst_w / src_w;
scaling_h = (double)dst_h / src_h;
+1 -2
View File
@@ -396,8 +396,7 @@ struct SDL_VideoDevice
bool checked_texture_framebuffer;
bool is_dummy;
bool suspend_screensaver;
SDL_Window *wakeup_window;
SDL_Mutex *wakeup_lock; // Initialized only if WaitEventTimeout/SendWakeupEvent are supported
void *wakeup_window;
int num_displays;
SDL_VideoDisplay **displays;
SDL_Rect desktop_bounds;
+19 -7
View File
@@ -1731,12 +1731,25 @@ SDL_VideoDisplay *SDL_GetVideoDisplayForFullscreenWindow(SDL_Window *window)
return SDL_GetVideoDisplay(displayID);
}
#define SDL_PROP_SDL2_COMPAT_WINDOW_PREFERRED_FULLSCREEN_DISPLAY "sdl2-compat.window.preferred_fullscreen_display"
SDL_DisplayID SDL_GetDisplayForWindow(SDL_Window *window)
{
SDL_DisplayID displayID = 0;
CHECK_WINDOW_MAGIC(window, 0);
/* sdl2-compat calls this function to get a display on which to make the window fullscreen,
* so pass it the preferred fullscreen display ID in a property.
*/
SDL_PropertiesID window_props = SDL_GetWindowProperties(window);
SDL_VideoDisplay *fs_display = SDL_GetVideoDisplayForFullscreenWindow(window);
if (fs_display) {
SDL_SetNumberProperty(window_props, SDL_PROP_SDL2_COMPAT_WINDOW_PREFERRED_FULLSCREEN_DISPLAY, fs_display->id);
} else {
SDL_ClearProperty(window_props, SDL_PROP_SDL2_COMPAT_WINDOW_PREFERRED_FULLSCREEN_DISPLAY);
}
// An explicit fullscreen display overrides all
if (window->flags & SDL_WINDOW_FULLSCREEN) {
displayID = window->current_fullscreen_mode.displayID;
@@ -2500,7 +2513,9 @@ SDL_Window *SDL_CreateWindowWithProperties(SDL_PropertiesID props)
SDL_UpdateWindowHierarchy(window, parent);
if (_this->CreateSDLWindow && !_this->CreateSDLWindow(_this, window, props)) {
PUSH_SDL_ERROR()
SDL_DestroyWindow(window);
POP_SDL_ERROR()
return NULL;
}
@@ -2748,7 +2763,7 @@ SDL_Window *SDL_GetWindowFromID(SDL_WindowID id)
}
}
}
SDL_SetError("Invalid window ID"); \
SDL_SetError("Invalid window ID");
return NULL;
}
@@ -4266,9 +4281,7 @@ void SDL_DestroyWindow(SDL_Window *window)
_this->current_glwin = NULL;
}
if (_this->wakeup_window == window) {
_this->wakeup_window = NULL;
}
SDL_CompareAndSwapAtomicPointer(&_this->wakeup_window, window, NULL);
// Now invalidate magic
SDL_SetObjectValid(window, SDL_OBJECT_TYPE_WINDOW, false);
@@ -5021,8 +5034,7 @@ bool SDL_GL_GetAttribute(SDL_GLAttr attr, int *value)
}
if (fbo_type != GL_NONE) {
glGetFramebufferAttachmentParameterivFunc(GL_FRAMEBUFFER, attachment, attachmentattrib, (GLint *)value);
}
else {
} else {
*value = 0;
}
if (glBindFramebufferFunc && (current_fbo != 0)) {
@@ -5253,7 +5265,7 @@ bool SDL_GL_SwapWindow(SDL_Window *window)
bool SDL_GL_DestroyContext(SDL_GLContext context)
{
if (!_this) {
return SDL_UninitializedVideo(); \
return SDL_UninitializedVideo();
}
if (!context) {
return SDL_InvalidParamError("context");
+11
View File
@@ -158,6 +158,17 @@ bool Cocoa_SetClipboardData(SDL_VideoDevice *_this)
@autoreleasepool {
SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->internal;
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
// SetClipboardText specialization so text is available after the app quits
if (_this->clipboard_callback && _this->num_clipboard_mime_types == 1) {
if (SDL_strncmp(_this->clipboard_mime_types[0], "text/plain;charset=utf-8", 24) == 0) {
[pasteboard declareTypes:@[ NSPasteboardTypeString ] owner:nil];
[pasteboard setString:@((char *)_this->clipboard_userdata) forType:NSPasteboardTypeString];
data.clipboard_count = [pasteboard changeCount];
return true;
}
}
NSPasteboardItem *newItem = [NSPasteboardItem new];
NSMutableArray *utiTypes = [NSMutableArray new];
Cocoa_PasteboardDataProvider *provider = [[Cocoa_PasteboardDataProvider alloc] initWith: _this->clipboard_callback userData: _this->clipboard_userdata];
+8 -2
View File
@@ -450,12 +450,18 @@ void Cocoa_HandleMouseEvent(SDL_VideoDevice *_this, NSEvent *event)
// 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
// created under the mouse on macOS 12.7. But, only set the focus if
// the event acutally has a non-NULL window, otherwise what would happen
// is that after an NSEventTypeMouseEntered there would sometimes be
// NSEventTypeMouseMoved without a window causing us to suppress subsequent
// mouse move events.
NSEventType event_type = [event type];
if (event_type == NSEventTypeMouseExited) {
Cocoa_MouseFocus = NULL;
} else {
Cocoa_MouseFocus = [event window];
if ([event window] != NULL) {
Cocoa_MouseFocus = [event window];
}
}
switch (event_type) {
-4
View File
@@ -49,9 +49,6 @@ static void Cocoa_VideoQuit(SDL_VideoDevice *_this);
static void Cocoa_DeleteDevice(SDL_VideoDevice *device)
{
@autoreleasepool {
if (device->wakeup_lock) {
SDL_DestroyMutex(device->wakeup_lock);
}
CFBridgingRelease(device->internal);
SDL_free(device);
}
@@ -81,7 +78,6 @@ static SDL_VideoDevice *Cocoa_CreateDevice(void)
return NULL;
}
device->internal = (SDL_VideoData *)CFBridgingRetain(data);
device->wakeup_lock = SDL_CreateMutex();
device->system_theme = Cocoa_GetSystemTheme();
// Set the function pointers
+59 -4
View File
@@ -2022,6 +2022,7 @@ static void Cocoa_SendMouseButtonClicks(SDL_Mouse *mouse, NSEvent *theEvent, SDL
@interface SDL3View : NSView
{
SDL_Window *_sdlWindow;
NSTrackingArea *_trackingArea; // only used on macOS <= 11.0
}
- (void)setSDLWindow:(SDL_Window *)window;
@@ -2033,6 +2034,7 @@ static void Cocoa_SendMouseButtonClicks(SDL_Mouse *mouse, NSEvent *theEvent, SDL
- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent;
- (BOOL)wantsUpdateLayer;
- (void)updateLayer;
- (void)updateTrackingAreas;
@end
@implementation SDL3View
@@ -2104,15 +2106,62 @@ static void Cocoa_SendMouseButtonClicks(SDL_Mouse *mouse, NSEvent *theEvent, SDL
- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent
{
if (SDL_GetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH)) {
if (_sdlWindow->flags & SDL_WINDOW_POPUP_MENU) {
return YES;
} else if (SDL_GetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH)) {
return SDL_GetHintBoolean(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, false);
} else {
return SDL_GetHintBoolean("SDL_MAC_MOUSE_FOCUS_CLICKTHROUGH", false);
}
}
- (void)updateTrackingAreas
{
[super updateTrackingAreas];
if (@available(macOS 12.0, *)) {
// we (currently) use the tracking areas as a workaround for older macOSes, but we might be safe everywhere...
} else {
SDL_CocoaWindowData *windata = (__bridge SDL_CocoaWindowData *)_sdlWindow->internal;
if (_trackingArea) {
[self removeTrackingArea:_trackingArea];
}
_trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] options:NSTrackingMouseEnteredAndExited|NSTrackingActiveAlways owner:windata.listener userInfo:nil];
[self addTrackingArea:_trackingArea];
}
}
@end
static void Cocoa_UpdateMouseFocus()
{
const NSPoint mouseLocation = [NSEvent mouseLocation];
// Find the topmost window under the pointer and send a motion event if it is an SDL window.
[NSApp enumerateWindowsWithOptions:NSWindowListOrderedFrontToBack
usingBlock:^(NSWindow *nswin, BOOL *stop) {
NSRect r = [nswin contentRectForFrameRect:[nswin frame]];
if (NSPointInRect(mouseLocation, r)) {
SDL_VideoDevice *vid = SDL_GetVideoDevice();
SDL_Window *sdlwindow;
for (sdlwindow = vid->windows; sdlwindow; sdlwindow = sdlwindow->next) {
if (nswin == ((__bridge SDL_CocoaWindowData *)sdlwindow->internal).nswindow) {
break;
}
}
*stop = YES;
if (sdlwindow) {
int wx, wy;
SDL_RelativeToGlobalForWindow(sdlwindow, sdlwindow->x, sdlwindow->y, &wx, &wy);
// Calculate the cursor coordinates relative to the window.
const float dx = mouseLocation.x - wx;
const float dy = (CGDisplayPixelsHigh(kCGDirectMainDisplay) - mouseLocation.y) - wy;
SDL_SendMouseMotion(0, sdlwindow, SDL_GLOBAL_MOUSE_ID, false, dx, dy);
}
}
}];
}
static bool SetupWindowData(SDL_VideoDevice *_this, SDL_Window *window, NSWindow *nswindow, NSView *nsview)
{
@autoreleasepool {
@@ -2210,8 +2259,10 @@ static bool SetupWindowData(SDL_VideoDevice *_this, SDL_Window *window, NSWindow
} else {
if (window->flags & SDL_WINDOW_TOOLTIP) {
[nswindow setIgnoresMouseEvents:YES];
} else if (window->flags & SDL_WINDOW_POPUP_MENU) {
[nswindow setAcceptsMouseMovedEvents:NO];
} else if ((window->flags & SDL_WINDOW_POPUP_MENU) && !(window->flags & SDL_WINDOW_HIDDEN)) {
Cocoa_SetKeyboardFocus(window, window->parent == SDL_GetKeyboardFocus());
Cocoa_UpdateMouseFocus();
}
}
@@ -2531,8 +2582,8 @@ void Cocoa_SetWindowMaximumSize(SDL_VideoDevice *_this, SDL_Window *window)
SDL_CocoaWindowData *windata = (__bridge SDL_CocoaWindowData *)window->internal;
NSSize maxSize;
maxSize.width = window->max_w;
maxSize.height = window->max_h;
maxSize.width = window->max_w ? window->max_w : CGFLOAT_MAX;
maxSize.height = window->max_h ? window->max_h : CGFLOAT_MAX;
[windata.nswindow setContentMaxSize:maxSize];
}
@@ -2596,6 +2647,9 @@ void Cocoa_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
[nswindow orderWindow:NSWindowBelow relativeTo:[[NSApp keyWindow] windowNumber]];
}
}
} else if (window->flags & SDL_WINDOW_POPUP_MENU) {
Cocoa_SetKeyboardFocus(window, window->parent == SDL_GetKeyboardFocus());
Cocoa_UpdateMouseFocus();
}
}
[nswindow setIsVisible:YES];
@@ -2643,6 +2697,7 @@ void Cocoa_HideWindow(SDL_VideoDevice *_this, SDL_Window *window)
}
Cocoa_SetKeyboardFocus(new_focus, set_focus);
Cocoa_UpdateMouseFocus();
} else if (window->parent && waskey) {
/* Key status is not automatically set on the parent when a child is hidden. Check if the
* child window was key, and set the first visible parent to be key if so.
@@ -78,7 +78,7 @@ bool Emscripten_UpdateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *wind
if (!Module['SDL3']) Module['SDL3'] = {};
var SDL3 = Module['SDL3'];
if (SDL3.ctxCanvas !== canvas) {
SDL3.ctx = Module['createContext'](canvas, false, true);
SDL3.ctx = Browser.createContext(canvas, false, true);
SDL3.ctxCanvas = canvas;
}
if (SDL3.w !== w || SDL3.h !== h || SDL3.imageCtx !== SDL3.ctx) {
@@ -101,7 +101,7 @@ SDL_GLContext Emscripten_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *
context = emscripten_webgl_create_context(window_data->canvas_id, &attribs);
if (context < 0) {
if (!context) {
SDL_SetError("Could not create webgl context");
return NULL;
}
+1 -1
View File
@@ -64,7 +64,7 @@ static SDL_SystemTheme Emscripten_GetSystemTheme(void)
/* Technically, light theme can mean explicit light theme or no preference.
https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme#syntax */
int theme_code = EM_ASM_INT({
int theme_code = MAIN_THREAD_EM_ASM_INT({
if (!window.matchMedia) {
return -1;
}
+9 -4
View File
@@ -1368,9 +1368,14 @@ bool KMSDRM_CreateSurfaces(SDL_VideoDevice *_this, SDL_Window *window)
windata->gs = KMSDRM_gbm_surface_create(viddata->gbm_dev,
dispdata->mode.hdisplay, dispdata->mode.vdisplay,
surface_fmt, surface_flags);
if (!windata->gs && errno == ENOSYS) {
// Try again without the scanout flags, needed on NVIDIA drivers
windata->gs = KMSDRM_gbm_surface_create(viddata->gbm_dev,
dispdata->mode.hdisplay, dispdata->mode.vdisplay,
surface_fmt, 0);
}
if (!windata->gs) {
return SDL_SetError("Could not create GBM surface");
return SDL_SetError("Could not create GBM surface: %s", strerror(errno));
}
/* We can't get the EGL context yet because SDL_CreateRenderer has not been called,
@@ -1729,9 +1734,9 @@ bool KMSDRM_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Propert
}
/* Create the window surfaces with the size we have just chosen.
Needs the window diverdata in place. */
Needs the window driverdata in place. */
if (!KMSDRM_CreateSurfaces(_this, window)) {
return SDL_SetError("Can't window GBM/EGL surfaces on window creation.");
return false;
}
} // NON-Vulkan block ends.
+2
View File
@@ -118,6 +118,8 @@ static SDL_VideoDevice *PSP_Create(void)
device->PumpEvents = PSP_PumpEvents;
device->device_caps = VIDEO_DEVICE_CAPS_FULLSCREEN_ONLY;
return device;
}
+10 -2
View File
@@ -112,7 +112,6 @@ sub open_file {
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "SDL_surface_c.h"
#ifdef SDL_HAVE_BLIT_AUTO
@@ -641,6 +640,14 @@ sub output_copyinc
__EOF__
}
sub output_copyinc_h
{
print FILE <<__EOF__;
#include "SDL_blit.h"
__EOF__
}
sub output_copyfunctable
{
print FILE <<__EOF__;
@@ -693,7 +700,7 @@ __EOF__
}
}
print FILE <<__EOF__;
{ 0, 0, 0, 0, NULL }
{ SDL_PIXELFORMAT_UNKNOWN, SDL_PIXELFORMAT_UNKNOWN, 0, 0, NULL }
};
__EOF__
@@ -716,6 +723,7 @@ sub output_copyfunc_c
}
open_file("SDL_blit_auto.h");
output_copyinc_h();
output_copydefs();
for (my $i = 0; $i <= $#src_formats; ++$i) {
for (my $j = 0; $j <= $#dst_formats; ++$j) {
+2 -1
View File
@@ -100,7 +100,7 @@ RECENT REVISION HISTORY:
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
Phil Jordan Henner Zeller 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
@@ -1914,6 +1914,7 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r
int i,j;
unsigned char *good;
if (data == NULL) return data;
if (req_comp == img_n) return data;
STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
+16 -17
View File
@@ -124,31 +124,30 @@ static BOOL UIKit_ShowMessageBoxAlertController(const SDL_MessageBoxData *messag
return YES;
}
static void UIKit_ShowMessageBoxImpl(const SDL_MessageBoxData *messageboxdata, int *buttonID, int *result)
typedef struct UIKit_ShowMessageBoxData
{
const SDL_MessageBoxData *messageboxdata;
int *buttonID;
bool result;
} UIKit_ShowMessageBoxData;
static void SDLCALL UIKit_ShowMessageBoxMainThreadCallback(void *userdata)
{
@autoreleasepool {
if (UIKit_ShowMessageBoxAlertController(messageboxdata, buttonID)) {
*result = true;
} else {
*result = SDL_SetError("Could not show message box.");
}
UIKit_ShowMessageBoxData *data = (UIKit_ShowMessageBoxData *) userdata;
data->result = UIKit_ShowMessageBoxAlertController(data->messageboxdata, data->buttonID);
}
}
bool UIKit_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID)
{
@autoreleasepool {
__block int result = true;
if ([NSThread isMainThread]) {
UIKit_ShowMessageBoxImpl(messageboxdata, buttonID, &result);
} else {
dispatch_sync(dispatch_get_main_queue(), ^{
UIKit_ShowMessageBoxImpl(messageboxdata, buttonID, &result);
});
}
return result;
UIKit_ShowMessageBoxData data = { messageboxdata, buttonID, false };
if (!SDL_RunOnMainThread(UIKit_ShowMessageBoxMainThreadCallback, &data, true)) {
return false;
} else if (!data.result) {
return SDL_SetError("Could not show message box.");
}
return true;
}
#endif // SDL_VIDEO_DRIVER_UIKIT
+1 -1
View File
@@ -240,7 +240,7 @@ extern int SDL_AppleTVRemoteOpenedAsJoystick;
int i;
SDL_MouseButtonFlags buttons = SDL_GetMouseState(NULL, NULL);
for (i = 0; i < MAX_MOUSE_BUTTONS; ++i) {
for (i = 1; i <= MAX_MOUSE_BUTTONS; ++i) {
if (buttons & SDL_BUTTON_MASK(i)) {
SDL_SendMouseButton(UIKit_GetEventTimestamp([touch timestamp]), sdlwindow, SDL_GLOBAL_MOUSE_ID, (Uint8)i, false);
}
+2
View File
@@ -153,6 +153,8 @@ static SDL_VideoDevice *VITA_Create(void)
device->PumpEvents = VITA_PumpEvents;
device->device_caps = VIDEO_DEVICE_CAPS_FULLSCREEN_ONLY;
return device;
}
-2
View File
@@ -60,8 +60,6 @@ extern SDL_Window *Vita_Window;
// Display and window functions
extern bool VITA_VideoInit(SDL_VideoDevice *_this);
extern void VITA_VideoQuit(SDL_VideoDevice *_this);
extern bool VITA_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display);
extern bool VITA_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
extern bool VITA_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props);
extern void VITA_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window);
extern bool VITA_SetWindowPosition(SDL_VideoDevice *_this, SDL_Window *window);
+38 -38
View File
@@ -163,16 +163,9 @@ static bool Wayland_SurfaceHasActiveTouches(struct wl_surface *surface)
static Uint64 Wayland_GetEventTimestamp(Uint64 nsTimestamp)
{
static Uint64 last;
static Uint64 timestamp_offset;
static Uint64 timestamp_offset = 0;
const Uint64 now = SDL_GetTicksNS();
if (nsTimestamp < last) {
// 32-bit timer rollover, bump the offset
timestamp_offset += SDL_MS_TO_NS(0x100000000LLU);
}
last = nsTimestamp;
if (!timestamp_offset) {
timestamp_offset = (now - nsTimestamp);
}
@@ -196,19 +189,24 @@ static const struct zwp_input_timestamps_v1_listener timestamp_listener = {
Wayland_input_timestamp_listener
};
static Uint64 Wayland_EventTimestampMSToNS(Uint32 wl_timestamp_ms)
{
static Uint64 timestamp_offset = 0;
static Uint32 last = 0;
// Handle 32-bit timer rollover.
if (wl_timestamp_ms < last) {
timestamp_offset += SDL_MS_TO_NS(SDL_UINT64_C(0x100000000));
}
last = wl_timestamp_ms;
return SDL_MS_TO_NS(wl_timestamp_ms) + timestamp_offset;
}
static Uint64 Wayland_GetKeyboardTimestamp(struct SDL_WaylandInput *input, Uint32 wl_timestamp_ms)
{
if (wl_timestamp_ms) {
return Wayland_GetEventTimestamp(input->keyboard_timestamp_ns ? input->keyboard_timestamp_ns : SDL_MS_TO_NS(wl_timestamp_ms));
}
return 0;
}
static Uint64 Wayland_GetKeyboardTimestampRaw(struct SDL_WaylandInput *input, Uint32 wl_timestamp_ms)
{
if (wl_timestamp_ms) {
return input->keyboard_timestamp_ns ? input->keyboard_timestamp_ns : SDL_MS_TO_NS(wl_timestamp_ms);
return Wayland_GetEventTimestamp(input->keyboard_timestamp_ns ? input->keyboard_timestamp_ns : Wayland_EventTimestampMSToNS(wl_timestamp_ms));
}
return 0;
@@ -217,7 +215,7 @@ static Uint64 Wayland_GetKeyboardTimestampRaw(struct SDL_WaylandInput *input, Ui
static Uint64 Wayland_GetPointerTimestamp(struct SDL_WaylandInput *input, Uint32 wl_timestamp_ms)
{
if (wl_timestamp_ms) {
return Wayland_GetEventTimestamp(input->pointer_timestamp_ns ? input->pointer_timestamp_ns : SDL_MS_TO_NS(wl_timestamp_ms));
return Wayland_GetEventTimestamp(input->pointer_timestamp_ns ? input->pointer_timestamp_ns : Wayland_EventTimestampMSToNS(wl_timestamp_ms));
}
return 0;
@@ -226,7 +224,7 @@ static Uint64 Wayland_GetPointerTimestamp(struct SDL_WaylandInput *input, Uint32
Uint64 Wayland_GetTouchTimestamp(struct SDL_WaylandInput *input, Uint32 wl_timestamp_ms)
{
if (wl_timestamp_ms) {
return Wayland_GetEventTimestamp(input->touch_timestamp_ns ? input->touch_timestamp_ns : SDL_MS_TO_NS(wl_timestamp_ms));
return Wayland_GetEventTimestamp(input->touch_timestamp_ns ? input->touch_timestamp_ns : Wayland_EventTimestampMSToNS(wl_timestamp_ms));
}
return 0;
@@ -269,10 +267,11 @@ void Wayland_CreateCursorShapeDevice(struct SDL_WaylandInput *input)
static bool keyboard_repeat_handle(SDL_WaylandKeyboardRepeat *repeat_info, Uint64 elapsed)
{
bool ret = false;
while (elapsed >= repeat_info->next_repeat_ns) {
if (repeat_info->scancode != SDL_SCANCODE_UNKNOWN) {
const Uint64 timestamp = repeat_info->wl_press_time_ns + repeat_info->next_repeat_ns;
SDL_SendKeyboardKeyIgnoreModifiers(Wayland_GetEventTimestamp(timestamp), repeat_info->keyboard_id, repeat_info->key, repeat_info->scancode, true);
const Uint64 timestamp = repeat_info->base_time_ns + repeat_info->next_repeat_ns;
SDL_SendKeyboardKeyIgnoreModifiers(timestamp, repeat_info->keyboard_id, repeat_info->key, repeat_info->scancode, true);
}
if (repeat_info->text[0]) {
SDL_SendKeyboardText(repeat_info->text);
@@ -291,8 +290,8 @@ static void keyboard_repeat_clear(SDL_WaylandKeyboardRepeat *repeat_info)
repeat_info->is_key_down = false;
}
static void keyboard_repeat_set(SDL_WaylandKeyboardRepeat *repeat_info, Uint32 keyboard_id, uint32_t key, Uint64 wl_press_time_ns,
uint32_t scancode, bool has_text, char text[8])
static void keyboard_repeat_set(SDL_WaylandKeyboardRepeat *repeat_info, Uint32 keyboard_id, uint32_t key, Uint32 wl_press_time_ms,
Uint64 base_time_ns, uint32_t scancode, bool has_text, char text[8])
{
if (!repeat_info->is_initialized || !repeat_info->repeat_rate) {
return;
@@ -300,12 +299,13 @@ static void keyboard_repeat_set(SDL_WaylandKeyboardRepeat *repeat_info, Uint32 k
repeat_info->is_key_down = true;
repeat_info->keyboard_id = keyboard_id;
repeat_info->key = key;
repeat_info->wl_press_time_ns = wl_press_time_ns;
repeat_info->wl_press_time_ms = wl_press_time_ms;
repeat_info->base_time_ns = base_time_ns;
repeat_info->sdl_press_time_ns = SDL_GetTicksNS();
repeat_info->next_repeat_ns = SDL_MS_TO_NS(repeat_info->repeat_delay_ms);
repeat_info->scancode = scancode;
if (has_text) {
SDL_copyp(repeat_info->text, text);
SDL_memcpy(repeat_info->text, text, sizeof(repeat_info->text));
} else {
repeat_info->text[0] = '\0';
}
@@ -598,11 +598,11 @@ static void pointer_handle_leave(void *data, struct wl_pointer *pointer,
wind->sdlwindow->flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
input->buttons_pressed = 0;
SDL_SendMouseButton(Wayland_GetPointerTimestamp(input, 0), wind->sdlwindow, input->pointer_id, SDL_BUTTON_LEFT, false);
SDL_SendMouseButton(Wayland_GetPointerTimestamp(input, 0), wind->sdlwindow, input->pointer_id, SDL_BUTTON_RIGHT, false);
SDL_SendMouseButton(Wayland_GetPointerTimestamp(input, 0), wind->sdlwindow, input->pointer_id, SDL_BUTTON_MIDDLE, false);
SDL_SendMouseButton(Wayland_GetPointerTimestamp(input, 0), wind->sdlwindow, input->pointer_id, SDL_BUTTON_X1, false);
SDL_SendMouseButton(Wayland_GetPointerTimestamp(input, 0), wind->sdlwindow, input->pointer_id, SDL_BUTTON_X2, false);
SDL_SendMouseButton(0, wind->sdlwindow, input->pointer_id, SDL_BUTTON_LEFT, false);
SDL_SendMouseButton(0, wind->sdlwindow, input->pointer_id, SDL_BUTTON_RIGHT, false);
SDL_SendMouseButton(0, wind->sdlwindow, input->pointer_id, SDL_BUTTON_MIDDLE, false);
SDL_SendMouseButton(0, wind->sdlwindow, input->pointer_id, SDL_BUTTON_X1, false);
SDL_SendMouseButton(0, wind->sdlwindow, input->pointer_id, SDL_BUTTON_X2, false);
}
/* A pointer leave event may be emitted if the compositor hides the pointer in response to receiving a touch event.
@@ -1199,7 +1199,7 @@ static void touch_handler_motion(void *data, struct wl_touch *touch, uint32_t ti
const float x = (float)wl_fixed_to_double(fx) / window_data->current.logical_width;
const float y = (float)wl_fixed_to_double(fy) / window_data->current.logical_height;
SDL_SendTouchMotion(Wayland_GetPointerTimestamp(input, timestamp), (SDL_TouchID)(uintptr_t)touch,
SDL_SendTouchMotion(Wayland_GetTouchTimestamp(input, timestamp), (SDL_TouchID)(uintptr_t)touch,
(SDL_FingerID)(id + 1), window_data->sdlwindow, x, y, 1.0f);
}
}
@@ -1855,7 +1855,7 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
char text[8];
bool has_text = false;
bool handled_by_ime = false;
const Uint64 timestamp_raw_ns = Wayland_GetKeyboardTimestampRaw(input, time);
const Uint64 timestamp_ns = Wayland_GetKeyboardTimestamp(input, time);
Wayland_UpdateImplicitGrabSerial(input, serial);
@@ -1871,7 +1871,8 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
* Using SDL_GetTicks would be wrong, as it would report when the release event is processed,
* which may be off if the application hasn't pumped events for a while.
*/
keyboard_repeat_handle(&input->keyboard_repeat, timestamp_raw_ns - input->keyboard_repeat.wl_press_time_ns);
const Uint64 elapsed = SDL_MS_TO_NS(time - input->keyboard_repeat.wl_press_time_ms);
keyboard_repeat_handle(&input->keyboard_repeat, elapsed);
keyboard_repeat_clear(&input->keyboard_repeat);
}
keyboard_input_get_text(text, input, key, false, &handled_by_ime);
@@ -1879,9 +1880,8 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
const SDL_Scancode scancode = Wayland_GetScancodeForKey(input, key);
Wayland_HandleModifierKeys(input, scancode, state == WL_KEYBOARD_KEY_STATE_PRESSED);
Uint64 timestamp = Wayland_GetKeyboardTimestamp(input, time);
SDL_SendKeyboardKeyIgnoreModifiers(timestamp, input->keyboard_id, key, scancode, state == WL_KEYBOARD_KEY_STATE_PRESSED);
SDL_SendKeyboardKeyIgnoreModifiers(timestamp_ns, input->keyboard_id, key, scancode, state == WL_KEYBOARD_KEY_STATE_PRESSED);
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
if (has_text && !(SDL_GetModState() & (SDL_KMOD_CTRL | SDL_KMOD_ALT))) {
@@ -1890,7 +1890,7 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
}
}
if (input->xkb.keymap && WAYLAND_xkb_keymap_key_repeats(input->xkb.keymap, key + 8)) {
keyboard_repeat_set(&input->keyboard_repeat, input->keyboard_id, key, timestamp_raw_ns, scancode, has_text, text);
keyboard_repeat_set(&input->keyboard_repeat, input->keyboard_id, key, time, timestamp_ns, scancode, has_text, text);
}
}
}
@@ -2951,7 +2951,7 @@ static void tablet_tool_handle_frame(void *data, struct zwp_tablet_tool_v2 *tool
return; // Not a pen we report on.
}
const Uint64 timestamp = Wayland_GetEventTimestamp(SDL_MS_TO_NS(time));
const Uint64 timestamp = Wayland_GetEventTimestamp(Wayland_EventTimestampMSToNS(time));
const SDL_PenID instance_id = sdltool->instance_id;
SDL_Window *window = sdltool->tool_focus;
+7 -6
View File
@@ -49,17 +49,18 @@ typedef struct SDL_WaylandTabletInput
typedef struct
{
int32_t repeat_rate; // Repeat rate in range of [1, 1000] character(s) per second
int32_t repeat_delay_ms; // Time to first repeat event in milliseconds
Uint32 keyboard_id; // ID of the source keyboard.
Sint32 repeat_rate; // Repeat rate in range of [1, 1000] character(s) per second
Sint32 repeat_delay_ms; // Time to first repeat event in milliseconds
Uint32 keyboard_id; // ID of the source keyboard.
bool is_initialized;
bool is_key_down;
uint32_t key;
Uint64 wl_press_time_ns; // Key press time as reported by the Wayland API
Uint32 key;
Uint32 wl_press_time_ms; // Key press time as reported by the Wayland API in milliseconds
Uint64 base_time_ns; // Key press time as reported by the Wayland API in nanoseconds
Uint64 sdl_press_time_ns; // Key press time expressed in SDL ticks
Uint64 next_repeat_ns; // Next repeat event in nanoseconds
uint32_t scancode;
Uint32 scancode;
char text[8];
} SDL_WaylandKeyboardRepeat;
+32 -12
View File
@@ -58,7 +58,7 @@ bool Wayland_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_Prop
if (internal->text_input_manager) {
if (input && input->text_input) {
const SDL_Rect *rect = &input->text_input->cursor_rect;
const SDL_Rect *rect = &input->text_input->text_input_rect;
enum zwp_text_input_v3_content_hint hint = ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE;
enum zwp_text_input_v3_content_purpose purpose;
@@ -125,12 +125,21 @@ bool Wayland_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_Prop
// Now that it's enabled, set the input properties
zwp_text_input_v3_set_content_type(input->text_input->text_input, hint, purpose);
if (!SDL_RectEmpty(rect)) {
// This gets reset on enable so we have to cache it
SDL_WindowData *wind = window->internal;
const SDL_Rect scaled_rect = {
(int)SDL_floor(window->text_input_rect.x / wind->pointer_scale.x),
(int)SDL_floor(window->text_input_rect.y / wind->pointer_scale.y),
(int)SDL_ceil(window->text_input_rect.w / wind->pointer_scale.x),
(int)SDL_ceil(window->text_input_rect.h / wind->pointer_scale.y)
};
const int scaled_cursor = (int)SDL_floor(window->text_input_cursor / wind->pointer_scale.x);
// Clamp the x value so it doesn't run too far past the end of the text input area.
zwp_text_input_v3_set_cursor_rectangle(input->text_input->text_input,
rect->x,
rect->y,
rect->w,
rect->h);
SDL_min(scaled_rect.x + scaled_cursor, scaled_rect.x + scaled_rect.w),
scaled_rect.y,
1,
scaled_rect.h);
}
zwp_text_input_v3_commit(input->text_input->text_input);
}
@@ -174,13 +183,24 @@ bool Wayland_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window)
if (internal->text_input_manager) {
struct SDL_WaylandInput *input = internal->input;
if (input && input->text_input) {
if (!SDL_RectsEqual(&window->text_input_rect, &input->text_input->cursor_rect)) {
SDL_copyp(&input->text_input->cursor_rect, &window->text_input_rect);
SDL_WindowData *wind = window->internal;
const SDL_Rect scaled_rect = {
(int)SDL_floor(window->text_input_rect.x / wind->pointer_scale.x),
(int)SDL_floor(window->text_input_rect.y / wind->pointer_scale.y),
(int)SDL_ceil(window->text_input_rect.w / wind->pointer_scale.x),
(int)SDL_ceil(window->text_input_rect.h / wind->pointer_scale.y)
};
const int scaled_cursor = (int)SDL_floor(window->text_input_cursor / wind->pointer_scale.x);
if (!SDL_RectsEqual(&scaled_rect, &input->text_input->text_input_rect) || scaled_cursor != input->text_input->text_input_cursor) {
SDL_copyp(&input->text_input->text_input_rect, &scaled_rect);
input->text_input->text_input_cursor = scaled_cursor;
// Clamp the x value so it doesn't run too far past the end of the text input area.
zwp_text_input_v3_set_cursor_rectangle(input->text_input->text_input,
window->text_input_rect.x,
window->text_input_rect.y,
window->text_input_rect.w,
window->text_input_rect.h);
SDL_min(scaled_rect.x + scaled_cursor, scaled_rect.x + scaled_rect.w),
scaled_rect.y,
1,
scaled_rect.h);
zwp_text_input_v3_commit(input->text_input->text_input);
}
}
+2 -1
View File
@@ -26,7 +26,8 @@
typedef struct SDL_WaylandTextInput
{
struct zwp_text_input_v3 *text_input;
SDL_Rect cursor_rect;
SDL_Rect text_input_rect;
int text_input_cursor;
bool has_preedit;
} SDL_WaylandTextInput;
-4
View File
@@ -446,9 +446,6 @@ static void Wayland_DeleteDevice(SDL_VideoDevice *device)
WAYLAND_wl_display_disconnect(data->display);
SDL_ClearProperty(SDL_GetGlobalProperties(), SDL_PROP_GLOBAL_VIDEO_WAYLAND_WL_DISPLAY_POINTER);
}
if (device->wakeup_lock) {
SDL_DestroyMutex(device->wakeup_lock);
}
SDL_free(data);
SDL_free(device);
SDL_WAYLAND_UnloadSymbols();
@@ -589,7 +586,6 @@ static SDL_VideoDevice *Wayland_CreateDevice(bool require_preferred_protocols)
}
device->internal = data;
device->wakeup_lock = SDL_CreateMutex();
// Set the function pointers
device->VideoInit = Wayland_VideoInit;
+14
View File
@@ -2055,6 +2055,10 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
struct wl_callback *cb = wl_display_sync(_this->internal->display);
wl_callback_add_listener(cb, &show_hide_sync_listener, (void*)((uintptr_t)window->id));
data->showing_window = true;
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_SHOWN, 0, 0);
data->showing_window = false;
// Send an exposure event to signal that the client should draw.
if (data->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_FRAME) {
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_EXPOSED, 0, 0);
@@ -2277,6 +2281,11 @@ SDL_FullscreenResult Wayland_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Win
return SDL_FULLSCREEN_FAILED;
}
// Drop fullscreen leave requests when showing the window.
if (wind->showing_window && fullscreen == SDL_FULLSCREEN_OP_LEAVE) {
return SDL_FULLSCREEN_SUCCEEDED;
}
if (wind->show_hide_sync_required) {
WAYLAND_wl_display_roundtrip(_this->internal->display);
}
@@ -2331,6 +2340,11 @@ void Wayland_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_WindowData *wind = window->internal;
// Drop restore requests when showing the window.
if (wind->showing_window) {
return;
}
// Not currently fullscreen or maximized, and no state pending; nothing to do.
if (!(window->flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_MAXIMIZED)) &&
!wind->fullscreen_deadline_count && !wind->maximized_restored_deadline_count) {
+1
View File
@@ -198,6 +198,7 @@ struct SDL_WindowData
bool is_fullscreen;
bool fullscreen_exclusive;
bool drop_fullscreen_requests;
bool showing_window;
bool fullscreen_was_positioned;
bool show_hide_sync_required;
bool scale_to_display;
+42 -27
View File
@@ -352,7 +352,7 @@ static void WIN_UpdateMouseCapture(void)
}
}
static void WIN_UpdateFocus(SDL_Window *window, bool expect_focus)
static void WIN_UpdateFocus(SDL_Window *window, bool expect_focus, DWORD pos)
{
SDL_WindowData *data = window->internal;
HWND hwnd = data->hwnd;
@@ -389,7 +389,8 @@ static void WIN_UpdateFocus(SDL_Window *window, bool expect_focus)
// In relative mode we are guaranteed to have mouse focus if we have keyboard focus
if (!SDL_GetMouse()->relative_mode) {
GetCursorPos(&cursorPos);
cursorPos.x = (LONG)GET_X_LPARAM(pos);
cursorPos.y = (LONG)GET_Y_LPARAM(pos);
ScreenToClient(hwnd, &cursorPos);
SDL_SendMouseMotion(WIN_GetEventTimestamp(), window, SDL_GLOBAL_MOUSE_ID, false, (float)cursorPos.x, (float)cursorPos.y);
}
@@ -472,11 +473,6 @@ static SDL_MOUSE_EVENT_SOURCE GetMouseMessageSource(ULONG extrainfo)
return SDL_MOUSE_EVENT_SOURCE_PEN;
}
}
/* Sometimes WM_INPUT events won't have the correct touch signature,
so we have to rely purely on the touch bit being set. */
if (SDL_TouchDevicesAvailable() && extrainfo & 0x80) {
return SDL_MOUSE_EVENT_SOURCE_TOUCH;
}
return SDL_MOUSE_EVENT_SOURCE_MOUSE;
}
#endif // !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
@@ -614,7 +610,8 @@ static void WIN_HandleRawMouseInput(Uint64 timestamp, SDL_VideoData *data, HANDL
return;
}
if (GetMouseMessageSource(rawmouse->ulExtraInformation) != SDL_MOUSE_EVENT_SOURCE_MOUSE) {
if (GetMouseMessageSource(rawmouse->ulExtraInformation) != SDL_MOUSE_EVENT_SOURCE_MOUSE ||
(SDL_TouchDevicesAvailable() && (rawmouse->ulExtraInformation & 0x80) == 0x80)) {
return;
}
@@ -1235,22 +1232,19 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
case WM_NCACTIVATE:
{
// Don't immediately clip the cursor in case we're clicking minimize/maximize buttons
// This is the only place that this flag is set. This causes all subsequent calls to
// WIN_UpdateClipCursor for this window to be no-ops in this frame's message-pumping.
// This flag is unset at the end of message pumping each frame for every window, and
// should never be carried over between frames.
data->skip_update_clipcursor = true;
data->postpone_clipcursor = true;
data->clipcursor_queued = true;
/* Update the focus here, since it's possible to get WM_ACTIVATE and WM_SETFOCUS without
actually being the foreground window, but this appears to get called in all cases where
the global foreground window changes to and from this window. */
WIN_UpdateFocus(data->window, !!wParam);
WIN_UpdateFocus(data->window, !!wParam, GetMessagePos());
} break;
case WM_ACTIVATE:
{
// Update the focus in case we changed focus to a child window and then away from the application
WIN_UpdateFocus(data->window, !!LOWORD(wParam));
WIN_UpdateFocus(data->window, !!LOWORD(wParam), GetMessagePos());
} break;
case WM_MOUSEACTIVATE:
@@ -1273,14 +1267,14 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
case WM_SETFOCUS:
{
// Update the focus in case it's changing between top-level windows in the same application
WIN_UpdateFocus(data->window, true);
WIN_UpdateFocus(data->window, true, GetMessagePos());
} break;
case WM_KILLFOCUS:
case WM_ENTERIDLE:
{
// Update the focus in case it's changing between top-level windows in the same application
WIN_UpdateFocus(data->window, false);
WIN_UpdateFocus(data->window, false, GetMessagePos());
} break;
case WM_POINTERENTER:
@@ -1361,8 +1355,10 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
const Uint64 timestamp = WIN_GetEventTimestamp();
SDL_Window *window = data->window;
const bool istouching = IS_POINTER_INCONTACT_WPARAM(wParam) && IS_POINTER_FIRSTBUTTON_WPARAM(wParam);
// if lifting off, do it first, so any motion changes don't cause app issues.
if (msg == WM_POINTERUP) {
if (!istouching) {
SDL_SendPenTouch(timestamp, pen, window, (pen_info.penFlags & PEN_FLAG_INVERTED) != 0, false);
}
@@ -1392,7 +1388,7 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
}
// if setting down, do it last, so the pen is positioned correctly from the first contact.
if (msg == WM_POINTERDOWN) {
if (istouching) {
SDL_SendPenTouch(timestamp, pen, window, (pen_info.penFlags & PEN_FLAG_INVERTED) != 0, true);
}
@@ -1408,9 +1404,8 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
window->flags & (SDL_WINDOW_MOUSE_RELATIVE_MODE | SDL_WINDOW_MOUSE_GRABBED) ||
(window->mouse_rect.w > 0 && window->mouse_rect.h > 0)
);
if (wish_clip_cursor) {
data->skip_update_clipcursor = false;
WIN_UpdateClipCursor(window);
if (wish_clip_cursor) { // queue clipcursor refresh on pump finish
data->clipcursor_queued = true;
}
}
@@ -1435,6 +1430,7 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
SDL_SendMouseMotion(WIN_GetEventTimestamp(), window, SDL_GLOBAL_MOUSE_ID, false, (float)GET_X_LPARAM(lParam), (float)GET_Y_LPARAM(lParam));
}
}
} break;
case WM_LBUTTONUP:
@@ -1498,8 +1494,10 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
if (!(data->window->flags & SDL_WINDOW_MOUSE_CAPTURE)) {
if (SDL_GetMouseFocus() == data->window && !SDL_GetMouse()->relative_mode && !IsIconic(hwnd)) {
SDL_Mouse *mouse;
DWORD pos = GetMessagePos();
POINT cursorPos;
GetCursorPos(&cursorPos);
cursorPos.x = GET_X_LPARAM(pos);
cursorPos.y = GET_Y_LPARAM(pos);
ScreenToClient(hwnd, &cursorPos);
mouse = SDL_GetMouse();
if (!mouse->was_touch_mouse_events) { // we're not a touch handler causing a mouse leave?
@@ -1638,7 +1636,7 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
// 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);
GetCursorPos(&cursorPos); // want the most current pos so as to not cause position change
ScreenToClient(hwnd, &cursorPos);
PostMessage(hwnd, WM_MOUSEMOVE, 0, cursorPos.x | (((Uint32)((Sint16)cursorPos.y)) << 16));
}
@@ -1852,6 +1850,9 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
data->initial_size_rect.bottom = data->window->y + data->window->h;
SetTimer(hwnd, (UINT_PTR)SDL_IterateMainCallbacks, USER_TIMER_MINIMUM, NULL);
// Reset the keyboard, as we won't get any key up events during the modal loop
SDL_ResetKeyboard();
}
} break;
@@ -2590,13 +2591,27 @@ void WIN_PumpEvents(SDL_VideoDevice *_this)
}
}
// Update the clipping rect in case someone else has stolen it
// fire queued clipcursor refreshes
if (_this) {
SDL_Window *window = _this->windows;
while (window) {
bool refresh_clipcursor = false;
SDL_WindowData *data = window->internal;
if (data && data->skip_update_clipcursor) {
data->skip_update_clipcursor = false;
if (data) {
refresh_clipcursor = data->clipcursor_queued;
data->clipcursor_queued = false; // Must be cleared unconditionally.
data->postpone_clipcursor = false; // Must be cleared unconditionally.
// Must happen before UpdateClipCursor.
// Although its occurrence currently
// always coincides with the queuing of
// clipcursor, it is logically distinct
// and this coincidence might no longer
// be true in the future.
// Ergo this placement concordantly
// conveys its unconditionality
// vis-a-vis the queuing of clipcursor.
}
if (refresh_clipcursor) {
WIN_UpdateClipCursor(window);
}
window = window->next;
-4
View File
@@ -120,9 +120,6 @@ static void WIN_DeleteDevice(SDL_VideoDevice *device)
SDL_UnloadObject(data->dxgiDLL);
}
#endif
if (device->wakeup_lock) {
SDL_DestroyMutex(device->wakeup_lock);
}
SDL_free(device->internal->rawinput);
SDL_free(device->internal);
SDL_free(device);
@@ -148,7 +145,6 @@ static SDL_VideoDevice *WIN_CreateDevice(void)
return NULL;
}
device->internal = data;
device->wakeup_lock = SDL_CreateMutex();
device->system_theme = WIN_GetSystemTheme();
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
+31 -7
View File
@@ -348,6 +348,10 @@ bool WIN_SetWindowPositionInternal(SDL_Window *window, UINT flags, SDL_WindowRec
// Update any child windows
for (child_window = window->first_child; child_window; child_window = child_window->next_sibling) {
if (!child_window->internal) {
// This child window is not yet fully initialized.
continue;
}
if (!WIN_SetWindowPositionInternal(child_window, flags, SDL_WINDOWRECT_CURRENT)) {
result = false;
}
@@ -1028,8 +1032,9 @@ void WIN_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int *
void WIN_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_WindowData *data = window->internal;
HWND hwnd = data->hwnd;
DWORD style;
HWND hwnd;
bool bActivate = SDL_GetHintBoolean(SDL_HINT_WINDOW_ACTIVATE_WHEN_SHOWN, true);
@@ -1038,17 +1043,30 @@ void WIN_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
WIN_SetWindowPosition(_this, window);
}
hwnd = window->internal->hwnd;
// If the window isn't borderless and will be fullscreen, use the borderless style to hide the initial borders.
if (window->pending_flags & SDL_WINDOW_FULLSCREEN) {
if (!(window->flags & SDL_WINDOW_BORDERLESS)) {
window->flags |= SDL_WINDOW_BORDERLESS;
style = GetWindowLong(hwnd, GWL_STYLE);
style &= ~STYLE_MASK;
style |= GetWindowStyle(window);
SetWindowLong(hwnd, GWL_STYLE, style);
window->flags &= ~SDL_WINDOW_BORDERLESS;
}
}
style = GetWindowLong(hwnd, GWL_EXSTYLE);
if (style & WS_EX_NOACTIVATE) {
bActivate = false;
}
data->showing_window = true;
if (bActivate) {
ShowWindow(hwnd, SW_SHOW);
} else {
// Use SetWindowPos instead of ShowWindow to avoid activating the parent window if this is a child window
SetWindowPos(hwnd, NULL, 0, 0, 0, 0, window->internal->copybits_flag | SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
}
data->showing_window = false;
if (window->flags & SDL_WINDOW_POPUP_MENU && bActivate) {
WIN_SetKeyboardFocus(window, window->parent == SDL_GetKeyboardFocus());
@@ -1207,10 +1225,12 @@ void WIN_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_WindowData *data = window->internal;
if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
HWND hwnd = data->hwnd;
data->expected_resize = true;
ShowWindow(hwnd, SW_RESTORE);
data->expected_resize = false;
if (!data->showing_window || window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED)) {
HWND hwnd = data->hwnd;
data->expected_resize = true;
ShowWindow(hwnd, SW_RESTORE);
data->expected_resize = false;
}
} else {
data->windowed_mode_was_maximized = false;
}
@@ -1218,18 +1238,22 @@ void WIN_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window)
static void WIN_UpdateCornerRoundingForHWND(SDL_VideoDevice *_this, HWND hwnd, DWM_WINDOW_CORNER_PREFERENCE cornerPref)
{
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
SDL_VideoData *videodata = _this->internal;
if (videodata->DwmSetWindowAttribute) {
videodata->DwmSetWindowAttribute(hwnd, DWMWA_WINDOW_CORNER_PREFERENCE, &cornerPref, sizeof(cornerPref));
}
#endif
}
static void WIN_UpdateBorderColorForHWND(SDL_VideoDevice *_this, HWND hwnd, COLORREF colorRef)
{
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
SDL_VideoData *videodata = _this->internal;
if (videodata->DwmSetWindowAttribute) {
videodata->DwmSetWindowAttribute(hwnd, DWMWA_BORDER_COLOR, &colorRef, sizeof(colorRef));
}
#endif
}
/**
@@ -1591,7 +1615,7 @@ void WIN_UnclipCursorForWindow(SDL_Window *window) {
void WIN_UpdateClipCursor(SDL_Window *window)
{
SDL_WindowData *data = window->internal;
if (data->in_title_click || data->focus_click_pending || data->skip_update_clipcursor) {
if (data->in_title_click || data->focus_click_pending || data->postpone_clipcursor) {
return;
}
+3 -1
View File
@@ -78,11 +78,13 @@ struct SDL_WindowData
bool in_border_change;
bool in_title_click;
Uint8 focus_click_pending;
bool skip_update_clipcursor;
bool postpone_clipcursor;
bool clipcursor_queued;
bool windowed_mode_was_maximized;
bool in_window_deactivation;
bool force_ws_maximizebox;
bool disable_move_size_events;
bool showing_window;
int in_modal_loop;
RECT initial_size_rect;
RECT cursor_clipped_rect; // last successfully committed clipping rect for this window
+3
View File
@@ -71,6 +71,9 @@
#ifdef SDL_VIDEO_DRIVER_X11_XSHAPE
#include <X11/extensions/shape.h>
#endif
#ifdef SDL_VIDEO_DRIVER_X11_XTEST
#include <X11/extensions/XTest.h>
#endif
#ifdef __cplusplus
extern "C" {
+83 -48
View File
@@ -506,17 +506,32 @@ static void X11_DispatchFocusOut(SDL_VideoDevice *_this, SDL_WindowData *data)
static void X11_DispatchMapNotify(SDL_WindowData *data)
{
SDL_Window *window = data->window;
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESTORED, 0, 0);
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_SHOWN, 0, 0);
if (!(window->flags & SDL_WINDOW_HIDDEN) && (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
data->was_shown = true;
// This may be sent when restoring a minimized window.
if (window->flags & SDL_WINDOW_MINIMIZED) {
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESTORED, 0, 0);
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_EXPOSED, 0, 0);
}
if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
SDL_UpdateWindowGrab(window);
}
}
static void X11_DispatchUnmapNotify(SDL_WindowData *data)
{
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_HIDDEN, 0, 0);
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_MINIMIZED, 0, 0);
SDL_Window *window = data->window;
// This may be sent when minimizing a window.
if (!window->is_hiding) {
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_MINIMIZED, 0, 0);
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_OCCLUDED, 0, 0);
} else {
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_HIDDEN, 0, 0);
}
}
static void DispatchWindowMove(SDL_VideoDevice *_this, const SDL_WindowData *data, const SDL_Point *point)
@@ -1096,6 +1111,41 @@ void X11_GetBorderValues(SDL_WindowData *data)
}
}
void X11_EmitConfigureNotifyEvents(SDL_WindowData *data, XConfigureEvent *xevent)
{
if (xevent->x != data->last_xconfigure.x ||
xevent->y != data->last_xconfigure.y) {
if (!data->size_move_event_flags) {
SDL_Window *w;
int x = xevent->x;
int y = xevent->y;
data->pending_operation &= ~X11_PENDING_OP_MOVE;
SDL_GlobalToRelativeForWindow(data->window, x, y, &x, &y);
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_MOVED, x, y);
for (w = data->window->first_child; w; w = w->next_sibling) {
// Don't update hidden child popup windows, their relative position doesn't change
if (SDL_WINDOW_IS_POPUP(w) && !(w->flags & SDL_WINDOW_HIDDEN)) {
X11_UpdateWindowPosition(w, true);
}
}
}
}
if (xevent->width != data->last_xconfigure.width ||
xevent->height != data->last_xconfigure.height) {
if (!data->size_move_event_flags) {
data->pending_operation &= ~X11_PENDING_OP_RESIZE;
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_RESIZED,
xevent->width,
xevent->height);
}
}
SDL_copyp(&data->last_xconfigure, xevent);
}
static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
{
SDL_VideoData *videodata = _this->internal;
@@ -1291,8 +1341,10 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
SDL_SendMouseMotion(0, data->window, SDL_GLOBAL_MOUSE_ID, false, (float)xevent->xcrossing.x, (float)xevent->xcrossing.y);
}
// We ungrab in LeaveNotify, so we may need to grab again here
SDL_UpdateWindowGrab(data->window);
// We ungrab in LeaveNotify, so we may need to grab again here, but not if captured, as the capture can be lost.
if (!(data->window->flags & SDL_WINDOW_MOUSE_CAPTURE)) {
SDL_UpdateWindowGrab(data->window);
}
X11_ProcessHitTest(_this, data, mouse->last_x, mouse->last_y, true);
} break;
@@ -1320,7 +1372,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
xevent->xcrossing.detail != NotifyInferior) {
/* In order for interaction with the window decorations and menu to work properly
on Mutter, we need to ungrab the keyboard when the the mouse leaves. */
on Mutter, we need to ungrab the keyboard when the mouse leaves. */
if (!(data->window->flags & SDL_WINDOW_FULLSCREEN)) {
X11_SetWindowKeyboardGrab(_this, data->window, false);
}
@@ -1447,9 +1499,8 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
xevent->xconfigure.x, xevent->xconfigure.y,
xevent->xconfigure.width, xevent->xconfigure.height);
#endif
// Real configure notify events are relative to the parent, synthetic events are absolute.
if (!xevent->xconfigure.send_event)
{
// Real configure notify events are relative to the parent, synthetic events are absolute.
if (!xevent->xconfigure.send_event) {
unsigned int NumChildren;
Window ChildReturn, Root, Parent;
Window *Children;
@@ -1462,41 +1513,23 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
&ChildReturn);
}
if (xevent->xconfigure.x != data->last_xconfigure.x ||
xevent->xconfigure.y != data->last_xconfigure.y) {
if (!data->size_move_event_flags) {
SDL_Window *w;
int x = xevent->xconfigure.x;
int y = xevent->xconfigure.y;
/* Xfce sends ConfigureNotify before PropertyNotify when toggling fullscreen and maximized, which
* is backwards from every other window manager, as well as what is expected by SDL and its clients.
* Defer emitting the size/move events until the corresponding PropertyNotify arrives.
*/
const Uint32 changed = X11_GetNetWMState(_this, data->window, xevent->xproperty.window) ^ data->window->flags;
if (changed & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_MAXIMIZED)) {
SDL_copyp(&data->pending_xconfigure, &xevent->xconfigure);
data->emit_size_move_after_property_notify = true;
}
data->pending_operation &= ~X11_PENDING_OP_MOVE;
SDL_GlobalToRelativeForWindow(data->window, x, y, &x, &y);
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_MOVED, x, y);
for (w = data->window->first_child; w; w = w->next_sibling) {
// Don't update hidden child popup windows, their relative position doesn't change
if (SDL_WINDOW_IS_POPUP(w) && !(w->flags & SDL_WINDOW_HIDDEN)) {
X11_UpdateWindowPosition(w, true);
}
}
}
if (!data->emit_size_move_after_property_notify) {
X11_EmitConfigureNotifyEvents(data, &xevent->xconfigure);
}
#ifdef SDL_VIDEO_DRIVER_X11_XSYNC
X11_HandleConfigure(data->window, &xevent->xconfigure);
#endif /* SDL_VIDEO_DRIVER_X11_XSYNC */
if (xevent->xconfigure.width != data->last_xconfigure.width ||
xevent->xconfigure.height != data->last_xconfigure.height) {
if (!data->size_move_event_flags) {
data->pending_operation &= ~X11_PENDING_OP_RESIZE;
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_RESIZED,
xevent->xconfigure.width,
xevent->xconfigure.height);
}
}
data->last_xconfigure = xevent->xconfigure;
} break;
// Have we been requested to quit (or another client message?)
@@ -1782,19 +1815,15 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
if (xevent->xproperty.atom == data->videodata->atoms._NET_WM_STATE) {
/* Get the new state from the window manager.
Compositing window managers can alter visibility of windows
without ever mapping / unmapping them, so we handle that here,
because they use the NETWM protocol to notify us of changes.
* Compositing window managers can alter visibility of windows
* without ever mapping / unmapping them, so we handle that here,
* because they use the NETWM protocol to notify us of changes.
*/
const SDL_WindowFlags flags = X11_GetNetWMState(_this, data->window, xevent->xproperty.window);
const SDL_WindowFlags changed = flags ^ data->window->flags;
if ((changed & (SDL_WINDOW_HIDDEN | SDL_WINDOW_FULLSCREEN)) != 0) {
if (flags & SDL_WINDOW_HIDDEN) {
X11_DispatchUnmapNotify(data);
} else {
X11_DispatchMapNotify(data);
}
if ((changed & SDL_WINDOW_HIDDEN) && !(flags & SDL_WINDOW_HIDDEN)) {
X11_DispatchMapNotify(data);
}
if (!SDL_WINDOW_IS_POPUP(data->window)) {
@@ -1805,6 +1834,8 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
if (!(flags & SDL_WINDOW_MINIMIZED)) {
const bool commit = SDL_memcmp(&data->window->current_fullscreen_mode, &data->requested_fullscreen_mode, sizeof(SDL_DisplayMode)) != 0;
// Ensure the maximized flag is cleared before entering fullscreen.
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_RESTORED, 0, 0);
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_ENTER_FULLSCREEN, 0, 0);
if (commit) {
/* This was initiated by the compositor, or the mode was changed between the request and the window
@@ -1896,6 +1927,10 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
}
}
}
if (data->emit_size_move_after_property_notify) {
X11_EmitConfigureNotifyEvents(data, &data->pending_xconfigure);
data->emit_size_move_after_property_notify = false;
}
if ((flags & SDL_WINDOW_INPUT_FOCUS)) {
if (data->pending_move) {
DispatchWindowMove(_this, data, &data->pending_move_point);
Loaded 100 of 108 files, more files were not shown because too many files have changed in this diff. Show more