From f5fdf502fa99369b83615dbc469193d291b1430f Mon Sep 17 00:00:00 2001 From: Dax Dupont <17237624+DaxDupont@users.noreply.github.com> Date: Tue, 18 Feb 2025 21:06:12 +0100 Subject: [PATCH 1/2] [FIRE-10419] Selectively process devices based on CLSID to prevent stuttering #82 --- indra/llwindow/llwindowcallbacks.cpp | 2 +- indra/llwindow/llwindowcallbacks.h | 2 +- indra/llwindow/llwindowwin32.cpp | 62 ++++++++++++++++++++++++++-- indra/newview/llviewerwindow.cpp | 4 +- indra/newview/llviewerwindow.h | 2 +- 5 files changed, 63 insertions(+), 9 deletions(-) diff --git a/indra/llwindow/llwindowcallbacks.cpp b/indra/llwindow/llwindowcallbacks.cpp index c160382c17..059602819e 100644 --- a/indra/llwindow/llwindowcallbacks.cpp +++ b/indra/llwindow/llwindowcallbacks.cpp @@ -184,7 +184,7 @@ bool LLWindowCallbacks::handleTimerEvent(LLWindow *window) return false; } -bool LLWindowCallbacks::handleDeviceChange(LLWindow *window) +bool LLWindowCallbacks::handleDeviceChange(LLWindow *window, bool deviceRemoved) { return false; } diff --git a/indra/llwindow/llwindowcallbacks.h b/indra/llwindow/llwindowcallbacks.h index 63b585231f..950ccff034 100644 --- a/indra/llwindow/llwindowcallbacks.h +++ b/indra/llwindow/llwindowcallbacks.h @@ -67,7 +67,7 @@ public: virtual void handleWindowUnblock(LLWindow *window); // window coming back after taking over CPU for a while virtual void handleDataCopy(LLWindow *window, S32 data_type, void *data); virtual bool handleTimerEvent(LLWindow *window); - virtual bool handleDeviceChange(LLWindow *window); + virtual bool handleDeviceChange(LLWindow *window, bool deviceRemoved); virtual bool handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height); virtual bool handleWindowDidChangeScreen(LLWindow *window); diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index c4a3674a4f..6b134f489d 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -580,6 +580,15 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, // Make an instance of our window then define the window class mhInstance = GetModuleHandle(NULL); + // Get a notification filter setup for HID devices + DEV_BROADCAST_DEVICEINTERFACE notificationFilter; + + ZeroMemory(¬ificationFilter, sizeof(notificationFilter)); + notificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); + notificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + + HDEVNOTIFY deviceNotification = RegisterDeviceNotification(mWindowHandle, ¬ificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES); + // Init Direct Input - needed for joystick / Spacemouse LPDIRECTINPUT8 di8_interface; @@ -2291,6 +2300,24 @@ void LLWindowWin32::gatherInput() updateCursor(); } +// Define device classID for filtering +constexpr std::array classIDStrings = { + L"{745a17a0-74d3-11d0-b6fe-00a0c90f57da}", // Modern HID + L"{4d36e96c-e325-11ce-bfc1-08002be10318}", // Legacy/Serial + L"{a5dcbf10-6530-11d2-901f-00c04fb951ed}" // SpaceNavigator/Xbox +}; + +std::array deviceCLSIDWhitelist; + +// Convert to CLSID to make it easier +void initializeDeviceCLSIDArray() +{ + for (size_t i = 0; i < classIDStrings.size(); ++i) + { + CLSIDFromString(classIDStrings[i], &deviceCLSIDWhitelist[i]); + } +} + static LLTrace::BlockTimerStatHandle FTM_KEYHANDLER("Handle Keyboard"); static LLTrace::BlockTimerStatHandle FTM_MOUSEHANDLER("Handle Mouse"); @@ -2349,11 +2376,38 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_DEVICECHANGE: { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_DEVICECHANGE"); - if (w_param == DBT_DEVNODES_CHANGED || w_param == DBT_DEVICEARRIVAL) - { - WINDOW_IMP_POST(window_imp->mCallbacks->handleDeviceChange(window_imp)); - return 1; + // [FIRE-10419] Prevent all devices from being scanned on each change + // if (w_param == DBT_DEVNODES_CHANGED || w_param == DBT_DEVICEARRIVAL) + // { + // WINDOW_IMP_POST(window_imp->mCallbacks->handleDeviceChange(window_imp)); + // return 1; + // } + + // Only bother initalizing when needed. + if (deviceCLSIDWhitelist.empty()) + { + initializeDeviceCLSIDArray(); + } + + if (w_param == DBT_DEVICEARRIVAL || w_param == DBT_DEVICEREMOVECOMPLETE) + { + DEV_BROADCAST_HDR* dtype = (DEV_BROADCAST_HDR*)l_param; + if (dtype->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) + { + DEV_BROADCAST_DEVICEINTERFACE* iface = (DEV_BROADCAST_DEVICEINTERFACE*)l_param; + + // Iterate through the CLSID whitelist for comparison and only fire if it's a useful device + for (const auto& guid : deviceCLSIDWhitelist) + { + if (memcmp(&iface->dbcc_classguid, &guid, sizeof(GUID)) == 0) + { + bool deviceRemoved = (w_param == DBT_DEVICEREMOVECOMPLETE); + WINDOW_IMP_POST(window_imp->mCallbacks->handleDeviceChange(window_imp, deviceRemoved)); + break; + } + } + } } break; } diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 030b01a6f3..4cca37f63f 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1839,10 +1839,10 @@ bool LLViewerWindow::handleTimerEvent(LLWindow *window) return false; } -bool LLViewerWindow::handleDeviceChange(LLWindow *window) +bool LLViewerWindow::handleDeviceChange(LLWindow *window, bool deviceRemoved) { // give a chance to use a joystick after startup (hot-plugging) - if (!LLViewerJoystick::getInstance()->isJoystickInitialized() ) + if (!deviceRemoved && !LLViewerJoystick::getInstance()->isJoystickInitialized()) { LLViewerJoystick::getInstance()->init(true); return true; diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index f63be5dbf1..3e751f5b16 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -225,7 +225,7 @@ public: /*virtual*/ void handleWindowUnblock(LLWindow *window); /*virtual*/ void handleDataCopy(LLWindow *window, S32 data_type, void *data); /*virtual*/ bool handleTimerEvent(LLWindow *window); - /*virtual*/ bool handleDeviceChange(LLWindow *window); + /*virtual*/ bool handleDeviceChange(LLWindow *window, bool deviceRemoved); /*virtual*/ bool handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height); /*virtual*/ bool handleWindowDidChangeScreen(LLWindow *window); From 4aff595bdf508cbf63eb8fadbd26698b4bb752d5 Mon Sep 17 00:00:00 2001 From: Dax Dupont <17237624+DaxDupont@users.noreply.github.com> Date: Fri, 21 Feb 2025 22:50:33 +0100 Subject: [PATCH 2/2] Added FS comments --- indra/llwindow/llwindowcallbacks.cpp | 2 +- indra/llwindow/llwindowcallbacks.h | 2 +- indra/llwindow/llwindowwin32.cpp | 7 ++++--- indra/newview/llviewerwindow.cpp | 14 +++++++++++++- indra/newview/llviewerwindow.h | 2 +- 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/indra/llwindow/llwindowcallbacks.cpp b/indra/llwindow/llwindowcallbacks.cpp index 059602819e..86e6a9baf3 100644 --- a/indra/llwindow/llwindowcallbacks.cpp +++ b/indra/llwindow/llwindowcallbacks.cpp @@ -184,7 +184,7 @@ bool LLWindowCallbacks::handleTimerEvent(LLWindow *window) return false; } -bool LLWindowCallbacks::handleDeviceChange(LLWindow *window, bool deviceRemoved) +bool LLWindowCallbacks::handleDeviceChange(LLWindow *window, bool deviceRemoved) // [FIRE-10419] Added deviceRemoved bool to prevent reinitialize on disconnect. { return false; } diff --git a/indra/llwindow/llwindowcallbacks.h b/indra/llwindow/llwindowcallbacks.h index 950ccff034..dee4577d93 100644 --- a/indra/llwindow/llwindowcallbacks.h +++ b/indra/llwindow/llwindowcallbacks.h @@ -67,7 +67,7 @@ public: virtual void handleWindowUnblock(LLWindow *window); // window coming back after taking over CPU for a while virtual void handleDataCopy(LLWindow *window, S32 data_type, void *data); virtual bool handleTimerEvent(LLWindow *window); - virtual bool handleDeviceChange(LLWindow *window, bool deviceRemoved); + virtual bool handleDeviceChange(LLWindow *window, bool deviceRemoved); // [FIRE-10419] Added deviceRemoved bool to prevent reinitialize on disconnect. virtual bool handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height); virtual bool handleWindowDidChangeScreen(LLWindow *window); diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 6b134f489d..e707b06abf 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -579,8 +579,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, // Make an instance of our window then define the window class mhInstance = GetModuleHandle(NULL); - - // Get a notification filter setup for HID devices + // [FIRE-10419] Add notification filters for device notifcations for HID device handling DEV_BROADCAST_DEVICEINTERFACE notificationFilter; ZeroMemory(¬ificationFilter, sizeof(notificationFilter)); @@ -588,7 +587,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, notificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; HDEVNOTIFY deviceNotification = RegisterDeviceNotification(mWindowHandle, ¬ificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES); - + // // Init Direct Input - needed for joystick / Spacemouse LPDIRECTINPUT8 di8_interface; @@ -2384,6 +2383,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ // return 1; // } + // Only bother initalizing when needed. if (deviceCLSIDWhitelist.empty()) { @@ -2410,6 +2410,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ } } break; + // } case WM_PAINT: diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 4cca37f63f..b0792712c2 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1839,7 +1839,19 @@ bool LLViewerWindow::handleTimerEvent(LLWindow *window) return false; } -bool LLViewerWindow::handleDeviceChange(LLWindow *window, bool deviceRemoved) +// [FIRE-10419] Added deviceRemoved bool to prevent reinitialize on disconnect. +// bool LLViewerWindow::handleDeviceChange(LLWindow* window) +// { +// if (!LLViewerJoystick::getInstance()->isJoystickInitialized()) +// { +// LLViewerJoystick::getInstance()->init(true); +// return true; +// } +// return false; +// } +// + +bool LLViewerWindow::handleDeviceChange(LLWindow *window, bool deviceRemoved) { // give a chance to use a joystick after startup (hot-plugging) if (!deviceRemoved && !LLViewerJoystick::getInstance()->isJoystickInitialized()) diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 3e751f5b16..1ddd41e547 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -225,7 +225,7 @@ public: /*virtual*/ void handleWindowUnblock(LLWindow *window); /*virtual*/ void handleDataCopy(LLWindow *window, S32 data_type, void *data); /*virtual*/ bool handleTimerEvent(LLWindow *window); - /*virtual*/ bool handleDeviceChange(LLWindow *window, bool deviceRemoved); + /*virtual*/ bool handleDeviceChange(LLWindow *window, bool deviceRemoved); // [FIRE-10419] Added deviceRemoved bool to prevent reinitialize on disconnect. /*virtual*/ bool handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height); /*virtual*/ bool handleWindowDidChangeScreen(LLWindow *window);