Skip to content

Instantly share code, notes, and snippets.

@xrq-phys
Created July 21, 2026 12:04
Show Gist options
  • Select an option

  • Save xrq-phys/0bdf6605fce60483dd1cbf2d4700253d to your computer and use it in GitHub Desktop.

Select an option

Save xrq-phys/0bdf6605fce60483dd1cbf2d4700253d to your computer and use it in GitHub Desktop.

Low-latency Touhou under Wine on KDE Plasma

AIGC content based on human-in-the-loop results on a real machine.

Hardware is Intel Arc.

This is a known-working setup for running older Direct3D 9 Touhou games with OpenInputLagPatch (OILP) or vpatch on Linux. It covers both native Wayland and X11 on KDE Plasma/KWin.

Short version

On both display systems:

  • Use either OILP or vpatch for the game's frame limiter and latency fixes. Do not load both at once.
  • Use the game's real fullscreen mode. A window that KWin stretches to fullscreen is not equivalent: in this test it resized the swapchain to the desktop resolution and produced distorted output.
  • Disable in-game VSync. OILP already requests immediate presentation and, with D3D9Ex enabled, limits the D3D9 frame queue to one frame.

For native Wayland:

  • Use GE-Proton with its native Wine Wayland driver.
  • Use a current stable DXVK. The version verified here is DXVK 3.0.2.
  • In KWin, allow tearing for the game.
  • Do not leave protocol tracing or forced WSI presentation environment variables enabled.

For an X11 session:

  • Add a KWin window rule that forces compositing off for the game.
  • Tearing is expected; that is the tradeoff that removed the large compositor latency in this setup.

Native Wayland setup

1. Configure Lutris

The verified runner was GE-Proton 11-1, launched by Lutris through UMU.

Use these Lutris settings:

Game executable: oilp_loader.exe (or the vpatch launcher, but not both)
Runner: Wine
Wine version: GE-Proton
Graphics: Wayland
Enable DXVK: On
Environment variables: empty

Use fullscreen in the Touhou game configuration. Do not use KWin's “Fullscreen” window action as a replacement for the game's fullscreen mode.

The resulting process should load winewayland.drv, not winex11.drv. Lutris implements its Wayland selection by setting PROTON_ENABLE_WAYLAND=1.

2. Install DXVK 3.0.2 for this game

Lutris 0.5.22 hides its DXVK-version selector for Proton runners because Proton normally manages DXVK itself. GE-Proton 11-1's bundled development DXVK was not usable on the tested Intel Arc A770 system, so DXVK 3.0.2 was installed as a per-game override.

Download DXVK from the official release:

https://github.com/doitsujin/dxvk/releases/tag/v3.0.2

For a 32-bit D3D9 Touhou game, copy only the 32-bit D3D9 DLL next to the game executable:

GAME_DIR=/path/to/th10
DXVK_ARCHIVE=/tmp/dxvk-3.0.2.tar.gz

curl --fail --location --output "$DXVK_ARCHIVE" \
  https://github.com/doitsujin/dxvk/releases/download/v3.0.2/dxvk-3.0.2.tar.gz

echo '9c538924110a7cdef871ca36dee218c0774124374ffdeb38af4b76be55bdf7c2  /tmp/dxvk-3.0.2.tar.gz' \
  | sha256sum --check

tar -xzf "$DXVK_ARCHIVE" -C /tmp
cp /tmp/dxvk-3.0.2/x32/d3d9.dll "$GAME_DIR/d3d9.dll"

The local d3d9.dll takes precedence over GE-Proton's bundled copy. Back up an existing local DLL before replacing it.

DXVK 3.0.2 fixed two different fullscreen failures seen with other builds:

DXVK build Observed result
GE-Proton 11-1 bundled v2.7.1-822-g8c9b4822dd40d350 Intel i915 GPU hang followed by VK_ERROR_DEVICE_LOST; black screen with working audio. This also reproduced under X11 and without OILP.
DXVK 2.6.2 Windowed native Wayland worked, but real fullscreen exited in vkCreateSwapchainKHR with exception 0xc0000005.
DXVK 3.0.2 Native-Wayland D3D9 fullscreen worked with OILP.

These failures were specific to the tested software and hardware combination; they do not prove that every system requires exactly the same DXVK version.

3. Configure KWin tearing

In System Settings → Window Management → Window Rules, create or edit a rule matching the Touhou executables. A regular-expression class match such as th\d+ can cover the numbered games.

Set:

Allow tearing: Force, Yes

KWin 6.7.3 enables tearing globally by default, but the per-window force rule makes the intended behavior explicit. Adaptive Sync/VRR may remain on Automatic; VRR being enabled is not, by itself, proof that asynchronous tearing was requested.

With the working configuration, the trace showed all of the following:

DXVK: v3.0.2
Windowed: false
Present mode: VK_PRESENT_MODE_IMMEDIATE_KHR
Buffer size: 640x480
wp_content_type_v1.set_content_type(3)
wp_tearing_control_v1.set_presentation_hint(1)

The last two lines mean that the surface was identified as game content and that Mesa sent KWin the Wayland asynchronous-presentation hint.

4. Keep the launch environment clean

The working launch did not need any of these overrides:

MESA_VK_WSI_PRESENT_MODE
DXVK_CONFIG
WAYLAND_DEBUG

In particular, remove WAYLAND_DEBUG=client before measuring latency. It logs every Wayland request and every frame's presentation feedback, producing a continuous stream of journal output that can perturb the measurement.

OILP already sets D3DPRESENT_INTERVAL_IMMEDIATE and calls IDirect3DDevice9Ex::SetMaximumFrameLatency(1) when D3D9Ex = 1, so duplicating those choices in DXVK_CONFIG is unnecessary for this setup.

X11 setup

Run OILP or vpatch and select fullscreen in the game itself. Under a KWin X11 session, create a window rule matching the game and set:

Block compositing: Force, Yes

With KWin compositing enabled, the tested game had no visible tearing but about 100 ms more latency than Windows. With compositing disabled, tearing became visible and latency was approximately the same as Windows.

“Block compositing” is an X11 solution. A Wayland compositor is also the display server and cannot simply be disabled for one window; native Wayland instead uses the tearing-control protocol described above.

OILP notes

A representative low-latency OILP configuration includes:

[Option]
GameFPS = 60
BltPrepareTime = 2
Sleep = 1
D3D9Ex = 1
FullscreenRefreshRate = 1

BltPrepareTime is system-dependent and should be tuned while watching for missed deadlines. ShowOverlay = 1 is useful while tuning and is not required afterward.

Diagnosing a bad launch

  • Audio and input work, but the screen is black: check the DXVK log for VK_ERROR_DEVICE_LOST and the kernel log for GPU HANG. This is not merely a Wayland fullscreen or tearing-policy problem.
  • The game exits as fullscreen starts: check Lutris output for vkCreateSwapchainKHR Exception 0xc0000005 in Unix call and test a current stable DXVK.
  • KWin-forced fullscreen looks stretched or distorted: return to the game's real fullscreen mode. In the observed case, KWin changed the Vulkan swapchain from 640×480 to the 3840×2160 desktop size.
  • DXVK says IMMEDIATE but latency is still high: confirm that KWin allows tearing for the window, remove all debug logging, and verify the Wayland set_presentation_hint(1) request with a short diagnostic launch only.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment