To look for already opened device, or available device index.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
This is a bit of refactoring prior to some more patches to make XInput device enumeration and report reading asynchronous.
Currently every call to XInputGetState does an ioctl, which introduces a very high load on wineserver and windevice (with multiple round trips to satisfy the ioctl).
I intend to optimize this by using a thread queueing asynchronous reads to get the HID reports, and update the state in background, as well as refreshing the device list. XInputGetState would then only be about acquiring the critical section and copying the state.
dlls/xinput1_3/hid.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-)
diff --git a/dlls/xinput1_3/hid.c b/dlls/xinput1_3/hid.c index 0f4dec44ee3..e7a77813c71 100644 --- a/dlls/xinput1_3/hid.c +++ b/dlls/xinput1_3/hid.c @@ -71,6 +71,20 @@ struct hid_platform_private {
static DWORD last_check = 0;
+static BOOL find_opened_device(xinput_controller *devices, SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail, int *free_slot) +{ + struct hid_platform_private *private; + int i; + + *free_slot = XUSER_MAX_COUNT; + for (i = XUSER_MAX_COUNT; i > 0; i--) + { + if (!(private = devices[i - 1].platform_private)) *free_slot = i - 1; + else if (!wcscmp(detail->DevicePath, private->device_path)) return TRUE; + } + return FALSE; +} + static void MarkUsage(struct hid_platform_private *private, WORD usage, LONG min, LONG max, USHORT bits) { struct axis_info info = {min, max-min, bits}; @@ -219,7 +233,7 @@ void HID_find_gamepads(xinput_controller *devices) HIDP_CAPS caps; NTSTATUS status; DWORD idx; - int i, open_device_idx; + int i;
idx = GetTickCount(); if ((idx - last_check) < 2000) @@ -255,24 +269,9 @@ void HID_find_gamepads(xinput_controller *devices) if (!wcsstr(data->DevicePath, L"IG_")) continue;
- open_device_idx = -1; - for (i = 0; i < XUSER_MAX_COUNT; i++) - { - struct hid_platform_private *private = devices[i].platform_private; - if (devices[i].platform_private) - { - if (!wcscmp(data->DevicePath, private->device_path)) - break; - } - else if(open_device_idx < 0) - open_device_idx = i; - } - if (i != XUSER_MAX_COUNT) - /* this device is already opened */ - continue; - if (open_device_idx < 0) - /* no open device slots */ - break; + if (find_opened_device(devices, data, &i)) continue; /* already opened */ + if (i == XUSER_MAX_COUNT) break; /* no more slots */ + device = CreateFileW(data->DevicePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 ); if (device == INVALID_HANDLE_VALUE) continue; @@ -286,7 +285,7 @@ void HID_find_gamepads(xinput_controller *devices) WARN("ignoring HID device, unsupported usage page %04x\n", caps.UsagePage); else if (caps.Usage != HID_USAGE_GENERIC_GAMEPAD && caps.Usage != HID_USAGE_GENERIC_JOYSTICK && caps.Usage != HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER) WARN("ignoring HID device, unsupported usage %04x:%04x\n", caps.UsagePage, caps.Usage); - else if (!init_controller(&devices[open_device_idx], ppd, &caps, device, data->DevicePath)) + else if (!init_controller(&devices[i], ppd, &caps, device, data->DevicePath)) WARN("ignoring HID device, failed to initialize\n"); else goto done;
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/xinput1_3/hid.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-)
diff --git a/dlls/xinput1_3/hid.c b/dlls/xinput1_3/hid.c index e7a77813c71..ac95ad3c402 100644 --- a/dlls/xinput1_3/hid.c +++ b/dlls/xinput1_3/hid.c @@ -223,12 +223,12 @@ failed:
void HID_find_gamepads(xinput_controller *devices) { + char buffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + MAX_PATH * sizeof(WCHAR)]; + SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail = (SP_DEVICE_INTERFACE_DETAIL_DATA_W *)buffer; HDEVINFO device_info_set; GUID hid_guid; SP_DEVICE_INTERFACE_DATA interface_data; - SP_DEVICE_INTERFACE_DETAIL_DATA_W *data; PHIDP_PREPARSED_DATA ppd; - DWORD detail_size = MAX_PATH * sizeof(WCHAR); HANDLE device; HIDP_CAPS caps; NTSTATUS status; @@ -251,9 +251,7 @@ void HID_find_gamepads(xinput_controller *devices) HidD_GetHidGuid(&hid_guid);
device_info_set = SetupDiGetClassDevsW(&hid_guid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); - - if (!(data = malloc(sizeof(*data) + detail_size))) goto done; - data->cbSize = sizeof(*data); + detail->cbSize = sizeof(*detail);
ZeroMemory(&interface_data, sizeof(interface_data)); interface_data.cbSize = sizeof(interface_data); @@ -262,17 +260,16 @@ void HID_find_gamepads(xinput_controller *devices) while (SetupDiEnumDeviceInterfaces(device_info_set, NULL, &hid_guid, idx++, &interface_data)) { - if (!SetupDiGetDeviceInterfaceDetailW(device_info_set, - &interface_data, data, sizeof(*data) + detail_size, NULL, NULL)) + if (!SetupDiGetDeviceInterfaceDetailW(device_info_set, &interface_data, detail, sizeof(buffer), NULL, NULL)) continue;
- if (!wcsstr(data->DevicePath, L"IG_")) + if (!wcsstr(detail->DevicePath, L"IG_")) continue;
- if (find_opened_device(devices, data, &i)) continue; /* already opened */ + if (find_opened_device(devices, detail, &i)) continue; /* already opened */ if (i == XUSER_MAX_COUNT) break; /* no more slots */
- device = CreateFileW(data->DevicePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 ); + device = CreateFileW(detail->DevicePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 ); if (device == INVALID_HANDLE_VALUE) continue;
@@ -285,7 +282,7 @@ void HID_find_gamepads(xinput_controller *devices) WARN("ignoring HID device, unsupported usage page %04x\n", caps.UsagePage); else if (caps.Usage != HID_USAGE_GENERIC_GAMEPAD && caps.Usage != HID_USAGE_GENERIC_JOYSTICK && caps.Usage != HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER) WARN("ignoring HID device, unsupported usage %04x:%04x\n", caps.UsagePage, caps.Usage); - else if (!init_controller(&devices[i], ppd, &caps, device, data->DevicePath)) + else if (!init_controller(&devices[i], ppd, &caps, device, detail->DevicePath)) WARN("ignoring HID device, failed to initialize\n"); else goto done; @@ -295,7 +292,6 @@ void HID_find_gamepads(xinput_controller *devices) }
done: - free(data); SetupDiDestroyDeviceInfoList(device_info_set); LeaveCriticalSection(&xinput_crit); }
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/xinput1_3/hid.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/dlls/xinput1_3/hid.c b/dlls/xinput1_3/hid.c index ac95ad3c402..382469a0be9 100644 --- a/dlls/xinput1_3/hid.c +++ b/dlls/xinput1_3/hid.c @@ -285,13 +285,12 @@ void HID_find_gamepads(xinput_controller *devices) else if (!init_controller(&devices[i], ppd, &caps, device, detail->DevicePath)) WARN("ignoring HID device, failed to initialize\n"); else - goto done; + continue;
CloseHandle(device); HidD_FreePreparsedData(ppd); }
-done: SetupDiDestroyDeviceInfoList(device_info_set); LeaveCriticalSection(&xinput_crit); }
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/xinput1_3/hid.c | 14 +++++++------- dlls/xinput1_3/xinput_main.c | 10 +++++----- dlls/xinput1_3/xinput_private.h | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/dlls/xinput1_3/hid.c b/dlls/xinput1_3/hid.c index 382469a0be9..00907b54bed 100644 --- a/dlls/xinput1_3/hid.c +++ b/dlls/xinput1_3/hid.c @@ -71,7 +71,7 @@ struct hid_platform_private {
static DWORD last_check = 0;
-static BOOL find_opened_device(xinput_controller *devices, SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail, int *free_slot) +static BOOL find_opened_device(SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail, int *free_slot) { struct hid_platform_private *private; int i; @@ -79,7 +79,7 @@ static BOOL find_opened_device(xinput_controller *devices, SP_DEVICE_INTERFACE_D *free_slot = XUSER_MAX_COUNT; for (i = XUSER_MAX_COUNT; i > 0; i--) { - if (!(private = devices[i - 1].platform_private)) *free_slot = i - 1; + if (!(private = controllers[i - 1].platform_private)) *free_slot = i - 1; else if (!wcscmp(detail->DevicePath, private->device_path)) return TRUE; } return FALSE; @@ -221,7 +221,7 @@ failed: return FALSE; }
-void HID_find_gamepads(xinput_controller *devices) +void HID_find_gamepads(void) { char buffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + MAX_PATH * sizeof(WCHAR)]; SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail = (SP_DEVICE_INTERFACE_DETAIL_DATA_W *)buffer; @@ -266,7 +266,7 @@ void HID_find_gamepads(xinput_controller *devices) if (!wcsstr(detail->DevicePath, L"IG_")) continue;
- if (find_opened_device(devices, detail, &i)) continue; /* already opened */ + if (find_opened_device(detail, &i)) continue; /* already opened */ if (i == XUSER_MAX_COUNT) break; /* no more slots */
device = CreateFileW(detail->DevicePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 ); @@ -282,7 +282,7 @@ void HID_find_gamepads(xinput_controller *devices) WARN("ignoring HID device, unsupported usage page %04x\n", caps.UsagePage); else if (caps.Usage != HID_USAGE_GENERIC_GAMEPAD && caps.Usage != HID_USAGE_GENERIC_JOYSTICK && caps.Usage != HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER) WARN("ignoring HID device, unsupported usage %04x:%04x\n", caps.UsagePage, caps.Usage); - else if (!init_controller(&devices[i], ppd, &caps, device, detail->DevicePath)) + else if (!init_controller(&controllers[i], ppd, &caps, device, detail->DevicePath)) WARN("ignoring HID device, failed to initialize\n"); else continue; @@ -317,11 +317,11 @@ static void remove_gamepad(xinput_controller *device) LeaveCriticalSection(&device->crit); }
-void HID_destroy_gamepads(xinput_controller *devices) +void HID_destroy_gamepads(void) { int i; for (i = 0; i < XUSER_MAX_COUNT; i++) - remove_gamepad(&devices[i]); + remove_gamepad(&controllers[i]); }
static SHORT scale_short(LONG value, const struct axis_info *axis) diff --git a/dlls/xinput1_3/xinput_main.c b/dlls/xinput1_3/xinput_main.c index 63b7dd7f0b5..2d9f54c83f2 100644 --- a/dlls/xinput1_3/xinput_main.c +++ b/dlls/xinput1_3/xinput_main.c @@ -104,7 +104,7 @@ BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved) break; case DLL_PROCESS_DETACH: if (reserved) break; - HID_destroy_gamepads(controllers); + HID_destroy_gamepads(); break; } return TRUE; @@ -120,7 +120,7 @@ void WINAPI DECLSPEC_HOTPATCH XInputEnable(BOOL enable) to the controllers. Setting to true will send the last vibration value (sent to XInputSetState) to the controller and allow messages to be sent */ - HID_find_gamepads(controllers); + HID_find_gamepads();
for (index = 0; index < XUSER_MAX_COUNT; index ++) { @@ -136,7 +136,7 @@ DWORD WINAPI DECLSPEC_HOTPATCH XInputSetState(DWORD index, XINPUT_VIBRATION* vib
TRACE("(index %u, vibration %p)\n", index, vibration);
- HID_find_gamepads(controllers); + HID_find_gamepads();
if (index >= XUSER_MAX_COUNT) return ERROR_BAD_ARGUMENTS; @@ -157,7 +157,7 @@ static DWORD xinput_get_state(DWORD index, XINPUT_STATE *state) if (!state) return ERROR_BAD_ARGUMENTS;
- HID_find_gamepads(controllers); + HID_find_gamepads();
if (index >= XUSER_MAX_COUNT) return ERROR_BAD_ARGUMENTS; @@ -421,7 +421,7 @@ DWORD WINAPI DECLSPEC_HOTPATCH XInputGetCapabilities(DWORD index, DWORD flags, X { TRACE("(index %u, flags 0x%x, capabilities %p)\n", index, flags, capabilities);
- HID_find_gamepads(controllers); + HID_find_gamepads();
if (index >= XUSER_MAX_COUNT) return ERROR_BAD_ARGUMENTS; diff --git a/dlls/xinput1_3/xinput_private.h b/dlls/xinput1_3/xinput_private.h index 0de4f3b0b03..2bf16c0ffce 100644 --- a/dlls/xinput1_3/xinput_private.h +++ b/dlls/xinput1_3/xinput_private.h @@ -30,8 +30,8 @@ typedef struct _xinput_controller extern CRITICAL_SECTION xinput_crit; extern xinput_controller controllers[XUSER_MAX_COUNT];
-void HID_find_gamepads(xinput_controller *devices) DECLSPEC_HIDDEN; -void HID_destroy_gamepads(xinput_controller *devices) DECLSPEC_HIDDEN; +void HID_find_gamepads(void) DECLSPEC_HIDDEN; +void HID_destroy_gamepads(void) DECLSPEC_HIDDEN; void HID_update_state(xinput_controller* device, XINPUT_STATE *state) DECLSPEC_HIDDEN; DWORD HID_set_state(xinput_controller* device, XINPUT_VIBRATION* state) DECLSPEC_HIDDEN; void HID_enable(xinput_controller* device, BOOL enable) DECLSPEC_HIDDEN;