Use a separate sensor watching function for gamepad events to avoid reliance on system sensor events and prevent a potential deadlock

This commit is contained in:
Sam Lantinga 2023-06-19 16:17:34 -07:00
parent 70e43c150e
commit 20ea35138f
3 changed files with 53 additions and 33 deletions

View file

@ -318,22 +318,6 @@ static void RecenterGamepad(SDL_Gamepad *gamepad)
}
}
/* SDL defines sensor orientation relative to the device natural
orientation, so when it's changed orientation to be used as a
gamepad, change the sensor orientation to match.
*/
static void AdjustSensorOrientation(SDL_Joystick *joystick, float *src, float *dst)
{
unsigned int i, j;
for (i = 0; i < 3; ++i) {
dst[i] = 0.0f;
for (j = 0; j < 3; ++j) {
dst[i] += joystick->sensor_transform[i][j] * src[j];
}
}
}
/*
* Event filter to fire gamepad events from joystick ones
*/
@ -408,23 +392,6 @@ static int SDLCALL SDL_GamepadEventWatcher(void *userdata, SDL_Event *event)
SDL_PushEvent(&deviceevent);
}
} break;
case SDL_EVENT_SENSOR_UPDATE:
{
SDL_LockJoysticks();
for (gamepad = SDL_gamepads; gamepad; gamepad = gamepad->next) {
if (gamepad->joystick->accel && gamepad->joystick->accel_sensor == event->sensor.which) {
float data[3];
AdjustSensorOrientation(gamepad->joystick, event->sensor.data, data);
SDL_SendJoystickSensor(event->common.timestamp, gamepad->joystick, SDL_SENSOR_ACCEL, event->sensor.sensor_timestamp, data, SDL_arraysize(data));
}
if (gamepad->joystick->gyro && gamepad->joystick->gyro_sensor == event->sensor.which) {
float data[3];
AdjustSensorOrientation(gamepad->joystick, event->sensor.data, data);
SDL_SendJoystickSensor(event->common.timestamp, gamepad->joystick, SDL_SENSOR_GYRO, event->sensor.sensor_timestamp, data, SDL_arraysize(data));
}
}
SDL_UnlockJoysticks();
} break;
default:
break;
}
@ -432,6 +399,52 @@ static int SDLCALL SDL_GamepadEventWatcher(void *userdata, SDL_Event *event)
return 1;
}
/* SDL defines sensor orientation relative to the device natural
orientation, so when it's changed orientation to be used as a
gamepad, change the sensor orientation to match.
*/
static void AdjustSensorOrientation(SDL_Joystick *joystick, float *src, float *dst)
{
unsigned int i, j;
for (i = 0; i < 3; ++i) {
dst[i] = 0.0f;
for (j = 0; j < 3; ++j) {
dst[i] += joystick->sensor_transform[i][j] * src[j];
}
}
}
/*
* Event filter to fire gamepad sensor events from system sensor events
*
* We don't use SDL_GamepadEventWatcher() for this because we want to
* deliver gamepad sensor events when system sensor events are disabled,
* and we also need to avoid a potential deadlock where joystick event
* delivery locks the joysticks and then the event queue, but sensor
* event delivery would lock the event queue and then from within the
* event watcher function lock the joysticks.
*/
void SDL_GamepadSensorWatcher(Uint64 timestamp, SDL_SensorID sensor, Uint64 sensor_timestamp, float *data, int num_values)
{
SDL_Gamepad *gamepad;
SDL_LockJoysticks();
for (gamepad = SDL_gamepads; gamepad; gamepad = gamepad->next) {
if (gamepad->joystick->accel && gamepad->joystick->accel_sensor == sensor) {
float gamepad_data[3];
AdjustSensorOrientation(gamepad->joystick, data, gamepad_data);
SDL_SendJoystickSensor(timestamp, gamepad->joystick, SDL_SENSOR_ACCEL, sensor_timestamp, gamepad_data, SDL_arraysize(gamepad_data));
}
if (gamepad->joystick->gyro && gamepad->joystick->gyro_sensor == sensor) {
float gamepad_data[3];
AdjustSensorOrientation(gamepad->joystick, data, gamepad_data);
SDL_SendJoystickSensor(timestamp, gamepad->joystick, SDL_SENSOR_GYRO, sensor_timestamp, gamepad_data, SDL_arraysize(gamepad_data));
}
}
SDL_UnlockJoysticks();
}
#ifdef __ANDROID__
/*
* Helper function to guess at a mapping based on the elements reported for this gamepad

View file

@ -42,4 +42,7 @@ extern SDL_bool SDL_ShouldIgnoreGamepad(const char *name, SDL_JoystickGUID guid)
/* Handle delayed guide button on a gamepad */
extern void SDL_GamepadHandleDelayedGuideButton(SDL_Joystick *joystick);
/* Handle system sensor data */
extern void SDL_GamepadSensorWatcher(Uint64 timestamp, SDL_SensorID sensor, Uint64 sensor_timestamp, float *data, int num_values);
#endif /* SDL_gamepad_c_h_ */

View file

@ -27,6 +27,7 @@
#ifndef SDL_EVENTS_DISABLED
#include "../events/SDL_events_c.h"
#endif
#include "../joystick/SDL_gamepad_c.h"
static SDL_SensorDriver *SDL_sensor_drivers[] = {
#ifdef SDL_SENSOR_ANDROID
@ -501,6 +502,9 @@ int SDL_SendSensorUpdate(Uint64 timestamp, SDL_Sensor *sensor, Uint64 sensor_tim
posted = SDL_PushEvent(&event) == 1;
}
#endif /* !SDL_EVENTS_DISABLED */
SDL_GamepadSensorWatcher(timestamp, sensor->instance_id, sensor_timestamp, data, num_values);
return posted;
}