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 RaycastOcclusionCull World3D scenario memory leak #82291

Merged
merged 1 commit into from
Sep 28, 2023

Conversation

bitsawer
Copy link
Member

@bitsawer bitsawer commented Sep 25, 2023

Related issue #71884, I don't think this PR fixes that one but in theory its possible due to the changes in thread and other resource lifetime management in this PR. I tried to check the tagged Liblast commit, but it's too old to work with 4.2 without a lot of modifications, including some GDScript changes.

The problem is that RaycastOcclusionCull tracks it's scenarios (what World3D basically does behind the scenes) in a pretty unusual matter. When creating and deleting them using add_scenario() and remove_scenario() it tries to do so lazily. The problem is that when a scenario is deleted, it just marks it as removed but doesn't actually delete it yet. This becomes problem because the only place it actually does the deletion is in RaycastOcclusionCull::buffer_update(), but this is only called if the scenario is active.

The result is that if a World3D / scenario (or a node like Viewport using them) is removed, in many cases the scenario culling data never actually gets freed because it no longer gets updated, so it can't check the removed flag. In the issue MRP RaycastOcclusionCull::scenarios HashMap keeps growing forever as the scenarios are never released as the Viewports are no longer in the scene tree and thus are not updated and cleaned up.

I fixed this by making the add_scenario() and remove_scenario() work in a more traditional way, which makes the lifetime management much easier. I also fixed another leak as scenario commit_thread Thread objects were not always freed properly.

However, as the existing solution was a pretty non-standard compared to other RID allocate / delete API's, there might be a reason why it is done in such a strange way. I tested this PR with a lot of projects including the occlusion culling demo and I could not find any issues, but it's always possible it's done that way because of some obscure corner-case. Or maybe it's just a workaround for some old issue that has already been fixed as I don't see how the existing RID check in add_scenario() can trigger in any normal use, it didn't happen even a single time during my testing.

Copy link
Contributor

@JFonS JFonS left a comment

Choose a reason for hiding this comment

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

There was probably a reason why I wrote things this way, but I can't remember it anymore.

Since the logic was flawed anyway, I would merge this and address the original reason when/if it becomes apparent again.

@YuriSizov YuriSizov merged commit 4c95ebd into godotengine:master Sep 28, 2023
15 checks passed
@YuriSizov
Copy link
Contributor

Thanks!

@bitsawer bitsawer deleted the fix_occlusion_culling_leak branch September 29, 2023 09:45
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.

Using SubViewport with own_world_3d = true causes memory leak.
3 participants