Summary: | xf86-input-libinput: Rough and lopsided mouse movement in games/apps that reposition mouse | ||
---|---|---|---|
Product: | Wayland | Reporter: | Danni H <dannihfoss> |
Component: | libinput | Assignee: | Wayland bug list <wayland-bugs> |
Status: | RESOLVED NOTOURBUG | QA Contact: | |
Severity: | normal | ||
Priority: | medium | CC: | peter.hutterer |
Version: | 1.3.0 | ||
Hardware: | All | ||
OS: | Linux (All) | ||
Whiteboard: | |||
i915 platform: | i915 features: | ||
Attachments: |
listprops.txt
evemu.txt |
Description
Danni H
2016-07-18 23:26:26 UTC
Created attachment 125137 [details]
evemu.txt
Not at all relevant, because evemu does not record any mouse reposition events, but is listed here for completeness as it's under "required information for triage". This is simply me attempting to move the mouse in a circle.
get libinput from git and build it with the gtk+-devel package installed at configure time. That gives you the tools/event-gui binary we use for testing. When you run this tool (as root) can you reproduce the weird mouse movement? If not then the issue is somewhere above libinput. Mouse movement inside tools/event-gui is fine, but it's also not repositioning the mouse cursor (plus it looks like it's reading raw mouse input rather than the window system's mouse position). Would this mean the issue itself is inside xf86-input-libinput? (In reply to Danni H from comment #3) > Mouse movement inside tools/event-gui is fine, but it's also not > repositioning the mouse cursor (plus it looks like it's reading raw mouse > input rather than the window system's mouse position). Would this mean the > issue itself is inside xf86-input-libinput? yeah, that tool takes the output from libinput directly. so if the tool behaves fine but X doesn't then the issue is somewhere higher than libinput. what versions of everything do you have? xserver, libinput, xf86-input-libinput, ... Installed packages are from the Arch Linux repos: libinput 1.3.3-1 xf86-input-libinput 0.19.0-1 xorg-server 1.18.3-2 linux 4.6.3-1 Any other package versions you're looking for? The issue's been around since I initially started using xf86-input-libinput. ok, confirmed with JoyExhibition (the only one I could get for free, SLADE doesn't currently compile on F24). I'll look into that This is a bug in Unity3D, the libinput driver passes on the events correctly but because we do pointer acceleration inside libinput, slow motion is mostly subpixel motion. We also have a different accel methods, so subpixel motion is more common. In evdev, the driver itself does not usually handle subpixel motion, coordinates submitted to the server are always in whole integers (see below though). The odd thing about unity3d here is that it continuously sends WarpPointer requests (and to which the server replies with a core Motion event). unity3d does this that even while the mouse isn't moving. Note that core motion events do not contain subpixel information and the server buffers that internally until a full pixel motion has been reached. Also note that internally the server only deals with absolute coordinates once the immediate event has been dealt with (i.e. scaled into screen coordinates and/or accelerated). The server picks the correct device to warp, so normally you'd have a sequence like this: * pointer is at 100.0/100.0 * mouse moves by 0.2/0.0 pixels * mouse moves by 0.5/0.0 pixels * mouse moves by 0.4/0.0 pixels * server sends motion event for 101/100, position internally is 101.1/100 unity3d keeps sending WarpPointer requests and by definition they move the mouse onto the given position. Since WarpPointer is a core request it doesn't do subpixel. So now you get this sequence: * pointer is at 100.0/100.0 * mouse moves by 0.2/0.0 pixels * mouse moves by 0.5/0.0 pixels * WarpPointer resets to 100/100 * mouse moves by 0.4/0.0 pixels * WarpPointer resets to 100/100 * mouse moves by 0.8/0.0 pixels * WarpPointer resets to 100/100 * mouse moves by 0.8/0.0 pixels * mouse moves by 0.6/0.0 pixels * server sends motion event for 101/100, position internally is 101.4/100 * WarpPointer resets to 100/100 As you can see, some events are swallowed because the continuous WarpPointer requests simply undo any internal buffering the server does. This can be reproduced with the synaptics driver which also does acceleration and submits subpixel motion and the evdev driver when the Option Resolution is set to something higher than the mouse resolution (and thus most motion events are subpixel motion). So I'm going to have to punt this to Unity3D, it's broken with all drivers that send subpixel motion. I have several questions still:
You mention that subpixel movement is buffered inside the server. Would this make it an X.org Server bug, then? Does WarpPointer take integer or float arguments for the destination coordinates? Will this bug remain after the move to Wayland? That is probably what concerns me the most right now.
> The odd thing about unity3d here is that it continuously sends WarpPointer
> requests (and to which the server replies with a core Motion event). unity3d
> does this that even while the mouse isn't moving.
I believe this is also fairly standard practice among applications that use this method of mouse movement (and why I don't think this is strictly Unity3D's fault - see SLADE also has this issue). Additionally, if the application were to reposition the mouse pointer only if the mouse were moving, it would still result in the fractional becoming lost, so movement would still be somewhat lopsided.
If I propose a patch, will it be considered for inclusion? Or, is there some workaround that can be applied here to the hundreds of Unity3D games that will basically never receive an update to fix the issue?
Correct me if I'm wrong but it looks like WarpPointer takes ints for the destination coordinates: https://tronche.com/gui/x/xlib/input/XWarpPointer.html So presumably the fix would be inside the server's implementation of WarpPointer? (In reply to Danni H from comment #8) > You mention that subpixel movement is buffered inside the server. Would this > make it an X.org Server bug, then? Does WarpPointer take integer or float > arguments for the destination coordinates? Will this bug remain after the > move to Wayland? That is probably what concerns me the most right now. WarpPointer predates subpixel coordinates by about 20 years :) so no, it only takes integer coordinates. There is an XIWarpPointer request that takes subpixel coordinates but that requires switching to XI2 (which is only... 8 years old?) we cannot change the WarpPointer protocol request itself because that's ABI and has been for 20 years. Either way, since this is a protocol restriction it will not affect Wayland clients directly but likely still be an issue when XWayland is in play. > > The odd thing about unity3d here is that it continuously sends WarpPointer > > requests (and to which the server replies with a core Motion event). unity3d > > does this that even while the mouse isn't moving. > > I believe this is also fairly standard practice among applications that use > this method of mouse movement (and why I don't think this is strictly > Unity3D's fault - see SLADE also has this issue). Additionally, if the > application were to reposition the mouse pointer only if the mouse were > moving, it would still result in the fractional becoming lost, so movement > would still be somewhat lopsided. yeah, I agree, it'd still not be right but slightly less of an issue. The thing is: you still have this issue with evdev whenever pointer acceleration causes subpixel motion (I'd have to figure out when exactly this happens), it's just not as obvious. You can somewhat work around this by using the libinput "flat" acceleration profile. In that mode no pointer acceleration is performed by libinput and motion is sent as-is to the server (which also doesn't accelerate). So you only get full-pixel motion and many people claim it provides a more natural feel for games anyway (ymmv). > If I propose a patch, will it be considered for inclusion? Or, is there some > workaround that can be applied here to the hundreds of Unity3D games that > will basically never receive an update to fix the issue? tbh, I don't know *how* to fix this (short of the above workaround). I contemplated the idea of making the xserver aware about within-pixel warp requests so that it retains the subpixel data when we're warping from 100.4 to 100. That would be relatively easy but it would cause odd and inconsistent behaviour once we go beyond the first pixel so that's a no-go. And short of that hack I cannot come up with a satisfying solution. Hmm, what sort of odd and inconsistent behavior? Do you have an example? My understanding is that moving the mouse 5.5 pixels from 100 to 105.5 would result in mouse pointer integral at 105 with 0.5 leftover, with the mouse moving another 0.5 the next frame to bring it to 106. Is there a corner case I'm not aware of? If this isn't a satisfactory workaround, I think at least we should add 0.5 to the destination coordinates when warping the pointer - this would at least center the mouse pointer in sub-pixel space around the target pixel, such that it would take an equal amount of movement in any direction to move to the next pixel. It wouldn't be as smooth as evdev but it would at least be less lopsided and it wouldn't feel quite so much like pushing a bus up a hill. my thought about in-pixel warping would've caused a warp to 100 to behave differently dependent on the distance: * from 100.3 it would warp to 100.3 * from 100.9 it would warp to 100.9 * from 101.1 it would warp to 100.0 * from 110.9 it would warp to 100.0 because once you get outside of the single pixel range, you need to reset subpixel information. This wouldn't be a problem for large warps because relying on subpixel there doesn't matter anyway. but it would be problematic for exactly your use-case where we sometimes hit a pixel, sometimes not. it would require some magic threshold of "keep the subpixel if warping less than 10 pixels" or something like that but that sounds a bit too magic. a 0.5 base position is an interesting idea though it will need special casing for screen edges because a half-pixel would trigger a move to the next screen. I don't think there should be any ill effects for anything else. it would be something worth trying if you have the time. Hi, where would be a good place to discuss the implementation of a possible fix for this issue? I'm not really sure why you would need to reset subpixel information when traveling large distances. Wouldn't one simply be able to do something like this: xPos += floor(destinationX) - floor(sourceX); This would move the cursor while preserving the fractional because it would only ever adjust the mouse position by some number of whole pixels. (In reply to Danni H from comment #13) > Hi, where would be a good place to discuss the implementation of a possible > fix for this issue? best is the xorg-devel list, this is core X server stuff. > I'm not really sure why you would need to reset subpixel information when > traveling large distances. Wouldn't one simply be able to do something like > this: > > xPos += floor(destinationX) - floor(sourceX); > > This would move the cursor while preserving the fractional because it would > only ever adjust the mouse position by some number of whole pixels. well, that's the bit up for discussion. Because we're only dealing with subpixel here I think we should be fine with the 0.5 offset but my gut tells me warping a request of 0/0 to 0.9/0.9 because that's the leftover is wrong. There are a few places where subpixels matter (iirc pointer barries for example) and you may different behaviour depending on whether there's a remainder or not. |
Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.