Autodesk / Autodesk/maya-usd

Anonymous and session layers randomly switched between USD proxies when loading scenes with mayaUsdLayerManager

Open
#2,770 1 comment 3 reactions 1 assignee Claimed by @santosd View on GitHub
bug
Dominant language
Wolfram Language
Stars
905
Forks
223
Avg merge
2d 9h
Merged PRs (30d)
17

Description

**Bug description**
After saving a Maya scene containing USD proxy nodes that have anonymous and/or session layer while setting the `mayaUsd_SerializedUsdEditsLocation` option var to `2` (i.e. saving edits in the Maya scene using the `mayaUsdLayerManager` node), re-opening the Maya scene in the same Maya session (i.e. not closing Maya) can result in the anonymous layers and/or session layers from multiple USD proxy nodes to be exchanged, resulting in completely broken scenes.

The results are not consistent, but the more USD proxy nodes there are in the scene and the more scene saves/reopenings are done, the more the bug occurs. This _seems_ to be due to some sort of layer caching by layer identifier used by the layer manager, because if Maya is closed, and the saved scene is re-opened one or multiple times without re-saving, the bug doesn't occur.

To make this clearer, imagine we have a USD proxy node "A" in which the root layer contains an apple mesh, and USD proxy node "B" in which the root layer contains a piano mesh. After saving the scene, and re-opening it in the same session of Maya, the root layer if USD proxy node "A" may potentially now have the piano mesh instead of the apple mesh. This doesn't occur every time, but fairly frequently.

**Steps to reproduce**
Steps to reproduce the behavior:
1. Open Maya.
2. Set the `mayaUsd_SerializedUsdEditsLocation` option var to `2` to save USD edits from anonymous and session layers within the Maya scene itself using the `mayaUsdLayerManager` node. Use `cmds.optionVar(intValue=("mayaUsd_SerializedUsdEditsLocation", 2)`.
3. Create many (e.g. 20) USD proxy nodes with root anonymous layers, each with something unique in the layer (e.g. a unique mesh).
4. On each USD proxy node, store a Maya attribute that will also store the unique data (e.g. a string attribute storing the name of the mesh present in the layer, such as "apple").
5. Save the Maya scene somewhere.
6. In the same Maya session (do not close Maya), re-open the scene that was previously saved.
7. Check if the content of all the USD proxy nodes match the Maya attribute stored on them (e.g. layer with apple mesh should match the "apple" attribute value). If everything matches, try re-opening the scene between 1 and 20 times.
8. Notice that the layers of some USD proxy nodes were switched with those from other USD proxy nodes.

I made a script to replicate this very easily:
```
import uuid

from maya import cmds
import mayaUsd.ufe

def create_usd_proxies(proxies_count=20):
    for number in range(proxies_count):
        # Create a USD proxy node and get its USD stage.
        usd_proxy_node = cmds.ls(cmds.createNode("mayaUsdProxyShape"), long=True)[0]
        usd_stage = mayaUsd.ufe.getStage(usd_proxy_node)
        root_layer = usd_stage.GetRootLayer()

        # Create a prim with a name that will be unique to this USD proxy node's stage.
        prim_name = "my_prim_" + str(uuid.uuid4()).replace("-", "")
        prim_path = "/%s" % prim_name
        usd_stage.DefinePrim(prim_path)
        root_layer.defaultPrim = prim_name

        # Store the prim name on the USD proxy node to compare it with the actual prim name later.
        cmds.addAttr(usd_proxy_node, ln="stored_prim_name", dt="string")
        cmds.setAttr("%s.stored_prim_name" % usd_proxy_node, prim_name, type="string")

def save_and_reopen_maya_scene_until_mismatch(maya_scene_file_path, failsafe_retries_limit=50):
    # Save the scene so that it can be re-opened to trigger the bug.
    cmds.file(rename=maya_scene_file_path)
    cmds.file(save=True, force=True, type="mayaAscii")

    # Re-open the Maya scene until a mismatch between a prim name stored on a USD proxy node and the actual prim name
    # on the stage's root layer is found. This would mean that one or more anonymous layers were switched at load time.
    failsafe_retries_count = 0
    found_mismatches = 0
    scene_reopenings_count = 0
    usd_proxy_nodes = []

    while not found_mismatches:
        if failsafe_retries_count >= failsafe_retries_limit:
            break

        # Keep re-opening the scene until at least one mismatch is found.
        cmds.file(maya_scene_file_path, open=True, force=True)
        scene_reopenings_count += 1
        usd_proxy_nodes = cmds.ls(type="mayaUsdProxyShape", long=True)

        for usd_proxy_node in usd_proxy_nodes:
            usd_stage = mayaUsd.ufe.getStage(usd_proxy_node)
            root_layer = usd_stage.GetRootLayer()
            stored_prim_name = cmds.getAttr("%s.stored_prim_name" % usd_proxy_node)
            actual_prim_name = root_layer.defaultPrim

            if stored_prim_name != actual_prim_name:
                print(
                    'USD proxy "%s" has a mismatch: "%s" VS "%s"' % (usd_proxy_node, stored_prim_name, actual_prim_name)
                )
                found_mismatches += 1

        failsafe_retries_count += 1

    if found_mismatches:
        print(
            "Found %i mismatch(es) out of %i USD proxies after %i scene re-openings"
            % (found_mismatches, len(usd_proxy_nodes), scene_reopenings_count)
        )
    else:
        print("No mismatch found. That's most likely incredible luck. Re-run the script again.")

cmds.file(new=True, force=True)
create_usd_proxies()
save_and_reopen_maya_scene_until_mismatch("/some/path/of/your/choosing/test_maya_usd_layer_manager_bug.ma")
```

**Expected behavior**
The layers of each USD proxy node should always remain the same.

**Specs (if applicable):**
- Maya versions: 2022.4 and 2023.1
- Maya USD versions: at least 0.19.0 and 0.20.0

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.