Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice
  3. Dismiss Notice

Bug Custom UI shader causing engine crash.

Discussion in 'Scripting' started by Syadeu, Apr 11, 2024.

  1. Syadeu

    Syadeu

    Joined:
    Feb 28, 2018
    Posts:
    3
    This is full custom ui shader.

    Shader "UI/BlueprintSpriteShader"
    {
    Properties
    {
    _Blueprint("Blueprint", Range(0, 1)) = 1
    _LineWidth("Line Width", Range(0, 10)) = .01
    _LineSpacing("Line Spacing", Float) = .5
    _LineColor("Line Color", Color) = (1,0.6459123,0)
    _Rotation ("Rotation", Range(0,360)) = 0
    _BlurWidth ("Edge Blur", Float) = 0.01
    _Alpha ("Alpha", Range(0,1)) = 1

    [PerRendererData] _MainTex ("Texture", 2D) = "white" {}
    _Color("Tint", Color) = (1,1,1,1)

    _Stencil ("Stencil ID", Float) = 0
    _StencilComp ("Stencil Comparison", Float) = 8 // Always
    _StencilOp ("Stencil Operation", Float) = 0 // Keep
    _StencilWriteMask ("Stencil Write Mask", Float) = 255
    _StencilReadMask ("Stencil Read Mask", Float) = 255
    }
    SubShader
    {
    Tags
    {
    "Queue" = "Transparent"
    "IgnoreProjector" = "True"
    "RenderType" = "Transparent"
    "PreviewType" = "Plane"
    "CanUseSpriteAtlas" = "True"
    }
    Stencil
    {
    Ref [_Stencil]
    Comp [_StencilComp]
    Pass [_StencilOp]
    WriteMask [_StencilWriteMask]
    ReadMask [_StencilReadMask]

    }

    Cull Off
    Lighting Off
    ZWrite Off
    ZTest [unity_GUIZTest]
    // ZTest Always
    Blend SrcAlpha OneMinusSrcAlpha

    Pass
    {
    CGPROGRAM
    #pragma vertex vert
    #pragma fragment frag
    #pragma multi_compile_instancing

    #include "UnityCG.cginc"

    struct appdata
    {
    float4 vertex : POSITION;
    fixed4 color : COLOR;
    float2 uv : TEXCOORD0;
    };

    struct v2f
    {
    float2 uv : TEXCOORD0;
    fixed4 color : COLOR;
    float4 vertex : SV_POSITION;
    float3 worldPos : TEXCOORD1;
    };

    sampler2D _MainTex;

    float _Blueprint;
    float _Rotation;
    float _LineWidth;
    float _LineSpacing;
    half4 _LineColor;
    float _Alpha;
    float _BlurWidth;

    v2f vert (appdata v)
    {
    v2f o;
    o.vertex = UnityObjectToClipPos(v.vertex);
    o.uv = v.uv;
    o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
    o.color = v.color;
    return o;
    }

    fixed4 frag (v2f i) : SV_Target
    {
    fixed4 col = tex2D(_MainTex, i.uv);
    col.xyz *= i.color.xyz;
    fixed4 mainCol = col;

    float angle = radians(_Rotation);
    float2x2 rotationMatrix = float2x2(cos(angle), -sin(angle), sin(angle), cos(angle));

    float2 rotatedUV = mul(i.worldPos.xy * (_LineWidth), rotationMatrix);

    float gridPattern = rotatedUV.x + rotatedUV.y;
    float lineWidth = _LineSpacing / 2.0;
    float grid = smoothstep(lineWidth, lineWidth + _BlurWidth, abs(frac(gridPattern / _LineSpacing + 0.5) - 0.5));

    col.a *= _Alpha;
    fixed4 gridColor = lerp(col, _LineColor, grid);

    col = lerp(0, mainCol, _Alpha);
    col = lerp(col, gridColor, _Blueprint);

    col.a *= i.color.a;
    return col;
    }
    ENDCG
    }
    }
    }


    And parent has Mask component for masking alpha.
    When I try to re-activate GameObject which has Image component uses that shader material in children, engine goes to crash.

    I suspect when the Image component become a visible and notify to Canvas draw it, somehow Material inside of Image component couldn't fetch Material's texture.
    This is very odd to me because that Material has no texture should be null or something like RectTransform sized texture.

    This is full material shader helper C# code.

    [RequireComponent(typeof(Image))]
    [ExecuteInEditMode]
    public sealed class BlueprintSpriteShader : MonoBehaviour
    {
    private static readonly int s_Alpha = UnityEngine.Shader.PropertyToID("_Alpha");
    private static readonly int s_Blueprint = UnityEngine.Shader.PropertyToID("_Blueprint");
    private static readonly int s_LineWidth = UnityEngine.Shader.PropertyToID("_LineWidth");
    private static readonly int s_LineSpacing = UnityEngine.Shader.PropertyToID("_LineSpacing");
    private static readonly int s_LineColor = UnityEngine.Shader.PropertyToID("_LineColor");
    private static readonly int s_Rotation = UnityEngine.Shader.PropertyToID("_Rotation");
    private static readonly int s_BlurWidth = UnityEngine.Shader.PropertyToID("_BlurWidth");

    private Image m_Image;
    private bool m_MaterialInstanced;

    [SerializeField, HideInInspector]
    private float
    m_Alpha = 1,
    m_Blueprint = 1,
    m_LineWidth = 0.01f,
    m_LineSpacing = 0.5f,
    m_Rotation = 0,
    m_BlurWidth = 0.01f;
    [SerializeField, HideInInspector] private Color m_LineColor = new Color(1, 0.6459123f, 0, 1);

    private Image Image
    {
    get
    {
    if (m_Image == null)
    {
    m_Image = GetComponent<Image>();
    }
    return m_Image;
    }
    }

    private void OnEnable()
    {
    if (Image.material == null)
    {
    UnityEngine.Shader shader = UnityEngine.Shader.Find("UI/BlueprintSpriteShader");
    var mat = new Material(shader);
    UpdateMaterialProperties(mat);
    Image.material = mat;
    #if UNITY_EDITOR
    EditorUtility.SetDirty(Image);
    #endif
    }

    EnsureInstancedMaterial();
    }

    private void OnDisable()
    {
    if (Image.material != null)
    {
    #if UNITY_EDITOR
    if (!Application.isPlaying)
    {
    // DestroyImmediate(Image.material);
    }
    else
    #endif
    {
    Destroy(Image.material);
    }
    }
    }
    private bool ValidateMaterial()
    {
    UnityEngine.Shader shader = UnityEngine.Shader.Find("UI/BlueprintSpriteShader");
    return Image.material != null && Image.material.shader == shader;
    }

    private void EnsureInstancedMaterial()
    {
    #if UNITY_EDITOR
    if (!Application.isPlaying) return;
    #endif
    if (m_MaterialInstanced) return;

    var mat = Instantiate(Image.material);
    UpdateMaterialProperties(mat);

    Image.material = mat;
    m_MaterialInstanced = true;
    }

    private void UpdateMaterialProperties(Material mat)
    {
    mat.SetFloat(s_Alpha, m_Alpha);
    mat.SetFloat(s_Blueprint, m_Blueprint);
    mat.SetFloat(s_LineWidth, m_LineWidth);
    mat.SetFloat(s_LineSpacing, m_LineSpacing);
    mat.SetColor(s_LineColor, m_LineColor);
    mat.SetFloat(s_Rotation, m_Rotation);
    mat.SetFloat(s_BlurWidth, m_BlurWidth);
    }

    private Material Material => Image.materialForRendering;

    #if ODIN_INSPECTOR
    [ShowIfGroup(path: "General", Condition = "@" + nameof(Material) + "!=null && " + nameof(ValidateMaterial) + "()")]
    [ShowInInspector, PropertyRange(0, 1)]
    #endif
    public float Alpha
    {
    get => m_Alpha;
    set
    {
    EnsureInstancedMaterial();
    m_Alpha = value;
    #if UNITY_EDITOR
    if (!Application.isPlaying)
    {
    EditorUtility.SetDirty(this);
    }
    #endif
    Material.SetFloat(s_Alpha, m_Alpha);
    }
    }
    #if ODIN_INSPECTOR
    [ShowIfGroup(path: "General", Condition = "@" + nameof(Material) + "!=null && " + nameof(ValidateMaterial) + "()")]
    [ShowInInspector, PropertyRange(0, 1)]
    #endif
    public float Blueprint
    {
    get => m_Blueprint;
    set
    {
    EnsureInstancedMaterial();
    m_Blueprint = value;
    #if UNITY_EDITOR
    if (!Application.isPlaying)
    {
    EditorUtility.SetDirty(this);
    }
    #endif
    Material.SetFloat(s_Blueprint, m_Blueprint);
    }
    }
    #if ODIN_INSPECTOR
    [ShowIfGroup(path: "General")]
    [ShowInInspector]
    #endif
    public float LineWidth
    {
    get => m_LineWidth;
    set
    {
    EnsureInstancedMaterial();
    m_LineWidth = value;
    #if UNITY_EDITOR
    if (!Application.isPlaying)
    {
    EditorUtility.SetDirty(this);
    }
    #endif
    Material.SetFloat(s_LineWidth, m_LineWidth);
    }
    }
    #if ODIN_INSPECTOR
    [ShowIfGroup(path: "General")]
    [ShowInInspector]
    #endif
    public float LineSpacing
    {
    get => m_LineSpacing;
    set
    {
    EnsureInstancedMaterial();
    m_LineSpacing = value;
    #if UNITY_EDITOR
    if (!Application.isPlaying)
    {
    EditorUtility.SetDirty(this);
    }
    #endif
    Material.SetFloat(s_LineSpacing, m_LineSpacing);
    }
    }
    #if ODIN_INSPECTOR
    [ShowIfGroup(path: "General")]
    [ShowInInspector]
    #endif
    public Color LineColor
    {
    get => m_LineColor;
    set
    {
    EnsureInstancedMaterial();
    m_LineColor = value;
    #if UNITY_EDITOR
    if (!Application.isPlaying)
    {
    EditorUtility.SetDirty(this);
    }
    #endif
    Material.SetColor(s_LineColor, m_LineColor);
    }
    }
    #if ODIN_INSPECTOR
    [ShowIfGroup(path: "General")]
    [ShowInInspector, PropertyRange(0, 360)]
    #endif
    public float Rotation
    {
    get => m_Rotation;
    set
    {
    EnsureInstancedMaterial();
    m_Rotation = value;
    #if UNITY_EDITOR
    if (!Application.isPlaying)
    {
    EditorUtility.SetDirty(this);
    }
    #endif
    Material.SetFloat(s_Rotation, m_Rotation);
    }
    }
    #if ODIN_INSPECTOR
    [ShowIfGroup(path: "General")]
    [ShowInInspector]
    #endif
    public float EdgeBlur
    {
    get => m_BlurWidth;
    set
    {
    EnsureInstancedMaterial();
    m_BlurWidth = value;
    #if UNITY_EDITOR
    if (!Application.isPlaying)
    {
    EditorUtility.SetDirty(this);
    }
    #endif
    Material.SetFloat(s_BlurWidth, m_BlurWidth);
    }
    }


    I don't know which code can cause engine crash. Any idea?


    =================================================================
    Basic Fault Address Reporting
    =================================================================
    Memory around native instruction pointer (0x1036f76cc):0x1036f76bc 60 00 00 54 e0 03 13 aa 0f 4b 48 94 68 aa 40 f9 `..T.....KH.h.@.
    0x1036f76cc 09 c1 46 39 69 00 00 36 08 0d 40 f9 88 00 00 b5 ..F9i..6..@.....
    0x1036f76dc e0 03 13 aa 21 00 80 52 0b e5 ff 97 e9 03 13 aa ....!..R........
    0x1036f76ec 2a 0d 49 f8 aa 01 00 b4 e8 03 09 aa 4b 1d 40 b9 *.I.........K.@.

    =================================================================
    Managed Stacktrace:
    =================================================================
    at <unknown> <0xffffffff>
    at UnityEngine.Material:GetTextureImpl <0x00007>
    at UnityEngine.Material:GetTexture <0x00027>
    at UnityEngine.Material:get_mainTexture <0x0006b>
    at UnityEngine.UI.Image:get_mainTexture <0x0005f>
    at UnityEngine.UI.Graphic:UpdateMaterial <0x0008f>
    at UnityEngine.UI.Image:UpdateMaterial <0x00017>
    at UnityEngine.UI.Graphic:Rebuild <0x00087>
    at UnityEngine.UI.CanvasUpdateRegistry:PerformUpdate <0x00467>
    at <Module>:invoke_void <0x000af>
    at UnityEngine.Canvas:SendWillRenderCanvases <0x00037>
    at System.Object:runtime_invoke_void <0x00067>
    =================================================================
    Obtained 45 stack frames.
    #0 0x000001036f76cc in Material::GetTexture(ShaderLab::FastPropertyName)
    #1 0x00000102d42598 in Material_CUSTOM_GetTextureImpl(ScriptingBackendNativeObjectPtrOpaque*, int)
    #2 0x0000038076ebb0 in (wrapper managed-to-native) UnityEngine.Material:GetTextureImpl (UnityEngine.Material,int) [{0x37c1d3688} + 0x78] (0x38076eb38 0x38076ec30) [0x137f02a80 - Unity Child Domain]
    #3 0x000004204ae870 in UnityEngine.Material:GetTexture (string) [{0x37c1d3538} + 0x28] [/Users/bokken/build/output/unity/unity/Runtime/Export/Shaders/Material.cs :: 172u] (0x4204ae848 0x4204ae87c) [0x137f02a80 - Unity Child Domain]
    #4 0x000004204ae60c in UnityEngine.Material:get_mainTexture () [{0x1191936b8} + 0x6c] [/Users/bokken/build/output/unity/unity/Runtime/Export/Shaders/Material.bindings.cs :: 64u] (0x4204ae5a0 0x4204ae628) [0x137f02a80 - Unity Child Domain]
    #5 0x000004204ad818 in UnityEngine.UI.Image:get_mainTexture () [{0x395616c58} + 0x60] [./Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/Image.cs :: 695u] (0x4204ad7b8 0x4204ad884) [0x137f02a80 - Unity Child Domain]
    #6 0x000004204ad248 in UnityEngine.UI.Graphic:UpdateMaterial () [{0x39501fa70} + 0x90] [./Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/Graphic.cs :: 676u] (0x4204ad1b8 0x4204ad26c) [0x137f02a80 - Unity Child Domain]
    #7 0x000004204ad008 in UnityEngine.UI.Image:UpdateMaterial () [{0x395616dc0} + 0x18] [./Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/Image.cs :: 951u] (0x4204acff0 0x4204ad094) [0x137f02a80 - Unity Child Domain]
    #8 0x000004204a53e0 in UnityEngine.UI.Graphic:Rebuild (UnityEngine.UI.CanvasUpdate) [{0x39501f9f8} + 0x88] [./Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/Graphic.cs :: 654u] (0x4204a5358 0x4204a53f4) [0x137f02a80 - Unity Child Domain]
    #9 0x0000041e2ef740 in UnityEngine.UI.CanvasUpdateRegistry:PerformUpdate () [{0x37c066570} + 0x468] [./Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/CanvasUpdateRegistry.cs :: 216u] (0x41e2ef2d8 0x41e2ef9a0) [0x137f02a80 - Unity Child Domain]
    #10 0x0000041e2ef1d0 in (wrapper delegate-invoke) <Module>:invoke_void () [{0x119564d70} + 0xb0] (0x41e2ef120 0x41e2ef230) [0x137f02a80 - Unity Child Domain]
    #11 0x0000041e2ef2c8 in UnityEngine.Canvas:SendWillRenderCanvases () [{0x134dcf2b0} + 0x38] [/Users/bokken/build/output/unity/unity/Modules/UI/ScriptBindings/UICanvas.bindings.cs :: 105u] (0x41e2ef290 0x41e2ef2d8) [0x137f02a80 - Unity Child Domain]
    #12 0x0000041e5c1b38 in (wrapper runtime-invoke) object:runtime_invoke_void (object,intptr,intptr,intptr) [{0x37bec4470} + 0x68] (0x41e5c1ad0 0x41e5c1bcc) [0x137f02a80 - Unity Child Domain]
    #13 0x0000035c954d90 in mono_jit_runtime_invoke
    #14 0x0000035cadb24c in do_runtime_invoke
    #15 0x0000035cadb16c in mono_runtime_invoke
    #16 0x000001039eb3c8 in scripting_method_invoke(ScriptingMethodPtr, ScriptingObjectPtr, ScriptingArguments&, ScriptingExceptionPtr*, bool)
    #17 0x000001039c64c8 in ScriptingInvocation::Invoke(ScriptingExceptionPtr*, bool)
    #18 0x00000103f4c6d8 in UI::CanvasManager::WillRenderCanvases()
    #19 0x00000103f4ecd8 in UI::InitializeCanvasManager()::UIEventsWillRenderCanvasesRegistrator::Forward()
    #20 0x00000103627734 in InitPlayerLoopCallbacks()::PostLateUpdatePlayerUpdateCanvasesRegistrator::Forward()
    #21 0x0000010360ef58 in ExecutePlayerLoop(NativePlayerLoopSystem*)
    #22 0x0000010360ef8c in ExecutePlayerLoop(NativePlayerLoopSystem*)
    #23 0x0000010360f38c in PlayerLoop()
    #24 0x00000104587634 in EditorPlayerLoop::Execute()
    #25 0x00000104587e1c in PlayerLoopController::InternalUpdateScene(bool, bool)
    #26 0x00000104580748 in PlayerLoopController::UpdateSceneIfNeededFromMainLoop()
    #27 0x0000010457dc44 in Application::TickTimer()
    #28 0x0000010580e8f0 in -[EditorApplication TickTimer]
    #29 0x00000189160224 in __NSFireTimer
    #30 0x5228800188011f90 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__
    #31 0xda19000188011c34 in __CFRunLoopDoTimer
    #32 0x7a0100018801176c in __CFRunLoopDoTimers
    #33 0x1c0b000187ff4ba4 in __CFRunLoopRun
    #34 0x9b6c000187ff3e0c in CFRunLoopRunSpecific
    #35 0xf61880019278f000 in RunCurrentEventLoopInMode
    #36 0x4f1f00019278ec90 in ReceiveNextEventCommon
    #37 0x12c00019278eb94 in _BlockUntilNextEventMatchingListInModeWithFilter
    #38 0x522d00018b84c970 in _DPSNextEvent
    #39 0xb52080018c03edec in -[NSApplication(NSEventRouting) _nextEventMatchingEventMask:untilDate:inMode:dequeue:]
    #40 0xa56d80018b83fcb8 in -[NSApplication run]
    #41 0x290d80018b816f54 in NSApplicationMain
    #42 0xdc46000105826d6c in EditorMain(int, char const**)
    #43 0x000001058270b8 in main
    #44 0x00000187b8e0e0 in start
    Launching bug reporter
    Attribute Qt::AA_EnableHighDpiScaling must be set before QCoreApplication is created.
    [40m[32minfo[39m[22m[49m: Microsoft.Hosting.Lifetime[0]
    Application is shutting down...
    [40m[32minfo[39m[22m[49m: Unity.ILPP.Runner.PostProcessingAssemblyLoadContext[0]
    ALC ILPP context 1 is unloading

     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    39,357
    It does kinda look that way from the stacktrace.

    Try maybe a reimport-all? Perhaps that texture is borked in some way.

    Try replace the actual texture too... at this point you're just sorta left to bisect between this failing setup and some known functioning setup, so I would just start hack/slash/destroying stuff until it no longer crashes, then see what the last change was.

    https://en.wikipedia.org/wiki/Bisection_(software_engineering)

    (Obviously, source control required!)
     
  3. Syadeu

    Syadeu

    Joined:
    Feb 28, 2018
    Posts:
    3
    I've figured out something bigger problem after reimporting all.
    Even the reimport process didn't succeed as well stacktrace said another Material caused the engine crash.
    Strangely, Material does not have any relationship with the first shader Material in the first place at all.

    Anyway, I managed to reimport all by removing all crashing Materials and Library, Obj folder by myself.
    Still, engine crash.

    Nothings changed. Keep engine crashing.

    -----

    As far as I've figured, If the Image component is alive and active it doesn't have any problem. The problem is after de-activate the component(or parent GameObject) and trying to re-activate it.

    And also replacing runtime instanced Material to asset version of Material(referencing) same as well.

    Screenshot 2024-04-12 at 1.11.53 PM.png
    Screenshot 2024-04-12 at 1.13.25 PM.png
     
    Kurt-Dekker likes this.
  4. Syadeu

    Syadeu

    Joined:
    Feb 28, 2018
    Posts:
    3
    Okay, I found the solution.

    In the C# helper code, I destroyed instanced Material to prevent occupied graphics buffer and create new Material when it's activated. I think this causes an internal Material fetching error that the Image component still references destroyed Material.

    It seems it makes sense if the Image component is connected to Material on native side and does not update/upload Material at OnEnable sequence.

    UI graphics has so much difference from normal graphics API...
     
    Kurt-Dekker likes this.
  5. gabrieloc

    gabrieloc

    Joined:
    Apr 6, 2014
    Posts:
    53
    Wow. Can confirm destroying an instanced material used in UI was the issue.

    Serves me right for being responsible and cleaning up instances