I have revisited this input issue and found a few things.
I created a few test scenes, which can be found here
https://github.com/HiddenMonk/UnityInputLagTest
All tests were done with no VSync, and QualitySettings.maxQueuedFrames = 0
Also, these tests are just in regards to windows. Anything else is not tested.
First - all my previous tests were wrong. You can see from my previous posts I was seeing inconsistencies based on the recorder I was using and what not, and what I have found was that Fraps seems to be showing the mouse cursor on the wrong frames.
I was able to confirm this by using my “Detected Input lag” test scene, which logs when input was sent, using windows mouse_event (or SendInput) command. Fraps showed that the mouse moved a few frames before the game even logged it moved. This is why it seemed like there were a couple of frames of input lag.
I contacted a youtuber named Battle(non)sense, who does analysis of games, such as for their networking or input lag, if he could use his high speed camera to do a few tests, and he very kindly agreed to help ^^.
What we found was that with a 1000hz mouse, a monitor at a refresh rate of 144hz and framerate of 144, there seemed to be about a 5 frame delay from when the mouse was pressed to when the screen reacted or logged the frame that the input was pressed. We tested on both “Fullscreen windowed” (which has more input lag and is used by default by unity) and “Exclusive fullscreen” which has less input lag, and they both gave similar results. We also tested at 144hz 500fps (we used dx9 since dx11 couldnt get past 320 or so framerate for some reason?) and it seems there were 10 to 20 frame delay (hard to tell), which make it seems like this isnt a frame issue, but a time issue.
Here are the results in terms of total milliseconds lag.
Please note that the important test was the “exclusive fullscreen” test, which unfortunately we only did one of since we didnt realize in the beginning we were testing with borderless fullscreen.
Click for results
Here are the high speed recordings
Click for video
When compared to Battle(non)sense previous input tests of other games, it seems unity is around the same in terms of ms lag, but this test scene was a very simple test scene, and those games are high end games. Would unity have more input lag if the scene was very demanding?
Here are the input lag results of other games or engines based on Battle(non)sense tests
Sample Size: 20
Monitor ASUS PG248Q
Overwatch - 144Hz, exclusive Fullscreen:
300fps - 30ms(min), 36.72ms(avg) , 43.33ms(max)
CS:GO - 144Hz, exclusive Fullscreen:
142fps - 30.83ms(min), 36.11ms(avg) , 45ms(max)
400fps - 25.83ms(min), 31.39ms(avg) , 38.33ms(max)
Unreal Engine 4 Test Scene - DX11, 144Hz, exclusive Fullscreen:
1000fps - 24.17ms(min), 28.89ms(avg) , 35ms(max)
Sources
Compared to unity
Unity3d Test Scene – DX11, 144Hz, exclusive Fullscreen:
144fps - 30ms(min), 37.22ms(avg) , 45ms(max)
However, remember this is a simple test scene, while the games are full fledge high end games.
Also, since we are comparing against complete games, it is unsure if there is extra code in those games that purposely causes the input to lag a bit.
The 5 frame delay worried me. So I used a program called OllyDbg to look at the assembly code and memory of the unity build, and what I found was that unity was using windows Raw Input normally. That is, they poll PeekMessageA to see if there are any messages, if so they grab the message and check if its of type WM_INPUT, if so they call GetRawInputData to get its data and then rinse and repeat for all the input messages that are there. I also saw that the memory that GetInput or mousePosition use were being written to every frame. This implies that there should be no frame delays and that unitys input system is correctly polling every frame for input and updating the values.
To further support this claim, I also have a “Auto Input lag” test scene that uses windows “mouse_event” or “SendInput” command which, I have confirmed with ollydbg, sends the command to the raw input thread as if it was an actual mouse sending the input, and when calling this in unity, unity properly detects it the next frame.
So unless if unity is purposely limiting how much input is being updated somewhere that I cant see, I dont think there is any frame delay caused by the input system.
Click for OllyDbg image
So why do we see a 5 frame delay in the high speed recording? Well, there are many variables that can cause input lag, such as the rendering system or the computer monitor itself. There is framebuffering or vsync that can cause input lag, but I disabled those already, so those shouldnt be the issue unless if QualitySettings.maxQueuedFrames = 0 doesnt actually disable frame buffering or if unity is doing something behind the scenes to still cause lag between the frame we see on the computer monitor and the frame the game is actually on. (keep in mind I already have the frame on screen being displayed as Time.frameCount + 1 since when viewing the frame on the screen we would already by running the next frame).
Monitors do have a display lag, which is how long it takes for the monitor to do any post processing on the image before it displays it (for things like scaling, interpolation, etc…). This delay can go high to something like 60ms (usually on tv screens, computer screens are faster). I dont know what Battle(non)sense monitors display lag is, as there is no easy way to test this, but I wouldnt think it would be more than 14ms.
One thing I dont understand about this whole display lag thing is that, how can a 144hz screen have a display lag of 60ms? If the screen updates every 7ms, but takes 60ms to actually process the image, how in the world is it updating at 144hz? Is it that the 60ms delay is just a initial delay, but then runs at 7ms normally afterwards, but will always be 60ms behind the true frame?
Overall, I am not sure if this 5 frame delay is actually caused by unitys rendering, or by Battle(non)sense monitor, or something else such as QualitySettings.maxQueuedFrames = 0 not actually disabling frame buffering (since I think I read that nvidia thinks 0 means use the default value of 3?). However, I am almost certain that it has nothing to do with the actual input system.
I have also pretty much confirmed that unity GetAxisRaw(“Mouse X”), and maybe even GetAxis, ignores mouse acceleration. This can be seen with my “Mouse Acceleration” test scene.
So, some reasons you may experience input lag…
1 - Unity by default runs in “Fullscreen Windowed” mode, which can cause input lag. In project player settings, make sure dx9 and dx11 run in “Exclusive” mode. This can also be handled with a command line (that isnt documented) -window-mode exclusive or -window-mode borderless (Unity 5.3+ only I think?)
2 - Vsync is on. Disable it for less input lag.
3 - Frames are being buffered. QualitySettings.maxQueuedFrames should be 0 or a low value. (not sure if 0 actually disables it).
4 - Unity updates input only at the start of the frame, where as for most accurate input you would want to grab the input right as you need it. This is currently just how unity works, so you would need a high framerate for better input detection.
5 - Your monitor has a high display lag.
6 - You are grabbing input in FixedUpdate instead of Update
Once again, a big thanks to Battle(non)sense for helping me out =)
He did all the recordings (there were lots more recordings done then what I showed), calculated and provided the results image, told me about display lags, thought of the borderless window causing extra lag, and more ^^