Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Question Is this a bug? "Layout update is struggling to process current layout" Error Upon Resolution Change

Discussion in 'UI Toolkit' started by sharkbitgamesdev, Nov 23, 2021.

  1. sharkbitgamesdev

    sharkbitgamesdev

    Joined:
    Dec 2, 2019
    Posts:
    18
    So, I am getting this error when I change my game's resolution:
    Layout update is struggling to process current layout (consider simplifying to avoid recursive layout): VisualElement New Panel Settings (x:0.00, y:0.00, width:1200.00, height:674.49) world rect: (x:0.00, y:0.00, width:1200.00, height:674.49)​

    I know the exact bit of code that is causing this, which is this GeometryChanged callback:

    Code (CSharp):
    1. private void PosCallbackView(GeometryChangedEvent evt,
    2.         MapTile currentTile)
    3.     {
    4.         PositionTile(currentTile, 20, 11);
    5.     }
    6.  
    7.     public void PositionTile(MapTile currentTile, int centerX, int centerY)
    8.     {
    9.         int XOff = currentTile.room.X - centerX;
    10.         int YOff = currentTile.room.Y - centerY;
    11.         Debug.Log("pos");
    12.         //Tiles are squares, so...
    13.         float tileSize = currentTile.Container.layout.width;
    14.  
    15.         Vector2 offsetPosition = new Vector2(
    16.             XOff * tileSize,
    17.             -YOff * tileSize);
    18.  
    19.         float width = (currentTile.Container.parent.layout.width / 2) - (tileSize / 2);
    20.         float height = (currentTile.Container.parent.layout.height / 2) - (tileSize / 2);
    21.  
    22.         SetPosition(currentTile.Container, new Vector2(
    23.             offsetPosition.x -
    24.             -width,
    25.             offsetPosition.y -
    26.             -height));
    27.     }
    28.  
    29. public void SetPosition(VisualElement mapTile, Vector2 pos)
    30.     {
    31.         mapTile.style.left = pos.x;
    32.         mapTile.style.top = pos.y;
    33.     }
    The thing is, this error only pops up in certain resolutions? In some others, the method works exactly as intended. So, I am at a loss here. I don't really see why that would happen, so I think it might be a bug? But I am not sure, anyone's got some insight?
     
  2. JuliaP_Unity

    JuliaP_Unity

    Unity Technologies

    Joined:
    Mar 26, 2020
    Posts:
    666
    Is
    PosCallbackView
    being called again when you're setting positions inside it?
    Could unregister the callback before you call
    PositionTile
    and then register again once it's done to test if the error message still appears, but I'm guessing this is what happened.
     
  3. sharkbitgamesdev

    sharkbitgamesdev

    Joined:
    Dec 2, 2019
    Posts:
    18
    Ok, so you were right about the callback being called several times in the resolutions that cause the error. As a matter of fact, the callback seems to just be called without end; even after implementing your suggestion.

    But I made another strange discovery, this only happens the first time this method chain happens. For some context, these methods are handling the layout of a mini map. So when the map changes, the tiles are scrapped and called again to instantiate a new map. Latter instances of the mini map don't cause this error to pop up at all, the callback is called exactly as expected.

    I scoured my code top to bottom, and there doesn't look to be any outside influences on it that would cause something erratic like this to happen. I am quite stumped.
     
  4. JuliaP_Unity

    JuliaP_Unity

    Unity Technologies

    Joined:
    Mar 26, 2020
    Posts:
    666
    Yeah now that I think about it, you should probably wait til the next
    GeometryChangedEvent
    happens before you assign the callback again, otherwise it'll chain indeed.

    Could it be the element to which you assign the callback to? I can't see in the code you provided where this is done but I suspect it may be related to that. Are you assigning it to more than one VisualElement?
     
  5. sharkbitgamesdev

    sharkbitgamesdev

    Joined:
    Dec 2, 2019
    Posts:
    18
    If this were the case, wouldn't that always be a problem? For example, if I start the game at Full HD resolution, the callback happens 4 times in a row, I imagine due to the tiles accommodating to the layout as the map is generated. But if I start the game at QHD resolution, the callback is chained ad infinitum only the first time the map is generated. It's really weird. If I change resolutions on the fly, while the game is running, things are pretty normal.

    Code (CSharp):
    1. public Dictionary<string, MapTile> GenerateMiniMap(VisualElement MapGroup,
    2.         Dictionary<string, WorldRoom> dic)
    3.     {
    4.         Dictionary<string, MapTile> MapRecipient = GenerateMap(MapGroup, dic);
    5.         //Instantiate the tiles apropriately
    6.         foreach (KeyValuePair<string, MapTile> entry in MapRecipient)
    7.         {
    8.             entry.Value.Container.RegisterCallback
    9.                 <GeometryChangedEvent, MapTile>(PosCallbackMini, entry.Value);
    10.         }
    11.  
    12.         return MapRecipient;
    13.     }
    This is where I assign it. I assign the callback to the visual element of each tile, and that's it.
     
  6. JuliaP_Unity

    JuliaP_Unity

    Unity Technologies

    Joined:
    Mar 26, 2020
    Posts:
    666
    Yeah this is indeed intriguing. I suppose rounding issues could account for the layout changing over and over again, ever so slightly, but that wouldn't explain why it only happens the first time and then if you're changing resolutions on the fly it won't happen anymore.

    Have you tried delaying the first call in the first place to see if it makes a difference? I mean letting a frame (or a few frames) go through before you even generate the map in the first place?

    I'm sending this post to other coworkers to see if anyone has an idea. Thanks for bringing this to our attention!
     
  7. uMathieu

    uMathieu

    Unity Technologies

    Joined:
    Jun 6, 2017
    Posts:
    386
    2 options:
    * Change SetPosition so it writes to style.translate instead, it will be also be more performant
    * Round things to 0.1 pt with something like mapTile.style.left = ((int) (pos.x * 16))/16.0f;

    Changing styles during the layout pass can lead to layout trashing because of floating point inaccuracies and pixel alignment.