Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
adb8abf
Add optional camera PiP over completed render products
hougantc-nvda Oct 21, 2026
36e2957
Clarify camera test contracts and remove unused test flag
hougantc-nvda Oct 21, 2026
4d081f3
docs: update camera panel setup for public use
hougantc-nvda Oct 22, 2026
593d016
scope: keep camera panels focused on the active presentation path
hougantc-nvda Oct 22, 2026
5156f07
docs: remove obsolete camera fixture comment
hougantc-nvda Oct 22, 2026
7f78c53
docs: carry OVXR version guidance into camera panels
hougantc-nvda Oct 22, 2026
e7d56c5
Merge OVXR session naming into camera panels
hougantc-nvda Oct 22, 2026
2e8fe62
Merge the OVXR application interface name into camera panels
hougantc-nvda Oct 22, 2026
393b6db
Merge public OVXR wording into camera panels
hougantc-nvda Oct 22, 2026
5b54ee1
Place PiP formatting with its introducing code
hougantc-nvda Oct 22, 2026
0cbc686
Inherit device-reported OpenXR extension requirements
hougantc-nvda Oct 22, 2026
c977eef
Place OVXR camera presentation and tests in the OVXR package
hougantc-nvda Oct 22, 2026
c6efde9
Merge explicit abstract protocol declarations into camera panels
hougantc-nvda Oct 22, 2026
954f3db
Merge branch 'review-scope/pr1294' into review-scope/pr1295
hougantc-nvda Oct 22, 2026
c6c1e76
Use the module import consistently in camera quad tests
hougantc-nvda Oct 22, 2026
93f7e08
Use installed SDKs and static CUDA linkage for OVXR camera support
hougantc-nvda Oct 22, 2026
c6b92ab
Require CUDA 13 bindings for OVXR camera output
hougantc-nvda Oct 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ option(BUILD_PLUGIN_SHARPA_AVATAR "Build Sharpa AvatarExo Glove plugin (Linux; s
option(BUILD_EXAMPLES "Build examples" ON)
option(BUILD_EXAMPLE_TELEOP_ROS2 "Build only the teleop_ros2 ROS 2 reference integration (e.g. for Docker)" OFF)
option(BUILD_TESTING "Build unit tests" ON)
option(BUILD_OVXR_CAMERA_QUADS "Build optional application-owned OVXR camera quad support" OFF)
# Televiz (src/viz) needs Vulkan, the CUDA Toolkit, and glslangValidator.
# Only Vulkan and CUDA gate the default -- without them the machine cannot build
# viz at all, so a core-only source build still configures. glslangValidator is
Expand Down
28 changes: 28 additions & 0 deletions docs/source/getting_started/ovxr.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,34 @@ from the Isaac Capture wheel. These packages retain their own licenses:
CloudXR native libraries are bundled in Isaac Capture wheels and remain subject
to their separate NVIDIA license and CloudXR EULA acceptance.

Optional camera panels
----------------------

Camera picture-in-picture panels require the native camera helper. Follow the
source-build guide to configure a build for your application's Python version,
then enable camera support and rebuild the wheel:

.. code-block:: bash

cmake -S . -B build -DBUILD_OVXR_CAMERA_QUADS=ON
cmake --build build --target python_package python_stubs python_wheel --parallel

Install the generated wheel with its ``ovxr`` extra using the instructions
above. The extra requires CUDA 13 Python bindings for GPU camera output;
``BUILD_OVXR_CAMERA_QUADS`` controls whether the wheel contains the native helper.
The helper is disabled by default.

Use a CUDA 13-compatible NVIDIA driver (R580 or newer), meeting any stricter
requirements of the selected bindings and renderer. See the
`CUDA compatibility requirements <https://docs.nvidia.com/deploy/cuda-compatibility/minor-version-compatibility.html>`_.
Installing Python packages or a CUDA Toolkit does not update the host driver.

Install the Vulkan development SDK before configuring camera support. Linux
builds also require the CUDA Toolkit. CMake discovers these installed dependencies.
Use ``CUDAToolkit_ROOT`` to select a CUDA Toolkit installation and ``VULKAN_SDK``
to help locate a Vulkan SDK. The GPU driver and Vulkan runtime loader are required
on the host.

Use from another application
----------------------------

Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ ui = [
]
ovxr = [
"ovxr==0.1.0.5842",
"cuda-bindings>=13,<14",
]
retargeters = [
"dex-retargeting>=0.4.6,<0.6.0",
Expand Down
63 changes: 63 additions & 0 deletions scripts/check_camera_quad_wheel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

"""Check optional camera-helper delivery in an actual project wheel.

Run against wheels built with BUILD_OVXR_CAMERA_QUADS ON and OFF, including
ON -> OFF -> ON in the same build directory to detect stale packaged data.
"""

import argparse
import hashlib
import json
from pathlib import Path, PurePosixPath
from zipfile import ZipFile


def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("wheel", type=Path)
parser.add_argument(
"--camera-quads", action=argparse.BooleanOptionalAction, required=True
)
args = parser.parse_args()
prefix = "isaaccapture/ovxr_session_manager/openxr_layer/"
expected = {
prefix + "libXrApiLayer_isaacteleop_pip.so",
prefix + "XrApiLayer_isaacteleop_pip.json",
}
with ZipFile(args.wheel) as wheel:
members = {
name
for name in wheel.namelist()
if name.startswith(prefix) and not name.endswith("/")
}
wanted = expected if args.camera_quads else set()
if members != wanted:
raise RuntimeError(
f"Camera helper package differs: expected {sorted(wanted)}, got {sorted(members)}"
)
if args.camera_quads:
manifest = json.loads(
wheel.read(prefix + "XrApiLayer_isaacteleop_pip.json")
)
library = manifest["api_layer"]["library_path"]
if str(PurePosixPath(library)) != "libXrApiLayer_isaacteleop_pip.so":
raise RuntimeError(
f"Camera manifest selects an undeclared library: {library!r}"
)
print(
json.dumps(
{
"wheel": str(args.wheel),
"sha256": hashlib.sha256(args.wheel.read_bytes()).hexdigest(),
"camera_quads": args.camera_quads,
"result": "PASS",
},
indent=2,
)
)


if __name__ == "__main__":
main()
4 changes: 4 additions & 0 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ add_subdirectory(deviceio_session)
# Build MCAP library (depends on deviceio for DeviceIOSession and tracker interfaces)
add_subdirectory(mcap)

if(BUILD_OVXR_CAMERA_QUADS)
add_subdirectory(ovxr_pip_layer)
endif()

# CloudXR runtime helper (stages the vendored CloudXR runtime SDK bundle).
# Its pure-Python source lives in src/python/isaaccapture/cloudxr/, as does the
# retargeting engine's and the session manager's.
Expand Down
4 changes: 4 additions & 0 deletions src/core/ovxr_pip_layer/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

add_subdirectory(cpp)
10 changes: 10 additions & 0 deletions src/core/ovxr_pip_layer/XrApiLayer_isaacteleop_pip.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"file_format_version": "1.0.0",
"api_layer": {
"name": "XR_APILAYER_ISAACTELEOP_camera_quad",
"library_path": "./libXrApiLayer_isaacteleop_pip.so",
"api_version": "1.1",
"implementation_version": "1",
"description": "Isaac Teleop application-owned camera quad on the borrowed OVXR session"
}
}
42 changes: 42 additions & 0 deletions src/core/ovxr_pip_layer/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

find_package(Vulkan REQUIRED)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
find_package(CUDAToolkit REQUIRED)
endif()

add_library(ovxr_pip_layer SHARED pip_layer.cpp)
target_compile_features(ovxr_pip_layer PRIVATE cxx_std_20)
target_include_directories(ovxr_pip_layer PRIVATE
$<TARGET_PROPERTY:openxr_loader,INTERFACE_INCLUDE_DIRECTORIES>)
target_link_libraries(ovxr_pip_layer PRIVATE Vulkan::Vulkan log_bridge::log_bridge_core)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
# Keep static logger/fmt symbols private to the helper's existing C ABI.
set(_pip_exports "${CMAKE_CURRENT_BINARY_DIR}/ovxr_pip_exports.map")
file(GENERATE OUTPUT "${_pip_exports}"
CONTENT "{ global: isaacteleop_pip_*; local: *; };\n")
target_link_options(ovxr_pip_layer PRIVATE "-Wl,--version-script,${_pip_exports}")
set_property(TARGET ovxr_pip_layer APPEND PROPERTY LINK_DEPENDS "${_pip_exports}")
endif()
if(CUDAToolkit_FOUND AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_compile_definitions(ovxr_pip_layer PRIVATE ISAAC_TELEOP_PIP_CUDA)
target_link_libraries(ovxr_pip_layer PRIVATE CUDA::cudart_static)
endif()
set_target_properties(ovxr_pip_layer PROPERTIES
OUTPUT_NAME XrApiLayer_isaacteleop_pip
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/python_package/$<CONFIG>/isaaccapture/ovxr_session_manager/openxr_layer")

set(OVXR_PIP_LAYER_DIR
"${CMAKE_BINARY_DIR}/python_package/$<CONFIG>/isaaccapture/ovxr_session_manager/openxr_layer")
add_custom_command(
OUTPUT "${OVXR_PIP_LAYER_DIR}/XrApiLayer_isaacteleop_pip.json"
COMMAND ${CMAKE_COMMAND} -E make_directory "${OVXR_PIP_LAYER_DIR}"
COMMAND ${CMAKE_COMMAND} -E copy
"${PROJECT_SOURCE_DIR}/src/core/ovxr_pip_layer/XrApiLayer_isaacteleop_pip.json"
"${OVXR_PIP_LAYER_DIR}/XrApiLayer_isaacteleop_pip.json"
DEPENDS "${PROJECT_SOURCE_DIR}/src/core/ovxr_pip_layer/XrApiLayer_isaacteleop_pip.json")
set_source_files_properties("${OVXR_PIP_LAYER_DIR}/XrApiLayer_isaacteleop_pip.json"
PROPERTIES GENERATED TRUE HEADER_FILE_ONLY TRUE)
target_sources(ovxr_pip_layer PRIVATE "${OVXR_PIP_LAYER_DIR}/XrApiLayer_isaacteleop_pip.json")
add_library(ovxr_pip_layer::ovxr_pip_layer ALIAS ovxr_pip_layer)
Loading
Loading