Search Unity

Built-in VertexLit shader failing to compile for Oculus Go

Discussion in 'AR/VR (XR) Discussion' started by JoeStrout, Sep 5, 2018.

  1. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    I'm getting tons of these errors in adb logcat today:

    I'm presuming this is related to the fact that my app locks up, requiring the Go to be rebooted, when it hits this scene, because these are among the process's last words before it dies.

    Any idea what's going on here, and what can be done about it?
     
  2. BrandonFogerty

    BrandonFogerty

    Joined:
    Jan 29, 2016
    Posts:
    83
    Hi @JoeStrout!

    That error means you are trying to use the single-pass instancing stereo rendering mode, however, your GPU doesn't support the required GPU extension for SPI to work. That makes sense because Oculus Go should never attempt to use single-pass instancing. Instead, it should be trying to use the multiview stereo rendering method. We just tried reproing the issue you encountered using the 'Legacy Shaders/VertexLit' shader and did not encounter this issue. Could you provide the full adb log including the startup information? Could you also let me know which version of Unity you are using? Thanks!
     
    ROBYER1 likes this.
  3. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    I'm afraid I no longer have that project in a broken state (I probably just replaced the shader with a different one).

    But regarding the bombshell you just dropped:
    Wait, what? The Go doesn't support single-pass stereo rendering?

    I've been very careful to keep my player set to Single Pass Multiview or Instanced — as strongly recommended by Oculus. I use only the GLES3 API, make sure to use only single-pass-compatible shaders, etc. Are you telling me this is all for naught? Are you sure?
     
  4. BrandonFogerty

    BrandonFogerty

    Joined:
    Jan 29, 2016
    Posts:
    83
    Hi @JoeStrout!

    It is not all for naught. =)

    Multiview and Single-Pass Instancing are two similar but different stereo rendering methods. At the end of the day, they are both trying to accomplish a similar goal. Both stereo modes provide us the capability to render an object to both eyes in a texture array with a single draw call without requiring the inefficiency of a geometry shader. The way they achieve this goal is slightly different. Regardless of which stereo rendering mode you use, we use a texture array where slice 0 represents the left eye and slice 1 represents the right eye. Before we render an object, we bind both slices of the texture array and submit a single instanced draw call. Both stereo modes are almost identical up to this point except with regards to how we bind texture layers to the framebuffer. That point aside, where they diverge is in how we determine which slice to render to on the GPU. Single-pass instancing is a more explicit approach when compared with multiview. When using single-pass instancing, it is the job of the shader developer to explicitly inform the GPU as to which texture slice we should be rendering to. This is handled automatically for you when using Unity's built-in stereo shader macros or when using Unity's built-in shaders.

    Code (CSharp):
    1. struct v2f
    2. {
    3.     float4 vertex : SV_POSITION;
    4.     float2 texcoord : TEXCOORD0;
    5.     UNITY_VERTEX_OUTPUT_STEREO // <-- For Single-Pass Instancing, inform the GPU that we will be writing to a specific texture array slice.
    6. };
    7.  
    8. v2f vert (appdata_t v)
    9. {
    10.     v2f o;
    11.     UNITY_SETUP_INSTANCE_ID(v); // <-- Calculate the texture slice/ unity_StereoEyeIndex variable based on the current instance id.
    12.     UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); // <-- Inform the GPU which texture slice we would like to draw to based on the value of unity_StereoEyeIndex.
    When you use the macro "UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO" with single-pass instancing, we write to a special GPU register which informs the GPU which texture slice to write to.

    What about multiview? Well, the main difference is that we don't need to explicitly tell the GPU which texture slice to write to from the vertex shader. The GPU already knows and handles this for you implicitly.

    Single-Pass Instancing is mostly used by desktop platforms. Most mobile GPUs only support multiview. Therefore, when Unity runtime starts up, we query the GPU and XR platform to determine which stereo rendering mode is supported on that device. Based on that, we choose at runtime which stereo rendering path to use. I hope that clarifies things a bit.

    The Oculus Go support's multiview and does not support single-pass instancing. Therefore Unity should have never attempted to use a shader that required the GL_AMD_vertex_shader_layer GPU extension as that is what we use to support single-pass instancing for OpenGL platforms.
     
    Last edited: Sep 14, 2018
    ROBYER1 and tcmeric like this.
  5. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Ah, I think I see. So "multiview" (good) is different from "multi-pass" (bad). And with my current settings, I'm using the former (which is good).
     
  6. BrandonFogerty

    BrandonFogerty

    Joined:
    Jan 29, 2016
    Posts:
    83
    Hi @JoeStrout!

    Yes. MutiView and Multi-Pass are two very different animals. Multiview is a tiger and multipass is a tortoise.
    Multiview is much faster. This is because the GPU takes a lot of the burden of work off of the CPU's shoulders.
    With multi-pass, we must iterate through the scene graph twice and submit two draw calls for every object that needs to be rendered.

    You can think of the difference between multi-pass and multi-view/single pass instancing like this.
    Imagine you have two messages you need to mail from New York to Seattle to the same person. Unfortunately, the postal worker can only deliver one message at a time. Therefore you have to write two separate letters. Before you can send the second letter, you have to wait for the first letter to be received. Pretty inefficient huh? The letter is a draw call. The method of how you send the two letters is called multi-pass. You required a pass or delivery for each letter.

    Imagine now simply writing both messages in the same letter and having the postal worker deliver the single letter. The receiver can then process both messages at the same time. This is Multi-view/Single-Pass instancing.

    Either way, you must pay the cost of sending a single letter from New York to Seattle which is significant. The distance from New York to Seattle represents the distance and time it takes to deliver a message from the CPU to the GPU. However, you can pack your letter with twice the amount of information and therefore send both your messages to the receiver in much less time.

    Now all that isn't to say the multi-pass is bad. The analogy will start to break down here but if you only had enough room on a piece of paper to write a single message, then you would need to send two letters. Unfortunately, some older GPUs can't support choosing a texture array slice from a vertex shader. In that case, you have to use single-pass double wide or multi-pass.

    However, in your case, multi-pass isn't even an option. On android based platforms, Unity will make the best decision for you automatically based on what your device and XR platform supports. In your case, this should be multi-view.
     
    Last edited: Sep 14, 2018
    ROBYER1 and tcmeric like this.
  7. ROBYER1

    ROBYER1

    Joined:
    Oct 9, 2015
    Posts:
    1,454
    I have seen that Multi-View is finally the new standard introduced in the XR Subsystems Oculus Android package settings. Is it now replacing Single-Pass for Oculus devices?

    I also have shader compile errors -
    undeclared identifier 'unity_StereoEyeIndex'

    I have a bug report for it here: Case 1188487