The open source OpenXR runtime

Compare changes

Choose any two refs to compare.

Changed files
+6402 -2552
.gitlab-ci
cmake
doc
changes
auxiliary
compositor
drivers
ipc
misc_features
misc_fixes
state_trackers
xrt
scripts
src
xrt
auxiliary
compositor
drivers
include
ipc
state_trackers
targets
common
ctl
libmonado
sdl_test
service
service-lib
tracking
tests
+1 -2
.gitlab-ci/templates/.gitlab-ci.yml.jinja
··· 142 - .gitlab-ci/ci-cmake-build.sh {{- make_cmake_args(job.cmake_defines) }} 143 {%- if job.pahole %} 144 145 - - src/xrt/ipc/shared/proto.py src/xrt/ipc/shared/proto.json structs.txt 146 - mkdir -p "{{ job.name}}" 147 - - pahole --sizes --class_name file://structs.txt build/src/xrt/targets/openxr/libopenxr_monado.so > "{{ job.name}}/ipc-sizes.txt"{% endif %} 148 149 {#- gradle builds -#} 150 {%- elif "android" in job.name %}
··· 142 - .gitlab-ci/ci-cmake-build.sh {{- make_cmake_args(job.cmake_defines) }} 143 {%- if job.pahole %} 144 145 - mkdir -p "{{ job.name}}" 146 + - pahole --sizes --class_name file://build/ipc-structs.txt build/src/xrt/targets/openxr/libopenxr_monado.so > "{{ job.name}}/ipc-sizes.txt"{% endif %} 147 148 {#- gradle builds -#} 149 {%- elif "android" in job.name %}
+3 -3
.gitlab-ci/templates/include.win_containers.yml
··· 1 # {#- included by .gitlab-ci.yml.jinja #} 2 # {#- SPDX-License-Identifier: CC0-1.0 #} 3 - # {#- SPDX-FileCopyrightText: 2018-2022 Collabora, Ltd. and the Monado contributors #} 4 5 ### 6 # Windows container-related jobs (prep and usage) ··· 9 inherit: 10 default: false 11 variables: 12 - MONADO_WIN_BASE_TAG: "20250418.0" 13 - MONADO_WIN_MAIN_TAG: "20250418.0" 14 MONADO_BASE_IMAGE_PATH: "win2022/vs2022_base" 15 MONADO_MAIN_IMAGE_PATH: "win2022/vs2022" 16
··· 1 # {#- included by .gitlab-ci.yml.jinja #} 2 # {#- SPDX-License-Identifier: CC0-1.0 #} 3 + # {#- SPDX-FileCopyrightText: 2018-2025 Collabora, Ltd. and the Monado contributors #} 4 5 ### 6 # Windows container-related jobs (prep and usage) ··· 9 inherit: 10 default: false 11 variables: 12 + MONADO_WIN_BASE_TAG: "20251127.3" 13 + MONADO_WIN_MAIN_TAG: "20251127.3" 14 MONADO_BASE_IMAGE_PATH: "win2022/vs2022_base" 15 MONADO_MAIN_IMAGE_PATH: "win2022/vs2022" 16
+3 -3
.gitlab-ci/windows/monado_deps_build.ps1
··· 1 # Copyright 2019-2022, Mesa contributors 2 - # Copyright 2022, Collabora, Ltd. 3 # SPDX-License-Identifier: MIT 4 # Based on https://gitlab.freedesktop.org/mesa/mesa/-/blob/8396df5ad90aeb6ab2267811aba2187954562f81/.gitlab-ci/windows/mesa_deps_build.ps1 5 6 - $VulkanRTVersion = "1.3.283.0" 7 8 # Download new TLS certs from Windows Update 9 Get-Date ··· 28 Get-Date 29 Write-Host "Installing Vulkan runtime components" 30 $VulkanInstaller = "C:\VulkanRTInstaller.exe" 31 - Invoke-WebRequest -Uri "https://sdk.lunarg.com/sdk/download/$VulkanRTVersion/windows/VulkanRT-$VulkanRTVersion-Installer.exe" -OutFile "$VulkanInstaller" 32 Start-Process -NoNewWindow -Wait "$VulkanInstaller" -ArgumentList "/S" 33 if (!$?) { 34 Write-Host "Failed to install Vulkan runtime components"
··· 1 # Copyright 2019-2022, Mesa contributors 2 + # Copyright 2022-2025, Collabora, Ltd. 3 # SPDX-License-Identifier: MIT 4 # Based on https://gitlab.freedesktop.org/mesa/mesa/-/blob/8396df5ad90aeb6ab2267811aba2187954562f81/.gitlab-ci/windows/mesa_deps_build.ps1 5 6 + $VulkanRTVersion = "1.4.328.1" 7 8 # Download new TLS certs from Windows Update 9 Get-Date ··· 28 Get-Date 29 Write-Host "Installing Vulkan runtime components" 30 $VulkanInstaller = "C:\VulkanRTInstaller.exe" 31 + Invoke-WebRequest -Uri "https://sdk.lunarg.com/sdk/download/$VulkanRTVersion/windows/VulkanRT-X64-$VulkanRTVersion-Installer.exe" -OutFile "$VulkanInstaller" 32 Start-Process -NoNewWindow -Wait "$VulkanInstaller" -ArgumentList "/S" 33 if (!$?) { 34 Write-Host "Failed to install Vulkan runtime components"
+2 -2
.gitlab-ci/windows/monado_deps_vs2022.ps1
··· 1 # Copyright 2019-2022, Mesa contributors 2 - # Copyright 2022, Collabora, Ltd. 3 # SPDX-License-Identifier: MIT 4 # Based on https://gitlab.freedesktop.org/mesa/mesa/-/blob/8396df5ad90aeb6ab2267811aba2187954562f81/.gitlab-ci/windows/mesa_deps_vs2019.ps1 5 ··· 29 "--add" 30 "Microsoft.VisualStudio.Component.Windows10SDK" 31 "--add" 32 - "Microsoft.VisualStudio.Component.Windows11SDK.22000" 33 "--add" 34 "Component.Microsoft.Windows.CppWinRT" 35 "--add"
··· 1 # Copyright 2019-2022, Mesa contributors 2 + # Copyright 2022-2025, Collabora, Ltd. 3 # SPDX-License-Identifier: MIT 4 # Based on https://gitlab.freedesktop.org/mesa/mesa/-/blob/8396df5ad90aeb6ab2267811aba2187954562f81/.gitlab-ci/windows/mesa_deps_vs2019.ps1 5 ··· 29 "--add" 30 "Microsoft.VisualStudio.Component.Windows10SDK" 31 "--add" 32 + "Microsoft.VisualStudio.Component.Windows11SDK.26100" 33 "--add" 34 "Component.Microsoft.Windows.CppWinRT" 35 "--add"
+4 -6
.gitlab-ci.yml
··· 56 inherit: 57 default: false 58 variables: 59 - MONADO_WIN_BASE_TAG: "20250418.0" 60 - MONADO_WIN_MAIN_TAG: "20250418.0" 61 MONADO_BASE_IMAGE_PATH: "win2022/vs2022_base" 62 MONADO_MAIN_IMAGE_PATH: "win2022/vs2022" 63 ··· 369 370 - .gitlab-ci/prebuild.sh 371 - .gitlab-ci/ci-cmake-build.sh -DCMAKE_BUILD_TYPE=Debug -DXRT_HAVE_OPENCV=OFF 372 - - src/xrt/ipc/shared/proto.py src/xrt/ipc/shared/proto.json structs.txt 373 - mkdir -p "debian:cmake-no-opencv" 374 - - pahole --sizes --class_name file://structs.txt build/src/xrt/targets/openxr/libopenxr_monado.so > "debian:cmake-no-opencv/ipc-sizes.txt" 375 - cd build && ctest --output-on-failure 376 artifacts: 377 paths: ··· 408 409 - .gitlab-ci/prebuild.sh 410 - .gitlab-ci/ci-cmake-build.sh -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=.gitlab-ci/i386.cmake -DXRT_HAVE_OPENCV=OFF 411 - - src/xrt/ipc/shared/proto.py src/xrt/ipc/shared/proto.json structs.txt 412 - mkdir -p "debian:cmake:32bit" 413 - - pahole --sizes --class_name file://structs.txt build/src/xrt/targets/openxr/libopenxr_monado.so > "debian:cmake:32bit/ipc-sizes.txt" 414 - cd build && ctest --output-on-failure 415 artifacts: 416 paths:
··· 56 inherit: 57 default: false 58 variables: 59 + MONADO_WIN_BASE_TAG: "20251127.3" 60 + MONADO_WIN_MAIN_TAG: "20251127.3" 61 MONADO_BASE_IMAGE_PATH: "win2022/vs2022_base" 62 MONADO_MAIN_IMAGE_PATH: "win2022/vs2022" 63 ··· 369 370 - .gitlab-ci/prebuild.sh 371 - .gitlab-ci/ci-cmake-build.sh -DCMAKE_BUILD_TYPE=Debug -DXRT_HAVE_OPENCV=OFF 372 - mkdir -p "debian:cmake-no-opencv" 373 + - pahole --sizes --class_name file://build/ipc-structs.txt build/src/xrt/targets/openxr/libopenxr_monado.so > "debian:cmake-no-opencv/ipc-sizes.txt" 374 - cd build && ctest --output-on-failure 375 artifacts: 376 paths: ··· 407 408 - .gitlab-ci/prebuild.sh 409 - .gitlab-ci/ci-cmake-build.sh -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=.gitlab-ci/i386.cmake -DXRT_HAVE_OPENCV=OFF 410 - mkdir -p "debian:cmake:32bit" 411 + - pahole --sizes --class_name file://build/ipc-structs.txt build/src/xrt/targets/openxr/libopenxr_monado.so > "debian:cmake:32bit/ipc-sizes.txt" 412 - cd build && ctest --output-on-failure 413 artifacts: 414 paths:
+2
CMakeLists.txt
··· 58 include(OptionWithDeps) 59 include(SPIR-V) 60 include(GNUInstallDirs) 61 if(NOT GIT_DESC) 62 include(GetGitRevisionDescription) 63 git_describe(GIT_DESC "--always") ··· 367 option(XRT_FEATURE_OPENXR_ACTIVE_ACTION_SET_PRIORITY "Enable XR_EXT_active_action_set_priority" ON) 368 option(XRT_FEATURE_OPENXR_BODY_TRACKING_FB "Enable XR_FB_body_tracking" OFF) 369 option(XRT_FEATURE_OPENXR_DISPLAY_REFRESH_RATE "Enable XR_FB_display_refresh_rate" ON) 370 option(XRT_FEATURE_OPENXR_FACE_TRACKING2_FB "Enable XR_FB_face_tracking2" OFF) 371 option(XRT_FEATURE_OPENXR_FACIAL_TRACKING_HTC "Enable XR_HTC_facial_tracking" OFF) 372 option(XRT_FEATURE_OPENXR_FORCE_FEEDBACK_CURL "Enable XR_MNDX_force_feedback_curl" ON)
··· 58 include(OptionWithDeps) 59 include(SPIR-V) 60 include(GNUInstallDirs) 61 + include(MergeJSON) 62 if(NOT GIT_DESC) 63 include(GetGitRevisionDescription) 64 git_describe(GIT_DESC "--always") ··· 368 option(XRT_FEATURE_OPENXR_ACTIVE_ACTION_SET_PRIORITY "Enable XR_EXT_active_action_set_priority" ON) 369 option(XRT_FEATURE_OPENXR_BODY_TRACKING_FB "Enable XR_FB_body_tracking" OFF) 370 option(XRT_FEATURE_OPENXR_DISPLAY_REFRESH_RATE "Enable XR_FB_display_refresh_rate" ON) 371 + option(XRT_FEATURE_OPENXR_FACE_TRACKING_ANDROID "Enable XR_ANDROID_face_tracking" OFF) 372 option(XRT_FEATURE_OPENXR_FACE_TRACKING2_FB "Enable XR_FB_face_tracking2" OFF) 373 option(XRT_FEATURE_OPENXR_FACIAL_TRACKING_HTC "Enable XR_HTC_facial_tracking" OFF) 374 option(XRT_FEATURE_OPENXR_FORCE_FEEDBACK_CURL "Enable XR_MNDX_force_feedback_curl" ON)
+77
cmake/MergeJSON.cmake
···
··· 1 + # Copyright 2025, NVIDIA CORPORATION. 2 + # SPDX-License-Identifier: BSL-1.0 3 + 4 + # JSON merge function: merges multiple JSON files into one output file 5 + # 6 + # To use this function in your CMakeLists.txt: 7 + # include(${CMAKE_SOURCE_DIR}/scripts/CMakeLists.txt) 8 + # 9 + # Usage: 10 + # merge_json_files( 11 + # OUTPUT <output_file> 12 + # SOURCES <json_file1> <json_file2> ... 13 + # [ALLOW_OVERWRITE] 14 + # [IGNORE_SCHEMA] 15 + # ) 16 + # 17 + # Arguments: 18 + # OUTPUT - Output file path (required) 19 + # SOURCES - List of JSON files to merge (required) 20 + # ALLOW_OVERWRITE - Optional flag to allow duplicate keys 21 + # IGNORE_SCHEMA - Optional flag to ignore "$schema" field in output 22 + # 23 + # The function automatically: 24 + # - Sorts input files alphabetically for consistent results 25 + # - Tracks dependencies so output is regenerated when inputs change 26 + # - Errors on duplicate keys unless ALLOW_OVERWRITE is specified 27 + # 28 + # Example: 29 + # merge_json_files( 30 + # OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/merged.json" 31 + # SOURCES file1.json file2.json file3.json 32 + # IGNORE_SCHEMA 33 + # ) 34 + 35 + function(merge_json_files) 36 + set(options ALLOW_OVERWRITE IGNORE_SCHEMA) 37 + set(oneValueArgs OUTPUT) 38 + set(multiValueArgs SOURCES) 39 + 40 + cmake_parse_arguments( 41 + MERGE_JSON "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} 42 + ) 43 + 44 + if(NOT MERGE_JSON_OUTPUT) 45 + message(FATAL_ERROR "merge_json_files: OUTPUT argument is required") 46 + endif() 47 + 48 + if(NOT MERGE_JSON_SOURCES) 49 + message(FATAL_ERROR "merge_json_files: SOURCES argument is required") 50 + endif() 51 + 52 + # Build command arguments 53 + set(MERGE_COMMAND ${PYTHON_EXECUTABLE} 54 + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/merge_json.py -o 55 + "${MERGE_JSON_OUTPUT}" 56 + ) 57 + 58 + if(MERGE_JSON_ALLOW_OVERWRITE) 59 + list(APPEND MERGE_COMMAND --allow-overwrite) 60 + endif() 61 + 62 + if(MERGE_JSON_IGNORE_SCHEMA) 63 + list(APPEND MERGE_COMMAND --ignore-schema) 64 + endif() 65 + 66 + list(APPEND MERGE_COMMAND ${MERGE_JSON_SOURCES}) 67 + 68 + # Create custom command with proper dependencies 69 + add_custom_command( 70 + OUTPUT "${MERGE_JSON_OUTPUT}" 71 + COMMAND ${MERGE_COMMAND} 72 + VERBATIM 73 + DEPENDS ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/merge_json.py 74 + ${MERGE_JSON_SOURCES} 75 + COMMENT "Merging JSON files into ${MERGE_JSON_OUTPUT}" 76 + ) 77 + endfunction()
+2 -2
cmake/SPIR-V.cmake
··· 14 function(spirv_shaders ret) 15 set(options) 16 set(oneValueArgs SPIRV_VERSION) 17 - set(multiValueArgs SOURCES) 18 cmake_parse_arguments(_spirvshaders "${options}" "${oneValueArgs}" 19 "${multiValueArgs}" ${ARGN}) 20 ··· 30 add_custom_command( 31 OUTPUT ${HEADER} 32 COMMAND ${GLSLANGVALIDATOR_COMMAND} -V --target-env spirv${_spirvshaders_SPIRV_VERSION} ${GLSL} --vn ${IDENTIFIER} -o ${HEADER} 33 - DEPENDS ${GLSL}) 34 list(APPEND HEADERS ${HEADER}) 35 endforeach() 36
··· 14 function(spirv_shaders ret) 15 set(options) 16 set(oneValueArgs SPIRV_VERSION) 17 + set(multiValueArgs SOURCES DEPENDS) 18 cmake_parse_arguments(_spirvshaders "${options}" "${oneValueArgs}" 19 "${multiValueArgs}" ${ARGN}) 20 ··· 30 add_custom_command( 31 OUTPUT ${HEADER} 32 COMMAND ${GLSLANGVALIDATOR_COMMAND} -V --target-env spirv${_spirvshaders_SPIRV_VERSION} ${GLSL} --vn ${IDENTIFIER} -o ${HEADER} 33 + DEPENDS ${GLSL} ${_spirvshaders_DEPENDS}) 34 list(APPEND HEADERS ${HEADER}) 35 endforeach() 36
+139
cmake/merge_json.py
···
··· 1 + #!/usr/bin/env python3 2 + # Copyright 2025, NVIDIA CORPORATION. 3 + # SPDX-License-Identifier: BSL-1.0 4 + """ 5 + Helper script to merge multiple JSON files into one. 6 + 7 + This script merges the root JSON objects from multiple input files 8 + while preserving field ordering. Files are processed in sorted order 9 + to ensure consistent results. Fields are merged in the order they 10 + appear across the input files. 11 + """ 12 + 13 + import argparse 14 + import json 15 + import sys 16 + from pathlib import Path 17 + 18 + 19 + def merge_json_files(json_files, output_file, allow_overwrite=False, 20 + ignore_schema=False): 21 + """ 22 + Merge multiple JSON files into a single output file. 23 + 24 + Args: 25 + json_files: List of paths to JSON files to merge 26 + output_file: Path to the output file 27 + allow_overwrite: If True, allow later files to overwrite keys 28 + from earlier files 29 + ignore_schema: If True, ignore the "$schema" field in input files 30 + """ 31 + merged = {} 32 + 33 + # Sort files to ensure consistent ordering 34 + sorted_files = sorted(json_files) 35 + 36 + for json_file in sorted_files: 37 + try: 38 + with open(json_file, 'r', encoding='utf-8') as f: 39 + data = json.load(f) 40 + 41 + if not isinstance(data, dict): 42 + print(f"Error: {json_file} does not contain a JSON " 43 + f"object at root level", 44 + file=sys.stderr) 45 + sys.exit(1) 46 + 47 + # Merge while preserving order - check for duplicates 48 + for key, value in data.items(): 49 + if key == "$schema" and ignore_schema: 50 + continue 51 + if key in merged: 52 + if allow_overwrite: 53 + print(f"Warning: Key '{key}' from {json_file} " 54 + f"overwrites previous definition", 55 + file=sys.stderr) 56 + else: 57 + print(f"Error: Duplicate key '{key}' found in " 58 + f"{json_file}. Use --allow-overwrite to " 59 + f"permit overwriting.", 60 + file=sys.stderr) 61 + sys.exit(1) 62 + merged[key] = value 63 + 64 + except FileNotFoundError: 65 + print(f"Error: File not found: {json_file}", file=sys.stderr) 66 + sys.exit(1) 67 + except json.JSONDecodeError as e: 68 + print(f"Error: Failed to parse JSON from {json_file}: {e}", 69 + file=sys.stderr) 70 + sys.exit(1) 71 + except Exception as e: 72 + print(f"Error: Failed to read {json_file}: {e}", 73 + file=sys.stderr) 74 + sys.exit(1) 75 + 76 + 77 + # Write merged JSON to output file 78 + try: 79 + with open(output_file, 'w', encoding='utf-8') as f: 80 + json.dump(merged, f, indent='\t', ensure_ascii=False) 81 + f.write('\n') # Add trailing newline 82 + 83 + # Printing, left in if we want it in the future. 84 + if False: 85 + print(f"Successfully merged {len(json_files)} file(s) into " 86 + f"{output_file}") 87 + except Exception as e: 88 + print(f"Error: Failed to write to {output_file}: {e}", 89 + file=sys.stderr) 90 + sys.exit(1) 91 + 92 + 93 + def main(): 94 + parser = argparse.ArgumentParser( 95 + description='Merge multiple JSON files into one, preserving ' 96 + 'field ordering.', 97 + formatter_class=argparse.RawDescriptionHelpFormatter, 98 + epilog=""" 99 + Examples: 100 + %(prog)s -o merged.json file1.json file2.json file3.json 101 + %(prog)s -o output.json base.json overrides.json 102 + %(prog)s -o output.json --allow-overwrite base.json overrides.json 103 + %(prog)s -o output.json --ignore-schema schema.json data.json 104 + """ 105 + ) 106 + 107 + parser.add_argument('-o', '--output', 108 + required=True, 109 + metavar='OUTPUT', 110 + help='Output file path for the merged JSON') 111 + 112 + parser.add_argument('--allow-overwrite', 113 + action='store_true', 114 + help='Allow later files to overwrite duplicate ' 115 + 'keys from earlier files') 116 + 117 + parser.add_argument('--ignore-schema', 118 + action='store_true', 119 + help='Ignore the "$schema" field in input files') 120 + 121 + parser.add_argument('json_files', 122 + nargs='+', 123 + metavar='JSON_FILE', 124 + help='JSON files (will be sorted alphabetically)') 125 + 126 + args = parser.parse_args() 127 + 128 + # Validate that we have at least one input file 129 + if not args.json_files: 130 + print("Error: At least one JSON file must be provided", 131 + file=sys.stderr) 132 + sys.exit(1) 133 + 134 + merge_json_files(args.json_files, args.output, args.allow_overwrite, 135 + args.ignore_schema) 136 + 137 + 138 + if __name__ == '__main__': 139 + main()
+1 -1
doc/changes/auxiliary/mr.2398.md
··· 1 - u/system: Make the system re-usable by other code.
··· 1 + u/system: Make the system reusable by other code.
+1
doc/changes/auxiliary/mr.2613.md
···
··· 1 + a/math: Make relation history motion estimation API take in a single mutable relation
+2
doc/changes/compositor/mr.2596.md
··· 1 --- 2 - mr.2616 3 --- 4 5 c/compositor: Support compensation for rolling scanout HMDs
··· 1 --- 2 + - mr.2615 3 - mr.2616 4 + - mr.2620 5 --- 6 7 c/compositor: Support compensation for rolling scanout HMDs
+1
doc/changes/drivers/mr.2425.md
···
··· 1 + - steamvr_lh: generate hand tracking and palm pose from skeleton
+1
doc/changes/ipc/mr.2644.md
···
··· 1 + Bump IPC_MAX_CLIENTS from 8 to 32.
+2
doc/changes/misc_features/mr.2605.md
···
··· 1 + ### Added 2 + - oxr: Implements XR_ANDROID_face_tracking extension.
+1
doc/changes/misc_fixes/mr.2579.md
···
··· 1 + Fixes tests_aux_d3d_d3d11 failing in DuplicateHandle before importing
+1 -1
doc/changes/state_trackers/mr.2399.md
··· 1 - gui: Refactor GUI state tracker into a base that can be more easily re-used 2 and that brings in fewer dependencies.
··· 1 + gui: Refactor GUI state tracker into a base that can be more easily reused 2 and that brings in fewer dependencies.
+1
doc/changes/state_trackers/mr.2647.md
···
··· 1 + st/oxr: Report proper timestamps in XrEventDataSessionStateChanged instead of 0.
+3
doc/changes/xrt/mr.2612.1.md
···
··· 1 + Add @ref xrt_view_type argument to @ref xrt_device::get_view_poses function, 2 + this decouples the type of the view from the number. Letting us have different 3 + semantics for the same view count.
+4
doc/changes/xrt/mr.2612.2.md
···
··· 1 + Make it possible for the compositor to expose multiple view configurations types 2 + supported, and letting the compositor control the sizes for them separately. 3 + This change introduces @ref xrt_view_config and @ref xrt_view_config_properties 4 + which are added to @ref xrt_system_compositor_info.
+3
doc/changes/xrt/mr.2612.3.md
···
··· 1 + Change the interface to allow for late creation of the @ref xrt_system and other 2 + system level structs. Allowing the server to launch accept apps and decide 3 + which form factor or view configuration to support until a later date.
+3
doc/changes/xrt/mr.2633.md
···
··· 1 + Enable the use of [X_macro](https://en.wikipedia.org/wiki/X_macro) pattern with 2 + more the enums in the `xrt_defines.h` header. Code has been changed to use these 3 + as well reducing the amount of generated code needed.
+2 -1
scripts/generate_oxr_ext_support.py
··· 76 ['XR_EXT_samsung_odyssey_controller', 'XRT_FEATURE_OPENXR_INTERACTION_WINMR'], 77 ['XR_EXT_user_presence', 'XRT_FEATURE_OPENXR_USER_PRESENCE'], 78 # Vendor extensions, sorted alphabetically. 79 ['XR_BD_controller_interaction', 'XRT_FEATURE_OPENXR_INTERACTION_BYTEDANCE'], 80 ['XR_FB_body_tracking', 'XRT_FEATURE_OPENXR_BODY_TRACKING_FB'], 81 ['XR_FB_composition_layer_alpha_blend', 'XRT_FEATURE_OPENXR_LAYER_FB_ALPHA_BLEND'], ··· 105 ['XR_HTCX_vive_tracker_interaction', 'ALWAYS_DISABLED'], 106 ['XR_MNDX_ball_on_a_stick_controller', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'], 107 ['XR_MNDX_blubur_s1', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'], 108 - ['XR_MNDX_oculus_remote', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'], 109 ['XR_MNDX_egl_enable', 'XR_USE_PLATFORM_EGL'], 110 ['XR_MNDX_force_feedback_curl', 'XRT_FEATURE_OPENXR_FORCE_FEEDBACK_CURL'], 111 ['XR_MNDX_hydra', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'], 112 ['XR_MNDX_psvr2_interaction', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'], 113 ['XR_MNDX_system_buttons', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'], 114 ['XR_MNDX_xdev_space', 'XRT_FEATURE_OPENXR_XDEV_SPACE'],
··· 76 ['XR_EXT_samsung_odyssey_controller', 'XRT_FEATURE_OPENXR_INTERACTION_WINMR'], 77 ['XR_EXT_user_presence', 'XRT_FEATURE_OPENXR_USER_PRESENCE'], 78 # Vendor extensions, sorted alphabetically. 79 + ['XR_ANDROID_face_tracking', 'XRT_FEATURE_OPENXR_FACE_TRACKING_ANDROID'], 80 ['XR_BD_controller_interaction', 'XRT_FEATURE_OPENXR_INTERACTION_BYTEDANCE'], 81 ['XR_FB_body_tracking', 'XRT_FEATURE_OPENXR_BODY_TRACKING_FB'], 82 ['XR_FB_composition_layer_alpha_blend', 'XRT_FEATURE_OPENXR_LAYER_FB_ALPHA_BLEND'], ··· 106 ['XR_HTCX_vive_tracker_interaction', 'ALWAYS_DISABLED'], 107 ['XR_MNDX_ball_on_a_stick_controller', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'], 108 ['XR_MNDX_blubur_s1', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'], 109 ['XR_MNDX_egl_enable', 'XR_USE_PLATFORM_EGL'], 110 ['XR_MNDX_force_feedback_curl', 'XRT_FEATURE_OPENXR_FORCE_FEEDBACK_CURL'], 111 ['XR_MNDX_hydra', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'], 112 + ['XR_MNDX_oculus_remote', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'], 113 ['XR_MNDX_psvr2_interaction', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'], 114 ['XR_MNDX_system_buttons', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'], 115 ['XR_MNDX_xdev_space', 'XRT_FEATURE_OPENXR_XDEV_SPACE'],
+1
scripts/mapping.imp
··· 40 { symbol: ["XRT_FEATURE_OPENXR_BODY_TRACKING_FULL_BODY_META", "public", "\"xrt/xrt_config_build.h\"", "public"] }, 41 { symbol: ["XRT_FEATURE_OPENXR_DEBUG_UTILS", "public", "\"xrt/xrt_config_build.h\"", "public"] }, 42 { symbol: ["XRT_FEATURE_OPENXR_DISPLAY_REFRESH_RATE", "public", "\"xrt/xrt_config_build.h\"", "public"] }, 43 { symbol: ["XRT_FEATURE_OPENXR_FACE_TRACKING2_FB", "public", "\"xrt/xrt_config_build.h\"", "public"] }, 44 { symbol: ["XRT_FEATURE_OPENXR_FACIAL_TRACKING_HTC", "public", "\"xrt/xrt_config_build.h\"", "public"] }, 45 { symbol: ["XRT_FEATURE_OPENXR_FORCE_FEEDBACK_CURL", "public", "\"xrt/xrt_config_build.h\"", "public"] },
··· 40 { symbol: ["XRT_FEATURE_OPENXR_BODY_TRACKING_FULL_BODY_META", "public", "\"xrt/xrt_config_build.h\"", "public"] }, 41 { symbol: ["XRT_FEATURE_OPENXR_DEBUG_UTILS", "public", "\"xrt/xrt_config_build.h\"", "public"] }, 42 { symbol: ["XRT_FEATURE_OPENXR_DISPLAY_REFRESH_RATE", "public", "\"xrt/xrt_config_build.h\"", "public"] }, 43 + { symbol: ["XRT_FEATURE_OPENXR_FACE_TRACKING_ANDROID", "public", "\"xrt/xrt_config_build.h\"", "public"] }, 44 { symbol: ["XRT_FEATURE_OPENXR_FACE_TRACKING2_FB", "public", "\"xrt/xrt_config_build.h\"", "public"] }, 45 { symbol: ["XRT_FEATURE_OPENXR_FACIAL_TRACKING_HTC", "public", "\"xrt/xrt_config_build.h\"", "public"] }, 46 { symbol: ["XRT_FEATURE_OPENXR_FORCE_FEEDBACK_CURL", "public", "\"xrt/xrt_config_build.h\"", "public"] },
-17
src/xrt/auxiliary/bindings/b_generated_bindings_helpers.c.template
··· 14 15 // clang-format off 16 17 - const char * 18 - xrt_input_name_string(enum xrt_input_name input) { 19 - switch(input) 20 - { 21 - $xrt_input_name_string_switch 22 - } 23 - } 24 - 25 enum xrt_input_name 26 xrt_input_name_enum(const char *input) 27 { 28 $xrt_input_name_enum_content 29 - } 30 - 31 - const char * 32 - xrt_output_name_string(enum xrt_output_name output) 33 - { 34 - switch(output) 35 - { 36 - $xrt_output_name_string_switch 37 - } 38 } 39 40 enum xrt_output_name
··· 14 15 // clang-format off 16 17 enum xrt_input_name 18 xrt_input_name_enum(const char *input) 19 { 20 $xrt_input_name_enum_content 21 } 22 23 enum xrt_output_name
-6
src/xrt/auxiliary/bindings/b_generated_bindings_helpers.h
··· 17 extern "C" { 18 #endif 19 20 - const char * 21 - xrt_input_name_string(enum xrt_input_name input); 22 - 23 enum xrt_input_name 24 xrt_input_name_enum(const char *input); 25 - 26 - const char * 27 - xrt_output_name_string(enum xrt_output_name output); 28 29 enum xrt_output_name 30 xrt_output_name_enum(const char *output);
··· 17 extern "C" { 18 #endif 19 20 enum xrt_input_name 21 xrt_input_name_enum(const char *input); 22 23 enum xrt_output_name 24 xrt_output_name_enum(const char *output);
-12
src/xrt/auxiliary/bindings/bindings.py
··· 588 inputs.add("XRT_INPUT_HT_CONFORMING_RIGHT") 589 inputs.add("XRT_INPUT_GENERIC_TRACKER_POSE") 590 591 - xrt_input_name_string_switch = '\n'.join( 592 - [(f'\tcase {input}: return "{input}";') for input in sorted(inputs)] 593 - ) 594 - xrt_input_name_string_switch += (f'\n\tdefault: return "UNKNOWN";') 595 - 596 xrt_input_name_enum_content = '\n'.join( 597 [f'\tif(strcmp("{input}", input) == 0) return {input};' for input in sorted(inputs)] 598 ) 599 xrt_input_name_enum_content += f'\n\treturn XRT_INPUT_GENERIC_TRACKER_POSE;' 600 601 - xrt_output_name_string_switch = '\n'.join( 602 - [(f'\tcase {output}: return "{output}";') for output in sorted(outputs)] 603 - ) 604 - xrt_output_name_string_switch+= f'\n\tdefault: return "UNKNOWN";' 605 - 606 xrt_output_name_enum_content = '\n'.join( 607 [f'\tif(strcmp("{output}", output) == 0) return {output};' for output in sorted(outputs)] 608 ) ··· 614 615 with open(file, "w") as f: 616 filled = src.substitute( 617 - xrt_input_name_string_switch=xrt_input_name_string_switch, 618 xrt_input_name_enum_content=xrt_input_name_enum_content, 619 - xrt_output_name_string_switch=xrt_output_name_string_switch, 620 xrt_output_name_enum_content=xrt_output_name_enum_content 621 ) 622 f.write(filled)
··· 588 inputs.add("XRT_INPUT_HT_CONFORMING_RIGHT") 589 inputs.add("XRT_INPUT_GENERIC_TRACKER_POSE") 590 591 xrt_input_name_enum_content = '\n'.join( 592 [f'\tif(strcmp("{input}", input) == 0) return {input};' for input in sorted(inputs)] 593 ) 594 xrt_input_name_enum_content += f'\n\treturn XRT_INPUT_GENERIC_TRACKER_POSE;' 595 596 xrt_output_name_enum_content = '\n'.join( 597 [f'\tif(strcmp("{output}", output) == 0) return {output};' for output in sorted(outputs)] 598 ) ··· 604 605 with open(file, "w") as f: 606 filled = src.substitute( 607 xrt_input_name_enum_content=xrt_input_name_enum_content, 608 xrt_output_name_enum_content=xrt_output_name_enum_content 609 ) 610 f.write(filled)
-1
src/xrt/auxiliary/d3d/d3d_d3d12_allocator.hpp
··· 31 * @param xsci Swapchain create info: note that the format is assumed to be a DXGI_FORMAT (conversion to typeless is 32 * automatic) 33 * @param image_count The number of images to create. 34 - * @param keyed_mutex Whether to create images with a shared "keyed mutex" as well 35 * @param[out] out_images A vector that will be cleared and populated with the images. 36 * @param[out] out_handles A vector that will be cleared and populated with the corresponding native handles. 37 * @param[out] out_image_mem_size The image memory allocation size in bytes
··· 31 * @param xsci Swapchain create info: note that the format is assumed to be a DXGI_FORMAT (conversion to typeless is 32 * automatic) 33 * @param image_count The number of images to create. 34 * @param[out] out_images A vector that will be cleared and populated with the images. 35 * @param[out] out_handles A vector that will be cleared and populated with the corresponding native handles. 36 * @param[out] out_image_mem_size The image memory allocation size in bytes
+21
src/xrt/auxiliary/math/m_api.h
··· 18 19 #include "xrt/xrt_defines.h" 20 21 #ifdef __cplusplus 22 extern "C" { 23 #endif ··· 74 * @ingroup aux_math 75 */ 76 #define CLAMP(X, A, B) (MIN(MAX((X), (A)), (B))) 77 78 79 /*
··· 18 19 #include "xrt/xrt_defines.h" 20 21 + #include "math/m_mathinclude.h" 22 + 23 #ifdef __cplusplus 24 extern "C" { 25 #endif ··· 76 * @ingroup aux_math 77 */ 78 #define CLAMP(X, A, B) (MIN(MAX((X), (A)), (B))) 79 + 80 + /*! 81 + * Degrees to radians conversion. 82 + * 83 + * @ingroup aux_math 84 + */ 85 + // clang-format off 86 + // @todo: Remove the clang-format off/on when we move to a newer clang-format in CI. 87 + #define DEG_TO_RAD(DEG) ((DEG) * M_PI / 180.) 88 + // clang-format on 89 + 90 + /*! 91 + * Radians to degrees conversion. 92 + * 93 + * @ingroup aux_math 94 + */ 95 + // clang-format off 96 + #define RAD_TO_DEG(RAD) ((RAD) * 180.0 / M_PI) 97 + // clang-format on 98 99 100 /*
+37 -33
src/xrt/auxiliary/math/m_relation_history.cpp
··· 183 } 184 } 185 186 - bool 187 - m_relation_history_estimate_motion(struct m_relation_history *rh, 188 - const struct xrt_space_relation *in_relation, 189 - int64_t timestamp, 190 - struct xrt_space_relation *out_relation) 191 { 192 193 - int64_t last_time_ns; 194 - struct xrt_space_relation last_relation; 195 - if (!m_relation_history_get_latest(rh, &last_time_ns, &last_relation)) { 196 - return false; 197 - }; 198 199 - float dt = (float)time_ns_to_s(timestamp - last_time_ns); 200 201 - // Used to find out what values are valid in both the old relation and the new relation 202 - enum xrt_space_relation_flags tmp_flags = 203 - (enum xrt_space_relation_flags)(last_relation.relation_flags & in_relation->relation_flags); 204 - 205 - // Brevity 206 - enum xrt_space_relation_flags &outf = out_relation->relation_flags; 207 - 208 - 209 - if (tmp_flags & XRT_SPACE_RELATION_POSITION_VALID_BIT) { 210 - outf = (enum xrt_space_relation_flags)(outf | XRT_SPACE_RELATION_POSITION_VALID_BIT); 211 - outf = (enum xrt_space_relation_flags)(outf | XRT_SPACE_RELATION_POSITION_TRACKED_BIT); 212 213 - outf = (enum xrt_space_relation_flags)(outf | XRT_SPACE_RELATION_LINEAR_VELOCITY_VALID_BIT); 214 215 - out_relation->linear_velocity = (in_relation->pose.position - last_relation.pose.position) / dt; 216 } 217 218 - if (tmp_flags & XRT_SPACE_RELATION_ORIENTATION_VALID_BIT) { 219 - outf = (enum xrt_space_relation_flags)(outf | XRT_SPACE_RELATION_ORIENTATION_VALID_BIT); 220 - outf = (enum xrt_space_relation_flags)(outf | XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT); 221 222 - outf = (enum xrt_space_relation_flags)(outf | XRT_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT); 223 224 - math_quat_finite_difference(&last_relation.pose.orientation, &in_relation->pose.orientation, dt, 225 - &out_relation->angular_velocity); 226 } 227 228 - out_relation->pose = in_relation->pose; 229 - 230 - return true; 231 } 232 233 bool
··· 183 } 184 } 185 186 + static void 187 + m_relation_history_estimate_motion(struct xrt_space_relation const &old_relation, 188 + struct xrt_space_relation const &new_relation, 189 + float dt, 190 + struct xrt_vec3 &out_linear_velocity, 191 + struct xrt_vec3 &out_angular_velocity, 192 + enum xrt_space_relation_flags &out_flags) 193 { 194 + assert(dt != 0.0f); 195 196 + enum xrt_space_relation_flags shared_flags = 197 + (enum xrt_space_relation_flags)(old_relation.relation_flags & new_relation.relation_flags); 198 199 + // If both relations have position data, estimate linear velocity 200 + if (shared_flags & XRT_SPACE_RELATION_POSITION_VALID_BIT) { 201 + out_flags = (enum xrt_space_relation_flags)(out_flags | XRT_SPACE_RELATION_LINEAR_VELOCITY_VALID_BIT); 202 203 + out_linear_velocity = (new_relation.pose.position - old_relation.pose.position) / dt; 204 + } 205 206 + // If both relations have orientation data, estimate angular velocity 207 + if (shared_flags & XRT_SPACE_RELATION_ORIENTATION_VALID_BIT) { 208 + out_flags = (enum xrt_space_relation_flags)(out_flags | XRT_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT); 209 210 + math_quat_finite_difference(&old_relation.pose.orientation, &new_relation.pose.orientation, dt, 211 + &out_angular_velocity); 212 } 213 + } 214 + 215 + bool 216 + m_relation_history_push_with_motion_estimation(struct m_relation_history *rh, 217 + struct xrt_space_relation const *in_relation, 218 + int64_t timestamp) 219 + { 220 + assert((in_relation->relation_flags & XRT_SPACE_RELATION_LINEAR_VELOCITY_VALID_BIT) == 0); 221 + assert((in_relation->relation_flags & XRT_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT) == 0); 222 223 + struct xrt_space_relation final_relation = *in_relation; 224 225 + int64_t last_time_ns; 226 + struct xrt_space_relation last_relation; 227 + if (m_relation_history_get_latest(rh, &last_time_ns, &last_relation) && timestamp > last_time_ns) { 228 + float dt = (float)time_ns_to_s(timestamp - last_time_ns); 229 230 + m_relation_history_estimate_motion(last_relation, *in_relation, dt, final_relation.linear_velocity, 231 + final_relation.angular_velocity, final_relation.relation_flags); 232 } 233 234 + return m_relation_history_push(rh, &final_relation, timestamp); 235 } 236 237 bool
+15 -17
src/xrt/auxiliary/math/m_relation_history.h
··· 63 m_relation_history_push(struct m_relation_history *rh, struct xrt_space_relation const *in_relation, int64_t timestamp); 64 65 /*! 66 - * Interpolates or extrapolates to the desired timestamp. 67 * 68 - * Read-only operation - doesn't remove anything from the buffer or anything like that - you can call this as often as 69 - * you want. 70 * 71 * @public @memberof m_relation_history 72 */ 73 - enum m_relation_history_result 74 - m_relation_history_get(const struct m_relation_history *rh, 75 - int64_t at_timestamp_ns, 76 - struct xrt_space_relation *out_relation); 77 78 /*! 79 - * Estimates the movement (velocity and angular velocity) of a new relation based on 80 - * the latest relation found in the buffer (as returned by m_relation_history_get_latest). 81 * 82 - * Read-only on m_relation_history and in_relation. 83 - * Copies in_relation->pose to out_relation->pose, and writes new flags and linear/angular velocities to 84 - * out_relation->pose. OK to alias in_relation and out_relation. 85 * 86 * @public @memberof m_relation_history 87 */ 88 - bool 89 - m_relation_history_estimate_motion(struct m_relation_history *rh, 90 - const struct xrt_space_relation *in_relation, 91 - int64_t timestamp, 92 - struct xrt_space_relation *out_relation); 93 94 /*! 95 * Get the latest report in the buffer, if any.
··· 63 m_relation_history_push(struct m_relation_history *rh, struct xrt_space_relation const *in_relation, int64_t timestamp); 64 65 /*! 66 + * Pushes a new pose to the history, estimating linear and angular velocity based on the previous entry. 67 * 68 + * If the history is full, it will also pop a pose out of the other side of the buffer. 69 + * 70 + * @return false if the timestamp is earlier than the most recent timestamp already recorded 71 * 72 * @public @memberof m_relation_history 73 */ 74 + bool 75 + m_relation_history_push_with_motion_estimation(struct m_relation_history *rh, 76 + struct xrt_space_relation const *in_relation, 77 + int64_t timestamp); 78 79 /*! 80 + * Interpolates or extrapolates to the desired timestamp. 81 * 82 + * Read-only operation - doesn't remove anything from the buffer or anything like that - you can call this as often 83 + * as you want. 84 * 85 * @public @memberof m_relation_history 86 */ 87 + enum m_relation_history_result 88 + m_relation_history_get(const struct m_relation_history *rh, 89 + int64_t at_timestamp_ns, 90 + struct xrt_space_relation *out_relation); 91 92 /*! 93 * Get the latest report in the buffer, if any.
+4 -4
src/xrt/auxiliary/tracking/t_tracker_slam.cpp
··· 407 { 408 t.timing.enabled = false; 409 410 - u_var_add_ro_ftext(&t, "\n%s", "Tracker timing"); 411 412 // Setup toggle button 413 static const char *msg[2] = {"[OFF] Enable timing", "[ON] Disable timing"}; ··· 527 { 528 t.features.enabled = false; 529 530 - u_var_add_ro_ftext(&t, "\n%s", "Tracker features"); 531 532 // Setup toggle button 533 static const char *msg[2] = {"[OFF] Enable features info", "[ON] Disable features info"}; ··· 695 static void 696 gt_ui_setup(TrackerSlam &t) 697 { 698 - u_var_add_ro_ftext(&t, "\n%s", "Tracker groundtruth"); 699 t.gt.diff_ui.values.data = t.gt.diffs_mm; 700 t.gt.diff_ui.values.length = UI_GTDIFF_POSE_COUNT; 701 t.gt.diff_ui.values.index_ptr = &t.gt.diff_idx; ··· 1081 } 1082 1083 u_var_add_gui_header(&t, NULL, "Stats"); 1084 - u_var_add_ro_ftext(&t, "\n%s", "Record to CSV files"); 1085 u_var_add_bool(&t, &t.slam_traj_writer->enabled, "Record tracked trajectory"); 1086 u_var_add_bool(&t, &t.pred_traj_writer->enabled, "Record predicted trajectory"); 1087 u_var_add_bool(&t, &t.filt_traj_writer->enabled, "Record filtered trajectory");
··· 407 { 408 t.timing.enabled = false; 409 410 + u_var_add_ro_raw_text(&t, "\nTracker timing", "Tracker timing"); 411 412 // Setup toggle button 413 static const char *msg[2] = {"[OFF] Enable timing", "[ON] Disable timing"}; ··· 527 { 528 t.features.enabled = false; 529 530 + u_var_add_ro_raw_text(&t, "\nTracker features", "Tracker features"); 531 532 // Setup toggle button 533 static const char *msg[2] = {"[OFF] Enable features info", "[ON] Disable features info"}; ··· 695 static void 696 gt_ui_setup(TrackerSlam &t) 697 { 698 + u_var_add_ro_raw_text(&t, "\nTracker groundtruth", "Tracker groundtruth"); 699 t.gt.diff_ui.values.data = t.gt.diffs_mm; 700 t.gt.diff_ui.values.length = UI_GTDIFF_POSE_COUNT; 701 t.gt.diff_ui.values.index_ptr = &t.gt.diff_idx; ··· 1081 } 1082 1083 u_var_add_gui_header(&t, NULL, "Stats"); 1084 + u_var_add_ro_raw_text(&t, "\nRecord to CSV files", "Record to CSV files"); 1085 u_var_add_bool(&t, &t.slam_traj_writer->enabled, "Record tracked trajectory"); 1086 u_var_add_bool(&t, &t.pred_traj_writer->enabled, "Record predicted trajectory"); 1087 u_var_add_bool(&t, &t.filt_traj_writer->enabled, "Record filtered trajectory");
+2
src/xrt/auxiliary/util/CMakeLists.txt
··· 29 u_deque.h 30 u_device.c 31 u_device.h 32 u_distortion.c 33 u_distortion.h 34 u_distortion_mesh.c
··· 29 u_deque.h 30 u_device.c 31 u_device.h 32 + u_device_ni.c 33 + u_device_ni.h 34 u_distortion.c 35 u_distortion.h 36 u_distortion_mesh.c
+2 -1
src/xrt/auxiliary/util/u_config_json.c
··· 14 #include "util/u_file.h" 15 #include "util/u_json.h" 16 #include "util/u_debug.h" 17 18 #include "u_config_json.h" 19 ··· 504 505 cJSON_AddItemToObject(entry, "offset", make_pose(&overrides[i].offset)); 506 507 - const char *input_name_string = xrt_input_name_string(overrides[i].input_name); 508 cJSON_AddStringToObject(entry, "xrt_input_name", input_name_string); 509 510 cJSON_AddItemToArray(o, entry);
··· 14 #include "util/u_file.h" 15 #include "util/u_json.h" 16 #include "util/u_debug.h" 17 + #include "util/u_pretty_print.h" 18 19 #include "u_config_json.h" 20 ··· 505 506 cJSON_AddItemToObject(entry, "offset", make_pose(&overrides[i].offset)); 507 508 + const char *input_name_string = u_str_xrt_input_name(overrides[i].input_name); 509 cJSON_AddStringToObject(entry, "xrt_input_name", input_name_string); 510 511 cJSON_AddItemToArray(o, entry);
+51 -58
src/xrt/auxiliary/util/u_device.c
··· 11 */ 12 13 #include "util/u_device.h" 14 #include "util/u_logging.h" 15 #include "util/u_misc.h" 16 #include "util/u_visibility_mask.h" ··· 461 u_device_get_view_poses(struct xrt_device *xdev, 462 const struct xrt_vec3 *default_eye_relation, 463 int64_t at_timestamp_ns, 464 uint32_t view_count, 465 struct xrt_space_relation *out_head_relation, 466 struct xrt_fov *out_fovs, ··· 510 511 /* 512 * 513 - * Not implemented function helpers. 514 * 515 */ 516 517 - #define E(FN) U_LOG_E("Function " #FN " is not implemented for '%s'", xdev->str) 518 - 519 - xrt_result_t 520 - u_device_ni_get_hand_tracking(struct xrt_device *xdev, 521 - enum xrt_input_name name, 522 - int64_t desired_timestamp_ns, 523 - struct xrt_hand_joint_set *out_value, 524 - int64_t *out_timestamp_ns) 525 { 526 - E(get_hand_tracking); 527 - return XRT_ERROR_NOT_IMPLEMENTED; 528 - } 529 530 - xrt_result_t 531 - u_device_ni_set_output(struct xrt_device *xdev, enum xrt_output_name name, const struct xrt_output_value *value) 532 - { 533 - E(set_output); 534 - return XRT_ERROR_NOT_IMPLEMENTED; 535 - } 536 537 - xrt_result_t 538 - u_device_ni_get_view_poses(struct xrt_device *xdev, 539 - const struct xrt_vec3 *default_eye_relation, 540 - int64_t at_timestamp_ns, 541 - uint32_t view_count, 542 - struct xrt_space_relation *out_head_relation, 543 - struct xrt_fov *out_fovs, 544 - struct xrt_pose *out_poses) 545 - { 546 - E(get_view_poses); 547 - return XRT_ERROR_NOT_IMPLEMENTED; 548 - } 549 - 550 - xrt_result_t 551 - u_device_ni_compute_distortion( 552 - struct xrt_device *xdev, uint32_t view, float u, float v, struct xrt_uv_triplet *out_result) 553 - { 554 - E(compute_distortion); 555 - return XRT_ERROR_NOT_IMPLEMENTED; 556 - } 557 558 - xrt_result_t 559 - u_device_ni_get_visibility_mask(struct xrt_device *xdev, 560 - enum xrt_visibility_mask_type type, 561 - uint32_t view_index, 562 - struct xrt_visibility_mask **out_mask) 563 - { 564 - E(get_visibility_mask); 565 - return XRT_ERROR_NOT_IMPLEMENTED; 566 - } 567 568 - bool 569 - u_device_ni_is_form_factor_available(struct xrt_device *xdev, enum xrt_form_factor form_factor) 570 - { 571 - E(is_form_factor_available); 572 - return false; 573 - } 574 575 - xrt_result_t 576 - u_device_ni_get_battery_status(struct xrt_device *xdev, bool *out_present, bool *out_charging, float *out_charge) 577 - { 578 - E(get_battery_status); 579 - return XRT_ERROR_NOT_IMPLEMENTED; 580 }
··· 11 */ 12 13 #include "util/u_device.h" 14 + #include "util/u_device_ni.h" 15 #include "util/u_logging.h" 16 #include "util/u_misc.h" 17 #include "util/u_visibility_mask.h" ··· 462 u_device_get_view_poses(struct xrt_device *xdev, 463 const struct xrt_vec3 *default_eye_relation, 464 int64_t at_timestamp_ns, 465 + enum xrt_view_type view_type, 466 uint32_t view_count, 467 struct xrt_space_relation *out_head_relation, 468 struct xrt_fov *out_fovs, ··· 512 513 /* 514 * 515 + * Helper function to fill in defaults. 516 * 517 */ 518 519 + void 520 + u_device_populate_function_pointers(struct xrt_device *xdev, 521 + u_device_get_tracked_pose_function_t get_tracked_pose_fn, 522 + u_device_destroy_function_t destroy_fn) 523 { 524 + if (get_tracked_pose_fn == NULL) { 525 + U_LOG_E("Got get_tracked_pose_fn == NULL!"); 526 + assert(get_tracked_pose_fn != NULL); 527 + } 528 529 + if (destroy_fn == NULL) { 530 + U_LOG_E("Got destroy_fn == NULL!"); 531 + assert(destroy_fn != NULL); 532 + } 533 534 + /* 535 + * This must be implemented by the xrt_device, but not necessarily by 536 + * the driver so use noop version. 537 + */ 538 + xdev->update_inputs = u_device_noop_update_inputs; 539 540 + // This must be implemented by the driver. 541 + xdev->get_tracked_pose = get_tracked_pose_fn; 542 543 + /* 544 + * These are not required to be implemented by the xrt_device, so use 545 + * not implemented versions, and let the driver override if needed. 546 + */ 547 + xdev->get_hand_tracking = u_device_ni_get_hand_tracking; 548 + xdev->get_face_tracking = u_device_ni_get_face_tracking; 549 + xdev->get_body_skeleton = u_device_ni_get_body_skeleton; 550 + xdev->get_body_joints = u_device_ni_get_body_joints; 551 + xdev->reset_body_tracking_calibration_meta = u_device_ni_reset_body_tracking_calibration_meta; 552 + xdev->set_body_tracking_calibration_override_meta = u_device_ni_set_body_tracking_calibration_override_meta; 553 + xdev->set_output = u_device_ni_set_output; 554 + xdev->get_output_limits = u_device_ni_get_output_limits; 555 + xdev->get_presence = u_device_ni_get_presence; 556 + xdev->begin_plane_detection_ext = u_device_ni_begin_plane_detection_ext; 557 + xdev->destroy_plane_detection_ext = u_device_ni_destroy_plane_detection_ext; 558 + xdev->get_plane_detection_state_ext = u_device_ni_get_plane_detection_state_ext; 559 + xdev->get_plane_detections_ext = u_device_ni_get_plane_detections_ext; 560 + xdev->get_view_poses = u_device_ni_get_view_poses; 561 + xdev->compute_distortion = u_device_ni_compute_distortion; 562 + xdev->get_visibility_mask = u_device_ni_get_visibility_mask; 563 + xdev->ref_space_usage = u_device_ni_ref_space_usage; 564 + xdev->is_form_factor_available = u_device_ni_is_form_factor_available; 565 + xdev->get_battery_status = u_device_ni_get_battery_status; 566 + xdev->get_brightness = u_device_ni_get_brightness; 567 + xdev->set_brightness = u_device_ni_set_brightness; 568 + xdev->begin_feature = u_device_ni_begin_feature; 569 + xdev->end_feature = u_device_ni_end_feature; 570 571 + // This must be implemented by the driver. 572 + xdev->destroy = destroy_fn; 573 }
+22 -56
src/xrt/auxiliary/util/u_device.h
··· 171 u_device_get_view_poses(struct xrt_device *xdev, 172 const struct xrt_vec3 *default_eye_relation, 173 int64_t at_timestamp_ns, 174 uint32_t view_count, 175 struct xrt_space_relation *out_head_relation, 176 struct xrt_fov *out_fovs, ··· 205 206 /* 207 * 208 - * Not implemented function helpers. 209 * 210 */ 211 212 /*! 213 - * Not implemented function for @ref xrt_device::get_hand_tracking. 214 - * 215 - * @ingroup aux_util 216 - */ 217 - xrt_result_t 218 - u_device_ni_get_hand_tracking(struct xrt_device *xdev, 219 - enum xrt_input_name name, 220 - int64_t desired_timestamp_ns, 221 - struct xrt_hand_joint_set *out_value, 222 - int64_t *out_timestamp_ns); 223 - 224 - /*! 225 - * Not implemented function for @ref xrt_device::set_output. 226 - * 227 - * @ingroup aux_util 228 - */ 229 - xrt_result_t 230 - u_device_ni_set_output(struct xrt_device *xdev, enum xrt_output_name name, const struct xrt_output_value *value); 231 - 232 - /*! 233 - * Not implemented function for @ref xrt_device::get_view_poses. 234 - * 235 - * @ingroup aux_util 236 - */ 237 - xrt_result_t 238 - u_device_ni_get_view_poses(struct xrt_device *xdev, 239 - const struct xrt_vec3 *default_eye_relation, 240 - int64_t at_timestamp_ns, 241 - uint32_t view_count, 242 - struct xrt_space_relation *out_head_relation, 243 - struct xrt_fov *out_fovs, 244 - struct xrt_pose *out_poses); 245 - 246 - /*! 247 - * Not implemented function for @ref xrt_device::compute_distortion. 248 * 249 * @ingroup aux_util 250 */ 251 - xrt_result_t 252 - u_device_ni_compute_distortion( 253 - struct xrt_device *xdev, uint32_t view, float u, float v, struct xrt_uv_triplet *out_result); 254 255 /*! 256 - * Not implemented function for @ref xrt_device::get_visibility_mask. 257 * 258 * @ingroup aux_util 259 */ 260 - xrt_result_t 261 - u_device_ni_get_visibility_mask(struct xrt_device *xdev, 262 - enum xrt_visibility_mask_type type, 263 - uint32_t view_index, 264 - struct xrt_visibility_mask **out_mask); 265 266 /*! 267 - * Not implemented function for @ref xrt_device::is_form_factor_available. 268 * 269 - * @ingroup aux_util 270 - */ 271 - bool 272 - u_device_ni_is_form_factor_available(struct xrt_device *xdev, enum xrt_form_factor form_factor); 273 - 274 - /*! 275 - * Not implemented function for @ref xrt_device::get_battery_status. 276 * 277 * @ingroup aux_util 278 */ 279 - xrt_result_t 280 - u_device_ni_get_battery_status(struct xrt_device *xdev, bool *out_present, bool *out_charging, float *out_charge); 281 - 282 283 #ifdef __cplusplus 284 }
··· 171 u_device_get_view_poses(struct xrt_device *xdev, 172 const struct xrt_vec3 *default_eye_relation, 173 int64_t at_timestamp_ns, 174 + enum xrt_view_type view_type, 175 uint32_t view_count, 176 struct xrt_space_relation *out_head_relation, 177 struct xrt_fov *out_fovs, ··· 206 207 /* 208 * 209 + * Helper function to fill in defaults. 210 * 211 */ 212 213 /*! 214 + * Function pointer type for the device's get_tracked_pose function. 215 * 216 * @ingroup aux_util 217 */ 218 + typedef xrt_result_t (*u_device_get_tracked_pose_function_t)(struct xrt_device *xdev, 219 + const enum xrt_input_name name, 220 + const int64_t at_timestamp_ns, 221 + struct xrt_space_relation *const out_relation); 222 223 /*! 224 + * Function pointer type for the device's destroy function. 225 * 226 * @ingroup aux_util 227 */ 228 + typedef void (*u_device_destroy_function_t)(struct xrt_device *xdev); 229 230 /*! 231 + * Populate the device's function pointers with default implementations. 232 * 233 + * This function fills in all device function pointers with either noop or 234 + * not-implemented versions, allowing drivers to override only the functions 235 + * they actually implement. The exceptions are get_tracked_pose and destroy, 236 + * which must be implemented by the driver and are passed in as function 237 + * pointers, these must not be NULL. 238 * 239 + * @param[in,out] xdev The device to populate with default function pointers. 240 + * @param[in] get_tracked_pose_fn The function pointer to the device's get_tracked_pose function. 241 + * @param[in] destroy_fn The function pointer to the device's destroy function. 242 * @ingroup aux_util 243 */ 244 + void 245 + u_device_populate_function_pointers(struct xrt_device *xdev, 246 + u_device_get_tracked_pose_function_t get_tracked_pose_fn, 247 + u_device_destroy_function_t destroy_fn); 248 249 #ifdef __cplusplus 250 }
+217
src/xrt/auxiliary/util/u_device_ni.c
···
··· 1 + // Copyright 2019-2025, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief Not implemented function helpers for device drivers. 6 + * @author Jakob Bornecrantz <jakob@collabora.com> 7 + * @author Rylie Pavlik <rylie.pavlik@collabora.com> 8 + * @author Moshi Turner <moshiturner@protonmail.com> 9 + * @author Simon Zeni <simon.zeni@collabora.com> 10 + * @ingroup aux_util 11 + */ 12 + 13 + #include "util/u_device_ni.h" 14 + #include "util/u_logging.h" 15 + 16 + 17 + /* 18 + * 19 + * Not implemented function helpers. 20 + * 21 + */ 22 + 23 + #define E(FN) U_LOG_E("Function " #FN " is not implemented for '%s'", xdev->str) 24 + 25 + xrt_result_t 26 + u_device_ni_get_hand_tracking(struct xrt_device *xdev, 27 + enum xrt_input_name name, 28 + int64_t desired_timestamp_ns, 29 + struct xrt_hand_joint_set *out_value, 30 + int64_t *out_timestamp_ns) 31 + { 32 + E(get_hand_tracking); 33 + return XRT_ERROR_NOT_IMPLEMENTED; 34 + } 35 + 36 + xrt_result_t 37 + u_device_ni_get_face_tracking(struct xrt_device *xdev, 38 + enum xrt_input_name facial_expression_type, 39 + int64_t at_timestamp_ns, 40 + struct xrt_facial_expression_set *out_value) 41 + { 42 + E(get_face_tracking); 43 + return XRT_ERROR_NOT_IMPLEMENTED; 44 + } 45 + 46 + xrt_result_t 47 + u_device_ni_get_body_skeleton(struct xrt_device *xdev, 48 + enum xrt_input_name body_tracking_type, 49 + struct xrt_body_skeleton *out_value) 50 + { 51 + E(get_body_skeleton); 52 + return XRT_ERROR_NOT_IMPLEMENTED; 53 + } 54 + 55 + xrt_result_t 56 + u_device_ni_get_body_joints(struct xrt_device *xdev, 57 + enum xrt_input_name body_tracking_type, 58 + int64_t desired_timestamp_ns, 59 + struct xrt_body_joint_set *out_value) 60 + { 61 + E(get_body_joints); 62 + return XRT_ERROR_NOT_IMPLEMENTED; 63 + } 64 + 65 + xrt_result_t 66 + u_device_ni_reset_body_tracking_calibration_meta(struct xrt_device *xdev) 67 + { 68 + E(reset_body_tracking_calibration_meta); 69 + return XRT_ERROR_NOT_IMPLEMENTED; 70 + } 71 + 72 + xrt_result_t 73 + u_device_ni_set_body_tracking_calibration_override_meta(struct xrt_device *xdev, float new_body_height) 74 + { 75 + E(set_body_tracking_calibration_override_meta); 76 + return XRT_ERROR_NOT_IMPLEMENTED; 77 + } 78 + 79 + xrt_result_t 80 + u_device_ni_set_output(struct xrt_device *xdev, enum xrt_output_name name, const struct xrt_output_value *value) 81 + { 82 + E(set_output); 83 + return XRT_ERROR_NOT_IMPLEMENTED; 84 + } 85 + 86 + xrt_result_t 87 + u_device_ni_get_output_limits(struct xrt_device *xdev, struct xrt_output_limits *limits) 88 + { 89 + E(get_output_limits); 90 + return XRT_ERROR_NOT_IMPLEMENTED; 91 + } 92 + 93 + xrt_result_t 94 + u_device_ni_get_presence(struct xrt_device *xdev, bool *presence) 95 + { 96 + E(get_presence); 97 + return XRT_ERROR_NOT_IMPLEMENTED; 98 + } 99 + 100 + xrt_result_t 101 + u_device_ni_begin_plane_detection_ext(struct xrt_device *xdev, 102 + const struct xrt_plane_detector_begin_info_ext *begin_info, 103 + uint64_t plane_detection_id, 104 + uint64_t *out_plane_detection_id) 105 + { 106 + E(begin_plane_detection_ext); 107 + return XRT_ERROR_NOT_IMPLEMENTED; 108 + } 109 + 110 + xrt_result_t 111 + u_device_ni_destroy_plane_detection_ext(struct xrt_device *xdev, uint64_t plane_detection_id) 112 + { 113 + E(destroy_plane_detection_ext); 114 + return XRT_ERROR_NOT_IMPLEMENTED; 115 + } 116 + 117 + xrt_result_t 118 + u_device_ni_get_plane_detection_state_ext(struct xrt_device *xdev, 119 + uint64_t plane_detection_id, 120 + enum xrt_plane_detector_state_ext *out_state) 121 + { 122 + E(get_plane_detection_state_ext); 123 + return XRT_ERROR_NOT_IMPLEMENTED; 124 + } 125 + 126 + xrt_result_t 127 + u_device_ni_get_plane_detections_ext(struct xrt_device *xdev, 128 + uint64_t plane_detection_id, 129 + struct xrt_plane_detections_ext *out_detections) 130 + { 131 + E(get_plane_detections_ext); 132 + return XRT_ERROR_NOT_IMPLEMENTED; 133 + } 134 + 135 + xrt_result_t 136 + u_device_ni_get_view_poses(struct xrt_device *xdev, 137 + const struct xrt_vec3 *default_eye_relation, 138 + int64_t at_timestamp_ns, 139 + enum xrt_view_type view_type, 140 + uint32_t view_count, 141 + struct xrt_space_relation *out_head_relation, 142 + struct xrt_fov *out_fovs, 143 + struct xrt_pose *out_poses) 144 + { 145 + E(get_view_poses); 146 + return XRT_ERROR_NOT_IMPLEMENTED; 147 + } 148 + 149 + xrt_result_t 150 + u_device_ni_compute_distortion( 151 + struct xrt_device *xdev, uint32_t view, float u, float v, struct xrt_uv_triplet *out_result) 152 + { 153 + E(compute_distortion); 154 + return XRT_ERROR_NOT_IMPLEMENTED; 155 + } 156 + 157 + xrt_result_t 158 + u_device_ni_get_visibility_mask(struct xrt_device *xdev, 159 + enum xrt_visibility_mask_type type, 160 + uint32_t view_index, 161 + struct xrt_visibility_mask **out_mask) 162 + { 163 + E(get_visibility_mask); 164 + return XRT_ERROR_NOT_IMPLEMENTED; 165 + } 166 + 167 + xrt_result_t 168 + u_device_ni_ref_space_usage(struct xrt_device *xdev, 169 + enum xrt_reference_space_type type, 170 + enum xrt_input_name name, 171 + bool used) 172 + { 173 + E(ref_space_usage); 174 + return XRT_ERROR_NOT_IMPLEMENTED; 175 + } 176 + 177 + bool 178 + u_device_ni_is_form_factor_available(struct xrt_device *xdev, enum xrt_form_factor form_factor) 179 + { 180 + E(is_form_factor_available); 181 + return false; 182 + } 183 + 184 + xrt_result_t 185 + u_device_ni_get_battery_status(struct xrt_device *xdev, bool *out_present, bool *out_charging, float *out_charge) 186 + { 187 + E(get_battery_status); 188 + return XRT_ERROR_NOT_IMPLEMENTED; 189 + } 190 + 191 + xrt_result_t 192 + u_device_ni_get_brightness(struct xrt_device *xdev, float *out_brightness) 193 + { 194 + E(get_brightness); 195 + return XRT_ERROR_NOT_IMPLEMENTED; 196 + } 197 + 198 + xrt_result_t 199 + u_device_ni_set_brightness(struct xrt_device *xdev, float brightness, bool relative) 200 + { 201 + E(set_brightness); 202 + return XRT_ERROR_NOT_IMPLEMENTED; 203 + } 204 + 205 + xrt_result_t 206 + u_device_ni_begin_feature(struct xrt_device *xdev, enum xrt_device_feature_type type) 207 + { 208 + E(begin_feature); 209 + return XRT_ERROR_NOT_IMPLEMENTED; 210 + } 211 + 212 + xrt_result_t 213 + u_device_ni_end_feature(struct xrt_device *xdev, enum xrt_device_feature_type type) 214 + { 215 + E(end_feature); 216 + return XRT_ERROR_NOT_IMPLEMENTED; 217 + }
+249
src/xrt/auxiliary/util/u_device_ni.h
···
··· 1 + // Copyright 2019-2025, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief Not implemented function helpers for device drivers. 6 + * @author Jakob Bornecrantz <jakob@collabora.com> 7 + * @author Rylie Pavlik <rylie.pavlik@collabora.com> 8 + * @author Moshi Turner <moshiturner@protonmail.com> 9 + * @author Simon Zeni <simon.zeni@collabora.com> 10 + * @ingroup aux_util 11 + */ 12 + 13 + #pragma once 14 + 15 + #include "xrt/xrt_compiler.h" 16 + #include "xrt/xrt_device.h" 17 + 18 + #ifdef __cplusplus 19 + extern "C" { 20 + #endif 21 + 22 + 23 + /* 24 + * 25 + * Not implemented function helpers. 26 + * 27 + */ 28 + 29 + /*! 30 + * Not implemented function for @ref xrt_device::get_hand_tracking. 31 + * 32 + * @ingroup aux_util 33 + */ 34 + xrt_result_t 35 + u_device_ni_get_hand_tracking(struct xrt_device *xdev, 36 + enum xrt_input_name name, 37 + int64_t desired_timestamp_ns, 38 + struct xrt_hand_joint_set *out_value, 39 + int64_t *out_timestamp_ns); 40 + 41 + /*! 42 + * Not implemented function for @ref xrt_device::get_face_tracking. 43 + * 44 + * @ingroup aux_util 45 + */ 46 + xrt_result_t 47 + u_device_ni_get_face_tracking(struct xrt_device *xdev, 48 + enum xrt_input_name facial_expression_type, 49 + int64_t at_timestamp_ns, 50 + struct xrt_facial_expression_set *out_value); 51 + 52 + /*! 53 + * Not implemented function for @ref xrt_device::get_body_skeleton. 54 + * 55 + * @ingroup aux_util 56 + */ 57 + xrt_result_t 58 + u_device_ni_get_body_skeleton(struct xrt_device *xdev, 59 + enum xrt_input_name body_tracking_type, 60 + struct xrt_body_skeleton *out_value); 61 + 62 + /*! 63 + * Not implemented function for @ref xrt_device::get_body_joints. 64 + * 65 + * @ingroup aux_util 66 + */ 67 + xrt_result_t 68 + u_device_ni_get_body_joints(struct xrt_device *xdev, 69 + enum xrt_input_name body_tracking_type, 70 + int64_t desired_timestamp_ns, 71 + struct xrt_body_joint_set *out_value); 72 + 73 + /*! 74 + * Not implemented function for @ref xrt_device::reset_body_tracking_calibration_meta. 75 + * 76 + * @ingroup aux_util 77 + */ 78 + xrt_result_t 79 + u_device_ni_reset_body_tracking_calibration_meta(struct xrt_device *xdev); 80 + 81 + /*! 82 + * Not implemented function for @ref xrt_device::set_body_tracking_calibration_override_meta. 83 + * 84 + * @ingroup aux_util 85 + */ 86 + xrt_result_t 87 + u_device_ni_set_body_tracking_calibration_override_meta(struct xrt_device *xdev, float new_body_height); 88 + 89 + /*! 90 + * Not implemented function for @ref xrt_device::set_output. 91 + * 92 + * @ingroup aux_util 93 + */ 94 + xrt_result_t 95 + u_device_ni_set_output(struct xrt_device *xdev, enum xrt_output_name name, const struct xrt_output_value *value); 96 + 97 + /*! 98 + * Not implemented function for @ref xrt_device::get_output_limits. 99 + * 100 + * @ingroup aux_util 101 + */ 102 + xrt_result_t 103 + u_device_ni_get_output_limits(struct xrt_device *xdev, struct xrt_output_limits *limits); 104 + 105 + /*! 106 + * Not implemented function for @ref xrt_device::get_presence. 107 + * 108 + * @ingroup aux_util 109 + */ 110 + xrt_result_t 111 + u_device_ni_get_presence(struct xrt_device *xdev, bool *presence); 112 + 113 + /*! 114 + * Not implemented function for @ref xrt_device::begin_plane_detection_ext. 115 + * 116 + * @ingroup aux_util 117 + */ 118 + xrt_result_t 119 + u_device_ni_begin_plane_detection_ext(struct xrt_device *xdev, 120 + const struct xrt_plane_detector_begin_info_ext *begin_info, 121 + uint64_t plane_detection_id, 122 + uint64_t *out_plane_detection_id); 123 + 124 + /*! 125 + * Not implemented function for @ref xrt_device::destroy_plane_detection_ext. 126 + * 127 + * @ingroup aux_util 128 + */ 129 + xrt_result_t 130 + u_device_ni_destroy_plane_detection_ext(struct xrt_device *xdev, uint64_t plane_detection_id); 131 + 132 + /*! 133 + * Not implemented function for @ref xrt_device::get_plane_detection_state_ext. 134 + * 135 + * @ingroup aux_util 136 + */ 137 + xrt_result_t 138 + u_device_ni_get_plane_detection_state_ext(struct xrt_device *xdev, 139 + uint64_t plane_detection_id, 140 + enum xrt_plane_detector_state_ext *out_state); 141 + 142 + /*! 143 + * Not implemented function for @ref xrt_device::get_plane_detections_ext. 144 + * 145 + * @ingroup aux_util 146 + */ 147 + xrt_result_t 148 + u_device_ni_get_plane_detections_ext(struct xrt_device *xdev, 149 + uint64_t plane_detection_id, 150 + struct xrt_plane_detections_ext *out_detections); 151 + 152 + /*! 153 + * Not implemented function for @ref xrt_device::get_view_poses. 154 + * 155 + * @ingroup aux_util 156 + */ 157 + xrt_result_t 158 + u_device_ni_get_view_poses(struct xrt_device *xdev, 159 + const struct xrt_vec3 *default_eye_relation, 160 + int64_t at_timestamp_ns, 161 + enum xrt_view_type view_type, 162 + uint32_t view_count, 163 + struct xrt_space_relation *out_head_relation, 164 + struct xrt_fov *out_fovs, 165 + struct xrt_pose *out_poses); 166 + 167 + /*! 168 + * Not implemented function for @ref xrt_device::compute_distortion. 169 + * 170 + * @ingroup aux_util 171 + */ 172 + xrt_result_t 173 + u_device_ni_compute_distortion( 174 + struct xrt_device *xdev, uint32_t view, float u, float v, struct xrt_uv_triplet *out_result); 175 + 176 + /*! 177 + * Not implemented function for @ref xrt_device::get_visibility_mask. 178 + * 179 + * @ingroup aux_util 180 + */ 181 + xrt_result_t 182 + u_device_ni_get_visibility_mask(struct xrt_device *xdev, 183 + enum xrt_visibility_mask_type type, 184 + uint32_t view_index, 185 + struct xrt_visibility_mask **out_mask); 186 + 187 + /*! 188 + * Not implemented function for @ref xrt_device::ref_space_usage. 189 + * 190 + * @ingroup aux_util 191 + */ 192 + xrt_result_t 193 + u_device_ni_ref_space_usage(struct xrt_device *xdev, 194 + enum xrt_reference_space_type type, 195 + enum xrt_input_name name, 196 + bool used); 197 + 198 + /*! 199 + * Not implemented function for @ref xrt_device::is_form_factor_available. 200 + * 201 + * @ingroup aux_util 202 + */ 203 + bool 204 + u_device_ni_is_form_factor_available(struct xrt_device *xdev, enum xrt_form_factor form_factor); 205 + 206 + /*! 207 + * Not implemented function for @ref xrt_device::get_battery_status. 208 + * 209 + * @ingroup aux_util 210 + */ 211 + xrt_result_t 212 + u_device_ni_get_battery_status(struct xrt_device *xdev, bool *out_present, bool *out_charging, float *out_charge); 213 + 214 + /*! 215 + * Not implemented function for @ref xrt_device::get_brightness. 216 + * 217 + * @ingroup aux_util 218 + */ 219 + xrt_result_t 220 + u_device_ni_get_brightness(struct xrt_device *xdev, float *out_brightness); 221 + 222 + /*! 223 + * Not implemented function for @ref xrt_device::set_brightness. 224 + * 225 + * @ingroup aux_util 226 + */ 227 + xrt_result_t 228 + u_device_ni_set_brightness(struct xrt_device *xdev, float brightness, bool relative); 229 + 230 + /*! 231 + * Not implemented function for @ref xrt_device::begin_feature. 232 + * 233 + * @ingroup aux_util 234 + */ 235 + xrt_result_t 236 + u_device_ni_begin_feature(struct xrt_device *xdev, enum xrt_device_feature_type type); 237 + 238 + /*! 239 + * Not implemented function for @ref xrt_device::end_feature. 240 + * 241 + * @ingroup aux_util 242 + */ 243 + xrt_result_t 244 + u_device_ni_end_feature(struct xrt_device *xdev, enum xrt_device_feature_type type); 245 + 246 + 247 + #ifdef __cplusplus 248 + } 249 + #endif
-2
src/xrt/auxiliary/util/u_hand_simulation.c
··· 32 struct xrt_quat q[HAND_SIM_NUM_FINGERS][HAND_SIM_NUM_ORIENTATIONS_IN_FINGER]; 33 }; 34 35 - #define DEG_TO_RAD(DEG) (DEG * M_PI / 180.) 36 - 37 // For debugging. 38 #if 0 39 #include <iostream>
··· 32 struct xrt_quat q[HAND_SIM_NUM_FINGERS][HAND_SIM_NUM_ORIENTATIONS_IN_FINGER]; 33 }; 34 35 // For debugging. 36 #if 0 37 #include <iostream>
-2
src/xrt/auxiliary/util/u_hand_tracking.c
··· 20 #include "util/u_time.h" 21 22 23 - #define DEG_TO_RAD(DEG) (DEG * M_PI / 180.) 24 - 25 bool 26 u_hand_joint_is_metacarpal(enum xrt_hand_joint joint) 27 {
··· 20 #include "util/u_time.h" 21 22 23 bool 24 u_hand_joint_is_metacarpal(enum xrt_hand_joint joint) 25 {
+61 -2
src/xrt/auxiliary/util/u_logging.c
··· 1 // Copyright 2019-2025, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 74 75 /* 76 * 77 * Logging sink. 78 * 79 */ ··· 294 int ret = 0; 295 296 #ifdef XRT_FEATURE_COLOR_LOG 297 - if (isatty(STDERR_FILENO)) { 298 ret = print_prefix_color(func, level, buf, remaining); 299 } else { 300 ret = print_prefix_mono(func, level, buf, remaining); ··· 407 OutputDebugStringA(storage); 408 #endif 409 410 - fwrite(storage, printed, 1, stderr); 411 412 #else 413 #error "Port needed for logging function" ··· 454 u_log(file, line, calling_fn, level, "%s", sink.buffer); 455 } 456 457 void 458 u_log(const char *file, int line, const char *func, enum u_logging_level level, const char *format, ...) 459 { 460 va_list args; 461 va_start(args, format); 462 DISPATCH_SINK(file, line, func, level, format, args); 463 do_print(file, line, func, level, format, args); ··· 474 ...) 475 { 476 va_list args; 477 va_start(args, format); 478 DISPATCH_SINK(file, line, func, level, format, args); 479 do_print(file, line, func, level, format, args);
··· 1 // Copyright 2019-2025, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 75 76 /* 77 * 78 + * Logging file code. 79 + * 80 + */ 81 + 82 + static FILE *g_log_file = NULL; 83 + 84 + void 85 + u_log_set_output_file(const char *filename) 86 + { 87 + // While not thread safe, this function is externally synchronized. 88 + if (g_log_file != NULL) { 89 + FILE *tmp = g_log_file; 90 + g_log_file = NULL; 91 + 92 + fflush(tmp); 93 + fclose(tmp); 94 + tmp = NULL; 95 + } 96 + 97 + if (filename == NULL) { 98 + return; // Turning off file logging. 99 + } 100 + 101 + g_log_file = fopen(filename, "w"); 102 + if (g_log_file == NULL) { 103 + U_LOG_E("Failed to open '%s'", filename); 104 + } 105 + } 106 + 107 + 108 + /* 109 + * 110 * Logging sink. 111 * 112 */ ··· 327 int ret = 0; 328 329 #ifdef XRT_FEATURE_COLOR_LOG 330 + if (g_log_file == NULL && isatty(STDERR_FILENO)) { 331 ret = print_prefix_color(func, level, buf, remaining); 332 } else { 333 ret = print_prefix_mono(func, level, buf, remaining); ··· 440 OutputDebugStringA(storage); 441 #endif 442 443 + FILE *output = g_log_file != NULL ? g_log_file : stderr; 444 + fwrite(storage, printed, 1, output); 445 + 446 + #if defined(XRT_OS_WINDOWS) 447 + /* 448 + * Windows like to buffer messages, call flush here to make sure all 449 + * logs gets written out in case of sudden exits and crashes. 450 + */ 451 + fflush(output); 452 + #endif 453 454 #else 455 #error "Port needed for logging function" ··· 496 u_log(file, line, calling_fn, level, "%s", sink.buffer); 497 } 498 499 + static u_log_filter_func_t g_filter = NULL; 500 + 501 + void 502 + u_log_set_filter(u_log_filter_func_t filter) 503 + { 504 + g_filter = filter; 505 + } 506 + 507 void 508 u_log(const char *file, int line, const char *func, enum u_logging_level level, const char *format, ...) 509 { 510 va_list args; 511 + // Check filter first 512 + if (g_filter != NULL && !g_filter(file, line, func, level)) { 513 + return; // Skip this message 514 + } 515 + 516 va_start(args, format); 517 DISPATCH_SINK(file, line, func, level, format, args); 518 do_print(file, line, func, level, format, args); ··· 529 ...) 530 { 531 va_list args; 532 + // Check filter first 533 + if (g_filter != NULL && !g_filter(file, line, func, level)) { 534 + return; // Skip this message 535 + } 536 va_start(args, format); 537 DISPATCH_SINK(file, line, func, level, format, args); 538 do_print(file, line, func, level, format, args);
+32
src/xrt/auxiliary/util/u_logging.h
··· 1 // Copyright 2020-2025, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 68 const char *format, 69 va_list args, 70 void *data); 71 72 /*! 73 * For places where you really want printf, prints a new-line. ··· 270 u_log_get_global_level(void); 271 272 /*! 273 * @brief Main non-device-related log implementation function: do not call directly, use a macro that wraps it. 274 * 275 * This function always logs: level is used for printing or passed to native logging functions. ··· 377 const char *calling_fn, 378 xrt_result_t xret, 379 const char *called_fn); 380 381 /*! 382 * @}
··· 1 // Copyright 2020-2025, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 69 const char *format, 70 va_list args, 71 void *data); 72 + 73 + /*! 74 + * Function typedef for filtering log messages. 75 + * 76 + * @param file Source file name associated with a message. 77 + * @param line Source file line associated with a message. 78 + * @param func Function name associated with a message. 79 + * @param level Message level: used for formatting or forwarding to native log functions. 80 + * @return true if message should be logged, false to filter it out. 81 + */ 82 + typedef bool (*u_log_filter_func_t)(const char *file, int line, const char *func, enum u_logging_level level); 83 84 /*! 85 * For places where you really want printf, prints a new-line. ··· 282 u_log_get_global_level(void); 283 284 /*! 285 + * Sets the output file for the logging instead of stderr, this function is 286 + * externally synchronized with ALL other logging functions. Which means do not 287 + * call any other logging function from different threads during a call to this 288 + * function. Also to avoid leaks call this function with NULL to close the 289 + * internally managed FILE object. 290 + * 291 + * WANRING THIS FUNCTION IS EXTERNALLY SYNCHRONIZED WITH ALL OTHER FUNCTIONS. 292 + */ 293 + void 294 + u_log_set_output_file(const char *filename); 295 + 296 + /*! 297 * @brief Main non-device-related log implementation function: do not call directly, use a macro that wraps it. 298 * 299 * This function always logs: level is used for printing or passed to native logging functions. ··· 401 const char *calling_fn, 402 xrt_result_t xret, 403 const char *called_fn); 404 + 405 + /*! 406 + * @brief Add function to set the filter 407 + * 408 + * @param filter Filter function to set 409 + */ 410 + void 411 + u_log_set_filter(u_log_filter_func_t filter); 412 413 /*! 414 * @}
+86 -52
src/xrt/auxiliary/util/u_pretty_print.c
··· 1 // Copyright 2022-2024, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 39 case XRT_INPUT_TYPE_HAND_TRACKING: return "HAND_TRACKING"; 40 case XRT_INPUT_TYPE_FACE_TRACKING: return "FACE_TRACKING"; 41 case XRT_INPUT_TYPE_BODY_TRACKING: return "BODY_TRACKING"; 42 - default: return "<UNKNOWN>"; 43 } 44 } 45 46 void ··· 70 71 /* 72 * 73 * 'Exported' functions. 74 * 75 */ ··· 112 void 113 u_pp_xrt_input_name(struct u_pp_delegate dg, enum xrt_input_name name) 114 { 115 - #define XRT_INPUT_LIST_TO_CASE(NAME, _) \ 116 - case NAME: DG(#NAME); return; 117 - 118 - switch (name) { 119 - XRT_INPUT_LIST(XRT_INPUT_LIST_TO_CASE) 120 } 121 122 - #undef XRT_INPUT_LIST_TO_CASE 123 - 124 /* 125 - * No default case so we get warnings of missing entries. 126 * Invalid values handled below. 127 */ 128 ··· 136 void 137 u_pp_xrt_output_name(struct u_pp_delegate dg, enum xrt_output_name name) 138 { 139 - #define XRT_OUTPUT_CASE(NAME) \ 140 - case NAME: DG(#NAME); return 141 142 - switch (name) { 143 - XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_SIMPLE_VIBRATION); 144 - XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_PSMV_RUMBLE_VIBRATION); 145 - XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_INDEX_HAPTIC); 146 - XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_VIVE_HAPTIC); 147 - XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_WMR_HAPTIC); 148 149 - XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_XBOX_HAPTIC_LEFT); 150 - XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_XBOX_HAPTIC_RIGHT); 151 - XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_XBOX_HAPTIC_LEFT_TRIGGER); 152 - XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_XBOX_HAPTIC_RIGHT_TRIGGER); 153 154 - XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_TOUCH_HAPTIC); 155 - 156 - XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_FORCE_FEEDBACK_LEFT); 157 - XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_FORCE_FEEDBACK_RIGHT); 158 - 159 - XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_G2_CONTROLLER_HAPTIC); 160 - XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_ODYSSEY_CONTROLLER_HAPTIC); 161 - XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_ML2_CONTROLLER_VIBRATION); 162 - 163 - XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_PSSENSE_VIBRATION); 164 - XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_PSSENSE_TRIGGER_FEEDBACK); 165 - 166 - XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_VIVE_TRACKER_HAPTIC); 167 - 168 - XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_OPPO_MR_HAPTIC); 169 - 170 - XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_PICO_NEO3_HAPTIC); 171 - XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_PICO4_HAPTIC); 172 - 173 - XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_VIVE_COSMOS_HAPTIC); 174 - XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_VIVE_FOCUS3_HAPTIC); 175 - 176 - XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_TOUCH_PRO_HAPTIC); 177 - XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_TOUCH_PRO_HAPTIC_TRIGGER); 178 - XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_TOUCH_PRO_HAPTIC_THUMB); 179 - XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_TOUCH_PLUS_HAPTIC); 180 - 181 - XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_PSVR2_HAPTIC); 182 - } 183 - 184 - #undef XRT_OUTPUT_CASE 185 } 186 187 void ··· 234 case XRT_OPERATION_CANCELLED: DG("XRT_OPERATION_CANCELLED"); return; 235 case XRT_ERROR_FUTURE_RESULT_NOT_READY: DG("XRT_ERROR_FUTURE_RESULT_NOT_READY"); return; 236 case XRT_ERROR_FUTURE_ALREADY_COMPLETE: DG("XRT_ERROR_FUTURE_ALREADY_COMPLETE"); return; 237 } 238 // clang-format on 239
··· 1 // Copyright 2022-2024, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 40 case XRT_INPUT_TYPE_HAND_TRACKING: return "HAND_TRACKING"; 41 case XRT_INPUT_TYPE_FACE_TRACKING: return "FACE_TRACKING"; 42 case XRT_INPUT_TYPE_BODY_TRACKING: return "BODY_TRACKING"; 43 } 44 + 45 + return "<UNKNOWN>"; 46 + } 47 + 48 + const char * 49 + get_xrt_output_type_short_str(enum xrt_output_type type) 50 + { 51 + switch (type) { 52 + case XRT_OUTPUT_TYPE_VIBRATION: return "XRT_OUTPUT_TYPE_VIBRATION"; 53 + case XRT_OUTPUT_TYPE_FORCE_FEEDBACK: return "XRT_OUTPUT_TYPE_FORCE_FEEDBACK"; 54 + } 55 + 56 + return "<UNKNOWN>"; 57 } 58 59 void ··· 83 84 /* 85 * 86 + * 'Exported' str functions. 87 + * 88 + */ 89 + 90 + const char * 91 + u_str_xrt_input_name_or_null(enum xrt_input_name name) 92 + { 93 + #define XRT_INPUT_LIST_TO_CASE(NAME, _) \ 94 + case NAME: return #NAME; 95 + 96 + // No default case so we get warnings of missing entries. 97 + switch (name) { 98 + XRT_INPUT_LIST(XRT_INPUT_LIST_TO_CASE) 99 + } 100 + 101 + #undef XRT_INPUT_LIST_TO_CASE 102 + 103 + return NULL; 104 + } 105 + 106 + const char * 107 + u_str_xrt_output_name_or_null(enum xrt_output_name name) 108 + { 109 + #define XRT_OUTPUT_LIST_TO_CASE(NAME, _) \ 110 + case NAME: return #NAME; 111 + 112 + // No default case so we get warnings of missing entries. 113 + switch (name) { 114 + XRT_OUTPUT_LIST(XRT_OUTPUT_LIST_TO_CASE) 115 + } 116 + 117 + #undef XRT_OUTPUT_LIST_TO_CASE 118 + 119 + return NULL; 120 + } 121 + 122 + const char * 123 + u_str_xrt_device_name_or_null(enum xrt_device_name name) 124 + { 125 + #define XRT_DEVICE_NAME_LIST_TO_CASE(NAME) \ 126 + case NAME: return #NAME; 127 + 128 + // No default case so we get warnings of missing entries. 129 + switch (name) { 130 + XRT_DEVICE_NAME_LIST(XRT_DEVICE_NAME_LIST_TO_CASE) 131 + } 132 + 133 + #undef XRT_DEVICE_NAME_LIST_TO_CASE 134 + 135 + return NULL; 136 + } 137 + 138 + 139 + /* 140 + * 141 * 'Exported' functions. 142 * 143 */ ··· 180 void 181 u_pp_xrt_input_name(struct u_pp_delegate dg, enum xrt_input_name name) 182 { 183 + const char *might_be_null = u_str_xrt_input_name_or_null(name); 184 + if (might_be_null != NULL) { 185 + DG(might_be_null); 186 + return; 187 } 188 189 /* 190 * Invalid values handled below. 191 */ 192 ··· 200 void 201 u_pp_xrt_output_name(struct u_pp_delegate dg, enum xrt_output_name name) 202 { 203 + const char *might_be_null = u_str_xrt_output_name_or_null(name); 204 + if (might_be_null != NULL) { 205 + DG(might_be_null); 206 + return; 207 + } 208 209 + /* 210 + * Invalid values handled below. 211 + */ 212 213 + uint32_t id = XRT_GET_OUTPUT_ID(name); 214 + enum xrt_output_type type = XRT_GET_OUTPUT_TYPE(name); 215 + const char *str = get_xrt_output_type_short_str(type); 216 217 + u_pp(dg, "XRT_OUTPUT_0x%04x_%s", id, str); 218 } 219 220 void ··· 267 case XRT_OPERATION_CANCELLED: DG("XRT_OPERATION_CANCELLED"); return; 268 case XRT_ERROR_FUTURE_RESULT_NOT_READY: DG("XRT_ERROR_FUTURE_RESULT_NOT_READY"); return; 269 case XRT_ERROR_FUTURE_ALREADY_COMPLETE: DG("XRT_ERROR_FUTURE_ALREADY_COMPLETE"); return; 270 + case XRT_ERROR_DEVICE_NOT_ATTACHABLE: DG("XRT_ERROR_DEVICE_NOT_ATTACHABLE"); return; 271 } 272 // clang-format on 273
+43
src/xrt/auxiliary/util/u_pretty_print.h
··· 29 * they can easily be chained together to form a debug message printing out 30 * various information. Most of the final logging functions in Monado inserts a 31 * newline at the end of the message and we don't want two to be inserted. 32 */ 33 34 /*! 35 * Function prototype for receiving pretty printed strings.
··· 29 * they can easily be chained together to form a debug message printing out 30 * various information. Most of the final logging functions in Monado inserts a 31 * newline at the end of the message and we don't want two to be inserted. 32 + * 33 + * There are also helpers that goes from an enum to a string that that doesn't 34 + * use the delegate to do the printing, these returns string that are compiled 35 + * into the binary. They will return 'UNKNOWN' if they don't know the value. 36 + * But can be made to return NULL on unknown. 37 */ 38 + 39 + /*! 40 + * Returns a string of the input name, or NULL if invalid. 41 + * 42 + * @ingroup aux_pretty 43 + */ 44 + const char * 45 + u_str_xrt_input_name_or_null(enum xrt_input_name name); 46 + 47 + /*! 48 + * Returns a string of the output name, or NULL if invalid. 49 + * 50 + * @ingroup aux_pretty 51 + */ 52 + const char * 53 + u_str_xrt_output_name_or_null(enum xrt_output_name name); 54 + 55 + /*! 56 + * Returns a string of the device name, or NULL if invalid. 57 + * 58 + * @ingroup aux_pretty 59 + */ 60 + const char * 61 + u_str_xrt_device_name_or_null(enum xrt_device_name name); 62 + 63 + #define U_STR_NO_NULL(NAME, TYPE) \ 64 + static inline const char *NAME(TYPE enumerate) \ 65 + { \ 66 + const char *str = NAME##_or_null(enumerate); \ 67 + return str != NULL ? str : "UNKNOWN"; \ 68 + } 69 + 70 + U_STR_NO_NULL(u_str_xrt_input_name, enum xrt_input_name) 71 + U_STR_NO_NULL(u_str_xrt_output_name, enum xrt_output_name) 72 + U_STR_NO_NULL(u_str_xrt_device_name, enum xrt_device_name) 73 + 74 + #undef U_STR_NO_NULL 75 + 76 77 /*! 78 * Function prototype for receiving pretty printed strings.
+1 -1
src/xrt/auxiliary/util/u_sink_converter.c
··· 1071 sum += xf->data[(((y * 2) + 1) * xf->stride) + (x * 2)]; 1072 sum += xf->data[(((y * 2) + 1) * xf->stride) + (x * 2) + 1]; 1073 1074 - converted->data[(y * converted->stride) + x] = sum / 4; 1075 } 1076 } 1077
··· 1071 sum += xf->data[(((y * 2) + 1) * xf->stride) + (x * 2)]; 1072 sum += xf->data[(((y * 2) + 1) * xf->stride) + (x * 2) + 1]; 1073 1074 + converted->data[(y * converted->stride) + x] = (uint8_t)(sum / 4); 1075 } 1076 } 1077
+132 -18
src/xrt/auxiliary/util/u_space_overseer.c
··· 1 // Copyright 2023, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 42 U_SPACE_TYPE_POSE, 43 U_SPACE_TYPE_OFFSET, 44 U_SPACE_TYPE_ROOT, 45 }; 46 47 /*! ··· 330 m_relation_chain_push_relation(xrc, &xsr); 331 } break; 332 case U_SPACE_TYPE_OFFSET: m_relation_chain_push_pose_if_not_identity(xrc, &space->offset.pose); break; 333 - case U_SPACE_TYPE_ROOT: return; // Stops the traversing. 334 } 335 336 // Please tail-call optimise this miss compiler. ··· 352 case U_SPACE_TYPE_NULL: break; 353 case U_SPACE_TYPE_POSE: break; 354 case U_SPACE_TYPE_OFFSET: break; 355 - case U_SPACE_TYPE_ROOT: return; // Stops the traversing. 356 } 357 358 // Can't tail-call optimise this one :( ··· 371 } break; 372 case U_SPACE_TYPE_OFFSET: m_relation_chain_push_inverted_pose_if_not_identity(xrc, &space->offset.pose); break; 373 case U_SPACE_TYPE_ROOT: assert(false); // Should not get here. 374 } 375 } 376 ··· 469 470 // Created with one reference. 471 uso->base.semantic.root = &us->base; 472 } 473 474 ··· 1033 return xret; 1034 } 1035 1036 static void 1037 destroy(struct xrt_space_overseer *xso) 1038 { ··· 1089 uso->base.set_tracking_origin_offset = set_tracking_origin_offset; 1090 uso->base.get_reference_space_offset = get_reference_space_offset; 1091 uso->base.set_reference_space_offset = set_reference_space_offset; 1092 uso->base.destroy = destroy; 1093 uso->broadcast = broadcast; 1094 ··· 1117 bool root_is_unbounded, 1118 bool per_app_local_spaces) 1119 { 1120 - struct xrt_space *root = uso->base.semantic.root; // Convenience 1121 uso->per_app_local_spaces = per_app_local_spaces; 1122 1123 for (uint32_t i = 0; i < xdev_count; i++) { 1124 - struct xrt_device *xdev = xdevs[i]; 1125 - struct xrt_tracking_origin *torig = xdev->tracking_origin; 1126 - uint64_t key = (uint64_t)(intptr_t)torig; 1127 - struct xrt_space *xs = NULL; 1128 - 1129 - void *ptr = NULL; 1130 - u_hashmap_int_find(uso->xto_map, key, &ptr); 1131 - 1132 - if (ptr != NULL) { 1133 - xs = (struct xrt_space *)ptr; 1134 - } else { 1135 - u_space_overseer_create_offset_space(uso, root, &torig->initial_offset, &xs); 1136 - u_hashmap_int_insert(uso->xto_map, key, xs); 1137 } 1138 - 1139 - u_space_overseer_link_space_to_device(uso, xs, xdev); 1140 } 1141 1142 // If these are set something is probably wrong, but just in case unset them.
··· 1 // Copyright 2023, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 43 U_SPACE_TYPE_POSE, 44 U_SPACE_TYPE_OFFSET, 45 U_SPACE_TYPE_ROOT, 46 + 47 + /*! 48 + * Space designed to be attachable to others, most importantly it is 49 + * re-attachable, and in order to move all of the spaces that has this 50 + * space as it's parent/next we need a node that can be updated. 51 + */ 52 + U_SPACE_TYPE_ATTACHABLE, 53 }; 54 55 /*! ··· 338 m_relation_chain_push_relation(xrc, &xsr); 339 } break; 340 case U_SPACE_TYPE_OFFSET: m_relation_chain_push_pose_if_not_identity(xrc, &space->offset.pose); break; 341 + case U_SPACE_TYPE_ROOT: return; // Stops the traversing. 342 + case U_SPACE_TYPE_ATTACHABLE: break; // No-op 343 } 344 345 // Please tail-call optimise this miss compiler. ··· 361 case U_SPACE_TYPE_NULL: break; 362 case U_SPACE_TYPE_POSE: break; 363 case U_SPACE_TYPE_OFFSET: break; 364 + case U_SPACE_TYPE_ROOT: return; // Stops the traversing. 365 + case U_SPACE_TYPE_ATTACHABLE: break; // No-op 366 } 367 368 // Can't tail-call optimise this one :( ··· 381 } break; 382 case U_SPACE_TYPE_OFFSET: m_relation_chain_push_inverted_pose_if_not_identity(xrc, &space->offset.pose); break; 383 case U_SPACE_TYPE_ROOT: assert(false); // Should not get here. 384 + case U_SPACE_TYPE_ATTACHABLE: break; // No-op 385 } 386 } 387 ··· 480 481 // Created with one reference. 482 uso->base.semantic.root = &us->base; 483 + } 484 + 485 + 486 + /* 487 + * 488 + * Device helpers. 489 + * 490 + */ 491 + 492 + /*! 493 + * Helper function to add a device to the space overseer. This function 494 + * handles creating or finding a space for the device's tracking origin 495 + * and linking the device to that space. 496 + */ 497 + static xrt_result_t 498 + add_device_helper(struct u_space_overseer *uso, struct xrt_device *xdev) 499 + { 500 + struct xrt_tracking_origin *torig = xdev->tracking_origin; 501 + assert(torig != NULL); 502 + 503 + struct xrt_space *root = uso->base.semantic.root; 504 + uint64_t key = (uint64_t)(intptr_t)torig; 505 + struct xrt_space *xs = NULL; 506 + 507 + // Need to take the write lock. 508 + pthread_rwlock_wrlock(&uso->lock); 509 + 510 + // Does this tracking origin already have space. 511 + void *ptr = NULL; 512 + u_hashmap_int_find(uso->xto_map, key, &ptr); 513 + 514 + if (ptr != NULL) { 515 + xs = (struct xrt_space *)ptr; 516 + } else if (torig->type == XRT_TRACKING_TYPE_ATTACHABLE) { 517 + /* 518 + * If we ever make u_space_overseer sub-classable make sure 519 + * this calls the right function, can't call interface function 520 + * as the lock is held here. 521 + */ 522 + xs = (struct xrt_space *)create_space(U_SPACE_TYPE_ATTACHABLE, u_space(root)); 523 + u_hashmap_int_insert(uso->xto_map, key, xs); 524 + } else { 525 + /* 526 + * If we ever make u_space_overseer sub-classable make sure 527 + * this calls the right function, can't call interface function 528 + * as the lock is held here. 529 + */ 530 + xs = (struct xrt_space *)create_space(U_SPACE_TYPE_OFFSET, u_space(root)); 531 + 532 + update_offset_write_locked(u_space(xs), &torig->initial_offset); 533 + 534 + u_hashmap_int_insert(uso->xto_map, key, xs); 535 + } 536 + 537 + pthread_rwlock_unlock(&uso->lock); 538 + 539 + u_space_overseer_link_space_to_device(uso, xs, xdev); 540 + 541 + return XRT_SUCCESS; 542 } 543 544 ··· 1103 return xret; 1104 } 1105 1106 + static xrt_result_t 1107 + add_device(struct xrt_space_overseer *xso, struct xrt_device *xdev) 1108 + { 1109 + struct u_space_overseer *uso = u_space_overseer(xso); 1110 + 1111 + return add_device_helper(uso, xdev); 1112 + } 1113 + 1114 + static xrt_result_t 1115 + attach_device(struct xrt_space_overseer *xso, struct xrt_device *xdev, struct xrt_space *space) 1116 + { 1117 + struct u_space_overseer *uso = u_space_overseer(xso); 1118 + 1119 + // Check that the device has the correct tracking origin type. 1120 + if (xdev->tracking_origin == NULL || xdev->tracking_origin->type != XRT_TRACKING_TYPE_ATTACHABLE) { 1121 + U_LOG_E("Device '%s' does not have XRT_TRACKING_TYPE_ATTACHABLE tracking origin type", xdev->str); 1122 + return XRT_ERROR_DEVICE_NOT_ATTACHABLE; 1123 + } 1124 + 1125 + // If no space is provided, use the root space. 1126 + struct xrt_space *target_space = space; 1127 + if (target_space == NULL) { 1128 + target_space = uso->base.semantic.root; 1129 + } 1130 + 1131 + xrt_result_t xret = XRT_SUCCESS; 1132 + pthread_rwlock_wrlock(&uso->lock); 1133 + 1134 + 1135 + void *ptr = NULL; 1136 + uint64_t key = (uint64_t)(intptr_t)xdev->tracking_origin; 1137 + u_hashmap_int_find(uso->xto_map, key, &ptr); 1138 + if (ptr == NULL) { 1139 + U_LOG_E("Device doesn't have space associated with it!"); 1140 + xret = XRT_ERROR_DEVICE_NOT_ATTACHABLE; 1141 + goto err_unlock; 1142 + } 1143 + 1144 + struct u_space *us = (struct u_space *)ptr; 1145 + if (us->type != U_SPACE_TYPE_ATTACHABLE) { 1146 + U_LOG_E("Device doesn't have a attachable space!"); 1147 + xret = XRT_ERROR_DEVICE_NOT_ATTACHABLE; 1148 + goto err_unlock; 1149 + } 1150 + 1151 + // Update the link. 1152 + u_space_reference(&us->next, u_space(target_space)); 1153 + 1154 + err_unlock: 1155 + pthread_rwlock_unlock(&uso->lock); 1156 + 1157 + return xret; 1158 + } 1159 + 1160 static void 1161 destroy(struct xrt_space_overseer *xso) 1162 { ··· 1213 uso->base.set_tracking_origin_offset = set_tracking_origin_offset; 1214 uso->base.get_reference_space_offset = get_reference_space_offset; 1215 uso->base.set_reference_space_offset = set_reference_space_offset; 1216 + uso->base.add_device = add_device; 1217 + uso->base.attach_device = attach_device; 1218 uso->base.destroy = destroy; 1219 uso->broadcast = broadcast; 1220 ··· 1243 bool root_is_unbounded, 1244 bool per_app_local_spaces) 1245 { 1246 uso->per_app_local_spaces = per_app_local_spaces; 1247 1248 + // Add all devices to the space overseer. 1249 for (uint32_t i = 0; i < xdev_count; i++) { 1250 + xrt_result_t xret = add_device_helper(uso, xdevs[i]); 1251 + if (xret != XRT_SUCCESS) { 1252 + U_LOG_E("Failed to add device '%s' to space overseer!", xdevs[i]->str); 1253 } 1254 } 1255 1256 // If these are set something is probably wrong, but just in case unset them.
+12 -2
src/xrt/auxiliary/util/u_var.h
··· 1 // Copyright 2019-2024, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 83 //! Pointer that will be passed to the function as its only argument 84 void *ptr; 85 86 //! Button text, use var `name` if zeroed 87 char label[64]; 88 ··· 229 U_VAR_KIND_NATIVE_IMAGES_DEBUG, 230 U_VAR_KIND_LOG_LEVEL, 231 U_VAR_KIND_RO_TEXT, 232 - U_VAR_KIND_RO_FTEXT, 233 U_VAR_KIND_RO_I16, 234 U_VAR_KIND_RO_I32, 235 U_VAR_KIND_RO_U16, ··· 247 U_VAR_KIND_GUI_HEADER, 248 U_VAR_KIND_GUI_HEADER_BEGIN, 249 U_VAR_KIND_GUI_HEADER_END, 250 U_VAR_KIND_BUTTON, 251 U_VAR_KIND_COMBO, 252 U_VAR_KIND_HISTOGRAM_F32, ··· 389 ADD_FUNC(native_images_debug, struct u_native_images_debug, NATIVE_IMAGES_DEBUG) \ 390 ADD_FUNC(log_level, enum u_logging_level, LOG_LEVEL) \ 391 ADD_FUNC(ro_text, const char, RO_TEXT) \ 392 - ADD_FUNC(ro_ftext, const char, RO_FTEXT) \ 393 ADD_FUNC(ro_i16, int16_t, RO_I16) \ 394 ADD_FUNC(ro_i32, int32_t, RO_I32) \ 395 ADD_FUNC(ro_u16, uint16_t, RO_U16) \ ··· 407 ADD_FUNC(gui_header, bool, GUI_HEADER) \ 408 ADD_FUNC(gui_header_begin, bool, GUI_HEADER_BEGIN) \ 409 ADD_FUNC(gui_header_end, bool, GUI_HEADER_END) \ 410 ADD_FUNC(button, struct u_var_button, BUTTON) \ 411 ADD_FUNC(combo, struct u_var_combo, COMBO) \ 412 ADD_FUNC(draggable_f32, struct u_var_draggable_f32, DRAGGABLE_F32) \
··· 1 // Copyright 2019-2024, Collabora, Ltd. 2 + // Copyright 2024-2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 84 //! Pointer that will be passed to the function as its only argument 85 void *ptr; 86 87 + /*! 88 + * Is the pointer pressing down on the button curruently, this is not 89 + * edge triggered like the callback. For a mouse this means that the 90 + * pointer is hovering the button and the left is held down. 91 + */ 92 + xrt_atomic_s32_t downed; 93 + 94 //! Button text, use var `name` if zeroed 95 char label[64]; 96 ··· 237 U_VAR_KIND_NATIVE_IMAGES_DEBUG, 238 U_VAR_KIND_LOG_LEVEL, 239 U_VAR_KIND_RO_TEXT, 240 + U_VAR_KIND_RO_RAW_TEXT, 241 U_VAR_KIND_RO_I16, 242 U_VAR_KIND_RO_I32, 243 U_VAR_KIND_RO_U16, ··· 255 U_VAR_KIND_GUI_HEADER, 256 U_VAR_KIND_GUI_HEADER_BEGIN, 257 U_VAR_KIND_GUI_HEADER_END, 258 + U_VAR_KIND_GUI_SAMELINE, 259 U_VAR_KIND_BUTTON, 260 U_VAR_KIND_COMBO, 261 U_VAR_KIND_HISTOGRAM_F32, ··· 398 ADD_FUNC(native_images_debug, struct u_native_images_debug, NATIVE_IMAGES_DEBUG) \ 399 ADD_FUNC(log_level, enum u_logging_level, LOG_LEVEL) \ 400 ADD_FUNC(ro_text, const char, RO_TEXT) \ 401 + ADD_FUNC(ro_raw_text, const char, RO_RAW_TEXT) \ 402 ADD_FUNC(ro_i16, int16_t, RO_I16) \ 403 ADD_FUNC(ro_i32, int32_t, RO_I32) \ 404 ADD_FUNC(ro_u16, uint16_t, RO_U16) \ ··· 416 ADD_FUNC(gui_header, bool, GUI_HEADER) \ 417 ADD_FUNC(gui_header_begin, bool, GUI_HEADER_BEGIN) \ 418 ADD_FUNC(gui_header_end, bool, GUI_HEADER_END) \ 419 + ADD_FUNC(gui_sameline, void, GUI_SAMELINE) \ 420 ADD_FUNC(button, struct u_var_button, BUTTON) \ 421 ADD_FUNC(combo, struct u_var_combo, COMBO) \ 422 ADD_FUNC(draggable_f32, struct u_var_draggable_f32, DRAGGABLE_F32) \
+52 -17
src/xrt/auxiliary/util/u_worker.c
··· 1 // Copyright 2022, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 94 //! Pointer to poll of threads. 95 struct u_worker_thread_pool *uwtp; 96 97 - //! Number of tasks that is pending or being worked on in this group. 98 - size_t current_submitted_tasks_count; 99 100 - //! Number of threads that have been released or newly entered wait. 101 size_t released_count; 102 103 struct ··· 143 continue; 144 } 145 146 - *out_task = p->tasks[i]; 147 p->tasks[i] = (struct task){NULL, NULL, NULL}; 148 p->tasks_in_array_count--; 149 return; 150 } 151 ··· 164 165 p->tasks[i] = (struct task){g, func, data}; 166 p->tasks_in_array_count++; 167 - g->current_submitted_tasks_count++; 168 return; 169 } 170 ··· 201 */ 202 203 static bool 204 - locked_group_should_enter_wait_loop(struct pool *p, struct group *g) 205 { 206 - if (g->current_submitted_tasks_count == 0) { 207 return false; 208 } 209 210 - // Enter the loop as a released thread. 211 - g->released_count++; 212 - 213 return true; 214 } 215 ··· 237 */ 238 239 // Tasks available. 240 - if (g->current_submitted_tasks_count > 0) { 241 242 // We have been released or newly entered the loop. 243 if (g->released_count > 0) { ··· 265 locked_group_wake_waiter_if_allowed(struct pool *p, struct group *g) 266 { 267 // Are there still outstanding tasks? 268 - if (g->current_submitted_tasks_count > 0) { 269 return; 270 } 271 ··· 343 344 snprintf(t->name, sizeof(t->name), "%s: Worker", p->prefix); 345 U_TRACE_SET_THREAD_NAME(t->name); 346 347 os_mutex_lock(&p->mutex); 348 ··· 373 // No longer working. 374 p->working_count--; 375 376 - // Only now decrement the task count on the owning group. 377 - task.g->current_submitted_tasks_count--; 378 379 // Wake up any waiter. 380 locked_group_wake_waiter_if_allowed(p, task.g); ··· 401 XRT_TRACE_MARKER(); 402 int ret; 403 404 - assert(starting_worker_count < thread_count); 405 - if (starting_worker_count >= thread_count) { 406 return NULL; 407 } 408 ··· 532 os_mutex_lock(&p->mutex); 533 534 // Can we early out? 535 - if (!locked_group_should_enter_wait_loop(p, g)) { 536 os_mutex_unlock(&p->mutex); 537 return; 538 } 539 540 // Wait here until all work been started and completed. 541 while (locked_group_should_wait(p, g)) {
··· 1 // Copyright 2022, Collabora, Ltd. 2 + // Copyright 2024-2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 95 //! Pointer to poll of threads. 96 struct u_worker_thread_pool *uwtp; 97 98 + /*! 99 + * The number of tasks that are pending execution by a worker. 100 + * They reside in the pool::tasks array. 101 + */ 102 + uint32_t current_tasks_in_array; 103 + 104 + /*! 105 + * Number of tasks that are being worked on. 106 + * They live inside of the working thread. 107 + */ 108 + uint32_t current_working_tasks; 109 110 + /*! 111 + * Number of waiting threads that have been released by a worker, 112 + * or a thread that has started waiting (see u_worker_group_wait_all). 113 + */ 114 size_t released_count; 115 116 struct ··· 156 continue; 157 } 158 159 + struct task task = p->tasks[i]; 160 p->tasks[i] = (struct task){NULL, NULL, NULL}; 161 + 162 p->tasks_in_array_count--; 163 + task.g->current_tasks_in_array--; 164 + task.g->current_working_tasks++; 165 + 166 + *out_task = task; 167 + 168 return; 169 } 170 ··· 183 184 p->tasks[i] = (struct task){g, func, data}; 185 p->tasks_in_array_count++; 186 + g->current_tasks_in_array++; 187 return; 188 } 189 ··· 220 */ 221 222 static bool 223 + locked_group_has_tasks_waiting_or_inflight(const struct group *g) 224 { 225 + if (g->current_tasks_in_array == 0 && g->current_working_tasks == 0) { 226 return false; 227 } 228 229 return true; 230 } 231 ··· 253 */ 254 255 // Tasks available. 256 + if (locked_group_has_tasks_waiting_or_inflight(g)) { 257 258 // We have been released or newly entered the loop. 259 if (g->released_count > 0) { ··· 281 locked_group_wake_waiter_if_allowed(struct pool *p, struct group *g) 282 { 283 // Are there still outstanding tasks? 284 + if (locked_group_has_tasks_waiting_or_inflight(g)) { 285 return; 286 } 287 ··· 359 360 snprintf(t->name, sizeof(t->name), "%s: Worker", p->prefix); 361 U_TRACE_SET_THREAD_NAME(t->name); 362 + os_thread_name(&t->thread, t->name); 363 364 os_mutex_lock(&p->mutex); 365 ··· 390 // No longer working. 391 p->working_count--; 392 393 + // We are no longer working on the task. 394 + task.g->current_working_tasks--; 395 + 396 + // This must hold true. 397 + assert(task.g->current_tasks_in_array <= p->tasks_in_array_count); 398 399 // Wake up any waiter. 400 locked_group_wake_waiter_if_allowed(p, task.g); ··· 421 XRT_TRACE_MARKER(); 422 int ret; 423 424 + assert(starting_worker_count <= thread_count); 425 + if (starting_worker_count > thread_count) { 426 return NULL; 427 } 428 ··· 552 os_mutex_lock(&p->mutex); 553 554 // Can we early out? 555 + if (!locked_group_has_tasks_waiting_or_inflight(g)) { 556 os_mutex_unlock(&p->mutex); 557 return; 558 } 559 + 560 + /* 561 + * The released_count is tied to the decrement of worker_limit, that is 562 + * when a waiting thread is woken up the worker_limit is decreased, and 563 + * released_count is increased. The waiting thread will then double 564 + * check that it can be released or not, if it can not be released it 565 + * will once again donate this thread and increase the worker_limit. 566 + * 567 + * If it can be released it will decrement released_count and exit the 568 + * loop below. 569 + * 570 + * So if we increment it here, the loop will increase worker_limit 571 + * which is what we want. 572 + */ 573 + g->released_count++; 574 575 // Wait here until all work been started and completed. 576 while (locked_group_should_wait(p, g)) {
+12
src/xrt/auxiliary/util/u_worker.hpp
··· 1 // Copyright 2022, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 103 ~SharedThreadGroup() 104 { 105 u_worker_group_reference(&mGroup, nullptr); 106 } 107 108 friend TaskCollection;
··· 1 // Copyright 2022, Collabora, Ltd. 2 + // Copyright 2024-2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 104 ~SharedThreadGroup() 105 { 106 u_worker_group_reference(&mGroup, nullptr); 107 + } 108 + 109 + /*! 110 + * In-general it's recommended to use the TaskCollection helper, 111 + * but some use cases requires direct access to the push function, 112 + * so it's provided here. 113 + */ 114 + void 115 + push(u_worker_group_func_t f, void *data) 116 + { 117 + u_worker_group_push(mGroup, f, data); 118 } 119 120 friend TaskCollection;
-2
src/xrt/auxiliary/vive/vive_poses.c
··· 12 #include "math/m_mathinclude.h" 13 #include "math/m_api.h" 14 15 - #define DEG_TO_RAD(DEG) (DEG * M_PI / 180.) 16 - 17 static void 18 vive_poses_apply_right_transform(struct xrt_vec3 *out_transform_position, struct xrt_vec3 *out_transform_rotation) 19 {
··· 12 #include "math/m_mathinclude.h" 13 #include "math/m_api.h" 14 15 static void 16 vive_poses_apply_right_transform(struct xrt_vec3 *out_transform_position, struct xrt_vec3 *out_transform_rotation) 17 {
+41 -35
src/xrt/auxiliary/vk/vk_bundle_init.c
··· 241 242 vk->features.timestamp_compute_and_graphics = pdp.limits.timestampComputeAndGraphics; 243 vk->features.timestamp_period = pdp.limits.timestampPeriod; 244 - vk->features.max_per_stage_descriptor_sampled_images = pdp.limits.maxPerStageDescriptorSampledImages; 245 - vk->features.max_per_stage_descriptor_storage_images = pdp.limits.maxPerStageDescriptorStorageImages; 246 247 248 /* ··· 975 return false; 976 } 977 978 - static bool 979 build_device_extensions(struct vk_bundle *vk, 980 VkPhysicalDevice physical_device, 981 struct u_string_list *required_device_ext_list, ··· 992 NULL, // layer_name 993 &prop_count, // out_prop_count 994 &props); // out_props 995 - if (ret != VK_SUCCESS) { 996 - VK_ERROR(vk, "vk_enumerate_physical_device_extension_properties: %s", vk_result_string(ret)); 997 - return false; 998 - } 999 1000 uint32_t required_device_ext_count = u_string_list_get_size(required_device_ext_list); 1001 const char *const *required_device_exts = u_string_list_get_data(required_device_ext_list); ··· 1004 for (uint32_t i = 0; i < required_device_ext_count; i++) { 1005 const char *ext = required_device_exts[i]; 1006 if (!check_extension(vk, props, prop_count, ext)) { 1007 - VK_DEBUG(vk, "VkPhysicalDevice does not support required extension %s", ext); 1008 free(props); 1009 - return false; 1010 } 1011 VK_DEBUG(vk, "Using required device ext %s", ext); 1012 } ··· 1042 1043 free(props); 1044 1045 - 1046 - return true; 1047 } 1048 1049 /*! ··· 1325 struct u_string_list *optional_device_ext_list, 1326 const struct vk_device_features *optional_device_features) 1327 { 1328 VkResult ret; 1329 1330 ret = select_physical_device(vk, forced_index); 1331 - if (ret != VK_SUCCESS) { 1332 - return ret; 1333 - } 1334 1335 - struct u_string_list *device_ext_list = NULL; 1336 - if (!build_device_extensions(vk, vk->physical_device, required_device_ext_list, optional_device_ext_list, 1337 - &device_ext_list)) { 1338 - return VK_ERROR_EXTENSION_NOT_PRESENT; 1339 - } 1340 1341 1342 /* ··· 1359 if (!vk->has_EXT_global_priority && // 1360 !vk->has_KHR_global_priority && // 1361 global_priority != VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT) { 1362 - return VK_ERROR_NOT_PERMITTED_EXT; 1363 } 1364 1365 vk_reset_queues(vk); ··· 1367 struct vk_queue_family main_queue_family = {0}; 1368 if (only_compute) { 1369 ret = find_queue_family(vk, VK_QUEUE_COMPUTE_BIT, &main_queue_family); 1370 } else { 1371 ret = find_graphics_queue_family(vk, &main_queue_family); 1372 - } 1373 - 1374 - if (ret != VK_SUCCESS) { 1375 - return ret; 1376 } 1377 1378 assert(main_queue_family.queue_family.queueCount > 0); ··· 1576 1577 ret = vk->vkCreateDevice(vk->physical_device, &device_create_info, NULL, &vk->device); 1578 1579 u_string_list_destroy(&device_ext_list); 1580 1581 - if (ret != VK_SUCCESS) { 1582 - VK_DEBUG(vk, "vkCreateDevice: %s (%d)", vk_result_string(ret), ret); 1583 - if (ret == VK_ERROR_NOT_PERMITTED_EXT) { 1584 - VK_DEBUG(vk, "Is CAP_SYS_NICE set? Try: sudo setcap cap_sys_nice+ep monado-service"); 1585 - } 1586 - return ret; 1587 } 1588 1589 // Fill in the device features we are interested in. 1590 fill_in_device_features(vk, main_queue.family_index); ··· 1594 1595 // Now setup all of the device specific functions. 1596 ret = vk_get_device_functions(vk); 1597 - if (ret != VK_SUCCESS) { 1598 - goto err_destroy; 1599 - } 1600 1601 vk->main_queue = vk_insert_get_queue(vk, &main_queue); 1602 assert(vk->main_queue != NULL); 1603 #if defined(VK_KHR_video_encode_queue) 1604 vk->encode_queue = vk_insert_get_queue(vk, &encode_queue); 1605 #endif ··· 1611 return ret; 1612 1613 err_destroy: 1614 - vk->vkDestroyDevice(vk->device, NULL); 1615 - vk->device = NULL; 1616 1617 return ret; 1618 }
··· 241 242 vk->features.timestamp_compute_and_graphics = pdp.limits.timestampComputeAndGraphics; 243 vk->features.timestamp_period = pdp.limits.timestampPeriod; 244 + 245 + vk->limits.max_sampler_allocation_count = pdp.limits.maxSamplerAllocationCount; 246 + vk->limits.max_bound_descriptor_sets = pdp.limits.maxBoundDescriptorSets; 247 + vk->limits.max_descriptor_set_samplers = pdp.limits.maxDescriptorSetSamplers; 248 + vk->limits.max_descriptor_set_sampled_images = pdp.limits.maxDescriptorSetSampledImages; 249 + vk->limits.max_per_stage_descriptor_samplers = pdp.limits.maxPerStageDescriptorSamplers; 250 + vk->limits.max_per_stage_descriptor_sampled_images = pdp.limits.maxPerStageDescriptorSampledImages; 251 + vk->limits.max_per_stage_descriptor_storage_images = pdp.limits.maxPerStageDescriptorStorageImages; 252 253 254 /* ··· 981 return false; 982 } 983 984 + static VkResult 985 build_device_extensions(struct vk_bundle *vk, 986 VkPhysicalDevice physical_device, 987 struct u_string_list *required_device_ext_list, ··· 998 NULL, // layer_name 999 &prop_count, // out_prop_count 1000 &props); // out_props 1001 + VK_CHK_AND_RET(ret, "vk_enumerate_physical_device_extension_properties"); 1002 1003 uint32_t required_device_ext_count = u_string_list_get_size(required_device_ext_list); 1004 const char *const *required_device_exts = u_string_list_get_data(required_device_ext_list); ··· 1007 for (uint32_t i = 0; i < required_device_ext_count; i++) { 1008 const char *ext = required_device_exts[i]; 1009 if (!check_extension(vk, props, prop_count, ext)) { 1010 + VK_ERROR(vk, "VkPhysicalDevice does not support required extension %s", ext); 1011 free(props); 1012 + return VK_ERROR_EXTENSION_NOT_PRESENT; 1013 } 1014 VK_DEBUG(vk, "Using required device ext %s", ext); 1015 } ··· 1045 1046 free(props); 1047 1048 + return VK_SUCCESS; 1049 } 1050 1051 /*! ··· 1327 struct u_string_list *optional_device_ext_list, 1328 const struct vk_device_features *optional_device_features) 1329 { 1330 + struct u_string_list *device_ext_list = NULL; 1331 VkResult ret; 1332 1333 ret = select_physical_device(vk, forced_index); 1334 + VK_CHK_WITH_GOTO(ret, "select_physical_device", err_destroy); 1335 1336 + ret = build_device_extensions( // 1337 + vk, // 1338 + vk->physical_device, // 1339 + required_device_ext_list, // 1340 + optional_device_ext_list, // 1341 + &device_ext_list); // 1342 + VK_CHK_WITH_GOTO(ret, "build_device_extensions", err_destroy); 1343 1344 1345 /* ··· 1362 if (!vk->has_EXT_global_priority && // 1363 !vk->has_KHR_global_priority && // 1364 global_priority != VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT) { 1365 + ret = VK_ERROR_NOT_PERMITTED_EXT; 1366 + goto err_destroy; 1367 } 1368 1369 vk_reset_queues(vk); ··· 1371 struct vk_queue_family main_queue_family = {0}; 1372 if (only_compute) { 1373 ret = find_queue_family(vk, VK_QUEUE_COMPUTE_BIT, &main_queue_family); 1374 + VK_CHK_WITH_GOTO(ret, "find_queue_family", err_destroy); 1375 } else { 1376 ret = find_graphics_queue_family(vk, &main_queue_family); 1377 + VK_CHK_WITH_GOTO(ret, "find_graphics_queue_family", err_destroy); 1378 } 1379 1380 assert(main_queue_family.queue_family.queueCount > 0); ··· 1578 1579 ret = vk->vkCreateDevice(vk->physical_device, &device_create_info, NULL, &vk->device); 1580 1581 + // Destroy the list now. 1582 u_string_list_destroy(&device_ext_list); 1583 1584 + if (ret == VK_ERROR_NOT_PERMITTED_EXT) { 1585 + // Don't spam the not permitted returns as we try all of the different priorities. 1586 + VK_DEBUG(vk, "Is CAP_SYS_NICE set? Try: sudo setcap cap_sys_nice+ep monado-service"); 1587 + goto err_destroy; 1588 } 1589 + VK_CHK_WITH_GOTO(ret, "vkCreateDevice", err_destroy); 1590 1591 // Fill in the device features we are interested in. 1592 fill_in_device_features(vk, main_queue.family_index); ··· 1596 1597 // Now setup all of the device specific functions. 1598 ret = vk_get_device_functions(vk); 1599 + VK_CHK_WITH_GOTO(ret, "vk_get_device_functions", err_destroy); 1600 1601 vk->main_queue = vk_insert_get_queue(vk, &main_queue); 1602 assert(vk->main_queue != NULL); 1603 + 1604 #if defined(VK_KHR_video_encode_queue) 1605 vk->encode_queue = vk_insert_get_queue(vk, &encode_queue); 1606 #endif ··· 1612 return ret; 1613 1614 err_destroy: 1615 + if (vk->device != VK_NULL_HANDLE) { 1616 + vk->vkDestroyDevice(vk->device, NULL); 1617 + vk->device = VK_NULL_HANDLE; 1618 + } 1619 + 1620 + // Safe to call even if null. 1621 + u_string_list_destroy(&device_ext_list); 1622 1623 return ret; 1624 }
+27 -6
src/xrt/auxiliary/vk/vk_helpers.h
··· 200 //! Were timeline semaphore requested, available, and enabled? 201 bool timeline_semaphore; 202 203 - //! Per stage limit on sampled images (includes combined). 204 - uint32_t max_per_stage_descriptor_sampled_images; 205 - 206 - //! Per stage limit on storage images. 207 - uint32_t max_per_stage_descriptor_storage_images; 208 - 209 //! Was synchronization2 requested, available, and enabled? 210 bool synchronization_2; 211 ··· 215 //! Was KHR_video_maintenance1 requested, available, and enabled? 216 bool video_maintenance_1; 217 } features; 218 219 //! Is the GPU a tegra device. 220 bool is_tegra; ··· 1077 1078 /*! 1079 * Creates a VkDevice and initialises the VkQueue. 1080 * 1081 * @ingroup aux_vk 1082 */
··· 200 //! Were timeline semaphore requested, available, and enabled? 201 bool timeline_semaphore; 202 203 //! Was synchronization2 requested, available, and enabled? 204 bool synchronization_2; 205 ··· 209 //! Was KHR_video_maintenance1 requested, available, and enabled? 210 bool video_maintenance_1; 211 } features; 212 + 213 + struct 214 + { 215 + //! Maximum number of sampler objects, as created by vkCreateSampler, which can simultaneously exist on 216 + uint32_t max_sampler_allocation_count; 217 + 218 + //! Maximum number of descriptor sets that can be simultaneously used by a pipeline. 219 + uint32_t max_bound_descriptor_sets; 220 + 221 + //! Maximum number of samplers that can be included in a pipeline layout. 222 + uint32_t max_descriptor_set_samplers; 223 + 224 + //! Maximum number of sampled images that can be included in a pipeline layout. 225 + uint32_t max_descriptor_set_sampled_images; 226 + 227 + //! Maximum number of samplers that can be accessible to a single shader stage in a pipeline layout. 228 + uint32_t max_per_stage_descriptor_samplers; 229 + 230 + //! Per stage limit on sampled images (includes combined). 231 + uint32_t max_per_stage_descriptor_sampled_images; 232 + 233 + //! Per stage limit on storage images. 234 + uint32_t max_per_stage_descriptor_storage_images; 235 + } limits; 236 237 //! Is the GPU a tegra device. 238 bool is_tegra; ··· 1095 1096 /*! 1097 * Creates a VkDevice and initialises the VkQueue. 1098 + * 1099 + * The @p vk_bundle must have been zero initialized, have the instance functions 1100 + * loaded and a valid instance. 1101 * 1102 * @ingroup aux_vk 1103 */
+15 -6
src/xrt/auxiliary/vk/vk_image_allocator.c
··· 184 .sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID, 185 .externalFormat = a_buffer_format_props.externalFormat, 186 }; 187 - CHAIN(format_android); 188 189 if (image_format == VK_FORMAT_R8G8B8A8_SRGB) { 190 // Some versions of Android can't allocate native sRGB, use UNORM and correct gamma later. ··· 192 193 // https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#VUID-VkImageViewCreateInfo-image-01019 194 image_create_flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; 195 - 196 - // https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkImageCreateInfo.html#VUID-VkImageCreateInfo-pNext-02396 197 - format_android.externalFormat = 0; 198 - assert(a_buffer_format_props.format != VK_FORMAT_UNDEFINED); // Make sure there is a Vulkan format. 199 - assert(format_android.externalFormat == 0); 200 201 add_format_non_dup(&flh, VK_FORMAT_R8G8B8A8_UNORM); 202 add_format_non_dup(&flh, VK_FORMAT_R8G8B8A8_SRGB); 203 } 204 205 if (vk_csci_is_format_supported(vk, image_format, info->bits)) { ··· 256 // VUID-VkImageCreateInfo-pNext-01974 257 if (format_android.externalFormat != 0) { 258 create_info.format = VK_FORMAT_UNDEFINED; 259 } 260 #endif 261
··· 184 .sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID, 185 .externalFormat = a_buffer_format_props.externalFormat, 186 }; 187 188 if (image_format == VK_FORMAT_R8G8B8A8_SRGB) { 189 // Some versions of Android can't allocate native sRGB, use UNORM and correct gamma later. ··· 191 192 // https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#VUID-VkImageViewCreateInfo-image-01019 193 image_create_flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; 194 + has_mutable_usage = true; 195 196 add_format_non_dup(&flh, VK_FORMAT_R8G8B8A8_UNORM); 197 add_format_non_dup(&flh, VK_FORMAT_R8G8B8A8_SRGB); 198 + } 199 + 200 + // https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkImageCreateInfo.html#VUID-VkImageCreateInfo-pNext-02396 201 + if (has_mutable_usage) { 202 + format_android.externalFormat = 0; 203 + // Make sure there is a Vulkan format. 204 + if (a_buffer_format_props.format == VK_FORMAT_UNDEFINED) { 205 + VK_WARN(vk, 206 + "vkGetAndroidHardwareBufferPropertiesANDROID: AHB has no Vulkan-mappable format. " 207 + "External format chain required, but external formats cannot be mutable. Swapchain " 208 + "creation may fail!"); 209 + assert(false); 210 + } 211 } 212 213 if (vk_csci_is_format_supported(vk, image_format, info->bits)) { ··· 264 // VUID-VkImageCreateInfo-pNext-01974 265 if (format_android.externalFormat != 0) { 266 create_info.format = VK_FORMAT_UNDEFINED; 267 + CHAIN(format_android); 268 } 269 #endif 270
+21 -5
src/xrt/compositor/client/comp_d3d11_client.cpp
··· 763 static void 764 client_d3d11_compositor_init_try_timeline_semaphores(struct client_d3d11_compositor *c) 765 { 766 c->timeline_semaphore_value = 1; 767 // See if we can make a "timeline semaphore", also known as ID3D11Fence 768 if (!c->xcn->base.create_semaphore || !c->xcn->base.layer_commit_with_semaphore) { 769 return; 770 } 771 - struct xrt_compositor_semaphore *xcsem = nullptr; 772 - wil::unique_handle timeline_semaphore_handle; 773 - if (XRT_SUCCESS != xrt_comp_create_semaphore(&(c->xcn->base), timeline_semaphore_handle.put(), &xcsem)) { 774 D3D_WARN(c, "Native compositor tried but failed to created a timeline semaphore for us."); 775 return; 776 } 777 D3D_INFO(c, "Native compositor created a timeline semaphore for us."); 778 779 unique_compositor_semaphore_ref timeline_semaphore{xcsem}; 780 781 - // try to import and signal 782 - wil::com_ptr<ID3D11Fence> fence = import_fence(*(c->fence_device), timeline_semaphore_handle.get()); 783 HRESULT hr = c->fence_context->Signal(fence.get(), c->timeline_semaphore_value); 784 if (!SUCCEEDED(hr)) { 785 D3D_WARN(c,
··· 763 static void 764 client_d3d11_compositor_init_try_timeline_semaphores(struct client_d3d11_compositor *c) 765 { 766 + struct xrt_compositor_semaphore *xcsem{nullptr}; 767 + HANDLE timeline_semaphore_handle_raw{}; 768 + xrt_result_t xret; 769 + 770 + // Set the value to something non-zero. 771 c->timeline_semaphore_value = 1; 772 + 773 // See if we can make a "timeline semaphore", also known as ID3D11Fence 774 if (!c->xcn->base.create_semaphore || !c->xcn->base.layer_commit_with_semaphore) { 775 return; 776 } 777 + 778 + /* 779 + * This call returns a HANDLE in the out_handle argument, it is owned by 780 + * the returned xrt_compositor_semaphore object we should not track it. 781 + */ 782 + xret = xrt_comp_create_semaphore( // 783 + &(c->xcn->base), // xc 784 + &timeline_semaphore_handle_raw, // out_handle 785 + &xcsem); // out_xcsem 786 + if (xret != XRT_SUCCESS) { 787 D3D_WARN(c, "Native compositor tried but failed to created a timeline semaphore for us."); 788 return; 789 } 790 D3D_INFO(c, "Native compositor created a timeline semaphore for us."); 791 792 + // Because importFence throws on failure we use this ref. 793 unique_compositor_semaphore_ref timeline_semaphore{xcsem}; 794 795 + // Try to import the fence. 796 + wil::com_ptr<ID3D11Fence> fence = import_fence(*(c->fence_device), timeline_semaphore_handle_raw); 797 + 798 + // And try to signal the fence to make sure it works. 799 HRESULT hr = c->fence_context->Signal(fence.get(), c->timeline_semaphore_value); 800 if (!SUCCEEDED(hr)) { 801 D3D_WARN(c,
+20 -7
src/xrt/compositor/client/comp_d3d12_client.cpp
··· 1 // Copyright 2019-2024, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 801 } 802 struct xrt_layer_data d = *data; 803 804 // No flip required: D3D12 swapchain image convention matches Vulkan. 805 return xrt_comp_layer_projection(&c->xcn->base, xdev, xscn, &d); 806 } ··· 1017 static void 1018 client_d3d12_compositor_init_try_timeline_semaphores(struct client_d3d12_compositor *c) 1019 { 1020 c->timeline_semaphore_value = 1; 1021 1022 // See if we can make a "timeline semaphore", also known as ID3D12Fence ··· 1024 return; 1025 } 1026 1027 - struct xrt_compositor_semaphore *xcsem = nullptr; 1028 - wil::unique_handle timeline_semaphore_handle; 1029 - if (XRT_SUCCESS != xrt_comp_create_semaphore(&(c->xcn->base), timeline_semaphore_handle.put(), &xcsem)) { 1030 D3D_WARN(c, "Native compositor tried but failed to created a timeline semaphore for us."); 1031 return; 1032 } ··· 1038 // Try to import, importFence throws on failure. 1039 wil::com_ptr<ID3D12Fence1> fence = xrt::auxiliary::d3d::d3d12::importFence( // 1040 *(c->device), // 1041 - timeline_semaphore_handle.get()); // 1042 - 1043 - // The fence now owns the handle., importFence throws on failure. 1044 - timeline_semaphore_handle.release(); 1045 1046 // Check flags. 1047 D3D12_FENCE_FLAGS flags = fence->GetCreationFlags();
··· 1 // Copyright 2019-2024, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 802 } 803 struct xrt_layer_data d = *data; 804 805 + // Scale to compensate for power-of-two texture sizes. 806 + for (uint32_t i = 0; i < data->view_count; ++i) { 807 + client_d3d12_swapchain_scale_rect(xsc[i], &d.proj.v[i].sub.norm_rect); 808 + } 809 // No flip required: D3D12 swapchain image convention matches Vulkan. 810 return xrt_comp_layer_projection(&c->xcn->base, xdev, xscn, &d); 811 } ··· 1022 static void 1023 client_d3d12_compositor_init_try_timeline_semaphores(struct client_d3d12_compositor *c) 1024 { 1025 + struct xrt_compositor_semaphore *xcsem{nullptr}; 1026 + HANDLE timeline_semaphore_handle_raw{}; 1027 + xrt_result_t xret; 1028 + 1029 + // Set the value to something non-zero. 1030 c->timeline_semaphore_value = 1; 1031 1032 // See if we can make a "timeline semaphore", also known as ID3D12Fence ··· 1034 return; 1035 } 1036 1037 + /* 1038 + * This call returns a HANDLE in the out_handle argument, it is owned by 1039 + * the returned xrt_compositor_semaphore object we should not track it. 1040 + */ 1041 + xret = xrt_comp_create_semaphore( // 1042 + &(c->xcn->base), // xc 1043 + &timeline_semaphore_handle_raw, // out_handle 1044 + &xcsem); // out_xcsem 1045 + if (xret != XRT_SUCCESS) { 1046 D3D_WARN(c, "Native compositor tried but failed to created a timeline semaphore for us."); 1047 return; 1048 } ··· 1054 // Try to import, importFence throws on failure. 1055 wil::com_ptr<ID3D12Fence1> fence = xrt::auxiliary::d3d::d3d12::importFence( // 1056 *(c->device), // 1057 + timeline_semaphore_handle_raw); // 1058 1059 // Check flags. 1060 D3D12_FENCE_FLAGS flags = fence->GetCreationFlags();
+189 -19
src/xrt/compositor/client/comp_egl_client.c
··· 200 #endif 201 } 202 203 static xrt_result_t 204 create_context( 205 EGLDisplay display, EGLConfig config, EGLContext app_context, EGLint api_type, EGLContext *out_our_context) ··· 207 EGLint old_api_type = eglQueryAPI(); 208 209 eglBindAPI(api_type); 210 211 - size_t attrc = 0; 212 - EGLint attrs[9] = {0}; 213 - 214 - attrs[attrc++] = EGL_CONTEXT_MAJOR_VERSION; 215 - attrs[attrc++] = 3; 216 // Panfrost only supports 3.1 217 - attrs[attrc++] = EGL_CONTEXT_MINOR_VERSION; 218 - attrs[attrc++] = 1; 219 220 - if (api_type == EGL_OPENGL_API) { 221 - attrs[attrc++] = EGL_CONTEXT_OPENGL_PROFILE_MASK; 222 - attrs[attrc++] = EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT; 223 } 224 225 - EGLint strategy; 226 - if (api_type == EGL_OPENGL_ES_API && 227 - eglQueryContext(display, app_context, EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, &strategy)) { 228 - attrs[attrc++] = EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT; 229 - attrs[attrc++] = strategy; 230 } 231 232 - attrs[attrc++] = EGL_NONE; 233 - assert(attrc <= ARRAY_SIZE(attrs)); 234 235 - EGLContext our_context = eglCreateContext(display, config, app_context, attrs); 236 237 // Restore old API type. 238 if (old_api_type == EGL_NONE) { ··· 240 } 241 242 if (our_context == EGL_NO_CONTEXT) { 243 - EGL_ERROR("eglCreateContext: %s", egl_error_str(eglGetError())); 244 return XRT_ERROR_OPENGL; 245 } 246
··· 200 #endif 201 } 202 203 + struct egl_attrs 204 + { 205 + EGLint api; 206 + EGLint major; 207 + EGLint minor; 208 + bool compat_profile; // Only for desktop OpenGL 209 + bool robust; 210 + bool lose_context_on_reset; 211 + EGLint image_prio; 212 + }; 213 + 214 + static int 215 + make_egl_attrs(EGLint *attrs, size_t len, const struct egl_attrs *params) 216 + { 217 + if (params->api != EGL_OPENGL_API && params->api != EGL_OPENGL_ES_API) { 218 + U_LOG_E("make_egl_attrs: only OpenGL and OpenGL ES is supported"); 219 + return -1; 220 + } 221 + 222 + size_t attrc = 0; 223 + 224 + #define ADD_ATTR(v) \ 225 + do { \ 226 + if (!len) { \ 227 + return -1; \ 228 + } \ 229 + len--; \ 230 + attrs[attrc++] = (v); \ 231 + } while (0) 232 + 233 + #define ADD_PAIR(k, v) \ 234 + do { \ 235 + ADD_ATTR(k); \ 236 + ADD_ATTR(v); \ 237 + } while (0) 238 + 239 + EGLint khr_flags = 0; 240 + 241 + ADD_PAIR(EGL_CONTEXT_MAJOR_VERSION, params->major); 242 + ADD_PAIR(EGL_CONTEXT_MINOR_VERSION, params->minor); 243 + 244 + if (params->api == EGL_OPENGL_API && params->compat_profile) { 245 + ADD_PAIR(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT); 246 + } 247 + 248 + if (params->robust) { 249 + if (params->api == EGL_OPENGL_ES_API) { 250 + ADD_PAIR(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, EGL_TRUE); 251 + } else if (params->api == EGL_OPENGL_API) { 252 + khr_flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR; 253 + } 254 + } 255 + 256 + if (params->lose_context_on_reset) { 257 + if (params->api == EGL_OPENGL_ES_API) { 258 + ADD_PAIR(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, EGL_LOSE_CONTEXT_ON_RESET_EXT); 259 + } else if (params->api == EGL_OPENGL_API) { 260 + ADD_PAIR(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, EGL_LOSE_CONTEXT_ON_RESET_KHR); 261 + } 262 + } 263 + 264 + if (params->api == EGL_OPENGL_API && khr_flags) { 265 + ADD_PAIR(EGL_CONTEXT_FLAGS_KHR, khr_flags); 266 + } 267 + 268 + if (params->image_prio && params->image_prio != EGL_CONTEXT_PRIORITY_MEDIUM_IMG) { 269 + ADD_PAIR(EGL_CONTEXT_PRIORITY_LEVEL_IMG, params->image_prio); 270 + } 271 + 272 + ADD_ATTR(EGL_NONE); 273 + 274 + #undef ADD_ATTR 275 + #undef ADD_PAIR 276 + 277 + return attrc; 278 + } 279 + 280 + static void 281 + print_egl_attrs(EGLint *attrs) 282 + { 283 + int i = 0; 284 + EGL_DEBUG("egl attributes:"); 285 + do { 286 + EGL_DEBUG("> attr: %d 0x%x", i, attrs[i]); 287 + } while (attrs[i++] != EGL_NONE); 288 + } 289 + 290 + static EGLint 291 + get_reset_strategy(EGLint api_type, EGLDisplay display, EGLContext app_context) 292 + { 293 + EGLint ext; 294 + switch (api_type) { 295 + case EGL_OPENGL_ES_API: ext = EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT; break; 296 + case EGL_OPENGL_API: 297 + /* This is non-standard, but supported in mesa */ 298 + ext = EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR; 299 + break; 300 + default: return 0; 301 + } 302 + 303 + EGLint strategy = 0; 304 + if (!eglQueryContext(display, app_context, ext, &strategy)) { 305 + return 0; 306 + } 307 + return strategy; 308 + } 309 + 310 static xrt_result_t 311 create_context( 312 EGLDisplay display, EGLConfig config, EGLContext app_context, EGLint api_type, EGLContext *out_our_context) ··· 314 EGLint old_api_type = eglQueryAPI(); 315 316 eglBindAPI(api_type); 317 + const char *api_string = 318 + api_type == EGL_OPENGL_API ? "opengl" : (api_type == EGL_OPENGL_ES_API ? "opengl_es" : ""); 319 320 // Panfrost only supports 3.1 321 + const EGLint major = 3; 322 + const EGLint minor = 1; 323 324 + EGLint image_prio; 325 + if (!eglQueryContext(display, app_context, EGL_CONTEXT_PRIORITY_LEVEL_IMG, &image_prio)) { 326 + image_prio = 0; 327 } 328 329 + const size_t attrs_len = 21; 330 + EGLint attrs[4][attrs_len]; 331 + int attrc = 0; 332 + 333 + struct egl_attrs build_attrs = { 334 + .api = api_type, 335 + .major = major, 336 + .minor = minor, 337 + .compat_profile = true, 338 + .image_prio = image_prio, 339 + }; 340 + 341 + /* If the source context was created with robust and/or lose notify enabled, 342 + * then we need to enable it too or we get EGL_BAD_MATCH. 343 + * 344 + * Problems with those options: 345 + * 1. Different way to activate them for OpenGL and OpenGL ES. 346 + * 2. No standard way to know if the options were used to create the original context. 347 + * (with an exception for OpenGL ES) 348 + * 349 + * So, the most reliable way to create our shared context is to try all those combinations... 350 + */ 351 + EGLint reset_strategy = get_reset_strategy(api_type, display, app_context); 352 + EGL_DEBUG("Current reset strategy (%s): 0x%x", api_string, reset_strategy); 353 + if (reset_strategy) { 354 + build_attrs.lose_context_on_reset = (reset_strategy == EGL_LOSE_CONTEXT_ON_RESET); 355 + 356 + if (make_egl_attrs(attrs[attrc++], attrs_len, &build_attrs) == -1) { 357 + return XRT_ERROR_OPENGL; 358 + } 359 + 360 + build_attrs.robust = true; 361 + if (make_egl_attrs(attrs[attrc++], attrs_len, &build_attrs) == -1) { 362 + return XRT_ERROR_OPENGL; 363 + } 364 + } else { 365 + /* Try context with all optional features disabled first */ 366 + if (make_egl_attrs(attrs[attrc++], attrs_len, &build_attrs) == -1) { 367 + return XRT_ERROR_OPENGL; 368 + } 369 + 370 + /* Then, try all combination of robustness and lose notification */ 371 + build_attrs.robust = false; 372 + build_attrs.lose_context_on_reset = true; 373 + if (make_egl_attrs(attrs[attrc++], attrs_len, &build_attrs) == -1) { 374 + return XRT_ERROR_OPENGL; 375 + } 376 + 377 + build_attrs.robust = true; 378 + build_attrs.lose_context_on_reset = false; 379 + if (make_egl_attrs(attrs[attrc++], attrs_len, &build_attrs) == -1) { 380 + return XRT_ERROR_OPENGL; 381 + } 382 + 383 + build_attrs.robust = true; 384 + build_attrs.lose_context_on_reset = true; 385 + if (make_egl_attrs(attrs[attrc++], attrs_len, &build_attrs) == -1) { 386 + return XRT_ERROR_OPENGL; 387 + } 388 } 389 390 + assert((unsigned)attrc <= ARRAY_SIZE(attrs)); 391 392 + EGLContext our_context = EGL_NO_CONTEXT; 393 + const char *last_error = ""; 394 + for (int i = 0; i != attrc; i++) { 395 + our_context = eglCreateContext(display, config, app_context, attrs[i]); 396 + if (our_context != EGL_NO_CONTEXT) { 397 + EGL_DEBUG("eglCreateContext (%s): try %d, context created", api_string, i); 398 + print_egl_attrs(attrs[i]); 399 + break; 400 + } 401 + 402 + last_error = egl_error_str(eglGetError()); 403 + EGL_DEBUG("eglCreateContext (%s): try %d, %s", api_string, i, last_error); 404 + print_egl_attrs(attrs[i]); 405 + } 406 407 // Restore old API type. 408 if (old_api_type == EGL_NONE) { ··· 410 } 411 412 if (our_context == EGL_NO_CONTEXT) { 413 + EGL_ERROR("eglCreateContext (%s): %s", api_string, last_error); 414 return XRT_ERROR_OPENGL; 415 } 416
+27 -11
src/xrt/compositor/main/comp_compositor.c
··· 1031 1032 COMP_DEBUG(c, "Doing init %p", (void *)c); 1033 1034 - if (xdev->hmd->view_count == 0) { 1035 - U_LOG_E("Bug detected: HMD \"%s\" does not set xdev->hmd.view_count. Value must be > 0!", xdev->str); 1036 assert(xdev->hmd->view_count > 0); 1037 } 1038 1039 // Do this as early as possible. ··· 1121 struct xrt_system_compositor_info sys_info_storage = {0}; 1122 struct xrt_system_compositor_info *sys_info = &sys_info_storage; 1123 1124 - // Required by OpenXR spec. 1125 - sys_info->max_layers = XRT_MAX_LAYERS; 1126 sys_info->compositor_vk_deviceUUID = c->settings.selected_gpu_deviceUUID; 1127 sys_info->client_vk_deviceUUID = c->settings.client_gpu_deviceUUID; 1128 sys_info->client_d3d_deviceLUID = c->settings.client_gpu_deviceLUID; ··· 1131 sys_info->supports_fov_mutable = true; 1132 1133 // clang-format off 1134 - uint32_t view_count = xdev->hmd->view_count; 1135 for (uint32_t i = 0; i < view_count; ++i) { 1136 uint32_t w = (uint32_t)(xdev->hmd->views[i].display.w_pixels * scale); 1137 uint32_t h = (uint32_t)(xdev->hmd->views[i].display.h_pixels * scale); 1138 uint32_t w_2 = xdev->hmd->views[i].display.w_pixels * 2; 1139 uint32_t h_2 = xdev->hmd->views[i].display.h_pixels * 2; 1140 1141 - sys_info->views[i].recommended.width_pixels = w; 1142 - sys_info->views[i].recommended.height_pixels = h; 1143 - sys_info->views[i].recommended.sample_count = 1; 1144 - sys_info->views[i].max.width_pixels = w_2; 1145 - sys_info->views[i].max.height_pixels = h_2; 1146 - sys_info->views[i].max.sample_count = 1; 1147 } 1148 // clang-format on 1149 1150 // If we can add e.g. video pass-through capabilities, we may need to change (augment) this list. 1151 // Just copying it directly right now.
··· 1031 1032 COMP_DEBUG(c, "Doing init %p", (void *)c); 1033 1034 + uint32_t view_count = xdev->hmd->view_count; 1035 + enum xrt_view_type view_type = 0; // Invalid 1036 + 1037 + switch (view_count) { 1038 + case 0: 1039 + U_LOG_E("Bug detected: HMD \"%s\" xdev->hmd.view_count must be > 0!", xdev->str); 1040 assert(xdev->hmd->view_count > 0); 1041 + break; 1042 + case 1: view_type = XRT_VIEW_TYPE_MONO; break; 1043 + case 2: view_type = XRT_VIEW_TYPE_STEREO; break; 1044 + default: 1045 + U_LOG_E("Bug detected: HMD \"%s\" xdev->hmd.view_count must be 1 or 2, not %u!", xdev->str, view_count); 1046 + assert(view_count == 1 && view_count == 2); 1047 + break; 1048 } 1049 1050 // Do this as early as possible. ··· 1132 struct xrt_system_compositor_info sys_info_storage = {0}; 1133 struct xrt_system_compositor_info *sys_info = &sys_info_storage; 1134 1135 + // Required by OpenXR spec (minimum 16). 1136 + sys_info->max_layers = render_max_layers_capable( // 1137 + get_vk(c), // 1138 + c->settings.use_compute, // 1139 + XRT_MAX_LAYERS); // 1140 sys_info->compositor_vk_deviceUUID = c->settings.selected_gpu_deviceUUID; 1141 sys_info->client_vk_deviceUUID = c->settings.client_gpu_deviceUUID; 1142 sys_info->client_d3d_deviceLUID = c->settings.client_gpu_deviceLUID; ··· 1145 sys_info->supports_fov_mutable = true; 1146 1147 // clang-format off 1148 for (uint32_t i = 0; i < view_count; ++i) { 1149 uint32_t w = (uint32_t)(xdev->hmd->views[i].display.w_pixels * scale); 1150 uint32_t h = (uint32_t)(xdev->hmd->views[i].display.h_pixels * scale); 1151 uint32_t w_2 = xdev->hmd->views[i].display.w_pixels * 2; 1152 uint32_t h_2 = xdev->hmd->views[i].display.h_pixels * 2; 1153 1154 + sys_info->view_configs[0].views[i].recommended.width_pixels = w; 1155 + sys_info->view_configs[0].views[i].recommended.height_pixels = h; 1156 + sys_info->view_configs[0].views[i].recommended.sample_count = 1; 1157 + sys_info->view_configs[0].views[i].max.width_pixels = w_2; 1158 + sys_info->view_configs[0].views[i].max.height_pixels = h_2; 1159 + sys_info->view_configs[0].views[i].max.sample_count = 1; 1160 } 1161 // clang-format on 1162 + sys_info->view_configs[0].view_type = view_type; 1163 + sys_info->view_configs[0].view_count = view_count; 1164 + sys_info->view_config_count = 1; // Only one view config for now. 1165 1166 // If we can add e.g. video pass-through capabilities, we may need to change (augment) this list. 1167 // Just copying it directly right now.
+7 -2
src/xrt/compositor/main/comp_renderer.c
··· 259 struct xrt_fov xdev_fovs[XRT_MAX_VIEWS] = XRT_STRUCT_INIT; 260 struct xrt_pose xdev_poses[2][XRT_MAX_VIEWS] = XRT_STRUCT_INIT; 261 262 - uint64_t scanout_time_ns = 0; 263 if (r->c->xdev->hmd->screens[0].scanout_direction == XRT_SCANOUT_DIRECTION_TOP_TO_BOTTOM) { 264 scanout_time_ns = r->c->xdev->hmd->screens[0].scanout_time_ns; 265 } else if (r->c->xdev->hmd->screens[0].scanout_direction != XRT_SCANOUT_DIRECTION_NONE) { ··· 274 r->c->xdev, // 275 &default_eye_relation, // 276 begin_timestamp_ns, // at_timestamp_ns 277 view_count, // 278 &head_relation[0], // out_head_relation 279 xdev_fovs, // out_fovs 280 - xdev_poses[0]); 281 if (xret != XRT_SUCCESS) { 282 struct u_pp_sink_stack_only sink; 283 u_pp_delegate_t dg = u_pp_sink_stack_only_init(&sink); ··· 292 r->c->xdev, // 293 &default_eye_relation, // 294 end_timestamp_ns, // at_timestamp_ns 295 view_count, // 296 &head_relation[1], // out_head_relation 297 xdev_fovs, // out_fovs
··· 259 struct xrt_fov xdev_fovs[XRT_MAX_VIEWS] = XRT_STRUCT_INIT; 260 struct xrt_pose xdev_poses[2][XRT_MAX_VIEWS] = XRT_STRUCT_INIT; 261 262 + // Determine view type based on view count 263 + enum xrt_view_type view_type = (view_count == 1) ? XRT_VIEW_TYPE_MONO : XRT_VIEW_TYPE_STEREO; 264 + 265 + int64_t scanout_time_ns = 0; 266 if (r->c->xdev->hmd->screens[0].scanout_direction == XRT_SCANOUT_DIRECTION_TOP_TO_BOTTOM) { 267 scanout_time_ns = r->c->xdev->hmd->screens[0].scanout_time_ns; 268 } else if (r->c->xdev->hmd->screens[0].scanout_direction != XRT_SCANOUT_DIRECTION_NONE) { ··· 277 r->c->xdev, // 278 &default_eye_relation, // 279 begin_timestamp_ns, // at_timestamp_ns 280 + view_type, // 281 view_count, // 282 &head_relation[0], // out_head_relation 283 xdev_fovs, // out_fovs 284 + xdev_poses[0]); // 285 if (xret != XRT_SUCCESS) { 286 struct u_pp_sink_stack_only sink; 287 u_pp_delegate_t dg = u_pp_sink_stack_only_init(&sink); ··· 296 r->c->xdev, // 297 &default_eye_relation, // 298 end_timestamp_ns, // at_timestamp_ns 299 + view_type, // 300 view_count, // 301 &head_relation[1], // out_head_relation 302 xdev_fovs, // out_fovs
+4
src/xrt/compositor/main/comp_settings.c
··· 10 #include "util/u_debug.h" 11 #include "comp_settings.h" 12 13 #define USE_COMPUTE_DEFAULT false 14 15 // clang-format off 16 DEBUG_GET_ONCE_LOG_OPTION(log, "XRT_COMPOSITOR_LOG", U_LOGGING_INFO)
··· 10 #include "util/u_debug.h" 11 #include "comp_settings.h" 12 13 + #ifdef XRT_OS_ANDROID 14 #define USE_COMPUTE_DEFAULT false 15 + #else 16 + #define USE_COMPUTE_DEFAULT true 17 + #endif 18 19 // clang-format off 20 DEBUG_GET_ONCE_LOG_OPTION(log, "XRT_COMPOSITOR_LOG", U_LOGGING_INFO)
+2 -2
src/xrt/compositor/main/comp_window_direct.c
··· 64 COMP_PRINT_MODE(ct->c, "Available Vk modes for direct mode"); 65 for (int i = 0; i < mode_count; i++) { 66 VkDisplayModePropertiesKHR *props = &mode_properties[i]; 67 - uint16_t width = props->parameters.visibleRegion.width; 68 - uint16_t height = props->parameters.visibleRegion.height; 69 float refresh = (float)props->parameters.refreshRate / 1000.f; 70 71 COMP_PRINT_MODE(ct->c, "| %2d | %dx%d@%.2f", i, width, height, refresh);
··· 64 COMP_PRINT_MODE(ct->c, "Available Vk modes for direct mode"); 65 for (int i = 0; i < mode_count; i++) { 66 VkDisplayModePropertiesKHR *props = &mode_properties[i]; 67 + uint32_t width = props->parameters.visibleRegion.width; 68 + uint32_t height = props->parameters.visibleRegion.height; 69 float refresh = (float)props->parameters.refreshRate / 1000.f; 70 71 COMP_PRINT_MODE(ct->c, "| %2d | %dx%d@%.2f", i, width, height, refresh);
+16 -3
src/xrt/compositor/multi/comp_multi_system.c
··· 1 // Copyright 2019-2024, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 422 .fb_face_tracking2_enabled = false, 423 .meta_body_tracking_full_body_enabled = false, 424 .meta_body_tracking_calibration_enabled = false, 425 }; 426 427 switch (msc->sessions.state) { ··· 556 U_LOG_I("Stopped native session, shutting down."); 557 xrt_comp_end_session(xc); 558 break; 559 - case MULTI_SYSTEM_STATE_STOPPED: break; 560 - default: assert(false); 561 } 562 563 os_thread_helper_unlock(&msc->oth); ··· 581 */ 582 583 static xrt_result_t 584 - system_compositor_set_state(struct xrt_system_compositor *xsc, struct xrt_compositor *xc, bool visible, bool focused) 585 { 586 struct multi_system_compositor *msc = multi_system_compositor(xsc); 587 struct multi_compositor *mc = multi_compositor(xc); ··· 596 xse.type = XRT_SESSION_EVENT_STATE_CHANGE; 597 xse.state.visible = visible; 598 xse.state.focused = focused; 599 600 return multi_compositor_push_event(mc, &xse); 601 }
··· 1 // Copyright 2019-2024, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 423 .fb_face_tracking2_enabled = false, 424 .meta_body_tracking_full_body_enabled = false, 425 .meta_body_tracking_calibration_enabled = false, 426 + .android_face_tracking_enabled = false, 427 }; 428 429 switch (msc->sessions.state) { ··· 558 U_LOG_I("Stopped native session, shutting down."); 559 xrt_comp_end_session(xc); 560 break; 561 + case MULTI_SYSTEM_STATE_STOPPED: U_LOG_I("Already stopped, nothing to clean up."); break; 562 + case MULTI_SYSTEM_STATE_INIT_WARM_START: 563 + U_LOG_I("Cleaning up from warm start state."); 564 + xrt_comp_end_session(xc); 565 + break; 566 + case MULTI_SYSTEM_STATE_INVALID: 567 + U_LOG_W("Cleaning up from invalid state."); 568 + // Best effort cleanup 569 + xrt_comp_end_session(xc); 570 + break; 571 + default: U_LOG_E("Unknown session state during cleanup: %d", msc->sessions.state); assert(false); 572 } 573 574 os_thread_helper_unlock(&msc->oth); ··· 592 */ 593 594 static xrt_result_t 595 + system_compositor_set_state( 596 + struct xrt_system_compositor *xsc, struct xrt_compositor *xc, bool visible, bool focused, int64_t timestamp_ns) 597 { 598 struct multi_system_compositor *msc = multi_system_compositor(xsc); 599 struct multi_compositor *mc = multi_compositor(xc); ··· 608 xse.type = XRT_SESSION_EVENT_STATE_CHANGE; 609 xse.state.visible = visible; 610 xse.state.focused = focused; 611 + xse.state.timestamp_ns = timestamp_ns; 612 613 return multi_compositor_push_event(mc, &xse); 614 }
+38 -10
src/xrt/compositor/null/null_compositor.c
··· 268 { 269 struct xrt_system_compositor_info *sys_info = &c->sys_info; 270 271 - // Required by OpenXR spec. 272 sys_info->max_layers = XRT_MAX_LAYERS; 273 274 // UUIDs and LUID already set in vk init. 275 (void)sys_info->compositor_vk_deviceUUID; 276 (void)sys_info->client_vk_deviceUUID; 277 (void)sys_info->client_d3d_deviceLUID; 278 (void)sys_info->client_d3d_deviceLUID_valid; 279 - uint32_t view_count = xdev->hmd->view_count; 280 // clang-format off 281 for (uint32_t i = 0; i < view_count; ++i) { 282 - sys_info->views[i].recommended.width_pixels = RECOMMENDED_VIEW_WIDTH; 283 - sys_info->views[i].recommended.height_pixels = RECOMMENDED_VIEW_HEIGHT; 284 - sys_info->views[i].recommended.sample_count = 1; 285 - sys_info->views[i].max.width_pixels = MAX_VIEW_WIDTH; 286 - sys_info->views[i].max.height_pixels = MAX_VIEW_HEIGHT; 287 - sys_info->views[i].max.sample_count = 1; 288 } 289 // clang-format on 290 291 // Copy the list directly. 292 assert(xdev->hmd->blend_mode_count <= XRT_MAX_DEVICE_BLEND_MODES); ··· 436 437 struct xrt_fov fovs[2] = {0}; 438 struct xrt_pose poses[2] = {0}; 439 - xrt_result_t xret = 440 - xrt_device_get_view_poses(c->xdev, &default_eye_relation, display_time_ns, 2, &head_relation, fovs, poses); 441 if (xret != XRT_SUCCESS) { 442 return xret; 443 }
··· 268 { 269 struct xrt_system_compositor_info *sys_info = &c->sys_info; 270 271 + /* 272 + * Required by OpenXR spec (minimum 16). 273 + * 274 + * NOTE: When using Vulkan compositor components (c/render, c/util), 275 + * call render_max_layers_capable() to clamp this value based on 276 + * actual device limits. 277 + */ 278 sys_info->max_layers = XRT_MAX_LAYERS; 279 280 + uint32_t view_count = xdev->hmd->view_count; 281 + enum xrt_view_type view_type = 0; // Invalid 282 + 283 + switch (view_count) { 284 + case 0: U_LOG_E("Bug detected: HMD \"%s\" xdev->hmd.view_count must be > 0!", xdev->str); return false; 285 + case 1: view_type = XRT_VIEW_TYPE_MONO; break; 286 + case 2: view_type = XRT_VIEW_TYPE_STEREO; break; 287 + default: 288 + U_LOG_E("Bug detected: HMD \"%s\" xdev->hmd.view_count must be 1 or 2, not %u!", xdev->str, view_count); 289 + return false; 290 + } 291 + 292 // UUIDs and LUID already set in vk init. 293 (void)sys_info->compositor_vk_deviceUUID; 294 (void)sys_info->client_vk_deviceUUID; 295 (void)sys_info->client_d3d_deviceLUID; 296 (void)sys_info->client_d3d_deviceLUID_valid; 297 // clang-format off 298 for (uint32_t i = 0; i < view_count; ++i) { 299 + sys_info->view_configs[0].views[i].recommended.width_pixels = RECOMMENDED_VIEW_WIDTH; 300 + sys_info->view_configs[0].views[i].recommended.height_pixels = RECOMMENDED_VIEW_HEIGHT; 301 + sys_info->view_configs[0].views[i].recommended.sample_count = 1; 302 + sys_info->view_configs[0].views[i].max.width_pixels = MAX_VIEW_WIDTH; 303 + sys_info->view_configs[0].views[i].max.height_pixels = MAX_VIEW_HEIGHT; 304 + sys_info->view_configs[0].views[i].max.sample_count = 1; 305 } 306 // clang-format on 307 + sys_info->view_configs[0].view_type = view_type; 308 + sys_info->view_configs[0].view_count = view_count; 309 + sys_info->view_config_count = 1; // Only one view config type supported. 310 311 // Copy the list directly. 312 assert(xdev->hmd->blend_mode_count <= XRT_MAX_DEVICE_BLEND_MODES); ··· 456 457 struct xrt_fov fovs[2] = {0}; 458 struct xrt_pose poses[2] = {0}; 459 + 460 + xrt_result_t xret = xrt_device_get_view_poses( // 461 + c->xdev, // 462 + &default_eye_relation, // 463 + display_time_ns, // 464 + XRT_VIEW_TYPE_STEREO, // 465 + 2, // 466 + &head_relation, // 467 + fovs, // 468 + poses); // 469 if (xret != XRT_SUCCESS) { 470 return xret; 471 }
+48 -12
src/xrt/compositor/render/render_interface.h
··· 1 // Copyright 2019-2023, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 58 #define RENDER_MAX_LAYERS (XRT_MAX_LAYERS) 59 60 /*! 61 * Max number of images that can be given at a single time to the layer 62 * squasher in a single dispatch. 63 */ 64 - #define RENDER_MAX_IMAGES_SIZE (RENDER_MAX_LAYERS * XRT_MAX_VIEWS) 65 - #define RENDER_MAX_IMAGES_COUNT(RENDER_RESOURCES) (RENDER_MAX_LAYERS * RENDER_RESOURCES->view_count) 66 67 /*! 68 * Maximum number of times that the layer squasher shader can run per ··· 87 //! The binding that the shared layer fragment shader has its source on. 88 #define RENDER_BINDING_LAYER_SHARED_SRC 1 89 90 91 /* 92 * 93 * Util functions. 94 * 95 */ 96 97 /*! 98 * Create a simplified projection matrix for timewarp. ··· 1207 struct 1208 { 1209 uint32_t value; 1210 - uint32_t padding[3]; 1211 } layer_count; 1212 1213 struct xrt_normalized_rect pre_transform; 1214 struct xrt_normalized_rect post_transforms[RENDER_MAX_LAYERS]; 1215 1216 - //! std140 uvec2, corresponds to enum xrt_layer_type and unpremultiplied alpha. 1217 struct 1218 { 1219 - uint32_t val; 1220 - uint32_t unpremultiplied; 1221 - uint32_t padding[XRT_MAX_VIEWS]; 1222 - } layer_type[RENDER_MAX_LAYERS]; 1223 1224 - //! Which image/sampler(s) correspond to each layer. 1225 struct 1226 { 1227 - uint32_t images[XRT_MAX_VIEWS]; 1228 //! @todo Implement separated samplers and images (and change to samplers[2]) 1229 - uint32_t padding[XRT_MAX_VIEWS]; 1230 - } images_samplers[RENDER_MAX_LAYERS]; 1231 1232 //! Shared between cylinder and equirect2. 1233 struct xrt_matrix_4x4 mv_inverse[RENDER_MAX_LAYERS];
··· 1 // Copyright 2019-2023, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 59 #define RENDER_MAX_LAYERS (XRT_MAX_LAYERS) 60 61 /*! 62 + * The maximum number samplers per view that can be used by the compute shader 63 + * for layer composition (layer.comp) 64 + */ 65 + #define RENDER_CS_MAX_SAMPLERS_PER_VIEW 2 66 + 67 + /*! 68 * Max number of images that can be given at a single time to the layer 69 * squasher in a single dispatch. 70 */ 71 + #define RENDER_MAX_IMAGES_SIZE (RENDER_MAX_LAYERS * RENDER_CS_MAX_SAMPLERS_PER_VIEW) 72 73 /*! 74 * Maximum number of times that the layer squasher shader can run per ··· 93 //! The binding that the shared layer fragment shader has its source on. 94 #define RENDER_BINDING_LAYER_SHARED_SRC 1 95 96 + /*! 97 + * The maximum number samplers per view that can be used by the compute shader 98 + * for layer composition (layer.comp) 99 + */ 100 + #define RENDER_CS_MAX_SAMPLERS_PER_VIEW 2 101 102 /* 103 * 104 * Util functions. 105 * 106 */ 107 + 108 + /*! 109 + * Determines the maximum number of compositor layers supported based on Vulkan 110 + * device limits and the composition path being used. 111 + * 112 + * @param vk Vulkan bundle containing device properties 113 + * @param use_compute True if using compute pipeline path, false for graphics 114 + * @param desired_max_layers Maximum layers requested by the compositor 115 + * @return Actual maximum layers supported, clamped by device limits (minimum 16) 116 + * 117 + */ 118 + uint32_t 119 + render_max_layers_capable(const struct vk_bundle *vk, bool use_compute, uint32_t desired_max_layers); 120 121 /*! 122 * Create a simplified projection matrix for timewarp. ··· 1231 struct 1232 { 1233 uint32_t value; 1234 + uint32_t padding[3]; // Padding up to a vec4. 1235 } layer_count; 1236 1237 struct xrt_normalized_rect pre_transform; 1238 struct xrt_normalized_rect post_transforms[RENDER_MAX_LAYERS]; 1239 1240 + /*! 1241 + * Corresponds to enum xrt_layer_type and unpremultiplied alpha. 1242 + * 1243 + * std140 uvec2, because it is an array it gets padded to vec4. 1244 + */ 1245 struct 1246 { 1247 + uint32_t layer_type; 1248 + uint32_t unpremultiplied_alpha; 1249 + uint32_t _padding0; 1250 + uint32_t _padding1; 1251 + } layer_data[RENDER_MAX_LAYERS]; 1252 1253 + /*! 1254 + * Which image/sampler(s) correspond to each layer. 1255 + * 1256 + * std140 uvec2, because it is an array it gets padded to vec4. 1257 + */ 1258 struct 1259 { 1260 + uint32_t color_image_index; 1261 + uint32_t depth_image_index; 1262 + 1263 //! @todo Implement separated samplers and images (and change to samplers[2]) 1264 + uint32_t _padding0; 1265 + uint32_t _padding1; 1266 + } image_info[RENDER_MAX_LAYERS]; 1267 1268 //! Shared between cylinder and equirect2. 1269 struct xrt_matrix_4x4 mv_inverse[RENDER_MAX_LAYERS];
+1 -1
src/xrt/compositor/render/render_resources.c
··· 543 r->compute.ubo_binding = 3; 544 545 r->compute.layer.image_array_size = 546 - MIN(vk->features.max_per_stage_descriptor_sampled_images, RENDER_MAX_IMAGES_COUNT(r)); 547 548 549 /*
··· 543 r->compute.ubo_binding = 3; 544 545 r->compute.layer.image_array_size = 546 + MIN(vk->limits.max_per_stage_descriptor_sampled_images, RENDER_MAX_IMAGES_SIZE); 547 548 549 /*
+49
src/xrt/compositor/render/render_util.c
··· 87 * 88 */ 89 90 void 91 render_calc_time_warp_matrix(const struct xrt_pose *src_pose, 92 const struct xrt_fov *src_fov,
··· 87 * 88 */ 89 90 + uint32_t 91 + render_max_layers_capable(const struct vk_bundle *vk, bool use_compute, uint32_t desired_max_layers) 92 + { 93 + /*! 94 + * Graphics pipeline: 95 + * 96 + * This path has no relevant Vulkan device limits that would 97 + * constrain the maximum number of layers (each layer uses a single descriptor 98 + * set bound individually per draw). 99 + */ 100 + if (!use_compute) { 101 + // The min required by OpenXR spec is 16. 102 + return MAX(desired_max_layers, 16); 103 + } 104 + 105 + /*! 106 + * Compute pipeline: 107 + * 108 + * Clamp max layers based on compute pipeline descriptor limits. 109 + * 110 + * The compute path uses an array of combined image samplers, with 111 + * @ref samplers_per_layer samplers needed per layer. We check both the 112 + * per-stage sampler and sampled image limits, then calculate the 113 + * maximum number of complete layers that fit within those limits. 114 + */ 115 + uint32_t desired_image_sampler_count = desired_max_layers * RENDER_CS_MAX_SAMPLERS_PER_VIEW; 116 + 117 + const uint32_t max_sizes[] = { 118 + vk->limits.max_per_stage_descriptor_samplers, 119 + vk->limits.max_per_stage_descriptor_sampled_images, 120 + }; 121 + for (uint32_t i = 0; i < ARRAY_SIZE(max_sizes); ++i) { 122 + desired_image_sampler_count = MIN(desired_image_sampler_count, max_sizes[i]); 123 + } 124 + 125 + const uint32_t calculated_max_layers = desired_image_sampler_count / RENDER_CS_MAX_SAMPLERS_PER_VIEW; 126 + 127 + if (calculated_max_layers < 16) { 128 + VK_WARN(vk, 129 + "Device supports only %u compositor layers due to Vulkan limits. " 130 + "which is below Vulkan minimum of 16. " 131 + "This may indicate a driver bug. Attempting 16 anyway.", 132 + calculated_max_layers); 133 + } 134 + 135 + // The min required by OpenXR spec is 16. 136 + return MAX(calculated_max_layers, 16); 137 + } 138 + 139 void 140 render_calc_time_warp_matrix(const struct xrt_pose *src_pose, 141 const struct xrt_fov *src_fov,
+38 -24
src/xrt/compositor/shaders/layer.comp
··· 1 // Copyright 2021-2023, Collabora Ltd. 2 // Author: Jakob Bornecrantz <jakob@collabora.com> 3 // Author: Christoph Haag <christoph.haag@collabora.com> 4 // SPDX-License-Identifier: BSL-1.0 ··· 7 #extension GL_GOOGLE_include_directive : require 8 9 #include "srgb.inc.glsl" 10 11 - //! @todo should this be a spcialization const? 12 - #define XRT_LAYER_PROJECTION 0 13 - #define XRT_LAYER_PROJECTION_DEPTH 1 14 - #define XRT_LAYER_QUAD 2 15 - #define XRT_LAYER_CUBE 3 16 - #define XRT_LAYER_CYLINDER 4 17 - #define XRT_LAYER_EQUIRECT1 5 18 - #define XRT_LAYER_EQUIRECT2 6 19 20 const float PI = acos(-1); 21 ··· 40 vec4 pre_transform; 41 vec4 post_transform[RENDER_MAX_LAYERS]; 42 43 - // corresponds to enum xrt_layer_type 44 - uvec2 layer_type_and_unpremultiplied[RENDER_MAX_LAYERS]; 45 46 // which image/sampler(s) correspond to each layer 47 - ivec2 images_samplers[RENDER_MAX_LAYERS]; 48 49 // shared between cylinder and equirect2 50 mat4 mv_inverse[RENDER_MAX_LAYERS]; ··· 226 227 vec2 uv_sub = fma(sample_point, ubo.post_transform[layer].zw, ubo.post_transform[layer].xy); 228 229 - uint index = ubo.images_samplers[layer].x; 230 #ifdef DEBUG 231 out_color += texture(source[index], uv_sub) / 2.f; 232 #else ··· 325 326 vec2 uv_sub = fma(sample_point, ubo.post_transform[layer].zw, ubo.post_transform[layer].xy); 327 328 - uint index = ubo.images_samplers[layer].x; 329 #ifdef DEBUG 330 out_color += texture(source[index], uv_sub) / 2.0; 331 #else ··· 341 342 vec4 do_projection(vec2 view_uv, uint layer) 343 { 344 - uint source_image_index = ubo.images_samplers[layer].x; 345 346 // Do any transformation needed. 347 vec2 uv = transform_uv(view_uv, layer); ··· 373 374 vec4 do_quad(vec2 view_uv, uint layer) 375 { 376 - uint source_image_index = ubo.images_samplers[layer].x; 377 378 // center point of the plane in view space. 379 vec3 quad_position = ubo.quad_position[layer].xyz; ··· 459 for (uint layer = 0; layer < layer_count; layer++) { 460 vec4 rgba = vec4(0, 0, 0, 0); 461 462 - switch (ubo.layer_type_and_unpremultiplied[layer].x) { 463 - case XRT_LAYER_CYLINDER: 464 rgba = do_cylinder(view_uv, layer); 465 break; 466 - case XRT_LAYER_EQUIRECT2: 467 rgba = do_equirect2(view_uv, layer); 468 break; 469 - case XRT_LAYER_PROJECTION: 470 - case XRT_LAYER_PROJECTION_DEPTH: 471 rgba = do_projection(view_uv, layer); 472 break; 473 - case XRT_LAYER_QUAD: 474 - rgba = do_quad(view_uv, layer); 475 - break; 476 default: break; 477 } 478 479 - if (ubo.layer_type_and_unpremultiplied[layer].y != 0) { 480 // Unpremultipled blend factor of src.a. 481 accum.rgb = mix(accum.rgb, rgba.rgb, rgba.a); 482 } else {
··· 1 // Copyright 2021-2023, Collabora Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // Author: Jakob Bornecrantz <jakob@collabora.com> 4 // Author: Christoph Haag <christoph.haag@collabora.com> 5 // SPDX-License-Identifier: BSL-1.0 ··· 8 #extension GL_GOOGLE_include_directive : require 9 10 #include "srgb.inc.glsl" 11 + #include "layer_defines.inc.glsl" 12 + 13 + 14 + struct layer_data 15 + { 16 + uint layer_type; 17 + uint unpremultiplied_alpha; 18 19 + // This struct is used in an array, gets padded to vec4. 20 + uint _padding0; 21 + uint _padding1; 22 + }; 23 + 24 + struct image_info 25 + { 26 + uint color_image_index; 27 + uint depth_image_index; 28 + 29 + // This struct is used in an array, gets padded to vec4. 30 + uint _padding0; 31 + uint _padding1; 32 + }; 33 + 34 35 const float PI = acos(-1); 36 ··· 55 vec4 pre_transform; 56 vec4 post_transform[RENDER_MAX_LAYERS]; 57 58 + // Per-layer data. 59 + layer_data layer_data[RENDER_MAX_LAYERS]; 60 61 // which image/sampler(s) correspond to each layer 62 + image_info image_info[RENDER_MAX_LAYERS]; 63 64 // shared between cylinder and equirect2 65 mat4 mv_inverse[RENDER_MAX_LAYERS]; ··· 241 242 vec2 uv_sub = fma(sample_point, ubo.post_transform[layer].zw, ubo.post_transform[layer].xy); 243 244 + uint index = ubo.image_info[layer].color_image_index; 245 #ifdef DEBUG 246 out_color += texture(source[index], uv_sub) / 2.f; 247 #else ··· 340 341 vec2 uv_sub = fma(sample_point, ubo.post_transform[layer].zw, ubo.post_transform[layer].xy); 342 343 + uint index = ubo.image_info[layer].color_image_index; 344 #ifdef DEBUG 345 out_color += texture(source[index], uv_sub) / 2.0; 346 #else ··· 356 357 vec4 do_projection(vec2 view_uv, uint layer) 358 { 359 + uint source_image_index = ubo.image_info[layer].color_image_index; 360 361 // Do any transformation needed. 362 vec2 uv = transform_uv(view_uv, layer); ··· 388 389 vec4 do_quad(vec2 view_uv, uint layer) 390 { 391 + uint source_image_index = ubo.image_info[layer].color_image_index; 392 393 // center point of the plane in view space. 394 vec3 quad_position = ubo.quad_position[layer].xyz; ··· 474 for (uint layer = 0; layer < layer_count; layer++) { 475 vec4 rgba = vec4(0, 0, 0, 0); 476 477 + switch (ubo.layer_data[layer].layer_type) { 478 + case LAYER_COMP_TYPE_QUAD: 479 + rgba = do_quad(view_uv, layer); 480 + break; 481 + case LAYER_COMP_TYPE_CYLINDER: 482 rgba = do_cylinder(view_uv, layer); 483 break; 484 + case LAYER_COMP_TYPE_EQUIRECT2: 485 rgba = do_equirect2(view_uv, layer); 486 break; 487 + case LAYER_COMP_TYPE_PROJECTION: 488 rgba = do_projection(view_uv, layer); 489 break; 490 default: break; 491 } 492 493 + if (ubo.layer_data[layer].unpremultiplied_alpha != 0) { 494 // Unpremultipled blend factor of src.a. 495 accum.rgb = mix(accum.rgb, rgba.rgb, rgba.a); 496 } else {
+22
src/xrt/compositor/shaders/layer_defines.inc.glsl
···
··· 1 + // Copyright 2025, NVIDIA CORPORATION. 2 + // SPDX-License-Identifier: BSL-1.0 3 + 4 + /* 5 + * This file is included by both C code, like comp_render_cs.c, and GLSL code, 6 + * like layer.comp, so it uses a very limited set of features of both. 7 + */ 8 + #ifndef LAYER_DEFINES_INC_GLSL 9 + #define LAYER_DEFINES_INC_GLSL 10 + 11 + //! To handle invalid/unsupported layer types. 12 + #define LAYER_COMP_TYPE_NOOP 0 13 + //! Maps to XRT_LAYER_QUAD (not numerically) 14 + #define LAYER_COMP_TYPE_QUAD 1 15 + //! Maps to XRT_LAYER_CYLINDER (not numerically) 16 + #define LAYER_COMP_TYPE_CYLINDER 2 17 + //! Maps to XRT_LAYER_EQUIRECT2 (not numerically) 18 + #define LAYER_COMP_TYPE_EQUIRECT2 3 19 + //! Maps to XRT_LAYER_PROJECTION[_DEPTH] (not numerically) 20 + #define LAYER_COMP_TYPE_PROJECTION 4 21 + 22 + #endif // LAYER_DEFINES_INC_GLSL
+32 -9
src/xrt/compositor/util/comp_render_cs.c
··· 26 27 #include "render/render_interface.h" 28 29 #include "util/comp_render.h" 30 #include "util/comp_render_helpers.h" 31 #include "util/comp_base.h" ··· 33 34 /* 35 * 36 - * Compute layer data builders. 37 * 38 */ 39 ··· 54 return &sc->images[image_index]; 55 } 56 57 /// Data setup for a cylinder layer 58 static inline void 59 do_cs_cylinder_layer(const struct comp_layer *layer, ··· 113 ubo_data->cylinder_data[cur_layer].central_angle = c->central_angle; 114 ubo_data->cylinder_data[cur_layer].aspect_ratio = c->aspect_ratio; 115 116 - ubo_data->images_samplers[cur_layer].images[0] = cur_image; 117 cur_image++; 118 119 *out_cur_image = cur_image; ··· 176 ubo_data->eq2_data[cur_layer].upper_vertical_angle = eq2->upper_vertical_angle; 177 ubo_data->eq2_data[cur_layer].lower_vertical_angle = eq2->lower_vertical_angle; 178 179 - ubo_data->images_samplers[cur_layer].images[0] = cur_image; 180 cur_image++; 181 182 *out_cur_image = cur_image; ··· 214 // Color 215 src_samplers[cur_image] = clamp_to_border_black; 216 src_image_views[cur_image] = get_image_view(image, layer_data->flags, array_index); 217 - ubo_data->images_samplers[cur_layer + 0].images[0] = cur_image++; 218 219 // Depth 220 if (layer_data->type == XRT_LAYER_PROJECTION_DEPTH) { ··· 224 225 src_samplers[cur_image] = clamp_to_edge; // Edge to keep depth stable at edges. 226 src_image_views[cur_image] = get_image_view(d_image, layer_data->flags, d_array_index); 227 - ubo_data->images_samplers[cur_layer + 0].images[1] = cur_image++; 228 } 229 230 set_post_transform_rect( // ··· 323 ubo_data->quad_position[cur_layer].val = quad_position; 324 ubo_data->quad_normal[cur_layer].val = normal_view_space; 325 ubo_data->inverse_quad_transform[cur_layer] = inverse_quad_transform; 326 - ubo_data->images_samplers[cur_layer].images[0] = cur_image; 327 cur_image++; 328 329 *out_cur_image = cur_image; ··· 660 continue; 661 } 662 663 - ubo_data->layer_type[cur_layer].val = data->type; 664 - ubo_data->layer_type[cur_layer].unpremultiplied = is_layer_unpremultiplied(data); 665 666 // Finally okay to increment the current layer. 667 cur_layer++; ··· 671 ubo_data->layer_count.value = cur_layer; 672 673 for (uint32_t i = cur_layer; i < RENDER_MAX_LAYERS; i++) { 674 - ubo_data->layer_type[i].val = UINT32_MAX; 675 } 676 677 //! @todo: If Vulkan 1.2, use VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT and skip this
··· 26 27 #include "render/render_interface.h" 28 29 + #include "shaders/layer_defines.inc.glsl" 30 + 31 #include "util/comp_render.h" 32 #include "util/comp_render_helpers.h" 33 #include "util/comp_base.h" ··· 35 36 /* 37 * 38 + * Helpers 39 * 40 */ 41 ··· 56 return &sc->images[image_index]; 57 } 58 59 + 60 + static inline uint32_t 61 + xrt_layer_to_cs_layer_type(const struct xrt_layer_data *data) 62 + { 63 + switch (data->type) { 64 + case XRT_LAYER_QUAD: return LAYER_COMP_TYPE_QUAD; 65 + case XRT_LAYER_CYLINDER: return LAYER_COMP_TYPE_CYLINDER; 66 + case XRT_LAYER_EQUIRECT2: return LAYER_COMP_TYPE_EQUIRECT2; 67 + case XRT_LAYER_PROJECTION: 68 + case XRT_LAYER_PROJECTION_DEPTH: return LAYER_COMP_TYPE_PROJECTION; 69 + default: U_LOG_E("Invalid layer type! %u", data->type); return LAYER_COMP_TYPE_NOOP; 70 + } 71 + } 72 + 73 + 74 + /* 75 + * 76 + * Compute layer data builders. 77 + * 78 + */ 79 + 80 /// Data setup for a cylinder layer 81 static inline void 82 do_cs_cylinder_layer(const struct comp_layer *layer, ··· 136 ubo_data->cylinder_data[cur_layer].central_angle = c->central_angle; 137 ubo_data->cylinder_data[cur_layer].aspect_ratio = c->aspect_ratio; 138 139 + ubo_data->image_info[cur_layer].color_image_index = cur_image; 140 cur_image++; 141 142 *out_cur_image = cur_image; ··· 199 ubo_data->eq2_data[cur_layer].upper_vertical_angle = eq2->upper_vertical_angle; 200 ubo_data->eq2_data[cur_layer].lower_vertical_angle = eq2->lower_vertical_angle; 201 202 + ubo_data->image_info[cur_layer].color_image_index = cur_image; 203 cur_image++; 204 205 *out_cur_image = cur_image; ··· 237 // Color 238 src_samplers[cur_image] = clamp_to_border_black; 239 src_image_views[cur_image] = get_image_view(image, layer_data->flags, array_index); 240 + ubo_data->image_info[cur_layer + 0].color_image_index = cur_image++; 241 242 // Depth 243 if (layer_data->type == XRT_LAYER_PROJECTION_DEPTH) { ··· 247 248 src_samplers[cur_image] = clamp_to_edge; // Edge to keep depth stable at edges. 249 src_image_views[cur_image] = get_image_view(d_image, layer_data->flags, d_array_index); 250 + ubo_data->image_info[cur_layer + 0].depth_image_index = cur_image++; 251 } 252 253 set_post_transform_rect( // ··· 346 ubo_data->quad_position[cur_layer].val = quad_position; 347 ubo_data->quad_normal[cur_layer].val = normal_view_space; 348 ubo_data->inverse_quad_transform[cur_layer] = inverse_quad_transform; 349 + ubo_data->image_info[cur_layer].color_image_index = cur_image; 350 cur_image++; 351 352 *out_cur_image = cur_image; ··· 683 continue; 684 } 685 686 + ubo_data->layer_data[cur_layer].layer_type = xrt_layer_to_cs_layer_type(data); 687 + ubo_data->layer_data[cur_layer].unpremultiplied_alpha = is_layer_unpremultiplied(data); 688 689 // Finally okay to increment the current layer. 690 cur_layer++; ··· 694 ubo_data->layer_count.value = cur_layer; 695 696 for (uint32_t i = cur_layer; i < RENDER_MAX_LAYERS; i++) { 697 + ubo_data->layer_data[i].layer_type = LAYER_COMP_TYPE_NOOP; // Explicit no-op. 698 } 699 700 //! @todo: If Vulkan 1.2, use VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT and skip this
+3 -1
src/xrt/compositor/util/comp_swapchain.c
··· 41 { 42 struct comp_swapchain *sc = comp_swapchain(xsc); 43 44 - VK_TRACE(sc->vk, "DESTROY"); 45 46 u_threading_stack_push(&sc->cscs->destroy_swapchains, sc); 47 } ··· 476 static void 477 really_destroy(struct comp_swapchain *sc) 478 { 479 // Reuse close function. 480 comp_swapchain_teardown(sc); 481
··· 41 { 42 struct comp_swapchain *sc = comp_swapchain(xsc); 43 44 + VK_DEBUG(sc->vk, "%p DESTROY(not-actual)", (void *)sc); 45 46 u_threading_stack_push(&sc->cscs->destroy_swapchains, sc); 47 } ··· 476 static void 477 really_destroy(struct comp_swapchain *sc) 478 { 479 + VK_DEBUG(sc->vk, "%p REALLY_DESTROY", (void *)sc); 480 + 481 // Reuse close function. 482 comp_swapchain_teardown(sc); 483
+1 -6
src/xrt/drivers/android/android_sensors.c
··· 133 args->tray_to_lens_distance_meters = params.tray_to_lens_distance; 134 } 135 136 - #define DEG_TO_RAD(x) (float)(x * M_PI / 180.0) 137 args->fov = (struct xrt_fov){.angle_left = -DEG_TO_RAD(angles[0]), 138 .angle_right = DEG_TO_RAD(angles[1]), 139 .angle_down = -DEG_TO_RAD(angles[2]), 140 .angle_up = DEG_TO_RAD(angles[3])}; 141 - #undef DEG_TO_RAD 142 143 ANDROID_INFO(d, "loaded calibration for device %s (%s)", model, vendor); 144 ··· 354 struct android_device *d = U_DEVICE_ALLOCATE(struct android_device, flags, 1, 0); 355 356 d->base.name = XRT_DEVICE_GENERIC_HMD; 357 - d->base.destroy = android_device_destroy; 358 - d->base.update_inputs = u_device_noop_update_inputs; 359 - d->base.set_output = u_device_ni_set_output; 360 - d->base.get_tracked_pose = android_device_get_tracked_pose; 361 d->base.get_view_poses = u_device_get_view_poses; 362 d->base.get_visibility_mask = u_device_get_visibility_mask; 363 d->base.compute_distortion = android_device_compute_distortion;
··· 133 args->tray_to_lens_distance_meters = params.tray_to_lens_distance; 134 } 135 136 args->fov = (struct xrt_fov){.angle_left = -DEG_TO_RAD(angles[0]), 137 .angle_right = DEG_TO_RAD(angles[1]), 138 .angle_down = -DEG_TO_RAD(angles[2]), 139 .angle_up = DEG_TO_RAD(angles[3])}; 140 141 ANDROID_INFO(d, "loaded calibration for device %s (%s)", model, vendor); 142 ··· 352 struct android_device *d = U_DEVICE_ALLOCATE(struct android_device, flags, 1, 0); 353 354 d->base.name = XRT_DEVICE_GENERIC_HMD; 355 + u_device_populate_function_pointers(&d->base, android_device_get_tracked_pose, android_device_destroy); 356 d->base.get_view_poses = u_device_get_view_poses; 357 d->base.get_visibility_mask = u_device_get_visibility_mask; 358 d->base.compute_distortion = android_device_compute_distortion;
+2 -2
src/xrt/drivers/arduino/arduino_device.c
··· 405 406 m_imu_3dof_init(&ad->fusion, M_IMU_3DOF_USE_GRAVITY_DUR_300MS); 407 408 - #define DEG_TO_RAD ((double)M_PI / 180.0) 409 float accel_ticks_to_float = (4.0 * MATH_GRAVITY_M_S2) / INT16_MAX; 410 - float gyro_ticks_to_float = (2000.0 * DEG_TO_RAD) / INT16_MAX; 411 412 m_imu_pre_filter_init(&ad->pre_filter, accel_ticks_to_float, gyro_ticks_to_float); 413 m_imu_pre_filter_set_switch_x_and_y(&ad->pre_filter);
··· 405 406 m_imu_3dof_init(&ad->fusion, M_IMU_3DOF_USE_GRAVITY_DUR_300MS); 407 408 + #define DEG_TO_RAD_MULTIPLIER ((double)M_PI / 180.0) 409 float accel_ticks_to_float = (4.0 * MATH_GRAVITY_M_S2) / INT16_MAX; 410 + float gyro_ticks_to_float = (2000.0 * DEG_TO_RAD_MULTIPLIER) / INT16_MAX; 411 412 m_imu_pre_filter_init(&ad->pre_filter, accel_ticks_to_float, gyro_ticks_to_float); 413 m_imu_pre_filter_set_switch_x_and_y(&ad->pre_filter);
+10 -2
src/xrt/drivers/blubur_s1/blubur_s1_hmd.c
··· 157 blubur_s1_hmd_get_view_poses(struct xrt_device *xdev, 158 const struct xrt_vec3 *default_eye_relation, 159 int64_t at_timestamp_ns, 160 uint32_t view_count, 161 struct xrt_space_relation *out_head_relation, 162 struct xrt_fov *out_fovs, 163 struct xrt_pose *out_poses) 164 { 165 - return u_device_get_view_poses(xdev, default_eye_relation, at_timestamp_ns, view_count, out_head_relation, 166 - out_fovs, out_poses); 167 } 168 169 static void
··· 157 blubur_s1_hmd_get_view_poses(struct xrt_device *xdev, 158 const struct xrt_vec3 *default_eye_relation, 159 int64_t at_timestamp_ns, 160 + enum xrt_view_type view_type, 161 uint32_t view_count, 162 struct xrt_space_relation *out_head_relation, 163 struct xrt_fov *out_fovs, 164 struct xrt_pose *out_poses) 165 { 166 + return u_device_get_view_poses( // 167 + xdev, // 168 + default_eye_relation, // 169 + at_timestamp_ns, // 170 + view_type, // 171 + view_count, // 172 + out_head_relation, // 173 + out_fovs, // 174 + out_poses); // 175 } 176 177 static void
+1 -5
src/xrt/drivers/euroc/euroc_device.c
··· 206 xd->inputs[0].name = XRT_INPUT_SIMPLE_GRIP_POSE; 207 } 208 209 - xd->update_inputs = u_device_noop_update_inputs; 210 - xd->get_tracked_pose = euroc_device_get_tracked_pose; 211 - xd->destroy = euroc_device_destroy; 212 if (is_hmd) { 213 xd->get_view_poses = u_device_get_view_poses; 214 - } else { 215 - xd->get_view_poses = u_device_ni_get_view_poses; 216 } 217 218 u_var_add_root(ed, dev_name, false);
··· 206 xd->inputs[0].name = XRT_INPUT_SIMPLE_GRIP_POSE; 207 } 208 209 + u_device_populate_function_pointers(xd, euroc_device_get_tracked_pose, euroc_device_destroy); 210 if (is_hmd) { 211 xd->get_view_poses = u_device_get_view_poses; 212 } 213 214 u_var_add_root(ed, dev_name, false);
+37 -19
src/xrt/drivers/ht_ctrl_emu/ht_ctrl_emu.cpp
··· 1 // Copyright 2021, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 45 enum cemu_input_index 46 { 47 CEMU_INDEX_HAND_TRACKING, 48 - CEMU_INDEX_SELECT, 49 - CEMU_INDEX_MENU, 50 CEMU_INDEX_GRIP, 51 CEMU_INDEX_AIM, 52 CEMU_NUM_INPUTS, ··· 372 struct cemu_device *dev = cemu_device(xdev); 373 struct cemu_system *sys = dev->sys; 374 375 - if (name != XRT_INPUT_SIMPLE_GRIP_POSE && name != XRT_INPUT_SIMPLE_AIM_POSE) { 376 U_LOG_XDEV_UNSUPPORTED_INPUT(&dev->base, dev->sys->log_level, name); 377 return XRT_ERROR_INPUT_UNSUPPORTED; 378 } ··· 390 391 xret = XRT_SUCCESS; 392 switch (name) { 393 - case XRT_INPUT_SIMPLE_GRIP_POSE: { 394 xret = do_grip_pose(&joint_set, out_relation, sys->grip_offset_from_palm, dev->hand_index); 395 break; 396 } 397 - case XRT_INPUT_SIMPLE_AIM_POSE: { 398 // Assume that now we're doing everything in the timestamp from the hand-tracker, so use 399 // hand_timestamp_ns. This will cause the controller to lag behind but otherwise be correct 400 xret = do_aim_pose(dev, &joint_set, at_timestamp_ns, hand_timestamp_ns, out_relation); ··· 435 U_LOG_CHK_AND_RET(sys->log_level, xret, "xrt_device_get_hand_tracking"); 436 437 if (!joint_set.is_active) { 438 - xdev->inputs[CEMU_INDEX_SELECT].value.boolean = false; 439 - xdev->inputs[CEMU_INDEX_MENU].value.boolean = false; 440 return XRT_SUCCESS; 441 } 442 443 decide(joint_set.values.hand_joint_set_default[XRT_HAND_JOINT_INDEX_TIP].relation.pose.position, 444 joint_set.values.hand_joint_set_default[XRT_HAND_JOINT_THUMB_TIP].relation.pose.position, 445 - &xdev->inputs[CEMU_INDEX_SELECT].value.boolean); 446 447 // For now, all other inputs are off - detecting any gestures more complicated than pinch is too unreliable for 448 // now. 449 - xdev->inputs[CEMU_INDEX_MENU].value.boolean = false; 450 451 return XRT_SUCCESS; 452 } 453 454 455 extern "C" int 456 cemu_devices_create(struct xrt_device *head, struct xrt_device *hands, struct xrt_device **out_xdevs) ··· 480 481 cemud[i]->base.tracking_origin = hands->tracking_origin; 482 483 - cemud[i]->base.name = XRT_DEVICE_SIMPLE_CONTROLLER; 484 cemud[i]->base.supported.hand_tracking = true; 485 cemud[i]->base.supported.orientation_tracking = true; 486 cemud[i]->base.supported.position_tracking = true; 487 - 488 489 cemud[i]->base.inputs[CEMU_INDEX_HAND_TRACKING].name = ht_input_names[i]; 490 - cemud[i]->base.inputs[CEMU_INDEX_SELECT].name = XRT_INPUT_SIMPLE_SELECT_CLICK; 491 - cemud[i]->base.inputs[CEMU_INDEX_MENU].name = XRT_INPUT_SIMPLE_MENU_CLICK; 492 - cemud[i]->base.inputs[CEMU_INDEX_GRIP].name = XRT_INPUT_SIMPLE_GRIP_POSE; 493 - cemud[i]->base.inputs[CEMU_INDEX_AIM].name = XRT_INPUT_SIMPLE_AIM_POSE; 494 495 cemud[i]->base.update_inputs = cemu_device_update_inputs; 496 - cemud[i]->base.get_tracked_pose = cemu_device_get_tracked_pose; 497 - cemud[i]->base.set_output = u_device_ni_set_output; 498 cemud[i]->base.get_hand_tracking = cemu_device_get_hand_tracking; 499 - cemud[i]->base.destroy = cemu_device_destroy; 500 501 cemud[i]->base.device_type = 502 i ? XRT_DEVICE_TYPE_RIGHT_HAND_CONTROLLER : XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER; ··· 513 } 514 515 cemud[i]->ht_input_name = ht_input_names[i]; 516 - 517 cemud[i]->hand_index = i; 518 system->out_hand[i] = cemud[i]; 519
··· 1 // Copyright 2021, Collabora, Ltd. 2 + // Copyright 2024-2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 46 enum cemu_input_index 47 { 48 CEMU_INDEX_HAND_TRACKING, 49 + CEMU_INDEX_PINCH_BOOL, 50 + CEMU_INDEX_PINCH_FLOAT, 51 CEMU_INDEX_GRIP, 52 CEMU_INDEX_AIM, 53 CEMU_NUM_INPUTS, ··· 373 struct cemu_device *dev = cemu_device(xdev); 374 struct cemu_system *sys = dev->sys; 375 376 + if (name != XRT_INPUT_HAND_CTRL_EMU_AIM_POSE && name != XRT_INPUT_HAND_CTRL_EMU_GRIP_POSE) { 377 U_LOG_XDEV_UNSUPPORTED_INPUT(&dev->base, dev->sys->log_level, name); 378 return XRT_ERROR_INPUT_UNSUPPORTED; 379 } ··· 391 392 xret = XRT_SUCCESS; 393 switch (name) { 394 + case XRT_INPUT_HAND_CTRL_EMU_GRIP_POSE: { 395 xret = do_grip_pose(&joint_set, out_relation, sys->grip_offset_from_palm, dev->hand_index); 396 break; 397 } 398 + case XRT_INPUT_HAND_CTRL_EMU_AIM_POSE: { 399 // Assume that now we're doing everything in the timestamp from the hand-tracker, so use 400 // hand_timestamp_ns. This will cause the controller to lag behind but otherwise be correct 401 xret = do_aim_pose(dev, &joint_set, at_timestamp_ns, hand_timestamp_ns, out_relation); ··· 436 U_LOG_CHK_AND_RET(sys->log_level, xret, "xrt_device_get_hand_tracking"); 437 438 if (!joint_set.is_active) { 439 + xdev->inputs[CEMU_INDEX_PINCH_BOOL].value.boolean = false; 440 + xdev->inputs[CEMU_INDEX_PINCH_FLOAT].value.vec1.x = 0.f; 441 return XRT_SUCCESS; 442 } 443 444 decide(joint_set.values.hand_joint_set_default[XRT_HAND_JOINT_INDEX_TIP].relation.pose.position, 445 joint_set.values.hand_joint_set_default[XRT_HAND_JOINT_THUMB_TIP].relation.pose.position, 446 + &xdev->inputs[CEMU_INDEX_PINCH_BOOL].value.boolean); 447 448 // For now, all other inputs are off - detecting any gestures more complicated than pinch is too unreliable for 449 // now. 450 + if (xdev->inputs[CEMU_INDEX_PINCH_BOOL].value.boolean) { 451 + xdev->inputs[CEMU_INDEX_PINCH_FLOAT].value.vec1.x = 1.0f; 452 + } else { 453 + xdev->inputs[CEMU_INDEX_PINCH_FLOAT].value.vec1.x = 0.0f; 454 + } 455 456 return XRT_SUCCESS; 457 } 458 459 + static struct xrt_binding_input_pair simple_inputs[3] = { 460 + {XRT_INPUT_SIMPLE_SELECT_CLICK, XRT_INPUT_HAND_CTRL_EMU_PINCH_BOOL}, 461 + {XRT_INPUT_SIMPLE_GRIP_POSE, XRT_INPUT_HAND_CTRL_EMU_GRIP_POSE}, 462 + {XRT_INPUT_SIMPLE_AIM_POSE, XRT_INPUT_HAND_CTRL_EMU_AIM_POSE}, 463 + }; 464 + 465 + static struct xrt_binding_profile binding_profiles[1] = { 466 + { 467 + .name = XRT_DEVICE_SIMPLE_CONTROLLER, 468 + .inputs = simple_inputs, 469 + .input_count = ARRAY_SIZE(simple_inputs), 470 + .outputs = nullptr, 471 + .output_count = 0, 472 + }, 473 + }; 474 475 extern "C" int 476 cemu_devices_create(struct xrt_device *head, struct xrt_device *hands, struct xrt_device **out_xdevs) ··· 500 501 cemud[i]->base.tracking_origin = hands->tracking_origin; 502 503 + cemud[i]->base.name = XRT_DEVICE_HAND_CTRL_EMU; 504 cemud[i]->base.supported.hand_tracking = true; 505 cemud[i]->base.supported.orientation_tracking = true; 506 cemud[i]->base.supported.position_tracking = true; 507 + cemud[i]->base.binding_profiles = binding_profiles; 508 + cemud[i]->base.binding_profile_count = ARRAY_SIZE(binding_profiles); 509 510 cemud[i]->base.inputs[CEMU_INDEX_HAND_TRACKING].name = ht_input_names[i]; 511 + cemud[i]->base.inputs[CEMU_INDEX_PINCH_BOOL].name = XRT_INPUT_HAND_CTRL_EMU_PINCH_BOOL; 512 + cemud[i]->base.inputs[CEMU_INDEX_PINCH_FLOAT].name = XRT_INPUT_HAND_CTRL_EMU_PINCH_VALUE; 513 + cemud[i]->base.inputs[CEMU_INDEX_GRIP].name = XRT_INPUT_HAND_CTRL_EMU_GRIP_POSE; 514 + cemud[i]->base.inputs[CEMU_INDEX_AIM].name = XRT_INPUT_HAND_CTRL_EMU_AIM_POSE; 515 516 + u_device_populate_function_pointers(&cemud[i]->base, cemu_device_get_tracked_pose, cemu_device_destroy); 517 cemud[i]->base.update_inputs = cemu_device_update_inputs; 518 cemud[i]->base.get_hand_tracking = cemu_device_get_hand_tracking; 519 520 cemud[i]->base.device_type = 521 i ? XRT_DEVICE_TYPE_RIGHT_HAND_CONTROLLER : XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER; ··· 532 } 533 534 cemud[i]->ht_input_name = ht_input_names[i]; 535 cemud[i]->hand_index = i; 536 system->out_hand[i] = cemud[i]; 537
+2 -6
src/xrt/drivers/hydra/hydra_driver.c
··· 345 (XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT | XRT_SPACE_RELATION_ORIENTATION_VALID_BIT) | 346 (XRT_SPACE_RELATION_POSITION_TRACKED_BIT | XRT_SPACE_RELATION_POSITION_VALID_BIT); 347 348 - m_relation_history_estimate_motion(state->relation_history, &space_relation, now, &space_relation); 349 - 350 - m_relation_history_push(state->relation_history, &space_relation, now); 351 352 state->buttons = hydra_read_uint8(&buf); 353 ··· 799 for (size_t i = 0; i < 2; ++i) { 800 struct hydra_device *hd = hs->devs[i]; 801 802 - hd->base.destroy = hydra_device_destroy; 803 hd->base.update_inputs = hydra_device_update_inputs; 804 - hd->base.get_tracked_pose = hydra_device_get_tracked_pose; 805 - hd->base.set_output = u_device_ni_set_output; 806 hd->base.name = XRT_DEVICE_HYDRA; 807 snprintf(hd->base.str, XRT_DEVICE_NAME_LEN, "%s %i", "Razer Hydra Controller", (int)(i + 1)); 808 snprintf(hd->base.serial, XRT_DEVICE_NAME_LEN, "%s%i", "RZRHDRC", (int)(i + 1));
··· 345 (XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT | XRT_SPACE_RELATION_ORIENTATION_VALID_BIT) | 346 (XRT_SPACE_RELATION_POSITION_TRACKED_BIT | XRT_SPACE_RELATION_POSITION_VALID_BIT); 347 348 + m_relation_history_push_with_motion_estimation(state->relation_history, &space_relation, now); 349 350 state->buttons = hydra_read_uint8(&buf); 351 ··· 797 for (size_t i = 0; i < 2; ++i) { 798 struct hydra_device *hd = hs->devs[i]; 799 800 + u_device_populate_function_pointers(&hd->base, hydra_device_get_tracked_pose, hydra_device_destroy); 801 hd->base.update_inputs = hydra_device_update_inputs; 802 hd->base.name = XRT_DEVICE_HYDRA; 803 snprintf(hd->base.str, XRT_DEVICE_NAME_LEN, "%s %i", "Razer Hydra Controller", (int)(i + 1)); 804 snprintf(hd->base.serial, XRT_DEVICE_NAME_LEN, "%s%i", "RZRHDRC", (int)(i + 1));
+11 -2
src/xrt/drivers/multi_wrapper/multi.c
··· 196 get_view_poses(struct xrt_device *xdev, 197 const struct xrt_vec3 *default_eye_relation, 198 int64_t at_timestamp_ns, 199 uint32_t view_count, 200 struct xrt_space_relation *out_head_relation, 201 struct xrt_fov *out_fovs, ··· 203 { 204 struct multi_device *d = (struct multi_device *)xdev; 205 struct xrt_device *target = d->tracking_override.target; 206 - xrt_result_t xret = xrt_device_get_view_poses(target, default_eye_relation, at_timestamp_ns, view_count, 207 - out_head_relation, out_fovs, out_poses); 208 if (xret != XRT_SUCCESS) { 209 return xret; 210 }
··· 196 get_view_poses(struct xrt_device *xdev, 197 const struct xrt_vec3 *default_eye_relation, 198 int64_t at_timestamp_ns, 199 + enum xrt_view_type view_type, 200 uint32_t view_count, 201 struct xrt_space_relation *out_head_relation, 202 struct xrt_fov *out_fovs, ··· 204 { 205 struct multi_device *d = (struct multi_device *)xdev; 206 struct xrt_device *target = d->tracking_override.target; 207 + 208 + xrt_result_t xret = xrt_device_get_view_poses( // 209 + target, // 210 + default_eye_relation, // 211 + at_timestamp_ns, // 212 + view_type, // 213 + view_count, // 214 + out_head_relation, // 215 + out_fovs, // 216 + out_poses); // 217 if (xret != XRT_SUCCESS) { 218 return xret; 219 }
+2
src/xrt/drivers/north_star/ns_hmd.c
··· 389 ns_hmd_get_view_poses(struct xrt_device *xdev, 390 const struct xrt_vec3 *default_eye_relation, 391 int64_t at_timestamp_ns, 392 uint32_t view_count, 393 struct xrt_space_relation *out_head_relation, 394 struct xrt_fov *out_fovs, ··· 402 xdev, // 403 default_eye_relation, // 404 at_timestamp_ns, // 405 view_count, // 406 out_head_relation, // 407 out_fovs, //
··· 389 ns_hmd_get_view_poses(struct xrt_device *xdev, 390 const struct xrt_vec3 *default_eye_relation, 391 int64_t at_timestamp_ns, 392 + enum xrt_view_type view_type, 393 uint32_t view_count, 394 struct xrt_space_relation *out_head_relation, 395 struct xrt_fov *out_fovs, ··· 403 xdev, // 404 default_eye_relation, // 405 at_timestamp_ns, // 406 + view_type, // 407 view_count, // 408 out_head_relation, // 409 out_fovs, //
+2 -5
src/xrt/drivers/ohmd/oh_device.c
··· 757 758 enum u_device_alloc_flags flags = U_DEVICE_ALLOC_HMD; 759 struct oh_device *ohd = U_DEVICE_ALLOCATE(struct oh_device, flags, 1, 0); 760 ohd->base.update_inputs = oh_device_update_inputs; 761 - ohd->base.get_tracked_pose = oh_device_get_tracked_pose; 762 ohd->base.get_view_poses = u_device_get_view_poses; 763 - ohd->base.destroy = oh_device_destroy; 764 ohd->base.inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE; 765 ohd->base.name = XRT_DEVICE_GENERIC_HMD; 766 ohd->ctx = ctx; ··· 1074 1075 enum u_device_alloc_flags flags = 0; 1076 struct oh_device *ohd = U_DEVICE_ALLOCATE(struct oh_device, flags, input_count, output_count); 1077 ohd->base.update_inputs = oh_device_update_inputs; 1078 ohd->base.set_output = oh_device_set_output; 1079 - ohd->base.get_tracked_pose = oh_device_get_tracked_pose; 1080 - ohd->base.get_view_poses = u_device_ni_get_view_poses; 1081 - ohd->base.destroy = oh_device_destroy; 1082 if (oculus_touch) { 1083 ohd->ohmd_device_type = OPENHMD_OCULUS_RIFT_CONTROLLER; 1084 ohd->base.name = XRT_DEVICE_TOUCH_CONTROLLER;
··· 757 758 enum u_device_alloc_flags flags = U_DEVICE_ALLOC_HMD; 759 struct oh_device *ohd = U_DEVICE_ALLOCATE(struct oh_device, flags, 1, 0); 760 + u_device_populate_function_pointers(&ohd->base, oh_device_get_tracked_pose, oh_device_destroy); 761 ohd->base.update_inputs = oh_device_update_inputs; 762 ohd->base.get_view_poses = u_device_get_view_poses; 763 ohd->base.inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE; 764 ohd->base.name = XRT_DEVICE_GENERIC_HMD; 765 ohd->ctx = ctx; ··· 1073 1074 enum u_device_alloc_flags flags = 0; 1075 struct oh_device *ohd = U_DEVICE_ALLOCATE(struct oh_device, flags, input_count, output_count); 1076 + u_device_populate_function_pointers(&ohd->base, oh_device_get_tracked_pose, oh_device_destroy); 1077 ohd->base.update_inputs = oh_device_update_inputs; 1078 ohd->base.set_output = oh_device_set_output; 1079 if (oculus_touch) { 1080 ohd->ohmd_device_type = OPENHMD_OCULUS_RIFT_CONTROLLER; 1081 ohd->base.name = XRT_DEVICE_TOUCH_CONTROLLER;
+6 -8
src/xrt/drivers/pssense/pssense_driver.c
··· 43 44 DEBUG_GET_ONCE_LOG_OPTION(pssense_log, "PSSENSE_LOG", U_LOGGING_INFO) 45 46 - #define DEG_TO_RAD(DEG) (DEG * M_PI / 180.) 47 - 48 static struct xrt_binding_input_pair simple_inputs_pssense[4] = { 49 {XRT_INPUT_SIMPLE_SELECT_CLICK, XRT_INPUT_PSSENSE_TRIGGER_VALUE}, 50 {XRT_INPUT_SIMPLE_MENU_CLICK, XRT_INPUT_PSSENSE_OPTIONS_CLICK}, ··· 84 PSSENSE_INDEX_CIRCLE_TOUCH, 85 PSSENSE_INDEX_SQUEEZE_CLICK, 86 PSSENSE_INDEX_SQUEEZE_TOUCH, 87 - PSSENSE_INDEX_SQUEEZE_PROXIMITY, 88 PSSENSE_INDEX_TRIGGER_CLICK, 89 PSSENSE_INDEX_TRIGGER_TOUCH, 90 PSSENSE_INDEX_TRIGGER_VALUE, 91 - PSSENSE_INDEX_TRIGGER_PROXIMITY, 92 PSSENSE_INDEX_THUMBSTICK, 93 PSSENSE_INDEX_THUMBSTICK_CLICK, 94 PSSENSE_INDEX_THUMBSTICK_TOUCH, ··· 661 pssense->base.inputs[PSSENSE_INDEX_CIRCLE_TOUCH].value.boolean = pssense->state.circle_touch; 662 pssense->base.inputs[PSSENSE_INDEX_SQUEEZE_CLICK].value.boolean = pssense->state.squeeze_click; 663 pssense->base.inputs[PSSENSE_INDEX_SQUEEZE_TOUCH].value.boolean = pssense->state.squeeze_touch; 664 - pssense->base.inputs[PSSENSE_INDEX_SQUEEZE_PROXIMITY].value.vec1.x = pssense->state.squeeze_proximity; 665 pssense->base.inputs[PSSENSE_INDEX_TRIGGER_CLICK].value.boolean = pssense->state.trigger_click; 666 pssense->base.inputs[PSSENSE_INDEX_TRIGGER_TOUCH].value.boolean = pssense->state.trigger_touch; 667 pssense->base.inputs[PSSENSE_INDEX_TRIGGER_VALUE].value.vec1.x = pssense->state.trigger_value; 668 - pssense->base.inputs[PSSENSE_INDEX_TRIGGER_PROXIMITY].value.vec1.x = pssense->state.trigger_proximity; 669 pssense->base.inputs[PSSENSE_INDEX_THUMBSTICK].value.vec2 = pssense->state.thumbstick; 670 pssense->base.inputs[PSSENSE_INDEX_THUMBSTICK_CLICK].value.boolean = pssense->state.thumbstick_click; 671 pssense->base.inputs[PSSENSE_INDEX_THUMBSTICK_TOUCH].value.boolean = pssense->state.thumbstick_touch; ··· 933 SET_INPUT(CIRCLE_TOUCH); 934 SET_INPUT(SQUEEZE_CLICK); 935 SET_INPUT(SQUEEZE_TOUCH); 936 - SET_INPUT(SQUEEZE_PROXIMITY); 937 SET_INPUT(TRIGGER_CLICK); 938 SET_INPUT(TRIGGER_TOUCH); 939 SET_INPUT(TRIGGER_VALUE); 940 - SET_INPUT(TRIGGER_PROXIMITY); 941 SET_INPUT(THUMBSTICK); 942 SET_INPUT(THUMBSTICK_CLICK); 943 SET_INPUT(THUMBSTICK_TOUCH);
··· 43 44 DEBUG_GET_ONCE_LOG_OPTION(pssense_log, "PSSENSE_LOG", U_LOGGING_INFO) 45 46 static struct xrt_binding_input_pair simple_inputs_pssense[4] = { 47 {XRT_INPUT_SIMPLE_SELECT_CLICK, XRT_INPUT_PSSENSE_TRIGGER_VALUE}, 48 {XRT_INPUT_SIMPLE_MENU_CLICK, XRT_INPUT_PSSENSE_OPTIONS_CLICK}, ··· 82 PSSENSE_INDEX_CIRCLE_TOUCH, 83 PSSENSE_INDEX_SQUEEZE_CLICK, 84 PSSENSE_INDEX_SQUEEZE_TOUCH, 85 + PSSENSE_INDEX_SQUEEZE_PROXIMITY_FLOAT, 86 PSSENSE_INDEX_TRIGGER_CLICK, 87 PSSENSE_INDEX_TRIGGER_TOUCH, 88 PSSENSE_INDEX_TRIGGER_VALUE, 89 + PSSENSE_INDEX_TRIGGER_PROXIMITY_FLOAT, 90 PSSENSE_INDEX_THUMBSTICK, 91 PSSENSE_INDEX_THUMBSTICK_CLICK, 92 PSSENSE_INDEX_THUMBSTICK_TOUCH, ··· 659 pssense->base.inputs[PSSENSE_INDEX_CIRCLE_TOUCH].value.boolean = pssense->state.circle_touch; 660 pssense->base.inputs[PSSENSE_INDEX_SQUEEZE_CLICK].value.boolean = pssense->state.squeeze_click; 661 pssense->base.inputs[PSSENSE_INDEX_SQUEEZE_TOUCH].value.boolean = pssense->state.squeeze_touch; 662 + pssense->base.inputs[PSSENSE_INDEX_SQUEEZE_PROXIMITY_FLOAT].value.vec1.x = pssense->state.squeeze_proximity; 663 pssense->base.inputs[PSSENSE_INDEX_TRIGGER_CLICK].value.boolean = pssense->state.trigger_click; 664 pssense->base.inputs[PSSENSE_INDEX_TRIGGER_TOUCH].value.boolean = pssense->state.trigger_touch; 665 pssense->base.inputs[PSSENSE_INDEX_TRIGGER_VALUE].value.vec1.x = pssense->state.trigger_value; 666 + pssense->base.inputs[PSSENSE_INDEX_TRIGGER_PROXIMITY_FLOAT].value.vec1.x = pssense->state.trigger_proximity; 667 pssense->base.inputs[PSSENSE_INDEX_THUMBSTICK].value.vec2 = pssense->state.thumbstick; 668 pssense->base.inputs[PSSENSE_INDEX_THUMBSTICK_CLICK].value.boolean = pssense->state.thumbstick_click; 669 pssense->base.inputs[PSSENSE_INDEX_THUMBSTICK_TOUCH].value.boolean = pssense->state.thumbstick_touch; ··· 931 SET_INPUT(CIRCLE_TOUCH); 932 SET_INPUT(SQUEEZE_CLICK); 933 SET_INPUT(SQUEEZE_TOUCH); 934 + SET_INPUT(SQUEEZE_PROXIMITY_FLOAT); 935 SET_INPUT(TRIGGER_CLICK); 936 SET_INPUT(TRIGGER_TOUCH); 937 SET_INPUT(TRIGGER_VALUE); 938 + SET_INPUT(TRIGGER_PROXIMITY_FLOAT); 939 SET_INPUT(THUMBSTICK); 940 SET_INPUT(THUMBSTICK_CLICK); 941 SET_INPUT(THUMBSTICK_TOUCH);
+1 -4
src/xrt/drivers/realsense/rs_ddev.c
··· 448 449 U_LOG_D("Realsense opts are %i %i %i %i %i\n", rs->enable_mapping, rs->enable_pose_jumping, 450 rs->enable_relocalization, rs->enable_pose_prediction, rs->enable_pose_filtering); 451 - rs->base.update_inputs = u_device_noop_update_inputs; 452 - rs->base.get_tracked_pose = rs_ddev_get_tracked_pose; 453 - rs->base.get_view_poses = u_device_ni_get_view_poses; 454 - rs->base.destroy = rs_ddev_destroy; 455 rs->base.name = XRT_DEVICE_REALSENSE; 456 rs->base.tracking_origin->type = XRT_TRACKING_TYPE_EXTERNAL_SLAM; 457
··· 448 449 U_LOG_D("Realsense opts are %i %i %i %i %i\n", rs->enable_mapping, rs->enable_pose_jumping, 450 rs->enable_relocalization, rs->enable_pose_prediction, rs->enable_pose_filtering); 451 + u_device_populate_function_pointers(&rs->base, rs_ddev_get_tracked_pose, rs_ddev_destroy); 452 rs->base.name = XRT_DEVICE_REALSENSE; 453 rs->base.tracking_origin->type = XRT_TRACKING_TYPE_EXTERNAL_SLAM; 454
+1 -4
src/xrt/drivers/remote/r_device.c
··· 193 struct r_device, flags, input_count, output_count); 194 195 // Setup the basics. 196 rd->base.update_inputs = r_device_update_inputs; 197 - rd->base.get_tracked_pose = r_device_get_tracked_pose; 198 rd->base.get_hand_tracking = r_device_get_hand_tracking; 199 - rd->base.get_view_poses = u_device_ni_get_view_poses; 200 - rd->base.set_output = u_device_ni_set_output; 201 - rd->base.destroy = r_device_destroy; 202 rd->base.tracking_origin = &r->origin; 203 rd->base.supported.orientation_tracking = true; 204 rd->base.supported.position_tracking = true;
··· 193 struct r_device, flags, input_count, output_count); 194 195 // Setup the basics. 196 + u_device_populate_function_pointers(&rd->base, r_device_get_tracked_pose, r_device_destroy); 197 rd->base.update_inputs = r_device_update_inputs; 198 rd->base.get_hand_tracking = r_device_get_hand_tracking; 199 rd->base.tracking_origin = &r->origin; 200 rd->base.supported.orientation_tracking = true; 201 rd->base.supported.position_tracking = true;
+3 -5
src/xrt/drivers/remote/r_hmd.c
··· 78 r_hmd_get_view_poses(struct xrt_device *xdev, 79 const struct xrt_vec3 *default_eye_relation, 80 int64_t at_timestamp_ns, 81 uint32_t view_count, 82 struct xrt_space_relation *out_head_relation, 83 struct xrt_fov *out_fovs, ··· 90 xdev, // 91 default_eye_relation, // 92 at_timestamp_ns, // 93 view_count, // 94 out_head_relation, // 95 out_fovs, // ··· 122 struct r_hmd, flags, input_count, output_count); 123 124 // Setup the basics. 125 - rh->base.update_inputs = u_device_noop_update_inputs; 126 - rh->base.get_tracked_pose = r_hmd_get_tracked_pose; 127 - rh->base.get_hand_tracking = u_device_ni_get_hand_tracking; 128 rh->base.get_view_poses = r_hmd_get_view_poses; 129 - rh->base.set_output = u_device_ni_set_output; 130 - rh->base.destroy = r_hmd_destroy; 131 rh->base.tracking_origin = &r->origin; 132 rh->base.supported.orientation_tracking = true; 133 rh->base.supported.position_tracking = true;
··· 78 r_hmd_get_view_poses(struct xrt_device *xdev, 79 const struct xrt_vec3 *default_eye_relation, 80 int64_t at_timestamp_ns, 81 + enum xrt_view_type view_type, 82 uint32_t view_count, 83 struct xrt_space_relation *out_head_relation, 84 struct xrt_fov *out_fovs, ··· 91 xdev, // 92 default_eye_relation, // 93 at_timestamp_ns, // 94 + view_type, // 95 view_count, // 96 out_head_relation, // 97 out_fovs, // ··· 124 struct r_hmd, flags, input_count, output_count); 125 126 // Setup the basics. 127 + u_device_populate_function_pointers(&rh->base, r_hmd_get_tracked_pose, r_hmd_destroy); 128 rh->base.get_view_poses = r_hmd_get_view_poses; 129 rh->base.tracking_origin = &r->origin; 130 rh->base.supported.orientation_tracking = true; 131 rh->base.supported.position_tracking = true;
+10 -7
src/xrt/drivers/rift/rift_hmd.c
··· 230 rift_hmd_get_view_poses(struct xrt_device *xdev, 231 const struct xrt_vec3 *default_eye_relation, 232 int64_t at_timestamp_ns, 233 uint32_t view_count, 234 struct xrt_space_relation *out_head_relation, 235 struct xrt_fov *out_fovs, ··· 237 { 238 struct rift_hmd *hmd = rift_hmd(xdev); 239 240 - return u_device_get_view_poses(xdev, // 241 - &(struct xrt_vec3){hmd->extra_display_info.icd, 0.0f, 0.0f}, // 242 - at_timestamp_ns, // 243 - view_count, // 244 - out_head_relation, // 245 - out_fovs, // 246 - out_poses); 247 } 248 249 static xrt_result_t
··· 230 rift_hmd_get_view_poses(struct xrt_device *xdev, 231 const struct xrt_vec3 *default_eye_relation, 232 int64_t at_timestamp_ns, 233 + enum xrt_view_type view_type, 234 uint32_t view_count, 235 struct xrt_space_relation *out_head_relation, 236 struct xrt_fov *out_fovs, ··· 238 { 239 struct rift_hmd *hmd = rift_hmd(xdev); 240 241 + return u_device_get_view_poses( // 242 + xdev, // 243 + &(struct xrt_vec3){hmd->extra_display_info.icd, 0.0f, 0.0f}, // 244 + at_timestamp_ns, // 245 + view_type, // 246 + view_count, // 247 + out_head_relation, // 248 + out_fovs, // 249 + out_poses); 250 } 251 252 static xrt_result_t
-1
src/xrt/drivers/rift/rift_interface.h
··· 37 #define IMU_SAMPLE_RATE (1000) // 1000hz 38 #define NS_PER_SAMPLE (1000 * 1000) // 1ms (1,000,000 ns) per sample 39 40 - #define DEG_TO_RAD(DEG) (DEG * M_PI / 180.0) 41 #define MICROMETERS_TO_METERS(microns) (float)microns / 1000000.0f 42 43 // value taken from LibOVR 0.4.4
··· 37 #define IMU_SAMPLE_RATE (1000) // 1000hz 38 #define NS_PER_SAMPLE (1000 * 1000) // 1ms (1,000,000 ns) per sample 39 40 #define MICROMETERS_TO_METERS(microns) (float)microns / 1000000.0f 41 42 // value taken from LibOVR 0.4.4
+1 -5
src/xrt/drivers/rift_s/rift_s_controller.c
··· 40 /* Set to 1 to print controller states continuously */ 41 #define DUMP_CONTROLLER_STATE 0 42 43 - #define DEG_TO_RAD(D) ((D)*M_PI / 180.) 44 - 45 static struct xrt_binding_input_pair simple_inputs_rift_s[4] = { 46 {XRT_INPUT_SIMPLE_SELECT_CLICK, XRT_INPUT_TOUCH_TRIGGER_VALUE}, 47 {XRT_INPUT_SIMPLE_MENU_CLICK, XRT_INPUT_TOUCH_MENU_CLICK}, ··· 606 607 os_mutex_init(&ctrl->mutex); 608 609 ctrl->base.update_inputs = rift_s_controller_update_inputs; 610 - ctrl->base.set_output = u_device_ni_set_output; 611 - ctrl->base.get_tracked_pose = rift_s_controller_get_tracked_pose; 612 ctrl->base.get_view_poses = u_device_get_view_poses; 613 - ctrl->base.destroy = rift_s_controller_destroy; 614 ctrl->base.name = XRT_DEVICE_TOUCH_CONTROLLER; 615 ctrl->base.device_type = device_type; 616
··· 40 /* Set to 1 to print controller states continuously */ 41 #define DUMP_CONTROLLER_STATE 0 42 43 static struct xrt_binding_input_pair simple_inputs_rift_s[4] = { 44 {XRT_INPUT_SIMPLE_SELECT_CLICK, XRT_INPUT_TOUCH_TRIGGER_VALUE}, 45 {XRT_INPUT_SIMPLE_MENU_CLICK, XRT_INPUT_TOUCH_MENU_CLICK}, ··· 604 605 os_mutex_init(&ctrl->mutex); 606 607 + u_device_populate_function_pointers(&ctrl->base, rift_s_controller_get_tracked_pose, rift_s_controller_destroy); 608 ctrl->base.update_inputs = rift_s_controller_update_inputs; 609 ctrl->base.get_view_poses = u_device_get_view_poses; 610 ctrl->base.name = XRT_DEVICE_TOUCH_CONTROLLER; 611 ctrl->base.device_type = device_type; 612
-2
src/xrt/drivers/rift_s/rift_s_hmd.c
··· 40 41 #include "rift_s_hmd.h" 42 43 - #define DEG_TO_RAD(D) ((D)*M_PI / 180.) 44 - 45 46 static xrt_result_t 47 rift_s_get_tracked_pose(struct xrt_device *xdev,
··· 40 41 #include "rift_s_hmd.h" 42 43 44 static xrt_result_t 45 rift_s_get_tracked_pose(struct xrt_device *xdev,
+2
src/xrt/drivers/sample/sample_hmd.c
··· 132 sample_hmd_get_view_poses(struct xrt_device *xdev, 133 const struct xrt_vec3 *default_eye_relation, 134 int64_t at_timestamp_ns, 135 uint32_t view_count, 136 struct xrt_space_relation *out_head_relation, 137 struct xrt_fov *out_fovs, ··· 145 xdev, // 146 default_eye_relation, // 147 at_timestamp_ns, // 148 view_count, // 149 out_head_relation, // 150 out_fovs, //
··· 132 sample_hmd_get_view_poses(struct xrt_device *xdev, 133 const struct xrt_vec3 *default_eye_relation, 134 int64_t at_timestamp_ns, 135 + enum xrt_view_type view_type, 136 uint32_t view_count, 137 struct xrt_space_relation *out_head_relation, 138 struct xrt_fov *out_fovs, ··· 146 xdev, // 147 default_eye_relation, // 148 at_timestamp_ns, // 149 + view_type, // 150 view_count, // 151 out_head_relation, // 152 out_fovs, //
+2 -2
src/xrt/drivers/simula/svr_hmd.c
··· 97 return XRT_SUCCESS; 98 } 99 100 - #define DEG_TO_RAD(DEG) (DEG * M_PI / 180.) 101 - 102 static xrt_result_t 103 svr_hmd_get_view_poses(struct xrt_device *xdev, 104 const struct xrt_vec3 *default_eye_relation, 105 int64_t at_timestamp_ns, 106 uint32_t view_count, 107 struct xrt_space_relation *out_head_relation, 108 struct xrt_fov *out_fovs, ··· 115 xdev, // 116 default_eye_relation, // 117 at_timestamp_ns, // 118 view_count, // 119 out_head_relation, // 120 out_fovs, //
··· 97 return XRT_SUCCESS; 98 } 99 100 static xrt_result_t 101 svr_hmd_get_view_poses(struct xrt_device *xdev, 102 const struct xrt_vec3 *default_eye_relation, 103 int64_t at_timestamp_ns, 104 + enum xrt_view_type view_type, 105 uint32_t view_count, 106 struct xrt_space_relation *out_head_relation, 107 struct xrt_fov *out_fovs, ··· 114 xdev, // 115 default_eye_relation, // 116 at_timestamp_ns, // 117 + view_type, // 118 view_count, // 119 out_head_relation, // 120 out_fovs, //
+1 -5
src/xrt/drivers/simulated/simulated_controller.c
··· 347 348 // Allocate. 349 struct simulated_device *sd = U_DEVICE_ALLOCATE(struct simulated_device, flags, input_count, output_count); 350 sd->base.update_inputs = simulated_device_update_inputs; 351 - sd->base.get_tracked_pose = simulated_device_get_tracked_pose; 352 - sd->base.get_hand_tracking = u_device_ni_get_hand_tracking; 353 - sd->base.get_view_poses = u_device_ni_get_view_poses; 354 - sd->base.set_output = u_device_ni_set_output; 355 - sd->base.destroy = simulated_device_destroy; 356 sd->base.tracking_origin = origin; 357 sd->base.supported.orientation_tracking = true; 358 sd->base.supported.position_tracking = true;
··· 347 348 // Allocate. 349 struct simulated_device *sd = U_DEVICE_ALLOCATE(struct simulated_device, flags, input_count, output_count); 350 + u_device_populate_function_pointers(&sd->base, simulated_device_get_tracked_pose, simulated_device_destroy); 351 sd->base.update_inputs = simulated_device_update_inputs; 352 sd->base.tracking_origin = origin; 353 sd->base.supported.orientation_tracking = true; 354 sd->base.supported.position_tracking = true;
+365 -101
src/xrt/drivers/steamvr_lh/device.cpp
··· 9 */ 10 11 #include "math/m_api.h" 12 #include "math/m_relation_history.h" 13 #include "math/m_space.h" 14 ··· 16 17 #include "util/u_debug.h" 18 #include "util/u_device.h" 19 - #include "util/u_hand_simulation.h" 20 #include "util/u_hand_tracking.h" 21 #include "util/u_logging.h" 22 #include "util/u_json.hpp" 23 24 #include "xrt/xrt_defines.h" 25 #include "xrt/xrt_device.h" 26 #include "xrt/xrt_prober.h" ··· 34 #include <cmath> 35 #include <functional> 36 #include <cstring> 37 #include <thread> 38 #include <algorithm> 39 #include <map> 40 - 41 42 #define DEV_ERR(...) U_LOG_IFL_E(ctx->log_level, __VA_ARGS__) 43 #define DEV_WARN(...) U_LOG_IFL_W(ctx->log_level, __VA_ARGS__) ··· 52 xrt_device_name name; 53 const std::vector<xrt_input_name> poses; 54 const std::unordered_map<std::string_view, xrt_input_name> non_poses; 55 - const std::unordered_map<std::string_view, IndexFinger> finger_curls; 56 }; 57 58 namespace { 59 // Adding support for a new controller is a simple as adding it here. 60 // The key for the map needs to be the name of input profile as indicated by the lighthouse driver. 61 const std::unordered_map<std::string_view, InputClass> controller_classes{ ··· 66 { 67 XRT_INPUT_VIVE_GRIP_POSE, 68 XRT_INPUT_VIVE_AIM_POSE, 69 }, 70 { 71 {"/input/application_menu/click", XRT_INPUT_VIVE_MENU_CLICK}, ··· 76 {"/input/trigger/value", XRT_INPUT_VIVE_TRIGGER_VALUE}, 77 {"/input/grip/click", XRT_INPUT_VIVE_SQUEEZE_CLICK}, 78 {"/input/trackpad", XRT_INPUT_VIVE_TRACKPAD}, 79 - }, 80 - { 81 - // No fingers on this controller type 82 }, 83 }, 84 }, ··· 89 { 90 XRT_INPUT_INDEX_GRIP_POSE, 91 XRT_INPUT_INDEX_AIM_POSE, 92 }, 93 { 94 {"/input/system/click", XRT_INPUT_INDEX_SYSTEM_CLICK}, ··· 109 {"/input/trackpad/touch", XRT_INPUT_INDEX_TRACKPAD_TOUCH}, 110 {"/input/trackpad", XRT_INPUT_INDEX_TRACKPAD}, 111 }, 112 - { 113 - {"/input/finger/index", IndexFinger::Index}, 114 - {"/input/finger/middle", IndexFinger::Middle}, 115 - {"/input/finger/ring", IndexFinger::Ring}, 116 - {"/input/finger/pinky", IndexFinger::Pinky}, 117 - }, 118 }, 119 }, 120 { ··· 130 {"/input/application_menu/click", XRT_INPUT_VIVE_TRACKER_MENU_CLICK}, 131 {"/input/trigger/click", XRT_INPUT_VIVE_TRACKER_TRIGGER_CLICK}, 132 {"/input/thumb/click", XRT_INPUT_VIVE_TRACKER_TRACKPAD_CLICK}, 133 - }, 134 - { 135 - // No fingers on this controller type 136 }, 137 }, 138 }, ··· 150 {"/input/trigger/click", XRT_INPUT_VIVE_TRACKER_TRIGGER_CLICK}, 151 {"/input/thumb/click", XRT_INPUT_VIVE_TRACKER_TRACKPAD_CLICK}, 152 }, 153 - { 154 - // No fingers on this controller type 155 - }, 156 }, 157 }, 158 }; 159 - 160 int64_t 161 chrono_timestamp_ns() 162 { ··· 214 215 return brightness; 216 } 217 } // namespace 218 219 Property::Property(vr::PropertyTypeTag_t tag, void *buffer, uint32_t bufferSize) ··· 249 this->xrt_device::get_hand_tracking = 250 &device_bouncer<ControllerDevice, &ControllerDevice::get_hand_tracking, xrt_result_t>; 251 this->xrt_device::set_output = &device_bouncer<ControllerDevice, &ControllerDevice::set_output, xrt_result_t>; 252 } 253 254 Device::~Device() ··· 285 init_chaperone(builder.steam_install); 286 } 287 288 - void 289 - ControllerDevice::set_hand_tracking_hand(xrt_input_name name) 290 - { 291 - if (has_index_hand_tracking) { 292 - inputs_map["HAND"]->name = name; 293 - } 294 - } 295 - 296 // NOTE: No operations that would force inputs_vec or finger_inputs_vec to reallocate (such as insertion) 297 // should be done after this function is called, otherwise the pointers in inputs_map/finger_inputs_map 298 // would be invalidated. ··· 314 inputs_map.insert({path, &inputs_vec.back()}); 315 } 316 317 - has_index_hand_tracking = debug_get_bool_option_lh_emulate_hand() && !input_class->finger_curls.empty(); 318 - if (has_index_hand_tracking) { 319 - finger_inputs_vec.reserve(input_class->finger_curls.size()); 320 - for (const auto &[path, finger] : input_class->finger_curls) { 321 - assert(finger_inputs_vec.capacity() >= finger_inputs_vec.size() + 1); 322 - finger_inputs_vec.push_back({0, finger, 0.f}); 323 - finger_inputs_map.insert({path, &finger_inputs_vec.back()}); 324 - } 325 - assert(inputs_vec.capacity() >= inputs_vec.size() + 1); 326 - inputs_vec.push_back({true, 0, XRT_INPUT_HT_CONFORMING_LEFT, {}}); 327 - inputs_map.insert({std::string_view("HAND"), &inputs_vec.back()}); 328 - } 329 - 330 this->inputs = inputs_vec.data(); 331 this->input_count = inputs_vec.size(); 332 } ··· 345 } 346 } 347 348 - const std::vector<std::string> FACE_BUTTONS = { 349 - "/input/system/touch", "/input/a/touch", "/input/b/touch", "/input/thumbstick/touch", "/input/trackpad/touch", 350 - }; 351 352 void 353 - ControllerDevice::update_hand_tracking(int64_t desired_timestamp_ns, struct xrt_hand_joint_set *out) 354 { 355 - if (!has_index_hand_tracking) 356 return; 357 - float index = 0.f; 358 - float middle = 0.f; 359 - float ring = 0.f; 360 - float pinky = 0.f; 361 - float thumb = 0.f; 362 - for (auto fi : finger_inputs_vec) { 363 - switch (fi.finger) { 364 - case IndexFinger::Index: index = fi.value; break; 365 - case IndexFinger::Middle: middle = fi.value; break; 366 - case IndexFinger::Ring: ring = fi.value; break; 367 - case IndexFinger::Pinky: pinky = fi.value; break; 368 - default: break; 369 - } 370 } 371 - for (const auto &name : FACE_BUTTONS) { 372 - auto *input = get_input_from_name(name); 373 - if (input && input->value.boolean) { 374 - thumb = 1.f; 375 - break; 376 - } 377 } 378 - auto curl_values = u_hand_tracking_curl_values{pinky, ring, middle, index, thumb}; 379 380 - struct xrt_space_relation hand_relation = {}; 381 - m_relation_history_get(relation_hist, desired_timestamp_ns, &hand_relation); 382 383 - u_hand_sim_simulate_for_valve_index_knuckles(&curl_values, get_xrt_hand(), &hand_relation, out); 384 385 - struct xrt_relation_chain chain = {}; 386 387 - struct xrt_pose pose_offset = XRT_POSE_IDENTITY; 388 - vive_poses_get_pose_offset(name, device_type, inputs_map["HAND"]->name, &pose_offset); 389 390 - m_relation_chain_push_pose(&chain, &pose_offset); 391 - m_relation_chain_push_relation(&chain, &hand_relation); 392 - m_relation_chain_resolve(&chain, &out->hand_pose); 393 } 394 395 xrt_input * 396 Device::get_input_from_name(const std::string_view name) 397 { 398 // Return nullptr without any other output to suppress a pile of useless warnings found below. 399 - if (name == "/input/finger/index" || name == "/input/finger/middle" || name == "/input/finger/ring" || 400 - name == "/input/finger/pinky") { 401 return nullptr; 402 } 403 auto input = inputs_map.find(name); ··· 447 return XRT_SUCCESS; 448 } 449 450 - IndexFingerInput * 451 - ControllerDevice::get_finger_from_name(const std::string_view name) 452 - { 453 - auto finger = finger_inputs_map.find(name); 454 - if (finger == finger_inputs_map.end()) { 455 - DEV_WARN("requested unknown finger name %s for device %s", std::string(name).c_str(), serial); 456 - return nullptr; 457 - } 458 - return finger->second; 459 - } 460 - 461 xrt_result_t 462 ControllerDevice::get_hand_tracking(enum xrt_input_name name, 463 int64_t desired_timestamp_ns, 464 struct xrt_hand_joint_set *out_value, 465 int64_t *out_timestamp_ns) 466 { 467 - if (!has_index_hand_tracking) 468 return XRT_ERROR_NOT_IMPLEMENTED; 469 - update_hand_tracking(desired_timestamp_ns, out_value); 470 - out_value->is_active = true; 471 - hand_tracking_timestamp = desired_timestamp_ns; 472 - *out_timestamp_ns = hand_tracking_timestamp; 473 return XRT_SUCCESS; 474 } 475 ··· 527 Device::get_pose(at_timestamp_ns, &rel); 528 529 xrt_pose pose_offset = XRT_POSE_IDENTITY; 530 - vive_poses_get_pose_offset(input_class->name, device_type, name, &pose_offset); 531 532 xrt_relation_chain relchain = {}; 533 534 m_relation_chain_push_pose(&relchain, &pose_offset); ··· 605 xrt_result_t 606 HmdDevice::get_view_poses(const xrt_vec3 *default_eye_relation, 607 uint64_t at_timestamp_ns, 608 uint32_t view_count, 609 xrt_space_relation *out_head_relation, 610 xrt_fov *out_fovs, ··· 617 this, // 618 &eye_relation, // 619 at_timestamp_ns, // 620 view_count, // 621 out_head_relation, // 622 out_fovs, // ··· 804 relation.linear_velocity = copy_vec3(newPose.vecVelocity); 805 relation.angular_velocity = copy_vec3(newPose.vecAngularVelocity); 806 807 math_quat_rotate_vec3(&relation.pose.orientation, &relation.angular_velocity, &relation.angular_velocity); 808 - 809 - // apply over local transform 810 - const xrt_pose local = copy_pose(newPose.qDriverFromHeadRotation, newPose.vecDriverFromHeadTranslation); 811 math_pose_transform(&relation.pose, &local, &relation.pose); 812 813 // apply world transform ··· 868 } 869 870 void 871 - HmdDevice::set_scanout_type(xrt_scanout_direction direction, uint64_t time_ns) 872 { 873 auto set = [this, direction, time_ns] { 874 hmd_parts->base.screens[0].scanout_direction = direction; ··· 1047 case vr::Prop_DisplayFrequency_Float: { 1048 assert(prop.unBufferSize == sizeof(float)); 1049 float freq = *static_cast<float *>(prop.pvBuffer); 1050 - uint64_t interval_ns = (1.f / freq) * 1e9f; 1051 set_nominal_frame_interval(interval_ns); 1052 if (variant == VIVE_VARIANT_PRO) { 1053 set_scanout_type(XRT_SCANOUT_DIRECTION_TOP_TO_BOTTOM, interval_ns * 1600.0 / 1624.0); ··· 1129 const std::string_view name = {static_cast<char *>(prop.pvBuffer), prop.unBufferSize}; 1130 if (name == "SlimeVR Virtual Tracker\0"sv) { 1131 static const InputClass input_class = { 1132 - XRT_DEVICE_VIVE_TRACKER, {XRT_INPUT_GENERIC_TRACKER_POSE}, {}, {}}; 1133 this->name = input_class.name; 1134 set_input_class(&input_class); 1135 this->manufacturer = name.substr(0, name.find_first_of(' ')); ··· 1148 } 1149 case vr::TrackedControllerRole_RightHand: { 1150 this->device_type = XRT_DEVICE_TYPE_RIGHT_HAND_CONTROLLER; 1151 - set_hand_tracking_hand(XRT_INPUT_HT_CONFORMING_RIGHT); 1152 break; 1153 } 1154 case vr::TrackedControllerRole_LeftHand: { 1155 this->device_type = XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER; 1156 - set_hand_tracking_hand(XRT_INPUT_HT_CONFORMING_LEFT); 1157 break; 1158 } 1159 case vr::TrackedControllerRole_OptOut: {
··· 9 */ 10 11 #include "math/m_api.h" 12 + #include "math/m_predict.h" 13 #include "math/m_relation_history.h" 14 #include "math/m_space.h" 15 ··· 17 18 #include "util/u_debug.h" 19 #include "util/u_device.h" 20 #include "util/u_hand_tracking.h" 21 #include "util/u_logging.h" 22 #include "util/u_json.hpp" 23 24 + #include "util/u_time.h" 25 #include "xrt/xrt_defines.h" 26 #include "xrt/xrt_device.h" 27 #include "xrt/xrt_prober.h" ··· 35 #include <cmath> 36 #include <functional> 37 #include <cstring> 38 + #include <numbers> 39 + #include <openvr_driver.h> 40 #include <thread> 41 #include <algorithm> 42 #include <map> 43 44 #define DEV_ERR(...) U_LOG_IFL_E(ctx->log_level, __VA_ARGS__) 45 #define DEV_WARN(...) U_LOG_IFL_W(ctx->log_level, __VA_ARGS__) ··· 54 xrt_device_name name; 55 const std::vector<xrt_input_name> poses; 56 const std::unordered_map<std::string_view, xrt_input_name> non_poses; 57 }; 58 59 namespace { 60 + using namespace std::string_view_literals; 61 + // From https://github.com/ValveSoftware/openvr/blob/master/docs/Driver_API_Documentation.md#bone-structure 62 + enum HandSkeletonBone : int32_t 63 + { 64 + eBone_Root = 0, 65 + eBone_Wrist, 66 + eBone_Thumb0, 67 + eBone_Thumb1, 68 + eBone_Thumb2, 69 + eBone_Thumb3, 70 + eBone_IndexFinger0, 71 + eBone_IndexFinger1, 72 + eBone_IndexFinger2, 73 + eBone_IndexFinger3, 74 + eBone_IndexFinger4, 75 + eBone_MiddleFinger0, 76 + eBone_MiddleFinger1, 77 + eBone_MiddleFinger2, 78 + eBone_MiddleFinger3, 79 + eBone_MiddleFinger4, 80 + eBone_RingFinger0, 81 + eBone_RingFinger1, 82 + eBone_RingFinger2, 83 + eBone_RingFinger3, 84 + eBone_RingFinger4, 85 + eBone_PinkyFinger0, 86 + eBone_PinkyFinger1, 87 + eBone_PinkyFinger2, 88 + eBone_PinkyFinger3, 89 + eBone_PinkyFinger4, 90 + eBone_Aux_Thumb, 91 + eBone_Aux_IndexFinger, 92 + eBone_Aux_MiddleFinger, 93 + eBone_Aux_RingFinger, 94 + eBone_Aux_PinkyFinger, 95 + eBone_Count 96 + }; 97 + 98 // Adding support for a new controller is a simple as adding it here. 99 // The key for the map needs to be the name of input profile as indicated by the lighthouse driver. 100 const std::unordered_map<std::string_view, InputClass> controller_classes{ ··· 105 { 106 XRT_INPUT_VIVE_GRIP_POSE, 107 XRT_INPUT_VIVE_AIM_POSE, 108 + XRT_INPUT_GENERIC_PALM_POSE, 109 }, 110 { 111 {"/input/application_menu/click", XRT_INPUT_VIVE_MENU_CLICK}, ··· 116 {"/input/trigger/value", XRT_INPUT_VIVE_TRIGGER_VALUE}, 117 {"/input/grip/click", XRT_INPUT_VIVE_SQUEEZE_CLICK}, 118 {"/input/trackpad", XRT_INPUT_VIVE_TRACKPAD}, 119 }, 120 }, 121 }, ··· 126 { 127 XRT_INPUT_INDEX_GRIP_POSE, 128 XRT_INPUT_INDEX_AIM_POSE, 129 + XRT_INPUT_GENERIC_PALM_POSE, 130 }, 131 { 132 {"/input/system/click", XRT_INPUT_INDEX_SYSTEM_CLICK}, ··· 147 {"/input/trackpad/touch", XRT_INPUT_INDEX_TRACKPAD_TOUCH}, 148 {"/input/trackpad", XRT_INPUT_INDEX_TRACKPAD}, 149 }, 150 }, 151 }, 152 { ··· 162 {"/input/application_menu/click", XRT_INPUT_VIVE_TRACKER_MENU_CLICK}, 163 {"/input/trigger/click", XRT_INPUT_VIVE_TRACKER_TRIGGER_CLICK}, 164 {"/input/thumb/click", XRT_INPUT_VIVE_TRACKER_TRACKPAD_CLICK}, 165 }, 166 }, 167 }, ··· 179 {"/input/trigger/click", XRT_INPUT_VIVE_TRACKER_TRIGGER_CLICK}, 180 {"/input/thumb/click", XRT_INPUT_VIVE_TRACKER_TRACKPAD_CLICK}, 181 }, 182 }, 183 }, 184 }; 185 int64_t 186 chrono_timestamp_ns() 187 { ··· 239 240 return brightness; 241 } 242 + xrt_pose 243 + bone_to_pose(const vr::VRBoneTransform_t &bone) 244 + { 245 + return xrt_pose{xrt_quat{bone.orientation.x, bone.orientation.y, bone.orientation.z, bone.orientation.w}, 246 + xrt_vec3{bone.position.v[0], bone.position.v[1], bone.position.v[2]}}; 247 + } 248 } // namespace 249 250 Property::Property(vr::PropertyTypeTag_t tag, void *buffer, uint32_t bufferSize) ··· 280 this->xrt_device::get_hand_tracking = 281 &device_bouncer<ControllerDevice, &ControllerDevice::get_hand_tracking, xrt_result_t>; 282 this->xrt_device::set_output = &device_bouncer<ControllerDevice, &ControllerDevice::set_output, xrt_result_t>; 283 + 284 + this->inputs_map["/skeleton/hand/left"] = &hand_tracking_inputs[XRT_HAND_LEFT]; 285 + this->inputs_map["/skeleton/hand/right"] = &hand_tracking_inputs[XRT_HAND_RIGHT]; 286 } 287 288 Device::~Device() ··· 319 init_chaperone(builder.steam_install); 320 } 321 322 // NOTE: No operations that would force inputs_vec or finger_inputs_vec to reallocate (such as insertion) 323 // should be done after this function is called, otherwise the pointers in inputs_map/finger_inputs_map 324 // would be invalidated. ··· 340 inputs_map.insert({path, &inputs_vec.back()}); 341 } 342 343 this->inputs = inputs_vec.data(); 344 this->input_count = inputs_vec.size(); 345 } ··· 358 } 359 } 360 361 + void 362 + ControllerDevice::set_active_hand(xrt_hand hand) 363 + { 364 + this->skeleton_hand = hand; 365 + } 366 + 367 + namespace { 368 + xrt_quat 369 + from_euler_angles(float x, float y, float z) 370 + { 371 + const xrt_vec3 v{x, y, z}; 372 + xrt_quat out; 373 + math_quat_from_euler_angles(&v, &out); 374 + return out; 375 + } 376 + 377 + constexpr float pi = std::numbers::pi_v<float>; 378 + constexpr float frac_pi_2 = pi / 2.0f; 379 + 380 + // OpenVR skeletal poses are defined with the palms facing each other, but OpenXR 381 + // hand tracking is defined with the palms facing down. These per hand rotations 382 + // are necessary to translate to what OpenXR expects. 383 + const xrt_quat right_hand_rotate = from_euler_angles(0.0f, frac_pi_2, 0.0f); 384 + const xrt_quat left_hand_rotate = from_euler_angles(0.0f, frac_pi_2, pi); 385 + 386 + xrt_quat 387 + right_wrist_rotate_init() 388 + { 389 + const xrt_quat rot1 = from_euler_angles(0.0f, 0.0f, frac_pi_2); 390 + const xrt_quat rot2 = from_euler_angles(0.0f, pi, 0.0f); 391 + xrt_quat ret; 392 + math_quat_rotate(&rot1, &rot2, &ret); 393 + return ret; 394 + } 395 + xrt_quat 396 + left_wrist_rotate_init() 397 + { 398 + const xrt_quat rot1 = from_euler_angles(pi, 0.0f, 0.0f); 399 + const xrt_quat rot2 = from_euler_angles(0.0f, 0.0f, -frac_pi_2); 400 + xrt_quat ret; 401 + math_quat_rotate(&rot1, &rot2, &ret); 402 + return ret; 403 + } 404 + 405 + const xrt_quat right_wrist_rotate = right_wrist_rotate_init(); 406 + const xrt_quat left_wrist_rotate = left_wrist_rotate_init(); 407 + 408 + xrt_pose 409 + generate_palm_pose(const xrt_pose &metacarpal_pose, const xrt_pose &proximal_pose) 410 + { 411 + // OpenVR doesn't provide a palm joint, but the OpenXR palm is in the middle of 412 + // the metacarpal and proximal bones of the middle finger, 413 + // so we'll interpolate between them to generate it. 414 + xrt_pose pose; 415 + math_pose_interpolate(&metacarpal_pose, &proximal_pose, 0.5, &pose); 416 + // Use metacarpal orientation, because the palm shouldn't really rotate 417 + pose.orientation = metacarpal_pose.orientation; 418 + return pose; 419 + } 420 + 421 + xrt_pose 422 + palm_offset_index(xrt_hand hand) 423 + { 424 + // Taken from: 425 + // https://github.com/ValveSoftware/OpenXR-Canonical-Pose-Tool/blob/5e6f3f6db584d58483058ff3262e7eef02c3acfd/dist/steamvr/cpt_SteamVR-valve_index_controller.xml#L1 426 + switch (hand) { 427 + case XRT_HAND_LEFT: 428 + return xrt_pose{.orientation = xrt_quat{.x = -0.46, .y = -0.02, .z = -0.01, .w = 0.89}, 429 + .position = xrt_vec3{.x = -0.015, .y = 0.0, .z = 0.001}}; 430 + case XRT_HAND_RIGHT: 431 + return xrt_pose{.orientation = xrt_quat{.x = -0.46, .y = 0.02, .z = 0.01, .w = 0.89}, 432 + .position = xrt_vec3{.x = 0.015, .y = 0.0, .z = 0.001}}; 433 + } 434 + 435 + return {}; 436 + } 437 + 438 + } // namespace 439 440 void 441 + ControllerDevice::set_skeleton(std::span<const vr::VRBoneTransform_t> bones, 442 + xrt_hand hand, 443 + bool is_simulated, 444 + const char *path) 445 { 446 + assert(bones.size() == eBone_Count); 447 + generate_palm_pose_offset(bones, hand); 448 + if (!is_simulated && debug_get_bool_option_lh_emulate_hand()) { 449 + assert(inputs_vec.capacity() >= inputs_vec.size() + 1); 450 + const xrt_input_name tracker_name = 451 + (hand == XRT_HAND_RIGHT) ? XRT_INPUT_HT_CONFORMING_RIGHT : XRT_INPUT_HT_CONFORMING_LEFT; 452 + inputs_vec.push_back({true, 0, tracker_name, {}}); 453 + inputs_map.insert({path, &inputs_vec.back()}); 454 + this->input_count = inputs_vec.size(); 455 + has_hand_tracking = true; 456 + } 457 + } 458 + 459 + void 460 + ControllerDevice::generate_palm_pose_offset(std::span<const vr::VRBoneTransform_t> bones, xrt_hand hand) 461 + { 462 + if (this->input_class->name == XRT_DEVICE_INDEX_CONTROLLER) { 463 + xrt_pose grip_offset; 464 + vive_poses_get_pose_offset(this->input_class->name, this->device_type, XRT_INPUT_INDEX_GRIP_POSE, 465 + &grip_offset); 466 + auto offset = palm_offset_index(hand); 467 + math_pose_transform(&grip_offset, &offset, &offset); 468 + palm_offsets[hand] = offset; 469 return; 470 } 471 + // The palm pose offset is generated from the OpenVR provided skeleton. 472 + // https://github.com/ValveSoftware/openvr/blob/master/docs/Driver_API_Documentation.md#notes-on-the-skeleton 473 + 474 + xrt_pose root = bone_to_pose(bones[eBone_Root]); 475 + xrt_pose wrist = bone_to_pose(bones[eBone_Wrist]); 476 + xrt_pose metacarpal = bone_to_pose(bones[eBone_MiddleFinger0]); 477 + xrt_pose proximal = bone_to_pose(bones[eBone_MiddleFinger1]); 478 + 479 + // The skeleton pose is given with the Root bone as origin. 480 + // To convert from this, according to OpenVR docs we transform the wrist 481 + // and then counter-transform the metacarpals 482 + xrt_pose root_inv; 483 + math_pose_invert(&root, &root_inv); 484 + math_pose_transform(&root_inv, &wrist, &wrist); 485 + math_pose_transform(&root, &metacarpal, &metacarpal); 486 + math_pose_transform(&wrist, &metacarpal, &metacarpal); 487 + math_pose_transform(&metacarpal, &proximal, &proximal); 488 + 489 + xrt_pose palm_offset = generate_palm_pose(metacarpal, proximal); 490 + xrt_quat palm_rotate = from_euler_angles(0.0f, 0.0f, frac_pi_2); 491 + 492 + switch (hand) { 493 + case XRT_HAND_LEFT: { 494 + math_quat_rotate(&palm_offset.orientation, &left_hand_rotate, &palm_offset.orientation); 495 + math_quat_invert(&palm_rotate, &palm_rotate); 496 + break; 497 } 498 + case XRT_HAND_RIGHT: { 499 + math_quat_rotate(&palm_offset.orientation, &right_hand_rotate, &palm_offset.orientation); 500 + break; 501 + } 502 + } 503 + math_quat_rotate(&palm_offset.orientation, &palm_rotate, &palm_offset.orientation); 504 + 505 + // For controllers like the Vive Wands which can be in any hand, it will store both the left hand 506 + // and the right hand skeletons, so we need to store both. 507 + palm_offsets[hand] = palm_offset; 508 + } 509 + 510 + void 511 + ControllerDevice::update_skeleton_transforms(std::span<const vr::VRBoneTransform_t> bones) 512 + { 513 + if (!has_hand_tracking) { 514 + return; 515 + } 516 + 517 + assert(bones.size() == eBone_Count); 518 + 519 + xrt_hand_joint_set joint_set; 520 + int64_t timestamp; 521 + if (!m_relation_history_get_latest(relation_hist, &timestamp, &joint_set.hand_pose)) { 522 + return; 523 + } 524 + joint_set.is_active = true; 525 + auto &joints = joint_set.values.hand_joint_set_default; 526 + 527 + xrt_pose root = bone_to_pose(bones[eBone_Root]); 528 + xrt_pose wrist = bone_to_pose(bones[eBone_Wrist]); 529 + 530 + // Here we're doing the same transformation as seen in generate_palm_pose_offset. 531 + xrt_pose root_inv; 532 + math_pose_invert(&root, &root_inv); 533 + math_pose_transform(&root_inv, &wrist, &wrist); 534 + 535 + constexpr auto valid_flags = (enum xrt_space_relation_flags)( 536 + XRT_SPACE_RELATION_POSITION_VALID_BIT | XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | 537 + XRT_SPACE_RELATION_POSITION_TRACKED_BIT | XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT); 538 + 539 + xrt_pose wrist_xr = wrist; 540 + 541 + switch (skeleton_hand) { 542 + case XRT_HAND_LEFT: { 543 + math_quat_rotate(&wrist_xr.orientation, &left_wrist_rotate, &wrist_xr.orientation); 544 + break; 545 + } 546 + case XRT_HAND_RIGHT: { 547 + math_quat_rotate(&wrist_xr.orientation, &right_wrist_rotate, &wrist_xr.orientation); 548 + break; 549 + } 550 + } 551 552 + joints[XRT_HAND_JOINT_WRIST].relation.pose = wrist_xr; 553 + joints[XRT_HAND_JOINT_WRIST].relation.relation_flags = valid_flags; 554 555 + xrt_pose parent_pose; 556 + for (int joint = XRT_HAND_JOINT_THUMB_METACARPAL; joint <= XRT_HAND_JOINT_LITTLE_TIP; ++joint) { 557 + // Luckily openvr and openxr joint values match 558 + xrt_pose pose = bone_to_pose(bones[joint]); 559 + joints[joint].relation.relation_flags = valid_flags; 560 561 + if (u_hand_joint_is_metacarpal((xrt_hand_joint)joint)) { 562 + // Counter transform metacarpals 563 + math_pose_transform(&root, &pose, &pose); 564 + math_pose_transform(&wrist, &pose, &pose); 565 + } else { 566 + math_pose_transform(&parent_pose, &pose, &pose); 567 + } 568 569 + parent_pose = pose; 570 + 571 + // Rotate joint to OpenXR orientation 572 + switch (skeleton_hand) { 573 + case XRT_HAND_LEFT: math_quat_rotate(&pose.orientation, &left_hand_rotate, &pose.orientation); break; 574 + case XRT_HAND_RIGHT: math_quat_rotate(&pose.orientation, &right_hand_rotate, &pose.orientation); break; 575 + } 576 + joints[joint].relation.pose = pose; 577 + } 578 + 579 + joints[XRT_HAND_JOINT_PALM].relation.relation_flags = valid_flags; 580 + joints[XRT_HAND_JOINT_PALM].relation.pose = 581 + generate_palm_pose(joints[XRT_HAND_JOINT_MIDDLE_METACARPAL].relation.pose, 582 + joints[XRT_HAND_JOINT_MIDDLE_PROXIMAL].relation.pose); 583 584 + u_hand_joints_apply_joint_width(&joint_set); 585 + this->joint_history.push_back(JointsWithTimestamp{joint_set, timestamp}); 586 } 587 588 xrt_input * 589 Device::get_input_from_name(const std::string_view name) 590 { 591 + static const std::array ignore_inputs = {"/input/finger/index"sv, "/input/finger/middle"sv, 592 + "/input/finger/ring"sv, "/input/finger/pinky"sv, 593 + "/input/grip/touch"sv}; 594 + 595 // Return nullptr without any other output to suppress a pile of useless warnings found below. 596 + if (std::ranges::find(ignore_inputs, name) != std::ranges::end(ignore_inputs)) { 597 return nullptr; 598 } 599 auto input = inputs_map.find(name); ··· 643 return XRT_SUCCESS; 644 } 645 646 xrt_result_t 647 ControllerDevice::get_hand_tracking(enum xrt_input_name name, 648 int64_t desired_timestamp_ns, 649 struct xrt_hand_joint_set *out_value, 650 int64_t *out_timestamp_ns) 651 { 652 + if (!has_hand_tracking) { 653 return XRT_ERROR_NOT_IMPLEMENTED; 654 + } 655 + 656 + // No handtracking data? 657 + if (joint_history.empty()) { 658 + out_value->is_active = false; 659 + return XRT_SUCCESS; 660 + } 661 + 662 + const auto it = std::ranges::lower_bound(joint_history, desired_timestamp_ns, {}, 663 + [](const JointsWithTimestamp &joint) { return joint.timestamp; }); 664 + 665 + auto predict_joint_set = [out_value, out_timestamp_ns, 666 + desired_timestamp_ns](const JointsWithTimestamp &joints) { 667 + out_value->is_active = joints.joint_set.is_active; 668 + int64_t delta_ns = desired_timestamp_ns - joints.timestamp; 669 + double delta_s = time_ns_to_s(delta_ns); 670 + 671 + *out_timestamp_ns = desired_timestamp_ns; 672 + m_predict_relation(&joints.joint_set.hand_pose, delta_s, &out_value->hand_pose); 673 + for (int i = 0; i < XRT_HAND_JOINT_COUNT; i++) { 674 + auto &new_joint = joints.joint_set.values.hand_joint_set_default[i]; 675 + auto &interp_joint = out_value->values.hand_joint_set_default[i]; 676 + 677 + m_predict_relation(&new_joint.relation, delta_s, &interp_joint.relation); 678 + interp_joint.radius = new_joint.radius; 679 + } 680 + }; 681 + 682 + if (it == joint_history.end()) { 683 + // Timestamp is newer than anything in history 684 + predict_joint_set(joint_history.back()); 685 + } else if (desired_timestamp_ns == it->timestamp) { 686 + *out_value = it->joint_set; 687 + *out_timestamp_ns = it->timestamp; 688 + } else if (it == joint_history.begin()) { 689 + // Timestamp is older than anything in history 690 + predict_joint_set(joint_history.front()); 691 + } else { 692 + // Interpolate 693 + auto it_previous = it - 1; 694 + 695 + auto delta_before = desired_timestamp_ns - it_previous->timestamp; 696 + auto delta_after = it->timestamp - desired_timestamp_ns; 697 + float lerp_amt = (float)delta_before / (float)(delta_after - delta_before); 698 + 699 + auto interpolate = [lerp_amt](xrt_space_relation &previous, xrt_space_relation &next, 700 + xrt_space_relation &out) { 701 + auto flags = (xrt_space_relation_flags)(previous.relation_flags & next.relation_flags); 702 + m_space_relation_interpolate(&previous, &next, lerp_amt, flags, &out); 703 + }; 704 + 705 + interpolate(it_previous->joint_set.hand_pose, it->joint_set.hand_pose, out_value->hand_pose); 706 + 707 + for (int i = 0; i < XRT_HAND_JOINT_COUNT; i++) { 708 + auto &prev = it_previous->joint_set.values.hand_joint_set_default[i]; 709 + auto &next = it->joint_set.values.hand_joint_set_default[i]; 710 + auto &out = out_value->values.hand_joint_set_default[i]; 711 + interpolate(prev.relation, next.relation, out.relation); 712 + out.radius = next.radius; 713 + } 714 + 715 + *out_timestamp_ns = desired_timestamp_ns; 716 + } 717 + 718 return XRT_SUCCESS; 719 } 720 ··· 772 Device::get_pose(at_timestamp_ns, &rel); 773 774 xrt_pose pose_offset = XRT_POSE_IDENTITY; 775 776 + if (name == XRT_INPUT_GENERIC_PALM_POSE) { 777 + if (!palm_offsets[skeleton_hand].has_value()) { 778 + DEV_ERR("%s hand skeleton has not been initialized", 779 + skeleton_hand == XRT_HAND_LEFT ? "left" : "right"); 780 + *out_relation = XRT_SPACE_RELATION_ZERO; 781 + return XRT_SUCCESS; 782 + } 783 + pose_offset = *palm_offsets[skeleton_hand]; 784 + } else { 785 + vive_poses_get_pose_offset(input_class->name, device_type, name, &pose_offset); 786 + } 787 xrt_relation_chain relchain = {}; 788 789 m_relation_chain_push_pose(&relchain, &pose_offset); ··· 860 xrt_result_t 861 HmdDevice::get_view_poses(const xrt_vec3 *default_eye_relation, 862 uint64_t at_timestamp_ns, 863 + xrt_view_type view_type, 864 uint32_t view_count, 865 xrt_space_relation *out_head_relation, 866 xrt_fov *out_fovs, ··· 873 this, // 874 &eye_relation, // 875 at_timestamp_ns, // 876 + view_type, // 877 view_count, // 878 out_head_relation, // 879 out_fovs, // ··· 1061 relation.linear_velocity = copy_vec3(newPose.vecVelocity); 1062 relation.angular_velocity = copy_vec3(newPose.vecAngularVelocity); 1063 1064 + // local transform (head to driver offset) 1065 + const xrt_pose local = copy_pose(newPose.qDriverFromHeadRotation, newPose.vecDriverFromHeadTranslation); 1066 + 1067 + // IMU linear velocity contribution due to rotation around driver origin (tangential velocity) 1068 + xrt_vec3 tangential_velocity; 1069 + math_vec3_cross(&relation.angular_velocity, &local.position, &tangential_velocity); 1070 + math_quat_rotate_vec3(&relation.pose.orientation, &tangential_velocity, &tangential_velocity); 1071 + math_vec3_accum(&tangential_velocity, &relation.linear_velocity); 1072 + 1073 + // apply local transform 1074 math_quat_rotate_vec3(&relation.pose.orientation, &relation.angular_velocity, &relation.angular_velocity); 1075 math_pose_transform(&relation.pose, &local, &relation.pose); 1076 1077 // apply world transform ··· 1132 } 1133 1134 void 1135 + HmdDevice::set_scanout_type(xrt_scanout_direction direction, int64_t time_ns) 1136 { 1137 auto set = [this, direction, time_ns] { 1138 hmd_parts->base.screens[0].scanout_direction = direction; ··· 1311 case vr::Prop_DisplayFrequency_Float: { 1312 assert(prop.unBufferSize == sizeof(float)); 1313 float freq = *static_cast<float *>(prop.pvBuffer); 1314 + int64_t interval_ns = (1.f / freq) * 1e9f; 1315 set_nominal_frame_interval(interval_ns); 1316 if (variant == VIVE_VARIANT_PRO) { 1317 set_scanout_type(XRT_SCANOUT_DIRECTION_TOP_TO_BOTTOM, interval_ns * 1600.0 / 1624.0); ··· 1393 const std::string_view name = {static_cast<char *>(prop.pvBuffer), prop.unBufferSize}; 1394 if (name == "SlimeVR Virtual Tracker\0"sv) { 1395 static const InputClass input_class = { 1396 + XRT_DEVICE_VIVE_TRACKER, {XRT_INPUT_GENERIC_TRACKER_POSE}, {}}; 1397 this->name = input_class.name; 1398 set_input_class(&input_class); 1399 this->manufacturer = name.substr(0, name.find_first_of(' ')); ··· 1412 } 1413 case vr::TrackedControllerRole_RightHand: { 1414 this->device_type = XRT_DEVICE_TYPE_RIGHT_HAND_CONTROLLER; 1415 + set_active_hand(XRT_HAND_RIGHT); 1416 break; 1417 } 1418 case vr::TrackedControllerRole_LeftHand: { 1419 this->device_type = XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER; 1420 + set_active_hand(XRT_HAND_LEFT); 1421 break; 1422 } 1423 case vr::TrackedControllerRole_OptOut: {
+26 -11
src/xrt/drivers/steamvr_lh/device.hpp
··· 11 12 #include "math/m_relation_history.h" 13 14 #include "xrt/xrt_device.h" 15 16 #include "vive/vive_common.h" ··· 23 #include <vector> 24 #include <memory> 25 #include <unordered_map> 26 27 #include <condition_variable> 28 #include <mutex> ··· 176 xrt_result_t 177 get_view_poses(const xrt_vec3 *default_eye_relation, 178 uint64_t at_timestamp_ns, 179 uint32_t view_count, 180 xrt_space_relation *out_head_relation, 181 xrt_fov *out_fovs, ··· 211 set_nominal_frame_interval(uint64_t interval_ns); 212 213 void 214 - set_scanout_type(enum xrt_scanout_direction direction, uint64_t time_ns); 215 216 std::condition_variable hmd_parts_cv; 217 std::mutex hmd_parts_mut; ··· 233 xrt_result_t 234 get_tracked_pose(xrt_input_name name, uint64_t at_timestamp_ns, xrt_space_relation *out_relation) override; 235 236 - IndexFingerInput * 237 - get_finger_from_name(std::string_view name); 238 - 239 xrt_result_t 240 get_hand_tracking(enum xrt_input_name name, 241 int64_t desired_timestamp_ns, ··· 246 get_xrt_hand(); 247 248 void 249 - update_hand_tracking(int64_t desired_timestamp_ns, struct xrt_hand_joint_set *out); 250 251 protected: 252 void 253 set_input_class(const InputClass *input_class); 254 255 private: 256 vr::VRInputComponentHandle_t haptic_handle{0}; 257 std::unique_ptr<xrt_output> output{nullptr}; 258 - bool has_index_hand_tracking{false}; 259 - std::vector<IndexFingerInput> finger_inputs_vec; 260 - std::unordered_map<std::string_view, IndexFingerInput *> finger_inputs_map; 261 - uint64_t hand_tracking_timestamp; 262 263 - void 264 - set_hand_tracking_hand(xrt_input_name name); 265 266 vr::ETrackedPropertyError 267 handle_property_write(const vr::PropertyWrite_t &prop) override;
··· 11 12 #include "math/m_relation_history.h" 13 14 + #include "util/u_template_historybuf.hpp" 15 #include "xrt/xrt_device.h" 16 17 #include "vive/vive_common.h" ··· 24 #include <vector> 25 #include <memory> 26 #include <unordered_map> 27 + #include <span> 28 + #include <array> 29 + #include <optional> 30 31 #include <condition_variable> 32 #include <mutex> ··· 180 xrt_result_t 181 get_view_poses(const xrt_vec3 *default_eye_relation, 182 uint64_t at_timestamp_ns, 183 + xrt_view_type view_type, 184 uint32_t view_count, 185 xrt_space_relation *out_head_relation, 186 xrt_fov *out_fovs, ··· 216 set_nominal_frame_interval(uint64_t interval_ns); 217 218 void 219 + set_scanout_type(enum xrt_scanout_direction direction, int64_t time_ns); 220 221 std::condition_variable hmd_parts_cv; 222 std::mutex hmd_parts_mut; ··· 238 xrt_result_t 239 get_tracked_pose(xrt_input_name name, uint64_t at_timestamp_ns, xrt_space_relation *out_relation) override; 240 241 xrt_result_t 242 get_hand_tracking(enum xrt_input_name name, 243 int64_t desired_timestamp_ns, ··· 248 get_xrt_hand(); 249 250 void 251 + update_skeleton_transforms(std::span<const vr::VRBoneTransform_t> bones); 252 + 253 + void 254 + set_skeleton(std::span<const vr::VRBoneTransform_t> bones, xrt_hand hand, bool is_simulated, const char *path); 255 + 256 + void 257 + set_active_hand(xrt_hand hand); 258 259 protected: 260 void 261 set_input_class(const InputClass *input_class); 262 + 263 + void 264 + generate_palm_pose_offset(std::span<const vr::VRBoneTransform_t> bones, xrt_hand hand); 265 266 private: 267 vr::VRInputComponentHandle_t haptic_handle{0}; 268 std::unique_ptr<xrt_output> output{nullptr}; 269 + bool has_hand_tracking{false}; 270 + xrt_hand skeleton_hand = XRT_HAND_LEFT; 271 + std::array<std::optional<xrt_pose>, 2> palm_offsets; 272 + std::array<xrt_input, 2> hand_tracking_inputs{}; 273 274 + struct JointsWithTimestamp 275 + { 276 + xrt_hand_joint_set joint_set; 277 + int64_t timestamp{0}; 278 + }; 279 + xrt::auxiliary::util::HistoryBuffer<JointsWithTimestamp, 5> joint_history; 280 281 vr::ETrackedPropertyError 282 handle_property_write(const vr::PropertyWrite_t &prop) override;
+2 -17
src/xrt/drivers/steamvr_lh/interfaces/context.hpp
··· 28 29 #include "xrt/xrt_tracking.h" 30 31 - enum IndexFinger 32 - { 33 - Invalid = -1, 34 - Index = 1, 35 - Middle, 36 - Ring, 37 - Pinky, 38 - }; 39 - 40 - struct IndexFingerInput 41 - { 42 - int64_t timestamp; 43 - IndexFinger finger; 44 - float value; 45 - }; 46 - 47 struct xrt_input; 48 class Device; 49 class Context final : public xrt_tracking_origin, 50 public vr::IVRDriverContext, 51 public vr::IVRServerDriverHost, ··· 70 71 std::vector<vr::VRInputComponentHandle_t> handles; 72 std::unordered_map<vr::VRInputComponentHandle_t, xrt_input *> handle_to_input; 73 - std::unordered_map<vr::VRInputComponentHandle_t, IndexFingerInput *> handle_to_finger; 74 struct Vec2Components 75 { 76 vr::VRInputComponentHandle_t x; ··· 78 }; 79 std::unordered_map<vr::VRInputComponentHandle_t, Vec2Components *> vec2_inputs; 80 std::unordered_map<xrt_input *, std::unique_ptr<Vec2Components>> vec2_input_to_components; 81 82 struct Event 83 {
··· 28 29 #include "xrt/xrt_tracking.h" 30 31 struct xrt_input; 32 class Device; 33 + class ControllerDevice; 34 class Context final : public xrt_tracking_origin, 35 public vr::IVRDriverContext, 36 public vr::IVRServerDriverHost, ··· 55 56 std::vector<vr::VRInputComponentHandle_t> handles; 57 std::unordered_map<vr::VRInputComponentHandle_t, xrt_input *> handle_to_input; 58 struct Vec2Components 59 { 60 vr::VRInputComponentHandle_t x; ··· 62 }; 63 std::unordered_map<vr::VRInputComponentHandle_t, Vec2Components *> vec2_inputs; 64 std::unordered_map<xrt_input *, std::unique_ptr<Vec2Components>> vec2_input_to_components; 65 + std::unordered_map<vr::VRInputComponentHandle_t, ControllerDevice *> skeleton_to_controller; 66 67 struct Event 68 {
+57 -24
src/xrt/drivers/steamvr_lh/steamvr_lh.cpp
··· 162 MATCH_INTERFACE(vr::IVRDriverManager_Version, &man); 163 MATCH_INTERFACE(vr::IVRBlockQueue_Version, &blockqueue); 164 MATCH_INTERFACE(vr::IVRPaths_Version, &paths); 165 166 // Internal interfaces 167 MATCH_INTERFACE("IVRServer_XXX", &server); ··· 479 return vr::VRInputError_InvalidHandle; 480 } 481 if (xrt_input *input = device->get_input_from_name(name); input) { 482 - CTX_DEBUG("creating component %s", name); 483 vr::VRInputComponentHandle_t handle = new_handle(); 484 handle_to_input[handle] = input; 485 *pHandle = handle; 486 - } else if (device != hmd) { 487 - auto *controller = static_cast<ControllerDevice *>(device); 488 - if (IndexFingerInput *finger = controller->get_finger_from_name(name); finger) { 489 - CTX_DEBUG("creating finger component %s", name); 490 - vr::VRInputComponentHandle_t handle = new_handle(); 491 - handle_to_finger[handle] = finger; 492 - *pHandle = handle; 493 - } 494 } 495 return vr::VRInputError_None; 496 } ··· 593 } else { 594 input->value.vec1.x = fNewValue; 595 } 596 - } else { 597 - if (ulComponent != vr::k_ulInvalidInputComponentHandle) { 598 - if (auto finger_input = handle_to_finger.find(ulComponent); 599 - finger_input != handle_to_finger.end() && finger_input->second) { 600 - auto now = std::chrono::steady_clock::now(); 601 - std::chrono::duration<double, std::chrono::seconds::period> offset_dur(fTimeOffset); 602 - std::chrono::duration offset = (now + offset_dur).time_since_epoch(); 603 - int64_t timestamp = 604 - std::chrono::duration_cast<std::chrono::nanoseconds>(offset).count(); 605 - finger_input->second->timestamp = timestamp; 606 - finger_input->second->value = fNewValue; 607 - } else { 608 - CTX_WARN("Unmapped component %" PRIu64, ulComponent); 609 - } 610 - } 611 } 612 return vr::VRInputError_None; 613 } ··· 649 uint32_t unGripLimitTransformCount, 650 vr::VRInputComponentHandle_t *pHandle) 651 { 652 return vr::VRInputError_None; 653 } 654 ··· 658 const vr::VRBoneTransform_t *pTransforms, 659 uint32_t unTransformCount) 660 { 661 return vr::VRInputError_None; 662 } 663 ··· 754 out_roles->left = left; 755 out_roles->right = right; 756 out_roles->gamepad = gamepad; 757 } 758 759 return XRT_SUCCESS;
··· 162 MATCH_INTERFACE(vr::IVRDriverManager_Version, &man); 163 MATCH_INTERFACE(vr::IVRBlockQueue_Version, &blockqueue); 164 MATCH_INTERFACE(vr::IVRPaths_Version, &paths); 165 + // This version of the interface is not in a public header. 166 + // Luckily it seems to be compatible with the previous version. 167 + MATCH_INTERFACE("IVRPaths_002", &paths); 168 169 // Internal interfaces 170 MATCH_INTERFACE("IVRServer_XXX", &server); ··· 482 return vr::VRInputError_InvalidHandle; 483 } 484 if (xrt_input *input = device->get_input_from_name(name); input) { 485 + CTX_DEBUG("creating component %s for %p", name, (void *)device); 486 vr::VRInputComponentHandle_t handle = new_handle(); 487 handle_to_input[handle] = input; 488 *pHandle = handle; 489 } 490 return vr::VRInputError_None; 491 } ··· 588 } else { 589 input->value.vec1.x = fNewValue; 590 } 591 } 592 return vr::VRInputError_None; 593 } ··· 629 uint32_t unGripLimitTransformCount, 630 vr::VRInputComponentHandle_t *pHandle) 631 { 632 + std::string_view path(pchSkeletonPath); // should be /skeleton/hand/left or /skeleton/hand/right 633 + std::string_view skeleton_pfx("/skeleton/hand/"); 634 + if (!path.starts_with(skeleton_pfx)) { 635 + CTX_ERR("Got invalid skeleton path: %s", std::string(path).c_str()); 636 + return vr::VRInputError_InvalidSkeleton; 637 + } 638 + 639 + if (auto ret = create_component_common(ulContainer, pchSkeletonPath, pHandle); ret != vr::VRInputError_None) { 640 + return ret; 641 + } 642 + 643 + auto *device = static_cast<ControllerDevice *>(prop_container_to_device(ulContainer)); 644 + path.remove_prefix(skeleton_pfx.size()); 645 + xrt_hand hand; 646 + if (path == "left") { 647 + hand = XRT_HAND_LEFT; 648 + } else if (path == "right") { 649 + hand = XRT_HAND_RIGHT; 650 + } else { 651 + CTX_ERR("Got invalid skeleton path suffix: %s", std::string(path).c_str()); 652 + return vr::VRInputError_InvalidSkeleton; 653 + } 654 + 655 + device->set_skeleton(std::span(pGripLimitTransforms, unGripLimitTransformCount), hand, 656 + eSkeletalTrackingLevel == vr::VRSkeletalTracking_Estimated, pchSkeletonPath); 657 + skeleton_to_controller[*pHandle] = device; 658 + 659 return vr::VRInputError_None; 660 } 661 ··· 665 const vr::VRBoneTransform_t *pTransforms, 666 uint32_t unTransformCount) 667 { 668 + if (eMotionRange != vr::VRSkeletalMotionRange_WithoutController) { 669 + return vr::VRInputError_None; 670 + } 671 + 672 + if (!update_component_common(ulComponent, 0)) { 673 + return vr::VRInputError_InvalidHandle; 674 + } 675 + 676 + auto *device = skeleton_to_controller[ulComponent]; 677 + if (!device) { 678 + CTX_ERR("Got unknown component handle %lu", ulComponent); 679 + return vr::VRInputError_InvalidHandle; 680 + } 681 + 682 + device->update_skeleton_transforms(std::span(pTransforms, unTransformCount)); 683 + 684 return vr::VRInputError_None; 685 } 686 ··· 777 out_roles->left = left; 778 out_roles->right = right; 779 out_roles->gamepad = gamepad; 780 + 781 + if (left != XRT_DEVICE_ROLE_UNASSIGNED) { 782 + auto *left_dev = static_cast<ControllerDevice *>(xsysd->xdevs[left]); 783 + left_dev->set_active_hand(XRT_HAND_LEFT); 784 + } 785 + 786 + if (right != XRT_DEVICE_ROLE_UNASSIGNED) { 787 + auto *right_dev = static_cast<ControllerDevice *>(xsysd->xdevs[right]); 788 + right_dev->set_active_hand(XRT_HAND_RIGHT); 789 + } 790 } 791 792 return XRT_SUCCESS;
+2
src/xrt/drivers/survive/survive_driver.c
··· 530 survive_device_get_view_poses(struct xrt_device *xdev, 531 const struct xrt_vec3 *default_eye_relation, 532 int64_t at_timestamp_ns, 533 uint32_t view_count, 534 struct xrt_space_relation *out_head_relation, 535 struct xrt_fov *out_fovs, ··· 554 xdev, // 555 &eye_relation, // 556 at_timestamp_ns, // 557 view_count, // 558 out_head_relation, // 559 out_fovs, //
··· 530 survive_device_get_view_poses(struct xrt_device *xdev, 531 const struct xrt_vec3 *default_eye_relation, 532 int64_t at_timestamp_ns, 533 + enum xrt_view_type view_type, 534 uint32_t view_count, 535 struct xrt_space_relation *out_head_relation, 536 struct xrt_fov *out_fovs, ··· 555 xdev, // 556 &eye_relation, // 557 at_timestamp_ns, // 558 + view_type, // 559 view_count, // 560 out_head_relation, // 561 out_fovs, //
+1 -4
src/xrt/drivers/twrap/twrap_slam.c
··· 159 160 161 162 - dx->base.update_inputs = u_device_noop_update_inputs; 163 - dx->base.get_tracked_pose = twrap_slam_get_tracked_pose; 164 - dx->base.get_view_poses = u_device_ni_get_view_poses; 165 - dx->base.destroy = twrap_slam_destroy; 166 dx->base.name = name; 167 dx->base.tracking_origin->type = XRT_TRACKING_TYPE_OTHER; 168 dx->base.inputs[0].name = XRT_INPUT_GENERIC_TRACKER_POSE;
··· 159 160 161 162 + u_device_populate_function_pointers(&dx->base, twrap_slam_get_tracked_pose, twrap_slam_destroy); 163 dx->base.name = name; 164 dx->base.tracking_origin->type = XRT_TRACKING_TYPE_OTHER; 165 dx->base.inputs[0].name = XRT_INPUT_GENERIC_TRACKER_POSE;
+2
src/xrt/drivers/vive/vive_device.c
··· 212 vive_device_get_view_poses(struct xrt_device *xdev, 213 const struct xrt_vec3 *default_eye_relation, 214 int64_t at_timestamp_ns, 215 uint32_t view_count, 216 struct xrt_space_relation *out_head_relation, 217 struct xrt_fov *out_fovs, ··· 226 xdev, // 227 default_eye_relation, // 228 at_timestamp_ns, // 229 view_count, // 230 out_head_relation, // 231 out_fovs, //
··· 212 vive_device_get_view_poses(struct xrt_device *xdev, 213 const struct xrt_vec3 *default_eye_relation, 214 int64_t at_timestamp_ns, 215 + enum xrt_view_type view_type, 216 uint32_t view_count, 217 struct xrt_space_relation *out_head_relation, 218 struct xrt_fov *out_fovs, ··· 227 xdev, // 228 default_eye_relation, // 229 at_timestamp_ns, // 230 + view_type, // 231 view_count, // 232 out_head_relation, // 233 out_fovs, //
+1 -1
src/xrt/drivers/vp2/vp2_hid.c
··· 256 VP2_INFO(vp2, "Destroyed Vive Pro 2 HID device."); 257 258 free(vp2); 259 - }
··· 256 VP2_INFO(vp2, "Destroyed Vive Pro 2 HID device."); 257 258 free(vp2); 259 + }
+4 -2
src/xrt/drivers/wmr/wmr_controller_base.c
··· 526 wmr_controller_base_init(struct wmr_controller_base *wcb, 527 struct wmr_controller_connection *conn, 528 enum xrt_device_type controller_type, 529 - enum u_logging_level log_level) 530 { 531 DRV_TRACE_MARKER(); 532 ··· 544 snprintf(wcb->base.serial, XRT_DEVICE_NAME_LEN, "Right Controller"); 545 } 546 547 - wcb->base.get_tracked_pose = wmr_controller_base_get_tracked_pose; 548 549 wcb->base.name = XRT_DEVICE_WMR_CONTROLLER; 550 wcb->base.device_type = controller_type;
··· 526 wmr_controller_base_init(struct wmr_controller_base *wcb, 527 struct wmr_controller_connection *conn, 528 enum xrt_device_type controller_type, 529 + enum u_logging_level log_level, 530 + u_device_destroy_function_t destroy_fn) 531 { 532 DRV_TRACE_MARKER(); 533 ··· 545 snprintf(wcb->base.serial, XRT_DEVICE_NAME_LEN, "Right Controller"); 546 } 547 548 + // Set all functions. 549 + u_device_populate_function_pointers(&wcb->base, wmr_controller_base_get_tracked_pose, destroy_fn); 550 551 wcb->base.name = XRT_DEVICE_WMR_CONTROLLER; 552 wcb->base.device_type = controller_type;
+3 -1
src/xrt/drivers/wmr/wmr_controller_base.h
··· 16 17 #include "os/os_threading.h" 18 #include "math/m_imu_3dof.h" 19 #include "util/u_logging.h" 20 #include "xrt/xrt_device.h" 21 ··· 129 wmr_controller_base_init(struct wmr_controller_base *wcb, 130 struct wmr_controller_connection *conn, 131 enum xrt_device_type controller_type, 132 - enum u_logging_level log_level); 133 134 void 135 wmr_controller_base_deinit(struct wmr_controller_base *wcb);
··· 16 17 #include "os/os_threading.h" 18 #include "math/m_imu_3dof.h" 19 + #include "util/u_device.h" 20 #include "util/u_logging.h" 21 #include "xrt/xrt_device.h" 22 ··· 130 wmr_controller_base_init(struct wmr_controller_base *wcb, 131 struct wmr_controller_connection *conn, 132 enum xrt_device_type controller_type, 133 + enum u_logging_level log_level, 134 + u_device_destroy_function_t destroy_fn); 135 136 void 137 wmr_controller_base_deinit(struct wmr_controller_base *wcb);
+3 -5
src/xrt/drivers/wmr/wmr_controller_hp.c
··· 360 U_DEVICE_ALLOCATE(struct wmr_controller_hp, flags, WMR_CONTROLLER_INDEX_COUNT, 1); 361 struct wmr_controller_base *wcb = (struct wmr_controller_base *)(ctrl); 362 363 - if (!wmr_controller_base_init(wcb, conn, controller_type, log_level)) { 364 wmr_controller_hp_destroy(&wcb->base); 365 return NULL; 366 } 367 368 wcb->handle_input_packet = handle_input_packet; 369 370 wcb->base.name = XRT_DEVICE_HP_REVERB_G2_CONTROLLER; 371 372 if (controller_type == XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER) { ··· 374 } else { 375 snprintf(wcb->base.str, ARRAY_SIZE(wcb->base.str), "HP Reverb G2 Right Controller"); 376 } 377 - 378 - wcb->base.destroy = wmr_controller_hp_destroy; 379 - wcb->base.update_inputs = wmr_controller_hp_update_inputs; 380 - wcb->base.set_output = u_device_ni_set_output; 381 382 SET_INPUT(wcb, MENU_CLICK, MENU_CLICK); 383 SET_INPUT(wcb, HOME_CLICK, HOME_CLICK);
··· 360 U_DEVICE_ALLOCATE(struct wmr_controller_hp, flags, WMR_CONTROLLER_INDEX_COUNT, 1); 361 struct wmr_controller_base *wcb = (struct wmr_controller_base *)(ctrl); 362 363 + if (!wmr_controller_base_init(wcb, conn, controller_type, log_level, wmr_controller_hp_destroy)) { 364 wmr_controller_hp_destroy(&wcb->base); 365 return NULL; 366 } 367 368 wcb->handle_input_packet = handle_input_packet; 369 370 + // Only set those we want to overwrite. 371 + wcb->base.update_inputs = wmr_controller_hp_update_inputs; 372 wcb->base.name = XRT_DEVICE_HP_REVERB_G2_CONTROLLER; 373 374 if (controller_type == XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER) { ··· 376 } else { 377 snprintf(wcb->base.str, ARRAY_SIZE(wcb->base.str), "HP Reverb G2 Right Controller"); 378 } 379 380 SET_INPUT(wcb, MENU_CLICK, MENU_CLICK); 381 SET_INPUT(wcb, HOME_CLICK, HOME_CLICK);
+4 -4
src/xrt/drivers/wmr/wmr_controller_og.c
··· 413 struct wmr_controller_og *ctrl = U_DEVICE_ALLOCATE(struct wmr_controller_og, flags, 11, 1); 414 struct wmr_controller_base *wcb = (struct wmr_controller_base *)(ctrl); 415 416 - if (!wmr_controller_base_init(wcb, conn, controller_type, log_level)) { 417 wmr_controller_og_destroy(&wcb->base); 418 return NULL; 419 } 420 421 wcb->handle_input_packet = handle_input_packet; 422 423 if (pid == ODYSSEY_CONTROLLER_PID) { 424 wcb->base.name = XRT_DEVICE_SAMSUNG_ODYSSEY_CONTROLLER; 425 } else { 426 wcb->base.name = XRT_DEVICE_WMR_CONTROLLER; 427 } 428 - wcb->base.destroy = wmr_controller_og_destroy; 429 - wcb->base.update_inputs = wmr_controller_og_update_inputs; 430 - wcb->base.set_output = u_device_ni_set_output; 431 432 if (pid == ODYSSEY_CONTROLLER_PID) { 433 SET_ODYSSEY_INPUT(wcb, MENU_CLICK);
··· 413 struct wmr_controller_og *ctrl = U_DEVICE_ALLOCATE(struct wmr_controller_og, flags, 11, 1); 414 struct wmr_controller_base *wcb = (struct wmr_controller_base *)(ctrl); 415 416 + if (!wmr_controller_base_init(wcb, conn, controller_type, log_level, wmr_controller_og_destroy)) { 417 wmr_controller_og_destroy(&wcb->base); 418 return NULL; 419 } 420 421 wcb->handle_input_packet = handle_input_packet; 422 423 + // Only set those we want to overwrite. 424 + wcb->base.update_inputs = wmr_controller_og_update_inputs; 425 + 426 if (pid == ODYSSEY_CONTROLLER_PID) { 427 wcb->base.name = XRT_DEVICE_SAMSUNG_ODYSSEY_CONTROLLER; 428 } else { 429 wcb->base.name = XRT_DEVICE_WMR_CONTROLLER; 430 } 431 432 if (pid == ODYSSEY_CONTROLLER_PID) { 433 SET_ODYSSEY_INPUT(wcb, MENU_CLICK);
+12
src/xrt/drivers/wmr/wmr_hmd.c
··· 1947 wh->base.compute_distortion = compute_distortion_wmr; 1948 u_distortion_mesh_fill_in_compute(&wh->base); 1949 1950 // Set initial HMD screen power state. 1951 wh->hmd_screen_enable = true; 1952
··· 1947 wh->base.compute_distortion = compute_distortion_wmr; 1948 u_distortion_mesh_fill_in_compute(&wh->base); 1949 1950 + // Set HMD Scanout direction and time 1951 + if (wh->hmd_desc->hmd_type == WMR_HEADSET_SAMSUNG_800ZAA || 1952 + wh->hmd_desc->hmd_type == WMR_HEADSET_SAMSUNG_XE700X3AI) { 1953 + 1954 + wh->base.hmd->screens[0].scanout_direction = XRT_SCANOUT_DIRECTION_TOP_TO_BOTTOM; 1955 + wh->base.hmd->screens[0].scanout_time_ns = 1956 + wh->base.hmd->screens[0].nominal_frame_interval_ns * 1600.0 / 1624.0; 1957 + } else { 1958 + wh->base.hmd->screens[0].scanout_direction = XRT_SCANOUT_DIRECTION_NONE; 1959 + wh->base.hmd->screens[0].scanout_time_ns = 0; 1960 + } 1961 + 1962 // Set initial HMD screen power state. 1963 wh->hmd_screen_enable = true; 1964
+49 -29
src/xrt/include/xrt/xrt_compositor.h
··· 1 // Copyright 2019-2024, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 858 * 859 */ 860 861 - /*! 862 - * View type to be rendered to by the compositor. 863 - */ 864 - enum xrt_view_type 865 - { 866 - XRT_VIEW_TYPE_MONO = 1, 867 - XRT_VIEW_TYPE_STEREO = 2, 868 - }; 869 - 870 enum xrt_compositor_frame_point 871 { 872 XRT_COMPOSITOR_FRAME_POINT_WOKE, //!< The client woke up after waiting. ··· 974 bool fb_face_tracking2_enabled; 975 bool meta_body_tracking_full_body_enabled; 976 bool meta_body_tracking_calibration_enabled; 977 }; 978 979 /*! ··· 1046 struct xrt_compositor_fence **out_xcf); 1047 1048 /*! 1049 - * Create a compositor semaphore, also returns a native handle. 1050 */ 1051 xrt_result_t (*create_semaphore)(struct xrt_compositor *xc, 1052 xrt_graphics_sync_handle_t *out_handle, ··· 2291 *xcn_ptr = NULL; 2292 } 2293 2294 2295 /* 2296 * ··· 2304 */ 2305 struct xrt_system_compositor_info 2306 { 2307 - struct 2308 - { 2309 - struct 2310 - { 2311 - uint32_t width_pixels; 2312 - uint32_t height_pixels; 2313 - uint32_t sample_count; 2314 - } recommended; //!< Recommended for this view. 2315 - 2316 - struct 2317 - { 2318 - uint32_t width_pixels; 2319 - uint32_t height_pixels; 2320 - uint32_t sample_count; 2321 - } max; //!< Maximums for this view. 2322 - } views[XRT_MAX_VIEWS]; //!< View configuration information. 2323 2324 //! Maximum number of composition layers supported, never changes. 2325 uint32_t max_layers; ··· 2373 xrt_result_t (*set_state)(struct xrt_system_compositor *xsc, 2374 struct xrt_compositor *xc, 2375 bool visible, 2376 - bool focused); 2377 2378 /*! 2379 * Set the rendering Z order for rendering, visible has higher priority ··· 2473 * @public @memberof xrt_system_compositor 2474 */ 2475 static inline xrt_result_t 2476 - xrt_syscomp_set_state(struct xrt_system_compositor *xsc, struct xrt_compositor *xc, bool visible, bool focused) 2477 { 2478 if (xsc->xmcc == NULL) { 2479 return XRT_ERROR_MULTI_SESSION_NOT_IMPLEMENTED; 2480 } 2481 2482 - return xsc->xmcc->set_state(xsc, xc, visible, focused); 2483 } 2484 2485 /*!
··· 1 // Copyright 2019-2024, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 859 * 860 */ 861 862 enum xrt_compositor_frame_point 863 { 864 XRT_COMPOSITOR_FRAME_POINT_WOKE, //!< The client woke up after waiting. ··· 966 bool fb_face_tracking2_enabled; 967 bool meta_body_tracking_full_body_enabled; 968 bool meta_body_tracking_calibration_enabled; 969 + bool android_face_tracking_enabled; 970 }; 971 972 /*! ··· 1039 struct xrt_compositor_fence **out_xcf); 1040 1041 /*! 1042 + * Create a compositor semaphore, also returns a native handle of the 1043 + * semaphore which is owned by the @ref xrt_compositor_semaphore struct. 1044 + * The return values are always both valid, or on an error condition 1045 + * encountered and error is returned, both not valid (untouched). 1046 + * 1047 + * @param[in] xc Compositor self pointer. 1048 + * @param[out] out_handle Native handle owned by the samephore. 1049 + * @param[out] out_handle Return of the created semahpore. 1050 */ 1051 xrt_result_t (*create_semaphore)(struct xrt_compositor *xc, 1052 xrt_graphics_sync_handle_t *out_handle, ··· 2291 *xcn_ptr = NULL; 2292 } 2293 2294 + /*! 2295 + * Holds information about the view configuration properties for a view in a system compositor. 2296 + */ 2297 + struct xrt_view_config_properties 2298 + { 2299 + struct 2300 + { 2301 + uint32_t width_pixels; 2302 + uint32_t height_pixels; 2303 + uint32_t sample_count; 2304 + } recommended; //!< Recommended for this view. 2305 + 2306 + struct 2307 + { 2308 + uint32_t width_pixels; 2309 + uint32_t height_pixels; 2310 + uint32_t sample_count; 2311 + } max; //!< Maximums for this view. 2312 + }; 2313 + 2314 + struct xrt_view_config 2315 + { 2316 + //! Which view type this is for, mono, stereo, quad_with_inset, etc... 2317 + enum xrt_view_type view_type; 2318 + 2319 + //! Must match the view_type, in the future view_types might have variable views. 2320 + uint32_t view_count; 2321 + 2322 + //! The per view information. 2323 + struct xrt_view_config_properties views[XRT_MAX_COMPOSITOR_VIEW_CONFIGS_VIEW_COUNT]; 2324 + }; 2325 + 2326 2327 /* 2328 * ··· 2336 */ 2337 struct xrt_system_compositor_info 2338 { 2339 + uint32_t view_config_count; 2340 + struct xrt_view_config view_configs[XRT_MAX_COMPOSITOR_VIEW_CONFIGS_COUNT]; 2341 2342 //! Maximum number of composition layers supported, never changes. 2343 uint32_t max_layers; ··· 2391 xrt_result_t (*set_state)(struct xrt_system_compositor *xsc, 2392 struct xrt_compositor *xc, 2393 bool visible, 2394 + bool focused, 2395 + int64_t timestamp_ns); 2396 2397 /*! 2398 * Set the rendering Z order for rendering, visible has higher priority ··· 2492 * @public @memberof xrt_system_compositor 2493 */ 2494 static inline xrt_result_t 2495 + xrt_syscomp_set_state( 2496 + struct xrt_system_compositor *xsc, struct xrt_compositor *xc, bool visible, bool focused, int64_t timestamp_ns) 2497 { 2498 if (xsc->xmcc == NULL) { 2499 return XRT_ERROR_MULTI_SESSION_NOT_IMPLEMENTED; 2500 } 2501 2502 + return xsc->xmcc->set_state(xsc, xc, visible, focused, timestamp_ns); 2503 } 2504 2505 /*!
+1
src/xrt/include/xrt/xrt_config_build.h.cmake_in
··· 37 #cmakedefine XRT_FEATURE_OPENXR_BODY_TRACKING_FULL_BODY_META 38 #cmakedefine XRT_FEATURE_OPENXR_DEBUG_UTILS 39 #cmakedefine XRT_FEATURE_OPENXR_DISPLAY_REFRESH_RATE 40 #cmakedefine XRT_FEATURE_OPENXR_FACE_TRACKING2_FB 41 #cmakedefine XRT_FEATURE_OPENXR_FACIAL_TRACKING_HTC 42 #cmakedefine XRT_FEATURE_OPENXR_FORCE_FEEDBACK_CURL
··· 37 #cmakedefine XRT_FEATURE_OPENXR_BODY_TRACKING_FULL_BODY_META 38 #cmakedefine XRT_FEATURE_OPENXR_DEBUG_UTILS 39 #cmakedefine XRT_FEATURE_OPENXR_DISPLAY_REFRESH_RATE 40 + #cmakedefine XRT_FEATURE_OPENXR_FACE_TRACKING_ANDROID 41 #cmakedefine XRT_FEATURE_OPENXR_FACE_TRACKING2_FB 42 #cmakedefine XRT_FEATURE_OPENXR_FACIAL_TRACKING_HTC 43 #cmakedefine XRT_FEATURE_OPENXR_FORCE_FEEDBACK_CURL
+307 -131
src/xrt/include/xrt/xrt_defines.h
··· 1 // Copyright 2019-2024, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 715 * 716 */ 717 718 /*! 719 * A enum that is used to name devices so that the 720 * state trackers can reason about the devices easier. 721 */ 722 enum xrt_device_name 723 { 724 - XRT_DEVICE_INVALID = 0, 725 - 726 - XRT_DEVICE_GENERIC_HMD = 1, 727 - 728 - // Vive stuff. 729 - XRT_DEVICE_VIVE_PRO, 730 - XRT_DEVICE_VIVE_WAND, 731 - XRT_DEVICE_VIVE_TRACKER, // Generic, only used for bindings. 732 - XRT_DEVICE_VIVE_TRACKER_GEN1, 733 - XRT_DEVICE_VIVE_TRACKER_GEN2, 734 - XRT_DEVICE_VIVE_TRACKER_GEN3, 735 - XRT_DEVICE_VIVE_TRACKER_TUNDRA, 736 737 - // "Controllers" somewhat sorted as listed in spec. 738 - XRT_DEVICE_SIMPLE_CONTROLLER, 739 - XRT_DEVICE_DAYDREAM, 740 - XRT_DEVICE_WMR_CONTROLLER, 741 - XRT_DEVICE_XBOX_CONTROLLER, 742 - XRT_DEVICE_GO_CONTROLLER, 743 - XRT_DEVICE_TOUCH_CONTROLLER, 744 - XRT_DEVICE_INDEX_CONTROLLER, 745 746 - XRT_DEVICE_HP_REVERB_G2_CONTROLLER, 747 - XRT_DEVICE_SAMSUNG_ODYSSEY_CONTROLLER, 748 - XRT_DEVICE_ML2_CONTROLLER, 749 - XRT_DEVICE_OPPO_MR_CONTROLLER, 750 - 751 - XRT_DEVICE_HAND_INTERACTION, 752 - 753 - XRT_DEVICE_EYE_GAZE_INTERACTION, 754 - 755 - XRT_DEVICE_PSMV, 756 - XRT_DEVICE_PSSENSE, 757 - XRT_DEVICE_HYDRA, 758 - XRT_DEVICE_RIFT_REMOTE, 759 - XRT_DEVICE_BLUBUR_S1, 760 - XRT_DEVICE_PSVR2, 761 - 762 - // Other misc stuff. 763 - XRT_DEVICE_HAND_TRACKER, 764 - XRT_DEVICE_REALSENSE, 765 - XRT_DEVICE_DEPTHAI, 766 - 767 - //! XR_EXT_hand_interaction 768 - XRT_DEVICE_EXT_HAND_INTERACTION, 769 - 770 - //! XR_HTC_facial_tracking 771 - XRT_DEVICE_HTC_FACE_TRACKING, 772 - 773 - //! XR_FB_body_tracking 774 - XRT_DEVICE_FB_BODY_TRACKING, 775 - 776 - //! XR_FB_face_tracking2 777 - XRT_DEVICE_FB_FACE_TRACKING2, 778 - 779 - // added in OpenXR 1.1 780 - XRT_DEVICE_PICO_NEO3_CONTROLLER, 781 - XRT_DEVICE_PICO4_CONTROLLER, 782 - XRT_DEVICE_PICO_G3_CONTROLLER, 783 - 784 - XRT_DEVICE_VIVE_COSMOS_CONTROLLER, 785 - XRT_DEVICE_VIVE_FOCUS3_CONTROLLER, 786 - 787 - XRT_DEVICE_TOUCH_PRO_CONTROLLER, 788 - XRT_DEVICE_TOUCH_PLUS_CONTROLLER, 789 - XRT_DEVICE_TOUCH_CONTROLLER_RIFT_CV1, 790 - XRT_DEVICE_TOUCH_CONTROLLER_QUEST_1_RIFT_S, 791 - XRT_DEVICE_TOUCH_CONTROLLER_QUEST_2, 792 }; 793 794 /*! ··· 1117 _(XRT_INPUT_PSSENSE_CIRCLE_TOUCH , XRT_INPUT_NAME(0x030a, BOOLEAN)) \ 1118 _(XRT_INPUT_PSSENSE_SQUEEZE_CLICK , XRT_INPUT_NAME(0x030b, BOOLEAN)) \ 1119 _(XRT_INPUT_PSSENSE_SQUEEZE_TOUCH , XRT_INPUT_NAME(0x030c, BOOLEAN)) \ 1120 - _(XRT_INPUT_PSSENSE_SQUEEZE_PROXIMITY , XRT_INPUT_NAME(0x030d, VEC1_ZERO_TO_ONE)) \ 1121 - _(XRT_INPUT_PSSENSE_TRIGGER_CLICK , XRT_INPUT_NAME(0x030e, BOOLEAN)) \ 1122 - _(XRT_INPUT_PSSENSE_TRIGGER_TOUCH , XRT_INPUT_NAME(0x030f, BOOLEAN)) \ 1123 - _(XRT_INPUT_PSSENSE_TRIGGER_VALUE , XRT_INPUT_NAME(0x0310, VEC1_ZERO_TO_ONE)) \ 1124 - _(XRT_INPUT_PSSENSE_TRIGGER_PROXIMITY , XRT_INPUT_NAME(0x0311, VEC1_ZERO_TO_ONE)) \ 1125 - _(XRT_INPUT_PSSENSE_THUMBSTICK , XRT_INPUT_NAME(0x0312, VEC2_MINUS_ONE_TO_ONE)) \ 1126 - _(XRT_INPUT_PSSENSE_THUMBSTICK_CLICK , XRT_INPUT_NAME(0x0313, BOOLEAN)) \ 1127 - _(XRT_INPUT_PSSENSE_THUMBSTICK_TOUCH , XRT_INPUT_NAME(0x0314, BOOLEAN)) \ 1128 - _(XRT_INPUT_PSSENSE_GRIP_POSE , XRT_INPUT_NAME(0x0315, POSE)) \ 1129 - _(XRT_INPUT_PSSENSE_AIM_POSE , XRT_INPUT_NAME(0x0316, POSE)) \ 1130 \ 1131 /** XR_EXT_hand_interaction */ \ 1132 _(XRT_INPUT_HAND_PINCH_POSE , XRT_INPUT_NAME(0x0401, POSE)) \ ··· 1164 _(XRT_INPUT_HTC_LIP_FACE_TRACKING , XRT_INPUT_NAME(0x0602, FACE_TRACKING)) \ 1165 _(XRT_INPUT_FB_FACE_TRACKING2_AUDIO , XRT_INPUT_NAME(0x0603, FACE_TRACKING)) \ 1166 _(XRT_INPUT_FB_FACE_TRACKING2_VISUAL , XRT_INPUT_NAME(0x0604, FACE_TRACKING)) \ 1167 \ 1168 _(XRT_INPUT_GENERIC_BODY_TRACKING , XRT_INPUT_NAME(0x0700, BODY_TRACKING)) \ 1169 _(XRT_INPUT_FB_BODY_TRACKING , XRT_INPUT_NAME(0x0701, BODY_TRACKING)) \ ··· 1318 \ 1319 _(XRT_INPUT_BLUBUR_S1_MENU_CLICK , XRT_INPUT_NAME(0x1000, BOOLEAN)) \ 1320 \ 1321 - _(XRT_INPUT_PSVR2_SYSTEM_CLICK , XRT_INPUT_NAME(0x1100, BOOLEAN)) 1322 - 1323 - 1324 // clang-format on 1325 1326 ··· 1470 #define XRT_OUTPUT_TYPE_BITMASK 0xffu 1471 1472 /*! 1473 * Base type of this output. 1474 * 1475 * @ingroup xrt_iface ··· 1482 // clang-format on 1483 }; 1484 1485 - #define XRT_OUTPUT_NAME(id, type) ((UINT32_C(id) << XRT_OUTPUT_TYPE_BITWIDTH) | (uint32_t)XRT_OUTPUT_TYPE_##type) 1486 1487 enum xrt_face_expression2_fb 1488 { ··· 1649 #define XRT_FACIAL_EXPRESSION_EYE_COUNT_HTC 14 1650 #define XRT_FACIAL_EXPRESSION_LIP_COUNT_HTC 37 1651 1652 struct xrt_facial_base_expression_set_htc 1653 { 1654 int64_t sample_time_ns; ··· 1681 bool is_eye_following_blendshapes_valid; 1682 }; 1683 1684 struct xrt_facial_expression_set 1685 { 1686 union { ··· 1688 struct xrt_facial_eye_expression_set_htc eye_expression_set_htc; 1689 struct xrt_facial_lip_expression_set_htc lip_expression_set_htc; 1690 struct xrt_facial_expression_set2_fb face_expression_set2_fb; 1691 }; 1692 }; 1693 ··· 1958 }; 1959 1960 /*! 1961 - * Name of a output with a baked in type. 1962 - * 1963 - * @see xrt_output_type 1964 - * @ingroup xrt_iface 1965 - */ 1966 - enum xrt_output_name 1967 - { 1968 - // clang-format off 1969 - XRT_OUTPUT_NAME_SIMPLE_VIBRATION = XRT_OUTPUT_NAME(0x0010, VIBRATION), 1970 - XRT_OUTPUT_NAME_PSMV_RUMBLE_VIBRATION = XRT_OUTPUT_NAME(0x0020, VIBRATION), 1971 - XRT_OUTPUT_NAME_INDEX_HAPTIC = XRT_OUTPUT_NAME(0x0030, VIBRATION), 1972 - XRT_OUTPUT_NAME_VIVE_HAPTIC = XRT_OUTPUT_NAME(0x0040, VIBRATION), 1973 - XRT_OUTPUT_NAME_WMR_HAPTIC = XRT_OUTPUT_NAME(0x0050, VIBRATION), 1974 - 1975 - XRT_OUTPUT_NAME_XBOX_HAPTIC_LEFT = XRT_OUTPUT_NAME(0x0060, VIBRATION), 1976 - XRT_OUTPUT_NAME_XBOX_HAPTIC_RIGHT = XRT_OUTPUT_NAME(0x0061, VIBRATION), 1977 - XRT_OUTPUT_NAME_XBOX_HAPTIC_LEFT_TRIGGER = XRT_OUTPUT_NAME(0x0062, VIBRATION), 1978 - XRT_OUTPUT_NAME_XBOX_HAPTIC_RIGHT_TRIGGER = XRT_OUTPUT_NAME(0x0063, VIBRATION), 1979 - 1980 - XRT_OUTPUT_NAME_TOUCH_HAPTIC = XRT_OUTPUT_NAME(0x0070, VIBRATION), 1981 - 1982 - XRT_OUTPUT_NAME_FORCE_FEEDBACK_LEFT = XRT_OUTPUT_NAME(0x0080, FORCE_FEEDBACK), 1983 - XRT_OUTPUT_NAME_FORCE_FEEDBACK_RIGHT = XRT_OUTPUT_NAME(0x0081, FORCE_FEEDBACK), 1984 - 1985 - XRT_OUTPUT_NAME_G2_CONTROLLER_HAPTIC = XRT_OUTPUT_NAME(0x0090, VIBRATION), 1986 - XRT_OUTPUT_NAME_ODYSSEY_CONTROLLER_HAPTIC = XRT_OUTPUT_NAME(0x00A0, VIBRATION), 1987 - XRT_OUTPUT_NAME_ML2_CONTROLLER_VIBRATION = XRT_OUTPUT_NAME(0x00B0, VIBRATION), 1988 - 1989 - XRT_OUTPUT_NAME_PSSENSE_VIBRATION = XRT_OUTPUT_NAME(0x00C0, VIBRATION), 1990 - XRT_OUTPUT_NAME_PSSENSE_TRIGGER_FEEDBACK = XRT_OUTPUT_NAME(0x00C1, FORCE_FEEDBACK), 1991 - 1992 - XRT_OUTPUT_NAME_VIVE_TRACKER_HAPTIC = XRT_OUTPUT_NAME(0x00D0, VIBRATION), 1993 - 1994 - XRT_OUTPUT_NAME_OPPO_MR_HAPTIC = XRT_OUTPUT_NAME(0x00E0, VIBRATION), 1995 - 1996 - XRT_OUTPUT_NAME_PICO_NEO3_HAPTIC = XRT_OUTPUT_NAME(0x00F0, VIBRATION), 1997 - XRT_OUTPUT_NAME_PICO4_HAPTIC = XRT_OUTPUT_NAME(0x0100, VIBRATION), 1998 - 1999 - XRT_OUTPUT_NAME_VIVE_COSMOS_HAPTIC = XRT_OUTPUT_NAME(0x0200, VIBRATION), 2000 - XRT_OUTPUT_NAME_VIVE_FOCUS3_HAPTIC = XRT_OUTPUT_NAME(0x0300, VIBRATION), 2001 - 2002 - XRT_OUTPUT_NAME_TOUCH_PRO_HAPTIC = XRT_OUTPUT_NAME(0x0400, VIBRATION), 2003 - XRT_OUTPUT_NAME_TOUCH_PRO_HAPTIC_TRIGGER = XRT_OUTPUT_NAME(0x0500, VIBRATION), 2004 - XRT_OUTPUT_NAME_TOUCH_PRO_HAPTIC_THUMB = XRT_OUTPUT_NAME(0x0600, VIBRATION), 2005 - XRT_OUTPUT_NAME_TOUCH_PLUS_HAPTIC = XRT_OUTPUT_NAME(0x0700, VIBRATION), 2006 - 2007 - XRT_OUTPUT_NAME_PSVR2_HAPTIC = XRT_OUTPUT_NAME(0x0800, VIBRATION), 2008 - // clang-format on 2009 - }; 2010 - 2011 - /*! 2012 * Value used to indicate a haptic pulse of the minimal supported duration. 2013 * 2014 * @ingroup xrt_iface ··· 2107 { 2108 XRT_FORM_FACTOR_HMD, //!< Head mounted display. 2109 XRT_FORM_FACTOR_HANDHELD, //!< Handheld display. 2110 }; 2111 2112 /*!
··· 1 // Copyright 2019-2024, Collabora, Ltd. 2 + // Copyright 2024-2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 716 * 717 */ 718 719 + // clang-format off 720 + #define XRT_DEVICE_NAME_LIST(_) \ 721 + _(XRT_DEVICE_INVALID) \ 722 + \ 723 + _(XRT_DEVICE_GENERIC_HMD) \ 724 + \ 725 + /* Vive stuff. */ \ 726 + _(XRT_DEVICE_VIVE_PRO) \ 727 + _(XRT_DEVICE_VIVE_WAND) \ 728 + _(XRT_DEVICE_VIVE_TRACKER) /* Generic, only used for bindings. */ \ 729 + _(XRT_DEVICE_VIVE_TRACKER_GEN1) \ 730 + _(XRT_DEVICE_VIVE_TRACKER_GEN2) \ 731 + _(XRT_DEVICE_VIVE_TRACKER_GEN3) \ 732 + _(XRT_DEVICE_VIVE_TRACKER_TUNDRA) \ 733 + \ 734 + /* "Controllers" somewhat sorted as listed in spec. */\ 735 + _(XRT_DEVICE_SIMPLE_CONTROLLER) \ 736 + _(XRT_DEVICE_DAYDREAM) \ 737 + _(XRT_DEVICE_WMR_CONTROLLER) \ 738 + _(XRT_DEVICE_XBOX_CONTROLLER) \ 739 + _(XRT_DEVICE_GO_CONTROLLER) \ 740 + _(XRT_DEVICE_TOUCH_CONTROLLER) \ 741 + _(XRT_DEVICE_INDEX_CONTROLLER) \ 742 + \ 743 + _(XRT_DEVICE_HP_REVERB_G2_CONTROLLER) \ 744 + _(XRT_DEVICE_SAMSUNG_ODYSSEY_CONTROLLER) \ 745 + _(XRT_DEVICE_ML2_CONTROLLER) \ 746 + _(XRT_DEVICE_OPPO_MR_CONTROLLER) \ 747 + \ 748 + _(XRT_DEVICE_HAND_INTERACTION) \ 749 + \ 750 + _(XRT_DEVICE_EYE_GAZE_INTERACTION) \ 751 + \ 752 + _(XRT_DEVICE_PSMV) \ 753 + _(XRT_DEVICE_PSSENSE) \ 754 + _(XRT_DEVICE_HYDRA) \ 755 + _(XRT_DEVICE_RIFT_REMOTE) \ 756 + _(XRT_DEVICE_BLUBUR_S1) \ 757 + _(XRT_DEVICE_PSVR2) \ 758 + \ 759 + /* Other misc stuff. */\ 760 + _(XRT_DEVICE_HAND_TRACKER) \ 761 + _(XRT_DEVICE_REALSENSE) \ 762 + _(XRT_DEVICE_DEPTHAI) \ 763 + \ 764 + /*! XR_EXT_hand_interaction */\ 765 + _(XRT_DEVICE_EXT_HAND_INTERACTION) \ 766 + \ 767 + /*! XR_HTC_facial_tracking */\ 768 + _(XRT_DEVICE_HTC_FACE_TRACKING) \ 769 + \ 770 + /*! XR_FB_body_tracking */\ 771 + _(XRT_DEVICE_FB_BODY_TRACKING) \ 772 + \ 773 + /*! XR_FB_face_tracking2 */\ 774 + _(XRT_DEVICE_FB_FACE_TRACKING2) \ 775 + \ 776 + /* added in OpenXR 1.1 */\ 777 + _(XRT_DEVICE_PICO_NEO3_CONTROLLER) \ 778 + _(XRT_DEVICE_PICO4_CONTROLLER) \ 779 + _(XRT_DEVICE_PICO_G3_CONTROLLER) \ 780 + \ 781 + _(XRT_DEVICE_VIVE_COSMOS_CONTROLLER) \ 782 + _(XRT_DEVICE_VIVE_FOCUS3_CONTROLLER) \ 783 + \ 784 + _(XRT_DEVICE_TOUCH_PRO_CONTROLLER) \ 785 + _(XRT_DEVICE_TOUCH_PLUS_CONTROLLER) \ 786 + _(XRT_DEVICE_TOUCH_CONTROLLER_RIFT_CV1) \ 787 + _(XRT_DEVICE_TOUCH_CONTROLLER_QUEST_1_RIFT_S) \ 788 + _(XRT_DEVICE_TOUCH_CONTROLLER_QUEST_2) \ 789 + \ 790 + /* Hand based controller emulation. */\ 791 + _(XRT_DEVICE_HAND_CTRL_EMU) \ 792 + \ 793 + /* Please keep this comment and the trailing \ to reduce lines changed when adding entries. */ 794 + // clang-format on 795 + 796 /*! 797 * A enum that is used to name devices so that the 798 * state trackers can reason about the devices easier. 799 */ 800 enum xrt_device_name 801 { 802 + #define XRT_DEVICE_NAME_TO_ENUM(NAME) NAME, 803 804 + XRT_DEVICE_NAME_LIST(XRT_DEVICE_NAME_TO_ENUM) 805 806 + #undef XRT_DEVICE_NAME_TO_ENUM 807 }; 808 809 /*! ··· 1132 _(XRT_INPUT_PSSENSE_CIRCLE_TOUCH , XRT_INPUT_NAME(0x030a, BOOLEAN)) \ 1133 _(XRT_INPUT_PSSENSE_SQUEEZE_CLICK , XRT_INPUT_NAME(0x030b, BOOLEAN)) \ 1134 _(XRT_INPUT_PSSENSE_SQUEEZE_TOUCH , XRT_INPUT_NAME(0x030c, BOOLEAN)) \ 1135 + _(XRT_INPUT_PSSENSE_SQUEEZE_PROXIMITY , XRT_INPUT_NAME(0x030d, BOOLEAN)) \ 1136 + _(XRT_INPUT_PSSENSE_SQUEEZE_PROXIMITY_FLOAT , XRT_INPUT_NAME(0x030e, VEC1_ZERO_TO_ONE)) \ 1137 + _(XRT_INPUT_PSSENSE_TRIGGER_CLICK , XRT_INPUT_NAME(0x030f, BOOLEAN)) \ 1138 + _(XRT_INPUT_PSSENSE_TRIGGER_TOUCH , XRT_INPUT_NAME(0x0310, BOOLEAN)) \ 1139 + _(XRT_INPUT_PSSENSE_TRIGGER_VALUE , XRT_INPUT_NAME(0x0311, VEC1_ZERO_TO_ONE)) \ 1140 + _(XRT_INPUT_PSSENSE_TRIGGER_PROXIMITY , XRT_INPUT_NAME(0x0312, BOOLEAN)) \ 1141 + _(XRT_INPUT_PSSENSE_TRIGGER_PROXIMITY_FLOAT , XRT_INPUT_NAME(0x0313, VEC1_ZERO_TO_ONE)) \ 1142 + _(XRT_INPUT_PSSENSE_THUMBSTICK , XRT_INPUT_NAME(0x0314, VEC2_MINUS_ONE_TO_ONE)) \ 1143 + _(XRT_INPUT_PSSENSE_THUMBSTICK_CLICK , XRT_INPUT_NAME(0x0315, BOOLEAN)) \ 1144 + _(XRT_INPUT_PSSENSE_THUMBSTICK_TOUCH , XRT_INPUT_NAME(0x0316, BOOLEAN)) \ 1145 + _(XRT_INPUT_PSSENSE_GRIP_POSE , XRT_INPUT_NAME(0x0317, POSE)) \ 1146 + _(XRT_INPUT_PSSENSE_AIM_POSE , XRT_INPUT_NAME(0x0318, POSE)) \ 1147 \ 1148 /** XR_EXT_hand_interaction */ \ 1149 _(XRT_INPUT_HAND_PINCH_POSE , XRT_INPUT_NAME(0x0401, POSE)) \ ··· 1181 _(XRT_INPUT_HTC_LIP_FACE_TRACKING , XRT_INPUT_NAME(0x0602, FACE_TRACKING)) \ 1182 _(XRT_INPUT_FB_FACE_TRACKING2_AUDIO , XRT_INPUT_NAME(0x0603, FACE_TRACKING)) \ 1183 _(XRT_INPUT_FB_FACE_TRACKING2_VISUAL , XRT_INPUT_NAME(0x0604, FACE_TRACKING)) \ 1184 + _(XRT_INPUT_ANDROID_FACE_TRACKING , XRT_INPUT_NAME(0x0605, FACE_TRACKING)) \ 1185 \ 1186 _(XRT_INPUT_GENERIC_BODY_TRACKING , XRT_INPUT_NAME(0x0700, BODY_TRACKING)) \ 1187 _(XRT_INPUT_FB_BODY_TRACKING , XRT_INPUT_NAME(0x0701, BODY_TRACKING)) \ ··· 1336 \ 1337 _(XRT_INPUT_BLUBUR_S1_MENU_CLICK , XRT_INPUT_NAME(0x1000, BOOLEAN)) \ 1338 \ 1339 + _(XRT_INPUT_PSVR2_SYSTEM_CLICK , XRT_INPUT_NAME(0x1100, BOOLEAN)) \ 1340 + \ 1341 + _(XRT_INPUT_HAND_CTRL_EMU_PINCH_BOOL , XRT_INPUT_NAME(0x1200, BOOLEAN)) \ 1342 + _(XRT_INPUT_HAND_CTRL_EMU_PINCH_VALUE , XRT_INPUT_NAME(0x1201, VEC1_ZERO_TO_ONE)) \ 1343 + _(XRT_INPUT_HAND_CTRL_EMU_GRIP_POSE , XRT_INPUT_NAME(0x1202, POSE)) \ 1344 + _(XRT_INPUT_HAND_CTRL_EMU_AIM_POSE , XRT_INPUT_NAME(0x1203, POSE)) \ 1345 + \ 1346 + /* Please keep this comment and the trailing \ to reduce lines changed when adding entries. */ 1347 // clang-format on 1348 1349 ··· 1493 #define XRT_OUTPUT_TYPE_BITMASK 0xffu 1494 1495 /*! 1496 + * @brief Create an enum value for xrt_output_name that packs an ID and output 1497 + * type. 1498 + * 1499 + * @param id an integer 1500 + * @param type The suffix of an xrt_output_type value name: `XRT_OUTPUT_TYPE_` is 1501 + * prepended automatically. 1502 + * 1503 + * @see xrt_output_name 1504 + * @ingroup xrt_iface 1505 + */ 1506 + #define XRT_OUTPUT_NAME(id, type) ((UINT32_C(id) << XRT_OUTPUT_TYPE_BITWIDTH) | (uint32_t)XRT_OUTPUT_TYPE_##type) 1507 + 1508 + /*! 1509 + * @brief Extract the xrt_output_type from an xrt_output_name. 1510 + * 1511 + * @param name An xrt_output_name value 1512 + * 1513 + * @relates xrt_output_name 1514 + * @returns @ref xrt_output_type 1515 + * @ingroup xrt_iface 1516 + */ 1517 + #define XRT_GET_OUTPUT_TYPE(name) ((enum xrt_output_type)(name & XRT_OUTPUT_TYPE_BITMASK)) 1518 + 1519 + /*! 1520 + * @brief Extract the xrt_output_name id from an xrt_output_name. 1521 + * 1522 + * @param name An xrt_output_name value 1523 + * 1524 + * @relates xrt_output_name 1525 + * @returns The extracted id. 1526 + * @ingroup xrt_iface 1527 + */ 1528 + #define XRT_GET_OUTPUT_ID(name) ((uint32_t)(name >> XRT_OUTPUT_TYPE_BITWIDTH)) 1529 + 1530 + /*! 1531 * Base type of this output. 1532 * 1533 * @ingroup xrt_iface ··· 1540 // clang-format on 1541 }; 1542 1543 + // clang-format off 1544 + #define XRT_OUTPUT_LIST(_) \ 1545 + _(XRT_OUTPUT_NAME_SIMPLE_VIBRATION , XRT_OUTPUT_NAME(0x0010, VIBRATION)) \ 1546 + _(XRT_OUTPUT_NAME_PSMV_RUMBLE_VIBRATION , XRT_OUTPUT_NAME(0x0020, VIBRATION)) \ 1547 + _(XRT_OUTPUT_NAME_INDEX_HAPTIC , XRT_OUTPUT_NAME(0x0030, VIBRATION)) \ 1548 + _(XRT_OUTPUT_NAME_VIVE_HAPTIC , XRT_OUTPUT_NAME(0x0040, VIBRATION)) \ 1549 + _(XRT_OUTPUT_NAME_WMR_HAPTIC , XRT_OUTPUT_NAME(0x0050, VIBRATION)) \ 1550 + \ 1551 + _(XRT_OUTPUT_NAME_XBOX_HAPTIC_LEFT , XRT_OUTPUT_NAME(0x0060, VIBRATION)) \ 1552 + _(XRT_OUTPUT_NAME_XBOX_HAPTIC_RIGHT , XRT_OUTPUT_NAME(0x0061, VIBRATION)) \ 1553 + _(XRT_OUTPUT_NAME_XBOX_HAPTIC_LEFT_TRIGGER , XRT_OUTPUT_NAME(0x0062, VIBRATION)) \ 1554 + _(XRT_OUTPUT_NAME_XBOX_HAPTIC_RIGHT_TRIGGER , XRT_OUTPUT_NAME(0x0063, VIBRATION)) \ 1555 + \ 1556 + _(XRT_OUTPUT_NAME_TOUCH_HAPTIC , XRT_OUTPUT_NAME(0x0070, VIBRATION)) \ 1557 + \ 1558 + _(XRT_OUTPUT_NAME_FORCE_FEEDBACK_LEFT , XRT_OUTPUT_NAME(0x0080, FORCE_FEEDBACK)) \ 1559 + _(XRT_OUTPUT_NAME_FORCE_FEEDBACK_RIGHT , XRT_OUTPUT_NAME(0x0081, FORCE_FEEDBACK)) \ 1560 + \ 1561 + _(XRT_OUTPUT_NAME_G2_CONTROLLER_HAPTIC , XRT_OUTPUT_NAME(0x0090, VIBRATION)) \ 1562 + _(XRT_OUTPUT_NAME_ODYSSEY_CONTROLLER_HAPTIC , XRT_OUTPUT_NAME(0x00A0, VIBRATION)) \ 1563 + _(XRT_OUTPUT_NAME_ML2_CONTROLLER_VIBRATION , XRT_OUTPUT_NAME(0x00B0, VIBRATION)) \ 1564 + \ 1565 + _(XRT_OUTPUT_NAME_PSSENSE_VIBRATION , XRT_OUTPUT_NAME(0x00C0, VIBRATION)) \ 1566 + _(XRT_OUTPUT_NAME_PSSENSE_TRIGGER_FEEDBACK , XRT_OUTPUT_NAME(0x00C1, FORCE_FEEDBACK)) \ 1567 + \ 1568 + _(XRT_OUTPUT_NAME_VIVE_TRACKER_HAPTIC , XRT_OUTPUT_NAME(0x00D0, VIBRATION)) \ 1569 + \ 1570 + _(XRT_OUTPUT_NAME_OPPO_MR_HAPTIC , XRT_OUTPUT_NAME(0x00E0, VIBRATION)) \ 1571 + \ 1572 + _(XRT_OUTPUT_NAME_PICO_NEO3_HAPTIC , XRT_OUTPUT_NAME(0x00F0, VIBRATION)) \ 1573 + _(XRT_OUTPUT_NAME_PICO4_HAPTIC , XRT_OUTPUT_NAME(0x0100, VIBRATION)) \ 1574 + \ 1575 + _(XRT_OUTPUT_NAME_VIVE_COSMOS_HAPTIC , XRT_OUTPUT_NAME(0x0200, VIBRATION)) \ 1576 + _(XRT_OUTPUT_NAME_VIVE_FOCUS3_HAPTIC , XRT_OUTPUT_NAME(0x0300, VIBRATION)) \ 1577 + \ 1578 + _(XRT_OUTPUT_NAME_TOUCH_PRO_HAPTIC , XRT_OUTPUT_NAME(0x0400, VIBRATION)) \ 1579 + _(XRT_OUTPUT_NAME_TOUCH_PRO_HAPTIC_TRIGGER , XRT_OUTPUT_NAME(0x0500, VIBRATION)) \ 1580 + _(XRT_OUTPUT_NAME_TOUCH_PRO_HAPTIC_THUMB , XRT_OUTPUT_NAME(0x0600, VIBRATION)) \ 1581 + _(XRT_OUTPUT_NAME_TOUCH_PLUS_HAPTIC , XRT_OUTPUT_NAME(0x0700, VIBRATION)) \ 1582 + \ 1583 + _(XRT_OUTPUT_NAME_PSVR2_HAPTIC , XRT_OUTPUT_NAME(0x0800, VIBRATION)) \ 1584 + \ 1585 + /* Please keep this comment and the trailing \ to reduce lines changed when adding entries. */ 1586 + // clang-format on 1587 + 1588 + /*! 1589 + * Name of a output with a baked in type. 1590 + * 1591 + * @see xrt_output_type 1592 + * @ingroup xrt_iface 1593 + */ 1594 + enum xrt_output_name 1595 + { 1596 + #define XRT_OUTPUT_LIST_TO_NAME_VALUE(NAME, VALUE) NAME = VALUE, 1597 + 1598 + XRT_OUTPUT_LIST(XRT_OUTPUT_LIST_TO_NAME_VALUE) 1599 + 1600 + #undef XRT_OUTPUT_LIST_TO_NAME_VALUE 1601 + }; 1602 1603 enum xrt_face_expression2_fb 1604 { ··· 1765 #define XRT_FACIAL_EXPRESSION_EYE_COUNT_HTC 14 1766 #define XRT_FACIAL_EXPRESSION_LIP_COUNT_HTC 37 1767 1768 + enum xrt_face_confidence_regions_android 1769 + { 1770 + XRT_FACE_CONFIDENCE_REGIONS_LOWER_ANDROID = 0, 1771 + XRT_FACE_CONFIDENCE_REGIONS_LEFT_UPPER_ANDROID = 1, 1772 + XRT_FACE_CONFIDENCE_REGIONS_RIGHT_UPPER_ANDROID = 2, 1773 + }; 1774 + 1775 + enum xrt_face_parameter_indices_android 1776 + { 1777 + XRT_FACE_PARAMETER_INDICES_BROW_LOWERER_L_ANDROID = 0, 1778 + XRT_FACE_PARAMETER_INDICES_BROW_LOWERER_R_ANDROID = 1, 1779 + XRT_FACE_PARAMETER_INDICES_CHEEK_PUFF_L_ANDROID = 2, 1780 + XRT_FACE_PARAMETER_INDICES_CHEEK_PUFF_R_ANDROID = 3, 1781 + XRT_FACE_PARAMETER_INDICES_CHEEK_RAISER_L_ANDROID = 4, 1782 + XRT_FACE_PARAMETER_INDICES_CHEEK_RAISER_R_ANDROID = 5, 1783 + XRT_FACE_PARAMETER_INDICES_CHEEK_SUCK_L_ANDROID = 6, 1784 + XRT_FACE_PARAMETER_INDICES_CHEEK_SUCK_R_ANDROID = 7, 1785 + XRT_FACE_PARAMETER_INDICES_CHIN_RAISER_B_ANDROID = 8, 1786 + XRT_FACE_PARAMETER_INDICES_CHIN_RAISER_T_ANDROID = 9, 1787 + XRT_FACE_PARAMETER_INDICES_DIMPLER_L_ANDROID = 10, 1788 + XRT_FACE_PARAMETER_INDICES_DIMPLER_R_ANDROID = 11, 1789 + XRT_FACE_PARAMETER_INDICES_EYES_CLOSED_L_ANDROID = 12, 1790 + XRT_FACE_PARAMETER_INDICES_EYES_CLOSED_R_ANDROID = 13, 1791 + XRT_FACE_PARAMETER_INDICES_EYES_LOOK_DOWN_L_ANDROID = 14, 1792 + XRT_FACE_PARAMETER_INDICES_EYES_LOOK_DOWN_R_ANDROID = 15, 1793 + XRT_FACE_PARAMETER_INDICES_EYES_LOOK_LEFT_L_ANDROID = 16, 1794 + XRT_FACE_PARAMETER_INDICES_EYES_LOOK_LEFT_R_ANDROID = 17, 1795 + XRT_FACE_PARAMETER_INDICES_EYES_LOOK_RIGHT_L_ANDROID = 18, 1796 + XRT_FACE_PARAMETER_INDICES_EYES_LOOK_RIGHT_R_ANDROID = 19, 1797 + XRT_FACE_PARAMETER_INDICES_EYES_LOOK_UP_L_ANDROID = 20, 1798 + XRT_FACE_PARAMETER_INDICES_EYES_LOOK_UP_R_ANDROID = 21, 1799 + XRT_FACE_PARAMETER_INDICES_INNER_BROW_RAISER_L_ANDROID = 22, 1800 + XRT_FACE_PARAMETER_INDICES_INNER_BROW_RAISER_R_ANDROID = 23, 1801 + XRT_FACE_PARAMETER_INDICES_JAW_DROP_ANDROID = 24, 1802 + XRT_FACE_PARAMETER_INDICES_JAW_SIDEWAYS_LEFT_ANDROID = 25, 1803 + XRT_FACE_PARAMETER_INDICES_JAW_SIDEWAYS_RIGHT_ANDROID = 26, 1804 + XRT_FACE_PARAMETER_INDICES_JAW_THRUST_ANDROID = 27, 1805 + XRT_FACE_PARAMETER_INDICES_LID_TIGHTENER_L_ANDROID = 28, 1806 + XRT_FACE_PARAMETER_INDICES_LID_TIGHTENER_R_ANDROID = 29, 1807 + XRT_FACE_PARAMETER_INDICES_LIP_CORNER_DEPRESSOR_L_ANDROID = 30, 1808 + XRT_FACE_PARAMETER_INDICES_LIP_CORNER_DEPRESSOR_R_ANDROID = 31, 1809 + XRT_FACE_PARAMETER_INDICES_LIP_CORNER_PULLER_L_ANDROID = 32, 1810 + XRT_FACE_PARAMETER_INDICES_LIP_CORNER_PULLER_R_ANDROID = 33, 1811 + XRT_FACE_PARAMETER_INDICES_LIP_FUNNELER_LB_ANDROID = 34, 1812 + XRT_FACE_PARAMETER_INDICES_LIP_FUNNELER_LT_ANDROID = 35, 1813 + XRT_FACE_PARAMETER_INDICES_LIP_FUNNELER_RB_ANDROID = 36, 1814 + XRT_FACE_PARAMETER_INDICES_LIP_FUNNELER_RT_ANDROID = 37, 1815 + XRT_FACE_PARAMETER_INDICES_LIP_PRESSOR_L_ANDROID = 38, 1816 + XRT_FACE_PARAMETER_INDICES_LIP_PRESSOR_R_ANDROID = 39, 1817 + XRT_FACE_PARAMETER_INDICES_LIP_PUCKER_L_ANDROID = 40, 1818 + XRT_FACE_PARAMETER_INDICES_LIP_PUCKER_R_ANDROID = 41, 1819 + XRT_FACE_PARAMETER_INDICES_LIP_STRETCHER_L_ANDROID = 42, 1820 + XRT_FACE_PARAMETER_INDICES_LIP_STRETCHER_R_ANDROID = 43, 1821 + XRT_FACE_PARAMETER_INDICES_LIP_SUCK_LB_ANDROID = 44, 1822 + XRT_FACE_PARAMETER_INDICES_LIP_SUCK_LT_ANDROID = 45, 1823 + XRT_FACE_PARAMETER_INDICES_LIP_SUCK_RB_ANDROID = 46, 1824 + XRT_FACE_PARAMETER_INDICES_LIP_SUCK_RT_ANDROID = 47, 1825 + XRT_FACE_PARAMETER_INDICES_LIP_TIGHTENER_L_ANDROID = 48, 1826 + XRT_FACE_PARAMETER_INDICES_LIP_TIGHTENER_R_ANDROID = 49, 1827 + XRT_FACE_PARAMETER_INDICES_LIPS_TOWARD_ANDROID = 50, 1828 + XRT_FACE_PARAMETER_INDICES_LOWER_LIP_DEPRESSOR_L_ANDROID = 51, 1829 + XRT_FACE_PARAMETER_INDICES_LOWER_LIP_DEPRESSOR_R_ANDROID = 52, 1830 + XRT_FACE_PARAMETER_INDICES_MOUTH_LEFT_ANDROID = 53, 1831 + XRT_FACE_PARAMETER_INDICES_MOUTH_RIGHT_ANDROID = 54, 1832 + XRT_FACE_PARAMETER_INDICES_NOSE_WRINKLER_L_ANDROID = 55, 1833 + XRT_FACE_PARAMETER_INDICES_NOSE_WRINKLER_R_ANDROID = 56, 1834 + XRT_FACE_PARAMETER_INDICES_OUTER_BROW_RAISER_L_ANDROID = 57, 1835 + XRT_FACE_PARAMETER_INDICES_OUTER_BROW_RAISER_R_ANDROID = 58, 1836 + XRT_FACE_PARAMETER_INDICES_UPPER_LID_RAISER_L_ANDROID = 59, 1837 + XRT_FACE_PARAMETER_INDICES_UPPER_LID_RAISER_R_ANDROID = 60, 1838 + XRT_FACE_PARAMETER_INDICES_UPPER_LIP_RAISER_L_ANDROID = 61, 1839 + XRT_FACE_PARAMETER_INDICES_UPPER_LIP_RAISER_R_ANDROID = 62, 1840 + XRT_FACE_PARAMETER_INDICES_TONGUE_OUT_ANDROID = 63, 1841 + XRT_FACE_PARAMETER_INDICES_TONGUE_LEFT_ANDROID = 64, 1842 + XRT_FACE_PARAMETER_INDICES_TONGUE_RIGHT_ANDROID = 65, 1843 + XRT_FACE_PARAMETER_INDICES_TONGUE_UP_ANDROID = 66, 1844 + XRT_FACE_PARAMETER_INDICES_TONGUE_DOWN_ANDROID = 67, 1845 + }; 1846 + 1847 + enum xrt_face_tracking_state_android 1848 + { 1849 + XRT_FACE_TRACKING_STATE_PAUSED_ANDROID = 0, 1850 + XRT_FACE_TRACKING_STATE_STOPPED_ANDROID = 1, 1851 + XRT_FACE_TRACKING_STATE_TRACKING_ANDROID = 2, 1852 + }; 1853 + 1854 + #define XRT_FACE_PARAMETER_COUNT_ANDROID 68 1855 + 1856 + #define XRT_FACE_REGION_CONFIDENCE_COUNT_ANDROID 3 1857 + 1858 struct xrt_facial_base_expression_set_htc 1859 { 1860 int64_t sample_time_ns; ··· 1887 bool is_eye_following_blendshapes_valid; 1888 }; 1889 1890 + struct xrt_facial_expression_set_android 1891 + { 1892 + // ordered by xrt_face_parameter_indices_android 1893 + float parameters[XRT_FACE_PARAMETER_COUNT_ANDROID]; 1894 + float region_confidences[XRT_FACE_REGION_CONFIDENCE_COUNT_ANDROID]; 1895 + 1896 + uint64_t sample_time_ns; 1897 + 1898 + XRT_ALIGNAS(8) bool is_valid; 1899 + }; 1900 + 1901 struct xrt_facial_expression_set 1902 { 1903 union { ··· 1905 struct xrt_facial_eye_expression_set_htc eye_expression_set_htc; 1906 struct xrt_facial_lip_expression_set_htc lip_expression_set_htc; 1907 struct xrt_facial_expression_set2_fb face_expression_set2_fb; 1908 + struct xrt_facial_expression_set_android face_expression_set_android; 1909 }; 1910 }; 1911 ··· 2176 }; 2177 2178 /*! 2179 * Value used to indicate a haptic pulse of the minimal supported duration. 2180 * 2181 * @ingroup xrt_iface ··· 2274 { 2275 XRT_FORM_FACTOR_HMD, //!< Head mounted display. 2276 XRT_FORM_FACTOR_HANDHELD, //!< Handheld display. 2277 + }; 2278 + 2279 + /*! 2280 + * View type to be rendered to by the compositor. 2281 + */ 2282 + enum xrt_view_type 2283 + { 2284 + XRT_VIEW_TYPE_MONO = 1, 2285 + XRT_VIEW_TYPE_STEREO = 2, 2286 }; 2287 2288 /*!
+55 -22
src/xrt/include/xrt/xrt_device.h
··· 103 //! Nominal frame interval 104 uint64_t nominal_frame_interval_ns; 105 enum xrt_scanout_direction scanout_direction; 106 - uint64_t scanout_time_ns; 107 } screens[1]; 108 109 /*! ··· 406 struct xrt_facial_expression_set *out_value); 407 408 /*! 409 * @brief Get the body skeleton in T-pose, used to query the skeleton hierarchy, scale, proportions etc 410 * 411 * @param[in] xdev The device. ··· 489 * @param[out] out_plane_detection_id The id of the new plane detection request generated by the xdev. 490 * @return generally XRT_SUCCESS, except for internal runtime failures. 491 */ 492 - enum xrt_result (*begin_plane_detection_ext)(struct xrt_device *xdev, 493 - const struct xrt_plane_detector_begin_info_ext *begin_info, 494 - uint64_t plane_detection_id, 495 - uint64_t *out_plane_detection_id); 496 497 /*! 498 * Destroy internal resources associated with plane_detector_id. ··· 501 * @param[in] plane_detection_id An id generated by the xdev. 502 * @return generally XRT_SUCCESS, except for internal runtime failures. 503 */ 504 - enum xrt_result (*destroy_plane_detection_ext)(struct xrt_device *xdev, uint64_t plane_detection_id); 505 506 /*! 507 * Get the state of a plane detection request. ··· 511 * @param[out] out_state The state of the plane detection. 512 * @return generally XRT_SUCCESS, except for internal runtime failures. 513 */ 514 - enum xrt_result (*get_plane_detection_state_ext)(struct xrt_device *xdev, 515 - uint64_t plane_detection_id, 516 - enum xrt_plane_detector_state_ext *out_state); 517 518 /*! 519 * Get results of a plane detection request. ··· 523 * @param[out] detections The detected planes, if any. 524 * @return generally XRT_SUCCESS, except for internal runtime failures. 525 */ 526 - enum xrt_result (*get_plane_detections_ext)(struct xrt_device *xdev, 527 - uint64_t plane_detection_id, 528 - struct xrt_plane_detections_ext *out_detections); 529 530 /*! 531 * @brief Get the per-view pose in relation to the view space. ··· 550 * input. 551 * @param[in] at_timestamp_ns This is when the caller wants the poses and FOVs to be from. 552 * @param[in] view_count Number of views. 553 * @param[out] out_head_relation 554 * The head pose in the device tracking space. 555 * Combine with @p out_poses to get the views in ··· 567 xrt_result_t (*get_view_poses)(struct xrt_device *xdev, 568 const struct xrt_vec3 *default_eye_relation, 569 int64_t at_timestamp_ns, 570 uint32_t view_count, 571 struct xrt_space_relation *out_head_relation, 572 struct xrt_fov *out_fovs, ··· 754 } 755 756 /*! 757 * Helper function for @ref xrt_device::get_body_skeleton. 758 * 759 * @copydoc xrt_device::get_body_skeleton ··· 858 } 859 860 /*! 861 - * Helper function for @ref xrt_device::begin_plane_detection. 862 * 863 * @public @memberof xrt_device 864 */ 865 - static inline enum xrt_result 866 xrt_device_begin_plane_detection_ext(struct xrt_device *xdev, 867 const struct xrt_plane_detector_begin_info_ext *begin_info, 868 uint64_t plane_detection_id, ··· 872 } 873 874 /*! 875 - * Helper function for @ref xrt_device::destroy_plane_detection. 876 * 877 * @public @memberof xrt_device 878 */ 879 - static inline enum xrt_result 880 xrt_device_destroy_plane_detection_ext(struct xrt_device *xdev, uint64_t plane_detection_id) 881 { 882 return xdev->destroy_plane_detection_ext(xdev, plane_detection_id); 883 } 884 885 /*! 886 - * Helper function for @ref xrt_device::get_plane_detections. 887 * 888 * @public @memberof xrt_device 889 */ 890 - static inline enum xrt_result 891 xrt_device_get_plane_detection_state_ext(struct xrt_device *xdev, 892 uint64_t plane_detection_id, 893 enum xrt_plane_detector_state_ext *out_state) ··· 896 } 897 898 /*! 899 - * Helper function for @ref xrt_device::get_plane_detections. 900 * 901 * @public @memberof xrt_device 902 */ 903 - static inline enum xrt_result 904 xrt_device_get_plane_detections_ext(struct xrt_device *xdev, 905 uint64_t plane_detection_id, 906 struct xrt_plane_detections_ext *out_detections) ··· 918 xrt_device_get_view_poses(struct xrt_device *xdev, 919 const struct xrt_vec3 *default_eye_relation, 920 int64_t at_timestamp_ns, 921 uint32_t view_count, 922 struct xrt_space_relation *out_head_relation, 923 struct xrt_fov *out_fovs, 924 struct xrt_pose *out_poses) 925 { 926 - return xdev->get_view_poses(xdev, default_eye_relation, at_timestamp_ns, view_count, out_head_relation, 927 - out_fovs, out_poses); 928 } 929 930 /*!
··· 103 //! Nominal frame interval 104 uint64_t nominal_frame_interval_ns; 105 enum xrt_scanout_direction scanout_direction; 106 + int64_t scanout_time_ns; 107 } screens[1]; 108 109 /*! ··· 406 struct xrt_facial_expression_set *out_value); 407 408 /*! 409 + * @brief Gets the face tracking calibration state 410 + * 411 + * @param[in] xdev The device. 412 + * @param[in] out_value Is face tracking calibrated? 413 + * 414 + * @see xrt_input_name 415 + */ 416 + xrt_result_t (*get_face_calibration_state_android)(struct xrt_device *xdev, bool *out_face_is_calibrated); 417 + 418 + /*! 419 * @brief Get the body skeleton in T-pose, used to query the skeleton hierarchy, scale, proportions etc 420 * 421 * @param[in] xdev The device. ··· 499 * @param[out] out_plane_detection_id The id of the new plane detection request generated by the xdev. 500 * @return generally XRT_SUCCESS, except for internal runtime failures. 501 */ 502 + xrt_result_t (*begin_plane_detection_ext)(struct xrt_device *xdev, 503 + const struct xrt_plane_detector_begin_info_ext *begin_info, 504 + uint64_t plane_detection_id, 505 + uint64_t *out_plane_detection_id); 506 507 /*! 508 * Destroy internal resources associated with plane_detector_id. ··· 511 * @param[in] plane_detection_id An id generated by the xdev. 512 * @return generally XRT_SUCCESS, except for internal runtime failures. 513 */ 514 + xrt_result_t (*destroy_plane_detection_ext)(struct xrt_device *xdev, uint64_t plane_detection_id); 515 516 /*! 517 * Get the state of a plane detection request. ··· 521 * @param[out] out_state The state of the plane detection. 522 * @return generally XRT_SUCCESS, except for internal runtime failures. 523 */ 524 + xrt_result_t (*get_plane_detection_state_ext)(struct xrt_device *xdev, 525 + uint64_t plane_detection_id, 526 + enum xrt_plane_detector_state_ext *out_state); 527 528 /*! 529 * Get results of a plane detection request. ··· 533 * @param[out] detections The detected planes, if any. 534 * @return generally XRT_SUCCESS, except for internal runtime failures. 535 */ 536 + xrt_result_t (*get_plane_detections_ext)(struct xrt_device *xdev, 537 + uint64_t plane_detection_id, 538 + struct xrt_plane_detections_ext *out_detections); 539 540 /*! 541 * @brief Get the per-view pose in relation to the view space. ··· 560 * input. 561 * @param[in] at_timestamp_ns This is when the caller wants the poses and FOVs to be from. 562 * @param[in] view_count Number of views. 563 + * @param[in] view_type Type of view configuration (mono or stereo). 564 * @param[out] out_head_relation 565 * The head pose in the device tracking space. 566 * Combine with @p out_poses to get the views in ··· 578 xrt_result_t (*get_view_poses)(struct xrt_device *xdev, 579 const struct xrt_vec3 *default_eye_relation, 580 int64_t at_timestamp_ns, 581 + enum xrt_view_type view_type, 582 uint32_t view_count, 583 struct xrt_space_relation *out_head_relation, 584 struct xrt_fov *out_fovs, ··· 766 } 767 768 /*! 769 + * Helper function for @ref xrt_device::get_face_calibration_state_android. 770 + * 771 + * @copydoc xrt_device::get_face_calibration_state_android 772 + * 773 + * @public @memberof xrt_device 774 + */ 775 + static inline xrt_result_t 776 + xrt_device_get_face_calibration_state_android(struct xrt_device *xdev, bool *out_face_is_calibrated) 777 + { 778 + return xdev->get_face_calibration_state_android(xdev, out_face_is_calibrated); 779 + } 780 + 781 + /*! 782 * Helper function for @ref xrt_device::get_body_skeleton. 783 * 784 * @copydoc xrt_device::get_body_skeleton ··· 883 } 884 885 /*! 886 + * Helper function for @ref xrt_device::begin_plane_detection_ext. 887 * 888 * @public @memberof xrt_device 889 */ 890 + static inline xrt_result_t 891 xrt_device_begin_plane_detection_ext(struct xrt_device *xdev, 892 const struct xrt_plane_detector_begin_info_ext *begin_info, 893 uint64_t plane_detection_id, ··· 897 } 898 899 /*! 900 + * Helper function for @ref xrt_device::destroy_plane_detection_ext. 901 * 902 * @public @memberof xrt_device 903 */ 904 + static inline xrt_result_t 905 xrt_device_destroy_plane_detection_ext(struct xrt_device *xdev, uint64_t plane_detection_id) 906 { 907 return xdev->destroy_plane_detection_ext(xdev, plane_detection_id); 908 } 909 910 /*! 911 + * Helper function for @ref xrt_device::get_plane_detections_ext. 912 * 913 * @public @memberof xrt_device 914 */ 915 + static inline xrt_result_t 916 xrt_device_get_plane_detection_state_ext(struct xrt_device *xdev, 917 uint64_t plane_detection_id, 918 enum xrt_plane_detector_state_ext *out_state) ··· 921 } 922 923 /*! 924 + * Helper function for @ref xrt_device::get_plane_detections_ext. 925 * 926 * @public @memberof xrt_device 927 */ 928 + static inline xrt_result_t 929 xrt_device_get_plane_detections_ext(struct xrt_device *xdev, 930 uint64_t plane_detection_id, 931 struct xrt_plane_detections_ext *out_detections) ··· 943 xrt_device_get_view_poses(struct xrt_device *xdev, 944 const struct xrt_vec3 *default_eye_relation, 945 int64_t at_timestamp_ns, 946 + enum xrt_view_type view_type, 947 uint32_t view_count, 948 struct xrt_space_relation *out_head_relation, 949 struct xrt_fov *out_fovs, 950 struct xrt_pose *out_poses) 951 { 952 + return xdev->get_view_poses( // 953 + xdev, // 954 + default_eye_relation, // 955 + at_timestamp_ns, // 956 + view_type, // 957 + view_count, // 958 + out_head_relation, // 959 + out_fovs, // 960 + out_poses); // 961 } 962 963 /*!
+21
src/xrt/include/xrt/xrt_instance.h
··· 1 // Copyright 2020-2024, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 81 bool fb_face_tracking2_enabled; 82 bool meta_body_tracking_full_body_enabled; 83 bool meta_body_tracking_calibration_enabled; 84 }; 85 86 /*! ··· 126 */ 127 128 /*! 129 * Creates all of the system resources like the devices and system 130 * compositor. The system compositor is optional. 131 * ··· 198 */ 199 struct xrt_instance_android *android_instance; 200 }; 201 202 /*! 203 * @copydoc xrt_instance::create_system
··· 1 // Copyright 2020-2024, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 82 bool fb_face_tracking2_enabled; 83 bool meta_body_tracking_full_body_enabled; 84 bool meta_body_tracking_calibration_enabled; 85 + bool android_face_tracking_enabled; 86 }; 87 88 /*! ··· 128 */ 129 130 /*! 131 + * Checks if the system can be created with create_system(). 132 + */ 133 + xrt_result_t (*is_system_available)(struct xrt_instance *xinst, bool *out_available); 134 + 135 + /*! 136 * Creates all of the system resources like the devices and system 137 * compositor. The system compositor is optional. 138 * ··· 205 */ 206 struct xrt_instance_android *android_instance; 207 }; 208 + 209 + 210 + /*! 211 + * @copydoc xrt_instance::create_system 212 + * 213 + * Helper for calling through the function pointer. 214 + * 215 + * @public @memberof xrt_instance 216 + */ 217 + static inline xrt_result_t 218 + xrt_instance_is_system_available(struct xrt_instance *xinst, bool *out_available) 219 + { 220 + return xinst->is_system_available(xinst, out_available); 221 + } 222 223 /*! 224 * @copydoc xrt_instance::create_system
+18
src/xrt/include/xrt/xrt_limits.h
··· 1 // Copyright 2019-2022, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 9 10 #pragma once 11 12 #include "xrt/xrt_compiler.h" 13 14 ··· 20 * Max number of views supported by a compositor, artificial limit. 21 */ 22 #define XRT_MAX_VIEWS 2 23 24 /*! 25 * Maximum number of handles sent in one call. ··· 61 /*! 62 * Max number of layers which can be handled at once. 63 */ 64 #define XRT_MAX_LAYERS 128 65 66 /*! 67 * @}
··· 1 // Copyright 2019-2022, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 10 11 #pragma once 12 13 + #include "xrt/xrt_config_os.h" 14 #include "xrt/xrt_compiler.h" 15 16 ··· 22 * Max number of views supported by a compositor, artificial limit. 23 */ 24 #define XRT_MAX_VIEWS 2 25 + 26 + /* 27 + * System needs to support at least 4 views for stereo with foveated inset. 28 + */ 29 + #define XRT_MAX_COMPOSITOR_VIEW_CONFIGS_VIEW_COUNT (XRT_MAX_VIEWS > 4 ? XRT_MAX_VIEWS : 4) 30 + 31 + /* 32 + * Max number of view configurations a system compositor can support simultaneously. 33 + */ 34 + #define XRT_MAX_COMPOSITOR_VIEW_CONFIGS_COUNT 2 35 36 /*! 37 * Maximum number of handles sent in one call. ··· 73 /*! 74 * Max number of layers which can be handled at once. 75 */ 76 + #ifdef XRT_OS_ANDROID 77 + #define XRT_MAX_LAYERS 32 78 + #elif defined(XRT_OS_LINUX) || defined(XRT_OS_WINDOWS) 79 #define XRT_MAX_LAYERS 128 80 + #else 81 + #error "Unknown platform, define XRT_MAX_LAYERS for your OS" 82 + #endif 83 84 /*! 85 * @}
+6
src/xrt/include/xrt/xrt_results.h
··· 251 * Invoking complete on an already completed future 252 */ 253 XRT_ERROR_FUTURE_ALREADY_COMPLETE = -41, 254 } xrt_result_t;
··· 251 * Invoking complete on an already completed future 252 */ 253 XRT_ERROR_FUTURE_ALREADY_COMPLETE = -41, 254 + 255 + /*! 256 + * The device's tracking origin is not of type 257 + * XRT_TRACKING_TYPE_ATTACHABLE. 258 + */ 259 + XRT_ERROR_DEVICE_NOT_ATTACHABLE = -42, 260 } xrt_result_t;
+1
src/xrt/include/xrt/xrt_session.h
··· 80 enum xrt_session_event_type type; 81 bool visible; 82 bool focused; 83 }; 84 85 /*!
··· 80 enum xrt_session_event_type type; 81 bool visible; 82 bool focused; 83 + int64_t timestamp_ns; 84 }; 85 86 /*!
+80
src/xrt/include/xrt/xrt_space.h
··· 1 // Copyright 2019-2023, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 303 struct xrt_space **out_local_space, 304 struct xrt_space **out_local_floor_space); 305 306 /*! 307 * Destroy function. 308 * ··· 513 struct xrt_space **out_local_floor_space) 514 { 515 return xso->create_local_space(xso, out_local_space, out_local_floor_space); 516 } 517 518 /*!
··· 1 // Copyright 2019-2023, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 304 struct xrt_space **out_local_space, 305 struct xrt_space **out_local_floor_space); 306 307 + /* 308 + * 309 + * Special inter-monado component functions. 310 + * 311 + */ 312 + 313 + /*! 314 + * Add a new device to be tracked by the space overseer. The exact 315 + * semantic of the space is determined by the implementation of the 316 + * space overseer. And may be outright rejected by the implementation. 317 + * 318 + * After this call completes successfully, the device can be passed 319 + * into the @ref xrt_space_overseer::locate_device function, but may 320 + * not be locatable immediately. 321 + * 322 + * This function is not intended to be called by the OpenXR state 323 + * tracker, but by other monado components that need to add devices 324 + * but does not own the space overseer. Components like the fixer 325 + * uppers or for push devices. 326 + * 327 + * @param[in] xso The space overseer. 328 + * @param[in] xdev The device to be tracked. 329 + * @return XRT_SUCCESS if added, otherwise an error code. 330 + */ 331 + xrt_result_t (*add_device)(struct xrt_space_overseer *xso, struct xrt_device *xdev); 332 + 333 + /*! 334 + * Attach a device to a different space then it was associated with 335 + * originally, the space overseer might not support this operation. 336 + * 337 + * For some space overseer implementations this operation requires 338 + * that the device has the tracking origin type of 339 + * @ref XRT_TRACKING_TYPE_ATTACHABLE. Which space that becomes the 340 + * parent space of the device when @p space is NULL is undefined, 341 + * and the device might become un-trackable. 342 + * 343 + * @param[in] xso Owning space overseer. 344 + * @param[in] xdev Device to attach. 345 + * @param[in] space Space to attach the device to, may be NULL. 346 + * 347 + * @return XRT_SUCCESS on success. 348 + * @return XRT_ERROR_DEVICE_NOT_ATTACHABLE if the device does not have 349 + * the XRT_TRACKING_TYPE_ATTACHABLE tracking origin type. 350 + */ 351 + xrt_result_t (*attach_device)(struct xrt_space_overseer *xso, struct xrt_device *xdev, struct xrt_space *space); 352 + 353 + 354 + /* 355 + * 356 + * Destroy function always comes last. 357 + * 358 + */ 359 + 360 /*! 361 * Destroy function. 362 * ··· 567 struct xrt_space **out_local_floor_space) 568 { 569 return xso->create_local_space(xso, out_local_space, out_local_floor_space); 570 + } 571 + 572 + /*! 573 + * @copydoc xrt_space_overseer::add_device 574 + * 575 + * Helper for calling through the function pointer. 576 + * 577 + * @public @memberof xrt_space_overseer 578 + */ 579 + static inline xrt_result_t 580 + xrt_space_overseer_add_device(struct xrt_space_overseer *xso, struct xrt_device *xdev) 581 + { 582 + return xso->add_device(xso, xdev); 583 + } 584 + 585 + /*! 586 + * @copydoc xrt_space_overseer::attach_device 587 + * 588 + * Helper for calling through the function pointer. 589 + * 590 + * @public @memberof xrt_space_overseer 591 + */ 592 + static inline xrt_result_t 593 + xrt_space_overseer_attach_device(struct xrt_space_overseer *xso, struct xrt_device *xdev, struct xrt_space *space) 594 + { 595 + return xso->attach_device(xso, xdev, space); 596 } 597 598 /*!
+4
src/xrt/include/xrt/xrt_tracking.h
··· 1 // Copyright 2019, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 60 61 // The device(s) are tracked by other methods. 62 XRT_TRACKING_TYPE_OTHER, 63 }; 64 65 /*!
··· 1 // Copyright 2019, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 61 62 // The device(s) are tracked by other methods. 63 XRT_TRACKING_TYPE_OTHER, 64 + 65 + // The device(s) are (re)attachable. 66 + XRT_TRACKING_TYPE_ATTACHABLE, 67 }; 68 69 /*!
+32 -3
src/xrt/ipc/CMakeLists.txt
··· 1 # Copyright 2020-2021, Collabora, Ltd. 2 # SPDX-License-Identifier: BSL-1.0 3 4 ### 5 # Generator 6 7 foreach( ··· 16 OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${fn}" 17 COMMAND 18 ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/shared/proto.py 19 - ${CMAKE_CURRENT_SOURCE_DIR}/shared/proto.json 20 - "${CMAKE_CURRENT_BINARY_DIR}/${fn}" 21 VERBATIM 22 DEPENDS 23 ${CMAKE_CURRENT_SOURCE_DIR}/shared/proto.py 24 ${CMAKE_CURRENT_SOURCE_DIR}/shared/ipcproto/common.py 25 - ${CMAKE_CURRENT_SOURCE_DIR}/shared/proto.json 26 COMMENT "Generating ${fn} from protocol JSON description" 27 ) 28 endforeach() 29 30 set(IPC_COMMON_SOURCES 31 ${CMAKE_CURRENT_BINARY_DIR}/ipc_protocol_generated.h
··· 1 # Copyright 2020-2021, Collabora, Ltd. 2 + # Copyright 2025, NVIDIA CORPORATION. 3 # SPDX-License-Identifier: BSL-1.0 4 5 ### 6 + # Merge split protocol JSON files into single proto.json 7 + file(GLOB PROTO_JSON_FILES "${CMAKE_CURRENT_SOURCE_DIR}/shared/proto/*.json") 8 + 9 + merge_json_files( 10 + OUTPUT 11 + "${CMAKE_CURRENT_BINARY_DIR}/proto.json" 12 + SOURCES 13 + ${PROTO_JSON_FILES} 14 + IGNORE_SCHEMA 15 + ) 16 + 17 + ### 18 # Generator 19 20 foreach( ··· 29 OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${fn}" 30 COMMAND 31 ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/shared/proto.py 32 + ${CMAKE_CURRENT_BINARY_DIR}/proto.json "${CMAKE_CURRENT_BINARY_DIR}/${fn}" 33 VERBATIM 34 DEPENDS 35 ${CMAKE_CURRENT_SOURCE_DIR}/shared/proto.py 36 ${CMAKE_CURRENT_SOURCE_DIR}/shared/ipcproto/common.py 37 + ${CMAKE_CURRENT_BINARY_DIR}/proto.json 38 + ${CMAKE_CURRENT_SOURCE_DIR}/shared/ipc_protocol_generated.h.template 39 COMMENT "Generating ${fn} from protocol JSON description" 40 ) 41 endforeach() 42 + 43 + # Generate IPC structures list in the build root 44 + add_custom_command( 45 + OUTPUT "${CMAKE_BINARY_DIR}/ipc-structs.txt" 46 + COMMAND 47 + ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/shared/proto.py 48 + ${CMAKE_CURRENT_BINARY_DIR}/proto.json "${CMAKE_BINARY_DIR}/ipc-structs.txt" 49 + VERBATIM 50 + DEPENDS 51 + ${CMAKE_CURRENT_SOURCE_DIR}/shared/proto.py 52 + ${CMAKE_CURRENT_SOURCE_DIR}/shared/ipcproto/common.py 53 + ${CMAKE_CURRENT_BINARY_DIR}/proto.json 54 + COMMENT "Generating ipc-structs.txt from protocol JSON description" 55 + ) 56 + 57 + add_custom_target(ipc_structs_list ALL DEPENDS "${CMAKE_BINARY_DIR}/ipc-structs.txt") 58 59 set(IPC_COMMON_SOURCES 60 ${CMAKE_CURRENT_BINARY_DIR}/ipc_protocol_generated.h
+24 -1
src/xrt/ipc/client/ipc_client.h
··· 1 // Copyright 2020-2023, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 16 17 #include "util/u_threading.h" 18 #include "util/u_logging.h" 19 20 #include "shared/ipc_utils.h" 21 #include "shared/ipc_protocol.h" ··· 69 #endif // XRT_OS_ANDROID 70 }; 71 72 73 /* 74 * ··· 125 struct xrt_space_overseer * 126 ipc_client_space_overseer_create(struct ipc_connection *ipc_c); 127 128 - struct xrt_system_devices * 129 ipc_client_system_devices_create(struct ipc_connection *ipc_c); 130 131 struct xrt_session *
··· 1 // Copyright 2020-2023, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 17 18 #include "util/u_threading.h" 19 #include "util/u_logging.h" 20 + #include "util/u_system_helpers.h" 21 22 #include "shared/ipc_utils.h" 23 #include "shared/ipc_protocol.h" ··· 71 #endif // XRT_OS_ANDROID 72 }; 73 74 + /*! 75 + * Client side implementation of the system devices struct. 76 + */ 77 + struct ipc_client_system_devices 78 + { 79 + //! @public Base 80 + struct u_system_devices base; 81 + 82 + //! Connection to service. 83 + struct ipc_connection *ipc_c; 84 + 85 + struct xrt_tracking_origin *xtracks[XRT_SYSTEM_MAX_DEVICES]; 86 + 87 + size_t xtrack_count; 88 + 89 + struct xrt_reference feature_use[XRT_DEVICE_FEATURE_MAX_ENUM]; 90 + }; 91 + 92 93 /* 94 * ··· 145 struct xrt_space_overseer * 146 ipc_client_space_overseer_create(struct ipc_connection *ipc_c); 147 148 + uint32_t 149 + ipc_client_space_get_id(struct xrt_space *space); 150 + 151 + struct ipc_client_system_devices * 152 ipc_client_system_devices_create(struct ipc_connection *ipc_c); 153 154 struct xrt_session *
+12 -1
src/xrt/ipc/client/ipc_client_compositor.c
··· 1 // Copyright 2020, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 288 &use_dedicated_allocation, // out 289 remote_handles, // handles 290 XRT_MAX_SWAPCHAIN_IMAGES); // handles 291 IPC_CHK_AND_RET(icc->ipc_c, xret, "ipc_call_swapchain_create"); 292 293 struct ipc_client_swapchain *ics = U_TYPED_CALLOC(struct ipc_client_swapchain); ··· 345 handles, // handles 346 image_count, // handles 347 &id); // out 348 - IPC_CHK_AND_RET(icc->ipc_c, xret, "ipc_call_swapchain_create"); 349 350 struct ipc_client_swapchain *ics = U_TYPED_CALLOC(struct ipc_client_swapchain); 351 ics->base.base.image_count = image_count;
··· 1 // Copyright 2020, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 289 &use_dedicated_allocation, // out 290 remote_handles, // handles 291 XRT_MAX_SWAPCHAIN_IMAGES); // handles 292 + if (xret == XRT_ERROR_SWAPCHAIN_FLAG_VALID_BUT_UNSUPPORTED) { 293 + // Don't error print this, will spam CTS logs. 294 + IPC_DEBUG(icc->ipc_c, "Got XRT_ERROR_SWAPCHAIN_FLAG_VALID_BUT_UNSUPPORTED"); 295 + return xret; 296 + } 297 IPC_CHK_AND_RET(icc->ipc_c, xret, "ipc_call_swapchain_create"); 298 299 struct ipc_client_swapchain *ics = U_TYPED_CALLOC(struct ipc_client_swapchain); ··· 351 handles, // handles 352 image_count, // handles 353 &id); // out 354 + if (xret == XRT_ERROR_SWAPCHAIN_FLAG_VALID_BUT_UNSUPPORTED) { 355 + // Don't error print this, not an error. 356 + IPC_DEBUG(icc->ipc_c, "Got XRT_ERROR_SWAPCHAIN_FLAG_VALID_BUT_UNSUPPORTED"); 357 + return xret; 358 + } 359 + IPC_CHK_AND_RET(icc->ipc_c, xret, "ipc_call_swapchain_import"); 360 361 struct ipc_client_swapchain *ics = U_TYPED_CALLOC(struct ipc_client_swapchain); 362 ics->base.base.image_count = image_count;
+1 -4
src/xrt/ipc/client/ipc_client_device.c
··· 86 ipc_client_device_t *icd = U_DEVICE_ALLOCATE(ipc_client_device_t, flags, 0, 0); 87 88 // Fills in almost everything a regular device needs. 89 - ipc_client_xdev_init(icd, ipc_c, xtrack, device_id); 90 - 91 - // Need to set the destroy function. 92 - icd->base.destroy = ipc_client_device_destroy; 93 94 // Setup variable tracker. 95 u_var_add_root(icd, icd->base.str, true);
··· 86 ipc_client_device_t *icd = U_DEVICE_ALLOCATE(ipc_client_device_t, flags, 0, 0); 87 88 // Fills in almost everything a regular device needs. 89 + ipc_client_xdev_init(icd, ipc_c, xtrack, device_id, ipc_client_device_destroy); 90 91 // Setup variable tracker. 92 u_var_add_root(icd, icd->base.str, true);
+6 -2
src/xrt/ipc/client/ipc_client_hmd.c
··· 66 call_get_view_poses_raw(ipc_client_hmd_t *ich, 67 const struct xrt_vec3 *default_eye_relation, 68 int64_t at_timestamp_ns, 69 uint32_t view_count, 70 struct xrt_space_relation *out_head_relation, 71 struct xrt_fov *out_fovs, ··· 82 ich->device_id, // 83 default_eye_relation, // 84 at_timestamp_ns, // 85 view_count); // 86 IPC_CHK_WITH_GOTO(ich->ipc_c, xret, "ipc_send_device_get_view_poses_locked", out); 87 ··· 131 ipc_client_hmd_get_view_poses(struct xrt_device *xdev, 132 const struct xrt_vec3 *default_eye_relation, 133 int64_t at_timestamp_ns, 134 uint32_t view_count, 135 struct xrt_space_relation *out_head_relation, 136 struct xrt_fov *out_fovs, ··· 148 ich->device_id, // 149 default_eye_relation, // 150 at_timestamp_ns, // 151 view_count, // 152 &info); // 153 IPC_CHK_AND_RET(ich->ipc_c, xret, "ipc_call_device_get_view_poses_2"); ··· 164 ich, // 165 default_eye_relation, // 166 at_timestamp_ns, // 167 view_count, // 168 out_head_relation, // 169 out_fovs, // ··· 316 ipc_client_hmd_t *ich = U_DEVICE_ALLOCATE(ipc_client_hmd_t, flags, 0, 0); 317 318 // Fills in almost everything a regular device needs. 319 - ipc_client_xdev_init(ich, ipc_c, xtrack, device_id); 320 321 // Fill in needed HMD functions, and destroy. 322 ich->base.get_view_poses = ipc_client_hmd_get_view_poses; 323 ich->base.compute_distortion = ipc_client_hmd_compute_distortion; 324 ich->base.is_form_factor_available = ipc_client_hmd_is_form_factor_available; 325 ich->base.get_visibility_mask = ipc_client_hmd_get_visibility_mask; 326 - ich->base.destroy = ipc_client_hmd_destroy; 327 ich->base.get_brightness = ipc_client_hmd_get_brightness; 328 ich->base.set_brightness = ipc_client_hmd_set_brightness; 329
··· 66 call_get_view_poses_raw(ipc_client_hmd_t *ich, 67 const struct xrt_vec3 *default_eye_relation, 68 int64_t at_timestamp_ns, 69 + enum xrt_view_type view_type, 70 uint32_t view_count, 71 struct xrt_space_relation *out_head_relation, 72 struct xrt_fov *out_fovs, ··· 83 ich->device_id, // 84 default_eye_relation, // 85 at_timestamp_ns, // 86 + view_type, // 87 view_count); // 88 IPC_CHK_WITH_GOTO(ich->ipc_c, xret, "ipc_send_device_get_view_poses_locked", out); 89 ··· 133 ipc_client_hmd_get_view_poses(struct xrt_device *xdev, 134 const struct xrt_vec3 *default_eye_relation, 135 int64_t at_timestamp_ns, 136 + enum xrt_view_type view_type, 137 uint32_t view_count, 138 struct xrt_space_relation *out_head_relation, 139 struct xrt_fov *out_fovs, ··· 151 ich->device_id, // 152 default_eye_relation, // 153 at_timestamp_ns, // 154 + view_type, // 155 view_count, // 156 &info); // 157 IPC_CHK_AND_RET(ich->ipc_c, xret, "ipc_call_device_get_view_poses_2"); ··· 168 ich, // 169 default_eye_relation, // 170 at_timestamp_ns, // 171 + view_type, // 172 view_count, // 173 out_head_relation, // 174 out_fovs, // ··· 321 ipc_client_hmd_t *ich = U_DEVICE_ALLOCATE(ipc_client_hmd_t, flags, 0, 0); 322 323 // Fills in almost everything a regular device needs. 324 + ipc_client_xdev_init(ich, ipc_c, xtrack, device_id, ipc_client_hmd_destroy); 325 326 // Fill in needed HMD functions, and destroy. 327 ich->base.get_view_poses = ipc_client_hmd_get_view_poses; 328 ich->base.compute_distortion = ipc_client_hmd_compute_distortion; 329 ich->base.is_form_factor_available = ipc_client_hmd_is_form_factor_available; 330 ich->base.get_visibility_mask = ipc_client_hmd_get_visibility_mask; 331 ich->base.get_brightness = ipc_client_hmd_get_brightness; 332 ich->base.set_brightness = ipc_client_hmd_set_brightness; 333
+45 -58
src/xrt/ipc/client/ipc_client_instance.c
··· 1 // Copyright 2020-2024, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 78 79 struct ipc_connection ipc_c; 80 81 - struct xrt_tracking_origin *xtracks[XRT_SYSTEM_MAX_DEVICES]; 82 - size_t xtrack_count; 83 - 84 - struct xrt_device *xdevs[XRT_SYSTEM_MAX_DEVICES]; 85 - size_t xdev_count; 86 - 87 #ifdef XRT_OS_ANDROID 88 struct android_instance_base android; 89 #endif ··· 136 */ 137 138 static xrt_result_t 139 ipc_client_instance_create_system(struct xrt_instance *xinst, 140 struct xrt_system **out_xsys, 141 struct xrt_system_devices **out_xsysd, ··· 151 assert(*out_xsysd == NULL); 152 assert(out_xsysc == NULL || *out_xsysc == NULL); 153 154 - struct xrt_system_devices *xsysd = NULL; 155 struct xrt_system_compositor *xsysc = NULL; 156 157 // Allocate a helper xrt_system_devices struct. 158 - xsysd = ipc_client_system_devices_create(&ii->ipc_c); 159 160 - // Take the devices from this instance. 161 - for (uint32_t i = 0; i < ii->xdev_count; i++) { 162 - xsysd->xdevs[i] = ii->xdevs[i]; 163 - ii->xdevs[i] = NULL; 164 } 165 - xsysd->xdev_count = ii->xdev_count; 166 - ii->xdev_count = 0; 167 168 #define SET_ROLE(ROLE) \ 169 do { \ ··· 231 232 // service considers us to be connected until fd is closed 233 ipc_client_connection_fini(&ii->ipc_c); 234 - 235 - for (size_t i = 0; i < ii->xtrack_count; i++) { 236 - u_var_remove_root(ii->xtracks[i]); 237 - free(ii->xtracks[i]); 238 - ii->xtracks[i] = NULL; 239 - } 240 - ii->xtrack_count = 0; 241 242 #ifdef XRT_OS_ANDROID 243 android_instance_base_cleanup(&(ii->android), xinst); ··· 269 ipc_instance_create(const struct xrt_instance_info *i_info, struct xrt_instance **out_xinst) 270 { 271 struct ipc_client_instance *ii = U_TYPED_CALLOC(struct ipc_client_instance); 272 ii->base.create_system = ipc_client_instance_create_system; 273 ii->base.get_prober = ipc_client_instance_get_prober; 274 ii->base.destroy = ipc_client_instance_destroy; ··· 294 free(ii); 295 return xret; 296 } 297 - 298 - uint32_t count = 0; 299 - struct xrt_tracking_origin *xtrack = NULL; 300 - struct ipc_shared_memory *ism = ii->ipc_c.ism; 301 - 302 - // Query the server for how many tracking origins it has. 303 - count = 0; 304 - for (uint32_t i = 0; i < ism->itrack_count; i++) { 305 - xtrack = U_TYPED_CALLOC(struct xrt_tracking_origin); 306 - 307 - memcpy(xtrack->name, ism->itracks[i].name, sizeof(xtrack->name)); 308 - 309 - xtrack->type = ism->itracks[i].type; 310 - xtrack->initial_offset = ism->itracks[i].offset; 311 - ii->xtracks[count++] = xtrack; 312 - 313 - u_var_add_root(xtrack, "Tracking origin", true); 314 - u_var_add_ro_text(xtrack, xtrack->name, "name"); 315 - u_var_add_pose(xtrack, &xtrack->initial_offset, "offset"); 316 - } 317 - 318 - ii->xtrack_count = count; 319 - 320 - // Query the server for how many devices it has. 321 - count = 0; 322 - for (uint32_t i = 0; i < ism->isdev_count; i++) { 323 - struct ipc_shared_device *isdev = &ism->isdevs[i]; 324 - xtrack = ii->xtracks[isdev->tracking_origin_index]; 325 - 326 - if (isdev->device_type == XRT_DEVICE_TYPE_HMD) { 327 - ii->xdevs[count++] = ipc_client_hmd_create(&ii->ipc_c, xtrack, i); 328 - } else { 329 - ii->xdevs[count++] = ipc_client_device_create(&ii->ipc_c, xtrack, i); 330 - } 331 - } 332 - 333 - ii->xdev_count = count; 334 335 ii->base.startup_timestamp = ii->ipc_c.ism->startup_timestamp; 336
··· 1 // Copyright 2020-2024, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 79 80 struct ipc_connection ipc_c; 81 82 #ifdef XRT_OS_ANDROID 83 struct android_instance_base android; 84 #endif ··· 131 */ 132 133 static xrt_result_t 134 + ipc_client_instance_is_system_available(struct xrt_instance *xinst, bool *out_available) 135 + { 136 + struct ipc_client_instance *ii = ipc_client_instance(xinst); 137 + xrt_result_t xret = ipc_call_instance_is_system_available(&ii->ipc_c, out_available); 138 + IPC_CHK_ALWAYS_RET(&ii->ipc_c, xret, "ipc_call_instance_is_system_available"); 139 + } 140 + 141 + static xrt_result_t 142 ipc_client_instance_create_system(struct xrt_instance *xinst, 143 struct xrt_system **out_xsys, 144 struct xrt_system_devices **out_xsysd, ··· 154 assert(*out_xsysd == NULL); 155 assert(out_xsysc == NULL || *out_xsysc == NULL); 156 157 struct xrt_system_compositor *xsysc = NULL; 158 159 // Allocate a helper xrt_system_devices struct. 160 + struct ipc_client_system_devices *icsd = ipc_client_system_devices_create(&ii->ipc_c); 161 + struct xrt_system_devices *xsysd = &icsd->base.base; 162 + 163 + uint32_t count = 0; 164 + struct xrt_tracking_origin *xtrack = NULL; 165 + struct ipc_shared_memory *ism = ii->ipc_c.ism; 166 167 + // Query the server for how many tracking origins it has. 168 + count = 0; 169 + for (uint32_t i = 0; i < ism->itrack_count; i++) { 170 + xtrack = U_TYPED_CALLOC(struct xrt_tracking_origin); 171 + 172 + memcpy(xtrack->name, ism->itracks[i].name, sizeof(xtrack->name)); 173 + 174 + xtrack->type = ism->itracks[i].type; 175 + xtrack->initial_offset = ism->itracks[i].offset; 176 + icsd->xtracks[count++] = xtrack; 177 + 178 + u_var_add_root(xtrack, "Tracking origin", true); 179 + u_var_add_ro_text(xtrack, xtrack->name, "name"); 180 + u_var_add_pose(xtrack, &xtrack->initial_offset, "offset"); 181 + } 182 + icsd->xtrack_count = count; 183 + 184 + // Query the server for how many devices it has. 185 + count = 0; 186 + for (uint32_t i = 0; i < ism->isdev_count; i++) { 187 + struct ipc_shared_device *isdev = &ism->isdevs[i]; 188 + xtrack = icsd->xtracks[isdev->tracking_origin_index]; 189 + 190 + if (isdev->device_type == XRT_DEVICE_TYPE_HMD) { 191 + xsysd->xdevs[count++] = ipc_client_hmd_create(&ii->ipc_c, xtrack, i); 192 + } else { 193 + xsysd->xdevs[count++] = ipc_client_device_create(&ii->ipc_c, xtrack, i); 194 + } 195 } 196 + xsysd->xdev_count = count; 197 198 #define SET_ROLE(ROLE) \ 199 do { \ ··· 261 262 // service considers us to be connected until fd is closed 263 ipc_client_connection_fini(&ii->ipc_c); 264 265 #ifdef XRT_OS_ANDROID 266 android_instance_base_cleanup(&(ii->android), xinst); ··· 292 ipc_instance_create(const struct xrt_instance_info *i_info, struct xrt_instance **out_xinst) 293 { 294 struct ipc_client_instance *ii = U_TYPED_CALLOC(struct ipc_client_instance); 295 + ii->base.is_system_available = ipc_client_instance_is_system_available; 296 ii->base.create_system = ipc_client_instance_create_system; 297 ii->base.get_prober = ipc_client_instance_get_prober; 298 ii->base.destroy = ipc_client_instance_destroy; ··· 318 free(ii); 319 return xret; 320 } 321 322 ii->base.startup_timestamp = ii->ipc_c.ism->startup_timestamp; 323
+25
src/xrt/ipc/client/ipc_client_space_overseer.c
··· 1 // Copyright 2023, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 317 return ipc_call_space_set_reference_space_offset(icspo->ipc_c, type, offset); 318 } 319 320 static void 321 destroy(struct xrt_space_overseer *xso) 322 { ··· 373 icspo->base.set_tracking_origin_offset = set_tracking_origin_offset; 374 icspo->base.get_reference_space_offset = get_reference_space_offset; 375 icspo->base.set_reference_space_offset = set_reference_space_offset; 376 icspo->base.destroy = destroy; 377 icspo->ipc_c = ipc_c; 378 ··· 395 396 return &icspo->base; 397 }
··· 1 // Copyright 2023, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 318 return ipc_call_space_set_reference_space_offset(icspo->ipc_c, type, offset); 319 } 320 321 + static xrt_result_t 322 + add_device(struct xrt_space_overseer *xso, struct xrt_device *xdev) 323 + { 324 + return XRT_ERROR_NOT_IMPLEMENTED; 325 + } 326 + 327 + static xrt_result_t 328 + attach_device(struct xrt_space_overseer *xso, struct xrt_device *xdev, struct xrt_space *space) 329 + { 330 + // For IPC client, attachable devices are handled on the server side. 331 + // This should not be called from the client in the typical use case. 332 + return XRT_ERROR_NOT_IMPLEMENTED; 333 + } 334 + 335 static void 336 destroy(struct xrt_space_overseer *xso) 337 { ··· 388 icspo->base.set_tracking_origin_offset = set_tracking_origin_offset; 389 icspo->base.get_reference_space_offset = get_reference_space_offset; 390 icspo->base.set_reference_space_offset = set_reference_space_offset; 391 + icspo->base.add_device = add_device; 392 + icspo->base.attach_device = attach_device; 393 icspo->base.destroy = destroy; 394 icspo->ipc_c = ipc_c; 395 ··· 412 413 return &icspo->base; 414 } 415 + 416 + uint32_t 417 + ipc_client_space_get_id(struct xrt_space *space) 418 + { 419 + assert(space != NULL); 420 + 421 + return ipc_client_space(space)->id; 422 + }
+3
src/xrt/ipc/client/ipc_client_system.c
··· 1 // Copyright 2020-2023, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 135 ipc_client_system_create(struct ipc_connection *ipc_c, struct xrt_system_compositor *xsysc) 136 { 137 struct ipc_client_system *icsys = U_TYPED_CALLOC(struct ipc_client_system); 138 xrt_result_t xret = ipc_call_system_get_properties(ipc_c, &icsys->base.properties); 139 if (xret != XRT_SUCCESS) { 140 free(icsys); 141 return NULL;
··· 1 // Copyright 2020-2023, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 136 ipc_client_system_create(struct ipc_connection *ipc_c, struct xrt_system_compositor *xsysc) 137 { 138 struct ipc_client_system *icsys = U_TYPED_CALLOC(struct ipc_client_system); 139 + 140 xrt_result_t xret = ipc_call_system_get_properties(ipc_c, &icsys->base.properties); 141 + IPC_CHK_ONLY_PRINT(ipc_c, xret, "ipc_call_system_get_properties"); 142 if (xret != XRT_SUCCESS) { 143 free(icsys); 144 return NULL;
+11 -14
src/xrt/ipc/client/ipc_client_system_devices.c
··· 1 // Copyright 2023, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 12 #include "ipc_client_generated.h" 13 14 #include "util/u_system_helpers.h" 15 - 16 - 17 - struct ipc_client_system_devices 18 - { 19 - //! @public Base 20 - struct u_system_devices base; 21 - 22 - //! Connection to service. 23 - struct ipc_connection *ipc_c; 24 - 25 - struct xrt_reference feature_use[XRT_DEVICE_FEATURE_MAX_ENUM]; 26 - }; 27 28 29 /* ··· 93 { 94 struct ipc_client_system_devices *usysd = ipc_system_devices(xsysd); 95 96 u_system_devices_close(&usysd->base.base); 97 98 free(usysd); ··· 105 * 106 */ 107 108 - struct xrt_system_devices * 109 ipc_client_system_devices_create(struct ipc_connection *ipc_c) 110 { 111 struct ipc_client_system_devices *icsd = U_TYPED_CALLOC(struct ipc_client_system_devices); ··· 115 icsd->base.base.feature_dec = ipc_client_system_devices_feature_dec; 116 icsd->ipc_c = ipc_c; 117 118 - return &icsd->base.base; 119 }
··· 1 // Copyright 2023, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 13 #include "ipc_client_generated.h" 14 15 #include "util/u_system_helpers.h" 16 + #include "util/u_var.h" 17 18 19 /* ··· 83 { 84 struct ipc_client_system_devices *usysd = ipc_system_devices(xsysd); 85 86 + for (size_t i = 0; i < usysd->xtrack_count; i++) { 87 + u_var_remove_root(usysd->xtracks[i]); 88 + free(usysd->xtracks[i]); 89 + usysd->xtracks[i] = NULL; 90 + } 91 + usysd->xtrack_count = 0; 92 + 93 u_system_devices_close(&usysd->base.base); 94 95 free(usysd); ··· 102 * 103 */ 104 105 + struct ipc_client_system_devices * 106 ipc_client_system_devices_create(struct ipc_connection *ipc_c) 107 { 108 struct ipc_client_system_devices *icsd = U_TYPED_CALLOC(struct ipc_client_system_devices); ··· 112 icsd->base.base.feature_dec = ipc_client_system_devices_feature_dec; 113 icsd->ipc_c = ipc_c; 114 115 + return icsd; 116 }
+8 -9
src/xrt/ipc/client/ipc_client_xdev.c
··· 391 ipc_client_xdev_init(struct ipc_client_xdev *icx, 392 struct ipc_connection *ipc_c, 393 struct xrt_tracking_origin *xtrack, 394 - uint32_t device_id) 395 { 396 // Helpers. 397 struct ipc_shared_memory *ism = ipc_c->ism; ··· 400 // Important fields. 401 icx->ipc_c = ipc_c; 402 icx->device_id = device_id; 403 404 // Shared implemented functions. 405 icx->base.update_inputs = ipc_client_xdev_update_inputs; 406 - icx->base.get_tracked_pose = ipc_client_xdev_get_tracked_pose; 407 icx->base.get_hand_tracking = ipc_client_xdev_get_hand_tracking; 408 icx->base.get_face_tracking = ipc_client_xdev_get_face_tracking; 409 icx->base.get_body_skeleton = ipc_client_xdev_get_body_skeleton; ··· 420 icx->base.destroy_plane_detection_ext = ipc_client_xdev_destroy_plane_detection_ext; 421 icx->base.get_plane_detection_state_ext = ipc_client_xdev_get_plane_detection_state_ext; 422 icx->base.get_plane_detections_ext = ipc_client_xdev_get_plane_detections_ext; 423 - 424 - // Not implemented functions, some get overridden. 425 - icx->base.get_view_poses = u_device_ni_get_view_poses; 426 - icx->base.compute_distortion = u_device_ni_compute_distortion; 427 - icx->base.get_visibility_mask = u_device_ni_get_visibility_mask; 428 - icx->base.is_form_factor_available = u_device_ni_is_form_factor_available; 429 - icx->base.get_battery_status = u_device_ni_get_battery_status; 430 431 // Copying the information from the isdev. 432 icx->base.device_type = isdev->device_type;
··· 391 ipc_client_xdev_init(struct ipc_client_xdev *icx, 392 struct ipc_connection *ipc_c, 393 struct xrt_tracking_origin *xtrack, 394 + uint32_t device_id, 395 + u_device_destroy_function_t destroy_fn) 396 { 397 // Helpers. 398 struct ipc_shared_memory *ism = ipc_c->ism; ··· 401 // Important fields. 402 icx->ipc_c = ipc_c; 403 icx->device_id = device_id; 404 + 405 + /* 406 + * Fill in not implemented or noop versions first, 407 + * destroy gets filled in by either device or HMD. 408 + */ 409 + u_device_populate_function_pointers(&icx->base, ipc_client_xdev_get_tracked_pose, destroy_fn); 410 411 // Shared implemented functions. 412 icx->base.update_inputs = ipc_client_xdev_update_inputs; 413 icx->base.get_hand_tracking = ipc_client_xdev_get_hand_tracking; 414 icx->base.get_face_tracking = ipc_client_xdev_get_face_tracking; 415 icx->base.get_body_skeleton = ipc_client_xdev_get_body_skeleton; ··· 426 icx->base.destroy_plane_detection_ext = ipc_client_xdev_destroy_plane_detection_ext; 427 icx->base.get_plane_detection_state_ext = ipc_client_xdev_get_plane_detection_state_ext; 428 icx->base.get_plane_detections_ext = ipc_client_xdev_get_plane_detections_ext; 429 430 // Copying the information from the isdev. 431 icx->base.device_type = isdev->device_type;
+5 -1
src/xrt/ipc/client/ipc_client_xdev.h
··· 13 14 #pragma once 15 16 #ifdef __cplusplus 17 extern "C" { 18 #endif ··· 58 ipc_client_xdev_init(struct ipc_client_xdev *icx, 59 struct ipc_connection *ipc_c, 60 struct xrt_tracking_origin *xtrack, 61 - uint32_t device_id); 62 63 /*! 64 * Frees any memory that was allocated as part of init and resets some pointers.
··· 13 14 #pragma once 15 16 + #include "util/u_device.h" 17 + 18 + 19 #ifdef __cplusplus 20 extern "C" { 21 #endif ··· 61 ipc_client_xdev_init(struct ipc_client_xdev *icx, 62 struct ipc_connection *ipc_c, 63 struct xrt_tracking_origin *xtrack, 64 + uint32_t device_id, 65 + u_device_destroy_function_t destroy_fn); 66 67 /*! 68 * Frees any memory that was allocated as part of init and resets some pointers.
+29 -4
src/xrt/ipc/server/ipc_server.h
··· 1 // Copyright 2020-2023, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 22 23 #include "shared/ipc_protocol.h" 24 #include "shared/ipc_message_channel.h" 25 26 #include <stdio.h> 27 ··· 89 { 90 //! Link back to the main server. 91 struct ipc_server *server; 92 93 //! Session for this client. 94 struct xrt_session *xs; ··· 188 { 189 //! The actual device. 190 struct xrt_device *xdev; 191 - 192 - //! Is the IO suppressed for this device. 193 - bool io_active; 194 }; 195 196 /*! ··· 329 * @public @memberof ipc_server_mainloop 330 */ 331 int 332 - ipc_server_mainloop_init(struct ipc_server_mainloop *ml); 333 334 /*! 335 * @brief Poll the mainloop. ··· 407 408 struct os_mutex lock; 409 } global_state; 410 }; 411 412 413 /*! 414 * Get the current state of a client.
··· 1 // Copyright 2020-2023, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 23 24 #include "shared/ipc_protocol.h" 25 #include "shared/ipc_message_channel.h" 26 + 27 + #include "ipc_server_interface.h" 28 29 #include <stdio.h> 30 ··· 92 { 93 //! Link back to the main server. 94 struct ipc_server *server; 95 + 96 + //! Has the system part of the shm initialized. 97 + bool has_init_shm_system; 98 99 //! Session for this client. 100 struct xrt_session *xs; ··· 194 { 195 //! The actual device. 196 struct xrt_device *xdev; 197 }; 198 199 /*! ··· 332 * @public @memberof ipc_server_mainloop 333 */ 334 int 335 + ipc_server_mainloop_init(struct ipc_server_mainloop *ml, bool no_stdin); 336 337 /*! 338 * @brief Poll the mainloop. ··· 410 411 struct os_mutex lock; 412 } global_state; 413 + 414 + /*! 415 + * Callbacks for server events. 416 + */ 417 + const struct ipc_server_callbacks *callbacks; 418 + 419 + /*! 420 + * User data passed to callbacks. 421 + */ 422 + void *callback_data; 423 + 424 + //! Disable listening on stdin for server stop. 425 + bool no_stdin; 426 }; 427 428 + /*! 429 + * Finish setting up the server by creating the system, compositor and devices. 430 + * 431 + * @ingroup ipc_server 432 + */ 433 + xrt_result_t 434 + ipc_server_init_system_if_available_locked(struct ipc_server *s, 435 + volatile struct ipc_client_state *ics, 436 + bool *out_available); 437 438 /*! 439 * Get the current state of a client.
+41 -17
src/xrt/ipc/server/ipc_server_handler.c
··· 1 // Copyright 2020-2024, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 387 EXT(meta_body_tracking_full_body_enabled); 388 EXT(meta_body_tracking_calibration_enabled); 389 EXT(fb_face_tracking2_enabled); 390 391 #undef EXT 392 #undef PTT ··· 400 } 401 402 xrt_result_t 403 ipc_handle_system_compositor_get_info(volatile struct ipc_client_state *ics, 404 struct xrt_system_compositor_info *out_info) 405 { ··· 440 ics->xc = &xcn->base; 441 442 xrt_syscomp_set_state(ics->server->xsysc, ics->xc, ics->client_state.session_visible, 443 - ics->client_state.session_focused); 444 xrt_syscomp_set_z_order(ics->server->xsysc, ics->xc, ics->client_state.z_order); 445 446 return XRT_SUCCESS; ··· 485 .fb_face_tracking2_enabled = ics->client_state.info.fb_face_tracking2_enabled, 486 .meta_body_tracking_full_body_enabled = ics->client_state.info.meta_body_tracking_full_body_enabled, 487 .meta_body_tracking_calibration_enabled = ics->client_state.info.meta_body_tracking_calibration_enabled, 488 }; 489 490 return xrt_comp_begin_session(ics->xc, &begin_session_info); ··· 1623 } 1624 1625 xrt_result_t 1626 - ipc_handle_system_toggle_io_device(volatile struct ipc_client_state *ics, uint32_t device_id) 1627 - { 1628 - if (device_id >= IPC_MAX_DEVICES) { 1629 - return XRT_ERROR_IPC_FAILURE; 1630 - } 1631 - 1632 - struct ipc_device *idev = &ics->server->idevs[device_id]; 1633 - 1634 - idev->io_active = !idev->io_active; 1635 - 1636 - return XRT_SUCCESS; 1637 - } 1638 - 1639 - xrt_result_t 1640 ipc_handle_swapchain_get_properties(volatile struct ipc_client_state *ics, 1641 const struct xrt_swapchain_create_info *info, 1642 struct xrt_swapchain_create_properties *xsccp) ··· 1931 struct xrt_input *dst = &ism->inputs[isdev->first_input_index]; 1932 size_t size = sizeof(struct xrt_input) * isdev->input_count; 1933 1934 - bool io_active = ics->io_active && idev->io_active; 1935 if (io_active) { 1936 memcpy(dst, src, size); 1937 } else { ··· 1986 } 1987 1988 // Special case the headpose. 1989 - bool disabled = (!isdev->io_active || !ics->io_active) && name != XRT_INPUT_GENERIC_HEAD_POSE; 1990 bool active_on_client = input->active; 1991 1992 // We have been disabled but the client hasn't called update. ··· 2026 uint32_t id, 2027 const struct xrt_vec3 *fallback_eye_relation, 2028 int64_t at_timestamp_ns, 2029 uint32_t view_count) 2030 { 2031 struct ipc_message_channel *imc = (struct ipc_message_channel *)&ics->imc; ··· 2055 xdev, // 2056 fallback_eye_relation, // 2057 at_timestamp_ns, // 2058 view_count, // 2059 &reply.head_relation, // 2060 fovs, // ··· 2100 uint32_t id, 2101 const struct xrt_vec3 *default_eye_relation, 2102 int64_t at_timestamp_ns, 2103 uint32_t view_count, 2104 struct ipc_info_get_view_poses_2 *out_info) 2105 { ··· 2107 uint32_t device_id = id; 2108 struct xrt_device *xdev = NULL; 2109 GET_XDEV_OR_RETURN(ics, device_id, xdev); 2110 return xrt_device_get_view_poses( // 2111 xdev, // 2112 default_eye_relation, // 2113 at_timestamp_ns, // 2114 view_count, // 2115 &out_info->head_relation, // 2116 out_info->fovs, // ··· 2556 GET_XDEV_OR_RETURN(ics, device_id, xdev); 2557 // Get facial expression data. 2558 return xrt_device_get_face_tracking(xdev, facial_expression_type, at_timestamp_ns, out_value); 2559 } 2560 2561 xrt_result_t
··· 1 // Copyright 2020-2024, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 388 EXT(meta_body_tracking_full_body_enabled); 389 EXT(meta_body_tracking_calibration_enabled); 390 EXT(fb_face_tracking2_enabled); 391 + EXT(android_face_tracking_enabled); 392 393 #undef EXT 394 #undef PTT ··· 402 } 403 404 xrt_result_t 405 + ipc_handle_instance_is_system_available(volatile struct ipc_client_state *ics, bool *out_available) 406 + { 407 + IPC_TRACE_MARKER(); 408 + 409 + xrt_result_t xret = XRT_SUCCESS; 410 + 411 + struct ipc_server *s = ics->server; 412 + 413 + os_mutex_lock(&s->global_state.lock); 414 + 415 + xret = ipc_server_init_system_if_available_locked(s, ics, out_available); 416 + IPC_CHK_WITH_GOTO(s, xret, "ipc_server_init_system_if_available_locked", cleanup); 417 + 418 + cleanup: 419 + os_mutex_unlock(&s->global_state.lock); 420 + return xret; 421 + } 422 + 423 + xrt_result_t 424 ipc_handle_system_compositor_get_info(volatile struct ipc_client_state *ics, 425 struct xrt_system_compositor_info *out_info) 426 { ··· 461 ics->xc = &xcn->base; 462 463 xrt_syscomp_set_state(ics->server->xsysc, ics->xc, ics->client_state.session_visible, 464 + ics->client_state.session_focused, os_monotonic_get_ns()); 465 xrt_syscomp_set_z_order(ics->server->xsysc, ics->xc, ics->client_state.z_order); 466 467 return XRT_SUCCESS; ··· 506 .fb_face_tracking2_enabled = ics->client_state.info.fb_face_tracking2_enabled, 507 .meta_body_tracking_full_body_enabled = ics->client_state.info.meta_body_tracking_full_body_enabled, 508 .meta_body_tracking_calibration_enabled = ics->client_state.info.meta_body_tracking_calibration_enabled, 509 + .android_face_tracking_enabled = ics->client_state.info.android_face_tracking_enabled, 510 }; 511 512 return xrt_comp_begin_session(ics->xc, &begin_session_info); ··· 1645 } 1646 1647 xrt_result_t 1648 ipc_handle_swapchain_get_properties(volatile struct ipc_client_state *ics, 1649 const struct xrt_swapchain_create_info *info, 1650 struct xrt_swapchain_create_properties *xsccp) ··· 1939 struct xrt_input *dst = &ism->inputs[isdev->first_input_index]; 1940 size_t size = sizeof(struct xrt_input) * isdev->input_count; 1941 1942 + bool io_active = ics->io_active; 1943 if (io_active) { 1944 memcpy(dst, src, size); 1945 } else { ··· 1994 } 1995 1996 // Special case the headpose. 1997 + bool disabled = !ics->io_active && name != XRT_INPUT_GENERIC_HEAD_POSE; 1998 bool active_on_client = input->active; 1999 2000 // We have been disabled but the client hasn't called update. ··· 2034 uint32_t id, 2035 const struct xrt_vec3 *fallback_eye_relation, 2036 int64_t at_timestamp_ns, 2037 + enum xrt_view_type view_type, 2038 uint32_t view_count) 2039 { 2040 struct ipc_message_channel *imc = (struct ipc_message_channel *)&ics->imc; ··· 2064 xdev, // 2065 fallback_eye_relation, // 2066 at_timestamp_ns, // 2067 + view_type, // 2068 view_count, // 2069 &reply.head_relation, // 2070 fovs, // ··· 2110 uint32_t id, 2111 const struct xrt_vec3 *default_eye_relation, 2112 int64_t at_timestamp_ns, 2113 + enum xrt_view_type view_type, 2114 uint32_t view_count, 2115 struct ipc_info_get_view_poses_2 *out_info) 2116 { ··· 2118 uint32_t device_id = id; 2119 struct xrt_device *xdev = NULL; 2120 GET_XDEV_OR_RETURN(ics, device_id, xdev); 2121 + 2122 return xrt_device_get_view_poses( // 2123 xdev, // 2124 default_eye_relation, // 2125 at_timestamp_ns, // 2126 + view_type, // 2127 view_count, // 2128 &out_info->head_relation, // 2129 out_info->fovs, // ··· 2569 GET_XDEV_OR_RETURN(ics, device_id, xdev); 2570 // Get facial expression data. 2571 return xrt_device_get_face_tracking(xdev, facial_expression_type, at_timestamp_ns, out_value); 2572 + } 2573 + 2574 + xrt_result_t 2575 + ipc_handle_device_device_get_face_calibration_state_android(volatile struct ipc_client_state *ics, 2576 + uint32_t id, 2577 + bool *out_face_is_calibrated) 2578 + { 2579 + const uint32_t device_id = id; 2580 + struct xrt_device *xdev = NULL; 2581 + GET_XDEV_OR_RETURN(ics, device_id, xdev); 2582 + return xrt_device_get_face_calibration_state_android(xdev, out_face_is_calibrated); 2583 } 2584 2585 xrt_result_t
+32
src/xrt/ipc/server/ipc_server_interface.h
··· 36 { 37 //! Information passed onto the debug gui. 38 struct u_debug_gui_create_info udgci; 39 }; 40 41 /*! ··· 70 * @param[in] data User data given passed into the main function. 71 */ 72 void (*mainloop_leaving)(struct ipc_server *s, struct xrt_instance *xinst, void *data); 73 }; 74 75 /*! ··· 80 int 81 ipc_server_main_common(const struct ipc_server_main_info *ismi, const struct ipc_server_callbacks *iscb, void *data); 82 83 84 #ifndef XRT_OS_ANDROID 85
··· 36 { 37 //! Information passed onto the debug gui. 38 struct u_debug_gui_create_info udgci; 39 + 40 + //! Flag whether runtime should exit on app disconnect. 41 + bool exit_on_disconnect; 42 + 43 + //! Disable listening on stdin for server stop. 44 + bool no_stdin; 45 }; 46 47 /*! ··· 76 * @param[in] data User data given passed into the main function. 77 */ 78 void (*mainloop_leaving)(struct ipc_server *s, struct xrt_instance *xinst, void *data); 79 + 80 + /*! 81 + * A new client has connected to the IPC server. 82 + * 83 + * param s The IPC server. 84 + * param client_id The ID of the newly connected client. 85 + * param data User data given passed into the main function. 86 + */ 87 + void (*client_connected)(struct ipc_server *s, uint32_t client_id, void *data); 88 + 89 + /*! 90 + * A client has disconnected from the IPC server. 91 + * 92 + * param s The IPC server. 93 + * param client_id The ID of the newly connected client. 94 + * param data User data given passed into the main function. 95 + */ 96 + void (*client_disconnected)(struct ipc_server *s, uint32_t client_id, void *data); 97 }; 98 99 /*! ··· 104 int 105 ipc_server_main_common(const struct ipc_server_main_info *ismi, const struct ipc_server_callbacks *iscb, void *data); 106 107 + /*! 108 + * Asks the server to shut down, this call is asynchronous and will return 109 + * immediately. Use callbacks to be notified when the server stops. 110 + * 111 + * @memberof ipc_server 112 + */ 113 + int 114 + ipc_server_stop(struct ipc_server *s); 115 116 #ifndef XRT_OS_ANDROID 117
+1 -1
src/xrt/ipc/server/ipc_server_mainloop_android.c
··· 139 } 140 141 int 142 - ipc_server_mainloop_init(struct ipc_server_mainloop *ml) 143 { 144 int ret = init_pipe(ml); 145 if (ret < 0) {
··· 139 } 140 141 int 142 + ipc_server_mainloop_init(struct ipc_server_mainloop *ml, bool no_stdin) 143 { 144 int ret = init_pipe(ml); 145 if (ret < 0) {
+5 -12
src/xrt/ipc/server/ipc_server_mainloop_linux.c
··· 1 // Copyright 2020-2021, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 46 #include <systemd/sd-daemon.h> 47 #endif 48 49 - /* 50 - * "XRT_NO_STDIN" option disables stdin and prevents monado-service from terminating. 51 - * This could be useful for situations where there is no proper or in a non-interactive shell. 52 - * Two example scenarios are: 53 - * * IDE terminals, 54 - * * Some scripting environments where monado-service is spawned in the background 55 - */ 56 - DEBUG_GET_ONCE_BOOL_OPTION(skip_stdin, "XRT_NO_STDIN", false) 57 58 /* 59 * ··· 175 } 176 177 static int 178 - init_epoll(struct ipc_server_mainloop *ml) 179 { 180 int ret = epoll_create1(EPOLL_CLOEXEC); 181 if (ret < 0) { ··· 186 187 struct epoll_event ev = {0}; 188 189 - if (!ml->launched_by_socket && !debug_get_bool_option_skip_stdin()) { 190 // Can't do this when launched by systemd socket activation by 191 // default. 192 // This polls stdin. ··· 265 } 266 267 int 268 - ipc_server_mainloop_init(struct ipc_server_mainloop *ml) 269 { 270 IPC_TRACE_MARKER(); 271 ··· 275 return ret; 276 } 277 278 - ret = init_epoll(ml); 279 if (ret < 0) { 280 ipc_server_mainloop_deinit(ml); 281 return ret;
··· 1 // Copyright 2020-2021, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 47 #include <systemd/sd-daemon.h> 48 #endif 49 50 51 /* 52 * ··· 168 } 169 170 static int 171 + init_epoll(struct ipc_server_mainloop *ml, bool no_stdin) 172 { 173 int ret = epoll_create1(EPOLL_CLOEXEC); 174 if (ret < 0) { ··· 179 180 struct epoll_event ev = {0}; 181 182 + if (!ml->launched_by_socket && !no_stdin) { 183 // Can't do this when launched by systemd socket activation by 184 // default. 185 // This polls stdin. ··· 258 } 259 260 int 261 + ipc_server_mainloop_init(struct ipc_server_mainloop *ml, bool no_stdin) 262 { 263 IPC_TRACE_MARKER(); 264 ··· 268 return ret; 269 } 270 271 + ret = init_epoll(ml, no_stdin); 272 if (ret < 0) { 273 ipc_server_mainloop_deinit(ml); 274 return ret;
+3 -2
src/xrt/ipc/server/ipc_server_mainloop_windows.cpp
··· 1 // Copyright 2022, Magic Leap, Inc. 2 // Copyright 2020-2022, Collabora, Ltd. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 218 { 219 IPC_TRACE_MARKER(); 220 221 - if (_kbhit()) { 222 U_LOG_E("console input! exiting..."); 223 ipc_server_handle_shutdown_signal(vs); 224 return; ··· 249 } 250 251 int 252 - ipc_server_mainloop_init(struct ipc_server_mainloop *ml) 253 { 254 IPC_TRACE_MARKER(); 255
··· 1 // Copyright 2022, Magic Leap, Inc. 2 // Copyright 2020-2022, Collabora, Ltd. 3 + // Copyright 2025, NVIDIA CORPORATION. 4 // SPDX-License-Identifier: BSL-1.0 5 /*! 6 * @file ··· 219 { 220 IPC_TRACE_MARKER(); 221 222 + if (!vs->no_stdin && _kbhit()) { 223 U_LOG_E("console input! exiting..."); 224 ipc_server_handle_shutdown_signal(vs); 225 return; ··· 250 } 251 252 int 253 + ipc_server_mainloop_init(struct ipc_server_mainloop *ml, bool no_stdin) 254 { 255 IPC_TRACE_MARKER(); 256
+29 -3
src/xrt/ipc/server/ipc_server_per_client_thread.c
··· 1 // Copyright 2020-2023, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 200 { 201 U_TRACE_SET_THREAD_NAME("IPC Client"); 202 203 - IPC_INFO(ics->server, "Client %u connected", ics->client_state.id); 204 205 // Claim the client fd. 206 int epoll_fd = setup_epoll(ics); ··· 231 232 // Detect clients disconnecting gracefully. 233 if (ret > 0 && (event.events & EPOLLHUP) != 0) { 234 - IPC_INFO(ics->server, "Client disconnected."); 235 break; 236 } 237 ··· 249 break; 250 } 251 252 // Read the whole command now that we know its size 253 uint8_t buf[IPC_BUF_SIZE] = {0}; 254 ··· 274 close(epoll_fd); 275 epoll_fd = -1; 276 277 // Following code is same for all platforms. 278 common_shutdown(ics); 279 } ··· 297 { 298 U_TRACE_SET_THREAD_NAME("IPC Client"); 299 300 - IPC_INFO(ics->server, "Client connected"); 301 302 while (ics->server->running) { 303 uint8_t buf[IPC_BUF_SIZE] = {0}; ··· 353 break; 354 } 355 } 356 357 // Following code is same for all platforms. 358 common_shutdown(ics);
··· 1 // Copyright 2020-2023, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 201 { 202 U_TRACE_SET_THREAD_NAME("IPC Client"); 203 204 + // Call the client connected callback. 205 + ics->server->callbacks->client_connected( // 206 + ics->server, // 207 + ics->client_state.id, // 208 + ics->server->callback_data); // 209 210 // Claim the client fd. 211 int epoll_fd = setup_epoll(ics); ··· 236 237 // Detect clients disconnecting gracefully. 238 if (ret > 0 && (event.events & EPOLLHUP) != 0) { 239 break; 240 } 241 ··· 253 break; 254 } 255 256 + // This needs to hold true. 257 + if (cmd_size > IPC_BUF_SIZE) { 258 + IPC_ERROR(ics->server, "Command too large! (%u > %u)", (uint32_t)cmd_size, IPC_BUF_SIZE); 259 + break; 260 + } 261 + 262 // Read the whole command now that we know its size 263 uint8_t buf[IPC_BUF_SIZE] = {0}; 264 ··· 284 close(epoll_fd); 285 epoll_fd = -1; 286 287 + // Call the client disconnected callback. 288 + ics->server->callbacks->client_disconnected( // 289 + ics->server, // 290 + ics->client_state.id, // 291 + ics->server->callback_data); // 292 + 293 // Following code is same for all platforms. 294 common_shutdown(ics); 295 } ··· 313 { 314 U_TRACE_SET_THREAD_NAME("IPC Client"); 315 316 + // Call the client connected callback. 317 + ics->server->callbacks->client_connected( // 318 + ics->server, // 319 + ics->client_state.id, // 320 + ics->server->callback_data); // 321 322 while (ics->server->running) { 323 uint8_t buf[IPC_BUF_SIZE] = {0}; ··· 373 break; 374 } 375 } 376 + 377 + // Call the client disconnected callback. 378 + ics->server->callbacks->client_disconnected( // 379 + ics->server, // 380 + ics->client_state.id, // 381 + ics->server->callback_data); // 382 383 // Following code is same for all platforms. 384 common_shutdown(ics);
+164 -48
src/xrt/ipc/server/ipc_server_process.c
··· 57 * 58 */ 59 60 - DEBUG_GET_ONCE_BOOL_OPTION(exit_on_disconnect, "IPC_EXIT_ON_DISCONNECT", false) 61 DEBUG_GET_ONCE_BOOL_OPTION(exit_when_idle, "IPC_EXIT_WHEN_IDLE", false) 62 DEBUG_GET_ONCE_NUM_OPTION(exit_when_idle_delay_ms, "IPC_EXIT_WHEN_IDLE_DELAY_MS", 5000) 63 DEBUG_GET_ONCE_LOG_OPTION(ipc_log, "IPC_LOG", U_LOGGING_INFO) 64 65 66 /* ··· 90 static void 91 init_idev(struct ipc_device *idev, struct xrt_device *xdev) 92 { 93 - if (xdev != NULL) { 94 - idev->io_active = true; 95 - idev->xdev = xdev; 96 - } else { 97 - idev->io_active = false; 98 - } 99 } 100 101 static void 102 teardown_idev(struct ipc_device *idev) 103 { 104 - idev->io_active = false; 105 } 106 107 static void ··· 280 } 281 282 XRT_CHECK_RESULT static xrt_result_t 283 - init_shm(struct ipc_server *s, volatile struct ipc_client_state *cs) 284 { 285 const size_t size = sizeof(struct ipc_shared_memory); 286 xrt_shmem_handle_t handle; 287 288 - xrt_result_t xret = ipc_shmem_create(size, &handle, (void **)&s->isms[cs->server_thread_index]); 289 IPC_CHK_AND_RET(s, xret, "ipc_shmem_create"); 290 291 // we have a filehandle, we will pass this to our client 292 - cs->ism_handle = handle; 293 294 295 /* 296 * 297 * Setup the shared memory state. ··· 300 301 uint32_t count = 0; 302 struct ipc_shared_memory *ism = s->isms[cs->server_thread_index]; 303 - 304 - ism->startup_timestamp = os_monotonic_get_ns(); 305 306 // Setup the tracking origins. 307 count = 0; ··· 402 403 // Setup the HMD 404 // set view count 405 - assert(s->xsysd->static_roles.head->hmd); 406 - ism->hmd.view_count = s->xsysd->static_roles.head->hmd->view_count; 407 - for (uint32_t view = 0; view < s->xsysd->static_roles.head->hmd->view_count; ++view) { 408 - ism->hmd.views[view].display.w_pixels = s->xsysd->static_roles.head->hmd->views[view].display.w_pixels; 409 - ism->hmd.views[view].display.h_pixels = s->xsysd->static_roles.head->hmd->views[view].display.h_pixels; 410 - } 411 412 - for (size_t i = 0; i < s->xsysd->static_roles.head->hmd->blend_mode_count; i++) { 413 - // Not super necessary, we also do this assert in oxr_system.c 414 - assert(u_verify_blend_mode_valid(s->xsysd->static_roles.head->hmd->blend_modes[i])); 415 - ism->hmd.blend_modes[i] = s->xsysd->static_roles.head->hmd->blend_modes[i]; 416 } 417 - ism->hmd.blend_mode_count = s->xsysd->static_roles.head->hmd->blend_mode_count; 418 419 // Finally tell the client how many devices we have. 420 ism->isdev_count = count; ··· 424 ism->roles.eyes = find_xdev_index(s, s->xsysd->static_roles.eyes); 425 ism->roles.face = find_xdev_index(s, s->xsysd->static_roles.face); 426 ism->roles.body = find_xdev_index(s, s->xsysd->static_roles.body); 427 #define SET_HT_ROLE(SRC) \ 428 ism->roles.hand_tracking.SRC.left = find_xdev_index(s, s->xsysd->static_roles.hand_tracking.SRC.left); \ 429 ism->roles.hand_tracking.SRC.right = find_xdev_index(s, s->xsysd->static_roles.hand_tracking.SRC.right); 430 SET_HT_ROLE(unobstructed) 431 SET_HT_ROLE(conforming) 432 #undef SET_HT_ROLE 433 - 434 - // Fill out git version info. 435 - snprintf(ism->u_git_tag, IPC_VERSION_NAME_LEN, "%s", u_git_tag); 436 - 437 - return XRT_SUCCESS; 438 } 439 440 static void ··· 455 } 456 457 static xrt_result_t 458 - init_all(struct ipc_server *s, enum u_logging_level log_level) 459 { 460 xrt_result_t xret = XRT_SUCCESS; 461 int ret; ··· 463 // First order of business set the log level. 464 s->log_level = log_level; 465 466 // This should never fail. 467 ret = os_mutex_init(&s->global_state.lock); 468 if (ret < 0) { ··· 480 481 // Yes we should be running. 482 s->running = true; 483 - s->exit_on_disconnect = debug_get_bool_option_exit_on_disconnect(); 484 s->exit_when_idle = debug_get_bool_option_exit_when_idle(); 485 s->last_client_disconnect_ns = 0; 486 uint64_t delay_ms = debug_get_num_option_exit_when_idle_delay_ms(); ··· 489 xret = xrt_instance_create(NULL, &s->xinst); 490 IPC_CHK_WITH_GOTO(s, xret, "xrt_instance_create", error); 491 492 - xret = xrt_instance_create_system(s->xinst, &s->xsys, &s->xsysd, &s->xso, &s->xsysc); 493 - IPC_CHK_WITH_GOTO(s, xret, "xrt_instance_create_system", error); 494 - 495 - // Always succeeds. 496 - init_idevs(s); 497 - init_tracking_origins(s); 498 - 499 - ret = ipc_server_mainloop_init(&s->ml); 500 if (ret < 0) { 501 xret = XRT_ERROR_IPC_MAINLOOP_FAILED_TO_INIT; 502 } ··· 599 ics->client_state.z_order = z_order; 600 601 if (ics->xc != NULL) { 602 - xrt_syscomp_set_state(ics->server->xsysc, ics->xc, visible, focused); 603 xrt_syscomp_set_z_order(ics->server->xsysc, ics->xc, z_order); 604 } 605 } ··· 771 return XRT_SUCCESS; 772 } 773 774 775 /* 776 * ··· 779 */ 780 781 xrt_result_t 782 ipc_server_get_client_app_state(struct ipc_server *s, uint32_t client_id, struct ipc_app_state *out_ias) 783 { 784 os_mutex_lock(&s->global_state.lock); ··· 937 it->state = IPC_THREAD_STARTING; 938 939 // Allocate a new ID, avoid zero. 940 - //! @todo validate ID. 941 - uint32_t id = ++vs->id_generator; 942 943 // Reset everything. 944 U_ZERO((struct ipc_client_state *)ics); 945 946 // Set state. 947 ics->client_state.id = id; 948 ics->imc.ipc_handle = ipc_handle; 949 ics->server = vs; ··· 955 ics->plane_detection_ids = NULL; 956 ics->plane_detection_xdev = NULL; 957 958 - xrt_result_t xret = init_shm(vs, ics); 959 if (xret != XRT_SUCCESS) { 960 961 // Unlock when we are done. ··· 995 // Allocate the server itself. 996 struct ipc_server *s = U_TYPED_CALLOC(struct ipc_server); 997 998 #ifdef XRT_OS_WINDOWS 999 timeBeginPeriod(1); 1000 #endif ··· 1006 */ 1007 u_debug_gui_create(&ismi->udgci, &s->debug_gui); 1008 1009 - xret = init_all(s, log_level); 1010 U_LOG_CHK_ONLY_PRINT(log_level, xret, "init_all"); 1011 if (xret != XRT_SUCCESS) { 1012 - // Propegate the failure. 1013 callbacks->init_failed(xret, data); 1014 u_debug_gui_stop(&s->debug_gui); 1015 free(s); 1016 return -1; 1017 } 1018 1019 // Start the debug UI now (if enabled). 1020 u_debug_gui_start(s->debug_gui, s->xinst, s->xsysd); 1021 - 1022 - // Tell the callbacks we are entering the main-loop. 1023 - callbacks->mainloop_entering(s, s->xinst, data); 1024 1025 // Main loop. 1026 ret = main_loop(s); ··· 1044 return ret; 1045 } 1046 1047 1048 #ifndef XRT_OS_ANDROID 1049 ··· 1071 // No-op 1072 } 1073 1074 int 1075 ipc_server_main(int argc, char **argv, const struct ipc_server_main_info *ismi) 1076 { ··· 1078 .init_failed = init_failed, 1079 .mainloop_entering = mainloop_entering, 1080 .mainloop_leaving = mainloop_leaving, 1081 }; 1082 1083 return ipc_server_main_common(ismi, &callbacks, NULL);
··· 57 * 58 */ 59 60 DEBUG_GET_ONCE_BOOL_OPTION(exit_when_idle, "IPC_EXIT_WHEN_IDLE", false) 61 DEBUG_GET_ONCE_NUM_OPTION(exit_when_idle_delay_ms, "IPC_EXIT_WHEN_IDLE_DELAY_MS", 5000) 62 DEBUG_GET_ONCE_LOG_OPTION(ipc_log, "IPC_LOG", U_LOGGING_INFO) 63 + 64 + /* 65 + * "XRT_NO_STDIN" option disables stdin and prevents monado-service from terminating. 66 + * This could be useful for situations where there is no proper or in a non-interactive shell. 67 + * Two example scenarios are: 68 + * * IDE terminals, 69 + * * Some scripting environments where monado-service is spawned in the background 70 + */ 71 + DEBUG_GET_ONCE_BOOL_OPTION(no_stdin, "XRT_NO_STDIN", false) 72 73 74 /* ··· 98 static void 99 init_idev(struct ipc_device *idev, struct xrt_device *xdev) 100 { 101 + idev->xdev = xdev; 102 } 103 104 static void 105 teardown_idev(struct ipc_device *idev) 106 { 107 + idev->xdev = NULL; 108 } 109 110 static void ··· 283 } 284 285 XRT_CHECK_RESULT static xrt_result_t 286 + init_shm_and_instance_state(struct ipc_server *s, volatile struct ipc_client_state *ics) 287 { 288 const size_t size = sizeof(struct ipc_shared_memory); 289 xrt_shmem_handle_t handle; 290 291 + xrt_result_t xret = ipc_shmem_create(size, &handle, (void **)&s->isms[ics->server_thread_index]); 292 IPC_CHK_AND_RET(s, xret, "ipc_shmem_create"); 293 294 // we have a filehandle, we will pass this to our client 295 + ics->ism_handle = handle; 296 + 297 + // Convenience 298 + struct ipc_shared_memory *ism = s->isms[ics->server_thread_index]; 299 300 + // Clients expect git version info and timestamp available upon connect. 301 + snprintf(ism->u_git_tag, IPC_VERSION_NAME_LEN, "%s", u_git_tag); 302 303 + // Used to synchronize all client's xrt_instance::startup_timestamp. 304 + ism->startup_timestamp = os_monotonic_get_ns(); 305 + 306 + return XRT_SUCCESS; 307 + } 308 + 309 + static void 310 + init_system_shm_state(struct ipc_server *s, volatile struct ipc_client_state *cs) 311 + { 312 /* 313 * 314 * Setup the shared memory state. ··· 317 318 uint32_t count = 0; 319 struct ipc_shared_memory *ism = s->isms[cs->server_thread_index]; 320 321 // Setup the tracking origins. 322 count = 0; ··· 417 418 // Setup the HMD 419 // set view count 420 + const struct xrt_device *xhead = s->xsysd->static_roles.head; 421 + const struct xrt_hmd_parts *xhmd = xhead != NULL ? xhead->hmd : NULL; 422 + U_ZERO(&ism->hmd); 423 + if (xhmd != NULL) { 424 + ism->hmd.view_count = xhmd->view_count; 425 + for (uint32_t view = 0; view < xhmd->view_count; ++view) { 426 + ism->hmd.views[view].display.w_pixels = xhmd->views[view].display.w_pixels; 427 + ism->hmd.views[view].display.h_pixels = xhmd->views[view].display.h_pixels; 428 + } 429 430 + for (uint32_t i = 0; i < xhmd->blend_mode_count; i++) { 431 + // Not super necessary, we also do this assert in oxr_system.c 432 + assert(u_verify_blend_mode_valid(xhmd->blend_modes[i])); 433 + ism->hmd.blend_modes[i] = xhmd->blend_modes[i]; 434 + } 435 + ism->hmd.blend_mode_count = xhmd->blend_mode_count; 436 } 437 438 // Finally tell the client how many devices we have. 439 ism->isdev_count = count; ··· 443 ism->roles.eyes = find_xdev_index(s, s->xsysd->static_roles.eyes); 444 ism->roles.face = find_xdev_index(s, s->xsysd->static_roles.face); 445 ism->roles.body = find_xdev_index(s, s->xsysd->static_roles.body); 446 + 447 #define SET_HT_ROLE(SRC) \ 448 ism->roles.hand_tracking.SRC.left = find_xdev_index(s, s->xsysd->static_roles.hand_tracking.SRC.left); \ 449 ism->roles.hand_tracking.SRC.right = find_xdev_index(s, s->xsysd->static_roles.hand_tracking.SRC.right); 450 SET_HT_ROLE(unobstructed) 451 SET_HT_ROLE(conforming) 452 #undef SET_HT_ROLE 453 } 454 455 static void ··· 470 } 471 472 static xrt_result_t 473 + init_all(struct ipc_server *s, 474 + enum u_logging_level log_level, 475 + const struct ipc_server_callbacks *callbacks, 476 + void *callback_data, 477 + bool exit_on_disconnect) 478 { 479 xrt_result_t xret = XRT_SUCCESS; 480 int ret; ··· 482 // First order of business set the log level. 483 s->log_level = log_level; 484 485 + // Store callbacks and data 486 + s->callbacks = callbacks; 487 + s->callback_data = callback_data; 488 + 489 // This should never fail. 490 ret = os_mutex_init(&s->global_state.lock); 491 if (ret < 0) { ··· 503 504 // Yes we should be running. 505 s->running = true; 506 + s->exit_on_disconnect = exit_on_disconnect; 507 s->exit_when_idle = debug_get_bool_option_exit_when_idle(); 508 s->last_client_disconnect_ns = 0; 509 uint64_t delay_ms = debug_get_num_option_exit_when_idle_delay_ms(); ··· 512 xret = xrt_instance_create(NULL, &s->xinst); 513 IPC_CHK_WITH_GOTO(s, xret, "xrt_instance_create", error); 514 515 + ret = ipc_server_mainloop_init(&s->ml, s->no_stdin); 516 if (ret < 0) { 517 xret = XRT_ERROR_IPC_MAINLOOP_FAILED_TO_INIT; 518 } ··· 615 ics->client_state.z_order = z_order; 616 617 if (ics->xc != NULL) { 618 + xrt_syscomp_set_state(ics->server->xsysc, ics->xc, visible, focused, os_monotonic_get_ns()); 619 xrt_syscomp_set_z_order(ics->server->xsysc, ics->xc, z_order); 620 } 621 } ··· 787 return XRT_SUCCESS; 788 } 789 790 + static uint32_t 791 + allocate_id_locked(struct ipc_server *s) 792 + { 793 + uint32_t id = 0; 794 + while (id == 0) { 795 + // Allocate a new one. 796 + id = ++s->id_generator; 797 + 798 + for (uint32_t i = 0; i < IPC_MAX_CLIENTS; i++) { 799 + volatile struct ipc_client_state *ics = &s->threads[i].ics; 800 + 801 + // If we find the ID, get a new one by setting to zero. 802 + if (ics->client_state.id == id) { 803 + id = 0; 804 + break; 805 + } 806 + } 807 + } 808 + 809 + // Paranoia. 810 + if (id == 0) { 811 + U_LOG_E("Got app(client) id 0, not allowed!"); 812 + assert(id > 0); 813 + } 814 + 815 + return id; 816 + } 817 + 818 819 /* 820 * ··· 823 */ 824 825 xrt_result_t 826 + ipc_server_init_system_if_available_locked(struct ipc_server *s, 827 + volatile struct ipc_client_state *ics, 828 + bool *out_available) 829 + { 830 + xrt_result_t xret = XRT_SUCCESS; 831 + 832 + bool available = false; 833 + 834 + if (s->xsys) { 835 + available = true; 836 + } else { 837 + xret = xrt_instance_is_system_available(s->xinst, &available); 838 + IPC_CHK_WITH_GOTO(s, xret, "xrt_instance_is_system_available", error); 839 + 840 + if (available) { 841 + xret = xrt_instance_create_system(s->xinst, &s->xsys, &s->xsysd, &s->xso, &s->xsysc); 842 + IPC_CHK_WITH_GOTO(s, xret, "xrt_instance_create_system", error); 843 + 844 + // Always succeeds. 845 + init_idevs(s); 846 + init_tracking_origins(s); 847 + } 848 + } 849 + 850 + if (available && ics != NULL && !ics->has_init_shm_system) { 851 + init_system_shm_state(s, ics); 852 + ics->has_init_shm_system = true; 853 + } 854 + 855 + if (out_available) { 856 + *out_available = available; 857 + } 858 + 859 + return XRT_SUCCESS; 860 + 861 + error: 862 + return xret; 863 + } 864 + 865 + xrt_result_t 866 ipc_server_get_client_app_state(struct ipc_server *s, uint32_t client_id, struct ipc_app_state *out_ias) 867 { 868 os_mutex_lock(&s->global_state.lock); ··· 1021 it->state = IPC_THREAD_STARTING; 1022 1023 // Allocate a new ID, avoid zero. 1024 + uint32_t id = allocate_id_locked(vs); 1025 1026 // Reset everything. 1027 U_ZERO((struct ipc_client_state *)ics); 1028 1029 // Set state. 1030 + ics->local_space_overseer_index = UINT32_MAX; 1031 ics->client_state.id = id; 1032 ics->imc.ipc_handle = ipc_handle; 1033 ics->server = vs; ··· 1039 ics->plane_detection_ids = NULL; 1040 ics->plane_detection_xdev = NULL; 1041 1042 + xrt_result_t xret = init_shm_and_instance_state(vs, ics); 1043 if (xret != XRT_SUCCESS) { 1044 1045 // Unlock when we are done. ··· 1079 // Allocate the server itself. 1080 struct ipc_server *s = U_TYPED_CALLOC(struct ipc_server); 1081 1082 + // Can be set by either. 1083 + s->no_stdin = ismi->no_stdin || debug_get_bool_option_no_stdin(); 1084 + 1085 #ifdef XRT_OS_WINDOWS 1086 timeBeginPeriod(1); 1087 #endif ··· 1093 */ 1094 u_debug_gui_create(&ismi->udgci, &s->debug_gui); 1095 1096 + xret = init_all(s, log_level, callbacks, data, ismi->exit_on_disconnect); 1097 U_LOG_CHK_ONLY_PRINT(log_level, xret, "init_all"); 1098 if (xret != XRT_SUCCESS) { 1099 + // Propagate the failure. 1100 callbacks->init_failed(xret, data); 1101 u_debug_gui_stop(&s->debug_gui); 1102 free(s); 1103 return -1; 1104 } 1105 1106 + // Tell the callbacks we are entering the main-loop. 1107 + callbacks->mainloop_entering(s, s->xinst, data); 1108 + 1109 + // Early init the system. If not available now, will try again per client request. 1110 + xret = ipc_server_init_system_if_available_locked( // 1111 + s, // 1112 + NULL, // optional - ics 1113 + NULL); // optional - out_available 1114 + if (xret != XRT_SUCCESS) { 1115 + U_LOG_CHK_ONLY_PRINT(log_level, xret, "ipc_server_init_system_if_available_locked"); 1116 + } 1117 + 1118 // Start the debug UI now (if enabled). 1119 u_debug_gui_start(s->debug_gui, s->xinst, s->xsysd); 1120 1121 // Main loop. 1122 ret = main_loop(s); ··· 1140 return ret; 1141 } 1142 1143 + int 1144 + ipc_server_stop(struct ipc_server *s) 1145 + { 1146 + s->running = false; 1147 + return 0; 1148 + } 1149 1150 #ifndef XRT_OS_ANDROID 1151 ··· 1173 // No-op 1174 } 1175 1176 + void 1177 + client_connected(struct ipc_server *s, uint32_t client_id, void *data) 1178 + { 1179 + IPC_INFO(s, "Client %u connected", client_id); 1180 + } 1181 + 1182 + void 1183 + client_disconnected(struct ipc_server *s, uint32_t client_id, void *data) 1184 + { 1185 + IPC_INFO(s, "Client %u disconnected", client_id); 1186 + } 1187 + 1188 int 1189 ipc_server_main(int argc, char **argv, const struct ipc_server_main_info *ismi) 1190 { ··· 1192 .init_failed = init_failed, 1193 .mainloop_entering = mainloop_entering, 1194 .mainloop_leaving = mainloop_leaving, 1195 + .client_connected = client_connected, 1196 + .client_disconnected = client_disconnected, 1197 }; 1198 1199 return ipc_server_main_common(ismi, &callbacks, NULL);
+7 -6
src/xrt/ipc/shared/ipc_protocol.h
··· 1 // Copyright 2020-2024 Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 31 32 33 #define IPC_CRED_SIZE 1 // auth not implemented 34 - #define IPC_BUF_SIZE 512 // must be >= largest message length in bytes 35 #define IPC_MAX_VIEWS 8 // max views we will return configs for 36 #define IPC_MAX_FORMATS 32 // max formats our server-side compositor supports 37 #define IPC_MAX_DEVICES 8 // max number of devices we will map using shared mem 38 #define IPC_MAX_LAYERS XRT_MAX_LAYERS 39 #define IPC_MAX_SLOTS 128 40 - #define IPC_MAX_CLIENTS 8 41 #define IPC_MAX_RAW_VIEWS 32 // Max views that we can get, artificial limit. 42 #define IPC_EVENT_QUEUE_SIZE 32 43 ··· 84 { 85 enum xrt_device_name name; 86 87 //! Number of inputs. 88 uint32_t input_count; 89 - //! Offset into the array of pairs where this input bindings starts. 90 - uint32_t first_input_index; 91 92 - //! Number of outputs. 93 - uint32_t output_count; 94 //! Offset into the array of pairs where this output bindings starts. 95 uint32_t first_output_index; 96 }; 97 98 /*!
··· 1 // Copyright 2020-2024 Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 32 33 34 #define IPC_CRED_SIZE 1 // auth not implemented 35 + #define IPC_BUF_SIZE 2048 // must be >= largest message length in bytes 36 #define IPC_MAX_VIEWS 8 // max views we will return configs for 37 #define IPC_MAX_FORMATS 32 // max formats our server-side compositor supports 38 #define IPC_MAX_DEVICES 8 // max number of devices we will map using shared mem 39 #define IPC_MAX_LAYERS XRT_MAX_LAYERS 40 #define IPC_MAX_SLOTS 128 41 + #define IPC_MAX_CLIENTS 32 42 #define IPC_MAX_RAW_VIEWS 32 // Max views that we can get, artificial limit. 43 #define IPC_EVENT_QUEUE_SIZE 32 44 ··· 85 { 86 enum xrt_device_name name; 87 88 + //! Offset into the array of pairs where this input bindings starts. 89 + uint32_t first_input_index; 90 //! Number of inputs. 91 uint32_t input_count; 92 93 //! Offset into the array of pairs where this output bindings starts. 94 uint32_t first_output_index; 95 + //! Number of outputs. 96 + uint32_t output_count; 97 }; 98 99 /*!
+56
src/xrt/ipc/shared/ipc_protocol_generated.h.template
···
··· 1 + // Copyright 2020-2025, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief Generated IPC protocol header. 6 + * @author Jakob Bornecrantz <jakob@collabora.com> 7 + * @ingroup ipc 8 + */ 9 + 10 + #pragma once 11 + 12 + #include "xrt/xrt_compiler.h" 13 + #include "xrt/xrt_defines.h" 14 + #include "xrt/xrt_device.h" 15 + 16 + 17 + #ifdef __cplusplus 18 + extern "C" { 19 + #endif 20 + 21 + 22 + struct ipc_connection; 23 + 24 + typedef enum ipc_command 25 + { 26 + IPC_ERR = 0, 27 + $ipc_commands 28 + } ipc_command_t; 29 + 30 + struct ipc_command_msg 31 + { 32 + enum ipc_command cmd; 33 + }; 34 + 35 + struct ipc_result_reply 36 + { 37 + xrt_result_t result; 38 + }; 39 + 40 + static inline const char * 41 + ipc_cmd_to_str(ipc_command_t id) 42 + { 43 + switch (id) { 44 + case IPC_ERR: return "IPC_ERR"; 45 + $ipc_cmd_cases 46 + default: return "IPC_UNKNOWN"; 47 + } 48 + } 49 + 50 + #pragma pack (push, 1) 51 + $ipc_msg_structs 52 + #pragma pack (pop) 53 + 54 + #ifdef __cplusplus 55 + } 56 + #endif
+19
src/xrt/ipc/shared/proto/10-instance.json
···
··· 1 + { 2 + "$schema": "../proto.schema.json", 3 + 4 + "instance_get_shm_fd": { 5 + "out_handles": {"type": "xrt_shmem_handle_t"} 6 + }, 7 + 8 + "instance_describe_client": { 9 + "in": [ 10 + {"name": "desc", "type": "struct ipc_client_description"} 11 + ] 12 + }, 13 + 14 + "instance_is_system_available": { 15 + "out": [ 16 + {"name": "available", "type": "bool"} 17 + ] 18 + } 19 + }
+3
src/xrt/ipc/shared/proto/10-instance.json.license
···
··· 1 + Copyright 2018-2025, Collabora, Ltd. 2 + 3 + SPDX-License-Identifier: BSL-1.0
+119
src/xrt/ipc/shared/proto/50-compositor.json
···
··· 1 + { 2 + "$schema": "../proto.schema.json", 3 + 4 + "compositor_get_info": { 5 + "out": [ 6 + {"name": "info", "type": "struct xrt_compositor_info"} 7 + ] 8 + }, 9 + 10 + "compositor_predict_frame": { 11 + "out": [ 12 + {"name": "frame_id", "type": "int64_t"}, 13 + {"name": "wake_up_time", "type": "int64_t"}, 14 + {"name": "predicted_display_time", "type": "int64_t"}, 15 + {"name": "predicted_display_period", "type": "int64_t"} 16 + ] 17 + }, 18 + 19 + "compositor_wait_woke": { 20 + "in": [ 21 + {"name": "frame_id", "type": "int64_t"} 22 + ] 23 + }, 24 + 25 + "compositor_begin_frame": { 26 + "in": [ 27 + {"name": "frame_id", "type": "int64_t"} 28 + ] 29 + }, 30 + 31 + "compositor_discard_frame": { 32 + "in": [ 33 + {"name": "frame_id", "type": "int64_t"} 34 + ] 35 + }, 36 + 37 + "compositor_layer_sync": { 38 + "in": [ 39 + {"name": "slot_id", "type": "uint32_t"} 40 + ], 41 + "in_handles": {"type": "xrt_graphics_sync_handle_t"}, 42 + "out": [ 43 + {"name": "free_slot_id", "type": "uint32_t"} 44 + ] 45 + }, 46 + 47 + "compositor_layer_sync_with_semaphore": { 48 + "in": [ 49 + {"name": "slot_id", "type": "uint32_t"}, 50 + {"name": "semaphore_id", "type": "uint32_t"}, 51 + {"name": "semaphore_value", "type": "uint64_t"} 52 + ], 53 + "out": [ 54 + {"name": "free_slot_id", "type": "uint32_t"} 55 + ] 56 + }, 57 + 58 + "compositor_set_performance_level": { 59 + "in": [ 60 + {"name": "domain", "type": "enum xrt_perf_domain"}, 61 + {"name": "level", "type": "enum xrt_perf_set_level"} 62 + ] 63 + }, 64 + 65 + "compositor_set_thread_hint": { 66 + "in": [ 67 + {"name": "hint", "type": "enum xrt_thread_hint"}, 68 + {"name": "thread_id", "type": "uint32_t"} 69 + ] 70 + }, 71 + 72 + "compositor_get_display_refresh_rate": { 73 + "out": [ 74 + {"name": "out_display_refresh_rate_hz", "type": "float"} 75 + ] 76 + }, 77 + 78 + "compositor_request_display_refresh_rate": { 79 + "in": [ 80 + {"name": "display_refresh_rate_hz", "type": "float"} 81 + ] 82 + }, 83 + 84 + "compositor_get_reference_bounds_rect": { 85 + "in": [ 86 + {"name": "reference_space_type", "type": "enum xrt_reference_space_type"} 87 + ], 88 + "out": [ 89 + {"name": "bounds", "type": "struct xrt_vec2"} 90 + ] 91 + }, 92 + 93 + "compositor_create_passthrough": { 94 + "in": [ 95 + {"name": "info", "type": "struct xrt_passthrough_create_info"} 96 + ] 97 + }, 98 + 99 + "compositor_create_passthrough_layer": { 100 + "in": [ 101 + {"name": "info", "type": "struct xrt_passthrough_layer_create_info"} 102 + ] 103 + }, 104 + 105 + "compositor_destroy_passthrough": {}, 106 + 107 + "compositor_semaphore_create": { 108 + "out": [ 109 + {"name": "id", "type": "uint32_t"} 110 + ], 111 + "out_handles": {"type": "xrt_graphics_sync_handle_t"} 112 + }, 113 + 114 + "compositor_semaphore_destroy": { 115 + "in": [ 116 + {"name": "id", "type": "uint32_t"} 117 + ] 118 + } 119 + }
+3
src/xrt/ipc/shared/proto/50-compositor.json.license
···
··· 1 + Copyright 2018-2025, Collabora, Ltd. 2 + 3 + SPDX-License-Identifier: BSL-1.0
+254
src/xrt/ipc/shared/proto/50-device.json
···
··· 1 + { 2 + "$schema": "../proto.schema.json", 3 + 4 + "device_update_input": { 5 + "in": [ 6 + {"name": "id", "type": "uint32_t"} 7 + ] 8 + }, 9 + 10 + "device_get_tracked_pose": { 11 + "in": [ 12 + {"name": "id", "type": "uint32_t"}, 13 + {"name": "name", "type": "enum xrt_input_name"}, 14 + {"name": "at_timestamp", "type": "int64_t"} 15 + ], 16 + "out": [ 17 + {"name": "relation", "type": "struct xrt_space_relation"} 18 + ] 19 + }, 20 + 21 + "device_get_hand_tracking": { 22 + "in": [ 23 + {"name": "id", "type": "uint32_t"}, 24 + {"name": "name", "type": "enum xrt_input_name"}, 25 + {"name": "at_timestamp", "type": "int64_t"} 26 + ], 27 + "out": [ 28 + {"name": "value", "type": "struct xrt_hand_joint_set"}, 29 + {"name": "timestamp", "type": "int64_t"} 30 + ] 31 + }, 32 + 33 + "device_get_view_poses": { 34 + "varlen": true, 35 + "in": [ 36 + {"name": "id", "type": "uint32_t"}, 37 + {"name": "fallback_eye_relation", "type": "struct xrt_vec3"}, 38 + {"name": "at_timestamp_ns", "type": "int64_t"}, 39 + {"name": "view_type", "type": "enum xrt_view_type"}, 40 + {"name": "view_count", "type": "uint32_t"} 41 + ], 42 + "out": [ 43 + {"name": "head_relation", "type": "struct xrt_space_relation"}, 44 + {"name": "view_count", "type": "uint32_t"} 45 + ] 46 + }, 47 + 48 + "device_get_view_poses_2": { 49 + "in": [ 50 + {"name": "id", "type": "uint32_t"}, 51 + {"name": "fallback_eye_relation", "type": "struct xrt_vec3"}, 52 + {"name": "at_timestamp_ns", "type": "int64_t"}, 53 + {"name": "view_type", "type": "enum xrt_view_type"}, 54 + {"name": "view_count", "type": "uint32_t"} 55 + ], 56 + "out": [ 57 + {"name": "info", "type": "struct ipc_info_get_view_poses_2"} 58 + ] 59 + }, 60 + 61 + "device_compute_distortion": { 62 + "in": [ 63 + {"name": "id", "type": "uint32_t"}, 64 + {"name": "view", "type": "uint32_t"}, 65 + {"name": "u", "type": "float"}, 66 + {"name": "v", "type": "float"} 67 + ], 68 + "out": [ 69 + {"name": "triplet", "type": "struct xrt_uv_triplet"} 70 + ] 71 + }, 72 + 73 + "device_begin_plane_detection_ext": { 74 + "in": [ 75 + {"name": "id", "type": "uint32_t"}, 76 + {"name": "plane_detection_id", "type": "uint64_t"} 77 + ], 78 + "out": [ 79 + {"name": "out_plane_detection_id", "type": "uint64_t"} 80 + ] 81 + }, 82 + 83 + "device_destroy_plane_detection_ext": { 84 + "in": [ 85 + {"name": "id", "type": "uint32_t"}, 86 + {"name": "plane_detection_id", "type": "uint64_t"} 87 + ] 88 + }, 89 + 90 + "device_get_plane_detection_state_ext": { 91 + "in": [ 92 + {"name": "id", "type": "uint32_t"}, 93 + {"name": "plane_detection_id", "type": "uint64_t"} 94 + ], 95 + "out": [ 96 + {"name": "state", "type": "enum xrt_plane_detector_state_ext"} 97 + ] 98 + }, 99 + 100 + "device_get_plane_detections_ext": { 101 + "varlen": true, 102 + "in": [ 103 + {"name": "id", "type": "uint32_t"}, 104 + {"name": "plane_detection_id", "type": "uint64_t"} 105 + ], 106 + "out": [ 107 + {"name": "location_size", "type": "uint32_t"}, 108 + {"name": "polygon_size", "type": "uint32_t"}, 109 + {"name": "vertex_size", "type": "uint32_t"} 110 + ] 111 + }, 112 + 113 + "device_get_presence": { 114 + "in": [ 115 + {"name": "id", "type": "uint32_t"} 116 + ], 117 + "out": [ 118 + {"name": "presence", "type": "bool"} 119 + ] 120 + }, 121 + 122 + "device_set_output": { 123 + "in": [ 124 + {"name": "id", "type": "uint32_t"}, 125 + {"name": "name", "type": "enum xrt_output_name"}, 126 + {"name": "value", "type": "struct xrt_output_value"} 127 + ] 128 + }, 129 + 130 + "device_set_haptic_output": { 131 + "varlen": true, 132 + "in": [ 133 + {"name": "id", "type": "uint32_t"}, 134 + {"name": "name", "type": "enum xrt_output_name"}, 135 + {"name": "samples", "type": "struct ipc_pcm_haptic_buffer"} 136 + ], 137 + "out":[ 138 + {"name": "samples_consumed", "type": "uint32_t"} 139 + ] 140 + }, 141 + 142 + "device_get_output_limits": { 143 + "in": [ 144 + {"name": "id", "type": "uint32_t"} 145 + ], 146 + "out":[ 147 + {"name": "limits", "type": "struct xrt_output_limits"} 148 + ] 149 + }, 150 + 151 + "device_get_visibility_mask": { 152 + "varlen": true, 153 + "in": [ 154 + {"name": "id", "type": "uint32_t"}, 155 + {"name": "type", "type": "enum xrt_visibility_mask_type"}, 156 + {"name": "view_index", "type": "uint32_t"} 157 + ], 158 + "out": [ 159 + {"name": "mask_size", "type": "uint32_t"} 160 + ] 161 + }, 162 + 163 + "device_is_form_factor_available": { 164 + "in": [ 165 + {"name": "id", "type": "uint32_t"}, 166 + {"name": "form_factor", "type": "enum xrt_form_factor"} 167 + ], 168 + "out": [ 169 + {"name": "available", "type": "bool"} 170 + ] 171 + }, 172 + 173 + "device_get_face_tracking": { 174 + "in": [ 175 + {"name": "id", "type": "uint32_t"}, 176 + {"name": "facial_expression_type", "type": "enum xrt_input_name"}, 177 + {"name": "at_timestamp_ns", "type": "int64_t"} 178 + ], 179 + "out": [ 180 + {"name": "value", "type": "struct xrt_facial_expression_set"} 181 + ] 182 + }, 183 + 184 + "device_device_get_face_calibration_state_android": { 185 + "in": [ 186 + {"name": "id", "type": "uint32_t"} 187 + ], 188 + "out": [ 189 + {"name": "face_is_calibrated", "type": "bool"} 190 + ] 191 + }, 192 + 193 + "device_get_body_skeleton": { 194 + "in": [ 195 + {"name": "id", "type": "uint32_t"}, 196 + {"name": "body_tracking_type", "type": "enum xrt_input_name"} 197 + ], 198 + "out": [ 199 + {"name": "value", "type": "struct xrt_body_skeleton"} 200 + ] 201 + }, 202 + 203 + "device_get_body_joints": { 204 + "in": [ 205 + {"name": "id", "type": "uint32_t"}, 206 + {"name": "body_tracking_type", "type": "enum xrt_input_name"}, 207 + {"name": "desired_timestamp_ns", "type": "int64_t"} 208 + ], 209 + "out": [ 210 + {"name": "value", "type": "struct xrt_body_joint_set"} 211 + ] 212 + }, 213 + 214 + "device_reset_body_tracking_calibration_meta": { 215 + "in": [ 216 + {"name": "id", "type": "uint32_t"} 217 + ] 218 + }, 219 + 220 + "device_set_body_tracking_calibration_override_meta": { 221 + "in": [ 222 + {"name": "id", "type": "uint32_t"}, 223 + {"name": "new_body_height", "type": "float"} 224 + ] 225 + }, 226 + 227 + "device_get_battery_status": { 228 + "in": [ 229 + {"name": "id", "type": "uint32_t"} 230 + ], 231 + "out": [ 232 + {"name": "present", "type": "bool"}, 233 + {"name": "charging", "type": "bool"}, 234 + {"name": "charge", "type": "float"} 235 + ] 236 + }, 237 + 238 + "device_get_brightness": { 239 + "in": [ 240 + {"name": "id", "type": "uint32_t"} 241 + ], 242 + "out": [ 243 + {"name": "brightness", "type": "float"} 244 + ] 245 + }, 246 + 247 + "device_set_brightness": { 248 + "in": [ 249 + {"name": "id", "type": "uint32_t"}, 250 + {"name": "brightness", "type": "float"}, 251 + {"name": "relative", "type": "bool"} 252 + ] 253 + } 254 + }
+3
src/xrt/ipc/shared/proto/50-device.json.license
···
··· 1 + Copyright 2018-2025, Collabora, Ltd. 2 + 3 + SPDX-License-Identifier: BSL-1.0
+33
src/xrt/ipc/shared/proto/50-future.json
···
··· 1 + { 2 + "$schema": "../proto.schema.json", 3 + 4 + "future_get_state": { 5 + "in": [ 6 + {"name": "future_id", "type": "uint32_t"} 7 + ], 8 + "out": [ 9 + {"name": "out_state", "type": "enum xrt_future_state"} 10 + ] 11 + }, 12 + 13 + "future_cancel": { 14 + "in": [ 15 + {"name": "future_id", "type": "uint32_t"} 16 + ] 17 + }, 18 + 19 + "future_destroy": { 20 + "in": [ 21 + {"name": "future_id", "type": "uint32_t"} 22 + ] 23 + }, 24 + 25 + "future_get_result": { 26 + "in": [ 27 + {"name": "future_id", "type": "uint32_t"} 28 + ], 29 + "out": [ 30 + {"name": "out_ft_result", "type": "struct xrt_future_result"} 31 + ] 32 + } 33 + }
+3
src/xrt/ipc/shared/proto/50-future.json.license
···
··· 1 + Copyright 2018-2025, Collabora, Ltd. 2 + 3 + SPDX-License-Identifier: BSL-1.0
+22
src/xrt/ipc/shared/proto/50-session.json
···
··· 1 + { 2 + "$schema": "../proto.schema.json", 3 + 4 + "session_create": { 5 + "in": [ 6 + {"name": "xsi", "type": "struct xrt_session_info"}, 7 + {"name": "create_native_compositor", "type": "bool"} 8 + ] 9 + }, 10 + 11 + "session_poll_events": { 12 + "out": [ 13 + {"name": "event", "type": "union xrt_session_event"} 14 + ] 15 + }, 16 + 17 + "session_begin": {}, 18 + 19 + "session_end": {}, 20 + 21 + "session_destroy": {} 22 + }
+3
src/xrt/ipc/shared/proto/50-session.json.license
···
··· 1 + Copyright 2018-2025, Collabora, Ltd. 2 + 3 + SPDX-License-Identifier: BSL-1.0
+122
src/xrt/ipc/shared/proto/50-space.json
···
··· 1 + { 2 + "$schema": "../proto.schema.json", 3 + 4 + "space_create_semantic_ids": { 5 + "out": [ 6 + {"name": "root_id", "type": "uint32_t"}, 7 + {"name": "view_id", "type": "uint32_t"}, 8 + {"name": "local_id", "type": "uint32_t"}, 9 + {"name": "local_floor_id", "type": "uint32_t"}, 10 + {"name": "stage_id", "type": "uint32_t"}, 11 + {"name": "unbounded_id", "type": "uint32_t"} 12 + ] 13 + }, 14 + 15 + "space_create_offset": { 16 + "in": [ 17 + {"name": "parent_id", "type": "uint32_t"}, 18 + {"name": "offset", "type": "struct xrt_pose"} 19 + ], 20 + "out": [ 21 + {"name": "space_id", "type": "uint32_t"} 22 + ] 23 + }, 24 + 25 + "space_create_pose": { 26 + "in": [ 27 + {"name": "xdev_id", "type": "uint32_t"}, 28 + {"name": "name", "type": "enum xrt_input_name"} 29 + ], 30 + "out": [ 31 + {"name": "space_id", "type": "uint32_t"} 32 + ] 33 + }, 34 + 35 + "space_locate_space": { 36 + "in": [ 37 + {"name": "base_space_id", "type": "uint32_t"}, 38 + {"name": "base_offset", "type": "struct xrt_pose"}, 39 + {"name": "at_timestamp", "type": "int64_t"}, 40 + {"name": "space_id", "type": "uint32_t"}, 41 + {"name": "offset", "type": "struct xrt_pose"} 42 + ], 43 + "out": [ 44 + {"name": "relation", "type": "struct xrt_space_relation"} 45 + ] 46 + }, 47 + 48 + "space_locate_spaces": { 49 + "varlen": true, 50 + "in": [ 51 + {"name": "base_space_id", "type": "uint32_t"}, 52 + {"name": "base_offset", "type": "struct xrt_pose"}, 53 + {"name": "space_count", "type": "uint32_t"}, 54 + {"name": "at_timestamp", "type": "int64_t"} 55 + ] 56 + }, 57 + 58 + "space_locate_device": { 59 + "in": [ 60 + {"name": "base_space_id", "type": "uint32_t"}, 61 + {"name": "base_offset", "type": "struct xrt_pose"}, 62 + {"name": "at_timestamp", "type": "int64_t"}, 63 + {"name": "xdev_id", "type": "uint32_t"} 64 + ], 65 + "out": [ 66 + {"name": "relation", "type": "struct xrt_space_relation"} 67 + ] 68 + }, 69 + 70 + "space_destroy": { 71 + "in": [ 72 + {"name": "space_id", "type": "uint32_t"} 73 + ] 74 + }, 75 + 76 + "space_mark_ref_space_in_use": { 77 + "in": [ 78 + {"name": "type", "type": "enum xrt_reference_space_type"} 79 + ] 80 + }, 81 + 82 + "space_unmark_ref_space_in_use": { 83 + "in": [ 84 + {"name": "type", "type": "enum xrt_reference_space_type"} 85 + ] 86 + }, 87 + 88 + "space_recenter_local_spaces": { 89 + }, 90 + 91 + "space_get_tracking_origin_offset": { 92 + "in": [ 93 + {"name": "origin_id", "type": "uint32_t"} 94 + ], 95 + "out": [ 96 + {"name": "offset", "type": "struct xrt_pose"} 97 + ] 98 + }, 99 + 100 + "space_set_tracking_origin_offset": { 101 + "in": [ 102 + {"name": "origin_id", "type": "uint32_t"}, 103 + {"name": "offset", "type": "struct xrt_pose"} 104 + ] 105 + }, 106 + 107 + "space_get_reference_space_offset": { 108 + "in": [ 109 + {"name": "type", "type": "enum xrt_reference_space_type"} 110 + ], 111 + "out": [ 112 + {"name": "offset", "type": "struct xrt_pose"} 113 + ] 114 + }, 115 + 116 + "space_set_reference_space_offset": { 117 + "in": [ 118 + {"name": "type", "type": "enum xrt_reference_space_type"}, 119 + {"name": "offset", "type": "struct xrt_pose"} 120 + ] 121 + } 122 + }
+3
src/xrt/ipc/shared/proto/50-space.json.license
···
··· 1 + Copyright 2018-2025, Collabora, Ltd. 2 + 3 + SPDX-License-Identifier: BSL-1.0
+66
src/xrt/ipc/shared/proto/50-swapchain.json
···
··· 1 + { 2 + "$schema": "../proto.schema.json", 3 + 4 + "swapchain_get_properties": { 5 + "in": [ 6 + {"name": "info", "type": "struct xrt_swapchain_create_info"} 7 + ], 8 + "out": [ 9 + {"name": "xsccp", "type": "struct xrt_swapchain_create_properties"} 10 + ] 11 + }, 12 + 13 + "swapchain_create": { 14 + "in": [ 15 + {"name": "info", "type": "struct xrt_swapchain_create_info"} 16 + ], 17 + "out": [ 18 + {"name": "id", "type": "uint32_t"}, 19 + {"name": "image_count", "type": "uint32_t"}, 20 + {"name": "size", "type": "uint64_t"}, 21 + {"name": "use_dedicated_allocation", "type": "bool"} 22 + ], 23 + "out_handles": {"type": "xrt_graphics_buffer_handle_t"} 24 + }, 25 + 26 + "swapchain_import": { 27 + "in": [ 28 + {"name": "info", "type": "struct xrt_swapchain_create_info"}, 29 + {"name": "args", "type": "struct ipc_arg_swapchain_from_native"} 30 + ], 31 + "out": [ 32 + {"name": "id", "type": "uint32_t"} 33 + ], 34 + "in_handles": {"type": "xrt_graphics_buffer_handle_t"} 35 + }, 36 + 37 + "swapchain_wait_image": { 38 + "in": [ 39 + {"name": "id", "type": "uint32_t"}, 40 + {"name": "timeout_ns", "type": "int64_t"}, 41 + {"name": "index", "type": "uint32_t"} 42 + ] 43 + }, 44 + 45 + "swapchain_acquire_image": { 46 + "in": [ 47 + {"name": "id", "type": "uint32_t"} 48 + ], 49 + "out": [ 50 + {"name": "index", "type": "uint32_t"} 51 + ] 52 + }, 53 + 54 + "swapchain_release_image": { 55 + "in": [ 56 + {"name": "id", "type": "uint32_t"}, 57 + {"name": "index", "type": "uint32_t"} 58 + ] 59 + }, 60 + 61 + "swapchain_destroy": { 62 + "in": [ 63 + {"name": "id", "type": "uint32_t"} 64 + ] 65 + } 66 + }
+3
src/xrt/ipc/shared/proto/50-swapchain.json.license
···
··· 1 + Copyright 2018-2025, Collabora, Ltd. 2 + 3 + SPDX-License-Identifier: BSL-1.0
+66
src/xrt/ipc/shared/proto/50-system.json
···
··· 1 + { 2 + "$schema": "../proto.schema.json", 3 + 4 + "system_get_properties": { 5 + "out": [ 6 + {"name": "properties", "type": "struct xrt_system_properties"} 7 + ] 8 + }, 9 + 10 + "system_get_client_info": { 11 + "in": [ 12 + {"name": "id", "type": "uint32_t"} 13 + ], 14 + "out": [ 15 + {"name": "ias", "type": "struct ipc_app_state"} 16 + ] 17 + }, 18 + 19 + "system_get_clients": { 20 + "out": [ 21 + {"name": "clients", "type": "struct ipc_client_list"} 22 + ] 23 + }, 24 + 25 + "system_set_primary_client": { 26 + "in": [ 27 + {"name": "id", "type": "uint32_t"} 28 + ] 29 + }, 30 + 31 + "system_set_focused_client": { 32 + "in": [ 33 + {"name": "id", "type": "uint32_t"} 34 + ] 35 + }, 36 + 37 + "system_toggle_io_client": { 38 + "in": [ 39 + {"name": "id", "type": "uint32_t"} 40 + ] 41 + }, 42 + 43 + "system_devices_get_roles": { 44 + "out": [ 45 + {"name": "system_roles", "type": "struct xrt_system_roles"} 46 + ] 47 + }, 48 + 49 + "system_devices_begin_feature": { 50 + "in": [ 51 + {"name": "type", "type": "enum xrt_device_feature_type"} 52 + ] 53 + }, 54 + 55 + "system_devices_end_feature": { 56 + "in": [ 57 + {"name": "type", "type": "enum xrt_device_feature_type"} 58 + ] 59 + }, 60 + 61 + "system_compositor_get_info": { 62 + "out": [ 63 + {"name": "info", "type": "struct xrt_system_compositor_info"} 64 + ] 65 + } 66 + }
+3
src/xrt/ipc/shared/proto/50-system.json.license
···
··· 1 + Copyright 2018-2025, Collabora, Ltd. 2 + 3 + SPDX-License-Identifier: BSL-1.0
-669
src/xrt/ipc/shared/proto.json
··· 1 - { 2 - "$schema": "./proto.schema.json", 3 - 4 - "instance_get_shm_fd": { 5 - "out_handles": {"type": "xrt_shmem_handle_t"} 6 - }, 7 - 8 - "instance_describe_client": { 9 - "in": [ 10 - {"name": "desc", "type": "struct ipc_client_description"} 11 - ] 12 - }, 13 - 14 - "system_get_properties": { 15 - "out": [ 16 - {"name": "properties", "type": "struct xrt_system_properties"} 17 - ] 18 - }, 19 - 20 - "system_get_client_info": { 21 - "in": [ 22 - {"name": "id", "type": "uint32_t"} 23 - ], 24 - "out": [ 25 - {"name": "ias", "type": "struct ipc_app_state"} 26 - ] 27 - }, 28 - 29 - "system_get_clients": { 30 - "out": [ 31 - {"name": "clients", "type": "struct ipc_client_list"} 32 - ] 33 - }, 34 - 35 - "system_set_primary_client": { 36 - "in": [ 37 - {"name": "id", "type": "uint32_t"} 38 - ] 39 - }, 40 - 41 - "system_set_focused_client": { 42 - "in": [ 43 - {"name": "id", "type": "uint32_t"} 44 - ] 45 - }, 46 - 47 - "system_toggle_io_client": { 48 - "in": [ 49 - {"name": "id", "type": "uint32_t"} 50 - ] 51 - }, 52 - 53 - "system_toggle_io_device": { 54 - "in": [ 55 - {"name": "id", "type": "uint32_t"} 56 - ] 57 - }, 58 - 59 - "system_devices_get_roles": { 60 - "out": [ 61 - {"name": "system_roles", "type": "struct xrt_system_roles"} 62 - ] 63 - }, 64 - 65 - "system_devices_begin_feature": { 66 - "in": [ 67 - {"name": "type", "type": "enum xrt_device_feature_type"} 68 - ] 69 - }, 70 - 71 - "system_devices_end_feature": { 72 - "in": [ 73 - {"name": "type", "type": "enum xrt_device_feature_type"} 74 - ] 75 - }, 76 - 77 - "system_compositor_get_info": { 78 - "out": [ 79 - {"name": "info", "type": "struct xrt_system_compositor_info"} 80 - ] 81 - }, 82 - 83 - "session_create": { 84 - "in": [ 85 - {"name": "xsi", "type": "struct xrt_session_info"}, 86 - {"name": "create_native_compositor", "type": "bool"} 87 - ] 88 - }, 89 - 90 - "session_poll_events": { 91 - "out": [ 92 - {"name": "event", "type": "union xrt_session_event"} 93 - ] 94 - }, 95 - 96 - "session_begin": {}, 97 - 98 - "session_end": {}, 99 - 100 - "session_destroy": {}, 101 - 102 - "space_create_semantic_ids": { 103 - "out": [ 104 - {"name": "root_id", "type": "uint32_t"}, 105 - {"name": "view_id", "type": "uint32_t"}, 106 - {"name": "local_id", "type": "uint32_t"}, 107 - {"name": "local_floor_id", "type": "uint32_t"}, 108 - {"name": "stage_id", "type": "uint32_t"}, 109 - {"name": "unbounded_id", "type": "uint32_t"} 110 - ] 111 - }, 112 - 113 - "space_create_offset": { 114 - "in": [ 115 - {"name": "parent_id", "type": "uint32_t"}, 116 - {"name": "offset", "type": "struct xrt_pose"} 117 - ], 118 - "out": [ 119 - {"name": "space_id", "type": "uint32_t"} 120 - ] 121 - }, 122 - 123 - "space_create_pose": { 124 - "in": [ 125 - {"name": "xdev_id", "type": "uint32_t"}, 126 - {"name": "name", "type": "enum xrt_input_name"} 127 - ], 128 - "out": [ 129 - {"name": "space_id", "type": "uint32_t"} 130 - ] 131 - }, 132 - 133 - "space_locate_space": { 134 - "in": [ 135 - {"name": "base_space_id", "type": "uint32_t"}, 136 - {"name": "base_offset", "type": "struct xrt_pose"}, 137 - {"name": "at_timestamp", "type": "int64_t"}, 138 - {"name": "space_id", "type": "uint32_t"}, 139 - {"name": "offset", "type": "struct xrt_pose"} 140 - ], 141 - "out": [ 142 - {"name": "relation", "type": "struct xrt_space_relation"} 143 - ] 144 - }, 145 - 146 - "space_locate_spaces": { 147 - "varlen": true, 148 - "in": [ 149 - {"name": "base_space_id", "type": "uint32_t"}, 150 - {"name": "base_offset", "type": "struct xrt_pose"}, 151 - {"name": "space_count", "type": "uint32_t"}, 152 - {"name": "at_timestamp", "type": "int64_t"} 153 - ] 154 - }, 155 - 156 - "space_locate_device": { 157 - "in": [ 158 - {"name": "base_space_id", "type": "uint32_t"}, 159 - {"name": "base_offset", "type": "struct xrt_pose"}, 160 - {"name": "at_timestamp", "type": "int64_t"}, 161 - {"name": "xdev_id", "type": "uint32_t"} 162 - ], 163 - "out": [ 164 - {"name": "relation", "type": "struct xrt_space_relation"} 165 - ] 166 - }, 167 - 168 - "space_destroy": { 169 - "in": [ 170 - {"name": "space_id", "type": "uint32_t"} 171 - ] 172 - }, 173 - 174 - "space_mark_ref_space_in_use": { 175 - "in": [ 176 - {"name": "type", "type": "enum xrt_reference_space_type"} 177 - ] 178 - }, 179 - 180 - "space_unmark_ref_space_in_use": { 181 - "in": [ 182 - {"name": "type", "type": "enum xrt_reference_space_type"} 183 - ] 184 - }, 185 - 186 - "space_recenter_local_spaces": { 187 - }, 188 - 189 - "space_get_tracking_origin_offset": { 190 - "in": [ 191 - {"name": "origin_id", "type": "uint32_t"} 192 - ], 193 - "out": [ 194 - {"name": "offset", "type": "struct xrt_pose"} 195 - ] 196 - }, 197 - 198 - "space_set_tracking_origin_offset": { 199 - "in": [ 200 - {"name": "origin_id", "type": "uint32_t"}, 201 - {"name": "offset", "type": "struct xrt_pose"} 202 - ] 203 - }, 204 - 205 - "space_get_reference_space_offset": { 206 - "in": [ 207 - {"name": "type", "type": "enum xrt_reference_space_type"} 208 - ], 209 - "out": [ 210 - {"name": "offset", "type": "struct xrt_pose"} 211 - ] 212 - }, 213 - 214 - "space_set_reference_space_offset": { 215 - "in": [ 216 - {"name": "type", "type": "enum xrt_reference_space_type"}, 217 - {"name": "offset", "type": "struct xrt_pose"} 218 - ] 219 - }, 220 - 221 - "compositor_get_info": { 222 - "out": [ 223 - {"name": "info", "type": "struct xrt_compositor_info"} 224 - ] 225 - }, 226 - 227 - "compositor_predict_frame": { 228 - "out": [ 229 - {"name": "frame_id", "type": "int64_t"}, 230 - {"name": "wake_up_time", "type": "int64_t"}, 231 - {"name": "predicted_display_time", "type": "int64_t"}, 232 - {"name": "predicted_display_period", "type": "int64_t"} 233 - ] 234 - }, 235 - 236 - "compositor_wait_woke": { 237 - "in": [ 238 - {"name": "frame_id", "type": "int64_t"} 239 - ] 240 - }, 241 - 242 - "compositor_begin_frame": { 243 - "in": [ 244 - {"name": "frame_id", "type": "int64_t"} 245 - ] 246 - }, 247 - 248 - "compositor_discard_frame": { 249 - "in": [ 250 - {"name": "frame_id", "type": "int64_t"} 251 - ] 252 - }, 253 - 254 - "compositor_layer_sync": { 255 - "in": [ 256 - {"name": "slot_id", "type": "uint32_t"} 257 - ], 258 - "in_handles": {"type": "xrt_graphics_sync_handle_t"}, 259 - "out": [ 260 - {"name": "free_slot_id", "type": "uint32_t"} 261 - ] 262 - }, 263 - 264 - "compositor_layer_sync_with_semaphore": { 265 - "in": [ 266 - {"name": "slot_id", "type": "uint32_t"}, 267 - {"name": "semaphore_id", "type": "uint32_t"}, 268 - {"name": "semaphore_value", "type": "uint64_t"} 269 - ], 270 - "out": [ 271 - {"name": "free_slot_id", "type": "uint32_t"} 272 - ] 273 - }, 274 - 275 - "compositor_set_performance_level": { 276 - "in": [ 277 - {"name": "domain", "type": "enum xrt_perf_domain"}, 278 - {"name": "level", "type": "enum xrt_perf_set_level"} 279 - ] 280 - }, 281 - 282 - "compositor_set_thread_hint": { 283 - "in": [ 284 - {"name": "hint", "type": "enum xrt_thread_hint"}, 285 - {"name": "thread_id", "type": "uint32_t"} 286 - ] 287 - }, 288 - 289 - "compositor_get_display_refresh_rate": { 290 - "out": [ 291 - {"name": "out_display_refresh_rate_hz", "type": "float"} 292 - ] 293 - }, 294 - 295 - "compositor_request_display_refresh_rate": { 296 - "in": [ 297 - {"name": "display_refresh_rate_hz", "type": "float"} 298 - ] 299 - }, 300 - 301 - "compositor_get_reference_bounds_rect": { 302 - "in": [ 303 - {"name": "reference_space_type", "type": "enum xrt_reference_space_type"} 304 - ], 305 - "out": [ 306 - {"name": "bounds", "type": "struct xrt_vec2"} 307 - ] 308 - }, 309 - 310 - "swapchain_get_properties": { 311 - "in": [ 312 - {"name": "info", "type": "struct xrt_swapchain_create_info"} 313 - ], 314 - "out": [ 315 - {"name": "xsccp", "type": "struct xrt_swapchain_create_properties"} 316 - ] 317 - }, 318 - 319 - "swapchain_create": { 320 - "in": [ 321 - {"name": "info", "type": "struct xrt_swapchain_create_info"} 322 - ], 323 - "out": [ 324 - {"name": "id", "type": "uint32_t"}, 325 - {"name": "image_count", "type": "uint32_t"}, 326 - {"name": "size", "type": "uint64_t"}, 327 - {"name": "use_dedicated_allocation", "type": "bool"} 328 - ], 329 - "out_handles": {"type": "xrt_graphics_buffer_handle_t"} 330 - }, 331 - 332 - "compositor_create_passthrough": { 333 - "in": [ 334 - {"name": "info", "type": "struct xrt_passthrough_create_info"} 335 - ] 336 - }, 337 - 338 - "compositor_create_passthrough_layer": { 339 - "in": [ 340 - {"name": "info", "type": "struct xrt_passthrough_layer_create_info"} 341 - ] 342 - }, 343 - 344 - "compositor_destroy_passthrough": {}, 345 - 346 - "swapchain_import": { 347 - "in": [ 348 - {"name": "info", "type": "struct xrt_swapchain_create_info"}, 349 - {"name": "args", "type": "struct ipc_arg_swapchain_from_native"} 350 - ], 351 - "out": [ 352 - {"name": "id", "type": "uint32_t"} 353 - ], 354 - "in_handles": {"type": "xrt_graphics_buffer_handle_t"} 355 - }, 356 - 357 - "swapchain_wait_image": { 358 - "in": [ 359 - {"name": "id", "type": "uint32_t"}, 360 - {"name": "timeout_ns", "type": "int64_t"}, 361 - {"name": "index", "type": "uint32_t"} 362 - ] 363 - }, 364 - 365 - "swapchain_acquire_image": { 366 - "in": [ 367 - {"name": "id", "type": "uint32_t"} 368 - ], 369 - "out": [ 370 - {"name": "index", "type": "uint32_t"} 371 - ] 372 - }, 373 - 374 - "swapchain_release_image": { 375 - "in": [ 376 - {"name": "id", "type": "uint32_t"}, 377 - {"name": "index", "type": "uint32_t"} 378 - ] 379 - }, 380 - 381 - "swapchain_destroy": { 382 - "in": [ 383 - {"name": "id", "type": "uint32_t"} 384 - ] 385 - }, 386 - 387 - "compositor_semaphore_create": { 388 - "out": [ 389 - {"name": "id", "type": "uint32_t"} 390 - ], 391 - "out_handles": {"type": "xrt_graphics_sync_handle_t"} 392 - }, 393 - 394 - "compositor_semaphore_destroy": { 395 - "in": [ 396 - {"name": "id", "type": "uint32_t"} 397 - ] 398 - }, 399 - 400 - "device_update_input": { 401 - "in": [ 402 - {"name": "id", "type": "uint32_t"} 403 - ] 404 - }, 405 - 406 - "device_get_tracked_pose": { 407 - "in": [ 408 - {"name": "id", "type": "uint32_t"}, 409 - {"name": "name", "type": "enum xrt_input_name"}, 410 - {"name": "at_timestamp", "type": "int64_t"} 411 - ], 412 - "out": [ 413 - {"name": "relation", "type": "struct xrt_space_relation"} 414 - ] 415 - }, 416 - 417 - "device_get_hand_tracking": { 418 - "in": [ 419 - {"name": "id", "type": "uint32_t"}, 420 - {"name": "name", "type": "enum xrt_input_name"}, 421 - {"name": "at_timestamp", "type": "int64_t"} 422 - ], 423 - "out": [ 424 - {"name": "value", "type": "struct xrt_hand_joint_set"}, 425 - {"name": "timestamp", "type": "int64_t"} 426 - ] 427 - }, 428 - 429 - "device_get_view_poses": { 430 - "varlen": true, 431 - "in": [ 432 - {"name": "id", "type": "uint32_t"}, 433 - {"name": "fallback_eye_relation", "type": "struct xrt_vec3"}, 434 - {"name": "at_timestamp_ns", "type": "int64_t"}, 435 - {"name": "view_count", "type": "uint32_t"} 436 - ], 437 - "out": [ 438 - {"name": "head_relation", "type": "struct xrt_space_relation"}, 439 - {"name": "view_count", "type": "uint32_t"} 440 - ] 441 - }, 442 - 443 - "device_get_view_poses_2": { 444 - "in": [ 445 - {"name": "id", "type": "uint32_t"}, 446 - {"name": "fallback_eye_relation", "type": "struct xrt_vec3"}, 447 - {"name": "at_timestamp_ns", "type": "int64_t"}, 448 - {"name": "view_count", "type": "uint32_t"} 449 - ], 450 - "out": [ 451 - {"name": "info", "type": "struct ipc_info_get_view_poses_2"} 452 - ] 453 - }, 454 - 455 - "device_compute_distortion": { 456 - "in": [ 457 - {"name": "id", "type": "uint32_t"}, 458 - {"name": "view", "type": "uint32_t"}, 459 - {"name": "u", "type": "float"}, 460 - {"name": "v", "type": "float"} 461 - ], 462 - "out": [ 463 - {"name": "triplet", "type": "struct xrt_uv_triplet"} 464 - ] 465 - }, 466 - 467 - "device_begin_plane_detection_ext": { 468 - "in": [ 469 - {"name": "id", "type": "uint32_t"}, 470 - {"name": "plane_detection_id", "type": "uint64_t"} 471 - ], 472 - "out": [ 473 - {"name": "out_plane_detection_id", "type": "uint64_t"} 474 - ] 475 - }, 476 - 477 - "device_destroy_plane_detection_ext": { 478 - "in": [ 479 - {"name": "id", "type": "uint32_t"}, 480 - {"name": "plane_detection_id", "type": "uint64_t"} 481 - ] 482 - }, 483 - 484 - "device_get_plane_detection_state_ext": { 485 - "in": [ 486 - {"name": "id", "type": "uint32_t"}, 487 - {"name": "plane_detection_id", "type": "uint64_t"} 488 - ], 489 - "out": [ 490 - {"name": "state", "type": "enum xrt_plane_detector_state_ext"} 491 - ] 492 - }, 493 - 494 - "device_get_plane_detections_ext": { 495 - "varlen": true, 496 - "in": [ 497 - {"name": "id", "type": "uint32_t"}, 498 - {"name": "plane_detection_id", "type": "uint64_t"} 499 - ], 500 - "out": [ 501 - {"name": "location_size", "type": "uint32_t"}, 502 - {"name": "polygon_size", "type": "uint32_t"}, 503 - {"name": "vertex_size", "type": "uint32_t"} 504 - ] 505 - }, 506 - 507 - "device_get_presence": { 508 - "in": [ 509 - {"name": "id", "type": "uint32_t"} 510 - ], 511 - "out": [ 512 - {"name": "presence", "type": "bool"} 513 - ] 514 - }, 515 - 516 - "device_set_output": { 517 - "in": [ 518 - {"name": "id", "type": "uint32_t"}, 519 - {"name": "name", "type": "enum xrt_output_name"}, 520 - {"name": "value", "type": "struct xrt_output_value"} 521 - ] 522 - }, 523 - 524 - "device_set_haptic_output": { 525 - "varlen": true, 526 - "in": [ 527 - {"name": "id", "type": "uint32_t"}, 528 - {"name": "name", "type": "enum xrt_output_name"}, 529 - {"name": "samples", "type": "struct ipc_pcm_haptic_buffer"} 530 - ], 531 - "out":[ 532 - {"name": "samples_consumed", "type": "uint32_t"} 533 - ] 534 - }, 535 - 536 - "device_get_output_limits": { 537 - "in": [ 538 - {"name": "id", "type": "uint32_t"} 539 - ], 540 - "out":[ 541 - {"name": "limits", "type": "struct xrt_output_limits"} 542 - ] 543 - }, 544 - 545 - "device_get_visibility_mask": { 546 - "varlen": true, 547 - "in": [ 548 - {"name": "id", "type": "uint32_t"}, 549 - {"name": "type", "type": "enum xrt_visibility_mask_type"}, 550 - {"name": "view_index", "type": "uint32_t"} 551 - ], 552 - "out": [ 553 - {"name": "mask_size", "type": "uint32_t"} 554 - ] 555 - }, 556 - 557 - "device_is_form_factor_available": { 558 - "in": [ 559 - {"name": "id", "type": "uint32_t"}, 560 - {"name": "form_factor", "type": "enum xrt_form_factor"} 561 - ], 562 - "out": [ 563 - {"name": "available", "type": "bool"} 564 - ] 565 - }, 566 - 567 - "device_get_face_tracking": { 568 - "in": [ 569 - {"name": "id", "type": "uint32_t"}, 570 - {"name": "facial_expression_type", "type": "enum xrt_input_name"}, 571 - {"name": "at_timestamp_ns", "type": "int64_t"} 572 - ], 573 - "out": [ 574 - {"name": "value", "type": "struct xrt_facial_expression_set"} 575 - ] 576 - }, 577 - 578 - "device_get_body_skeleton": { 579 - "in": [ 580 - {"name": "id", "type": "uint32_t"}, 581 - {"name": "body_tracking_type", "type": "enum xrt_input_name"} 582 - ], 583 - "out": [ 584 - {"name": "value", "type": "struct xrt_body_skeleton"} 585 - ] 586 - }, 587 - 588 - "device_get_body_joints": { 589 - "in": [ 590 - {"name": "id", "type": "uint32_t"}, 591 - {"name": "body_tracking_type", "type": "enum xrt_input_name"}, 592 - {"name": "desired_timestamp_ns", "type": "int64_t"} 593 - ], 594 - "out": [ 595 - {"name": "value", "type": "struct xrt_body_joint_set"} 596 - ] 597 - }, 598 - 599 - "device_reset_body_tracking_calibration_meta": { 600 - "in": [ 601 - {"name": "id", "type": "uint32_t"} 602 - ] 603 - }, 604 - 605 - "device_set_body_tracking_calibration_override_meta": { 606 - "in": [ 607 - {"name": "id", "type": "uint32_t"}, 608 - {"name": "new_body_height", "type": "float"} 609 - ] 610 - }, 611 - 612 - "device_get_battery_status": { 613 - "in": [ 614 - {"name": "id", "type": "uint32_t"} 615 - ], 616 - "out": [ 617 - {"name": "present", "type": "bool"}, 618 - {"name": "charging", "type": "bool"}, 619 - {"name": "charge", "type": "float"} 620 - ] 621 - }, 622 - 623 - "device_get_brightness": { 624 - "in": [ 625 - {"name": "id", "type": "uint32_t"} 626 - ], 627 - "out": [ 628 - {"name": "brightness", "type": "float"} 629 - ] 630 - }, 631 - 632 - "device_set_brightness": { 633 - "in": [ 634 - {"name": "id", "type": "uint32_t"}, 635 - {"name": "brightness", "type": "float"}, 636 - {"name": "relative", "type": "bool"} 637 - ] 638 - }, 639 - 640 - "future_get_state": { 641 - "in": [ 642 - {"name": "future_id", "type": "uint32_t"} 643 - ], 644 - "out": [ 645 - {"name": "out_state", "type": "enum xrt_future_state"} 646 - ] 647 - }, 648 - 649 - "future_cancel": { 650 - "in": [ 651 - {"name": "future_id", "type": "uint32_t"} 652 - ] 653 - }, 654 - 655 - "future_destroy": { 656 - "in": [ 657 - {"name": "future_id", "type": "uint32_t"} 658 - ] 659 - }, 660 - 661 - "future_get_result": { 662 - "in": [ 663 - {"name": "future_id", "type": "uint32_t"} 664 - ], 665 - "out": [ 666 - {"name": "out_ft_result", "type": "struct xrt_future_result"} 667 - ] 668 - } 669 - }
···
-3
src/xrt/ipc/shared/proto.json.license
··· 1 - Copyright 2018-2023, Collabora, Ltd. 2 - 3 - SPDX-License-Identifier: BSL-1.0
···
+50 -60
src/xrt/ipc/shared/proto.py
··· 1 #!/usr/bin/env python3 2 # Copyright 2020-2023, Collabora, Ltd. 3 # SPDX-License-Identifier: BSL-1.0 4 """Generate code from a JSON file describing the IPC protocol.""" 5 6 import argparse 7 8 from ipcproto.common import (Proto, write_decl, write_invocation, 9 write_result_handler, write_cpp_header_guard_start, ··· 136 137 Defines command enum, utility functions, and command and reply structures. 138 """ 139 - f = open(file, "w") 140 - f.write(header.format(brief='Generated IPC protocol header', suffix='')) 141 - f.write(''' 142 - #pragma once 143 144 - #include "xrt/xrt_compiler.h" 145 146 - ''') 147 148 - write_cpp_header_guard_start(f) 149 - f.write(''' 150 - 151 - struct ipc_connection; 152 - ''') 153 - 154 - f.write('\ntypedef enum ipc_command') 155 - f.write('\n{') 156 - f.write('\n\tIPC_ERR = 0,') 157 - for call in p.calls: 158 - f.write("\n\t" + call.id + ",") 159 - f.write("\n} ipc_command_t;\n") 160 - 161 - f.write(''' 162 - struct ipc_command_msg 163 - { 164 - \tenum ipc_command cmd; 165 - }; 166 - 167 - struct ipc_result_reply 168 - { 169 - \txrt_result_t result; 170 - }; 171 - 172 - ''') 173 - 174 - write_decl(f, return_type='static inline const char *', 175 - function_name='ipc_cmd_to_str', args=['ipc_command_t id']) 176 - f.write('\n{') 177 - f.write('\n\tswitch (id) {') 178 - f.write('\n\tcase IPC_ERR: return "IPC_ERR";') 179 - for call in p.calls: 180 - f.write('\n\tcase ' + call.id + ': return "' + call.id + '";') 181 - f.write('\n\tdefault: return "IPC_UNKNOWN";') 182 - f.write('\n\t}\n}\n') 183 - 184 - f.write('#pragma pack (push, 1)') 185 - 186 for call in p.calls: 187 # Should we emit a msg struct. 188 if call.needs_msg_struct: 189 - f.write('\nstruct ipc_' + call.name + '_msg\n') 190 - f.write('{\n') 191 - f.write('\tenum ipc_command cmd;\n') 192 for arg in call.in_args: 193 - f.write('\t' + arg.get_struct_field() + ';\n') 194 if call.in_handles: 195 - f.write('\t%s %s;\n' % (call.in_handles.count_arg_type, 196 - call.in_handles.count_arg_name)) 197 - f.write('};\n') 198 # Should we emit a reply struct. 199 if call.out_args: 200 - f.write('\nstruct ipc_' + call.name + '_reply\n') 201 - f.write('{\n') 202 - f.write('\txrt_result_t result;\n') 203 for arg in call.out_args: 204 - f.write('\t' + arg.get_struct_field() + ';\n') 205 - f.write('};\n') 206 207 - f.write('#pragma pack (pop)\n') 208 209 - write_cpp_header_guard_end(f) 210 - f.close() 211 212 213 def generate_client_c(file, p): ··· 530 generate_server_c(output, p) 531 if output.endswith("ipc_server_generated.h"): 532 generate_server_header(output, p) 533 - if output.endswith("structs.txt"): 534 generate_struct_names(output, p) 535 536
··· 1 #!/usr/bin/env python3 2 # Copyright 2020-2023, Collabora, Ltd. 3 + # Copyright 2025, NVIDIA CORPORATION. 4 # SPDX-License-Identifier: BSL-1.0 5 """Generate code from a JSON file describing the IPC protocol.""" 6 7 import argparse 8 + import os.path 9 + from string import Template 10 11 from ipcproto.common import (Proto, write_decl, write_invocation, 12 write_result_handler, write_cpp_header_guard_start, ··· 139 140 Defines command enum, utility functions, and command and reply structures. 141 """ 142 + # Get the directory where this script is located 143 + script_dir = os.path.dirname(os.path.abspath(__file__)) 144 + template_file = os.path.join(script_dir, 'ipc_protocol_generated.h.template') 145 146 + # Goes directly into the template file. 147 + ipc_commands = '\n'.join([f'\t{call.id},' for call in p.calls]) 148 149 + # Goes directly into the template file. 150 + ipc_cmd_cases = '\n'.join([f'\tcase {call.id}: return "{call.id}";' for call in p.calls]) 151 152 + # Build message and reply structs. 153 + ipc_msg_structs_list = [] 154 for call in p.calls: 155 # Should we emit a msg struct. 156 if call.needs_msg_struct: 157 + struct_lines = [f'struct ipc_{call.name}_msg'] 158 + struct_lines.append('{') 159 + struct_lines.append('\tenum ipc_command cmd;') 160 for arg in call.in_args: 161 + struct_lines.append('\t' + arg.get_struct_field() + ';') 162 if call.in_handles: 163 + struct_lines.append('\t%s %s;' % (call.in_handles.count_arg_type, 164 + call.in_handles.count_arg_name)) 165 + struct_lines.append('};') 166 + 167 + # Each entry contains a struct complete struct declaration. 168 + ipc_msg_structs_list.append('\n'.join(struct_lines)) 169 + 170 # Should we emit a reply struct. 171 if call.out_args: 172 + struct_lines = [f'struct ipc_{call.name}_reply'] 173 + struct_lines.append('{') 174 + struct_lines.append('\txrt_result_t result;') 175 for arg in call.out_args: 176 + struct_lines.append('\t' + arg.get_struct_field() + ';') 177 + struct_lines.append('};') 178 179 + # Each entry contains a struct complete struct declaration. 180 + ipc_msg_structs_list.append('\n'.join(struct_lines)) 181 + 182 + # What finally goes into the template file. 183 + # The struct declarations doesn't end on a newline, 184 + # so insert two for each declaration. 185 + ipc_msg_structs = '\n\n'.join(ipc_msg_structs_list) 186 187 + # Read the template file. 188 + with open(template_file, 'r') as f: 189 + template = Template(f.read()) 190 + 191 + # Substitute values into the template. 192 + filled = template.substitute( 193 + ipc_commands=ipc_commands, 194 + ipc_cmd_cases=ipc_cmd_cases, 195 + ipc_msg_structs=ipc_msg_structs 196 + ) 197 + 198 + # Write the generated header file. 199 + with open(file, 'w') as f: 200 + f.write(filled) 201 202 203 def generate_client_c(file, p): ··· 520 generate_server_c(output, p) 521 if output.endswith("ipc_server_generated.h"): 522 generate_server_header(output, p) 523 + if output.endswith("structs.txt") or output.endswith("ipc-structs.txt"): 524 generate_struct_names(output, p) 525 526
+10 -1
src/xrt/state_trackers/gui/gui_scene_debug.c
··· 521 igPopItemFlag(); 522 igPopStyleVar(1); 523 } 524 } 525 526 static void ··· 689 case U_VAR_KIND_POSE: on_pose(name, ptr); break; 690 case U_VAR_KIND_LOG_LEVEL: igCombo_Str(name, (int *)ptr, "Trace\0Debug\0Info\0Warn\0Error\0\0", 5); break; 691 case U_VAR_KIND_RO_TEXT: igText("%s: '%s'", name, (char *)ptr); break; 692 - case U_VAR_KIND_RO_FTEXT: igText(ptr ? (char *)ptr : "%s", name); break; 693 case U_VAR_KIND_RO_I16: igInputScalar(name, ImGuiDataType_S16, ptr, NULL, NULL, NULL, ro_i_flags); break; 694 case U_VAR_KIND_RO_I32: igInputScalar(name, ImGuiDataType_S32, ptr, NULL, NULL, NULL, ro_i_flags); break; 695 case U_VAR_KIND_RO_U16: igInputScalar(name, ImGuiDataType_U16, ptr, NULL, NULL, NULL, ro_i_flags); break; ··· 706 case U_VAR_KIND_GUI_HEADER: assert(false && "Should be handled before this"); break; 707 case U_VAR_KIND_GUI_HEADER_BEGIN: on_gui_header_begin(name, state); break; 708 case U_VAR_KIND_GUI_HEADER_END: on_gui_header_end(); break; 709 case U_VAR_KIND_SINK_DEBUG: on_sink_debug_var(name, ptr, state); break; 710 case U_VAR_KIND_NATIVE_IMAGES_DEBUG: on_native_images_debug_var(name, ptr, state); break; 711 case U_VAR_KIND_DRAGGABLE_F32: on_draggable_f32_var(name, ptr); break;
··· 521 igPopItemFlag(); 522 igPopStyleVar(1); 523 } 524 + 525 + // Checking for downed. 526 + if (disabled) { 527 + btn->downed = false; 528 + } else { 529 + btn->downed = igIsItemHovered(ImGuiHoveredFlags_RectOnly) && igIsMouseDown_Nil(ImGuiMouseButton_Left) && 530 + igIsItemActive(); 531 + } 532 } 533 534 static void ··· 697 case U_VAR_KIND_POSE: on_pose(name, ptr); break; 698 case U_VAR_KIND_LOG_LEVEL: igCombo_Str(name, (int *)ptr, "Trace\0Debug\0Info\0Warn\0Error\0\0", 5); break; 699 case U_VAR_KIND_RO_TEXT: igText("%s: '%s'", name, (char *)ptr); break; 700 + case U_VAR_KIND_RO_RAW_TEXT: igText("%s", (char *)ptr); break; 701 case U_VAR_KIND_RO_I16: igInputScalar(name, ImGuiDataType_S16, ptr, NULL, NULL, NULL, ro_i_flags); break; 702 case U_VAR_KIND_RO_I32: igInputScalar(name, ImGuiDataType_S32, ptr, NULL, NULL, NULL, ro_i_flags); break; 703 case U_VAR_KIND_RO_U16: igInputScalar(name, ImGuiDataType_U16, ptr, NULL, NULL, NULL, ro_i_flags); break; ··· 714 case U_VAR_KIND_GUI_HEADER: assert(false && "Should be handled before this"); break; 715 case U_VAR_KIND_GUI_HEADER_BEGIN: on_gui_header_begin(name, state); break; 716 case U_VAR_KIND_GUI_HEADER_END: on_gui_header_end(); break; 717 + case U_VAR_KIND_GUI_SAMELINE: igSameLine(0.0, 4.0f); break; 718 case U_VAR_KIND_SINK_DEBUG: on_sink_debug_var(name, ptr, state); break; 719 case U_VAR_KIND_NATIVE_IMAGES_DEBUG: on_native_images_debug_var(name, ptr, state); break; 720 case U_VAR_KIND_DRAGGABLE_F32: on_draggable_f32_var(name, ptr); break;
+10 -1
src/xrt/state_trackers/gui/gui_scene_remote.c
··· 413 igBegin("Remote control", NULL, 0); 414 415 #ifdef XRT_BUILD_DRIVER_REMOTE 416 - if (gr->rc.fd < 0) { 417 on_not_connected(gr, p); 418 } else { 419 on_connected(gr, p); ··· 451 452 gr->base.render = scene_render; 453 gr->base.destroy = scene_destroy; 454 gr->rc.fd = -1; 455 456 // GUI input defaults. 457 if (address != NULL) {
··· 413 igBegin("Remote control", NULL, 0); 414 415 #ifdef XRT_BUILD_DRIVER_REMOTE 416 + #ifdef XRT_OS_WINDOWS 417 + bool socket_invalid = gr->rc.fd == INVALID_SOCKET; 418 + #else 419 + bool socket_invalid = gr->rc.fd < 0; 420 + #endif 421 + if (socket_invalid) { 422 on_not_connected(gr, p); 423 } else { 424 on_connected(gr, p); ··· 456 457 gr->base.render = scene_render; 458 gr->base.destroy = scene_destroy; 459 + #ifdef XRT_OS_WINDOWS 460 + gr->rc.fd = INVALID_SOCKET; 461 + #else 462 gr->rc.fd = -1; 463 + #endif 464 465 // GUI input defaults. 466 if (address != NULL) {
+2 -2
src/xrt/state_trackers/gui/gui_scene_tracking_overrides.c
··· 11 #include "util/u_misc.h" 12 #include "util/u_format.h" 13 #include "util/u_logging.h" 14 15 #include "util/u_config_json.h" 16 ··· 23 #include "gui_common.h" 24 #include "gui_imgui.h" 25 26 - #include "bindings/b_generated_bindings_helpers.h" 27 28 struct gui_tracking_overrides 29 { ··· 243 continue; 244 } 245 246 - const char *name_str = xrt_input_name_string(input_name); 247 bool selected = o->input_name == input_name; 248 if (igCheckbox(name_str, &selected)) { 249 o->input_name = input_name;
··· 11 #include "util/u_misc.h" 12 #include "util/u_format.h" 13 #include "util/u_logging.h" 14 + #include "util/u_pretty_print.h" 15 16 #include "util/u_config_json.h" 17 ··· 24 #include "gui_common.h" 25 #include "gui_imgui.h" 26 27 28 struct gui_tracking_overrides 29 { ··· 243 continue; 244 } 245 246 + const char *name_str = u_str_xrt_input_name(input_name); 247 bool selected = o->input_name == input_name; 248 if (igCheckbox(name_str, &selected)) { 249 o->input_name = input_name;
+5 -1
src/xrt/state_trackers/oxr/CMakeLists.txt
··· 106 target_sources(st_oxr PRIVATE oxr_api_body_tracking.c oxr_body_tracking.c) 107 endif() 108 109 if(XRT_FEATURE_OPENXR_FACIAL_TRACKING_HTC) 110 - target_sources(st_oxr PRIVATE oxr_api_face_tracking.c oxr_face_tracking.c) 111 endif() 112 113 if(XRT_FEATURE_OPENXR_FACE_TRACKING2_FB)
··· 106 target_sources(st_oxr PRIVATE oxr_api_body_tracking.c oxr_body_tracking.c) 107 endif() 108 109 + if(XRT_FEATURE_OPENXR_FACE_TRACKING_ANDROID) 110 + target_sources(st_oxr PRIVATE oxr_api_face_tracking_android.c oxr_face_tracking_android.c) 111 + endif() 112 + 113 if(XRT_FEATURE_OPENXR_FACIAL_TRACKING_HTC) 114 + target_sources(st_oxr PRIVATE oxr_api_face_tracking_htc.c oxr_face_tracking_htc.c) 115 endif() 116 117 if(XRT_FEATURE_OPENXR_FACE_TRACKING2_FB)
+7 -7
src/xrt/state_trackers/oxr/oxr_api_action.c
··· 1 // Copyright 2019-2023, Collabora, Ltd. 2 - // Copyright 2023, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 156 os_mutex_unlock(&sess->sys->sync_actions_mutex); 157 } 158 159 - if (syncInfo->countActiveActionSets == 0) { 160 - // nothing to do 161 - return XR_SUCCESS; 162 - } 163 - 164 for (uint32_t i = 0; i < syncInfo->countActiveActionSets; i++) { 165 struct oxr_action_set *act_set = NULL; 166 OXR_VERIFY_ACTIONSET_NOT_NULL(&log, syncInfo->activeActionSets[i].actionSet, act_set); 167 168 XrResult res = oxr_verify_subaction_path_sync(&log, sess->sys->inst, act_set, ··· 238 path_verify_fn_t dpad_path_fn = NULL; 239 path_verify_fn_t dpad_emulator_fn = NULL; 240 ext_verify_fn_t ext_verify_fn = NULL; 241 - bool has_dpad = inst->extensions.EXT_dpad_binding; 242 243 struct profile_template *interaction_profile_template = NULL; 244 for (uint32_t i = 0; i < ARRAY_SIZE(profile_templates); i++) {
··· 1 // Copyright 2019-2023, Collabora, Ltd. 2 + // Copyright 2023-2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 156 os_mutex_unlock(&sess->sys->sync_actions_mutex); 157 } 158 159 for (uint32_t i = 0; i < syncInfo->countActiveActionSets; i++) { 160 struct oxr_action_set *act_set = NULL; 161 + 162 OXR_VERIFY_ACTIONSET_NOT_NULL(&log, syncInfo->activeActionSets[i].actionSet, act_set); 163 164 XrResult res = oxr_verify_subaction_path_sync(&log, sess->sys->inst, act_set, ··· 234 path_verify_fn_t dpad_path_fn = NULL; 235 path_verify_fn_t dpad_emulator_fn = NULL; 236 ext_verify_fn_t ext_verify_fn = NULL; 237 + #ifdef OXR_HAVE_EXT_dpad_binding 238 + const bool has_dpad = inst->extensions.EXT_dpad_binding; 239 + #else 240 + const bool has_dpad = false; 241 + #endif 242 243 struct profile_template *interaction_profile_template = NULL; 244 for (uint32_t i = 0; i < ARRAY_SIZE(profile_templates); i++) {
-90
src/xrt/state_trackers/oxr/oxr_api_face_tracking.c
··· 1 - // Copyright 2024, Collabora, Ltd. 2 - // SPDX-License-Identifier: BSL-1.0 3 - /*! 4 - * @file 5 - * @brief face tracking related API entrypoint functions. 6 - * @author Korcan Hussein <korcan.hussein@collabora.com> 7 - * @ingroup oxr_api 8 - */ 9 - 10 - #include <stdio.h> 11 - #include <stdlib.h> 12 - #include <string.h> 13 - 14 - #include "util/u_trace_marker.h" 15 - 16 - #include "oxr_objects.h" 17 - #include "oxr_logger.h" 18 - 19 - #include "oxr_api_funcs.h" 20 - #include "oxr_api_verify.h" 21 - #include "oxr_handle.h" 22 - 23 - XRAPI_ATTR XrResult XRAPI_CALL 24 - oxr_xrCreateFacialTrackerHTC(XrSession session, 25 - const XrFacialTrackerCreateInfoHTC *createInfo, 26 - XrFacialTrackerHTC *facialTracker) 27 - { 28 - OXR_TRACE_MARKER(); 29 - 30 - struct oxr_logger log; 31 - XrResult ret = XR_SUCCESS; 32 - struct oxr_session *sess = NULL; 33 - struct oxr_facial_tracker_htc *facial_tracker_htc = NULL; 34 - OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrCreateFacialTrackerHTC"); 35 - OXR_VERIFY_SESSION_NOT_LOST(&log, sess); 36 - OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, createInfo, XR_TYPE_FACIAL_TRACKER_CREATE_INFO_HTC); 37 - OXR_VERIFY_EXTENSION(&log, sess->sys->inst, HTC_facial_tracking); 38 - 39 - ret = oxr_facial_tracker_htc_create(&log, sess, createInfo, &facial_tracker_htc); 40 - if (ret != XR_SUCCESS) { 41 - return ret; 42 - } 43 - 44 - OXR_VERIFY_ARG_NOT_NULL(&log, facial_tracker_htc); 45 - *facialTracker = oxr_facial_tracker_htc_to_openxr(facial_tracker_htc); 46 - 47 - return XR_SUCCESS; 48 - } 49 - 50 - XRAPI_ATTR XrResult XRAPI_CALL 51 - oxr_xrDestroyFacialTrackerHTC(XrFacialTrackerHTC facialTracker) 52 - { 53 - OXR_TRACE_MARKER(); 54 - 55 - struct oxr_logger log; 56 - struct oxr_facial_tracker_htc *facial_tracker_htc = NULL; 57 - OXR_VERIFY_FACE_TRACKER_HTC_AND_INIT_LOG(&log, facialTracker, facial_tracker_htc, "xrDestroyFacialTrackerHTC"); 58 - 59 - return oxr_handle_destroy(&log, &facial_tracker_htc->handle); 60 - } 61 - 62 - XRAPI_ATTR XrResult XRAPI_CALL 63 - oxr_xrGetFacialExpressionsHTC(XrFacialTrackerHTC facialTracker, XrFacialExpressionsHTC *facialExpressions) 64 - { 65 - OXR_TRACE_MARKER(); 66 - 67 - struct oxr_logger log; 68 - struct oxr_facial_tracker_htc *facial_tracker_htc = NULL; 69 - OXR_VERIFY_FACE_TRACKER_HTC_AND_INIT_LOG(&log, facialTracker, facial_tracker_htc, "xrGetFacialExpressionsHTC"); 70 - OXR_VERIFY_SESSION_NOT_LOST(&log, facial_tracker_htc->sess); 71 - OXR_VERIFY_ARG_NOT_NULL(&log, facial_tracker_htc->xdev); 72 - OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, facialExpressions, XR_TYPE_FACIAL_EXPRESSIONS_HTC); 73 - OXR_VERIFY_ARG_NOT_NULL(&log, facialExpressions->expressionWeightings); 74 - 75 - #define OXR_VERIFY_FACE_EXPRESSION_COUNT(fttype) \ 76 - if (facial_tracker_htc->facial_tracking_type == XRT_FACIAL_TRACKING_TYPE_##fttype##_DEFAULT_HTC && \ 77 - facialExpressions->expressionCount < XRT_FACIAL_EXPRESSION_##fttype##_COUNT_HTC) { \ 78 - return oxr_error( \ 79 - &log, XR_ERROR_SIZE_INSUFFICIENT, \ 80 - "\"expressionCount\" (%d) size is less than the minimum size (%d) required for " #fttype \ 81 - " expressions.\n", \ 82 - facialExpressions->expressionCount, XRT_FACIAL_EXPRESSION_##fttype##_COUNT_HTC); \ 83 - } 84 - 85 - OXR_VERIFY_FACE_EXPRESSION_COUNT(EYE) 86 - OXR_VERIFY_FACE_EXPRESSION_COUNT(LIP) 87 - #undef OXR_VERIFY_FACE_EXPRESSION_COUNT 88 - 89 - return oxr_get_facial_expressions_htc(&log, facial_tracker_htc, facialExpressions); 90 - }
···
+82
src/xrt/state_trackers/oxr/oxr_api_face_tracking_android.c
···
··· 1 + // Copyright 2025, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief Android face tracking related API entrypoint functions. 6 + * @author Korcan Hussein <korcan.hussein@collabora.com> 7 + * @ingroup oxr_api 8 + */ 9 + 10 + #include <stdio.h> 11 + #include <stdlib.h> 12 + #include <string.h> 13 + 14 + #include "util/u_trace_marker.h" 15 + 16 + #include "oxr_objects.h" 17 + #include "oxr_logger.h" 18 + 19 + #include "oxr_api_funcs.h" 20 + #include "oxr_api_verify.h" 21 + #include "oxr_handle.h" 22 + 23 + XRAPI_ATTR XrResult XRAPI_CALL 24 + oxr_xrCreateFaceTrackerANDROID(XrSession session, 25 + const XrFaceTrackerCreateInfoANDROID *createInfo, 26 + XrFaceTrackerANDROID *faceTracker) 27 + { 28 + OXR_TRACE_MARKER(); 29 + struct oxr_logger log; 30 + struct oxr_session *sess = NULL; 31 + OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrCreateFaceTrackerANDROID"); 32 + OXR_VERIFY_SESSION_NOT_LOST(&log, sess); 33 + OXR_VERIFY_EXTENSION(&log, sess->sys->inst, ANDROID_face_tracking); 34 + OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, createInfo, XR_TYPE_FACE_TRACKER_CREATE_INFO_ANDROID); 35 + return oxr_face_tracker_android_create(&log, sess, createInfo, faceTracker); 36 + } 37 + 38 + XRAPI_ATTR XrResult XRAPI_CALL 39 + oxr_xrDestroyFaceTrackerANDROID(XrFaceTrackerANDROID facialTracker) 40 + { 41 + OXR_TRACE_MARKER(); 42 + struct oxr_logger log; 43 + struct oxr_face_tracker_android *face_tracker_android = NULL; 44 + OXR_VERIFY_FACE_TRACKER_ANDROID_AND_INIT_LOG(&log, facialTracker, face_tracker_android, 45 + "xrDestroyFaceTrackerANDROID"); 46 + return oxr_handle_destroy(&log, &face_tracker_android->handle); 47 + } 48 + 49 + XRAPI_ATTR XrResult XRAPI_CALL 50 + oxr_xrGetFaceStateANDROID(XrFaceTrackerANDROID faceTracker, 51 + const XrFaceStateGetInfoANDROID *getInfo, 52 + XrFaceStateANDROID *faceStateOutput) 53 + { 54 + OXR_TRACE_MARKER(); 55 + struct oxr_logger log; 56 + struct oxr_face_tracker_android *face_tracker_android = NULL; 57 + OXR_VERIFY_FACE_TRACKER_ANDROID_AND_INIT_LOG(&log, faceTracker, face_tracker_android, "xrGetFaceStateANDROID"); 58 + OXR_VERIFY_SESSION_NOT_LOST(&log, face_tracker_android->sess); 59 + OXR_VERIFY_ARG_NOT_NULL(&log, face_tracker_android->xdev); 60 + OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, getInfo, XR_TYPE_FACE_STATE_GET_INFO_ANDROID); 61 + OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, faceStateOutput, XR_TYPE_FACE_STATE_ANDROID); 62 + OXR_VERIFY_ARG_TIME_NOT_ZERO(&log, getInfo->time); 63 + OXR_VERIFY_TWO_CALL_ARRAY(&log, faceStateOutput->parametersCapacityInput, 64 + (&faceStateOutput->parametersCountOutput), faceStateOutput->parameters); 65 + OXR_VERIFY_TWO_CALL_ARRAY(&log, faceStateOutput->regionConfidencesCapacityInput, 66 + (&faceStateOutput->regionConfidencesCountOutput), faceStateOutput->regionConfidences); 67 + return oxr_get_face_state_android(&log, face_tracker_android, getInfo, faceStateOutput); 68 + } 69 + 70 + XRAPI_ATTR XrResult XRAPI_CALL 71 + oxr_xrGetFaceCalibrationStateANDROID(XrFaceTrackerANDROID faceTracker, XrBool32 *faceIsCalibratedOutput) 72 + { 73 + OXR_TRACE_MARKER(); 74 + struct oxr_logger log; 75 + struct oxr_face_tracker_android *face_tracker_android = NULL; 76 + OXR_VERIFY_FACE_TRACKER_ANDROID_AND_INIT_LOG(&log, faceTracker, face_tracker_android, 77 + "xrGetFaceCalibrationStateANDROID"); 78 + OXR_VERIFY_SESSION_NOT_LOST(&log, face_tracker_android->sess); 79 + OXR_VERIFY_ARG_NOT_NULL(&log, face_tracker_android->xdev); 80 + OXR_VERIFY_ARG_NOT_NULL(&log, faceIsCalibratedOutput); 81 + return oxr_get_face_calibration_state_android(&log, face_tracker_android, faceIsCalibratedOutput); 82 + }
+90
src/xrt/state_trackers/oxr/oxr_api_face_tracking_htc.c
···
··· 1 + // Copyright 2024, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief face tracking related API entrypoint functions. 6 + * @author Korcan Hussein <korcan.hussein@collabora.com> 7 + * @ingroup oxr_api 8 + */ 9 + 10 + #include <stdio.h> 11 + #include <stdlib.h> 12 + #include <string.h> 13 + 14 + #include "util/u_trace_marker.h" 15 + 16 + #include "oxr_objects.h" 17 + #include "oxr_logger.h" 18 + 19 + #include "oxr_api_funcs.h" 20 + #include "oxr_api_verify.h" 21 + #include "oxr_handle.h" 22 + 23 + XRAPI_ATTR XrResult XRAPI_CALL 24 + oxr_xrCreateFacialTrackerHTC(XrSession session, 25 + const XrFacialTrackerCreateInfoHTC *createInfo, 26 + XrFacialTrackerHTC *facialTracker) 27 + { 28 + OXR_TRACE_MARKER(); 29 + 30 + struct oxr_logger log; 31 + XrResult ret = XR_SUCCESS; 32 + struct oxr_session *sess = NULL; 33 + struct oxr_facial_tracker_htc *facial_tracker_htc = NULL; 34 + OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrCreateFacialTrackerHTC"); 35 + OXR_VERIFY_SESSION_NOT_LOST(&log, sess); 36 + OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, createInfo, XR_TYPE_FACIAL_TRACKER_CREATE_INFO_HTC); 37 + OXR_VERIFY_EXTENSION(&log, sess->sys->inst, HTC_facial_tracking); 38 + 39 + ret = oxr_facial_tracker_htc_create(&log, sess, createInfo, &facial_tracker_htc); 40 + if (ret != XR_SUCCESS) { 41 + return ret; 42 + } 43 + 44 + OXR_VERIFY_ARG_NOT_NULL(&log, facial_tracker_htc); 45 + *facialTracker = oxr_facial_tracker_htc_to_openxr(facial_tracker_htc); 46 + 47 + return XR_SUCCESS; 48 + } 49 + 50 + XRAPI_ATTR XrResult XRAPI_CALL 51 + oxr_xrDestroyFacialTrackerHTC(XrFacialTrackerHTC facialTracker) 52 + { 53 + OXR_TRACE_MARKER(); 54 + 55 + struct oxr_logger log; 56 + struct oxr_facial_tracker_htc *facial_tracker_htc = NULL; 57 + OXR_VERIFY_FACE_TRACKER_HTC_AND_INIT_LOG(&log, facialTracker, facial_tracker_htc, "xrDestroyFacialTrackerHTC"); 58 + 59 + return oxr_handle_destroy(&log, &facial_tracker_htc->handle); 60 + } 61 + 62 + XRAPI_ATTR XrResult XRAPI_CALL 63 + oxr_xrGetFacialExpressionsHTC(XrFacialTrackerHTC facialTracker, XrFacialExpressionsHTC *facialExpressions) 64 + { 65 + OXR_TRACE_MARKER(); 66 + 67 + struct oxr_logger log; 68 + struct oxr_facial_tracker_htc *facial_tracker_htc = NULL; 69 + OXR_VERIFY_FACE_TRACKER_HTC_AND_INIT_LOG(&log, facialTracker, facial_tracker_htc, "xrGetFacialExpressionsHTC"); 70 + OXR_VERIFY_SESSION_NOT_LOST(&log, facial_tracker_htc->sess); 71 + OXR_VERIFY_ARG_NOT_NULL(&log, facial_tracker_htc->xdev); 72 + OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, facialExpressions, XR_TYPE_FACIAL_EXPRESSIONS_HTC); 73 + OXR_VERIFY_ARG_NOT_NULL(&log, facialExpressions->expressionWeightings); 74 + 75 + #define OXR_VERIFY_FACE_EXPRESSION_COUNT(fttype) \ 76 + if (facial_tracker_htc->facial_tracking_type == XRT_FACIAL_TRACKING_TYPE_##fttype##_DEFAULT_HTC && \ 77 + facialExpressions->expressionCount < XRT_FACIAL_EXPRESSION_##fttype##_COUNT_HTC) { \ 78 + return oxr_error( \ 79 + &log, XR_ERROR_SIZE_INSUFFICIENT, \ 80 + "\"expressionCount\" (%d) size is less than the minimum size (%d) required for " #fttype \ 81 + " expressions.\n", \ 82 + facialExpressions->expressionCount, XRT_FACIAL_EXPRESSION_##fttype##_COUNT_HTC); \ 83 + } 84 + 85 + OXR_VERIFY_FACE_EXPRESSION_COUNT(EYE) 86 + OXR_VERIFY_FACE_EXPRESSION_COUNT(LIP) 87 + #undef OXR_VERIFY_FACE_EXPRESSION_COUNT 88 + 89 + return oxr_get_facial_expressions_htc(&log, facial_tracker_htc, facialExpressions); 90 + }
+24
src/xrt/state_trackers/oxr/oxr_api_funcs.h
··· 779 oxr_xrCancelFutureEXT(XrInstance instance, const XrFutureCancelInfoEXT *cancelInfo); 780 #endif 781 782 /*! 783 * @} 784 */
··· 779 oxr_xrCancelFutureEXT(XrInstance instance, const XrFutureCancelInfoEXT *cancelInfo); 780 #endif 781 782 + /* 783 + * 784 + * oxr_api_face_tracking_android.c 785 + * 786 + */ 787 + 788 + #ifdef OXR_HAVE_ANDROID_face_tracking 789 + XRAPI_ATTR XrResult XRAPI_CALL 790 + oxr_xrCreateFaceTrackerANDROID(XrSession session, 791 + const XrFaceTrackerCreateInfoANDROID *createInfo, 792 + XrFaceTrackerANDROID *faceTracker); 793 + 794 + XRAPI_ATTR XrResult XRAPI_CALL 795 + oxr_xrDestroyFaceTrackerANDROID(XrFaceTrackerANDROID facialTracker); 796 + 797 + XRAPI_ATTR XrResult XRAPI_CALL 798 + oxr_xrGetFaceStateANDROID(XrFaceTrackerANDROID faceTracker, 799 + const XrFaceStateGetInfoANDROID *getInfo, 800 + XrFaceStateANDROID *faceStateOutput); 801 + 802 + XRAPI_ATTR XrResult XRAPI_CALL 803 + oxr_xrGetFaceCalibrationStateANDROID(XrFaceTrackerANDROID faceTracker, XrBool32 *faceIsCalibratedOutput); 804 + #endif 805 + 806 /*! 807 * @} 808 */
+50 -10
src/xrt/state_trackers/oxr/oxr_api_instance.c
··· 1 // Copyright 2018-2019, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 256 struct oxr_logger log; 257 OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst, "xrResultToString"); 258 259 - #define MAKE_RESULT_CASE(VAL, _) \ 260 - case VAL: snprintf(buffer, XR_MAX_RESULT_STRING_SIZE, #VAL); break; 261 262 switch (value) { 263 XR_LIST_ENUM_XrResult(MAKE_RESULT_CASE); 264 default: 265 - snprintf(buffer, XR_MAX_RESULT_STRING_SIZE, "XR_UNKNOWN_%s_%d", value < 0 ? "FAILURE" : "SUCCESS", 266 - value); 267 } 268 // The function snprintf always null terminates. 269 270 return XR_SUCCESS; 271 } ··· 282 static_assert(XR_MAX_STRUCTURE_NAME_SIZE == 64, 283 "XR_MAX_STRUCTURE_NAME_SIZE has changed, please update the format string"); 284 285 - #define MAKE_TYPE_CASE(VAL, _) \ 286 - case VAL: snprintf(buffer, XR_MAX_STRUCTURE_NAME_SIZE, "%.63s", #VAL); break; 287 288 switch (value) { 289 XR_LIST_ENUM_XrStructureType(MAKE_TYPE_CASE); 290 - default: snprintf(buffer, XR_MAX_STRUCTURE_NAME_SIZE, "XR_UNKNOWN_STRUCTURE_TYPE_%d", value); 291 } 292 // The function snprintf always null terminates. 293 #undef MAKE_TYPE_CASE 294 return XR_SUCCESS; 295 } 296 ··· 311 static_assert(XR_MAX_STRUCTURE_NAME_SIZE_EXTENDED_KHR == 256, 312 "XR_MAX_STRUCTURE_NAME_SIZE_EXTENDED_KHR has changed, please update the format string"); 313 314 - #define MAKE_TYPE_CASE(VAL, _) \ 315 - case VAL: snprintf(buffer, XR_MAX_STRUCTURE_NAME_SIZE_EXTENDED_KHR, "%.255s", #VAL); break; 316 317 switch (value) { 318 XR_LIST_ENUM_XrStructureType(MAKE_TYPE_CASE); 319 - default: snprintf(buffer, XR_MAX_STRUCTURE_NAME_SIZE_EXTENDED_KHR, "XR_UNKNOWN_STRUCTURE_TYPE_%d", value); 320 } 321 // The function snprintf always null terminates. 322 #undef MAKE_TYPE_CASE 323 return XR_SUCCESS; 324 } 325 #endif // OXR_HAVE_KHR_extended_struct_name_lengths
··· 1 // Copyright 2018-2019, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 257 struct oxr_logger log; 258 OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst, "xrResultToString"); 259 260 + // clang-format off 261 + #define MAKE_RESULT_CASE(VAL, _) case VAL: snprintf(buffer, XR_MAX_RESULT_STRING_SIZE, #VAL); break; 262 + #define EXT_RESULT(VAL) if (value == VAL) { snprintf(buffer, XR_MAX_RESULT_STRING_SIZE, #VAL); } else 263 + // clang-format on 264 265 switch (value) { 266 XR_LIST_ENUM_XrResult(MAKE_RESULT_CASE); 267 default: 268 + // Magic comment to make clang-format happy. 269 + { 270 + snprintf(buffer, XR_MAX_RESULT_STRING_SIZE, "XR_UNKNOWN_%s_%d", 271 + value < 0 ? "FAILURE" : "SUCCESS", value); 272 + } 273 } 274 + 275 // The function snprintf always null terminates. 276 + #undef MAKE_RESULT_CASE 277 + #undef EXT_RESULT 278 279 return XR_SUCCESS; 280 } ··· 291 static_assert(XR_MAX_STRUCTURE_NAME_SIZE == 64, 292 "XR_MAX_STRUCTURE_NAME_SIZE has changed, please update the format string"); 293 294 + // clang-format off 295 + #define MAKE_TYPE_CASE(VAL, _) case VAL: snprintf(buffer, XR_MAX_STRUCTURE_NAME_SIZE, "%.63s", #VAL); break; 296 + #define EXT_TYPE(VAL) if (value == VAL) { snprintf(buffer, XR_MAX_STRUCTURE_NAME_SIZE, "%.63s", #VAL); } else 297 + // clang-format on 298 299 switch (value) { 300 XR_LIST_ENUM_XrStructureType(MAKE_TYPE_CASE); 301 + default: 302 + #ifdef OXR_HAVE_MNDX_xdev_space 303 + EXT_TYPE(XR_TYPE_SYSTEM_XDEV_SPACE_PROPERTIES_MNDX) 304 + EXT_TYPE(XR_TYPE_CREATE_XDEV_LIST_INFO_MNDX) 305 + EXT_TYPE(XR_TYPE_GET_XDEV_INFO_MNDX) 306 + EXT_TYPE(XR_TYPE_XDEV_PROPERTIES_MNDX) 307 + EXT_TYPE(XR_TYPE_CREATE_XDEV_SPACE_INFO_MNDX) 308 + #endif 309 + { 310 + snprintf(buffer, XR_MAX_STRUCTURE_NAME_SIZE, "XR_UNKNOWN_STRUCTURE_TYPE_%d", value); 311 + } 312 } 313 + 314 // The function snprintf always null terminates. 315 #undef MAKE_TYPE_CASE 316 + #undef EXT_TYPE 317 + 318 return XR_SUCCESS; 319 } 320 ··· 335 static_assert(XR_MAX_STRUCTURE_NAME_SIZE_EXTENDED_KHR == 256, 336 "XR_MAX_STRUCTURE_NAME_SIZE_EXTENDED_KHR has changed, please update the format string"); 337 338 + // clang-format off 339 + #define MAKE_TYPE_CASE(VAL, _) case VAL: snprintf(buffer, XR_MAX_STRUCTURE_NAME_SIZE_EXTENDED_KHR, "%.255s", #VAL); break; 340 + #define EXT_TYPE(VAL) if (value == VAL) { snprintf(buffer, XR_MAX_STRUCTURE_NAME_SIZE_EXTENDED_KHR, "%.255s", #VAL); } else 341 + // clang-format on 342 343 switch (value) { 344 XR_LIST_ENUM_XrStructureType(MAKE_TYPE_CASE); 345 + default: 346 + #ifdef OXR_HAVE_MNDX_xdev_space 347 + EXT_TYPE(XR_TYPE_SYSTEM_XDEV_SPACE_PROPERTIES_MNDX) 348 + EXT_TYPE(XR_TYPE_CREATE_XDEV_LIST_INFO_MNDX) 349 + EXT_TYPE(XR_TYPE_GET_XDEV_INFO_MNDX) 350 + EXT_TYPE(XR_TYPE_XDEV_PROPERTIES_MNDX) 351 + EXT_TYPE(XR_TYPE_CREATE_XDEV_SPACE_INFO_MNDX) 352 + #endif 353 + { 354 + snprintf(buffer, XR_MAX_STRUCTURE_NAME_SIZE_EXTENDED_KHR, "XR_UNKNOWN_STRUCTURE_TYPE_%d", 355 + value); 356 + } 357 } 358 + 359 // The function snprintf always null terminates. 360 #undef MAKE_TYPE_CASE 361 + #undef EXT_TYPE 362 + 363 return XR_SUCCESS; 364 } 365 #endif // OXR_HAVE_KHR_extended_struct_name_lengths
+7
src/xrt/state_trackers/oxr/oxr_api_negotiate.c
··· 419 ENTRY_IF_EXT(xrCancelFutureEXT, EXT_future); 420 #endif // OXR_HAVE_EXT_future 421 422 #ifdef OXR_HAVE_KHR_extended_struct_name_lengths 423 ENTRY_IF_EXT(xrStructureTypeToString2KHR, KHR_extended_struct_name_lengths); 424 #endif // OXR_HAVE_KHR_extended_struct_name_lengths
··· 419 ENTRY_IF_EXT(xrCancelFutureEXT, EXT_future); 420 #endif // OXR_HAVE_EXT_future 421 422 + #ifdef OXR_HAVE_ANDROID_face_tracking 423 + ENTRY_IF_EXT(xrCreateFaceTrackerANDROID, ANDROID_face_tracking); 424 + ENTRY_IF_EXT(xrDestroyFaceTrackerANDROID, ANDROID_face_tracking); 425 + ENTRY_IF_EXT(xrGetFaceCalibrationStateANDROID, ANDROID_face_tracking); 426 + ENTRY_IF_EXT(xrGetFaceStateANDROID, ANDROID_face_tracking); 427 + #endif 428 + 429 #ifdef OXR_HAVE_KHR_extended_struct_name_lengths 430 ENTRY_IF_EXT(xrStructureTypeToString2KHR, KHR_extended_struct_name_lengths); 431 #endif // OXR_HAVE_KHR_extended_struct_name_lengths
+11 -12
src/xrt/state_trackers/oxr/oxr_api_session.c
··· 1 // Copyright 2019-2024, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 99 // in a headless session there is no compositor and primaryViewConfigurationType must be ignored 100 if (sess->compositor != NULL) { 101 OXR_VERIFY_VIEW_CONFIG_TYPE(&log, sess->sys->inst, beginInfo->primaryViewConfigurationType); 102 } 103 104 // Going to effectively double check this, but this gives us an early out. ··· 239 OXR_VERIFY_SPACE_NOT_NULL(&log, viewLocateInfo->space, spc); 240 OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, viewState, XR_TYPE_VIEW_STATE); 241 OXR_VERIFY_VIEW_CONFIG_TYPE(&log, sess->sys->inst, viewLocateInfo->viewConfigurationType); 242 243 if (viewCapacityInput == 0) { 244 OXR_VERIFY_ARG_NOT_NULL(&log, viewCountOutput); ··· 255 viewLocateInfo->displayTime); 256 } 257 258 - if (viewLocateInfo->viewConfigurationType != sess->sys->view_config_type) { 259 - return oxr_error(&log, XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED, 260 - "(viewConfigurationType == 0x%08x) " 261 - "unsupported view configuration type", 262 - viewLocateInfo->viewConfigurationType); 263 - } 264 - 265 return oxr_session_locate_views( // 266 &log, // 267 sess, // ··· 300 visibilityMask->indexCountOutput = 0; 301 302 OXR_VERIFY_VIEW_CONFIG_TYPE(&log, sess->sys->inst, viewConfigurationType); 303 - if (viewConfigurationType != sess->sys->view_config_type) { 304 - return oxr_error(&log, XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED, 305 - "(viewConfigurationType == 0x%08x) unsupported view configuration type", 306 - viewConfigurationType); 307 - } 308 309 OXR_VERIFY_VIEW_INDEX(&log, viewIndex); 310
··· 1 // Copyright 2019-2024, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 100 // in a headless session there is no compositor and primaryViewConfigurationType must be ignored 101 if (sess->compositor != NULL) { 102 OXR_VERIFY_VIEW_CONFIG_TYPE(&log, sess->sys->inst, beginInfo->primaryViewConfigurationType); 103 + OXR_VERIFY_VIEW_CONFIG_TYPE_SUPPORTED(&log, sess->sys, beginInfo->primaryViewConfigurationType); 104 } 105 106 // Going to effectively double check this, but this gives us an early out. ··· 241 OXR_VERIFY_SPACE_NOT_NULL(&log, viewLocateInfo->space, spc); 242 OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, viewState, XR_TYPE_VIEW_STATE); 243 OXR_VERIFY_VIEW_CONFIG_TYPE(&log, sess->sys->inst, viewLocateInfo->viewConfigurationType); 244 + OXR_VERIFY_VIEW_CONFIG_TYPE_SUPPORTED(&log, sess->sys, viewLocateInfo->viewConfigurationType); 245 + 246 + if (viewLocateInfo->viewConfigurationType != sess->current_view_config_type) { 247 + return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE, 248 + "(viewLocateInfo->viewConfigurationType == 0x%" PRIx32 249 + ") is not view configuration passed into xrBeginSession(0x%" PRIx32 ")", 250 + viewLocateInfo->viewConfigurationType, sess->current_view_config_type); 251 + } 252 253 if (viewCapacityInput == 0) { 254 OXR_VERIFY_ARG_NOT_NULL(&log, viewCountOutput); ··· 265 viewLocateInfo->displayTime); 266 } 267 268 return oxr_session_locate_views( // 269 &log, // 270 sess, // ··· 303 visibilityMask->indexCountOutput = 0; 304 305 OXR_VERIFY_VIEW_CONFIG_TYPE(&log, sess->sys->inst, viewConfigurationType); 306 + OXR_VERIFY_VIEW_CONFIG_TYPE_SUPPORTED(&log, sess->sys, viewConfigurationType); 307 308 OXR_VERIFY_VIEW_INDEX(&log, viewIndex); 309
+46 -3
src/xrt/state_trackers/oxr/oxr_api_swapchain.c
··· 1 // Copyright 2019-2020, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 82 83 // Short hand. 84 struct oxr_instance *inst = sess->sys->inst; 85 86 XrSwapchainUsageFlags flags = 0; 87 flags |= XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT; ··· 102 "(createInfo->usageFlags == 0x%04" PRIx64 ") contains invalid flags", 103 createInfo->usageFlags); 104 } 105 bool format_supported = false; 106 - struct xrt_compositor *c = sess->compositor; 107 - for (uint32_t i = 0; i < c->info.format_count; i++) { 108 - if (c->info.formats[i] == createInfo->format) { 109 format_supported = true; 110 break; 111 } ··· 115 return oxr_error(&log, XR_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED, 116 "(createInfo->format == 0x%04" PRIx64 ") is not supported", createInfo->format); 117 } 118 119 #ifdef OXR_HAVE_KHR_vulkan_swapchain_format_list 120 const XrVulkanSwapchainFormatListCreateInfoKHR *format_list = NULL; ··· 136 } 137 } 138 #endif 139 140 ret = sess->create_swapchain(&log, sess, createInfo, &sc); 141 if (ret != XR_SUCCESS) {
··· 1 // Copyright 2019-2020, Collabora, Ltd. 2 + // Copyright 2024-2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 83 84 // Short hand. 85 struct oxr_instance *inst = sess->sys->inst; 86 + struct xrt_compositor_info *xc_info = &sess->compositor->info; 87 + struct xrt_system_compositor_info *xsysc_info = &sess->sys->xsysc->info; 88 + 89 + 90 + /* 91 + * Usage flags. 92 + */ 93 94 XrSwapchainUsageFlags flags = 0; 95 flags |= XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT; ··· 110 "(createInfo->usageFlags == 0x%04" PRIx64 ") contains invalid flags", 111 createInfo->usageFlags); 112 } 113 + 114 + 115 + /* 116 + * Format. 117 + */ 118 + 119 bool format_supported = false; 120 + for (uint32_t i = 0; i < xc_info->format_count; i++) { 121 + if (xc_info->formats[i] == createInfo->format) { 122 format_supported = true; 123 break; 124 } ··· 128 return oxr_error(&log, XR_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED, 129 "(createInfo->format == 0x%04" PRIx64 ") is not supported", createInfo->format); 130 } 131 + 132 + 133 + /* 134 + * Format list. 135 + */ 136 137 #ifdef OXR_HAVE_KHR_vulkan_swapchain_format_list 138 const XrVulkanSwapchainFormatListCreateInfoKHR *format_list = NULL; ··· 154 } 155 } 156 #endif 157 + 158 + 159 + /* 160 + * Sample count. 161 + */ 162 + 163 + if (createInfo->sampleCount == 0) { 164 + return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE, "(createInfo->sampleCount == 0) must not be zero"); 165 + } 166 + 167 + // TODO Find the max of the views[0].max.sample_count limits. 168 + assert(xsysc_info->view_config_count > 0); 169 + assert(xsysc_info->view_configs[0].view_count > 0); 170 + uint32_t max_sample_count = xsysc_info->view_configs[0].views[0].max.sample_count; 171 + 172 + if (createInfo->sampleCount > max_sample_count) { 173 + return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE, 174 + "(createInfo->sampleCount == %u) must not be larger then max (%u)", 175 + createInfo->sampleCount, max_sample_count); 176 + } 177 + 178 + 179 + /* 180 + * Validation done. 181 + */ 182 183 ret = sess->create_swapchain(&log, sess, createInfo, &sc); 184 if (ret != XR_SUCCESS) {
+26 -10
src/xrt/state_trackers/oxr/oxr_api_system.c
··· 1 // Copyright 2018-2020, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 64 struct oxr_system *systems[1] = {&inst->system}; 65 uint32_t system_count = ARRAY_SIZE(systems); 66 67 - XrResult ret = oxr_system_select(&log, systems, system_count, getInfo->formFactor, &selected); 68 if (ret != XR_SUCCESS) { 69 - return ret; 70 } 71 72 *systemId = selected->systemId; ··· 121 OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst, "xrEnumerateEnvironmentBlendModes"); 122 OXR_VERIFY_SYSTEM_AND_GET(&log, inst, systemId, sys); 123 OXR_VERIFY_VIEW_CONFIG_TYPE(&log, inst, viewConfigurationType); 124 - 125 - if (viewConfigurationType != sys->view_config_type) { 126 - return oxr_error(&log, XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED, 127 - "(viewConfigurationType == 0x%08x) " 128 - "unsupported view configuration type", 129 - viewConfigurationType); 130 - } 131 132 return oxr_system_enumerate_blend_modes(&log, sys, viewConfigurationType, environmentBlendModeCapacityInput, 133 environmentBlendModeCountOutput, environmentBlendModes); ··· 146 OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst, "xrGetViewConfigurationProperties"); 147 OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, configurationProperties, XR_TYPE_VIEW_CONFIGURATION_PROPERTIES); 148 OXR_VERIFY_SYSTEM_AND_GET(&log, inst, systemId, sys); 149 150 return oxr_system_get_view_conf_properties(&log, sys, viewConfigurationType, configurationProperties); 151 } ··· 164 struct oxr_logger log; 165 OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst, "xrEnumerateViewConfigurationViews"); 166 OXR_VERIFY_SYSTEM_AND_GET(&log, inst, systemId, sys); 167 168 for (uint32_t i = 0; i < viewCapacityInput; i++) { 169 OXR_VERIFY_ARG_ARRAY_ELEMENT_TYPE(&log, views, i, XR_TYPE_VIEW_CONFIGURATION_VIEW); ··· 328 329 OXR_VERIFY_SYSTEM_AND_GET(&log, inst, getInfo->systemId, sys); 330 OXR_VERIFY_ARG_NOT_NULL(&log, vkPhysicalDevice); 331 OXR_VERIFY_XSYSC(&log, sys); 332 333 - return oxr_vk_get_physical_device(&log, inst, sys, getInfo->vulkanInstance, vkGetInstanceProcAddr, 334 vkPhysicalDevice); 335 } 336 ··· 393 394 // createInfo->vulkanAllocator can be NULL 395 396 if (createInfo->vulkanCreateInfo->sType != VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO) { 397 return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE, 398 "createInfo->vulkanCreateInfo->sType must be " ··· 428 OXR_VERIFY_ARG_NOT_NULL(&log, sys->suggested_vulkan_physical_device); 429 OXR_VERIFY_ARG_NOT_NULL(&log, sys->vulkan_enable2_instance); 430 OXR_VERIFY_XSYSC(&log, sys); 431 432 if (sys->suggested_vulkan_physical_device != createInfo->vulkanPhysicalDevice) { 433 return oxr_error(&log, XR_ERROR_HANDLE_INVALID,
··· 1 // Copyright 2018-2020, Collabora, Ltd. 2 + // Copyright 2024-2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 65 struct oxr_system *systems[1] = {&inst->system}; 66 uint32_t system_count = ARRAY_SIZE(systems); 67 68 + /* 69 + * This lock is needed to make sure that xrGetSystem can be called from 70 + * multiple threads. This happens in the CTS. 71 + */ 72 + os_mutex_lock(&inst->system_init_lock); 73 + XrResult ret = oxr_instance_init_system_locked(&log, inst); 74 + os_mutex_unlock(&inst->system_init_lock); 75 + 76 if (ret != XR_SUCCESS) { 77 + return ret; // Already logged 78 + } 79 + 80 + ret = oxr_system_select(&log, systems, system_count, getInfo->formFactor, &selected); 81 + if (ret != XR_SUCCESS) { 82 + return ret; // Already logged 83 } 84 85 *systemId = selected->systemId; ··· 134 OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst, "xrEnumerateEnvironmentBlendModes"); 135 OXR_VERIFY_SYSTEM_AND_GET(&log, inst, systemId, sys); 136 OXR_VERIFY_VIEW_CONFIG_TYPE(&log, inst, viewConfigurationType); 137 + OXR_VERIFY_VIEW_CONFIG_TYPE_SUPPORTED(&log, sys, viewConfigurationType); 138 139 return oxr_system_enumerate_blend_modes(&log, sys, viewConfigurationType, environmentBlendModeCapacityInput, 140 environmentBlendModeCountOutput, environmentBlendModes); ··· 153 OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst, "xrGetViewConfigurationProperties"); 154 OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, configurationProperties, XR_TYPE_VIEW_CONFIGURATION_PROPERTIES); 155 OXR_VERIFY_SYSTEM_AND_GET(&log, inst, systemId, sys); 156 + OXR_VERIFY_VIEW_CONFIG_TYPE(&log, inst, viewConfigurationType); 157 + OXR_VERIFY_VIEW_CONFIG_TYPE_SUPPORTED(&log, sys, viewConfigurationType); 158 159 return oxr_system_get_view_conf_properties(&log, sys, viewConfigurationType, configurationProperties); 160 } ··· 173 struct oxr_logger log; 174 OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst, "xrEnumerateViewConfigurationViews"); 175 OXR_VERIFY_SYSTEM_AND_GET(&log, inst, systemId, sys); 176 + OXR_VERIFY_VIEW_CONFIG_TYPE(&log, inst, viewConfigurationType); 177 + OXR_VERIFY_VIEW_CONFIG_TYPE_SUPPORTED(&log, sys, viewConfigurationType); 178 179 for (uint32_t i = 0; i < viewCapacityInput; i++) { 180 OXR_VERIFY_ARG_ARRAY_ELEMENT_TYPE(&log, views, i, XR_TYPE_VIEW_CONFIGURATION_VIEW); ··· 339 340 OXR_VERIFY_SYSTEM_AND_GET(&log, inst, getInfo->systemId, sys); 341 OXR_VERIFY_ARG_NOT_NULL(&log, vkPhysicalDevice); 342 + OXR_VERIFY_ARG_NOT_NULL(&log, sys->vk_get_instance_proc_addr); 343 OXR_VERIFY_XSYSC(&log, sys); 344 345 + return oxr_vk_get_physical_device(&log, inst, sys, getInfo->vulkanInstance, sys->vk_get_instance_proc_addr, 346 vkPhysicalDevice); 347 } 348 ··· 405 406 // createInfo->vulkanAllocator can be NULL 407 408 + sys->vk_get_instance_proc_addr = createInfo->pfnGetInstanceProcAddr; 409 + 410 if (createInfo->vulkanCreateInfo->sType != VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO) { 411 return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE, 412 "createInfo->vulkanCreateInfo->sType must be " ··· 442 OXR_VERIFY_ARG_NOT_NULL(&log, sys->suggested_vulkan_physical_device); 443 OXR_VERIFY_ARG_NOT_NULL(&log, sys->vulkan_enable2_instance); 444 OXR_VERIFY_XSYSC(&log, sys); 445 + 446 + sys->vk_get_instance_proc_addr = createInfo->pfnGetInstanceProcAddr; 447 448 if (sys->suggested_vulkan_physical_device != createInfo->vulkanPhysicalDevice) { 449 return oxr_error(&log, XR_ERROR_HANDLE_INVALID,
+56 -11
src/xrt/state_trackers/oxr/oxr_api_verify.h
··· 1 // Copyright 2018-2024, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 22 struct oxr_action_set; 23 struct oxr_extension_status; 24 struct oxr_instance; 25 struct oxr_logger; 26 struct oxr_subaction_paths; 27 ··· 95 #define OXR_VERIFY_FUTURE_AND_INIT_LOG(log, thing, new_thing, name) \ 96 OXR_VERIFY_AND_SET_AND_INIT(log, thing, new_thing, oxr_future_ext, FUTURE, name, new_thing->inst); \ 97 OXR_VERIFY_FUTURE_VALID(log, new_thing) 98 // clang-format on 99 100 #define OXR_VERIFY_INSTANCE_NOT_NULL(log, arg, new_arg) OXR_VERIFY_SET(log, arg, new_arg, oxr_instance, INSTANCE); ··· 200 } \ 201 } while (false) 202 203 #define OXR_VERIFY_SUBACTION_PATHS(log, count, paths) \ 204 do { \ 205 if (count > 0 && paths == NULL) { \ ··· 232 \ 233 if (!math_vec3_validate((struct xrt_vec3 *)&p.position)) { \ 234 return oxr_error(log, XR_ERROR_POSE_INVALID, "(" #p ".position) is not valid"); \ 235 } \ 236 } while (false) 237 ··· 243 } \ 244 } while (false) 245 246 #define OXR_VERIFY_VIEW_INDEX(log, index) \ 247 do { \ 248 if (index > 2) { \ ··· 308 } \ 309 } while (false) 310 311 - #define OXR_VERIFY_FORM_FACTOR(log, form_factor) \ 312 - do { \ 313 - XrFormFactor _form_factor = (form_factor); \ 314 - if (_form_factor != XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY && \ 315 - _form_factor != XR_FORM_FACTOR_HANDHELD_DISPLAY) { \ 316 - \ 317 - return oxr_error(log, XR_ERROR_FORM_FACTOR_UNSUPPORTED, \ 318 - "(" #form_factor " == 0x%08x) is not a valid form factor", _form_factor); \ 319 - } \ 320 - } while (false) 321 - 322 #define OXR_VERIFY_HAND_TRACKING_DATA_SOURCE_OR_NULL(log, data_source_info) \ 323 do { \ 324 if (data_source_info != NULL) { \ ··· 333 do { \ 334 if (OXR_FT->xft == NULL) { \ 335 return oxr_error(LOG, XR_ERROR_FUTURE_INVALID_EXT, "future is not valid"); \ 336 } \ 337 } while (false) 338 ··· 408 struct oxr_instance *inst, 409 XrViewConfigurationType view_conf, 410 const char *view_conf_name); 411 412 XrResult 413 oxr_verify_XrSessionCreateInfo(struct oxr_logger * /*log*/,
··· 1 // Copyright 2018-2024, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 23 struct oxr_action_set; 24 struct oxr_extension_status; 25 struct oxr_instance; 26 + struct oxr_system; 27 struct oxr_logger; 28 struct oxr_subaction_paths; 29 ··· 97 #define OXR_VERIFY_FUTURE_AND_INIT_LOG(log, thing, new_thing, name) \ 98 OXR_VERIFY_AND_SET_AND_INIT(log, thing, new_thing, oxr_future_ext, FUTURE, name, new_thing->inst); \ 99 OXR_VERIFY_FUTURE_VALID(log, new_thing) 100 + #define OXR_VERIFY_FACE_TRACKER_ANDROID_AND_INIT_LOG(log, thing, new_thing, name) \ 101 + OXR_VERIFY_AND_SET_AND_INIT(log, thing, new_thing, oxr_face_tracker_android, FTRACKER, name, new_thing->sess->sys->inst) 102 // clang-format on 103 104 #define OXR_VERIFY_INSTANCE_NOT_NULL(log, arg, new_arg) OXR_VERIFY_SET(log, arg, new_arg, oxr_instance, INSTANCE); ··· 204 } \ 205 } while (false) 206 207 + #define OXR_VERIFY_TWO_CALL_ARRAY(log, inputCapacity, countOutput, array) \ 208 + do { \ 209 + OXR_VERIFY_ARG_NOT_NULL(log, countOutput); \ 210 + if (inputCapacity > 0) { \ 211 + OXR_VERIFY_ARG_NOT_NULL(log, array); \ 212 + } \ 213 + } while (false) 214 + 215 + #define OXR_VERIFY_TWO_CALL_ARRAY_AND_TYPE(log, inputCapacity, countOutput, array, type_enum) \ 216 + do { \ 217 + OXR_VERIFY_ARG_NOT_NULL(log, countOutput); \ 218 + if (inputCapacity > 0) { \ 219 + OXR_VERIFY_ARG_NOT_NULL(log, array); \ 220 + for (uint32_t i = 0; i < inputCapacity; ++i) { \ 221 + OXR_VERIFY_ARG_ARRAY_ELEMENT_TYPE(log, array, i, type_enum); \ 222 + } \ 223 + } \ 224 + } while (false) 225 + 226 #define OXR_VERIFY_SUBACTION_PATHS(log, count, paths) \ 227 do { \ 228 if (count > 0 && paths == NULL) { \ ··· 255 \ 256 if (!math_vec3_validate((struct xrt_vec3 *)&p.position)) { \ 257 return oxr_error(log, XR_ERROR_POSE_INVALID, "(" #p ".position) is not valid"); \ 258 + } \ 259 + } while (false) 260 + 261 + #define OXR_VERIFY_FORM_FACTOR(log, form_factor) \ 262 + do { \ 263 + XrFormFactor _form_factor = (form_factor); \ 264 + if (_form_factor != XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY && \ 265 + _form_factor != XR_FORM_FACTOR_HANDHELD_DISPLAY) { \ 266 + \ 267 + return oxr_error(log, XR_ERROR_FORM_FACTOR_UNSUPPORTED, \ 268 + "(" #form_factor " == 0x%08x) is not a valid form factor", _form_factor); \ 269 } \ 270 } while (false) 271 ··· 277 } \ 278 } while (false) 279 280 + #define OXR_VERIFY_VIEW_CONFIG_TYPE_SUPPORTED(log, sys, view_conf) \ 281 + do { \ 282 + XrResult verify_ret = oxr_verify_view_config_type_supported(log, sys, view_conf, #view_conf); \ 283 + if (verify_ret != XR_SUCCESS) { \ 284 + return verify_ret; \ 285 + } \ 286 + } while (false) 287 + 288 #define OXR_VERIFY_VIEW_INDEX(log, index) \ 289 do { \ 290 if (index > 2) { \ ··· 350 } \ 351 } while (false) 352 353 #define OXR_VERIFY_HAND_TRACKING_DATA_SOURCE_OR_NULL(log, data_source_info) \ 354 do { \ 355 if (data_source_info != NULL) { \ ··· 364 do { \ 365 if (OXR_FT->xft == NULL) { \ 366 return oxr_error(LOG, XR_ERROR_FUTURE_INVALID_EXT, "future is not valid"); \ 367 + } \ 368 + } while (false) 369 + 370 + #define OXR_VERIFY_ARG_TIME_NOT_ZERO(log, xr_time) \ 371 + do { \ 372 + if (xr_time <= (XrTime)0) { \ 373 + return oxr_error(log, XR_ERROR_TIME_INVALID, "(time == %" PRIi64 ") is not a valid time.", \ 374 + xr_time); \ 375 } \ 376 } while (false) 377 ··· 447 struct oxr_instance *inst, 448 XrViewConfigurationType view_conf, 449 const char *view_conf_name); 450 + 451 + XrResult 452 + oxr_verify_view_config_type_supported(struct oxr_logger *log, 453 + struct oxr_system *sys, 454 + XrViewConfigurationType view_conf, 455 + const char *view_conf_name); 456 457 XrResult 458 oxr_verify_XrSessionCreateInfo(struct oxr_logger * /*log*/,
+23 -2
src/xrt/state_trackers/oxr/oxr_binding.c
··· 1 // Copyright 2018-2020,2023 Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 462 if (name == XRT_DEVICE_INVALID) { 463 return false; 464 } 465 /* 466 * Map xrt_device_name to an interaction profile XrPath. 467 - * Set *out_p to an oxr_interaction_profile if bindings for that interaction profile XrPath have been suggested. 468 */ 469 for (uint32_t i = 0; i < ARRAY_SIZE(profile_templates); i++) { 470 if (name == profile_templates[i].name) { 471 - if (interaction_profile_find_in_session(log, sess, profile_templates[i].path_cache, out_p)) { 472 return true; 473 } 474 }
··· 1 // Copyright 2018-2020,2023 Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 463 if (name == XRT_DEVICE_INVALID) { 464 return false; 465 } 466 + 467 /* 468 * Map xrt_device_name to an interaction profile XrPath. 469 + * 470 + * There might be multiple OpenXR interaction profiles that maps to a 471 + * a single @ref xrt_device_name, so we can't just grab the first one 472 + * that we find and assume that wasn't bound then there isn't an OpenXR 473 + * interaction profile bound for that device name. So we will need to 474 + * keep looping until we find an OpenXR interaction profile, or we run 475 + * out of interaction profiles that the app has suggested. 476 + * 477 + * For XRT_DEVICE_HAND_INTERACTION both the OpenXR hand-interaction 478 + * profiles maps to it, but the app might only provide binding for one. 479 + * 480 + * Set *out_p to an oxr_interaction_profile if bindings for that 481 + * interaction profile XrPath have been suggested. 482 */ 483 for (uint32_t i = 0; i < ARRAY_SIZE(profile_templates); i++) { 484 if (name == profile_templates[i].name) { 485 + interaction_profile_find_in_session(log, sess, profile_templates[i].path_cache, out_p); 486 + 487 + /* 488 + * Keep looping even if the current matching OpenXR 489 + * interaction profile wasn't suggested by the app. 490 + * See comment above. 491 + */ 492 + if (*out_p != NULL) { 493 return true; 494 } 495 }
+77
src/xrt/state_trackers/oxr/oxr_conversions.h
··· 16 #include "xrt/xrt_vulkan_includes.h" 17 #include "xrt/xrt_openxr_includes.h" 18 19 20 /* 21 * ··· 289 default: assert(false); return XR_HAND_TRACKING_DATA_SOURCE_MAX_ENUM_EXT; 290 } 291 }
··· 16 #include "xrt/xrt_vulkan_includes.h" 17 #include "xrt/xrt_openxr_includes.h" 18 19 + #include "oxr_defines.h" 20 + 21 22 /* 23 * ··· 291 default: assert(false); return XR_HAND_TRACKING_DATA_SOURCE_MAX_ENUM_EXT; 292 } 293 } 294 + 295 + 296 + /* 297 + * 298 + * Basic types 299 + * 300 + */ 301 + 302 + static inline XrExtent2Di 303 + xrt_size_to_xr(const struct xrt_size *x) 304 + { 305 + return (XrExtent2Di){ 306 + .width = x->w, 307 + .height = x->h, 308 + }; 309 + } 310 + 311 + static inline XrVector2f 312 + xrt_vec2_to_xr(const struct xrt_vec2 *v) 313 + { 314 + return (XrVector2f){ 315 + .x = v->x, 316 + .y = v->y, 317 + }; 318 + } 319 + 320 + static inline XrVector3f 321 + xrt_vec3_to_xr(const struct xrt_vec3 *v) 322 + { 323 + return (XrVector3f){ 324 + .x = v->x, 325 + .y = v->y, 326 + .z = v->z, 327 + }; 328 + } 329 + 330 + static inline XrQuaternionf 331 + xrt_quat_to_xr(const struct xrt_quat *q) 332 + { 333 + return (XrQuaternionf){ 334 + .x = q->x, 335 + .y = q->y, 336 + .z = q->z, 337 + .w = q->w, 338 + }; 339 + } 340 + 341 + static inline XrPosef 342 + xrt_pose_to_xr(const struct xrt_pose *q) 343 + { 344 + return (XrPosef){ 345 + .orientation = xrt_quat_to_xr(&q->orientation), 346 + .position = xrt_vec3_to_xr(&q->position), 347 + }; 348 + } 349 + 350 + 351 + /* 352 + * 353 + * View things 354 + * 355 + */ 356 + 357 + static inline XrViewConfigurationType 358 + xrt_view_type_to_xr(enum xrt_view_type view_type) 359 + { 360 + switch (view_type) { 361 + case XRT_VIEW_TYPE_MONO: return XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO; 362 + case XRT_VIEW_TYPE_STEREO: return XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO; 363 + } 364 + 365 + // Used as default, to get warnings. 366 + assert(false && "Invalid view type"); 367 + return XR_VIEW_CONFIGURATION_TYPE_MAX_ENUM; 368 + }
+18 -18
src/xrt/state_trackers/oxr/oxr_defines.h
··· 15 16 // For corruption and layer checking. 17 // clang-format off 18 - #define OXR_XR_DEBUG_INSTANCE (*(uint64_t *)"oxrinst\0") 19 - #define OXR_XR_DEBUG_SESSION (*(uint64_t *)"oxrsess\0") 20 - #define OXR_XR_DEBUG_SPACE (*(uint64_t *)"oxrspac\0") 21 - #define OXR_XR_DEBUG_PATH (*(uint64_t *)"oxrpath\0") 22 - #define OXR_XR_DEBUG_ACTION (*(uint64_t *)"oxracti\0") 23 - #define OXR_XR_DEBUG_SWAPCHAIN (*(uint64_t *)"oxrswap\0") 24 - #define OXR_XR_DEBUG_ACTIONSET (*(uint64_t *)"oxraset\0") 25 - #define OXR_XR_DEBUG_MESSENGER (*(uint64_t *)"oxrmess\0") 26 - #define OXR_XR_DEBUG_SOURCESET (*(uint64_t *)"oxrsrcs\0") 27 - #define OXR_XR_DEBUG_SOURCE (*(uint64_t *)"oxrsrc_\0") 28 - #define OXR_XR_DEBUG_HTRACKER (*(uint64_t *)"oxrhtra\0") 29 - #define OXR_XR_DEBUG_PASSTHROUGH (*(uint64_t *)"oxrpass\0") 30 - #define OXR_XR_DEBUG_PASSTHROUGH_LAYER (*(uint64_t *)"oxrptla\0") 31 - #define OXR_XR_DEBUG_FTRACKER (*(uint64_t *)"oxrftra\0") 32 // body tracker 33 - #define OXR_XR_DEBUG_BTRACKER (*(uint64_t *)"oxrbtra\0") 34 - #define OXR_XR_DEBUG_XDEVLIST (*(uint64_t *)"oxrxdli\0") 35 // plane detection 36 - #define OXR_XR_DEBUG_PLANEDET (*(uint64_t *)"oxrplan\0") 37 // futures 38 - #define OXR_XR_DEBUG_FUTURE (*(uint64_t *)"oxrfutr\0") 39 // clang-format on 40 41 /*!
··· 15 16 // For corruption and layer checking. 17 // clang-format off 18 + #define OXR_XR_DEBUG_INSTANCE (*(uint64_t *)"oxrinst\0") 19 + #define OXR_XR_DEBUG_SESSION (*(uint64_t *)"oxrsess\0") 20 + #define OXR_XR_DEBUG_SPACE (*(uint64_t *)"oxrspac\0") 21 + #define OXR_XR_DEBUG_PATH (*(uint64_t *)"oxrpath\0") 22 + #define OXR_XR_DEBUG_ACTION (*(uint64_t *)"oxracti\0") 23 + #define OXR_XR_DEBUG_SWAPCHAIN (*(uint64_t *)"oxrswap\0") 24 + #define OXR_XR_DEBUG_ACTIONSET (*(uint64_t *)"oxraset\0") 25 + #define OXR_XR_DEBUG_MESSENGER (*(uint64_t *)"oxrmess\0") 26 + #define OXR_XR_DEBUG_SOURCESET (*(uint64_t *)"oxrsrcs\0") 27 + #define OXR_XR_DEBUG_SOURCE (*(uint64_t *)"oxrsrc_\0") 28 + #define OXR_XR_DEBUG_HTRACKER (*(uint64_t *)"oxrhtra\0") 29 + #define OXR_XR_DEBUG_PASSTHROUGH (*(uint64_t *)"oxrpass\0") 30 + #define OXR_XR_DEBUG_PASSTHROUGH_LAYER (*(uint64_t *)"oxrptla\0") 31 + #define OXR_XR_DEBUG_FTRACKER (*(uint64_t *)"oxrftra\0") 32 // body tracker 33 + #define OXR_XR_DEBUG_BTRACKER (*(uint64_t *)"oxrbtra\0") 34 + #define OXR_XR_DEBUG_XDEVLIST (*(uint64_t *)"oxrxdli\0") 35 // plane detection 36 + #define OXR_XR_DEBUG_PLANEDET (*(uint64_t *)"oxrplan\0") 37 // futures 38 + #define OXR_XR_DEBUG_FUTURE (*(uint64_t *)"oxrfutr\0") 39 // clang-format on 40 41 /*!
+24 -12
src/xrt/state_trackers/oxr/oxr_extension_support.h
··· 475 476 477 /* 478 * XR_BD_controller_interaction 479 */ 480 #if defined(XR_BD_controller_interaction) && defined(XRT_FEATURE_OPENXR_INTERACTION_BYTEDANCE) ··· 797 798 799 /* 800 - * XR_MNDX_oculus_remote 801 - */ 802 - #if defined(XR_MNDX_oculus_remote) && defined(XRT_FEATURE_OPENXR_INTERACTION_MNDX) 803 - #define OXR_HAVE_MNDX_oculus_remote 804 - #define OXR_EXTENSION_SUPPORT_MNDX_oculus_remote(_) _(MNDX_oculus_remote, MNDX_OCULUS_REMOTE) 805 - #else 806 - #define OXR_EXTENSION_SUPPORT_MNDX_oculus_remote(_) 807 - #endif 808 - 809 - 810 - /* 811 * XR_MNDX_egl_enable 812 */ 813 #if defined(XR_MNDX_egl_enable) && defined(XR_USE_PLATFORM_EGL) ··· 837 #define OXR_EXTENSION_SUPPORT_MNDX_hydra(_) _(MNDX_hydra, MNDX_HYDRA) 838 #else 839 #define OXR_EXTENSION_SUPPORT_MNDX_hydra(_) 840 #endif 841 842 ··· 936 OXR_EXTENSION_SUPPORT_EXT_plane_detection(_) \ 937 OXR_EXTENSION_SUPPORT_EXT_samsung_odyssey_controller(_) \ 938 OXR_EXTENSION_SUPPORT_EXT_user_presence(_) \ 939 OXR_EXTENSION_SUPPORT_BD_controller_interaction(_) \ 940 OXR_EXTENSION_SUPPORT_FB_body_tracking(_) \ 941 OXR_EXTENSION_SUPPORT_FB_composition_layer_alpha_blend(_) \ ··· 964 OXR_EXTENSION_SUPPORT_HTCX_vive_tracker_interaction(_) \ 965 OXR_EXTENSION_SUPPORT_MNDX_ball_on_a_stick_controller(_) \ 966 OXR_EXTENSION_SUPPORT_MNDX_blubur_s1(_) \ 967 - OXR_EXTENSION_SUPPORT_MNDX_oculus_remote(_) \ 968 OXR_EXTENSION_SUPPORT_MNDX_egl_enable(_) \ 969 OXR_EXTENSION_SUPPORT_MNDX_force_feedback_curl(_) \ 970 OXR_EXTENSION_SUPPORT_MNDX_hydra(_) \ 971 OXR_EXTENSION_SUPPORT_MNDX_psvr2_interaction(_) \ 972 OXR_EXTENSION_SUPPORT_MNDX_system_buttons(_) \ 973 OXR_EXTENSION_SUPPORT_MNDX_xdev_space(_)
··· 475 476 477 /* 478 + * XR_ANDROID_face_tracking 479 + */ 480 + #if defined(XR_ANDROID_face_tracking) && defined(XRT_FEATURE_OPENXR_FACE_TRACKING_ANDROID) 481 + #define OXR_HAVE_ANDROID_face_tracking 482 + #define OXR_EXTENSION_SUPPORT_ANDROID_face_tracking(_) _(ANDROID_face_tracking, ANDROID_FACE_TRACKING) 483 + #else 484 + #define OXR_EXTENSION_SUPPORT_ANDROID_face_tracking(_) 485 + #endif 486 + 487 + 488 + /* 489 * XR_BD_controller_interaction 490 */ 491 #if defined(XR_BD_controller_interaction) && defined(XRT_FEATURE_OPENXR_INTERACTION_BYTEDANCE) ··· 808 809 810 /* 811 * XR_MNDX_egl_enable 812 */ 813 #if defined(XR_MNDX_egl_enable) && defined(XR_USE_PLATFORM_EGL) ··· 837 #define OXR_EXTENSION_SUPPORT_MNDX_hydra(_) _(MNDX_hydra, MNDX_HYDRA) 838 #else 839 #define OXR_EXTENSION_SUPPORT_MNDX_hydra(_) 840 + #endif 841 + 842 + 843 + /* 844 + * XR_MNDX_oculus_remote 845 + */ 846 + #if defined(XR_MNDX_oculus_remote) && defined(XRT_FEATURE_OPENXR_INTERACTION_MNDX) 847 + #define OXR_HAVE_MNDX_oculus_remote 848 + #define OXR_EXTENSION_SUPPORT_MNDX_oculus_remote(_) _(MNDX_oculus_remote, MNDX_OCULUS_REMOTE) 849 + #else 850 + #define OXR_EXTENSION_SUPPORT_MNDX_oculus_remote(_) 851 #endif 852 853 ··· 947 OXR_EXTENSION_SUPPORT_EXT_plane_detection(_) \ 948 OXR_EXTENSION_SUPPORT_EXT_samsung_odyssey_controller(_) \ 949 OXR_EXTENSION_SUPPORT_EXT_user_presence(_) \ 950 + OXR_EXTENSION_SUPPORT_ANDROID_face_tracking(_) \ 951 OXR_EXTENSION_SUPPORT_BD_controller_interaction(_) \ 952 OXR_EXTENSION_SUPPORT_FB_body_tracking(_) \ 953 OXR_EXTENSION_SUPPORT_FB_composition_layer_alpha_blend(_) \ ··· 976 OXR_EXTENSION_SUPPORT_HTCX_vive_tracker_interaction(_) \ 977 OXR_EXTENSION_SUPPORT_MNDX_ball_on_a_stick_controller(_) \ 978 OXR_EXTENSION_SUPPORT_MNDX_blubur_s1(_) \ 979 OXR_EXTENSION_SUPPORT_MNDX_egl_enable(_) \ 980 OXR_EXTENSION_SUPPORT_MNDX_force_feedback_curl(_) \ 981 OXR_EXTENSION_SUPPORT_MNDX_hydra(_) \ 982 + OXR_EXTENSION_SUPPORT_MNDX_oculus_remote(_) \ 983 OXR_EXTENSION_SUPPORT_MNDX_psvr2_interaction(_) \ 984 OXR_EXTENSION_SUPPORT_MNDX_system_buttons(_) \ 985 OXR_EXTENSION_SUPPORT_MNDX_xdev_space(_)
-119
src/xrt/state_trackers/oxr/oxr_face_tracking.c
··· 1 - // Copyright 2024, Collabora, Ltd. 2 - // SPDX-License-Identifier: BSL-1.0 3 - /*! 4 - * @file 5 - * @brief face tracking related API entrypoint functions. 6 - * @author Korcan Hussein <korcan.hussein@collabora.com> 7 - * @ingroup oxr_main 8 - */ 9 - 10 - #include <stdio.h> 11 - #include <stdlib.h> 12 - #include <string.h> 13 - 14 - #include "oxr_objects.h" 15 - #include "oxr_logger.h" 16 - #include "oxr_handle.h" 17 - 18 - static enum xrt_facial_tracking_type_htc 19 - oxr_to_xrt_facial_tracking_type_htc(enum XrFacialTrackingTypeHTC ft_type) 20 - { 21 - return (enum xrt_facial_tracking_type_htc)ft_type; 22 - } 23 - 24 - static enum xrt_input_name 25 - oxr_facial_tracking_type_htc_to_input_name(enum xrt_facial_tracking_type_htc ft_type) 26 - { 27 - switch (ft_type) { 28 - case XRT_FACIAL_TRACKING_TYPE_LIP_DEFAULT_HTC: return XRT_INPUT_HTC_LIP_FACE_TRACKING; 29 - case XRT_FACIAL_TRACKING_TYPE_EYE_DEFAULT_HTC: 30 - default: return XRT_INPUT_HTC_EYE_FACE_TRACKING; 31 - } 32 - } 33 - 34 - static XrResult 35 - oxr_facial_tracker_htc_destroy_cb(struct oxr_logger *log, struct oxr_handle_base *hb) 36 - { 37 - struct oxr_facial_tracker_htc *face_tracker_htc = (struct oxr_facial_tracker_htc *)hb; 38 - free(face_tracker_htc); 39 - return XR_SUCCESS; 40 - } 41 - 42 - XrResult 43 - oxr_facial_tracker_htc_create(struct oxr_logger *log, 44 - struct oxr_session *sess, 45 - const XrFacialTrackerCreateInfoHTC *createInfo, 46 - struct oxr_facial_tracker_htc **out_face_tracker_htc) 47 - { 48 - bool supports_eye = false; 49 - bool supports_lip = false; 50 - oxr_system_get_face_tracking_htc_support(log, sess->sys->inst, &supports_eye, &supports_lip); 51 - 52 - const enum xrt_facial_tracking_type_htc facial_tracking_type = 53 - oxr_to_xrt_facial_tracking_type_htc(createInfo->facialTrackingType); 54 - 55 - if (facial_tracking_type == XRT_FACIAL_TRACKING_TYPE_EYE_DEFAULT_HTC && !supports_eye) { 56 - return oxr_error(log, XR_ERROR_FEATURE_UNSUPPORTED, "System does not support HTC eye facial tracking"); 57 - } 58 - if (facial_tracking_type == XRT_FACIAL_TRACKING_TYPE_LIP_DEFAULT_HTC && !supports_lip) { 59 - return oxr_error(log, XR_ERROR_FEATURE_UNSUPPORTED, "System does not support HTC lip facial tracking"); 60 - } 61 - 62 - struct xrt_device *xdev = GET_XDEV_BY_ROLE(sess->sys, face); 63 - if (xdev == NULL) { 64 - return oxr_error(log, XR_ERROR_FEATURE_UNSUPPORTED, "No device found for face tracking role"); 65 - } 66 - 67 - if (!xdev->supported.face_tracking) { 68 - return oxr_error(log, XR_ERROR_FEATURE_UNSUPPORTED, "Device does not support HTC facial tracking"); 69 - } 70 - 71 - struct oxr_facial_tracker_htc *face_tracker_htc = NULL; 72 - OXR_ALLOCATE_HANDLE_OR_RETURN(log, face_tracker_htc, OXR_XR_DEBUG_FTRACKER, oxr_facial_tracker_htc_destroy_cb, 73 - &sess->handle); 74 - 75 - face_tracker_htc->sess = sess; 76 - face_tracker_htc->xdev = xdev; 77 - face_tracker_htc->facial_tracking_type = facial_tracking_type; 78 - 79 - *out_face_tracker_htc = face_tracker_htc; 80 - 81 - return XR_SUCCESS; 82 - } 83 - 84 - XrResult 85 - oxr_get_facial_expressions_htc(struct oxr_logger *log, 86 - struct oxr_facial_tracker_htc *facial_tracker_htc, 87 - XrFacialExpressionsHTC *facialExpressions) 88 - { 89 - const bool is_eye_tracking = 90 - facial_tracker_htc->facial_tracking_type == XRT_FACIAL_TRACKING_TYPE_EYE_DEFAULT_HTC; 91 - const size_t expression_count = 92 - is_eye_tracking ? XRT_FACIAL_EXPRESSION_EYE_COUNT_HTC : XRT_FACIAL_EXPRESSION_LIP_COUNT_HTC; 93 - 94 - struct xrt_facial_expression_set facial_expression_set_result = {0}; 95 - float *expression_weights = is_eye_tracking 96 - ? facial_expression_set_result.eye_expression_set_htc.expression_weights 97 - : facial_expression_set_result.lip_expression_set_htc.expression_weights; 98 - memset(expression_weights, 0, sizeof(float) * expression_count); 99 - 100 - const enum xrt_input_name ft_input_name = 101 - oxr_facial_tracking_type_htc_to_input_name(facial_tracker_htc->facial_tracking_type); 102 - 103 - int64_t at_timestamp_ns = os_monotonic_get_ns(); 104 - 105 - xrt_device_get_face_tracking(facial_tracker_htc->xdev, ft_input_name, at_timestamp_ns, 106 - &facial_expression_set_result); 107 - 108 - facialExpressions->isActive = facial_expression_set_result.base_expression_set_htc.is_active; 109 - if (facialExpressions->isActive == XR_FALSE) 110 - return XR_SUCCESS; 111 - 112 - const struct oxr_instance *inst = facial_tracker_htc->sess->sys->inst; 113 - facialExpressions->sampleTime = time_state_monotonic_to_ts_ns( 114 - inst->timekeeping, facial_expression_set_result.base_expression_set_htc.sample_time_ns); 115 - 116 - memcpy(facialExpressions->expressionWeightings, expression_weights, sizeof(float) * expression_count); 117 - 118 - return XR_SUCCESS; 119 - }
···
+135
src/xrt/state_trackers/oxr/oxr_face_tracking_android.c
···
··· 1 + // Copyright 2025, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief Android face tracking related API entrypoint functions. 6 + * @author Korcan Hussein <korcan.hussein@collabora.com> 7 + * @ingroup oxr_main 8 + */ 9 + 10 + #include <stdio.h> 11 + #include <stdlib.h> 12 + #include <string.h> 13 + 14 + #include "oxr_objects.h" 15 + #include "oxr_logger.h" 16 + #include "oxr_handle.h" 17 + #include "oxr_xret.h" 18 + #include "oxr_two_call.h" 19 + 20 + static XrResult 21 + oxr_face_tracker_android_destroy_cb(struct oxr_logger *log, struct oxr_handle_base *hb) 22 + { 23 + struct oxr_face_tracker_android *face_tracker_android = (struct oxr_face_tracker_android *)hb; 24 + free(face_tracker_android); 25 + return XR_SUCCESS; 26 + } 27 + 28 + XrResult 29 + oxr_face_tracker_android_create(struct oxr_logger *log, 30 + struct oxr_session *sess, 31 + const XrFaceTrackerCreateInfoANDROID *createInfo, 32 + XrFaceTrackerANDROID *faceTracker) 33 + { 34 + bool supported = false; 35 + oxr_system_get_face_tracking_android_support(log, sess->sys->inst, &supported); 36 + if (!supported) { 37 + return oxr_error(log, XR_ERROR_FEATURE_UNSUPPORTED, "System does not support Android face tracking"); 38 + } 39 + 40 + struct xrt_device *xdev = GET_XDEV_BY_ROLE(sess->sys, face); 41 + if (xdev == NULL) { 42 + return oxr_error(log, XR_ERROR_FEATURE_UNSUPPORTED, "No device found for face tracking role"); 43 + } 44 + 45 + if (!xdev->supported.face_tracking) { 46 + return oxr_error(log, XR_ERROR_FEATURE_UNSUPPORTED, "Device does not support HTC facial tracking"); 47 + } 48 + 49 + struct oxr_face_tracker_android *face_tracker_android = NULL; 50 + OXR_ALLOCATE_HANDLE_OR_RETURN(log, face_tracker_android, OXR_XR_DEBUG_FTRACKER, 51 + oxr_face_tracker_android_destroy_cb, &sess->handle); 52 + 53 + face_tracker_android->sess = sess; 54 + face_tracker_android->xdev = xdev; 55 + 56 + *faceTracker = oxr_face_tracker_android_to_openxr(face_tracker_android); 57 + return oxr_session_success_result(sess); 58 + } 59 + 60 + XrResult 61 + oxr_get_face_state_android(struct oxr_logger *log, 62 + struct oxr_face_tracker_android *facial_tracker_android, 63 + const XrFaceStateGetInfoANDROID *getInfo, 64 + XrFaceStateANDROID *faceStateOutput) 65 + { 66 + /*! 67 + * OXR_TWO_CALL_CHECK_* macro usage here is not technically necessary because validation 68 + * is handled in the API layer before this function is called, but we still reuse them here 69 + * for declarative purposes of handling two-call patterns of setting capacities on the first call. 70 + */ 71 + 72 + /*! 73 + * Use the goto macro variant because a two-call check needs to happen with region confidences 74 + * as well; we can't early exit for only one of them. 75 + */ 76 + XrResult xres = XR_SUCCESS; 77 + OXR_TWO_CALL_CHECK_GOTO(log, faceStateOutput->parametersCapacityInput, 78 + (&faceStateOutput->parametersCountOutput), XRT_FACE_PARAMETER_COUNT_ANDROID, xres, 79 + region_confidences_check); 80 + region_confidences_check: 81 + if (xres != XR_SUCCESS) { 82 + return xres; 83 + } 84 + 85 + OXR_TWO_CALL_CHECK_ONLY(log, faceStateOutput->regionConfidencesCapacityInput, 86 + (&faceStateOutput->regionConfidencesCountOutput), 87 + XRT_FACE_REGION_CONFIDENCE_COUNT_ANDROID, xres); 88 + 89 + const struct oxr_instance *inst = facial_tracker_android->sess->sys->inst; 90 + const int64_t at_timestamp_ns = time_state_ts_to_monotonic_ns(inst->timekeeping, getInfo->time); 91 + 92 + struct xrt_facial_expression_set facial_expression_set_result = {0}; 93 + const xrt_result_t xret = 94 + xrt_device_get_face_tracking(facial_tracker_android->xdev, XRT_INPUT_ANDROID_FACE_TRACKING, at_timestamp_ns, 95 + &facial_expression_set_result); 96 + OXR_CHECK_XRET(log, facial_tracker_android->sess, xret, "oxr_get_face_state_android"); 97 + 98 + const struct xrt_facial_expression_set_android *face_expression_set_android = 99 + &facial_expression_set_result.face_expression_set_android; 100 + 101 + faceStateOutput->isValid = face_expression_set_android->is_valid; 102 + if (faceStateOutput->isValid == XR_FALSE) { 103 + return XR_SUCCESS; 104 + } 105 + 106 + faceStateOutput->sampleTime = 107 + time_state_monotonic_to_ts_ns(inst->timekeeping, face_expression_set_android->sample_time_ns); 108 + 109 + if (faceStateOutput->parametersCapacityInput) { 110 + memcpy(faceStateOutput->parameters, face_expression_set_android->parameters, 111 + sizeof(float) * faceStateOutput->parametersCapacityInput); 112 + } 113 + 114 + if (faceStateOutput->regionConfidencesCapacityInput) { 115 + memcpy(faceStateOutput->regionConfidences, face_expression_set_android->region_confidences, 116 + sizeof(float) * faceStateOutput->regionConfidencesCapacityInput); 117 + } 118 + 119 + return oxr_session_success_result(facial_tracker_android->sess); 120 + } 121 + 122 + XrResult 123 + oxr_get_face_calibration_state_android(struct oxr_logger *log, 124 + struct oxr_face_tracker_android *facial_tracker_android, 125 + XrBool32 *faceIsCalibratedOutput) 126 + { 127 + bool face_is_calibrated = false; 128 + const xrt_result_t xret = 129 + xrt_device_get_face_calibration_state_android(facial_tracker_android->xdev, &face_is_calibrated); 130 + OXR_CHECK_XRET(log, facial_tracker_android->sess, xret, "oxr_get_face_calibration_state_android"); 131 + 132 + *faceIsCalibratedOutput = face_is_calibrated; 133 + 134 + return oxr_session_success_result(facial_tracker_android->sess); 135 + }
+119
src/xrt/state_trackers/oxr/oxr_face_tracking_htc.c
···
··· 1 + // Copyright 2024, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief face tracking related API entrypoint functions. 6 + * @author Korcan Hussein <korcan.hussein@collabora.com> 7 + * @ingroup oxr_main 8 + */ 9 + 10 + #include <stdio.h> 11 + #include <stdlib.h> 12 + #include <string.h> 13 + 14 + #include "oxr_objects.h" 15 + #include "oxr_logger.h" 16 + #include "oxr_handle.h" 17 + 18 + static enum xrt_facial_tracking_type_htc 19 + oxr_to_xrt_facial_tracking_type_htc(enum XrFacialTrackingTypeHTC ft_type) 20 + { 21 + return (enum xrt_facial_tracking_type_htc)ft_type; 22 + } 23 + 24 + static enum xrt_input_name 25 + oxr_facial_tracking_type_htc_to_input_name(enum xrt_facial_tracking_type_htc ft_type) 26 + { 27 + switch (ft_type) { 28 + case XRT_FACIAL_TRACKING_TYPE_LIP_DEFAULT_HTC: return XRT_INPUT_HTC_LIP_FACE_TRACKING; 29 + case XRT_FACIAL_TRACKING_TYPE_EYE_DEFAULT_HTC: 30 + default: return XRT_INPUT_HTC_EYE_FACE_TRACKING; 31 + } 32 + } 33 + 34 + static XrResult 35 + oxr_facial_tracker_htc_destroy_cb(struct oxr_logger *log, struct oxr_handle_base *hb) 36 + { 37 + struct oxr_facial_tracker_htc *face_tracker_htc = (struct oxr_facial_tracker_htc *)hb; 38 + free(face_tracker_htc); 39 + return XR_SUCCESS; 40 + } 41 + 42 + XrResult 43 + oxr_facial_tracker_htc_create(struct oxr_logger *log, 44 + struct oxr_session *sess, 45 + const XrFacialTrackerCreateInfoHTC *createInfo, 46 + struct oxr_facial_tracker_htc **out_face_tracker_htc) 47 + { 48 + bool supports_eye = false; 49 + bool supports_lip = false; 50 + oxr_system_get_face_tracking_htc_support(log, sess->sys->inst, &supports_eye, &supports_lip); 51 + 52 + const enum xrt_facial_tracking_type_htc facial_tracking_type = 53 + oxr_to_xrt_facial_tracking_type_htc(createInfo->facialTrackingType); 54 + 55 + if (facial_tracking_type == XRT_FACIAL_TRACKING_TYPE_EYE_DEFAULT_HTC && !supports_eye) { 56 + return oxr_error(log, XR_ERROR_FEATURE_UNSUPPORTED, "System does not support HTC eye facial tracking"); 57 + } 58 + if (facial_tracking_type == XRT_FACIAL_TRACKING_TYPE_LIP_DEFAULT_HTC && !supports_lip) { 59 + return oxr_error(log, XR_ERROR_FEATURE_UNSUPPORTED, "System does not support HTC lip facial tracking"); 60 + } 61 + 62 + struct xrt_device *xdev = GET_XDEV_BY_ROLE(sess->sys, face); 63 + if (xdev == NULL) { 64 + return oxr_error(log, XR_ERROR_FEATURE_UNSUPPORTED, "No device found for face tracking role"); 65 + } 66 + 67 + if (!xdev->supported.face_tracking) { 68 + return oxr_error(log, XR_ERROR_FEATURE_UNSUPPORTED, "Device does not support HTC facial tracking"); 69 + } 70 + 71 + struct oxr_facial_tracker_htc *face_tracker_htc = NULL; 72 + OXR_ALLOCATE_HANDLE_OR_RETURN(log, face_tracker_htc, OXR_XR_DEBUG_FTRACKER, oxr_facial_tracker_htc_destroy_cb, 73 + &sess->handle); 74 + 75 + face_tracker_htc->sess = sess; 76 + face_tracker_htc->xdev = xdev; 77 + face_tracker_htc->facial_tracking_type = facial_tracking_type; 78 + 79 + *out_face_tracker_htc = face_tracker_htc; 80 + 81 + return XR_SUCCESS; 82 + } 83 + 84 + XrResult 85 + oxr_get_facial_expressions_htc(struct oxr_logger *log, 86 + struct oxr_facial_tracker_htc *facial_tracker_htc, 87 + XrFacialExpressionsHTC *facialExpressions) 88 + { 89 + const bool is_eye_tracking = 90 + facial_tracker_htc->facial_tracking_type == XRT_FACIAL_TRACKING_TYPE_EYE_DEFAULT_HTC; 91 + const size_t expression_count = 92 + is_eye_tracking ? XRT_FACIAL_EXPRESSION_EYE_COUNT_HTC : XRT_FACIAL_EXPRESSION_LIP_COUNT_HTC; 93 + 94 + struct xrt_facial_expression_set facial_expression_set_result = {0}; 95 + float *expression_weights = is_eye_tracking 96 + ? facial_expression_set_result.eye_expression_set_htc.expression_weights 97 + : facial_expression_set_result.lip_expression_set_htc.expression_weights; 98 + memset(expression_weights, 0, sizeof(float) * expression_count); 99 + 100 + const enum xrt_input_name ft_input_name = 101 + oxr_facial_tracking_type_htc_to_input_name(facial_tracker_htc->facial_tracking_type); 102 + 103 + int64_t at_timestamp_ns = os_monotonic_get_ns(); 104 + 105 + xrt_device_get_face_tracking(facial_tracker_htc->xdev, ft_input_name, at_timestamp_ns, 106 + &facial_expression_set_result); 107 + 108 + facialExpressions->isActive = facial_expression_set_result.base_expression_set_htc.is_active; 109 + if (facialExpressions->isActive == XR_FALSE) 110 + return XR_SUCCESS; 111 + 112 + const struct oxr_instance *inst = facial_tracker_htc->sess->sys->inst; 113 + facialExpressions->sampleTime = time_state_monotonic_to_ts_ns( 114 + inst->timekeeping, facial_expression_set_result.base_expression_set_htc.sample_time_ns); 115 + 116 + memcpy(facialExpressions->expressionWeightings, expression_weights, sizeof(float) * expression_count); 117 + 118 + return XR_SUCCESS; 119 + }
+99 -32
src/xrt/state_trackers/oxr/oxr_input.c
··· 1 // Copyright 2018-2024, Collabora, Ltd. 2 - // Copyright 2023, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 9 * @ingroup oxr_main 10 */ 11 12 - #include "b_generated_bindings_helpers.h" 13 #include "oxr_bindings/b_oxr_generated_bindings.h" 14 #include "util/u_debug.h" 15 #include "util/u_time.h" ··· 515 */ 516 517 static bool 518 do_inputs(struct oxr_binding *binding_point, 519 struct xrt_device *xdev, 520 struct xrt_binding_profile *xbp, ··· 523 uint32_t *input_count) 524 { 525 enum xrt_input_name name = 0; 526 - if (xbp == NULL) { 527 - name = binding_point->input; 528 - } else { 529 - for (size_t i = 0; i < xbp->input_count; i++) { 530 - if (binding_point->input != xbp->inputs[i].from) { 531 - continue; 532 - } 533 534 - // We have found a device mapping. 535 - name = xbp->inputs[i].device; 536 - break; 537 - } 538 539 - // Didn't find a mapping. 540 - if (name == 0) { 541 return false; 542 } 543 } 544 545 struct xrt_input *input = NULL; 546 - if (oxr_xdev_find_input(xdev, name, &input)) { 547 - uint32_t index = (*input_count)++; 548 - inputs[index].input = input; 549 - inputs[index].xdev = xdev; 550 - inputs[index].bound_path = matched_path; 551 - if (binding_point->dpad_activate != 0) { 552 - struct xrt_input *dpad_activate = NULL; 553 - if (!oxr_xdev_find_input(xdev, binding_point->dpad_activate, &dpad_activate)) { 554 - return false; 555 - } 556 - inputs[index].dpad_activate_name = binding_point->dpad_activate; 557 - inputs[index].dpad_activate = dpad_activate; 558 } 559 - return true; 560 } 561 562 - return false; 563 } 564 565 static bool ··· 771 if (found) { 772 if (xbp == NULL) { 773 oxr_slog(slog, "\t\t\t\tBound (xdev '%s'): %s!\n", xdev->str, 774 - xrt_input_name_string(binding_points[i]->input)); 775 } else { 776 oxr_slog(slog, "\t\t\t\tBound (xbp)!\n"); 777 } ··· 1626 // Only add the input if we can find a transform. 1627 1628 oxr_slog(slog, "\t\tFinding transforms for '%s' to action '%s' of type '%s'\n", 1629 - xrt_input_name_string(inputs[i].input->name), act_ref->name, 1630 xr_action_type_to_str(act_ref->action_type)); 1631 1632 enum oxr_dpad_region dpad_region; ··· 1667 struct xrt_input *input = cache->inputs[i].input; 1668 enum xrt_input_type t = XRT_GET_INPUT_TYPE(input->name); 1669 bool active = input->active; 1670 - oxr_slog(slog, "\t\t\t'%s' ('%s') on '%s' (%s)\n", xrt_input_name_string(input->name), 1671 xrt_input_type_to_str(t), cache->inputs[i].xdev->str, 1672 active ? "active" : "inactive"); 1673 } ··· 1862 struct oxr_action_set *act_set = NULL; 1863 struct oxr_action_set_attachment *act_set_attached = NULL; 1864 1865 // Check that all action sets has been attached. 1866 for (uint32_t i = 0; i < countActionSets; i++) { 1867 oxr_session_get_action_set_attachment(sess, actionSets[i].actionSet, &act_set_attached, &act_set); ··· 1871 "not been attached to this session", 1872 i, act_set != NULL ? act_set->data->name : "NULL"); 1873 } 1874 } 1875 1876 // Synchronize outputs to this time. ··· 1922 OXR_FOR_EACH_SUBACTION_PATH(ACCUMULATE_REQUESTED) 1923 #undef ACCUMULATE_REQUESTED 1924 } 1925 if (!any_action_with_subactionpath) { 1926 return oxr_error(log, XR_ERROR_PATH_UNSUPPORTED, 1927 "No action with specified subactionpath in actionset");
··· 1 // Copyright 2018-2024, Collabora, Ltd. 2 + // Copyright 2023-2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 9 * @ingroup oxr_main 10 */ 11 12 #include "oxr_bindings/b_oxr_generated_bindings.h" 13 #include "util/u_debug.h" 14 #include "util/u_time.h" ··· 514 */ 515 516 static bool 517 + find_xdev_name_from_pairs(const struct xrt_device *xdev, 518 + const struct xrt_binding_profile *xbp, 519 + enum xrt_input_name from_name, 520 + enum xrt_input_name *out_name) 521 + { 522 + if (from_name == 0) { 523 + *out_name = 0; 524 + return true; // Not asking for anything, just keep going. 525 + } 526 + 527 + /* 528 + * For asymmetrical devices like PS Sense being re-bound to a symmetrical 529 + * "device" like simple controller can be problemantic as depending on 530 + * which hand it is menu is bound to different inputs. Instead of making 531 + * the driver have two completely unique binding mappings per hand, we 532 + * instead loop over all pairs finding the first match. In other words 533 + * this means there can be multiple of the same 'from' value in the 534 + * array of input pairs. 535 + */ 536 + for (size_t i = 0; i < xbp->input_count; i++) { 537 + if (from_name != xbp->inputs[i].from) { 538 + continue; 539 + } 540 + 541 + // What is the name on the xdev? 542 + enum xrt_input_name xdev_name = xbp->inputs[i].device; 543 + 544 + // See if we can't find it. 545 + for (uint32_t k = 0; k < xdev->input_count; k++) { 546 + if (xdev->inputs[k].name == xdev_name) { 547 + *out_name = xdev_name; 548 + return true; 549 + } 550 + } 551 + } 552 + 553 + return false; 554 + } 555 + 556 + static bool 557 do_inputs(struct oxr_binding *binding_point, 558 struct xrt_device *xdev, 559 struct xrt_binding_profile *xbp, ··· 562 uint32_t *input_count) 563 { 564 enum xrt_input_name name = 0; 565 + enum xrt_input_name dpad_activate_name = 0; 566 567 + if (xbp != NULL) { 568 + bool t1 = find_xdev_name_from_pairs(xdev, xbp, binding_point->input, &name); 569 + bool t2 = find_xdev_name_from_pairs(xdev, xbp, binding_point->dpad_activate, &dpad_activate_name); 570 571 + // We couldn't find the needed inputs on the device. 572 + if (!t1 || !t2) { 573 return false; 574 } 575 + } else { 576 + name = binding_point->input; 577 + dpad_activate_name = binding_point->dpad_activate; 578 } 579 580 struct xrt_input *input = NULL; 581 + struct xrt_input *dpad_activate_input = NULL; 582 + 583 + // Early out if there is no such input. 584 + if (!oxr_xdev_find_input(xdev, name, &input)) { 585 + return false; 586 + } 587 + 588 + // Check this before allocating an input. 589 + if (dpad_activate_name != 0) { 590 + if (!oxr_xdev_find_input(xdev, dpad_activate_name, &dpad_activate_input)) { 591 + return false; 592 } 593 + } 594 + 595 + uint32_t index = (*input_count)++; 596 + inputs[index].input = input; 597 + inputs[index].xdev = xdev; 598 + inputs[index].bound_path = matched_path; 599 + if (dpad_activate_input != NULL) { 600 + inputs[index].dpad_activate_name = dpad_activate_name; 601 + inputs[index].dpad_activate = dpad_activate_input; 602 } 603 604 + return true; 605 } 606 607 static bool ··· 813 if (found) { 814 if (xbp == NULL) { 815 oxr_slog(slog, "\t\t\t\tBound (xdev '%s'): %s!\n", xdev->str, 816 + u_str_xrt_input_name(binding_points[i]->input)); 817 } else { 818 oxr_slog(slog, "\t\t\t\tBound (xbp)!\n"); 819 } ··· 1668 // Only add the input if we can find a transform. 1669 1670 oxr_slog(slog, "\t\tFinding transforms for '%s' to action '%s' of type '%s'\n", 1671 + u_str_xrt_input_name(inputs[i].input->name), act_ref->name, 1672 xr_action_type_to_str(act_ref->action_type)); 1673 1674 enum oxr_dpad_region dpad_region; ··· 1709 struct xrt_input *input = cache->inputs[i].input; 1710 enum xrt_input_type t = XRT_GET_INPUT_TYPE(input->name); 1711 bool active = input->active; 1712 + oxr_slog(slog, "\t\t\t'%s' ('%s') on '%s' (%s)\n", u_str_xrt_input_name(input->name), 1713 xrt_input_type_to_str(t), cache->inputs[i].xdev->str, 1714 active ? "active" : "inactive"); 1715 } ··· 1904 struct oxr_action_set *act_set = NULL; 1905 struct oxr_action_set_attachment *act_set_attached = NULL; 1906 1907 + /* 1908 + * No side-effects allowed in this section as we are still 1909 + * validating and checking for errors at this point. 1910 + */ 1911 + 1912 // Check that all action sets has been attached. 1913 for (uint32_t i = 0; i < countActionSets; i++) { 1914 oxr_session_get_action_set_attachment(sess, actionSets[i].actionSet, &act_set_attached, &act_set); ··· 1918 "not been attached to this session", 1919 i, act_set != NULL ? act_set->data->name : "NULL"); 1920 } 1921 + } 1922 + 1923 + /* 1924 + * Can only call this function if the session state is focused. This is 1925 + * not an error and has to be checked after all validation, but before 1926 + * any side-effects happens. 1927 + */ 1928 + if (sess->state != XR_SESSION_STATE_FOCUSED) { 1929 + return XR_SESSION_NOT_FOCUSED; 1930 + } 1931 + 1932 + /* 1933 + * Side-effects allowed below, but not validation. 1934 + */ 1935 + 1936 + if (countActionSets == 0) { 1937 + // Nothing to do. 1938 + return XR_SUCCESS; 1939 } 1940 1941 // Synchronize outputs to this time. ··· 1987 OXR_FOR_EACH_SUBACTION_PATH(ACCUMULATE_REQUESTED) 1988 #undef ACCUMULATE_REQUESTED 1989 } 1990 + 1991 + //! @TODO This validation is not allowed here, must done above. 1992 if (!any_action_with_subactionpath) { 1993 return oxr_error(log, XR_ERROR_PATH_UNSUPPORTED, 1994 "No action with specified subactionpath in actionset");
+96 -54
src/xrt/state_trackers/oxr/oxr_instance.c
··· 91 inst->system.visibility_mask[i] = NULL; 92 } 93 94 xrt_space_overseer_destroy(&inst->system.xso); 95 os_mutex_destroy(&inst->system.sync_actions_mutex); 96 xrt_system_devices_destroy(&inst->system.xsysd); ··· 199 { 200 // Reset. 201 inst->quirks.skip_end_session = false; 202 inst->quirks.disable_vulkan_format_depth_stencil = false; 203 inst->quirks.no_validation_error_in_create_ref_space = false; 204 ··· 256 ret = oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Failed to init sync action mutex"); 257 return ret; 258 } 259 260 #ifdef XRT_FEATURE_CLIENT_DEBUG_GUI 261 struct u_debug_gui_create_info udgci = { ··· 331 #ifdef OXR_HAVE_META_body_tracking_calibration 332 .meta_body_tracking_calibration_enabled = extensions->META_body_tracking_calibration, 333 #endif 334 }; 335 snprintf(i_info.app_info.application_name, sizeof(i_info.app_info.application_name), "%s", 336 createInfo->applicationInfo.applicationName); ··· 370 } 371 #endif // XRT_OS_ANDROID 372 373 - struct oxr_system *sys = &inst->system; 374 - 375 - // Create the compositor if we are not headless, currently always create it. 376 - bool should_create_compositor = true /* !inst->extensions.MND_headless */; 377 - 378 - // Create the system. 379 - if (should_create_compositor) { 380 - xret = xrt_instance_create_system(inst->xinst, &sys->xsys, &sys->xsysd, &sys->xso, &sys->xsysc); 381 - } else { 382 - xret = xrt_instance_create_system(inst->xinst, &sys->xsys, &sys->xsysd, &sys->xso, NULL); 383 - } 384 - 385 - if (xret != XRT_SUCCESS) { 386 - ret = oxr_error(log, XR_ERROR_INITIALIZATION_FAILED, "Failed to create the system '%i'", xret); 387 - oxr_instance_destroy(log, &inst->handle); 388 - return ret; 389 - } 390 - 391 - ret = XR_SUCCESS; 392 - if (sys->xsysd == NULL) { 393 - ret = oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Huh?! Field sys->xsysd was NULL?"); 394 - } else if (should_create_compositor && sys->xsysc == NULL) { 395 - ret = oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Huh?! Field sys->xsysc was NULL?"); 396 - } else if (!should_create_compositor && sys->xsysc != NULL) { 397 - ret = oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Huh?! Field sys->xsysc was not NULL?"); 398 - } 399 - 400 - if (ret != XR_SUCCESS) { 401 - oxr_instance_destroy(log, &inst->handle); 402 - return ret; 403 - } 404 - 405 - // Did we find any HMD 406 - // @todo Headless with only controllers? 407 - struct xrt_device *dev = GET_XDEV_BY_ROLE(sys, head); 408 - if (dev == NULL) { 409 - ret = oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Failed to find any HMD device"); 410 - oxr_instance_destroy(log, &inst->handle); 411 - return ret; 412 - } 413 - uint32_t view_count = dev->hmd->view_count; 414 - ret = oxr_system_fill_in(log, inst, XRT_SYSTEM_ID, view_count, &inst->system); 415 - if (ret != XR_SUCCESS) { 416 - oxr_instance_destroy(log, &inst->handle); 417 - return ret; 418 - } 419 - 420 inst->timekeeping = time_state_create(inst->xinst->startup_timestamp); 421 422 //! @todo check if this (and other creates) failed? ··· 429 430 u_var_add_root((void *)inst, "XrInstance", true); 431 432 - #ifdef XRT_FEATURE_CLIENT_DEBUG_GUI 433 - u_debug_gui_start(inst->debug_ui, inst->xinst, sys->xsysd); 434 - #endif 435 - 436 oxr_log(log, 437 "Instance created\n" 438 "\tcreateInfo->applicationInfo.applicationName: %s\n" ··· 442 "\tcreateInfo->applicationInfo.apiVersion: %d.%d.%d\n" 443 "\tappinfo.detected.engine.name: %s\n" 444 "\tappinfo.detected.engine.version: %i.%i.%i\n" 445 "\tquirks.disable_vulkan_format_depth_stencil: %s\n" 446 "\tquirks.no_validation_error_in_create_ref_space: %s\n" 447 "\tquirks.skip_end_session: %s\n" ··· 457 inst->appinfo.detected.engine.major, // 458 inst->appinfo.detected.engine.minor, // 459 inst->appinfo.detected.engine.patch, // 460 inst->quirks.disable_vulkan_format_depth_stencil ? "true" : "false", // 461 inst->quirks.no_validation_error_in_create_ref_space ? "true" : "false", // 462 inst->quirks.skip_end_session ? "true" : "false", // 463 inst->quirks.parallel_views ? "true" : "false" // 464 ); // 465 466 - debug_print_devices(log, sys); 467 - 468 - 469 #ifdef XRT_FEATURE_RENDERDOC 470 471 #ifdef __GNUC__ ··· 506 #endif 507 508 *out_instance = inst; 509 510 return XR_SUCCESS; 511 }
··· 91 inst->system.visibility_mask[i] = NULL; 92 } 93 94 + os_mutex_destroy(&inst->system_init_lock); 95 + 96 xrt_space_overseer_destroy(&inst->system.xso); 97 os_mutex_destroy(&inst->system.sync_actions_mutex); 98 xrt_system_devices_destroy(&inst->system.xsysd); ··· 201 { 202 // Reset. 203 inst->quirks.skip_end_session = false; 204 + inst->quirks.disable_vulkan_format_depth = false; 205 inst->quirks.disable_vulkan_format_depth_stencil = false; 206 inst->quirks.no_validation_error_in_create_ref_space = false; 207 ··· 259 ret = oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Failed to init sync action mutex"); 260 return ret; 261 } 262 + 263 + m_ret = os_mutex_init(&inst->system_init_lock); 264 + if (m_ret < 0) { 265 + ret = oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Failed to init system init mutex"); 266 + return ret; 267 + } 268 + 269 270 #ifdef XRT_FEATURE_CLIENT_DEBUG_GUI 271 struct u_debug_gui_create_info udgci = { ··· 341 #ifdef OXR_HAVE_META_body_tracking_calibration 342 .meta_body_tracking_calibration_enabled = extensions->META_body_tracking_calibration, 343 #endif 344 + #ifdef OXR_HAVE_ANDROID_face_tracking 345 + .android_face_tracking_enabled = extensions->ANDROID_face_tracking, 346 + #endif 347 }; 348 snprintf(i_info.app_info.application_name, sizeof(i_info.app_info.application_name), "%s", 349 createInfo->applicationInfo.applicationName); ··· 383 } 384 #endif // XRT_OS_ANDROID 385 386 inst->timekeeping = time_state_create(inst->xinst->startup_timestamp); 387 388 //! @todo check if this (and other creates) failed? ··· 395 396 u_var_add_root((void *)inst, "XrInstance", true); 397 398 oxr_log(log, 399 "Instance created\n" 400 "\tcreateInfo->applicationInfo.applicationName: %s\n" ··· 404 "\tcreateInfo->applicationInfo.apiVersion: %d.%d.%d\n" 405 "\tappinfo.detected.engine.name: %s\n" 406 "\tappinfo.detected.engine.version: %i.%i.%i\n" 407 + "\tquirks.disable_vulkan_format_depth: %s\n" 408 "\tquirks.disable_vulkan_format_depth_stencil: %s\n" 409 "\tquirks.no_validation_error_in_create_ref_space: %s\n" 410 "\tquirks.skip_end_session: %s\n" ··· 420 inst->appinfo.detected.engine.major, // 421 inst->appinfo.detected.engine.minor, // 422 inst->appinfo.detected.engine.patch, // 423 + inst->quirks.disable_vulkan_format_depth ? "true" : "false", // 424 inst->quirks.disable_vulkan_format_depth_stencil ? "true" : "false", // 425 inst->quirks.no_validation_error_in_create_ref_space ? "true" : "false", // 426 inst->quirks.skip_end_session ? "true" : "false", // 427 inst->quirks.parallel_views ? "true" : "false" // 428 ); // 429 430 #ifdef XRT_FEATURE_RENDERDOC 431 432 #ifdef __GNUC__ ··· 467 #endif 468 469 *out_instance = inst; 470 + 471 + return XR_SUCCESS; 472 + } 473 + 474 + XrResult 475 + oxr_instance_init_system_locked(struct oxr_logger *log, struct oxr_instance *inst) 476 + { 477 + struct oxr_system *sys = &inst->system; 478 + if (sys->xsys) { 479 + return XR_SUCCESS; 480 + } 481 + 482 + xrt_result_t xret; 483 + XrResult ret; 484 + 485 + bool available = false; 486 + xret = xrt_instance_is_system_available(inst->xinst, &available); 487 + if (xret != XRT_SUCCESS) { 488 + struct u_pp_sink_stack_only sink; 489 + u_pp_delegate_t dg = u_pp_sink_stack_only_init(&sink); 490 + u_pp(dg, "Call to xrt_instance_is_system_available failed: "); 491 + u_pp_xrt_result(dg, xret); 492 + ret = oxr_error(log, xret == XRT_ERROR_IPC_FAILURE ? XR_ERROR_INSTANCE_LOST : XR_ERROR_RUNTIME_FAILURE, 493 + "%s", sink.buffer); 494 + return ret; 495 + } 496 + if (!available) { 497 + return XR_ERROR_FORM_FACTOR_UNAVAILABLE; 498 + } 499 + 500 + // Create the compositor if we are not headless, currently always create it. 501 + bool should_create_compositor = true /* !inst->extensions.MND_headless */; 502 + 503 + // Create the system. 504 + if (should_create_compositor) { 505 + xret = xrt_instance_create_system(inst->xinst, &sys->xsys, &sys->xsysd, &sys->xso, &sys->xsysc); 506 + } else { 507 + xret = xrt_instance_create_system(inst->xinst, &sys->xsys, &sys->xsysd, &sys->xso, NULL); 508 + } 509 + 510 + if (xret != XRT_SUCCESS) { 511 + struct u_pp_sink_stack_only sink; 512 + u_pp_delegate_t dg = u_pp_sink_stack_only_init(&sink); 513 + u_pp(dg, "Call to xrt_instance_create_system failed: "); 514 + u_pp_xrt_result(dg, xret); 515 + ret = oxr_error(log, XR_ERROR_INITIALIZATION_FAILED, "%s", sink.buffer); 516 + return ret; 517 + } 518 + 519 + #ifdef XRT_FEATURE_CLIENT_DEBUG_GUI 520 + // Do this after creating the system. 521 + u_debug_gui_start(inst->debug_ui, inst->xinst, sys->xsysd); 522 + #endif 523 + 524 + ret = XR_SUCCESS; 525 + if (sys->xsysd == NULL) { 526 + ret = oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Huh?! Field sys->xsysd was NULL?"); 527 + } else if (should_create_compositor && sys->xsysc == NULL) { 528 + ret = oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Huh?! Field sys->xsysc was NULL?"); 529 + } else if (!should_create_compositor && sys->xsysc != NULL) { 530 + ret = oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Huh?! Field sys->xsysc was not NULL?"); 531 + } 532 + 533 + if (ret != XR_SUCCESS) { 534 + return ret; 535 + } 536 + 537 + // Did we find any HMD 538 + // @todo Headless with only controllers? 539 + struct xrt_device *dev = GET_XDEV_BY_ROLE(sys, head); 540 + if (dev == NULL) { 541 + ret = oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Failed to find any HMD device"); 542 + return ret; 543 + } 544 + uint32_t view_count = (uint32_t)dev->hmd->view_count; 545 + ret = oxr_system_fill_in(log, inst, XRT_SYSTEM_ID, view_count, &inst->system); 546 + if (ret != XR_SUCCESS) { 547 + return ret; 548 + } 549 + 550 + debug_print_devices(log, sys); 551 552 return XR_SUCCESS; 553 }
+134 -6
src/xrt/state_trackers/oxr/oxr_objects.h
··· 1 // Copyright 2018-2024, Collabora, Ltd. 2 - // Copyright 2023, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 127 struct oxr_action_set_ref; 128 struct oxr_action_ref; 129 struct oxr_hand_tracker; 130 struct oxr_facial_tracker_htc; 131 struct oxr_face_tracker2_fb; 132 struct oxr_body_tracker_fb; ··· 252 struct oxr_instance **out_inst); 253 254 /*! 255 * @public @memberof oxr_instance 256 */ 257 XrResult ··· 459 return XRT_CAST_PTR_TO_OXR_HANDLE(XrFaceTracker2FB, face_tracker2_fb); 460 } 461 #endif 462 /*! 463 * 464 * @name oxr_input.c ··· 976 XrTime time, 977 struct xrt_space_relation *out_relation); 978 979 980 /* 981 * ··· 1086 1087 bool 1088 oxr_system_get_force_feedback_support(struct oxr_logger *log, struct oxr_instance *inst); 1089 1090 void 1091 oxr_system_get_face_tracking_htc_support(struct oxr_logger *log, ··· 1474 }; 1475 1476 /*! 1477 * Single or multiple devices grouped together to form a system that sessions 1478 * can be created from. Might need to open devices to get all 1479 * properties from it, but shouldn't. ··· 1505 //! Have the client application called the gfx api requirements func? 1506 bool gotten_requirements; 1507 1508 - XrViewConfigurationType view_config_type; 1509 - XrViewConfigurationView views[2]; 1510 - uint32_t blend_mode_count; 1511 - XrEnvironmentBlendMode blend_modes[3]; 1512 1513 XrReferenceSpaceType reference_spaces[5]; 1514 uint32_t reference_space_count; ··· 1529 //! The device returned with the last xrGetVulkanGraphicsDeviceKHR or xrGetVulkanGraphicsDevice2KHR call. 1530 //! XR_NULL_HANDLE if neither has been called. 1531 VkPhysicalDevice suggested_vulkan_physical_device; 1532 1533 struct 1534 { ··· 1689 XrVersion major_minor; 1690 } openxr_version; 1691 1692 // Hardcoded single system. 1693 struct oxr_system system; 1694 ··· 1748 1749 struct 1750 { 1751 - //! Unreal has a bug in the VulkanRHI backend. 1752 bool disable_vulkan_format_depth_stencil; 1753 //! Unreal 4 has a bug calling xrEndSession; the function should just exit 1754 bool skip_end_session; 1755 ··· 1811 struct oxr_session *next; 1812 1813 XrSessionState state; 1814 1815 /*! 1816 * There is a extra state between xrBeginSession has been called and ··· 3023 XrResult 3024 oxr_event_push_XrEventDataUserPresenceChangedEXT(struct oxr_logger *log, struct oxr_session *sess, bool isUserPresent); 3025 #endif // OXR_HAVE_EXT_user_presence 3026 3027 /*! 3028 * @}
··· 1 // Copyright 2018-2024, Collabora, Ltd. 2 + // Copyright 2023-2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 127 struct oxr_action_set_ref; 128 struct oxr_action_ref; 129 struct oxr_hand_tracker; 130 + struct oxr_face_tracker_android; 131 struct oxr_facial_tracker_htc; 132 struct oxr_face_tracker2_fb; 133 struct oxr_body_tracker_fb; ··· 253 struct oxr_instance **out_inst); 254 255 /*! 256 + * Must be called with oxr_instance::system_init_lock held. 257 + * 258 + * @public @memberof oxr_instance 259 + */ 260 + XrResult 261 + oxr_instance_init_system_locked(struct oxr_logger *log, struct oxr_instance *inst); 262 + 263 + /*! 264 * @public @memberof oxr_instance 265 */ 266 XrResult ··· 468 return XRT_CAST_PTR_TO_OXR_HANDLE(XrFaceTracker2FB, face_tracker2_fb); 469 } 470 #endif 471 + 472 + #ifdef OXR_HAVE_ANDROID_face_tracking 473 + /*! 474 + * To go back to a OpenXR object. 475 + * 476 + * @relates oxr_facial_tracker_htc 477 + */ 478 + static inline XrFaceTrackerANDROID 479 + oxr_face_tracker_android_to_openxr(struct oxr_face_tracker_android *face_tracker_android) 480 + { 481 + return XRT_CAST_PTR_TO_OXR_HANDLE(XrFaceTrackerANDROID, face_tracker_android); 482 + } 483 + #endif 484 + 485 /*! 486 * 487 * @name oxr_input.c ··· 999 XrTime time, 1000 struct xrt_space_relation *out_relation); 1001 1002 + /*! 1003 + * Get the xrt_space associated with this oxr_space, the @ref xrt_space will 1004 + * be reference counted by this function so the caller will need to call 1005 + * @ref xrt_space_reference to decrement the reference count. 1006 + * 1007 + * @param log Logging struct. 1008 + * @param spc Oxr space to get the xrt_space from. 1009 + * @param[out] out_xspace Returns the xrt_space associated with this oxr_space. 1010 + * @return Any errors, XR_SUCCESS, xspace is not set on XR_ERROR_*. 1011 + */ 1012 + XRT_CHECK_RESULT XrResult 1013 + oxr_space_get_xrt_space(struct oxr_logger *log, struct oxr_space *spc, struct xrt_space **out_xspace); 1014 + 1015 1016 /* 1017 * ··· 1122 1123 bool 1124 oxr_system_get_force_feedback_support(struct oxr_logger *log, struct oxr_instance *inst); 1125 + 1126 + void 1127 + oxr_system_get_face_tracking_android_support(struct oxr_logger *log, struct oxr_instance *inst, bool *supported); 1128 1129 void 1130 oxr_system_get_face_tracking_htc_support(struct oxr_logger *log, ··· 1513 }; 1514 1515 /*! 1516 + * Holds the properties that a system supports for a view configuration type. 1517 + * 1518 + * @relates oxr_system 1519 + */ 1520 + struct oxr_view_config_properties 1521 + { 1522 + XrViewConfigurationType view_config_type; 1523 + 1524 + uint32_t view_count; 1525 + XrViewConfigurationView views[XRT_MAX_COMPOSITOR_VIEW_CONFIGS_VIEW_COUNT]; 1526 + 1527 + uint32_t blend_mode_count; 1528 + XrEnvironmentBlendMode blend_modes[3]; 1529 + }; 1530 + 1531 + /*! 1532 * Single or multiple devices grouped together to form a system that sessions 1533 * can be created from. Might need to open devices to get all 1534 * properties from it, but shouldn't. ··· 1560 //! Have the client application called the gfx api requirements func? 1561 bool gotten_requirements; 1562 1563 + uint32_t view_config_count; 1564 + struct oxr_view_config_properties view_configs[XRT_MAX_COMPOSITOR_VIEW_CONFIGS_COUNT]; 1565 1566 XrReferenceSpaceType reference_spaces[5]; 1567 uint32_t reference_space_count; ··· 1582 //! The device returned with the last xrGetVulkanGraphicsDeviceKHR or xrGetVulkanGraphicsDevice2KHR call. 1583 //! XR_NULL_HANDLE if neither has been called. 1584 VkPhysicalDevice suggested_vulkan_physical_device; 1585 + 1586 + /*! 1587 + * Stores the vkGetInstanceProcAddr passed to xrCreateVulkanInstanceKHR to be 1588 + * used when looking up Vulkan functions used by xrGetVulkanGraphicsDevice2KHR. 1589 + */ 1590 + PFN_vkGetInstanceProcAddr vk_get_instance_proc_addr; 1591 1592 struct 1593 { ··· 1748 XrVersion major_minor; 1749 } openxr_version; 1750 1751 + // Protects the function oxr_instance_init_system_locked. 1752 + struct os_mutex system_init_lock; 1753 + 1754 // Hardcoded single system. 1755 struct oxr_system system; 1756 ··· 1810 1811 struct 1812 { 1813 + /*! 1814 + * Some applications can't handle depth formats, or they trigger 1815 + * a bug in a specific version of the application or engine. 1816 + * This flag only disables depth formats 1817 + * @see disable_vulkan_format_depth_stencil for depth-stencil formats. 1818 + */ 1819 + bool disable_vulkan_format_depth; 1820 + 1821 + /*! 1822 + * Some applications can't handle depth stencil formats, or they 1823 + * trigger a bug in a specific version of the application or 1824 + * engine. 1825 + * 1826 + * This flag only disables depth-stencil formats, 1827 + * @see disable_vulkan_format_depth flag for depth only formats. 1828 + * 1829 + * In the past it was used to work around a bug in Unreal's 1830 + * VulkanRHI backend. 1831 + */ 1832 bool disable_vulkan_format_depth_stencil; 1833 + 1834 //! Unreal 4 has a bug calling xrEndSession; the function should just exit 1835 bool skip_end_session; 1836 ··· 1892 struct oxr_session *next; 1893 1894 XrSessionState state; 1895 + 1896 + /*! 1897 + * This is set in xrBeginSession and is the primaryViewConfiguration 1898 + * argument, this is then used in xrEndFrame to know which view 1899 + * configuration the application is submitting it's frame in. 1900 + */ 1901 + XrViewConfigurationType current_view_config_type; 1902 1903 /*! 1904 * There is a extra state between xrBeginSession has been called and ··· 3111 XrResult 3112 oxr_event_push_XrEventDataUserPresenceChangedEXT(struct oxr_logger *log, struct oxr_session *sess, bool isUserPresent); 3113 #endif // OXR_HAVE_EXT_user_presence 3114 + 3115 + #ifdef OXR_HAVE_ANDROID_face_tracking 3116 + /*! 3117 + * Android specific Facial tracker. 3118 + * 3119 + * Parent type/handle is @ref oxr_instance 3120 + * 3121 + * 3122 + * @obj{XrFaceTrackerANDROID} 3123 + * @extends oxr_handle_base 3124 + */ 3125 + struct oxr_face_tracker_android 3126 + { 3127 + //! Common structure for things referred to by OpenXR handles. 3128 + struct oxr_handle_base handle; 3129 + 3130 + //! Owner of this face tracker. 3131 + struct oxr_session *sess; 3132 + 3133 + //! xrt_device backing this face tracker 3134 + struct xrt_device *xdev; 3135 + }; 3136 + 3137 + XrResult 3138 + oxr_face_tracker_android_create(struct oxr_logger *log, 3139 + struct oxr_session *sess, 3140 + const XrFaceTrackerCreateInfoANDROID *createInfo, 3141 + XrFaceTrackerANDROID *faceTracker); 3142 + 3143 + XrResult 3144 + oxr_get_face_state_android(struct oxr_logger *log, 3145 + struct oxr_face_tracker_android *facial_tracker_android, 3146 + const XrFaceStateGetInfoANDROID *getInfo, 3147 + XrFaceStateANDROID *faceStateOutput); 3148 + 3149 + XrResult 3150 + oxr_get_face_calibration_state_android(struct oxr_logger *log, 3151 + struct oxr_face_tracker_android *facial_tracker_android, 3152 + XrBool32 *faceIsCalibratedOutput); 3153 + #endif // OXR_HAVE_ANDROID_face_tracking 3154 3155 /*! 3156 * @}
+203 -80
src/xrt/state_trackers/oxr/oxr_session.c
··· 1 // Copyright 2018-2024, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 65 */ 66 67 static bool 68 should_render(XrSessionState state) 69 { 70 switch (state) { ··· 127 if (inst->quirks.map_stage_to_local_floor) { 128 /* When stage is mapped to local_floor: 129 * ignore stage changes 130 - * for local_floor changes, send a duplicate envent for stage 131 * */ 132 switch (ref_change->ref_type) { 133 case XRT_SPACE_REFERENCE_TYPE_STAGE: return XR_SUCCESS; ··· 224 for (uint32_t i = 0; i < xc->info.format_count; i++) { 225 int64_t format = xc->info.formats[i]; 226 227 - if (inst->quirks.disable_vulkan_format_depth_stencil && 228 - format == 130 /* VK_FORMAT_D32_SFLOAT_S8_UINT */) { 229 continue; 230 } 231 ··· 249 250 struct xrt_compositor *xc = sess->compositor; 251 if (xc != NULL) { 252 - XrViewConfigurationType view_type = beginInfo->primaryViewConfigurationType; 253 - 254 - // in a headless session there is no compositor and primaryViewConfigurationType must be ignored 255 - if (sess->compositor != NULL && view_type != sess->sys->view_config_type) { 256 - /*! @todo we only support a single view config type per 257 - * system right now */ 258 - return oxr_error(log, XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED, 259 - "(beginInfo->primaryViewConfigurationType == " 260 - "0x%08x) view configuration type not supported", 261 - view_type); 262 - } 263 - 264 const struct oxr_extension_status *extensions = &sess->sys->inst->extensions; 265 266 const struct xrt_begin_session_info begin_session_info = { ··· 295 #ifdef OXR_HAVE_META_body_tracking_calibration 296 .meta_body_tracking_calibration_enabled = extensions->META_body_tracking_calibration, 297 #endif 298 }; 299 300 xrt_result_t xret = xrt_comp_begin_session(xc, &begin_session_info); ··· 313 // Headless, pretend we got event from the compositor. 314 sess->compositor_visible = true; 315 sess->compositor_focused = true; 316 317 // Transition into focused. 318 - oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, 0); 319 - oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE, 0); 320 - oxr_session_change_state(log, sess, XR_SESSION_STATE_FOCUSED, 0); 321 } 322 XrResult ret = oxr_frame_sync_begin_session(&sess->frame_sync); 323 if (ret != XR_SUCCESS) { ··· 325 "Frame sync object refused to let us begin session, probably already running"); 326 } 327 328 return oxr_session_success_result(sess); 329 } 330 ··· 372 sess->compositor_focused = false; 373 } 374 375 - oxr_session_change_state(log, sess, XR_SESSION_STATE_IDLE, 0); 376 if (sess->exiting) { 377 - oxr_session_change_state(log, sess, XR_SESSION_STATE_EXITING, 0); 378 } else { 379 #ifndef XRT_OS_ANDROID 380 // @todo In multi-clients scenario with a session being reused, changing session ··· 391 } 392 sess->has_ended_once = false; 393 394 return oxr_session_success_result(sess); 395 } 396 397 XrResult 398 oxr_session_request_exit(struct oxr_logger *log, struct oxr_session *sess) 399 { 400 if (sess->state == XR_SESSION_STATE_FOCUSED) { 401 - oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE, 0); 402 } 403 if (sess->state == XR_SESSION_STATE_VISIBLE) { 404 - oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, 0); 405 } 406 if (!sess->has_ended_once && sess->state != XR_SESSION_STATE_SYNCHRONIZED) { 407 - oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, 0); 408 // Fake the synchronization. 409 sess->has_ended_once = true; 410 } 411 412 //! @todo start fading out the app. 413 - oxr_session_change_state(log, sess, XR_SESSION_STATE_STOPPING, 0); 414 sess->exiting = true; 415 return oxr_session_success_result(sess); 416 } ··· 446 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "xrt_session is null"); 447 } 448 449 #ifdef XRT_OS_ANDROID 450 // Most recent Android activity lifecycle event was OnPause: move toward stopping 451 if (sess->sys->inst->activity_state == XRT_ANDROID_LIVECYCLE_EVENT_ON_PAUSE) { 452 if (sess->state == XR_SESSION_STATE_FOCUSED) { 453 U_LOG_I("Activity paused: changing session state FOCUSED->VISIBLE"); 454 - oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE, 0); 455 } 456 457 if (sess->state == XR_SESSION_STATE_VISIBLE) { 458 U_LOG_I("Activity paused: changing session state VISIBLE->SYNCHRONIZED"); 459 - oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, 0); 460 } 461 462 if (sess->state == XR_SESSION_STATE_SYNCHRONIZED) { 463 U_LOG_I("Activity paused: changing session state SYNCHRONIZED->STOPPING"); 464 - oxr_session_change_state(log, sess, XR_SESSION_STATE_STOPPING, 0); 465 } 466 // TODO return here to avoid polling other events? 467 // see https://gitlab.freedesktop.org/monado/monado/-/issues/419 ··· 471 if (sess->sys->inst->activity_state == XRT_ANDROID_LIVECYCLE_EVENT_ON_RESUME) { 472 if (sess->state == XR_SESSION_STATE_IDLE) { 473 U_LOG_I("Activity resumed: changing session state IDLE->READY"); 474 - oxr_session_change_state(log, sess, XR_SESSION_STATE_READY, 0); 475 } 476 } 477 #endif // XRT_OS_ANDROID ··· 491 case XRT_SESSION_EVENT_STATE_CHANGE: 492 sess->compositor_visible = xse.state.visible; 493 sess->compositor_focused = xse.state.focused; 494 break; 495 case XRT_SESSION_EVENT_OVERLAY_CHANGE: 496 #ifdef OXR_HAVE_EXTX_overlay ··· 530 break; 531 case XRT_SESSION_EVENT_VISIBILITY_MASK_CHANGE: 532 #ifdef OXR_HAVE_KHR_visibility_mask 533 - oxr_event_push_XrEventDataVisibilityMaskChangedKHR(log, sess, sess->sys->view_config_type, 534 - xse.mask_change.view_index); 535 break; 536 #endif // OXR_HAVE_KHR_visibility_mask 537 case XRT_SESSION_EVENT_USER_PRESENCE_CHANGE: ··· 545 } 546 547 if (sess->state == XR_SESSION_STATE_SYNCHRONIZED && sess->compositor_visible) { 548 - oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE, 0); 549 } 550 551 if (sess->state == XR_SESSION_STATE_VISIBLE && sess->compositor_focused) { 552 - oxr_session_change_state(log, sess, XR_SESSION_STATE_FOCUSED, 0); 553 } 554 555 if (sess->state == XR_SESSION_STATE_FOCUSED && !sess->compositor_focused) { 556 - oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE, 0); 557 } 558 559 if (sess->state == XR_SESSION_STATE_VISIBLE && !sess->compositor_visible) { 560 - oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, 0); 561 } 562 563 return XR_SUCCESS; ··· 655 struct xrt_space_relation T_xdev_head = XRT_SPACE_RELATION_ZERO; 656 struct xrt_fov fovs[XRT_MAX_VIEWS] = {0}; 657 struct xrt_pose poses[XRT_MAX_VIEWS] = {0}; 658 659 xrt_result_t xret = xrt_device_get_view_poses( // 660 xdev, // 661 &default_eye_relation, // 662 xdisplay_time, // 663 view_count, // 664 &T_xdev_head, // 665 fovs, // ··· 1047 u_hashmap_int_create(&sess->act_sets_attachments_by_key); 1048 u_hashmap_int_create(&sess->act_attachments_by_key); 1049 1050 // Done with basic init, set out variable. 1051 *out_session = sess; 1052 ··· 1061 } \ 1062 } while (false) 1063 1064 - #define OXR_CREATE_XRT_SESSION_AND_NATIVE_COMPOSITOR(LOG, XSI, SESS) \ 1065 do { \ 1066 - if ((SESS)->sys->xsysc == NULL) { \ 1067 - return oxr_error((LOG), XR_ERROR_RUNTIME_FAILURE, \ 1068 - "The system compositor wasn't created, can't create native compositor!"); \ 1069 - } \ 1070 - xrt_result_t xret = xrt_system_create_session((SESS)->sys->xsys, (XSI), &(SESS)->xs, &(SESS)->xcn); \ 1071 - if (xret == XRT_ERROR_MULTI_SESSION_NOT_IMPLEMENTED) { \ 1072 - return oxr_error((LOG), XR_ERROR_LIMIT_REACHED, "Per instance multi-session not supported."); \ 1073 - } \ 1074 - if (xret != XRT_SUCCESS) { \ 1075 - return oxr_error((LOG), XR_ERROR_RUNTIME_FAILURE, \ 1076 - "Failed to create xrt_session and xrt_compositor_native! '%i'", xret); \ 1077 - } \ 1078 - if ((SESS)->sys->xsysc->xmcc != NULL) { \ 1079 - xrt_syscomp_set_state((SESS)->sys->xsysc, &(SESS)->xcn->base, true, true); \ 1080 - xrt_syscomp_set_z_order((SESS)->sys->xsysc, &(SESS)->xcn->base, 0); \ 1081 } \ 1082 } while (false) 1083 1084 - #define OXR_SESSION_ALLOCATE_AND_INIT(LOG, SYS, GFX_TYPE, OUT) \ 1085 - do { \ 1086 - XrResult ret = oxr_session_allocate_and_init(LOG, SYS, GFX_TYPE, &OUT); \ 1087 - if (ret != XR_SUCCESS) { \ 1088 - return ret; \ 1089 - } \ 1090 - } while (0) 1091 1092 1093 /* ··· 1101 const struct xrt_session_info *xsi, 1102 struct oxr_session **out_session) 1103 { 1104 #if defined(XR_USE_PLATFORM_XLIB) && defined(XR_USE_GRAPHICS_API_OPENGL) 1105 XrGraphicsBindingOpenGLXlibKHR const *opengl_xlib = OXR_GET_INPUT_FROM_CHAIN( 1106 createInfo, XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR, XrGraphicsBindingOpenGLXlibKHR); ··· 1113 "xrGetOpenGL[ES]GraphicsRequirementsKHR"); 1114 } 1115 1116 - OXR_SESSION_ALLOCATE_AND_INIT(log, sys, OXR_SESSION_GRAPHICS_EXT_XLIB_GL, *out_session); 1117 - OXR_CREATE_XRT_SESSION_AND_NATIVE_COMPOSITOR(log, xsi, *out_session); 1118 return oxr_session_populate_gl_xlib(log, sys, opengl_xlib, *out_session); 1119 } 1120 #endif ··· 1132 "xrGetOpenGLESGraphicsRequirementsKHR"); 1133 } 1134 1135 - OXR_SESSION_ALLOCATE_AND_INIT(log, sys, OXR_SESSION_GRAPHICS_EXT_ANDROID_GLES, *out_session); 1136 - OXR_CREATE_XRT_SESSION_AND_NATIVE_COMPOSITOR(log, xsi, *out_session); 1137 return oxr_session_populate_gles_android(log, sys, opengles_android, *out_session); 1138 } 1139 #endif ··· 1149 "Has not called xrGetOpenGLGraphicsRequirementsKHR"); 1150 } 1151 1152 - OXR_SESSION_ALLOCATE_AND_INIT(log, sys, OXR_SESSION_GRAPHICS_EXT_WIN32_GL, *out_session); 1153 - OXR_CREATE_XRT_SESSION_AND_NATIVE_COMPOSITOR(log, xsi, *out_session); 1154 return oxr_session_populate_gl_win32(log, sys, opengl_win32, *out_session); 1155 } 1156 #endif ··· 1188 (void *)vulkan->physicalDevice, (void *)sys->suggested_vulkan_physical_device, fn); 1189 } 1190 1191 - OXR_SESSION_ALLOCATE_AND_INIT(log, sys, OXR_SESSION_GRAPHICS_EXT_VULKAN, *out_session); 1192 - OXR_CREATE_XRT_SESSION_AND_NATIVE_COMPOSITOR(log, xsi, *out_session); 1193 return oxr_session_populate_vk(log, sys, vulkan, *out_session); 1194 } 1195 #endif ··· 1206 "xrGetOpenGL[ES]GraphicsRequirementsKHR"); 1207 } 1208 1209 - OXR_SESSION_ALLOCATE_AND_INIT(log, sys, OXR_SESSION_GRAPHICS_EXT_EGL, *out_session); 1210 - OXR_CREATE_XRT_SESSION_AND_NATIVE_COMPOSITOR(log, xsi, *out_session); 1211 return oxr_session_populate_egl(log, sys, egl, *out_session); 1212 } 1213 #endif ··· 1224 return oxr_error(log, XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING, 1225 "Has not called xrGetD3D11GraphicsRequirementsKHR"); 1226 } 1227 - XrResult result = oxr_d3d11_check_device(log, sys, d3d11->device); 1228 1229 - if (!XR_SUCCEEDED(result)) { 1230 - return result; 1231 } 1232 1233 1234 - OXR_SESSION_ALLOCATE_AND_INIT(log, sys, OXR_SESSION_GRAPHICS_EXT_D3D11, *out_session); 1235 - OXR_CREATE_XRT_SESSION_AND_NATIVE_COMPOSITOR(log, xsi, *out_session); 1236 return oxr_session_populate_d3d11(log, sys, d3d11, *out_session); 1237 } 1238 #endif ··· 1249 return oxr_error(log, XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING, 1250 "Has not called xrGetD3D12GraphicsRequirementsKHR"); 1251 } 1252 - XrResult result = oxr_d3d12_check_device(log, sys, d3d12->device); 1253 1254 - if (!XR_SUCCEEDED(result)) { 1255 - return result; 1256 } 1257 1258 1259 - OXR_SESSION_ALLOCATE_AND_INIT(log, sys, OXR_SESSION_GRAPHICS_EXT_D3D12, *out_session); 1260 - OXR_CREATE_XRT_SESSION_AND_NATIVE_COMPOSITOR(log, xsi, *out_session); 1261 return oxr_session_populate_d3d12(log, sys, d3d12, *out_session); 1262 } 1263 #endif ··· 1271 1272 #ifdef OXR_HAVE_MND_headless 1273 if (sys->inst->extensions.MND_headless) { 1274 - OXR_SESSION_ALLOCATE_AND_INIT(log, sys, OXR_SESSION_GRAPHICS_EXT_HEADLESS, *out_session); 1275 (*out_session)->compositor = NULL; 1276 (*out_session)->create_swapchain = NULL; 1277 ··· 1320 return ret; 1321 } 1322 1323 // Everything is in order, start the state changes. 1324 - oxr_session_change_state(log, sess, XR_SESSION_STATE_IDLE, 0); 1325 - oxr_session_change_state(log, sess, XR_SESSION_STATE_READY, 0); 1326 1327 *out_session = sess; 1328
··· 1 // Copyright 2018-2024, Collabora, Ltd. 2 + // Copyright 2024-2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 66 */ 67 68 static bool 69 + should_skip_format_vk_1_and_2(const struct oxr_instance *inst, uint64_t format) 70 + { 71 + bool skip_depth_stencil = inst->quirks.disable_vulkan_format_depth_stencil; 72 + bool skip_stencil = false; 73 + bool skip_depth = inst->quirks.disable_vulkan_format_depth; 74 + 75 + // Access to Vulkan headers are not guaranteed. 76 + switch (format) { 77 + case 124: /* VK_FORMAT_D16_UNORM */ return skip_depth; 78 + case 125: /* VK_FORMAT_X8_D24_UNORM_PACK32*/ return skip_depth; 79 + case 126: /* VK_FORMAT_D32_SFLOAT */ return skip_depth; 80 + case 127: /* VK_FORMAT_S8_UINT */ return skip_stencil; 81 + case 129: /* VK_FORMAT_D24_UNORM_S8_UINT */ return skip_depth_stencil; 82 + case 130: /* VK_FORMAT_D32_SFLOAT_S8_UINT */ return skip_depth_stencil; 83 + default: return false; 84 + } 85 + } 86 + 87 + static bool 88 + should_skip_format(const struct oxr_instance *inst, const struct oxr_session *sess, uint64_t format) 89 + { 90 + if (sess->gfx_ext == OXR_SESSION_GRAPHICS_EXT_VULKAN) { 91 + /* 92 + * Hello future computer whisperer, if we split the graphics 93 + * extension enum into Vulkan1 and Vulkan2, make sure we call this 94 + * function for both, kthx. 95 + */ 96 + return should_skip_format_vk_1_and_2(inst, format); 97 + } else { 98 + return false; 99 + } 100 + } 101 + 102 + static bool 103 should_render(XrSessionState state) 104 { 105 switch (state) { ··· 162 if (inst->quirks.map_stage_to_local_floor) { 163 /* When stage is mapped to local_floor: 164 * ignore stage changes 165 + * for local_floor changes, send a duplicate event for stage 166 * */ 167 switch (ref_change->ref_type) { 168 case XRT_SPACE_REFERENCE_TYPE_STAGE: return XR_SUCCESS; ··· 259 for (uint32_t i = 0; i < xc->info.format_count; i++) { 260 int64_t format = xc->info.formats[i]; 261 262 + if (should_skip_format(inst, sess, format)) { 263 continue; 264 } 265 ··· 283 284 struct xrt_compositor *xc = sess->compositor; 285 if (xc != NULL) { 286 const struct oxr_extension_status *extensions = &sess->sys->inst->extensions; 287 288 const struct xrt_begin_session_info begin_session_info = { ··· 317 #ifdef OXR_HAVE_META_body_tracking_calibration 318 .meta_body_tracking_calibration_enabled = extensions->META_body_tracking_calibration, 319 #endif 320 + #ifdef OXR_HAVE_ANDROID_face_tracking 321 + .android_face_tracking_enabled = extensions->ANDROID_face_tracking, 322 + #endif 323 }; 324 325 xrt_result_t xret = xrt_comp_begin_session(xc, &begin_session_info); ··· 338 // Headless, pretend we got event from the compositor. 339 sess->compositor_visible = true; 340 sess->compositor_focused = true; 341 + 342 + int64_t now = os_monotonic_get_ns(); 343 + XrTime now_xr = time_state_monotonic_to_ts_ns(sess->sys->inst->timekeeping, now); 344 + if (now_xr <= 0) { 345 + // shouldn't happen but be sure to log if it does 346 + U_LOG_W("Time keeping oddity: XR_SESSION_STATE_SYNCHRONIZED state reached at XrTime %" PRIi64, 347 + now_xr); 348 + } 349 350 // Transition into focused. 351 + oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, now_xr); 352 + oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE, now_xr); 353 + oxr_session_change_state(log, sess, XR_SESSION_STATE_FOCUSED, now_xr); 354 } 355 XrResult ret = oxr_frame_sync_begin_session(&sess->frame_sync); 356 if (ret != XR_SUCCESS) { ··· 358 "Frame sync object refused to let us begin session, probably already running"); 359 } 360 361 + // Set the current view configuration type, used in xrEndFrame. 362 + sess->current_view_config_type = beginInfo->primaryViewConfigurationType; 363 + 364 return oxr_session_success_result(sess); 365 } 366 ··· 408 sess->compositor_focused = false; 409 } 410 411 + int64_t now = os_monotonic_get_ns(); 412 + XrTime now_xr = time_state_monotonic_to_ts_ns(sess->sys->inst->timekeeping, now); 413 + if (now_xr <= 0) { 414 + // shouldn't happen but be sure to log if it does 415 + U_LOG_W("Time keeping oddity: ending session at XrTime %" PRIi64, now_xr); 416 + } 417 + 418 + oxr_session_change_state(log, sess, XR_SESSION_STATE_IDLE, now_xr); 419 if (sess->exiting) { 420 + oxr_session_change_state(log, sess, XR_SESSION_STATE_EXITING, now_xr); 421 } else { 422 #ifndef XRT_OS_ANDROID 423 // @todo In multi-clients scenario with a session being reused, changing session ··· 434 } 435 sess->has_ended_once = false; 436 437 + // Unset the current view configuration type here. 438 + sess->current_view_config_type = XR_VIEW_CONFIGURATION_TYPE_MAX_ENUM; 439 + 440 return oxr_session_success_result(sess); 441 } 442 443 XrResult 444 oxr_session_request_exit(struct oxr_logger *log, struct oxr_session *sess) 445 { 446 + int64_t now = os_monotonic_get_ns(); 447 + XrTime now_xr = time_state_monotonic_to_ts_ns(sess->sys->inst->timekeeping, now); 448 + if (now_xr <= 0) { 449 + // shouldn't happen but be sure to log if it does 450 + U_LOG_W("Time keeping oddity: Requesting exit at XrTime %" PRIi64, now_xr); 451 + } 452 + 453 if (sess->state == XR_SESSION_STATE_FOCUSED) { 454 + oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE, now_xr); 455 } 456 if (sess->state == XR_SESSION_STATE_VISIBLE) { 457 + oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, now_xr); 458 } 459 if (!sess->has_ended_once && sess->state != XR_SESSION_STATE_SYNCHRONIZED) { 460 + oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, now_xr); 461 // Fake the synchronization. 462 sess->has_ended_once = true; 463 } 464 465 //! @todo start fading out the app. 466 + oxr_session_change_state(log, sess, XR_SESSION_STATE_STOPPING, now_xr); 467 sess->exiting = true; 468 return oxr_session_success_result(sess); 469 } ··· 499 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "xrt_session is null"); 500 } 501 502 + int64_t now = os_monotonic_get_ns(); 503 + XrTime now_xr = time_state_monotonic_to_ts_ns(sess->sys->inst->timekeeping, now); 504 + if (now_xr <= 0) { 505 + // shouldn't happen but be sure to log if it does 506 + U_LOG_W("Time keeping oddity: Polling session events at XrTime %" PRIi64, now_xr); 507 + } 508 + 509 #ifdef XRT_OS_ANDROID 510 // Most recent Android activity lifecycle event was OnPause: move toward stopping 511 if (sess->sys->inst->activity_state == XRT_ANDROID_LIVECYCLE_EVENT_ON_PAUSE) { 512 if (sess->state == XR_SESSION_STATE_FOCUSED) { 513 U_LOG_I("Activity paused: changing session state FOCUSED->VISIBLE"); 514 + oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE, now_xr); 515 } 516 517 if (sess->state == XR_SESSION_STATE_VISIBLE) { 518 U_LOG_I("Activity paused: changing session state VISIBLE->SYNCHRONIZED"); 519 + oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, now_xr); 520 } 521 522 if (sess->state == XR_SESSION_STATE_SYNCHRONIZED) { 523 U_LOG_I("Activity paused: changing session state SYNCHRONIZED->STOPPING"); 524 + oxr_session_change_state(log, sess, XR_SESSION_STATE_STOPPING, now_xr); 525 } 526 // TODO return here to avoid polling other events? 527 // see https://gitlab.freedesktop.org/monado/monado/-/issues/419 ··· 531 if (sess->sys->inst->activity_state == XRT_ANDROID_LIVECYCLE_EVENT_ON_RESUME) { 532 if (sess->state == XR_SESSION_STATE_IDLE) { 533 U_LOG_I("Activity resumed: changing session state IDLE->READY"); 534 + oxr_session_change_state(log, sess, XR_SESSION_STATE_READY, now_xr); 535 } 536 } 537 #endif // XRT_OS_ANDROID ··· 551 case XRT_SESSION_EVENT_STATE_CHANGE: 552 sess->compositor_visible = xse.state.visible; 553 sess->compositor_focused = xse.state.focused; 554 + 555 + // Do not use xse.state.timestamp_ns, server side focused / visible state does not correspond 556 + // 1:1 to the cycle we tell the app. In particular the compositor may have become focused / 557 + // visible much earlier than what we tell the app when it became so. 558 + 559 break; 560 case XRT_SESSION_EVENT_OVERLAY_CHANGE: 561 #ifdef OXR_HAVE_EXTX_overlay ··· 595 break; 596 case XRT_SESSION_EVENT_VISIBILITY_MASK_CHANGE: 597 #ifdef OXR_HAVE_KHR_visibility_mask 598 + // Assume mask changed for all view configuration types. 599 + for (uint32_t i = 0; i < sess->sys->view_config_count; i++) { 600 + struct oxr_view_config_properties *props = &sess->sys->view_configs[i]; 601 + oxr_event_push_XrEventDataVisibilityMaskChangedKHR( // 602 + log, // 603 + sess, // 604 + props->view_config_type, // 605 + xse.mask_change.view_index); // 606 + } 607 break; 608 #endif // OXR_HAVE_KHR_visibility_mask 609 case XRT_SESSION_EVENT_USER_PRESENCE_CHANGE: ··· 617 } 618 619 if (sess->state == XR_SESSION_STATE_SYNCHRONIZED && sess->compositor_visible) { 620 + oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE, now_xr); 621 } 622 623 if (sess->state == XR_SESSION_STATE_VISIBLE && sess->compositor_focused) { 624 + oxr_session_change_state(log, sess, XR_SESSION_STATE_FOCUSED, now_xr); 625 } 626 627 if (sess->state == XR_SESSION_STATE_FOCUSED && !sess->compositor_focused) { 628 + oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE, now_xr); 629 } 630 631 if (sess->state == XR_SESSION_STATE_VISIBLE && !sess->compositor_visible) { 632 + oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, now_xr); 633 } 634 635 return XR_SUCCESS; ··· 727 struct xrt_space_relation T_xdev_head = XRT_SPACE_RELATION_ZERO; 728 struct xrt_fov fovs[XRT_MAX_VIEWS] = {0}; 729 struct xrt_pose poses[XRT_MAX_VIEWS] = {0}; 730 + 731 + enum xrt_view_type view_type = view_count == 1 ? XRT_VIEW_TYPE_MONO : XRT_VIEW_TYPE_STEREO; 732 733 xrt_result_t xret = xrt_device_get_view_poses( // 734 xdev, // 735 &default_eye_relation, // 736 xdisplay_time, // 737 + view_type, // 738 view_count, // 739 &T_xdev_head, // 740 fovs, // ··· 1122 u_hashmap_int_create(&sess->act_sets_attachments_by_key); 1123 u_hashmap_int_create(&sess->act_attachments_by_key); 1124 1125 + // This is set to something valid in begin session, used in xrEndFrame. 1126 + sess->current_view_config_type = XR_VIEW_CONFIGURATION_TYPE_MAX_ENUM; 1127 + 1128 // Done with basic init, set out variable. 1129 *out_session = sess; 1130 ··· 1139 } \ 1140 } while (false) 1141 1142 + #define OXR_CHECK_XR_SUCCESS(LOG, FUNC, MSG) \ 1143 do { \ 1144 + XrResult _xr_result = FUNC; \ 1145 + if (_xr_result != XR_SUCCESS) { \ 1146 + return oxr_error(LOG, _xr_result, MSG); \ 1147 } \ 1148 } while (false) 1149 1150 + 1151 + 1152 + static XrResult 1153 + oxr_create_xrt_session_and_native_compositor(struct oxr_logger *log, 1154 + const struct xrt_session_info *xsi, 1155 + struct oxr_session *sess) 1156 + { 1157 + if (sess->sys->xsysc == NULL) { 1158 + return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, 1159 + "The system compositor wasn't created, can't create native compositor!"); 1160 + } 1161 + xrt_result_t xret = xrt_system_create_session(sess->sys->xsys, xsi, &sess->xs, &sess->xcn); 1162 + if (xret == XRT_ERROR_MULTI_SESSION_NOT_IMPLEMENTED) { 1163 + return oxr_error(log, XR_ERROR_LIMIT_REACHED, "Per instance multi-session not supported."); 1164 + } 1165 + if (xret != XRT_SUCCESS) { 1166 + return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, 1167 + "Failed to create xrt_session and xrt_compositor_native! '%i'", xret); 1168 + } 1169 + if (sess->sys->xsysc->xmcc != NULL) { 1170 + xrt_syscomp_set_state(sess->sys->xsysc, &sess->xcn->base, true, true, os_monotonic_get_ns()); 1171 + xrt_syscomp_set_z_order(sess->sys->xsysc, &sess->xcn->base, 0); 1172 + } 1173 + return XR_SUCCESS; 1174 + } 1175 + 1176 1177 1178 /* ··· 1186 const struct xrt_session_info *xsi, 1187 struct oxr_session **out_session) 1188 { 1189 + XrResult ret = XR_SUCCESS; 1190 + 1191 #if defined(XR_USE_PLATFORM_XLIB) && defined(XR_USE_GRAPHICS_API_OPENGL) 1192 XrGraphicsBindingOpenGLXlibKHR const *opengl_xlib = OXR_GET_INPUT_FROM_CHAIN( 1193 createInfo, XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR, XrGraphicsBindingOpenGLXlibKHR); ··· 1200 "xrGetOpenGL[ES]GraphicsRequirementsKHR"); 1201 } 1202 1203 + ret = oxr_session_allocate_and_init(log, sys, OXR_SESSION_GRAPHICS_EXT_XLIB_GL, out_session); 1204 + OXR_CHECK_XR_SUCCESS(log, ret, "Failed to allocate session"); 1205 + 1206 + ret = oxr_create_xrt_session_and_native_compositor(log, xsi, *out_session); 1207 + OXR_CHECK_XR_SUCCESS(log, ret, "Failed to create session/compositor"); 1208 + 1209 return oxr_session_populate_gl_xlib(log, sys, opengl_xlib, *out_session); 1210 } 1211 #endif ··· 1223 "xrGetOpenGLESGraphicsRequirementsKHR"); 1224 } 1225 1226 + ret = oxr_session_allocate_and_init(log, sys, OXR_SESSION_GRAPHICS_EXT_ANDROID_GLES, out_session); 1227 + OXR_CHECK_XR_SUCCESS(log, ret, "Failed to allocate session"); 1228 + 1229 + ret = oxr_create_xrt_session_and_native_compositor(log, xsi, *out_session); 1230 + OXR_CHECK_XR_SUCCESS(log, ret, "Failed to create session/compositor"); 1231 + 1232 return oxr_session_populate_gles_android(log, sys, opengles_android, *out_session); 1233 } 1234 #endif ··· 1244 "Has not called xrGetOpenGLGraphicsRequirementsKHR"); 1245 } 1246 1247 + ret = oxr_session_allocate_and_init(log, sys, OXR_SESSION_GRAPHICS_EXT_WIN32_GL, out_session); 1248 + OXR_CHECK_XR_SUCCESS(log, ret, "Failed to allocate session"); 1249 + 1250 + ret = oxr_create_xrt_session_and_native_compositor(log, xsi, *out_session); 1251 + OXR_CHECK_XR_SUCCESS(log, ret, "Failed to create session/compositor"); 1252 + 1253 return oxr_session_populate_gl_win32(log, sys, opengl_win32, *out_session); 1254 } 1255 #endif ··· 1287 (void *)vulkan->physicalDevice, (void *)sys->suggested_vulkan_physical_device, fn); 1288 } 1289 1290 + ret = oxr_session_allocate_and_init(log, sys, OXR_SESSION_GRAPHICS_EXT_VULKAN, out_session); 1291 + OXR_CHECK_XR_SUCCESS(log, ret, "Failed to allocate session"); 1292 + 1293 + ret = oxr_create_xrt_session_and_native_compositor(log, xsi, *out_session); 1294 + OXR_CHECK_XR_SUCCESS(log, ret, "Failed to create session/compositor"); 1295 + 1296 return oxr_session_populate_vk(log, sys, vulkan, *out_session); 1297 } 1298 #endif ··· 1309 "xrGetOpenGL[ES]GraphicsRequirementsKHR"); 1310 } 1311 1312 + ret = oxr_session_allocate_and_init(log, sys, OXR_SESSION_GRAPHICS_EXT_EGL, out_session); 1313 + OXR_CHECK_XR_SUCCESS(log, ret, "Failed to allocate session"); 1314 + 1315 + ret = oxr_create_xrt_session_and_native_compositor(log, xsi, *out_session); 1316 + OXR_CHECK_XR_SUCCESS(log, ret, "Failed to create session/compositor"); 1317 + 1318 return oxr_session_populate_egl(log, sys, egl, *out_session); 1319 } 1320 #endif ··· 1331 return oxr_error(log, XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING, 1332 "Has not called xrGetD3D11GraphicsRequirementsKHR"); 1333 } 1334 + ret = oxr_d3d11_check_device(log, sys, d3d11->device); 1335 1336 + if (!XR_SUCCEEDED(ret)) { 1337 + return ret; 1338 } 1339 1340 + ret = oxr_session_allocate_and_init(log, sys, OXR_SESSION_GRAPHICS_EXT_D3D11, out_session); 1341 + OXR_CHECK_XR_SUCCESS(log, ret, "Failed to allocate session"); 1342 1343 + ret = oxr_create_xrt_session_and_native_compositor(log, xsi, *out_session); 1344 + OXR_CHECK_XR_SUCCESS(log, ret, "Failed to create session/compositor"); 1345 + 1346 return oxr_session_populate_d3d11(log, sys, d3d11, *out_session); 1347 } 1348 #endif ··· 1359 return oxr_error(log, XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING, 1360 "Has not called xrGetD3D12GraphicsRequirementsKHR"); 1361 } 1362 + ret = oxr_d3d12_check_device(log, sys, d3d12->device); 1363 1364 + if (!XR_SUCCEEDED(ret)) { 1365 + return ret; 1366 } 1367 1368 + ret = oxr_session_allocate_and_init(log, sys, OXR_SESSION_GRAPHICS_EXT_D3D12, out_session); 1369 + OXR_CHECK_XR_SUCCESS(log, ret, "Failed to allocate session"); 1370 1371 + ret = oxr_create_xrt_session_and_native_compositor(log, xsi, *out_session); 1372 + OXR_CHECK_XR_SUCCESS(log, ret, "Failed to create session/compositor"); 1373 + 1374 return oxr_session_populate_d3d12(log, sys, d3d12, *out_session); 1375 } 1376 #endif ··· 1384 1385 #ifdef OXR_HAVE_MND_headless 1386 if (sys->inst->extensions.MND_headless) { 1387 + 1388 + ret = oxr_session_allocate_and_init(log, sys, OXR_SESSION_GRAPHICS_EXT_HEADLESS, out_session); 1389 + OXR_CHECK_XR_SUCCESS(log, ret, "Failed to allocate session"); 1390 + 1391 (*out_session)->compositor = NULL; 1392 (*out_session)->create_swapchain = NULL; 1393 ··· 1436 return ret; 1437 } 1438 1439 + int64_t now = os_monotonic_get_ns(); 1440 + XrTime now_xr = time_state_monotonic_to_ts_ns(sess->sys->inst->timekeeping, now); 1441 + if (now_xr <= 0) { 1442 + // shouldn't happen but be sure to log if it does 1443 + U_LOG_W("Time keeping oddity: XR_SESSION_STATE_IDLE reached at XrTime %" PRIi64, now_xr); 1444 + } 1445 + 1446 // Everything is in order, start the state changes. 1447 + oxr_session_change_state(log, sess, XR_SESSION_STATE_IDLE, now_xr); 1448 + oxr_session_change_state(log, sess, XR_SESSION_STATE_READY, now_xr); 1449 1450 *out_session = sess; 1451
+32 -33
src/xrt/state_trackers/oxr/oxr_session_frame_end.c
··· 38 #include <assert.h> 39 40 41 /* 42 * 43 * Helper functions and defines. ··· 334 #endif 335 } 336 337 /* 338 * 339 * Verify functions. ··· 595 return ret; 596 } 597 598 - switch (sess->sys->view_config_type) { 599 case XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO: 600 if (proj->viewCount != 1) { 601 return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, ··· 612 layer_index, proj->viewCount); 613 } 614 break; 615 case XR_VIEW_CONFIGURATION_TYPE_PRIMARY_QUAD_VARJO: 616 if (proj->viewCount != 4) { 617 return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, ··· 631 default: 632 assert(false && "view type validation unimplemented"); 633 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "view type %d not supported", 634 - sess->sys->view_config_type); 635 break; 636 } 637 ··· 1164 #endif 1165 } 1166 1167 /* 1168 * 1169 * Submit functions. 1170 * 1171 */ 1172 1173 - /** 1174 * Turn the poses supplied with a composition layer into the poses the compositor wants. 1175 * 1176 * @param log logger 1177 * @param sess session 1178 * @param spc space that @p pose_ptr is supplied in 1179 * @param pose_ptr pose supplied with layer 1180 - * @param inv_offset inverse of the tracking origin offset 1181 * @param timestamp timestamp for pose 1182 * @param[out] out_pose Resulting view-space pose 1183 * @return true if successfully transformed into a view space pose ··· 1187 struct oxr_session *sess, 1188 struct oxr_space *spc, 1189 const struct xrt_pose *pose_ptr, 1190 - const struct xrt_pose *inv_offset, 1191 uint64_t timestamp, 1192 struct xrt_pose *out_pose) 1193 { ··· 1241 struct oxr_logger *log, 1242 XrCompositionLayerQuad *quad, 1243 struct xrt_device *head, 1244 - struct xrt_pose *inv_offset, 1245 uint64_t oxr_timestamp, 1246 uint64_t xrt_timestamp) 1247 { ··· 1253 struct xrt_pose *pose_ptr = (struct xrt_pose *)&quad->pose; 1254 1255 struct xrt_pose pose; 1256 - if (!handle_space(log, sess, spc, pose_ptr, inv_offset, oxr_timestamp, &pose)) { 1257 return XR_SUCCESS; 1258 } 1259 ··· 1292 struct oxr_logger *log, 1293 XrCompositionLayerProjection *proj, 1294 struct xrt_device *head, 1295 - struct xrt_pose *inv_offset, 1296 uint64_t oxr_timestamp, 1297 uint64_t xrt_timestamp) 1298 { ··· 1316 scs[i] = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_swapchain *, proj->views[i].subImage.swapchain); 1317 pose_ptr = (struct xrt_pose *)&proj->views[i].pose; 1318 1319 - if (!handle_space(log, sess, spc, pose_ptr, inv_offset, oxr_timestamp, &pose[i])) { 1320 return XR_SUCCESS; 1321 } 1322 } ··· 1398 struct oxr_logger *log, 1399 const XrCompositionLayerCubeKHR *cube, 1400 struct xrt_device *head, 1401 - struct xrt_pose *inv_offset, 1402 uint64_t oxr_timestamp, 1403 uint64_t xrt_timestamp) 1404 { ··· 1437 .position = XRT_VEC3_ZERO, 1438 }; 1439 1440 - if (!handle_space(log, sess, spc, &pose, inv_offset, oxr_timestamp, &data.cube.pose)) { 1441 return XR_SUCCESS; 1442 } 1443 ··· 1453 struct oxr_logger *log, 1454 const XrCompositionLayerCylinderKHR *cylinder, 1455 struct xrt_device *head, 1456 - struct xrt_pose *inv_offset, 1457 uint64_t oxr_timestamp, 1458 uint64_t xrt_timestamp) 1459 { ··· 1466 struct xrt_pose *pose_ptr = (struct xrt_pose *)&cylinder->pose; 1467 1468 struct xrt_pose pose; 1469 - if (!handle_space(log, sess, spc, pose_ptr, inv_offset, oxr_timestamp, &pose)) { 1470 return XR_SUCCESS; 1471 } 1472 ··· 1505 struct oxr_logger *log, 1506 const XrCompositionLayerEquirectKHR *equirect, 1507 struct xrt_device *head, 1508 - struct xrt_pose *inv_offset, 1509 uint64_t oxr_timestamp, 1510 uint64_t xrt_timestamp) 1511 { ··· 1517 struct xrt_pose *pose_ptr = (struct xrt_pose *)&equirect->pose; 1518 1519 struct xrt_pose pose; 1520 - if (!handle_space(log, sess, spc, pose_ptr, inv_offset, oxr_timestamp, &pose)) { 1521 return XR_SUCCESS; 1522 } 1523 ··· 1554 } 1555 1556 static void 1557 - do_synchronize_state_change(struct oxr_logger *log, struct oxr_session *sess) 1558 { 1559 if (!sess->has_ended_once && sess->state < XR_SESSION_STATE_VISIBLE) { 1560 - oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, 0); 1561 sess->has_ended_once = true; 1562 } 1563 } ··· 1568 struct oxr_logger *log, 1569 const XrCompositionLayerEquirect2KHR *equirect, 1570 struct xrt_device *head, 1571 - struct xrt_pose *inv_offset, 1572 uint64_t oxr_timestamp, 1573 uint64_t xrt_timestamp) 1574 { ··· 1580 struct xrt_pose *pose_ptr = (struct xrt_pose *)&equirect->pose; 1581 1582 struct xrt_pose pose; 1583 - if (!handle_space(log, sess, spc, pose_ptr, inv_offset, oxr_timestamp, &pose)) { 1584 return XR_SUCCESS; 1585 } 1586 ··· 1619 struct oxr_logger *log, 1620 const XrCompositionLayerPassthroughFB *passthrough, 1621 struct xrt_device *head, 1622 - struct xrt_pose *inv_offset, 1623 uint64_t oxr_timestamp, 1624 uint64_t xrt_timestamp) 1625 { ··· 1668 struct xrt_compositor *xc = sess->compositor; 1669 1670 1671 /* 1672 * Early out for headless sessions. 1673 */ ··· 1678 sess->active_wait_frames--; 1679 os_mutex_unlock(&sess->active_wait_frames_lock); 1680 1681 - do_synchronize_state_change(log, sess); 1682 1683 return oxr_session_success_result(sess); 1684 } ··· 1721 sess->frame_id.begun = -1; 1722 sess->frame_started = false; 1723 1724 - do_synchronize_state_change(log, sess); 1725 1726 return oxr_session_success_result(sess); 1727 } ··· 1790 */ 1791 1792 // Do state change if needed. 1793 - do_synchronize_state_change(log, sess); 1794 - 1795 - struct xrt_pose inv_offset = {0}; 1796 - math_pose_invert(&xdev->tracking_origin->initial_offset, &inv_offset); 1797 1798 struct xrt_layer_frame_data data = { 1799 .frame_id = sess->frame_id.begun, ··· 1811 1812 switch (layer->type) { 1813 case XR_TYPE_COMPOSITION_LAYER_PROJECTION: 1814 - submit_projection_layer(sess, xc, log, (XrCompositionLayerProjection *)layer, xdev, &inv_offset, 1815 frameEndInfo->displayTime, xrt_display_time_ns); 1816 break; 1817 case XR_TYPE_COMPOSITION_LAYER_QUAD: 1818 - submit_quad_layer(sess, xc, log, (XrCompositionLayerQuad *)layer, xdev, &inv_offset, 1819 frameEndInfo->displayTime, xrt_display_time_ns); 1820 break; 1821 case XR_TYPE_COMPOSITION_LAYER_CUBE_KHR: 1822 - submit_cube_layer(sess, xc, log, (XrCompositionLayerCubeKHR *)layer, xdev, &inv_offset, 1823 frameEndInfo->displayTime, xrt_display_time_ns); 1824 break; 1825 case XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR: 1826 - submit_cylinder_layer(sess, xc, log, (XrCompositionLayerCylinderKHR *)layer, xdev, &inv_offset, 1827 frameEndInfo->displayTime, xrt_display_time_ns); 1828 break; 1829 case XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR: 1830 - submit_equirect1_layer(sess, xc, log, (XrCompositionLayerEquirectKHR *)layer, xdev, &inv_offset, 1831 frameEndInfo->displayTime, xrt_display_time_ns); 1832 break; 1833 case XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR: 1834 submit_equirect2_layer(sess, xc, log, (XrCompositionLayerEquirect2KHR *)layer, xdev, 1835 - &inv_offset, frameEndInfo->displayTime, xrt_display_time_ns); 1836 break; 1837 case XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB: 1838 submit_passthrough_layer(sess, xc, log, (XrCompositionLayerPassthroughFB *)layer, xdev, 1839 - &inv_offset, frameEndInfo->displayTime, xrt_display_time_ns); 1840 break; 1841 default: assert(false && "invalid layer type"); 1842 }
··· 38 #include <assert.h> 39 40 41 + 42 /* 43 * 44 * Helper functions and defines. ··· 335 #endif 336 } 337 338 + 339 /* 340 * 341 * Verify functions. ··· 597 return ret; 598 } 599 600 + switch (sess->current_view_config_type) { 601 case XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO: 602 if (proj->viewCount != 1) { 603 return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, ··· 614 layer_index, proj->viewCount); 615 } 616 break; 617 + // This also includes XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO_WITH_FOVEATED_INSET as both values are the same 618 case XR_VIEW_CONFIGURATION_TYPE_PRIMARY_QUAD_VARJO: 619 if (proj->viewCount != 4) { 620 return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, ··· 634 default: 635 assert(false && "view type validation unimplemented"); 636 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "view type %d not supported", 637 + sess->current_view_config_type); 638 break; 639 } 640 ··· 1167 #endif 1168 } 1169 1170 + 1171 /* 1172 * 1173 * Submit functions. 1174 * 1175 */ 1176 1177 + /*! 1178 * Turn the poses supplied with a composition layer into the poses the compositor wants. 1179 * 1180 * @param log logger 1181 * @param sess session 1182 * @param spc space that @p pose_ptr is supplied in 1183 * @param pose_ptr pose supplied with layer 1184 * @param timestamp timestamp for pose 1185 * @param[out] out_pose Resulting view-space pose 1186 * @return true if successfully transformed into a view space pose ··· 1190 struct oxr_session *sess, 1191 struct oxr_space *spc, 1192 const struct xrt_pose *pose_ptr, 1193 uint64_t timestamp, 1194 struct xrt_pose *out_pose) 1195 { ··· 1243 struct oxr_logger *log, 1244 XrCompositionLayerQuad *quad, 1245 struct xrt_device *head, 1246 uint64_t oxr_timestamp, 1247 uint64_t xrt_timestamp) 1248 { ··· 1254 struct xrt_pose *pose_ptr = (struct xrt_pose *)&quad->pose; 1255 1256 struct xrt_pose pose; 1257 + if (!handle_space(log, sess, spc, pose_ptr, oxr_timestamp, &pose)) { 1258 return XR_SUCCESS; 1259 } 1260 ··· 1293 struct oxr_logger *log, 1294 XrCompositionLayerProjection *proj, 1295 struct xrt_device *head, 1296 uint64_t oxr_timestamp, 1297 uint64_t xrt_timestamp) 1298 { ··· 1316 scs[i] = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_swapchain *, proj->views[i].subImage.swapchain); 1317 pose_ptr = (struct xrt_pose *)&proj->views[i].pose; 1318 1319 + if (!handle_space(log, sess, spc, pose_ptr, oxr_timestamp, &pose[i])) { 1320 return XR_SUCCESS; 1321 } 1322 } ··· 1398 struct oxr_logger *log, 1399 const XrCompositionLayerCubeKHR *cube, 1400 struct xrt_device *head, 1401 uint64_t oxr_timestamp, 1402 uint64_t xrt_timestamp) 1403 { ··· 1436 .position = XRT_VEC3_ZERO, 1437 }; 1438 1439 + if (!handle_space(log, sess, spc, &pose, oxr_timestamp, &data.cube.pose)) { 1440 return XR_SUCCESS; 1441 } 1442 ··· 1452 struct oxr_logger *log, 1453 const XrCompositionLayerCylinderKHR *cylinder, 1454 struct xrt_device *head, 1455 uint64_t oxr_timestamp, 1456 uint64_t xrt_timestamp) 1457 { ··· 1464 struct xrt_pose *pose_ptr = (struct xrt_pose *)&cylinder->pose; 1465 1466 struct xrt_pose pose; 1467 + if (!handle_space(log, sess, spc, pose_ptr, oxr_timestamp, &pose)) { 1468 return XR_SUCCESS; 1469 } 1470 ··· 1503 struct oxr_logger *log, 1504 const XrCompositionLayerEquirectKHR *equirect, 1505 struct xrt_device *head, 1506 uint64_t oxr_timestamp, 1507 uint64_t xrt_timestamp) 1508 { ··· 1514 struct xrt_pose *pose_ptr = (struct xrt_pose *)&equirect->pose; 1515 1516 struct xrt_pose pose; 1517 + if (!handle_space(log, sess, spc, pose_ptr, oxr_timestamp, &pose)) { 1518 return XR_SUCCESS; 1519 } 1520 ··· 1551 } 1552 1553 static void 1554 + do_synchronize_state_change(struct oxr_logger *log, struct oxr_session *sess, XrTime time) 1555 { 1556 if (!sess->has_ended_once && sess->state < XR_SESSION_STATE_VISIBLE) { 1557 + oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, time); 1558 sess->has_ended_once = true; 1559 } 1560 } ··· 1565 struct oxr_logger *log, 1566 const XrCompositionLayerEquirect2KHR *equirect, 1567 struct xrt_device *head, 1568 uint64_t oxr_timestamp, 1569 uint64_t xrt_timestamp) 1570 { ··· 1576 struct xrt_pose *pose_ptr = (struct xrt_pose *)&equirect->pose; 1577 1578 struct xrt_pose pose; 1579 + if (!handle_space(log, sess, spc, pose_ptr, oxr_timestamp, &pose)) { 1580 return XR_SUCCESS; 1581 } 1582 ··· 1615 struct oxr_logger *log, 1616 const XrCompositionLayerPassthroughFB *passthrough, 1617 struct xrt_device *head, 1618 uint64_t oxr_timestamp, 1619 uint64_t xrt_timestamp) 1620 { ··· 1663 struct xrt_compositor *xc = sess->compositor; 1664 1665 1666 + int64_t now = os_monotonic_get_ns(); 1667 + XrTime now_xr = time_state_monotonic_to_ts_ns(sess->sys->inst->timekeeping, now); 1668 + if (now_xr <= 0) { 1669 + // shouldn't happen but be sure to log if it does 1670 + U_LOG_W("Time keeping oddity: frame end at XrTime %" PRIi64, now_xr); 1671 + } 1672 + 1673 /* 1674 * Early out for headless sessions. 1675 */ ··· 1680 sess->active_wait_frames--; 1681 os_mutex_unlock(&sess->active_wait_frames_lock); 1682 1683 + do_synchronize_state_change(log, sess, now_xr); 1684 1685 return oxr_session_success_result(sess); 1686 } ··· 1723 sess->frame_id.begun = -1; 1724 sess->frame_started = false; 1725 1726 + do_synchronize_state_change(log, sess, now_xr); 1727 1728 return oxr_session_success_result(sess); 1729 } ··· 1792 */ 1793 1794 // Do state change if needed. 1795 + do_synchronize_state_change(log, sess, now_xr); 1796 1797 struct xrt_layer_frame_data data = { 1798 .frame_id = sess->frame_id.begun, ··· 1810 1811 switch (layer->type) { 1812 case XR_TYPE_COMPOSITION_LAYER_PROJECTION: 1813 + submit_projection_layer(sess, xc, log, (XrCompositionLayerProjection *)layer, xdev, 1814 frameEndInfo->displayTime, xrt_display_time_ns); 1815 break; 1816 case XR_TYPE_COMPOSITION_LAYER_QUAD: 1817 + submit_quad_layer(sess, xc, log, (XrCompositionLayerQuad *)layer, xdev, 1818 frameEndInfo->displayTime, xrt_display_time_ns); 1819 break; 1820 case XR_TYPE_COMPOSITION_LAYER_CUBE_KHR: 1821 + submit_cube_layer(sess, xc, log, (XrCompositionLayerCubeKHR *)layer, xdev, 1822 frameEndInfo->displayTime, xrt_display_time_ns); 1823 break; 1824 case XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR: 1825 + submit_cylinder_layer(sess, xc, log, (XrCompositionLayerCylinderKHR *)layer, xdev, 1826 frameEndInfo->displayTime, xrt_display_time_ns); 1827 break; 1828 case XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR: 1829 + submit_equirect1_layer(sess, xc, log, (XrCompositionLayerEquirectKHR *)layer, xdev, 1830 frameEndInfo->displayTime, xrt_display_time_ns); 1831 break; 1832 case XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR: 1833 submit_equirect2_layer(sess, xc, log, (XrCompositionLayerEquirect2KHR *)layer, xdev, 1834 + frameEndInfo->displayTime, xrt_display_time_ns); 1835 break; 1836 case XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB: 1837 submit_passthrough_layer(sess, xc, log, (XrCompositionLayerPassthroughFB *)layer, xdev, 1838 + frameEndInfo->displayTime, xrt_display_time_ns); 1839 break; 1840 default: assert(false && "invalid layer type"); 1841 }
+18
src/xrt/state_trackers/oxr/oxr_space.c
··· 1 // Copyright 2019-2024, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 612 613 return ret; 614 }
··· 1 // Copyright 2019-2024, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 613 614 return ret; 615 } 616 + 617 + XrResult 618 + oxr_space_get_xrt_space(struct oxr_logger *log, struct oxr_space *spc, struct xrt_space **out_xspace) 619 + { 620 + assert(out_xspace != NULL); 621 + assert(*out_xspace == NULL); 622 + 623 + struct xrt_space *xspace = NULL; 624 + XrResult ret = get_xrt_space(log, spc, &xspace); 625 + if (ret != XR_SUCCESS) { 626 + return ret; 627 + } 628 + 629 + xrt_space_reference(out_xspace, xspace); 630 + 631 + return XR_SUCCESS; 632 + }
+224 -105
src/xrt/state_trackers/oxr/oxr_system.c
··· 18 #include "util/u_debug.h" 19 #include "util/u_verify.h" 20 21 #include "oxr_objects.h" 22 #include "oxr_logger.h" 23 #include "oxr_two_call.h" 24 - #include "oxr_chain.h" 25 - #include "oxr_api_verify.h" 26 - #include "oxr_conversions.h" 27 28 29 DEBUG_GET_ONCE_NUM_OPTION(scale_percentage, "OXR_VIEWPORT_SCALE_PERCENTAGE", 100) 30 31 32 33 static bool 34 oxr_system_matches(struct oxr_logger *log, struct oxr_system *sys, XrFormFactor form_factor) 35 { 36 return xr_form_factor_to_xrt(form_factor) == sys->xsys->properties.form_factor; 37 } 38 39 XrResult 40 oxr_system_select(struct oxr_logger *log, 41 struct oxr_system **systems, ··· 98 return XR_SUCCESS; 99 } 100 101 - 102 - 103 XrResult 104 oxr_system_fill_in( 105 struct oxr_logger *log, struct oxr_instance *inst, XrSystemId systemId, uint32_t view_count, struct oxr_system *sys) ··· 108 109 sys->inst = inst; 110 sys->systemId = systemId; 111 - if (view_count == 1) { 112 - sys->view_config_type = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO; 113 - } else if (view_count == 2) { 114 - sys->view_config_type = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO; 115 - } else { 116 - assert(false && "view_count must be 1 or 2"); 117 - } 118 - U_LOG_D("sys->view_config_type = %d", sys->view_config_type); 119 sys->dynamic_roles_cache = (struct xrt_system_roles)XRT_SYSTEM_ROLES_INIT; 120 121 #ifdef XR_USE_GRAPHICS_API_VULKAN 122 sys->vulkan_enable2_instance = VK_NULL_HANDLE; 123 sys->suggested_vulkan_physical_device = VK_NULL_HANDLE; 124 #endif 125 #if defined(XR_USE_GRAPHICS_API_D3D11) || defined(XR_USE_GRAPHICS_API_D3D12) 126 U_ZERO(&(sys->suggested_d3d_luid)); 127 sys->suggested_d3d_luid_valid = false; 128 #endif 129 130 - // Headless. 131 - if (sys->xsysc == NULL) { 132 - sys->blend_modes[0] = XR_ENVIRONMENT_BLEND_MODE_OPAQUE; 133 - sys->blend_mode_count = 1; 134 - return XR_SUCCESS; 135 - } 136 137 - double scale = debug_get_num_option_scale_percentage() / 100.0; 138 - if (scale > 2.0) { 139 - scale = 2.0; 140 - oxr_log(log, "Clamped scale to 200%%\n"); 141 - } 142 - 143 - struct xrt_system_compositor_info *info = &sys->xsysc->info; 144 - 145 - #define imin(a, b) (a < b ? a : b) 146 - for (uint32_t i = 0; i < view_count; ++i) { 147 - uint32_t w = (uint32_t)(info->views[i].recommended.width_pixels * scale); 148 - uint32_t h = (uint32_t)(info->views[i].recommended.height_pixels * scale); 149 - uint32_t w_2 = info->views[i].max.width_pixels; 150 - uint32_t h_2 = info->views[i].max.height_pixels; 151 - 152 - w = imin(w, w_2); 153 - h = imin(h, h_2); 154 - 155 - sys->views[i].recommendedImageRectWidth = w; 156 - sys->views[i].maxImageRectWidth = w_2; 157 - sys->views[i].recommendedImageRectHeight = h; 158 - sys->views[i].maxImageRectHeight = h_2; 159 - sys->views[i].recommendedSwapchainSampleCount = info->views[i].recommended.sample_count; 160 - sys->views[i].maxSwapchainSampleCount = info->views[i].max.sample_count; 161 - } 162 163 - #undef imin 164 - 165 - 166 - /* 167 - * Blend mode support. 168 - */ 169 170 - assert(info->supported_blend_mode_count <= ARRAY_SIZE(sys->blend_modes)); 171 - assert(info->supported_blend_mode_count != 0); 172 173 - for (uint8_t i = 0; i < info->supported_blend_mode_count; i++) { 174 - assert(u_verify_blend_mode_valid(info->supported_blend_modes[i])); 175 - sys->blend_modes[i] = (XrEnvironmentBlendMode)info->supported_blend_modes[i]; 176 } 177 - sys->blend_mode_count = (uint32_t)info->supported_blend_mode_count; 178 179 180 /* ··· 290 OXR_CHECK_RET_IS_FFB_SUPPORTED(conforming_right) 291 #undef OXR_CHECK_RET_IS_FFB_SUPPORTED 292 return false; 293 } 294 295 void ··· 351 return; 352 } 353 354 - static bool 355 - oxr_system_get_body_tracking_support(struct oxr_logger *log, 356 - struct oxr_instance *inst, 357 - const enum xrt_input_name body_tracking_name) 358 - { 359 - struct oxr_system *sys = &inst->system; 360 - const struct xrt_device *body = GET_XDEV_BY_ROLE(sys, body); 361 - if (body == NULL || !body->supported.body_tracking || body->inputs == NULL) { 362 - return false; 363 - } 364 - 365 - for (size_t input_idx = 0; input_idx < body->input_count; ++input_idx) { 366 - const struct xrt_input *input = &body->inputs[input_idx]; 367 - if (input->name == body_tracking_name) { 368 - return true; 369 - } 370 - } 371 - return false; 372 - } 373 - 374 bool 375 oxr_system_get_body_tracking_fb_support(struct oxr_logger *log, struct oxr_instance *inst) 376 { ··· 475 } 476 #endif 477 478 #ifdef OXR_HAVE_HTC_facial_tracking 479 XrSystemFacialTrackingPropertiesHTC *htc_facial_tracking_props = NULL; 480 if (sys->inst->extensions.HTC_facial_tracking) { ··· 595 uint32_t *viewConfigurationTypeCountOutput, 596 XrViewConfigurationType *viewConfigurationTypes) 597 { 598 - OXR_TWO_CALL_HELPER(log, viewConfigurationTypeCapacityInput, viewConfigurationTypeCountOutput, 599 - viewConfigurationTypes, 1, &sys->view_config_type, XR_SUCCESS); 600 } 601 602 XrResult ··· 607 uint32_t *environmentBlendModeCountOutput, 608 XrEnvironmentBlendMode *environmentBlendModes) 609 { 610 - //! @todo Take into account viewConfigurationType 611 OXR_TWO_CALL_HELPER(log, environmentBlendModeCapacityInput, environmentBlendModeCountOutput, 612 - environmentBlendModes, sys->blend_mode_count, sys->blend_modes, XR_SUCCESS); 613 } 614 615 XrResult ··· 618 XrViewConfigurationType viewConfigurationType, 619 XrViewConfigurationProperties *configurationProperties) 620 { 621 - if (viewConfigurationType != sys->view_config_type) { 622 - return oxr_error(log, XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED, "Invalid view configuration type"); 623 } 624 625 - configurationProperties->viewConfigurationType = sys->view_config_type; 626 configurationProperties->fovMutable = sys->xsysc->info.supports_fov_mutable; 627 628 return XR_SUCCESS; 629 } 630 631 - static void 632 - view_configuration_view_fill_in(XrViewConfigurationView *target_view, XrViewConfigurationView *source_view) 633 - { 634 - // clang-format off 635 - target_view->recommendedImageRectWidth = source_view->recommendedImageRectWidth; 636 - target_view->maxImageRectWidth = source_view->maxImageRectWidth; 637 - target_view->recommendedImageRectHeight = source_view->recommendedImageRectHeight; 638 - target_view->maxImageRectHeight = source_view->maxImageRectHeight; 639 - target_view->recommendedSwapchainSampleCount = source_view->recommendedSwapchainSampleCount; 640 - target_view->maxSwapchainSampleCount = source_view->maxSwapchainSampleCount; 641 - // clang-format on 642 - } 643 - 644 XrResult 645 oxr_system_enumerate_view_conf_views(struct oxr_logger *log, 646 struct oxr_system *sys, ··· 649 uint32_t *viewCountOutput, 650 XrViewConfigurationView *views) 651 { 652 - if (viewConfigurationType != sys->view_config_type) { 653 - return oxr_error(log, XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED, "Invalid view configuration type"); 654 - } 655 - if (sys->view_config_type == XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO) { 656 - OXR_TWO_CALL_FILL_IN_HELPER(log, viewCapacityInput, viewCountOutput, views, 1, 657 - view_configuration_view_fill_in, sys->views, XR_SUCCESS); 658 - } else { 659 - OXR_TWO_CALL_FILL_IN_HELPER(log, viewCapacityInput, viewCountOutput, views, 2, 660 - view_configuration_view_fill_in, sys->views, XR_SUCCESS); 661 } 662 }
··· 18 #include "util/u_debug.h" 19 #include "util/u_verify.h" 20 21 + #include "oxr_api_verify.h" 22 + #include "oxr_chain.h" 23 + #include "oxr_conversions.h" 24 #include "oxr_objects.h" 25 #include "oxr_logger.h" 26 #include "oxr_two_call.h" 27 28 29 + /* 30 + * 31 + * General helpers 32 + * 33 + */ 34 + 35 DEBUG_GET_ONCE_NUM_OPTION(scale_percentage, "OXR_VIEWPORT_SCALE_PERCENTAGE", 100) 36 37 38 39 + static struct oxr_view_config_properties * 40 + get_view_config_properties(struct oxr_system *sys, XrViewConfigurationType view_config_type) 41 + { 42 + for (uint32_t i = 0; i < sys->view_config_count; i++) { 43 + if (sys->view_configs[i].view_config_type == view_config_type) { 44 + return &sys->view_configs[i]; 45 + } 46 + } 47 + 48 + return NULL; 49 + } 50 + 51 + static void 52 + fill_in_view_config_properties_blend_modes(struct oxr_view_config_properties *props, 53 + const struct xrt_system_compositor_info *info) 54 + { 55 + // Headless path. 56 + if (info == NULL) { 57 + props->blend_modes[0] = XR_ENVIRONMENT_BLEND_MODE_OPAQUE; 58 + props->blend_mode_count = 1; 59 + return; 60 + } 61 + 62 + assert(info->supported_blend_mode_count <= ARRAY_SIZE(props->blend_modes)); 63 + assert(info->supported_blend_mode_count != 0); 64 + 65 + for (uint8_t i = 0; i < info->supported_blend_mode_count; i++) { 66 + assert(u_verify_blend_mode_valid(info->supported_blend_modes[i])); 67 + props->blend_modes[i] = (XrEnvironmentBlendMode)info->supported_blend_modes[i]; 68 + } 69 + props->blend_mode_count = (uint32_t)info->supported_blend_mode_count; 70 + } 71 + 72 + static void 73 + fill_in_view_config_properties_view_config_type(struct oxr_view_config_properties *props, enum xrt_view_type view_type) 74 + { 75 + props->view_config_type = xrt_view_type_to_xr(view_type); 76 + U_LOG_D("props->view_config_type = %d", props->view_config_type); 77 + } 78 + 79 + static void 80 + fill_in_view_config_properties_views(struct oxr_logger *log, 81 + XrViewConfigurationView *xr_views, 82 + const struct xrt_view_config *view_config) 83 + { 84 + assert(view_config->view_count <= XRT_MAX_COMPOSITOR_VIEW_CONFIGS_VIEW_COUNT); 85 + 86 + double scale = debug_get_num_option_scale_percentage() / 100.0; 87 + if (scale > 2.0) { 88 + scale = 2.0; 89 + oxr_log(log, "Clamped scale to 200%%\n"); 90 + } 91 + 92 + #define imin(a, b) (a < b ? a : b) 93 + for (uint32_t i = 0; i < view_config->view_count; ++i) { 94 + uint32_t w = (uint32_t)(view_config->views[i].recommended.width_pixels * scale); 95 + uint32_t h = (uint32_t)(view_config->views[i].recommended.height_pixels * scale); 96 + uint32_t w_2 = view_config->views[i].max.width_pixels; 97 + uint32_t h_2 = view_config->views[i].max.height_pixels; 98 + 99 + w = imin(w, w_2); 100 + h = imin(h, h_2); 101 + 102 + xr_views[i].type = XR_TYPE_VIEW_CONFIGURATION_VIEW; 103 + xr_views[i].recommendedImageRectWidth = w; 104 + xr_views[i].maxImageRectWidth = w_2; 105 + xr_views[i].recommendedImageRectHeight = h; 106 + xr_views[i].maxImageRectHeight = h_2; 107 + xr_views[i].recommendedSwapchainSampleCount = view_config->views[i].recommended.sample_count; 108 + xr_views[i].maxSwapchainSampleCount = view_config->views[i].max.sample_count; 109 + } 110 + #undef imin 111 + } 112 + 113 + static void 114 + fill_in_view_config_properties(struct oxr_logger *log, 115 + struct oxr_view_config_properties *props, 116 + const struct xrt_system_compositor_info *info, 117 + const struct xrt_view_config *view_config) 118 + { 119 + fill_in_view_config_properties_blend_modes(props, info); 120 + fill_in_view_config_properties_view_config_type(props, view_config->view_type); 121 + fill_in_view_config_properties_views(log, props->views, view_config); 122 + props->view_count = view_config->view_count; 123 + } 124 + 125 static bool 126 oxr_system_matches(struct oxr_logger *log, struct oxr_system *sys, XrFormFactor form_factor) 127 { 128 return xr_form_factor_to_xrt(form_factor) == sys->xsys->properties.form_factor; 129 } 130 131 + static bool 132 + oxr_system_get_body_tracking_support(struct oxr_logger *log, 133 + struct oxr_instance *inst, 134 + const enum xrt_input_name body_tracking_name) 135 + { 136 + struct oxr_system *sys = &inst->system; 137 + const struct xrt_device *body = GET_XDEV_BY_ROLE(sys, body); 138 + if (body == NULL || !body->supported.body_tracking || body->inputs == NULL) { 139 + return false; 140 + } 141 + 142 + for (size_t input_idx = 0; input_idx < body->input_count; ++input_idx) { 143 + const struct xrt_input *input = &body->inputs[input_idx]; 144 + if (input->name == body_tracking_name) { 145 + return true; 146 + } 147 + } 148 + return false; 149 + } 150 + 151 + 152 + /* 153 + * 154 + * Two-call helpers. 155 + * 156 + */ 157 + 158 + static void 159 + view_configuration_type_fill_in(XrViewConfigurationType *target, struct oxr_view_config_properties *source) 160 + { 161 + *target = source->view_config_type; 162 + } 163 + 164 + static void 165 + view_configuration_view_fill_in(XrViewConfigurationView *target_view, XrViewConfigurationView *source_view) 166 + { 167 + // clang-format off 168 + target_view->recommendedImageRectWidth = source_view->recommendedImageRectWidth; 169 + target_view->maxImageRectWidth = source_view->maxImageRectWidth; 170 + target_view->recommendedImageRectHeight = source_view->recommendedImageRectHeight; 171 + target_view->maxImageRectHeight = source_view->maxImageRectHeight; 172 + target_view->recommendedSwapchainSampleCount = source_view->recommendedSwapchainSampleCount; 173 + target_view->maxSwapchainSampleCount = source_view->maxSwapchainSampleCount; 174 + // clang-format on 175 + } 176 + 177 + 178 + /* 179 + * 180 + * 'Exported' functions. 181 + * 182 + */ 183 + 184 XrResult 185 oxr_system_select(struct oxr_logger *log, 186 struct oxr_system **systems, ··· 243 return XR_SUCCESS; 244 } 245 246 XrResult 247 oxr_system_fill_in( 248 struct oxr_logger *log, struct oxr_instance *inst, XrSystemId systemId, uint32_t view_count, struct oxr_system *sys) ··· 251 252 sys->inst = inst; 253 sys->systemId = systemId; 254 sys->dynamic_roles_cache = (struct xrt_system_roles)XRT_SYSTEM_ROLES_INIT; 255 256 #ifdef XR_USE_GRAPHICS_API_VULKAN 257 sys->vulkan_enable2_instance = VK_NULL_HANDLE; 258 sys->suggested_vulkan_physical_device = VK_NULL_HANDLE; 259 + sys->vk_get_instance_proc_addr = VK_NULL_HANDLE; 260 #endif 261 #if defined(XR_USE_GRAPHICS_API_D3D11) || defined(XR_USE_GRAPHICS_API_D3D12) 262 U_ZERO(&(sys->suggested_d3d_luid)); 263 sys->suggested_d3d_luid_valid = false; 264 #endif 265 266 + if (sys->xsysc != NULL) { 267 + const struct xrt_system_compositor_info *info = &sys->xsysc->info; 268 269 + for (uint32_t i = 0; i < info->view_config_count; i++) { 270 + const struct xrt_view_config *view_config = &info->view_configs[i]; 271 272 + assert(sys->view_config_count < XRT_MAX_COMPOSITOR_VIEW_CONFIGS_COUNT); 273 + fill_in_view_config_properties( // 274 + log, // 275 + &sys->view_configs[sys->view_config_count], // 276 + info, // 277 + view_config); // 278 + sys->view_config_count++; 279 + } 280 + } else { 281 + // Headless path, view configs contain no views but still need blend modes and view types. 282 + assert(view_count == 1 || view_count == 2); 283 284 + enum xrt_view_type view_type = view_count == 1 ? XRT_VIEW_TYPE_MONO : XRT_VIEW_TYPE_STEREO; 285 286 + // First headless config: regular mono or stereo 287 + fill_in_view_config_properties_blend_modes(&sys->view_configs[0], NULL); 288 + fill_in_view_config_properties_view_config_type(&sys->view_configs[0], view_type); 289 + sys->view_config_count++; 290 } 291 292 293 /* ··· 403 OXR_CHECK_RET_IS_FFB_SUPPORTED(conforming_right) 404 #undef OXR_CHECK_RET_IS_FFB_SUPPORTED 405 return false; 406 + } 407 + 408 + void 409 + oxr_system_get_face_tracking_android_support(struct oxr_logger *log, struct oxr_instance *inst, bool *supported) 410 + { 411 + assert(supported); 412 + 413 + *supported = false; 414 + struct oxr_system *sys = &inst->system; 415 + const struct xrt_device *face_xdev = GET_XDEV_BY_ROLE(sys, face); 416 + 417 + if (face_xdev == NULL || !face_xdev->supported.face_tracking || face_xdev->inputs == NULL) { 418 + return; 419 + } 420 + 421 + for (size_t input_idx = 0; input_idx < face_xdev->input_count; ++input_idx) { 422 + const struct xrt_input *input = &face_xdev->inputs[input_idx]; 423 + if (input->name == XRT_INPUT_ANDROID_FACE_TRACKING) { 424 + *supported = true; 425 + return; 426 + } 427 + } 428 } 429 430 void ··· 486 return; 487 } 488 489 bool 490 oxr_system_get_body_tracking_fb_support(struct oxr_logger *log, struct oxr_instance *inst) 491 { ··· 590 } 591 #endif 592 593 + #ifdef OXR_HAVE_ANDROID_face_tracking 594 + XrSystemFaceTrackingPropertiesANDROID *android_face_tracking_props = NULL; 595 + if (sys->inst->extensions.ANDROID_face_tracking) { 596 + android_face_tracking_props = OXR_GET_OUTPUT_FROM_CHAIN( 597 + properties, XR_TYPE_SYSTEM_FACE_TRACKING_PROPERTIES_ANDROID, XrSystemFaceTrackingPropertiesANDROID); 598 + } 599 + 600 + if (android_face_tracking_props) { 601 + bool supported = false; 602 + oxr_system_get_face_tracking_android_support(log, sys->inst, &supported); 603 + android_face_tracking_props->supportsFaceTracking = supported; 604 + } 605 + #endif // OXR_HAVE_HTC_facial_tracking 606 + 607 #ifdef OXR_HAVE_HTC_facial_tracking 608 XrSystemFacialTrackingPropertiesHTC *htc_facial_tracking_props = NULL; 609 if (sys->inst->extensions.HTC_facial_tracking) { ··· 724 uint32_t *viewConfigurationTypeCountOutput, 725 XrViewConfigurationType *viewConfigurationTypes) 726 { 727 + OXR_TWO_CALL_FILL_IN_HELPER(log, viewConfigurationTypeCapacityInput, viewConfigurationTypeCountOutput, 728 + viewConfigurationTypes, sys->view_config_count, view_configuration_type_fill_in, 729 + sys->view_configs, XR_SUCCESS); 730 } 731 732 XrResult ··· 737 uint32_t *environmentBlendModeCountOutput, 738 XrEnvironmentBlendMode *environmentBlendModes) 739 { 740 + struct oxr_view_config_properties *props = get_view_config_properties(sys, viewConfigurationType); 741 + if (props == NULL) { 742 + return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Didn't find view configs"); 743 + } 744 + 745 OXR_TWO_CALL_HELPER(log, environmentBlendModeCapacityInput, environmentBlendModeCountOutput, 746 + environmentBlendModes, props->blend_mode_count, props->blend_modes, XR_SUCCESS); 747 } 748 749 XrResult ··· 752 XrViewConfigurationType viewConfigurationType, 753 XrViewConfigurationProperties *configurationProperties) 754 { 755 + struct oxr_view_config_properties *props = get_view_config_properties(sys, viewConfigurationType); 756 + if (props == NULL) { 757 + return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Didn't find view configs"); 758 } 759 760 + configurationProperties->viewConfigurationType = props->view_config_type; 761 configurationProperties->fovMutable = sys->xsysc->info.supports_fov_mutable; 762 763 return XR_SUCCESS; 764 } 765 766 XrResult 767 oxr_system_enumerate_view_conf_views(struct oxr_logger *log, 768 struct oxr_system *sys, ··· 771 uint32_t *viewCountOutput, 772 XrViewConfigurationView *views) 773 { 774 + struct oxr_view_config_properties *props = get_view_config_properties(sys, viewConfigurationType); 775 + if (props == NULL) { 776 + return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Didn't find view configs"); 777 } 778 + 779 + OXR_TWO_CALL_FILL_IN_HELPER(log, viewCapacityInput, viewCountOutput, views, props->view_count, 780 + view_configuration_view_fill_in, props->views, XR_SUCCESS); 781 }
+36 -12
src/xrt/state_trackers/oxr/oxr_two_call.h
··· 14 extern "C" { 15 #endif 16 17 - 18 - #define OXR_TWO_CALL_HELPER(log, cnt_input, cnt_output, output, count, data, sval) \ 19 do { \ 20 if ((cnt_output) == NULL) { \ 21 return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, #cnt_output); \ ··· 28 if ((cnt_input) < (uint32_t)(count)) { \ 29 return oxr_error(log, XR_ERROR_SIZE_INSUFFICIENT, #cnt_input); \ 30 } \ 31 for (uint32_t i = 0; i < (count); i++) { \ 32 (output)[i] = (data)[i]; \ 33 } \ ··· 37 //! Calls fill_fn(&output_struct[i], &source_struct[i]) to fill output_structs 38 #define OXR_TWO_CALL_FILL_IN_HELPER(log, cnt_input, cnt_output, output_structs, count, fill_fn, source_structs, sval) \ 39 do { \ 40 - if (cnt_output == NULL) { \ 41 - return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, #cnt_output); \ 42 - } \ 43 - *cnt_output = count; \ 44 \ 45 - if (cnt_input == 0) { \ 46 - return sval; \ 47 - } \ 48 - if (cnt_input < count) { \ 49 - return oxr_error(log, XR_ERROR_SIZE_INSUFFICIENT, #cnt_input); \ 50 - } \ 51 for (uint32_t i = 0; i < count; i++) { \ 52 fill_fn(&output_structs[i], &source_structs[i]); \ 53 } \ 54 return sval; \ 55 } while (false) 56 57 #ifdef __cplusplus
··· 14 extern "C" { 15 #endif 16 17 + #define OXR_TWO_CALL_CHECK_ONLY(log, cnt_input, cnt_output, count, sval) \ 18 do { \ 19 if ((cnt_output) == NULL) { \ 20 return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, #cnt_output); \ ··· 27 if ((cnt_input) < (uint32_t)(count)) { \ 28 return oxr_error(log, XR_ERROR_SIZE_INSUFFICIENT, #cnt_input); \ 29 } \ 30 + } while (false) 31 + 32 + #define OXR_TWO_CALL_CHECK_GOTO(log, cnt_input, cnt_output, count, sval, goto_label) \ 33 + do { \ 34 + if ((cnt_output) == NULL) { \ 35 + sval = oxr_error(log, XR_ERROR_VALIDATION_FAILURE, #cnt_output); \ 36 + goto goto_label; \ 37 + } \ 38 + *(cnt_output) = (uint32_t)(count); \ 39 + \ 40 + if ((cnt_input) == 0) { \ 41 + goto goto_label; \ 42 + } \ 43 + if ((cnt_input) < (uint32_t)(count)) { \ 44 + sval = oxr_error(log, XR_ERROR_SIZE_INSUFFICIENT, #cnt_input); \ 45 + goto goto_label; \ 46 + } \ 47 + } while (false) 48 + 49 + #define OXR_TWO_CALL_HELPER(log, cnt_input, cnt_output, output, count, data, sval) \ 50 + do { \ 51 + OXR_TWO_CALL_CHECK_ONLY(log, cnt_input, cnt_output, count, sval); \ 52 + \ 53 for (uint32_t i = 0; i < (count); i++) { \ 54 (output)[i] = (data)[i]; \ 55 } \ ··· 59 //! Calls fill_fn(&output_struct[i], &source_struct[i]) to fill output_structs 60 #define OXR_TWO_CALL_FILL_IN_HELPER(log, cnt_input, cnt_output, output_structs, count, fill_fn, source_structs, sval) \ 61 do { \ 62 + OXR_TWO_CALL_CHECK_ONLY(log, cnt_input, cnt_output, count, sval); \ 63 \ 64 for (uint32_t i = 0; i < count; i++) { \ 65 fill_fn(&output_structs[i], &source_structs[i]); \ 66 } \ 67 return sval; \ 68 + } while (false) 69 + 70 + //! Calls fill_fn(&output_struct[i], &source_struct[i]) to fill output_structs 71 + #define OXR_TWO_CALL_FILL_IN_GOTO(log, cnt_input, cnt_output, output_structs, count, fill_macro, source_structs, sval, \ 72 + goto_label) \ 73 + do { \ 74 + OXR_TWO_CALL_CHECK_GOTO(log, cnt_input, cnt_output, count, sval, goto_label); \ 75 + \ 76 + for (uint32_t i = 0; i < count; i++) { \ 77 + fill_macro(output_structs[i], source_structs[i]); \ 78 + } \ 79 } while (false) 80 81 #ifdef __cplusplus
+22
src/xrt/state_trackers/oxr/oxr_verify.c
··· 1 // Copyright 2018-2022, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 424 } 425 #endif 426 427 if (extensions->EXT_dpad_binding && !extensions->KHR_binding_modification) { 428 return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, 429 "XR_EXT_dpad_binding requires XR_KHR_binding_modification"); 430 } 431 432 return XR_SUCCESS; 433 } ··· 444 return XR_SUCCESS; 445 } 446 447 if (OXR_API_VERSION_AT_LEAST(inst, 1, 1)) { 448 if (view_conf == XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO_WITH_FOVEATED_INSET) { 449 return XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED; ··· 452 453 return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, "(%s == 0x%08x) invalid view configuration type", 454 view_conf_name, view_conf); 455 } 456 457 XrResult
··· 1 // Copyright 2018-2022, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 425 } 426 #endif 427 428 + #ifdef OXR_HAVE_EXT_dpad_binding 429 if (extensions->EXT_dpad_binding && !extensions->KHR_binding_modification) { 430 return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, 431 "XR_EXT_dpad_binding requires XR_KHR_binding_modification"); 432 } 433 + #endif 434 435 return XR_SUCCESS; 436 } ··· 447 return XR_SUCCESS; 448 } 449 450 + // Valid in OpenXR 1.1 and forward. 451 if (OXR_API_VERSION_AT_LEAST(inst, 1, 1)) { 452 if (view_conf == XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO_WITH_FOVEATED_INSET) { 453 return XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED; ··· 456 457 return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, "(%s == 0x%08x) invalid view configuration type", 458 view_conf_name, view_conf); 459 + } 460 + 461 + XrResult 462 + oxr_verify_view_config_type_supported(struct oxr_logger *log, 463 + struct oxr_system *sys, 464 + XrViewConfigurationType view_conf, 465 + const char *view_conf_name) 466 + { 467 + for (uint32_t i = 0; i < sys->view_config_count; i++) { 468 + struct oxr_view_config_properties *props = &sys->view_configs[i]; 469 + if (props->view_config_type == view_conf) { 470 + return XR_SUCCESS; 471 + } 472 + } 473 + 474 + return oxr_error(log, XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED, 475 + "(%s == 0x%08x) unsupported view configuration type by system %zu", view_conf_name, view_conf, 476 + sys->systemId); 477 } 478 479 XrResult
+41 -45
src/xrt/state_trackers/oxr/oxr_vulkan.c
··· 1 // Copyright 2018-2024, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 31 * 32 */ 33 34 - #define GET_PROC(name) PFN_##name name = (PFN_##name)getProc(vkInstance, #name) 35 36 #define UUID_STR_SIZE (XRT_UUID_SIZE * 3 + 1) 37 ··· 190 191 static XrResult 192 vk_get_instance_ext_props(struct oxr_logger *log, 193 - VkInstance instance, 194 - PFN_vkGetInstanceProcAddr GetInstanceProcAddr, 195 VkExtensionProperties **out_props, 196 uint32_t *out_prop_count) 197 { 198 - PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties = 199 - (PFN_vkEnumerateInstanceExtensionProperties)vkGetInstanceProcAddr(NULL, 200 - "vkEnumerateInstanceExtensionProperties"); 201 202 - if (!EnumerateInstanceExtensionProperties) { 203 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, 204 - "Failed to get EnumerateInstanceExtensionProperties fp"); 205 } 206 207 uint32_t prop_count = 0; 208 - VkResult res = EnumerateInstanceExtensionProperties(NULL, &prop_count, NULL); 209 if (res != VK_SUCCESS) { 210 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, 211 "Failed to enumerate instance extension properties count (%d)", res); ··· 214 215 VkExtensionProperties *props = U_TYPED_ARRAY_CALLOC(VkExtensionProperties, prop_count); 216 217 - res = EnumerateInstanceExtensionProperties(NULL, &prop_count, props); 218 if (res != VK_SUCCESS) { 219 free(props); 220 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, ··· 235 VkResult *vulkanResult) 236 { 237 238 - PFN_vkGetInstanceProcAddr GetInstanceProcAddr = createInfo->pfnGetInstanceProcAddr; 239 240 - PFN_vkCreateInstance CreateInstance = (PFN_vkCreateInstance)GetInstanceProcAddr(NULL, "vkCreateInstance"); 241 - if (!CreateInstance) { 242 //! @todo: clarify in spec 243 *vulkanResult = VK_ERROR_INITIALIZATION_FAILED; 244 return XR_SUCCESS; ··· 284 modified_info.ppEnabledExtensionNames = u_string_list_get_data(instance_ext_list); 285 modified_info.enabledExtensionCount = u_string_list_get_size(instance_ext_list); 286 287 - *vulkanResult = CreateInstance(&modified_info, createInfo->vulkanAllocator, vulkanInstance); 288 289 290 // Logging ··· 315 316 static XrResult 317 vk_get_device_ext_props(struct oxr_logger *log, 318 - VkInstance instance, 319 - PFN_vkGetInstanceProcAddr GetInstanceProcAddr, 320 VkPhysicalDevice physical_device, 321 VkExtensionProperties **out_props, 322 uint32_t *out_prop_count) 323 { 324 - PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties = 325 - (PFN_vkEnumerateDeviceExtensionProperties)GetInstanceProcAddr(instance, 326 - "vkEnumerateDeviceExtensionProperties"); 327 328 - if (!EnumerateDeviceExtensionProperties) { 329 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, 330 - "Failed to get vkEnumerateDeviceExtensionProperties fp"); 331 } 332 333 uint32_t prop_count = 0; 334 - VkResult res = EnumerateDeviceExtensionProperties(physical_device, NULL, &prop_count, NULL); 335 if (res != VK_SUCCESS) { 336 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, 337 "Failed to enumerate device extension properties count (%d)", res); ··· 340 341 VkExtensionProperties *props = U_TYPED_ARRAY_CALLOC(VkExtensionProperties, prop_count); 342 343 - res = EnumerateDeviceExtensionProperties(physical_device, NULL, &prop_count, props); 344 if (res != VK_SUCCESS) { 345 free(props); 346 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Failed to enumerate device extension properties (%d)", ··· 355 356 static XrResult 357 vk_get_device_features(struct oxr_logger *log, 358 - VkInstance instance, 359 - PFN_vkGetInstanceProcAddr GetInstanceProcAddr, 360 VkPhysicalDevice physical_device, 361 VkPhysicalDeviceFeatures2KHR *physical_device_features) 362 { 363 - PFN_vkGetPhysicalDeviceFeatures2KHR GetPhysicalDeviceFeatures2 = 364 - (PFN_vkGetPhysicalDeviceFeatures2KHR)GetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2KHR"); 365 366 - if (!GetPhysicalDeviceFeatures2) { 367 - oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Failed to get vkGetPhysicalDeviceFeatures2 fp"); 368 } 369 370 - GetPhysicalDeviceFeatures2( // 371 - physical_device, // physicalDevice 372 - physical_device_features); // pFeatures 373 374 return XR_SUCCESS; 375 } ··· 395 { 396 XrResult res; 397 398 - PFN_vkGetInstanceProcAddr GetInstanceProcAddr = createInfo->pfnGetInstanceProcAddr; 399 400 - PFN_vkCreateDevice CreateDevice = 401 - (PFN_vkCreateDevice)GetInstanceProcAddr(sys->vulkan_enable2_instance, "vkCreateDevice"); 402 - if (!CreateDevice) { 403 //! @todo: clarify in spec 404 *vulkanResult = VK_ERROR_INITIALIZATION_FAILED; 405 return XR_SUCCESS; ··· 513 } 514 #endif 515 516 - *vulkanResult = CreateDevice(physical_device, &modified_info, createInfo->vulkanAllocator, vulkanDevice); 517 518 519 // Logging ··· 571 oxr_vk_get_physical_device(struct oxr_logger *log, 572 struct oxr_instance *inst, 573 struct oxr_system *sys, 574 - VkInstance vkInstance, 575 - PFN_vkGetInstanceProcAddr getProc, 576 VkPhysicalDevice *vkPhysicalDevice) 577 { 578 - GET_PROC(vkEnumeratePhysicalDevices); 579 - GET_PROC(vkGetPhysicalDeviceProperties2KHR); 580 VkResult vk_ret; 581 uint32_t count; 582 ··· 584 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, " sys->xsysc == NULL"); 585 } 586 587 - vk_ret = vkEnumeratePhysicalDevices(vkInstance, &count, NULL); 588 if (vk_ret != VK_SUCCESS) { 589 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Call to vkEnumeratePhysicalDevices returned %u", 590 vk_ret); ··· 595 } 596 597 VkPhysicalDevice *phys = U_TYPED_ARRAY_CALLOC(VkPhysicalDevice, count); 598 - vk_ret = vkEnumeratePhysicalDevices(vkInstance, &count, phys); 599 if (vk_ret != VK_SUCCESS) { 600 free(phys); 601 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Call to vkEnumeratePhysicalDevices returned %u", ··· 622 .pNext = &pdidp, 623 }; 624 625 - vkGetPhysicalDeviceProperties2KHR(phys[i], &pdp2); 626 627 // These should always be true 628 static_assert(VK_UUID_SIZE == XRT_UUID_SIZE, "uuid sizes mismatch"); ··· 656 657 // vulkan_enable2 needs the physical device in xrCreateVulkanDeviceKHR 658 if (inst->extensions.KHR_vulkan_enable2) { 659 - sys->vulkan_enable2_instance = vkInstance; 660 } 661 sys->suggested_vulkan_physical_device = *vkPhysicalDevice; 662 if (log_level <= U_LOGGING_DEBUG) {
··· 1 // Copyright 2018-2024, Collabora, Ltd. 2 + // Copyright 2024-2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 32 * 33 */ 34 35 + #define GET_PROC(INST, NAME) PFN_vk##NAME loaded_##NAME = (PFN_vk##NAME)vulkanGetInstanceProcAddr(INST, "vk" #NAME) 36 37 #define UUID_STR_SIZE (XRT_UUID_SIZE * 3 + 1) 38 ··· 191 192 static XrResult 193 vk_get_instance_ext_props(struct oxr_logger *log, 194 + VkInstance vulkanInstance, 195 + PFN_vkGetInstanceProcAddr vulkanGetInstanceProcAddr, 196 VkExtensionProperties **out_props, 197 uint32_t *out_prop_count) 198 { 199 + GET_PROC(vulkanInstance, EnumerateInstanceExtensionProperties); 200 201 + if (!loaded_EnumerateInstanceExtensionProperties) { 202 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, 203 + "Failed to get vkEnumerateInstanceExtensionProperties function pointer."); 204 } 205 206 uint32_t prop_count = 0; 207 + VkResult res = loaded_EnumerateInstanceExtensionProperties(NULL, &prop_count, NULL); 208 if (res != VK_SUCCESS) { 209 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, 210 "Failed to enumerate instance extension properties count (%d)", res); ··· 213 214 VkExtensionProperties *props = U_TYPED_ARRAY_CALLOC(VkExtensionProperties, prop_count); 215 216 + res = loaded_EnumerateInstanceExtensionProperties(NULL, &prop_count, props); 217 if (res != VK_SUCCESS) { 218 free(props); 219 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, ··· 234 VkResult *vulkanResult) 235 { 236 237 + PFN_vkGetInstanceProcAddr vulkanGetInstanceProcAddr = createInfo->pfnGetInstanceProcAddr; 238 + GET_PROC(NULL, CreateInstance); 239 240 + if (!loaded_CreateInstance) { 241 //! @todo: clarify in spec 242 *vulkanResult = VK_ERROR_INITIALIZATION_FAILED; 243 return XR_SUCCESS; ··· 283 modified_info.ppEnabledExtensionNames = u_string_list_get_data(instance_ext_list); 284 modified_info.enabledExtensionCount = u_string_list_get_size(instance_ext_list); 285 286 + *vulkanResult = loaded_CreateInstance(&modified_info, createInfo->vulkanAllocator, vulkanInstance); 287 288 289 // Logging ··· 314 315 static XrResult 316 vk_get_device_ext_props(struct oxr_logger *log, 317 + VkInstance vulkanInstance, 318 + PFN_vkGetInstanceProcAddr vulkanGetInstanceProcAddr, 319 VkPhysicalDevice physical_device, 320 VkExtensionProperties **out_props, 321 uint32_t *out_prop_count) 322 { 323 + GET_PROC(vulkanInstance, EnumerateDeviceExtensionProperties); 324 325 + if (!loaded_EnumerateDeviceExtensionProperties) { 326 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, 327 + "Failed to get vkEnumerateDeviceExtensionProperties function pointer"); 328 } 329 330 uint32_t prop_count = 0; 331 + VkResult res = loaded_EnumerateDeviceExtensionProperties(physical_device, NULL, &prop_count, NULL); 332 if (res != VK_SUCCESS) { 333 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, 334 "Failed to enumerate device extension properties count (%d)", res); ··· 337 338 VkExtensionProperties *props = U_TYPED_ARRAY_CALLOC(VkExtensionProperties, prop_count); 339 340 + res = loaded_EnumerateDeviceExtensionProperties(physical_device, NULL, &prop_count, props); 341 if (res != VK_SUCCESS) { 342 free(props); 343 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Failed to enumerate device extension properties (%d)", ··· 352 353 static XrResult 354 vk_get_device_features(struct oxr_logger *log, 355 + VkInstance vulkanInstance, 356 + PFN_vkGetInstanceProcAddr vulkanGetInstanceProcAddr, 357 VkPhysicalDevice physical_device, 358 VkPhysicalDeviceFeatures2KHR *physical_device_features) 359 { 360 + GET_PROC(vulkanInstance, GetPhysicalDeviceFeatures2KHR); 361 362 + if (!loaded_GetPhysicalDeviceFeatures2KHR) { 363 + oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Failed to get vkGetPhysicalDeviceFeatures2KHR fp"); 364 } 365 366 + loaded_GetPhysicalDeviceFeatures2KHR( // 367 + physical_device, // physicalDevice 368 + physical_device_features); // pFeatures 369 370 return XR_SUCCESS; 371 } ··· 391 { 392 XrResult res; 393 394 + PFN_vkGetInstanceProcAddr vulkanGetInstanceProcAddr = createInfo->pfnGetInstanceProcAddr; 395 + GET_PROC(sys->vulkan_enable2_instance, CreateDevice); 396 397 + if (!loaded_CreateDevice) { 398 //! @todo: clarify in spec 399 *vulkanResult = VK_ERROR_INITIALIZATION_FAILED; 400 return XR_SUCCESS; ··· 508 } 509 #endif 510 511 + *vulkanResult = loaded_CreateDevice(physical_device, &modified_info, createInfo->vulkanAllocator, vulkanDevice); 512 513 514 // Logging ··· 566 oxr_vk_get_physical_device(struct oxr_logger *log, 567 struct oxr_instance *inst, 568 struct oxr_system *sys, 569 + VkInstance vulkanInstance, 570 + PFN_vkGetInstanceProcAddr vulkanGetInstanceProcAddr, 571 VkPhysicalDevice *vkPhysicalDevice) 572 { 573 + GET_PROC(vulkanInstance, EnumeratePhysicalDevices); 574 + GET_PROC(vulkanInstance, GetPhysicalDeviceProperties2KHR); 575 + 576 VkResult vk_ret; 577 uint32_t count; 578 ··· 580 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, " sys->xsysc == NULL"); 581 } 582 583 + vk_ret = loaded_EnumeratePhysicalDevices(vulkanInstance, &count, NULL); 584 if (vk_ret != VK_SUCCESS) { 585 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Call to vkEnumeratePhysicalDevices returned %u", 586 vk_ret); ··· 591 } 592 593 VkPhysicalDevice *phys = U_TYPED_ARRAY_CALLOC(VkPhysicalDevice, count); 594 + vk_ret = loaded_EnumeratePhysicalDevices(vulkanInstance, &count, phys); 595 if (vk_ret != VK_SUCCESS) { 596 free(phys); 597 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Call to vkEnumeratePhysicalDevices returned %u", ··· 618 .pNext = &pdidp, 619 }; 620 621 + loaded_GetPhysicalDeviceProperties2KHR(phys[i], &pdp2); 622 623 // These should always be true 624 static_assert(VK_UUID_SIZE == XRT_UUID_SIZE, "uuid sizes mismatch"); ··· 652 653 // vulkan_enable2 needs the physical device in xrCreateVulkanDeviceKHR 654 if (inst->extensions.KHR_vulkan_enable2) { 655 + sys->vulkan_enable2_instance = vulkanInstance; 656 } 657 sys->suggested_vulkan_physical_device = *vkPhysicalDevice; 658 if (log_level <= U_LOGGING_DEBUG) {
+22 -2
src/xrt/state_trackers/oxr/oxr_xret.h
··· 24 xrt_result_t check_ret = (RESULTS); \ 25 if (check_ret == XRT_ERROR_IPC_FAILURE) { \ 26 (SESS)->has_lost = true; \ 27 - return oxr_error(LOG, XR_ERROR_INSTANCE_LOST, "Call to " #FUNCTION " failed"); \ 28 } \ 29 if (check_ret != XRT_SUCCESS) { \ 30 - return oxr_error(LOG, XR_ERROR_RUNTIME_FAILURE, "Call to " #FUNCTION " failed"); \ 31 } \ 32 } while (false)
··· 24 xrt_result_t check_ret = (RESULTS); \ 25 if (check_ret == XRT_ERROR_IPC_FAILURE) { \ 26 (SESS)->has_lost = true; \ 27 + return oxr_error((LOG), XR_ERROR_INSTANCE_LOST, "Call to " #FUNCTION " failed"); \ 28 } \ 29 if (check_ret != XRT_SUCCESS) { \ 30 + return oxr_error((LOG), XR_ERROR_RUNTIME_FAILURE, "Call to " #FUNCTION " failed"); \ 31 + } \ 32 + } while (false) 33 + 34 + #define OXR_CHECK_XRET_ALWAYS_RET(LOG, SESS, RESULTS, FUNCTION) \ 35 + do { \ 36 + OXR_CHECK_XRET(LOG, SESS, RESULTS, FUNCTION); \ 37 + return XR_SUCCESS; \ 38 + } while (false) 39 + 40 + #define OXR_CHECK_XRET_GOTO(LOG, SESS, RESULTS, FUNCTION, XR_RES, GOTO_LABEL) \ 41 + do { \ 42 + xrt_result_t check_ret = (RESULTS); \ 43 + if (check_ret == XRT_ERROR_IPC_FAILURE) { \ 44 + (SESS)->has_lost = true; \ 45 + XR_RES = oxr_error(LOG, XR_ERROR_INSTANCE_LOST, "Call to " #FUNCTION " failed"); \ 46 + goto GOTO_LABEL; \ 47 + } \ 48 + if (check_ret != XRT_SUCCESS) { \ 49 + XR_RES = oxr_error(LOG, XR_ERROR_RUNTIME_FAILURE, "Call to " #FUNCTION " failed"); \ 50 + goto GOTO_LABEL; \ 51 } \ 52 } while (false)
+2 -1
src/xrt/state_trackers/steamvr_drv/ovrd_driver.cpp
··· 1108 1109 //! @todo more than 2 views 1110 struct xrt_space_relation head_relation; 1111 - xrt_device_get_view_poses(xdev, &ipd_vec, now_ns, 2, &head_relation, m_fovs, m_view_pose); 1112 1113 //! @todo more versatile IPD calculation 1114 float actual_ipd = -m_view_pose[0].position.x + m_view_pose[1].position.x;
··· 1108 1109 //! @todo more than 2 views 1110 struct xrt_space_relation head_relation; 1111 + xrt_device_get_view_poses(xdev, &ipd_vec, now_ns, XRT_VIEW_TYPE_STEREO, 2, &head_relation, m_fovs, 1112 + m_view_pose); 1113 1114 //! @todo more versatile IPD calculation 1115 float actual_ipd = -m_view_pose[0].position.x + m_view_pose[1].position.x;
+14
src/xrt/targets/common/target_instance.c
··· 1 // Copyright 2020-2024, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 50 * Internal functions. 51 * 52 */ 53 54 static xrt_result_t 55 t_instance_create_system(struct xrt_instance *xinst, ··· 168 } 169 170 struct t_instance *tinst = U_TYPED_CALLOC(struct t_instance); 171 tinst->base.create_system = t_instance_create_system; 172 tinst->base.get_prober = t_instance_get_prober; 173 tinst->base.destroy = t_instance_destroy;
··· 1 // Copyright 2020-2024, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 51 * Internal functions. 52 * 53 */ 54 + 55 + static xrt_result_t 56 + t_instance_is_system_available(struct xrt_instance *xinst, bool *out_available) 57 + { 58 + XRT_TRACE_MARKER(); 59 + 60 + assert(out_available != NULL); 61 + 62 + *out_available = true; 63 + 64 + return XRT_SUCCESS; 65 + } 66 67 static xrt_result_t 68 t_instance_create_system(struct xrt_instance *xinst, ··· 181 } 182 183 struct t_instance *tinst = U_TYPED_CALLOC(struct t_instance); 184 + tinst->base.is_system_available = t_instance_is_system_available; 185 tinst->base.create_system = t_instance_create_system; 186 tinst->base.get_prober = t_instance_get_prober; 187 tinst->base.destroy = t_instance_destroy;
+11
src/xrt/targets/ctl/main.c
··· 1 // Copyright 2020-2024, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 314 if (xret != XRT_SUCCESS) { 315 U_LOG_E("ipc_client_connection_init: %u", xret); 316 return -1; 317 } 318 319 switch (op_mode) {
··· 1 // Copyright 2020-2024, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 315 if (xret != XRT_SUCCESS) { 316 U_LOG_E("ipc_client_connection_init: %u", xret); 317 return -1; 318 + } 319 + 320 + bool is_system_available = false; 321 + xret = ipc_call_instance_is_system_available(&ipc_c, &is_system_available); 322 + if (xret != XRT_SUCCESS) { 323 + U_LOG_E("ipc_call_instance_is_system_available: %u", xret); 324 + return -1; 325 + } 326 + if (!is_system_available) { 327 + PE("System isn't available, devices won't be available!"); 328 } 329 330 switch (op_mode) {
+11
src/xrt/targets/libmonado/monado.c
··· 1 // Copyright 2019-2024, Collabora, Ltd. 2 // SPDX-License-Identifier: BSL-1.0 3 /*! 4 * @file ··· 145 PE("Connection init error '%i'!\n", xret); 146 free(r); 147 return MND_ERROR_CONNECTING_FAILED; 148 } 149 150 *out_root = r;
··· 1 // Copyright 2019-2024, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 3 // SPDX-License-Identifier: BSL-1.0 4 /*! 5 * @file ··· 146 PE("Connection init error '%i'!\n", xret); 147 free(r); 148 return MND_ERROR_CONNECTING_FAILED; 149 + } 150 + 151 + bool is_system_available = false; 152 + xret = ipc_call_instance_is_system_available(&r->ipc_c, &is_system_available); 153 + if (xret != XRT_SUCCESS) { 154 + PE("ipc_call_instance_is_system_available: '%i'!\n", xret); 155 + return -1; 156 + } 157 + if (!is_system_available) { 158 + PE("System isn't available, devices won't be available!"); 159 } 160 161 *out_root = r;
+28 -19
src/xrt/targets/sdl_test/sdl_compositor.c
··· 43 return &c->base.vk; 44 } 45 46 - #define SC_TRACE(c, ...) U_LOG_IFL_T(c->base.vk.log_level, __VA_ARGS__); 47 - #define SC_DEBUG(c, ...) U_LOG_IFL_D(c->base.vk.log_level, __VA_ARGS__); 48 - #define SC_INFO(c, ...) U_LOG_IFL_I(c->base.vk.log_level, __VA_ARGS__); 49 - #define SC_WARN(c, ...) U_LOG_IFL_W(c->base.vk.log_level, __VA_ARGS__); 50 - #define SC_ERROR(c, ...) U_LOG_IFL_E(c->base.vk.log_level, __VA_ARGS__); 51 52 53 /* ··· 246 struct comp_vulkan_formats formats = {0}; 247 comp_vulkan_formats_check(vk, &formats); 248 comp_vulkan_formats_copy_to_info(&formats, info); 249 - comp_vulkan_formats_log(c->base.vk.log_level, &formats); 250 251 return true; 252 } ··· 256 { 257 struct xrt_system_compositor_info *sys_info = &c->sys_info; 258 259 - // Required by OpenXR spec. 260 sys_info->max_layers = XRT_MAX_LAYERS; 261 262 // UUIDs and LUID already set in vk init. ··· 277 } 278 279 // clang-format off 280 - sys_info->views[0].recommended.width_pixels = w; 281 - sys_info->views[0].recommended.height_pixels = h; 282 - sys_info->views[0].recommended.sample_count = 1; 283 - sys_info->views[0].max.width_pixels = max; 284 - sys_info->views[0].max.height_pixels = max; 285 - sys_info->views[0].max.sample_count = 1; 286 287 - sys_info->views[1].recommended.width_pixels = min; // Second view is minimum 288 - sys_info->views[1].recommended.height_pixels = min; // Second view is minimum 289 - sys_info->views[1].recommended.sample_count = 1; 290 - sys_info->views[1].max.width_pixels = max; 291 - sys_info->views[1].max.height_pixels = max; 292 - sys_info->views[1].max.sample_count = 1; 293 // clang-format on 294 295 // Copy the list directly.
··· 43 return &c->base.vk; 44 } 45 46 + #define SC_TRACE(c, ...) U_LOG_IFL_T(get_vk(c)->log_level, __VA_ARGS__); 47 + #define SC_DEBUG(c, ...) U_LOG_IFL_D(get_vk(c)->log_level, __VA_ARGS__); 48 + #define SC_INFO(c, ...) U_LOG_IFL_I(get_vk(c)->log_level, __VA_ARGS__); 49 + #define SC_WARN(c, ...) U_LOG_IFL_W(get_vk(c)->log_level, __VA_ARGS__); 50 + #define SC_ERROR(c, ...) U_LOG_IFL_E(get_vk(c)->log_level, __VA_ARGS__); 51 52 53 /* ··· 246 struct comp_vulkan_formats formats = {0}; 247 comp_vulkan_formats_check(vk, &formats); 248 comp_vulkan_formats_copy_to_info(&formats, info); 249 + comp_vulkan_formats_log(vk->log_level, &formats); 250 251 return true; 252 } ··· 256 { 257 struct xrt_system_compositor_info *sys_info = &c->sys_info; 258 259 + /* 260 + * Required by OpenXR spec (minimum 16). 261 + * 262 + * NOTE: When using Vulkan compositor components (c/render, c/util), 263 + * call render_max_layers_capable() to clamp this value based on 264 + * actual device limits. 265 + */ 266 sys_info->max_layers = XRT_MAX_LAYERS; 267 268 // UUIDs and LUID already set in vk init. ··· 283 } 284 285 // clang-format off 286 + sys_info->view_configs[0].view_type = XRT_VIEW_TYPE_STEREO; 287 + sys_info->view_configs[0].view_count = 2; 288 + 289 + sys_info->view_configs[0].views[0].recommended.width_pixels = w; 290 + sys_info->view_configs[0].views[0].recommended.height_pixels = h; 291 + sys_info->view_configs[0].views[0].recommended.sample_count = 1; 292 + sys_info->view_configs[0].views[0].max.width_pixels = max; 293 + sys_info->view_configs[0].views[0].max.height_pixels = max; 294 + sys_info->view_configs[0].views[0].max.sample_count = 1; 295 296 + sys_info->view_configs[0].views[1].recommended.width_pixels = min; // Second view is minimum 297 + sys_info->view_configs[0].views[1].recommended.height_pixels = min; // Second view is minimum 298 + sys_info->view_configs[0].views[1].recommended.sample_count = 1; 299 + sys_info->view_configs[0].views[1].max.width_pixels = max; 300 + sys_info->view_configs[0].views[1].max.height_pixels = max; 301 + sys_info->view_configs[0].views[1].max.sample_count = 1; 302 // clang-format on 303 304 // Copy the list directly.
+4
src/xrt/targets/service/main.c
··· 11 12 #include "xrt/xrt_config_os.h" 13 14 #include "util/u_metrics.h" 15 #include "util/u_logging.h" 16 #include "util/u_trace_marker.h" ··· 22 #include "server/ipc_server_interface.h" 23 24 #include "target_lists.h" 25 26 27 // Insert the on load constructor to init trace marker. ··· 44 .window_title = "Monado! โœจโšก๐Ÿ”ฅ", 45 .open = U_DEBUG_GUI_OPEN_AUTO, 46 }, 47 }; 48 49 int ret = ipc_server_main(argc, argv, &ismi);
··· 11 12 #include "xrt/xrt_config_os.h" 13 14 + #include "util/u_debug.h" 15 #include "util/u_metrics.h" 16 #include "util/u_logging.h" 17 #include "util/u_trace_marker.h" ··· 23 #include "server/ipc_server_interface.h" 24 25 #include "target_lists.h" 26 + 27 + DEBUG_GET_ONCE_BOOL_OPTION(exit_on_disconnect, "IPC_EXIT_ON_DISCONNECT", false) 28 29 30 // Insert the on load constructor to init trace marker. ··· 47 .window_title = "Monado! โœจโšก๐Ÿ”ฅ", 48 .open = U_DEBUG_GUI_OPEN_AUTO, 49 }, 50 + .exit_on_disconnect = debug_get_bool_option_exit_on_disconnect(), 51 }; 52 53 int ret = ipc_server_main(argc, argv, &ismi);
+14
src/xrt/targets/service-lib/service_target.cpp
··· 78 // No-op 79 } 80 81 int32_t 82 addClient(int fd) 83 { ··· 140 .init_failed = signalInitFailed, 141 .mainloop_entering = signalStartupCompleteTrampoline, 142 .mainloop_leaving = signalShuttingDownTrampoline, 143 }; 144 145 //! Reference to the ipc_server, managed by ipc_server_process
··· 78 // No-op 79 } 80 81 + static void 82 + signalClientConnectedTrampoline(struct ipc_server *s, uint32_t client_id, void *data) 83 + { 84 + // No-op 85 + } 86 + 87 + static void 88 + signalClientDisconnectedTrampoline(struct ipc_server *s, uint32_t client_id, void *data) 89 + { 90 + // No-op 91 + } 92 + 93 int32_t 94 addClient(int fd) 95 { ··· 152 .init_failed = signalInitFailed, 153 .mainloop_entering = signalStartupCompleteTrampoline, 154 .mainloop_leaving = signalShuttingDownTrampoline, 155 + .client_connected = signalClientConnectedTrampoline, 156 + .client_disconnected = signalClientDisconnectedTrampoline, 157 }; 158 159 //! Reference to the ipc_server, managed by ipc_server_process
-1
src/xrt/tracking/hand/mercury/hg_sync.cpp
··· 25 26 27 namespace xrt::tracking::hand::mercury { 28 - #define DEG_TO_RAD(DEG) (DEG * M_PI / 180.) 29 30 DEBUG_GET_ONCE_LOG_OPTION(mercury_log, "MERCURY_LOG", U_LOGGING_WARN) 31 DEBUG_GET_ONCE_BOOL_OPTION(mercury_optimize_hand_size, "MERCURY_optimize_hand_size", true)
··· 25 26 27 namespace xrt::tracking::hand::mercury { 28 29 DEBUG_GET_ONCE_LOG_OPTION(mercury_log, "MERCURY_LOG", U_LOGGING_WARN) 30 DEBUG_GET_ONCE_BOOL_OPTION(mercury_optimize_hand_size, "MERCURY_optimize_hand_size", true)
+4 -10
src/xrt/tracking/hand/t_hand_tracking_async.c
··· 137 struct xrt_space_relation wrist_rel = 138 hta->working.hands[i].values.hand_joint_set_default[XRT_HAND_JOINT_WRIST].relation; 139 140 - m_relation_history_estimate_motion( // 141 - hta->present.relation_hist[i], // 142 - &wrist_rel, // 143 - hta->working.timestamp, // 144 - &wrist_rel); // 145 - 146 - m_relation_history_push( // 147 - hta->present.relation_hist[i], // 148 - &wrist_rel, // 149 - hta->working.timestamp); // 150 } 151 152 hta->hand_tracking_work_active = false;
··· 137 struct xrt_space_relation wrist_rel = 138 hta->working.hands[i].values.hand_joint_set_default[XRT_HAND_JOINT_WRIST].relation; 139 140 + m_relation_history_push_with_motion_estimation( // 141 + hta->present.relation_hist[i], // 142 + &wrist_rel, // 143 + hta->working.timestamp); // 144 } 145 146 hta->hand_tracking_work_active = false;
+7 -1
tests/CMakeLists.txt
··· 27 list(APPEND tests tests_aux_d3d_d3d11 tests_comp_client_d3d11) 28 endif() 29 if(XRT_HAVE_D3D12) 30 - list(APPEND tests tests_comp_client_d3d12) 31 endif() 32 if(XRT_HAVE_VULKAN) 33 list(APPEND tests tests_comp_client_vulkan tests_uv_to_tangent) ··· 52 target_link_libraries(${testname} PRIVATE xrt-external-catch2) 53 target_link_libraries(${testname} PRIVATE aux_util) 54 add_test(NAME ${testname} COMMAND ${testname} --success --allow-running-no-tests) 55 endforeach() 56 57 # For tests that require more than just aux_util, link those other libs down here. ··· 86 endif() 87 88 if(XRT_HAVE_D3D12) 89 target_link_libraries(tests_comp_client_d3d12 PRIVATE comp_client comp_mock) 90 endif() 91 ··· 111 if(XRT_HAVE_VULKAN AND XRT_HAVE_D3D11) 112 target_link_libraries(tests_aux_d3d_d3d11 PRIVATE comp_util aux_vk) 113 endif()
··· 27 list(APPEND tests tests_aux_d3d_d3d11 tests_comp_client_d3d11) 28 endif() 29 if(XRT_HAVE_D3D12) 30 + list(APPEND tests tests_aux_d3d_d3d12 tests_comp_client_d3d12) 31 endif() 32 if(XRT_HAVE_VULKAN) 33 list(APPEND tests tests_comp_client_vulkan tests_uv_to_tangent) ··· 52 target_link_libraries(${testname} PRIVATE xrt-external-catch2) 53 target_link_libraries(${testname} PRIVATE aux_util) 54 add_test(NAME ${testname} COMMAND ${testname} --success --allow-running-no-tests) 55 + set_target_properties(${testname} PROPERTIES FOLDER monado_tests) 56 endforeach() 57 58 # For tests that require more than just aux_util, link those other libs down here. ··· 87 endif() 88 89 if(XRT_HAVE_D3D12) 90 + target_link_libraries(tests_aux_d3d_d3d12 PRIVATE aux_d3d) 91 target_link_libraries(tests_comp_client_d3d12 PRIVATE comp_client comp_mock) 92 endif() 93 ··· 113 if(XRT_HAVE_VULKAN AND XRT_HAVE_D3D11) 114 target_link_libraries(tests_aux_d3d_d3d11 PRIVATE comp_util aux_vk) 115 endif() 116 + 117 + if(XRT_HAVE_VULKAN AND XRT_HAVE_D3D12) 118 + target_link_libraries(tests_aux_d3d_d3d12 PRIVATE comp_util aux_vk) 119 + endif()
+13 -15
tests/tests_aux_d3d_d3d11.cpp
··· 88 std::vector<xrt_image_native> xins; 89 xins.reserve(image_count); 90 91 - // Keep this around until after successful import, then detach all. 92 - std::vector<wil::unique_handle> handlesForImport; 93 - handlesForImport.reserve(image_count); 94 - 95 for (HANDLE handle : handles) { 96 - wil::unique_handle duped{u_graphics_buffer_ref(handle)}; 97 xrt_image_native xin; 98 - xin.handle = duped.get(); 99 xin.size = 0; 100 xin.use_dedicated_allocation = use_dedicated_allocation; 101 102 - handlesForImport.emplace_back(std::move(duped)); 103 xins.emplace_back(xin); 104 } 105 106 // Import into a vulkan image collection 107 - bool result = VK_SUCCESS == vk_ic_from_natives(vk, &vk_info, xins.data(), (uint32_t)xins.size(), vkic.get()); 108 109 - if (result) { 110 - // The imported swapchain took ownership of them now, release them from ownership here. 111 - for (auto &h : handlesForImport) { 112 - h.release(); 113 - } 114 - } 115 - return result; 116 } 117 #else 118
··· 88 std::vector<xrt_image_native> xins; 89 xins.reserve(image_count); 90 91 for (HANDLE handle : handles) { 92 + /*! 93 + * If shared resources have been allocated without using NT handles we can't use DuplicateHandle 94 + *(like u_graphics_buffer_ref does internally) or CloseHandle (which wil::~unique_handle will call). 95 + * More info: 96 + * https://learn.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-idxgiresource-getsharedhandle#remarks 97 + * When using KMT handles, their validity is tied to the underlying video memory (I guess that means a 98 + * ID3D11Texture2D object). 99 + */ 100 xrt_image_native xin; 101 + xin.handle = handle; 102 xin.size = 0; 103 xin.use_dedicated_allocation = use_dedicated_allocation; 104 + xin.is_dxgi_handle = true; 105 106 xins.emplace_back(xin); 107 } 108 109 // Import into a vulkan image collection 110 + const VkResult ret = vk_ic_from_natives(vk, &vk_info, xins.data(), (uint32_t)xins.size(), vkic.get()); 111 + VK_CHK_WITH_RET(ret, "vk_ic_from_natives", false); 112 113 + return true; 114 } 115 #else 116
+201
tests/tests_aux_d3d_d3d12.cpp
···
··· 1 + // Copyright 2022, Collabora, Ltd. 2 + // Copyright 2025, Holo-Light GmbH 3 + // SPDX-License-Identifier: BSL-1.0 4 + /*! 5 + * @file 6 + * @brief Direct3D 12 tests. 7 + * @author Rylie Pavlik <rylie.pavlik@collabora.com> 8 + * @author Krzysztof Lesiak <c-k.lesiak@holo-light.com> 9 + */ 10 + 11 + #include "catch_amalgamated.hpp" 12 + 13 + #include <util/u_win32_com_guard.hpp> 14 + #include <d3d/d3d_dxgi_helpers.hpp> 15 + #include <d3d/d3d_d3d12_helpers.hpp> 16 + #include <d3d/d3d_d3d12_allocator.hpp> 17 + #include "aux_d3d_dxgi_formats.hpp" 18 + 19 + #ifdef XRT_HAVE_VULKAN 20 + #include "vktest_init_bundle.hpp" 21 + #include <vk/vk_image_allocator.h> 22 + #include <util/u_handles.h> 23 + #include <d3d/d3d_dxgi_formats.h> 24 + #endif 25 + 26 + using namespace xrt::auxiliary::util; 27 + 28 + TEST_CASE("d3d12_device", "[.][needgpu]") 29 + { 30 + ComGuard comGuard; 31 + 32 + wil::com_ptr<IDXGIAdapter> adapter; 33 + CHECK_NOTHROW(adapter = xrt::auxiliary::d3d::getAdapterByIndex(0, U_LOGGING_TRACE)); 34 + CHECK(adapter); 35 + 36 + wil::com_ptr<ID3D12Device> device; 37 + CHECK_NOTHROW(device = xrt::auxiliary::d3d::d3d12::createDevice(adapter, U_LOGGING_TRACE)); 38 + CHECK(device); 39 + } 40 + 41 + #ifdef XRT_HAVE_VULKAN 42 + 43 + static inline bool 44 + tryImport(struct vk_bundle *vk, 45 + std::vector<wil::unique_handle> &handles, 46 + const struct xrt_swapchain_create_info &xsci, 47 + size_t image_mem_size) 48 + { 49 + // in d3d11 tryImport handles is const..here we do away with it so we can call release on handles passed in? 50 + // I need to read more about wil and figure out lifetime semantics of all this. 51 + 52 + INFO("Testing import into Vulkan"); 53 + 54 + static constexpr bool use_dedicated_allocation = false; 55 + xrt_swapchain_create_info vk_info = xsci; 56 + vk_info.format = d3d_dxgi_format_to_vk((DXGI_FORMAT)xsci.format); 57 + const auto free_vk_ic = [&](struct vk_image_collection *vkic) { 58 + vk_ic_destroy(vk, vkic); 59 + delete vkic; 60 + }; 61 + 62 + std::shared_ptr<vk_image_collection> vkic{new vk_image_collection, free_vk_ic}; 63 + 64 + uint32_t image_count = static_cast<uint32_t>(handles.size()); 65 + 66 + // Populate for import 67 + std::vector<xrt_image_native> xins; 68 + xins.reserve(image_count); 69 + 70 + for (auto &handle : handles) { 71 + xrt_image_native xin; 72 + xin.handle = handle.get(); 73 + xin.size = image_mem_size; 74 + xin.use_dedicated_allocation = use_dedicated_allocation; 75 + xin.is_dxgi_handle = false; 76 + 77 + xins.emplace_back(xin); 78 + } 79 + 80 + // Import into a vulkan image collection 81 + bool result = VK_SUCCESS == vk_ic_from_natives(vk, &vk_info, xins.data(), (uint32_t)xins.size(), vkic.get()); 82 + 83 + if (result) { 84 + // The imported swapchain took ownership of them now, release them from ownership here. 85 + for (wil::unique_handle &h : handles) { 86 + h.release(); 87 + } 88 + } 89 + return result; 90 + } 91 + #else 92 + 93 + static inline bool 94 + tryImport(struct vk_bundle * /* vk */, 95 + std::vector<wil::unique_handle> const & /* handles */, 96 + const struct xrt_swapchain_create_info & /* xsci */) 97 + { 98 + return true; 99 + } 100 + 101 + #endif 102 + 103 + TEST_CASE("d3d12_allocate", "[.][needgpu]") 104 + { 105 + unique_vk_bundle vk = makeVkBundle(); 106 + 107 + #ifdef XRT_HAVE_VULKAN 108 + REQUIRE(vktest_init_bundle(vk.get())); 109 + #endif 110 + 111 + ComGuard comGuard; 112 + 113 + wil::com_ptr<IDXGIAdapter> adapter = xrt::auxiliary::d3d::getAdapterByIndex(0, U_LOGGING_TRACE); 114 + wil::com_ptr<ID3D12Device> device = xrt::auxiliary::d3d::d3d12::createDevice(adapter, U_LOGGING_TRACE); 115 + std::vector<wil::com_ptr<ID3D12Resource>> images; 116 + std::vector<wil::unique_handle> handles; 117 + size_t out_image_mem_size = 0; 118 + 119 + size_t image_count = 3; 120 + 121 + xrt_swapchain_create_info xsci{}; 122 + CAPTURE(xsci.sample_count = 1); 123 + CAPTURE(xsci.width = 800); 124 + CAPTURE(xsci.height = 600); 125 + 126 + CAPTURE(xsci.mip_count = 1); 127 + xsci.face_count = 1; 128 + xsci.array_size = 1; 129 + 130 + SECTION("create images") 131 + { 132 + auto nameAndFormat = GENERATE(values(namesAndFormats)); 133 + DYNAMIC_SECTION("Texture format " << nameAndFormat.first) 134 + { 135 + auto format = nameAndFormat.second; 136 + CAPTURE(isDepthStencilFormat(format)); 137 + xsci.format = format; 138 + if (isDepthStencilFormat(format)) { 139 + xsci.bits = XRT_SWAPCHAIN_USAGE_DEPTH_STENCIL; 140 + } else { 141 + xsci.bits = XRT_SWAPCHAIN_USAGE_COLOR; 142 + } 143 + xsci.bits = (xrt_swapchain_usage_bits)(xsci.bits | XRT_SWAPCHAIN_USAGE_SAMPLED); 144 + images.clear(); 145 + handles.clear(); 146 + 147 + SECTION("invalid array size 0") 148 + { 149 + CAPTURE(xsci.array_size = 0); 150 + REQUIRE(XRT_SUCCESS != 151 + xrt::auxiliary::d3d::d3d12::allocateSharedImages( 152 + *device.get(), xsci, image_count, images, handles, out_image_mem_size)); 153 + CHECK(images.empty()); 154 + CHECK(handles.empty()); 155 + } 156 + SECTION("not array") 157 + { 158 + CAPTURE(xsci.array_size); 159 + REQUIRE(XRT_SUCCESS == 160 + xrt::auxiliary::d3d::d3d12::allocateSharedImages( 161 + *device.get(), xsci, image_count, images, handles, out_image_mem_size)); 162 + CHECK(images.size() == image_count); 163 + CHECK(handles.size() == image_count); 164 + CHECK(tryImport(vk.get(), handles, xsci, out_image_mem_size)); 165 + } 166 + SECTION("array of 2") 167 + { 168 + CAPTURE(xsci.array_size = 2); 169 + REQUIRE(XRT_SUCCESS == 170 + xrt::auxiliary::d3d::d3d12::allocateSharedImages( 171 + *device.get(), xsci, image_count, images, handles, out_image_mem_size)); 172 + CHECK(images.size() == image_count); 173 + CHECK(handles.size() == image_count); 174 + CHECK(tryImport(vk.get(), handles, xsci, out_image_mem_size)); 175 + } 176 + // this does not return an error...so i guess allocating cubemaps with d3d12 is fine? 177 + // SECTION("cubemaps not implemented") 178 + // { 179 + // CAPTURE(xsci.array_size); 180 + // CAPTURE(xsci.face_count = 6); 181 + // REQUIRE(XRT_ERROR_ALLOCATION == 182 + // xrt::auxiliary::d3d::d3d12::allocateSharedImages(*device.get(), xsci, 183 + // imageCount, 184 + // images, handles, 185 + // outImageMemSize)); 186 + // CHECK(images.empty()); 187 + // CHECK(handles.empty()); 188 + // } 189 + SECTION("protected content not implemented") 190 + { 191 + CAPTURE(xsci.array_size); 192 + CAPTURE(xsci.create = XRT_SWAPCHAIN_CREATE_PROTECTED_CONTENT); 193 + REQUIRE(XRT_ERROR_SWAPCHAIN_FLAG_VALID_BUT_UNSUPPORTED == 194 + xrt::auxiliary::d3d::d3d12::allocateSharedImages( 195 + *device.get(), xsci, image_count, images, handles, out_image_mem_size)); 196 + CHECK(images.empty()); 197 + CHECK(handles.empty()); 198 + } 199 + } 200 + } 201 + }