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

Vulkan: Massive performance hit when rendering transparent objects #60364

Closed
novemberist opened this issue Apr 19, 2022 · 7 comments · Fixed by #70214
Closed

Vulkan: Massive performance hit when rendering transparent objects #60364

novemberist opened this issue Apr 19, 2022 · 7 comments · Fixed by #70214

Comments

@novemberist
Copy link

novemberist commented Apr 19, 2022

Godot version

Godot 4.0 dev, commit 690fefe

System information

Fedora Linux 36 Beta, Vulkan, Gnome 42 (Wayland), Radeon RX580 (Mesa 22)

Issue description

I know that a certain performance hit is to be expected when rendering objects that have transparent parts. The official Godot documentation specifically suggests that transparent objects in a scene should be kept to a minimum. However, in practice, for certain kinds of assets, there is just no way around using transparent textures to avoid an otherwise insane vertex count, which is also very bad for performance (e.g. grass, foliage, trees etc.)

I've been playing around with grass and tree assets inside Godot lately and noticed that the performance hit is insane. Even a simple tree with a couple of planes and transparent textures easily brings my framerate down from 200 to something like 40, when using Alpha Scissor or Depth Pre-Pass with Depth Draw set to "Opaque Only".

I understand that these are mostly limitations by the way graphics rendering works and that in production a lot of trickery is involved to keep the amount of overdraw low. However, there are a lot of games that use a lot of foliage and trees and still perform well. I can't imagine that this would be currently possible with Godot and think there might be something wrong with transparency rendering.

The attached example might be a little extreme, but should illustrate the issue. It uses GPUParticles3D to render 20.000 patches of grass on a plane. Enabling transparency (Depth Pre-Pass with Opaque Only Depth Draw) reduces the framerate from around above 300 to below 30.
Bildschirmfoto vom 2022-04-19 02-29-30
Bildschirmfoto vom 2022-04-19 02-29-12

Steps to reproduce

see minimal reproduction project

Minimal reproduction project

transparency_test.zip

@mrjustaguy
Copy link
Contributor

mrjustaguy commented Apr 19, 2022

First off, Shadows are off for these types of effects for grass in 99% of instances, and secondly I don't think grass uses such high res textures.. 1k is overkill for grass, and that's possibly also hurting your performance massively.
Replacing with Icon.png which is 64x64 instead of 1024x1024 increased the FPS by a Huge margin, around 4-5x the performance with Alpha Scissor. I was unable to modify the Grass texture and down res it to give a more accurate comparison..
After getting some grass like materials of my own and doing a more apples to apples test, I've only seen about 10% performance gain

Switching to Mobile renderer seems to increase performance by 2-3x compared to Forward Clustered renderer (with SDFGI, SSAO and the likes disabled)

@novemberist
Copy link
Author

If the texture resolution was the problem, there would be a noticeable performance hit with or without transparency, which isn't the case here. I don't think icon.png serves well for a comparison, since it hardly has any transparent areas. The issue here ist not the low FPS of the example scene, but the extreme FPS difference between Alpha on and off. Shadows don't make much of a difference as far as i can tell.

@Calinou
Copy link
Member

Calinou commented Apr 19, 2022

I can confirm this on master 1d21779.

Note that I've disabled SSAO, SDFGI and Glow to isolate the performance bottleneck. Disabling those effects doesn't improve performance much, since the bottleneck is elsewhere.

image


Decreasing DirectionalLight3D's Shadow Max Distance helps, but performance remains low. Here's an example with Shadow Max Distance set to 1 (so the shadow doesn't actually reach any of the particles):

image


Setting the Cast Shadow property to Off on the GPUParticles3D node (which is used to draw the grass) restores performance to a similar level as decreasing the DirectionalLight3D Shadow Max Distance property:

image


Disabling depth prepass in the project settings helps a bit in this case, as there's relatively little overdraw in this scene when the grass uses transparency:

image

When the grass is set to be opaque, disabling the depth prepass worsens performance because there's a lot of overdraw.


Disabling depth prepass and shadow casting on the mesh almost results in 50 FPS:

image


Also setting the grass material's Cull Mode to Back increases performance to 86 FPS:

image


Using Pixel Dither to hide grass in the distance improves performance a lot:

image

It would likely improve performance even more once #50297 is merged.


The shading cost is likely the main bottleneck here. If you set the distance fade to Object Dither and position yourself in a way that entirely hides the whole particle system, performance is high:

image

But then, as soon as you move closer and some pixels from the particle system mesh are displayed, performance lowers a lot:

image


Can you reproduce the performance dip on a similar scene in 3.x (in GLES3)?

PS: In the MRP, the .tscn file size is massive because you saved binary data inside (encoded as Base64), which slows down loading and saving. Consider saving this binary data to an external binary .res resource (or save the whole scene as .res).

@Calinou Calinou added this to the 4.0 milestone Apr 19, 2022
@Calinou Calinou changed the title Massive performance hit when rendering transparent objects Vulkan: Massive performance hit when rendering transparent objects Apr 19, 2022
@novemberist
Copy link
Author

novemberist commented Apr 19, 2022

@Calinou thank you for the extensive testing. I will try something similar with Godot 3 and report back, but i guess I will have to write a custom shader for the grass first, since the particle node in Godot 3 is much less powerfull. The binary Data in the scene is probably the generated point texture for the emission shape. I didn't realize it was that big, sorry. As a side note: Performance becomes much better when setting the particle scale back to 1. Probably because a smaller particle causes less overdraw?

@Calinou
Copy link
Member

Calinou commented Apr 19, 2022

As a side note: Performance becomes much better when setting the particle scale back to 1. Probably because a smaller particle causes less overdraw?

Yes, as performance is largely determined by pixel shading cost in this scene. Therefore, making the grass smaller/shorter, using fewer grass instances or fading distant grass will improve performance.

@lawnjelly
Copy link
Member

lawnjelly commented Apr 19, 2022

Running the scene in a postage stamp sized window might give you some useful info here, whether the frame rate shoots up (in which case it is likely fill rate limited) or not (bottleneck elsewhere).

Fill rate is normally the problem with lots of overlapping transparency, and this agrees with @Calinou 's findings.

See:
https://docs.godotengine.org/en/stable/tutorials/performance/gpu_optimization.html#pixel-fragment-shaders-and-fill-rate

@novemberist
Copy link
Author

Just for the record: I can no longer reproduce the massive performance hit from my example project on my new GPU (Intel Arc 750), Fedora 37, Mesa-git. The difference between transparency on and off is more like 20% now and I am well above 100 FPS with most post-processing options enabled. Now I don't know if something in Godot's renderer changed in the past month or if this is just a case of a more beefy GPU / driver improvements. Anyway, since I can no longer reproduce this with the original setup, I will close this issue in favor of newer reports that might come in once Godot 4 is out and gets more widespead adoption.

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

Successfully merging a pull request may close this issue.

6 participants