You can't do blending directly in PQ space, which means you have to create a scene render target in linear space and use shaders to convert PQ texture data to linear, etc. All of this is out of scope for the SDL 2D renderer at the moment.
This allows color operations to happen in linear space between sRGB input and sRGB output. This is currently supported on the direct3d11, direct3d12 and opengl renderers.
This is a good resource on blending in linear space vs sRGB space:
https://blog.johnnovak.net/2016/09/21/what-every-coder-should-know-about-gamma/
Also added testcolorspace to verify colorspace changes
The usable fullscreen bounds need to be queried after window creation, as Wayland can send different usable bounds depending on the focused window's scaling mode.
The drawing uses the origin of the viewport as the coordinate origin, so we only need to clip against the size of the viewport.
Also added a unit test to catch this case in the future
These functions historically didn't set the error indicator on overflow.
Before commit 447b508a "error: SDL's allocators now call SDL_OutOfMemory
on error", their callers would call SDL_OutOfMemory() instead, which was
assumed to be close enough in meaning: "that's a silly amount of memory
that would overflow size_t" is similar to "that's more memory than
is available". Now that responsibility for calling SDL_OutOfMemory()
has been pushed down into SDL_calloc() and friends, the functions that
check for overflows might as well set more specific errors.
Signed-off-by: Simon McVittie <smcv@collabora.com>
A surface of width (0x7fff'ffff) / 2 = 0x3fff'ffff is not quite large
enough to make the pitch overflow in the way we wanted to test here:
with a 32-bit format, that makes each row 0xffff'fffc bytes, which
(just) fits in a 32-bit unsigned size_t. Increasing it to 0x4000'0000
pixels per row is enough to trigger the overflow we intended to test.
In SDL 2, this test bug was hidden by the fact that allocating
0xffff'fffc bytes on a 32-bit platform is very likely to fail, and SDL 2
reported both "malloc() failed" and "this amount of memory is too large
for a size_t" with the same error code.
Signed-off-by: Simon McVittie <smcv@collabora.com>
Adding 3 bytes of alignment to 0x7fff'ffff is not enough to make it
overflow a 4-byte unsigned size_t, so this test was not exercising
the intended failure mode. We cannot actually make this overflow
with a signed 32-bit width and an 8-bit format: the maximum width is
not enough to achieve that. However, if we switch to a 24-bit format,
we can make the calculation overflow.
In SDL 2, this test bug was hidden by the fact that allocating
0x7fff'ffff bytes on a 32-bit platform will usually fail, and SDL 2
reported both "malloc() failed" and "this amount of memory is too large
for a size_t" with the same error code.
Signed-off-by: Simon McVittie <smcv@collabora.com>
Add the ability to import and wrap external surfaces from external toolkits such as Qt and GTK.
Wayland surfaces and windows are more intrinsically tied to the client library than other windowing systems, so it is necessary to provide a way to initialize SDL with an existing wl_display object, which needs to be set prior to video system initialization, or export the internal SDL wl_display object for use by external applications or toolkits. For this, the global property SDL_PROPERTY_GLOBAL_VIDEO_WAYLAND_WL_DISPLAY_POINTER is used.
A Wayland example was added to testnative, and a basic example of Qt 6 interoperation is provided in the Wayland readme to demonstrate the use of external windows with both SDL owning the wl_display, and an external toolkit owning it.
If testautomation is running with only a specific audio driver enabled, we shouldn't try to open other ones, as they might fail.
Fixes https://github.com/libsdl-org/SDL/issues/8797
(cherry picked from commit 4c11307a4e75fbfde0d8ace6b19d612d2973bf0b)
Allow for the creation of SDL windows with a roleless surface that applications can use for their own purposes, such as with a windowing protocol other than XDG toplevel.
The property `wayland.surface_role_custom` will create a window with a surface that SDL can render to and handles input for, but is not associated with a toplevel window, so applications can use it for their own, custom purposes (e.g. wlr_layer_shell).
A test/minimal example is included in tests/testwaylandcustom.c
When a test has been disabled because it's known not to work reliably
or it's a test for unimplemented functionality, we probably don't want
to encourage developers and testers to run it and report its failures
as a bug.
Helps: #8798, #8800
Signed-off-by: Simon McVittie <smcv@collabora.com>
Added support for getting the real controller info, as well as the function SDL_GetGamepadSteamHandle() to get the Steam Input API handle, from the virtual gamepads provided by Steam.
Also added an event SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED which is triggered when a controller's API handle changes, e.g. the controllers were reassigned slots in the Steam UI.
Track and check move and resize requests separately, and consider them done if either the window is already at the expected location, or at least one configure event which moved or resized the window was processed. The avoids a timeout condition if resizing the window caused it to be implicitly moved in order to keep it within desktop bounds.
The automated positioning test now runs on GNOME/X11 without any sync requests timing out.
SDL window size, state, and position functions have been considered immediate, with their effects assuming to have taken effect upon successful return of the function. However, several windowing systems handle these requests asynchronously, resulting in the functions blocking until the changes have taken effect, potentially for long periods of time. Additionally, some windowing systems treat these as requests, and can potentially deny or fulfill the request in a manner differently than the application expects, such as not allowing a window to be positioned or sized beyond desktop borders, prohibiting fullscreen, and so on.
With these changes, applications can make requests of the window manager that do not block, with the understanding that an associated event will be sent if the request is fulfilled. Currently, size, position, maximize, minimize, and fullscreen calls are handled as asynchronous requests, with events being returned if the request is honored. If the application requires that the change take effect immediately, it can call the new SDL_SyncWindow function, which will attempt to block until the request is fulfilled, or some arbitrary timeout period elapses, the duration of which depends not only on the windowing system, but on the operation requested as well (e.g. a 100ms timeout is fine for most X11 events, but maximizing a window can take considerably longer for some reason). There is also a new hint 'SDL_VIDEO_SYNC_ALL_WINDOW_OPS' that will mimic the old behavior by synchronizing after every window operation with, again, the understanding that using this may result in the associated calls blocking for a relatively long period.
The deferred model also results in the window size and position getters not reporting false coordinates anymore, as they only forward what the window manager reports vs allowing applications to set arbitrary values, and fullscreen enter/leave events that were initiated via the window manager update the window state appropriately, where they didn't before.
Care was taken to ensure that order of operations is maintained, and that requests are not ignored or dropped. This does require some implicit internal synchronization in the various backends if many requests are made in a short period, as some state and behavior depends on other bits of state that need to be known at that particular point in time, but this isn't something that typical applications will hit, unless they are sending a lot of window state in a short time as the tests do.
The automated tests developed to test the previous behavior also resulted in previously undefined behavior being defined and normalized across platforms, particularly when it comes to the sizing and positioning of windows when they are in a fixed-size state, such as maximized or fullscreen. Size and position requests made when the window is not in a movable or resizable state will be deferred until it can be applied, so no requests are lost. These changes fix another long-standing issue with renderers recreating maximized windows, where the original non-maximized size was lost, resulting in the window being restored to the wrong size. All automated video tests pass across all platforms.
Overall, the "make a request/get an event" model better reflects how most windowing systems work, and some backends avoid spending significant time blocking while waiting for operations to complete.
This means the allocator's caller doesn't need to use SDL_OutOfMemory directly
if the allocation fails.
This applies to the usual allocators: SDL_malloc, SDL_calloc, SDL_realloc
(all of these regardless of if the app supplied a custom allocator or we're
using system malloc() or an internal copy of dlmalloc under the hood),
SDL_aligned_alloc, SDL_small_alloc, SDL_strdup, SDL_asprintf, SDL_wcsdup...
probably others. If it returns something you can pass to SDL_free, it should
work.
The caller might still need to use SDL_OutOfMemory if something that wasn't
SDL allocated the memory: operator new in C++ code, Objective-C's alloc
message, win32 GlobalAlloc, etc.
Fixes#8642.
The included ones need to wait until SDL_Init has run, or you'll get an empty
list, and we might also be adding more from an external gamecontrollerdb.txt
file, too.
Don't do it in POST_BUILD to avoid multiple parallel builds
stepping on each others toes.
Also don't use copy_if_different, but unconditionally copy it.
The build system should take care of dependencies.
Mesa and Nvidia handle it differently, and one or the other may fix their
implementation in the future, so test which way it works at runtime.
Reference Issue #8004.
* Moving forward and backward don't clear the current binding
* Use the tertiary face button to delete the current binding
* More small improvements to make navigation more intuitive
This patch adds an API for querying pressure-
sensitive pens, cf. SDL_pen.h:
- Enumerate all pens
- Get pen capabilities, names, GUIDs
- Distinguishes pens and erasers
- Distinguish attached and detached pens
- Pressure and tilt support
- Rotation, distance, throttle wheel support
(throttle wheel untested)
- Pen type and meta-information reporting
(partially tested)
Pen event reporting:
- Three new event structures: PenTip, PenMotion, and
PenButton
- Report location with sub-pixel precision
- Include axis and button status, is-eraser flag
Internal pen tracker, intended to be independent
of platform APIs, cf. SDL_pen_c.h:
- Track known pens
- Handle pen hotplugging
Automatic test:
- testautomation_pen.c
Other features:
- XInput2 implementation, incl. hotplugging
- Wayland implementation, incl. hotplugging
- Backward compatibility: pen events default to
emulating pens with mouse ID SDL_PEN_MOUSEID
- Can be toggled via SDL_HINT_PEN_NOT_MOUSE
- Test/demo program (testpen)
- Wacom pen feature identification by pen ID
Acknowledgements:
- Ping Cheng (Wacom) provided extensive feedback
on Wacom pen features and detection so that
hopefully untested Wacom devices have a
realistic chance of working out of the box.
This gives applications and binding systems a clearer view of what the hardware is so they can make intelligent decisions about how to present things to the user.
Gamepad mappings continue to use abxy for the face buttons for simplicity and compatibility with earlier versions of SDL, however the "SDL_GAMECONTROLLER_USE_BUTTON_LABELS" hint no longer has any effect.
Fixes https://github.com/libsdl-org/SDL/issues/6117
If the done signal is emitted by the common event handler, the window and all of its children have already been destroyed, so don't try to render with invalid renderer objects.
This lets apps optionally have a handful of callbacks for their entry points instead of a single main function. If used, the actual main/SDL_main/whatever entry point will be implemented in the single-header library SDL_main.h and the app will implement four separate functions:
First:
int SDL_AppInit(int argc, char **argv);
This will be called once before anything else. argc/argv work like they always do. If this returns 0, the app runs. If it returns < 0, the app calls SDL_AppQuit and terminates with an exit code that reports an error to the platform. If it returns > 0, the app calls SDL_AppQuit and terminates with an exit code that reports success to the platform. This function should not go into an infinite mainloop; it should do any one-time startup it requires and then return.
Then:
int SDL_AppIterate(void);
This is called over and over, possibly at the refresh rate of the display or some other metric that the platform dictates. This is where the heart of your app runs. It should return as quickly as reasonably possible, but it's not a "run one memcpy and that's all the time you have" sort of thing. The app should do any game updates, and render a frame of video. If it returns < 0, SDL will call SDL_AppQuit and terminate the process with an exit code that reports an error to the platform. If it returns > 0, the app calls SDL_AppQuit and terminates with an exit code that reports success to the platform. If it returns 0, then SDL_AppIterate will be called again at some regular frequency. The platform may choose to run this more or less (perhaps less in the background, etc), or it might just call this function in a loop as fast as possible. You do not check the event queue in this function (SDL_AppEvent exists for that).
Next:
int SDL_AppEvent(const SDL_Event *event);
This will be called once for each event pushed into the SDL queue. This may be called from any thread, and possibly in parallel to SDL_AppIterate. The fields in event do not need to be free'd (as you would normally need to do for SDL_EVENT_DROP_FILE, etc), and your app should not call SDL_PollEvent, SDL_PumpEvent, etc, as SDL will manage this for you. Return values are the same as from SDL_AppIterate(), so you can terminate in response to SDL_EVENT_QUIT, etc.
Finally:
void SDL_AppQuit(void);
This is called once before terminating the app--assuming the app isn't being forcibly killed or crashed--as a last chance to clean up. After this returns, SDL will call SDL_Quit so the app doesn't have to (but it's safe for the app to call it, too). Process termination proceeds as if the app returned normally from main(), so atexit handles will run, if your platform supports that.
The app does not implement SDL_main if using this. To turn this on, define SDL_MAIN_USE_CALLBACKS before including SDL_main.h. Defines like SDL_MAIN_HANDLED and SDL_MAIN_NOIMPL are also respected for callbacks, if the app wants to do some sort of magic main implementation thing.
In theory, on most platforms these can be implemented in the app itself, but this saves some #ifdefs in the app and lets everyone struggle less against some platforms, and might be more efficient in the long run, too.
On some platforms, it's possible this is the only reasonable way to go, but we haven't actually hit one that 100% requires it yet (but we will, if we want to write a RetroArch backend, for example).
Using the callback entry points works on every platform, because on platforms that don't require them, we can fake them with a simple loop in an internal implementation of the usual SDL_main.
The primary way we expect people to write SDL apps is with SDL_main, and this is not intended to replace it. If the app chooses to use this, it just removes some platform-specific details they might have to otherwise manage, and maybe removes a barrier to entry on some future platform.
Fixes#6785.
Reference PR #8247.
Almost nothing checks these return values, and there's no reason a valid
lock should fail to operate. The cases where a lock isn't valid (it's a
bogus pointer, it was previously destroyed, a thread is unlocking a lock it
doesn't own, etc) are undefined behavior and always were, and should be
treated as an application bug.
Reference Issue #8096.
The following objects now have properties that can be user modified:
* SDL_AudioStream
* SDL_Gamepad
* SDL_Joystick
* SDL_RWops
* SDL_Renderer
* SDL_Sensor
* SDL_Surface
* SDL_Texture
* SDL_Window
Also switched the D3D11 and D3D12 renderers to use real NV12 textures for NV12 data.
The combination of these two changes allows us to implement 0-copy video decode and playback for D3D11 in testffmpeg without any access to the renderer internals.
This avoids assuming that the pixels are suitably aligned for direct
access, which there's no guarantee that they are; in particular,
3-bytes-per-pixel RGB images are likely to have 3 out of 4 pixels
misaligned. On x86, dereferencing a misaligned pointer does what you
would expect, but on other architectures it's undefined whether it will
work, crash with SIGBUS, or silently give a wrong answer.
Signed-off-by: Simon McVittie <smcv@collabora.com>
We can't rely on irrational numbers like pi being represented exactly,
particularly when compiling for i386, where the i387 floating-point
interface carries out calculations in registers that have higher
precision than the actual double-precision variable. The 1980s were a
strange time.
Resolves: https://github.com/libsdl-org/SDL/issues/8311
Signed-off-by: Simon McVittie <smcv@collabora.com>
Now it offers the total requested bytes in addition to the amount
immediately needed (and immediately needed might be zero if the stream
already has enough queued to satisfy the request.
You can see it in action in testaudio by mousing over a logical device; it
will show a visualizer for the current PCM (whatever is currently being
recorded on a capture device, or whatever is being mixed for output on
playback devices).
Fixes#8122.
This is meant to offer a simplified API for people that are either migrating
directly from SDL2 with minimal effort or just want to make noise without
any of the fancy new API features.
Users of this API can just deal with a single SDL_AudioStream as their only
object/handle into the audio subsystem.
They are still allowed to open multiple devices (or open the same device
multiple times), but cannot change stream bindings on logical devices opened
through this function.
Destroying the single audio stream will also close the logical device behind
the scenes.