-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Keep the CloudXR runtime on the GPU the XR frames are rendered on #7381
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
65f7e4c
c6f7f90
ebb0b45
21f2d44
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| Fixed | ||
| ^^^^^ | ||
|
|
||
| * Fixed the Kit renderer not being restricted to a single GPU under ``--xr``. The | ||
| ``--/renderer/multiGpu/activeCudaGpus`` setting was only applied when ``multi_gpu`` was | ||
| ``False``, which is set for distributed runs alone, so an XR session left the renderer | ||
| spanning every visible GPU while physics ran on the selected device. XR streams a single | ||
| stereo swapchain that the CloudXR compositor imports, so the renderer is now pinned to the | ||
| simulation device whenever XR is enabled. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| Fixed | ||
| ^^^^^ | ||
|
|
||
| * Fixed the XR headset receiving noise instead of the rendered scene on multi-GPU hosts. | ||
| The auto-launched CloudXR runtime selected its own device, and because Vulkan's physical | ||
| device enumeration is unrelated to the CUDA ordering Isaac Lab picks the simulation and | ||
| renderer devices with, the compositor could end up on a different GPU than the one holding | ||
| the rendered swapchain. The runtime is now pinned to the renderer's CUDA device via | ||
| ``NV_CXR_GPU_INDEX_CUDA``; an index already set in the environment or in the | ||
| ``--cloudxr_env`` profile is left untouched. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,6 +29,35 @@ | |
| from .isaac_teleop_cfg import IsaacTeleopCfg | ||
| from .teleop_message_processor import TeleopMessageProcessor | ||
|
|
||
| # The CloudXR runtime accepts at most one of these; setting both is rejected outright. | ||
| _CXR_GPU_INDEX_ENV_VARS = ("NV_CXR_GPU_INDEX_CUDA", "NV_CXR_GPU_INDEX_VULKAN") | ||
|
|
||
|
|
||
| def _env_file_pins_gpu_index(env_file: str | None) -> bool: | ||
| """Whether a CloudXR ``.env`` profile already selects a GPU index.""" | ||
| if not env_file: | ||
| return False | ||
| try: | ||
| with open(env_file, encoding="utf-8") as handle: | ||
| lines = handle.readlines() | ||
| except OSError: | ||
| return False | ||
| return any(line.strip().split("=", 1)[0].strip() in _CXR_GPU_INDEX_ENV_VARS for line in lines) | ||
|
|
||
|
|
||
| def _renderer_cuda_index() -> int | None: | ||
| """CUDA index the Kit renderer is pinned to, or ``None`` when it is not pinned.""" | ||
| try: | ||
| import carb | ||
| except ImportError: | ||
| return None | ||
| setting = carb.settings.get_settings().get("/renderer/multiGpu/activeCudaGpus") | ||
| if not setting: | ||
| return None | ||
| first = str(setting).split(",")[0].strip() | ||
| return int(first) if first.isdigit() else None | ||
|
|
||
|
|
||
| if TYPE_CHECKING: | ||
| from .haptic_feedback import HapticFeedbackCfg | ||
|
|
||
|
|
@@ -1310,13 +1339,43 @@ def _ensure_cloudxr_runtime(self) -> None: | |
|
|
||
| from isaacteleop.cloudxr import CloudXRLauncher as _CloudXRLauncher | ||
|
|
||
| self._pin_cloudxr_to_render_device() | ||
|
|
||
| self._cloudxr_launcher = _CloudXRLauncher( | ||
| install_dir=str(Path.home() / ".cloudxr"), | ||
| env_config=self._cloudxr_env_file, | ||
| accept_eula=False, | ||
| ) | ||
| logger.info("CloudXR runtime auto-launched") | ||
|
|
||
| def _pin_cloudxr_to_render_device(self) -> None: | ||
| """Point the CloudXR runtime at the GPU the frames are rendered on. | ||
|
|
||
| Left to itself the runtime takes the first Vulkan physical device. That | ||
| enumeration is unrelated to the CUDA ordering Isaac Lab selects the | ||
| simulation and renderer devices with, so on a multi-GPU host the | ||
| compositor routinely lands on a different card than the one holding the | ||
| rendered swapchain. Nothing reports an error -- the client connects, the | ||
| session starts and the encoder logs normal frame timings -- but the | ||
| headset only shows noise. | ||
|
Comment on lines
+1354
to
+1360
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unsure if we need the context, but the reason it picks the first Vulkan device is that most (all) windowed applications will pick the first Vulkan device and then ignore what the runtime asks the app to use, becuse the first Vulkan device is the GPU that the monitor is plugged into (breaks down in "unusual" setups). |
||
|
|
||
| An explicit choice, in the process environment or in the | ||
| ``--cloudxr_env`` profile, is left untouched. | ||
| """ | ||
| if any(name in os.environ for name in _CXR_GPU_INDEX_ENV_VARS): | ||
| return | ||
| if _env_file_pins_gpu_index(self._cloudxr_env_file): | ||
| return | ||
|
Comment on lines
+1365
to
+1368
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe add warnings here if they don't match, and ask the user to check the configs? |
||
|
|
||
| index = _renderer_cuda_index() | ||
| if index is None and self._device.type == "cuda": | ||
| index = self._device.index | ||
| if index is None: | ||
| return | ||
|
|
||
| os.environ["NV_CXR_GPU_INDEX_CUDA"] = str(index) | ||
| logger.info("Pinned the CloudXR runtime to CUDA device %d", index) | ||
|
|
||
| # ------------------------------------------------------------------ | ||
| # OpenXR handle acquisition | ||
| # ------------------------------------------------------------------ | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.