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

High baseline energy impact on iOS when a Control node is present on screen (even if empty) #78278

Open
PabloNeirotti opened this issue Jun 15, 2023 · 31 comments

Comments

@PabloNeirotti
Copy link

PabloNeirotti commented Jun 15, 2023

Godot version

v4.1.beta1.official [828ec2c]

System information

iPhone 13 Pro Max - iOS 16.3.1

Issue description

Running the project on my iPhone, Xcode Debug shows a high energy consumption on Godot the moment there is one GUI control, such as a Panel, even if it's empty and no code is running. The GPU goes insane.

Without PanelContainer:

Screenshot 2023-06-15 at 4 42 38 PM

With PanelContainer:

Screenshot 2023-06-15 at 4 41 49 PM

It sounds excessive that just adding a panel apparently shoots up the GPU usage to 80% (mind it's relative) and energy consumption to High. Unless this is an expected overhead and isn't making actually running the game any slower.

Steps to reproduce

Setup a structure like this:

Screenshot 2023-06-15 at 4 30 59 PM

Remove "PanelContainer" for the consumption to go from High to Low.

Minimal reproduction project

N/A

@PabloNeirotti PabloNeirotti changed the title High baseline energy impact and GPU usage on mobile High baseline energy impact on mobile Jun 15, 2023
@Calinou
Copy link
Member

Calinou commented Jun 15, 2023

Did you enable Low Processor Mode in the Project Settings before exporting? If not, high CPU/GPU usage is expected as the engine must redraw 120 times per second on an iPhone 13 Pro/Pro Max and later. (120 Hz mode is enabled by default – you can disable it in the export preset options, but it makes UIs less snappy so it's not recommended.)

Also, consider using the Compatibility rendering method as it's better optimized for mobile devices compared to Forward Mobile.

Rendering a Panel node is fairly expensive compared to a simple image because it draws a polygon with a relatively high amount of points. macOS/iOS are notorious for having performance issues with this due to buffer orphaning, which may still be an issue when using Metal via Vulkan. #77278 should improve performance somewhat, but don't expect massive gains. 2D batching is also currently missing in the Vulkan-based renderers, which means that rendering lots of text will be slow unless using the Compatibility rendering method.

Even with the above points considered, we don't expect Godot to be as efficient as native GUI frameworks when it comes to rendering efficiency. It's just not feasible, given it was never designed with this purpose in mind.

It sounds excessive that just adding a panel apparently shoots up the GPU usage to 80% (mind it's relative) and energy consumption to High.

Note that utilization percentages can be misleading if the GPU isn't running at its highest clock due to power management. Does the profiler let you see the current power state of the GPU, such as its frequency in MHz?

@PabloNeirotti
Copy link
Author

PabloNeirotti commented Jun 15, 2023

Hi Calinou, thank you for your response.

To address your points:

The project is capped at 60 FPS. I'd only allow it to run at 120 FPS if there was a way to keep the cap for 3D rendering and not for 2D rendering/UI. I'll have a look.

I am using what the Godot IDE calls Mobile (I guess this Forward Mobile). Not sure if Compatibility is right for me as shadows are important in my project and seems to have quite a few limitations on this end, but I'll investigate. That said my concern is mostly whether "using GUI elements is bringing my performance down" rather than overall game performance.

But if PanelContainer is already bad for performance, I can try avoiding it by either using a different way of styling it or just write my own code for GUI instead where needed. I don't really need polygon drawing for my UI, as it'll be mostly made up of floating elements, and I already made panels with an "invisible shape" but clearly they still come with a cost associated even then.

It all started with me trying to find the bottlenecks in my game and I kept removing things until only UI was left and I couldn't understand why energy performance was being hit so badly. I'll focus on the UI first then.

I guess we can close this as this behavior is expected, right?

Either way, thank you for your response and for sharing that PR, I'll keep an eye on that.

@Calinou
Copy link
Member

Calinou commented Jun 15, 2023

But if PanelContainer is already bad for performance, I can try avoiding it by either using a different way of styling it or just write my own code for GUI instead where needed. I don't really need polygon drawing for my UI, as it'll be mostly made up of floating elements, and I already made panels with an "invisible shape" but clearly they still come with a cost associated even then.

You can use a StyleBoxTexture in the theme overrides so that it draws a nine-patch sprite instead of a polygon. This should be slightly faster on average.

@Zireael07
Copy link
Contributor

Small nit: Can you edit issue title to call out iOS/Apple? This keeps coming up in my feed and I keep thinking it's general mobile, or Android specific... and it's NOT.

@PabloNeirotti PabloNeirotti changed the title High baseline energy impact on mobile High baseline energy impact on iOS Jun 16, 2023
@PabloNeirotti
Copy link
Author

Small nit: Can you edit issue title to call out iOS/Apple? This keeps coming up in my feed and I keep thinking it's general mobile, or Android specific... and it's NOT.

Done

@clayjohn
Copy link
Member

@PabloNeirotti Can you compare using a single PanelContainer to having a single Sprite with a texture?

Without a full understanding of how Apple computes energy impact, it is hard to say whether this is expected. Drawing a single element, even if it contains a lot of polygons should be very fast and shouldn't stress the mobile GPU much. That being said, panels do contain a lot of very small/thin triangles which are bad for mobile GPUs in general. Comparing to a sprite would help us identify whether this is a) expected behaviour, b) an issue specific to panels, or c) a rendering issue

@Calinou
Copy link
Member

Calinou commented Jun 16, 2023

You could also try creating a custom StyleBoxFlat for the PanelContainer with the corner radii set to 0, which requires fewer polygons. You could also try leaving the rounded corners but disabling antialiasing on the StyleBoxFlat, which reduces polygon count. Lastly, try keeping rounded corners and antialiasing but reduce the corner detail to 1 or 2.

@PabloNeirotti
Copy link
Author

I just tested your suggestions, and here are the results:

StyleBoxFlat

Setup like this:

Screenshot 2023-06-17 at 11 04 59 AM

Measures like this:

Screenshot 2023-06-17 at 11 04 45 AM

I tried leaving antialiasing on as well, but got the same result.

Single Sprite with texture

Setup like this:

Screenshot 2023-06-17 at 11 07 42 AM

Measures like this:

Screenshot 2023-06-17 at 11 08 04 AM

Bonus: Using a button

Setup like this:

Screenshot 2023-06-17 at 11 09 33 AM

Measures like this:

Screenshot 2023-06-17 at 11 09 51 AM

I assumed buttons would be just as problematic (since they use polygons too, isn't that so?) but actually the energy impact is the same as having a Sprite, or nothing at all as well.

Hope this helps to shed some light into the issue. I guess I can stay away from PanelContainer for now 😄. Let me know if there is anything else I can do.

@Zireael07
Copy link
Contributor

Surprised that a Button is NOT problematic, too

@Calinou
Copy link
Member

Calinou commented Jun 17, 2023

Is your Button using the default StyleBoxFlat (i.e. not overridden)? Its corners look more rounded than usual in the editor.

PS: Remember that if your PanelContainer occupies more screen space, it's bound to use more GPU than a Button due to fillrate.

@PabloNeirotti
Copy link
Author

Oh no, that is a custom styled button. However I'd assume that it should be more resource intense since the panel is practically invisible when I styled it.

@clayjohn
Copy link
Member

Taking a look at PanelContainer (corner detail 1, antialising off) in RenderDoc and the primitive is definitely less than ideal. It uses 15 vertices and 72 indices. Only 4 vertices and 6 indices are actually used. The rest create degenerate triangles
Screenshot from 2023-06-17 15-42-12

I doubt that this fully explains the high power cost, but it may be part of it

@Calinou
Copy link
Member

Calinou commented Jun 19, 2023

Can you test the iOS export template from the #77278 build? Note that you also need to run the matching macOS editor build to be able to successfully use the custom export template.

You can find the builds here (you'll want ios-template and macos-editor): https://nightly.link/godotengine/godot/actions/runs/5032344665

Note that the macOS editor is a direct binary and not an .app bundle, so you need to make it executable with chmod +x before you can run it from a terminal.

Also, these builds are not fully optimized so CPU usage may go up. GPU usage shouldn't be meaningfully affected by this unless you run into a CPU-bottlenecked scenario (in which case GPU usage will go down because of the bottleneck).

@MarcusDobler
Copy link

I've the same issue! Even with only one empty ControllNode on the screen my GPU is going nuts! I get some warnings at compile time on Xcode:

2023-07-22 14:36:51.130380+0200 Connect[15898:312661] USER WARNING: Project setting "rendering/limits/global_shader_variables/buffer_size" exceeds maximum uniform buffer size of: 16384
2023-07-22 14:36:51.130504+0200 Connect[15898:312661] at: MaterialStorage (drivers/gles3/storage/material_storage.cpp:1114)
USER WARNING: Project setting "rendering/limits/global_shader_variables/buffer_size" exceeds maximum uniform buffer size of: 16384
at: MaterialStorage (drivers/gles3/storage/material_storage.cpp:1114)

Could this be the issue?

I've tried COMPATIBILITY and FORWARD it makes absolutely no difference in Energy consumption.

@Calinou
Copy link
Member

Calinou commented Jul 23, 2023

@MarcusDobler The warning is not related. That said, which device model and iOS version are you using?

PS: I'd recommend checking actual device temperature and battery life over a given period of time (compared to running the app with only a root Node), as the GPU usage indicator may be incorrect. For instance, you could let the app run idle for 1 hour (with the screen kept on somehow) and see how many percents of battery life you lost with a single Control node, then do the same with only a root Node.

@Calinou Calinou changed the title High baseline energy impact on iOS High baseline energy impact on iOS when a Control node is present on screen (even if empty) Jul 23, 2023
@MarcusDobler
Copy link

@Calinou i tested on iPone 14 Pro iOS 16.1 and and iPhone 6s iOS13. Both devices get pretty hot after 2 minutes! I'm doing an app only with control nodes.

@WhalesState
Copy link
Contributor

It seems like the Control nodes are not the issue here, can you please test with an empty Container node inside the scene ? it might be Container node is what causing the issue or the PanelContainer, also please test with just Panel not PanelContainer, thank you.

@MarcusDobler
Copy link

MarcusDobler commented Aug 5, 2023

I've made a complete empty project! Just one Main Node. It's a Control node. The Control node is doing nothing. On my iPhone 6s. Energy Impact is VERY HIGH. On my iPhone 14 Pro it's HIGH spiking to very high. At least on iOS Control Nodes seem to be very energy hungry.

Putting a Panel and or a Panel Container in the Main Scene is making it not better or worse. Energy impact stays on the level of the empty main control node.

Hope that helps.

@WhalesState
Copy link
Contributor

does it means that this setup will give a very high impact on your device but low impact on another one ? this is really confusing!

image

image

image

image

@MarcusDobler
Copy link

MarcusDobler commented Aug 5, 2023

Bildschirmfoto 2023-08-05 um 08 32 21 Bildschirmfoto 2023-08-05 um 06 47 51

My Main is green? Did I do something wrong! I do not have a Sprite in it.

@WhalesState
Copy link
Contributor

Bildschirmfoto 2023-08-05 um 08 32 21 My Main is green? Did I do something wrong! I do not have a Sprite in it.

it's clear now that this is a Control node related, not just a container issue but all Control nodes will result in a very high empact maybe when their size is large, the only difference in those 2 cases that gave low impact is that the size of the control node is small, the last test you can do to help tracking this is to set the control node size to Vector2(64, 64) to just insure that this issue is size related even if the Control node is empty. thank you

@MarcusDobler
Copy link

video2.mov

I did what you wanted me to do. I made a video for you so you can see the energy impact is increasing! Again the app is doing nothing. Its just the empty Scene with set to the size 64 by 64

@MarcusDobler
Copy link

Bildschirmfoto 2023-08-05 um 08 52 28

Maybe this helps GPU is very high

@WhalesState
Copy link
Contributor

I will be tracking the issue now reviewing the control node code and will inform you with the updates, I know it's an annoying issue so please be patient. thank you ^^

@MarcusDobler
Copy link

No problem, keep your time. Thank you for investigating.

@MarcusDobler
Copy link

Just for completeness, the tests are running on the iPhone6s. The last test is still in the low range on the iPhone 14 Pro, bordering on orange.
So maybe the iPhone 6s is too slow for Godot?

@WhalesState
Copy link
Contributor

I am tracking the node causing the issue, and I've observed that both Node2D and Control nodes consume a significant amount of GPU and CPU resources when the window size increases. However, there is no noticeable impact on performance when using a root node of type Node. This suggests that the issue is caused by the CanvasItem component. The lack of impact is evident when using a root node of type Node and testing with small-sized Button and Sprite nodes because Node does not derive from CanvasItem. The performance impact becomes apparent when using a larger-sized Panel node. The high GPU impact is mainly caused by the CanvasItem's shader, while the high CPU impact is primarily caused by the CanvasItem's functions that run every frame.

@MarcusDobler
Copy link

Thank you, I do not completely understand what you saying. Is it possible for me as a Godot User to do anything against the high energy impact? Did I set up my project wrong? I do not use any shaders. Size of the canvas adapts to the size of the used device.

@WhalesState
Copy link
Contributor

Upon further review of the images, it has become apparent that the high impact is solely due to the GPU. As a result, optimizing the CanvasItem C++ code is unlikely to provide significant fixes for this issue. The primary concern lies with the CanvasItem shader. Although you may not be explicitly using shaders, it is important to note that Godot utilizes shaders by default for CanvasItems. Therefore, addressing the performance issue may involve optimizing or modifying the CanvasItem shader code.

@MarcusDobler
Copy link

Ok

@MarcusDobler
Copy link

One more information, improving my apps energy consumption dramatically is setting:
Project Settings / Application / Low Processor Mode to [x] On

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: For team assessment
Development

No branches or pull requests

7 participants