Skip to content

[Bug/Enhancement] original EnvironmentDepthManager provider causes 90-100% PC GPU usage in Quest Link, while self-implemented sample-and-hold mode stays at 9-11% #96

Closed

Description

@changruizhu96

Unity version

6000.0.40

Where does the issue occur?

  • In Unity Editor
  • In Quest builds

Description

Summary

When running in Unity Editor over Quest Link, enabling EnvironmentDepthManager causes sustained PC GPU 3D usage around 90-100%, even in an almost empty scene with only Passthrough + EnvironmentDepthManager.

This happens even when OcclusionShadersMode is set to None, so the issue does not appear to be caused by occlusion shader rendering.

I tested a sample-and-hold workaround where the depth provider is only enabled when a new depth sample is needed, one valid depth texture is acquired, then the provider is disabled again while the last valid depth texture remains cached. With this approach, even at 90Hz sampling, sustained PC GPU 3D usage stays around 9-11%.

This suggests the abnormal GPU cost may be related to keeping the OpenXR environment depth provider continuously enabled in Quest Link Editor mode, rather than the cost of acquiring depth frames at high frequency.

Environment

  • Unity version: 6000.0.40
  • Meta XR Core SDK version: v85
  • Also tested: v77
  • Device: Quest 3
  • Runtime: Unity Editor over Quest Link
  • GPU: RTX 5090
  • Render pipeline: URP
  • Graphics API: Vulkan
  • Passthrough enabled: yes

Steps to reproduce

Minimal Reproduction

  1. Create an empty Unity scene.
  2. Enable Passthrough.
  3. Add EnvironmentDepthManager.
  4. Set OcclusionShadersMode to None.
  5. Run the scene in Unity Editor over Quest Link.
  6. Observe Windows Task Manager GPU 3D usage.

Observed Result

  • Passthrough only: low PC GPU 3D usage.
  • Passthrough + EnvironmentDepthManager continuous mode: sustained 90-100% PC GPU 3D usage.
  • Meta XR Core SDK v77: around 80% GPU 3D usage.
  • Meta XR Core SDK v85: around 90%+ GPU 3D usage.
  • The high GPU usage happens even when OcclusionShadersMode = None.

Sample-and-Hold Workaround Result

I tested a workaround that changes the manager behavior from continuous provider enabled to sample-and-hold:

  1. Enable the depth provider when a new sample is due.
  2. Acquire one updated depth texture.
  3. Keep the last valid depth texture bound/cached.
  4. Disable the depth provider until the next sample interval.

Results:

Mode Sample rate Sustained PC GPU 3D usage
Passthrough only N/A low / baseline
EnvironmentDepthManager continuous per-frame / continuous provider enabled 90-100%
Sample-and-hold 8Hz ~9-11%
Sample-and-hold 32Hz ~9-11%
Sample-and-hold 64Hz ~9-11%
Sample-and-hold 90Hz ~9-11%

There may be a short GPU spike when the provider is first enabled, but after that the usage drops and remains around 9-11%.

Expected Result

EnvironmentDepthManager should not cause sustained 90-100% PC GPU 3D usage in Quest Link Editor mode, especially when occlusion shader rendering is disabled.

If continuous provider mode is expected to be expensive in Quest Link, it would be helpful to expose an official configurable sampling mode or sample-and-hold mode.

Workaround / Hypothesis

The sample-and-hold test suggests that the cost is not primarily caused by the frequency of TryGetUpdatedDepthTexture() calls. Even at 90Hz sample-and-hold, GPU usage remains low.

The abnormal sustained GPU usage appears to be related to keeping the OpenXR environment depth provider continuously enabled in Quest Link Editor mode.

Enhancement Request

Please consider exposing an official API or inspector option for:

  • sample-and-hold depth updates
  • configurable environment depth sampling rate
  • keeping the last valid depth texture cached while temporarily disabling provider acquisition
  • safer provider lifecycle behavior in Unity Editor / Quest Link mode

This would allow applications that do not need fully continuous per-frame occlusion to use Environment Depth without saturating the PC GPU in Quest Link.

Logs

none

Additional info

//Simplified sample-and-hold workaround

private bool providerRunning;
private float nextSampleTime;
private float sampleHz = 90f;

private void OnBeforeRender()
{
    float now = Time.realtimeSinceStartup;

    if (!providerRunning && now >= nextSampleTime)
    {
        provider.SetDepthEnabled(true, removeHands: false);
        providerRunning = true;
    }

    if (!providerRunning)
    {
        return;
    }

    if (!provider.TryGetUpdatedDepthTexture(out var depthTexture, frameDescriptors))
    {
        return;
    }

    if (depthTexture == null || !depthTexture.IsCreated())
    {
        return;
    }

    Shader.SetGlobalTexture(EnvironmentDepthTextureId, depthTexture);

    provider.SetDepthEnabled(false, false);
    providerRunning = false;

    nextSampleTime = now + 1f / Mathf.Max(1f, sampleHz);
}


Activity

  1. pinned this issue on May 18, 2026
  2. TudorJude commented on May 18, 2026

    @TudorJude
    Contributor

    Hello,

    Thanks for the deep dive! This is quite interesting to read but it might just be new developments with Link. Back when we implemented Depth API, we never had this GPU load over Link so this sounds more like a regression in Link itself, the depth provider should not eat up this many resources.

    This is still very useful for people to get Depth a little faster over Link but the actual root cause might be something else. I will relay this to the people working on Link.

    I am pinning this, I think people can get some good value from this.

  3. changruizhu96 commented on May 18, 2026

    @changruizhu96
    Author

    Hello,

    Just a quick update: I've tested with V201, and the above method will cause a Unity crash.
    It happens because Meta Environment Depth gives Unity a native depth texture, but Unity fails to convert/register it as a normal RenderTexture.

    The failing path is roughly:

    EnvironmentDepthManager asks Meta’s depth provider for a depth frame.
    Meta returns a native depth texture.
    Unity tries to wrap it through XRDisplaySubsystem.GetRenderTexture().
    That step repeatedly fails.
    Each failed attempt still leaves texture create/destroy work inside Unity’s XR texture system.
    When Play Mode exits, Unity tries to clean up those XR textures, the destroy queue overflows, and the Editor crashes.

    But in v201, the GPU usage of environment depth manager dropped to around 60% .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions