Wayland video subsystem uses a mix of libc and SDL function.
This patch switches libc functions to SDL ones and fixes a mismatch in memory
allocation/dealoccation of SDL_Cursor in SDL_waylandmouse.c (calloc on line 201
and SDL_free on line 313) which caused memory corruption if custom memory
allocator where provided to SDL.
As written, these contain undefined stack contents, which in practice
causes crashes/hangs and/or triggers the validation layers (they
complain about `pNext` and `flags` not being NULL).
When hint SDL_HINT_OPENGL_ES_DRIVER is set to "1" (e.g. for ANGLE support), assertion due to !_this->gl_config.driver_loaded can be causes while EGL is available.
The implementation of clip logic for relative mode seemed to
unnecessarily limit the usable area to the middle of the window, in a
2x2 pixel region. This has the adverse side effect of moving the
operating system cursor to that location, even if it is in a valid
location in the window.
While in most scenarios this is handled correctly (by storing the
original position of the cursor in the window and restoring when leaving
relative mode), there are edge cases where this clip operation can cause
WM_MOUSEMOVE to fire at a point in time where it counts as a relative
delta from SDL's perspective.
X11_SetDisplayMode currently calls X11_XRRSetCrtcConfig alone. This results
in the monitor's viewport getting changed, but the underlying screen dimensions
stay the same.
The spec indicates that RRSetCrtcConfig only changes the crtc mode and has no effect
on the screen dimensions, only mentioning that the new crtc must fit entirely within the
screen size. For the size to change, RRSetScreenSize also needs to be called.
This affects Metro Exodus on Linux, when changing the resolution in the in-game settings
Metro gets stuck in a loop waiting for the size of its vulkan surface to change. Because
XRRSetScreenSize is not called the screen size is never changed, the vulkan surface dimensions
do not change, and Metro hangs forever watching for a surface size update that will
never come.
This change disables the CRTC, calls XRRSetScreenSize, and then updates the
CRTC configuration. This fixes changing the resolution from the Metro settings.
Tested with:
Metro Exodus, Portal 2
Based on a patch by Jochen Schäfer <josch1710@live.de> :
The problem is, that in the initialization code uses the same structure for
desktop_mode and current_mode. See SDL_os2video.c:OS2_VideoInit():
stSDLDisplay.desktop_mode = stSDLDisplayMode;
stSDLDisplay.current_mode = stSDLDisplayMode;
...
stSDLDisplayMode.driverdata = pDisplayData;
Then, if you call GetDisplayModes, current_mode will added to the modes
list, with the same driverdata pointer to desktop_mode.
SDL_AddDisplayMode( display, &display->current_mode );
When VideoQuit gets called, first the modes list gets freed including the
driverdata, the desktop_mode gets freed. See SDL_video.c:SDL_VideoQuit():
for (j = display->num_display_modes; j--;) {
SDL_free(display->display_modes[j].driverdata);
display->display_modes[j].driverdata = NULL;
}
SDL_free(display->display_modes);
display->display_modes = NULL;
SDL_free(display->desktop_mode.driverdata);
display->desktop_mode.driverdata = NULL;
So, the display_modes[j].driverdata gets freed, but desktop_mode->driverdata
points to the same memory, but is not NULL'ed. When desktop_mode->driverdata
gets freed the memory is already freed, and libcx crashes the application on
SDL_Quit.
We can be in a situation where we receive a win32 hook callback on the same
thread that is currently waiting. In that case, we do still need to trigger
a wakeup when an event is pushed because the hook itself won't necessarily
do that (depending on what we return from the hook).
When possible use native os functions to make a blocking call waiting for
an incoming event. Previous behavior was to continuously poll the event
queue with a small delay between each poll.
The blocking call uses a new optional video driver event,
WaitEventTimeout, if available. It is called only if an window
already shown is available. If present the window is designated
using the variable wakeup_window to receive a wakeup event if
needed.
The WaitEventTimeout function accept a timeout parameter. If
positive the call will wait for an event or return if the timeout
expired without any event. If the timeout is zero it will
implement a polling behavior. If the timeout is negative the
function will block indefinetely waiting for an event.
To let the main thread sees events sent form a different thread
a "wake-up" signal is sent to the main thread if the main thread
is in a blocking state. The wake-up event is sent to the designated
wakeup_window if present.
The wake-up event is sent only if the PushEvent call is coming
from a different thread. Before sending the wake-up event
the ID of the thread making the blocking call is saved using the
variable blocking_thread_id and it is compared to the current
thread's id to decide if the wake-up event should be sent.
Two new optional video device methods are introduced:
WaitEventTimeout
SendWakeupEvent
in addition the mutex
wakeup_lock
which is defined and initialized but only for the drivers supporting the
methods above.
If the methods are not present the system behaves as previously
performing a periodic polling of the events queue.
The blocking call is disabled if a joystick or sensor is detected
and falls back to previous behavior.