Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Godot 4 get_global_mouse_position() input lag with Forward+ renderer #75830

Open
VilleMantyla opened this issue Apr 8, 2023 · 23 comments
Open

Comments

@VilleMantyla
Copy link

Godot version

4.0.2

System information

Windows 10, GeForce GTX 1050 Ti

Issue description

The lag can easily be seen when moving a sprite with the mouse in _process()

extends Sprite2D
func _process(delta):
	position = get_global_mouse_position()

Steps to reproduce

2023-04-08.19-39-24.mp4

Minimal reproduction project

laggy_mouse.zip

@Calinou
Copy link
Member

Calinou commented Apr 8, 2023

I can't reproduce this on 4.0.2 (Linux, GeForce RTX 4090 with NVIDIA 530.41.03).

This occurs because you have low FPS. Therefore, input lag is expected, especially since V-Sync is enabled by default in Godot. Disabling V-Sync in the project settings will reduce input lag, but it'll introduce tearing instead.

Note that video recording software can cause FPS drops on low-end (and even not-so-low-end) systems. Also, can you reproduce this issue when running the exported project with the editor closed? Can you reproduce this after switching to the Mobile rendering method or Compatibility (try both)?

@VilleMantyla
Copy link
Author

Disabling V-Sync removes the lag completely. Running in Mobile rendering didn't change much, Compatibility improved the lag noticeably. Exporting the project with Forward+ changed nothing.

This issue occurred on my machine with this one particular project (i.e. a game I was making). Removed all the files and made the laggy_mouse.zip (posted above with the initial message). But as I tried to start fresh, only implementing the minimal scene and script, I could not reproduce the same behavior.

On a side note, I noticed that when my game window is not selected (the focus is on another window on Windows) there's no mouse lag, even with the initial setup. This is demonstrated in video below (at first the window is not selected, then I click on the window and the lag starts).

2023-04-08.21-05-58.mp4

@darthLeviN
Copy link
Contributor

darthLeviN commented Jun 25, 2023

I have the same problem here.
also, i have a 144Hz monitor but vsync locks in a 60fps.

i tried Input.use_accumulated_input = false but it didn't help with the input either.
keep in mind that with vsync disabled, 60fps work well. but with vsync enabled it will lead to big input delay.

@paskausks
Copy link

paskausks commented Jul 25, 2023

For my current project, this issue occurs as well, as well as the suggested changes to mitigate it:

Disabling V-Sync removes the lag completely. Running in Mobile rendering didn't change much, Compatibility improved the lag noticeably. Exporting the project with Forward+ changed nothing.

Windows 11, v4.1.stable.official [9704596]

@Calinou
Copy link
Member

Calinou commented Jul 25, 2023

@VilleMantyla @darthLeviN @paskausks Can you reproduce this if you set Display > Window > Mode to Exclusive Fullscreen?

@paskausks
Copy link

paskausks commented Jul 25, 2023

@VilleMantyla @darthLeviN @paskausks Can you reproduce this if you set Display > Window > Mode to Exclusive Fullscreen?

Seems like the input lag is somewhat reduced (EDIT: although after some back and forth A/B, seems like its the same) on exclusive fullscreen, but its still there.

@mattdavisgames
Copy link

mattdavisgames commented Sep 4, 2023

Hi, I just started using Godot with 4.1.1 and I'm experiencing this lag too.
Apologies for not having any neat captures or repro project yet. I can provide something more thorough if developers are interested, just wanted to roughly get my findings down first.

The same behaviour seems to be present in Forward+, Mobile and Compatibility rendering paths, and in Windowed, Fullscreen and Exclusive Fullscreen.
The following frame measurements were using Forward+, Fullscreen, using a 60fps recording on a 60Hz display.
I'm measuring latency between the Windows mouse cursor and the Godot object positioned at the cursor.

  • VSYNC_ENABLED (default): 4 frames of latency, no judder.
  • VSYNC_MAILBOX, uncapped framerate (about 200 fps): <1 frame (at 60Hz) latency. Minor judder. (The object is between cursor position of last frame and this frame.)
  • VSYNC_MAILBOX, framerate capped at 180: <1 frame (at 60Hz) latency. Minor judder.
  • VSYNC_MAILBOX, framerate capped at 60: 1 frame (at 60Hz) latency. Severe judder.

Here's the interesting part: using VSYNC_ENABLED and gradually increasing the CPU load until the framerate drops just under 60fps, the input latency drops to 1-2 frames, even though the framerate is lower.

I've never done any serious graphics programming, but this behaviour suggests that the problem is to do with Godot queuing too many frames in the swapchain when using vsync, leading to latency. When the CPU load increases, the GPU is forced to "use up" its queue of stored frames, reducing latency.

The issue may be less noticeable at framerates above 60, as 4 frames will take less time.

This vulkan page suggests that 2 "frames in flight" at once (https://vulkan-tutorial.com/Drawing_a_triangle/Drawing/Frames_in_flight) and searching the Godot source code for FRAME_LAG seems to suggest Godot implements this advice. But maybe something is bugged? I don't properly understand all of this, it's just a hunch that it has something to do with the swapchain.

(Using Windows 10, Intel i5-9300H CPU @ 2.40GHz, NVIDIA GTX 1650 Max-Q. Seems to be the same using integrated graphics or NVIDIA, though on my machine it seems to switch back to integrated automatically after a few seconds.)

EDIT: possibly the other source of lag is the forced use of triple buffering in vulkan_context.cpp:
uint32_t desiredNumOfSwapchainImages = 3;
I think that this, combined with FRAME_LAG = 2, could combine to create these 4 frames of lag. For a simple 2D game which pretty much any computer can run at the max refresh rate, it could make sense to be able to reduce these values to minimise input latency while keeping the consistent frame pacing and low power usage of vsync.

If I get a chance soon, I will learn to build the engine and test out this theory for myself.

@Calinou
Copy link
Member

Calinou commented Sep 9, 2023

I've never done any serious graphics programming, but this behaviour suggests that the problem is to do with Godot queuing too many frames in the swapchain when using vsync, leading to latency.

Please test #80566, which aims to fix that issue 🙂

Note that the OpenGL (Compatibilty) issues you've mentioned are probably not fixed by that PR. A different solution is needed there, assuming you can't reproduce the issue in Godot 3.5.2.

@TempoLabGames
Copy link

I created a project to help measure this type of problem without needing a high speed camera, and I've just ported it to Godot. It's currently Windows only (sorry) but you may find it useful: https://github.com/TempoLabGames/UnityRenderingLatencyDemo

On my Windows machine using the Forward+ renderer with Godot 4.1.1:

WindowMode.Fullscreen, VSyncMode.Enabled: 2 frames
WindowMode.Fullscreen, VSyncMode.Disabled: 1 frame (no tearing)
WindowMode.ExclusiveFullscreen, VSyncMode.Enabled: 5 frames
WindowMode.ExclusiveFullscreen, VSyncMode.Disabled: 0 frames (tearing)

I'm not currently able to test #80566 as these build links don't work for me, but I'd be happy to provide results if someone can point me to an updated build.

@huezo89
Copy link

huezo89 commented Oct 11, 2023

Same issue here where the game stutters if I move the mouse over the game's window (or fullscreen). Funny thing is I'm not calling any function related to the mouse, if I move the mouse outside of the game's windows, all is good, but as soon as I move the mouse into the game's window, the stutter begins.

@philousoph
Copy link

Using Godot 4.2 stable on my Macbook Pro M1 max I have the same lagging issues. It is a very simple scene where I don't even use the lmb in the script. But when clicking (like I would later to fire a laser) the one object is lagging in movement.
Here's a small snippet from the only script I have atm based on a tutorial and some little addings from.

extends Node2D

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
	# Get Mouse-Position
	var screen_width = DisplayServer.window_get_size()
	var mouse_position = get_global_mouse_position()
	#ar ship_width = find_child("Ship").name
	var ship = get_node("Ship").size
	var ship_width = roundi(ship.x/2)
	if mouse_position.x < ship_width:
		position.x = ship_width
	elif mouse_position.x > (screen_width.x - ship_width):
		position.x = screen_width.x - ship_width
	else:
		position.x = mouse_position.x
	#print(ship_width)
	pass

@philousoph
Copy link

Ok, hm, I disabled V-Sync and have no lag at all now. Why is this active by default? Is this only during debug runs or also in the final build?

@paskausks
Copy link

In my experience, turning off vsync turns my laptop into an airplane when running a build.

@philousoph
Copy link

In my experience, turning off vsync turns my laptop into an airplane when running a build.

Loud or fast? On my mac it's just fast.

@Alex2782
Copy link
Contributor

Alex2782 commented Dec 5, 2023

Engine.max_fps = 60

https://docs.godotengine.org/en/stable/classes/class_engine.html#class-engine-property-max-fps

@philousoph
Copy link

philousoph commented Dec 6, 2023

Hm, when set to 30 or 60 I have the same lag when using quick left MB . Only when set to 0 I have no lag at all. When set to 120 there is still some lag, but very minimal.
I don't hink that should be, or am I wrong?
As I'm a newb Godot User I can't say how it was prior to 4.2 stable.

Edit:
Based on this doc jitter and stutter I capped the fps tp 141 fps but still had disable v-sync. With it on it's a laggy nightmare when doing fast clicks. Going full-screen doesn't do any difference.

@philousoph
Copy link

Not the only one..? Reddit input lag
So it seems to be a bug Apple has introduced.....?

@belzecue
Copy link

FYI, same issue on Godot 3.6b4 under Linux (Debian). I have not yet checked on earlier 3.x releases. Significant lag when mouse-dragging a Sprite with vsync on. Running the vsync build gives a solid 60 fps, so it's nothing to do with low frame rate. With vsync off, as pointed out earlier in this issue, the lag is gone -- well, almost imperceptible but still slightly there.

In my project I've resorted to hiding the Sprite + swapping the cursor to the same Sprite texture when actively dragging, then undoing upon mouse release. That works well visually, but invisibly the Sprite is still lagging the cursor, meaning any physics collisions for that sprite will be out of whack during the frames of significant lag.

@Calinou
Copy link
Member

Calinou commented Jan 29, 2024

FYI, same issue on Godot 3.6b4 under Linux (Debian). I have not yet checked on earlier 3.x releases. Significant lag when mouse-dragging a Sprite with vsync on. Running the vsync build gives a solid 60 fps, so it's nothing to do with low frame rate. With vsync off, as pointed out earlier in this issue, the lag is gone -- well, almost imperceptible but still slightly there.

This is expected with V-Sync enabled, unless you have a monitor with VRR enabled and your FPS is lower than the monitor refresh rate (instructions).

This is why most drawing apps turn off V-Sync while drawing 🙂

Even with V-Sync off, dragging a sprite to follow mouse cursor movement will lag behind by at least 1 frame, so using a hardware cursor is the most responsive option.

@belzecue
Copy link

belzecue commented Jan 29, 2024

Understood, but this seems like a lot of frames of lag/smoothing.

Here, I'm using the hardware cursor swap method during dragging, and I've left the real sprite being dragged visible during dragging. (Note, recording is 30 fps.)

vsync ON:
https://github.com/godotengine/godot/assets/1931303/e81512e8-1aec-457e-a344-21e14621612a

vsync OFF:
https://github.com/godotengine/godot/assets/1931303/4ad4ea50-f503-448f-9717-2a85f611aa2d

@belzecue
Copy link

belzecue commented Jan 29, 2024

This is expected with V-Sync enabled, unless you have a monitor with VRR enabled and your FPS is lower than the monitor refresh rate (instructions).

Interesting link! So it's something to do with: "This avoids frame buffers from piling up to create input lag."

As you point out, reducing fps to just under monitor refresh rate reduces the mouse-drag lag. I did Engine.set_target_fps(55) with vsync on, and it was a big improvement -- although still not as good as turning vsync off. Weird science, this stuff.

EDIT: Unity perspective: https://gamedev.stackexchange.com/questions/148535/dragging-ui-element-lags-behind-the-cursor

@Calinou
Copy link
Member

Calinou commented Jan 29, 2024

As you point out, reducing fps to just under monitor refresh rate reduces the mouse-drag lag. I did Engine.set_target_fps(55) with vsync on, and it was a big improvement -- although still not as good as turning vsync off. Weird science, this stuff.

Remember that you need VRR (G-Sync/FreeSync) to be enabled on your display and graphics driver control panel for this to work. Also, for a 60 Hz display, you can use a framerate cap up to 58.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants