mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-08 08:10:30 -10:00
winraw: keyboard and mouse are read by the poll by default
Reading the raw input queue in bulk from the poll has been behind RETROARCH_RAWINPUT_POLL=1. It is the default now, and RETROARCH_RAWINPUT_POLL=0 turns it off, should something need telling apart from it. Tried on Windows with threaded video, Vulkan, a 1000 Hz mouse and a keyboard, a minute of play: 9714 reports read in 7679 reads - one read an iteration, 2241 of them with reports in - none taken by the pump as a message, no key event dropped. The old path's two calls a report would have been 19428. With nothing happening it is one read a frame that finds nothing: 604 frames in the menu, 604 reads. What that buys beside the calls: the state the core reads is what the devices had sent at the moment of the poll, not what the video thread's last pump left; key events reach the menu and the core's keyboard callback from the main thread rather than the video thread; and the window is the main thread's, not the video driver's. That run also settles what Wine could not: Windows gives raw input to a window whose thread does not have the focus. The sink registration stays as RETROARCH_RAWINPUT_POLL=2 for a system where that turns out otherwise. Not tried on Windows: video not threaded, where the window, the pump and the poll are one thread's, and winraw_joypad's reports can come out of the same bulk read. samples/input/winraw_poll now runs that arrangement under Wine - window made by the poll, the pump leaving the reports, the poll reading them in bulk - and the test's switch-off case is =0. The line of counts the driver logs when it is freed is a debug line now.
This commit is contained in:
1 parent
c1efc6ee18
commit
1df2715776
3 files changed
+91
-29
No files matched your search
@@ -500,7 +500,8 @@ jobs:
|
||||
run: |
|
||||
set -eu
|
||||
# input/drivers/winraw_input.c with its keyboard and mouse
|
||||
# read in bulk by the poll (RETROARCH_RAWINPUT_POLL). The real
|
||||
# read in bulk by the poll (the default;
|
||||
# RETROARCH_RAWINPUT_POLL=0 turns it off). The real
|
||||
# driver under Wine on a virtual display, with the focused
|
||||
# window made and pumped by a second thread as the video
|
||||
# thread does, and the driver started from that thread. With
|
||||
@@ -516,7 +517,10 @@ jobs:
|
||||
# the messages below WM_INPUT and above it, as the
|
||||
# frontend's does on that thread, dispatches the ordinary
|
||||
# ones and leaves the reports for one bulk read; free takes
|
||||
# the window down, twenty restarts each do the same.
|
||||
# the window down, twenty restarts each do the same; and
|
||||
# with the window, the pump and the poll all on one thread,
|
||||
# as without threaded video, the reports are read in bulk
|
||||
# the same.
|
||||
trap 'wineserver -k >/dev/null 2>&1 || true' EXIT
|
||||
make clean all
|
||||
WINEDEBUG=-all timeout 300 make check
|
||||
|
||||
@@ -48,9 +48,10 @@ extern "C" {
|
||||
|
||||
/* Threading model
|
||||
* ---------------
|
||||
* (As it is by default. With RETROARCH_RAWINPUT_POLL the window is
|
||||
* the polling thread's and the reports are read in bulk by the poll:
|
||||
* see "Read by the poll" further down.)
|
||||
* (This is how the driver was, and is with RETROARCH_RAWINPUT_POLL=0
|
||||
* in the environment. By default the window is the polling thread's
|
||||
* and the reports are read in bulk by the poll: see "Read by the
|
||||
* poll" further down.)
|
||||
*
|
||||
* On every Windows video driver that can actually use this input
|
||||
* driver, it is built by the video context driver's input_driver
|
||||
@@ -716,12 +717,14 @@ static void winraw_update_mouse_state(winraw_input_t *wr,
|
||||
|
||||
/* Read by the poll
|
||||
* ----------------
|
||||
* With RETROARCH_RAWINPUT_POLL set in the environment, the keyboard
|
||||
* and mouse window is made by the first winraw_poll(), on the thread
|
||||
* that polls, and the reports waiting for it are read in bulk - one
|
||||
* GetRawInputBuffer() for all of them - at the start of every poll.
|
||||
* The keyboard and mouse window is made by the first winraw_poll(),
|
||||
* on the thread that polls, and the reports waiting for it are read
|
||||
* in bulk - one GetRawInputBuffer() for all of them - at the start of
|
||||
* every poll. RETROARCH_RAWINPUT_POLL=0 in the environment turns this
|
||||
* off and leaves the driver as the threading note at the top has it,
|
||||
* should something need telling apart from it.
|
||||
*
|
||||
* As it is otherwise (the threading note at the top), the window is
|
||||
* As it was (the threading note at the top), the window is
|
||||
* made on whichever thread runs the video driver's init, and each
|
||||
* report is a WM_INPUT message taken when that thread pumps: a
|
||||
* PeekMessage() and a GetRawInputData() per report, once per video
|
||||
@@ -787,13 +790,17 @@ static void winraw_update_mouse_state(winraw_input_t *wr,
|
||||
* - the pump got to it before a poll did - is read from its message
|
||||
* first, as it always was, and only then is the rest read in bulk.
|
||||
*
|
||||
* RETROARCH_RAWINPUT_POLL=2 also registers as a sink. Raw input goes
|
||||
* to a window only while its application is in the foreground, and
|
||||
* the expectation is that Windows judges that by process, so that a
|
||||
* window on a thread that does not have the focus still gets it. If
|
||||
* it judges by thread, nothing would arrive with =1 under threaded
|
||||
* video; as a sink everything arrives, and the main window's focus
|
||||
* (winraw_focus) decides whether it is taken. */
|
||||
* Raw input goes to a window only while its application is in the
|
||||
* foreground, and under threaded video this window's thread is not
|
||||
* the one with the focus. Windows judges the foreground by process,
|
||||
* not by thread: tried on Windows with threaded video, the reports
|
||||
* arrive. RETROARCH_RAWINPUT_POLL=2 is kept for a system where they
|
||||
* do not: it registers as a sink, so that everything arrives, and
|
||||
* the main window's focus (winraw_focus) decides whether it is taken.
|
||||
*
|
||||
* Measured there, a minute of play with a 1000 Hz mouse in use: 9714
|
||||
* reports in 7679 reads, one read an iteration, none taken by the
|
||||
* pump. The old path's two calls a report would have been 19428. */
|
||||
|
||||
extern void winraw_joypad_take_hid(HANDLE device, const BYTE *data, DWORD size);
|
||||
|
||||
@@ -1101,12 +1108,13 @@ static bool winraw_poll_window_up(winraw_input_t *wr)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* RETROARCH_RAWINPUT_POLL: 1, or 2 to register as a sink as well. */
|
||||
/* On, unless RETROARCH_RAWINPUT_POLL=0. 2 registers as a sink as
|
||||
* well. */
|
||||
static bool winraw_poll_wanted(bool *sink)
|
||||
{
|
||||
const char *env = getenv("RETROARCH_RAWINPUT_POLL");
|
||||
*sink = (env && env[0] == '2');
|
||||
return env && (env[0] == '1' || env[0] == '2');
|
||||
return !(env && env[0] == '0');
|
||||
}
|
||||
|
||||
static void *winraw_init(const char *joypad_driver)
|
||||
@@ -1756,7 +1764,7 @@ static void winraw_free(void *data)
|
||||
PostMessageA(wr->window, WM_CLOSE, 0, 0);
|
||||
}
|
||||
winraw_drain_tid = 0;
|
||||
RARCH_LOG("[WinRaw] Read by the poll: %lu reports in %lu bulk reads"
|
||||
RARCH_DBG("[WinRaw] Read by the poll: %lu reports in %lu bulk reads"
|
||||
" and %lu as messages; %lu reads found nothing waiting"
|
||||
" (%lu key events dropped).\n",
|
||||
wr->drained, wr->drain_reads, wr->by_message, wr->drain_empty,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* winraw: the keyboard and mouse read in bulk by the poll
|
||||
* (RETROARCH_RAWINPUT_POLL).
|
||||
/* winraw: the keyboard and mouse read in bulk by the poll (the
|
||||
* default; RETROARCH_RAWINPUT_POLL=0 turns it off).
|
||||
*
|
||||
* The real driver, cross-built with mingw-w64 and run under Wine on a
|
||||
* virtual display. The window that has the focus is made and pumped
|
||||
@@ -31,7 +31,9 @@
|
||||
* the lock keys' toggles from the published value;
|
||||
* - background input is refused, unless registered as a sink with the
|
||||
* main window focused;
|
||||
* - free takes the window down, and twenty restarts each do the same.
|
||||
* - free takes the window down, and twenty restarts each do the same;
|
||||
* - with everything on one thread, as without threaded video, the
|
||||
* same holds.
|
||||
*
|
||||
* What it cannot check is the thing only Windows can answer: whether
|
||||
* Windows, like Wine, gives raw input to a window whose thread does
|
||||
@@ -248,7 +250,7 @@ int main(void)
|
||||
printf(" note no display for a window: injected input is not checked\n");
|
||||
|
||||
/* ---- the switch off: as it was -------------------------------- */
|
||||
_putenv("RETROARCH_RAWINPUT_POLL=");
|
||||
_putenv("RETROARCH_RAWINPUT_POLL=0");
|
||||
wr = (winraw_input_t*)init_on_video_thread();
|
||||
CHECK(wr != NULL, "init with the switch off");
|
||||
if (!wr)
|
||||
@@ -265,15 +267,16 @@ int main(void)
|
||||
PostMessageA(raw_window, WM_CLOSE, 0, 0);
|
||||
wr->window = NULL;
|
||||
winraw_free(wr);
|
||||
printf(" ok switch off: the window is made by init on init's thread, nothing read in bulk\n");
|
||||
printf(" ok =0: the window is made by init on init's thread, nothing read in bulk\n");
|
||||
|
||||
/* ---- the switch on -------------------------------------------- */
|
||||
_putenv("RETROARCH_RAWINPUT_POLL=1");
|
||||
/* unset: on is the default */
|
||||
_putenv("RETROARCH_RAWINPUT_POLL=");
|
||||
wr = (winraw_input_t*)init_on_video_thread();
|
||||
CHECK(wr != NULL, "init with the switch on");
|
||||
CHECK(wr != NULL, "init with nothing set");
|
||||
if (!wr)
|
||||
return 1;
|
||||
CHECK(wr->poll_drain && !wr->sink, "not reading in bulk with the switch on");
|
||||
CHECK(wr->poll_drain && !wr->sink, "not reading in bulk by default");
|
||||
CHECK(!wr->window, "init made the window");
|
||||
winraw_poll(wr);
|
||||
raw_window = wr->window;
|
||||
@@ -283,7 +286,7 @@ int main(void)
|
||||
"the window belongs to thread %lu; the poll's is %lu, init's %lu",
|
||||
(unsigned long)GetWindowThreadProcessId(raw_window, NULL),
|
||||
(unsigned long)main_tid, (unsigned long)vt_tid);
|
||||
printf(" ok switch on: init makes no window; the first poll does, on the polling thread\n");
|
||||
printf(" ok by default: init makes no window; the first poll does, on the polling thread\n");
|
||||
|
||||
/* ---- injected keys, read in bulk by one poll ------------------ */
|
||||
if (vt_window)
|
||||
@@ -526,6 +529,53 @@ int main(void)
|
||||
SetEvent(vt_quit);
|
||||
WaitForSingleObject(vt, 5000);
|
||||
|
||||
/* ---- video not threaded: everything on the one thread ---------- */
|
||||
/* The focused window, the driver's start, the pump and the poll are
|
||||
* all this thread's, as they are without threaded video. */
|
||||
{
|
||||
WNDCLASSA wc;
|
||||
HWND top;
|
||||
|
||||
memset(&wc, 0, sizeof(wc));
|
||||
wc.lpfnWndProc = plain_proc;
|
||||
wc.hInstance = GetModuleHandleA(NULL);
|
||||
wc.lpszClassName = "winraw-poll-test-same";
|
||||
RegisterClassA(&wc);
|
||||
top = CreateWindowExA(0, wc.lpszClassName, "t",
|
||||
WS_OVERLAPPEDWINDOW | WS_VISIBLE, 10, 10, 200, 100,
|
||||
NULL, NULL, wc.hInstance, NULL);
|
||||
wr = (winraw_input_t*)winraw_init("null");
|
||||
CHECK(wr != NULL, "init on the polling thread");
|
||||
if (top && wr && raw_arrives)
|
||||
{
|
||||
SetForegroundWindow(top);
|
||||
SetFocus(top);
|
||||
pump_leaving_raw_input();
|
||||
winraw_poll(wr);
|
||||
CHECK(wr->window && GetWindowThreadProcessId(wr->window, NULL) == main_tid,
|
||||
"the window is not this thread's");
|
||||
seen_n = 0;
|
||||
key(0x1E, true);
|
||||
key(0x1E, false);
|
||||
PostMessageA(top, WM_APP, 0, 0);
|
||||
Sleep(150);
|
||||
pump_leaving_raw_input();
|
||||
CHECK(wr->by_message == 0 && wr->drained == 0,
|
||||
"the pump took raw input on the one thread");
|
||||
winraw_poll(wr);
|
||||
CHECK(wr->drained == 2 && wr->by_message == 0 && seen_n == 2
|
||||
&& seen[0].down && seen[0].code == 0x1E && !seen[1].down,
|
||||
"on the one thread: %lu read in bulk, %lu as messages, %u events",
|
||||
wr->drained, wr->by_message, seen_n);
|
||||
seen_n = 0;
|
||||
printf(" ok video not threaded: window, pump and poll on one thread, reports read in bulk\n");
|
||||
}
|
||||
if (wr)
|
||||
winraw_free(wr);
|
||||
if (top)
|
||||
DestroyWindow(top);
|
||||
}
|
||||
|
||||
if (failures)
|
||||
{
|
||||
printf("FAIL winraw_poll_test: %u\n", failures);
|
||||
|
||||
Reference in new issue
Block a user