-
-
Notifications
You must be signed in to change notification settings - Fork 21.7k
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
New expand options of TextureRect
can cause infinite resizing in certain containers due to unstable implementation
#73071
Comments
GDB Backtrace
|
To add: this only happens if the TextureRect's expand mode is "Fit Width Proportional" |
I spent some time researching this bug, and it appears to be caused in part due to container sorting logic (specifically the AspectRatioContainer, but I haven't investigated other containers yet). Essentially, after changing the mode to Cover, the children are sorted / resized. This causes the container's minimum size to change, which causes the sorting to happen again, except this time the children are sized larger than before, which affects the container's minimum size (infinite loop), and this continues until the MessageQueue buffer is full, explaining the stack trace above. This leads me to believe the issue is with a signal/notification, because the message queue doesn't appear to be fully processing messages (and freeing up queue space). There may be a separate bug with the message queue causing an access violation, which may only manifest when the queue is full. I am investigating that too. |
The MessageQueue crash is likely #63298 But the infinite loop in container logic should be fixed independently of that one. |
Printing the godot.windows.editor.dev.x86_64_u7ZHEDWLNr.mp4EDIT: |
If the issue is caused by the TextureRect, then from the discussion on RC it seems that TextureRect is wrongly using its current size to compute its min size. This shouldn't be done. |
Then what should it use? The whole point of expand modes was to have the TextureRect fit the texture properly based on size. |
@KoBeWi It should use the current size to compute the size of the texture. But it should not use it to compute the min size of the control, otherwise it can lead to infinite growth and recalculation, as is observed. The texture size should be used for the min size.
|
Okay, so after looking into the feature, I think that the original problem should've been solved differently. This implementation tries to trick the container into keeping a ratio by manipulating the min size, but that leads to other issues, as min size has to be deterministic and it isn't. This feature doesn't work with all containers because of that, and it also glitches when the control is used standalone, with anchors. The solution to the problem should've been to introduce a new sizing flags for containers (or probably a modifier like Expand), so that we tell the container the desired behavior instead of trying to trick it with what is in essence a hack. That new flag would tell the container to take the min size of the child and use it as a ratio when filling the space, so if the container needs to make the height bigger, it also has to make the width bigger. Then on the TextureRect's side you need to give it a min size with a correct ratio matching your texture, which is a bit of a setup, but will work reliably. That's the proper solution, IMO. As for the current one, I'm not sure how to salvage it, because it relies on an unstable logic. The safest option would probably be to remove the newly added expand options and only keep the first two, keep size and ignore size. The rest should be converted to one of those. This is effectively the 3.x behavior, as it was before the original PR. Then we can work on a better solution, in 4.1 I guess. At the very least, that would disable the currently misbehaving options, and if we can ultimately salvage them, we can then add them back later. |
Anyway, something needs to be done fast because a crash/infinite loop isn't a good thing to have in 4.0 stable :/ |
If we are going for a temporary fix for the crash, I have a better solution: #73396 No reason to remove a functionality if it works fine in every case except one. |
It's not just one case, and the fact that it works at all is incidental. The implementation is simply incorrect, and we will not be able to remove it after 4.0.
I don't think adding hacks to fix existing hacks is a good solution. This also means anyone making a custom container would need to replicate your hack if they run into a similar issue. This is just backwards. If this is a temporary solution, what is your proposal for a permanent solution? |
I don't have a permanent solution for now. We could even go with your sizing flag solution (but it can't require setting minimum size), in worst case we will end up with a few legacy enum values for Expand flags are too important for TextureRect to remove them after they finally got implemented and made the class usable in containers. |
Why is that a limitations? Setting up min sizes is a normal practice for containers. You would need to supply the ratio somehow, without relying on the current size to avoid cascading issues. And you can't rely on node's specific properties for that.
A size flag would be easy to implement. I don't think committing to a problematic implementation just to preserve our current status quo is valid. I understand that you need this, but we should make it waterproof. I'm sorry that the PR hasn't been reviewed properly in the first place, so we could avoid it. |
Because it makes the TextureRect too rigid. If I use any expand mode other than "Keep Size", I don't care about texture size and just want the TextureRect to fit in whatever I put it into. Before Expand Modes I had to resort to all sorts of hacks to make it stretch properly in BoxContainers. Implementing a ratio that depends on custom minimum size is totally pointless, because that's exactly how TextureRect was before - you had to use custom minimum size. And the container may change size or the size can sometimes be arbitrary, which makes it very cumbersome to work with. As an example, you might want to have a HBoxContainer with text and icon. The icon is bigger than font, so you enable the "Expand" (as it was in 3.x) and set a minimum size, so the icon fits. But then you decide to change the font size, or whatever detail that affects the icon size. Suddenly it doesn't fit anymore and you have to manually set a new minimum size that will make the icon stretch properly. After doing it 10+ times, it becomes kind of annoying. It's even worse if the icon isn't square, because you need to calculate the minimum size that will make the icon keep aspect ratio. |
But what I propose doesn't require you to do any of that. You give it a small minimum size and leave the rest to the container. It will preserve the aspect ratio while scaling the texture up and down, just like it would with any other control. If you really want to remove this step of setting the min size manually, we could add a flag to TextureRect to have a min size be a small ratio based on the texture size (say, values between 0 and 1). That would still be deterministic and work with any container. So, Keep Size, Ignore Size, Use Size as Ratio for the expand mode and min size of TextureRect, and a Fit to Size Ratio flag for the container logic.
That's my problem with the implementation, you are still resorting to a hack, it's just hidden in the engine now. I'm surprised it works at all, because what happens right now is, and this is required for your hack to work, you can change the size below the min size returned by |
Hm, that could work 🤔 Still, removing the current flags is breaking compatibility. And if we were to do it anyway, I wonder if we could as well implement this feature now 🙃 |
I am interested in implementing the approach from @YuriSizov, including any compatibility shims / fixups. I'm a new contributor, but I think I can manage this implementation (including docs, compatibility/migration tooling, etc.). I think I will give it a try. :) |
@chutchinson Hey, thanks for offering! It depends on the timeline right now. If we only remove the current options right now, and work on the solution later, I'd be happy to help you with this. But if we want to have the implementation replaced in the next few days (or even today), it's probably better if one of the maintainers (well, me, I guess) works on it. I'll let you know the plan. |
The crash is fixed by #73396, so repurposing this issue for the underlying bug (feel free to edit the title if I didn't infer it correctly). |
@chutchinson If you want to work on a PR for the updated implementation, feel free. If you drop by the contributors chat, I can help you to figure out the necessary steps. |
TextureRect
can cause infinite resizing in certain containers due to unstable implementation
In the end it might be impossible to implement proportional sizing for controls without the min size hackery, similar to how it's done in The container sizing option that I proposed here only moves the hack from the child node, like Say we have a Which is not a problem in an anchored control, we can just grow in any direction. But if our Long story short, I'm putting a pin in this one. Feel free to come up with alternative ideas. So far I can imagine some path with introducing an extra concept, besides the min size, that containers can use for their sizing logic. That could allow us to divorce the container logic and general min size limitations a node might have. So a control node can have some "requested size" which the container will use for allocating some space (all the way up the chain), and min size would be only used to actually limit the minimal size. |
The crash doesn't seem to be fully fixed, it still crashes if there are other container nodes (e.g. These two functions are in conflict with each other.
The condition of the infinite loop is met. Similar to #75713 at this point. |
I came across this bug, so I’m sharing my experience – maybe it’ll be useful to you. The reproduction is quite simple: a VBoxContainer with a TextureRect set to Fit Width and expanding, and below it another TextureRect node set to Fit Height and not expanding. Then, simply enlarge the VBoxContainer until the first TextureRect becomes larger than its texture, at which point Godot freezes. Tested in 4.3 and 4.4_beta2. Here is the minimal project with repro: |
Godot version
4.0 RC1
System information
Intel Mac OS
Issue description
When using an aspect ratio container, with a texture rect as a child. Setting the aspect ratio container to anything other than 'fit' is crashing the editor
Steps to reproduce
Minimal reproduction project
aspectratiobug.zip
The text was updated successfully, but these errors were encountered: