SDL: joystick: linux: Avoid checking for gamepad mapping each frame

From 1542300a899fc81e814c6640142de4c88fecb5f7 Mon Sep 17 00:00:00 2001
From: Paul Cercueil <[EMAIL REDACTED]>
Date: Wed, 24 Mar 2021 22:37:08 +0000
Subject: [PATCH] joystick: linux: Avoid checking for gamepad mapping each
 frame

The information whether a specific joystick can be used as a gamepad is
not going to change every frame, so we can cache the result into a
variable.

This dramatically reduces the performance impact of SDL2 on small
embedded devices, since the code path that is now avoided was quite
heavy.

Fixes #4229.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 src/joystick/linux/SDL_sysjoystick.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/src/joystick/linux/SDL_sysjoystick.c b/src/joystick/linux/SDL_sysjoystick.c
index 466cee6da..206416889 100644
--- a/src/joystick/linux/SDL_sysjoystick.c
+++ b/src/joystick/linux/SDL_sysjoystick.c
@@ -113,6 +113,9 @@ typedef struct SDL_joylist_item
 
     /* Steam Controller support */
     SDL_bool m_bSteamController;
+
+    SDL_GamepadMapping *mapping;
+    SDL_bool has_gamepad_mapping;
 } SDL_joylist_item;
 
 static SDL_joylist_item *SDL_joylist = NULL;
@@ -376,6 +379,7 @@ MaybeRemoveDevice(const char *path)
 
             SDL_PrivateJoystickRemoved(item->device_instance);
 
+            SDL_free(item->mapping);
             SDL_free(item->path);
             SDL_free(item->name);
             SDL_free(item);
@@ -1403,6 +1407,21 @@ static SDL_bool
 LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
 {
     SDL_Joystick *joystick;
+    SDL_joylist_item *item = JoystickByDevIndex(device_index);
+
+    if (item->has_gamepad_mapping) {
+        SDL_memcpy(out, item->mapping, sizeof(*out));
+        return SDL_TRUE;
+    }
+
+    if (item->mapping)
+        return SDL_FALSE;
+
+    item->mapping = (SDL_GamepadMapping *) SDL_calloc(sizeof(*item->mapping), 1);
+    if (item->mapping == NULL) {
+        SDL_OutOfMemory();
+        return SDL_FALSE;
+    }
 
     joystick = (SDL_Joystick *) SDL_calloc(sizeof(*joystick), 1);
     if (joystick == NULL) {
@@ -1566,6 +1585,9 @@ LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
     LINUX_JoystickClose(joystick);
     SDL_free(joystick);
 
+    SDL_memcpy(item->mapping, out, sizeof(*out));
+    item->has_gamepad_mapping = SDL_TRUE;
+
     return SDL_TRUE;
 }