Search Unity

Bug Bit operations creates bitFieldExtractU function call not supported by Metal

Discussion in 'Shaders' started by chao3, Sep 26, 2022.

  1. chao3

    chao3

    Joined:
    Sep 1, 2014
    Posts:
    11
    Hello,

    I am trying to port Dear ImGui for Unity onto iOS:
    https://github.com/realgamessoftware/dear-imgui-unity

    And the code would run but the following shader code would generate bitFieldExtractU call:
    https://github.com/realgamessoftwar...aster/Resources/Shaders/PassesBuiltin.hlsl#L9

    Code (CSharp):
    1. Compilation failed:
    2. program_source:59:19: error: no matching function for call to ‘bitFieldExtractU’
    It seems like a basic bit field unpacking and it works on Windows Editor/Player, Android device/emulator, but it does not compile on macOS and iOS. The console log is attached at the end of this post.

    I would like to ask is there a way to fix this issue or work around it by forcing ShaderLab not outputting bitFieldExtractU? Thank you.

    Unity version with this issue: 2019.4.40 2020.3.36

    Code (CSharp):
    1. Built from ‘master’ branch, Version ’2020.3.36f1 (71f96b79b9f0)’, Build type ‘Release’, Scripting Backend ‘il2cpp’
    2. MemoryManager: UsingDefault’ Allocator.
    3. -> applicationDidFinishLaunching()
    4. Setting UIViewControllerBasedStatusBarAppearance to NO is no longer supported.
    5. Apple actively discourages that, and all application-wide methods of changing status bar appearance are deprecated
    6. -> applicationDidBecomeActive()
    7. GfxDevice: creating device client; threaded=1
    8. Initializing Metal device caps: Apple A8 GPU
    9. Initialize engine version: 2020.3.36f1 (71f96b79b9f0)
    10. UnloadTime: 3.636125 ms
    11. Compilation failed:
    12. program_source:59:19: error: no matching function for call to ‘bitFieldExtractU’
    13.     u_xlatu0.xy = bitFieldExtractU(uint2(0x8u, 0x8u), uint2(0x8u, 0x10u), input.TEXCOORD1);
    14.                   ^~~~~~~~~~~~~~~~
    15. program_source:29:31: note: candidate template ignored: could not match ‘vec<uint, N>(aka ‘unsigned int _attribute_((ext_vector_type(N)))) against ‘uint(aka ‘unsigned int)
    16. template <int N> vec<uint, N> bitFieldExtractU(const vec<uint, N> width, const vec<uint, N> offset, const vec<uint, N> src)
    17.                               ^
    18. #include <metal_stdlib>
    19. #include <metal_texture>
    20. using namespace metal;
    21. #if !(__HAVE_FMA__)
    22. #define fma(a,b,c) ((a) * (b) + (c))
    23. #endif
    24. struct VGlobals_Type
    25. {
    26.     float4 hlslcc_mtx4x4unity_ObjectToWorld[4];
    27.     float4 hlslcc_mtx4x4unity_MatrixVP[4];
    28. };
    29. struct Mtl_VertexIn
    30. {
    31.     float2 POSITION0 [[ attribute(0) ]] ;
    32.     float2 TEXCOORD0 [[ attribute(1) ]] ;
    33.     uint TEXCOORD1 [[ attribute(2) ]] ;
    34. };
    35. struct Mtl_VertexOut
    36. {
    37.     float4 mtl_Position [[ position ]];
    38.     float2 TEXCOORD0 [[ user(TEXCOORD0) ]];
    39.     half4 COLOR0 [[ user(COLOR0) ]];
    40. };
    41. template <int N> vec<uint, N> bitFieldExtractU(const vec<uint, N> width, const vec<uint, N> offset, const vec<uint, N> src)
    42. {
    43.     vec<bool, N> isWidthZero = (width == 0);
    44.     vec<bool, N> needsClamp = ((width + offset) < 32);
    45.     vec<uint, N> clampVersion = src << (32-(width+offset));
    46.     clampVersion = clampVersion >> (32 - width);
    47.     vec<uint, N> simpleVersion = src >> offset;
    48.     vec<uint, N> res = select(simpleVersion, clampVersion, needsClamp);
    49.     return select(res, vec<uint, N>(0), isWidthZero);
    50. };
    51. vertex Mtl_VertexOut xlatMtlMain(
    52.     constant VGlobals_Type& VGlobals [[ buffer(0) ]],
    53.     Mtl_VertexIn input [[ stage_in ]])
    54. {
    55.     Mtl_VertexOut output;
    56.     float4 u_xlat0;
    57.     uint2 u_xlatu0;
    58.     float4 u_xlat1;
    59.     u_xlat0 = input.POSITION0.yyyy * VGlobals.hlslcc_mtx4x4unity_ObjectToWorld[1];
    60.     u_xlat0 = fma(VGlobals.hlslcc_mtx4x4unity_ObjectToWorld[0], input.POSITION0.xxxx, u_xlat0);
    61.     u_xlat0 = u_xlat0 + VGlobals.hlslcc_mtx4x4unity_ObjectToWorld[3];
    62.     u_xlat1 = u_xlat0.yyyy * VGlobals.hlslcc_mtx4x4unity_MatrixVP[1];
    63.     u_xlat1 = fma(VGlobals.hlslcc_mtx4x4unity_MatrixVP[0], u_xlat0.xxxx, u_xlat1);
    64.     u_xlat1 = fma(VGlobals.hlslcc_mtx4x4unity_MatrixVP[2], u_xlat0.zzzz, u_xlat1);
    65.     output.mtl_Position = fma(VGlobals.hlslcc_mtx4x4unity_MatrixVP[3], u_xlat0.wwww, u_xlat1);
    66.     output.TEXCOORD0.xy = fma(input.TEXCOORD0.xy, float2(1.0, -1.0), float2(0.0, 1.0));
    67.     u_xlatu0.x = input.TEXCOORD1 & 0xffu;
    68.     //null = as_type<float4>(u_xlatu0.x % 0xffu);
    69.     u_xlatu0.x = u_xlatu0.x / 0xffu;
    70.     output.COLOR0.x = half(u_xlatu0.x);
    71.     u_xlatu0.xy = bitFieldExtractU(uint2(0x8u, 0x8u), uint2(0x8u, 0x10u), input.TEXCOORD1);
    72.     //null = as_type<float4>(u_xlatu0.xyxx % uint4(0xffu, 0xffu, 0x0u, 0x0u));
    73.     u_xlatu0.xy = u_xlatu0.xy / uint2(0xffu, 0xffu);
    74.     output.COLOR0.yz = half2(u_xlatu0.xy);
    75.     u_xlatu0.x = input.TEXCOORD1 >> 0x18u;
    76.     //null = as_type<float4>(u_xlatu0.x % 0xffu);
    77.     u_xlatu0.x = u_xlatu0.x / 0xffu;
    78.     output.COLOR0.w = half(u_xlatu0.x);
    79.     return output;
    80. }
     
  2. goncalo-vasconcelos

    goncalo-vasconcelos

    Joined:
    May 24, 2017
    Posts:
    8
    Sorry about not keeping the dear-imgui-unity package up to date. I'll try to do it later in the year.
    Perhaps you can avoid unpacking by setting the vertex attribute format for the color to UNorm8:

    In ImGuiRendererMesh.cs:
    Code (CSharp):
    1.  
    2.         // Color sent with TexCoord1 semantics because otherwise Color attribute would be reordered to come before UVs
    3.         static readonly VertexAttributeDescriptor[] AttributeDescriptors = new[]
    4.         {
    5.             new VertexAttributeDescriptor(VertexAttribute.Position , VertexAttributeFormat.Float32, 2), // position
    6.             new VertexAttributeDescriptor(VertexAttribute.TexCoord0, VertexAttributeFormat.Float32, 2), // uv
    7.             new VertexAttributeDescriptor(VertexAttribute.TexCoord1, VertexAttributeFormat.UNorm8 , 4), // color
    8.         };
    9.  
    In Common.hlsl:
    Code (CSharp):
    1.  
    2. struct ImVert
    3. {
    4.     float2 vertex   : POSITION;
    5.     float2 uv       : TEXCOORD0;
    6.     half4 color     : TEXCOORD1;
    7. };
    8.  
    And in PassesBuiltin.hlsl:
    Code (CSharp):
    1.  
    2. Varyings ImGuiPassVertex(ImVert input)
    3. {
    4.     Varyings output  = (Varyings)0;
    5.     output.vertex    = UnityObjectToClipPos(float4(input.vertex, 0, 1));
    6.     output.uv        = float2(input.uv.x, 1 - input.uv.y);
    7.     output.color     = input.color;
    8. #ifndef UNITY_COLORSPACE_GAMMA
    9.     output.color.rgb = GammaToLinearSpace(output.color.rgb);
    10. #endif
    11.     return output;
    12. }
    13.  
     
  3. chao3

    chao3

    Joined:
    Sep 1, 2014
    Posts:
    11
    Thank you very much for your help and creating the `dear-imgui-unity` repository. I'll try it after I learn how to operate on NativeArray<ImDrawVert> to map into other types of NativeArray. It’s a shame that the shader wouldn’t work since it seems the right way to go and works on every platform except Metal.


    Did a bit more testing and this issue happens on all latest versions of Unity including 2019.4.40, 2020.3.39 and 2021.3.10. The macOS editor would also not show properly unless “Metal Editor Support” is turned off. Once Unity decides to emit ‘bitFieldExtractU’ into Metal shader, the rendering would fail. And I tried to trick Unity into not generating ‘bitFieldExtractU’ but placing dummy conditions or dividing by 256 would not prevent it.
     
  4. chao3

    chao3

    Joined:
    Sep 1, 2014
    Posts:
    11
    This issue was submitted to Unity Bug Reporting Portal and marked as fix on 2023.1.0a17
     
    goncalo-vasconcelos likes this.