Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow concurrent buffering and dispatch of input events #76399

Merged
merged 1 commit into from
May 8, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion core/input/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@
#include "core/input/input_map.h"
#include "core/os/os.h"

#ifdef DEV_ENABLED
#include "core/os/thread.h"
#endif

static const char *_joy_buttons[(size_t)JoyButton::SDL_MAX] = {
"a",
"b",
Expand Down Expand Up @@ -486,6 +490,10 @@ Vector3 Input::get_gyroscope() const {
}

void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated) {
// This function does the final delivery of the input event to user land.
// Regardless where the event came from originally, this has to happen on the main thread.
DEV_ASSERT(Thread::get_caller_id() == Thread::get_main_id());

// Notes on mouse-touch emulation:
// - Emulated mouse events are parsed, that is, re-routed to this method, so they make the same effects
// as true mouse events. The only difference is the situation is flagged as emulated so they are not
Expand Down Expand Up @@ -537,7 +545,9 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
touch_event->set_position(mb->get_position());
touch_event->set_double_tap(mb->is_double_click());
touch_event->set_device(InputEvent::DEVICE_ID_EMULATION);
_THREAD_SAFE_UNLOCK_
event_dispatch_function(touch_event);
_THREAD_SAFE_LOCK_
}
}

Expand All @@ -563,7 +573,9 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
drag_event->set_velocity(get_last_mouse_velocity());
drag_event->set_device(InputEvent::DEVICE_ID_EMULATION);

_THREAD_SAFE_UNLOCK_
event_dispatch_function(drag_event);
_THREAD_SAFE_LOCK_
}
}

Expand Down Expand Up @@ -664,7 +676,9 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em

if (ge.is_valid()) {
if (event_dispatch_function) {
_THREAD_SAFE_UNLOCK_
event_dispatch_function(ge);
_THREAD_SAFE_LOCK_
}
}

Expand All @@ -687,7 +701,9 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
}

if (event_dispatch_function) {
_THREAD_SAFE_UNLOCK_
event_dispatch_function(p_event);
_THREAD_SAFE_LOCK_
}
}

Expand Down Expand Up @@ -937,8 +953,15 @@ void Input::flush_buffered_events() {
_THREAD_SAFE_METHOD_

while (buffered_events.front()) {
_parse_input_event_impl(buffered_events.front()->get(), false);
// The final delivery of the input event involves releasing the lock.
// While the lock is released, another thread may lock it and add new events to the back.
// Therefore, we get each event and pop it while we still have the lock,
// to ensure the list is in a consistent state.
List<Ref<InputEvent>>::Element *E = buffered_events.front();
Ref<InputEvent> e = E->get();
buffered_events.pop_front();

_parse_input_event_impl(e, false);
}
}

Expand Down