Search Unity

Compiled shader instructions appear silly

Discussion in 'Shaders' started by patrickreece, Jul 29, 2020.

  1. patrickreece

    patrickreece

    Joined:
    Nov 14, 2019
    Posts:
    23
    Hey, I'm trying to optimise a shader (for all platforms, but android in particular) and checking out some of the compiled code unity generated, I see a lot of operations that don't look like they do much, e.g.

    Code (CSharp):
    1.     u_xlat2.xyz = u_xlat2.xyz;
    2.     u_xlat3.xyz = u_xlat3.xyz;
    3.     u_xlat4.xyz = u_xlat4.xyz;
    4.     u_xlat1.xy = u_xlat1.xy;
    5.     u_xlat2.xyz = u_xlat2.xyz;
    6.     u_xlat3.xyz = u_xlat3.xyz;
    7.     u_xlat4.xyz = u_xlat4.xyz;
    8.     u_xlat5.x = u_xlat5.x;
    9.     u_xlat5.y = u_xlat14;
    It seem to me like only the last line there does anything. Am I wrong, and are these operations slowing down the shader? Are they indications I'm doing something wrong in my shader code?
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,342
    It’s a clear indication that you’re using OpenGL... and that’s about it.

    Really this isn’t a “compiled” shader. OpenGL doesn’t have compiled shaders in the same way that other APIs have. If you want to see what a compiled shader for an OpenGL platform looks like, you have to get the profiling tools for that platform so you can extract the actually compiled shader from the device. This is because OpenGL requires GLSL shaders to be handed to a device so it can compile them at runtime. Usually to a cache, but a compiled GLSL shader is only intended to be able to run on the device that compiled it.

    This is much different than Direct3D where the compiled shader code can run on any device that supports the version of Direct3D the shader was written and compiled for.

    Instead what you see when you view the “compiled” OpenGL shader is a shader that’s been converted from a compiled HLSL Shader to GLSL. It’s ugly, adds a lot of seemingly redundant code, but it works. Basically all of that redundant code will disappear once it is actually compiled by the device it runs on, just like adding x = x to an HLSL shader will result in no change to the compiled shader.
     
  3. patrickreece

    patrickreece

    Joined:
    Nov 14, 2019
    Posts:
    23
    Thank you for the explanation. I actually do see the same thing in DX11 in disassembly code from RenderDoc - not sure if that is 100% exactly the instructions that run on the GPU, but let me know if there is another way to view those.
    Code (CSharp):
    1.   33: nop
    2.   34: mov r1.xyzw, r1.xyzw
    3.   35: mov r6.x, r6.x
    4.   36: mov r6.y, r6.y
    5.   37: mov r6.z, r6.z
    6.   38: mov r6.w, r6.w
    7.   39: mov r7.x, r7.x
    8.   40: mov r7.y, r7.y
    9.   41: mov r7.z, r7.z
    10.   42: mov r7.w, r7.w
    11.   43: mov r8.xyzw, r8.xyzw
    12.   44: mov r4.x, r4.x
    13.   45: mov r4.y, r4.y
    14.   46: mov r4.z, r4.z
    15.   47: mov r4.w, r4.w
    I think this may be related to passing a uniform float4x4 into a function?
    It seems silly to have r4 pass one component at a time, and r8 all at once too.

    Also, your posts have been a huge help to me in learning many things about shaders and graphics programming in Unity in particular! Thanks so much.
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,342
    Super weird, but that explains why it shows up in the OpenGL shader, since it's a direct translation of that compiled DX11 shader. I'd still ignore it though.

    And no, it's not actually the code that runs on the GPU as there's another translation layer that the graphics drivers do to convert the complied shader code to that GPU's assembly.

    You can play with something like Shader Playground to see shaders compiled to AMD GPU assembly if you're curious.
    http://shader-playground.timjones.io/