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

Single PointLight2D causes extreme lag on Android #81152

Open
udit opened this issue Aug 30, 2023 · 8 comments
Open

Single PointLight2D causes extreme lag on Android #81152

udit opened this issue Aug 30, 2023 · 8 comments

Comments

@udit
Copy link

udit commented Aug 30, 2023

Godot version

v4.1.1.stable.official [bd6af8e]

System information

Android 13 - Vulkan (Mobile), Device - Redmi Note 7 Pro, CPU - Qualcomm Snapdragon 675 Octa-core upto 2.0GHz, GPU - Adreno 612 GPU upto 845MHz, Display - 2340x1080 FHD+ 409 PPI

Issue description

I made a test scene with 3 nodes - Fullscreen ColorRect, Sprite2D, PointLight2D. Whenever the light is in the active area, FPS reduces to 42 from 60. Is this an expected behaviour with Light2D? Seems like either I am doing something totally wrong or the light nodes are not at all usable for mobile games.

Screenshot_20230830-123903

60 FPS with light off:
Screenshot_20230830-124715

Steps to reproduce

Attaching the test project below. Just one click run on an android device.

Minimal reproduction project

Light2DTest.zip

@Calinou
Copy link
Member

Calinou commented Aug 30, 2023

The Vulkan Mobile rendering backend is high-end oriented, while your device is over 4 years old and also a mid-range device. Try using the Compatibility rendering method instead.

It's also worth trying to render to a lower resolution using the viewport stretch mode and a low window base size (such as 1170×540 for your device).

@udit
Copy link
Author

udit commented Aug 31, 2023

Using compatibility rendering method didn't have any effect on frame rate (I assume it's the 'Compatibility' option in the top right corner.). Halving the resolution down to 1170x540 did increase the FPS, I was even able to add 2 more light nodes before the frame rate dropped.

I also asked someone to run the apk on their Samsung Galaxy S23 Ultra and it runs smoothly in native resolution at 120 FPS when there are less than 20 light nodes and still runs above 60 FPS with more than thousand light nodes.

While I agree my device is potato compared to S23U, I do not think it should cause such a huge drop in performance with just one light node, because it can run games like Asphalt 9 with reasonable resolution and FPS with 3D graphics, light, shadows and reflections.

@Calinou
Copy link
Member

Calinou commented Aug 31, 2023

Using compatibility rendering method didn't have any effect on frame rate (I assume it's the 'Compatibility' option in the top right corner.).

Unfortunately, no. You need to open the Project Settings and change Rendering Method.mobile to gl_compatibility, then export the project again.

@udit
Copy link
Author

udit commented Sep 1, 2023

Thank you, that improved the FPS to 58 even in native resolution. So lowering the resolution along with this option should do the trick (although I do feel this is not optimal, I do not have any idea about Godot internals so I won't argue what is possible or not).

Are there any drawbacks of exporting 2d project with gl_compatibility? I guess this is not something that can be changed after exporting project? Like encapsulating this option into something like "high graphics" and "low graphics" option to end users?

@Zireael07
Copy link
Contributor

The biggest thing I can think of is inability to use instance shader parameters (they can come useful in 2d not just 3d).

As for your question, IIRC there's an open proposal for something like that.

@Calinou
Copy link
Member

Calinou commented Sep 1, 2023

Are there any drawbacks of exporting 2d project with gl_compatibility? I guess this is not something that can be changed after exporting project? Like encapsulating this option into something like "high graphics" and "low graphics" option to end users?

For mobile, we recommend Compatibility as it's the only rendering method that works reliably on older/low-end devices. The Mobile rendering method is high-end-oriented.

It is possible to provide a run-time selection that is effective after a restart (by writing user://override.cfg with the appropriate setting using the ConfigFile class), but it's not trivial to support. You will effectively have two rendering codepaths to cater for in your project, instead of just 1. Instead, it's usually better to stick to the lowest common denominator and design visuals around that.

@clayjohn
Copy link
Member

clayjohn commented Apr 19, 2024

I did a bit of testing related to this on another PR and I have a diff that helps. On my device (Pixel 4) it brings the performance back up to 60 FPS. I modified the MRP a bit to make it stress the GPU more by adding 16 lights total. On my Laptop (with iGPU) performance of the modified MRP goes from 240 FPS to 370 FPS

diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl
index 235c772e2d..dbff09c301 100644
--- a/servers/rendering/renderer_rd/shaders/canvas.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas.glsl
@@ -665,6 +665,12 @@ void main() {
 
                vec2 tex_uv = (vec4(vertex, 0.0, 1.0) * mat4(light_array.data[light_base].texture_matrix[0], light_array.data[light_base].texture_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
                vec2 tex_uv_atlas = tex_uv * light_array.data[light_base].atlas_rect.zw + light_array.data[light_base].atlas_rect.xy;
+
+               if (any(lessThan(tex_uv, vec2(0.0, 0.0))) || any(greaterThanEqual(tex_uv, vec2(1.0, 1.0)))) {
+                       //if outside the light texture, light color is zero
+                       continue;
+               }
+
                vec4 light_color = textureLod(sampler2D(atlas_texture, texture_sampler), tex_uv_atlas, 0.0);
                vec4 light_base_color = light_array.data[light_base].color;
 
@@ -689,10 +695,6 @@ void main() {
                        light_color.rgb *= base_color.rgb;
                }
 #endif
-               if (any(lessThan(tex_uv, vec2(0.0, 0.0))) || any(greaterThanEqual(tex_uv, vec2(1.0, 1.0)))) {
-                       //if outside the light texture, light color is zero
-                       light_color.a = 0.0;
-               }
 
                if (bool(light_array.data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
                        vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array.data[light_base].shadow_matrix[0], light_array.data[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.

Before:
42fps

After:

60fps

@akien-mga
Copy link
Member

A potential fix has been merged for this in #90920, please test 4.3-dev6 when it's released in a few days if you can, and confirm whether this solves the lag issue.

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

5 participants