input: the frontend starts the input driver for a Windows window

Every Windows video driver and context started the input driver for
its window itself: nine of them called input_driver_init_windows()
from their own start-up and handed the result back. With threaded
video that start-up runs on the video thread, so the input driver was
made there - by a thread that never polls it.

They hand back none now. Once the video driver is up,
video_driver_init_input() - the frontend, on its own thread - starts
the input driver for the window: the one kept from before the
restart; for a Windows window, the one input_driver_init_windows()
chooses (raw input if that is the setting and it starts, DirectInput
otherwise); failing those, the one the setting names, as before. The
video side says only what kind of window it put up. UWP and Xbox go
the same way, every video driver there being of the Windows family.
The test input driver, when it is the setting and has a file to play,
is still left to the setting.

What moves with it:

- DirectInput's devices are made on the frontend's thread, the one
  that reads them, with the window as the cooperative-level window as
  before.
- Raw input taken by the window's thread (RETROARCH_RAWINPUT_POLL=0)
  has its window on the frontend's thread. Its messages are then
  pumped by the thread that polls, so what the poll reads is no longer
  a video frame old: under Wine the old path's own measurement went
  from 12 ms in the menu to 0.02 ms.
- Read by the poll, raw input makes its window at the first poll and
  is unchanged.

The d3d11 driver started the input driver after its swap chain so
that it was started for the window that stays; that is true of every
driver now.

X11 and KMS contexts still start their own (input_driver_init_x11(),
input_driver_init_kms()); that is the rest of this.

CI: no file under gfx/ may call input_driver_init_windows().

Built for Windows with the d3d9, d3d10, d3d11, d3d12, wgl and gdi
drivers; d3d8 and d3d9cg carry the same two-line change and were not
built. The seven scenarios of the run of retroarch.exe under Wine
pass - raw input, the old raw path, DirectInput, threaded video on
and off - and each now also wants the frontend never to fall back to
picking the driver by name. The frontend-overhead harness passes.
This commit is contained in:
LibretroAdmin authored and libretroadmin committed 2026-10-03 11:39:53 +02:00
1 parent 04388402db
commit a8bc29e62b
14 files changed
+122 -25

No files matched your search

+16
View File
@@ -82,6 +82,22 @@ jobs:
fi
echo "[pass] gfx/ does not name input_state_get_ptr"
- name: Windows video drivers do not start the input driver
shell: bash
run: |
set -eu
# Every Windows video driver and context used to call
# input_driver_init_windows() from its own start-up. The
# frontend starts the input driver for the window once the
# video driver is up (video_driver_init_input()), and they
# hand back none. No file under gfx/ may call it again.
if grep -rn "input_driver_init_windows" --include=*.c --include=*.h \
--include=*.m --include=*.cpp gfx/; then
echo "FAIL: a video driver starts the input driver for a Windows window itself" >&2
exit 1
fi
echo "[pass] gfx/ does not call input_driver_init_windows"
- name: input/ does not reach into video state
shell: bash
run: |
+4 -2
View File
@@ -2533,8 +2533,10 @@ static void *d3d10_gfx_init(const video_info_t* video,
goto error;
}
input_driver_init_windows(settings->arrays.input_joypad_driver,
input, input_data);
/* no input driver of this driver's own: the frontend starts one
* for the window (video_driver_init_input()) */
*input = NULL;
*input_data = NULL;
if (!d3d10_init_swapchain(d3d10,
VIDEO_SCALE_W(d3d10->vp.full_dims),
+4 -4
View File
@@ -3922,10 +3922,10 @@ static void *d3d11_gfx_init(const video_info_t* video,
}
#endif
/* after the swap chain, so that it is started for the window that
* stays (an input driver may tie itself to the window) */
input_driver_init_windows(settings->arrays.input_joypad_driver,
input, input_data);
/* no input driver of this driver's own: the frontend starts one
* for the window (video_driver_init_input()) */
*input = NULL;
*input_data = NULL;
matrix_4x4_identity(d3d11->identity);
+4 -2
View File
@@ -5260,8 +5260,10 @@ static void *d3d12_gfx_init(const video_info_t* video,
else
d3d12->flags &= ~D3D12_ST_FLAG_VSYNC;
input_driver_init_windows(settings->arrays.input_joypad_driver,
input, input_data);
/* no input driver of this driver's own: the frontend starts one
* for the window (video_driver_init_input()) */
*input = NULL;
*input_data = NULL;
d3d12_init_base(d3d12);
+4 -2
View File
@@ -2477,8 +2477,10 @@ static bool d3d8_init_internal(d3d8_video_t *d3d,
if (!d3d8_initialize(d3d, &d3d->video_info))
return false;
input_driver_init_windows(settings->arrays.input_joypad_driver,
input, input_data);
/* no input driver of this driver's own: the frontend starts one
* for the window (video_driver_init_input()) */
*input = NULL;
*input_data = NULL;
return true;
}
+4 -2
View File
@@ -3862,8 +3862,10 @@ static bool d3d9_cg_init_internal(d3d9_video_t *d3d,
if (!d3d9_cg_initialize(d3d, &d3d->video_info))
return false;
input_driver_init_windows(settings->arrays.input_joypad_driver,
input, input_data);
/* no input driver of this driver's own: the frontend starts one
* for the window (video_driver_init_input()) */
*input = NULL;
*input_data = NULL;
{
char version_str[128];
+4 -2
View File
@@ -7265,8 +7265,10 @@ static bool d3d9_hlsl_init_internal(d3d9_video_t *d3d,
if (!d3d9_hlsl_initialize(d3d, &d3d->video_info))
return false;
input_driver_init_windows(settings->arrays.input_joypad_driver,
input, input_data);
/* no input driver of this driver's own: the frontend starts one
* for the window (video_driver_init_input()) */
*input = NULL;
*input_data = NULL;
{
char version_str[128];
+4 -2
View File
@@ -2464,8 +2464,10 @@ static void *gdi_init(const video_info_t *video,
RARCH_LOG("[GDI] Using resolution %ux%u.\n",
VIDEO_SCALE_W(temp_dims), VIDEO_SCALE_H(temp_dims));
input_driver_init_windows(
config_get_ptr()->arrays.input_joypad_driver, input, input_data);
/* no input driver of this driver's own: the frontend starts one
* for the window (video_driver_init_input()) */
*input = NULL;
*input_data = NULL;
RARCH_LOG("[GDI] Init complete.\n");
+4 -1
View File
@@ -264,7 +264,10 @@ static void gfx_ctx_w_vk_input_driver(void *data,
const char *joypad_name,
input_driver_t **input, void **input_data)
{
input_driver_init_windows(joypad_name, input, input_data);
/* no input driver of this driver's own: the frontend starts one
* for the window (video_driver_init_input()) */
*input = NULL;
*input_data = NULL;
}
static enum gfx_ctx_api gfx_ctx_w_vk_get_api(void *data) { return GFX_CTX_VULKAN_API; }
+4 -1
View File
@@ -699,7 +699,10 @@ static void gfx_ctx_wgl_input_driver(void *data,
const char *joypad_name,
input_driver_t **input, void **input_data)
{
input_driver_init_windows(joypad_name, input, input_data);
/* no input driver of this driver's own: the frontend starts one
* for the window (video_driver_init_input()) */
*input = NULL;
*input_data = NULL;
}
static enum gfx_ctx_api gfx_ctx_wgl_get_api(void *data) { return win32_api; }
+11 -1
View File
@@ -6285,7 +6285,17 @@ bool video_driver_init_internal(bool *video_is_threaded, bool verbosity_enabled)
video_st->current_video->suppress_screensaver(video_st->data,
settings->bools.ui_suspend_screensaver_enable);
if (!video_driver_init_input(tmp, settings, verbosity_enabled))
/* The input driver is the frontend's to start, for the window this
* driver put up. On UWP and Xbox every video driver's is a window
* of the Windows family. */
if (!video_driver_init_input(tmp, settings, verbosity_enabled,
#if defined(__WINRT__) || defined(_XBOX)
INPUT_WINDOW_WINDOWS
#else
(video_st->display_type == RARCH_DISPLAY_WIN32)
? INPUT_WINDOW_WINDOWS : INPUT_WINDOW_OTHER
#endif
))
return false;
#ifdef HAVE_OVERLAY
+33 -3
View File
@@ -6796,7 +6796,8 @@ bool input_driver_grab_mouse_for_video(void)
bool video_driver_init_input(
input_driver_t *tmp,
settings_t *settings,
bool verbosity_enabled)
bool verbosity_enabled,
enum input_window_kind window)
{
void *new_data = NULL;
input_driver_t **input = &input_driver_st.current_driver;
@@ -6842,10 +6843,39 @@ bool video_driver_init_input(
return true;
#endif
else
/* Video driver didn't provide an input driver,
* so we use configured one. */
{
#if defined(_WIN32) || defined(_XBOX) || defined(__WINRT__)
/* A Windows window: the video drivers used to start the input
* driver for it themselves, each calling
* input_driver_init_windows() from its own start-up - on the
* video thread, with threaded video. It is started here now, by
* the frontend, on its own thread: raw input if that is the
* setting and it starts, DirectInput otherwise. The test driver,
* when it is the setting and has a file to play, is left to the
* setting below as it was. */
if (window == INPUT_WINDOW_WINDOWS
#if HAVE_TEST_DRIVERS
&& !( strcmp(settings->arrays.input_driver, "test") == 0
&& *settings->paths.test_input_file_general)
#endif
)
{
input_driver_t *drv = NULL;
void *drv_data = NULL;
input_driver_init_windows(settings->arrays.input_joypad_driver,
&drv, &drv_data);
if (drv && drv_data)
{
*input = drv;
input_driver_st.current_data = drv_data;
return true;
}
}
#endif
/* Nothing for the window, or no such window: the configured one. */
RARCH_LOG("[Video] Graphics driver did not initialize an input driver."
" Attempting to pick a suitable driver.\n");
}
if (tmp)
*input = tmp;
+16 -1
View File
@@ -920,10 +920,25 @@ input_driver_t **input_driver_video_slots(void ***data_slot);
void input_driver_free_with_video(const void *video_data);
bool input_driver_grab_mouse_for_video(void);
/* What kind of window the video driver that has just started put up,
* for the input driver that goes with it. */
enum input_window_kind
{
INPUT_WINDOW_OTHER = 0,
/* a Windows window (or UWP, or Xbox): input_driver_init_windows() */
INPUT_WINDOW_WINDOWS
};
/* Called once the video driver is up. If it brought an input driver of
* its own, that is the input driver. Otherwise one is started here:
* the one kept from before the restart; for a Windows window, the one
* input_driver_init_windows() chooses; failing those, the one the
* setting names. */
bool video_driver_init_input(
input_driver_t *tmp,
settings_t *settings,
bool verbosity_enabled);
bool verbosity_enabled,
enum input_window_kind window);
bool input_driver_grab_mouse(void);
+10 -2
View File
@@ -47,6 +47,9 @@
# started by the same code, restarted
# with the video driver, works.
#
# In all of them the input driver is started by the frontend for the
# window, once the video driver is up, and not by the video driver.
#
# And the window. In every scenario above it is left up across both
# restarts and taken back by the driver that comes next - with
# threaded video, where the video thread is held for it, and without.
@@ -176,7 +179,7 @@ failures=0
# passes through
scenario() {
local name=$1 threaded=$2 want_bulk=$3 want_joy=$4 nomsg=$5
local log="$work/$name.log" try rc video bulk joy msg ok b_down b_up j_seq stale win off
local log="$work/$name.log" try rc video bulk joy msg ok b_down b_up j_seq stale win off byname
write_cfg "$threaded" "${6:-raw}" "${7:-winraw_joypad}"
# key delivery on a virtual display with no window manager is not
# exact: a scenario gets a second go before it counts as failed
@@ -203,6 +206,10 @@ scenario() {
[ "$j_seq" = "down up down up " ] || ok=no
off=$(count "$log" "not the core's")
[ "$off" = 0 ] || ok=no
# the frontend starts the input driver for the window; it never
# has to fall back to picking one by the setting's name
byname=$(count "$log" 'did not initialize an input driver')
[ "$byname" = 0 ] || ok=no
[ "$nomsg" != nomsg ] || [ "$msg" = 0 ] || ok=no
# the old path measures the wait the new one removes; the new
# one has nothing to measure
@@ -228,7 +235,8 @@ scenario() {
"lines on how old the state was at the poll: $stale;" \
"window left up, taken, not taken: $win (want ${WANT_WINDOW:-2 2 0});" \
"the core saw B pressed $b_down and released $b_up (want 2 and 2), J: ${j_seq:-nothing}(want down up down up)," \
"key events on a thread that is not the core's: $off (want 0)" \
"key events on a thread that is not the core's: $off (want 0)," \
"input driver picked by the setting's name: $byname (want 0)" \
"$([ "$nomsg" = nomsg ] && echo ", driver instances with reports taken as messages: $msg (want 0)")"
sed 's/\x1b\[[0-9;]*m//g' "$log" | tr -d '\r' | grep -av "ALSA lib\|Playlist\]" | tail -25
failures=$((failures + 1))