-
-
Notifications
You must be signed in to change notification settings - Fork 21.4k
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
Touch input causes FPS drop and stuttering on some iOS devices (Pro Motion?) #76425
Comments
I wonder if this would help: #76399 There's a 3.x variant of the PR you could test. That's just a hunch but maybe with the high refresh rate you're getting too many inputs processed and running potentially expensive logic for each event? |
@akien-mga Could be worth a shot, thanks - weird thing is that the issue persists even if I disable high refresh rate in the phone settings. So perhaps it's not directly related... |
I believe the attached project doesn't have any logic run on input events yet still causes a stutter. I looked at the Pro Motion support in the SDK. It allows for variable refresh rates to be set (see preferredFrameRateRange). But in practice, Have you run Instruments with the Animation Hitches tool? It captures Core Animation data and gives insight into the CADisplayLink timing. |
@tbveralrud I tried several runs, and it doesn't show any hitches. |
Tried this, did not help unfortunately. Also, I've tested on an iPhone 14 Plus (doesn't have ProMotion) and confirmed that the stutter doesn't happen there. So the problem must be related to ProMotion, or some other difference between 14 Pro Max and the 14 Plus (which there aren't many - only other big things are the dynamic island, and always-on display). |
Hi, We have a similar obscurity with 3.6beta1 on recent iOS devices only. The abnormal behavior doesn't happen on Android, Windows or when using 3.5.2. Only on recent iOS hardware. What we see is that our player character is being triggered to jump, but it jumps 1/3rd of the time. The touch logic is in a touch controller which arms a
What we see on the high-end iOS devices is that the It basically shows that either:
In the 1. case, the axiom of having at most 1 idle frame per physics frame is broken (we are at the default 60fps without bumping refresh rates). This means that In the 2. case, all bets are off. Unfortunately, we couldn't reproduce this with a stripped down version of an MRP so 2. is also a possibility. PS: Some more debugging reveals that 1. is the cause of the problem: The logs show:
In our case, So it boils down to why |
Can anyone reproduce this on 4.0.2? |
After doing a bit more digging, this may just be an issue on Apple's side. There are a number of reports about iPhone 14 Pro stuttering, some specifically regarding touch: And I just noticed that I can see the same kind of stuttering in some other games, for instance Tiny Wings. It sounds like Apple has been aware of this for some time, but it still hasn't been fixed properly. I just updated my phone to latest iOS (16.4.1) and it did not help. |
@djrain It sounds tempting to assume that the problem is on Apple’s side, but I see no rational explanation on why the problem is not present on previous Godot versions on the same hardware. BTW the touch logic works fine for us on both 3.5.2 and 3.6beta1. So for me this remains a major obscurity. Maybe a bisect on potential commits which may have broken it would be in order… |
@oeleo1 I'm not sure, but it sounds to me like you may have a different problem there. It could be related, but I would suggest opening a new issue to look into that, as it does sound concerning! |
@djrain Can you reproduce this issue on 3.5.2 or older? |
@Calinou yes, I've reproduced this in 3.5.1 and 4.0.2 RC2. |
@oeleo1 I agree that a new topic is appropriate for your issue. In the meantime, |
Yes, I need to spawn another ticket. @tbveralrud Yes, we already tried that |
Godot v4.1.1 |
Godot 4.2 same issue. Is there any chance this will get fixed? Very bad user experience on iOS. |
I am not positive the problem is identified or understood in order to propose a fix. Maybe we shall provide @lawnjelly with an iPad Pro (all iPad Pros from Gen 1 have ProMotion) so he can at least see the problem. Then again, not sure Godot can do something better than the logic in place with the frame rates (detection + adjustment) to remedy the situation. |
PS: I am very happy to report that the iPad Pro / iPhone stutter (presumably due to ProMotion rendering rate variations and input lags as reported here) are gone when we switched to FTI for 2D (Fixed Timestamp Interpolation) with the release of Godot 3.6beta4 - the 1st and long awaited 3.x release supporting FTI for 2D. Stutter completely gone, as FTI deals with it perfectly and the game runs smoothly as it run on other devices without ProMotion. So I encourage everyone here to retest their projects with FTI enabled. For us switching to FTI was a no brainer. Just enabling the global setting, renaming a couple of Excellent work @lawnjelly and Team! Thank you very much! For us this 3.6beta4 release is a huge milestone in both quality and functionality! |
@oeleo1 Are you sure the interpolation didn't solve a different issue in your game? The MRP here still reproduces the touch stutter for me in 3.6 beta 4 with physics interpolation enabled. The project doesn't use any physics, so I don't see how that setting would affect it. |
The name "physics interpolation" is misleading, but Juan insisted, as it is a simpler term for beginners. It is usually known as "fixed timestep interpolation". It has nothing to do with physics (except in this case the fixed timesteps coincide with physics steps in Godot). That said there is likely more than one issue being reported here. Some problems may be due to input threading (which has some fixes already in 3.6) and some problems may be due to lack of FTI. There may also be additional factors. |
@djrain I am quite confident the stutter we had was related to the varying 115-120 fps ProMotion devices with 60 tps physics.
Are you sure you still have stutter ? Or are you referring to the FPS drops due to input which do not necessarily result in stutter ? These two are different issues. With FTI, the FPS variations are still there, but the stutter is gone. That's what I am reporting. Now, on the iOS input resulting in FPS drops, two things are worth mentioning here:
All this to say that the MRP here is causing delays for sure, but I am not positive it is causing and exhibiting stutter. |
Just to clarify. In order to observe stutter, there has to be a moving object. The MRP doesn't have one. Just fading sprites appearing at the rate of the screen taps. The MRP and this bug report is about an FPS lag which is directly related to the input processing on iOS devices with ProMotion. The Fixed Timestamp Interpolation enabled in settings definitely solves most, if not ALL of the stutter one may have on a variable frame rate rendering device. So with FTI there is no stutter issue. There is an input processing issue which I have tried to break down above with some practical tips on reducing the phenomenon. What is still puzzling here is that on iOS devices without ProMotion, there are no input lags, while there ae lag on device with ProMotion - characterized with a (potentially variable, as per spec) rendering rate of 120 fps. But given that Godot's input code is standardized across devices and the observed phenomenon seems specific to Apple devices with ProMotion, Godot's due diligence homework is about figuring out why ProMotion results in screen touch input lags. This may be an Apple-specific problem, or a Godot threading priority problem showing up in this specific scenario. Hope this helps explaining where we stand on this topic. |
@oeleo1 okay, so in the MRP I added some sprites moving across the screen and removed all logic on input. And after enabling the interpolation, I'm still seeing plenty of visual stuttering on touch (in addition to the frame drops). I'm moving the sprites in _physics_process(). Is there another step I'm missing? I guess I don't understand what the new setting does exactly. |
Who knows :-) Can't say without looking at the new MRP. Moving the sprites is a vague notion here. Usually moving means tweening the position or using the
The new setting smoothes movements for you automatically by using the so called ProMotion typically uses adaptive rate rendering "up to 120 fps" while your Godot physics ticks are nominally fixed at 60 tps. So in theory, you shall have something like X-2.0 rendered rames per physics tick, where X varies typically from 1.5 to 1.9 with ProMotion. In short, when a frame is rendered on the screen, FTI makes sure the moving objects positions are computed properly so they appear exactly where they should be at the time the frame is rendered (which is a variable instant in time, happening before or after the physics tick). With FTI and a frame refresh rate of 110-120 fps with ProMotion, you shouldn't see a blink but a bunch of very smoothly moving objects. |
Thanks for the info! I'm just still confused about how I should be moving stuff, since you said that setting position directly won't work? For example in my game, I don't use physics nodes. My "Player" entity is basically just a Node2D with a Sprite2D child. To move the whole player, I directly set the position of the Node2D in _physics_process(). Evidently this does not do the trick... So what would I do differently to let the interpolation magic happen? |
Like I said, one of the simplest things you could do is to tween your player from pos_A to pos_B with a tween duration corresponding to your desired speed of movement. The granularity of the position and duration deltas is up to you. One usually uses velocity with |
Well, even using a KinematicBody2D and Here's a video from my iPhone 14 Pro Max. The first cycle is smooth without touch input, and on the second cycle I start tapping and get a significant FPS drop and visual stutters: RPReplay_Final1706564725.mov@oeleo1 Would you mind looking at the project and showing me what I'm doing wrong? That would be a huge help! |
Application -> Run -> Delta Smoothing can be disabled for mobile only if that is a problem for mobile. |
Messed up my multiple GitHub logins and identities, so repeating my post with the Godot version of myself ;-) Sorry about that. @djrain Finally got a minute to look into your project. With a few project settings adjustments, it's smooth like a Greek olive sliding on a French butter toast :-) No stutter for me.
Another piece of advice against stutter is to disable stdout and stderr :-). Although this doesn't apply to your project, any print output triggers useless complex formatting logic so if printing stuff is not absolutely necessary for debugging, stdout and stderr shall be off. Your project with these remarks applied doesn't exhibit any stutter for me. |
I wonder if there's a reliable way to detect VRR on all platforms, but last time I checked, it seemed difficult to impossible. That said, is ProMotion "true" VRR with a variable range between say, 48 and 120 Hz, or is it just a switch between 60 Hz and 120 Hz? The way delta smoothing works reminds me of DuckStation's Sync to Host Refresh Rate feature, which is also recommended to be disabled on VRR displays: |
The delta smoothing should turn off automatically with VRR (it's not intended to work in that scenario). If it doesn't that could be a bug, so worth reporting so I can investigate. If you can compile from source, you can enable this define in
|
I guess that's an Apple secret :-) In practice, it looks like a switch 60/120. We observe whatever values are reported every second by |
You can measure the exact time taken between rendering two frames by subtracting |
@oeleo1 So I opened your new project and exported it without any changes. Unfortunately, I'm still getting obvious stutters. Maybe I'm just tapping with more fingers or more rapidly than you are in order to see them? Here is how that looks. On the 3rd pass of the icons, you can see the stutters after I tapped with 3 fingers, about 3 seconds in: ProjectFixedNoChanges.movPotentially related issue is why the FPS is fixed at 60 while idle, and it jumps up to 120 temporarily after the touches?? I found that if I disable "hide home indicator", then the behavior is sort of opposite - it idles at 120, and drops a bit when tapped. Also, for some reason it seems I can only access the 120 FPS if the phone is screen recording, like I was here. If not recording, it only ever goes up to 80 fps... And all that only applies in Godot 3, I can't reproduce this odd FPS limit when not tapping in 4.2.1, there it always seems to run at a base of 120 as expected (though it still drops and stutters on taps). All this to say, the fix isn't working for me, and it seems something is wrong with the high refresh rate in Godot 3 compared to 4. |
@djrain To be honest, your latest stutter video looks much better to me than the previous ones, so I believe the new settings actually do work in your favor. That said, your report sounds like a big mess of uncorrelated events. I believe you because real life is a mess of such events. :-) Now, the only reasonable explanation is that currently Godot doesn't honor the VRR goodies dedicated to ProMotion for iPad/iPhone Pro models, nor does it support Adaptive-Sync displays on Macs. Lack of expertise, lack of time, lack of ressources, whatever - we just don't have it at this time. What Godot actually does and excells at is that it is reasoning about frame rates based on the effective occurrence of the frames as time goes. The delta smoothing option is a statistical rate observer of past timings aiming at correcting deviations for a fixed frame rendering scenario (so again, no good for VRR). The FTI option takes the approach of taking the fixed rate physics ticks as a basis, then compensate the variable rendering by interpolating positions (which is much better for VRR). Etc. But all these techniques suffer from the lack of real hardware hints on what the actual rendering rate is or how and when it changes. That's a problem indeed but I am sure that if you partner with @lawnjelly and the Godot iOS team you can put all the bits together in one place. So heads up on this! FYI, Apple has actually published some very useful technical bits related to ProMotion. Please check this developer article and especially this excellent video about optimizing for VRR, Adaptive-Sync and ProMotion. There are enough technical details on how to detect the presence of VRR, how to configure the That being said, I had a quick look at the current 3.x iphone code, and I didn't quite like the following bit in
Why is there a while loop about input events in the middle of a drawView call ? Unclear... And this bit precisely is probably causing some of the stutter we see. Also, the
All this to say that 1) we already benefit from the best settings at the time of this writing, 2) there is pending work to do in order to honor VRR for MacOS and iOS properly, 3) the above code probably neads a new look and a thorough review from the iOS folks. Last but not least, we shall gift Apple Pro hardware to all of our Godot developer friends. Not sure how I can buy @lawnjelly an iPhone or an iPad Pro but if there are practical ways to do it, I am all ears and I'll do it :-) |
While I haven't looked at Godot's source code yet here are some things which need to be considered based on my empirical knowledge (I've started learning Godot less than a month ago, so maybe I'm super wrong). My game needs requires input fine touch resolution (like in fine scrolling smth on very short lengths) for a good experience. The screen itself influences how many touch events can be generated. iOS Android As such, not enough touch events (for my case) because of a drop in FPS is something real to complain about and should be a bug as it would cause the user to compensate making things worse because the touch move events appear to first accumulate in a 10 events long buffer which is only sent to code in Godot after it fills - the worser the screen OR the worser the FPS then the more the user will overcompensate a touch move by moving the finger more. In extreme cases (lower than 20 FPS) this results in the user making a mistake because the 10 events buffer is eventually sent (with a big lag) to code (only touch move events Conclusion So, based on what I've read above and the coupling of touch move events to screen quality AND the Godot's coupling to the The OP may be causing AND accelerating the FPS drop by spiking the CPU on every frame (on every touch event) resulting in a vicious cycle which eventually results in hitting the max processing capacity of the CPU and thus stuttering. If that's so then he can easily fix his issue (ProMotion displays come with powerful Apple CPUs, don't they?). Maybe an empty project logging FPS, counting touch move events and profiling CPU usage on a jailbroken device would be needed to prove the OP's case if indeed Godot is taking too much CPU). The CPU profiler in the debugger is useless in his case: when working with iOS I have to detach the debugger in XCode because it is wasting so much CPU (depending on how much CPU processing my game makes) that it causes some SIGUSR1 signal which pauses the app (killing xcode resumes the game, couldn't figure out how to resume otherwise as the game would be killed). Feel free to diss me. |
*only touch move events are buffered (which sucks), other events are sent in immediately (which is good). |
*I'm not sure if there is a 10 events touch move buffer on iOS, but if one exists then sending all those events at once would cause the CPU spike depending on what's processed on every frame (I guess one event would be sent for every consecutive frame). This should be considered a bug in Godot (the buffer should be eliminated if the user isn't listening for gestures - then, a larger refactor should eliminate the coupling of touch events to rendered frames if such a coupling exists). |
Setting |
@Calinou Thank you, you saved me a lot of headache as I needed to measure the time passed between touch move events for some calculation. Also, I am now certain there is a touch move buffer on Android and no such buffer on iOS/Windows/Mac so it is an OS level Android issue. |
Agile input event flushing might help (it's only implemented on Android). It's disabled by default -- check the advanced Project Settings. |
@Calinou Thanks, its enabled already so that's not it. I've found lots of posts about this Android issue (feature), some call it "touch slop". I've found these docs, I'm still reading about it: https://developer.android.com/develop/ui/views/touch-and-input/gestures/viewgroup#vc ""Touch slop" refers to the distance in pixels a user's touch can wander before the gesture is interpreted as scrolling. Touch slop is typically used to prevent accidental scrolling when the user is performing another touch operation, such as touching on-screen elements." If this could be configured out of Godot it would make Godot more consistent accros platforms (and problably properly regulate the rate of touch events on Android). |
Godot version
3.6 beta 1
System information
iOS 16, GLES3
Issue description
Discussion started in #32139 but now seems like a separate issue.
I believe #69200 fixed that issue, but now I'm still seeing stutter and FPS drop from touch input on iPhone 14 Pro Max.
The issue is not reproducible on iPhone 12 or iPhone 6s, so I guess maybe this has to do with Pro Motion (high refresh rate).
Here are some screen recordings comparing a near-empty scene on iPhone 14 Pro Max and iPhone 6s. Godot icons indicate tapping input.
iPhone 6s - performance unaffected by touch input, as it should be:
6s.MP4
iPhone 14 Pro Max (high refresh rate DISABLED in Godot) - notice severe FPS drop:
14.disabled.mov
iPhone 14 Pro Max (high refresh rate enabled in Godot) - again, significant FPS drop:
14.enabled.mov
iPhone 14 is of course many times more powerful than the 6s, so this makes no sense at all. Especially the case where pro motion is not even enabled in Godot and the 14 is struggling.
Our game requires a lot of tapping, and these stutters are unfortunately making the difference between a nice smooth game, and a non-shippable one :( so we'd be super grateful for any help on this.
Steps to reproduce
Export and run MRP main scene on a recent iOS device (may require Pro Motion)
Minimal reproduction project
iOSTouchStutter.zip
The text was updated successfully, but these errors were encountered: