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

Fix android low processor usage mode flicker 3.x #55604

Conversation

Gromph
Copy link
Contributor

@Gromph Gromph commented Dec 3, 2021

This fixes #19304
The fix is to draw 2 more frames after VisualServer::has_changed returns false.
The next problem this also fixes is if the gl surface is lost (for example turning screen off/on, app switching, rotating device) then the screen sometimes would be black, or flicker between a rendered frame and a black frame. The fix for this is to draw 3 frames after any gl surface changed notifications from android

Master does not seem to have the original flicker problem, but the screen does stay black after app switching or screen off/on. So submitting a pull request for 3.x for now.

Fix by force drawing 2 more frames after last changed frame, also need to force 3 redraws after any gl surface changes
Fix by force drawing 2 more frames after last changed frame, also need to force 3 redraws after any gl surface changes
…thub.com:SilverCreekEntertainment/godot into fix-android-low-processor-usage-mode-flicker-3.x
Fix by force drawing 2 more frames after last changed frame, also need to force 3 redraws after any gl surface changes
…thub.com:SilverCreekEntertainment/godot into fix-android-low-processor-usage-mode-flicker-3.x
@Gromph Gromph requested review from a team as code owners December 3, 2021 19:42
Fix by force drawing 2 more frames after last changed frame, also need to force 3 redraws after any gl surface changes
…thub.com:SilverCreekEntertainment/godot into fix-android-low-processor-usage-mode-flicker-3.x
@Calinou
Copy link
Member

Calinou commented Feb 2, 2022

I tested this PR on a OnePlus 6 running Android 11 and it seems to work! Previously, I would get a lot of flickering and a black screen once returning to the app. Both issues are resolved by this PR 🙂

Testing project: test_low_processor_mode.zip

Android APK with this PR included: Test Low Processor Mode.zip
(extract the ZIP archive and find the APK inside)

Android APK exported from 3.4.2 without this PR: Test Low Processor Mode.zip
(extract the ZIP archive and find the APK inside)

Copy link
Contributor

@m4gr3d m4gr3d left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if I agree with the fix since it looks like we're applying a band-aid instead of fixing the root cause of the issue.

Do we know why drawing a few more frames removes the flicker, or why it's occurring in low-power mode in the first place.
Happy to defer to someone with more graphics expertise.

@Gromph
Copy link
Contributor Author

Gromph commented Feb 3, 2022

It is definitely a bandaid, I occasionally still saw flickers. So in our fork of godot I upped the number of frames force drawn from 3 to 6 in S_Android::set_display_size. Haven't seen any flickers since.

@Gromph Gromph closed this Feb 25, 2022
@Gromph Gromph deleted the fix-android-low-processor-usage-mode-flicker-3.x branch February 25, 2022 22:58
@Gromph Gromph restored the fix-android-low-processor-usage-mode-flicker-3.x branch February 25, 2022 22:58
@golddotasksquestions
Copy link

So in our fork of godot I upped the number of frames force drawn from 3 to 6 in S_Android::set_display_size. Haven't seen any flickers since.

Is this a possible solution for everyone? If so can this fix be added to core?
In my current card game project, my phone battery is drained by 18% if I just leave it and there is literally nothing changes during that time.
So I really need low processing mode for all the time you just stare at the screen and think your next move and it does not need to be refreshed at all. Without it Godot is a really bad choice for these type of mobile games and apps. Unfortunately right now low processing mode fickers so much it's not even usable for testing (on Android).

@Calinou
Copy link
Member

Calinou commented Mar 6, 2022

Is this a possible solution for everyone? If so can this fix be added to core?

It's pretty hacky (and will not save as much power as doing it properly), so I'd recommend you integrate this to a custom Android export template build right now.

@golddotasksquestions
Copy link

@Calinou Thanks for the suggestion, unfortunately custom builds is still above my current level of technical ability.

Not sure how hacky or stupid this is, but this is my current workaround:

I add a Timer node to my main scene, set wait_time to something like 5 seconds, and then these short lines of script:

func _input(event):
	Engine.target_fps = 0
	low_fps_timer.start()

func _on_low_fps_timer_timeout():
	Engine.target_fps = 1

This will reduce the frames drawn to 1 per second and set it back to the default 0 (0 in this case meaning unlimited), whenever there is any input of any kind at all.

With this I was able to reduce the battery drain from 18% to 5% over a period of 30 minutes.

@Relintai
Copy link
Contributor

I actually managed to figure it out.

TL;DR

The issue is that on the android backend the framebuffers are swapped automatically by android after every frame, whether the engine want it or not. That's why you see flicker, because you see a previous (black if not yet rendered) and the current frame swap constantly.

Not TL;DR

The way it's set up right now, is that the main view class always just calls GodotRenderer's onDrawFrame(), which in turn calls Main::iteration(), and then it automatically swaps framebuffers.

However godot's Main::iteration() is set up in a way where it handles inputs, updates the world, and then it decides whether it should draw or not, and if not, it just keeps the previous framebuffer in place, and then does some cleanups, so it always need to be called.

Note: Swapping buffers is implemented in OS, for example for windows it's [here]. Android does not have this implemented, as with the current setup it's unavailable anyway due to how the backend is set up.

The simplest fix would be to create a GLSurfaceView implementation, that lets the user control framebuffer swaps. However I don't know whether that's possible or not. If it's not possible that means Main would need to be changed by potentially quite a bit, along with the android backend.

@akien-mga
Copy link
Member

Superseded by #59606.

Thanks @Gromph and @Relintai for your work, that was key to develop the fix that got merged.

@Helioform
Copy link

It crashes everytime I try to make a Windows package. And I dont see any way to make an Android .apk or .aab file since it requires the SDK.

@Calinou
Copy link
Member

Calinou commented Apr 11, 2022

It crashes everytime I try to make a Windows package. And I dont see any way to make an Android .apk or .aab file since it requires the SDK.

What are you referring to? This pull request is Android-specific, and doesn't change code that is run on other platforms.

PS: Please don't ask support questions here, as this issue tracker is meant to be used for bug reports only. Use one of the other community channels instead.

@Helioform
Copy link

Helioform commented Apr 11, 2022 via email

@Calinou
Copy link
Member

Calinou commented Apr 12, 2022

Sorry I should have started another thread. But this was for the Android apk that I tried. I cannot package anything with it so I was wondering if this is a bug or just not implemented yet. Thanks.

Exporting from the Android editor isn't a supported use case yet. It will probably take a while until everything is stable enough to consider the Android editor production-ready.

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

Successfully merging this pull request may close these issues.

7 participants