CSI-2 (IMX219) delivers half frame rate (60→30 fps) with cuEGL/Argus?(Jetson Orin NX / JetPack 6.2.1)

I’m integrating a CSI-2 camera for an AGV vision stack on Jetson Orin NX 8GB and hit a repeatable “half-fps” behavior that appears coupled to the display stack / EGL path. I’d appreciate guidance on fixes or a supported low-memory display setup that preserves full frame rate without a heavy desktop.


Environment

  • Hardware: Jetson Orin NX Engineering Reference Developer Kit (Super) 8GB

  • JetPack / L4T: nvidia-jetpack 6.2.1+b38

  • Kernel:

Linux nvidia-sbc 5.15.148-rt-tegra #1 SMP PREEMPT_RT Mon Oct 14 17:05:40 PDT 2024 aarch64 aarch64 aarch64 GNU/Linux
  • (RT kernel / PREEMPT_RT)

  • OS: Ubuntu 22.04

  • Power/Frequency: NV Power Mode: MAXN_SUPER; jetson_clocks locked (GPU 1173 MHz, EMC 3199 MHz, etc.)

  • Camera: IMX219-83 Stereo Camera, Mode 4 = 1280×720 @ 60 fps (https://www.waveshare.com/wiki/IMX219-83_Stereo_Camera)

  • Camera stack: LibArgus / Isaac ROS Argus Camera (NITROS / GXF hawk extension; lower layer not open-sourced)

  • Consumer path: EGLStream + cuEGL (cuEGLStreamConsumerAcquireFrame)

Attachments available: measurefps_argus_cuda.cpp (minimal repro) and README.md (build/run steps and nsys capture notes).


Symptom

  • Goal: stable 1280×720 @ 60 fps in both no-X (multi-user) and with-X (graphical) runlevels.

  • Observed:

    • No X (multi-user.target): whether EGL_PLATFORM=surfaceless or DISPLAY=:0, I only get ~30 fps; AcquireFrame cadence ≈ 33 ms.

    • With X (graphical.target): consistently ~60 fps; AcquireFrame cadence ≈ 16.7 ms.

  • Analysis: nsys shows the slowdown is on the supply side (slower Acquire cadence), not GPU compute in my consumer.

    On shutdown I sometimes see EGL teardown messages:

SCF: Error NotSupported: Unable to make context current
SCF: Error InvalidState: Error destorying EGL context

Repro (key steps)

Runlevel switch

# No X (save memory)
sudo systemctl isolate multi-user.target

# With X (graphical)
sudo systemctl isolate graphical.target

Lock power & clocks (done in both cases)

sudo nvpmodel -m 0
sudo jetson_clocks --show
sudo tegrastats

Run the minimal repro

# No X
EGL_PLATFORM=surfaceless ./build/measurefps --mode 4 --fps 60 --frames 120

# With X
DISPLAY=:0 ./build/measurefps --mode 4 --fps 60 --frames 120
  • No X: avg_fps ≈ 30.x

  • With X: avg_fps ≈ 60.x


What I tried (didn’t resolve “half-fps”)

  • MAXN_SUPER + jetson_clocks confirmed (GPU/EMC locked).

  • In multi-user: tested both EGL_PLATFORM=surfaceless and DISPLAY=:0 → still ~30 fps.

  • Restarted nvargus-daemon; in controlled demos I fixed frame duration / exposure and disabled anti-banding — the overall “no-X → half-fps” behavior remains.

  • In production I cannot easily replace the closed lower layer of Isaac ROS / GXF hawk.


Working hypothesis

Under identical hardware and locked clocks, “With X → 60 fps / No X → ~30 fps” points to a timing/clocking policy difference inside the EGL/cuEGL/Argus path when no display stack is present (possibly involving Host1x/VI/ISP or display-domain interaction). My consumer is not the bottleneck; Acquire cadence itself slows to ~33 ms.


Questions for NVIDIA / community

  1. Is this a known issue or expected behavior for cuEGL/Argus when no X is running, especially on JetPack 6.2.1 with the PREEMPT_RT kernel?

  2. What’s the recommended low-memory display stack on Jetson to preserve full frame rate without a full desktop?

    • Minimal Xorg (no desktop) using AllowEmptyInitialConfiguration / UseDisplayDevice None (headless X).

    • Wayland/Weston + Xwayland as a lightweight compositor/compat layer.

      Are there official sample configs or systemd units for these?

  3. For no-X deployments, are there supported driver/kernel/BPMP devfreq knobs (or env vars) to ensure multimedia/Host1x/VI/ISP domains don’t down-clock or change scheduling such that the stream drops to ~30 fps?

  4. For Isaac ROS Argus Camera / GXF hawk: without modifying closed code, are there parameters / environment variables / graph options to keep camera streaming at 60 fps in headless mode (e.g., forcing a headless path, disabling any display-sync tendencies, enforcing frame-duration constraints)?

  5. Any official logging toggles / diagnostic steps (Argus/driver-side) you recommend to pinpoint which domain/policy triggers the half-fps cadence when X is absent?


Attachments

measurefps.zip (10.6 KB)

  • measurefps_argus_cuda.cpp — minimal repro (EGLDevice/surfaceless + cuEGL consumer + Argus stream), flags --mode / --fps / --frames; prints average fps and key messages.

Turning off X saves ~800 MB, but I still need consistent 60 fps from IMX219 mode 4 via cuEGL/Argus. Any guidance, known issues, or official recommendations to achieve this without a heavy desktop would be greatly appreciated. Thank you! 🙏