(IN-87175) GraphicsStateCollection Tracing causes crash

Calling GraphicsStateCollection.GetVariants on a GraphicsStateCollection that was used to trace is causing the engine to crash. I’m using Unity 6000.0.23 and URP. It crashes in the editor and windows builds.

I have submitted bug-report IN-87175 with several crash dumps for you to inspect.

Here is the code snippet that causes the crash, the way how I implemented it follows the advice given by Unity staff here:

// Start trace when level starts
m_GraphicsStateCollection = new GraphicsStateCollection();
m_GraphicsStateCollection.BeginTrace();

// Playing game...

// End trace when level ended and proceeds to next scene
m_GraphicsStateCollection.EndTrace();

var variants = new List<GraphicsStateCollection.ShaderVariant>();
m_GraphicsStateCollection.GetVariants(variants); // This line crashes

The reason why I call GetVariants is that I want to merge it with existing graphics state collections, so that I can feed it new data incrementally with each play.

The error message:

The relevant editor stack trace:

(KERNELBASE) RaiseException
(Unity) LaunchBugReporter
(Unity) EditorMonoConsole::LogToConsoleImplementation
(Unity) EditorMonoConsole::LogToConsoleImplementation
(Unity) DebugStringToFilePostprocessedStacktrace
(Unity) DebugStringToFile
(Unity) MemoryManager::Allocate
(Unity) malloc_internal
(Unity) core::StringStorageDefault<char>::grow
(Unity) GraphicsStateCollection::KeywordsFromShaderAndKeywordNames
(Unity) GraphicsStateCollection::GetVariants
(Unity) GraphicsStateCollection_CUSTOM_GetVariants
(Mono JIT Code) (wrapper managed-to-native) UnityEngine.Experimental.Rendering.GraphicsStateCollection:GetVariants_Injected (intptr,UnityEngine.Experimental.Rendering.GraphicsStateCollection/ShaderVariant[])
(Mono JIT Code) UnityEngine.Experimental.Rendering.GraphicsStateCollection:GetVariants (UnityEngine.Experimental.Rendering.GraphicsStateCollection/ShaderVariant[])
(Mono JIT Code) UnityEngine.Experimental.Rendering.GraphicsStateCollection:GetVariants (System.Collections.Generic.List`1<UnityEngine.Experimental.Rendering.GraphicsStateCollection/ShaderVariant>)

The relevant build stacktrace:

(UnityPlayer) GraphicsStateCollection::KeywordsFromShaderAndKeywordNames
(UnityPlayer) GraphicsStateCollection::GetVariants
(UnityPlayer) GraphicsStateCollection_CUSTOM_GetVariants

Is this a bug or is the way how I use it incorrect?

EDIT: I also just realized I can’t merge GraphicsStateCollection’s because there is no API to check if a GraphicsState is added to a Variant already. I guess I have to come up with something that doesn’t require a merge…

It seems I have it working now.

I now use the same GraphicsStateCollection during each level to load, warmup, trace and save. This way it’s already incremental and I don’t have to merge different GraphicsStateCollections.

Previously I used a separate GraphicsStateCollection to load/warmup and another one to trace/save.

2 Likes

Hi, do you assign your graphics state collection to a field and warm that up? Or do you load the file using GraphicsStateCollection.LoadFromFile?

I’m trying to figure out if LoadFromFile is necessary.

Thanks!

This is how I’m using it, but I’m not sure if it aligns with Unity’s best practices :slightly_smiling_face:

class ShaderWarmupBehaviour : MonoBehaviour
{
    JobHandle? m_JobHandle;
    
    void OnEnable()
    {
        StartCoroutine(Worker());
    }

    void OnDisable()
    {
        if (m_JobHandle.HasValue)
        {
            if (!m_JobHandle.Value.IsCompleted)
                m_JobHandle.Value.Complete();
            m_JobHandle = null;
        }
    }
            
    System.Collections.IEnumerator Worker()
    {
        var filePath = "<path to graphics state collection>";
        var graphicsStateCollection = new GraphicsStateCollection(filePath);

        m_JobHandle = graphicsStateCollection.WarmUp();
        while (!m_JobHandle.Value.IsCompleted)
        {
            // In my project, this keeps the loading screen visible
            // while the warmup process is still running.
            LoadUtility.waitFrame = true; 
            yield return null;
        }
    }
}

thanks! I think the way I am doing it (assigning the collection a field directly) works, unfortunately we have an issue where the tracing is not pickup up a substantial number of the variants/graphics states. Have you run into this same issue?

I don’t know, I haven’t looked at it in detail for a long time. How would I notice that variants are missing?

You would most likely have stuttering which you’d trace back (via the profiler) to the pipeline creation (can’t remember the Profiler Marker for this).

No worries, thanks a lot for taking the time to reply!