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

@changruizhu96

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);
}


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